feat: Implement LiteHashDRBG and RNG utilities

- Added BytesLike type for handling various byte representations.
- Implemented LiteHashDRBG class for SHA-512 based deterministic random bit generator.
- Created RNG interface defining methods for random number generation.
- Developed RandUtil class providing utility functions for RNG operations.
- Added conversion functions for BytesLike to ArrayBuffer and Uint8Array.
- Implemented comprehensive tests for RNG functionality and expected behaviors.
- Configured Vitest for testing environment setup.
This commit is contained in:
2025-12-27 04:45:59 +00:00
parent 206aa64c64
commit b3875a111f
12 changed files with 1751 additions and 5 deletions
-3
View File
@@ -6,9 +6,6 @@
# TODO: where does this rule come from?
docs/_book
# TODO: where does this rule come from?
test/
# ---> Node
# Logs
logs
+10 -1
View File
@@ -8,6 +8,15 @@
"build": "tsc -p tsconfig.json",
"dev": "node -e \"console.log('dev not configured')\"",
"lint": "node -e \"console.log('lint not configured')\"",
"test": "node -e \"console.log('test not configured')\""
"test": "vitest run --config vitest.config.ts"
},
"dependencies": {
"js-sha512": "^0.8.0"
},
"devDependencies": {
"chai": "^4.3.10",
"chai-bytes": "^0.1.2",
"lodash-es": "^4.17.21",
"vitest": "^2.0.5"
}
}
+6
View File
@@ -2,3 +2,9 @@ export * from './domain/entities';
export * from './ports/rng';
export * from './ports/world';
export * from './triggers';
export * from './util/BytesLike';
export * from './util/convertBytesLikeToArrayBuffer';
export * from './util/convertBytesLikeToUint8Array';
export * from './util/LiteHashDRBG';
export * from './util/RNG';
export * from './util/RandUtil';
+2
View File
@@ -0,0 +1,2 @@
export type Bytes = ArrayBuffer | DataView | Uint8Array;
export type BytesLike = Bytes | string;
+234
View File
@@ -0,0 +1,234 @@
import type { RNG } from './RNG';
import { sha512 } from 'js-sha512';
import { convertBytesLikeToUint8Array } from './convertBytesLikeToUint8Array';
import type { BytesLike } from './BytesLike';
const maxRngSupportBit = 53;
const maxInt = 0x1f_ffff_ffff_ffff; // NOTE: b 0, 10000110011, 11...11
const maxIntMore1 = 0x20_0000_0000_0000n; //NOTE: b 0, 10000110100, 00...00
const maxIntMore1f = Number(maxIntMore1);
export const bufferByteSize = 512 / 8; //SHA512
const intBitMapMask = new Map([
[0x1n, 1],
[0x3n, 2],
[0x7n, 3],
[0xfn, 4],
[0x1fn, 5],
[0x3fn, 6],
[0x7fn, 7],
[0xffn, 8],
[0x1ffn, 9],
[0x3ffn, 10],
[0x7ffn, 11],
[0xfffn, 12],
[0x1fffn, 13],
[0x3fffn, 14],
[0x7fffn, 15],
[0xffffn, 16],
[0x1ffffn, 17],
[0x3ffffn, 18],
[0x7ffffn, 19],
[0xfffffn, 20],
[0x1fffffn, 21],
[0x3fffffn, 22],
[0x7fffffn, 23],
[0xffffffn, 24],
[0x1ffffffn, 25],
[0x3ffffffn, 26],
[0x7ffffffn, 27],
[0xfffffffn, 28],
[0x1fffffffn, 29],
[0x3fffffffn, 30],
[0x7fffffffn, 31],
[0xffffffffn, 32],
[0x1ffffffffn, 33],
[0x3ffffffffn, 34],
[0x7ffffffffn, 35],
[0xfffffffffn, 36],
[0x1fffffffffn, 37],
[0x3fffffffffn, 38],
[0x7fffffffffn, 39],
[0xffffffffffn, 40],
[0x1ffffffffffn, 41],
[0x3ffffffffffn, 42],
[0x7ffffffffffn, 43],
[0xfffffffffffn, 44],
[0x1fffffffffffn, 45],
[0x3fffffffffffn, 46],
[0x7fffffffffffn, 47],
[0xffffffffffffn, 48],
[0x1ffffffffffffn, 49],
[0x3ffffffffffffn, 50],
[0x7ffffffffffffn, 51],
[0xfffffffffffffn, 52],
[0x1fffffffffffffn, 53],
]);
function calcBitMask(n: bigint): bigint {
n |= n >> 1n;
n |= n >> 2n;
n |= n >> 4n;
n |= n >> 8n;
n |= n >> 16n;
n |= n >> 32n;
return n;
}
// SHA-512 기반 DRBG 구현
export class LiteHashDRBG implements RNG {
protected buffer!: ArrayBuffer;
protected bufferIdx!: number;
protected hq: DataView;
protected hqIdxPos: number;
public constructor(protected seed: BytesLike, protected stateIdx = 0, bufferIdx = 0) {
if (bufferIdx < 0) {
throw new Error(`bufferIdx ${bufferIdx} < 0`);
}
if (bufferIdx >= bufferByteSize) {
throw new Error(`bufferidx ${bufferIdx} >= ${bufferByteSize}`);
}
if (stateIdx < 0) {
throw new Error(`stateIdx ${stateIdx} < 0`);
}
const seedU8 = convertBytesLikeToUint8Array(seed);
const hqBuffer = new ArrayBuffer(seedU8.byteLength + 4);
const hqU8 = new Uint8Array(hqBuffer);
hqU8.set(seedU8, 0);
this.hq = new DataView(hqBuffer);
this.hqIdxPos = seedU8.byteLength;
this.genNextBlock();
this.bufferIdx = bufferIdx;
}
protected genNextBlock(): void {
this.hq.setUint32(this.hqIdxPos, this.stateIdx, true);
const digest = sha512.arrayBuffer(this.hq.buffer);
this.buffer = digest;
this.bufferIdx = 0;
this.stateIdx += 1;
}
public getMaxInt(): number {
return maxInt;
}
public nextBytes(bytes: number, baseBytes?: number): Uint8Array {
bytes |= 0;
if (bytes <= 0) {
throw new Error(`${bytes} <= 0`);
}
if (this.bufferIdx + bytes <= bufferByteSize) {
if (baseBytes === undefined || bytes >= baseBytes) {
const result = this.buffer.slice(this.bufferIdx, this.bufferIdx + bytes);
this.bufferIdx += bytes;
if (this.bufferIdx === bufferByteSize) {
this.genNextBlock();
}
return new Uint8Array(result);
}
const resultBuffer = new ArrayBuffer(Math.max(bytes, baseBytes));
const result = new Uint8Array(resultBuffer);
result.set(new Uint8Array(this.buffer, this.bufferIdx, bytes));
this.bufferIdx += bytes;
if (this.bufferIdx === bufferByteSize) {
this.genNextBlock();
}
return result;
}
const resultBuffer = new ArrayBuffer(baseBytes ? Math.max(bytes, baseBytes) : bytes);
const result = new Uint8Array(resultBuffer);
result.set(new Uint8Array(this.buffer, this.bufferIdx));
let offset = bufferByteSize - this.bufferIdx;
let remain = bytes - offset;
while (remain > bufferByteSize) {
this.genNextBlock();
result.set(new Uint8Array(this.buffer), offset);
offset += bufferByteSize;
remain -= bufferByteSize;
}
this.genNextBlock();
if (remain === 0) {
return result;
}
result.set(new Uint8Array(this.buffer, 0, remain), offset);
this.bufferIdx = remain;
return result;
}
public nextBits(bits: number, baseBytes?: number): Uint8Array {
bits |= 0;
const bytes = (bits + 7) >> 3;
const headBits = bits & 0x7;
const result = this.nextBytes(bytes, baseBytes);
if (headBits === 0) {
return result;
}
result[bytes - 1] &= 0xff >> (8 - headBits);
return result;
}
protected _nextInt(bits: number): bigint {
const buffer = this.nextBits(bits, 8);
const dataView = new DataView(buffer.buffer);
return dataView.getBigUint64(0, true);
}
public nextInt(max?: number): number {
if (max === undefined || max === maxInt) {
return Number(this._nextInt(maxRngSupportBit));
}
if (max > maxInt) {
throw new Error('Over max int');
}
if (max === 0) {
return 0;
}
if (max < 0) {
return -this.nextInt(-max);
}
const mask = calcBitMask(BigInt(max));
const bits = intBitMapMask.get(mask) as number;
let n = Number(this._nextInt(bits));
while (n > max) {
n = Number(this._nextInt(bits));
}
return n;
}
public nextFloat1(): number {
// eslint-disable-next-line no-constant-condition
while (true) {
const nInt = this._nextInt(maxRngSupportBit + 1);
if (nInt < maxIntMore1) {
return Number(nInt) / maxIntMore1f;
}
if (nInt === maxIntMore1) {
return 1;
}
}
}
public static build(seed: BytesLike, stateIdx = 0): LiteHashDRBG {
return new LiteHashDRBG(seed, stateIdx);
}
}
+13
View File
@@ -0,0 +1,13 @@
export interface RNG {
/**
* nextInt()가 반환 가능한 최댓값
*/
getMaxInt(): number;
nextBytes(bytes: number): Uint8Array;
nextBits(bits: number): Uint8Array;
nextInt(max?: number): number;
nextFloat1(): number;
}
+145
View File
@@ -0,0 +1,145 @@
import type { RNG } from './RNG';
// RNG 유틸리티 모음
export class RandUtil {
constructor(protected rng: RNG) {
}
public nextFloat1(): number {
return this.rng.nextFloat1();
}
public nextRange(min: number, max: number): number {
const range = max - min;
return this.nextFloat1() * (range) + min;
}
public nextRangeInt(min: number, max: number): number {
const range = max - min;
return this.rng.nextInt(range) + min;
}
public nextInt(max?: number): number {
return this.rng.nextInt(max);
}
public nextBit(): boolean {
const view = new DataView(this.rng.nextBits(1) as ArrayBufferLike);
return view.getUint8(0) != 0;
}
public nextBool(prob = 0.5): boolean {
if (prob >= 1) {
return true;
}
if (prob === 0.5) {
return this.nextBit();
}
if (prob <= 0) {
return false;
}
return this.nextFloat1() < prob;
}
public shuffle<T>(srcArray: T[]): T[] {
const cnt = srcArray.length;
if (cnt === 0) {
return [];
}
if (cnt > this.rng.getMaxInt()) {
throw 'Invalid random int range';
}
const result: T[] = Array.from(srcArray);
for (let srcIdx = 0; srcIdx < cnt; srcIdx += 1) {
const destIdx = this.rng.nextInt(cnt - srcIdx - 1) + srcIdx;
if (srcIdx === destIdx) {
continue;
}
[result[srcIdx], result[destIdx]] = [result[destIdx], result[srcIdx]];
}
return result;
}
//Object는 integer key에 예외가 있어 shuffleAssoc은 없음
public choice<T>(items: T[] | Record<string | number, T> | Set<T>): T {
if (items instanceof Array) {
if (items.length === 0) {
throw new Error('Empty items');
}
const idx = this.rng.nextInt(items.length - 1);
return items[idx];
}
if (items instanceof Set) {
return this.choice(Array.from(items.values()));
}
return items[this.choice(Array.from(Object.keys(items)))];
}
public choiceUsingWeight(items: Record<string | number, number>): string | number {
if (Object.keys(items).length === 0) {
throw new Error('Empty items');
}
let sum = 0;
for (const value of Object.values(items)) {
if (value <= 0) {
continue;
}
sum += value;
}
let rd = this.nextFloat1() * sum;
for (const [item, value] of Object.entries(items)) {
if (value <= 0) {
if (rd <= 0) {
return item;
}
continue;
}
if (rd <= value) {
return item;
}
rd -= value;
}
throw new Error('Unreacheable');
}
public choiceUsingWeightPair<T>(items: [T, number][]): T {
if (items.length === 0) {
throw new Error('Empty items');
}
let sum = 0;
for (const [, value] of items) {
if (value <= 0) {
continue;
}
sum += value;
}
let rd = this.nextFloat1() * sum;
for (const [item, value] of items) {
if (value <= 0) {
if (rd <= 0) {
return item;
}
continue;
}
if (rd <= value) {
return item;
}
rd -= value;
}
throw new Error('Unreacheable');
}
}
@@ -0,0 +1,17 @@
import type { BytesLike } from './BytesLike';
export function convertBytesLikeToArrayBuffer(data: BytesLike, encodeUTF8 = true): ArrayBuffer {
if (data instanceof ArrayBuffer) {
return data;
}
if (data instanceof Uint8Array) {
return data.buffer;
}
if (typeof (data) === 'string') {
if (encodeUTF8) {
return (new TextEncoder()).encode(data).buffer;
}
return new Uint8Array(data.split('').map((s) => s.codePointAt(0) as number)).buffer;
}
return data.buffer;
}
@@ -0,0 +1,17 @@
import type { BytesLike } from './BytesLike';
export function convertBytesLikeToUint8Array(data: BytesLike, encodeUTF8 = true): Uint8Array {
if (data instanceof Uint8Array) {
return data;
}
if (data instanceof ArrayBuffer) {
return new Uint8Array(data);
}
if (typeof (data) === 'string') {
if (encodeUTF8) {
return (new TextEncoder()).encode(data);
}
return new Uint8Array(data.split('').map((s) => s.codePointAt(0) as number));
}
return new Uint8Array(data.buffer);
}
+370
View File
@@ -0,0 +1,370 @@
import chai, { assert } from 'chai';
import chaiBytes from 'chai-bytes';
import { bufferByteSize, LiteHashDRBG } from '../src/util/LiteHashDRBG';
import { RandUtil } from '../src/util/RandUtil';
import { convertBytesLikeToArrayBuffer } from '../src/util/convertBytesLikeToArrayBuffer';
import { convertBytesLikeToUint8Array as toBytes } from '../src/util/convertBytesLikeToUint8Array';
import _ from 'lodash-es';
chai.use(chaiBytes);
type Bytes = ArrayBuffer | DataView | Uint8Array;
type MaybeBytes = Bytes | string;
function fillBlock(body: MaybeBytes, filler: MaybeBytes = '\0', length = bufferByteSize): Uint8Array {
const u8Body = toBytes(body);
const u8Filler = toBytes(filler, false);
if (u8Filler.byteLength < 1) {
throw new Error('filler must have length');
}
const buffer = new Uint8Array(length);
buffer.set(u8Body, 0);
let bufferIdx = u8Body.byteLength;
while (bufferIdx + u8Filler.byteLength < length) {
buffer.set(u8Filler, bufferIdx);
bufferIdx += u8Filler.byteLength;
}
if (bufferIdx < length) {
const slice = new Uint8Array(u8Filler.buffer, u8Filler.byteOffset, length - bufferIdx);
buffer.set(slice, bufferIdx);
}
return buffer;
}
class DummyBlockRNG extends LiteHashDRBG {
private repeatBlockCnt: number;
private repeatBlock: ArrayBuffer[];
public constructor(repeatBlock: MaybeBytes[], stateIdx = 0) {
super('x');
this.repeatBlock = [];
for (const rawBlock of repeatBlock) {
const block = convertBytesLikeToArrayBuffer(rawBlock);
if (block.byteLength !== bufferByteSize) {
throw new Error;
}
this.repeatBlock.push(block);
}
this.repeatBlockCnt = this.repeatBlock.length;
this.stateIdx = stateIdx;
this.bufferIdx = 0;
this.genNextBlock();
}
protected genNextBlock() {
if (!this.repeatBlock) {
return;
}
this.buffer = this.repeatBlock[this.stateIdx];
this.bufferIdx = 0;
this.stateIdx = (this.stateIdx + 1) % this.repeatBlockCnt;
}
}
const fixedKey = 'HelloWorld';
describe('RNGtestDummy', () => {
const rng = new DummyBlockRNG([
fillBlock('', "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff")
]);
it('BasicConvert', () => {
assert.equal(toBytes("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff", false).length, 16);
});
it('SimpleByte', () => {
assert.equalBytes(toBytes("\x00", false), rng.nextBytes(1), 'b1');
assert.equalBytes(toBytes("\x11\x22", false), rng.nextBytes(2), 'b2');
assert.equalBytes(toBytes("\x33\x44\x55", false), rng.nextBytes(3), 'b3');
assert.equalBytes(toBytes("\x66\x77\x88\x99", false), rng.nextBytes(4), 'b4');
});
it('OverflowBlock', () => {
for (const idx in _.range(16)) {
assert.equalBytes(
toBytes("\xaa\xbb\xcc\xdd\xee\xff\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99", false),
rng.nextBytes(16)
);
}
});
it('MultiBlock', () => {
assert.equalBytes(
fillBlock('', "\xaa\xbb\xcc\xdd\xee\xff\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99", bufferByteSize * 2),
rng.nextBytes(bufferByteSize * 2)
);
});
it('bitTest', () => {
assert.equalBytes(toBytes("\x00", false), rng.nextBits(1)); //aa
assert.equalBytes(toBytes("\x01", false), rng.nextBits(1)); //bb
assert.equalBytes(toBytes("\xcc", false), rng.nextBits(8)); //cc
assert.equalBytes(toBytes("\xdd\x02", false), rng.nextBits(10)); //ddee
assert.equalBytes(toBytes("\x7f", false), rng.nextBits(7)); //ff
assert.equalBytes(toBytes("\x00\x11\x22\x33\x44\x55\x06", false), rng.nextBits(53));
});
it('int', () => {
assert.equal(0x77, rng.nextInt(0xff));
assert.equal(0x9988, rng.nextInt((1 << 16) - 1));
assert.equal(0xddccbbaa, rng.nextInt(0xffffffff));
assert.equal(0x0433221100ffee, rng.nextInt());
assert.equal(0x05, rng.nextInt(0x0f)); //55
assert.equal(0x06, rng.nextInt(0x12)); //66
assert.equal(0x08, rng.nextInt(99)); //77(119 -> 7bit) -> 88(136 -> 8bit -> 8)
assert.equal(0x99, rng.nextInt(0x99)); //99
assert.equal(0xaa, rng.nextInt(0xaa)); //aa (fit Max)
});
it('float', () => {
const floatMax = 2 ** 53;
const fa = rng.nextFloat1();
assert.equal(0x1100ffeeddccbb / floatMax, fa);
assert.isTrue(0.5313720384 > fa);
assert.isTrue(0.5313720383 < fa);
const fb = rng.nextFloat1();
assert.equal(0x08776655443322 / floatMax, fb);
});
});
describe('RandUtilDummy', () => {
it('shuffle', () => {
const rng = new DummyBlockRNG([fillBlock('', '\x17\x16\x15\x14\x13\x12\x11\x10')]);
const randUtil = new RandUtil(rng);
/**
* 7, [7,1,2,3,4,5,6,0]
* 6, [7,0,2,3,4,5,6,1]
* 5, [7,0,1,3,4,5,6,2]
* 4, [7,0,1,2,4,5,6,3]
* 3, [7,0,1,2,3,5,6,4]
* 2, [7,0,1,2,3,4,6,5]
* 1, [7,0,1,2,3,4,5,6]
*/
assert.deepEqual(
randUtil.shuffle(Array.from(_.range(8))),
[7, 0, 1, 2, 3, 4, 5, 6]
);
/**
* 0, [0,1,2,3,4,5,6,7,8,9]
* 7, [0,8,2,3,4,5,6,7,1,9]
* 6, [0,8,1,3,4,5,6,7,2,9]
* 5, [0,8,1,2,4,5,6,7,3,9]
* 4, [0,8,1,2,3,5,6,7,4,9]
* 3, [0,8,1,2,3,4,6,7,5,9]
* 2, [0,8,1,2,3,4,5,7,6,9]
* 1, [0,8,1,2,3,4,5,6,7,9]
* 0, [0,8,1,2,3,4,5,6,7,9]
*/
assert.deepEqual(
randUtil.shuffle(Array.from(_.range(10))),
[0, 8, 1, 2, 3, 4, 5, 6, 7, 9]
);
});
const rng = new DummyBlockRNG([fillBlock('', '\x17\x16\x15\x14\x13\x12\x11\x10')]);
const randUtil = new RandUtil(rng);
it('choice', () => {
//0x17(7), 0x16(6)
assert.equal(randUtil.choice([0, 1, 2, 3, 4, 5]), 5);
//0x15(5), Set 순서 유지
assert.equal(randUtil.choice(new Set([5, 3, 1, 2, 8, 0])), 8);
//0x14(4), 정렬 순서상 숫자(소-대) > 문자열(삽입순) > 심볼 순서
assert.equal(randUtil.choice({ c: 'c', a: 'a', b: 'b', 4: 'x', 2: 't', '3': 'q' }), 'c');
});
it('choiceUsingWeight', () => {
//0.6275740099377194 * 38.1 = 23.91
assert.equal(randUtil.choiceUsingWeight({
a: 0.1,
b: 10,
tt: 2,
x: -1,
c: 20,
d: 0,
e: 6
}), 'c');
//0.658946544056166
assert.equal(randUtil.choiceUsingWeightPair([
['xx', 10],
]), 'xx');
//0.6903152783785083 * 27.3 = 18.84560709973328
assert.equal(randUtil.choiceUsingWeightPair([
['e', 10],
['d', 4],
['c', 0.1],
['baba', 0.2],
['q', 9],
['xt', 4]
]), 'q');
});
});
describe('RNGexpectedError', () => {
const rng = new LiteHashDRBG(fixedKey);
it('nextBits0', () => {
assert.throw(() => rng.nextBits(0));
});
it('nextBits-1', () => {
assert.throw(() => rng.nextBits(-1));
});
it('nextBytes0', () => {
assert.throw(() => rng.nextBytes(0));
});
it('nextBytes-1', () => {
assert.throw(() => rng.nextBytes(-1));
});
const randUtil = new RandUtil(rng);
it('utilEmptyChoice', () => {
assert.throw(() => randUtil.choice([]));
});
it('utilEmptyChoiceUsingWeight', () => {
assert.throw(() => randUtil.choiceUsingWeight({}));
});
it('utilEmptyChoiceUsingWeightPair', () => {
assert.throw(() => randUtil.choiceUsingWeightPair([]));
});
});
describe('RNGAcceptable', () => {
const rng = new LiteHashDRBG(fixedKey);
it('RNG', () => {
rng.nextInt(0);
rng.nextInt(2 ** 53 - 1);
rng.nextBytes(65);
rng.nextBits(512);
});
const randUtil = new RandUtil(rng);
it('RandUtil', () => {
randUtil.choice([0, 0, 0]);
randUtil.choiceUsingWeight({
0: 0,
1: -1
});
randUtil.choiceUsingWeightPair([
[0, 0],
[1, 0],
[2, -2]
]);
randUtil.nextBool(1.1);
randUtil.nextBool(-0.1);
randUtil.shuffle([]);
randUtil.shuffle([1]);
randUtil.nextRange(0, 0);
randUtil.nextRangeInt(0, 0);
randUtil.nextRange(1, -1);
randUtil.nextRangeInt(1, -1);
});
it('RNGLong', () => {
const longKey = fixedKey;
for (const _a of _.range(8)) {
longKey.concat(longKey);
}
const rngLong = new LiteHashDRBG(longKey);
for (const _a of _.range(10)) {
rngLong.nextBytes(16);
}
});
});
/* Python TestVector
import hashlib
import struct
fixedKey = 'HelloWorld'.encode('utf-8')
def hash(key, idx):
idxV = struct.pack("<I", idx)
return hashlib.sha512(key + idxV).digest()
for idx in range(5):
print(hash(fixedKey, idx).hex())
*/
describe('RNG', () => {
//JS - PHP 일치 확인 정도로.
const testVector = Buffer.from([
'24d9ccd648556255fd0ee9f5b29918de90617341958b3b354d572167e4dee02b757816a2bbe0b502c52413ffd384381a9d7b4e193df6f4345d6a95e111d661c4',
'2e9264512f6f4b080cf1376b74fab6878ecf4a6e185942d2e5b22cf923885b9952d40601a414225d6901417fd4ce9368ac77e4a63d3fc9b58ab952bb8c33f165',
'8e2ebf5af6283a1b18f4c044c86c20d02be3890613c4cc8b7c6b7b35581263b972a82630df69a9289988422d7c3a9be5edf78d5de16fabd01e5dd4e458068d8a',
'398596047ba547bfe371ec863a3e019ab0dbc4bb3b27e9077685aae4283ff6bbccfd981d92f9358f7efffbb72a940414802d98466d132e2ad0a16a12946d5f47',
'b3606fe9b18c4aa7315e78bb9e47cb51cc4e203fcc2e631f0405c1b872c8e1cb5b6415ea74bbb77fffaaadb002b47cb4f4628dc0709634365b187667f5c708cb',
].join(''), 'hex');
it('bytes', () => {
const rng = new LiteHashDRBG(fixedKey);
let offset = 0;
assert.equalBytes(rng.nextBytes(10), testVector.slice(offset, offset + 10), '1');
offset += 10;
assert.equalBytes(rng.nextBytes(32), testVector.slice(offset, offset + 32), '2');
offset += 32;
assert.equalBytes(rng.nextBytes(1), testVector.slice(offset, offset + 1), '3');
offset += 1;
assert.equalBytes(rng.nextBytes(64), testVector.slice(offset, offset + 64), '4');
offset += 64;
assert.equalBytes(rng.nextBytes(5), testVector.slice(offset, offset + 5), '5');
offset += 5;
const lastA = rng.nextBytes(16, 18);
const lastB = new Uint8Array(18);
lastB.set(testVector.slice(offset, offset + 16));
assert.equalBytes(lastA, lastB);
});
it('bits', () => {
const rng = new LiteHashDRBG(fixedKey);
let offset = 0;
const testBits = [10, 4, 15, 32, 7, 99, 512, 1, 2, 3];
for (const bits of testBits) {
const bytes = Math.ceil(bits / 8);
const A = rng.nextBits(bits);
const B = new Uint8Array(testVector.slice(offset, offset + bytes));
offset += bytes;
if (bits % 8 != 0) {
const bitMask = 0xff >> (8 - (bits % 8));
B[bytes - 1] &= bitMask;
}
assert.equalBytes(A, B);
}
});
it('float', () => {
const rng = new LiteHashDRBG(fixedKey);
const rng2 = new DummyBlockRNG([
new Uint8Array(testVector.slice(bufferByteSize * 0, bufferByteSize * 1)),
new Uint8Array(testVector.slice(bufferByteSize * 1, bufferByteSize * 2)),
new Uint8Array(testVector.slice(bufferByteSize * 2, bufferByteSize * 3)),
new Uint8Array(testVector.slice(bufferByteSize * 3, bufferByteSize * 4)),
new Uint8Array(testVector.slice(bufferByteSize * 4, bufferByteSize * 5)),
]);
for (const idx of _.range(18)) {
assert.equal(rng.nextFloat1(), rng2.nextFloat1(), `float${idx}`);
}
});
});
+9
View File
@@ -0,0 +1,9 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
globals: true,
include: ['test/**/*.test.ts']
}
});
+928 -1
View File
@@ -27,15 +27,467 @@ importers:
packages/common: {}
packages/logic: {}
packages/logic:
dependencies:
js-sha512:
specifier: ^0.8.0
version: 0.8.0
devDependencies:
chai:
specifier: ^4.3.10
version: 4.5.0
chai-bytes:
specifier: ^0.1.2
version: 0.1.2(chai@4.5.0)
lodash-es:
specifier: ^4.17.21
version: 4.17.22
vitest:
specifier: ^2.0.5
version: 2.1.9(@types/node@20.19.27)
tools/build-scripts: {}
packages:
'@esbuild/aix-ppc64@0.21.5':
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [aix]
'@esbuild/android-arm64@0.21.5':
resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [android]
'@esbuild/android-arm@0.21.5':
resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
engines: {node: '>=12'}
cpu: [arm]
os: [android]
'@esbuild/android-x64@0.21.5':
resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
engines: {node: '>=12'}
cpu: [x64]
os: [android]
'@esbuild/darwin-arm64@0.21.5':
resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
engines: {node: '>=12'}
cpu: [arm64]
os: [darwin]
'@esbuild/darwin-x64@0.21.5':
resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
engines: {node: '>=12'}
cpu: [x64]
os: [darwin]
'@esbuild/freebsd-arm64@0.21.5':
resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
engines: {node: '>=12'}
cpu: [arm64]
os: [freebsd]
'@esbuild/freebsd-x64@0.21.5':
resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [freebsd]
'@esbuild/linux-arm64@0.21.5':
resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
engines: {node: '>=12'}
cpu: [arm64]
os: [linux]
'@esbuild/linux-arm@0.21.5':
resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
engines: {node: '>=12'}
cpu: [arm]
os: [linux]
'@esbuild/linux-ia32@0.21.5':
resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
engines: {node: '>=12'}
cpu: [ia32]
os: [linux]
'@esbuild/linux-loong64@0.21.5':
resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
engines: {node: '>=12'}
cpu: [loong64]
os: [linux]
'@esbuild/linux-mips64el@0.21.5':
resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
engines: {node: '>=12'}
cpu: [mips64el]
os: [linux]
'@esbuild/linux-ppc64@0.21.5':
resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
engines: {node: '>=12'}
cpu: [ppc64]
os: [linux]
'@esbuild/linux-riscv64@0.21.5':
resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
engines: {node: '>=12'}
cpu: [riscv64]
os: [linux]
'@esbuild/linux-s390x@0.21.5':
resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
engines: {node: '>=12'}
cpu: [s390x]
os: [linux]
'@esbuild/linux-x64@0.21.5':
resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
engines: {node: '>=12'}
cpu: [x64]
os: [linux]
'@esbuild/netbsd-x64@0.21.5':
resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
engines: {node: '>=12'}
cpu: [x64]
os: [netbsd]
'@esbuild/openbsd-x64@0.21.5':
resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
engines: {node: '>=12'}
cpu: [x64]
os: [openbsd]
'@esbuild/sunos-x64@0.21.5':
resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
engines: {node: '>=12'}
cpu: [x64]
os: [sunos]
'@esbuild/win32-arm64@0.21.5':
resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
engines: {node: '>=12'}
cpu: [arm64]
os: [win32]
'@esbuild/win32-ia32@0.21.5':
resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
engines: {node: '>=12'}
cpu: [ia32]
os: [win32]
'@esbuild/win32-x64@0.21.5':
resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
engines: {node: '>=12'}
cpu: [x64]
os: [win32]
'@jridgewell/sourcemap-codec@1.5.5':
resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==}
'@rollup/rollup-android-arm-eabi@4.54.0':
resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.54.0':
resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.54.0':
resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.54.0':
resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-freebsd-arm64@4.54.0':
resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==}
cpu: [arm64]
os: [freebsd]
'@rollup/rollup-freebsd-x64@4.54.0':
resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==}
cpu: [x64]
os: [freebsd]
'@rollup/rollup-linux-arm-gnueabihf@4.54.0':
resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.54.0':
resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm64-gnu@4.54.0':
resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-arm64-musl@4.54.0':
resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-loong64-gnu@4.54.0':
resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==}
cpu: [loong64]
os: [linux]
'@rollup/rollup-linux-ppc64-gnu@4.54.0':
resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==}
cpu: [ppc64]
os: [linux]
'@rollup/rollup-linux-riscv64-gnu@4.54.0':
resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-riscv64-musl@4.54.0':
resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.54.0':
resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==}
cpu: [s390x]
os: [linux]
'@rollup/rollup-linux-x64-gnu@4.54.0':
resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==}
cpu: [x64]
os: [linux]
'@rollup/rollup-linux-x64-musl@4.54.0':
resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==}
cpu: [x64]
os: [linux]
'@rollup/rollup-openharmony-arm64@4.54.0':
resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==}
cpu: [arm64]
os: [openharmony]
'@rollup/rollup-win32-arm64-msvc@4.54.0':
resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==}
cpu: [arm64]
os: [win32]
'@rollup/rollup-win32-ia32-msvc@4.54.0':
resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-gnu@4.54.0':
resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==}
cpu: [x64]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.54.0':
resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==}
cpu: [x64]
os: [win32]
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/node@20.19.27':
resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==}
'@vitest/expect@2.1.9':
resolution: {integrity: sha512-UJCIkTBenHeKT1TTlKMJWy1laZewsRIzYighyYiJKZreqtdxSos/S1t+ktRMQWu2CKqaarrkeszJx1cgC5tGZw==}
'@vitest/mocker@2.1.9':
resolution: {integrity: sha512-tVL6uJgoUdi6icpxmdrn5YNo3g3Dxv+IHJBr0GXHaEdTcw3F+cPKnsXFhli6nO+f/6SDKPHEK1UN+k+TQv0Ehg==}
peerDependencies:
msw: ^2.4.9
vite: ^5.0.0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
'@vitest/pretty-format@2.1.9':
resolution: {integrity: sha512-KhRIdGV2U9HOUzxfiHmY8IFHTdqtOhIzCpd8WRdJiE7D/HUcZVD0EgQCVjm+Q9gkUXWgBvMmTtZgIG48wq7sOQ==}
'@vitest/runner@2.1.9':
resolution: {integrity: sha512-ZXSSqTFIrzduD63btIfEyOmNcBmQvgOVsPNPe0jYtESiXkhd8u2erDLnMxmGrDCwHCCHE7hxwRDCT3pt0esT4g==}
'@vitest/snapshot@2.1.9':
resolution: {integrity: sha512-oBO82rEjsxLNJincVhLhaxxZdEtV0EFHMK5Kmx5sJ6H9L183dHECjiefOAdnqpIgT5eZwT04PoggUnW88vOBNQ==}
'@vitest/spy@2.1.9':
resolution: {integrity: sha512-E1B35FwzXXTs9FHNK6bDszs7mtydNi5MIfUWpceJ8Xbfb1gBMscAnwLbEu+B44ed6W3XjL9/ehLPHR1fkf1KLQ==}
'@vitest/utils@2.1.9':
resolution: {integrity: sha512-v0psaMSkNJ3A2NMrUEHFRzJtDPFn+/VWZ5WxImB21T9fjucJRmS7xCS3ppEnARb9y11OAzaD+P2Ps+b+BGX5iQ==}
assertion-error@1.1.0:
resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==}
assertion-error@2.0.1:
resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
engines: {node: '>=12'}
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
chai-bytes@0.1.2:
resolution: {integrity: sha512-0ol6oJS0y1ozj6AZK8n1pyv1/G+l44nqUJygAkK1UrYl+IOGie5vcrEdrAlwmLYGIA9NVvtHWosPYwWWIXf/XA==}
engines: {node: '>=4'}
peerDependencies:
chai: '>=2 <5'
chai@4.5.0:
resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==}
engines: {node: '>=4'}
chai@5.3.3:
resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
engines: {node: '>=18'}
check-error@1.0.3:
resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==}
check-error@2.1.1:
resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==}
engines: {node: '>= 16'}
debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
deep-eql@4.1.4:
resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
engines: {node: '>=6'}
deep-eql@5.0.2:
resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
engines: {node: '>=6'}
es-module-lexer@1.7.0:
resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==}
esbuild@0.21.5:
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
engines: {node: '>=12'}
hasBin: true
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
expect-type@1.3.0:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
get-func-name@2.0.2:
resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==}
js-sha512@0.8.0:
resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==}
lodash-es@4.17.22:
resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==}
loupe@2.3.7:
resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==}
loupe@3.2.1:
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
pathe@1.1.2:
resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==}
pathval@1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
pathval@2.0.1:
resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
engines: {node: '>= 14.16'}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
postcss@8.5.6:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
rollup@4.54.0:
resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
std-env@3.10.0:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
tinyexec@0.3.2:
resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
tinypool@1.1.1:
resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
engines: {node: ^18.0.0 || >=20.0.0}
tinyrainbow@1.2.0:
resolution: {integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==}
engines: {node: '>=14.0.0'}
tinyspy@3.0.2:
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
type-detect@4.1.0:
resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==}
engines: {node: '>=4'}
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
@@ -44,12 +496,487 @@ packages:
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
vite-node@2.1.9:
resolution: {integrity: sha512-AM9aQ/IPrW/6ENLQg3AGY4K1N2TGZdR5e4gu/MmmR2xR3Ll1+dib+nook92g4TV3PXVyeyxdWwtaCAiUL0hMxA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
vite@5.4.21:
resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@types/node': ^18.0.0 || >=20.0.0
less: '*'
lightningcss: ^1.21.0
sass: '*'
sass-embedded: '*'
stylus: '*'
sugarss: '*'
terser: ^5.4.0
peerDependenciesMeta:
'@types/node':
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
vitest@2.1.9:
resolution: {integrity: sha512-MSmPM9REYqDGBI8439mA4mWhV5sKmDlBKWIYbA3lRb2PTHACE0mgKwA8yQ2xq9vxDTuk4iPrECBAEW2aoFXY0Q==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/node': ^18.0.0 || >=20.0.0
'@vitest/browser': 2.1.9
'@vitest/ui': 2.1.9
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
'@edge-runtime/vm':
optional: true
'@types/node':
optional: true
'@vitest/browser':
optional: true
'@vitest/ui':
optional: true
happy-dom:
optional: true
jsdom:
optional: true
why-is-node-running@2.3.0:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
snapshots:
'@esbuild/aix-ppc64@0.21.5':
optional: true
'@esbuild/android-arm64@0.21.5':
optional: true
'@esbuild/android-arm@0.21.5':
optional: true
'@esbuild/android-x64@0.21.5':
optional: true
'@esbuild/darwin-arm64@0.21.5':
optional: true
'@esbuild/darwin-x64@0.21.5':
optional: true
'@esbuild/freebsd-arm64@0.21.5':
optional: true
'@esbuild/freebsd-x64@0.21.5':
optional: true
'@esbuild/linux-arm64@0.21.5':
optional: true
'@esbuild/linux-arm@0.21.5':
optional: true
'@esbuild/linux-ia32@0.21.5':
optional: true
'@esbuild/linux-loong64@0.21.5':
optional: true
'@esbuild/linux-mips64el@0.21.5':
optional: true
'@esbuild/linux-ppc64@0.21.5':
optional: true
'@esbuild/linux-riscv64@0.21.5':
optional: true
'@esbuild/linux-s390x@0.21.5':
optional: true
'@esbuild/linux-x64@0.21.5':
optional: true
'@esbuild/netbsd-x64@0.21.5':
optional: true
'@esbuild/openbsd-x64@0.21.5':
optional: true
'@esbuild/sunos-x64@0.21.5':
optional: true
'@esbuild/win32-arm64@0.21.5':
optional: true
'@esbuild/win32-ia32@0.21.5':
optional: true
'@esbuild/win32-x64@0.21.5':
optional: true
'@jridgewell/sourcemap-codec@1.5.5': {}
'@rollup/rollup-android-arm-eabi@4.54.0':
optional: true
'@rollup/rollup-android-arm64@4.54.0':
optional: true
'@rollup/rollup-darwin-arm64@4.54.0':
optional: true
'@rollup/rollup-darwin-x64@4.54.0':
optional: true
'@rollup/rollup-freebsd-arm64@4.54.0':
optional: true
'@rollup/rollup-freebsd-x64@4.54.0':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.54.0':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.54.0':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-arm64-musl@4.54.0':
optional: true
'@rollup/rollup-linux-loong64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-ppc64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-riscv64-musl@4.54.0':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-x64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-x64-musl@4.54.0':
optional: true
'@rollup/rollup-openharmony-arm64@4.54.0':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.54.0':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.54.0':
optional: true
'@rollup/rollup-win32-x64-gnu@4.54.0':
optional: true
'@rollup/rollup-win32-x64-msvc@4.54.0':
optional: true
'@types/estree@1.0.8': {}
'@types/node@20.19.27':
dependencies:
undici-types: 6.21.0
'@vitest/expect@2.1.9':
dependencies:
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
chai: 5.3.3
tinyrainbow: 1.2.0
'@vitest/mocker@2.1.9(vite@5.4.21(@types/node@20.19.27))':
dependencies:
'@vitest/spy': 2.1.9
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 5.4.21(@types/node@20.19.27)
'@vitest/pretty-format@2.1.9':
dependencies:
tinyrainbow: 1.2.0
'@vitest/runner@2.1.9':
dependencies:
'@vitest/utils': 2.1.9
pathe: 1.1.2
'@vitest/snapshot@2.1.9':
dependencies:
'@vitest/pretty-format': 2.1.9
magic-string: 0.30.21
pathe: 1.1.2
'@vitest/spy@2.1.9':
dependencies:
tinyspy: 3.0.2
'@vitest/utils@2.1.9':
dependencies:
'@vitest/pretty-format': 2.1.9
loupe: 3.2.1
tinyrainbow: 1.2.0
assertion-error@1.1.0: {}
assertion-error@2.0.1: {}
cac@6.7.14: {}
chai-bytes@0.1.2(chai@4.5.0):
dependencies:
chai: 4.5.0
chai@4.5.0:
dependencies:
assertion-error: 1.1.0
check-error: 1.0.3
deep-eql: 4.1.4
get-func-name: 2.0.2
loupe: 2.3.7
pathval: 1.1.1
type-detect: 4.1.0
chai@5.3.3:
dependencies:
assertion-error: 2.0.1
check-error: 2.1.1
deep-eql: 5.0.2
loupe: 3.2.1
pathval: 2.0.1
check-error@1.0.3:
dependencies:
get-func-name: 2.0.2
check-error@2.1.1: {}
debug@4.4.3:
dependencies:
ms: 2.1.3
deep-eql@4.1.4:
dependencies:
type-detect: 4.1.0
deep-eql@5.0.2: {}
es-module-lexer@1.7.0: {}
esbuild@0.21.5:
optionalDependencies:
'@esbuild/aix-ppc64': 0.21.5
'@esbuild/android-arm': 0.21.5
'@esbuild/android-arm64': 0.21.5
'@esbuild/android-x64': 0.21.5
'@esbuild/darwin-arm64': 0.21.5
'@esbuild/darwin-x64': 0.21.5
'@esbuild/freebsd-arm64': 0.21.5
'@esbuild/freebsd-x64': 0.21.5
'@esbuild/linux-arm': 0.21.5
'@esbuild/linux-arm64': 0.21.5
'@esbuild/linux-ia32': 0.21.5
'@esbuild/linux-loong64': 0.21.5
'@esbuild/linux-mips64el': 0.21.5
'@esbuild/linux-ppc64': 0.21.5
'@esbuild/linux-riscv64': 0.21.5
'@esbuild/linux-s390x': 0.21.5
'@esbuild/linux-x64': 0.21.5
'@esbuild/netbsd-x64': 0.21.5
'@esbuild/openbsd-x64': 0.21.5
'@esbuild/sunos-x64': 0.21.5
'@esbuild/win32-arm64': 0.21.5
'@esbuild/win32-ia32': 0.21.5
'@esbuild/win32-x64': 0.21.5
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.8
expect-type@1.3.0: {}
fsevents@2.3.3:
optional: true
get-func-name@2.0.2: {}
js-sha512@0.8.0: {}
lodash-es@4.17.22: {}
loupe@2.3.7:
dependencies:
get-func-name: 2.0.2
loupe@3.2.1: {}
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
ms@2.1.3: {}
nanoid@3.3.11: {}
pathe@1.1.2: {}
pathval@1.1.1: {}
pathval@2.0.1: {}
picocolors@1.1.1: {}
postcss@8.5.6:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
rollup@4.54.0:
dependencies:
'@types/estree': 1.0.8
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.54.0
'@rollup/rollup-android-arm64': 4.54.0
'@rollup/rollup-darwin-arm64': 4.54.0
'@rollup/rollup-darwin-x64': 4.54.0
'@rollup/rollup-freebsd-arm64': 4.54.0
'@rollup/rollup-freebsd-x64': 4.54.0
'@rollup/rollup-linux-arm-gnueabihf': 4.54.0
'@rollup/rollup-linux-arm-musleabihf': 4.54.0
'@rollup/rollup-linux-arm64-gnu': 4.54.0
'@rollup/rollup-linux-arm64-musl': 4.54.0
'@rollup/rollup-linux-loong64-gnu': 4.54.0
'@rollup/rollup-linux-ppc64-gnu': 4.54.0
'@rollup/rollup-linux-riscv64-gnu': 4.54.0
'@rollup/rollup-linux-riscv64-musl': 4.54.0
'@rollup/rollup-linux-s390x-gnu': 4.54.0
'@rollup/rollup-linux-x64-gnu': 4.54.0
'@rollup/rollup-linux-x64-musl': 4.54.0
'@rollup/rollup-openharmony-arm64': 4.54.0
'@rollup/rollup-win32-arm64-msvc': 4.54.0
'@rollup/rollup-win32-ia32-msvc': 4.54.0
'@rollup/rollup-win32-x64-gnu': 4.54.0
'@rollup/rollup-win32-x64-msvc': 4.54.0
fsevents: 2.3.3
siginfo@2.0.0: {}
source-map-js@1.2.1: {}
stackback@0.0.2: {}
std-env@3.10.0: {}
tinybench@2.9.0: {}
tinyexec@0.3.2: {}
tinypool@1.1.1: {}
tinyrainbow@1.2.0: {}
tinyspy@3.0.2: {}
type-detect@4.1.0: {}
typescript@5.9.3: {}
undici-types@6.21.0: {}
vite-node@2.1.9(@types/node@20.19.27):
dependencies:
cac: 6.7.14
debug: 4.4.3
es-module-lexer: 1.7.0
pathe: 1.1.2
vite: 5.4.21(@types/node@20.19.27)
transitivePeerDependencies:
- '@types/node'
- less
- lightningcss
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
vite@5.4.21(@types/node@20.19.27):
dependencies:
esbuild: 0.21.5
postcss: 8.5.6
rollup: 4.54.0
optionalDependencies:
'@types/node': 20.19.27
fsevents: 2.3.3
vitest@2.1.9(@types/node@20.19.27):
dependencies:
'@vitest/expect': 2.1.9
'@vitest/mocker': 2.1.9(vite@5.4.21(@types/node@20.19.27))
'@vitest/pretty-format': 2.1.9
'@vitest/runner': 2.1.9
'@vitest/snapshot': 2.1.9
'@vitest/spy': 2.1.9
'@vitest/utils': 2.1.9
chai: 5.3.3
debug: 4.4.3
expect-type: 1.3.0
magic-string: 0.30.21
pathe: 1.1.2
std-env: 3.10.0
tinybench: 2.9.0
tinyexec: 0.3.2
tinypool: 1.1.1
tinyrainbow: 1.2.0
vite: 5.4.21(@types/node@20.19.27)
vite-node: 2.1.9(@types/node@20.19.27)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 20.19.27
transitivePeerDependencies:
- less
- lightningcss
- msw
- sass
- sass-embedded
- stylus
- sugarss
- supports-color
- terser
why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2