서명, 검증 알고리즘을 알았으니 필요한 클래스들을 작성해보자.
class Signature:
def __init__(self, r, s):
self.r = r
self.s = s
def __repr__(self):
return 'Signature({:x},{:x})'.format(self.r, self.s)
S256Point
에 검증 메서드를 추가한다.class S256Point(Point): # 타원 곡선 위 점 상속
...
def verify(self, z, sig):
s_inv = pow(sig.s, N - 2, N) # <1>
u = z * s_inv % N # <2>
v = sig.r * s_inv % N # <3>
total = u * G + v * self # <4>
return total.x.num == sig.r # <5>
PrivateKey
클래스를 만들자.S256Point
)에 있는 메서드인 verify
로 그 서명을 넘겨주면 끝이다.class PrivateKey:
def __init__(self, secret):
self.secret = secret
self.point = secret * G # 공개키를 계산 후 보관한다.
def hex(self):
return '{:x}'.format(self.secret).zfill(64)
# end::source13[]
# tag::source14[]
def sign(self, z):
k = self.deterministic_k(z) # 그냥 무작위로 결정하면 안된다. k가 들키면 e도 털린다. 서명마다 k도 달라야한다. 아니면 털린다.
r = (k * G).x.num
k_inv = pow(k, N - 2, N)
s = (z + r * self.secret) * k_inv % N
if s > N / 2: # 가변성 문제로 N/x보다 작은 s값을 사용한다.
s = N - s
return Signature(r, s)
def deterministic_k(self, z): # 서명 마다 다른 k값을 명시적으로 사용하기 위한 코드
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 # <2>
k = hmac.new(k, v + b'\x00', s256).digest()
v = hmac.new(k, v, s256).digest()
# end::source14[]