rand.c (2338B)
1 #include <errno.h> 2 #include <fcntl.h> 3 #include <unistd.h> 4 5 #include "bits.h" 6 #include "rand.h" 7 #include "rcx.h" 8 #include "unix.h" 9 10 #define mix r_wymix_ 11 #define r4(p) ((u64)r_readh32(p)) 12 #define r8(p) ((u64)r_readh64(p)) 13 14 u64 r_seed = 0; 15 16 u64 r_hash_key[4] = { 17 U64_C(0xa0761d6478bd642f), 18 U64_C(0xe7037ed1a0b428db), 19 U64_C(0x8ebc6af09c88c6e3), 20 U64_C(0x589965cc75374cc3), 21 }; 22 23 u64 24 r_hash_(void *data, u64 len, u64 seed, u64 (*key)[4]) { 25 u8 *p = data; 26 27 seed ^= mix(seed ^ (*key)[0], (*key)[1]); 28 29 u64 a, b; 30 if unlikely (len == 0) { 31 a = 0; 32 b = 0; 33 } else if unlikely (len < 4) { 34 a = ((u64)p[0] << 16) | ((u64)p[len>>1] << 8) | (u64)p[len-1]; 35 b = 0; 36 } else if likely (len <= 16) { 37 a = (r4(p) << 32) | r4(p+((len>>3)<<2)); 38 b = (r4(p+len-4) << 32) | r4(p+len-4-((len>>3)<<2)); 39 } else { 40 u64 i = len; 41 if unlikely (i > 48) { 42 u64 seed0 = seed; 43 u64 seed1 = seed; 44 u64 seed2 = seed; 45 for (; i > 48; p += 48, i -= 48) { 46 seed0 = mix(r8(p+ 0) ^ (*key)[1], r8(p+ 8) ^ seed0); 47 seed1 = mix(r8(p+16) ^ (*key)[2], r8(p+24) ^ seed1); 48 seed2 = mix(r8(p+32) ^ (*key)[3], r8(p+40) ^ seed2); 49 } 50 seed = seed0 ^ seed1 ^ seed2; 51 } 52 for (; i > 16; p += 16, i -= 16) 53 seed = mix(r8(p) ^ (*key)[1], r8(p+8) ^ seed); 54 a = r8(p+i-16); 55 b = r8(p+i-8); 56 } 57 58 a ^= (*key)[1]; 59 b ^= seed; 60 r_mulu64(&b, &a, a, b); 61 return mix(a ^ (*key)[0] ^ len, b ^ (*key)[1]); 62 } 63 64 void 65 r_make_hash_key(u64 (*key)[4], u64 seed) { 66 u8 c[] = { 67 15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 68 53, 54, 57, 58, 60, 71, 75, 77, 78, 83, 69 85, 86, 89, 90, 92, 99, 101, 102, 105, 106, 70 108, 113, 114, 116, 120, 135, 139, 141, 142, 147, 71 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 72 172, 177, 178, 180, 184, 195, 197, 198, 201, 202, 73 204, 209, 210, 212, 216, 225, 226, 228, 232, 240, 74 }; 75 76 for (usize i = 0; i < 4; i++) { 77 again: 78 (*key)[i] = 0; 79 for (usize j = 0; j < 64; j += 8) 80 (*key)[i] |= (u64)c[r_prand64(&seed) % sizeof c] << j; 81 if ((*key)[i] % 2 == 0) 82 goto again; 83 for (usize j = 0; j < i; j++) { 84 if (r_popcnt64((*key)[j] ^ (*key)[i]) != 32) 85 goto again; 86 } 87 } 88 } 89 90 int 91 r_trand(void *buf, usize len) { 92 int fd = open("/dev/urandom", O_RDONLY); 93 if (fd < 0) return -1; 94 if (r_read_all(0, fd, buf, len) < 0) { 95 int e = errno; 96 close(fd); 97 errno = e; 98 return -1; 99 } 100 close(fd); 101 return 0; 102 }