1import unittest
2from util import *
3from ctypes import create_string_buffer
4
5# NIST cases from http://www.di-mgt.com.au/sha_testvectors.html
6# SHA-256d vectors from https://www.dlitz.net/crypto/shad256-test-vectors/SHAd256_Test_Vectors.txt
7sha2_cases = {
8    'abc':
9        ['ba7816bf 8f01cfea 414140de 5dae2223 b00361a3 96177a9c b410ff61 f20015ad',
10         'ddaf35a193617aba cc417349ae204131 12e6fa4e89a97ea2 0a9eeee64b55d39a'
11         '2192992a274fc1a8 36ba3c23a3feebbd 454d4423643ce80e 2a9ac94fa54ca49f',
12         '4f8b42c22dd3729b519ba6f68d2da7cc5b2d606d05daed5ad5128cc03e6c6358'],
13
14    '':
15        ['e3b0c442 98fc1c14 9afbf4c8 996fb924 27ae41e4 649b934c a495991b 7852b855',
16         'cf83e1357eefb8bd f1542850d66d8007 d620e4050b5715dc 83f4a921d36ce9ce'
17         '47d0d13c5d85f2b0 ff8318d2877eec2f 63b931bd47417a81 a538327af927da3e',
18         '5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456' ],
19
20    'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq':
21        ['248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1',
22         '204a8fc6dda82f0a 0ced7beb8e08a416 57c16ef468b228a8 279be331a703c335'
23         '96fd15c13b1b07f9 aa1d3bea57789ca0 31ad85c7a71dd703 54ec631238ca3445',
24         '0cffe17f68954dac3a84fb1458bd5ec99209449749b2b308b7cb55812f9563af'],
25
26    'abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn'
27    'hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu':
28        ['cf5b16a7 78af8380 036ce59e 7b049237 0b249b11 e8f07a51 afac4503 7afee9d1',
29         '8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018'
30         '501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909',
31         None],
32
33    'a' * 1000000:
34        ['cdc76e5c 9914fb92 81a1c7e2 84d73e67 f1809a48 a497200e 046d39cc c7112cd0',
35         'e718483d0ce76964 4e2e42c7bc15b463 8e1f98b13b204428 5632a803afa973eb'
36         'de0ff244877ea60a 4cb0432ce577c31b eb009c5c2c49aa2e 4eadb217ad8cc09b',
37         '80d1189477563e1b5206b2749f1afe4807e5705e8bd77887a60187a712156688'],
38}
39
40hash160_cases = [
41    # https://en.bitcoin.it/wiki/Technical_background_of_Bitcoin_addresses
42    [ '0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B235'
43      '22CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6',
44      '010966776006953D5567439E5E39F86A0D273BEE' ],
45    # Randomly generated cases from https://gobittest.appspot.com/Address
46    [ '045B3B9D153DDB9A9630C7C4F00A56212A3FCAD062E8014C3E95BF9DDBD651B37'
47      'FFC78E532BC15096F1BAF889B503228324485CCF02BA954F431D4B5BAE731070D',
48      '5CE3425A868F365E06272EA5472D344CC8D14E56' ],
49    [ '048DED2821E449EA2AD863A35972A97120074EF6A73C0D5DF97BF20538EF173EC'
50      '33E75210F7B5977BDD2939850B3EA3791049C83DF4F66296F935FDF38BD80C2AC',
51      'AFF2B47861A205E3AB67B2042C3F44F1C9283868' ],
52    [ '042125CC51DD979091CBA34E71A4B419708267566E72F68EB5891F70E90774A34'
53      '171C1C95F54DE84BC11CBC0E6BD4792D5C17C5C3A26F99A9D136AADB66463AD58',
54      '53190BD5877616554E72253D4CDD2D37E1AA0D73' ],
55]
56
57class HashTests(unittest.TestCase):
58
59    SHA256_LEN, SHA512_LEN, HASH160_LEN = 32, 64, 20
60
61    def make_outbuf(self, fn, aligned=True):
62        buf_len = self.SHA256_LEN
63        if fn == wally_sha512:
64            buf_len = self.SHA512_LEN
65        elif fn == wally_hash160:
66            buf_len = self.HASH160_LEN
67        offset = 0 if aligned else 1
68        buf = create_string_buffer(buf_len + offset)
69        return byref(buf, offset), buf_len
70
71
72    def do_hash(self, fn, hex_in, aligned=True):
73        buf, buf_len = self.make_outbuf(fn, aligned)
74        in_bytes, in_bytes_len = make_cbuffer(hex_in)
75        ret = fn(in_bytes, in_bytes_len, buf, buf_len)
76        self.assertEqual(ret, WALLY_OK)
77        ret, result = wally_hex_from_bytes(buf, buf_len)
78        self.assertEqual(ret, WALLY_OK)
79        return utf8(result)
80
81
82    def _do_test_sha_vectors(self):
83        for in_msg, values in sha2_cases.items():
84            msg = h(utf8(in_msg))
85            for i, fn in enumerate([wally_sha256, wally_sha512, wally_sha256d]):
86                if values[i] is not None:
87                    for aligned in [True, False]:
88                        result = self.do_hash(fn, msg, aligned)
89                        expected = utf8(values[i].replace(' ', ''))
90                        self.assertEqual(result, expected)
91
92
93    def test_sha_vectors(self):
94        self. _do_test_sha_vectors()
95        wally_init(0) # Enable optimized SHA256 and re-test
96        self. _do_test_sha_vectors()
97
98
99    def test_hash160_vectors(self):
100        for msg, expected in hash160_cases:
101            for aligned in [True, False]:
102                result = self.do_hash(wally_hash160, utf8(msg), aligned)
103                self.assertEqual(result, utf8(expected.lower()))
104
105
106    def test_invalid_args(self):
107        in_bytes, in_bytes_len = make_cbuffer(h(utf8('abc')))
108        for fn in [wally_sha256, wally_sha512, wally_sha256d, wally_hash160]:
109            buf, buf_len = self.make_outbuf(fn)
110            for args in [(None,     in_bytes_len, buf,  buf_len),
111                         (in_bytes, in_bytes_len, None, buf_len),
112                         (in_bytes, in_bytes_len, buf,  buf_len + 1)]:
113                self.assertEqual(fn(args[0], args[1], args[2], args[3]),
114                                 WALLY_EINVAL)
115
116
117if __name__ == '__main__':
118    unittest.main()
119