@openzeppelin/compact-contracts 0.3.0-alpha.2 → 0.4.0-alpha.1
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 -4
- package/access/AccessControl.compact +2 -2
- package/access/Ownable.compact +2 -2
- package/access/ShieldedAccessControl.compact +2 -2
- package/access/ZOwnablePK.compact +2 -2
- package/crypto/EcdhMask.compact +5 -5
- package/crypto/Ecdsa.compact +111 -0
- package/crypto/ElGamal.compact +33 -66
- package/multisig/EcdsaSignerManager.compact +229 -0
- package/multisig/ForwarderPrivate.compact +2 -2
- package/multisig/ForwarderShielded.compact +2 -2
- package/multisig/ForwarderUnshielded.compact +2 -2
- package/multisig/ProposalManager.compact +2 -2
- package/multisig/ShieldedTreasury.compact +2 -2
- package/multisig/ShieldedTreasuryStateless.compact +2 -2
- package/multisig/Signer.compact +2 -2
- package/multisig/UnshieldedTreasury.compact +2 -2
- package/multisig/presets/ShieldedMultiSig.compact +2 -2
- package/multisig/presets/ShieldedMultiSigV2.compact +72 -127
- package/multisig/presets/ShieldedMultiSigV3.compact +81 -138
- package/multisig/presets/forwarder/ForwarderPrivate.compact +2 -2
- package/multisig/presets/forwarder/ForwarderShielded.compact +2 -2
- package/multisig/presets/forwarder/ForwarderUnshielded.compact +2 -2
- package/package.json +22 -20
- package/security/Allowlist.compact +2 -2
- package/security/Blocklist.compact +2 -2
- package/security/Initializable.compact +2 -2
- package/security/Pausable.compact +2 -2
- package/token/ConfidentialFungibleToken.compact +9 -9
- package/token/FungibleToken.compact +2 -2
- package/token/MultiToken.compact +2 -2
- package/token/NativeShieldedToken.compact +2 -2
- package/token/NativeShieldedTokenCore.compact +2 -2
- package/token/NativeShieldedTokenFamily.compact +2 -2
- package/token/NonFungibleToken.compact +2 -2
- package/token/extensions/ConfidentialFungibleTokenPublicSupply.compact +2 -2
- package/token/extensions/NativeShieldedTokenDerivedNonce.compact +2 -2
- package/token/extensions/NativeShieldedTokenFamilyPublicSupply.compact +1 -1
- package/token/extensions/NativeShieldedTokenPublicSupply.compact +1 -1
- package/token/extensions/NativeShieldedTokenPublicSupplyCore.compact +1 -1
- package/utils/Utils.compact +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/ForwarderShielded.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @module ForwarderShielded
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/ForwarderUnshielded.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @module ForwarderUnshielded
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/ProposalManager.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @module ProposalManager
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/ShieldedTreasury.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @module ShieldedTreasury
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/ShieldedTreasuryStateless.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @module ShieldedTreasuryStateless
|
package/multisig/Signer.compact
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/Signer.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @module Signer<T>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/UnshieldedTreasury.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @module UnshieldedTreasury
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/presets/ShieldedMultiSig.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @module ShieldedMultiSig
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.4.0-alpha.1 (multisig/presets/ShieldedMultiSigV2.compact)
|
|
3
3
|
|
|
4
|
-
pragma language_version >= 0.
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @title ShieldedMultisigV2
|
|
@@ -22,38 +22,13 @@ pragma language_version >= 0.23.0;
|
|
|
22
22
|
|
|
23
23
|
import CompactStandardLibrary;
|
|
24
24
|
|
|
25
|
+
import "../EcdsaSignerManager" prefix EcdsaSignerManager_;
|
|
25
26
|
import "../ProposalManager" prefix Proposal_;
|
|
26
27
|
import "../ShieldedTreasuryStateless" prefix Treasury_;
|
|
27
|
-
import "../Signer"<Bytes<32>> prefix Signer_;
|
|
28
|
-
|
|
29
|
-
// ─── Types ──────────────────────────────────────────────────────
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* @description Accumulator for fold-based signature verification.
|
|
33
|
-
* Threads the valid count, previous commitment (for duplicate
|
|
34
|
-
* detection), and message hash through each iteration.
|
|
35
|
-
*/
|
|
36
|
-
export struct VerificationState {
|
|
37
|
-
validCount: Uint<8>,
|
|
38
|
-
prevCommitment: Bytes<32>,
|
|
39
|
-
msgHash: Bytes<32>
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @description Input to persistentHash for computing signer commitments.
|
|
44
|
-
* Combines the ECDSA public key with an instance-specific salt and
|
|
45
|
-
* domain separator to produce a unique, unlinkable commitment.
|
|
46
|
-
*/
|
|
47
|
-
export struct SignerCommitmentInput {
|
|
48
|
-
pk: Bytes<64>,
|
|
49
|
-
salt: Bytes<32>,
|
|
50
|
-
domain: Bytes<32>
|
|
51
|
-
}
|
|
52
28
|
|
|
53
29
|
// ─── State ──────────────────────────────────────────────────────
|
|
54
30
|
|
|
55
31
|
ledger _nonce: Counter;
|
|
56
|
-
ledger _instanceSalt: Bytes<32>;
|
|
57
32
|
|
|
58
33
|
// ─── Constructor ────────────────────────────────────────────────
|
|
59
34
|
|
|
@@ -61,14 +36,17 @@ ledger _instanceSalt: Bytes<32>;
|
|
|
61
36
|
* @description Deploys the multisig with 3 signer commitments and
|
|
62
37
|
* a threshold.
|
|
63
38
|
*
|
|
64
|
-
* Each commitment is
|
|
65
|
-
*
|
|
66
|
-
*
|
|
39
|
+
* Each commitment is `persistentHash(pkX, pkY, instanceSalt,
|
|
40
|
+
* "multisig:signer:")`. Use the exported `_calculateSignerId` circuit to
|
|
41
|
+
* derive them consistently with in-circuit verification.
|
|
67
42
|
*
|
|
68
43
|
* The instanceSalt should be a random value to prevent the same public
|
|
69
44
|
* key from producing the same commitment across different multisig
|
|
70
45
|
* deployments, breaking cross-contract signer correlation.
|
|
71
46
|
*
|
|
47
|
+
* @dev A threshold of 1 does not weaken `execute`, which always verifies two
|
|
48
|
+
* distinct registered signers.
|
|
49
|
+
*
|
|
72
50
|
* Requirements:
|
|
73
51
|
*
|
|
74
52
|
* - `thresh` must be > 0 and <= 2 (matches the 2-signature `execute` surface).
|
|
@@ -88,8 +66,7 @@ constructor(
|
|
|
88
66
|
thresh <= 2,
|
|
89
67
|
"ShieldedMultiSigV2: threshold cannot exceed 2 (execute verifies at most 2 signatures)"
|
|
90
68
|
);
|
|
91
|
-
|
|
92
|
-
Signer_initialize<3>(signerCommitments, thresh);
|
|
69
|
+
EcdsaSignerManager_initialize<3>(instanceSalt, signerCommitments, thresh);
|
|
93
70
|
}
|
|
94
71
|
|
|
95
72
|
// ─── Deposit ────────────────────────────────────────────────────
|
|
@@ -106,6 +83,8 @@ constructor(
|
|
|
106
83
|
* and extracting mt_index. Combined with the known ShieldedCoinInfo,
|
|
107
84
|
* this produces the QualifiedShieldedCoinInfo needed for spending.
|
|
108
85
|
*
|
|
86
|
+
* @circuitInfo k=13, rows=5898
|
|
87
|
+
*
|
|
109
88
|
* @param {ShieldedCoinInfo} coin - The incoming shielded coin.
|
|
110
89
|
*/
|
|
111
90
|
export circuit deposit(coin: ShieldedCoinInfo): [] {
|
|
@@ -119,33 +98,30 @@ export circuit deposit(coin: ShieldedCoinInfo): [] {
|
|
|
119
98
|
*
|
|
120
99
|
* The circuit reads the current nonce from the ledger, increments it,
|
|
121
100
|
* then reconstructs the message hash that signers must have signed
|
|
122
|
-
* off-chain: `persistentHash(
|
|
101
|
+
* off-chain: `persistentHash([domain, kernel.self(), nonce,
|
|
102
|
+
* persistentHash(to), coin color, amount])`. The digest is domain-separated
|
|
103
|
+
* and bound to the contract instance and the full recipient (kind and
|
|
104
|
+
* address), so a signature authorizes exactly one operation on one instance.
|
|
123
105
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* is verified against the message hash. Duplicate signers are rejected
|
|
128
|
-
* via inequality check on adjacent commitments.
|
|
106
|
+
* Approvals are checked by `EcdsaSignerManager`, which derives each signer's
|
|
107
|
+
* commitment from their public key and the instance salt, rejects duplicates,
|
|
108
|
+
* and enforces the threshold.
|
|
129
109
|
*
|
|
130
|
-
* @
|
|
131
|
-
* with ecdsaVerify when Compact ECDSA primitives are available.
|
|
132
|
-
*
|
|
133
|
-
* @notice Duplicate detection via != only works for exactly 2 signers.
|
|
134
|
-
* Production contracts with larger signer sets need a different
|
|
135
|
-
* uniqueness enforcement mechanism.
|
|
110
|
+
* @circuitInfo k=17, rows=98061
|
|
136
111
|
*
|
|
137
112
|
* Requirements:
|
|
138
113
|
*
|
|
139
114
|
* - Both public keys must hash to registered signer commitments.
|
|
140
|
-
* - Both signatures must be valid over the message hash
|
|
115
|
+
* - Both signatures must be valid over the message hash and use the low-s
|
|
116
|
+
* encoding.
|
|
141
117
|
* - Signers must not be duplicates.
|
|
142
118
|
* - Coin value must be >= amount.
|
|
143
119
|
*
|
|
144
120
|
* @param {Proposal_Recipient} to - The recipient.
|
|
145
121
|
* @param {Uint<128>} amount - The amount to send.
|
|
146
122
|
* @param {QualifiedShieldedCoinInfo} coin - The coin to spend (from operator's pool).
|
|
147
|
-
* @param {Vector<2,
|
|
148
|
-
* @param {Vector<2,
|
|
123
|
+
* @param {Vector<2, Secp256k1Point>} pubkeys - Public keys of approving signers.
|
|
124
|
+
* @param {Vector<2, Secp256k1EcdsaSignature>} signatures - ECDSA signatures over the operation.
|
|
149
125
|
*
|
|
150
126
|
* @returns {ShieldedSendResult} The send result including any change.
|
|
151
127
|
*/
|
|
@@ -153,128 +129,97 @@ export circuit execute(
|
|
|
153
129
|
to: Proposal_Recipient,
|
|
154
130
|
amount: Uint<128>,
|
|
155
131
|
coin: QualifiedShieldedCoinInfo,
|
|
156
|
-
pubkeys: Vector<2,
|
|
157
|
-
signatures: Vector<2,
|
|
132
|
+
pubkeys: Vector<2, Secp256k1Point>,
|
|
133
|
+
signatures: Vector<2, Secp256k1EcdsaSignature>
|
|
158
134
|
): ShieldedSendResult {
|
|
159
135
|
// Increment nonce
|
|
160
136
|
const currentNonce = _nonce;
|
|
161
137
|
_nonce.increment(1);
|
|
162
138
|
|
|
163
139
|
// Construct message hash
|
|
164
|
-
const msgHash = persistentHash<Vector<
|
|
140
|
+
const msgHash = persistentHash<Vector<6, Bytes<32>>>([
|
|
141
|
+
pad(32, "multisig:execute:"),
|
|
142
|
+
kernel.self().bytes,
|
|
165
143
|
currentNonce as Bytes<32>,
|
|
166
|
-
to
|
|
144
|
+
persistentHash<Proposal_Recipient>(to),
|
|
167
145
|
coin.color,
|
|
168
146
|
amount as Bytes<32>
|
|
169
147
|
]);
|
|
170
148
|
|
|
171
|
-
|
|
172
|
-
const initialState = VerificationState {
|
|
173
|
-
validCount: 0 as Uint<8>,
|
|
174
|
-
prevCommitment: pad(32, ""),
|
|
175
|
-
msgHash: msgHash
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
const finalState = fold(verifySignature, initialState, pubkeys, signatures);
|
|
179
|
-
Signer_assertThresholdMet(finalState.validCount);
|
|
149
|
+
EcdsaSignerManager_assertApprovals(msgHash, pubkeys, signatures);
|
|
180
150
|
|
|
181
151
|
// Execute transfer
|
|
182
152
|
const normalizedRecipient = Proposal_toShieldedRecipient(to);
|
|
183
153
|
return Treasury__send(coin, normalizedRecipient, amount);
|
|
184
154
|
}
|
|
185
155
|
|
|
186
|
-
// ───
|
|
156
|
+
// ─── Commitments ────────────────────────────────────────────────
|
|
187
157
|
|
|
188
158
|
/**
|
|
189
|
-
* @description
|
|
190
|
-
*
|
|
191
|
-
* Computes the signer's commitment from their public key and the
|
|
192
|
-
* instance salt, checks for duplicates against the previous commitment,
|
|
193
|
-
* verifies registry membership, and validates the ECDSA signature.
|
|
159
|
+
* @description Computes a signer commitment from a secp256k1 public key,
|
|
160
|
+
* as `persistentHash(pkX, pkY, salt, "multisig:signer:")`.
|
|
194
161
|
*
|
|
195
|
-
*
|
|
196
|
-
* @param {Bytes<64>} pubkey - The signer's ECDSA public key.
|
|
197
|
-
* @param {Bytes<64>} signature - The signer's signature over msgHash.
|
|
198
|
-
*
|
|
199
|
-
* @returns {VerificationState} Updated accumulator.
|
|
200
|
-
*/
|
|
201
|
-
circuit verifySignature(
|
|
202
|
-
state: VerificationState,
|
|
203
|
-
pubkey: Bytes<64>,
|
|
204
|
-
signature: Bytes<64>
|
|
205
|
-
): VerificationState {
|
|
206
|
-
const commitment = _calculateSignerId(pubkey, _instanceSalt);
|
|
207
|
-
|
|
208
|
-
// Duplicate detection — sufficient for 2 signers only
|
|
209
|
-
assert(commitment != state.prevCommitment, "Multisig: duplicate signer");
|
|
210
|
-
|
|
211
|
-
// Verify this commitment is a registered signer
|
|
212
|
-
Signer_assertSigner(commitment);
|
|
213
|
-
|
|
214
|
-
// TODO: Replace with actual ECDSA primitive when available
|
|
215
|
-
// assert(ecdsaVerify(pubkey, state.msgHash, signature), "Multisig: invalid signature");
|
|
216
|
-
assert(stubVerifySignature(pubkey, state.msgHash, signature), "Multisig: invalid signature");
|
|
217
|
-
|
|
218
|
-
return VerificationState {
|
|
219
|
-
validCount: state.validCount + 1 as Uint<8>,
|
|
220
|
-
prevCommitment: commitment,
|
|
221
|
-
msgHash: state.msgHash
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
/**
|
|
226
|
-
* @description Computes a signer commitment from an ECDSA public key.
|
|
162
|
+
* Pure, so the deployer can derive constructor commitments off-chain.
|
|
227
163
|
*
|
|
228
|
-
*
|
|
229
|
-
* - pk: the signer's ECDSA public key (64 bytes)
|
|
230
|
-
* - salt: instance-specific random value (prevents cross-contract correlation)
|
|
231
|
-
* - domain: "MultiSig:signer:" (domain separation)
|
|
164
|
+
* Requirements:
|
|
232
165
|
*
|
|
233
|
-
*
|
|
234
|
-
* to compute commitments for the constructor.
|
|
166
|
+
* - `pk` must not be the secp256k1 identity point, which has no coordinates.
|
|
235
167
|
*
|
|
236
|
-
* @param {
|
|
168
|
+
* @param {Secp256k1Point} pk - The secp256k1 public key.
|
|
237
169
|
* @param {Bytes<32>} salt - The instance salt.
|
|
238
170
|
*
|
|
239
171
|
* @returns {Bytes<32>} The signer commitment.
|
|
240
172
|
*/
|
|
241
173
|
export pure circuit _calculateSignerId(
|
|
242
|
-
pk:
|
|
174
|
+
pk: Secp256k1Point,
|
|
243
175
|
salt: Bytes<32>
|
|
244
176
|
): Bytes<32> {
|
|
245
|
-
return
|
|
246
|
-
pk: pk,
|
|
247
|
-
salt: salt,
|
|
248
|
-
domain: pad(32, "MultiSig:signer:")
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* @description Stub for ECDSA signature verification.
|
|
254
|
-
* Always returns true. MUST be replaced before any non-test deployment.
|
|
255
|
-
*/
|
|
256
|
-
circuit stubVerifySignature(
|
|
257
|
-
pubkey: Bytes<64>,
|
|
258
|
-
msgHash: Bytes<32>,
|
|
259
|
-
signature: Bytes<64>
|
|
260
|
-
): Boolean {
|
|
261
|
-
return true;
|
|
177
|
+
return EcdsaSignerManager_calculateSignerId(pk, salt);
|
|
262
178
|
}
|
|
263
179
|
|
|
264
180
|
// ─── View ───────────────────────────────────────────────────────
|
|
265
181
|
|
|
182
|
+
/**
|
|
183
|
+
* @description Returns the nonce the next `execute` digest will bind to.
|
|
184
|
+
*
|
|
185
|
+
* @circuitInfo k=6, rows=34
|
|
186
|
+
*
|
|
187
|
+
* @returns {Uint<64>} The current nonce.
|
|
188
|
+
*/
|
|
266
189
|
export circuit getNonce(): Uint<64> {
|
|
267
190
|
return _nonce;
|
|
268
191
|
}
|
|
269
192
|
|
|
193
|
+
/**
|
|
194
|
+
* @description Returns the number of registered signers.
|
|
195
|
+
*
|
|
196
|
+
* @circuitInfo k=6, rows=34
|
|
197
|
+
*
|
|
198
|
+
* @returns {Uint<8>} The signer count.
|
|
199
|
+
*/
|
|
270
200
|
export circuit getSignerCount(): Uint<8> {
|
|
271
|
-
return
|
|
201
|
+
return EcdsaSignerManager_getSignerCount();
|
|
272
202
|
}
|
|
273
203
|
|
|
204
|
+
/**
|
|
205
|
+
* @description Returns the approval threshold.
|
|
206
|
+
*
|
|
207
|
+
* @circuitInfo k=6, rows=34
|
|
208
|
+
*
|
|
209
|
+
* @returns {Uint<8>} The threshold.
|
|
210
|
+
*/
|
|
274
211
|
export circuit getThreshold(): Uint<8> {
|
|
275
|
-
return
|
|
212
|
+
return EcdsaSignerManager_getThreshold();
|
|
276
213
|
}
|
|
277
214
|
|
|
215
|
+
/**
|
|
216
|
+
* @description Returns whether the given commitment is a registered signer.
|
|
217
|
+
*
|
|
218
|
+
* @circuitInfo k=8, rows=129
|
|
219
|
+
*
|
|
220
|
+
* @param {Bytes<32>} commitment - The signer commitment to check.
|
|
221
|
+
* @returns {Boolean} True if registered.
|
|
222
|
+
*/
|
|
278
223
|
export circuit isSigner(commitment: Bytes<32>): Boolean {
|
|
279
|
-
return
|
|
224
|
+
return EcdsaSignerManager_isSigner(commitment);
|
|
280
225
|
}
|