3658a0c33f
- generateSeed() - Cryptographically secure random seed generation - deriveKeys() - CryptoNote key derivation (spend/view secret & public keys) - deriveCarrotKeys() - CARROT key derivation (all 6 CARROT keys) - Blake2b tests with RFC 7693 test vectors - CryptoNote key derivation tests - CARROT key derivation tests - Updated exports in index.js
266 lines
8.2 KiB
JavaScript
266 lines
8.2 KiB
JavaScript
/**
|
|
* Blake2b Tests
|
|
*
|
|
* Tests for Blake2b hash function with RFC 7693 test vectors.
|
|
*/
|
|
|
|
import { blake2b, blake2bHex } from '../src/blake2b.js';
|
|
import { bytesToHex, hexToBytes } from '../src/index.js';
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
function test(name, fn) {
|
|
try {
|
|
fn();
|
|
console.log(` ✓ ${name}`);
|
|
passed++;
|
|
} catch (error) {
|
|
console.log(` ✗ ${name}`);
|
|
console.log(` Error: ${error.message}`);
|
|
failed++;
|
|
}
|
|
}
|
|
|
|
function assertEqual(actual, expected, message = '') {
|
|
if (actual !== expected) {
|
|
throw new Error(`${message} Expected "${expected}", got "${actual}"`);
|
|
}
|
|
}
|
|
|
|
function assertLength(value, length, message = '') {
|
|
if (value.length !== length) {
|
|
throw new Error(`${message} Expected length ${length}, got ${value.length}`);
|
|
}
|
|
}
|
|
|
|
function assertTrue(value, message = '') {
|
|
if (!value) {
|
|
throw new Error(`${message} Expected true, got ${value}`);
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// RFC 7693 Test Vectors
|
|
// ============================================================
|
|
|
|
console.log('\n--- RFC 7693 Test Vectors ---');
|
|
|
|
// From RFC 7693 Appendix A (empty input, 64-byte output, no key)
|
|
test('Empty input, 64-byte output (RFC 7693)', () => {
|
|
const hash = blake2b(new Uint8Array(0), 64);
|
|
const expected = '786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce';
|
|
assertEqual(bytesToHex(hash), expected);
|
|
});
|
|
|
|
// From RFC 7693 Appendix A ("abc", 64-byte output, no key)
|
|
test('"abc" input, 64-byte output (RFC 7693)', () => {
|
|
const input = new TextEncoder().encode('abc');
|
|
const hash = blake2b(input, 64);
|
|
const expected = 'ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923';
|
|
assertEqual(bytesToHex(hash), expected);
|
|
});
|
|
|
|
// ============================================================
|
|
// Variable Output Length Tests
|
|
// ============================================================
|
|
|
|
console.log('\n--- Variable Output Length Tests ---');
|
|
|
|
test('blake2b returns correct length for 32 bytes', () => {
|
|
const hash = blake2b(new Uint8Array(0), 32);
|
|
assertLength(hash, 32);
|
|
});
|
|
|
|
test('blake2b returns correct length for 64 bytes', () => {
|
|
const hash = blake2b(new Uint8Array(0), 64);
|
|
assertLength(hash, 64);
|
|
});
|
|
|
|
test('blake2b returns correct length for 1 byte', () => {
|
|
const hash = blake2b(new Uint8Array(0), 1);
|
|
assertLength(hash, 1);
|
|
});
|
|
|
|
test('blake2b throws for output length 0', () => {
|
|
let threw = false;
|
|
try {
|
|
blake2b(new Uint8Array(0), 0);
|
|
} catch (e) {
|
|
threw = true;
|
|
}
|
|
assertTrue(threw, 'Should throw for output length 0');
|
|
});
|
|
|
|
test('blake2b throws for output length > 64', () => {
|
|
let threw = false;
|
|
try {
|
|
blake2b(new Uint8Array(0), 65);
|
|
} catch (e) {
|
|
threw = true;
|
|
}
|
|
assertTrue(threw, 'Should throw for output length 65');
|
|
});
|
|
|
|
// ============================================================
|
|
// Determinism Tests
|
|
// ============================================================
|
|
|
|
console.log('\n--- Determinism Tests ---');
|
|
|
|
test('blake2b is deterministic', () => {
|
|
const input = new Uint8Array([1, 2, 3, 4, 5]);
|
|
const h1 = blake2b(input, 32);
|
|
const h2 = blake2b(input, 32);
|
|
assertEqual(bytesToHex(h1), bytesToHex(h2));
|
|
});
|
|
|
|
test('blake2b produces different output for different input', () => {
|
|
const input1 = new Uint8Array([1, 2, 3]);
|
|
const input2 = new Uint8Array([1, 2, 4]);
|
|
const h1 = blake2b(input1, 32);
|
|
const h2 = blake2b(input2, 32);
|
|
assertTrue(bytesToHex(h1) !== bytesToHex(h2));
|
|
});
|
|
|
|
test('blake2b produces different output for different lengths', () => {
|
|
const input = new Uint8Array([1, 2, 3]);
|
|
const h32 = blake2b(input, 32);
|
|
const h64 = blake2b(input, 64);
|
|
// First 32 bytes should NOT be the same (different output length affects computation)
|
|
assertTrue(bytesToHex(h32) !== bytesToHex(h64).substring(0, 64));
|
|
});
|
|
|
|
// ============================================================
|
|
// Keyed Hashing Tests
|
|
// ============================================================
|
|
|
|
console.log('\n--- Keyed Hashing Tests ---');
|
|
|
|
test('blake2b with key returns different result than without', () => {
|
|
const input = new TextEncoder().encode('test');
|
|
const key = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]);
|
|
const h1 = blake2b(input, 32);
|
|
const h2 = blake2b(input, 32, key);
|
|
assertTrue(bytesToHex(h1) !== bytesToHex(h2));
|
|
});
|
|
|
|
test('blake2b with key is deterministic', () => {
|
|
const input = new TextEncoder().encode('test');
|
|
const key = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
|
|
const h1 = blake2b(input, 32, key);
|
|
const h2 = blake2b(input, 32, key);
|
|
assertEqual(bytesToHex(h1), bytesToHex(h2));
|
|
});
|
|
|
|
test('blake2b with different keys produces different output', () => {
|
|
const input = new TextEncoder().encode('test');
|
|
const key1 = new Uint8Array([1, 2, 3, 4]);
|
|
const key2 = new Uint8Array([1, 2, 3, 5]);
|
|
const h1 = blake2b(input, 32, key1);
|
|
const h2 = blake2b(input, 32, key2);
|
|
assertTrue(bytesToHex(h1) !== bytesToHex(h2));
|
|
});
|
|
|
|
test('blake2b throws for key > 64 bytes', () => {
|
|
let threw = false;
|
|
try {
|
|
blake2b(new Uint8Array(0), 32, new Uint8Array(65));
|
|
} catch (e) {
|
|
threw = true;
|
|
}
|
|
assertTrue(threw, 'Should throw for key > 64 bytes');
|
|
});
|
|
|
|
test('blake2b accepts 64-byte key', () => {
|
|
const key = new Uint8Array(64);
|
|
for (let i = 0; i < 64; i++) key[i] = i;
|
|
const hash = blake2b(new TextEncoder().encode('test'), 32, key);
|
|
assertLength(hash, 32);
|
|
});
|
|
|
|
// ============================================================
|
|
// blake2bHex Tests
|
|
// ============================================================
|
|
|
|
console.log('\n--- blake2bHex Tests ---');
|
|
|
|
test('blake2bHex returns hex string', () => {
|
|
const hash = blake2bHex(new TextEncoder().encode('test'), 32);
|
|
assertEqual(typeof hash, 'string');
|
|
assertLength(hash, 64); // 32 bytes = 64 hex chars
|
|
});
|
|
|
|
test('blake2bHex matches bytesToHex of blake2b', () => {
|
|
const input = new TextEncoder().encode('hello');
|
|
const hashBytes = blake2b(input, 32);
|
|
const hashHex = blake2bHex(input, 32);
|
|
assertEqual(hashHex, bytesToHex(hashBytes));
|
|
});
|
|
|
|
// ============================================================
|
|
// Large Input Tests
|
|
// ============================================================
|
|
|
|
console.log('\n--- Large Input Tests ---');
|
|
|
|
test('blake2b handles input larger than block size (128 bytes)', () => {
|
|
const input = new Uint8Array(256);
|
|
for (let i = 0; i < 256; i++) input[i] = i & 0xff;
|
|
const hash = blake2b(input, 32);
|
|
assertLength(hash, 32);
|
|
});
|
|
|
|
test('blake2b handles input exactly one block (128 bytes)', () => {
|
|
const input = new Uint8Array(128);
|
|
for (let i = 0; i < 128; i++) input[i] = i;
|
|
const hash = blake2b(input, 32);
|
|
assertLength(hash, 32);
|
|
});
|
|
|
|
test('blake2b handles input of multiple blocks', () => {
|
|
const input = new Uint8Array(512);
|
|
for (let i = 0; i < 512; i++) input[i] = i & 0xff;
|
|
const hash = blake2b(input, 32);
|
|
assertLength(hash, 32);
|
|
});
|
|
|
|
// ============================================================
|
|
// Additional Test Vectors (from other implementations)
|
|
// ============================================================
|
|
|
|
console.log('\n--- Additional Test Vectors ---');
|
|
|
|
// Empty input, 32-byte output
|
|
test('Empty input, 32-byte output', () => {
|
|
const hash = blake2b(new Uint8Array(0), 32);
|
|
const expected = '0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8';
|
|
assertEqual(bytesToHex(hash), expected);
|
|
});
|
|
|
|
// Test with sequential bytes
|
|
test('Sequential byte input (0-255)', () => {
|
|
const input = new Uint8Array(256);
|
|
for (let i = 0; i < 256; i++) input[i] = i;
|
|
const hash = blake2b(input, 64);
|
|
// This should produce a consistent output (determinism check)
|
|
assertLength(hash, 64);
|
|
assertTrue(bytesToHex(hash).length === 128);
|
|
});
|
|
|
|
// ============================================================
|
|
// Summary
|
|
// ============================================================
|
|
|
|
console.log('\n--- Blake2b Test Summary ---');
|
|
console.log(`Passed: ${passed}`);
|
|
console.log(`Failed: ${failed}`);
|
|
console.log(`Total: ${passed + failed}`);
|
|
|
|
if (failed > 0) {
|
|
console.log('\n⚠️ Some tests failed!');
|
|
process.exit(1);
|
|
} else {
|
|
console.log('\n✓ All blake2b tests passed!');
|
|
}
|