10
10
import random
11
11
import unittest
12
12
13
- from .key import FE , GE
13
+ from .key import FE , GE , SECP256K1_G
14
14
15
15
MINUS_3_SQRT = FE (- 3 ).sqrt ()
16
16
@@ -56,6 +56,28 @@ def xswiftec_inv(x, u, case):
56
56
w = - w
57
57
return w * (u * (MINUS_3_SQRT - 1 ) / 2 - v )
58
58
59
+ def xelligatorswift (x ):
60
+ """Given a field element X on the curve, find (u, t) that encode them."""
61
+ while True :
62
+ u = FE (random .randrange (1 , GE .ORDER ))
63
+ case = random .randrange (0 , 8 )
64
+ t = xswiftec_inv (x , u , case )
65
+ if t is not None :
66
+ return u , t
67
+
68
+ def ellswift_create ():
69
+ """Generate a (privkey, ellswift_pubkey) pair."""
70
+ priv = random .randrange (1 , GE .ORDER )
71
+ u , t = xelligatorswift ((priv * SECP256K1_G ).x )
72
+ return priv .to_bytes (32 , 'big' ), u .to_bytes () + t .to_bytes ()
73
+
74
+ def ellswift_ecdh_xonly (pubkey_theirs , privkey ):
75
+ """Compute X coordinate of shared ECDH point between ellswift pubkey and privkey."""
76
+ u = FE (int .from_bytes (pubkey_theirs [:32 ], 'big' ))
77
+ t = FE (int .from_bytes (pubkey_theirs [32 :], 'big' ))
78
+ d = int .from_bytes (privkey , 'big' )
79
+ return (d * GE .lift_x (xswiftec (u , t ))).x .to_bytes ()
80
+
59
81
class TestFrameworkEllSwift (unittest .TestCase ):
60
82
def test_elligator_forward (self ):
61
83
"""Verify that xswiftec maps all inputs to the curve."""
@@ -77,3 +99,11 @@ def test_elligator_roundtrip(self):
77
99
u , t = xelligatorswift (x )
78
100
x2 = xswiftec (u , t )
79
101
self .assertEqual (x2 , x )
102
+
103
+ def test_ellswift_ecdh_xonly (self ):
104
+ for _ in range (32 ):
105
+ privkey1 , encoding1 = ellswift_create ()
106
+ privkey2 , encoding2 = ellswift_create ()
107
+ shared_secret1 = ellswift_ecdh_xonly (encoding1 , privkey2 )
108
+ shared_secret2 = ellswift_ecdh_xonly (encoding2 , privkey1 )
109
+ assert shared_secret1 == shared_secret2
0 commit comments