楕円曲線暗号の公開鍵は(x,y)形式の一つの座標
ECDSA公開鍵をシリアライズする方法はSECフォーマットと呼ばれている
非圧縮と圧縮がある
1.プレフィックス0x04
2.32バイトのビッグエンディアン整数をx座標に追加
2.32バイトのビッグエンディアン整数をy座標に追加
### 非圧縮
class S256Point(Point): // 省略 def sec(self): return b'\x04' + self.x.num.to_bytes(32, 'big')\ + self.y.num.to_bytes(32, 'big')
priv = PrivateKey(5002) print(priv.point.sec(compressed=False).hex()) priv = PrivateKey(2018**5) print(priv.point.sec(compressed=False).hex()) priv = PrivateKey(0xdeadbeef12345) print(priv.point.sec(compressed=False).hex())
$ python3 app.py
040f85cb0c917647fadfd31e641231d3a01ac9d3d8a680aab2457e0036bf34d37e6949b302843a33cdf068589c8330bb5c09c1739420d65b7b33cfab6d10118d97
04027f3da1918455e03c46f659266a1bb5204e959db7364d2f473bdf8f0a13cc9dff87647fd023c13b4a4994f17691895806e1b40b57f4fd22581a4f46851f3b06
04d90cd625ee87dd38656dd95cf79f65f60f7273b67d3096e68
### 圧縮
class S256Field(FieldElement):
def __init__(self, num, prime=None):
super().__init__(num=num, prime=P)
def __repr__(self):
return '{:x}'.format(self.num).zfill(64)
def sqrt(self):
return self**((P + 1) // 4)
@classmethod
def parse(self, sec_bin):
if sec_bin[0] == 4:
x = int.from_bytes(sec_bin[1:33], 'big')
y = int.from_bytes(sec_bin[33:65], 'big')
return S256Point(x=x, y=y)
is_even = sec_bin[0] == 2
x = S256Field(int.from_bytes(sec_bin[1:], 'big'))
alpha = x**3 + S256Field(B)
beta = alpha.sqrt()
if beta.num % 2 == 0:
even_beta = beta
odd_beta = S256Field(P - beta.num)
else:
even_beta = S256Field(P - beta.num)
odd_beta = beta
if is_even:
return S256Point(x, even_beta)
else:
return S256Point(x, odd_beta)
priv = PrivateKey(5001)
print(priv.point.sec(compressed=True).hex())
priv = PrivateKey(2019**5)
print(priv.point.sec(compressed=True).hex())
priv = PrivateKey(0xdeadbeef54321)
print(priv.point.sec(compressed=True).hex())
$ python3 app.py
0357a4f368868a8a6d572991e484e664810ff14c05c0fa023275251151fe0e53d1
02933ec2d2b111b92737ec12f1c5d20f3233a0ad21cd8b36d0bca7a0cfa5cb8701
0296be5b1292f6c856b3c5654e886fc13511462059089cdf9c479623bfcbe77690