@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.
Files changed (155) hide show
  1. package/README.md +70 -162
  2. package/contracts/factory.sol +30 -34
  3. package/contracts/factory_upgradeable.sol +160 -0
  4. package/contracts/lib/common/util.sol +40 -0
  5. package/contracts/lib/interfaces/ILockableCapability.sol +318 -0
  6. package/contracts/lib/interfaces/{izeto.sol → IZeto.sol} +13 -1
  7. package/contracts/lib/interfaces/{izeto_initializable.sol → IZetoInitializable.sol} +14 -12
  8. package/contracts/lib/interfaces/{izeto_kyc.sol → IZetoKyc.sol} +3 -3
  9. package/contracts/lib/interfaces/IZetoLockableCapability.sol +237 -0
  10. package/contracts/lib/interfaces/IZetoStorage.sol +106 -0
  11. package/contracts/lib/interfaces/{izeto_lockable.sol → IZetoVerifier.sol} +8 -21
  12. package/contracts/lib/registry.sol +77 -27
  13. package/contracts/lib/storage/base.sol +210 -0
  14. package/contracts/lib/storage/nullifier.sol +166 -0
  15. package/contracts/lib/zeto_common.sol +277 -28
  16. package/contracts/lib/zeto_fungible.sol +451 -33
  17. package/contracts/lib/zeto_fungible_base.sol +69 -0
  18. package/contracts/lib/zeto_fungible_burn.sol +83 -53
  19. package/contracts/lib/zeto_fungible_burn_nullifier.sol +115 -72
  20. package/contracts/lib/zeto_fungible_nullifier.sol +167 -0
  21. package/contracts/lib/zeto_lockable.sol +613 -0
  22. package/contracts/lib/zeto_non_fungible.sol +236 -0
  23. package/contracts/lib/zeto_non_fungible_base.sol +61 -0
  24. package/contracts/lib/zeto_non_fungible_nullifier.sol +61 -0
  25. package/contracts/test/escrow1.sol +90 -34
  26. package/contracts/test/escrow2.sol +64 -29
  27. package/contracts/test/qurrency.sol +10 -2
  28. package/contracts/test/smt.sol +8 -3
  29. package/contracts/test/tendecimals.sol +14 -12
  30. package/contracts/verifiers/impl/anon.sol +189 -0
  31. package/contracts/verifiers/impl/anon_batch.sol +301 -0
  32. package/contracts/verifiers/impl/anon_enc.sol +266 -0
  33. package/contracts/verifiers/impl/anon_enc_batch.sol +602 -0
  34. package/contracts/verifiers/impl/anon_enc_nullifier.sol +287 -0
  35. package/contracts/verifiers/impl/anon_enc_nullifier_batch.sol +679 -0
  36. package/contracts/verifiers/impl/anon_enc_nullifier_kyc.sol +294 -0
  37. package/contracts/verifiers/impl/anon_enc_nullifier_kyc_batch.sol +686 -0
  38. package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation.sol +413 -0
  39. package/contracts/verifiers/impl/anon_enc_nullifier_non_repudiation_batch.sol +1141 -0
  40. package/contracts/verifiers/impl/anon_nullifier_kyc_transfer.sol +217 -0
  41. package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked.sol +196 -0
  42. package/contracts/verifiers/impl/anon_nullifier_kyc_transferLocked_batch.sol +308 -0
  43. package/contracts/verifiers/impl/anon_nullifier_kyc_transfer_batch.sol +385 -0
  44. package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer.sol +497 -0
  45. package/contracts/verifiers/impl/anon_nullifier_qurrency_transfer_batch.sol +1001 -0
  46. package/contracts/verifiers/{verifier_anon_nullifier_transferLocked.sol → impl/anon_nullifier_transfer.sol} +12 -19
  47. package/contracts/verifiers/{verifier_anon_nullifier_transferLocked_batch.sol → impl/anon_nullifier_transfer_batch.sol} +44 -51
  48. package/contracts/verifiers/impl/burn.sol +182 -0
  49. package/contracts/verifiers/impl/burn_batch.sol +238 -0
  50. package/contracts/verifiers/impl/burn_nullifier.sol +203 -0
  51. package/contracts/verifiers/impl/burn_nullifier_batch.sol +315 -0
  52. package/contracts/verifiers/impl/deposit.sol +182 -0
  53. package/contracts/verifiers/impl/deposit_kyc.sol +189 -0
  54. package/contracts/verifiers/impl/nf_anon.sol +175 -0
  55. package/contracts/verifiers/{verifier_nf_anon_nullifier_transferLocked.sol → impl/nf_anon_nullifier_transfer.sol} +6 -13
  56. package/contracts/verifiers/impl/withdraw.sol +189 -0
  57. package/contracts/verifiers/impl/withdraw_batch.sol +245 -0
  58. package/contracts/verifiers/impl/withdraw_nullifier.sol +210 -0
  59. package/contracts/verifiers/impl/withdraw_nullifier_batch.sol +322 -0
  60. package/contracts/verifiers/verifier_anon.sol +31 -186
  61. package/contracts/verifiers/verifier_anon_batch.sol +31 -298
  62. package/contracts/verifiers/verifier_anon_enc.sol +31 -263
  63. package/contracts/verifiers/verifier_anon_enc_batch.sol +31 -599
  64. package/contracts/verifiers/verifier_anon_enc_nullifier.sol +31 -284
  65. package/contracts/verifiers/verifier_anon_enc_nullifier_batch.sol +33 -676
  66. package/contracts/verifiers/verifier_anon_enc_nullifier_kyc.sol +31 -291
  67. package/contracts/verifiers/verifier_anon_enc_nullifier_kyc_batch.sol +33 -683
  68. package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation.sol +33 -410
  69. package/contracts/verifiers/verifier_anon_enc_nullifier_non_repudiation_batch.sol +33 -1138
  70. package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer.sol +33 -214
  71. package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked.sol +33 -221
  72. package/contracts/verifiers/verifier_anon_nullifier_kyc_transferLocked_batch.sol +33 -389
  73. package/contracts/verifiers/verifier_anon_nullifier_kyc_transfer_batch.sol +33 -382
  74. package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer.sol +33 -221
  75. package/contracts/verifiers/verifier_anon_nullifier_qurrency_transfer_batch.sol +33 -389
  76. package/contracts/verifiers/verifier_anon_nullifier_transfer.sol +33 -207
  77. package/contracts/verifiers/verifier_anon_nullifier_transfer_batch.sol +33 -375
  78. package/contracts/verifiers/verifier_burn.sol +31 -179
  79. package/contracts/verifiers/verifier_burn_batch.sol +31 -235
  80. package/contracts/verifiers/verifier_burn_nullifier.sol +31 -200
  81. package/contracts/verifiers/verifier_burn_nullifier_batch.sol +31 -312
  82. package/contracts/verifiers/verifier_deposit.sol +31 -179
  83. package/contracts/verifiers/verifier_deposit_kyc.sol +34 -0
  84. package/contracts/verifiers/verifier_nf_anon.sol +31 -172
  85. package/contracts/verifiers/verifier_nf_anon_nullifier_transfer.sol +33 -179
  86. package/contracts/verifiers/verifier_withdraw.sol +31 -186
  87. package/contracts/verifiers/verifier_withdraw_batch.sol +31 -242
  88. package/contracts/verifiers/verifier_withdraw_nullifier.sol +31 -207
  89. package/contracts/verifiers/verifier_withdraw_nullifier_batch.sol +33 -319
  90. package/contracts/zeto_anon.sol +77 -231
  91. package/contracts/zeto_anon_burnable.sol +56 -12
  92. package/contracts/zeto_anon_enc.sol +93 -190
  93. package/contracts/zeto_anon_enc_nullifier.sol +249 -195
  94. package/contracts/zeto_anon_enc_nullifier_kyc.sol +51 -232
  95. package/contracts/zeto_anon_enc_nullifier_non_repudiation.sol +231 -238
  96. package/contracts/zeto_anon_nullifier.sol +164 -298
  97. package/contracts/zeto_anon_nullifier_burnable.sol +68 -18
  98. package/contracts/zeto_anon_nullifier_kyc.sol +40 -345
  99. package/contracts/zeto_anon_nullifier_qurrency.sol +218 -360
  100. package/contracts/zeto_nf_anon.sol +55 -130
  101. package/contracts/zeto_nf_anon_nullifier.sol +90 -152
  102. package/hardhat.config.ts +9 -3
  103. package/ignition/modules/lib/deps.ts +9 -6
  104. package/ignition/modules/zeto_anon_burnable.ts +8 -7
  105. package/ignition/modules/zeto_anon_enc_nullifier.ts +33 -1
  106. package/ignition/modules/zeto_anon_enc_nullifier_kyc.ts +2 -2
  107. package/ignition/modules/zeto_anon_enc_nullifier_non_repudiation.ts +2 -1
  108. package/ignition/modules/zeto_anon_nullifier.ts +30 -5
  109. package/ignition/modules/zeto_anon_nullifier_burnable.ts +52 -17
  110. package/ignition/modules/zeto_anon_nullifier_kyc.ts +27 -12
  111. package/ignition/modules/zeto_anon_nullifier_qurrency.ts +2 -1
  112. package/ignition/modules/zeto_nf_anon_nullifier.ts +16 -12
  113. package/package.json +4 -2
  114. package/scripts/deploy_cloneable.ts +19 -10
  115. package/scripts/deploy_upgradeable.ts +9 -5
  116. package/scripts/tokens/Zeto_Anon.ts +3 -3
  117. package/scripts/tokens/Zeto_AnonBurnable.ts +1 -1
  118. package/scripts/tokens/Zeto_AnonEnc.ts +12 -3
  119. package/scripts/tokens/Zeto_AnonEncNullifier.ts +7 -3
  120. package/scripts/tokens/Zeto_AnonEncNullifierKyc.ts +1 -1
  121. package/scripts/tokens/Zeto_AnonEncNullifierNonRepudiation.ts +3 -1
  122. package/scripts/tokens/Zeto_AnonNullifier.ts +3 -1
  123. package/scripts/tokens/Zeto_AnonNullifierBurnable.ts +3 -1
  124. package/scripts/tokens/Zeto_AnonNullifierKyc.ts +1 -1
  125. package/scripts/tokens/Zeto_AnonNullifierQurrency.ts +3 -1
  126. package/scripts/tokens/Zeto_NfAnon.ts +2 -2
  127. package/scripts/tokens/Zeto_NfAnonNullifier.ts +3 -2
  128. package/test/factory.ts +46 -73
  129. package/test/factory_upgradeable.ts +311 -0
  130. package/test/lib/anon_nullifier_helpers.ts +89 -0
  131. package/test/lib/anon_zeto_helpers.ts +76 -0
  132. package/test/lib/deploy.ts +3 -2
  133. package/test/lib/utils.ts +74 -35
  134. package/test/test/escrow1.ts +185 -58
  135. package/test/test/escrow2.ts +200 -107
  136. package/test/test/qurrency.ts +13 -33
  137. package/test/usdc-shielding.ts +39 -26
  138. package/test/utils.ts +144 -21
  139. package/test/zeto_anon.ts +956 -465
  140. package/test/zeto_anon_enc.ts +881 -142
  141. package/test/zeto_anon_enc_nullifier.ts +847 -38
  142. package/test/zeto_anon_enc_nullifier_kyc.ts +120 -181
  143. package/test/zeto_anon_enc_nullifier_non_repudiation.ts +77 -46
  144. package/test/zeto_anon_nullifier.ts +1212 -953
  145. package/test/zeto_anon_nullifier_kyc.ts +674 -655
  146. package/test/zeto_anon_nullifier_qurrency.ts +452 -306
  147. package/test/zeto_nf_anon.ts +737 -137
  148. package/test/zeto_nf_anon_nullifier.ts +876 -246
  149. package/contracts/lib/zeto_base.sol +0 -293
  150. package/contracts/lib/zeto_fungible_withdraw.sol +0 -132
  151. package/contracts/lib/zeto_fungible_withdraw_nullifier.sol +0 -144
  152. package/contracts/lib/zeto_nullifier.sol +0 -334
  153. package/contracts/zkDvP.sol_ +0 -273
  154. package/test/zkDvP.ts_ +0 -455
  155. /package/contracts/lib/{common.sol → common/common.sol} +0 -0
