Skip to content

Commit 91ddb51

Browse files
stratosphersipa
andcommitted
Add ellswift mapping functions
Co-authored-by: Pieter Wuille <pieter.wuille@gmail.com>
1 parent 5b4477d commit 91ddb51

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2022 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Test-only Elligator Swift implementation
6+
7+
WARNING: This code is slow and uses bad randomness.
8+
Do not use for anything but tests."""
9+
10+
import random
11+
import unittest
12+
13+
from .key import FE, GE
14+
15+
MINUS_3_SQRT = FE(-3).sqrt()
16+
17+
def xswiftec(u, t):
18+
"""Decode field elements (u, t) to an X coordinate on the curve."""
19+
if u == 0:
20+
u = FE(1)
21+
if t == 0:
22+
t = FE(1)
23+
if u**3 + t**2 + 7 == 0:
24+
t = 2 * t
25+
X = (u**3 - t**2 + 7) / (2 * t)
26+
Y = (X + t) / (MINUS_3_SQRT * u)
27+
for x in (u + 4 * Y**2, (-X / Y - u) / 2, (X / Y - u) / 2):
28+
if GE.is_valid_x(x):
29+
return x
30+
assert False
31+
32+
def xswiftec_inv(x, u, case):
33+
"""Given x and u, find t such that xswiftec(u, t) = x, or return None.
34+
Case selects which of the up to 8 results to return."""
35+
if case & 2 == 0:
36+
if GE.is_valid_x(-x - u):
37+
return None
38+
v = x if case & 1 == 0 else -x - u
39+
s = -(u**3 + 7) / (u**2 + u*v + v**2)
40+
else:
41+
s = x - u
42+
if s == 0:
43+
return None
44+
r = (-s * (4 * (u**3 + 7) + 3 * s * u**2)).sqrt()
45+
if r is None:
46+
return None
47+
if case & 1:
48+
if r == 0:
49+
return None
50+
r = -r
51+
v = (-u + r / s) / 2
52+
w = s.sqrt()
53+
if w is None:
54+
return None
55+
if case & 4:
56+
w = -w
57+
return w * (u * (MINUS_3_SQRT - 1) / 2 - v)
58+
59+
class TestFrameworkEllSwift(unittest.TestCase):
60+
def test_elligator_forward(self):
61+
"""Verify that xswiftec maps all inputs to the curve."""
62+
for _ in range(32):
63+
u = FE(random.randrange(0, FE.SIZE))
64+
t = FE(random.randrange(0, FE.SIZE))
65+
x = xswiftec(u, t)
66+
self.assertTrue(GE.is_valid_x(x))
67+
68+
def test_elligator_roundtrip(self):
69+
"""Verify that encoding using xelligatorswift decodes back using xswiftec."""
70+
for _ in range(32):
71+
while True:
72+
# Loop until we find a valid X coordinate on the curve.
73+
x = FE(random.randrange(1, FE.SIZE))
74+
if GE.is_valid_x(x):
75+
break
76+
# Encoding it to (u, t), decode it back, and compare.
77+
u, t = xelligatorswift(x)
78+
x2 = xswiftec(u, t)
79+
self.assertEqual(x2, x)

test/functional/test_runner.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@
7272
TEST_FRAMEWORK_MODULES = [
7373
"address",
7474
"blocktools",
75-
"muhash",
75+
"ellswift",
7676
"key",
77+
"muhash",
7778
"script",
7879
"segwit_addr",
7980
"util",

0 commit comments

Comments
 (0)