def verify(msghash, sig, pub): assert isinstance(msghash, bytes) assert isinstance(sig, tuple) assert isinstance(pub, tuple) _, r, s = sig w = ec.inv(s, ec.N) z = convert.bytes_to_int(msghash) u1, u2 = z * w % ec.N, r * w % ec.N x, _ = ec.add(ec.multiply(ec.G, u1), ec.multiply(pub, u2)) return r == x
def sign(msghash, priv): assert isinstance(msghash, bytes) assert isinstance(priv, int) z = convert.bytes_to_int(msghash) k = deterministic_generate_k(msghash, priv) r, y = ec.multiply(ec.G, k) s = ec.inv(k, ec.N) * (z + r * priv) % ec.N # Ensure Low S constraint against tx malleability # https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Low_S_values_in_signatures if s > ec.N // 2: s = ec.N - s y += 1 # Switch parity of y, otherwise recover breaks. return 27 + (y % 2), r, s
def recover(msghash, sig): assert isinstance(msghash, bytes) assert isinstance(sig, tuple) v, r, s = sig x = r xcubedaxb = (x * x * x + ec.A * x + ec.B) % ec.P beta = pow(xcubedaxb, (ec.P + 1) // 4, ec.P) y = beta if v % 2 ^ beta % 2 else (ec.P - beta) # If xcubedaxb is not a quadratic residue, then r cannot be the x coord # for a point on the curve, and so the sig is invalid if (xcubedaxb - y * y) % ec.P != 0: return False z = convert.bytes_to_int(msghash) Gz = ec.jacobian_multiply((ec.Gx, ec.Gy, 1), (ec.N - z) % ec.N) XY = ec.jacobian_multiply((x, y, 1), s) Qr = ec.jacobian_add(Gz, XY) Q = ec.jacobian_multiply(Qr, ec.inv(r, ec.N)) Q = ec.from_jacobian(Q) return Q