Skip to content

Commit

Permalink
Test Elligator Squared encoding and decoding
Browse files Browse the repository at this point in the history
- source: src/modules/ellsq/tests_impl.h from secp256k1(PR 982)
- 2 tests are added:
    1. Generate a pubkey from a random curve point and encode it using ellsq_encode(). Then decode it back to a pubkey and check if it is the same pubkey we started with.
    2. Decode the test vector bytes to a compressed pubkey using ellsq_decode() and check if it matches test vector pubkey.
  • Loading branch information
stratospher committed Apr 2, 2022
1 parent 4c99817 commit 3fbe690
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 0 deletions.
32 changes: 32 additions & 0 deletions test/functional/test_framework/ellsq.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
Do not use for anything but tests."""

import hashlib
import os
import random
import unittest

Expand Down Expand Up @@ -218,6 +219,21 @@ def ellsq_decode(enc):
pubkey.set(compressed_sec)
return pubkey

ELLSQ_ENC_TESTS = [
[b"\x54\xca\xd2\x27\xb2\xc9\x8d\x5f\x7c\x78\x8c\xfc\x3d\xaf\xd6\x52\xf5\x8f\x69\xcf\xef\x63\x2b\x82\x2b\x35\xd0\xb0\xe2\x4f\xc0\x3a\xd2\x8c\xa1\x4b\x6f\x62\xd4\x53\x79\xc5\x3f\x70\xee\x40\x5c\xa9\x2c\xe7\xb6\xf9\x70\x83\x13\x05\xf2\x7d\xc4\x1e\xb6\x9d\xe0\x6e", b"\x02\x11\x62\x89\x03\x32\x88\x91\xae\x09\xd1\x08\xd8\x92\x43\xe4\x7e\x10\x9f\xe7\xb8\xbb\x1e\x2d\xf1\xa3\xae\x9b\x0e\x78\x08\x54\x9c"],
[b"\xfb\xe6\xce\xab\x4c\x5f\xdf\xa5\xfb\xee\x8f\x3d\x09\xa2\xf7\x23\x53\xe7\x4e\x5a\x9c\xd4\xab\x8e\x6a\x34\xd4\x95\x23\xa7\xd1\xa2\xc4\x50\xb7\x45\xda\xb1\xaf\xa9\x95\x4b\x3a\x35\x75\xe4\xe8\xe2\xdb\x3d\xa5\xcd\x4d\x56\x48\xea\xd0\x0a\x60\xb4\xcd\xfe\x84\xb3", b"\x02\xc0\x4c\x84\x85\xf9\x8d\x56\x6c\x79\xbf\x33\xa7\x0c\xb2\x32\x54\x9e\x3d\xe1\xc3\xe3\x01\xe3\x57\x1c\x83\x68\x97\xf0\x7c\x5d\x12"],
[b"\x71\x7e\x63\xd7\x71\xdb\xda\x67\x67\xd5\x8f\x26\xab\x5f\x54\x9b\xd2\xd1\x8a\xcf\x59\xff\x50\x77\x5f\x4e\xb5\x0a\xc0\x17\x4d\xf1\x7d\xd0\x34\xc8\xed\x08\x11\x61\x5e\x3e\xbb\x36\xf8\xf3\x3e\x09\x23\x8e\x4d\xa8\xf5\x01\x9d\x37\x00\x78\x4f\x37\xc1\x53\x53\x94", b"\x02\x72\x81\x15\x0c\xeb\xc3\xd7\xb3\xbb\xb9\x92\xf5\x81\xbb\xcb\x9e\x30\x4f\x87\x44\xf0\x19\x98\xa7\x1f\x5d\xe1\x14\xf8\x22\x91\xc4"],
[b"\x01\xf0\xbf\xe4\xf9\xbd\xee\x52\x5e\xb7\x7c\x8e\x35\x1e\x1f\x88\x3f\xb9\xcd\x37\x7e\xf7\xc5\xbd\xde\xe4\xf6\x60\x64\x43\x90\xf5\x95\x3e\x7d\x2b\x6c\xde\x36\x90\x3e\xa1\x34\x4b\x0d\x16\x33\x5c\xc5\x11\x5d\xaa\x97\x7c\x3c\x2b\xf9\x31\xac\xde\x2f\xf5\x78\x9a", b"\x02\x10\x44\x9d\x7e\xa0\x62\x3e\x80\xa5\x87\x01\x9f\xa5\x11\xaf\xd3\x94\xb2\x55\xb0\x8f\x91\xb5\xf7\x48\x2a\xe9\xd1\xa1\xa7\xfb\x7c"],
[b"\x82\xd5\x87\x1e\x18\x37\x66\xbd\x22\xe1\x13\xa8\x52\x79\xaa\x61\x7e\x6b\x9f\x73\x52\x2c\xd4\x6b\x90\x59\xba\x51\x97\xfa\x56\x44\xaf\x90\x41\x89\x30\x98\x7d\xb7\xab\x4a\x84\x0c\x72\x64\x1b\x58\xb3\x66\xe5\x7c\x92\x8c\x98\x3a\x47\x37\x82\x00\x3c\x36\x10\xab", b"\x03\xc8\xb2\x62\xf9\x31\x69\x43\x75\x51\x48\x3b\x8a\x61\x19\x83\x82\xe3\x11\x41\xaf\x61\xbf\x36\x10\x0b\xd0\x68\x46\x5d\xdd\xa8\x40"],
[b"\xda\x82\x53\xb4\x3b\x5a\xc2\x3b\x42\x36\x07\xe9\x18\xab\x5c\xaa\x5d\x7d\x34\x3d\x77\xa3\x99\x6a\x42\xeb\x33\x2a\x3b\x55\x1d\x8c\xda\x6c\xb6\xf9\x57\x4c\xe3\x60\x91\x2c\xf4\x5b\x90\x9a\x96\x2e\x4d\xed\x63\xae\x5a\xac\xb0\xab\x23\x29\x45\xb1\x01\xf7\x2b\x62", b"\x02\xe7\x28\x34\x1d\xf6\x93\x48\x71\xb3\x94\xbb\x4f\xb2\x8b\xd8\xd2\xdf\x39\x92\x55\xb0\x30\x02\xed\x6f\xc3\x8f\x28\xcf\xbf\x53\x56"],
[b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", b"\x03\x1b\x41\x2e\x7a\x96\x6d\x2c\x24\x3d\xbc\x5b\x18\xb7\xf9\xba\xf1\x85\xbc\xfe\x41\x38\x96\x04\x79\x64\x1a\xb1\xe6\x3b\x38\x1e\x11"],
[b"\xdc\x30\x98\xe4\x00\x61\x83\x30\xf3\x8b\x19\xe9\x20\x0a\xdf\x7f\xfb\x96\x84\x3f\xa8\x3c\x49\x1c\xf6\x7f\x34\xa7\x90\xbb\xcf\xe1\x23\xdc\x30\x07\xa4\xfd\x13\x3a\x39\x44\x0b\x06\x03\x1e\x9e\x2c\x38\x8e\x41\x47\xaf\x0e\x82\xbe\xda\x6d\x56\x4b\xf8\xcc\x37\xb1", b"\x02\x5b\x74\x48\x15\x22\xd4\xc2\x9f\x2e\x6a\x2f\x11\x7f\x9e\x39\xf9\xab\x01\xb1\xe9\xf2\xc3\x4c\x68\xbe\x8f\x53\x1b\xe0\x1f\x6e\xa7"],
[b"\x35\xd7\x0a\x71\x2c\xc0\x85\x7f\x8d\xb1\xbc\x55\x6a\x6c\x4e\xf8\x66\x24\xfd\x0a\x47\x7f\x96\x7e\xed\xc0\x32\xfc\xda\xac\xe7\x96\xc6\x73\xc5\x43\xd0\x07\x34\x32\x07\x85\x5b\xeb\xad\x85\xe9\x4b\xca\xc7\x78\x2b\x11\x57\x9a\x70\xdc\x88\xe2\xa4\x8d\x9d\xf2\xd4", b"\x02\xdb\x21\xb4\x8f\xe9\xf9\x95\x08\x3a\x1f\x9c\x1f\x3f\x4b\x31\x1d\x2c\x43\xa1\x28\xdb\xb3\xa4\xd4\x78\x41\xe4\xff\x5d\xd0\x2e\x61"],
[b"\x5f\xb8\x07\xce\x10\x0c\x90\xd2\x83\x7c\xcf\xc9\x4d\x8f\x8b\xa5\xd3\x5c\xd3\xd6\xfa\xfc\xd2\xf4\x1f\x24\x5b\x59\x6e\x36\x00\x57\xa0\x47\xf8\x31\xef\xf3\x6f\x2d\x7c\x83\x30\x36\xb2\x70\x74\x5a\x2c\xa3\x2c\x29\x05\x03\x2d\x0b\xe0\xdb\xa4\xa5\x91\xc9\xfb\xd8", b"\x03\x41\x58\x28\x65\x43\x5e\xe9\xc8\xc9\x27\xc3\x49\xbd\x3e\x43\x7b\xce\x2b\x5c\xfc\xd0\xc4\x17\x77\xc3\x4c\x71\xc6\x7b\x14\x06\x93"],
[b"\x1e\x76\x57\x72\xbf\x72\xde\xb8\x81\x54\x16\xbd\x54\x45\xdd\x75\x50\xcd\x86\x7a\xa2\x5a\xc6\x3f\x6f\xd9\xaf\xd3\x2f\x92\x1c\xc8\x8a\x06\x1a\xb5\xf6\x98\x1b\x55\x92\x1b\x90\x5b\x6f\x4f\x3d\xf4\x82\x5d\x79\x72\xd6\x99\xe3\xb4\x21\x4e\x40\x44\xcf\xbe\x65\x34", b"\x03\x90\xd2\x94\x30\x92\xec\x7e\xd8\xff\x5a\xf7\x04\x43\x2d\x0d\xbe\xb0\x33\x7c\xbf\x58\x22\x87\x18\x32\x76\x38\x68\x1f\x70\xd7\xf0"],
[b"\x86\xef\x92\xfd\x28\x09\x85\x4f\x74\xf7\x5a\xeb\xbe\xa1\x8a\xee\xc0\xee\xdd\x4e\x81\x92\xc8\x8c\xd7\xcf\xf5\xdf\xc0\x8a\x57\xdc\x32\x73\xbf\x6f\x39\x2d\xee\x48\x4a\x72\x2c\x3d\xb0\x0c\x0e\xfb\x40\xd5\x1e\x8a\x72\xfc\xfb\x78\x3f\xa7\xeb\xd4\x30\x82\xdb\x71", b"\x02\x31\x74\x79\x29\x80\x2d\x79\x76\x02\x26\x71\xb2\xf7\x5a\xc0\x31\x18\x56\xb3\x84\xf4\xb9\xa8\x00\x0d\x44\xa2\xab\xc5\x90\x3a\xd4"]
]

class TestFrameworkEllsq(unittest.TestCase):
def test_fe_to_ge_to_fe(self):
for i in range(100):
Expand Down Expand Up @@ -256,3 +272,19 @@ def test_ellsq_mapping(self):
if fe2 is not None:
group_ele = forward_map(fe2)
assert ge == group_ele

def test_encode_decode(self):
for i in range(100):
m = random.randrange(1, SECP256K1_ORDER)
curve_point = SECP256K1.affine(SECP256K1.mul([(SECP256K1_G, m)]))
pubkey1 = ECPubKey()
pubkey1.set_from_curve_point(curve_point)
ell64 = ellsq_encode(pubkey1, os.urandom(32))
pubkey2 = ellsq_decode(ell64)
assert pubkey1.get_bytes() == pubkey2.get_bytes()

def test_decode_test_vectors(self):
for test_vector in ELLSQ_ENC_TESTS:
ell64, pubkey = test_vector
dec_pubkey = ellsq_decode(ell64)
assert dec_pubkey.get_bytes() == pubkey
8 changes: 8 additions & 0 deletions test/functional/test_framework/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@ def set(self, data):
else:
self.valid = False

def set_from_curve_point(self, curve_point):
x, y = fe(curve_point[0]), fe(curve_point[1])
if y.val % 2 == 0:
compressed_sec = b'\x02' + x.val.to_bytes(32, 'big')
else:
compressed_sec = b'\x03' + x.val.to_bytes(32, 'big')
self.set(compressed_sec)

@property
def is_compressed(self):
return self.compressed
Expand Down

0 comments on commit 3fbe690

Please sign in to comment.