Skip to content

Commit 1b414d1

Browse files
committed
Add functions for encoding and decoding to bytes
Source: https://github.com/sipa/writeups/tree/main/elligator-square-for-bn
1 parent 1c2ef4c commit 1b414d1

File tree

1 file changed

+47
-1
lines changed

1 file changed

+47
-1
lines changed

test/functional/test_framework/ellsq.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
anything but tests."""
77

88
import random
9+
import secrets
910
import unittest
1011

11-
from .key import fe, SECP256K1, SECP256K1_G, SECP256K1_ORDER
12+
from .key import fe, SECP256K1, SECP256K1_FIELD_SIZE, SECP256K1_G, SECP256K1_ORDER
1213

1314
C1 = fe(-3).sqrt()
1415
C2 = (C1 - fe(1)) / fe(2)
@@ -124,6 +125,51 @@ def r(x,y,i):
124125
[(fe(0x3498662504b73c7c8cecb6c33cd493bdfc190e0f87d913d7ff9ad42e222bfe95), fe(0x245b3a61b8d46997f14f2fea2874899691eb32542b9907d65eb9d21d42454021)), [fe(0x7f556282c3dd9d263390d6bbddada698ab8fd7c7d1a06498f42b30437c8361ad), None , None , None ]]
125126
]
126127

128+
def encode(P):
129+
while True:
130+
u = fe(random.randrange(1, SECP256K1_ORDER))
131+
fe1 = f(u)
132+
# convert fe1 to jacobian form for EC operations
133+
fe1 = (fe1[0].val, fe1[1].val, 1)
134+
T = SECP256K1.negate(fe1)
135+
Q = SECP256K1.add(T, P)
136+
if SECP256K1.is_infinity(Q):
137+
Q = T
138+
j = secrets.choice([0,1,2,3])
139+
Q = SECP256K1.affine(Q)
140+
v = r(fe(Q[0]), fe(Q[1]), j)
141+
if v is not None:
142+
return (u, v)
143+
144+
def decode(u, v):
145+
fe1 = f(u)
146+
fe2 = f(v)
147+
# convert fe1 and fe2 to jacobian form for EC operations
148+
jac1 = (fe1[0].val, fe1[1].val, 1)
149+
jac2 = (fe2[0].val, fe2[1].val, 1)
150+
T = jac1
151+
S = jac2
152+
P = SECP256K1.add(T, S)
153+
if SECP256K1.is_infinity(P):
154+
P = T
155+
P = SECP256K1.affine(P)
156+
return (fe(P[0]), fe(P[1]))
157+
158+
P = SECP256K1_FIELD_SIZE
159+
FIELD_BITS = P.bit_length()
160+
FIELD_BYTES = (FIELD_BITS + 7) // 8
161+
162+
def encode_bytes(P):
163+
u, v = encode(P)
164+
up = u.val
165+
vp = v.val
166+
return up.to_bytes(FIELD_BYTES, 'big') + vp.to_bytes(FIELD_BYTES, 'big')
167+
168+
def decode_bytes(enc):
169+
u = (int.from_bytes(enc[:FIELD_BYTES], 'big') & ((1 << FIELD_BITS) - 1)) % P
170+
v = (int.from_bytes(enc[FIELD_BYTES:], 'big') & ((1 << FIELD_BITS) - 1)) % P
171+
return decode(fe(u), fe(v))
172+
127173
class TestFrameworkEllsq(unittest.TestCase):
128174
def test_fe_to_ge_to_fe(self):
129175
for i in range(100):

0 commit comments

Comments
 (0)