def child(self, i: int) -> 'Xprv':
        hardened = i >= 1 << 31
        if hardened:
            I = hmac.new(key=self.code,
                         msg=self.keydata() +
                         int_to_bytes(i).rjust(4, b'\x00'),
                         digestmod=hashlib.sha512).digest()
            tmp = int_to_bytes(i).rjust(4, b'\x00')

        else:
            I = hmac.new(key=self.code,
                         msg=self.key.to_public().encode(compressed=True) +
                         int_to_bytes(i).rjust(4, b'\x00'),
                         digestmod=hashlib.sha512).digest()
            tmp = self.key.to_public().encode(
                compressed=True) + int_to_bytes(i).rjust(4, b'\x00')

        I_L, I_R = bytes_to_int(I[:32]), I[32:]
        key = (I_L + self.key.int()) % CURVE.order
        if I_L >= CURVE.order or key == 0:
            return self.child(i + 1)
        ret_code = I_R
        if hardened:
            path = self.path + f'/{i - 2 ** 31}h'
        else:
            path = self.path + f'/{i}'

        return Xprv(WitPrivateKey.from_int(key),
                    ret_code,
                    depth=self.depth + 1,
                    i=i,
                    parent=self.fingerprint(),
                    path=path)
예제 #2
0
 def decode(cls, key: bytes) -> 'WitPublicKey':
     if key.startswith(b'\x04'):  # uncompressed key
         assert len(
             key) == 65, 'An uncompressed public key must be 65 bytes long'
         x, y = bytes_to_int(key[1:33]), bytes_to_int(key[33:])
     else:  # compressed key
         assert len(
             key) == 33, 'A compressed public key must be 33 bytes long'
         x = bytes_to_int(key[1:])
         root = nt.modsqrt(CURVE.f(x), P)
         if key.startswith(b'\x03'):  # odd root
             y = root if root % 2 == 1 else -root % P
         elif key.startswith(b'\x02'):  # even root
             y = root if root % 2 == 0 else -root % P
         else:
             assert False, 'Wrong key format'
     return cls(Point(x, y, curve=CURVE))
예제 #3
0
def encode(bts: bytes) -> str:
    n = bytes_to_int(bts)
    leading_zero_bytes = len(bts) - len(bts.lstrip(b'\x00'))
    int_digits = []
    while n:
        int_digits.append(int(n % BASE))
        n //= BASE
    for _ in range(leading_zero_bytes):
        int_digits.append(0)
    return ''.join(ALPHABET[i] for i in reversed(int_digits))
 def from_seed(cls,
               seed: Union[bytes, str],
               network_key=b'Bitcoin seed') -> 'Xprv':
     """
     :param seed:
     :param network_key:
     :return:
     """
     if isinstance(seed, str):
         seed = hex_to_bytes(seed)
     assert 16 <= len(seed) <= 64, 'Seed should be between 128 and 512 bits'
     I = hmac.new(key=network_key, msg=seed,
                  digestmod=hashlib.sha512).digest()
     I_L, I_R = I[:32], I[32:]
     if bytes_to_int(I_L) == 0 or bytes_to_int(I_L) > CURVE.order:
         raise KeyDerivationError
     key, code = WitPrivateKey(I_L), I_R
     # print(f'\tMaster Secret Key: {bytes_to_hex(I_L)}')
     # print(f'\tMaster Chain Code: {bytes_to_hex(I_R)}')
     return cls(key, code)
예제 #5
0
    def verify_hash(self, _hash, public_key):
        from witnet.crypto.number_theory import mulinv

        public_key: WitPublicKey = public_key
        if not (1 <= self.r < N and 1 <= self.s < N):
            return False

        e = bytes_to_int(_hash)
        w = mulinv(self.s, N)
        u1 = (e * w) % N
        u2 = (self.r * w) % N
        point: Point = CURVE.generator * u1 + public_key.point * u2
        return self.r % N == point.x % N
예제 #6
0
    def sign_hash(self, _hash) -> Signature:
        e = hex_to_int(_hash) if isinstance(_hash,
                                            str) else bytes_to_int(_hash)
        r, s = 0, 0
        while r == 0 or s == 0:
            k = secrets.randbelow(N)
            point = CURVE.generator * k
            r = point.x % N

            inv_k = nt.mulinv(k, N)
            s = (inv_k * (e + r * self.int())) % N

        return Signature(r=r, s=s)
예제 #7
0
    def deserialize(cls, bts: bytes) -> 'ExtendedKey':
        from witnet.crypto.hd_wallet.extended_private_key import Xprv
        from witnet.crypto.hd_wallet.extended_public_key import Xpub

        def read(n):
            nonlocal bts
            data, bts = bts[:n], bts[n:]
            return data

        net = read(4)
        is_private = net in network('Mainnet').values()
        is_public = net in network('Mainnet').values()
        assert is_public ^ is_private, f'Invalid network bytes : {bytes_to_hex(net)}'
        # address_lookup = {val: key for key, val in (network('Mainnet') if is_private else network('Mainnet')).items()}
        constructor = Xprv if is_private else Xpub
        depth = bytes_to_int(read(1))
        assert depth in range(256), f'Invalid depth : {depth}'
        fingerprint = read(4)
        i = bytes_to_int(read(4))
        if depth == 0:
            i = None
            path = None
        else:
            ih = f'{i}' if i < 2**31 else f"{i - 2 ** 31}h"
            path = '/'.join([constructor.root_path] +
                            ['x' for _ in range(depth - 1)] + [ih])

        code = read(32)
        key = read(33)
        key = WitPrivateKey(key) if is_private else WitPublicKey.decode(key)
        assert not bts, 'Leftover bytes'
        return constructor(key,
                           code,
                           depth=depth,
                           i=i,
                           parent=fingerprint,
                           path=path)
예제 #8
0
    def decode(cls, bts):
        from collections import deque
        data = deque(bts)
        lead = data.popleft() == 0x30
        assert lead, f'Invalid leading byte: 0x{lead:x}'  # ASN1 SEQUENCE
        sequence_length = data.popleft()
        assert sequence_length <= 70, f'Invalid Sequence length: {sequence_length}'
        lead = data.popleft()
        assert lead == 0x02, f'Invalid r leading byte: 0x{lead:x}'  # 0x02 byte before r
        len_r = data.popleft()
        assert len_r <= 33, f'Invalid r length: {len_r}'
        bts = bytes(data)

        r, data = bytes_to_int(bts[:len_r]), deque(bts[len_r:])

        lead = data.popleft()
        assert lead == 0x02, f'Invalid s leading byte: 0x{lead:x}'  # 0x02 byte before s
        len_s = data.popleft()
        assert len_s <= 33, f'Invalid s length: {len_s}'
        bts = bytes(data)
        s, rest = bytes_to_int(bts[:len_s]), bts[len_s:]
        assert len(rest) == 0, f'{len(rest)} leftover bytes'

        return cls(r, s)
예제 #9
0
 def bin(self):
     return format(bytes_to_int(self.msg), 'b')
예제 #10
0
 def int(self):
     return bytes_to_int(self.msg)
예제 #11
0
 def __init__(self, bts):
     assert bytes_to_int(bts) < N, 'Key larger than Curve Order'
     super().__init__(bts)