@semaphore-protocol/contracts 2.6.1 → 3.0.0-beta.6

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.
@@ -2,34 +2,18 @@
2
2
  pragma solidity 0.8.4;
3
3
 
4
4
  import "../interfaces/ISemaphoreVoting.sol";
5
- import "../base/SemaphoreCore.sol";
5
+ import "../interfaces/ISemaphoreVerifier.sol";
6
6
  import "../base/SemaphoreGroups.sol";
7
7
 
8
8
  /// @title Semaphore voting contract.
9
+ /// @notice It allows users to vote anonymously in a poll.
9
10
  /// @dev The following code allows you to create polls, add voters and allow them to vote anonymously.
10
- contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
11
- /// @dev Gets a tree depth and returns its verifier address.
12
- mapping(uint256 => IVerifier) internal verifiers;
11
+ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreGroups {
12
+ ISemaphoreVerifier public verifier;
13
13
 
14
14
  /// @dev Gets a poll id and returns the poll data.
15
15
  mapping(uint256 => Poll) internal polls;
16
16
 
17
- /// @dev Gets a nullifier hash and returns true or false.
18
- /// It is used to prevent double-voting.
19
- mapping(uint256 => bool) internal nullifierHashes;
20
-
21
- /// @dev Initializes the Semaphore verifiers used to verify the user's ZK proofs.
22
- /// @param _verifiers: List of Semaphore verifiers (address and related Merkle tree depth).
23
- constructor(Verifier[] memory _verifiers) {
24
- for (uint8 i = 0; i < _verifiers.length; ) {
25
- verifiers[_verifiers[i].merkleTreeDepth] = IVerifier(_verifiers[i].contractAddress);
26
-
27
- unchecked {
28
- ++i;
29
- }
30
- }
31
- }
32
-
33
17
  /// @dev Checks if the poll coordinator is the transaction sender.
34
18
  /// @param pollId: Id of the poll.
35
19
  modifier onlyCoordinator(uint256 pollId) {
@@ -40,23 +24,25 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
40
24
  _;
41
25
  }
42
26
 
27
+ /// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
28
+ /// @param _verifier: Semaphore verifier address.
29
+ constructor(ISemaphoreVerifier _verifier) {
30
+ verifier = _verifier;
31
+ }
32
+
43
33
  /// @dev See {ISemaphoreVoting-createPoll}.
44
34
  function createPoll(
45
35
  uint256 pollId,
46
36
  address coordinator,
47
37
  uint256 merkleTreeDepth
48
38
  ) public override {
49
- if (address(verifiers[merkleTreeDepth]) == address(0)) {
39
+ if (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
50
40
  revert Semaphore__MerkleTreeDepthIsNotSupported();
51
41
  }
52
42
 
53
- _createGroup(pollId, merkleTreeDepth, 0);
43
+ _createGroup(pollId, merkleTreeDepth);
54
44
 
55
- Poll memory poll;
56
-
57
- poll.coordinator = coordinator;
58
-
59
- polls[pollId] = poll;
45
+ polls[pollId].coordinator = coordinator;
60
46
 
61
47
  emit PollCreated(pollId, coordinator);
62
48
  }
@@ -83,29 +69,25 @@ contract SemaphoreVoting is ISemaphoreVoting, SemaphoreCore, SemaphoreGroups {
83
69
 
84
70
  /// @dev See {ISemaphoreVoting-castVote}.
85
71
  function castVote(
86
- bytes32 vote,
72
+ uint256 vote,
87
73
  uint256 nullifierHash,
88
74
  uint256 pollId,
89
75
  uint256[8] calldata proof
90
- ) public override onlyCoordinator(pollId) {
91
- Poll memory poll = polls[pollId];
92
-
93
- if (poll.state != PollState.Ongoing) {
76
+ ) public override {
77
+ if (polls[pollId].state != PollState.Ongoing) {
94
78
  revert Semaphore__PollIsNotOngoing();
95
79
  }
96
80
 
97
- if (nullifierHashes[nullifierHash]) {
81
+ if (polls[pollId].nullifierHashes[nullifierHash]) {
98
82
  revert Semaphore__YouAreUsingTheSameNillifierTwice();
99
83
  }
100
84
 
101
85
  uint256 merkleTreeDepth = getMerkleTreeDepth(pollId);
102
86
  uint256 merkleTreeRoot = getMerkleTreeRoot(pollId);
103
87
 
104
- IVerifier verifier = verifiers[merkleTreeDepth];
105
-
106
- _verifyProof(vote, merkleTreeRoot, nullifierHash, pollId, proof, verifier);
88
+ verifier.verifyProof(merkleTreeRoot, nullifierHash, vote, pollId, proof, merkleTreeDepth);
107
89
 
108
- nullifierHashes[nullifierHash] = true;
90
+ polls[pollId].nullifierHashes[nullifierHash] = true;
109
91
 
110
92
  emit VoteAdded(pollId, vote);
111
93
  }
@@ -2,55 +2,49 @@
2
2
  pragma solidity 0.8.4;
3
3
 
4
4
  import "../interfaces/ISemaphoreWhistleblowing.sol";
5
- import "../base/SemaphoreCore.sol";
5
+ import "../interfaces/ISemaphoreVerifier.sol";
6
6
  import "../base/SemaphoreGroups.sol";
7
7
 
8
8
  /// @title Semaphore whistleblowing contract.
9
+ /// @notice It allows users to leak information anonymously .
9
10
  /// @dev The following code allows you to create entities for whistleblowers (e.g. non-profit
10
- /// organization, newspaper) and to allow them to publish news leaks anonymously.
11
- /// Leaks can be IPFS hashes, permanent links or other kinds of reference.
12
- contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreCore, SemaphoreGroups {
13
- /// @dev Gets a tree depth and returns its verifier address.
14
- mapping(uint256 => IVerifier) internal verifiers;
11
+ /// organization, newspaper) and allow them to leak anonymously.
12
+ /// Leaks can be IPFS hashes, permanent links or other kinds of references.
13
+ contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreGroups {
14
+ ISemaphoreVerifier public verifier;
15
15
 
16
- /// @dev Gets an editor address and return their entity.
17
- mapping(address => uint256) private entities;
18
-
19
- /// @dev Initializes the Semaphore verifiers used to verify the user's ZK proofs.
20
- /// @param _verifiers: List of Semaphore verifiers (address and related Merkle tree depth).
21
- constructor(Verifier[] memory _verifiers) {
22
- for (uint8 i = 0; i < _verifiers.length; ) {
23
- verifiers[_verifiers[i].merkleTreeDepth] = IVerifier(_verifiers[i].contractAddress);
24
-
25
- unchecked {
26
- ++i;
27
- }
28
- }
29
- }
16
+ /// @dev Gets an entity id and return its editor address.
17
+ mapping(uint256 => address) private entities;
30
18
 
31
19
  /// @dev Checks if the editor is the transaction sender.
32
20
  /// @param entityId: Id of the entity.
33
21
  modifier onlyEditor(uint256 entityId) {
34
- if (entityId != entities[_msgSender()]) {
22
+ if (entities[entityId] != _msgSender()) {
35
23
  revert Semaphore__CallerIsNotTheEditor();
36
24
  }
37
25
 
38
26
  _;
39
27
  }
40
28
 
29
+ /// @dev Initializes the Semaphore verifier used to verify the user's ZK proofs.
30
+ /// @param _verifier: Semaphore verifier address.
31
+ constructor(ISemaphoreVerifier _verifier) {
32
+ verifier = _verifier;
33
+ }
34
+
41
35
  /// @dev See {ISemaphoreWhistleblowing-createEntity}.
42
36
  function createEntity(
43
37
  uint256 entityId,
44
38
  address editor,
45
39
  uint256 merkleTreeDepth
46
40
  ) public override {
47
- if (address(verifiers[merkleTreeDepth]) == address(0)) {
41
+ if (merkleTreeDepth < 16 || merkleTreeDepth > 32) {
48
42
  revert Semaphore__MerkleTreeDepthIsNotSupported();
49
43
  }
50
44
 
51
- _createGroup(entityId, merkleTreeDepth, 0);
45
+ _createGroup(entityId, merkleTreeDepth);
52
46
 
53
- entities[editor] = entityId;
47
+ entities[entityId] = editor;
54
48
 
55
49
  emit EntityCreated(entityId, editor);
56
50
  }
@@ -72,17 +66,15 @@ contract SemaphoreWhistleblowing is ISemaphoreWhistleblowing, SemaphoreCore, Sem
72
66
 
73
67
  /// @dev See {ISemaphoreWhistleblowing-publishLeak}.
74
68
  function publishLeak(
75
- bytes32 leak,
69
+ uint256 leak,
76
70
  uint256 nullifierHash,
77
71
  uint256 entityId,
78
72
  uint256[8] calldata proof
79
- ) public override onlyEditor(entityId) {
73
+ ) public override {
80
74
  uint256 merkleTreeDepth = getMerkleTreeDepth(entityId);
81
75
  uint256 merkleTreeRoot = getMerkleTreeRoot(entityId);
82
76
 
83
- IVerifier verifier = verifiers[merkleTreeDepth];
84
-
85
- _verifyProof(leak, merkleTreeRoot, nullifierHash, entityId, proof, verifier);
77
+ verifier.verifyProof(merkleTreeRoot, nullifierHash, leak, entityId, proof, merkleTreeDepth);
86
78
 
87
79
  emit LeakPublished(entityId, leak);
88
80
  }
@@ -1,8 +1,7 @@
1
1
  //SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.4;
3
3
 
4
- /// @title Semaphore interface.
5
- /// @dev Interface of a Semaphore contract.
4
+ /// @title Semaphore contract interface.
6
5
  interface ISemaphore {
7
6
  error Semaphore__CallerIsNotTheGroupAdmin();
8
7
  error Semaphore__MerkleTreeDepthIsNotSupported();
@@ -10,15 +9,10 @@ interface ISemaphore {
10
9
  error Semaphore__MerkleTreeRootIsNotPartOfTheGroup();
11
10
  error Semaphore__YouAreUsingTheSameNillifierTwice();
12
11
 
13
- struct Verifier {
14
- address contractAddress;
15
- uint256 merkleTreeDepth;
16
- }
17
-
18
12
  /// It defines all the group parameters, in addition to those in the Merkle tree.
19
13
  struct Group {
20
14
  address admin;
21
- uint256 merkleRootDuration;
15
+ uint256 merkleTreeDuration;
22
16
  mapping(uint256 => uint256) merkleRootCreationDates;
23
17
  mapping(uint256 => bool) nullifierHashes;
24
18
  }
@@ -29,6 +23,16 @@ interface ISemaphore {
29
23
  /// @param newAdmin: New admin of the group.
30
24
  event GroupAdminUpdated(uint256 indexed groupId, address indexed oldAdmin, address indexed newAdmin);
31
25
 
26
+ /// @dev Emitted when the Merkle tree duration of a group is updated.
27
+ /// @param groupId: Id of the group.
28
+ /// @param oldMerkleTreeDuration: Old Merkle tree duration of the group.
29
+ /// @param newMerkleTreeDuration: New Merkle tree duration of the group.
30
+ event GroupMerkleTreeDurationUpdated(
31
+ uint256 indexed groupId,
32
+ uint256 oldMerkleTreeDuration,
33
+ uint256 newMerkleTreeDuration
34
+ );
35
+
32
36
  /// @dev Emitted when a Semaphore proof is verified.
33
37
  /// @param groupId: Id of the group.
34
38
  /// @param merkleTreeRoot: Root of the Merkle tree.
@@ -37,10 +41,10 @@ interface ISemaphore {
37
41
  /// @param signal: Semaphore signal.
38
42
  event ProofVerified(
39
43
  uint256 indexed groupId,
40
- uint256 merkleTreeRoot,
41
- uint256 externalNullifier,
44
+ uint256 indexed merkleTreeRoot,
45
+ uint256 indexed externalNullifier,
42
46
  uint256 nullifierHash,
43
- bytes32 signal
47
+ uint256 signal
44
48
  );
45
49
 
46
50
  /// @dev Saves the nullifier hash to avoid double signaling and emits an event
@@ -54,7 +58,7 @@ interface ISemaphore {
54
58
  function verifyProof(
55
59
  uint256 groupId,
56
60
  uint256 merkleTreeRoot,
57
- bytes32 signal,
61
+ uint256 signal,
58
62
  uint256 nullifierHash,
59
63
  uint256 externalNullifier,
60
64
  uint256[8] calldata proof
@@ -63,25 +67,21 @@ interface ISemaphore {
63
67
  /// @dev Creates a new group. Only the admin will be able to add or remove members.
64
68
  /// @param groupId: Id of the group.
65
69
  /// @param depth: Depth of the tree.
66
- /// @param zeroValue: Zero value of the tree.
67
70
  /// @param admin: Admin of the group.
68
71
  function createGroup(
69
72
  uint256 groupId,
70
73
  uint256 depth,
71
- uint256 zeroValue,
72
74
  address admin
73
75
  ) external;
74
76
 
75
77
  /// @dev Creates a new group. Only the admin will be able to add or remove members.
76
78
  /// @param groupId: Id of the group.
77
79
  /// @param depth: Depth of the tree.
78
- /// @param zeroValue: Zero value of the tree.
79
80
  /// @param admin: Admin of the group.
80
81
  /// @param merkleTreeRootDuration: Time before the validity of a root expires.
81
82
  function createGroup(
82
83
  uint256 groupId,
83
84
  uint256 depth,
84
- uint256 zeroValue,
85
85
  address admin,
86
86
  uint256 merkleTreeRootDuration
87
87
  ) external;
@@ -91,6 +91,11 @@ interface ISemaphore {
91
91
  /// @param newAdmin: New admin of the group.
92
92
  function updateGroupAdmin(uint256 groupId, address newAdmin) external;
93
93
 
94
+ /// @dev Updates the group Merkle tree duration.
95
+ /// @param groupId: Id of the group.
96
+ /// @param newMerkleTreeDuration: New Merkle tree duration.
97
+ function updateGroupMerkleTreeDuration(uint256 groupId, uint256 newMerkleTreeDuration) external;
98
+
94
99
  /// @dev Adds a new member to an existing group.
95
100
  /// @param groupId: Id of the group.
96
101
  /// @param identityCommitment: New identity commitment.
@@ -1,12 +1,10 @@
1
1
  //SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.4;
3
3
 
4
- /// @title SemaphoreGroups interface.
5
- /// @dev Interface of a SemaphoreGroups contract.
4
+ /// @title SemaphoreGroups contract interface.
6
5
  interface ISemaphoreGroups {
7
6
  error Semaphore__GroupDoesNotExist();
8
7
  error Semaphore__GroupAlreadyExists();
9
- error Semaphore__GroupIdIsNotLessThanSnarkScalarField();
10
8
 
11
9
  /// @dev Emitted when a new group is created.
12
10
  /// @param groupId: Id of the group.
@@ -0,0 +1,37 @@
1
+ //SPDX-License-Identifier: MIT
2
+ pragma solidity 0.8.4;
3
+
4
+ import "../base/Pairing.sol";
5
+
6
+ /// @title SemaphoreVerifier contract interface.
7
+ interface ISemaphoreVerifier {
8
+ struct VerificationKey {
9
+ Pairing.G1Point alfa1;
10
+ Pairing.G2Point beta2;
11
+ Pairing.G2Point gamma2;
12
+ Pairing.G2Point delta2;
13
+ Pairing.G1Point[] IC;
14
+ }
15
+
16
+ struct Proof {
17
+ Pairing.G1Point A;
18
+ Pairing.G2Point B;
19
+ Pairing.G1Point C;
20
+ }
21
+
22
+ /// @dev Verifies whether a Semaphore proof is valid.
23
+ /// @param merkleTreeRoot: Root of the Merkle tree.
24
+ /// @param nullifierHash: Nullifier hash.
25
+ /// @param signal: Semaphore signal.
26
+ /// @param externalNullifier: External nullifier.
27
+ /// @param proof: Zero-knowledge proof.
28
+ /// @param merkleTreeDepth: Depth of the tree.
29
+ function verifyProof(
30
+ uint256 merkleTreeRoot,
31
+ uint256 nullifierHash,
32
+ uint256 signal,
33
+ uint256 externalNullifier,
34
+ uint256[8] calldata proof,
35
+ uint256 merkleTreeDepth
36
+ ) external view;
37
+ }
@@ -1,8 +1,7 @@
1
1
  //SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.4;
3
3
 
4
- /// @title SemaphoreVoting interface.
5
- /// @dev Interface of SemaphoreVoting contract.
4
+ /// @title SemaphoreVoting contract interface.
6
5
  interface ISemaphoreVoting {
7
6
  error Semaphore__CallerIsNotThePollCoordinator();
8
7
  error Semaphore__MerkleTreeDepthIsNotSupported();
@@ -24,6 +23,7 @@ interface ISemaphoreVoting {
24
23
  struct Poll {
25
24
  address coordinator;
26
25
  PollState state;
26
+ mapping(uint256 => bool) nullifierHashes;
27
27
  }
28
28
 
29
29
  /// @dev Emitted when a new poll is created.
@@ -40,7 +40,7 @@ interface ISemaphoreVoting {
40
40
  /// @dev Emitted when a user votes on a poll.
41
41
  /// @param pollId: Id of the poll.
42
42
  /// @param vote: User encrypted vote.
43
- event VoteAdded(uint256 indexed pollId, bytes32 vote);
43
+ event VoteAdded(uint256 indexed pollId, uint256 vote);
44
44
 
45
45
  /// @dev Emitted when a poll is ended.
46
46
  /// @param pollId: Id of the poll.
@@ -74,7 +74,7 @@ interface ISemaphoreVoting {
74
74
  /// @param pollId: Id of the poll.
75
75
  /// @param proof: Private zk-proof parameters.
76
76
  function castVote(
77
- bytes32 vote,
77
+ uint256 vote,
78
78
  uint256 nullifierHash,
79
79
  uint256 pollId,
80
80
  uint256[8] calldata proof
@@ -1,8 +1,7 @@
1
1
  //SPDX-License-Identifier: MIT
2
2
  pragma solidity 0.8.4;
3
3
 
4
- /// @title SemaphoreWhistleblowing interface.
5
- /// @dev Interface of SemaphoreWhistleblowing contract.
4
+ /// @title SemaphoreWhistleblowing contract interface.
6
5
  interface ISemaphoreWhistleblowing {
7
6
  error Semaphore__CallerIsNotTheEditor();
8
7
  error Semaphore__MerkleTreeDepthIsNotSupported();
@@ -20,7 +19,7 @@ interface ISemaphoreWhistleblowing {
20
19
  /// @dev Emitted when a whistleblower publish a new leak.
21
20
  /// @param entityId: Id of the entity.
22
21
  /// @param leak: News leak.
23
- event LeakPublished(uint256 indexed entityId, bytes32 leak);
22
+ event LeakPublished(uint256 indexed entityId, uint256 leak);
24
23
 
25
24
  /// @dev Creates an entity and the associated Merkle tree/group.
26
25
  /// @param entityId: Id of the entity.
@@ -55,7 +54,7 @@ interface ISemaphoreWhistleblowing {
55
54
  /// @param entityId: Id of the entity.
56
55
  /// @param proof: Private zk-proof parameters.
57
56
  function publishLeak(
58
- bytes32 leak,
57
+ uint256 leak,
59
58
  uint256 nullifierHash,
60
59
  uint256 entityId,
61
60
  uint256[8] calldata proof
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semaphore-protocol/contracts",
3
- "version": "2.6.1",
3
+ "version": "3.0.0-beta.6",
4
4
  "description": "Semaphore contracts to manage groups and broadcast anonymous signals.",
5
5
  "license": "MIT",
6
6
  "files": [
@@ -30,6 +30,6 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@openzeppelin/contracts": "4.7.3",
33
- "@zk-kit/incremental-merkle-tree.sol": "1.3.1"
33
+ "@zk-kit/incremental-merkle-tree.sol": "1.3.3"
34
34
  }
35
35
  }
@@ -1,4 +0,0 @@
1
- //SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.4;
3
-
4
- uint256 constant SNARK_SCALAR_FIELD = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
@@ -1,45 +0,0 @@
1
- //SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.4;
3
-
4
- import "../interfaces/ISemaphoreCore.sol";
5
- import "../interfaces/IVerifier.sol";
6
-
7
- /// @title Semaphore core contract.
8
- /// @notice Minimal code to allow users to signal their endorsement of an arbitrary string.
9
- /// @dev The following code verifies that the proof is correct and saves the hash of the
10
- /// nullifier to prevent double-signaling. External nullifier and Merkle trees (i.e. groups) must be
11
- /// managed externally.
12
- contract SemaphoreCore is ISemaphoreCore {
13
- /// @dev Asserts that no nullifier already exists and if the zero-knowledge proof is valid.
14
- /// Otherwise it reverts.
15
- /// @param signal: Semaphore signal.
16
- /// @param root: Root of the Merkle tree.
17
- /// @param nullifierHash: Nullifier hash.
18
- /// @param externalNullifier: External nullifier.
19
- /// @param proof: Zero-knowledge proof.
20
- /// @param verifier: Verifier address.
21
- function _verifyProof(
22
- bytes32 signal,
23
- uint256 root,
24
- uint256 nullifierHash,
25
- uint256 externalNullifier,
26
- uint256[8] calldata proof,
27
- IVerifier verifier
28
- ) internal view {
29
- uint256 signalHash = _hashSignal(signal);
30
-
31
- verifier.verifyProof(
32
- [proof[0], proof[1]],
33
- [[proof[2], proof[3]], [proof[4], proof[5]]],
34
- [proof[6], proof[7]],
35
- [root, nullifierHash, signalHash, externalNullifier]
36
- );
37
- }
38
-
39
- /// @dev Creates a keccak256 hash of the signal.
40
- /// @param signal: Semaphore signal.
41
- /// @return Hash of the signal.
42
- function _hashSignal(bytes32 signal) private pure returns (uint256) {
43
- return uint256(keccak256(abi.encodePacked(signal))) >> 8;
44
- }
45
- }
@@ -1,10 +0,0 @@
1
- //SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.4;
3
-
4
- /// @title SemaphoreCore interface.
5
- /// @dev Interface of SemaphoreCore contract.
6
- interface ISemaphoreCore {
7
- /// @notice Emitted when a proof is verified correctly and a new nullifier hash is added.
8
- /// @param nullifierHash: Hash of external and identity nullifiers.
9
- event NullifierHashAdded(uint256 nullifierHash);
10
- }
@@ -1,14 +0,0 @@
1
- //SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.4;
3
-
4
- /// @title SemaphoreNullifiers interface.
5
- /// @dev Interface of SemaphoreNullifiers contract.
6
- interface ISemaphoreNullifiers {
7
- /// @dev Emitted when a external nullifier is added.
8
- /// @param externalNullifier: External Semaphore nullifier.
9
- event ExternalNullifierAdded(uint256 externalNullifier);
10
-
11
- /// @dev Emitted when a external nullifier is removed.
12
- /// @param externalNullifier: External Semaphore nullifier.
13
- event ExternalNullifierRemoved(uint256 externalNullifier);
14
- }
@@ -1,13 +0,0 @@
1
- //SPDX-License-Identifier: MIT
2
- pragma solidity 0.8.4;
3
-
4
- /// @title Verifier interface.
5
- /// @dev Interface of Verifier contract.
6
- interface IVerifier {
7
- function verifyProof(
8
- uint256[2] memory a,
9
- uint256[2][2] memory b,
10
- uint256[2] memory c,
11
- uint256[4] memory input
12
- ) external view;
13
- }