Skip to content

Commit

Permalink
Test the Elligator Squared mapping functions
Browse files Browse the repository at this point in the history
- 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.
  • Loading branch information
stratospher committed Jan 7, 2022
1 parent 94767af commit 8eb51d7
Showing 1 changed file with 46 additions and 1 deletion.
47 changes: 46 additions & 1 deletion test/functional/test_framework/ellsq.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
keys, and is trivially vulnerable to side channel attacks. Do not use for
anything but tests."""

import random
import unittest

from .key import modsqrt, SECP256K1, SECP256K1_G, SECP256K1_ORDER

class fe:
"""Prime field over 2^256 - 2^32 - 977"""
p = 2**256 - 2**32 - 977
Expand Down Expand Up @@ -159,4 +164,44 @@ def SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p):
[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)]],
[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)]],
[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)]]
]
]

class TestFrameworkEllsq(unittest.TestCase):
def test_fe_to_ge_to_fe(self):
for i in range(100):
matches = 0
t = fe(random.randrange(1, SECP256K1_ORDER))
ge = f(t)
jac_ge = (ge[0].val, ge[1].val, 1)
assert(SECP256K1.on_curve(jac_ge))
# t should appear exactly once in preimages
for j in range(1,5):
field_ele = r(ge[0], ge[1], j)
if field_ele is not None:
matches += (field_ele == t)
assert(matches == 1)

def test_ge_to_fe_to_ge(self):
for i in range(100):
m = random.randrange(1, SECP256K1_ORDER)
A = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, m)]))
ge = (fe(A[0]), fe(A[1]))
preimages = []
for j in range(1, 5):
field_ele = r(ge[0], ge[1], j)
if field_ele is not None:
preimages.append(field_ele)
group_ele = f(field_ele)
assert (ge[0] == group_ele[0] and ge[1] == group_ele[1])
assert len(set(preimages)) == len(preimages)

def test_ellsq_mapping(self):
for test_vector in ellsq_tests:
ge = test_vector[0]
fe = test_vector[1]
for j in range(1, 5):
field_ele = r(ge[0], ge[1], j)
if field_ele is not None:
assert(field_ele == fe[j-1])
group_ele = f(field_ele)
assert (ge[0] == group_ele[0] and ge[1] == group_ele[1])

0 comments on commit 8eb51d7

Please sign in to comment.