@lfdecentralizedtrust/zeto-contracts 0.2.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -162
- package/contracts/factory.sol +30 -34
- package/contracts/factory_upgradeable.sol +160 -0
- package/contracts/lib/common/util.sol +40 -0
- package/contracts/lib/interfaces/ILockableCapability.sol +318 -0
- package/contracts/lib/interfaces/{izeto.sol → IZeto.sol} +13 -1
- package/contracts/lib/interfaces/{izeto_initializable.sol → IZetoInitializable.sol} +14 -12
- package/contracts/lib/interfaces/{izeto_kyc.sol → IZetoKyc.sol} +3 -3
- package/contracts/lib/interfaces/IZetoLockableCapability.sol +237 -0
- package/contracts/lib/interfaces/IZetoStorage.sol +106 -0
- package/contracts/lib/interfaces/{izeto_lockable.sol → IZetoVerifier.sol} +8 -21
- package/contracts/lib/registry.sol +77 -27
- package/contracts/lib/storage/base.sol +210 -0
- package/contracts/lib/storage/nullifier.sol +166 -0
- package/contracts/lib/zeto_common.sol +277 -28
- package/contracts/lib/zeto_fungible.sol +451 -33
- package/contracts/lib/zeto_fungible_base.sol +69 -0
- package/contracts/lib/zeto_fungible_burn.sol +83 -53
- package/contracts/lib/zeto_fungible_burn_nullifier.sol +115 -72
- package/contracts/lib/zeto_fungible_nullifier.sol +167 -0
- package/contracts/lib/zeto_lockable.sol +613 -0
- package/contracts/lib/zeto_non_fungible.sol +236 -0
- package/contracts/lib/zeto_non_fungible_base.sol +61 -0
- package/contracts/lib/zeto_non_fungible_nullifier.sol +61 -0
- package/contracts/test/escrow1.sol +90 -34
- package/contracts/test/escrow2.sol +64 -29
- package/contracts/test/qurrency.sol +10 -2
- package/contracts/test/smt.sol +8 -3
- package/contracts/test/tendecimals.sol +14 -12
- package/contracts/verifiers/impl/anon.sol +189 -0
- package/contracts/verifiers/impl/anon_batch.sol +301 -0
- package/contracts/verifiers/impl/anon_enc.sol +266 -0
- package/contracts/verifiers/impl/anon_enc_batch.sol +602 -0
- package/contracts/verifiers/impl/anon_enc_nullifier.sol +287 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_batch.sol +679 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_kyc.sol +294 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_kyc_batch.sol +686 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation.sol +413 -0
- package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation_batch.sol +1141 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transfer.sol +217 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked.sol +196 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked_batch.sol +308 -0
- package/contracts/verifiers/impl/anon_nullifier_kyc_transfer_batch.sol +385 -0
- package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer.sol +497 -0
- package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer_batch.sol +1001 -0
- package/contracts/verifiers/{verifier_anon_nullifier_transferLocked.sol → impl/anon_nullifier_transfer.sol} +12 -19
- package/contracts/verifiers/{verifier_anon_nullifier_transferLocked_batch.sol → impl/anon_nullifier_transfer_batch.sol} +44 -51
- package/contracts/verifiers/impl/burn.sol +182 -0
- package/contracts/verifiers/impl/burn_batch.sol +238 -0
- package/contracts/verifiers/impl/burn_nullifier.sol +203 -0
- package/contracts/verifiers/impl/burn_nullifier_batch.sol +315 -0
- package/contracts/verifiers/impl/deposit.sol +182 -0
- package/contracts/verifiers/impl/deposit_kyc.sol +189 -0
- package/contracts/verifiers/impl/nf_anon.sol +175 -0
- package/contracts/verifiers/{verifier_nf_anon_nullifier_transferLocked.sol → impl/nf_anon_nullifier_transfer.sol} +6 -13
- package/contracts/verifiers/impl/withdraw.sol +189 -0
- package/contracts/verifiers/impl/withdraw_batch.sol +245 -0
- package/contracts/verifiers/impl/withdraw_nullifier.sol +210 -0
- package/contracts/verifiers/impl/withdraw_nullifier_batch.sol +322 -0
- package/contracts/verifiers/verifier_anon.sol +31 -186
- package/contracts/verifiers/verifier_anon_batch.sol +31 -298
- package/contracts/verifiers/verifier_anon_enc.sol +31 -263
- package/contracts/verifiers/verifier_anon_enc_batch.sol +31 -599
- package/contracts/verifiers/verifier_anon_enc_nullifier.sol +31 -284
- package/contracts/verifiers/verifier_anon_enc_nullifier_batch.sol +33 -676
- package/contracts/verifiers/verifier_anon_enc_nullifier_kyc.sol +31 -291
- package/contracts/verifiers/verifier_anon_enc_nullifier_kyc_batch.sol +33 -683
- package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation.sol +33 -410
- package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation_batch.sol +33 -1138
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer.sol +33 -214
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked.sol +33 -221
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked_batch.sol +33 -389
- package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer_batch.sol +33 -382
- package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer.sol +33 -221
- package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer_batch.sol +33 -389
- package/contracts/verifiers/verifier_anon_nullifier_transfer.sol +33 -207
- package/contracts/verifiers/verifier_anon_nullifier_transfer_batch.sol +33 -375
- package/contracts/verifiers/verifier_burn.sol +31 -179
- package/contracts/verifiers/verifier_burn_batch.sol +31 -235
- package/contracts/verifiers/verifier_burn_nullifier.sol +31 -200
- package/contracts/verifiers/verifier_burn_nullifier_batch.sol +31 -312
- package/contracts/verifiers/verifier_deposit.sol +31 -179
- package/contracts/verifiers/verifier_deposit_kyc.sol +34 -0
- package/contracts/verifiers/verifier_nf_anon.sol +31 -172
- package/contracts/verifiers/verifier_nf_anon_nullifier_transfer.sol +33 -179
- package/contracts/verifiers/verifier_withdraw.sol +31 -186
- package/contracts/verifiers/verifier_withdraw_batch.sol +31 -242
- package/contracts/verifiers/verifier_withdraw_nullifier.sol +31 -207
- package/contracts/verifiers/verifier_withdraw_nullifier_batch.sol +33 -319
- package/contracts/zeto_anon.sol +77 -231
- package/contracts/zeto_anon_burnable.sol +56 -12
- package/contracts/zeto_anon_enc.sol +93 -190
- package/contracts/zeto_anon_enc_nullifier.sol +249 -195
- package/contracts/zeto_anon_enc_nullifier_kyc.sol +51 -232
- package/contracts/zeto_anon_enc_nullifier_non_repudiation.sol +231 -238
- package/contracts/zeto_anon_nullifier.sol +164 -298
- package/contracts/zeto_anon_nullifier_burnable.sol +68 -18
- package/contracts/zeto_anon_nullifier_kyc.sol +40 -345
- package/contracts/zeto_anon_nullifier_qurrency.sol +218 -360
- package/contracts/zeto_nf_anon.sol +55 -130
- package/contracts/zeto_nf_anon_nullifier.sol +90 -152
- package/hardhat.config.ts +9 -3
- package/ignition/modules/lib/deps.ts +9 -6
- package/ignition/modules/zeto_anon_burnable.ts +8 -7
- package/ignition/modules/zeto_anon_enc_nullifier.ts +33 -1
- package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +2 -2
- package/ignition/modules/zeto_anon_enc_nullifier_non_repudiation.ts +2 -1
- package/ignition/modules/zeto_anon_nullifier.ts +30 -5
- package/ignition/modules/zeto_anon_nullifier_burnable.ts +52 -17
- package/ignition/modules/zeto_anon_nullifier_kyc.ts +27 -12
- package/ignition/modules/zeto_anon_nullifier_qurrency.ts +2 -1
- package/ignition/modules/zeto_nf_anon_nullifier.ts +16 -12
- package/package.json +4 -2
- package/scripts/deploy_cloneable.ts +19 -10
- package/scripts/deploy_upgradeable.ts +9 -5
- package/scripts/tokens/Zeto_Anon.ts +3 -3
- package/scripts/tokens/Zeto_AnonBurnable.ts +1 -1
- package/scripts/tokens/Zeto_AnonEnc.ts +12 -3
- package/scripts/tokens/Zeto_AnonEncNullifier.ts +7 -3
- package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +1 -1
- package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +3 -1
- package/scripts/tokens/Zeto_AnonNullifier.ts +3 -1
- package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +3 -1
- package/scripts/tokens/Zeto_AnonNullifierKyc.ts +1 -1
- package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +3 -1
- package/scripts/tokens/Zeto_NfAnon.ts +2 -2
- package/scripts/tokens/Zeto_NfAnonNullifier.ts +3 -2
- package/test/factory.ts +46 -73
- package/test/factory_upgradeable.ts +311 -0
- package/test/lib/anon_nullifier_helpers.ts +89 -0
- package/test/lib/anon_zeto_helpers.ts +76 -0
- package/test/lib/deploy.ts +3 -2
- package/test/lib/utils.ts +74 -35
- package/test/test/escrow1.ts +185 -58
- package/test/test/escrow2.ts +200 -107
- package/test/test/qurrency.ts +13 -33
- package/test/usdc-shielding.ts +39 -26
- package/test/utils.ts +144 -21
- package/test/zeto_anon.ts +956 -465
- package/test/zeto_anon_enc.ts +881 -142
- package/test/zeto_anon_enc_nullifier.ts +847 -38
- package/test/zeto_anon_enc_nullifier_kyc.ts +120 -181
- package/test/zeto_anon_enc_nullifier_non_repudiation.ts +77 -46
- package/test/zeto_anon_nullifier.ts +1212 -953
- package/test/zeto_anon_nullifier_kyc.ts +674 -655
- package/test/zeto_anon_nullifier_qurrency.ts +452 -306
- package/test/zeto_nf_anon.ts +737 -137
- package/test/zeto_nf_anon_nullifier.ts +876 -246
- package/contracts/lib/zeto_base.sol +0 -293
- package/contracts/lib/zeto_fungible_withdraw.sol +0 -132
- package/contracts/lib/zeto_fungible_withdraw_nullifier.sol +0 -144
- package/contracts/lib/zeto_nullifier.sol +0 -334
- package/contracts/zkDvP.sol_ +0 -273
- package/test/zkDvP.ts_ +0 -455
- /package/contracts/lib/{common.sol → common/common.sol} +0 -0
|
@@ -15,155 +15,80 @@
|
|
|
15
15
|
// limitations under the License.
|
|
16
16
|
pragma solidity ^0.8.27;
|
|
17
17
|
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {Commonlib} from "./lib/common.sol";
|
|
22
|
-
import {IZetoInitializable} from "./lib/interfaces/izeto_initializable.sol";
|
|
18
|
+
import {ZetoNonFungibleBase} from "./lib/zeto_non_fungible_base.sol";
|
|
19
|
+
import {Commonlib} from "./lib/common/common.sol";
|
|
20
|
+
import {IZetoInitializable} from "./lib/interfaces/IZetoInitializable.sol";
|
|
23
21
|
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
24
22
|
|
|
25
|
-
/// @title A sample implementation of a Zeto based non-fungible token with
|
|
23
|
+
/// @title A sample implementation of a Zeto based non-fungible token with
|
|
24
|
+
/// anonymity (no encryption, no nullifier history masking).
|
|
26
25
|
/// @author Kaleido, Inc.
|
|
26
|
+
/// @notice Decimals: this token uses **4** decimals, inherited from
|
|
27
|
+
/// {ZetoCommon.decimals}. NFT integrators rarely consult
|
|
28
|
+
/// `decimals()` but it is preserved for ABI symmetry with the
|
|
29
|
+
/// fungible siblings.
|
|
27
30
|
/// @dev The proof has the following statements:
|
|
28
|
-
/// - The sender owns the private key whose public key is part of the pre-image of the input
|
|
29
|
-
///
|
|
30
|
-
///
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
/// - The sender owns the private key whose public key is part of the pre-image of the input UTXO commitment
|
|
32
|
+
/// - The output UTXO commitment is well-formed
|
|
33
|
+
///
|
|
34
|
+
/// Single-input/single-output transfer. The lock lifecycle is
|
|
35
|
+
/// intentionally omitted in this revival; see {ZetoNonFungible}.
|
|
36
|
+
contract Zeto_NfAnon is ZetoNonFungibleBase, UUPSUpgradeable {
|
|
37
|
+
/// @dev Lock the implementation contract on construction.
|
|
38
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
39
|
+
constructor() {
|
|
40
|
+
_disableInitializers();
|
|
41
|
+
}
|
|
33
42
|
|
|
34
43
|
function initialize(
|
|
35
|
-
string
|
|
36
|
-
string
|
|
44
|
+
string calldata name,
|
|
45
|
+
string calldata symbol,
|
|
37
46
|
address initialOwner,
|
|
38
47
|
IZetoInitializable.VerifiersInfo calldata verifiers
|
|
39
48
|
) public initializer {
|
|
40
|
-
|
|
41
|
-
_verifier = (Groth16Verifier_NfAnon)(verifiers.verifier);
|
|
49
|
+
__ZetoNonFungibleBase_init(name, symbol, initialOwner, verifiers);
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
function _authorizeUpgrade(address) internal override onlyOwner {}
|
|
45
53
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
uint256
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
inputs[0] = input;
|
|
64
|
-
uint256[] memory outputs = new uint256[](1);
|
|
65
|
-
outputs[0] = output;
|
|
66
|
-
uint256[] memory lockedOutputs;
|
|
67
|
-
validateTransactionProposal(inputs, outputs, lockedOutputs, false);
|
|
68
|
-
|
|
69
|
-
// construct the public inputs
|
|
70
|
-
uint256[2] memory publicInputs;
|
|
71
|
-
publicInputs[0] = input;
|
|
72
|
-
publicInputs[1] = output;
|
|
73
|
-
|
|
74
|
-
// Check the proof
|
|
75
|
-
require(
|
|
76
|
-
_verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
|
|
77
|
-
"Invalid proof"
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
processInputsAndOutputs(inputs, outputs, lockedOutputs, false);
|
|
81
|
-
|
|
82
|
-
emit UTXOTransfer(inputs, outputs, msg.sender, data);
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* @dev the main function of the contract.
|
|
88
|
-
*
|
|
89
|
-
* @param input The UTXO to be spent by the transaction.
|
|
90
|
-
* @param output The new UTXO to generate, for future transactions to spend.
|
|
91
|
-
* @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
|
|
92
|
-
* that the outputs are valid in terms of obeying mass conservation rules.
|
|
93
|
-
*
|
|
94
|
-
* Emits a {UTXOTransfer} event.
|
|
95
|
-
*/
|
|
96
|
-
function transferLocked(
|
|
97
|
-
uint256 input,
|
|
98
|
-
uint256 output,
|
|
99
|
-
Commonlib.Proof calldata proof,
|
|
100
|
-
bytes calldata data
|
|
101
|
-
) public returns (bool) {
|
|
102
|
-
uint256[] memory inputs = new uint256[](1);
|
|
103
|
-
inputs[0] = input;
|
|
104
|
-
uint256[] memory outputs = new uint256[](1);
|
|
105
|
-
outputs[0] = output;
|
|
106
|
-
uint256[] memory lockedOutputs;
|
|
107
|
-
validateTransactionProposal(inputs, outputs, lockedOutputs, true);
|
|
108
|
-
|
|
109
|
-
// construct the public inputs
|
|
110
|
-
uint256[2] memory publicInputs;
|
|
111
|
-
publicInputs[0] = input;
|
|
112
|
-
publicInputs[1] = output;
|
|
113
|
-
|
|
114
|
-
// Check the proof
|
|
115
|
-
require(
|
|
116
|
-
_verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
|
|
117
|
-
"Invalid proof"
|
|
54
|
+
/// @dev Public-inputs layout: [input, output]. `inputsLocked` is
|
|
55
|
+
/// ignored because this token does not implement the lock
|
|
56
|
+
/// lifecycle.
|
|
57
|
+
function constructPublicInputs(
|
|
58
|
+
uint256[] memory inputs,
|
|
59
|
+
uint256[] memory outputs,
|
|
60
|
+
bytes memory proof,
|
|
61
|
+
bool /* inputsLocked */
|
|
62
|
+
)
|
|
63
|
+
internal
|
|
64
|
+
pure
|
|
65
|
+
override
|
|
66
|
+
returns (uint256[] memory, Commonlib.Proof memory)
|
|
67
|
+
{
|
|
68
|
+
Commonlib.Proof memory proofStruct = abi.decode(
|
|
69
|
+
proof,
|
|
70
|
+
(Commonlib.Proof)
|
|
118
71
|
);
|
|
72
|
+
uint256[] memory publicInputs = new uint256[](2);
|
|
73
|
+
publicInputs[0] = inputs[0];
|
|
74
|
+
publicInputs[1] = outputs[0];
|
|
119
75
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
emit UTXOTransfer(inputs, outputs, msg.sender, data);
|
|
123
|
-
return true;
|
|
76
|
+
return (publicInputs, proofStruct);
|
|
124
77
|
}
|
|
78
|
+
}
|
|
125
79
|
|
|
126
|
-
|
|
127
|
-
|
|
80
|
+
/// @dev ERC-7201 (`erc7201:zeto.storage.Zeto_NfAnon`).
|
|
81
|
+
library Zeto_NfAnonStorage {
|
|
82
|
+
struct Layout {
|
|
83
|
+
uint256 __reserved;
|
|
128
84
|
}
|
|
129
85
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
uint256 lockedOutput,
|
|
133
|
-
Commonlib.Proof calldata proof,
|
|
134
|
-
address delegate,
|
|
135
|
-
bytes calldata data
|
|
136
|
-
) public {
|
|
137
|
-
uint256[] memory inputs = new uint256[](1);
|
|
138
|
-
inputs[0] = input;
|
|
139
|
-
uint256[] memory outputs;
|
|
140
|
-
uint256[] memory lockedOutputs = new uint256[](1);
|
|
141
|
-
lockedOutputs[0] = lockedOutput;
|
|
142
|
-
validateTransactionProposal(inputs, outputs, lockedOutputs, false);
|
|
143
|
-
|
|
144
|
-
// construct the public inputs
|
|
145
|
-
uint256[2] memory publicInputs;
|
|
146
|
-
publicInputs[0] = input;
|
|
147
|
-
publicInputs[1] = lockedOutput;
|
|
148
|
-
|
|
149
|
-
// Check the proof
|
|
150
|
-
require(
|
|
151
|
-
_verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
|
|
152
|
-
"Invalid proof"
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
processInputsAndOutputs(inputs, outputs, lockedOutputs, false);
|
|
156
|
-
|
|
157
|
-
// lock the intended outputs
|
|
158
|
-
_lock(inputs, outputs, lockedOutputs, delegate, data);
|
|
159
|
-
}
|
|
86
|
+
bytes32 private constant STORAGE_LOCATION =
|
|
87
|
+
0xafcd749646d899cf78964151db8f542448d05467330245e10728559327401500;
|
|
160
88
|
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
bytes calldata data
|
|
166
|
-
) public {
|
|
167
|
-
transferLocked(input, output, proof, data);
|
|
89
|
+
function layout() internal pure returns (Layout storage $) {
|
|
90
|
+
assembly {
|
|
91
|
+
$.slot := STORAGE_LOCATION
|
|
92
|
+
}
|
|
168
93
|
}
|
|
169
94
|
}
|
|
@@ -15,177 +15,115 @@
|
|
|
15
15
|
// limitations under the License.
|
|
16
16
|
pragma solidity ^0.8.27;
|
|
17
17
|
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {ZetoNullifier} from "./lib/zeto_nullifier.sol";
|
|
22
|
-
import {Commonlib} from "./lib/common.sol";
|
|
23
|
-
import {IZetoInitializable} from "./lib/interfaces/izeto_initializable.sol";
|
|
18
|
+
import {ZetoNonFungibleNullifier} from "./lib/zeto_non_fungible_nullifier.sol";
|
|
19
|
+
import {Commonlib} from "./lib/common/common.sol";
|
|
20
|
+
import {IZetoInitializable} from "./lib/interfaces/IZetoInitializable.sol";
|
|
24
21
|
import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
|
|
25
22
|
|
|
26
|
-
/// @title A sample implementation of a Zeto based non-fungible token with
|
|
23
|
+
/// @title A sample implementation of a Zeto based non-fungible token with
|
|
24
|
+
/// anonymity and history masking via nullifiers.
|
|
27
25
|
/// @author Kaleido, Inc.
|
|
26
|
+
/// @notice Decimals: this token uses **4** decimals, inherited from
|
|
27
|
+
/// {ZetoCommon.decimals}. NFT integrators rarely consult
|
|
28
|
+
/// `decimals()` but it is preserved for ABI symmetry with the
|
|
29
|
+
/// fungible siblings.
|
|
28
30
|
/// @dev The proof has the following statements:
|
|
29
|
-
/// -
|
|
30
|
-
///
|
|
31
|
-
/// -
|
|
32
|
-
/// -
|
|
33
|
-
///
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
31
|
+
/// - The sender owns the private key whose public key is part of the pre-image of the input UTXO commitment
|
|
32
|
+
/// (which corresponds to the nullifier).
|
|
33
|
+
/// - The nullifier represents an input commitment included in a Sparse Merkle Tree represented by the root hash.
|
|
34
|
+
/// - The output UTXO commitment is well-formed.
|
|
35
|
+
///
|
|
36
|
+
/// Two public-inputs layouts are produced depending on whether the
|
|
37
|
+
/// transition is consuming an unlocked input (a nullifier proven
|
|
38
|
+
/// against the unlocked-commitments SMT) or a locked input (a raw
|
|
39
|
+
/// UTXO hash whose locked status is verified by the storage layer
|
|
40
|
+
/// itself):
|
|
41
|
+
/// - unlocked: `[nullifier, root, output]` -> verified by
|
|
42
|
+
/// {Groth16Verifier_NfAnonNullifierTransfer}.
|
|
43
|
+
/// - locked: `[input, output]` -> verified by the
|
|
44
|
+
/// simpler {Groth16Verifier_NfAnon}.
|
|
45
|
+
/// This mirrors how {Zeto_AnonNullifier} reuses the non-nullifier
|
|
46
|
+
/// verifier for its lock path. The locked branch does not require
|
|
47
|
+
/// a Merkle inclusion proof because the contract has already
|
|
48
|
+
/// validated the input via {NullifierStorage.validateInputs} (it
|
|
49
|
+
/// defers to {BaseStorage.validateInputs} when `inputsLocked`).
|
|
50
|
+
contract Zeto_NfAnonNullifier is ZetoNonFungibleNullifier, UUPSUpgradeable {
|
|
51
|
+
/// @dev Lock the implementation contract on construction.
|
|
52
|
+
/// @custom:oz-upgrades-unsafe-allow constructor
|
|
53
|
+
constructor() {
|
|
54
|
+
_disableInitializers();
|
|
55
|
+
}
|
|
42
56
|
|
|
43
57
|
function initialize(
|
|
44
|
-
string
|
|
45
|
-
string
|
|
58
|
+
string calldata name,
|
|
59
|
+
string calldata symbol,
|
|
46
60
|
address initialOwner,
|
|
47
61
|
IZetoInitializable.VerifiersInfo calldata verifiers
|
|
48
62
|
) public initializer {
|
|
49
|
-
|
|
50
|
-
_verifier = (Groth16Verifier_NfAnonNullifierTransfer)(
|
|
51
|
-
verifiers.verifier
|
|
52
|
-
);
|
|
53
|
-
_lockVerifier = (Groth16Verifier_NfAnonNullifierTransferLocked)(
|
|
54
|
-
verifiers.lockVerifier
|
|
55
|
-
);
|
|
63
|
+
__ZetoNonFungibleNullifier_init(name, symbol, initialOwner, verifiers);
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
function _authorizeUpgrade(address) internal override onlyOwner {}
|
|
59
67
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
function
|
|
72
|
-
uint256
|
|
73
|
-
uint256 output,
|
|
74
|
-
uint256 root,
|
|
75
|
-
Commonlib.Proof calldata proof,
|
|
76
|
-
bytes calldata data
|
|
77
|
-
) public returns (bool) {
|
|
78
|
-
uint256[] memory nullifiers = new uint256[](1);
|
|
79
|
-
nullifiers[0] = nullifier;
|
|
80
|
-
uint256[] memory outputs = new uint256[](1);
|
|
81
|
-
outputs[0] = output;
|
|
82
|
-
validateTransactionProposal(nullifiers, outputs, root, false);
|
|
83
|
-
checkProof(nullifiers, outputs, root, proof);
|
|
84
|
-
uint256[] memory empty;
|
|
85
|
-
processInputsAndOutputs(nullifiers, outputs, empty, address(0));
|
|
86
|
-
|
|
87
|
-
emit UTXOTransfer(nullifiers, outputs, msg.sender, data);
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* @dev the main function of the contract.
|
|
93
|
-
*
|
|
94
|
-
* @param nullifier A nullifier that are secretly bound to the UTXO to be spent by the transaction.
|
|
95
|
-
* @param output new UTXO to generate, for future transactions to spend.
|
|
96
|
-
* @param root The root hash of the Sparse Merkle Tree that contains the nullifier.
|
|
97
|
-
* @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
|
|
98
|
-
* that the outputs are valid in terms of obeying mass conservation rules.
|
|
99
|
-
*
|
|
100
|
-
* Emits a {UTXOTransfer} event.
|
|
101
|
-
*/
|
|
102
|
-
function transferLocked(
|
|
103
|
-
uint256 nullifier,
|
|
104
|
-
uint256 output,
|
|
105
|
-
uint256 root,
|
|
106
|
-
Commonlib.Proof calldata proof,
|
|
107
|
-
bytes calldata data
|
|
108
|
-
) public returns (bool) {
|
|
109
|
-
uint256[] memory nullifiers = new uint256[](1);
|
|
110
|
-
nullifiers[0] = nullifier;
|
|
111
|
-
uint256[] memory outputs = new uint256[](1);
|
|
112
|
-
outputs[0] = output;
|
|
113
|
-
validateTransactionProposal(nullifiers, outputs, root, true);
|
|
114
|
-
checkProofLocked(nullifiers, outputs, root, proof);
|
|
115
|
-
uint256[] memory empty;
|
|
116
|
-
processInputsAndOutputs(nullifiers, outputs, empty, address(0));
|
|
117
|
-
|
|
118
|
-
emit UTXOTransfer(nullifiers, outputs, msg.sender, data);
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function mint(uint256[] memory utxos, bytes calldata data) public {
|
|
123
|
-
_mint(utxos, data);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function lock(
|
|
127
|
-
uint256 nullifier,
|
|
128
|
-
uint256 lockedOutput,
|
|
129
|
-
uint256 root,
|
|
130
|
-
Commonlib.Proof calldata proof,
|
|
131
|
-
address delegate,
|
|
132
|
-
bytes calldata data
|
|
133
|
-
) public {
|
|
134
|
-
uint256[] memory nullifiers = new uint256[](1);
|
|
135
|
-
nullifiers[0] = nullifier;
|
|
136
|
-
uint256[] memory lockedOutputs = new uint256[](1);
|
|
137
|
-
lockedOutputs[0] = lockedOutput;
|
|
138
|
-
validateTransactionProposal(nullifiers, lockedOutputs, root, false);
|
|
139
|
-
checkProof(nullifiers, lockedOutputs, root, proof);
|
|
140
|
-
|
|
141
|
-
processNullifiers(nullifiers);
|
|
142
|
-
|
|
143
|
-
// lock the intended outputs
|
|
144
|
-
uint256[] memory outputs;
|
|
145
|
-
_lock(nullifiers, outputs, lockedOutputs, delegate, data);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function checkProof(
|
|
149
|
-
uint256[] memory nullifiers,
|
|
68
|
+
/// @dev Public-inputs layout depends on `inputsLocked`:
|
|
69
|
+
/// - !inputsLocked: `[nullifier, root, output]` paired with the
|
|
70
|
+
/// `nf_anon_nullifier_transfer` circuit. The proof carries
|
|
71
|
+
/// `(uint256 root, Commonlib.Proof)`; the root is decoded
|
|
72
|
+
/// and validated here so that `validateTransactionProposal`
|
|
73
|
+
/// does not need to pre-decode the proof.
|
|
74
|
+
/// - inputsLocked: `[input, output]` paired with the simpler
|
|
75
|
+
/// `nf_anon` circuit. No root: the storage layer has
|
|
76
|
+
/// already verified the input is in `_lockedUtxos`, so we
|
|
77
|
+
/// do not re-prove inclusion in a locked-SMT. The proof
|
|
78
|
+
/// payload is just `Commonlib.Proof`.
|
|
79
|
+
function constructPublicInputs(
|
|
80
|
+
uint256[] memory inputs,
|
|
150
81
|
uint256[] memory outputs,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
82
|
+
bytes memory proof,
|
|
83
|
+
bool inputsLocked
|
|
84
|
+
)
|
|
85
|
+
internal
|
|
86
|
+
view
|
|
87
|
+
override
|
|
88
|
+
returns (uint256[] memory, Commonlib.Proof memory)
|
|
89
|
+
{
|
|
90
|
+
if (inputsLocked) {
|
|
91
|
+
Commonlib.Proof memory proofStruct = abi.decode(
|
|
92
|
+
proof,
|
|
93
|
+
(Commonlib.Proof)
|
|
94
|
+
);
|
|
95
|
+
uint256[] memory publicInputs = new uint256[](2);
|
|
96
|
+
publicInputs[0] = inputs[0];
|
|
97
|
+
publicInputs[1] = outputs[0];
|
|
98
|
+
return (publicInputs, proofStruct);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
(uint256 root, Commonlib.Proof memory proofStruct) = abi.decode(
|
|
102
|
+
proof,
|
|
103
|
+
(uint256, Commonlib.Proof)
|
|
104
|
+
);
|
|
105
|
+
validateRoot(root);
|
|
106
|
+
|
|
107
|
+
uint256[] memory publicInputs = new uint256[](3);
|
|
108
|
+
publicInputs[0] = inputs[0];
|
|
157
109
|
publicInputs[1] = root;
|
|
158
110
|
publicInputs[2] = outputs[0];
|
|
111
|
+
return (publicInputs, proofStruct);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
159
114
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
);
|
|
115
|
+
/// @dev ERC-7201 (`erc7201:zeto.storage.Zeto_NfAnonNullifier`).
|
|
116
|
+
library Zeto_NfAnonNullifierStorage {
|
|
117
|
+
struct Layout {
|
|
118
|
+
uint256 __reserved;
|
|
165
119
|
}
|
|
166
120
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
uint256[] memory outputs,
|
|
170
|
-
uint256 root,
|
|
171
|
-
Commonlib.Proof calldata proof
|
|
172
|
-
) internal view {
|
|
173
|
-
// construct the public inputs
|
|
174
|
-
uint256[4] memory publicInputs;
|
|
175
|
-
publicInputs[0] = nullifiers[0];
|
|
176
|
-
publicInputs[1] = uint256(uint160(msg.sender));
|
|
177
|
-
publicInputs[2] = root;
|
|
178
|
-
publicInputs[3] = outputs[0];
|
|
121
|
+
bytes32 private constant STORAGE_LOCATION =
|
|
122
|
+
0xb42e743e63c75bf1f2c05ab181e1371afad8f4114706ec6cfc12171a24893700;
|
|
179
123
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
proof.pB,
|
|
185
|
-
proof.pC,
|
|
186
|
-
publicInputs
|
|
187
|
-
),
|
|
188
|
-
"Invalid proof"
|
|
189
|
-
);
|
|
124
|
+
function layout() internal pure returns (Layout storage $) {
|
|
125
|
+
assembly {
|
|
126
|
+
$.slot := STORAGE_LOCATION
|
|
127
|
+
}
|
|
190
128
|
}
|
|
191
129
|
}
|
package/hardhat.config.ts
CHANGED
|
@@ -20,8 +20,8 @@ import "@openzeppelin/hardhat-upgrades";
|
|
|
20
20
|
import crypto from "crypto";
|
|
21
21
|
|
|
22
22
|
const keys = [
|
|
23
|
-
crypto.randomBytes(32).toString("hex"),
|
|
24
|
-
crypto.randomBytes(32).toString("hex"),
|
|
23
|
+
process.env.ETH_PRIVATE_KEY_1 || crypto.randomBytes(32).toString("hex"),
|
|
24
|
+
process.env.ETH_PRIVATE_KEY_2 || crypto.randomBytes(32).toString("hex"),
|
|
25
25
|
crypto.randomBytes(32).toString("hex"),
|
|
26
26
|
crypto.randomBytes(32).toString("hex"),
|
|
27
27
|
crypto.randomBytes(32).toString("hex"),
|
|
@@ -41,14 +41,20 @@ const config: HardhatUserConfig = {
|
|
|
41
41
|
settings: {
|
|
42
42
|
optimizer: {
|
|
43
43
|
enabled: true,
|
|
44
|
-
runs:
|
|
44
|
+
runs: 25,
|
|
45
45
|
},
|
|
46
|
+
viaIR: true,
|
|
46
47
|
},
|
|
47
48
|
},
|
|
48
49
|
paths: {
|
|
49
50
|
sources: "contracts"
|
|
50
51
|
},
|
|
51
52
|
networks: {
|
|
53
|
+
hardhat: {
|
|
54
|
+
// a small number of verifiers are bigger than the default 24576 bytes
|
|
55
|
+
// so we need to allow unlimited contract size to avoid test errors
|
|
56
|
+
allowUnlimitedContractSize: true,
|
|
57
|
+
},
|
|
52
58
|
besu: {
|
|
53
59
|
url: "http://localhost:8545",
|
|
54
60
|
accounts: keys,
|
|
@@ -23,12 +23,7 @@ export const SmtLibModule = buildModule("SmtLib", (m) => {
|
|
|
23
23
|
const poseidon3 = m.library("Poseidon3", PoseidonArtifact(3));
|
|
24
24
|
const poseidon5 = m.library("Poseidon5", PoseidonArtifact(5));
|
|
25
25
|
const poseidon6 = m.library("Poseidon6", PoseidonArtifact(6));
|
|
26
|
-
const smtLib = m.contract("SmtLib", []
|
|
27
|
-
libraries: {
|
|
28
|
-
PoseidonUnit2L: poseidon2,
|
|
29
|
-
PoseidonUnit3L: poseidon3,
|
|
30
|
-
},
|
|
31
|
-
});
|
|
26
|
+
const smtLib = m.contract("SmtLib", []);
|
|
32
27
|
return { smtLib, poseidon2, poseidon3, poseidon5, poseidon6 };
|
|
33
28
|
});
|
|
34
29
|
|
|
@@ -40,6 +35,14 @@ export const DepositVerifierModule = buildModule(
|
|
|
40
35
|
},
|
|
41
36
|
);
|
|
42
37
|
|
|
38
|
+
export const DepositKycVerifierModule = buildModule(
|
|
39
|
+
"Groth16Verifier_DepositKyc",
|
|
40
|
+
(m) => {
|
|
41
|
+
const verifier = m.contract("Groth16Verifier_DepositKyc", []);
|
|
42
|
+
return { verifier };
|
|
43
|
+
},
|
|
44
|
+
);
|
|
45
|
+
|
|
43
46
|
export const WithdrawNullifierVerifierModule = buildModule(
|
|
44
47
|
"Groth16Verifier_WithdrawNullifier",
|
|
45
48
|
(m) => {
|
|
@@ -36,10 +36,13 @@ const BurnVerifierModule = buildModule("Groth16Verifier_Burn", (m) => {
|
|
|
36
36
|
return { verifier };
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
const BatchBurnVerifierModule = buildModule(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
const BatchBurnVerifierModule = buildModule(
|
|
40
|
+
"Groth16Verifier_BurnBatch",
|
|
41
|
+
(m) => {
|
|
42
|
+
const verifier = m.contract("Groth16Verifier_BurnBatch", []);
|
|
43
|
+
return { verifier };
|
|
44
|
+
},
|
|
45
|
+
);
|
|
43
46
|
|
|
44
47
|
export default buildModule("Zeto_AnonBurnable", (m) => {
|
|
45
48
|
const { verifier } = m.useModule(VerifierModule);
|
|
@@ -50,9 +53,7 @@ export default buildModule("Zeto_AnonBurnable", (m) => {
|
|
|
50
53
|
BatchWithdrawVerifierModule,
|
|
51
54
|
);
|
|
52
55
|
const { verifier: burnVerifier } = m.useModule(BurnVerifierModule);
|
|
53
|
-
const { verifier: batchBurnVerifier } = m.useModule(
|
|
54
|
-
BatchBurnVerifierModule,
|
|
55
|
-
);
|
|
56
|
+
const { verifier: batchBurnVerifier } = m.useModule(BatchBurnVerifierModule);
|
|
56
57
|
return {
|
|
57
58
|
depositVerifier,
|
|
58
59
|
withdrawVerifier,
|
|
@@ -35,10 +35,39 @@ const BatchVerifierModule = buildModule(
|
|
|
35
35
|
},
|
|
36
36
|
);
|
|
37
37
|
|
|
38
|
+
// Locked-input transfers reuse the plain {Groth16Verifier_AnonEnc} verifier
|
|
39
|
+
// (the same one the non-nullifier {Zeto_AnonEnc} token uses for its
|
|
40
|
+
// regular transfers), NOT a nullifier-aware verifier.
|
|
41
|
+
//
|
|
42
|
+
// Rationale: under the new ILockableCapability storage, locked UTXOs are
|
|
43
|
+
// kept in a flat per-lock mapping keyed by lockId — there is no SMT for
|
|
44
|
+
// locked UTXOs and the locked-input proof has no nullifier history to
|
|
45
|
+
// bind against. {Zeto_AnonEncNullifier.constructPublicInputs(...,
|
|
46
|
+
// inputsLocked = true)} reflects this by emitting public inputs as
|
|
47
|
+
// `[ecdhPublicKey, encryptedValues, inputCommitments, outputCommitments,
|
|
48
|
+
// encryptionNonce]` — exactly what `Groth16Verifier_AnonEnc` expects.
|
|
49
|
+
// The encryption witness (ECDH key + encrypted blob) still applies because
|
|
50
|
+
// the receiver still needs data availability for the post-spend outputs.
|
|
51
|
+
const LockVerifierModule = buildModule("Groth16Verifier_AnonEnc", (m) => {
|
|
52
|
+
const verifier = m.contract("Groth16Verifier_AnonEnc", []);
|
|
53
|
+
return { verifier };
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Batched (10-in / 10-out) twin of {LockVerifierModule}. Same rationale.
|
|
57
|
+
const BatchLockVerifierModule = buildModule(
|
|
58
|
+
"Groth16Verifier_AnonEncBatch",
|
|
59
|
+
(m) => {
|
|
60
|
+
const verifier = m.contract("Groth16Verifier_AnonEncBatch", []);
|
|
61
|
+
return { verifier };
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
38
65
|
export default buildModule("Zeto_AnonEncNullifier", (m) => {
|
|
39
|
-
const { smtLib, poseidon3 } = m.useModule(SmtLibModule);
|
|
66
|
+
const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
|
|
40
67
|
const { verifier } = m.useModule(VerifierModule);
|
|
68
|
+
const { verifier: lockVerifier } = m.useModule(LockVerifierModule);
|
|
41
69
|
const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
|
|
70
|
+
const { verifier: batchLockVerifier } = m.useModule(BatchLockVerifierModule);
|
|
42
71
|
const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
|
|
43
72
|
const { verifier: withdrawVerifier } = m.useModule(
|
|
44
73
|
WithdrawNullifierVerifierModule,
|
|
@@ -51,9 +80,12 @@ export default buildModule("Zeto_AnonEncNullifier", (m) => {
|
|
|
51
80
|
depositVerifier,
|
|
52
81
|
withdrawVerifier,
|
|
53
82
|
verifier,
|
|
83
|
+
lockVerifier,
|
|
54
84
|
batchVerifier,
|
|
85
|
+
batchLockVerifier,
|
|
55
86
|
batchWithdrawVerifier,
|
|
56
87
|
smtLib,
|
|
88
|
+
poseidon2,
|
|
57
89
|
poseidon3,
|
|
58
90
|
};
|
|
59
91
|
});
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
|
|
18
18
|
import {
|
|
19
19
|
SmtLibModule,
|
|
20
|
-
|
|
20
|
+
DepositKycVerifierModule,
|
|
21
21
|
WithdrawNullifierVerifierModule,
|
|
22
22
|
BatchWithdrawNullifierVerifierModule,
|
|
23
23
|
} from "./lib/deps";
|
|
@@ -42,7 +42,7 @@ export default buildModule("Zeto_AnonEncNullifierKyc", (m) => {
|
|
|
42
42
|
const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
|
|
43
43
|
const { verifier } = m.useModule(VerifierModule);
|
|
44
44
|
const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
|
|
45
|
-
const { verifier: depositVerifier } = m.useModule(
|
|
45
|
+
const { verifier: depositVerifier } = m.useModule(DepositKycVerifierModule);
|
|
46
46
|
const { verifier: withdrawVerifier } = m.useModule(
|
|
47
47
|
WithdrawNullifierVerifierModule,
|
|
48
48
|
);
|
|
@@ -45,7 +45,7 @@ const BatchVerifierModule = buildModule(
|
|
|
45
45
|
);
|
|
46
46
|
|
|
47
47
|
export default buildModule("Zeto_AnonEncNullifierNonRepudiation", (m) => {
|
|
48
|
-
const { smtLib, poseidon3 } = m.useModule(SmtLibModule);
|
|
48
|
+
const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
|
|
49
49
|
const { verifier } = m.useModule(VerifierModule);
|
|
50
50
|
const { verifier: batchVerifier } = m.useModule(BatchVerifierModule);
|
|
51
51
|
const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
|
|
@@ -62,6 +62,7 @@ export default buildModule("Zeto_AnonEncNullifierNonRepudiation", (m) => {
|
|
|
62
62
|
batchVerifier,
|
|
63
63
|
batchWithdrawVerifier,
|
|
64
64
|
smtLib,
|
|
65
|
+
poseidon2,
|
|
65
66
|
poseidon3,
|
|
66
67
|
};
|
|
67
68
|
});
|