summaryrefslogtreecommitdiff
path: root/examples/redis-unstable/modules/vector-sets/mixer.h
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/modules/vector-sets/mixer.h')
-rw-r--r--examples/redis-unstable/modules/vector-sets/mixer.h106
1 files changed, 106 insertions, 0 deletions
diff --git a/examples/redis-unstable/modules/vector-sets/mixer.h b/examples/redis-unstable/modules/vector-sets/mixer.h
new file mode 100644
index 0000000..d75e193
--- /dev/null
+++ b/examples/redis-unstable/modules/vector-sets/mixer.h
@@ -0,0 +1,106 @@
1/* Redis implementation for vector sets. The data structure itself
2 * is implemented in hnsw.c.
3 *
4 * Copyright (c) 2009-Present, Redis Ltd.
5 * All rights reserved.
6 *
7 * Licensed under your choice of (a) the Redis Source Available License 2.0
8 * (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the
9 * GNU Affero General Public License v3 (AGPLv3).
10 * Originally authored by: Salvatore Sanfilippo.
11 *
12 * =============================================================================
13 *
14 * Mixing function for HNSW link integrity verification
15 * Designed to resist collision attacks when salts are unknown.
16 */
17
18#include <stdint.h>
19#include <string.h>
20
21static inline uint64_t ROTL64(uint64_t x, int r) {
22 return (x << r) | (x >> (64 - r));
23}
24
25// Use more rounds and stronger constants
26#define MIX_PRIME_1 0xFF51AFD7ED558CCDULL
27#define MIX_PRIME_2 0xC4CEB9FE1A85EC53ULL
28#define MIX_PRIME_3 0x9E3779B97F4A7C15ULL
29#define MIX_PRIME_4 0xBF58476D1CE4E5B9ULL
30#define MIX_PRIME_5 0x94D049BB133111EBULL
31#define MIX_PRIME_6 0x2B7E151628AED2A7ULL
32
33/* Mixer design goals:
34 * 1. Thorough mixing of the level parameter.
35 * 2. Enough rounds of mixing.
36 * 3. Cross-influence between h1 and h2.
37 * 4. Domain separation to prevent related-key attacks.
38 */
39void secure_pair_mixer_128(uint64_t salt0, uint64_t salt1,
40 uint64_t id1_in, uint64_t id2_in, uint64_t level,
41 uint64_t* out_h1, uint64_t* out_h2) {
42 // Order independence (A -> B links should hash as B -> A links).
43 uint64_t id_a = (id1_in < id2_in) ? id1_in : id2_in;
44 uint64_t id_b = (id1_in < id2_in) ? id2_in : id1_in;
45
46 // Domain separation: mix salts with a constant to prevent
47 // related-key attacks.
48 uint64_t h1 = salt0 ^ 0xDEADBEEFDEADBEEFULL;
49 uint64_t h2 = salt1 ^ 0xCAFEBABECAFEBABEULL;
50
51 // First, thoroughly mix the level into both accumulators
52 // This prevents predictable level values from being a weakness
53 uint64_t level_mix = level;
54 level_mix *= MIX_PRIME_5;
55 level_mix ^= level_mix >> 32;
56 level_mix *= MIX_PRIME_6;
57
58 h1 ^= level_mix;
59 h2 ^= ROTL64(level_mix, 31);
60
61 // Mix in id_a with strong diffusion.
62 h1 ^= id_a;
63 h1 *= MIX_PRIME_1;
64 h1 = ROTL64(h1, 23);
65 h1 *= MIX_PRIME_2;
66
67 // Mix in id_b.
68 h2 ^= id_b;
69 h2 *= MIX_PRIME_3;
70 h2 = ROTL64(h2, 29);
71 h2 *= MIX_PRIME_4;
72
73 // Three rounds of cross-mixing for better security.
74 for (int i = 0; i < 3; i++) {
75 // Cross-influence.
76 uint64_t tmp = h1;
77 h1 += h2;
78 h2 += tmp;
79
80 // Mix h1.
81 h1 ^= ROTL64(h1, 31);
82 h1 *= MIX_PRIME_1;
83 h1 ^= salt0;
84
85 // Mix h2.
86 h2 ^= ROTL64(h2, 37);
87 h2 *= MIX_PRIME_2;
88 h2 ^= salt1;
89 }
90
91 // Finalization with avalanche rounds.
92 h1 ^= h1 >> 33;
93 h1 *= MIX_PRIME_3;
94 h1 ^= h1 >> 29;
95 h1 *= MIX_PRIME_4;
96 h1 ^= h1 >> 32;
97
98 h2 ^= h2 >> 33;
99 h2 *= MIX_PRIME_5;
100 h2 ^= h2 >> 29;
101 h2 *= MIX_PRIME_6;
102 h2 ^= h2 >> 32;
103
104 *out_h1 = h1;
105 *out_h2 = h2;
106}