mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 02:25:40 +01:00
Merge pull request #348
6466625
Improvements for coordinate decompression (Pieter Wuille)
This commit is contained in:
commit
970164dace
@ -87,9 +87,11 @@ static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp2
|
||||
* The output magnitude is 1 (but not guaranteed to be normalized). */
|
||||
static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
|
||||
/** Sets a field element to be the (modular) square root (if any exist) of another. Requires the
|
||||
* input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be
|
||||
* normalized). Return value indicates whether a square root was found. */
|
||||
/** If a has a square root, it is computed in r and 1 is returned. If a does not
|
||||
* have a square root, the root of its negation is computed and 0 is returned.
|
||||
* The input's magnitude can be at most 8. The output magnitude is 1 (but not
|
||||
* guaranteed to be normalized). The result in r will always be a square
|
||||
* itself. */
|
||||
static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a);
|
||||
|
||||
/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be
|
||||
|
@ -29,6 +29,15 @@ SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const
|
||||
}
|
||||
|
||||
static int secp256k1_fe_sqrt_var(secp256k1_fe *r, const secp256k1_fe *a) {
|
||||
/** Given that p is congruent to 3 mod 4, we can compute the square root of
|
||||
* a mod p as the (p+1)/4'th power of a.
|
||||
*
|
||||
* As (p+1)/4 is an even number, it will have the same result for a and for
|
||||
* (-a). Only one of these two numbers actually has a square root however,
|
||||
* so we test at the end by squaring and comparing to the input.
|
||||
* Also because (p+1)/4 is an even number, the computed square root is
|
||||
* itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)).
|
||||
*/
|
||||
secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1;
|
||||
int j;
|
||||
|
||||
|
@ -43,6 +43,12 @@ typedef struct {
|
||||
/** Set a group element equal to the point with given X and Y coordinates */
|
||||
static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y);
|
||||
|
||||
/** Set a group element (affine) equal to the point with the given X coordinate
|
||||
* and a Y coordinate that is a quadratic residue modulo p. The return value
|
||||
* is true iff a coordinate with the given X coordinate exists.
|
||||
*/
|
||||
static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x);
|
||||
|
||||
/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness
|
||||
* for Y. Return value indicates whether the result is valid. */
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd);
|
||||
|
@ -165,7 +165,7 @@ static void secp256k1_ge_clear(secp256k1_ge *r) {
|
||||
secp256k1_fe_clear(&r->y);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||
static int secp256k1_ge_set_xquad_var(secp256k1_ge *r, const secp256k1_fe *x) {
|
||||
secp256k1_fe x2, x3, c;
|
||||
r->x = *x;
|
||||
secp256k1_fe_sqr(&x2, x);
|
||||
@ -173,7 +173,11 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o
|
||||
r->infinity = 0;
|
||||
secp256k1_fe_set_int(&c, 7);
|
||||
secp256k1_fe_add(&c, &x3);
|
||||
if (!secp256k1_fe_sqrt_var(&r->y, &c)) {
|
||||
return secp256k1_fe_sqrt_var(&r->y, &c);
|
||||
}
|
||||
|
||||
static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) {
|
||||
if (!secp256k1_ge_set_xquad_var(r, x)) {
|
||||
return 0;
|
||||
}
|
||||
secp256k1_fe_normalize_var(&r->y);
|
||||
@ -181,6 +185,7 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int o
|
||||
secp256k1_fe_negate(&r->y, &r->y, 1);
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) {
|
||||
|
67
src/tests.c
67
src/tests.c
@ -1420,6 +1420,16 @@ void random_fe(secp256k1_fe *x) {
|
||||
} while(1);
|
||||
}
|
||||
|
||||
void random_fe_test(secp256k1_fe *x) {
|
||||
unsigned char bin[32];
|
||||
do {
|
||||
secp256k1_rand256_test(bin);
|
||||
if (secp256k1_fe_set_b32(x, bin)) {
|
||||
return;
|
||||
}
|
||||
} while(1);
|
||||
}
|
||||
|
||||
void random_fe_non_zero(secp256k1_fe *nz) {
|
||||
int tries = 10;
|
||||
while (--tries >= 0) {
|
||||
@ -2038,6 +2048,62 @@ void run_ec_combine(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void test_group_decompress(const secp256k1_fe* x) {
|
||||
/* The input itself, normalized. */
|
||||
secp256k1_fe fex = *x;
|
||||
secp256k1_fe tmp;
|
||||
/* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */
|
||||
secp256k1_ge ge_quad, ge_even, ge_odd;
|
||||
/* Return values of the above calls. */
|
||||
int res_quad, res_even, res_odd;
|
||||
|
||||
secp256k1_fe_normalize_var(&fex);
|
||||
|
||||
res_quad = secp256k1_ge_set_xquad_var(&ge_quad, &fex);
|
||||
res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0);
|
||||
res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1);
|
||||
|
||||
CHECK(res_quad == res_even);
|
||||
CHECK(res_quad == res_odd);
|
||||
|
||||
if (res_quad) {
|
||||
secp256k1_fe_normalize_var(&ge_quad.x);
|
||||
secp256k1_fe_normalize_var(&ge_odd.x);
|
||||
secp256k1_fe_normalize_var(&ge_even.x);
|
||||
secp256k1_fe_normalize_var(&ge_quad.y);
|
||||
secp256k1_fe_normalize_var(&ge_odd.y);
|
||||
secp256k1_fe_normalize_var(&ge_even.y);
|
||||
|
||||
/* No infinity allowed. */
|
||||
CHECK(!ge_quad.infinity);
|
||||
CHECK(!ge_even.infinity);
|
||||
CHECK(!ge_odd.infinity);
|
||||
|
||||
/* Check that the x coordinates check out. */
|
||||
CHECK(secp256k1_fe_equal_var(&ge_quad.x, x));
|
||||
CHECK(secp256k1_fe_equal_var(&ge_even.x, x));
|
||||
CHECK(secp256k1_fe_equal_var(&ge_odd.x, x));
|
||||
|
||||
/* Check that the Y coordinate result in ge_quad is a square. */
|
||||
CHECK(secp256k1_fe_sqrt_var(&tmp, &ge_quad.y));
|
||||
secp256k1_fe_sqr(&tmp, &tmp);
|
||||
CHECK(secp256k1_fe_equal_var(&tmp, &ge_quad.y));
|
||||
|
||||
/* Check odd/even Y in ge_odd, ge_even. */
|
||||
CHECK(secp256k1_fe_is_odd(&ge_odd.y));
|
||||
CHECK(!secp256k1_fe_is_odd(&ge_even.y));
|
||||
}
|
||||
}
|
||||
|
||||
void run_group_decompress(void) {
|
||||
int i;
|
||||
for (i = 0; i < count * 4; i++) {
|
||||
secp256k1_fe fe;
|
||||
random_fe_test(&fe);
|
||||
test_group_decompress(&fe);
|
||||
}
|
||||
}
|
||||
|
||||
/***** ECMULT TESTS *****/
|
||||
|
||||
void run_ecmult_chain(void) {
|
||||
@ -4259,6 +4325,7 @@ int main(int argc, char **argv) {
|
||||
|
||||
/* group tests */
|
||||
run_ge();
|
||||
run_group_decompress();
|
||||
|
||||
/* ecmult tests */
|
||||
run_wnaf();
|
||||
|
Loading…
Reference in New Issue
Block a user