diff --git a/src/group.h b/src/group.h index 0f5ec6fe..992ff5c9 100644 --- a/src/group.h +++ b/src/group.h @@ -182,6 +182,14 @@ static void secp256k1_ge_to_bytes(unsigned char *buf, const secp256k1_ge *a); * provided buffer correctly encodes a group element. */ static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf); +/** Convert a group element (that is allowed to be infinity) to a 64-byte + * array. The output array is platform-dependent. */ +static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge); + +/** Convert a 64-byte array into a group element. This function assumes that the + * provided buffer is the output of secp256k1_ge_to_bytes_ext. */ +static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data); + /** 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 cb390ee8..2e096f41 100644 --- a/src/group_impl.h +++ b/src/group_impl.h @@ -963,4 +963,21 @@ static void secp256k1_ge_from_bytes(secp256k1_ge *r, const unsigned char *buf) { secp256k1_ge_from_storage(r, &s); } +static void secp256k1_ge_to_bytes_ext(unsigned char *data, const secp256k1_ge *ge) { + if (secp256k1_ge_is_infinity(ge)) { + memset(data, 0, 64); + } else { + secp256k1_ge_to_bytes(data, ge); + } +} + +static void secp256k1_ge_from_bytes_ext(secp256k1_ge *ge, const unsigned char *data) { + static const unsigned char zeros[64] = { 0 }; + if (secp256k1_memcmp_var(data, zeros, sizeof(zeros)) == 0) { + secp256k1_ge_set_infinity(ge); + } else { + secp256k1_ge_from_bytes(ge, data); + } +} + #endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/src/tests.c b/src/tests.c index 502161e9..935a03eb 100644 --- a/src/tests.c +++ b/src/tests.c @@ -3985,17 +3985,28 @@ static void test_add_neg_y_diff_x(void) { static void test_ge_bytes(void) { int i; - for (i = 0; i < COUNT; i++) { + for (i = 0; i < COUNT + 1; i++) { unsigned char buf[64]; secp256k1_ge p, q; - testutil_random_ge_test(&p); + if (i == 0) { + secp256k1_ge_set_infinity(&p); + } else { + 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)); + + secp256k1_ge_from_bytes_ext(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); } + secp256k1_ge_to_bytes_ext(buf, &p); + secp256k1_ge_from_bytes_ext(&q, buf); + CHECK(secp256k1_ge_eq_var(&p, &q)); } }