@crisp-e3/contracts 0.5.9 → 0.5.11

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.
@@ -16,6 +16,14 @@ import { HonkVerifier } from "./CRISPVerifier.sol";
16
16
  contract CRISPProgram is IE3Program, Ownable {
17
17
  using InternalLazyIMT for LazyIMTData;
18
18
 
19
+ /// @notice Enum to represent credit modes
20
+ enum CreditMode {
21
+ /// @notice Everyone has constant credits
22
+ CONSTANT,
23
+ /// @notice Credits are custom (can be based on token balance, etc)
24
+ CUSTOM
25
+ }
26
+
19
27
  /// @notice Struct to store all data related to a voting round
20
28
  struct RoundData {
21
29
  uint256 merkleRoot;
@@ -23,6 +31,7 @@ contract CRISPProgram is IE3Program, Ownable {
23
31
  mapping(address slot => uint40 index) voteSlots;
24
32
  LazyIMTData votes;
25
33
  uint256 numOptions;
34
+ CreditMode creditMode;
26
35
  }
27
36
 
28
37
  // Constants
@@ -40,13 +49,11 @@ contract CRISPProgram is IE3Program, Ownable {
40
49
  HonkVerifier private immutable honkVerifier;
41
50
 
42
51
  // Mappings
43
- mapping(address => bool) public authorizedContracts;
44
52
  mapping(uint256 e3Id => RoundData) e3Data;
45
53
 
46
54
  // Errors
47
55
  error CallerNotAuthorized();
48
56
  error E3AlreadyInitialized();
49
- error E3DoesNotExist();
50
57
  error EnclaveAddressZero();
51
58
  error Risc0VerifierAddressZero();
52
59
  error InvalidHonkVerifier();
@@ -58,6 +65,9 @@ contract CRISPProgram is IE3Program, Ownable {
58
65
  error SlotIsEmpty();
59
66
  error MerkleRootNotSet();
60
67
  error InvalidNumOptions();
68
+ error InputDeadlinePassed(uint256 e3Id, uint256 deadline);
69
+ error KeyNotPublished(uint256 e3Id);
70
+ error E3NotAcceptingInputs(uint256 e3Id);
61
71
 
62
72
  // Events
63
73
  event InputPublished(uint256 indexed e3Id, bytes encryptedVote, uint256 index);
@@ -75,7 +85,6 @@ contract CRISPProgram is IE3Program, Ownable {
75
85
  enclave = _enclave;
76
86
  risc0Verifier = _risc0Verifier;
77
87
  honkVerifier = _honkVerifier;
78
- authorizedContracts[address(_enclave)] = true;
79
88
  imageId = _imageId;
80
89
  }
81
90
 
@@ -117,14 +126,17 @@ contract CRISPProgram is IE3Program, Ownable {
117
126
  bytes calldata,
118
127
  bytes calldata customParams
119
128
  ) external returns (bytes32) {
120
- if (!authorizedContracts[msg.sender] && msg.sender != owner()) revert CallerNotAuthorized();
129
+ if (msg.sender != address(enclave) && msg.sender != owner()) revert CallerNotAuthorized();
121
130
  if (e3Data[e3Id].paramsHash != bytes32(0)) revert E3AlreadyInitialized();
122
131
 
123
132
  // decode custom params to get the number of options
124
- (, , uint256 numOptions) = abi.decode(customParams, (address, uint256, uint256));
133
+ (, , uint256 numOptions, CreditMode creditMode, ) = abi.decode(customParams, (address, uint256, uint256, CreditMode, uint256));
125
134
  if (numOptions < 2) revert InvalidNumOptions();
126
135
 
136
+ // we need to know the number of options for decoding the tally
127
137
  e3Data[e3Id].numOptions = numOptions;
138
+ // we want to save the credit mode so it can be verified on chain by everyone
139
+ e3Data[e3Id].creditMode = creditMode;
128
140
 
129
141
  e3Data[e3Id].paramsHash = keccak256(e3ProgramParams);
130
142
 
@@ -135,9 +147,24 @@ contract CRISPProgram is IE3Program, Ownable {
135
147
  }
136
148
 
137
149
  /// @inheritdoc IE3Program
138
- function validateInput(uint256 e3Id, address, bytes memory data) external {
139
- // it should only be called via Enclave for now
140
- if (!authorizedContracts[msg.sender] && msg.sender != owner()) revert CallerNotAuthorized();
150
+ function publishInput(uint256 e3Id, bytes memory data) external {
151
+ E3 memory e3 = enclave.getE3(e3Id);
152
+
153
+ // check that we are in the correct stage
154
+ IEnclave.E3Stage stage = enclave.getE3Stage(e3Id);
155
+ if (stage != IEnclave.E3Stage.KeyPublished) {
156
+ revert KeyNotPublished(e3Id);
157
+ }
158
+
159
+ // check that we are not past the input deadline
160
+ if (block.timestamp > e3.inputWindow[1]) {
161
+ revert InputDeadlinePassed(e3Id, e3.inputWindow[1]);
162
+ }
163
+
164
+ // check that we are within the input window
165
+ if (block.timestamp < e3.inputWindow[0]) {
166
+ revert E3NotAcceptingInputs(e3Id);
167
+ }
141
168
 
142
169
  // We need to ensure that the CRISP admin set the merkle root of the census.
143
170
  if (e3Data[e3Id].merkleRoot == 0) revert MerkleRootNotSet();
@@ -151,9 +178,6 @@ contract CRISPProgram is IE3Program, Ownable {
151
178
 
152
179
  (uint40 voteIndex, bytes32 previousEncryptedVoteCommitment) = _processVote(e3Id, slotAddress, encryptedVoteCommitment);
153
180
 
154
- // Fetch E3 to get committee public key
155
- E3 memory e3 = enclave.getE3(e3Id);
156
-
157
181
  // Set the public inputs for the proof. Order must match Noir circuit.
158
182
  bytes32[] memory noirPublicInputs = new bytes32[](7);
159
183
  noirPublicInputs[0] = previousEncryptedVoteCommitment;
@@ -232,12 +256,13 @@ contract CRISPProgram is IE3Program, Ownable {
232
256
 
233
257
  /// @inheritdoc IE3Program
234
258
  function verify(uint256 e3Id, bytes32 ciphertextOutputHash, bytes memory proof) external view override returns (bool) {
235
- if (e3Data[e3Id].paramsHash == bytes32(0)) revert E3DoesNotExist();
259
+ bytes32 paramsHash = getParamsHash(e3Id);
260
+
236
261
  bytes32 inputRoot = bytes32(e3Data[e3Id].votes._root(TREE_DEPTH));
237
262
  bytes memory journal = new bytes(396); // (32 + 1) * 4 * 3
238
263
 
239
264
  _encodeLengthPrefixAndHash(journal, 0, ciphertextOutputHash);
240
- _encodeLengthPrefixAndHash(journal, 132, e3Data[e3Id].paramsHash);
265
+ _encodeLengthPrefixAndHash(journal, 132, paramsHash);
241
266
  _encodeLengthPrefixAndHash(journal, 264, inputRoot);
242
267
 
243
268
  risc0Verifier.verify(proof, imageId, sha256(journal));