@openzeppelin/miden-multisig-client 0.13.4 → 0.14.3
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 +10 -13
- package/dist/account/builder.d.ts +3 -3
- package/dist/account/builder.d.ts.map +1 -1
- package/dist/account/builder.js +10 -10
- package/dist/account/builder.js.map +1 -1
- package/dist/account/builder.test.js +16 -14
- package/dist/account/builder.test.js.map +1 -1
- package/dist/account/masm/account-components/auth.d.ts +4 -4
- package/dist/account/masm/account-components/auth.d.ts.map +1 -1
- package/dist/account/masm/account-components/auth.js +8 -12
- package/dist/account/masm/account-components/auth.js.map +1 -1
- package/dist/account/masm/auth.d.ts +4 -4
- package/dist/account/masm/auth.d.ts.map +1 -1
- package/dist/account/masm/auth.js +226 -124
- package/dist/account/masm/auth.js.map +1 -1
- package/dist/account/storage.d.ts.map +1 -1
- package/dist/account/storage.js +24 -6
- package/dist/account/storage.js.map +1 -1
- package/dist/account/storage.test.d.ts +2 -0
- package/dist/account/storage.test.d.ts.map +1 -0
- package/dist/account/storage.test.js +73 -0
- package/dist/account/storage.test.js.map +1 -0
- package/dist/client.d.ts +9 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +24 -14
- package/dist/client.js.map +1 -1
- package/dist/client.test.js +45 -8
- package/dist/client.test.js.map +1 -1
- package/dist/index.d.ts +6 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -12
- package/dist/index.js.map +1 -1
- package/dist/multisig/proposal/execution.d.ts +3 -2
- package/dist/multisig/proposal/execution.d.ts.map +1 -1
- package/dist/multisig/proposal/execution.js +8 -12
- package/dist/multisig/proposal/execution.js.map +1 -1
- package/dist/multisig.d.ts +7 -4
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +53 -35
- package/dist/multisig.js.map +1 -1
- package/dist/multisig.test.js +17 -29
- package/dist/multisig.test.js.map +1 -1
- package/dist/procedures.d.ts +8 -8
- package/dist/procedures.js +8 -8
- package/dist/raw-client.d.ts +13 -0
- package/dist/raw-client.d.ts.map +1 -0
- package/dist/raw-client.js +42 -0
- package/dist/raw-client.js.map +1 -0
- package/dist/raw-client.test.d.ts +2 -0
- package/dist/raw-client.test.d.ts.map +1 -0
- package/dist/raw-client.test.js +89 -0
- package/dist/raw-client.test.js.map +1 -0
- package/dist/signers/ecdsa.d.ts +3 -1
- package/dist/signers/ecdsa.d.ts.map +1 -1
- package/dist/signers/ecdsa.js +15 -1
- package/dist/signers/ecdsa.js.map +1 -1
- package/dist/signers/ecdsa.test.js +27 -4
- package/dist/signers/ecdsa.test.js.map +1 -1
- package/dist/signers/falcon.d.ts +3 -1
- package/dist/signers/falcon.d.ts.map +1 -1
- package/dist/signers/falcon.js +15 -1
- package/dist/signers/falcon.js.map +1 -1
- package/dist/signers/falcon.test.js +39 -3
- package/dist/signers/falcon.test.js.map +1 -1
- package/dist/transaction/consumeNotes.d.ts +2 -2
- package/dist/transaction/consumeNotes.d.ts.map +1 -1
- package/dist/transaction/consumeNotes.js +5 -4
- package/dist/transaction/consumeNotes.js.map +1 -1
- package/dist/transaction/options.d.ts +1 -0
- package/dist/transaction/options.d.ts.map +1 -1
- package/dist/transaction/p2id.d.ts.map +1 -1
- package/dist/transaction/p2id.js +7 -10
- package/dist/transaction/p2id.js.map +1 -1
- package/dist/transaction/p2id.test.js +19 -9
- package/dist/transaction/p2id.test.js.map +1 -1
- package/dist/transaction/summary.d.ts +2 -2
- package/dist/transaction/summary.d.ts.map +1 -1
- package/dist/transaction/summary.js +4 -2
- package/dist/transaction/summary.js.map +1 -1
- package/dist/transaction/updateGuardian.d.ts +2 -2
- package/dist/transaction/updateGuardian.d.ts.map +1 -1
- package/dist/transaction/updateGuardian.js +8 -11
- package/dist/transaction/updateGuardian.js.map +1 -1
- package/dist/transaction/updateProcedureThreshold.d.ts +2 -2
- package/dist/transaction/updateProcedureThreshold.d.ts.map +1 -1
- package/dist/transaction/updateProcedureThreshold.js +8 -10
- package/dist/transaction/updateProcedureThreshold.js.map +1 -1
- package/dist/transaction/updateSigners.d.ts +2 -2
- package/dist/transaction/updateSigners.d.ts.map +1 -1
- package/dist/transaction/updateSigners.js +8 -10
- package/dist/transaction/updateSigners.js.map +1 -1
- package/dist/transaction.test.js +6 -6
- package/dist/transaction.test.js.map +1 -1
- package/dist/utils/key.d.ts.map +1 -1
- package/dist/utils/key.js +3 -3
- package/dist/utils/key.js.map +1 -1
- package/dist/utils/key.test.js +4 -2
- package/dist/utils/key.test.js.map +1 -1
- package/dist/utils/signature.d.ts +2 -0
- package/dist/utils/signature.d.ts.map +1 -1
- package/dist/utils/signature.js +10 -5
- package/dist/utils/signature.js.map +1 -1
- package/dist/utils/signature.test.js +9 -9
- package/dist/utils/signature.test.js.map +1 -1
- package/masm/account_components/auth/multisig.masm +2 -3
- package/masm/account_components/auth/multisig_ecdsa.masm +2 -3
- package/masm/account_components/auth/multisig_guardian.masm +2 -3
- package/masm/account_components/auth/multisig_guardian_ecdsa.masm +2 -3
- package/masm/auth/guardian.masm +30 -8
- package/masm/auth/guardian_ecdsa.masm +24 -7
- package/masm/auth/multisig.masm +86 -55
- package/masm/auth/multisig_ecdsa.masm +86 -54
- package/package.json +3 -3
- package/src/account/builder.test.ts +16 -14
- package/src/account/builder.ts +13 -12
- package/src/account/masm/account-components/auth.ts +8 -12
- package/src/account/masm/auth.ts +226 -124
- package/src/account/storage.test.ts +90 -0
- package/src/account/storage.ts +27 -6
- package/src/client.test.ts +52 -8
- package/src/client.ts +39 -16
- package/src/index.ts +6 -12
- package/src/multisig/proposal/execution.ts +18 -14
- package/src/multisig.test.ts +17 -29
- package/src/multisig.ts +61 -36
- package/src/procedures.ts +8 -8
- package/src/raw-client.test.ts +133 -0
- package/src/raw-client.ts +75 -0
- package/src/signers/ecdsa.test.ts +35 -4
- package/src/signers/ecdsa.ts +18 -2
- package/src/signers/falcon.test.ts +50 -3
- package/src/signers/falcon.ts +18 -2
- package/src/transaction/consumeNotes.ts +16 -5
- package/src/transaction/options.ts +1 -0
- package/src/transaction/p2id.test.ts +19 -9
- package/src/transaction/p2id.ts +8 -13
- package/src/transaction/summary.ts +11 -4
- package/src/transaction/updateGuardian.ts +22 -14
- package/src/transaction/updateProcedureThreshold.ts +20 -15
- package/src/transaction/updateSigners.ts +22 -14
- package/src/transaction.test.ts +6 -6
- package/src/utils/key.test.ts +4 -2
- package/src/utils/key.ts +7 -3
- package/src/utils/signature.test.ts +10 -10
- package/src/utils/signature.ts +12 -5
package/src/signers/ecdsa.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RequestAuthPayload } from '@openzeppelin/guardian-client';
|
|
2
|
-
import { AuthSecretKey } from '@miden-sdk/miden-sdk';
|
|
2
|
+
import { AccountId, AuthSecretKey, type MidenClient, type Word } from '@miden-sdk/miden-sdk';
|
|
3
3
|
import type { Signer, SignatureScheme } from '../types.js';
|
|
4
4
|
import { bytesToHex, normalizeHexWord } from '../utils/encoding.js';
|
|
5
5
|
import { AuthDigest } from '../utils/digest.js';
|
|
@@ -9,13 +9,15 @@ export class EcdsaSigner implements Signer {
|
|
|
9
9
|
readonly publicKey: string;
|
|
10
10
|
readonly scheme: SignatureScheme = 'ecdsa';
|
|
11
11
|
private readonly secretKey: AuthSecretKey;
|
|
12
|
+
private readonly publicKeyCommitment: Word;
|
|
12
13
|
|
|
13
14
|
constructor(secretKey: AuthSecretKey) {
|
|
14
15
|
this.secretKey = secretKey;
|
|
15
16
|
const pubKey = secretKey.publicKey();
|
|
16
17
|
const serialized = pubKey.serialize();
|
|
17
18
|
this.publicKey = bytesToHex(serialized.slice(1));
|
|
18
|
-
this.
|
|
19
|
+
this.publicKeyCommitment = pubKey.toCommitment();
|
|
20
|
+
this.commitment = normalizeHexWord(this.publicKeyCommitment.toHex());
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
async signAccountIdWithTimestamp(accountId: string, timestamp: number): Promise<string> {
|
|
@@ -37,6 +39,20 @@ export class EcdsaSigner implements Signer {
|
|
|
37
39
|
return this.signWord(word);
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
async bindAccountKey(midenClient: MidenClient, accountId: string): Promise<void> {
|
|
43
|
+
const targetAccountId = AccountId.fromHex(accountId);
|
|
44
|
+
const existingAccountId = await midenClient.keystore.getAccountId(this.publicKeyCommitment);
|
|
45
|
+
if (existingAccountId) {
|
|
46
|
+
if (existingAccountId.toString().toLowerCase() === accountId.toLowerCase()) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
throw new Error(
|
|
50
|
+
`Signer commitment ${this.commitment} is already bound to account ${existingAccountId.toString()}`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
await midenClient.keystore.insert(targetAccountId, this.secretKey);
|
|
54
|
+
}
|
|
55
|
+
|
|
40
56
|
private signWord(word: ReturnType<typeof AuthDigest.fromCommitmentHex>): string {
|
|
41
57
|
const signature = this.secretKey.sign(word);
|
|
42
58
|
const signatureBytes = signature.serialize();
|
|
@@ -6,10 +6,12 @@ vi.mock('@miden-sdk/miden-sdk', () => {
|
|
|
6
6
|
serialize: () => new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
+
const mockCommitment = {
|
|
10
|
+
toHex: () => '0x' + 'a'.repeat(64),
|
|
11
|
+
};
|
|
12
|
+
|
|
9
13
|
const mockPublicKey = {
|
|
10
|
-
toCommitment: () =>
|
|
11
|
-
toHex: () => '0x' + 'a'.repeat(64),
|
|
12
|
-
}),
|
|
14
|
+
toCommitment: () => mockCommitment,
|
|
13
15
|
serialize: () => new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
|
|
14
16
|
};
|
|
15
17
|
|
|
@@ -30,6 +32,7 @@ vi.mock('@miden-sdk/miden-sdk', () => {
|
|
|
30
32
|
},
|
|
31
33
|
AccountId: {
|
|
32
34
|
fromHex: vi.fn((hex: string) => ({
|
|
35
|
+
toString: () => hex,
|
|
33
36
|
prefix: () => ({ asInt: () => BigInt(1) }),
|
|
34
37
|
suffix: () => ({ asInt: () => BigInt(2) }),
|
|
35
38
|
})),
|
|
@@ -147,4 +150,48 @@ describe('FalconSigner', () => {
|
|
|
147
150
|
expect(signature).toBe('0x010203040506070809');
|
|
148
151
|
});
|
|
149
152
|
});
|
|
153
|
+
|
|
154
|
+
describe('bindAccountKey', () => {
|
|
155
|
+
it('inserts the signer key when the commitment is not bound yet', async () => {
|
|
156
|
+
const midenClient = {
|
|
157
|
+
keystore: {
|
|
158
|
+
getAccountId: vi.fn().mockResolvedValue(null),
|
|
159
|
+
insert: vi.fn().mockResolvedValue(undefined),
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
await signer.bindAccountKey(midenClient as never, '0x' + 'd'.repeat(30));
|
|
164
|
+
|
|
165
|
+
expect(midenClient.keystore.getAccountId).toHaveBeenCalledTimes(1);
|
|
166
|
+
expect(midenClient.keystore.insert).toHaveBeenCalledTimes(1);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('skips insert when the signer key is already bound to the same account', async () => {
|
|
170
|
+
const accountId = '0x' + 'd'.repeat(30);
|
|
171
|
+
const midenClient = {
|
|
172
|
+
keystore: {
|
|
173
|
+
getAccountId: vi.fn().mockResolvedValue({ toString: () => accountId }),
|
|
174
|
+
insert: vi.fn().mockResolvedValue(undefined),
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
await signer.bindAccountKey(midenClient as never, accountId);
|
|
179
|
+
|
|
180
|
+
expect(midenClient.keystore.insert).not.toHaveBeenCalled();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('throws when the signer key is already bound to a different account', async () => {
|
|
184
|
+
const midenClient = {
|
|
185
|
+
keystore: {
|
|
186
|
+
getAccountId: vi.fn().mockResolvedValue({ toString: () => '0x' + 'e'.repeat(30) }),
|
|
187
|
+
insert: vi.fn().mockResolvedValue(undefined),
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
await expect(
|
|
192
|
+
signer.bindAccountKey(midenClient as never, '0x' + 'd'.repeat(30)),
|
|
193
|
+
).rejects.toThrow('already bound to account');
|
|
194
|
+
expect(midenClient.keystore.insert).not.toHaveBeenCalled();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
150
197
|
});
|
package/src/signers/falcon.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RequestAuthPayload } from '@openzeppelin/guardian-client';
|
|
2
|
-
import { AuthSecretKey, type Word } from '@miden-sdk/miden-sdk';
|
|
2
|
+
import { AccountId, AuthSecretKey, type MidenClient, type Word } from '@miden-sdk/miden-sdk';
|
|
3
3
|
import type { Signer, SignatureScheme } from '../types.js';
|
|
4
4
|
import { bytesToHex } from '../utils/encoding.js';
|
|
5
5
|
import { AuthDigest } from '../utils/digest.js';
|
|
@@ -9,11 +9,13 @@ export class FalconSigner implements Signer {
|
|
|
9
9
|
readonly publicKey: string;
|
|
10
10
|
readonly scheme: SignatureScheme = 'falcon';
|
|
11
11
|
private readonly secretKey: AuthSecretKey;
|
|
12
|
+
private readonly publicKeyCommitment: Word;
|
|
12
13
|
|
|
13
14
|
constructor(secretKey: AuthSecretKey) {
|
|
14
15
|
this.secretKey = secretKey;
|
|
15
16
|
const pubKey = secretKey.publicKey();
|
|
16
|
-
this.
|
|
17
|
+
this.publicKeyCommitment = pubKey.toCommitment();
|
|
18
|
+
this.commitment = this.publicKeyCommitment.toHex();
|
|
17
19
|
const serialized = pubKey.serialize();
|
|
18
20
|
const falconPubKey = serialized.slice(1);
|
|
19
21
|
this.publicKey = bytesToHex(falconPubKey);
|
|
@@ -38,6 +40,20 @@ export class FalconSigner implements Signer {
|
|
|
38
40
|
return this.signWord(word);
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
async bindAccountKey(midenClient: MidenClient, accountId: string): Promise<void> {
|
|
44
|
+
const targetAccountId = AccountId.fromHex(accountId);
|
|
45
|
+
const existingAccountId = await midenClient.keystore.getAccountId(this.publicKeyCommitment);
|
|
46
|
+
if (existingAccountId) {
|
|
47
|
+
if (existingAccountId.toString().toLowerCase() === accountId.toLowerCase()) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
throw new Error(
|
|
51
|
+
`Signer commitment ${this.commitment} is already bound to account ${existingAccountId.toString()}`,
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
await midenClient.keystore.insert(targetAccountId, this.secretKey);
|
|
55
|
+
}
|
|
56
|
+
|
|
41
57
|
private signWord(word: Word): string {
|
|
42
58
|
const signature = this.secretKey.sign(word);
|
|
43
59
|
const signatureBytes = signature.serialize();
|
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
MidenClient,
|
|
3
|
+
TransactionRequest,
|
|
4
|
+
WasmWebClient,
|
|
5
|
+
Word,
|
|
6
|
+
} from '@miden-sdk/miden-sdk';
|
|
7
|
+
import {
|
|
8
|
+
NoteAndArgs,
|
|
9
|
+
NoteAndArgsArray,
|
|
10
|
+
TransactionRequestBuilder,
|
|
11
|
+
Word as WordType,
|
|
12
|
+
} from '@miden-sdk/miden-sdk';
|
|
13
|
+
import { getRawMidenClient } from '../raw-client.js';
|
|
3
14
|
import { randomWord } from '../utils/random.js';
|
|
4
15
|
import { normalizeHexWord } from '../utils/encoding.js';
|
|
5
16
|
import type { SignatureOptions } from './options.js';
|
|
6
17
|
|
|
7
18
|
export async function buildConsumeNotesTransactionRequest(
|
|
8
|
-
|
|
19
|
+
client: MidenClient | WasmWebClient,
|
|
9
20
|
noteIds: string[],
|
|
10
21
|
options: SignatureOptions = {},
|
|
11
22
|
): Promise<{ request: TransactionRequest; salt: Word }> {
|
|
@@ -13,10 +24,10 @@ export async function buildConsumeNotesTransactionRequest(
|
|
|
13
24
|
throw new Error('At least one note ID is required');
|
|
14
25
|
}
|
|
15
26
|
|
|
16
|
-
|
|
27
|
+
const rawClient = await getRawMidenClient(client, options.midenRpcEndpoint);
|
|
17
28
|
const noteAndArgsArray = new NoteAndArgsArray();
|
|
18
29
|
for (const noteIdHex of noteIds) {
|
|
19
|
-
const inputNoteRecord = await
|
|
30
|
+
const inputNoteRecord = await rawClient.getInputNote(noteIdHex);
|
|
20
31
|
if (!inputNoteRecord) {
|
|
21
32
|
throw new Error(`Note not found in local store: ${noteIdHex}`);
|
|
22
33
|
}
|
|
@@ -21,10 +21,20 @@ const {
|
|
|
21
21
|
mockRandomWord: vi.fn().mockReturnValue({
|
|
22
22
|
toHex: () => '0x' + 'aa'.repeat(32),
|
|
23
23
|
}),
|
|
24
|
-
mockWordFromHex: vi.fn((hex: string) =>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
mockWordFromHex: vi.fn((hex: string) => {
|
|
25
|
+
const normalized = hex.toLowerCase();
|
|
26
|
+
return {
|
|
27
|
+
toHex: () => hex,
|
|
28
|
+
toFelts: () => normalized === `0x${'00'.repeat(32)}`
|
|
29
|
+
? [
|
|
30
|
+
{ value: 0n },
|
|
31
|
+
{ value: 0n },
|
|
32
|
+
{ value: 0n },
|
|
33
|
+
{ value: 0n },
|
|
34
|
+
]
|
|
35
|
+
: saltFelts,
|
|
36
|
+
};
|
|
37
|
+
}),
|
|
28
38
|
saltFelts,
|
|
29
39
|
};
|
|
30
40
|
});
|
|
@@ -50,7 +60,7 @@ vi.mock('@miden-sdk/miden-sdk', () => {
|
|
|
50
60
|
constructor(_assets: unknown[]) {}
|
|
51
61
|
}
|
|
52
62
|
|
|
53
|
-
class
|
|
63
|
+
class NoteStorage {
|
|
54
64
|
constructor(_inputs: FeltArray) {}
|
|
55
65
|
}
|
|
56
66
|
|
|
@@ -82,7 +92,7 @@ vi.mock('@miden-sdk/miden-sdk', () => {
|
|
|
82
92
|
constructor(_faucet: unknown, _amount: bigint) {}
|
|
83
93
|
}
|
|
84
94
|
|
|
85
|
-
class
|
|
95
|
+
class NoteArray {
|
|
86
96
|
constructor(_notes: unknown[]) {}
|
|
87
97
|
}
|
|
88
98
|
|
|
@@ -116,13 +126,13 @@ vi.mock('@miden-sdk/miden-sdk', () => {
|
|
|
116
126
|
FeltArray,
|
|
117
127
|
FungibleAsset,
|
|
118
128
|
MidenArrays: {
|
|
119
|
-
|
|
129
|
+
NoteArray,
|
|
120
130
|
},
|
|
121
131
|
Note,
|
|
122
132
|
NoteAssets,
|
|
123
|
-
NoteInputs,
|
|
124
133
|
NoteMetadata,
|
|
125
134
|
NoteRecipient,
|
|
135
|
+
NoteStorage,
|
|
126
136
|
NoteScript: {
|
|
127
137
|
p2id: vi.fn(() => ({ kind: 'p2id-script' })),
|
|
128
138
|
},
|
|
@@ -135,7 +145,7 @@ vi.mock('@miden-sdk/miden-sdk', () => {
|
|
|
135
145
|
OutputNote: {
|
|
136
146
|
full: vi.fn((note: unknown) => ({ note })),
|
|
137
147
|
},
|
|
138
|
-
|
|
148
|
+
Poseidon2: {
|
|
139
149
|
hashElements: mockHashElements,
|
|
140
150
|
},
|
|
141
151
|
TransactionRequestBuilder,
|
package/src/transaction/p2id.ts
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import type { TransactionRequest, Word } from '@miden-sdk/miden-sdk';
|
|
2
2
|
import {
|
|
3
3
|
AccountId,
|
|
4
|
-
Felt,
|
|
5
4
|
FeltArray,
|
|
6
5
|
FungibleAsset,
|
|
7
6
|
MidenArrays,
|
|
8
7
|
Note,
|
|
9
8
|
NoteAssets,
|
|
10
|
-
NoteInputs,
|
|
11
9
|
NoteMetadata,
|
|
12
10
|
NoteRecipient,
|
|
13
11
|
NoteScript,
|
|
12
|
+
NoteStorage,
|
|
14
13
|
NoteTag,
|
|
15
14
|
NoteType,
|
|
16
|
-
|
|
17
|
-
Rpo256,
|
|
15
|
+
Poseidon2,
|
|
18
16
|
TransactionRequestBuilder,
|
|
19
17
|
Word as WordType,
|
|
20
18
|
} from '@miden-sdk/miden-sdk';
|
|
@@ -23,12 +21,10 @@ import { normalizeHexWord } from '../utils/encoding.js';
|
|
|
23
21
|
import type { SignatureOptions } from './options.js';
|
|
24
22
|
|
|
25
23
|
export function deriveP2idSerialNumber(salt: Word): Word {
|
|
26
|
-
|
|
24
|
+
const zeroWord = WordType.fromHex(`0x${'00'.repeat(32)}`);
|
|
25
|
+
return Poseidon2.hashElements(new FeltArray([
|
|
27
26
|
...salt.toFelts(),
|
|
28
|
-
|
|
29
|
-
new Felt(0n),
|
|
30
|
-
new Felt(0n),
|
|
31
|
-
new Felt(0n),
|
|
27
|
+
...zeroWord.toFelts(),
|
|
32
28
|
]));
|
|
33
29
|
}
|
|
34
30
|
|
|
@@ -43,12 +39,12 @@ function buildP2idNote(
|
|
|
43
39
|
const serialNum = deriveP2idSerialNumber(salt);
|
|
44
40
|
|
|
45
41
|
const noteScript = NoteScript.p2id();
|
|
46
|
-
const
|
|
42
|
+
const noteStorage = new NoteStorage(new FeltArray([
|
|
47
43
|
recipient.suffix(),
|
|
48
44
|
recipient.prefix(),
|
|
49
45
|
]));
|
|
50
46
|
|
|
51
|
-
const noteRecipient = new NoteRecipient(serialNum, noteScript,
|
|
47
|
+
const noteRecipient = new NoteRecipient(serialNum, noteScript, noteStorage);
|
|
52
48
|
const noteTag = NoteTag.withAccountTarget(recipient);
|
|
53
49
|
|
|
54
50
|
const noteMetadata = new NoteMetadata(
|
|
@@ -84,8 +80,7 @@ export function buildP2idTransactionRequest(
|
|
|
84
80
|
authSaltHex,
|
|
85
81
|
);
|
|
86
82
|
|
|
87
|
-
const
|
|
88
|
-
const outputNotes = new MidenArrays.OutputNoteArray([outputNote]);
|
|
83
|
+
const outputNotes = new MidenArrays.NoteArray([note]);
|
|
89
84
|
|
|
90
85
|
const authSaltForBuilder = WordType.fromHex(normalizeHexWord(authSaltHex));
|
|
91
86
|
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
MidenClient,
|
|
3
|
+
TransactionRequest,
|
|
4
|
+
TransactionSummary,
|
|
5
|
+
WasmWebClient,
|
|
6
|
+
} from '@miden-sdk/miden-sdk';
|
|
2
7
|
import { AccountId } from '@miden-sdk/miden-sdk';
|
|
8
|
+
import { getRawMidenClient } from '../raw-client.js';
|
|
3
9
|
|
|
4
10
|
export async function executeForSummary(
|
|
5
|
-
client:
|
|
11
|
+
client: MidenClient | WasmWebClient,
|
|
6
12
|
accountId: string,
|
|
7
13
|
txRequest: TransactionRequest,
|
|
14
|
+
midenRpcEndpoint?: string,
|
|
8
15
|
): Promise<TransactionSummary> {
|
|
9
16
|
const acc = AccountId.fromHex(accountId);
|
|
10
|
-
|
|
17
|
+
const rawClient = await getRawMidenClient(client, midenRpcEndpoint);
|
|
18
|
+
return rawClient.executeForSummary(acc, txRequest);
|
|
11
19
|
}
|
|
12
|
-
|
|
@@ -1,50 +1,58 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AdviceMap,
|
|
3
3
|
FeltArray,
|
|
4
|
+
type MidenClient,
|
|
4
5
|
TransactionRequest,
|
|
5
6
|
TransactionRequestBuilder,
|
|
6
7
|
TransactionScript,
|
|
7
|
-
|
|
8
|
+
type WasmWebClient,
|
|
8
9
|
Word,
|
|
9
10
|
Word as WordType,
|
|
10
11
|
} from '@miden-sdk/miden-sdk';
|
|
11
12
|
import { GUARDIAN_ECDSA_MASM, GUARDIAN_MASM } from '../account/masm/auth.js';
|
|
13
|
+
import { compileTxScript } from '../raw-client.js';
|
|
12
14
|
import { normalizeHexWord } from '../utils/encoding.js';
|
|
13
15
|
import { randomWord } from '../utils/random.js';
|
|
14
16
|
import type { SignatureOptions } from './options.js';
|
|
15
17
|
import type { SignatureScheme } from '../types.js';
|
|
16
18
|
|
|
17
|
-
function buildUpdateGuardianScript(
|
|
18
|
-
|
|
19
|
+
async function buildUpdateGuardianScript(
|
|
20
|
+
client: MidenClient | WasmWebClient,
|
|
19
21
|
signatureScheme: SignatureScheme,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const guardianLibraryPath =
|
|
22
|
+
midenRpcEndpoint?: string,
|
|
23
|
+
): Promise<TransactionScript> {
|
|
24
|
+
const guardianLibraryPath = 'oz_guardian::guardian';
|
|
23
25
|
const guardianMasm = signatureScheme === 'ecdsa' ? GUARDIAN_ECDSA_MASM : GUARDIAN_MASM;
|
|
24
|
-
const guardianProcedure = signatureScheme === 'ecdsa' ? 'guardian_ecdsa' : 'guardian';
|
|
25
|
-
const guardianLib = libBuilder.buildLibrary(guardianLibraryPath, guardianMasm);
|
|
26
|
-
libBuilder.linkDynamicLibrary(guardianLib);
|
|
27
26
|
|
|
28
27
|
const scriptSource = `
|
|
29
|
-
use
|
|
28
|
+
use oz_guardian::guardian
|
|
30
29
|
|
|
31
30
|
begin
|
|
32
31
|
adv.push_mapval
|
|
33
32
|
dropw
|
|
34
|
-
call
|
|
33
|
+
call.guardian::update_guardian_public_key
|
|
35
34
|
end
|
|
36
35
|
`;
|
|
37
36
|
|
|
38
|
-
return
|
|
37
|
+
return compileTxScript(
|
|
38
|
+
client,
|
|
39
|
+
scriptSource,
|
|
40
|
+
[{ namespace: guardianLibraryPath, code: guardianMasm }],
|
|
41
|
+
midenRpcEndpoint,
|
|
42
|
+
);
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
export async function buildUpdateGuardianTransactionRequest(
|
|
42
|
-
|
|
46
|
+
client: MidenClient | WasmWebClient,
|
|
43
47
|
newGuardianPubkey: string,
|
|
44
48
|
options: SignatureOptions = {},
|
|
45
49
|
): Promise<{ request: TransactionRequest; salt: Word }> {
|
|
46
50
|
const signatureScheme = options.signatureScheme ?? 'falcon';
|
|
47
|
-
const script = buildUpdateGuardianScript(
|
|
51
|
+
const script = await buildUpdateGuardianScript(
|
|
52
|
+
client,
|
|
53
|
+
signatureScheme,
|
|
54
|
+
options.midenRpcEndpoint,
|
|
55
|
+
);
|
|
48
56
|
|
|
49
57
|
const authSaltHex = options.salt ? options.salt.toHex() : randomWord().toHex();
|
|
50
58
|
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Felt,
|
|
3
3
|
FeltArray,
|
|
4
|
-
|
|
4
|
+
type MidenClient,
|
|
5
|
+
Poseidon2,
|
|
5
6
|
TransactionRequest,
|
|
6
7
|
TransactionRequestBuilder,
|
|
7
8
|
TransactionScript,
|
|
8
|
-
|
|
9
|
+
type WasmWebClient,
|
|
9
10
|
Word,
|
|
10
11
|
Word as WordType,
|
|
11
12
|
} from '@miden-sdk/miden-sdk';
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
MULTISIG_MASM,
|
|
15
16
|
} from '../account/masm/auth.js';
|
|
16
17
|
import { getProcedureRoot, type ProcedureName } from '../procedures.js';
|
|
18
|
+
import { compileTxScript } from '../raw-client.js';
|
|
17
19
|
import { normalizeHexWord } from '../utils/encoding.js';
|
|
18
20
|
import { randomWord } from '../utils/random.js';
|
|
19
21
|
import type { SignatureOptions } from './options.js';
|
|
@@ -31,25 +33,22 @@ function buildProcedureThresholdAdvice(
|
|
|
31
33
|
new Felt(0n),
|
|
32
34
|
new Felt(0n),
|
|
33
35
|
]);
|
|
34
|
-
const configHash =
|
|
36
|
+
const configHash = Poseidon2.hashElements(payload);
|
|
35
37
|
return { configHash, payload };
|
|
36
38
|
}
|
|
37
39
|
|
|
38
|
-
function buildUpdateProcedureThresholdScript(
|
|
39
|
-
|
|
40
|
+
async function buildUpdateProcedureThresholdScript(
|
|
41
|
+
client: MidenClient | WasmWebClient,
|
|
40
42
|
procedure: ProcedureName,
|
|
41
43
|
threshold: number,
|
|
42
44
|
signatureScheme: SignatureScheme,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
+
midenRpcEndpoint?: string,
|
|
46
|
+
): Promise<TransactionScript> {
|
|
45
47
|
const multisigMasm = signatureScheme === 'ecdsa' ? MULTISIG_ECDSA_MASM : MULTISIG_MASM;
|
|
46
|
-
|
|
47
|
-
const multisigLib = libBuilder.buildLibrary('auth::multisig', multisigMasm);
|
|
48
|
-
libBuilder.linkDynamicLibrary(multisigLib);
|
|
49
48
|
const procedureRoot = normalizeHexWord(getProcedureRoot(procedure));
|
|
50
49
|
|
|
51
50
|
const scriptSource = `
|
|
52
|
-
use
|
|
51
|
+
use oz_multisig::multisig
|
|
53
52
|
|
|
54
53
|
begin
|
|
55
54
|
push.${procedureRoot}
|
|
@@ -60,11 +59,16 @@ begin
|
|
|
60
59
|
end
|
|
61
60
|
`;
|
|
62
61
|
|
|
63
|
-
return
|
|
62
|
+
return compileTxScript(
|
|
63
|
+
client,
|
|
64
|
+
scriptSource,
|
|
65
|
+
[{ namespace: 'oz_multisig::multisig', code: multisigMasm }],
|
|
66
|
+
midenRpcEndpoint,
|
|
67
|
+
);
|
|
64
68
|
}
|
|
65
69
|
|
|
66
70
|
export async function buildUpdateProcedureThresholdTransactionRequest(
|
|
67
|
-
|
|
71
|
+
client: MidenClient | WasmWebClient,
|
|
68
72
|
procedure: ProcedureName,
|
|
69
73
|
threshold: number,
|
|
70
74
|
options: SignatureOptions = {},
|
|
@@ -72,11 +76,12 @@ export async function buildUpdateProcedureThresholdTransactionRequest(
|
|
|
72
76
|
const signatureScheme = options.signatureScheme ?? 'falcon';
|
|
73
77
|
const { configHash } = buildProcedureThresholdAdvice(procedure, threshold);
|
|
74
78
|
|
|
75
|
-
const script = buildUpdateProcedureThresholdScript(
|
|
76
|
-
|
|
79
|
+
const script = await buildUpdateProcedureThresholdScript(
|
|
80
|
+
client,
|
|
77
81
|
procedure,
|
|
78
82
|
threshold,
|
|
79
83
|
signatureScheme,
|
|
84
|
+
options.midenRpcEndpoint,
|
|
80
85
|
);
|
|
81
86
|
const authSaltHex = options.salt ? options.salt.toHex() : randomWord().toHex();
|
|
82
87
|
const authSalt = WordType.fromHex(normalizeHexWord(authSaltHex));
|
|
@@ -2,11 +2,12 @@ import {
|
|
|
2
2
|
AdviceMap,
|
|
3
3
|
Felt,
|
|
4
4
|
FeltArray,
|
|
5
|
-
|
|
5
|
+
type MidenClient,
|
|
6
|
+
Poseidon2,
|
|
6
7
|
TransactionRequest,
|
|
7
8
|
TransactionRequestBuilder,
|
|
8
9
|
TransactionScript,
|
|
9
|
-
|
|
10
|
+
type WasmWebClient,
|
|
10
11
|
Word,
|
|
11
12
|
Word as WordType,
|
|
12
13
|
} from '@miden-sdk/miden-sdk';
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
MULTISIG_ECDSA_MASM,
|
|
15
16
|
MULTISIG_MASM,
|
|
16
17
|
} from '../account/masm/auth.js';
|
|
18
|
+
import { compileTxScript } from '../raw-client.js';
|
|
17
19
|
import { normalizeHexWord } from '../utils/encoding.js';
|
|
18
20
|
import { randomWord } from '../utils/random.js';
|
|
19
21
|
import type { SignatureOptions } from './options.js';
|
|
@@ -35,33 +37,35 @@ function buildMultisigConfigAdvice(
|
|
|
35
37
|
felts.push(...word.toFelts());
|
|
36
38
|
}
|
|
37
39
|
const payload = new FeltArray(felts);
|
|
38
|
-
const configHash =
|
|
40
|
+
const configHash = Poseidon2.hashElements(payload);
|
|
39
41
|
return { configHash, payload };
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
function buildUpdateSignersScript(
|
|
43
|
-
|
|
44
|
+
async function buildUpdateSignersScript(
|
|
45
|
+
client: MidenClient | WasmWebClient,
|
|
44
46
|
signatureScheme: SignatureScheme,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
midenRpcEndpoint?: string,
|
|
48
|
+
): Promise<TransactionScript> {
|
|
47
49
|
const multisigMasm = signatureScheme === 'ecdsa' ? MULTISIG_ECDSA_MASM : MULTISIG_MASM;
|
|
48
50
|
|
|
49
|
-
const multisigLib = libBuilder.buildLibrary('auth::multisig', multisigMasm);
|
|
50
|
-
libBuilder.linkDynamicLibrary(multisigLib);
|
|
51
|
-
|
|
52
51
|
const scriptSource = `
|
|
53
|
-
use
|
|
52
|
+
use oz_multisig::multisig
|
|
54
53
|
|
|
55
54
|
begin
|
|
56
55
|
call.multisig::update_signers_and_threshold
|
|
57
56
|
end
|
|
58
57
|
`;
|
|
59
58
|
|
|
60
|
-
return
|
|
59
|
+
return compileTxScript(
|
|
60
|
+
client,
|
|
61
|
+
scriptSource,
|
|
62
|
+
[{ namespace: 'oz_multisig::multisig', code: multisigMasm }],
|
|
63
|
+
midenRpcEndpoint,
|
|
64
|
+
);
|
|
61
65
|
}
|
|
62
66
|
|
|
63
67
|
export async function buildUpdateSignersTransactionRequest(
|
|
64
|
-
|
|
68
|
+
client: MidenClient | WasmWebClient,
|
|
65
69
|
threshold: number,
|
|
66
70
|
signerCommitments: string[],
|
|
67
71
|
options: SignatureOptions = {},
|
|
@@ -76,7 +80,11 @@ export async function buildUpdateSignersTransactionRequest(
|
|
|
76
80
|
const advice = new AdviceMap();
|
|
77
81
|
advice.insert(configHashForAdvice, payload);
|
|
78
82
|
|
|
79
|
-
const script = buildUpdateSignersScript(
|
|
83
|
+
const script = await buildUpdateSignersScript(
|
|
84
|
+
client,
|
|
85
|
+
signatureScheme,
|
|
86
|
+
options.midenRpcEndpoint,
|
|
87
|
+
);
|
|
80
88
|
|
|
81
89
|
const authSaltHex = options.salt ? options.salt.toHex() : randomWord().toHex();
|
|
82
90
|
|
package/src/transaction.test.ts
CHANGED
|
@@ -6,7 +6,7 @@ vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
|
6
6
|
AdviceMap: vi.fn(),
|
|
7
7
|
Felt: vi.fn().mockImplementation((v) => ({ value: v })),
|
|
8
8
|
FeltArray: vi.fn().mockImplementation((arr) => arr),
|
|
9
|
-
|
|
9
|
+
Poseidon2: { hashElements: vi.fn() },
|
|
10
10
|
Signature: { deserialize: vi.fn() },
|
|
11
11
|
TransactionRequestBuilder: vi.fn().mockImplementation(() => ({
|
|
12
12
|
withCustomScript: vi.fn().mockReturnThis(),
|
|
@@ -110,21 +110,21 @@ describe('transaction utilities', () => {
|
|
|
110
110
|
});
|
|
111
111
|
|
|
112
112
|
describe('signatureHexToBytes', () => {
|
|
113
|
-
it('should prepend auth scheme byte (
|
|
113
|
+
it('should prepend auth scheme byte (2 = Falcon Poseidon2)', () => {
|
|
114
114
|
const result = signatureHexToBytes('deadbeef');
|
|
115
|
-
expect(result[0]).toBe(
|
|
115
|
+
expect(result[0]).toBe(2);
|
|
116
116
|
expect(result.slice(1)).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
it('should prepend auth scheme byte (1 = ECDSA)', () => {
|
|
120
120
|
const result = signatureHexToBytes('deadbeef', 'ecdsa');
|
|
121
|
-
expect(result[0]).toBe(1);
|
|
121
|
+
expect(result[0]).toBe(1);
|
|
122
122
|
expect(result.slice(1)).toEqual(new Uint8Array([0xde, 0xad, 0xbe, 0xef]));
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
it('should handle 0x prefix', () => {
|
|
126
126
|
const result = signatureHexToBytes('0xaabbccdd');
|
|
127
|
-
expect(result[0]).toBe(
|
|
127
|
+
expect(result[0]).toBe(2);
|
|
128
128
|
expect(result.slice(1)).toEqual(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]));
|
|
129
129
|
});
|
|
130
130
|
|
|
@@ -136,7 +136,7 @@ describe('transaction utilities', () => {
|
|
|
136
136
|
|
|
137
137
|
it('should handle empty signature', () => {
|
|
138
138
|
const result = signatureHexToBytes('');
|
|
139
|
-
expect(result).toEqual(new Uint8Array([
|
|
139
|
+
expect(result).toEqual(new Uint8Array([2]));
|
|
140
140
|
});
|
|
141
141
|
});
|
|
142
142
|
});
|
package/src/utils/key.test.ts
CHANGED
|
@@ -18,6 +18,8 @@ vi.mock('@miden-sdk/miden-sdk', () => ({
|
|
|
18
18
|
}));
|
|
19
19
|
|
|
20
20
|
vi.mock('./signature.js', () => ({
|
|
21
|
+
ECDSA_AUTH_SCHEME_ID: 1,
|
|
22
|
+
FALCON_AUTH_SCHEME_ID: 2,
|
|
21
23
|
tryComputeCommitmentHex: vi.fn((_hex: string, _scheme: string) => '0x' + 'cc'.repeat(32)),
|
|
22
24
|
}));
|
|
23
25
|
|
|
@@ -32,9 +34,9 @@ describe('PublicKeyFormat', () => {
|
|
|
32
34
|
expect(result.publicKeyHex).toMatch(/^0x[a-f0-9]{64}$/);
|
|
33
35
|
});
|
|
34
36
|
|
|
35
|
-
it('should detect
|
|
37
|
+
it('should detect 0x02-prefixed key as falcon', () => {
|
|
36
38
|
const bytes = new Uint8Array(200);
|
|
37
|
-
bytes[0] =
|
|
39
|
+
bytes[0] = 0x02;
|
|
38
40
|
bytes[1] = 0xab;
|
|
39
41
|
const result = PublicKeyFormat.parse(bytes);
|
|
40
42
|
expect(result.scheme).toBe('falcon');
|