diff options
Diffstat (limited to 'examples/redis-unstable/modules/vector-sets/mixer.h')
| -rw-r--r-- | examples/redis-unstable/modules/vector-sets/mixer.h | 106 |
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 | |||
| 21 | static 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 | */ | ||
| 39 | void 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 | } | ||
