Add secp256k1_fe_is_square_var function
The implementation calls the secp256k1_modinvNN_jacobi_var code, falling back to computing a square root in the (extremely rare) case it failed converge.
This commit is contained in:
parent
1de2a01c2b
commit
6be01036c8
|
@ -219,6 +219,19 @@ static void bench_field_sqrt(void* arg, int iters) {
|
||||||
CHECK(j <= iters);
|
CHECK(j <= iters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void bench_field_is_square_var(void* arg, int iters) {
|
||||||
|
int i, j = 0;
|
||||||
|
bench_inv *data = (bench_inv*)arg;
|
||||||
|
secp256k1_fe t = data->fe[0];
|
||||||
|
|
||||||
|
for (i = 0; i < iters; i++) {
|
||||||
|
j += secp256k1_fe_is_square_var(&t);
|
||||||
|
secp256k1_fe_add(&t, &data->fe[1]);
|
||||||
|
secp256k1_fe_normalize_var(&t);
|
||||||
|
}
|
||||||
|
CHECK(j <= iters);
|
||||||
|
}
|
||||||
|
|
||||||
static void bench_group_double_var(void* arg, int iters) {
|
static void bench_group_double_var(void* arg, int iters) {
|
||||||
int i;
|
int i;
|
||||||
bench_inv *data = (bench_inv*)arg;
|
bench_inv *data = (bench_inv*)arg;
|
||||||
|
@ -371,6 +384,7 @@ int main(int argc, char **argv) {
|
||||||
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10);
|
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, iters*10);
|
||||||
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
|
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, iters);
|
||||||
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters);
|
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, iters);
|
||||||
|
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "issquare")) run_benchmark("field_is_square_var", bench_field_is_square_var, bench_setup, NULL, &data, 10, iters);
|
||||||
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
|
if (d || have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, iters);
|
||||||
|
|
||||||
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10);
|
if (d || have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, iters*10);
|
||||||
|
|
|
@ -135,4 +135,7 @@ static void secp256k1_fe_half(secp256k1_fe *r);
|
||||||
* magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
|
* magnitude set to 'm' and is normalized if (and only if) 'm' is zero. */
|
||||||
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
|
static void secp256k1_fe_get_bounds(secp256k1_fe *r, int m);
|
||||||
|
|
||||||
|
/** Determine whether a is a square (modulo p). */
|
||||||
|
static int secp256k1_fe_is_square_var(const secp256k1_fe *a);
|
||||||
|
|
||||||
#endif /* SECP256K1_FIELD_H */
|
#endif /* SECP256K1_FIELD_H */
|
||||||
|
|
|
@ -1365,4 +1365,31 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||||
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
|
VERIFY_CHECK(secp256k1_fe_normalizes_to_zero(r) == secp256k1_fe_normalizes_to_zero(&tmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
|
||||||
|
secp256k1_fe tmp;
|
||||||
|
secp256k1_modinv32_signed30 s;
|
||||||
|
int jac, ret;
|
||||||
|
|
||||||
|
tmp = *x;
|
||||||
|
secp256k1_fe_normalize_var(&tmp);
|
||||||
|
/* secp256k1_jacobi32_maybe_var cannot deal with input 0. */
|
||||||
|
if (secp256k1_fe_is_zero(&tmp)) return 1;
|
||||||
|
secp256k1_fe_to_signed30(&s, &tmp);
|
||||||
|
jac = secp256k1_jacobi32_maybe_var(&s, &secp256k1_const_modinfo_fe);
|
||||||
|
if (jac == 0) {
|
||||||
|
/* secp256k1_jacobi32_maybe_var failed to compute the Jacobi symbol. Fall back
|
||||||
|
* to computing a square root. This should be extremely rare with random
|
||||||
|
* input (except in VERIFY mode, where a lower iteration count is used). */
|
||||||
|
secp256k1_fe dummy;
|
||||||
|
ret = secp256k1_fe_sqrt(&dummy, &tmp);
|
||||||
|
} else {
|
||||||
|
#ifdef VERIFY
|
||||||
|
secp256k1_fe dummy;
|
||||||
|
VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
|
||||||
|
#endif
|
||||||
|
ret = jac >= 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
|
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
|
||||||
|
|
|
@ -664,4 +664,31 @@ static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *x) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int secp256k1_fe_is_square_var(const secp256k1_fe *x) {
|
||||||
|
secp256k1_fe tmp;
|
||||||
|
secp256k1_modinv64_signed62 s;
|
||||||
|
int jac, ret;
|
||||||
|
|
||||||
|
tmp = *x;
|
||||||
|
secp256k1_fe_normalize_var(&tmp);
|
||||||
|
/* secp256k1_jacobi64_maybe_var cannot deal with input 0. */
|
||||||
|
if (secp256k1_fe_is_zero(&tmp)) return 1;
|
||||||
|
secp256k1_fe_to_signed62(&s, &tmp);
|
||||||
|
jac = secp256k1_jacobi64_maybe_var(&s, &secp256k1_const_modinfo_fe);
|
||||||
|
if (jac == 0) {
|
||||||
|
/* secp256k1_jacobi64_maybe_var failed to compute the Jacobi symbol. Fall back
|
||||||
|
* to computing a square root. This should be extremely rare with random
|
||||||
|
* input (except in VERIFY mode, where a lower iteration count is used). */
|
||||||
|
secp256k1_fe dummy;
|
||||||
|
ret = secp256k1_fe_sqrt(&dummy, &tmp);
|
||||||
|
} else {
|
||||||
|
#ifdef VERIFY
|
||||||
|
secp256k1_fe dummy;
|
||||||
|
VERIFY_CHECK(jac == 2*secp256k1_fe_sqrt(&dummy, &tmp) - 1);
|
||||||
|
#endif
|
||||||
|
ret = jac >= 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
|
#endif /* SECP256K1_FIELD_REPR_IMPL_H */
|
||||||
|
|
|
@ -3299,8 +3299,10 @@ static void run_sqrt(void) {
|
||||||
for (j = 0; j < COUNT; j++) {
|
for (j = 0; j < COUNT; j++) {
|
||||||
random_fe(&x);
|
random_fe(&x);
|
||||||
secp256k1_fe_sqr(&s, &x);
|
secp256k1_fe_sqr(&s, &x);
|
||||||
|
CHECK(secp256k1_fe_is_square_var(&s));
|
||||||
test_sqrt(&s, &x);
|
test_sqrt(&s, &x);
|
||||||
secp256k1_fe_negate(&t, &s, 1);
|
secp256k1_fe_negate(&t, &s, 1);
|
||||||
|
CHECK(!secp256k1_fe_is_square_var(&t));
|
||||||
test_sqrt(&t, NULL);
|
test_sqrt(&t, NULL);
|
||||||
secp256k1_fe_mul(&t, &s, &ns);
|
secp256k1_fe_mul(&t, &s, &ns);
|
||||||
test_sqrt(&t, NULL);
|
test_sqrt(&t, NULL);
|
||||||
|
|
Loading…
Reference in New Issue