|
6 | 6 | import hashlib
|
7 | 7 | import unittest
|
8 | 8 |
|
9 |
| -def rot32(v, bits): |
10 |
| - """Rotate the 32-bit value v left by bits bits.""" |
11 |
| - bits %= 32 # Make sure the term below does not throw an exception |
12 |
| - return ((v << bits) & 0xffffffff) | (v >> (32 - bits)) |
13 |
| - |
14 |
| -def chacha20_doubleround(s): |
15 |
| - """Apply a ChaCha20 double round to 16-element state array s. |
16 |
| -
|
17 |
| - See https://cr.yp.to/chacha/chacha-20080128.pdf and https://tools.ietf.org/html/rfc8439 |
18 |
| - """ |
19 |
| - QUARTER_ROUNDS = [(0, 4, 8, 12), |
20 |
| - (1, 5, 9, 13), |
21 |
| - (2, 6, 10, 14), |
22 |
| - (3, 7, 11, 15), |
23 |
| - (0, 5, 10, 15), |
24 |
| - (1, 6, 11, 12), |
25 |
| - (2, 7, 8, 13), |
26 |
| - (3, 4, 9, 14)] |
27 |
| - |
28 |
| - for a, b, c, d in QUARTER_ROUNDS: |
29 |
| - s[a] = (s[a] + s[b]) & 0xffffffff |
30 |
| - s[d] = rot32(s[d] ^ s[a], 16) |
31 |
| - s[c] = (s[c] + s[d]) & 0xffffffff |
32 |
| - s[b] = rot32(s[b] ^ s[c], 12) |
33 |
| - s[a] = (s[a] + s[b]) & 0xffffffff |
34 |
| - s[d] = rot32(s[d] ^ s[a], 8) |
35 |
| - s[c] = (s[c] + s[d]) & 0xffffffff |
36 |
| - s[b] = rot32(s[b] ^ s[c], 7) |
37 |
| - |
38 |
| -def chacha20_32_to_384(key32): |
39 |
| - """Specialized ChaCha20 implementation with 32-byte key, 0 IV, 384-byte output.""" |
40 |
| - # See RFC 8439 section 2.3 for chacha20 parameters |
41 |
| - CONSTANTS = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574] |
42 |
| - |
43 |
| - key_bytes = [0]*8 |
44 |
| - for i in range(8): |
45 |
| - key_bytes[i] = int.from_bytes(key32[(4 * i):(4 * (i+1))], 'little') |
46 |
| - |
47 |
| - INITIALIZATION_VECTOR = [0] * 4 |
48 |
| - init = CONSTANTS + key_bytes + INITIALIZATION_VECTOR |
49 |
| - out = bytearray() |
50 |
| - for counter in range(6): |
51 |
| - init[12] = counter |
52 |
| - s = init.copy() |
53 |
| - for _ in range(10): |
54 |
| - chacha20_doubleround(s) |
55 |
| - for i in range(16): |
56 |
| - out.extend(((s[i] + init[i]) & 0xffffffff).to_bytes(4, 'little')) |
57 |
| - return bytes(out) |
| 9 | +from .chacha20 import chacha20_block |
58 | 10 |
|
59 | 11 | def data_to_num3072(data):
|
60 | 12 | """Hash a 32-byte array data to a 3072-bit number using 6 Chacha20 operations."""
|
61 |
| - bytes384 = chacha20_32_to_384(data) |
| 13 | + bytes384 = b"" |
| 14 | + for counter in range(6): |
| 15 | + bytes384 += chacha20_block(data, bytes(12), counter) |
62 | 16 | return int.from_bytes(bytes384, 'little')
|
63 | 17 |
|
64 | 18 | class MuHash3072:
|
@@ -99,12 +53,3 @@ def test_muhash(self):
|
99 | 53 | finalized = muhash.digest()
|
100 | 54 | # This mirrors the result in the C++ MuHash3072 unit test
|
101 | 55 | self.assertEqual(finalized[::-1].hex(), "10d312b100cbd32ada024a6646e40d3482fcff103668d2625f10002a607d5863")
|
102 |
| - |
103 |
| - def test_chacha20(self): |
104 |
| - def chacha_check(key, result): |
105 |
| - self.assertEqual(chacha20_32_to_384(key)[:64].hex(), result) |
106 |
| - |
107 |
| - # Test vectors from https://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04#section-7 |
108 |
| - # Since the nonce is hardcoded to 0 in our function we only use those vectors. |
109 |
| - chacha_check([0]*32, "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586") |
110 |
| - chacha_check([0]*31 + [1], "4540f05a9f1fb296d7736e7b208e3c96eb4fe1834688d2604f450952ed432d41bbe2a0b6ea7566d2a5d1e7e20d42af2c53d792b1c43fea817e9ad275ae546963") |
0 commit comments