This repository has been archived by the owner on Jul 24, 2024. It is now read-only.
forked from cosanta/cosanta-core
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge dashpay#808: Exhaustive test improvements + exhaustive schnorrs…
…ig tests 8b7dcdd Add exhaustive test for extrakeys and schnorrsig (Pieter Wuille) 08d7d89 Make pubkey parsing test whether points are in the correct subgroup (Pieter Wuille) 87af00b Abstract out challenge computation in schnorrsig (Pieter Wuille) 63e1b2a Disable output buffering in tests_exhaustive.c (Pieter Wuille) 39f67dd Support splitting exhaustive tests across cores (Pieter Wuille) e99b26f Give exhaustive_tests count and seed cmdline inputs (Pieter Wuille) 49e6630 refactor: move RNG seeding to testrand (Pieter Wuille) b110c10 Change exhaustive test groups so they have a point with X=1 (Pieter Wuille) cec7b18 Select exhaustive lambda in function of order (Pieter Wuille) 78f6cdf Make the curve B constant a secp256k1_fe (Pieter Wuille) d7f39ae Delete gej_is_valid_var: unused outside tests (Pieter Wuille) 8bcd78c Make secp256k1_scalar_b32 detect overflow in scalar_low (Pieter Wuille) c498366 Move exhaustive tests for recovery to module (Pieter Wuille) be31791 Make group order purely compile-time in exhaustive tests (Pieter Wuille) Pull request description: A few miscellaneous improvements: * Just use EXHAUSTIVE_TEST_ORDER as order everywhere, rather than a variable * Move exhaustive tests for recovery module to the recovery module directory * Make `secp256k1_scalar_set_b32` detect overflow correctly for scalar_low (a comment in the recovery exhaustive test indicated why this was the case, but this looks incorrect). * Change the small test groups so that they include a point with X coordinate 1. * Initialize the RNG seed, allowing configurating from the cmdline, and report it. * Permit changing the number of iterations (re-randomizing for each). * Support splitting the work across cores from the cmdline. And a big one: * Add exhaustive tests for schnorrsig module (and limited ones for extrakeys). ACKs for top commit: real-or-random: ACK 8b7dcdd jonasnick: ACK 8b7dcdd Tree-SHA512: 18d7f362402085238faaced164c0ca34079717a477001fc0b13448b3529ea2ad705793a13b7a36f34bf12e9231fee11070f88cc51bfc2a83ca82aa13f7aaae71
- Loading branch information
Showing
18 changed files
with
874 additions
and
341 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# Define field size and field | ||
P = 2^256 - 2^32 - 977 | ||
F = GF(P) | ||
BETA = F(0x7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee) | ||
|
||
assert(BETA != F(1) and BETA^3 == F(1)) | ||
|
||
orders_done = set() | ||
results = {} | ||
first = True | ||
for b in range(1, P): | ||
# There are only 6 curves (up to isomorphism) of the form y^2=x^3+B. Stop once we have tried all. | ||
if len(orders_done) == 6: | ||
break | ||
|
||
E = EllipticCurve(F, [0, b]) | ||
print("Analyzing curve y^2 = x^3 + %i" % b) | ||
n = E.order() | ||
# Skip curves with an order we've already tried | ||
if n in orders_done: | ||
print("- Isomorphic to earlier curve") | ||
continue | ||
orders_done.add(n) | ||
# Skip curves isomorphic to the real secp256k1 | ||
if n.is_pseudoprime(): | ||
print(" - Isomorphic to secp256k1") | ||
continue | ||
|
||
print("- Finding subgroups") | ||
|
||
# Find what prime subgroups exist | ||
for f, _ in n.factor(): | ||
print("- Analyzing subgroup of order %i" % f) | ||
# Skip subgroups of order >1000 | ||
if f < 4 or f > 1000: | ||
print(" - Bad size") | ||
continue | ||
|
||
# Iterate over X coordinates until we find one that is on the curve, has order f, | ||
# and for which curve isomorphism exists that maps it to X coordinate 1. | ||
for x in range(1, P): | ||
# Skip X coordinates not on the curve, and construct the full point otherwise. | ||
if not E.is_x_coord(x): | ||
continue | ||
G = E.lift_x(F(x)) | ||
|
||
print(" - Analyzing (multiples of) point with X=%i" % x) | ||
|
||
# Skip points whose order is not a multiple of f. Project the point to have | ||
# order f otherwise. | ||
if (G.order() % f): | ||
print(" - Bad order") | ||
continue | ||
G = G * (G.order() // f) | ||
|
||
# Find lambda for endomorphism. Skip if none can be found. | ||
lam = None | ||
for l in Integers(f)(1).nth_root(3, all=True): | ||
if int(l)*G == E(BETA*G[0], G[1]): | ||
lam = int(l) | ||
break | ||
if lam is None: | ||
print(" - No endomorphism for this subgroup") | ||
break | ||
|
||
# Now look for an isomorphism of the curve that gives this point an X | ||
# coordinate equal to 1. | ||
# If (x,y) is on y^2 = x^3 + b, then (a^2*x, a^3*y) is on y^2 = x^3 + a^6*b. | ||
# So look for m=a^2=1/x. | ||
m = F(1)/G[0] | ||
if not m.is_square(): | ||
print(" - No curve isomorphism maps it to a point with X=1") | ||
continue | ||
a = m.sqrt() | ||
rb = a^6*b | ||
RE = EllipticCurve(F, [0, rb]) | ||
|
||
# Use as generator twice the image of G under the above isormorphism. | ||
# This means that generator*(1/2 mod f) will have X coordinate 1. | ||
RG = RE(1, a^3*G[1]) * 2 | ||
# And even Y coordinate. | ||
if int(RG[1]) % 2: | ||
RG = -RG | ||
assert(RG.order() == f) | ||
assert(lam*RG == RE(BETA*RG[0], RG[1])) | ||
|
||
# We have found curve RE:y^2=x^3+rb with generator RG of order f. Remember it | ||
results[f] = {"b": rb, "G": RG, "lambda": lam} | ||
print(" - Found solution") | ||
break | ||
|
||
print("") | ||
|
||
print("") | ||
print("") | ||
print("/* To be put in src/group_impl.h: */") | ||
first = True | ||
for f in sorted(results.keys()): | ||
b = results[f]["b"] | ||
G = results[f]["G"] | ||
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) | ||
first = False | ||
print("static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST(") | ||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) | ||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[0]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) | ||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) | ||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(G[1]) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) | ||
print(");") | ||
print("static const secp256k1_fe secp256k1_fe_const_b = SECP256K1_FE_CONST(") | ||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x," % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4))) | ||
print(" 0x%08x, 0x%08x, 0x%08x, 0x%08x" % tuple((int(b) >> (32 * (7 - i))) & 0xffffffff for i in range(4, 8))) | ||
print(");") | ||
print("# else") | ||
print("# error No known generator for the specified exhaustive test group order.") | ||
print("# endif") | ||
|
||
print("") | ||
print("") | ||
print("/* To be put in src/scalar_impl.h: */") | ||
first = True | ||
for f in sorted(results.keys()): | ||
lam = results[f]["lambda"] | ||
print("# %s EXHAUSTIVE_TEST_ORDER == %i" % ("if" if first else "elif", f)) | ||
first = False | ||
print("# define EXHAUSTIVE_TEST_LAMBDA %i" % lam) | ||
print("# else") | ||
print("# error No known lambda for the specified exhaustive test group order.") | ||
print("# endif") | ||
print("") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
include_HEADERS += include/secp256k1_extrakeys.h | ||
noinst_HEADERS += src/modules/extrakeys/tests_impl.h | ||
noinst_HEADERS += src/modules/extrakeys/tests_exhaustive_impl.h | ||
noinst_HEADERS += src/modules/extrakeys/main_impl.h |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/********************************************************************** | ||
* Copyright (c) 2020 Pieter Wuille * | ||
* Distributed under the MIT software license, see the accompanying * | ||
* file COPYING or http://www.opensource.org/licenses/mit-license.php.* | ||
**********************************************************************/ | ||
|
||
#ifndef _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_ | ||
#define _SECP256K1_MODULE_EXTRAKEYS_TESTS_EXHAUSTIVE_ | ||
|
||
#include "src/modules/extrakeys/main_impl.h" | ||
#include "include/secp256k1_extrakeys.h" | ||
|
||
static void test_exhaustive_extrakeys(const secp256k1_context *ctx, const secp256k1_ge* group) { | ||
secp256k1_keypair keypair[EXHAUSTIVE_TEST_ORDER - 1]; | ||
secp256k1_pubkey pubkey[EXHAUSTIVE_TEST_ORDER - 1]; | ||
secp256k1_xonly_pubkey xonly_pubkey[EXHAUSTIVE_TEST_ORDER - 1]; | ||
int parities[EXHAUSTIVE_TEST_ORDER - 1]; | ||
unsigned char xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - 1][32]; | ||
int i; | ||
|
||
for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { | ||
secp256k1_fe fe; | ||
secp256k1_scalar scalar_i; | ||
unsigned char buf[33]; | ||
int parity; | ||
|
||
secp256k1_scalar_set_int(&scalar_i, i); | ||
secp256k1_scalar_get_b32(buf, &scalar_i); | ||
|
||
/* Construct pubkey and keypair. */ | ||
CHECK(secp256k1_keypair_create(ctx, &keypair[i - 1], buf)); | ||
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey[i - 1], buf)); | ||
|
||
/* Construct serialized xonly_pubkey from keypair. */ | ||
CHECK(secp256k1_keypair_xonly_pub(ctx, &xonly_pubkey[i - 1], &parities[i - 1], &keypair[i - 1])); | ||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, xonly_pubkey_bytes[i - 1], &xonly_pubkey[i - 1])); | ||
|
||
/* Parse the xonly_pubkey back and verify it matches the previously serialized value. */ | ||
CHECK(secp256k1_xonly_pubkey_parse(ctx, &xonly_pubkey[i - 1], xonly_pubkey_bytes[i - 1])); | ||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); | ||
CHECK(memcmp(xonly_pubkey_bytes[i - 1], buf, 32) == 0); | ||
|
||
/* Construct the xonly_pubkey from the pubkey, and verify it matches the same. */ | ||
CHECK(secp256k1_xonly_pubkey_from_pubkey(ctx, &xonly_pubkey[i - 1], &parity, &pubkey[i - 1])); | ||
CHECK(parity == parities[i - 1]); | ||
CHECK(secp256k1_xonly_pubkey_serialize(ctx, buf, &xonly_pubkey[i - 1])); | ||
CHECK(memcmp(xonly_pubkey_bytes[i - 1], buf, 32) == 0); | ||
|
||
/* Compare the xonly_pubkey bytes against the precomputed group. */ | ||
secp256k1_fe_set_b32(&fe, xonly_pubkey_bytes[i - 1]); | ||
CHECK(secp256k1_fe_equal_var(&fe, &group[i].x)); | ||
|
||
/* Check the parity against the precomputed group. */ | ||
fe = group[i].y; | ||
secp256k1_fe_normalize_var(&fe); | ||
CHECK(secp256k1_fe_is_odd(&fe) == parities[i - 1]); | ||
|
||
/* Verify that the higher half is identical to the lower half mirrored. */ | ||
if (i > EXHAUSTIVE_TEST_ORDER / 2) { | ||
CHECK(memcmp(xonly_pubkey_bytes[i - 1], xonly_pubkey_bytes[EXHAUSTIVE_TEST_ORDER - i - 1], 32) == 0); | ||
CHECK(parities[i - 1] == 1 - parities[EXHAUSTIVE_TEST_ORDER - i - 1]); | ||
} | ||
} | ||
|
||
/* TODO: keypair/xonly_pubkey tweak tests */ | ||
} | ||
|
||
#endif |
Oops, something went wrong.