@@ -15,51 +15,39 @@
15
15
  // limitations under the License.
16
16
  pragma solidity ^0.8.27;
17
17
 
18
- import {IZeto} from "./lib/interfaces/izeto.sol";
19
- import {MAX_BATCH} from "./lib/interfaces/izeto.sol";
20
- import {Groth16Verifier_Deposit} from "./verifiers/verifier_deposit.sol";
21
- import {Groth16Verifier_WithdrawNullifier} from "./verifiers/verifier_withdraw_nullifier.sol";
22
- import {Groth16Verifier_WithdrawNullifierBatch} from "./verifiers/verifier_withdraw_nullifier_batch.sol";
23
- import {Groth16Verifier_AnonNullifierTransfer} from "./verifiers/verifier_anon_nullifier_transfer.sol";
24
- import {Groth16Verifier_AnonNullifierTransferLocked} from "./verifiers/verifier_anon_nullifier_transferLocked.sol";
25
- import {Groth16Verifier_AnonNullifierTransferBatch} from "./verifiers/verifier_anon_nullifier_transfer_batch.sol";
26
- import {Groth16Verifier_AnonNullifierTransferLockedBatch} from "./verifiers/verifier_anon_nullifier_transferLocked_batch.sol";
27
- import {ZetoNullifier} from "./lib/zeto_nullifier.sol";
28
- import {ZetoFungibleWithdrawWithNullifiers} from "./lib/zeto_fungible_withdraw_nullifier.sol";
29
- import {Commonlib} from "./lib/common.sol";
30
- import {IZetoInitializable} from "./lib/interfaces/izeto_initializable.sol";
18
+ import {IZeto, MAX_BATCH} from "./lib/interfaces/IZeto.sol";
19
+ import {ZetoFungibleNullifier} from "./lib/zeto_fungible_nullifier.sol";
20
+ import {Commonlib} from "./lib/common/common.sol";
21
+ import {IZetoInitializable} from "./lib/interfaces/IZetoInitializable.sol";
31
22
  import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
