create-fhevm-example 1.4.3 → 1.4.5

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 (32) hide show
  1. package/contracts/advanced/BlindAuction.sol +22 -57
  2. package/contracts/advanced/EncryptedEscrow.sol +7 -31
  3. package/contracts/advanced/HiddenVoting.sol +19 -54
  4. package/contracts/advanced/PrivateKYC.sol +9 -33
  5. package/contracts/advanced/PrivatePayroll.sol +9 -35
  6. package/contracts/basic/decryption/PublicDecryptMultipleValues.sol +19 -21
  7. package/contracts/basic/decryption/PublicDecryptSingleValue.sol +19 -20
  8. package/contracts/basic/decryption/UserDecryptMultipleValues.sol +11 -21
  9. package/contracts/basic/decryption/UserDecryptSingleValue.sol +15 -30
  10. package/contracts/basic/encryption/EncryptMultipleValues.sol +16 -22
  11. package/contracts/basic/encryption/EncryptSingleValue.sol +15 -17
  12. package/contracts/basic/encryption/FHECounter.sol +19 -17
  13. package/contracts/basic/fhe-operations/FHEAdd.sol +14 -16
  14. package/contracts/basic/fhe-operations/FHEArithmetic.sol +19 -31
  15. package/contracts/basic/fhe-operations/FHEComparison.sol +12 -29
  16. package/contracts/basic/fhe-operations/FHEIfThenElse.sol +9 -10
  17. package/contracts/concepts/FHEAccessControl.sol +28 -28
  18. package/contracts/concepts/FHEAntiPatterns.sol +8 -37
  19. package/contracts/concepts/FHEHandles.sol +14 -29
  20. package/contracts/concepts/FHEInputProof.sol +13 -33
  21. package/contracts/gaming/EncryptedLottery.sol +11 -38
  22. package/contracts/gaming/EncryptedPoker.sol +8 -34
  23. package/contracts/gaming/RockPaperScissors.sol +43 -64
  24. package/contracts/openzeppelin/ERC7984.sol +6 -1
  25. package/contracts/openzeppelin/ERC7984ERC20Wrapper.sol +5 -1
  26. package/contracts/openzeppelin/SwapERC7984ToERC20.sol +5 -1
  27. package/contracts/openzeppelin/SwapERC7984ToERC7984.sol +5 -1
  28. package/contracts/openzeppelin/VestingWallet.sol +13 -17
  29. package/dist/scripts/commands/generate-config.js +18 -3
  30. package/dist/scripts/shared/config.d.ts.map +1 -1
  31. package/dist/scripts/shared/config.js +81 -75
  32. package/package.json +1 -1
