733ecd2681
Add root Cargo workspace with 9 crates: salvium-crypto (extended), salvium-types, salvium-consensus, salvium-wallet, salvium-tx, salvium-rpc, salvium-miner (extended), salvium-cli, salvium-multisig. New modules: chain_state, block_weight, alt_chain, validation, offline signing, stake lifecycle, wallet sync/query/encryption/utxo, randomx utilities, and full multisig crate with CARROT support. Delete 188 JS test/helper/debug files; archive integration test scripts to test/legacy-js/ for live testnet use. Testnet integration tests (transfer, stake, burn, convert, sweep) remain as #[ignore]- gated Rust tests runnable with --ignored against a live daemon.
249 lines
7.4 KiB
JavaScript
249 lines
7.4 KiB
JavaScript
/**
|
|
* Debug WASM - check state after pass 0
|
|
*/
|
|
|
|
import { blake2b } from '../src/blake2b.js';
|
|
import { readFileSync } from 'fs';
|
|
import { fileURLToPath } from 'url';
|
|
import { dirname, join } from 'path';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
|
|
const ARGON2_BLOCK_SIZE = 1024;
|
|
const ARGON2_PREHASH_DIGEST_LENGTH = 64;
|
|
const ARGON2_PREHASH_SEED_LENGTH = 72;
|
|
const ARGON2_SYNC_POINTS = 4;
|
|
const ARGON2_VERSION = 0x13;
|
|
const RANDOMX_ARGON_MEMORY = 262144;
|
|
const RANDOMX_ARGON_ITERATIONS = 3;
|
|
const RANDOMX_ARGON_LANES = 1;
|
|
const RANDOMX_ARGON_SALT = new TextEncoder().encode("RandomX\x03");
|
|
|
|
function blake2bLong(outLen, input) {
|
|
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 blake2b(prefixed, outLen);
|
|
}
|
|
|
|
const result = new Uint8Array(outLen);
|
|
let v = blake2b(prefixed, 64);
|
|
result.set(v.subarray(0, 32), 0);
|
|
|
|
let pos = 32;
|
|
while (pos < outLen - 64) {
|
|
v = blake2b(v, 64);
|
|
result.set(v.subarray(0, 32), pos);
|
|
pos += 32;
|
|
}
|
|
|
|
const remaining = outLen - pos;
|
|
v = blake2b(v, remaining);
|
|
result.set(v, pos);
|
|
|
|
return result;
|
|
}
|
|
|
|
function initialHash(ctx) {
|
|
const parts = [];
|
|
const addU32 = (val) => {
|
|
const arr = new Uint8Array(4);
|
|
arr[0] = val & 0xff;
|
|
arr[1] = (val >> 8) & 0xff;
|
|
arr[2] = (val >> 16) & 0xff;
|
|
arr[3] = (val >> 24) & 0xff;
|
|
parts.push(arr);
|
|
};
|
|
|
|
addU32(ctx.lanes);
|
|
addU32(ctx.outLen);
|
|
addU32(ctx.mCost);
|
|
addU32(ctx.tCost);
|
|
addU32(ctx.version);
|
|
addU32(ctx.type);
|
|
addU32(ctx.password.length);
|
|
if (ctx.password.length > 0) parts.push(ctx.password);
|
|
addU32(ctx.salt.length);
|
|
if (ctx.salt.length > 0) parts.push(ctx.salt);
|
|
addU32(0);
|
|
addU32(0);
|
|
|
|
let totalLen = 0;
|
|
for (const p of parts) totalLen += p.length;
|
|
const input = new Uint8Array(totalLen);
|
|
let offset = 0;
|
|
for (const p of parts) {
|
|
input.set(p, offset);
|
|
offset += p.length;
|
|
}
|
|
|
|
return blake2b(input, ARGON2_PREHASH_DIGEST_LENGTH);
|
|
}
|
|
|
|
console.log('=== Debug WASM - Check state after pass 0 ===\n');
|
|
|
|
// Load WASM
|
|
const wasmPath = join(__dirname, '../build/randomx.wasm');
|
|
const wasmBuffer = readFileSync(wasmPath);
|
|
|
|
const wasmMemory = new WebAssembly.Memory({
|
|
initial: 4096 + 512,
|
|
maximum: 8192
|
|
});
|
|
|
|
const imports = {
|
|
env: {
|
|
memory: wasmMemory,
|
|
abort: () => {}
|
|
}
|
|
};
|
|
|
|
const { instance } = await WebAssembly.instantiate(wasmBuffer, imports);
|
|
const wasm = instance.exports;
|
|
|
|
// Setup
|
|
const key = new TextEncoder().encode("test key 000");
|
|
const lanes = RANDOMX_ARGON_LANES;
|
|
const memoryBlocks = Math.floor(RANDOMX_ARGON_MEMORY / (ARGON2_BLOCK_SIZE / 1024));
|
|
const segmentLength = Math.floor(memoryBlocks / (lanes * ARGON2_SYNC_POINTS));
|
|
const laneLength = segmentLength * ARGON2_SYNC_POINTS;
|
|
const totalBlocks = lanes * laneLength;
|
|
const totalBytes = totalBlocks * ARGON2_BLOCK_SIZE;
|
|
|
|
// Initialize WASM
|
|
const memPtr = 0;
|
|
wasm.argon2d_init(memPtr, totalBlocks, laneLength, segmentLength);
|
|
|
|
// Create context
|
|
const ctx = {
|
|
password: key,
|
|
salt: RANDOMX_ARGON_SALT,
|
|
tCost: RANDOMX_ARGON_ITERATIONS,
|
|
mCost: RANDOMX_ARGON_MEMORY,
|
|
lanes,
|
|
outLen: 0,
|
|
version: ARGON2_VERSION,
|
|
type: 0
|
|
};
|
|
|
|
// Generate H0
|
|
const blockHash = initialHash(ctx);
|
|
|
|
// Build seed for block 0
|
|
const seed = new Uint8Array(ARGON2_PREHASH_SEED_LENGTH);
|
|
seed.set(blockHash);
|
|
|
|
// Fill first two blocks
|
|
const mem = new Uint8Array(wasmMemory.buffer);
|
|
const tempPtr = totalBytes + 1024;
|
|
|
|
seed[64] = 0; seed[65] = 0; seed[66] = 0; seed[67] = 0;
|
|
seed[68] = 0; seed[69] = 0; seed[70] = 0; seed[71] = 0;
|
|
const block0 = blake2bLong(ARGON2_BLOCK_SIZE, seed);
|
|
mem.set(block0, tempPtr);
|
|
wasm.argon2d_write_block(0, tempPtr);
|
|
|
|
seed[64] = 1;
|
|
const block1 = blake2bLong(ARGON2_BLOCK_SIZE, seed);
|
|
mem.set(block1, tempPtr);
|
|
wasm.argon2d_write_block(1, tempPtr);
|
|
|
|
const wasmView = new DataView(wasmMemory.buffer);
|
|
|
|
console.log('Before pass 0:');
|
|
console.log(' Block 0:', '0x' + wasmView.getBigUint64(0, true).toString(16));
|
|
console.log(' Block 1:', '0x' + wasmView.getBigUint64(1024, true).toString(16));
|
|
console.log(' Block 2:', '0x' + wasmView.getBigUint64(2 * 1024, true).toString(16));
|
|
console.log(' Block 262143:', '0x' + wasmView.getBigUint64(262143 * 1024, true).toString(16));
|
|
|
|
// Run pass 0
|
|
console.log('\nRunning pass 0...');
|
|
for (let slice = 0; slice < ARGON2_SYNC_POINTS; slice++) {
|
|
for (let lane = 0; lane < lanes; lane++) {
|
|
wasm.argon2d_fill_segment(0, lane, slice);
|
|
}
|
|
}
|
|
|
|
console.log('\nAfter pass 0:');
|
|
console.log(' Block 0:', '0x' + wasmView.getBigUint64(0, true).toString(16));
|
|
console.log(' Block 1:', '0x' + wasmView.getBigUint64(1024, true).toString(16));
|
|
console.log(' Block 2:', '0x' + wasmView.getBigUint64(2 * 1024, true).toString(16));
|
|
console.log(' Block 262143:', '0x' + wasmView.getBigUint64(262143 * 1024, true).toString(16));
|
|
|
|
// Run pass 1 slice 0 step by step
|
|
console.log('\n=== Manual trace of pass 1, slice 0, first iteration ===');
|
|
|
|
// In fillSegment for pass=1, lane=0, slice=0:
|
|
// startingIndex = 0 (since not (pass==0 && slice==0))
|
|
// currOffset = 0*laneLength + 0*segmentLength + 0 = 0
|
|
// prevOffset = (0 % laneLength == 0) ? 0 + laneLength - 1 : 0 - 1 = 262143
|
|
|
|
const prevBlockIdx = 262143;
|
|
const currBlockIdx = 0;
|
|
|
|
console.log('prevBlockIdx:', prevBlockIdx);
|
|
console.log('currBlockIdx:', currBlockIdx);
|
|
|
|
// Get pseudo-random from prev block
|
|
const pseudoRand = wasmView.getBigUint64(prevBlockIdx * 1024, true);
|
|
console.log('pseudoRand (from block 262143):', '0x' + pseudoRand.toString(16));
|
|
|
|
// refLane calculation
|
|
const refLane = Number((pseudoRand >> 32n) % 1n);
|
|
console.log('refLane:', refLane);
|
|
|
|
// indexAlpha parameters
|
|
const pass = 1;
|
|
const slice = 0;
|
|
const index = 0;
|
|
const sameLane = true;
|
|
|
|
// For pass != 0, sameLane:
|
|
// referenceAreaSize = laneLength - segmentLength + index - 1 = 262144 - 65536 + 0 - 1 = 196607
|
|
const referenceAreaSize = laneLength - segmentLength + index - 1;
|
|
console.log('referenceAreaSize:', referenceAreaSize);
|
|
|
|
// relativePos calculation
|
|
let relativePos = pseudoRand & 0xFFFFFFFFn;
|
|
relativePos = (relativePos * relativePos) >> 32n;
|
|
relativePos = BigInt(referenceAreaSize) - 1n - ((BigInt(referenceAreaSize) * relativePos) >> 32n);
|
|
console.log('relativePos:', relativePos);
|
|
|
|
// startPosition for pass != 0, slice=0
|
|
// startPosition = (slice == 3) ? 0 : (slice + 1) * segmentLength = (0 == 3) ? 0 : 1 * 65536 = 65536
|
|
const startPosition = 65536;
|
|
console.log('startPosition:', startPosition);
|
|
|
|
const refIndex = (startPosition + Number(relativePos)) % laneLength;
|
|
console.log('refIndex:', refIndex);
|
|
|
|
const refBlockIdx = laneLength * refLane + refIndex;
|
|
console.log('refBlockIdx:', refBlockIdx);
|
|
|
|
// Check what the ref block contains
|
|
console.log('refBlock first qword:', '0x' + wasmView.getBigUint64(refBlockIdx * 1024, true).toString(16));
|
|
|
|
// withXor for pass != 0 and version != 0x10
|
|
const withXor = true;
|
|
console.log('withXor:', withXor);
|
|
|
|
console.log('\n=== Running fill_block ===');
|
|
console.log('fillBlock(prevBlockIdx=262143, refBlockIdx=' + refBlockIdx + ', currBlockIdx=0, withXor=true)');
|
|
|
|
// Save current value for comparison
|
|
const currBefore = wasmView.getBigUint64(0, true);
|
|
console.log('currBlock before:', '0x' + currBefore.toString(16));
|
|
|
|
// Now run pass 1 slice 0
|
|
wasm.argon2d_fill_segment(1, 0, 0);
|
|
|
|
const currAfter = wasmView.getBigUint64(0, true);
|
|
console.log('currBlock after:', '0x' + currAfter.toString(16));
|
|
console.log('Block 0 changed:', currBefore !== currAfter);
|