github.com/moontrade/unsafe@v0.9.1/memory/hash/hash.js (about) 1 class WyF3 { 2 static DefaultSeed = BigInt.asUintN(64, 0xa0761d6478bd642fn); 3 static s1 = BigInt.asUintN(64, 0xe7037ed1a0b428dbn); 4 static s2 = BigInt.asUintN(64, 0x8ebc6af09c88c6e3n); 5 static s3 = BigInt.asUintN(64, 0x589965cc75374cc3n); 6 static s4 = BigInt.asUintN(64, 0x1d8e4e27c47d124fn); 7 static mask64 = BigInt.asUintN(64, 0xFFFFFFFFFFFFFFFFn); 8 static mask128 = BigInt.asUintN(128, 0xFFFFFFFFFFFFFFFFn); 9 static uint64hi = BigInt.asUintN(64, WyF3.s1 ^ BigInt.asUintN(64, 8n)); 10 static numberBuffer = Uint8Array.of(0, 0, 0, 0, 0, 0, 0, 0); 11 static numberBufferView = new DataView(WyF3.numberBuffer.buffer); 12 13 static mix(x, y) { 14 // mul128 15 let r = BigInt.asUintN(128, x) * BigInt.asUintN(128, y); 16 let hi = BigInt.asUintN(64, (r >> 64n) & WyF3.mask128); 17 let lo = BigInt.asUintN(64, r & WyF3.mask128); 18 return hi ^ lo; 19 } 20 21 static read32(d, offset) { 22 return BigInt.asUintN(64, BigInt(d.getUint32(offset, true))); 23 } 24 25 static uint64(value = 0n, seed = WyF3.DefaultSeed) { 26 WyF3.numberBufferView.setBigUint64(0, BigInt.asUintN(64, BigInt(value)), true); 27 return WyF3.uint64Internal(seed); 28 } 29 30 static number(value = 0, seed = WyF3.DefaultSeed) { 31 WyF3.numberBufferView.setFloat64(0, value, true); 32 return WyF3.uint64Internal(seed); 33 } 34 35 static uint64Internal(seed = WyF3.DefaultSeed) { 36 const v = WyF3.numberBufferView.getBigUint64(0, true); 37 let hi = BigInt.asUintN(64, (v >> 32n) & WyF3.mask64); 38 let lo = BigInt.asUintN(64, v & WyF3.mask64); 39 return WyF3.mix(WyF3.uint64hi, WyF3.mix(hi ^ WyF3.s1, lo ^ seed)); 40 } 41 42 static string(data = '', seed = WyF3.DefaultSeed) { 43 const d = new TextEncoder().encode(data); 44 return WyF3.hashBytes(new DataView(d.buffer), seed); 45 } 46 47 static hash(value, seed = WyF3.DefaultSeed) { 48 if (typeof value === 'string') { 49 return WyF3.string(value, seed); 50 } 51 if (typeof value === 'bigint') { 52 return WyF3.uint64(value, seed); 53 } 54 if (typeof value === 'number') { 55 return WyF3.number(value, seed); 56 } 57 if (value instanceof DataView) { 58 return WyF3.hashBytes(value, seed); 59 } 60 if (value instanceof ArrayBuffer) { 61 return WyF3.hashBytes(new DataView(value), seed); 62 } 63 if (value instanceof Uint8Array) { 64 return WyF3.hashBytes(new DataView(value.buffer), seed); 65 } 66 throw 'WyF3.hash supports string, bigint, number, DataView, ArrayBuffer, Uint8Array'; 67 } 68 69 /** 70 * 71 * @param d DataView 72 * @param seed 73 * @returns {*} 74 */ 75 static hashBytes(d, seed = WyF3.DefaultSeed) { 76 let length = d.byteLength; 77 let a; 78 let b; 79 80 if (length <= 16) { 81 if (length >= 4) { 82 a = (WyF3.read32(d, 0) << BigInt.asUintN(64, 32n)) | WyF3.read32(d, (length >> 3) << 2); 83 b = (WyF3.read32(d, length - 4) << BigInt.asUintN(64, 32n)) | WyF3.read32(d, length - 4 - ((length >> 3) << 2)); 84 } else if (length > 0) { 85 a = BigInt.asUintN(64, BigInt(d.getUint8(0) << 16 | 86 d.getUint8(length >> 1) << 8 | 87 d.getUint8(length - 1))); 88 b = 0n; 89 } 90 } else { 91 let index = length; 92 let start = 0; 93 if (length > 48) { 94 let see1 = seed; 95 let see2 = seed; 96 for (; index > 48;) { 97 seed = WyF3.mix(d.getBigUint64(start, true) ^ WyF3.s1, d.getBigUint64(start + 8, true) ^ seed); 98 see1 = WyF3.mix(d.getBigUint64(start + 16, true) ^ WyF3.s2, d.getBigUint64(start + 24, true) ^ see1); 99 see2 = WyF3.mix(d.getBigUint64(start + 32, true) ^ WyF3.s3, d.getBigUint64(start + 40, true) ^ see2); 100 index -= 48; 101 start += 48; 102 } 103 seed ^= see1 ^ see2; 104 } 105 106 for (; index > 16;) { 107 seed = WyF3.mix(d.getBigUint64(start, true) ^ WyF3.s1, d.getBigUint64(start + 8, true) ^ seed); 108 index -= 16; 109 start += 16; 110 } 111 112 a = d.getBigUint64(start + index - 16, true); 113 b = d.getBigUint64(start + index - 8, true); 114 } 115 116 return WyF3.mix(WyF3.s1 ^ BigInt(length), WyF3.mix(a ^ WyF3.s1, b ^ seed)); 117 } 118 } 119 120 class WyF3Rand { 121 static DEFAULT = new WyF3Rand(new Date().getTime()); 122 123 constructor(seed) { 124 this.seed = BigInt.asUintN(64, BigInt(seed)); 125 } 126 127 static RAND_C0 = BigInt.asUintN(64, 0xa0761d6478bd642fn); 128 static RAND_C1 = BigInt.asUintN(64, 0xe7037ed1a0b428dbn); 129 130 131 next() { 132 this.seed += WyF3Rand.RAND_C0; 133 return WyF3.mix(this.seed, this.seed ^ WyF3Rand.RAND_C1); 134 } 135 136 // static NORM_01 = 1.0 / (1.0 << 52); 137 // static GAUSSIAN_NORM = 1.0 / (1.0 << 20); 138 // 139 // next01() { 140 // WyF3.numberBufferView.setBigUint64(0, this.next(), true); 141 // let r = WyF3.numberBufferView.getFloat64(0, true); 142 // return (r >> 12) * WyF3Rand.NORM_01; 143 // } 144 // 145 // nextGaussian() { 146 // WyF3.numberBufferView.setBigUint64(0, this.next(), true); 147 // let r = WyF3.numberBufferView.getBigUint64(0, true); 148 // WyF3.numberBufferView.setBigUint64(0, (r & 0x1fffffn) + ((r >> 21n) & 0x1fffffn) + ((r >> 42n) & 0x1fffffn), true); 149 // return WyF3.numberBufferView.getFloat64(0, true) * WyF3Rand.GAUSSIAN_NORM 150 // // return ((r & 0x1fffff) + ((r >> 21) & 0x1fffff) + ((r >> 42) & 0x1fffff)) * WyF3Rand.GAUSSIAN_NORM - 3.0; 151 // } 152 }