楕円曲線暗号の公開鍵は(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