@@ -10,33 +10,23 @@ import {
10
10
  import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
11
11
 
12
12
  /**
13
- * @notice Blind Auction with encrypted bids - only the winning price is revealed
14
- *
15
- * @dev Demonstrates advanced FHE patterns:
16
- * - Encrypted bid storage and comparison
17
- * - FHE.gt() and FHE.select() for finding maximum
18
- * - FHE.makePubliclyDecryptable() for revealing results
19
- * - FHE.checkSignatures() for proof verification
20
- *
21
- * Flow:
22
- * 1. Owner creates auction with end time and minimum bid
23
- * 2. Bidders submit encrypted bids (one per address)
24
- * 3. Owner ends auction → winner computed via FHE.gt/select
25
- * 4. Anyone can reveal winner after decryption proof is ready
26
- *
27
- * ⚠️ IMPORTANT: Losing bids remain encrypted forever!
13
+ * @notice Blind auction where bids remain encrypted until the end.
14
+ * Bidders submit encrypted amounts. The contract finds the highest bid
15
+ * using FHE.gt and FHE.select without ever decrypting losing bids.
16
+ * Only the winning bid amount is revealed after the auction closes.
17
+ * Losing bids remain private forever, ensuring true bid confidentiality.
18
+
19
+ * @dev Flow: bid() endAuction() → revealWinner()
20
+ * Uses FHE.gt/select to find winner without revealing losing bids.
21
+ * Losing bids remain encrypted forever!
28
22
  */
29
23
  contract BlindAuction is ZamaEthereumConfig {
30
- // ==================== TYPES ====================
31
-
32
24
  enum AuctionState {
33
25
  Open, // Accepting bids
34
26
  Closed, // Bidding ended, pending reveal
35
27
  Revealed // Winner revealed on-chain
36
28
  }
37
29
 
38
- // ==================== STATE ====================
39
-
40
30
  /// Auction owner (deployer)
41
31
  address public owner;
42
32
 
@@ -70,8 +60,6 @@ contract BlindAuction is ZamaEthereumConfig {
70
60
  /// Revealed winning amount (set after reveal)
71
61
  uint64 public winningAmount;
72
62
 
73
- // ==================== EVENTS ====================
74
-
75
63
  /// @notice Emitted when a new bid is placed
76
64
  /// @param bidder Address of the bidder
77
65
  event BidPlaced(address indexed bidder);
@@ -89,16 +77,12 @@ contract BlindAuction is ZamaEthereumConfig {
89
77
  /// @param amount Winning bid amount
90
78
  event WinnerRevealed(address indexed winner, uint64 amount);
91
79
 
92
- // ==================== MODIFIERS ====================
93
-
94
80
  /// @dev Restricts function to owner only
95
81
  modifier onlyOwner() {
96
82
  require(msg.sender == owner, "Only owner can call");
97
83
  _;
98
84
  }
99
85
 
100
- // ==================== CONSTRUCTOR ====================
101
-
102
86
  /// @notice Creates a new blind auction
103
87
  /// @param _endTime Unix timestamp when bidding ends
104
88
  /// @param _minimumBid Minimum bid amount (plaintext)
@@ -110,11 +94,8 @@ contract BlindAuction is ZamaEthereumConfig {
110
94
  auctionState = AuctionState.Open;
111
95
  }
112
96
 
113
- // ==================== BIDDING ====================
114
-
115
97
  /// @notice Submit an encrypted bid to the auction
116
98
  /// @dev Each address can only bid once
117
- /// @param encryptedBid The encrypted bid amount
118
99
  /// @param inputProof Proof validating the encrypted input
119
100
  function bid(
120
101
  externalEuint64 encryptedBid,
@@ -124,13 +105,11 @@ contract BlindAuction is ZamaEthereumConfig {
124
105
  require(block.timestamp < endTime, "Auction has ended");
125
106
  require(!hasBid[msg.sender], "Already placed a bid");
126
107
 
127
- // 🔐 Convert external encrypted input to internal euint64
108
+ // Convert external encrypted input to internal handle (proof verified)
128
109
  euint64 bidAmount = FHE.fromExternal(encryptedBid, inputProof);
129
-
130
- // ✅ Grant contract permission to operate on this value
131
110
  FHE.allowThis(bidAmount);
132
111
 
133
- // 📋 Store the bid
112
+ // Store bid - amount stays encrypted
134
113
  _bids[msg.sender] = bidAmount;
135
114
  hasBid[msg.sender] = true;
136
115
  bidders.push(msg.sender);
@@ -138,30 +117,24 @@ contract BlindAuction is ZamaEthereumConfig {
138
117
  emit BidPlaced(msg.sender);
139
118
  }
140
119
 
141
- // ==================== END AUCTION ====================
142
-
143
120
  /// @notice End the auction and compute the winner
121
+ /// @dev ⚡ Gas: O(n) loop with FHE.gt/select. ~200k gas per bidder!
144
122
  /// @dev Only owner can call after end time
145
123
  function endAuction() external onlyOwner {
146
124
  require(auctionState == AuctionState.Open, "Auction not open");
147
125
  require(block.timestamp >= endTime, "Auction not yet ended");
148
126
  require(bidders.length > 0, "No bids placed");
149
127
 
150
- // 🏆 Find the winning bid using encrypted comparisons
151
-
152
- // Initialize with first bidder
128
+ // Find winner using encrypted comparisons (no bids revealed!)
153
129
  euint64 currentMax = _bids[bidders[0]];
154
130
  euint64 currentWinnerIdx = FHE.asEuint64(0);
155
131
 
156
- // 🔄 Iterate through remaining bidders
157
132
  for (uint256 i = 1; i < bidders.length; i++) {
158
133
  euint64 candidateBid = _bids[bidders[i]];
159
134
 
160
- // 🔍 Compare: is candidate > currentMax?
161
- // Note: If equal, first bidder wins (no update)
135
+ // 🔀 Why select? if/else would leak which bid is higher!
136
+ // Losing bids remain encrypted forever
162
137
  ebool isGreater = FHE.gt(candidateBid, currentMax);
163
-
164
- // 🔀 Select the higher bid and its index
165
138
  currentMax = FHE.select(isGreater, candidateBid, currentMax);
166
139
  currentWinnerIdx = FHE.select(
167
140
  isGreater,
@@ -170,14 +143,12 @@ contract BlindAuction is ZamaEthereumConfig {
170
143
  );
171
144
  }
172
145
 
173
- // 📊 Check minimum bid threshold
146
+ // Check minimum bid (comparison stays encrypted)
174
147
  ebool meetsMinimum = FHE.ge(currentMax, FHE.asEuint64(minimumBid));
175
-
176
- // If no one meets minimum, winner stays at index 0 but amount becomes 0
177
148
  _winningBid = FHE.select(meetsMinimum, currentMax, FHE.asEuint64(0));
178
149
  _winnerIndex = currentWinnerIdx;
179
150
 
180
- // 🔓 Make results publicly decryptable
151
+ // Mark for public decryption via KMS relayer
181
152
  FHE.allowThis(_winningBid);
182
153
  FHE.allowThis(_winnerIndex);
183
154
  FHE.makePubliclyDecryptable(_winningBid);
@@ -189,36 +160,32 @@ contract BlindAuction is ZamaEthereumConfig {
189
160
  }
190
161
 
191
162
  /// @notice Reveal the winner with KMS decryption proof
192
- /// @dev Anyone can call with valid decryption proof
193
- /// @param abiEncodedResults ABI-encoded (uint64 amount, uint64 index)
194
- /// @param decryptionProof KMS signature proving decryption
163
+ /// @dev Anyone can call once relayer provides proof.
164
+ /// ⚠️ Order matters! cts[] must match abi.decode() order.
195
165
  function revealWinner(
196
166
  bytes memory abiEncodedResults,
197
167
  bytes memory decryptionProof
198
168
  ) external {
199
169
  require(auctionState == AuctionState.Closed, "Auction not closed");
200
170
 
201
- // 🔐 Build ciphertext list for verification
202
- // Order MUST match abiEncodedResults encoding order!
171
+ // Build handle array - order must match abi.decode() below!
203
172
  bytes32[] memory cts = new bytes32[](2);
204
173
  cts[0] = FHE.toBytes32(_winningBid);
205
174
  cts[1] = FHE.toBytes32(_winnerIndex);
206
175
 
207
- // 🔍 Verify the decryption proof (reverts if invalid)
176
+ // Verify KMS signatures (reverts if proof invalid)
208
177
  FHE.checkSignatures(cts, abiEncodedResults, decryptionProof);
209
178
 
210
- // 📤 Decode the verified results
179
+ // Decode verified plaintext results
211
180
  (uint64 revealedAmount, uint64 winnerIdx) = abi.decode(
212
181
  abiEncodedResults,
213
182
  (uint64, uint64)
214
183
  );
215
184
 
216
- // 🏆 Look up winner address
217
185
  if (revealedAmount >= minimumBid && winnerIdx < bidders.length) {
218
186
  winner = bidders[winnerIdx];
219
187
  winningAmount = revealedAmount;
220
188
  } else {
221
- // No valid winner (all bids below minimum)
222
189
  winner = address(0);
223
190
  winningAmount = 0;
224
191
  }
@@ -228,8 +195,6 @@ contract BlindAuction is ZamaEthereumConfig {
228
195
  emit WinnerRevealed(winner, winningAmount);
229
196
  }
230
197
 
231
- // ==================== VIEW FUNCTIONS ====================
232
-
233
198
  /// @notice Get the number of bidders
234
199
  function getBidderCount() external view returns (uint256) {
235
200
  return bidders.length;
@@ -10,26 +10,16 @@ import {
10
10
  import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
11
11
 
12
12
  /**
13
- * @notice Encrypted Escrow service - amounts hidden until release!
13
+ * @notice Confidential escrow service with hidden transaction amounts.
14
+ * Buyer and seller agree on encrypted escrow amount. Funds are held
15
+ * securely until conditions are met. Amount remains hidden from public
16
+ * view until release or refund. Includes arbiter for dispute resolution.
17
+ * Perfect for high-value transactions requiring privacy.
14
18
  *
15
- * @dev Demonstrates secure escrow with FHE:
16
- * - Escrow amounts remain encrypted
17
- * - Conditions verified without revealing values
18
- * - Multi-party agreement pattern
19
- * - Dispute resolution with arbiter
20
- *
21
- * Flow:
22
- * 1. Buyer creates escrow with encrypted amount
23
- * 2. Buyer deposits funds
24
- * 3. Seller delivers goods/services
25
- * 4. Buyer releases funds OR disputes
26
- * 5. Arbiter resolves disputes if needed
27
- *
28
- * ⚠️ IMPORTANT: Amount revealed only on release/refund
19
+ * @dev Flow: createEscrow() fundEscrow() → release()/requestRefund()/raiseDispute()
20
+ * Multi-party agreement with arbiter for disputes.
29
21
  */
30
22
  contract EncryptedEscrow is ZamaEthereumConfig {
31
- // ==================== TYPES ====================
32
-
33
23
  enum EscrowState {
34
24
  Created, // Escrow created, awaiting deposit
35
25
  Funded, // Funds deposited
@@ -49,8 +39,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
49
39
  uint256 deadline;
50
40
  }
51
41
 
52
- // ==================== STATE ====================
53
-
54
42
  /// Contract owner
55
43
  address public owner;
56
44
 
@@ -63,8 +51,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
63
51
  /// Arbiter fee percentage (default 1%)
64
52
  uint256 public arbiterFeePercent;
65
53
 
66
- // ==================== EVENTS ====================
67
-
68
54
  /// @notice Emitted when escrow is created
69
55
  /// @param escrowId ID of the escrow
70
56
  /// @param buyer Address of buyer
@@ -100,8 +86,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
100
86
  /// @param winner Address favored in resolution
101
87
  event DisputeResolved(uint256 indexed escrowId, address indexed winner);
102
88
 
103
- // ==================== CONSTRUCTOR ====================
104
-
105
89
  /// @notice Creates the escrow contract
106
90
  /// @param _arbiterFeePercent Fee percentage for arbiter (0-10)
107
91
  constructor(uint256 _arbiterFeePercent) {
@@ -110,8 +94,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
110
94
  arbiterFeePercent = _arbiterFeePercent;
111
95
  }
112
96
 
113
- // ==================== ESCROW CREATION ====================
114
-
115
97
  /// @notice Create a new escrow with encrypted amount
116
98
  /// @param seller Address of the seller
117
99
  /// @param arbiter Address of dispute arbiter
@@ -172,8 +154,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
172
154
  emit EscrowFunded(escrowId, msg.value);
173
155
  }
174
156
 
175
- // ==================== RELEASE / REFUND ====================
176
-
177
157
  /// @notice Release funds to seller
178
158
  /// @dev Only buyer can release after delivery
179
159
  /// @param escrowId ID of escrow to release
@@ -211,8 +191,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
211
191
  emit FundsRefunded(escrowId, escrow.buyer);
212
192
  }
213
193
 
214
- // ==================== DISPUTE RESOLUTION ====================
215
-
216
194
  /// @notice Raise a dispute
217
195
  /// @param escrowId ID of escrow
218
196
  function raiseDispute(uint256 escrowId) external {
@@ -264,8 +242,6 @@ contract EncryptedEscrow is ZamaEthereumConfig {
264
242
  emit DisputeResolved(escrowId, winner);
265
243
  }
266
244
 
267
- // ==================== VIEW FUNCTIONS ====================
268
-
269
245
  /// @notice Get escrow details
270
246
  function getEscrow(
271
247
  uint256 escrowId
@@ -5,33 +5,22 @@ import {FHE, euint64, ebool, externalEuint8} from "@fhevm/solidity/lib/FHE.sol";
5
5
  import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
6
6
 
7
7
  /**
8
- * @notice Hidden Voting with encrypted ballots and homomorphic tallying
8
+ * @notice Private voting system with homomorphic vote tallying.
9
+ * Voters submit encrypted ballots (Yes/No). Votes are tallied using
10
+ * homomorphic addition WITHOUT decrypting individual ballots. Only the
11
+ * final tally is revealed - individual votes remain private forever.
12
+ * Perfect for DAO governance, elections, or any scenario requiring ballot secrecy.
9
13
  *
10
- * @dev Demonstrates FHE voting patterns:
11
- * - Encrypted vote submission (0 = No, 1 = Yes)
12
- * - Homomorphic addition for vote tallying
13
- * - FHE.makePubliclyDecryptable() for revealing final results
14
- * - Privacy: individual votes remain encrypted forever
15
- *
16
- * Flow:
17
- * 1. Owner creates a proposal with voting duration
18
- * 2. Eligible voters submit encrypted votes (0 or 1)
19
- * 3. Votes are homomorphically added to running totals
20
- * 4. After voting ends, owner closes and results become decryptable
21
- * 5. Anyone can reveal final Yes/No counts with valid proof
14
+ * @dev Flow: vote() closeVoting() → revealResults()
15
+ * Gas: Each vote costs ~200k gas (FHE.add + FHE.select operations)
22
16
  */
23
17
  contract HiddenVoting is ZamaEthereumConfig {
24
- // ==================== TYPES ====================
25
-
26
18
  enum VotingState {
27
19
  Active, // Accepting votes
28
20
  Closed, // Voting ended, pending reveal
29
21
  Revealed // Results revealed on-chain
30
22
  }
31
23
 
32
- // ==================== STATE ====================
33
-
34
- /// Voting owner (deployer)
35
24
  address public owner;
36
25
 
37
26
  /// Current voting state
@@ -59,9 +48,7 @@ contract HiddenVoting is ZamaEthereumConfig {
59
48
  uint64 public revealedYesVotes;
60
49
  uint64 public revealedNoVotes;
61
50
 
62
- // ==================== EVENTS ====================
63
-
64
- /// @notice Emitted when a vote is cast
51
+ /// Emitted when a vote is cast
65
52
  /// @param voter Address of the voter
66
53
  event VoteCast(address indexed voter);
67
54
 
@@ -75,19 +62,11 @@ contract HiddenVoting is ZamaEthereumConfig {
75
62
  /// @param noVotes Final No vote count
76
63
  event ResultsRevealed(uint64 yesVotes, uint64 noVotes);
77
64
 
78
- // ==================== MODIFIERS ====================
79
-
80
- /// @dev Restricts function to owner only
81
65
  modifier onlyOwner() {
82
66
  require(msg.sender == owner, "Only owner can call");
83
67
  _;
84
68
  }
85
69
 
86
- // ==================== CONSTRUCTOR ====================
87
-
88
- /// @notice Creates a new voting proposal
89
- /// @param _proposal Description of what is being voted on
90
- /// @param _durationSeconds How long voting is open
91
70
  constructor(string memory _proposal, uint256 _durationSeconds) {
92
71
  require(bytes(_proposal).length > 0, "Empty proposal");
93
72
  require(_durationSeconds > 0, "Duration must be positive");
@@ -97,18 +76,15 @@ contract HiddenVoting is ZamaEthereumConfig {
97
76
  endTime = block.timestamp + _durationSeconds;
98
77
  votingState = VotingState.Active;
99
78
 
100
- // 🔐 Initialize encrypted counters to zero
79
+ // Initialize encrypted counters
101
80
  _yesVotes = FHE.asEuint64(0);
102
81
  _noVotes = FHE.asEuint64(0);
103
82
  FHE.allowThis(_yesVotes);
104
83
  FHE.allowThis(_noVotes);
105
84
  }
106
85
 
107
- // ==================== VOTING ====================
108
-
109
- /// @notice Cast an encrypted vote
110
- /// @dev Vote must be 0 (No) or 1 (Yes). Values > 1 are treated as Yes.
111
- /// @param encryptedVote Encrypted vote (0 or 1)
86
+ /// @notice Cast an encrypted vote (0=No, 1=Yes)
87
+ /// @dev Homomorphic tallying: votes added without decryption!
112
88
  /// @param inputProof Proof validating the encrypted input
113
89
  function vote(
114
90
  externalEuint8 encryptedVote,
@@ -118,14 +94,13 @@ contract HiddenVoting is ZamaEthereumConfig {
118
94
  require(block.timestamp < endTime, "Voting has ended");
119
95
  require(!hasVoted[msg.sender], "Already voted");
120
96
 
121
- // 🔐 Convert external encrypted input
122
- // Note: Using euint8 for vote, but storing as euint64 for addition
97
+ // Convert vote and normalize to 0 or 1
123
98
  euint64 voteValue = FHE.asEuint64(
124
99
  FHE.fromExternal(encryptedVote, inputProof)
125
100
  );
126
101
 
127
- // 📊 Homomorphic vote counting
128
- // We use select to normalize: if vote > 0, count as 1 for Yes
102
+ // 🧮 Why homomorphic? Votes are tallied WITHOUT decrypting individual ballots!
103
+ // Individual votes remain private forever
129
104
  ebool isYes = FHE.gt(voteValue, FHE.asEuint64(0));
130
105
 
131
106
  // ➕ Add to Yes counter if vote is Yes (1)
@@ -136,7 +111,6 @@ contract HiddenVoting is ZamaEthereumConfig {
136
111
  );
137
112
  _yesVotes = FHE.add(_yesVotes, yesIncrement);
138
113
 
139
- // ➕ Add to No counter if vote is No (0)
140
114
  euint64 noIncrement = FHE.select(
141
115
  isYes,
142
116
  FHE.asEuint64(0),
@@ -144,26 +118,21 @@ contract HiddenVoting is ZamaEthereumConfig {
144
118
  );
145
119
  _noVotes = FHE.add(_noVotes, noIncrement);
146
120
 
147
- // ✅ Update permissions for new values
148
- FHE.allowThis(_yesVotes);
149
121
  FHE.allowThis(_noVotes);
150
122
 
151
- // 📋 Record that this address has voted
152
123
  hasVoted[msg.sender] = true;
153
124
  voterCount++;
154
125
 
155
126
  emit VoteCast(msg.sender);
156
127
  }
157
128
 
158
- // ==================== CLOSE VOTING ====================
159
-
160
- /// @notice Close voting and prepare results for decryption
129
+ /// @notice Close voting and mark results for decryption
161
130
  /// @dev Only owner can call after voting period ends
162
131
  function closeVoting() external onlyOwner {
163
132
  require(votingState == VotingState.Active, "Voting not active");
164
133
  require(block.timestamp >= endTime, "Voting not yet ended");
165
134
 
166
- // 🔓 Make results publicly decryptable
135
+ // Mark totals for public decryption via relayer
167
136
  FHE.makePubliclyDecryptable(_yesVotes);
168
137
  FHE.makePubliclyDecryptable(_noVotes);
169
138
 
@@ -182,15 +151,15 @@ contract HiddenVoting is ZamaEthereumConfig {
182
151
  ) external {
183
152
  require(votingState == VotingState.Closed, "Voting not closed");
184
153
 
185
- // 🔐 Build ciphertext list for verification
154
+ // Build handle array for signature verification
186
155
  bytes32[] memory cts = new bytes32[](2);
187
156
  cts[0] = FHE.toBytes32(_yesVotes);
188
157
  cts[1] = FHE.toBytes32(_noVotes);
189
158
 
190
- // 🔍 Verify the decryption proof (reverts if invalid)
159
+ // Verify KMS proof (reverts if invalid)
191
160
  FHE.checkSignatures(cts, abiEncodedResults, decryptionProof);
192
161
 
193
- // 📤 Decode the verified results
162
+ // Decode verified plaintext results
194
163
  (uint64 yesCount, uint64 noCount) = abi.decode(
195
164
  abiEncodedResults,
196
165
  (uint64, uint64)
@@ -203,15 +172,11 @@ contract HiddenVoting is ZamaEthereumConfig {
203
172
  emit ResultsRevealed(yesCount, noCount);
204
173
  }
205
174
 
206
- // ==================== VIEW FUNCTIONS ====================
207
-
208
- /// @notice Get encrypted Yes votes handle (after voting closed)
209
175
  function getEncryptedYesVotes() external view returns (euint64) {
210
176
  require(votingState != VotingState.Active, "Voting still active");
211
177
  return _yesVotes;
212
178
  }
213
179
 
214
- /// @notice Get encrypted No votes handle (after voting closed)
215
180
  function getEncryptedNoVotes() external view returns (euint64) {
216
181
  require(votingState != VotingState.Active, "Voting still active");
217
182
  return _noVotes;
@@ -12,24 +12,18 @@ import {
12
12
  import {ZamaEthereumConfig} from "@fhevm/solidity/config/ZamaConfig.sol";
13
13
 
14
14
  /**
15
- * @notice Private KYC - verify identity without revealing personal data!
15
+ * @notice Privacy-preserving identity verification using predicate proofs.
16
+ * Users submit encrypted personal data (age, country, credit score).
17
+ * Contract can verify predicates like "Is user 18+?" or "Good credit?"
18
+ * without learning the actual values. Returns encrypted booleans that
19
+ * prove compliance without revealing sensitive information. Revolutionary
20
+ * for KYC/AML compliance while preserving user privacy.
16
21
  *
17
- * @dev Demonstrates identity verification using FHE predicates:
18
- * - Users submit encrypted KYC attributes (age, country, credit score)
19
- * - Verifiers check conditions without seeing actual values
20
- * - Only boolean results revealed: "Is 18+?", "Is from allowed country?"
21
- * - Personal data never leaves encrypted form
22
- *
23
- * Verification types:
24
- * 1. Age verification: isAbove18(), isAbove21()
25
- * 2. Country check: isFromAllowedCountry()
26
- * 3. Credit score: hasCreditScoreAbove(threshold)
27
- *
28
- * ⚠️ IMPORTANT: This is a demo - production KYC needs trusted attesters!
22
+ * @dev Flow: submitKYC() verifyAge18()/verifyGoodCredit()/etc.
23
+ * Returns encrypted booleans: "Is 18+?", "Good credit?" without revealing actual values.
24
+ * ⚠️ Production KYC needs trusted attesters!
29
25
  */
30
26
  contract PrivateKYC is ZamaEthereumConfig {
31
- // ==================== TYPES ====================
32
-
33
27
  struct Identity {
34
28
  euint8 age; // 0-255 years
35
29
  euint8 countryCode; // ISO 3166-1 numeric (1-255)
@@ -38,8 +32,6 @@ contract PrivateKYC is ZamaEthereumConfig {
38
32
  uint256 verifiedAt; // Timestamp of verification
39
33
  }
40
34
 
41
- // ==================== STATE ====================
42
-
43
35
  /// Contract owner (KYC admin)
44
36
  address public owner;
45
37
 
@@ -56,8 +48,6 @@ contract PrivateKYC is ZamaEthereumConfig {
56
48
  /// Minimum credit score for "good" rating
57
49
  uint16 public constant MIN_CREDIT_GOOD = 700;
58
50
 
59
- // ==================== EVENTS ====================
60
-
61
51
  /// @notice Emitted when user submits KYC
62
52
  /// @param user Address of user
63
53
  event KYCSubmitted(address indexed user);
@@ -76,8 +66,6 @@ contract PrivateKYC is ZamaEthereumConfig {
76
66
  /// @param minAge Minimum age required
77
67
  event AgeVerificationRequested(address indexed user, uint8 minAge);
78
68
 
79
- // ==================== MODIFIERS ====================
80
-
81
69
  modifier onlyOwner() {
82
70
  require(msg.sender == owner, "Only owner");
83
71
  _;
@@ -88,8 +76,6 @@ contract PrivateKYC is ZamaEthereumConfig {
88
76
  _;
89
77
  }
90
78
 
91
- // ==================== CONSTRUCTOR ====================
92
-
93
79
  /// @notice Creates the KYC contract
94
80
  /// @param _allowedCountryCodes Initial list of allowed country codes
95
81
  constructor(uint8[] memory _allowedCountryCodes) {
@@ -101,8 +87,6 @@ contract PrivateKYC is ZamaEthereumConfig {
101
87
  }
102
88
  }
103
89
 
104
- // ==================== KYC SUBMISSION ====================
105
-
106
90
  /// @notice Submit encrypted KYC data
107
91
  /// @param encAge Encrypted age
108
92
  /// @param encCountry Encrypted country code
@@ -147,8 +131,6 @@ contract PrivateKYC is ZamaEthereumConfig {
147
131
  emit KYCRevoked(msg.sender);
148
132
  }
149
133
 
150
- // ==================== VERIFICATION FUNCTIONS ====================
151
-
152
134
  /// @notice Check if user is 18 or older
153
135
  /// @param user Address to verify
154
136
  /// @return result Encrypted boolean result
@@ -232,8 +214,6 @@ contract PrivateKYC is ZamaEthereumConfig {
232
214
  return result;
233
215
  }
234
216
 
235
- // ==================== DECRYPTABLE VERIFICATION ====================
236
-
237
217
  /// @notice Request age verification with public result
238
218
  /// @dev Makes the result publicly decryptable
239
219
  /// @param user Address to verify
@@ -252,8 +232,6 @@ contract PrivateKYC is ZamaEthereumConfig {
252
232
  return result;
253
233
  }
254
234
 
255
- // ==================== ADMIN FUNCTIONS ====================
256
-
257
235
  /// @notice Update country allowlist
258
236
  /// @param countryCode Country code to update
259
237
  /// @param allowed Whether to allow or deny
@@ -278,8 +256,6 @@ contract PrivateKYC is ZamaEthereumConfig {
278
256
  }
279
257
  }
280
258
 
281
- // ==================== VIEW FUNCTIONS ====================
282
-
283
259
  /// @notice Check if user has submitted KYC
284
260
  function hasSubmittedKYC(address user) external view returns (bool) {
285
261
  return _identities[user].isVerified;