@openzeppelin/miden-multisig-client 0.17.0-rc.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -47
- package/dist/account/builder.d.ts +2 -2
- package/dist/account/builder.d.ts.map +1 -1
- package/dist/account/builder.js +49 -24
- package/dist/account/builder.js.map +1 -1
- package/dist/connectivity.d.ts +2 -0
- package/dist/connectivity.d.ts.map +1 -1
- package/dist/connectivity.js +7 -4
- package/dist/connectivity.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/multisig/authArgErrors.d.ts +59 -0
- package/dist/multisig/authArgErrors.d.ts.map +1 -0
- package/dist/multisig/authArgErrors.js +115 -0
- package/dist/multisig/authArgErrors.js.map +1 -0
- package/dist/multisig/helpers.d.ts +5 -0
- package/dist/multisig/helpers.d.ts.map +1 -1
- package/dist/multisig/helpers.js +7 -2
- package/dist/multisig/helpers.js.map +1 -1
- package/dist/multisig.d.ts +140 -0
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +419 -12
- package/dist/multisig.js.map +1 -1
- package/dist/procedures.d.ts +1 -1
- package/dist/procedures.js +1 -1
- package/dist/recovery/proposalNoteImport.d.ts +173 -0
- package/dist/recovery/proposalNoteImport.d.ts.map +1 -0
- package/dist/recovery/proposalNoteImport.js +411 -0
- package/dist/recovery/proposalNoteImport.js.map +1 -0
- package/dist/recovery/publicNoteBackfill.d.ts +168 -0
- package/dist/recovery/publicNoteBackfill.d.ts.map +1 -0
- package/dist/recovery/publicNoteBackfill.js +368 -0
- package/dist/recovery/publicNoteBackfill.js.map +1 -0
- package/dist/recovery/recoverNotes.d.ts +147 -0
- package/dist/recovery/recoverNotes.d.ts.map +1 -0
- package/dist/recovery/recoverNotes.js +163 -0
- package/dist/recovery/recoverNotes.js.map +1 -0
- package/dist/recovery/transportDrain.d.ts +124 -0
- package/dist/recovery/transportDrain.d.ts.map +1 -0
- package/dist/recovery/transportDrain.js +262 -0
- package/dist/recovery/transportDrain.js.map +1 -0
- package/dist/transaction/consumeNotes.d.ts.map +1 -1
- package/dist/transaction/consumeNotes.js +4 -1
- package/dist/transaction/consumeNotes.js.map +1 -1
- package/dist/transaction/p2id.d.ts.map +1 -1
- package/dist/transaction/p2id.js +4 -1
- package/dist/transaction/p2id.js.map +1 -1
- package/dist/transaction/summary.d.ts +10 -4
- package/dist/transaction/summary.d.ts.map +1 -1
- package/dist/transaction/summary.js +13 -7
- package/dist/transaction/summary.js.map +1 -1
- package/dist/transaction/updateGuardian.js +4 -1
- package/dist/transaction/updateGuardian.js.map +1 -1
- package/dist/transaction/updateProcedureThreshold.js +4 -1
- package/dist/transaction/updateProcedureThreshold.js.map +1 -1
- package/dist/transaction/updateSigners.js +4 -1
- package/dist/transaction/updateSigners.js.map +1 -1
- package/dist/transaction.d.ts +1 -1
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +1 -1
- package/dist/transaction.js.map +1 -1
- package/package.json +14 -10
- package/src/account/builder.ts +87 -35
- package/src/connectivity.ts +9 -4
- package/src/index.ts +34 -1
- package/src/multisig/authArgErrors.ts +138 -0
- package/src/multisig/helpers.ts +7 -2
- package/src/multisig.ts +513 -20
- package/src/procedures.ts +1 -1
- package/src/recovery/proposalNoteImport.ts +548 -0
- package/src/recovery/publicNoteBackfill.ts +502 -0
- package/src/recovery/recoverNotes.ts +288 -0
- package/src/recovery/transportDrain.ts +330 -0
- package/src/transaction/consumeNotes.ts +4 -1
- package/src/transaction/p2id.ts +4 -1
- package/src/transaction/summary.ts +13 -7
- package/src/transaction/updateGuardian.ts +4 -1
- package/src/transaction/updateProcedureThreshold.ts +4 -1
- package/src/transaction/updateSigners.ts +4 -1
- package/src/transaction.ts +1 -1
- package/dist/account/builder.test.d.ts +0 -2
- package/dist/account/builder.test.d.ts.map +0 -1
- package/dist/account/builder.test.js +0 -166
- package/dist/account/builder.test.js.map +0 -1
- package/dist/account/masm/account-components/auth.d.ts +0 -2
- package/dist/account/masm/account-components/auth.d.ts.map +0 -1
- package/dist/account/masm/account-components/auth.js +0 -46
- package/dist/account/masm/account-components/auth.js.map +0 -1
- package/dist/account/masm/index.d.ts +0 -2
- package/dist/account/masm/index.d.ts.map +0 -1
- package/dist/account/masm/index.js +0 -4
- package/dist/account/masm/index.js.map +0 -1
- package/dist/account/masm.d.ts +0 -2
- package/dist/account/masm.d.ts.map +0 -1
- package/dist/account/masm.js +0 -4
- package/dist/account/masm.js.map +0 -1
- package/dist/account/storage.test.d.ts +0 -2
- package/dist/account/storage.test.d.ts.map +0 -1
- package/dist/account/storage.test.js +0 -73
- package/dist/account/storage.test.js.map +0 -1
- package/dist/client.test.d.ts +0 -2
- package/dist/client.test.d.ts.map +0 -1
- package/dist/client.test.js +0 -380
- package/dist/client.test.js.map +0 -1
- package/dist/connectivity.test.d.ts +0 -2
- package/dist/connectivity.test.d.ts.map +0 -1
- package/dist/connectivity.test.js +0 -61
- package/dist/connectivity.test.js.map +0 -1
- package/dist/inspector.test.d.ts +0 -2
- package/dist/inspector.test.d.ts.map +0 -1
- package/dist/inspector.test.js +0 -425
- package/dist/inspector.test.js.map +0 -1
- package/dist/lookupAuth.test.d.ts +0 -2
- package/dist/lookupAuth.test.d.ts.map +0 -1
- package/dist/lookupAuth.test.js +0 -138
- package/dist/lookupAuth.test.js.map +0 -1
- package/dist/multisig/consumeNotesErrors.test.d.ts +0 -2
- package/dist/multisig/consumeNotesErrors.test.d.ts.map +0 -1
- package/dist/multisig/consumeNotesErrors.test.js +0 -28
- package/dist/multisig/consumeNotesErrors.test.js.map +0 -1
- package/dist/multisig/helpers.test.d.ts +0 -2
- package/dist/multisig/helpers.test.d.ts.map +0 -1
- package/dist/multisig/helpers.test.js +0 -94
- package/dist/multisig/helpers.test.js.map +0 -1
- package/dist/multisig.test.d.ts +0 -2
- package/dist/multisig.test.d.ts.map +0 -1
- package/dist/multisig.test.js +0 -4112
- package/dist/multisig.test.js.map +0 -1
- package/dist/proposal/factory.test.d.ts +0 -2
- package/dist/proposal/factory.test.d.ts.map +0 -1
- package/dist/proposal/factory.test.js +0 -32
- package/dist/proposal/factory.test.js.map +0 -1
- package/dist/proposal/metadata.test.d.ts +0 -2
- package/dist/proposal/metadata.test.d.ts.map +0 -1
- package/dist/proposal/metadata.test.js +0 -193
- package/dist/proposal/metadata.test.js.map +0 -1
- package/dist/prover/config.test.d.ts +0 -2
- package/dist/prover/config.test.d.ts.map +0 -1
- package/dist/prover/config.test.js +0 -54
- package/dist/prover/config.test.js.map +0 -1
- package/dist/prover/errors.test.d.ts +0 -2
- package/dist/prover/errors.test.d.ts.map +0 -1
- package/dist/prover/errors.test.js +0 -29
- package/dist/prover/errors.test.js.map +0 -1
- package/dist/prover/retry.test.d.ts +0 -2
- package/dist/prover/retry.test.d.ts.map +0 -1
- package/dist/prover/retry.test.js +0 -20
- package/dist/prover/retry.test.js.map +0 -1
- package/dist/prover/workflow.test.d.ts +0 -2
- package/dist/prover/workflow.test.d.ts.map +0 -1
- package/dist/prover/workflow.test.js +0 -105
- package/dist/prover/workflow.test.js.map +0 -1
- package/dist/raw-client.test.d.ts +0 -2
- package/dist/raw-client.test.d.ts.map +0 -1
- package/dist/raw-client.test.js +0 -111
- package/dist/raw-client.test.js.map +0 -1
- package/dist/rpc/config.test.d.ts +0 -2
- package/dist/rpc/config.test.d.ts.map +0 -1
- package/dist/rpc/config.test.js +0 -24
- package/dist/rpc/config.test.js.map +0 -1
- package/dist/rpc/errors.test.d.ts +0 -2
- package/dist/rpc/errors.test.d.ts.map +0 -1
- package/dist/rpc/errors.test.js +0 -34
- package/dist/rpc/errors.test.js.map +0 -1
- package/dist/rpc/retry.test.d.ts +0 -2
- package/dist/rpc/retry.test.d.ts.map +0 -1
- package/dist/rpc/retry.test.js +0 -98
- package/dist/rpc/retry.test.js.map +0 -1
- package/dist/signers/ecdsa.test.d.ts +0 -2
- package/dist/signers/ecdsa.test.d.ts.map +0 -1
- package/dist/signers/ecdsa.test.js +0 -88
- package/dist/signers/ecdsa.test.js.map +0 -1
- package/dist/signers/falcon.test.d.ts +0 -2
- package/dist/signers/falcon.test.d.ts.map +0 -1
- package/dist/signers/falcon.test.js +0 -161
- package/dist/signers/falcon.test.js.map +0 -1
- package/dist/signers/miden-wallet.ecdsa-recovery.test.d.ts +0 -2
- package/dist/signers/miden-wallet.ecdsa-recovery.test.d.ts.map +0 -1
- package/dist/signers/miden-wallet.ecdsa-recovery.test.js +0 -148
- package/dist/signers/miden-wallet.ecdsa-recovery.test.js.map +0 -1
- package/dist/signers/miden-wallet.test.d.ts +0 -2
- package/dist/signers/miden-wallet.test.d.ts.map +0 -1
- package/dist/signers/miden-wallet.test.js +0 -164
- package/dist/signers/miden-wallet.test.js.map +0 -1
- package/dist/signers/para.test.d.ts +0 -2
- package/dist/signers/para.test.d.ts.map +0 -1
- package/dist/signers/para.test.js +0 -146
- package/dist/signers/para.test.js.map +0 -1
- package/dist/transaction/index.d.ts +0 -8
- package/dist/transaction/index.d.ts.map +0 -1
- package/dist/transaction/index.js +0 -7
- package/dist/transaction/index.js.map +0 -1
- package/dist/transaction/p2id.test.d.ts +0 -2
- package/dist/transaction/p2id.test.d.ts.map +0 -1
- package/dist/transaction/p2id.test.js +0 -246
- package/dist/transaction/p2id.test.js.map +0 -1
- package/dist/transaction/rpoRandomCoin.test.d.ts +0 -2
- package/dist/transaction/rpoRandomCoin.test.d.ts.map +0 -1
- package/dist/transaction/rpoRandomCoin.test.js +0 -52
- package/dist/transaction/rpoRandomCoin.test.js.map +0 -1
- package/dist/transaction/summary.test.d.ts +0 -2
- package/dist/transaction/summary.test.d.ts.map +0 -1
- package/dist/transaction/summary.test.js +0 -26
- package/dist/transaction/summary.test.js.map +0 -1
- package/dist/transaction.test.d.ts +0 -2
- package/dist/transaction.test.d.ts.map +0 -1
- package/dist/transaction.test.js +0 -122
- package/dist/transaction.test.js.map +0 -1
- package/dist/types/proposal.test.d.ts +0 -2
- package/dist/types/proposal.test.d.ts.map +0 -1
- package/dist/types/proposal.test.js +0 -56
- package/dist/types/proposal.test.js.map +0 -1
- package/dist/utils/digest.test.d.ts +0 -2
- package/dist/utils/digest.test.d.ts.map +0 -1
- package/dist/utils/digest.test.js +0 -48
- package/dist/utils/digest.test.js.map +0 -1
- package/dist/utils/ecdsa.test.d.ts +0 -2
- package/dist/utils/ecdsa.test.d.ts.map +0 -1
- package/dist/utils/ecdsa.test.js +0 -131
- package/dist/utils/ecdsa.test.js.map +0 -1
- package/dist/utils/encoding.test.d.ts +0 -2
- package/dist/utils/encoding.test.d.ts.map +0 -1
- package/dist/utils/encoding.test.js +0 -185
- package/dist/utils/encoding.test.js.map +0 -1
- package/dist/utils/key.test.d.ts +0 -2
- package/dist/utils/key.test.d.ts.map +0 -1
- package/dist/utils/key.test.js +0 -82
- package/dist/utils/key.test.js.map +0 -1
- package/dist/utils/signature.test.d.ts +0 -2
- package/dist/utils/signature.test.d.ts.map +0 -1
- package/dist/utils/signature.test.js +0 -164
- package/dist/utils/signature.test.js.map +0 -1
- package/dist/utils/word.test.d.ts +0 -2
- package/dist/utils/word.test.d.ts.map +0 -1
- package/dist/utils/word.test.js +0 -54
- package/dist/utils/word.test.js.map +0 -1
- package/masm/account_components/auth/guarded_multisig.masm +0 -42
- package/src/account/builder.test.ts +0 -238
- package/src/account/masm/account-components/auth.ts +0 -46
- package/src/account/masm/index.ts +0 -4
- package/src/account/masm.ts +0 -4
- package/src/account/storage.test.ts +0 -90
- package/src/client.test.ts +0 -473
- package/src/connectivity.test.ts +0 -67
- package/src/inspector.test.ts +0 -542
- package/src/lookupAuth.test.ts +0 -185
- package/src/multisig/consumeNotesErrors.test.ts +0 -43
- package/src/multisig/helpers.test.ts +0 -114
- package/src/multisig.test.ts +0 -5008
- package/src/proposal/factory.test.ts +0 -40
- package/src/proposal/metadata.test.ts +0 -235
- package/src/prover/config.test.ts +0 -90
- package/src/prover/errors.test.ts +0 -61
- package/src/prover/retry.test.ts +0 -38
- package/src/prover/workflow.test.ts +0 -145
- package/src/raw-client.test.ts +0 -171
- package/src/rpc/config.test.ts +0 -45
- package/src/rpc/errors.test.ts +0 -69
- package/src/rpc/retry.test.ts +0 -144
- package/src/signers/ecdsa.test.ts +0 -111
- package/src/signers/falcon.test.ts +0 -197
- package/src/signers/miden-wallet.ecdsa-recovery.test.ts +0 -201
- package/src/signers/miden-wallet.test.ts +0 -206
- package/src/signers/para.test.ts +0 -186
- package/src/transaction/index.ts +0 -13
- package/src/transaction/p2id.test.ts +0 -371
- package/src/transaction/rpoRandomCoin.test.ts +0 -64
- package/src/transaction/summary.test.ts +0 -32
- package/src/transaction.test.ts +0 -142
- package/src/types/proposal.test.ts +0 -68
- package/src/utils/digest.test.ts +0 -55
- package/src/utils/ecdsa.test.ts +0 -164
- package/src/utils/encoding.test.ts +0 -233
- package/src/utils/key.test.ts +0 -91
- package/src/utils/signature.test.ts +0 -210
- package/src/utils/word.test.ts +0 -64
package/src/transaction.test.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeAll } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// Mock Miden SDK before importing transaction module
|
|
4
|
-
vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
5
|
-
AccountId: { fromHex: vi.fn() },
|
|
6
|
-
AdviceMap: vi.fn(),
|
|
7
|
-
Felt: vi.fn().mockImplementation((v) => ({ value: v })),
|
|
8
|
-
FeltArray: vi.fn().mockImplementation((arr) => arr),
|
|
9
|
-
Poseidon2: { hashElements: vi.fn() },
|
|
10
|
-
Signature: { deserialize: vi.fn() },
|
|
11
|
-
TransactionRequestBuilder: vi.fn().mockImplementation(() => ({
|
|
12
|
-
withCustomScript: vi.fn().mockReturnThis(),
|
|
13
|
-
withScriptArg: vi.fn().mockReturnThis(),
|
|
14
|
-
extendAdviceMap: vi.fn().mockReturnThis(),
|
|
15
|
-
withAuthArg: vi.fn().mockReturnThis(),
|
|
16
|
-
build: vi.fn().mockReturnValue({}),
|
|
17
|
-
})),
|
|
18
|
-
Word: {
|
|
19
|
-
fromHex: vi.fn().mockImplementation((hex: string) => ({
|
|
20
|
-
toHex: () => hex,
|
|
21
|
-
toFelts: () => [1, 2, 3, 4],
|
|
22
|
-
})),
|
|
23
|
-
},
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
// Now import the module under test - use dynamic import to ensure mocks are in place
|
|
27
|
-
let normalizeHexWord: typeof import('./utils/encoding.js').normalizeHexWord;
|
|
28
|
-
let signatureHexToBytes: typeof import('./utils/signature.js').signatureHexToBytes;
|
|
29
|
-
let hexToBytes: typeof import('./utils/encoding.js').hexToBytes;
|
|
30
|
-
|
|
31
|
-
beforeAll(async () => {
|
|
32
|
-
const encoding = await import('./utils/encoding.js');
|
|
33
|
-
const sig = await import('./utils/signature.js');
|
|
34
|
-
normalizeHexWord = encoding.normalizeHexWord;
|
|
35
|
-
hexToBytes = encoding.hexToBytes;
|
|
36
|
-
signatureHexToBytes = sig.signatureHexToBytes;
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
describe('transaction utilities', () => {
|
|
40
|
-
describe('normalizeHexWord', () => {
|
|
41
|
-
it('should handle hex without 0x prefix', () => {
|
|
42
|
-
const result = normalizeHexWord('abc123');
|
|
43
|
-
expect(result).toBe('0x' + '0'.repeat(58) + 'abc123');
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('should handle hex with 0x prefix', () => {
|
|
47
|
-
const result = normalizeHexWord('0xabc123');
|
|
48
|
-
expect(result).toBe('0x' + '0'.repeat(58) + 'abc123');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should handle hex with 0X prefix', () => {
|
|
52
|
-
const result = normalizeHexWord('0Xabc123');
|
|
53
|
-
expect(result).toBe('0x' + '0'.repeat(58) + 'abc123');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should convert to lowercase', () => {
|
|
57
|
-
const result = normalizeHexWord('0xABC123DEF');
|
|
58
|
-
expect(result).toBe('0x' + '0'.repeat(55) + 'abc123def');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should pad to 64 characters', () => {
|
|
62
|
-
const result = normalizeHexWord('1');
|
|
63
|
-
expect(result).toBe('0x' + '0'.repeat(63) + '1');
|
|
64
|
-
expect(result.length).toBe(66); // 0x + 64 chars
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should preserve full 64-char hex', () => {
|
|
68
|
-
const fullHex = 'a'.repeat(64);
|
|
69
|
-
const result = normalizeHexWord(fullHex);
|
|
70
|
-
expect(result).toBe('0x' + fullHex);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should preserve full 64-char hex with prefix', () => {
|
|
74
|
-
const fullHex = 'b'.repeat(64);
|
|
75
|
-
const result = normalizeHexWord('0x' + fullHex);
|
|
76
|
-
expect(result).toBe('0x' + fullHex);
|
|
77
|
-
});
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
describe('hexToBytes', () => {
|
|
81
|
-
it('should convert hex string to Uint8Array', () => {
|
|
82
|
-
const result = hexToBytes('deadbeef');
|
|
83
|
-
expect(result).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('should handle 0x prefix', () => {
|
|
87
|
-
const result = hexToBytes('0xdeadbeef');
|
|
88
|
-
expect(result).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('should handle empty string', () => {
|
|
92
|
-
const result = hexToBytes('');
|
|
93
|
-
expect(result).toEqual(new Uint8Array([]));
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should handle single byte', () => {
|
|
97
|
-
const result = hexToBytes('ff');
|
|
98
|
-
expect(result).toEqual(new Uint8Array([0xff]));
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should handle zeros', () => {
|
|
102
|
-
const result = hexToBytes('00000000');
|
|
103
|
-
expect(result).toEqual(new Uint8Array([0, 0, 0, 0]));
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should handle mixed case', () => {
|
|
107
|
-
const result = hexToBytes('DeAdBeEf');
|
|
108
|
-
expect(result).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
describe('signatureHexToBytes', () => {
|
|
113
|
-
it('should prepend auth scheme byte (2 = Falcon Poseidon2)', () => {
|
|
114
|
-
const result = signatureHexToBytes('deadbeef');
|
|
115
|
-
expect(result[0]).toBe(2);
|
|
116
|
-
expect(result.slice(1)).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('should prepend auth scheme byte (1 = ECDSA)', () => {
|
|
120
|
-
const result = signatureHexToBytes('deadbeef', 'ecdsa');
|
|
121
|
-
expect(result[0]).toBe(1);
|
|
122
|
-
expect(result.slice(1)).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('should handle 0x prefix', () => {
|
|
126
|
-
const result = signatureHexToBytes('0xaabbccdd');
|
|
127
|
-
expect(result[0]).toBe(2);
|
|
128
|
-
expect(result.slice(1)).toEqual(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]));
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
it('should return correct length', () => {
|
|
132
|
-
const sigHex = 'a'.repeat(128); // 64 bytes
|
|
133
|
-
const result = signatureHexToBytes(sigHex);
|
|
134
|
-
expect(result.length).toBe(65); // 64 bytes + 1 prefix byte
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('should handle empty signature', () => {
|
|
138
|
-
const result = signatureHexToBytes('');
|
|
139
|
-
expect(result).toEqual(new Uint8Array([2]));
|
|
140
|
-
});
|
|
141
|
-
});
|
|
142
|
-
});
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
CONSUME_NOTES_METADATA_VERSION_V2,
|
|
4
|
-
type ConsumeNotesProposalMetadata,
|
|
5
|
-
MAX_CONSUME_NOTES_METADATA_BYTES,
|
|
6
|
-
isConsumeNotesV1,
|
|
7
|
-
isConsumeNotesV2,
|
|
8
|
-
} from './proposal.js';
|
|
9
|
-
|
|
10
|
-
describe('consume_notes metadata v1/v2 discriminator (issue #229)', () => {
|
|
11
|
-
it('v1 metadata omits metadataVersion and notes on the wire', () => {
|
|
12
|
-
const md: ConsumeNotesProposalMetadata = {
|
|
13
|
-
proposalType: 'consume_notes',
|
|
14
|
-
description: '',
|
|
15
|
-
noteIds: ['0xabc', '0xdef'],
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const json = JSON.parse(JSON.stringify(md));
|
|
19
|
-
expect(json.metadataVersion).toBeUndefined();
|
|
20
|
-
expect(json.notes).toBeUndefined();
|
|
21
|
-
expect(isConsumeNotesV1(md)).toBe(true);
|
|
22
|
-
expect(isConsumeNotesV2(md)).toBe(false);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('v2 metadata round-trips with discriminator and embedded notes', () => {
|
|
26
|
-
const md: ConsumeNotesProposalMetadata = {
|
|
27
|
-
proposalType: 'consume_notes',
|
|
28
|
-
description: '',
|
|
29
|
-
noteIds: ['0xabc'],
|
|
30
|
-
metadataVersion: CONSUME_NOTES_METADATA_VERSION_V2,
|
|
31
|
-
notes: ['YmFzZTY0Tm90ZQ=='],
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const json = JSON.stringify(md);
|
|
35
|
-
const parsed = JSON.parse(json) as ConsumeNotesProposalMetadata;
|
|
36
|
-
expect(parsed.metadataVersion).toBe(2);
|
|
37
|
-
expect(parsed.notes).toEqual(['YmFzZTY0Tm90ZQ==']);
|
|
38
|
-
expect(isConsumeNotesV2(parsed)).toBe(true);
|
|
39
|
-
expect(isConsumeNotesV1(parsed)).toBe(false);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('explicit metadataVersion === 1 is treated as v1', () => {
|
|
43
|
-
const md = {
|
|
44
|
-
proposalType: 'consume_notes',
|
|
45
|
-
description: '',
|
|
46
|
-
noteIds: ['0xabc'],
|
|
47
|
-
metadataVersion: 1 as unknown as 2, // legacy explicit-v1 case
|
|
48
|
-
} as ConsumeNotesProposalMetadata;
|
|
49
|
-
expect(isConsumeNotesV1(md)).toBe(true);
|
|
50
|
-
expect(isConsumeNotesV2(md)).toBe(false);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it('unknown future version is neither v1 nor v2; dispatch handles rejection', () => {
|
|
54
|
-
const md = {
|
|
55
|
-
proposalType: 'consume_notes',
|
|
56
|
-
description: '',
|
|
57
|
-
noteIds: ['0xabc'],
|
|
58
|
-
metadataVersion: 99 as unknown as 2,
|
|
59
|
-
} as ConsumeNotesProposalMetadata;
|
|
60
|
-
expect(isConsumeNotesV1(md)).toBe(false);
|
|
61
|
-
expect(isConsumeNotesV2(md)).toBe(false);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
it('pins MAX_CONSUME_NOTES_METADATA_BYTES at 256 KiB', () => {
|
|
65
|
-
expect(MAX_CONSUME_NOTES_METADATA_BYTES).toBe(256 * 1024);
|
|
66
|
-
expect(MAX_CONSUME_NOTES_METADATA_BYTES).toBe(262_144);
|
|
67
|
-
});
|
|
68
|
-
});
|
package/src/utils/digest.test.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { AuthDigest } from './digest.js';
|
|
3
|
-
|
|
4
|
-
vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
5
|
-
AccountId: {
|
|
6
|
-
fromHex: vi.fn(() => ({
|
|
7
|
-
prefix: () => ({ label: 'prefix' }),
|
|
8
|
-
suffix: () => ({ label: 'suffix' }),
|
|
9
|
-
})),
|
|
10
|
-
},
|
|
11
|
-
Felt: vi.fn().mockImplementation((value: bigint) => ({ value })),
|
|
12
|
-
FeltArray: vi.fn().mockImplementation((elements: unknown[]) => elements),
|
|
13
|
-
Word: {
|
|
14
|
-
fromHex: vi.fn((hex: string) => ({
|
|
15
|
-
toHex: () => hex,
|
|
16
|
-
toFelts: () => [],
|
|
17
|
-
})),
|
|
18
|
-
},
|
|
19
|
-
Rpo256: {
|
|
20
|
-
hashElements: vi.fn().mockReturnValue({
|
|
21
|
-
toHex: () => '0x' + 'aa'.repeat(32),
|
|
22
|
-
toFelts: () => [],
|
|
23
|
-
}),
|
|
24
|
-
},
|
|
25
|
-
}));
|
|
26
|
-
|
|
27
|
-
describe('AuthDigest', () => {
|
|
28
|
-
beforeEach(() => {
|
|
29
|
-
vi.clearAllMocks();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('uses the legacy 4-felt digest for account auth', async () => {
|
|
33
|
-
const { FeltArray, Rpo256 } = await import('@miden-sdk/miden-sdk');
|
|
34
|
-
|
|
35
|
-
AuthDigest.fromAccountIdWithTimestamp('0x' + 'ab'.repeat(15), 1700000000);
|
|
36
|
-
|
|
37
|
-
expect(FeltArray).toHaveBeenCalledWith([
|
|
38
|
-
{ label: 'prefix' },
|
|
39
|
-
{ label: 'suffix' },
|
|
40
|
-
{ value: 1700000000n },
|
|
41
|
-
{ value: 0n },
|
|
42
|
-
]);
|
|
43
|
-
expect(Rpo256.hashElements).toHaveBeenCalledTimes(1);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('includes the request payload hash for request-bound auth', async () => {
|
|
47
|
-
const { Rpo256 } = await import('@miden-sdk/miden-sdk');
|
|
48
|
-
|
|
49
|
-
AuthDigest.fromRequest('0x' + 'ab'.repeat(15), 1700000000, {
|
|
50
|
-
toBytes: () => new Uint8Array([1, 2, 3, 4]),
|
|
51
|
-
} as never);
|
|
52
|
-
|
|
53
|
-
expect(Rpo256.hashElements).toHaveBeenCalledTimes(2);
|
|
54
|
-
});
|
|
55
|
-
});
|
package/src/utils/ecdsa.test.ts
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { secp256k1 } from '@noble/curves/secp256k1';
|
|
3
|
-
import { keccak_256 } from '@noble/hashes/sha3.js';
|
|
4
|
-
import { EcdsaFormat } from './ecdsa.js';
|
|
5
|
-
import { bytesToHex } from './encoding.js';
|
|
6
|
-
|
|
7
|
-
describe('EcdsaFormat', () => {
|
|
8
|
-
describe('normalizeRecoveryByte', () => {
|
|
9
|
-
it('should normalize v=27 to recovery_id=0', () => {
|
|
10
|
-
const rHex = 'aa'.repeat(32);
|
|
11
|
-
const sHex = 'bb'.repeat(32);
|
|
12
|
-
const sig = `0x${rHex}${sHex}1b`;
|
|
13
|
-
const result = EcdsaFormat.normalizeRecoveryByte(sig);
|
|
14
|
-
expect(result).toBe(`0x${rHex}${sHex}00`);
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('should normalize v=28 to recovery_id=1', () => {
|
|
18
|
-
const rHex = 'aa'.repeat(32);
|
|
19
|
-
const sHex = 'bb'.repeat(32);
|
|
20
|
-
const sig = `0x${rHex}${sHex}1c`;
|
|
21
|
-
const result = EcdsaFormat.normalizeRecoveryByte(sig);
|
|
22
|
-
expect(result).toBe(`0x${rHex}${sHex}01`);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should pass through v=0 unchanged', () => {
|
|
26
|
-
const rHex = 'aa'.repeat(32);
|
|
27
|
-
const sHex = 'bb'.repeat(32);
|
|
28
|
-
const sig = `0x${rHex}${sHex}00`;
|
|
29
|
-
const result = EcdsaFormat.normalizeRecoveryByte(sig);
|
|
30
|
-
expect(result).toBe(sig);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should pass through 64-byte signature unchanged', () => {
|
|
34
|
-
const sig = `0x${'ab'.repeat(64)}`;
|
|
35
|
-
const result = EcdsaFormat.normalizeRecoveryByte(sig);
|
|
36
|
-
expect(result).toBe(sig);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should throw on invalid length', () => {
|
|
40
|
-
expect(() => EcdsaFormat.normalizeRecoveryByte('0x' + 'ab'.repeat(10))).toThrow(
|
|
41
|
-
'Invalid ECDSA signature length',
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('should handle input without 0x prefix', () => {
|
|
46
|
-
const rHex = 'aa'.repeat(32);
|
|
47
|
-
const sHex = 'bb'.repeat(32);
|
|
48
|
-
const sig = `${rHex}${sHex}1b`;
|
|
49
|
-
const result = EcdsaFormat.normalizeRecoveryByte(sig);
|
|
50
|
-
expect(result).toBe(`0x${rHex}${sHex}00`);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
describe('compressPublicKey', () => {
|
|
55
|
-
it('should compress a 65-byte uncompressed key with even y', () => {
|
|
56
|
-
const x = 'aa'.repeat(32);
|
|
57
|
-
const yEven = 'bb'.repeat(31) + 'b0';
|
|
58
|
-
const uncompressed = `0x04${x}${yEven}`;
|
|
59
|
-
const result = EcdsaFormat.compressPublicKey(uncompressed);
|
|
60
|
-
expect(result).toBe(`0x02${x}`);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('should compress a 65-byte uncompressed key with odd y', () => {
|
|
64
|
-
const x = 'aa'.repeat(32);
|
|
65
|
-
const yOdd = 'bb'.repeat(31) + 'b1';
|
|
66
|
-
const uncompressed = `0x04${x}${yOdd}`;
|
|
67
|
-
const result = EcdsaFormat.compressPublicKey(uncompressed);
|
|
68
|
-
expect(result).toBe(`0x03${x}`);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('should pass through a 33-byte compressed key unchanged', () => {
|
|
72
|
-
const compressed = `0x02${'aa'.repeat(32)}`;
|
|
73
|
-
const result = EcdsaFormat.compressPublicKey(compressed);
|
|
74
|
-
expect(result).toBe(compressed);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should throw on invalid length', () => {
|
|
78
|
-
expect(() => EcdsaFormat.compressPublicKey('0x' + 'ab'.repeat(10))).toThrow(
|
|
79
|
-
'Expected 65-byte uncompressed public key',
|
|
80
|
-
);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should throw on 65 bytes without 04 prefix', () => {
|
|
84
|
-
expect(() => EcdsaFormat.compressPublicKey('0x05' + 'ab'.repeat(64))).toThrow(
|
|
85
|
-
'Expected 65-byte uncompressed public key',
|
|
86
|
-
);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
describe('isValidPublicKeyPoint', () => {
|
|
91
|
-
// The secp256k1 generator point G, compressed — a known-valid point.
|
|
92
|
-
const G = '0x0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798';
|
|
93
|
-
|
|
94
|
-
it('accepts a valid compressed secp256k1 point', () => {
|
|
95
|
-
expect(EcdsaFormat.isValidPublicKeyPoint(G)).toBe(true);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
it('rejects a valid-length key whose x is off-curve', () => {
|
|
99
|
-
expect(EcdsaFormat.isValidPublicKeyPoint('0x02' + 'ff'.repeat(32))).toBe(false);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it('rejects a valid-length key with a bad prefix byte', () => {
|
|
103
|
-
expect(EcdsaFormat.isValidPublicKeyPoint('0xff' + 'ab'.repeat(32))).toBe(false);
|
|
104
|
-
});
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
describe('keccakDigestHex', () => {
|
|
108
|
-
it('should return 0x-prefixed hex of keccak-256 hash', () => {
|
|
109
|
-
const result = EcdsaFormat.keccakDigestHex(new Uint8Array(0));
|
|
110
|
-
expect(result).toMatch(/^0x[a-f0-9]{64}$/);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('should produce correct hash for empty input', () => {
|
|
114
|
-
const result = EcdsaFormat.keccakDigestHex(new Uint8Array(0));
|
|
115
|
-
expect(result).toBe('0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470');
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('should produce different hashes for different inputs', () => {
|
|
119
|
-
const a = EcdsaFormat.keccakDigestHex(new Uint8Array([1]));
|
|
120
|
-
const b = EcdsaFormat.keccakDigestHex(new Uint8Array([2]));
|
|
121
|
-
expect(a).not.toBe(b);
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
describe('recoverCompressedPublicKeyHex', () => {
|
|
126
|
-
const privateKey = new Uint8Array(32).fill(0x11);
|
|
127
|
-
const message = new Uint8Array([9, 8, 7, 6, 5]);
|
|
128
|
-
|
|
129
|
-
function sign(priv: Uint8Array, msg: Uint8Array): Uint8Array {
|
|
130
|
-
const sig = secp256k1.sign(keccak_256(msg), priv);
|
|
131
|
-
const out = new Uint8Array(65);
|
|
132
|
-
out.set(sig.toCompactRawBytes(), 0); // r || s
|
|
133
|
-
out[64] = sig.recovery; // v
|
|
134
|
-
return out;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
it('recovers the compressed public key that produced the signature', () => {
|
|
138
|
-
const expected = bytesToHex(secp256k1.getPublicKey(privateKey, true));
|
|
139
|
-
const recovered = EcdsaFormat.recoverCompressedPublicKeyHex(message, sign(privateKey, message));
|
|
140
|
-
expect(recovered).toBe(expected);
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('accepts an Ethereum-style recovery byte (27/28)', () => {
|
|
144
|
-
const sig = sign(privateKey, message);
|
|
145
|
-
sig[64] += 27; // 0/1 -> 27/28
|
|
146
|
-
const expected = bytesToHex(secp256k1.getPublicKey(privateKey, true));
|
|
147
|
-
expect(EcdsaFormat.recoverCompressedPublicKeyHex(message, sig)).toBe(expected);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('throws when the signature is not 65 bytes', () => {
|
|
151
|
-
expect(() => EcdsaFormat.recoverCompressedPublicKeyHex(message, new Uint8Array(64))).toThrow(
|
|
152
|
-
/65-byte signature/,
|
|
153
|
-
);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('throws on an invalid recovery byte', () => {
|
|
157
|
-
const sig = sign(privateKey, message);
|
|
158
|
-
sig[64] = 5;
|
|
159
|
-
expect(() => EcdsaFormat.recoverCompressedPublicKeyHex(message, sig)).toThrow(
|
|
160
|
-
/recovery byte must be/,
|
|
161
|
-
);
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
});
|
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
ensureHexPrefix,
|
|
4
|
-
normalizeHexWord,
|
|
5
|
-
bytesToHex,
|
|
6
|
-
hexToBytes,
|
|
7
|
-
uint8ArrayToBase64,
|
|
8
|
-
base64ToUint8Array,
|
|
9
|
-
} from './encoding.js';
|
|
10
|
-
|
|
11
|
-
describe('encoding utilities', () => {
|
|
12
|
-
describe('ensureHexPrefix', () => {
|
|
13
|
-
it('adds 0x prefix when missing', () => {
|
|
14
|
-
expect(ensureHexPrefix('abc123')).toBe('0xabc123');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
it('preserves existing 0x prefix', () => {
|
|
18
|
-
expect(ensureHexPrefix('0xabc123')).toBe('0xabc123');
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('preserves existing 0X prefix', () => {
|
|
22
|
-
expect(ensureHexPrefix('0Xabc123')).toBe('0Xabc123');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('handles empty string', () => {
|
|
26
|
-
expect(ensureHexPrefix('')).toBe('0x');
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('handles single character', () => {
|
|
30
|
-
expect(ensureHexPrefix('a')).toBe('0xa');
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('normalizeHexWord', () => {
|
|
35
|
-
it('pads short hex to 64 characters', () => {
|
|
36
|
-
const result = normalizeHexWord('abc123');
|
|
37
|
-
expect(result).toBe('0x' + '0'.repeat(58) + 'abc123');
|
|
38
|
-
expect(result.length).toBe(66); // 0x + 64 chars
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('preserves full 64-char hex', () => {
|
|
42
|
-
const fullHex = 'a'.repeat(64);
|
|
43
|
-
expect(normalizeHexWord(fullHex)).toBe('0x' + fullHex);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('handles 0x prefix', () => {
|
|
47
|
-
expect(normalizeHexWord('0xabc')).toBe('0x' + '0'.repeat(61) + 'abc');
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('handles 0X prefix', () => {
|
|
51
|
-
expect(normalizeHexWord('0Xabc')).toBe('0x' + '0'.repeat(61) + 'abc');
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('converts to lowercase', () => {
|
|
55
|
-
expect(normalizeHexWord('ABC')).toBe('0x' + '0'.repeat(61) + 'abc');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('handles empty string', () => {
|
|
59
|
-
expect(normalizeHexWord('')).toBe('0x' + '0'.repeat(64));
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it('handles single digit', () => {
|
|
63
|
-
expect(normalizeHexWord('1')).toBe('0x' + '0'.repeat(63) + '1');
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('handles full 64-char hex with prefix', () => {
|
|
67
|
-
const fullHex = 'b'.repeat(64);
|
|
68
|
-
expect(normalizeHexWord('0x' + fullHex)).toBe('0x' + fullHex);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
describe('bytesToHex', () => {
|
|
73
|
-
it('converts Uint8Array to hex string', () => {
|
|
74
|
-
const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);
|
|
75
|
-
expect(bytesToHex(bytes)).toBe('0xdeadbeef');
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('handles empty array', () => {
|
|
79
|
-
expect(bytesToHex(new Uint8Array([]))).toBe('0x');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('handles single byte', () => {
|
|
83
|
-
expect(bytesToHex(new Uint8Array([0xff]))).toBe('0xff');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('pads single digit bytes with zero', () => {
|
|
87
|
-
const bytes = new Uint8Array([0x0a, 0x0b, 0x0c]);
|
|
88
|
-
expect(bytesToHex(bytes)).toBe('0x0a0b0c');
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it('handles zeros', () => {
|
|
92
|
-
const bytes = new Uint8Array([0x00, 0x00, 0x00]);
|
|
93
|
-
expect(bytesToHex(bytes)).toBe('0x000000');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('handles max byte value', () => {
|
|
97
|
-
const bytes = new Uint8Array([0xff, 0xff]);
|
|
98
|
-
expect(bytesToHex(bytes)).toBe('0xffff');
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('handles long arrays', () => {
|
|
102
|
-
const bytes = new Uint8Array(32).fill(0xaa);
|
|
103
|
-
const result = bytesToHex(bytes);
|
|
104
|
-
expect(result).toBe('0x' + 'aa'.repeat(32));
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe('hexToBytes', () => {
|
|
109
|
-
it('converts hex string to Uint8Array', () => {
|
|
110
|
-
expect(hexToBytes('deadbeef')).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it('handles 0x prefix', () => {
|
|
114
|
-
expect(hexToBytes('0xdeadbeef')).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('handles 0X prefix', () => {
|
|
118
|
-
expect(hexToBytes('0Xdeadbeef')).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('handles empty string', () => {
|
|
122
|
-
expect(hexToBytes('')).toEqual(new Uint8Array([]));
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('handles empty with prefix', () => {
|
|
126
|
-
expect(hexToBytes('0x')).toEqual(new Uint8Array([]));
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
it('handles single byte', () => {
|
|
130
|
-
expect(hexToBytes('ff')).toEqual(new Uint8Array([0xff]));
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('handles zeros', () => {
|
|
134
|
-
expect(hexToBytes('00000000')).toEqual(new Uint8Array([0, 0, 0, 0]));
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it('handles mixed case', () => {
|
|
138
|
-
expect(hexToBytes('DeAdBeEf')).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('handles long hex strings', () => {
|
|
142
|
-
const hex = 'aa'.repeat(32);
|
|
143
|
-
const result = hexToBytes(hex);
|
|
144
|
-
expect(result).toEqual(new Uint8Array(32).fill(0xaa));
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
describe('roundtrip bytesToHex/hexToBytes', () => {
|
|
149
|
-
it('survives roundtrip bytes -> hex -> bytes', () => {
|
|
150
|
-
const original = new Uint8Array([0xde, 0xad, 0xbe, 0xef, 0x01, 0x23, 0x45, 0x67]);
|
|
151
|
-
const hex = bytesToHex(original);
|
|
152
|
-
const roundtripped = hexToBytes(hex);
|
|
153
|
-
expect(roundtripped).toEqual(original);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('survives roundtrip hex -> bytes -> hex', () => {
|
|
157
|
-
const original = '0xdeadbeef01234567';
|
|
158
|
-
const bytes = hexToBytes(original);
|
|
159
|
-
const roundtripped = bytesToHex(bytes);
|
|
160
|
-
expect(roundtripped).toBe(original);
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
describe('uint8ArrayToBase64', () => {
|
|
165
|
-
it('converts Uint8Array to base64', () => {
|
|
166
|
-
const bytes = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
|
|
167
|
-
expect(uint8ArrayToBase64(bytes)).toBe('SGVsbG8=');
|
|
168
|
-
});
|
|
169
|
-
|
|
170
|
-
it('handles empty array', () => {
|
|
171
|
-
expect(uint8ArrayToBase64(new Uint8Array([]))).toBe('');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('handles binary data', () => {
|
|
175
|
-
const bytes = new Uint8Array([0xff, 0x00, 0xaa, 0x55]);
|
|
176
|
-
const base64 = uint8ArrayToBase64(bytes);
|
|
177
|
-
expect(base64).toBeTruthy();
|
|
178
|
-
// Verify by round-tripping
|
|
179
|
-
expect(base64ToUint8Array(base64)).toEqual(bytes);
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it('handles single byte', () => {
|
|
183
|
-
const bytes = new Uint8Array([65]); // 'A'
|
|
184
|
-
expect(uint8ArrayToBase64(bytes)).toBe('QQ==');
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it('handles bytes requiring padding', () => {
|
|
188
|
-
const bytes = new Uint8Array([1]);
|
|
189
|
-
const base64 = uint8ArrayToBase64(bytes);
|
|
190
|
-
expect(base64).toBe('AQ==');
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
describe('base64ToUint8Array', () => {
|
|
195
|
-
it('converts base64 to Uint8Array', () => {
|
|
196
|
-
const base64 = 'SGVsbG8='; // "Hello"
|
|
197
|
-
expect(base64ToUint8Array(base64)).toEqual(new Uint8Array([72, 101, 108, 108, 111]));
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
it('handles empty string', () => {
|
|
201
|
-
expect(base64ToUint8Array('')).toEqual(new Uint8Array([]));
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('handles binary data', () => {
|
|
205
|
-
const base64 = '/wCqVQ=='; // [0xff, 0x00, 0xaa, 0x55]
|
|
206
|
-
expect(base64ToUint8Array(base64)).toEqual(new Uint8Array([0xff, 0x00, 0xaa, 0x55]));
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('handles base64 without padding', () => {
|
|
210
|
-
const base64 = 'YWJj'; // "abc" - no padding needed
|
|
211
|
-
expect(base64ToUint8Array(base64)).toEqual(new Uint8Array([97, 98, 99]));
|
|
212
|
-
});
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
describe('roundtrip uint8ArrayToBase64/base64ToUint8Array', () => {
|
|
216
|
-
it('survives roundtrip bytes -> base64 -> bytes', () => {
|
|
217
|
-
const original = new Uint8Array([0, 1, 2, 3, 255, 254, 253, 252]);
|
|
218
|
-
const base64 = uint8ArrayToBase64(original);
|
|
219
|
-
const roundtripped = base64ToUint8Array(base64);
|
|
220
|
-
expect(roundtripped).toEqual(original);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it('survives roundtrip for large arrays', () => {
|
|
224
|
-
const original = new Uint8Array(1000);
|
|
225
|
-
for (let i = 0; i < 1000; i++) {
|
|
226
|
-
original[i] = i % 256;
|
|
227
|
-
}
|
|
228
|
-
const base64 = uint8ArrayToBase64(original);
|
|
229
|
-
const roundtripped = base64ToUint8Array(base64);
|
|
230
|
-
expect(roundtripped).toEqual(original);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
});
|