Skip to content

Commit

Permalink
Increase test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmillr committed Dec 21, 2024
1 parent 502e6d3 commit 41047d4
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 7 deletions.
7 changes: 6 additions & 1 deletion src/_md.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ import { Hash, createView, Input, toBytes } from './utils.js';
/**
* Polyfill for Safari 14
*/
function setBigUint64(view: DataView, byteOffset: number, value: bigint, isLE: boolean): void {
export function setBigUint64(
view: DataView,
byteOffset: number,
value: bigint,
isLE: boolean
): void {
if (typeof view.setBigUint64 === 'function') return view.setBigUint64(byteOffset, value, isLE);
const _32n = BigInt(32);
const _u32_max = BigInt(0xffffffff);
Expand Down
4 changes: 2 additions & 2 deletions src/blake2s.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ export const B2S_IV = /* @__PURE__ */ new Uint32Array([
]);

// Mixing function G splitted in two halfs
function G1s(a: number, b: number, c: number, d: number, x: number) {
export function G1s(a: number, b: number, c: number, d: number, x: number) {
a = (a + b + x) | 0;
d = rotr(d ^ a, 16);
c = (c + d) | 0;
b = rotr(b ^ c, 12);
return { a, b, c, d };
}

function G2s(a: number, b: number, c: number, d: number, x: number) {
export function G2s(a: number, b: number, c: number, d: number, x: number) {
a = (a + b + x) | 0;
d = rotr(d ^ a, 8);
c = (c + d) | 0;
Expand Down
35 changes: 32 additions & 3 deletions test/argon2.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { deepStrictEqual } = require('assert');
const { deepStrictEqual, throws } = require('assert');
const { describe, should } = require('micro-should');
const { argon2i, argon2d, argon2id } = require('../argon2');
const { argon2iAsync, argon2dAsync, argon2idAsync } = require('../argon2');
Expand All @@ -9,7 +9,7 @@ const asyncMap = new Map([
[argon2d, argon2dAsync],
[argon2id, argon2idAsync],
]);

const IGNORE_SLOW = false;
const VECTORS = [
{
fn: argon2i,
Expand Down Expand Up @@ -342,9 +342,38 @@ const VECTORS = [
salt: 'diffsalt',
exp: 'bdf32b05ccc42eb15d58fd19b1f856b113da1e9a5874fdcc544308565aa8141c',
},
].filter((i) => !!i);
].filter((i) => !!i && (!IGNORE_SLOW || i.m <= 256));

describe('Argon2', () => {
should('types', async () => {
const opt = {
t: 2,
m: 256,
p: 1,
};
argon2id('password', 'diffsalt', opt);
throws(() => argon2id('password', 'diffsalt', { ...opt, p: 0 }));
throws(() => argon2id('password', 'diffsalt', { ...opt, p: true }));
throws(() => argon2id('password', 'diffsalt', { ...opt, t: 0 }));
throws(() => argon2id('password', 'diffsalt', { ...opt, t: true }));
throws(() => argon2id('password', 'diffsalt', { ...opt, onProgress: true }));
throws(() => argon2id('password', 'salt', opt));
throws(() => argon2id('password', 'diffsalt', { ...opt, maxmem: 1 }));
throws(() => argon2id('password', 'diffsalt', { ...opt, maxmem: true }));
throws(() => argon2id('password', 'diffsalt', { ...opt, dkLen: 0 }));
throws(() => argon2id('password', 'diffsalt', { ...opt, m: true }));
throws(() => argon2id('password', 'diffsalt', { ...opt, m: 1 }));
throws(() => argon2id('password', true, opt));
throws(() => argon2id(true, 'diffsalt', opt));
const t = [];
await argon2idAsync('password', 'diffsalt', {
...opt,
onProgress: (p) => {
t.push(p);
},
});
deepStrictEqual(t.length !== 0, true);
});
for (let i = 0; i < VECTORS.length; i++) {
const v = VECTORS[i];
const ver = v.version || 0x13;
Expand Down
2 changes: 2 additions & 0 deletions test/blake.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ describe('blake', () => {
should(`BLAKE2s: key`, () => {
for (const key of TYPE_TEST.bytes) throws(() => blake2s.fn('data', { key }));
throws(() => blake2s.fn('data', { key: new Uint8Array(33) }));
throws(() => blake2s.fn('data', { key: new Uint8Array(0) }));
});

should(`BLAKE2b: key`, () => {
for (const key of TYPE_TEST.bytes) throws(() => blake2b.fn('data', { key }));
throws(() => blake2b.fn('data', { key: new Uint8Array(65) }));
throws(() => blake2b.fn('data', { key: new Uint8Array(0) }));
});

should(`BLAKE2s: personalization/salt`, () => {
Expand Down
36 changes: 35 additions & 1 deletion test/eskdf.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { equal, rejects, throws } = require('assert');
const { equal, rejects, throws, deepStrictEqual } = require('assert');
const { describe, should } = require('micro-should');
const { eskdf } = require('../eskdf');
const { bytesToHex: toHex } = require('../utils');
Expand Down Expand Up @@ -46,6 +46,40 @@ describe('eskdf', () => {
throws(() => e.deriveChildKey('aes', 0, { keyLength: 64, modulus: BigInt(65537) }));
});
}
should('types', async () => {
const keyc = await eskdf('[email protected]', 'test2test');
deepStrictEqual(
toHex(keyc.deriveChildKey('ssh', 'test')),
'3bc39ad06a15d4867aaa53f4025077ecca7cd33b3f5b9da131b50586601726fa'
);
deepStrictEqual(
toHex(keyc.deriveChildKey('ssh', 0)),
'd7b14774e815d429e75b5f366b0df4eff32343e94f1b30a5e12eaab682974667'
);

throws(() => keyc.deriveChildKey('ssh', 'test', { keyLength: 1, modulus: 1 }));
throws(() => keyc.deriveChildKey('ssh', 'test', {}));
deepStrictEqual(
toHex(keyc.deriveChildKey('ssh', 0, { keyLength: 16 })),
'd7b14774e815d429e75b5f366b0df4ef'
);
throws(() => keyc.deriveChildKey('ssh', 'test', { modulus: -1n }));
throws(() => keyc.deriveChildKey('ssh', 'test', { modulus: 1n }));
deepStrictEqual(
toHex(keyc.deriveChildKey('ssh', 0, { modulus: 2n ** 128n - 1n })),
'e75b5f366b0df4f1a285d2d31f46d8f8'
);
throws(() => keyc.deriveChildKey('ssh', ''));
throws(() => keyc.deriveChildKey('ssh', '1'.repeat(256)));
throws(() => keyc.deriveChildKey('tmp', 'test'));
throws(() => keyc.deriveChildKey('ssh', true));
throws(() => keyc.deriveChildKey('ssh', 100n));
throws(() => keyc.deriveChildKey('ssh', new Uint8Array(10)));
// Expire
keyc.expire();
throws(() => keyc.deriveChildKey('ssh', 'test'));
throws(() => keyc.deriveChildKey('ssh', 0));
});
});

// should.run();
Expand Down
11 changes: 11 additions & 0 deletions test/hashes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,17 @@ function init() {
);
});

should('clone', () => {
const exp = hash.fn(BUF_768);
const t = hash.obj();
t.update(BUF_768.subarray(0, 10));
const t2 = t.clone();
t2.update(BUF_768.subarray(10));
deepStrictEqual(t2.digest(), exp);
t.update(BUF_768.subarray(10));
deepStrictEqual(t.digest(), exp);
});

should('partial', () => {
const fnH = hash.fn(BUF_768);
for (let i = 0; i < 256; i++) {
Expand Down
8 changes: 8 additions & 0 deletions test/kdf.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@ describe('scrypt', () => {
await rejects(() => scryptAsync('pwd', 'salt', { ...opt, N: 0 }), `scrypt(N=0)`);
// N==1 -> throws
throws(() => scrypt('pwd', 'salt', { ...opt, N: 1 }), `scrypt(N=1)`);
// on progress callback
throws(() => scrypt('pwd', 'salt', { ...opt, onProgress: true }));
// P = 0
throws(() => scrypt('pwd', 'salt', { ...opt, p: -1 }));
throws(() => scrypt('pwd', 'salt', { ...opt, p: 2 ** 48 }));
// dkLen
throws(() => scrypt('pwd', 'salt', { ...opt, dkLen: -1 }));
throws(() => scrypt('pwd', 'salt', { ...opt, dkLen: 2 ** 48 }));
await rejects(() => scryptAsync('pwd', 'salt', { ...opt, N: 1 }), `scrypt(N=1)`);
for (const t of TYPE_TEST.int) {
for (const k of ['N', 'r', 'p', 'dkLen']) {
Expand Down
105 changes: 105 additions & 0 deletions test/utils.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ const {
bytesToHex,
concatBytes,
hexToBytes,
createView,
isBytes,
randomBytes,
} = require('../utils');
const assert = require('../_assert');
const { sha256 } = require('../sha256');
const { setBigUint64 } = require('../_md');

describe('utils', () => {
const staticHexVectors = [
Expand Down Expand Up @@ -148,6 +154,105 @@ describe('utils etc', () => {
20 21 22 23 24 25`)
);
});
should('setBigUint64', () => {
const t = new Uint8Array(20);
const v = createView(t);
const VECTORS = [
{
n: 123n,
le: false,
hex: '000000000000007b000000000000000000000000',
},
{
n: 123n,
le: true,
hex: '7b00000000000000000000000000000000000000',
},
{
n: 2n ** 64n - 1n,
le: true,
hex: 'ffffffffffffffff000000000000000000000000',
},
{
n: 2n ** 64n - 1n,
le: true,
hex: '000000ffffffffffffffff000000000000000000',
pos: 3,
},
{
n: 0x123456789abcdef0n,
le: true,
hex: 'f0debc9a78563412000000000000000000000000',
},
{
n: 0x123456789abcdef0n,
le: false,
hex: '123456789abcdef0000000000000000000000000',
},
];
const createViewMock = (u8) => {
const v = createView(u8);
return {
setUint32: (o, wh, isLE) => v.setUint32(o, wh, isLE),
};
};

for (const cv of [createView, createViewMock]) {
for (const t of VECTORS) {
const b = new Uint8Array(20);
const v = cv(b);
setBigUint64(v, t.pos || 0, t.n, t.le);
deepStrictEqual(bytesToHex(b), t.hex);
}
}
});
should('randomBytes', () => {
const t = randomBytes(32);
deepStrictEqual(t instanceof Uint8Array, true);
deepStrictEqual(t.length, 32);
const t2 = randomBytes(12);
deepStrictEqual(t2 instanceof Uint8Array, true);
deepStrictEqual(t2.length, 12);
});
should('isBytes', () => {
deepStrictEqual(isBytes(new Uint8Array(0)), true);
deepStrictEqual(isBytes(Buffer.alloc(10)), true);
deepStrictEqual(isBytes(''), false);
deepStrictEqual(isBytes([1, 2, 3]), false);
});
});

describe('assert', () => {
should('anumber', () => {
deepStrictEqual(assert.anumber(10), undefined);
throws(() => assert.anumber(1.2));
throws(() => assert.anumber('1'));
throws(() => assert.anumber(true));
throws(() => assert.anumber(NaN));
});
should('abytes', () => {
deepStrictEqual(assert.abytes(new Uint8Array(0)), undefined);
deepStrictEqual(assert.abytes(Buffer.alloc(10)), undefined);
deepStrictEqual(assert.abytes(new Uint8Array(10)), undefined);
assert.abytes(new Uint8Array(11), 11, 12);
assert.abytes(new Uint8Array(12), 12, 12);
throws(() => assert.abytes('test'));
throws(() => assert.abytes(new Uint8Array(10), 11, 12));
throws(() => assert.abytes(new Uint8Array(10), 11, 12));
});
should('ahash', () => {
deepStrictEqual(assert.ahash(sha256), undefined);
throws(() => assert.ahash({}));
throws(() => assert.ahash({ blockLen: 1, outputLen: 1, create: () => {} }));
});
should('aexists', () => {
deepStrictEqual(assert.aexists({}), undefined);
throws(() => assert.aexists({ destroyed: true }));
});
should('aoutput', () => {
deepStrictEqual(assert.aoutput(new Uint8Array(10), { outputLen: 5 }), undefined);
throws(() => assert.aoutput(new Uint8Array(1), { outputLen: 5 }));
});
});

if (require.main === module) should.run();

0 comments on commit 41047d4

Please sign in to comment.