|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +import hashlib |
| 4 | +import json |
| 5 | +import sys |
| 6 | + |
| 7 | +def hash(data): |
| 8 | + return hashlib.blake2b(data, digest_size=32).digest() |
| 9 | + |
| 10 | +def hex(data): |
| 11 | + return ''.join(f'{x:02x}' for x in data) |
| 12 | + |
| 13 | +def compute_shuffle_eq329(s, r): |
| 14 | + if len(s) > 0: |
| 15 | + l = len(s) |
| 16 | + index = r[0] % l |
| 17 | + head = s[index] |
| 18 | + |
| 19 | + s_post = s.copy() |
| 20 | + s_post[index] = s[l-1] |
| 21 | + |
| 22 | + return [head] + compute_shuffle_eq329(s_post[:-1], r[1:]) |
| 23 | + else: |
| 24 | + return [] |
| 25 | + |
| 26 | +def number_vector(n): |
| 27 | + return [x for x in range(n)] |
| 28 | + |
| 29 | +def uniform_seed(n): |
| 30 | + return [n] * 32 |
| 31 | + |
| 32 | +def linear_seed(): |
| 33 | + return [i for i in range(32)] |
| 34 | + |
| 35 | +def varied_seed(n): |
| 36 | + # large 32 bit prime |
| 37 | + large_prime = 2147483647 |
| 38 | + result = [] |
| 39 | + next = n % large_prime |
| 40 | + |
| 41 | + # next is always a 32-bit prime, so it fits in 4 bytes. |
| 42 | + # this loop generates a cycle of modular exponents of a generator. |
| 43 | + # if this generator is unknown, this cycle is in practice unpredictable, |
| 44 | + # so this should generate a sequence that looks a bit like random |
| 45 | + # and should be enough for simple tests. |
| 46 | + for i in range(8): |
| 47 | + result = result + list(to_le_bytes(next, 4)) |
| 48 | + next = next * n % large_prime |
| 49 | + |
| 50 | + return result |
| 51 | + |
| 52 | +def inputs_Eq331(): |
| 53 | + zero_seed = uniform_seed(0) |
| 54 | + ff_seed = uniform_seed(255) |
| 55 | + simple_seed = linear_seed() |
| 56 | + irregular_seed = varied_seed(1_000_000_000_000) |
| 57 | + |
| 58 | + yield(number_vector(0), zero_seed) |
| 59 | + yield(number_vector(8), ff_seed) |
| 60 | + yield(number_vector(16), simple_seed) |
| 61 | + yield(number_vector(20), irregular_seed) |
| 62 | + |
| 63 | + yield(number_vector(50), zero_seed) |
| 64 | + yield(number_vector(100), ff_seed) |
| 65 | + yield(number_vector(200), simple_seed) |
| 66 | + yield(number_vector(341), irregular_seed) |
| 67 | + |
| 68 | + |
| 69 | +def to_le_bytes(n, k): |
| 70 | + return n.to_bytes(k, 'little') |
| 71 | + |
| 72 | +def from_le_bytes(b): |
| 73 | + return int.from_bytes(b, 'little') |
| 74 | + |
| 75 | +def compute_q(h, l): |
| 76 | + result = [] |
| 77 | + for i in range(l): |
| 78 | + preimage = bytes(h.copy()) + to_le_bytes(i // 8, 4) |
| 79 | + offset = 4*i % 32 |
| 80 | + slice = hash(preimage)[offset:offset + 4] |
| 81 | + result.append(from_le_bytes(slice)) |
| 82 | + |
| 83 | + return result |
| 84 | + |
| 85 | +def compute_shuffle_eq331(s, h): |
| 86 | + l = len(s) |
| 87 | + r = compute_q(h, l) |
| 88 | + |
| 89 | + return compute_shuffle_eq329(s, r) |
| 90 | + |
| 91 | +def is_permutation(list1, list2): |
| 92 | + return set(list1) == set(list2) |
| 93 | + |
| 94 | +def test_vectors_eq331(): |
| 95 | + for term in inputs_Eq331(): |
| 96 | + s, r = term |
| 97 | + output = compute_shuffle_eq331(s, r) |
| 98 | + assert(is_permutation(s, output)) |
| 99 | + |
| 100 | + yield { |
| 101 | + 'input': len(s), |
| 102 | + 'entropy': hex(r), |
| 103 | + 'output': output, |
| 104 | + } |
| 105 | + |
| 106 | +def main(): |
| 107 | + json.dump(list(test_vectors_eq331()), sys.stdout, indent=' ') |
| 108 | + |
| 109 | +main() |
0 commit comments