rcx

miscellaneous C library
git clone git://git.rr3.xyz/rcx
Log | Files | Refs | README | LICENSE

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 }