@openzeppelin/compact-contracts 0.5.0-alpha.1 → 0.5.0-alpha.2
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 +9 -4
- package/access/AccessControl.compact +8 -9
- package/access/Ownable.compact +19 -20
- package/access/ShieldedAccessControl.compact +1 -1
- package/access/ZOwnablePK.compact +3 -3
- package/crypto/Ecdh.compact +1 -1
- package/crypto/EcdhMask.compact +61 -22
- package/crypto/Ecdsa.compact +1 -1
- package/crypto/Eip712.compact +1 -1
- package/crypto/ElGamal.compact +13 -13
- package/math/UintN.compact +82 -0
- package/multisig/ForwarderPrivate.compact +1 -1
- package/multisig/ForwarderShielded.compact +1 -1
- package/multisig/ForwarderUnshielded.compact +1 -1
- package/multisig/ProposalManager.compact +3 -3
- package/multisig/Secp256k1EcdsaMultisig.compact +1 -1
- package/multisig/ShieldedTreasury.compact +1 -1
- package/multisig/ShieldedTreasuryStateless.compact +5 -11
- 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/{ShieldedMultiSigV2Example.compact → NativeShieldedStatelessTreasuryExample.compact} +23 -23
- package/multisig/examples/NativeShieldedTokenIssuerExample.compact +1 -1
- package/multisig/presets/NativeShieldedStatelessTreasury.compact +443 -0
- package/multisig/presets/NativeShieldedTokenIssuer.compact +1 -1
- package/package.json +11 -11
- 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/ConfidentialNoteFungibleToken.compact +1 -1
- package/token/FungibleToken.compact +34 -30
- package/token/MultiToken.compact +25 -21
- package/token/NativeShieldedToken.compact +2 -2
- package/token/NativeShieldedTokenCore.compact +1 -1
- package/token/NativeShieldedTokenFamily.compact +4 -4
- package/token/NonFungibleToken.compact +26 -22
- package/token/examples/ZOwnableNativeShieldedTokenExample.compact +1 -1
- package/token/extensions/ConfidentialFungibleTokenPublicSupply.compact +1 -1
- package/token/extensions/ConfidentialNoteFungibleTokenDelivery.compact +274 -0
- package/token/extensions/NativeShieldedTokenDerivedNonce.compact +1 -1
- package/token/extensions/NativeShieldedTokenFamilyPublicSupply.compact +1 -1
- package/token/extensions/NativeShieldedTokenPublicSupply.compact +1 -1
- package/token/extensions/NativeShieldedTokenPublicSupplyCore.compact +1 -1
- package/token/presets/ZOwnableNativeShieldedToken.compact +1 -1
- package/utils/EvmAbi.compact +1 -1
- package/utils/Utils.compact +1 -1
- package/multisig/presets/ShieldedMultiSigV2.compact +0 -289
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ This project is built on the Midnight Network.
|
|
|
10
10
|
|
|
11
11
|
> ## ⚠️ WARNING! ⚠️
|
|
12
12
|
>
|
|
13
|
-
>
|
|
13
|
+
> Pre-release versions (`-alpha`, `-rc`) contain experimental, unaudited code.
|
|
14
14
|
> Expect rapid iteration.
|
|
15
15
|
> **Use at your own risk.**
|
|
16
16
|
|
|
@@ -193,7 +193,7 @@ ZKIR v3: the library targets ZKIR v2, the compiler 0.34.0 default.
|
|
|
193
193
|
Pass `--feature-zkir-v3` only when the contract reaches a module that needs it:
|
|
194
194
|
the secp256k1-based `crypto/Ecdsa` and `multisig/Secp256k1EcdsaMultisig`,
|
|
195
195
|
or the `keccak256`-based `crypto/Eip712`.
|
|
196
|
-
`multisig/presets/
|
|
196
|
+
`multisig/presets/NativeShieldedStatelessTreasury`, `multisig/presets/NativeShieldedTokenIssuer`
|
|
197
197
|
and the `multisig/examples/` contracts reach both.
|
|
198
198
|
`utils/EvmAbi` needs no `keccak256` of its own and compiles on either backend.
|
|
199
199
|
Compiling the other modules under v3 currently hits upstream blockers,
|
|
@@ -233,6 +233,8 @@ yarn compile
|
|
|
233
233
|
yarn test
|
|
234
234
|
```
|
|
235
235
|
|
|
236
|
+
Integration and live suites are described in [TESTING.md](TESTING.md).
|
|
237
|
+
|
|
236
238
|
### Check/apply Biome formatter
|
|
237
239
|
|
|
238
240
|
```bash
|
|
@@ -247,6 +249,7 @@ yarn lint:fix
|
|
|
247
249
|
```bash
|
|
248
250
|
yarn compile:access
|
|
249
251
|
yarn compile:archive
|
|
252
|
+
yarn compile:math
|
|
250
253
|
...
|
|
251
254
|
```
|
|
252
255
|
|
|
@@ -278,9 +281,11 @@ rm -rf .turbo/
|
|
|
278
281
|
|
|
279
282
|
## Security
|
|
280
283
|
|
|
281
|
-
|
|
284
|
+
For production, use a stable release (no `-alpha` or `-rc` suffix) on the Midnight ledger it targets. Pre-releases are not audited and should not be used in production.
|
|
285
|
+
|
|
286
|
+
Scopes and audited commits are listed in [audits](./audits/README.md).
|
|
282
287
|
|
|
283
|
-
Please report any security issues you find to <security@openzeppelin.com>.
|
|
288
|
+
Please report any security issues you find to <security@openzeppelin.com>. See [SECURITY.md](SECURITY.md).
|
|
284
289
|
|
|
285
290
|
### Provenance
|
|
286
291
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.5.0-alpha.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.5.0-alpha.2 (access/AccessControl.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
@@ -61,18 +61,17 @@ pragma language_version >= 0.26.0;
|
|
|
61
61
|
* through the main role approval circuits (`grantRole` and `_grantRole`).
|
|
62
62
|
* In other words, role approvals to contract addresses are disallowed through these
|
|
63
63
|
* circuits.
|
|
64
|
-
* This is because
|
|
65
|
-
*
|
|
66
|
-
* circuit.
|
|
64
|
+
* This is because this library has not yet migrated to contract-to-contract calls, which means
|
|
65
|
+
* a contract granted a role cannot directly call the protected circuit.
|
|
67
66
|
*
|
|
68
67
|
* @notice This module does offer an experimental circuit that allows roles to be granted
|
|
69
68
|
* to contract addresses (`_unsafeGrantRole`).
|
|
70
69
|
* Note that the circuit name is very explicit ("unsafe") with this experimental circuit.
|
|
71
|
-
* Until contract-to-contract calls
|
|
70
|
+
* Until this library migrates to contract-to-contract calls,
|
|
72
71
|
* there is no direct way for a contract to call protected circuits.
|
|
73
72
|
*
|
|
74
|
-
* @notice The unsafe circuits are planned to become deprecated once
|
|
75
|
-
*
|
|
73
|
+
* @notice The unsafe circuits are planned to become deprecated once this library migrates to
|
|
74
|
+
* contract-to-contract calls.
|
|
76
75
|
*
|
|
77
76
|
* @dev Migration plan (safe -> C2C-capable role grants)
|
|
78
77
|
*
|
|
@@ -84,8 +83,8 @@ pragma language_version >= 0.26.0;
|
|
|
84
83
|
* which is the only kind of upgrade the CMA supports. Widening the type later would instead force
|
|
85
84
|
* a ledger-layout rewrite, which the CMA cannot perform.
|
|
86
85
|
*
|
|
87
|
-
* When C2C lands, an already-deployed contract migrates without changing its address
|
|
88
|
-
* state:
|
|
86
|
+
* When the C2C migration lands, an already-deployed contract migrates without changing its address
|
|
87
|
+
* or ledger state:
|
|
89
88
|
*
|
|
90
89
|
* - Minor release: mark `_unsafeGrantRole` deprecated (and emit a warning if possible); keep its
|
|
91
90
|
* implementation intact so existing callers continue to work.
|
package/access/Ownable.compact
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.5.0-alpha.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.5.0-alpha.2 (access/Ownable.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
@@ -28,18 +28,17 @@ pragma language_version >= 0.26.0;
|
|
|
28
28
|
* through the main transfer circuits (`transferOwnership` and `_transferOwnership`).
|
|
29
29
|
* In other words, ownership transfers to contract addresses are disallowed through these
|
|
30
30
|
* circuits.
|
|
31
|
-
* This is because
|
|
32
|
-
*
|
|
33
|
-
* circuit.
|
|
31
|
+
* This is because this library has not yet migrated to contract-to-contract calls, which means
|
|
32
|
+
* a contract granted ownership cannot directly call the protected circuit.
|
|
34
33
|
*
|
|
35
34
|
* @notice This module does offer experimental circuits that allow ownership to be granted
|
|
36
35
|
* to contract addresses (`_unsafeTransferOwnership` and `_unsafeUncheckedTransferOwnership`).
|
|
37
36
|
* Note that the circuit names are very explicit ("unsafe") with these experimental circuits.
|
|
38
|
-
* Until contract-to-contract calls
|
|
37
|
+
* Until this library migrates to contract-to-contract calls, there is no direct way for a contract
|
|
39
38
|
* to authenticate as an owner.
|
|
40
39
|
*
|
|
41
|
-
* @notice The unsafe circuits are planned to become deprecated once
|
|
42
|
-
*
|
|
40
|
+
* @notice The unsafe circuits are planned to become deprecated once this library migrates to
|
|
41
|
+
* contract-to-contract calls.
|
|
43
42
|
*
|
|
44
43
|
* @dev Migration plan (safe -> C2C-capable ownership transfers)
|
|
45
44
|
*
|
|
@@ -51,8 +50,8 @@ pragma language_version >= 0.26.0;
|
|
|
51
50
|
* which is the only kind of upgrade the CMA supports. Widening the type later would instead force
|
|
52
51
|
* a ledger-layout rewrite, which the CMA cannot perform.
|
|
53
52
|
*
|
|
54
|
-
* When C2C lands, an already-deployed contract migrates without changing its address
|
|
55
|
-
* state:
|
|
53
|
+
* When the C2C migration lands, an already-deployed contract migrates without changing its address
|
|
54
|
+
* or ledger state:
|
|
56
55
|
*
|
|
57
56
|
* - Minor release: mark `_unsafeTransferOwnership` (and `_unsafeUncheckedTransferOwnership`)
|
|
58
57
|
* deprecated (and emit a warning if possible); keep their implementation intact so existing
|
|
@@ -180,8 +179,8 @@ module Ownable {
|
|
|
180
179
|
/**
|
|
181
180
|
* @description Transfers ownership of the contract to `newOwner`.
|
|
182
181
|
*
|
|
183
|
-
* @notice Ownership transfers to contract addresses are
|
|
184
|
-
*
|
|
182
|
+
* @notice Ownership transfers to contract addresses are disallowed until this library migrates to
|
|
183
|
+
* contract-to-contract calls.
|
|
185
184
|
* This restriction prevents permanently disabling access to a circuit.
|
|
186
185
|
*
|
|
187
186
|
* @constraints k=13, rows=2947
|
|
@@ -206,10 +205,10 @@ module Ownable {
|
|
|
206
205
|
/**
|
|
207
206
|
* @description Unsafe variant of `transferOwnership`.
|
|
208
207
|
*
|
|
209
|
-
* @warning Ownership transfers to contract addresses are considered unsafe because
|
|
210
|
-
*
|
|
208
|
+
* @warning Ownership transfers to contract addresses are considered unsafe because this library
|
|
209
|
+
* has not yet migrated to contract-to-contract calls.
|
|
211
210
|
* Ownership privileges sent to a contract address may become uncallable.
|
|
212
|
-
* Once contract-to-contract calls
|
|
211
|
+
* Once this library migrates to contract-to-contract calls, this circuit may be deprecated.
|
|
213
212
|
*
|
|
214
213
|
* @constraints k=13, rows=2944
|
|
215
214
|
*
|
|
@@ -248,7 +247,7 @@ module Ownable {
|
|
|
248
247
|
assertOnlyOwner();
|
|
249
248
|
|
|
250
249
|
// We use `left` here because `assertOnlyOwner` would return a misleading
|
|
251
|
-
// error msg (
|
|
250
|
+
// error msg (this library has not yet migrated to c2c)
|
|
252
251
|
const zero = Either<Bytes<32>, ContractAddress> {
|
|
253
252
|
is_left: true, left: default<Bytes<32>>, right: default<ContractAddress>
|
|
254
253
|
};
|
|
@@ -284,8 +283,8 @@ module Ownable {
|
|
|
284
283
|
* @description Transfers ownership of the contract to `newOwner` without
|
|
285
284
|
* enforcing permission checks on the caller.
|
|
286
285
|
*
|
|
287
|
-
* @notice Ownership transfers to contract addresses are
|
|
288
|
-
*
|
|
286
|
+
* @notice Ownership transfers to contract addresses are disallowed until this library migrates to
|
|
287
|
+
* contract-to-contract calls.
|
|
289
288
|
* This restriction prevents circuits from being inadvertently locked in contracts.
|
|
290
289
|
*
|
|
291
290
|
* @constraints k=10, rows=598
|
|
@@ -308,10 +307,10 @@ module Ownable {
|
|
|
308
307
|
/**
|
|
309
308
|
* @description Unsafe variant of `_transferOwnership`.
|
|
310
309
|
*
|
|
311
|
-
* @warning Ownership transfers to contract addresses are considered unsafe because
|
|
312
|
-
*
|
|
310
|
+
* @warning Ownership transfers to contract addresses are considered unsafe because this library
|
|
311
|
+
* has not yet migrated to contract-to-contract calls.
|
|
313
312
|
* Ownership privileges sent to a contract address may become uncallable.
|
|
314
|
-
* Once contract-to-contract calls
|
|
313
|
+
* Once this library migrates to contract-to-contract calls, this circuit may be deprecated.
|
|
315
314
|
*
|
|
316
315
|
* @constraints k=10, rows=595
|
|
317
316
|
*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.5.0-alpha.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.5.0-alpha.2 (access/ZOwnablePK.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
@@ -15,8 +15,8 @@ pragma language_version >= 0.26.0;
|
|
|
15
15
|
* For the strongest security guarantees, use an Air-Gapped Public Key.
|
|
16
16
|
*
|
|
17
17
|
* @notice This module explicitly supports commitments derived from public keys;
|
|
18
|
-
* however, it may be possible to use contract addresses
|
|
19
|
-
* calls
|
|
18
|
+
* however, it may be possible to use contract addresses once this library migrates to
|
|
19
|
+
* contract-to-contract calls. This will be revisited when it's known if/how witnesses
|
|
20
20
|
* are used from a contract address context.
|
|
21
21
|
*
|
|
22
22
|
* @dev Features:
|
package/crypto/Ecdh.compact
CHANGED
package/crypto/EcdhMask.compact
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.5.0-alpha.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.5.0-alpha.2 (crypto/EcdhMask.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
@@ -9,7 +9,7 @@ pragma language_version >= 0.26.0;
|
|
|
9
9
|
* Jubjub public key, built on the key agreement in `crypto/Ecdh`. Delivers a
|
|
10
10
|
* value to whoever holds the secret behind a Jubjub public key WITHOUT encoding
|
|
11
11
|
* it in the exponent, so recovery needs no discrete-log search and the value is
|
|
12
|
-
* unbounded within `Uint<
|
|
12
|
+
* unbounded within `Uint<248>`. This is the direct-decrypt counterpart to the
|
|
13
13
|
* homomorphic `crypto/ElGamal`: use ElGamal to accumulate ciphertexts, use this
|
|
14
14
|
* to hand a recipient the plaintext.
|
|
15
15
|
*
|
|
@@ -28,6 +28,9 @@ pragma language_version >= 0.26.0;
|
|
|
28
28
|
* - `S = pk^e = g^{ek*e}`: the shared point, from `crypto/Ecdh` [`w = u^β`].
|
|
29
29
|
* - `mask = KDF(S, domain)`: the domain-separated field mask, see `kdf`
|
|
30
30
|
* [`k = H(w)`]. E_EG hashes `(v, w)`; E'_EG hashes `w` alone, as here.
|
|
31
|
+
* `kdf` is `kdfFromDigest(pointDigest(S), domain)`, a one-step hash KDF
|
|
32
|
+
* (the `H(Z ‖ FixedInfo)` shape of NIST SP 800-56C §4, one block, 248-bit
|
|
33
|
+
* output); a consumer deriving several masks from one `S` digests it once.
|
|
31
34
|
* - `ct = value + mask`: the field one-time pad [`c = E_s(k, m)`].
|
|
32
35
|
* - `Ciphertext { ephemeralPk: E, ct }`: the ciphertext [`(v, c)`].
|
|
33
36
|
* - Recipient recovers `S = E^ek`, `mask = KDF(S, domain)`, `value = ct - mask`.
|
|
@@ -73,23 +76,27 @@ pragma language_version >= 0.26.0;
|
|
|
73
76
|
*
|
|
74
77
|
* @dev Security. This is hashed ElGamal over Jubjub: Boneh and Shoup, *A
|
|
75
78
|
* Graduate Course in Applied Cryptography* v0.6, §11.5, in the Remark 11.1
|
|
76
|
-
* form that keys the KDF on the shared point alone.
|
|
79
|
+
* form that keys the KDF on the shared point alone. For plaintexts well below
|
|
80
|
+
* the pad's width (see the hiding bound below) it inherits that scheme's
|
|
77
81
|
* guarantee: IND-CPA under CDH in the random-oracle model (Theorem 11.4, the
|
|
78
82
|
* `persistentHash` KDF keyed by the secret point `S`), and so also under the
|
|
79
83
|
* stronger Oracle Diffie-Hellman assumption. It is NOT IND-CCA: Theorem 12.4
|
|
80
84
|
* needs a MAC, and the additive pad is malleable (see Integrity), which
|
|
81
85
|
* is acceptable here only because the on-chain ciphertext is bound in-circuit to
|
|
82
|
-
* the value it commits to elsewhere. Hiding
|
|
83
|
-
* a `degradeToTransient`
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* is PRF-like.
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
86
|
+
* the value it commits to elsewhere. Hiding depends on the plaintext width. The
|
|
87
|
+
* `kdf` output is a `degradeToTransient` value in `[0, 2^248)`. Taken as
|
|
88
|
+
* uniform, it hides a value below `2^w` within `2^(w-248)` statistical slack. A
|
|
89
|
+
* `Uint<128>` keeps about `2^-120`, leaving only the assumption that the hash of
|
|
90
|
+
* the DH secret is PRF-like. A full `Uint<248>` has no margin: a random one
|
|
91
|
+
* loses under one bit on average, but two chosen values far apart are
|
|
92
|
+
* distinguishable. The type excludes anything at or above `2^248`.
|
|
93
|
+
* Confidentiality relies on the runtime constraining every `JubjubPoint` into
|
|
94
|
+
* the prime-order subgroup (see `crypto/ElGamal`), so `S` cannot be a
|
|
95
|
+
* low-order point that leaks `ek`.
|
|
96
|
+
* Binding the ephemeral `E` into the KDF is deliberately omitted (Remark 11.1):
|
|
97
|
+
* for a fixed `recipientPk`, `E = g^e` and `S = pk^e` are both determined by
|
|
98
|
+
* `e`, so `KDF(S)` already varies with `E`; folding it in only tightens the CCA
|
|
99
|
+
* reduction (Remark 12.2) which this module does not claim.
|
|
93
100
|
*
|
|
94
101
|
* @dev Shared key with `crypto/ElGamal` (in scope). A consumer MAY use the same
|
|
95
102
|
* recipient Jubjub key for both these memos (hashed ElGamal) and exponential-
|
|
@@ -131,7 +138,7 @@ module EcdhMask {
|
|
|
131
138
|
*
|
|
132
139
|
* @notice `e` MUST be fresh per call (see the module freshness precondition).
|
|
133
140
|
*
|
|
134
|
-
* @constraints k=14, rows=
|
|
141
|
+
* @constraints k=14, rows=9318 (zkir-v3)
|
|
135
142
|
*
|
|
136
143
|
* Requirements:
|
|
137
144
|
*
|
|
@@ -139,14 +146,15 @@ module EcdhMask {
|
|
|
139
146
|
* - `e` is non-zero, a valid Jubjub scalar (`< ℓ`), secret, and fresh per call.
|
|
140
147
|
*
|
|
141
148
|
* @param recipientPk - The recipient's Jubjub public key (`g^ek`).
|
|
142
|
-
* @param value - The value to deliver
|
|
149
|
+
* @param value - The value to deliver, any `Uint<248>`. The hiding margin
|
|
150
|
+
* shrinks as its width grows (see the module security note).
|
|
143
151
|
* @param e - A fresh ephemeral scalar.
|
|
144
152
|
* @param domain - The consumer's domain-separation tag (must match decrypt).
|
|
145
153
|
* @return The ciphertext `{ ephemeralPk = g^e, ct = value + KDF(pk^e) }`.
|
|
146
154
|
*/
|
|
147
155
|
export pure circuit encrypt(
|
|
148
156
|
recipientPk: JubjubPoint,
|
|
149
|
-
value: Uint<
|
|
157
|
+
value: Uint<248>,
|
|
150
158
|
e: JubjubScalar,
|
|
151
159
|
domain: Bytes<32>
|
|
152
160
|
): Ciphertext {
|
|
@@ -167,7 +175,7 @@ module EcdhMask {
|
|
|
167
175
|
* @dev Uses `persistentHash` deliberately: the recipient reproduces this mask
|
|
168
176
|
* to decrypt, possibly across a platform upgrade, so it must be upgrade-stable.
|
|
169
177
|
*
|
|
170
|
-
* @constraints k=13, rows=
|
|
178
|
+
* @constraints k=13, rows=7914 (zkir-v3)
|
|
171
179
|
*
|
|
172
180
|
* @param sShared - The ECDH shared secret point (`pk^e` for the sender,
|
|
173
181
|
* `E^ek` for the recipient; equal by construction).
|
|
@@ -175,9 +183,40 @@ module EcdhMask {
|
|
|
175
183
|
* @return The field mask.
|
|
176
184
|
*/
|
|
177
185
|
export pure circuit kdf(sShared: JubjubPoint, domain: Bytes<32>): Field {
|
|
178
|
-
|
|
186
|
+
return kdfFromDigest(pointDigest(sShared), domain);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @description `H(sShared)`, the secret input of `kdf`. A consumer deriving
|
|
191
|
+
* several masks from one shared point digests it once and calls
|
|
192
|
+
* `kdfFromDigest` per tag.
|
|
193
|
+
*
|
|
194
|
+
* @constraints k=13, rows=4098 (zkir-v3)
|
|
195
|
+
*
|
|
196
|
+
* @param sShared - The ECDH shared secret point.
|
|
197
|
+
* @return The point's digest, secret while `sShared` is.
|
|
198
|
+
*/
|
|
199
|
+
export pure circuit pointDigest(sShared: JubjubPoint): Bytes<32> {
|
|
200
|
+
return persistentHash<JubjubPoint>(sShared);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* @description The mask for `domain` from a point digest:
|
|
205
|
+
* `kdf(S, domain) == kdfFromDigest(pointDigest(S), domain)`.
|
|
206
|
+
*
|
|
207
|
+
* @notice One mask per `(digest, domain)`. Pad one value under each pair,
|
|
208
|
+
* and give every mask drawn from one digest its own tag; two values under
|
|
209
|
+
* one pair share the pad and leak their difference.
|
|
210
|
+
*
|
|
211
|
+
* @constraints k=13, rows=3956 (zkir-v3)
|
|
212
|
+
*
|
|
213
|
+
* @param digest - `pointDigest` of the shared point.
|
|
214
|
+
* @param domain - The consumer's domain-separation tag.
|
|
215
|
+
* @return The field mask.
|
|
216
|
+
*/
|
|
217
|
+
export pure circuit kdfFromDigest(digest: Bytes<32>, domain: Bytes<32>): Field {
|
|
179
218
|
return degradeToTransient(
|
|
180
|
-
persistentHash<Vector<2, Bytes<32>>>([
|
|
219
|
+
persistentHash<Vector<2, Bytes<32>>>([digest, domain])
|
|
181
220
|
);
|
|
182
221
|
}
|
|
183
222
|
|
|
@@ -189,14 +228,14 @@ module EcdhMask {
|
|
|
189
228
|
* (SEC 1 §5.1.4, action 3). `encrypt` cannot produce one, so a wallet that
|
|
190
229
|
* meets one holds a placeholder, not an encryption.
|
|
191
230
|
*
|
|
192
|
-
* @constraints k=14, rows=8976
|
|
231
|
+
* @constraints k=14, rows=8976 (zkir-v3)
|
|
193
232
|
*
|
|
194
233
|
* @param ciphertext - The ciphertext to decrypt.
|
|
195
234
|
* @param ekScalar - The recipient's secret scalar (`crypto/ElGamal`'s
|
|
196
235
|
* `secretToScalar(EK)`).
|
|
197
236
|
* @param domain - The consumer's domain-separation tag (must match encrypt).
|
|
198
237
|
* @return The recovered value as a `Field` (equal to the original `value`,
|
|
199
|
-
* which is `< 2^
|
|
238
|
+
* which is `< 2^248`).
|
|
200
239
|
*/
|
|
201
240
|
export pure circuit decrypt(ciphertext: Ciphertext, ekScalar: JubjubScalar, domain: Bytes<32>): Field {
|
|
202
241
|
// `encrypt` never emits an identity ephemeral; one here is a malformed
|
package/crypto/Ecdsa.compact
CHANGED
package/crypto/Eip712.compact
CHANGED
package/crypto/ElGamal.compact
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.5.0-alpha.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.5.0-alpha.2 (crypto/ElGamal.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
@@ -71,16 +71,17 @@ pragma language_version >= 0.26.0;
|
|
|
71
71
|
* @dev Weak keys. Encrypting under the identity point yields `c2 = m` with no
|
|
72
72
|
* masking (the plaintext is exposed), and the identity is a valid subgroup
|
|
73
73
|
* point so the runtime subgroup guarantee does NOT catch it. `encryptPoint`
|
|
74
|
-
* therefore
|
|
75
|
-
*
|
|
74
|
+
* therefore takes its mask from `crypto/Ecdh`'s `deriveShared`, which rejects
|
|
75
|
+
* an identity `pk`, and every encryption path routes through it, so
|
|
76
|
+
* confidentiality is protected regardless of the importer. An importing
|
|
76
77
|
* module MAY additionally reject an identity `pk` where keys enter the system
|
|
77
78
|
* (e.g. at registration) to fail fast with a clear error rather than at first
|
|
78
79
|
* encryption — a UX nicety, not a confidentiality requirement.
|
|
79
80
|
*
|
|
80
|
-
* @dev Randomness. `
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
81
|
+
* @dev Randomness. `r = 0` zeros the mask (`r*pk = O`), yielding the
|
|
82
|
+
* non-hiding `(O, m)`; `deriveShared` rejects it as a zero ephemeral, so
|
|
83
|
+
* together with the identity-`pk` guard the mask is always non-trivial. The
|
|
84
|
+
* remaining obligations the circuit CANNOT enforce:
|
|
84
85
|
* every `r` MUST be a valid Jubjub scalar (`< ℓ`, the subgroup order; larger
|
|
85
86
|
* values fault `ecMul`), and MUST be fresh and secret. Reusing an `r` under the
|
|
86
87
|
* same `pk` leaks the difference of the two plaintexts (`c1` collides, so
|
|
@@ -89,6 +90,7 @@ pragma language_version >= 0.26.0;
|
|
|
89
90
|
*/
|
|
90
91
|
module ElGamal {
|
|
91
92
|
import CompactStandardLibrary;
|
|
93
|
+
import "./Ecdh" prefix Ecdh_;
|
|
92
94
|
|
|
93
95
|
// ---------------------------------------------------------------------------
|
|
94
96
|
// Types
|
|
@@ -215,12 +217,10 @@ module ElGamal {
|
|
|
215
217
|
* @return The ciphertext `(g^r, pk^r * m)`.
|
|
216
218
|
*/
|
|
217
219
|
export pure circuit encryptPoint(pk: JubjubPoint, m: JubjubPoint, r: JubjubScalar): Ciphertext {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
const c2 = ecAdd(mask, m);
|
|
223
|
-
return Ciphertext { c1: c1, c2: c2 };
|
|
220
|
+
// The weak-input guards come from `deriveShared`, not repeated here.
|
|
221
|
+
const shared = Ecdh_deriveShared(pk, r);
|
|
222
|
+
const c2 = ecAdd(shared.sShared, m);
|
|
223
|
+
return Ciphertext { c1: shared.ephemeralPk, c2: c2 };
|
|
224
224
|
}
|
|
225
225
|
|
|
226
226
|
/**
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.5.0-alpha.2 (math/UintN.compact)
|
|
3
|
+
|
|
4
|
+
pragma language_version >= 0.26.0;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @module UintN
|
|
8
|
+
* @description Wrapping arithmetic on `Uint<N>` for any width `N`: results
|
|
9
|
+
* are reduced modulo `2^N`, and no input fails. Instantiate with a width, e.g.
|
|
10
|
+
* `UintN<64>`, `UintN<248>`.
|
|
11
|
+
*
|
|
12
|
+
* @dev Names and semantics follow Rust's `wrapping_add` and `wrapping_sub`.
|
|
13
|
+
* The `Field` shape follows Noir's `WrappingAdd` and `WrappingSub`, with
|
|
14
|
+
* arkworks' `UInt<N>` as the generic-width precedent. Noir's `as` truncates,
|
|
15
|
+
* but `as Uint<N>` fails out of range. Each circuit therefore reduces
|
|
16
|
+
* explicitly, selects between two `Field` arms, and casts once, outside the
|
|
17
|
+
* select.
|
|
18
|
+
*
|
|
19
|
+
* @dev The `Field` arithmetic is exact while `a + b` stays below the field
|
|
20
|
+
* modulus, which holds for `N <= 253` and so for every width `Uint<N>` admits.
|
|
21
|
+
*
|
|
22
|
+
* Supported Operations:
|
|
23
|
+
* - MODULUS(): `2^N` as a `Field`.
|
|
24
|
+
* - wrappingAdd(a, b): `(a + b) mod 2^N`.
|
|
25
|
+
* - wrappingSub(a, b): `(a - b) mod 2^N`.
|
|
26
|
+
*/
|
|
27
|
+
module UintN<#N> {
|
|
28
|
+
/**
|
|
29
|
+
* @description `2^N` as a `Field`: the modulus of every circuit in this
|
|
30
|
+
* module.
|
|
31
|
+
*
|
|
32
|
+
* @constraints k=5, rows=23 (zkir-v2, any N)
|
|
33
|
+
* @constraints k=6, rows=31 (zkir-v3, any N)
|
|
34
|
+
*
|
|
35
|
+
* @returns {Field} `2^N`.
|
|
36
|
+
*/
|
|
37
|
+
export pure circuit MODULUS(): Field {
|
|
38
|
+
return fold((acc: Field, _bit: Boolean): Field => acc * 2,
|
|
39
|
+
1 as Field,
|
|
40
|
+
default<Vector<N, Boolean>>);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @description Wrapping (modular) addition. Computes `a + b`, wrapping
|
|
45
|
+
* around at the boundary of the type.
|
|
46
|
+
*
|
|
47
|
+
* @dev The wrap test is `a > MAX - b`, which needs no `Uint<N + 1>`.
|
|
48
|
+
*
|
|
49
|
+
* @constraints depends on N:
|
|
50
|
+
* - UintN<8>: k=9, rows=98 (zkir-v2), k=9, rows=85 (zkir-v3)
|
|
51
|
+
* - UintN<64>: k=9, rows=308 (zkir-v2), k=9, rows=133 (zkir-v3)
|
|
52
|
+
* - UintN<248>: k=10, rows=980 (zkir-v2), k=9, rows=307 (zkir-v3)
|
|
53
|
+
*
|
|
54
|
+
* @param {Uint<N>} a - The first operand.
|
|
55
|
+
* @param {Uint<N>} b - The second operand.
|
|
56
|
+
* @returns {Uint<N>} `(a + b) mod 2^N`.
|
|
57
|
+
*/
|
|
58
|
+
export pure circuit wrappingAdd(a: Uint<N>, b: Uint<N>): Uint<N> {
|
|
59
|
+
const modulus = MODULUS();
|
|
60
|
+
const wraps = a > ((modulus - 1) as Uint<N>) - b;
|
|
61
|
+
const sum = (a as Field) + (b as Field);
|
|
62
|
+
return (wraps ? sum - modulus : sum) as Uint<N>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* @description Wrapping (modular) subtraction. Computes `a - b`, wrapping
|
|
67
|
+
* around at the boundary of the type.
|
|
68
|
+
*
|
|
69
|
+
* @constraints depends on N:
|
|
70
|
+
* - UintN<8>: k=9, rows=84 (zkir-v2), k=9, rows=73 (zkir-v3)
|
|
71
|
+
* - UintN<64>: k=9, rows=273 (zkir-v2), k=9, rows=118 (zkir-v3)
|
|
72
|
+
* - UintN<248>: k=10, rows=885 (zkir-v2), k=9, rows=274 (zkir-v3)
|
|
73
|
+
*
|
|
74
|
+
* @param {Uint<N>} a - The minuend.
|
|
75
|
+
* @param {Uint<N>} b - The subtrahend.
|
|
76
|
+
* @returns {Uint<N>} `(a - b) mod 2^N`.
|
|
77
|
+
*/
|
|
78
|
+
export pure circuit wrappingSub(a: Uint<N>, b: Uint<N>): Uint<N> {
|
|
79
|
+
const diff = (a as Field) - (b as Field);
|
|
80
|
+
return (a < b ? diff + MODULUS() : diff) as Uint<N>;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.5.0-alpha.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.5.0-alpha.2 (multisig/ProposalManager.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
@@ -107,8 +107,8 @@ module ProposalManager {
|
|
|
107
107
|
* checks and the deadline comparison above. `_proposals` is exported ledger
|
|
108
108
|
* state and readable without a proof. `executedState` and
|
|
109
109
|
* `cancelledState` are pure, so a reader can obtain the sentinel values without
|
|
110
|
-
* hardcoding them. A state-reading accessor will be revisited once
|
|
111
|
-
*
|
|
110
|
+
* hardcoding them. A state-reading accessor will be revisited once this library migrates to
|
|
111
|
+
* contract-to-contract calls.
|
|
112
112
|
*/
|
|
113
113
|
export struct Proposal {
|
|
114
114
|
to: Recipient,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// SPDX-License-Identifier: MIT
|
|
2
|
-
// OpenZeppelin Compact Contracts v0.5.0-alpha.
|
|
2
|
+
// OpenZeppelin Compact Contracts v0.5.0-alpha.2 (multisig/ShieldedTreasuryStateless.compact)
|
|
3
3
|
|
|
4
4
|
pragma language_version >= 0.26.0;
|
|
5
5
|
|
|
@@ -63,16 +63,10 @@ module ShieldedTreasuryStateless {
|
|
|
63
63
|
* self — `sendShielded` already routes it to self.) No balance or
|
|
64
64
|
* received/sent accounting is tracked on the ledger.
|
|
65
65
|
*
|
|
66
|
-
* @warning The
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* contract publishes those coin details, including the amount left over from
|
|
71
|
-
* the coin that was spent. Note the compiler will NOT stop you: the
|
|
72
|
-
* `disclose` calls below clear the witness taint, so such a return compiles
|
|
73
|
-
* with no `disclose` of your own and no marker at the disclosure site. If you
|
|
74
|
-
* do not need in-circuit change handling, ignore the result. The change is
|
|
75
|
-
* recoverable off-chain from the transaction's private proving state.
|
|
66
|
+
* @warning The result holds the sent and change coins in plaintext.
|
|
67
|
+
* - Returning it from an entry point is safe: it stays with the caller.
|
|
68
|
+
* - Writing it to the ledger publishes both coins. The compiler will not
|
|
69
|
+
* warn, because `_send` already wraps its inputs in `disclose`.
|
|
76
70
|
*
|
|
77
71
|
* @notice Access control is NOT enforced here.
|
|
78
72
|
* The consuming contract must gate this behind its own
|
package/multisig/Signer.compact
CHANGED