def wif_from_prvkey(prvkey: int, compressed: bool) -> bytes: """private key to Wallet Import Format""" payload = b'\x80' + int2octets(prvkey, ec.psize) if compressed: payload += b'\x01' return b58encode_check(payload)
def key_agreement(dUV: int, QVU: Point, keydatasize: int, ec: EC, hf) -> bytes: P = pointMult(ec, dUV, QVU) if P == (1, 0): "invalid (zero) private key" z = P[0] zbytes = int2octets(z, ec.psize) k = kdf(zbytes, keydatasize, ec, hf) return k
def _ecssa_e(ec: EC, hf, r: int, P: Point, m: bytes) -> int: # Let e = int(hf(bytes(x(R)) || bytes(dG) || m)) mod n. ebytes = int2octets(r, ec.psize) # FIXME: hsize, nsize ? ebytes += point2octets(ec, P, True) ebytes += m ebytes = hf(ebytes).digest() e = bits2int(ec, ebytes) return e
def rfc6979(ec: EC, hf, h1: bytes, x: int) -> int: """Return a deterministic ephemeral key following rfc6979""" if not 0 < x < ec.n: raise ValueError(f"invalid private key {hex(x)}") hsize = hf().digest_size # bytes if len(h1) != hsize: errMsg = f"mismatch between hf digest size ({hsize}) and " errMsg += f"hashed message size ({len(h1)})" raise ValueError(errMsg) # https://tools.ietf.org/html/rfc6979 section 3.2 # h1 = hf(m) # 3.2.a # truncate and/or expand h1: encoding size is driven by nsize z1 = _bits2int(ec, h1) # leftmost ec.nlen bits z1 %= ec.n bm = int2octets(z1, ec.nsize) # bm = z1.to_bytes(nsize, 'big') # convert the private key x to a sequence of nsize octets bprv = int2octets(x, ec.nsize) # bprv = x.to_bytes(nsize, 'big') bprvbm = bprv + bm V = b'\x01' * hsize # 3.2.b K = b'\x00' * hsize # 3.2.c K = hmac.new(K, V + b'\x00' + bprvbm, hf).digest() # 3.2.d V = hmac.new(K, V, hf).digest() # 3.2.e K = hmac.new(K, V + b'\x01' + bprvbm, hf).digest() # 3.2.f V = hmac.new(K, V, hf).digest() # 3.2.g while True: # 3.2.h T = b'' # 3.2.h.1 while len(T) < ec.nsize: # 3.2.h.2 V = hmac.new(K, V, hf).digest() T += V k = _bits2int(ec, T) # candidate # 3.2.h.3 if 0 < k < ec.n: # acceptable values for k return k # successful candidate K = hmac.new(K, V + b'\x00', hf).digest() V = hmac.new(K, V, hf).digest()
def kdf(zbytes: bytes, keydatasize: int, ec: EC, hf) -> bytes: """ ANS-X9.63-KDF - SEC 1 specification source: http://www.secg.org/sec1-v2.pdf, section 3.6.1 """ hsize = hf().digest_size assert keydatasize < hsize * (2**32 - 1), "invalid" counter = 1 counter_bytes = counter.to_bytes(4, 'big') K_temp = [] for i in range((keydatasize + 1) // hsize): K_temp.append(hf(zbytes + counter_bytes).digest()) counter += 1 counter_bytes = counter.to_bytes(4, 'big') i += 1 K_bytes = b''.join(K_temp[i] for i in range(keydatasize // hsize)) K = octets2int(K_bytes) >> (keydatasize - hsize) return int2octets(K, ec.psize)