32
- import {console} from "hardhat/console.sol";
33
-
34
- uint256 constant INPUT_SIZE = 7;
35
- uint256 constant INPUT_SIZE_LOCKED = 8;
36
- uint256 constant BATCH_INPUT_SIZE = 31;
37
- uint256 constant BATCH_INPUT_SIZE_LOCKED = 32;
38
23
 
39
24
  /// @title A sample implementation of a Zeto based fungible token with anonymity and history masking
40
25
  /// @author Kaleido, Inc.
26
+ /// @notice Decimals: this token uses **4** decimals, inherited from
27
+ /// {ZetoCommon.decimals}. Indexers and UIs reading this contract
28
+ /// directly should treat balances accordingly.
41
29
  /// @dev The proof has the following statements:
42
30
  /// - each value in the output commitments must be a positive number in the range 0 ~ (2\*\*40 - 1)
43
31
  /// - the sum of the nullified values match the sum of output values
44
32
  /// - the hashes in the input and output match the hash(value, salt, owner public key) formula
45
33
  /// - the sender possesses the private BabyJubjub key, whose public key is part of the pre-image of the input commitment hashes, which match the corresponding nullifiers
46
34
  /// - the nullifiers represent input commitments that are included in a Sparse Merkle Tree represented by the root hash
47
- contract Zeto_AnonNullifier is
48
- IZeto,
49
- IZetoInitializable,
50
- ZetoNullifier,
51
- ZetoFungibleWithdrawWithNullifiers,
52
- UUPSUpgradeable
53
- {
54
- Groth16Verifier_AnonNullifierTransfer internal _verifier;
55
- Groth16Verifier_AnonNullifierTransferBatch internal _batchVerifier;
56
- Groth16Verifier_AnonNullifierTransferLocked internal _lockVerifier;
57
- Groth16Verifier_AnonNullifierTransferLockedBatch
58
- internal _batchLockVerifier;
35
+ contract Zeto_AnonNullifier is ZetoFungibleNullifier, UUPSUpgradeable {
36
+ /// @dev Lock the implementation contract on construction so that
37
+ /// {initialize} can only ever run on a proxy. Without this,
38
+ /// anyone could call {initialize} directly on the deployed
39
+ /// implementation, become its owner, and then `upgradeTo(any)`
40
+ /// via {_authorizeUpgrade} (the OZ "implementation takeover"
41
+ /// pattern, CVE-2022-35961 family). See OpenZeppelin's
42
+ /// `Initializable._disableInitializers` for the rationale.
43
+ /// @custom:oz-upgrades-unsafe-allow constructor
44
+ constructor() {
45
+ _disableInitializers();
46
+ }
59
47
 
60
48
  function initialize(
61
- string memory name,
62
- string memory symbol,
49
+ string calldata name,
50
+ string calldata symbol,
63
51
  address initialOwner,
64
52
  IZetoInitializable.VerifiersInfo calldata verifiers
65
53
  ) public virtual initializer {
@@ -67,29 +55,12 @@ contract Zeto_AnonNullifier is
67
55
  }
68
56
 
69
57
  function __ZetoAnonNullifier_init(
70
- string memory name_,
71
- string memory symbol_,
58
+ string calldata name_,
59
+ string calldata symbol_,
72
60
  address initialOwner,
73
61
  IZetoInitializable.VerifiersInfo calldata verifiers
74
62
  ) internal onlyInitializing {
75
- __ZetoNullifier_init(name_, symbol_, initialOwner);
76
- __ZetoFungibleWithdrawWithNullifiers_init(
77
- (Groth16Verifier_Deposit)(verifiers.depositVerifier),
78
- (Groth16Verifier_WithdrawNullifier)(verifiers.withdrawVerifier),
79
- (Groth16Verifier_WithdrawNullifierBatch)(
80
- verifiers.batchWithdrawVerifier
81
- )
82
- );
83
- _verifier = (Groth16Verifier_AnonNullifierTransfer)(verifiers.verifier);
84
- _lockVerifier = (Groth16Verifier_AnonNullifierTransferLocked)(
85
- verifiers.lockVerifier
86
- );
87
- _batchVerifier = (Groth16Verifier_AnonNullifierTransferBatch)(
88
- verifiers.batchVerifier
89
- );
90
- _batchLockVerifier = (Groth16Verifier_AnonNullifierTransferLockedBatch)(
91
- verifiers.batchLockVerifier
92
- );
63
+ __ZetoFungibleNullifier_init(name_, symbol_, initialOwner, verifiers);
93
64
  }
94
65
 
95
66
  function _authorizeUpgrade(address) internal override onlyOwner {}
@@ -97,284 +68,179 @@ contract Zeto_AnonNullifier is
97
68
  function constructPublicInputs(
98
69
  uint256[] memory nullifiers,
99
70
  uint256[] memory outputs,
100
- uint256 root,
101
- uint256 size,
102
- bool locked
103
- ) internal view returns (uint256[] memory publicInputs) {
104
- publicInputs = new uint256[](size);
105
- uint256 piIndex = 0;
106
- // copy input commitments
107
- for (uint256 i = 0; i < nullifiers.length; i++) {
108
- publicInputs[piIndex++] = nullifiers[i];
109
- }
110
- // when verifying locked transfers, additional public input
111
- // for the lock delegate
112
- if (locked) {
113
- publicInputs[piIndex++] = uint256(uint160(msg.sender));
71
+ bytes memory proof,
72
+ bool inputsLocked
73
+ )
74
+ internal
75
+ virtual
76
+ override
77
+ returns (uint256[] memory, Commonlib.Proof memory)
78
+ {
79
+ // Decode the proof to extract root and proof structure. Done once
80
+ // here so that {validateTransactionProposal} below can skip the
81
+ // root-only pre-decode it used to perform; root validation happens
82
+ // here instead.
83
+ uint256 root;
84
+ Commonlib.Proof memory proofStruct;
85
+ if (!inputsLocked) {
86
+ (root, proofStruct) = abi.decode(proof, (uint256, Commonlib.Proof));
87
+ validateRoot(root);
88
+ } else {
89
+ proofStruct = abi.decode(proof, (Commonlib.Proof));
114
90
  }
115
- // copy root
116
- publicInputs[piIndex++] = root;
117
91
 
118
- // populate enables
119
- for (uint256 i = 0; i < nullifiers.length; i++) {
120
- publicInputs[piIndex++] = (nullifiers[i] == 0) ? 0 : 1;
121
- }
92
+ // Get extra inputs from derived contracts
93
+ uint256[] memory extra = extraInputs();
122
94
 
123
- // copy output commitments
124
- for (uint256 i = 0; i < outputs.length; i++) {
125
- publicInputs[piIndex++] = outputs[i];
126
- }
95
+ // Calculate the total size needed for public inputs
96
+ uint256 size = _calculatePublicInputsSize(
97
+ nullifiers,
98
+ outputs,
99
+ extra,
100
+ inputsLocked
101
+ );
127
102
 
128
- return publicInputs;
103
+ // Create and populate the public inputs array
104
+ uint256[] memory publicInputs = new uint256[](size);
105
+ _fillPublicInputs(
106
+ publicInputs,
107
+ nullifiers,
108
+ outputs,
109
+ extra,
110
+ root,
111
+ inputsLocked
112
+ );
113
+
114
+ return (publicInputs, proofStruct);
129
115
  }
130
116
 
131
- /**
132
- * @dev the main function of the contract.
133
- *
134
- * @param nullifiers Array of nullifiers that are secretly bound to UTXOs to be spent by the transaction.
135
- * @param outputs Array of new UTXOs to generate, for future transactions to spend.
136
- * @param root The root hash of the Sparse Merkle Tree that contains the nullifiers.
137
- * @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
138
- * that the outputs are valid in terms of obeying mass conservation rules.
139
- *
140
- * Emits a {UTXOTransfer} event.
141
- */
142
- function transfer(
143
- uint256[] memory nullifiers,
117
+ function _calculatePublicInputsSize(
118
+ uint256[] memory inputs,
144
119
  uint256[] memory outputs,
145
- uint256 root,
146
- Commonlib.Proof calldata proof,
147
- bytes calldata data
148
- ) public returns (bool) {
149
- nullifiers = checkAndPadCommitments(nullifiers);
150
- outputs = checkAndPadCommitments(outputs);
151
- validateTransactionProposal(nullifiers, outputs, root, false);
152
- verifyProof(nullifiers, outputs, root, proof);
153
- uint256[] memory empty;
154
- processInputsAndOutputs(nullifiers, outputs, empty, address(0));
155
-
156
- uint256[] memory nullifierArray = new uint256[](nullifiers.length);
157
- uint256[] memory outputArray = new uint256[](outputs.length);
158
- for (uint256 i = 0; i < nullifiers.length; ++i) {
159
- nullifierArray[i] = nullifiers[i];
160
- outputArray[i] = outputs[i];
120
+ uint256[] memory extra,
121
+ bool inputsLocked
122
+ ) internal pure returns (uint256 size) {
123
+ if (inputsLocked) {
124
+ // locked inputs are UTXOs not nullifiers
125
+ size =
126
+ inputs.length +
127
+ extra.length + // extra inputs
128
+ outputs.length; // output commitments
129
+ } else {
130
+ size =
131
+ (inputs.length * 2) + // nullifiers and enabled flags
132
+ 1 + // root
133
+ extra.length + // extra inputs
134
+ outputs.length; // output commitments
161
135
  }
162
- emit UTXOTransfer(nullifierArray, outputArray, msg.sender, data);
163
- return true;
164
136
  }
165
137
 
166
- function transferLocked(
167
- uint256[] memory nullifiers,
138
+ function _fillPublicInputs(
139
+ uint256[] memory publicInputs,
140
+ uint256[] memory inputs,
168
141
  uint256[] memory outputs,
142
+ uint256[] memory extra,
169
143
  uint256 root,
170
- Commonlib.Proof calldata proof,
171
- bytes calldata data
172
- ) public returns (bool) {
173
- nullifiers = checkAndPadCommitments(nullifiers);
174
- outputs = checkAndPadCommitments(outputs);
175
- validateTransactionProposal(nullifiers, outputs, root, true);
176
- verifyProofLocked(nullifiers, outputs, root, proof);
177
- uint256[] memory empty;
178
- processInputsAndOutputs(nullifiers, outputs, empty, address(0));
144
+ bool inputsLocked
145
+ ) internal view {
146
+ uint256 piIndex = 0;
147
+
148
+ if (!inputsLocked) {
149
+ // Copy nullifiers
150
+ piIndex = _fillInputs_Nullifier(publicInputs, inputs, piIndex);
179
151
 
180
- uint256[] memory nullifierArray = new uint256[](nullifiers.length);
181
- uint256[] memory outputArray = new uint256[](outputs.length);
182
- for (uint256 i = 0; i < nullifiers.length; ++i) {
183
- nullifierArray[i] = nullifiers[i];
184
- outputArray[i] = outputs[i];
152
+ // Copy root
153
+ publicInputs[piIndex++] = root;
154
+
155
+ // Populate enabled flags
156
+ piIndex = _fillEnabledFlags_Nullifier(
157
+ publicInputs,
158
+ inputs,
159
+ piIndex
160
+ );
161
+
162
+ // Copy extra inputs
163
+ piIndex = _fillExtraInputs_Nullifier(publicInputs, extra, piIndex);
164
+
165
+ // Copy output commitments
166
+ _fillOutputCommitments_Nullifier(publicInputs, outputs, piIndex);
167
+ } else {
168
+ // Copy inputs
169
+ piIndex = _fillInputs_Nullifier(publicInputs, inputs, piIndex);
170
+
171
+ // Copy extra inputs
172
+ piIndex = _fillExtraInputs_Nullifier(publicInputs, extra, piIndex);
173
+
174
+ // Copy output commitments
175
+ _fillOutputCommitments_Nullifier(publicInputs, outputs, piIndex);
185
176
  }
186
- emit UTXOTransfer(nullifierArray, outputArray, msg.sender, data);
187
- return true;
188
177
  }
189
178
 
190
- function deposit(
191
- uint256 amount,
192
- uint256[] memory outputs,
193
- Commonlib.Proof calldata proof,
194
- bytes calldata data
195
- ) public {
196
- _deposit(amount, outputs, proof);
197
- _mint(outputs, data);
179
+ function _fillInputs_Nullifier(
180
+ uint256[] memory publicInputs,
181
+ uint256[] memory inputs,
182
+ uint256 startIndex
183
+ ) internal pure returns (uint256 nextIndex) {
184
+ uint256 piIndex = startIndex;
185
+ for (uint256 i = 0; i < inputs.length; i++) {
186
+ publicInputs[piIndex++] = inputs[i];
187
+ }
188
+ return piIndex;
198
189
  }
199
190
 
200
- function withdraw(
201
- uint256 amount,
191
+ function _fillEnabledFlags_Nullifier(
192
+ uint256[] memory publicInputs,
202
193
  uint256[] memory nullifiers,
203
- uint256 output,
204
- uint256 root,
205
- Commonlib.Proof calldata proof,
206
- bytes calldata data
207
- ) public {
208
- uint256[] memory outputs = new uint256[](nullifiers.length);
209
- outputs[0] = output;
210
- // Check and pad inputs and outputs based on the max size
211
- nullifiers = checkAndPadCommitments(nullifiers);
212
- outputs = checkAndPadCommitments(outputs);
213
- validateTransactionProposal(nullifiers, outputs, root, false);
214
- _withdrawWithNullifiers(amount, nullifiers, output, root, proof);
215
- uint256[] memory empty;
216
- processInputsAndOutputs(nullifiers, outputs, empty, address(0));
217
- emit UTXOWithdraw(amount, nullifiers, output, msg.sender, data);
194
+ uint256 startIndex
195
+ ) internal pure returns (uint256 nextIndex) {
196
+ uint256 piIndex = startIndex;
197
+ for (uint256 i = 0; i < nullifiers.length; i++) {
198
+ publicInputs[piIndex++] = (nullifiers[i] == 0) ? 0 : 1;
199
+ }
200
+ return piIndex;
218
201
  }
219
202
 
220
- function mint(
221
- uint256[] memory utxos,
222
- bytes calldata data
223
- ) public onlyOwner {
224
- _mint(utxos, data);
203
+ function _fillExtraInputs_Nullifier(
204
+ uint256[] memory publicInputs,
205
+ uint256[] memory extra,
206
+ uint256 startIndex
207
+ ) internal pure returns (uint256 nextIndex) {
208
+ uint256 piIndex = startIndex;
209
+ for (uint256 i = 0; i < extra.length; i++) {
210
+ publicInputs[piIndex++] = extra[i];
211
+ }
212
+ return piIndex;
225
213
  }
226
214
 
227
- function lock(
228
- uint256[] memory nullifiers,
215
+ function _fillOutputCommitments_Nullifier(
216
+ uint256[] memory publicInputs,
229
217
  uint256[] memory outputs,
230
- uint256[] memory lockedOutputs,
231
- uint256 root,
232
- Commonlib.Proof calldata proof,
233
- address delegate,
234
- bytes calldata data
235
- ) public {
236
- // merge the outputs and lockedOutputs and do a regular transfer
237
- uint256[] memory allOutputs = new uint256[](
238
- outputs.length + lockedOutputs.length
239
- );
218
+ uint256 startIndex
219
+ ) internal pure {
220
+ uint256 piIndex = startIndex;
240
221
  for (uint256 i = 0; i < outputs.length; i++) {
241
- allOutputs[i] = outputs[i];
242
- }
243
- for (uint256 i = 0; i < lockedOutputs.length; i++) {
244
- allOutputs[outputs.length + i] = lockedOutputs[i];
222
+ publicInputs[piIndex++] = outputs[i];
245
223
  }
246
- nullifiers = checkAndPadCommitments(nullifiers);
247
- allOutputs = checkAndPadCommitments(allOutputs);
248
- validateTransactionProposal(nullifiers, allOutputs, root, false);
249
- verifyProof(nullifiers, allOutputs, root, proof);
250
-
251
- processNullifiers(nullifiers);
252
-
253
- // lock the intended outputs
254
- _lock(nullifiers, outputs, lockedOutputs, delegate, data);
255
224
  }
256
225
 
257
- function unlock(
258
- uint256[] memory nullifiers,
259
- uint256[] memory outputs,
260
- uint256 root,
261
- Commonlib.Proof calldata proof,
262
- bytes calldata data
263
- ) public {
264
- transferLocked(nullifiers, outputs, root, proof, data);
226
+ function extraInputs() internal view virtual returns (uint256[] memory) {
227
+ // no extra inputs for this contract
228
+ return new uint256[](0);
265
229
  }
230
+ }
266
231
 
267
- function verifyProof(
268
- uint256[] memory nullifiers,
269
- uint256[] memory outputs,
270
- uint256 root,
271
- Commonlib.Proof calldata proof
272
- ) public view returns (bool) {
273
- if (nullifiers.length > 2 || outputs.length > 2) {
274
- uint256[] memory publicInputs = constructPublicInputs(
275
- nullifiers,
276
- outputs,
277
- root,
278
- BATCH_INPUT_SIZE,
279
- false
280
- );
281
- // construct the public inputs for batchVerifier
282
- uint256[BATCH_INPUT_SIZE] memory fixedSizeInputs;
283
- for (uint256 i = 0; i < fixedSizeInputs.length; i++) {
284
- fixedSizeInputs[i] = publicInputs[i];
285
- }
286
-
287
- // Check the proof using batchVerifier
288
- require(
289
- _batchVerifier.verifyProof(
290
- proof.pA,
291
- proof.pB,
292
- proof.pC,
293
- fixedSizeInputs
294
- ),
295
- "Invalid proof (batch)"
296
- );
297
- } else {
298
- uint256[] memory publicInputs = constructPublicInputs(
299
- nullifiers,
300
- outputs,
301
- root,
302
- INPUT_SIZE,
303
- false
304
- );
305
- // construct the public inputs for verifier
306
- uint256[INPUT_SIZE] memory fixedSizeInputs;
307
- for (uint256 i = 0; i < fixedSizeInputs.length; i++) {
308
- fixedSizeInputs[i] = publicInputs[i];
309
- }
310
- // Check the proof
311
- require(
312
- _verifier.verifyProof(
313
- proof.pA,
314
- proof.pB,
315
- proof.pC,
316
- fixedSizeInputs
317
- ),
318
- "Invalid proof"
319
- );
320
- }
321
- return true;
232
+ /// @dev ERC-7201 (`erc7201:zeto.storage.Zeto_AnonNullifier`).
233
+ library Zeto_AnonNullifierStorage {
234
+ struct Layout {
235
+ uint256 __reserved;
322
236
  }
323
237
 
324
- function verifyProofLocked(
325
- uint256[] memory nullifiers,
326
- uint256[] memory outputs,
327
- uint256 root,
328
- Commonlib.Proof calldata proof
329
- ) public view returns (bool) {
330
- if (nullifiers.length > 2 || outputs.length > 2) {
331
- uint256[] memory publicInputs = constructPublicInputs(
332
- nullifiers,
333
- outputs,
334
- root,
335
- BATCH_INPUT_SIZE_LOCKED,
336
- true
337
- );
338
- // construct the public inputs for batchVerifier
339
- uint256[BATCH_INPUT_SIZE_LOCKED] memory fixedSizeInputs;
340
- for (uint256 i = 0; i < fixedSizeInputs.length; i++) {
341
- fixedSizeInputs[i] = publicInputs[i];
342
- }
238
+ bytes32 private constant STORAGE_LOCATION =
239
+ 0xe49aec919d5bc8263575d088c75c14f60ed5ec12d5e1b7a7a34166fca4de8b00;
343
240
 
344
- // Check the proof using batchVerifier
345
- require(
346
- _batchLockVerifier.verifyProof(
347
- proof.pA,
348
- proof.pB,
349
- proof.pC,
350
- fixedSizeInputs
351
- ),
352
- "Invalid proof (batch)"
353
- );
354
- } else {
355
- uint256[] memory publicInputs = constructPublicInputs(
356
- nullifiers,
357
- outputs,
358
- root,
359
- INPUT_SIZE_LOCKED,
360
- true
361
- );
362
- // construct the public inputs for verifier
363
- uint256[INPUT_SIZE_LOCKED] memory fixedSizeInputs;
364
- for (uint256 i = 0; i < fixedSizeInputs.length; i++) {
365
- fixedSizeInputs[i] = publicInputs[i];
366
- }
367
- // Check the proof
368
- require(
369
- _lockVerifier.verifyProof(
370
- proof.pA,
371
- proof.pB,
372
- proof.pC,
373
- fixedSizeInputs
374
- ),
375
- "Invalid proof"
376
- );
241
+ function layout() internal pure returns (Layout storage $) {
242
+ assembly {
243
+ $.slot := STORAGE_LOCATION
377
244
  }
378
- return true;
379
245
  }
380
246
  }
@@ -15,35 +15,85 @@
15
15
  // limitations under the License.
16
16
  pragma solidity ^0.8.27;
17
17
 
18
- import {Groth16Verifier_BurnNullifier} from "./verifiers/verifier_burn_nullifier.sol";
19
- import {Groth16Verifier_BurnNullifierBatch} from "./verifiers/verifier_burn_nullifier_batch.sol";
18
+ import {IZetoInitializable} from "./lib/interfaces/IZetoInitializable.sol";
20
19
  import {Zeto_AnonNullifier} from "./zeto_anon_nullifier.sol";
21
- import {ZetoFungibleBurnableWithNullifiers} from "./lib/zeto_fungible_burn_nullifier.sol";
20
+ import {ZetoFungibleBurnableNullifier} from "./lib/zeto_fungible_burn_nullifier.sol";
21
+ import {Commonlib} from "./lib/common/common.sol";
22
+ import {ZetoCommon} from "./lib/zeto_common.sol";
22
23
 
23
- uint256 constant INPUT_SIZE = 4;
24
- uint256 constant BATCH_INPUT_SIZE = 20;
25
-
26
- /// @title A sample implementation of a Zeto based fungible token with anonymity and no encryption
24
+ /// @title A sample implementation of a Zeto based fungible token with
25
+ /// anonymity, history masking via nullifiers, and {burn} support.
27
26
  /// @author Kaleido, Inc.
28
- /// @dev The proof has the following statements:
27
+ /// @notice Decimals: this token uses **4** decimals, inherited from
28
+ /// {ZetoCommon.decimals}. Indexers and UIs reading this contract
29
+ /// directly should treat balances accordingly.
30
+ /// @dev The transfer proof has the following statements:
29
31
  /// - each value in the output commitments must be a positive number in the range 0 ~ (2\*\*40 - 1)
30
- /// - the sum of the input values match the sum of output values
31
- /// - the hashes in the input and output match the `hash(value, salt, owner public key)` formula
32
- /// - the sender possesses the private BabyJubjub key, whose public key is part of the pre-image of the input commitment hashes
32
+ /// - the sum of the nullified values match the sum of output values
33
+ /// - the hashes in the input and output match the hash(value, salt, owner public key) formula
34
+ /// - the sender possesses the private BabyJubjub key, whose public key is part of the pre-image of the input commitment hashes, which match the corresponding nullifiers
35
+ /// - the nullifiers represent input commitments that are included in a Sparse Merkle Tree represented by the root hash
36
+ ///
37
+ /// The burn proof has the analogous statements with the output side
38
+ /// collapsed to a single remainder commitment.
39
+ ///
40
+ /// Composes {Zeto_AnonNullifier} (transfer + lock lifecycle) with
41
+ /// {ZetoFungibleBurnableNullifier} (burn entry point). Both base
42
+ /// paths converge on the abstract {ZetoCommon.constructPublicInputs}
43
+ /// hook, so this leaf contract must explicitly disambiguate the
44
+ /// override; it simply forwards to {Zeto_AnonNullifier}'s
45
+ /// implementation, which is the same proof layout used for both
46
+ /// unlocked transfers and the locked-input spend flow inherited from
47
+ /// {ZetoFungible}.
48
+ ///
49
+ /// Unlike the pre-{ILockableCapability} version, there is no longer a
50
+ /// separate `constructPublicInputsForLock` hook to override; the lock
51
+ /// lifecycle now reuses {constructPublicInputs} with `inputsLocked = true`.
33
52
  contract Zeto_AnonNullifierBurnable is
34
53
  Zeto_AnonNullifier,
35
- ZetoFungibleBurnableWithNullifiers
54
+ ZetoFungibleBurnableNullifier
36
55
  {
56
+ /// @dev Lock the implementation contract on construction. The parent
57
+ /// {Zeto_AnonNullifier} already does this via its own constructor
58
+ /// (which Solidity invokes as part of every leaf's deployment),
59
+ /// but we restate it here so the H-2 protection survives any
60
+ /// future refactor that changes the inheritance graph.
61
+ /// `_disableInitializers()` is idempotent, so the duplicate call
62
+ /// is a harmless no-op.
63
+ /// @custom:oz-upgrades-unsafe-allow constructor
64
+ constructor() {
65
+ _disableInitializers();
66
+ }
67
+
37
68
  function initialize(
38
- string memory name,
39
- string memory symbol,
69
+ string calldata name,
70
+ string calldata symbol,
40
71
  address initialOwner,
41
- VerifiersInfo calldata verifiers
72
+ IZetoInitializable.VerifiersInfo calldata verifiers
42
73
  ) public override initializer {
43
74
  __ZetoAnonNullifier_init(name, symbol, initialOwner, verifiers);
44
- __ZetoFungibleBurnableWithNullifiers_init(
45
- (Groth16Verifier_BurnNullifier)(verifiers.burnVerifier),
46
- (Groth16Verifier_BurnNullifierBatch)(verifiers.batchBurnVerifier)
75
+ __ZetoFungibleBurnableNullifier_init(
76
+ verifiers.burnVerifier,
77
+ verifiers.batchBurnVerifier
47
78
  );
48
79
  }
80
+
81
+ function constructPublicInputs(
82
+ uint256[] memory inputs,
83
+ uint256[] memory outputs,
84
+ bytes memory proof,
85
+ bool inputsLocked
86
+ )
87
+ internal
88
+ override(Zeto_AnonNullifier, ZetoCommon)
89
+ returns (uint256[] memory, Commonlib.Proof memory)
90
+ {
91
+ return
92
+ Zeto_AnonNullifier.constructPublicInputs(
93
+ inputs,
94
+ outputs,
95
+ proof,
96
+ inputsLocked
97
+ );
98
+ }
49
99
  }