140 lines
4.6 KiB
JavaScript
140 lines
4.6 KiB
JavaScript
import * as THREE from "three";
|
||
|
||
|
||
function guidGenerator() {
|
||
var S4 = function() {
|
||
return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
|
||
};
|
||
return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
|
||
}
|
||
|
||
// Pure JS SHA-256 (works in browser or Node)
|
||
// Returns hex string
|
||
function sha256(message) {
|
||
// UTF-8 encode string to bytes
|
||
const msgBytes = new TextEncoder().encode(message);
|
||
|
||
// Constants (first 32 bits of the fractional parts of the cube roots of the first 64 primes)
|
||
const K = new Uint32Array([
|
||
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
|
||
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
|
||
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
|
||
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
|
||
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
|
||
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
|
||
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
|
||
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||
]);
|
||
|
||
// Initial hash values (first 32 bits of the fractional parts of the square roots of the first 8 primes)
|
||
let H = new Uint32Array([
|
||
0x6a09e667,0xbb67ae85,0x3c6ef372,0xa54ff53a,
|
||
0x510e527f,0x9b05688c,0x1f83d9ab,0x5be0cd19
|
||
]);
|
||
|
||
// Pre-processing: padding the message
|
||
const l = msgBytes.length * 8;
|
||
// Append 0x80 then zero bytes, then 64-bit big-endian length
|
||
const k = (512 - ((l + 8 + 64) % 512)) % 512; // number of zero bits
|
||
const totalBits = l + 1 + k + 64;
|
||
const totalBytes = totalBits / 8;
|
||
const padded = new Uint8Array(totalBytes);
|
||
|
||
// copy message
|
||
padded.set(msgBytes);
|
||
|
||
// append 1 bit (0x80)
|
||
padded[msgBytes.length] = 0x80;
|
||
|
||
// append length in bits as 64-bit big-endian integer
|
||
const lenPos = totalBytes - 8;
|
||
for (let i = 0; i < 8; i++) {
|
||
padded[lenPos + 7 - i] = (l >>> (i * 8)) & 0xff;
|
||
}
|
||
|
||
// Process the message in successive 512-bit chunks
|
||
const W = new Uint32Array(64);
|
||
|
||
function ROTR(n, x) { return (x >>> n) | (x << (32 - n)); }
|
||
function Σ0(x) { return ROTR(2,x) ^ ROTR(13,x) ^ ROTR(22,x); }
|
||
function Σ1(x) { return ROTR(6,x) ^ ROTR(11,x) ^ ROTR(25,x); }
|
||
function σ0(x) { return ROTR(7,x) ^ ROTR(18,x) ^ (x >>> 3); }
|
||
function σ1(x) { return ROTR(17,x) ^ ROTR(19,x) ^ (x >>> 10); }
|
||
|
||
for (let chunkStart = 0; chunkStart < padded.length; chunkStart += 64) {
|
||
// prepare message schedule W[0..63]
|
||
for (let i = 0; i < 16; i++) {
|
||
const j = chunkStart + i * 4;
|
||
W[i] = (padded[j] << 24) | (padded[j + 1] << 16) | (padded[j + 2] << 8) | (padded[j + 3]);
|
||
}
|
||
for (let i = 16; i < 64; i++) {
|
||
W[i] = (σ1(W[i - 2]) + W[i - 7] + σ0(W[i - 15]) + W[i - 16]) >>> 0;
|
||
}
|
||
|
||
// initialize working variables
|
||
let a = H[0], b = H[1], c = H[2], d = H[3];
|
||
let e = H[4], f = H[5], g = H[6], h = H[7];
|
||
|
||
for (let t = 0; t < 64; t++) {
|
||
const T1 = (h + Σ1(e) + ((e & f) ^ (~e & g)) + K[t] + W[t]) >>> 0;
|
||
const T2 = (Σ0(a) + ((a & b) ^ (a & c) ^ (b & c))) >>> 0;
|
||
h = g;
|
||
g = f;
|
||
f = e;
|
||
e = (d + T1) >>> 0;
|
||
d = c;
|
||
c = b;
|
||
b = a;
|
||
a = (T1 + T2) >>> 0;
|
||
}
|
||
|
||
// compute intermediate hash value
|
||
H[0] = (H[0] + a) >>> 0;
|
||
H[1] = (H[1] + b) >>> 0;
|
||
H[2] = (H[2] + c) >>> 0;
|
||
H[3] = (H[3] + d) >>> 0;
|
||
H[4] = (H[4] + e) >>> 0;
|
||
H[5] = (H[5] + f) >>> 0;
|
||
H[6] = (H[6] + g) >>> 0;
|
||
H[7] = (H[7] + h) >>> 0;
|
||
}
|
||
|
||
// produce the final hash (big-endian)
|
||
let hex = "";
|
||
for (let i = 0; i < 8; i++) {
|
||
hex += ("00000000" + H[i].toString(16)).slice(-8);
|
||
}
|
||
return hex;
|
||
}
|
||
|
||
function v3Encoder(vec3) { // THREE.Vector3 to Float32Array(3)
|
||
const arr = new Float32Array(3);
|
||
arr[0] = vec3.x;
|
||
arr[1] = vec3.y;
|
||
arr[2] = vec3.z;
|
||
return arr;
|
||
}
|
||
|
||
function v3Decoder(arr) { // Float32Array(3) to THREE.Vector3
|
||
return new THREE.Vector3(arr[0], arr[1], arr[2]);
|
||
}
|
||
|
||
function eulerEncoder(euler) { // THREE.Euler to Float32Array(3)
|
||
const arr = new Float32Array(3);
|
||
arr[0] = euler.x;
|
||
arr[1] = euler.y;
|
||
arr[2] = euler.z;
|
||
return arr;
|
||
}
|
||
|
||
function eulerDecoder(arr) { // Float32Array(3) to THREE.Euler
|
||
return new THREE.Euler(arr[0], arr[1], arr[2]);
|
||
}
|
||
|
||
const encoders = {
|
||
Vector3: { encode: v3Encoder, decode: v3Decoder },
|
||
Euler: { encode: eulerEncoder, decode: eulerDecoder },
|
||
// Add more as needed
|
||
};
|
||
|
||
export { guidGenerator, sha256, encoders }; |