diff --git a/src/group.h b/src/group.h index d81deb4264..0f5ec6fe47 100644 --- a/src/group.h +++ b/src/group.h @@ -174,6 +174,14 @@ static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_g /** Rescale a jacobian point by b which must be non-zero. Constant-time. */ static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); +/** Convert a group element that is not infinity to a 64-byte array. The output + * array is platform-dependent. */ +static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a); + +/** Convert a 64-byte array into group element. This function assumes that the + * provided buffer correctly encodes a group element. */ +static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf); + /** Determine if a point (which is assumed to be on the curve) is in the correct (sub)group of the curve. * * In normal mode, the used group is secp256k1, which has cofactor=1 meaning that every point on the curve is in the diff --git a/src/group_impl.h b/src/group_impl.h index 537be32ff6..cb390ee8e7 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -7,6 +7,8 @@ #ifndef SECP256K1_GROUP_IMPL_H #define SECP256K1_GROUP_IMPL_H +#include + #include "field.h" #include "group.h" #include "util.h" @@ -941,4 +943,24 @@ static int secp256k1_ge_x_frac_on_curve_var(const secp256k1_fe *xn, const secp25 return secp256k1_fe_is_square_var(&r); } +static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a) { + secp256k1_ge_storage s; + + /* We require that the secp256k1_ge_storage type is exactly 64 bytes. + * This is formally not guaranteed by the C standard, but should hold on any + * sane compiler in the real world. */ + STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); + VERIFY_CHECK(!secp256k1_ge_is_infinity(a)); + secp256k1_ge_to_storage(&s, a); + memcpy(buf, &s, 64); +} + +static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) { + secp256k1_ge_storage s; + + STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); + memcpy(&s, buf, 64); + secp256k1_ge_from_storage(r, &s); +} + #endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/src/secp256k1.c b/src/secp256k1.c index 72d725a74e..8821718a7d 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -238,25 +238,13 @@ static SECP256K1_INLINE void secp256k1_declassify(const secp256k1_context* ctx, } static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { - secp256k1_ge_storage s; - - /* We require that the secp256k1_ge_storage type is exactly 64 bytes. - * This is formally not guaranteed by the C standard, but should hold on any - * sane compiler in the real world. */ - STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); - memcpy(&s, &pubkey->data[0], 64); - secp256k1_ge_from_storage(ge, &s); + secp256k1_ge_from_bytes(ge, pubkey->data); ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); return 1; } static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { - secp256k1_ge_storage s; - - STATIC_ASSERT(sizeof(secp256k1_ge_storage) == 64); - VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); - secp256k1_ge_to_storage(&s, ge); - memcpy(&pubkey->data[0], &s, 64); + secp256k1_ge_to_bytes(pubkey->data, ge); } int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { diff --git a/src/tests.c b/src/tests.c index 70c15f870b..502161e94d 100644 --- a/src/tests.c +++ b/src/tests.c @@ -3982,6 +3982,23 @@ static void test_add_neg_y_diff_x(void) { CHECK(secp256k1_gej_eq_ge_var(&sumj, &res)); } +static void test_ge_bytes(void) { + int i; + + for (i = 0; i < COUNT; i++) { + unsigned char buf[64]; + secp256k1_ge p, q; + + testutil_random_ge_test(&p); + + if (!secp256k1_ge_is_infinity(&p)) { + secp256k1_ge_to_bytes(buf, &p); + secp256k1_ge_from_bytes(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); + } + } +} + static void run_ge(void) { int i; for (i = 0; i < COUNT * 32; i++) { @@ -3989,6 +4006,7 @@ static void run_ge(void) { } test_add_neg_y_diff_x(); test_intialized_inf(); + test_ge_bytes(); } static void test_gej_cmov(const secp256k1_gej *a, const secp256k1_gej *b) {