### 署名の作成
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()
これが基本要素なのか
なんか凄いな