feat(crypto): implement Legendre symbol

tychovrahe/trdisplay/qr
Ondřej Vejpustek 9 months ago
parent 5a9d399012
commit 3a2bdf16dd

@ -1591,6 +1591,39 @@ void bn_subtract(const bignum256 *x, const bignum256 *y, bignum256 *res) {
// == 1
}
// Returns 0 if x is zero
// Returns 1 if x is a square modulo prime
// Returns -1 if x is not a square modulo prime
// Assumes x is normalized, x < 2**259
// Assumes prime is normalized, 2**256 - 2**224 <= prime <= 2**256
// Assumes prime is a prime
// The function doesn't have neither constant control flow nor constant memory
// access flow with regard to prime
int bn_legendre(const bignum256 *x, const bignum256 *prime) {
// This is a naive implementation
// A better implementation would be to use the Euclidean algorithm together with the quadratic reciprocity law
// e = (prime - 1) / 2
bignum256 e = {0};
bn_copy(prime, &e);
bn_rshift(&e);
// res = x**e % prime
bignum256 res = {0};
bn_power_mod(x, &e, prime, &res);
bn_mod(&res, prime);
if (bn_is_one(&res)) {
return 1;
}
if (bn_is_zero(&res)) {
return 0;
}
return -1;
}
// q = x // d, r = x % d
// Assumes x is normalized, 1 <= d <= 61304
// Guarantees q is normalized

@ -108,6 +108,7 @@ void bn_subi(bignum256 *x, uint32_t y, const bignum256 *prime);
void bn_subtractmod(const bignum256 *x, const bignum256 *y, bignum256 *res,
const bignum256 *prime);
void bn_subtract(const bignum256 *x, const bignum256 *y, bignum256 *res);
int bn_legendre(const bignum256 *x, const bignum256 *prime);
void bn_long_division(bignum256 *x, uint32_t d, bignum256 *q, uint32_t *r);
void bn_divmod58(bignum256 *x, uint32_t *r);
void bn_divmod1000(bignum256 *x, uint32_t *r);

@ -551,6 +551,21 @@ def assert_bn_subtractmod(x, y, prime):
assert res % prime == (x - y) % prime
def legendre(x, prime):
res = pow(x, (prime - 1) // 2, prime)
if res == prime - 1:
return -1
return res
def assert_bn_legendre(x, prime):
bn_x = int_to_bignum(x)
bn_prime = int_to_bignum(prime)
return_value = lib.bn_legendre(bn_x, bn_prime)
assert return_value == legendre(x, prime)
def assert_bn_subtract(x, y):
bn_x = int_to_bignum(x)
bn_y = int_to_bignum(y)
@ -1005,6 +1020,11 @@ def test_bn_subtract_2(r):
assert_bn_subtract(a, b)
def test_bn_legendre(r, prime):
x = r.rand_int_bitsize(259)
assert_bn_legendre(x, prime)
def test_bn_long_division(r):
x = r.rand_int_normalized()
d = r.randrange(1, 61304 + 1)

Loading…
Cancel
Save