### 署名の作成
e = int.from_bytes(hash256(b'my secret'), 'big') z = int.from_bytes(hash256(b'my message'), 'big') # 署名しようとしているメッセージ k = 1234567890 r = (k*G).x.num # x座標のみ取り出す k_inv = pow(k, N-2, N) s = (z+r*e) * k_inv % N # モジュロ演算 point = e*G # 公開点は知らせる必要がある print(point) print(hex(z)) print(hex(r)) print(hex(s))
$ python3 app.py
Point(1153752822844410451703720272380683670327470420405725541447346968941621636178,4935740600172189071191766981850281297554521083605982627869195587800421042658)_0_7 FieldElement(115792089237316195423570985008687907853269984665640564039457584007908834671663)
0x231c6f3d980a6b0fb7152f85cee7eb52bf92433d9919b9c5218cb08e79cce78
0x2b698a0f0a4041b77e63488ad48c23e8e8838dd1fb7520408b121697b782ef22
0xbb14e602ef9e3f872e25fad328466b34e6734b7a0fcd58b1eb635447ffae8cb9
e = 12345 z = int.from_bytes(hash256(b'programming bitcoin'), 'big') k = 1234567890 r = (k*G).x.num k_inv = pow(k, N-2, N) s = (z+r*e) * k_inv % N point = e*G print(point) print(hex(z)) print(hex(r)) print(hex(s))
$ python3 app.py
Point(108607064596551879580190606910245687803607295064141551927605737287325610911759,6661302038839728943522144359728938428925407345457796456954441906546235843221)_0_7 FieldElement(115792089237316195423570985008687907853269984665640564039457584007908834671663)
0x6aac771a641117f22150921737c72c77e73150945342f7a490b77332abaac5c
0x2b698a0f0a4041b77e63488ad48c23e8e8838dd1fb7520408b121697b782ef22
0xd6f075528e124345b4b81029288861d9c33ddc49f8327005dfb203b3e9c1ee9c
### メッセージ署名
from random import randint class PrivateKey: def __init__(self, secret): self.secret = secret self.point = secret * G def hex(self): return '{:x}'.format(self.secret).zfill(64) def sign(self, z): k = randint(0, N-1) r = (k*G).x.num k_inv = pow(k, N-2, N) s = (z + r*self.secret) * k_inv % N if s > N/2: s = N - s return Signature(r, s)
k は署名ごとに一意である必要がある。
RFC6979
def sign(self, z): k = self.deterministic_k(z) r = (k*G).x.num k_inv = pow(k, N-2, N) s = (z + r*self.secret) * k_inv % N if s > N/2: s = N - s return Signature(r, s) def deterministic_k(self, z): k = b'\x00' * 32 v = b'\x01' * 32 if z > N: z -= N z_bytes = z.to_bytes(32, 'big') secret_bytes = self.secret.to_bytes(32, 'big') s256 = hashlib.sha256 k = hmac.new(k, v + b'\x00' + secret_bytes + z_bytes, s256).digest() v = hmac.new(k, v, s256).digest() k = hmac.new(k, v + b'\x01' + secret_bytes + z_bytes, s256).digest() v = hmac.new(k, v, s256).digest() while True: v = hmac.new(k, v, s256).digest() candidate = int.from_bytes(v, 'big') if candidate >= 1 and candidate < N: return candidate k = hmac.new(k, v + b'\x00', s256).digest() v = hmac.new(k, v, s256).digest()
これが基本要素なのか
なんか凄いな