Skip to content

Commit b3c5aab

Browse files
committed
Test the Elligator Squared mapping functions
- source: src/modules/ellsq/tests_impl.h from bitcoin-core/secp256k1#982 - 3 tests are added: 1. Generate random field elements and use f to map it to a valid group element on the curve. Then use r to map back the group element to the 4 possible pre-images, out of which only 1 is the field element we started with. 2. Generate random group elements on the curve and use r to map it to the 4 possible pre-images. Then map the field elements back to the group element and check if it's the same group element we started with, also making sure that the pre-images are distinct. 3. Verify the test cases which consists of group element and the 4 field elements.Map the group element to the 4 possible pre-images using r and check whether it's consistent with the 4 field elements given in the test case. Map the field element back to the group element using f and check whether it matches the test case.
1 parent 94767af commit b3c5aab

File tree

1 file changed

+46
-1
lines changed

1 file changed

+46
-1
lines changed

test/functional/test_framework/ellsq.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
keys, and is trivially vulnerable to side channel attacks. Do not use for
66
anything but tests."""
77

8+
import random
9+
import unittest
10+
11+
from .key import modsqrt, SECP256K1, SECP256K1_G, SECP256K1_ORDER
12+
813
class fe:
914
"""Prime field over 2^256 - 2^32 - 977"""
1015
p = 2**256 - 2**32 - 977
@@ -159,4 +164,44 @@ def SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p):
159164
[SECP256K1_GE_CONST(0x49a0dc06, 0x8c3f117a, 0xefdc842d, 0x3d358153, 0xf677f04c, 0x6dabc9c9, 0x1b09d452, 0xfef27b66, 0x7b944da4, 0x8a175dbc, 0x444ead8d, 0xb82eff66, 0xb081a8aa, 0xe6453fed, 0x2bca9720, 0xb44dd6e5), [SECP256K1_FE_CONST(0x7bf1e2b1, 0x720c1c44, 0x0db64687, 0xf16439fa, 0x41b39833, 0x8095f24e, 0xbeec0cfa, 0x88750dc9), SECP256K1_FE_CONST(0xdc97e26d, 0x3137445d, 0x6c1269b6, 0x1a765501, 0x0c19c36a, 0x2e361066, 0xe31e2bb1, 0x0403470b), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)]],
160165
[SECP256K1_GE_CONST(0xd09a4047, 0xf158fe52, 0xf96c661d, 0x02c68657, 0xc4c976ea, 0x96ea85ef, 0x46d6985b, 0xd540756b, 0xe793bfaa, 0xe9300f18, 0xe6f9b55a, 0xae263223, 0x68b61d51, 0xae5022ef, 0xe266c72d, 0x574178bc), [SECP256K1_FE_CONST(0x7e6175fd, 0xfbb9fb4f, 0xaf6e2b92, 0x5ef86c4a, 0x444d819a, 0xaa82dbee, 0x545d3d9b, 0x296375be), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)]],
161166
[SECP256K1_GE_CONST(0x34986625, 0x04b73c7c, 0x8cecb6c3, 0x3cd493bd, 0xfc190e0f, 0x87d913d7, 0xff9ad42e, 0x222bfe95, 0x245b3a61, 0xb8d46997, 0xf14f2fea, 0x28748996, 0x91eb3254, 0x2b9907d6, 0x5eb9d21d, 0x42454021), [SECP256K1_FE_CONST(0x7f556282, 0xc3dd9d26, 0x3390d6bb, 0xddada698, 0xab8fd7c7, 0xd1a06498, 0xf42b3043, 0x7c8361ad), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), SECP256K1_FE_CONST(0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000)]]
162-
]
167+
]
168+
169+
class TestFrameworkEllsq(unittest.TestCase):
170+
def test_fe_to_ge_fe(self):
171+
for i in range(100):
172+
matches = 0
173+
t = fe(random.randrange(1, SECP256K1_ORDER))
174+
ge = f(t)
175+
jac_ge = (ge[0].val, ge[1].val, 1)
176+
assert(SECP256K1.on_curve(jac_ge))
177+
# t should appear exactly once in preimages
178+
for j in range(1,5):
179+
field_ele = r(ge[0], ge[1], j)
180+
if field_ele is not None:
181+
matches += (field_ele == t)
182+
assert(matches == 1)
183+
184+
def test_ge_to_fe_to_ge(self):
185+
for i in range(100):
186+
m = random.randrange(1, SECP256K1_ORDER)
187+
A = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, m)]))
188+
ge = (fe(A[0]), fe(A[1]))
189+
preimages = []
190+
for j in range(1, 5):
191+
field_ele = r(ge[0], ge[1], j)
192+
if field_ele is not None:
193+
preimages.append(field_ele)
194+
group_ele = f(field_ele)
195+
assert (ge[0] == group_ele[0] and ge[1] == group_ele[1])
196+
assert len(set(preimages)) == len(preimages)
197+
198+
def test_ellsq_mapping(self):
199+
for test_vector in ellsq_tests:
200+
ge = test_vector[0]
201+
fe = test_vector[1]
202+
for j in range(1, 5):
203+
field_ele = r(ge[0], ge[1], j)
204+
if field_ele is not None:
205+
assert(field_ele == fe[j-1])
206+
group_ele = f(field_ele)
207+
assert (ge[0] == group_ele[0] and ge[1] == group_ele[1])

0 commit comments

Comments
 (0)