## 2019年4月14日日曜日

### Python - Serialization - Compressed SEC Format(Standards for Efficient Cryptography)

Programming Bitcoin: Learn How to Program Bitcoin from Scratch (Jimmy Song(著)、O'Reilly Media)のChapter 4(Serialization)、Compressed SEC Format、Exercises 2(79)の解答を求めてみる。

コード

Python 3

ecc_test.py

```#!/usr/bin/env python3
from unittest import TestCase, main
from ecc import FieldElement, Point, S256Point, PrivateKey

class S256PointTest(TestCase):
def setUp(self):
pass

def tearDown(self):
pass

def test_parse(self):
secrets = [5001, 2019**5, 0xdeadbeef54321]
for secret in secrets:
private_key = PrivateKey(secret)
point = private_key.point
self.assertEqual(point,
S256Point.parse(point.sec(compressed=True)))

if __name__ == '__main__':
main()
```

ecc.py

```#!/usr/bin/env python3
class S256Point(Point):
def __init__(self, x, y, a=None, b=None):
a = S256Field(A)
b = S256Field(B)
if type(x) == int:
x = S256Field(x)
y = S256Field(y)
super().__init__(x=x, y=y, a=a, b=b)

def __rmul__(self, coefficient):
return super().__rmul__(coefficient % N)

def __repr__(self):
if self.x is None:
return 'S256Point(infinity)'
return f'S256Point({self.x}, {self.y})'

def verify(self, z, sig):
s_inv = pow(sig.s, N - 2, N)
u = z * s_inv % N
v = sig.r * s_inv % N
total = u * G + v * self

def sec(self, compressed=True):
if compressed:
if self.y.num % 2 == 0:
prefix = b'\x02'
else:
prefix = b'\x03'
return prefix + self.x.num.to_bytes(32, 'big')
return b'\x04' + \
self.x.num.to_bytes(32, 'big') + \
self.y.num.to_bytes(32, 'big')

@staticmethod
def parse(sec_bin):
if sec_bin[0] == 4:
x = int.from_bytes(sec_bin[1:3], 'big')
y = int.from_bytes(sec_bin[33:36], 'big')
return S256Point(x, y)
x = S256Field(int.from_bytes(sec_bin[1:], 'big'))
left = x ** 3 + S256Field(A) * x + S256Field(B)
y = left.sqrt()
is_even = sec_bin[0] == 2
if (is_even and y.num % 2 != 0) or \
(not is_even and y.num % 2 == 0):
y = S256Field(P - y.num)
return S256Point(x, y)
```

sample2.py

```#!/usr/bin/env python3
from ecc import PrivateKey

secrets = [2001, 2019 ** 5, 0xdeadbeef52321]
for secret in secrets:
private_key = PrivateKey(secret)
sec = private_key.point.sec()
print(sec.hex())
```

```C:\Users\...>py ecc_test.py
....................
----------------------------------------------------------------------
Ran 20 tests in 0.041s

OK

C:\Users\...>py sample2.py
038d3f06b158ddd609f83b0531466fc2a3da6aa80b433a92ddeeb20435cf33ddae