7730b6993f
- Create assembly/vm.ts with full RandomX VM implementation
- 256 instructions, 2048 iterations per hash
- Native u64/f64 operations in WebAssembly
- Full mode dataset lookups (2GB pre-computed)
- Update miner to use WASM VM for full mode
- mining-worker-asm.js uses pre-compiled WASM
- ~32 H/s per thread (4x faster than light mode)
- 8 threads achieves ~260 H/s
- Clean up redundant code
- Remove mining-worker-full.js (old JIT approach)
- Consolidate 'asm' mode into 'full' mode
133 lines
4.4 KiB
JavaScript
133 lines
4.4 KiB
JavaScript
/**
|
|
* Debug Argon2 using @noble/hashes blake2b for comparison
|
|
*/
|
|
|
|
import { blake2b as nobleBlake2b } from '@noble/hashes/blake2.js';
|
|
import { blake2b as myBlake2b } from '../src/blake2b.js';
|
|
|
|
// Helper to convert bytes to hex
|
|
function bytesToHex(bytes) {
|
|
return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
|
|
}
|
|
|
|
// Store 32-bit LE
|
|
function store32LE(value) {
|
|
const bytes = new Uint8Array(4);
|
|
bytes[0] = value & 0xff;
|
|
bytes[1] = (value >> 8) & 0xff;
|
|
bytes[2] = (value >> 16) & 0xff;
|
|
bytes[3] = (value >> 24) & 0xff;
|
|
return bytes;
|
|
}
|
|
|
|
console.log('=== Compare Blake2b implementations ===\n');
|
|
|
|
// Test 1: Empty input
|
|
const emptyMy = myBlake2b(new Uint8Array(0), 64);
|
|
const emptyNoble = nobleBlake2b(new Uint8Array(0), { dkLen: 64 });
|
|
console.log('Empty input (my impl): ', bytesToHex(emptyMy));
|
|
console.log('Empty input (noble): ', bytesToHex(emptyNoble));
|
|
console.log('Match:', bytesToHex(emptyMy) === bytesToHex(emptyNoble));
|
|
console.log();
|
|
|
|
// Test 2: "abc"
|
|
const abc = new TextEncoder().encode("abc");
|
|
const abcMy = myBlake2b(abc, 64);
|
|
const abcNoble = nobleBlake2b(abc, { dkLen: 64 });
|
|
console.log('abc (my impl): ', bytesToHex(abcMy));
|
|
console.log('abc (noble): ', bytesToHex(abcNoble));
|
|
console.log('Match:', bytesToHex(abcMy) === bytesToHex(abcNoble));
|
|
console.log();
|
|
|
|
// Test 3: Build H0 input and compare
|
|
const key = new TextEncoder().encode("test key 000");
|
|
const salt = new Uint8Array([0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x58, 0x03]);
|
|
|
|
const h0Input = new Uint8Array(60);
|
|
let offset = 0;
|
|
h0Input.set(store32LE(1), offset); offset += 4; // lanes
|
|
h0Input.set(store32LE(0), offset); offset += 4; // outLen
|
|
h0Input.set(store32LE(262144), offset); offset += 4; // mCost
|
|
h0Input.set(store32LE(3), offset); offset += 4; // tCost
|
|
h0Input.set(store32LE(0x13), offset); offset += 4; // version
|
|
h0Input.set(store32LE(0), offset); offset += 4; // type
|
|
h0Input.set(store32LE(key.length), offset); offset += 4; // pwdLen
|
|
h0Input.set(key, offset); offset += key.length; // pwd
|
|
h0Input.set(store32LE(salt.length), offset); offset += 4; // saltLen
|
|
h0Input.set(salt, offset); offset += salt.length; // salt
|
|
h0Input.set(store32LE(0), offset); offset += 4; // secretLen
|
|
h0Input.set(store32LE(0), offset); offset += 4; // adLen
|
|
|
|
console.log('H0 input:', bytesToHex(h0Input));
|
|
console.log();
|
|
|
|
const h0My = myBlake2b(h0Input, 64);
|
|
const h0Noble = nobleBlake2b(h0Input, { dkLen: 64 });
|
|
console.log('H0 (my impl): ', bytesToHex(h0My));
|
|
console.log('H0 (noble): ', bytesToHex(h0Noble));
|
|
console.log('Match:', bytesToHex(h0My) === bytesToHex(h0Noble));
|
|
console.log();
|
|
|
|
// Now test blake2b_long using noble's implementation
|
|
console.log('=== Test blake2b_long ===\n');
|
|
|
|
function blake2bLongNoble(outLen, input) {
|
|
// Prefix with output length as 32-bit LE
|
|
const prefixed = new Uint8Array(4 + input.length);
|
|
prefixed[0] = outLen & 0xff;
|
|
prefixed[1] = (outLen >> 8) & 0xff;
|
|
prefixed[2] = (outLen >> 16) & 0xff;
|
|
prefixed[3] = (outLen >> 24) & 0xff;
|
|
prefixed.set(input, 4);
|
|
|
|
if (outLen <= 64) {
|
|
return nobleBlake2b(prefixed, { dkLen: outLen });
|
|
}
|
|
|
|
const result = new Uint8Array(outLen);
|
|
|
|
// First block
|
|
let v = nobleBlake2b(prefixed, { dkLen: 64 });
|
|
result.set(v.subarray(0, 32), 0);
|
|
|
|
let pos = 32;
|
|
while (pos < outLen - 64) {
|
|
v = nobleBlake2b(v, { dkLen: 64 });
|
|
result.set(v.subarray(0, 32), pos);
|
|
pos += 32;
|
|
}
|
|
|
|
// Final block
|
|
const remaining = outLen - pos;
|
|
v = nobleBlake2b(v, { dkLen: remaining });
|
|
result.set(v, pos);
|
|
|
|
return result;
|
|
}
|
|
|
|
// Build seed for first block (H0 || 0 || 0)
|
|
const seed = new Uint8Array(72);
|
|
seed.set(h0Noble); // Use noble's H0
|
|
seed.set(store32LE(0), 64); // position = 0
|
|
seed.set(store32LE(0), 68); // lane = 0
|
|
|
|
console.log('Seed (H0||0||0):', bytesToHex(seed));
|
|
console.log();
|
|
|
|
const block0Noble = blake2bLongNoble(1024, seed);
|
|
console.log('Block 0 first 64 bytes (noble):', bytesToHex(block0Noble.slice(0, 64)));
|
|
|
|
// Read first qword
|
|
function readLE64(bytes, offset) {
|
|
let val = 0n;
|
|
for (let i = 0; i < 8; i++) {
|
|
val |= BigInt(bytes[offset + i]) << BigInt(i * 8);
|
|
}
|
|
return val;
|
|
}
|
|
|
|
const cacheMemory0Noble = readLE64(block0Noble, 0);
|
|
console.log('cacheMemory[0] (noble):', '0x' + cacheMemory0Noble.toString(16));
|
|
console.log('Expected: ', '0x191e0e1d23c02186');
|
|
console.log('Match:', cacheMemory0Noble === 0x191e0e1d23c02186n);
|