@openzeppelin/compact-contracts 0.4.0-alpha.5 → 0.4.0-alpha.6
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 +1 -1
- package/access/AccessControl.compact +1 -1
- package/access/Ownable.compact +1 -1
- package/access/ShieldedAccessControl.compact +1 -1
- package/access/ZOwnablePK.compact +13 -4
- package/crypto/EcdhMask.compact +1 -1
- package/crypto/Ecdsa.compact +1 -1
- package/crypto/Eip712.compact +1 -1
- package/crypto/ElGamal.compact +1 -1
- package/multisig/ForwarderPrivate.compact +1 -1
- package/multisig/ForwarderShielded.compact +1 -1
- package/multisig/ForwarderUnshielded.compact +1 -1
- package/multisig/ProposalManager.compact +1 -1
- package/multisig/Secp256k1EcdsaMultisig.compact +275 -0
- package/multisig/ShieldedTreasury.compact +1 -1
- package/multisig/ShieldedTreasuryStateless.compact +1 -1
- package/multisig/Signer.compact +1 -1
- package/multisig/UnshieldedTreasury.compact +1 -1
- package/multisig/examples/ForwarderPrivateExample.compact +1 -1
- package/multisig/examples/ForwarderShieldedExample.compact +1 -1
- package/multisig/examples/ForwarderUnshieldedExample.compact +1 -1
- package/multisig/examples/NativeShieldedTokenIssuerExample.compact +4 -4
- package/multisig/examples/ShieldedMultiSigV2Example.compact +6 -8
- package/multisig/presets/NativeShieldedTokenIssuer.compact +84 -83
- package/multisig/presets/ShieldedMultiSigV2.compact +35 -43
- package/package.json +1 -1
- package/security/Allowlist.compact +1 -1
- package/security/Blocklist.compact +1 -1
- package/security/Initializable.compact +1 -1
- package/security/Pausable.compact +1 -1
- package/token/ConfidentialFungibleToken.compact +1 -1
- package/token/FungibleToken.compact +1 -1
- package/token/MultiToken.compact +1 -1
- package/token/NativeShieldedToken.compact +1 -1
- package/token/NativeShieldedTokenCore.compact +1 -1
- package/token/NativeShieldedTokenFamily.compact +1 -1
- package/token/NonFungibleToken.compact +1 -1
- package/token/examples/ZOwnableNativeShieldedTokenExample.compact +109 -0
- package/token/extensions/ConfidentialFungibleTokenPublicSupply.compact +1 -1
- package/token/extensions/NativeShieldedTokenDerivedNonce.compact +1 -1
- package/token/presets/ZOwnableNativeShieldedToken.compact +314 -0
- package/utils/EvmAbi.compact +1 -1
- package/utils/Utils.compact +1 -1
- package/multisig/EcdsaSignerManager.compact +0 -248
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.4.0-alpha.5 (multisig/EcdsaSignerManager.compact)
|
|
3
|
-
|
|
4
|
-
pragma language_version >= 0.26.0;
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @module EcdsaSignerManager
|
|
8
|
-
* @description Threshold authorization over secp256k1 ECDSA approvals for
|
|
9
|
-
* multisig contracts.
|
|
10
|
-
*
|
|
11
|
-
* Signer identities are stored as commitments: `persistentHash` over the
|
|
12
|
-
* signer's public-key coordinates, an instance salt, and a domain separator.
|
|
13
|
-
* The salt is per-deployment, so the same public key yields a different
|
|
14
|
-
* commitment in every instance and cannot be correlated across contracts.
|
|
15
|
-
*
|
|
16
|
-
* Wraps `Signer<Bytes<32>>` for the registry and threshold and configures it
|
|
17
|
-
* from `initialize`. Consuming contracts own the digest: they compute the
|
|
18
|
-
* message hash their signers signed, then hand it to `assertApprovals` with
|
|
19
|
-
* the parallel public-key and signature vectors.
|
|
20
|
-
*
|
|
21
|
-
* @notice Consuming contracts must not import `Signer` alongside this module.
|
|
22
|
-
* A second import instantiates a separate registry that `assertApprovals`
|
|
23
|
-
* never reads.
|
|
24
|
-
*/
|
|
25
|
-
module EcdsaSignerManager {
|
|
26
|
-
import CompactStandardLibrary;
|
|
27
|
-
import "../crypto/Ecdsa" prefix Ecdsa_;
|
|
28
|
-
import "./Signer"<Bytes<32>> prefix Signer_;
|
|
29
|
-
|
|
30
|
-
// Named import/re-export of the registry state only, so a consuming
|
|
31
|
-
// contract's ledger keys read as `_signers` rather than `Signer__signers`.
|
|
32
|
-
// The circuits stay behind the `Signer_` prefix.
|
|
33
|
-
import { _signers, _signerCount, _threshold } from "./Signer"<Bytes<32>>;
|
|
34
|
-
export { _signers, _signerCount, _threshold };
|
|
35
|
-
|
|
36
|
-
// ─── State ──────────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* @description Deployment-supplied salt for signer commitments. Set at
|
|
40
|
-
* initialization and never changed. The registered commitments must have been
|
|
41
|
-
* derived under this same salt.
|
|
42
|
-
*/
|
|
43
|
-
export sealed ledger _instanceSalt: Bytes<32>;
|
|
44
|
-
|
|
45
|
-
// ─── Types ──────────────────────────────────────────────────────────────────
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @description Input to `persistentHash` for computing signer commitments.
|
|
49
|
-
*/
|
|
50
|
-
struct SignerCommitmentInput {
|
|
51
|
-
pkX: Bytes<32>,
|
|
52
|
-
pkY: Bytes<32>,
|
|
53
|
-
salt: Bytes<32>,
|
|
54
|
-
domain: Bytes<32>
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* @description Accumulator threaded through the approval fold: the running
|
|
59
|
-
* valid count, the previous commitment (for duplicate detection), and the
|
|
60
|
-
* digest every signature is checked against.
|
|
61
|
-
*/
|
|
62
|
-
struct VerificationState {
|
|
63
|
-
validCount: Uint<8>,
|
|
64
|
-
prevCommitment: Bytes<32>,
|
|
65
|
-
msgHash: Bytes<32>
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// ─── Initialization ─────────────────────────────────────────────────────────
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* @description Stores the instance salt and registers the initial signer set.
|
|
72
|
-
* Call from the consuming contract's constructor only. Writes the `sealed`
|
|
73
|
-
* salt, so it cannot be reached from an exported circuit.
|
|
74
|
-
*
|
|
75
|
-
* Requirements:
|
|
76
|
-
*
|
|
77
|
-
* - Can only be called once.
|
|
78
|
-
* - `instanceSalt` should be cryptographically random.
|
|
79
|
-
* - `signerCommitments` must not contain duplicates.
|
|
80
|
-
* - `n` must be at least 2, the number of distinct signers `assertApprovals`
|
|
81
|
-
* verifies. A smaller set can never satisfy it.
|
|
82
|
-
* - `threshold` must be 2, the number of approvals `assertApprovals`
|
|
83
|
-
* verifies. Any other value would misreport what the circuit enforces.
|
|
84
|
-
*
|
|
85
|
-
* @param {Bytes<32>} instanceSalt - Per-deployment salt for commitment derivation.
|
|
86
|
-
* @param {Vector<n, Bytes<32>>} signerCommitments - Hashed signer identities.
|
|
87
|
-
* @param {Uint<8>} threshold - Approvals required. Must be 2.
|
|
88
|
-
* @returns {[]} Empty tuple.
|
|
89
|
-
*/
|
|
90
|
-
export circuit initialize<#n>(
|
|
91
|
-
instanceSalt: Bytes<32>,
|
|
92
|
-
signerCommitments: Vector<n, Bytes<32>>,
|
|
93
|
-
threshold: Uint<8>
|
|
94
|
-
): [] {
|
|
95
|
-
assert(Signer_getSignerCount() == 0, "EcdsaSignerManager: signers already registered");
|
|
96
|
-
_instanceSalt = disclose(instanceSalt);
|
|
97
|
-
assert(threshold == 2, "EcdsaSignerManager: threshold must be 2 (assertApprovals verifies 2 signatures)");
|
|
98
|
-
|
|
99
|
-
for (const commitment of signerCommitments) {
|
|
100
|
-
Signer__addSigner(commitment);
|
|
101
|
-
}
|
|
102
|
-
assert(Signer_getSignerCount() >= 2, "EcdsaSignerManager: fewer than 2 signers (assertApprovals verifies 2 signatures)");
|
|
103
|
-
Signer__changeThreshold(threshold);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// ─── Commitments ────────────────────────────────────────────────────────────
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* @description Computes a signer commitment from a secp256k1 public key,
|
|
110
|
-
* as `persistentHash(pkX, pkY, salt, "multisig:signer:")`.
|
|
111
|
-
*
|
|
112
|
-
* Pure, so the deployer can derive constructor commitments off-chain the
|
|
113
|
-
* same way the circuits derive them in-circuit.
|
|
114
|
-
*
|
|
115
|
-
* Requirements:
|
|
116
|
-
*
|
|
117
|
-
* - `pk` must not be the secp256k1 identity point, which has no coordinates.
|
|
118
|
-
*
|
|
119
|
-
* @param {Secp256k1Point} pk - The secp256k1 public key.
|
|
120
|
-
* @param {Bytes<32>} salt - The instance salt.
|
|
121
|
-
* @returns {Bytes<32>} The signer commitment.
|
|
122
|
-
*/
|
|
123
|
-
export pure circuit calculateSignerId(
|
|
124
|
-
pk: Secp256k1Point,
|
|
125
|
-
salt: Bytes<32>
|
|
126
|
-
): Bytes<32> {
|
|
127
|
-
return persistentHash<SignerCommitmentInput>(SignerCommitmentInput {
|
|
128
|
-
pkX: secp256k1PointX(pk) as Bytes<32>,
|
|
129
|
-
pkY: secp256k1PointY(pk) as Bytes<32>,
|
|
130
|
-
salt: salt,
|
|
131
|
-
domain: pad(32, "multisig:signer:")
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// ─── Approvals ──────────────────────────────────────────────────────────────
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* @description Verifies two approvals over `msgHash` and asserts the
|
|
139
|
-
* threshold is met.
|
|
140
|
-
*
|
|
141
|
-
* `pubkeys` and `signatures` are parallel: entry `i` of each belongs to the
|
|
142
|
-
* same signer.
|
|
143
|
-
*
|
|
144
|
-
* @dev Both entries are asserted, so the count handed to the threshold check
|
|
145
|
-
* is always 2, matching the only threshold `initialize` accepts.
|
|
146
|
-
*
|
|
147
|
-
* @constraints k=17, rows=64916 (zkir-v3)
|
|
148
|
-
*
|
|
149
|
-
* Requirements:
|
|
150
|
-
*
|
|
151
|
-
* - Every public key must hash to a registered signer commitment.
|
|
152
|
-
* - Every signature must be valid over `msgHash` and use the low-s encoding.
|
|
153
|
-
* - Signers must not be duplicates.
|
|
154
|
-
*
|
|
155
|
-
* @param {Bytes<32>} msgHash - The digest the signers approved.
|
|
156
|
-
* @param {Vector<2, Secp256k1Point>} pubkeys - Public keys of approving signers.
|
|
157
|
-
* @param {Vector<2, Secp256k1EcdsaSignature>} signatures - Signatures over `msgHash`.
|
|
158
|
-
* @returns {[]} Empty tuple.
|
|
159
|
-
*/
|
|
160
|
-
export circuit assertApprovals(
|
|
161
|
-
msgHash: Bytes<32>,
|
|
162
|
-
pubkeys: Vector<2, Secp256k1Point>,
|
|
163
|
-
signatures: Vector<2, Secp256k1EcdsaSignature>
|
|
164
|
-
): [] {
|
|
165
|
-
const initialState = VerificationState {
|
|
166
|
-
validCount: 0 as Uint<8>,
|
|
167
|
-
prevCommitment: pad(32, ""),
|
|
168
|
-
msgHash: msgHash
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const finalState = fold(verifySignature, initialState, pubkeys, signatures);
|
|
172
|
-
Signer_assertThresholdMet(finalState.validCount);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* @description Fold callback. Verifies one signer's approval.
|
|
177
|
-
*
|
|
178
|
-
* @notice Verification goes through `Ecdsa`'s low-s wrapper, so the high-s
|
|
179
|
-
* encoding of an approval is rejected as an invalid signature.
|
|
180
|
-
*
|
|
181
|
-
* @dev Duplicates are caught by comparing against the previous commitment
|
|
182
|
-
* alone, which is exhaustive only at width 2. Widening the approval vectors
|
|
183
|
-
* requires an all-pairs check.
|
|
184
|
-
*
|
|
185
|
-
* @param {VerificationState} state - Accumulator threaded through fold.
|
|
186
|
-
* @param {Secp256k1Point} pubkey - The signer's secp256k1 public key.
|
|
187
|
-
* @param {Secp256k1EcdsaSignature} signature - The signer's signature over `msgHash`.
|
|
188
|
-
* @returns {VerificationState} Updated accumulator.
|
|
189
|
-
*/
|
|
190
|
-
circuit verifySignature(
|
|
191
|
-
state: VerificationState,
|
|
192
|
-
pubkey: Secp256k1Point,
|
|
193
|
-
signature: Secp256k1EcdsaSignature
|
|
194
|
-
): VerificationState {
|
|
195
|
-
const commitment = calculateSignerId(pubkey, _instanceSalt);
|
|
196
|
-
|
|
197
|
-
assert(commitment != state.prevCommitment, "Multisig: duplicate signer");
|
|
198
|
-
|
|
199
|
-
Signer_assertSigner(commitment);
|
|
200
|
-
|
|
201
|
-
assert(
|
|
202
|
-
Ecdsa_secp256k1EcdsaVerifyLowS(state.msgHash, signature, pubkey),
|
|
203
|
-
"Multisig: invalid signature"
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
return VerificationState {
|
|
207
|
-
validCount: state.validCount + 1 as Uint<8>,
|
|
208
|
-
prevCommitment: commitment,
|
|
209
|
-
msgHash: state.msgHash
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// ─── View ───────────────────────────────────────────────────────────────────
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* @description Returns the number of registered signers.
|
|
217
|
-
*
|
|
218
|
-
* @constraints k=6, rows=34 (zkir-v3)
|
|
219
|
-
*
|
|
220
|
-
* @returns {Uint<8>} The signer count.
|
|
221
|
-
*/
|
|
222
|
-
export circuit getSignerCount(): Uint<8> {
|
|
223
|
-
return Signer_getSignerCount();
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* @description Returns the approval threshold.
|
|
228
|
-
*
|
|
229
|
-
* @constraints k=6, rows=34 (zkir-v3)
|
|
230
|
-
*
|
|
231
|
-
* @returns {Uint<8>} The threshold.
|
|
232
|
-
*/
|
|
233
|
-
export circuit getThreshold(): Uint<8> {
|
|
234
|
-
return Signer_getThreshold();
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* @description Returns whether the given commitment is a registered signer.
|
|
239
|
-
*
|
|
240
|
-
* @constraints k=8, rows=129 (zkir-v3)
|
|
241
|
-
*
|
|
242
|
-
* @param {Bytes<32>} commitment - The signer commitment to check.
|
|
243
|
-
* @returns {Boolean} True if registered.
|
|
244
|
-
*/
|
|
245
|
-
export circuit isSigner(commitment: Bytes<32>): Boolean {
|
|
246
|
-
return Signer_isSigner(commitment);
|
|
247
|
-
}
|
|
248
|
-
}
|