Skip to content

Commit 4f466d4

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 4a63d30 commit 4f466d4

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,9 +5,10 @@
55
Do not use for anything but tests."""
66

77
import random
8+
import secrets
89
import unittest
910

10-
from .key import fe, SECP256K1, SECP256K1_G, SECP256K1_ORDER
11+
from .key import fe, SECP256K1, SECP256K1_FIELD_SIZE, SECP256K1_G, SECP256K1_ORDER
1112

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

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

0 commit comments

Comments
 (0)