1import unittest
2import hmac
3import hashlib
4from util import *
5
6CA_PREFIX_LIQUID = 0x0c
7CA_PREFIX_LIQUID_REGTEST = 0x04
8EC_PUBLIC_KEY_LEN = 33
9
10class CATests(unittest.TestCase):
11
12    def test_master_blinding_key(self):
13
14        # from Trezor firmware code
15        class Slip21Node:
16            def __init__(self, seed = None):
17                if seed is not None:
18                    self.data = hmac.HMAC(b"Symmetric key seed", seed, hashlib.sha512).digest()
19                else:
20                    self.data = None
21
22            def derive_path(self, path):
23                for label in path:
24                    h = hmac.HMAC(self.data[0:32], b"\x00", hashlib.sha512)
25                    h.update(label)
26                    self.data = h.digest()
27
28            def key(self):
29                return self.data[32:64]
30
31        seed = create_string_buffer(64)
32        bip39_mnemonic_to_seed(b' '.join([b'all'] * 12), b'', seed, 64)
33        root = Slip21Node(seed = seed)
34        self.assertEqual(root.key(), unhexlify('dbf12b44133eaab506a740f6565cc117228cbf1dd70635cfa8ddfdc9af734756'))
35        root.derive_path([b'SLIP-0077'])
36        master_blinding_key = root.key()
37
38        out = create_string_buffer(64)
39        ret = wally_asset_blinding_key_from_seed(seed, 64, out, 64)
40        self.assertEqual(ret, WALLY_OK)
41        _, out_hex = wally_hex_from_bytes(out[32:], 32)
42        self.assertEqual(hexlify(master_blinding_key), utf8(out_hex))
43
44        unconfidential_addr = '2dpWh6jbhAowNsQ5agtFzi7j6nKscj6UnEr'
45        script, _ = make_cbuffer('76a914a579388225827d9f2fe9014add644487808c695d88ac')
46        private_blinding_key, _ = make_cbuffer('00' * 32)
47        ret = wally_asset_blinding_key_to_ec_private_key(root.data, len(root.data), script, len(script), private_blinding_key, len(private_blinding_key))
48        self.assertEqual(ret, WALLY_OK)
49        public_blinding_key, _ = make_cbuffer('00' * 33)
50        ret = wally_ec_public_key_from_private_key(private_blinding_key, len(private_blinding_key), public_blinding_key, len(public_blinding_key))
51        self.assertEqual(ret, WALLY_OK)
52
53        ret, address = wally_confidential_addr_from_addr(utf8(unconfidential_addr), CA_PREFIX_LIQUID_REGTEST, public_blinding_key, len(public_blinding_key))
54        self.assertEqual(address, "CTEkf75DFff5ReB7juTg2oehrj41aMj21kvvJaQdWsEAQohz1EDhu7Ayh6goxpz3GZRVKidTtaXaXYEJ")
55
56
57    def test_confidential_addr(self):
58        """Tests for confidential addresses"""
59
60        # The (Liquid) address that is to be blinded
61        addr = 'Q7qcjTLsYGoMA7TjUp97R6E6AM5VKqBik6'
62        # The blinding pubkey
63        pubkey_hex = '02dce16018bbbb8e36de7b394df5b5166e9adb7498be7d881a85a09aeecf76b623'
64        # The resulting confidential address
65        addr_c = utf8('VTpz1bNuCALgavJKgbAw9Lpp9A72rJy64XPqgqfnaLpMjRcPh5UHBqyRUE4WMZ3asjqu7YEPVAnWw2EK')
66
67        # Test we can extract the original address
68        ret, result = wally_confidential_addr_to_addr(addr_c, CA_PREFIX_LIQUID)
69        self.assertEqual((ret, result), (WALLY_OK, addr))
70
71        # Test we can extract the blinding pubkey
72        out, out_len = make_cbuffer('00' * EC_PUBLIC_KEY_LEN)
73        ret = wally_confidential_addr_to_ec_public_key(addr_c, CA_PREFIX_LIQUID, out, out_len)
74        self.assertEqual(ret, WALLY_OK)
75        _, out_hex = wally_hex_from_bytes(out, out_len)
76        self.assertEqual(utf8(pubkey_hex), utf8(out_hex))
77
78        # Test we can re-generate the confidential address from its inputs
79        ret, new_addr_c = wally_confidential_addr_from_addr(utf8(addr), CA_PREFIX_LIQUID, out, out_len)
80        self.assertEqual(ret, WALLY_OK)
81        self.assertEqual(utf8(new_addr_c), addr_c)
82
83
84if __name__ == '__main__':
85    unittest.main()
86