refactor(contracts): create SemaphoreProof struct

Former-commit-id: 111bf43066
This commit is contained in:
cedoor
2024-01-23 18:34:56 +00:00
parent e2365668bd
commit a623a5a7b0
3 changed files with 42 additions and 124 deletions

View File

@@ -102,36 +102,34 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
function validateProof(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 merkleTreeRoot,
uint256 nullifier,
uint256 message,
uint256 scope,
uint256[8] calldata proof
SemaphoreProof calldata proof
) external override onlyExistingGroup(groupId) {
if (groups[groupId].nullifiers[nullifier]) {
if (groups[groupId].nullifiers[proof.nullifier]) {
revert Semaphore__YouAreUsingTheSameNullifierTwice();
}
if (!verifyProof(groupId, merkleTreeDepth, merkleTreeRoot, nullifier, message, scope, proof)) {
if (!verifyProof(groupId, proof)) {
revert Semaphore__InvalidProof();
}
groups[groupId].nullifiers[nullifier] = true;
groups[groupId].nullifiers[proof.nullifier] = true;
emit ProofValidated(groupId, merkleTreeDepth, merkleTreeRoot, nullifier, message, scope, proof);
emit ProofValidated(
groupId,
proof.merkleTreeDepth,
proof.merkleTreeRoot,
proof.nullifier,
proof.message,
proof.scope,
proof.proof
);
}
function verifyProof(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 merkleTreeRoot,
uint256 nullifier,
uint256 message,
uint256 scope,
uint256[8] calldata proof
SemaphoreProof calldata proof
) public view override onlyExistingGroup(groupId) returns (bool) {
if (merkleTreeDepth < 1 || merkleTreeDepth > 12) {
if (proof.merkleTreeDepth < 1 || proof.merkleTreeDepth > 12) {
revert Semaphore__MerkleTreeDepthIsNotSupported();
}
@@ -145,8 +143,8 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
// A proof could have used an old Merkle tree root.
// https://github.com/semaphore-protocol/semaphore/issues/98
if (merkleTreeRoot != currentMerkleTreeRoot) {
uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[merkleTreeRoot];
if (proof.merkleTreeRoot != currentMerkleTreeRoot) {
uint256 merkleRootCreationDate = groups[groupId].merkleRootCreationDates[proof.merkleTreeRoot];
uint256 merkleTreeDuration = groups[groupId].merkleTreeDuration;
if (merkleRootCreationDate == 0) {
@@ -160,11 +158,11 @@ contract Semaphore is ISemaphore, SemaphoreGroups {
return
verifier.verifyProof(
[proof[0], proof[1]],
[[proof[2], proof[3]], [proof[4], proof[5]]],
[proof[6], proof[7]],
[merkleTreeRoot, nullifier, _hash(message), _hash(scope)],
merkleTreeDepth
[proof.proof[0], proof.proof[1]],
[[proof.proof[2], proof.proof[3]], [proof.proof[4], proof.proof[5]]],
[proof.proof[6], proof.proof[7]],
[proof.merkleTreeRoot, proof.nullifier, _hash(proof.message), _hash(proof.scope)],
proof.merkleTreeDepth
);
}

View File

@@ -17,6 +17,16 @@ interface ISemaphore {
mapping(uint256 => bool) nullifiers;
}
/// It defines all the group parameters used by Semaphore.sol.
struct SemaphoreProof {
uint256 merkleTreeDepth;
uint256 merkleTreeRoot;
uint256 nullifier;
uint256 message;
uint256 scope;
uint256[8] proof;
}
/// @dev Emitted when the Merkle tree duration of a group is updated.
/// @param groupId: Id of the group.
/// @param oldMerkleTreeDuration: Old Merkle tree duration of the group.
@@ -82,37 +92,11 @@ interface ISemaphore {
/// @dev Saves the nullifier hash to avoid double signaling and emits an event
/// if the zero-knowledge proof is valid.
/// @param groupId: Id of the group.
/// @param merkleTreeDepth: Depth of the Merkle tree.
/// @param merkleTreeRoot: Root of the Merkle tree.
/// @param nullifier: Nullifier.
/// @param message: Semaphore message.
/// @param scope: Scope.
/// @param proof: Zero-knowledge proof.
function validateProof(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 merkleTreeRoot,
uint256 nullifier,
uint256 message,
uint256 scope,
uint256[8] calldata proof
) external;
function validateProof(uint256 groupId, SemaphoreProof calldata proof) external;
/// @dev Verifies a zero-knowledge proof by returning true or false.
/// @param groupId: Id of the group.
/// @param merkleTreeDepth: Depth of the Merkle tree.
/// @param merkleTreeRoot: Root of the Merkle tree.
/// @param nullifier: Nullifier.
/// @param message: Semaphore message.
/// @param scope: Scope.
/// @param proof: Zero-knowledge proof.
function verifyProof(
uint256 groupId,
uint256 merkleTreeDepth,
uint256 merkleTreeRoot,
uint256 nullifier,
uint256 message,
uint256 scope,
uint256[8] calldata proof
) external view returns (bool);
function verifyProof(uint256 groupId, SemaphoreProof calldata proof) external view returns (bool);
}

View File

@@ -226,29 +226,13 @@ describe("Semaphore", () => {
})
it("Should not verify a proof if the group does not exist", async () => {
const transaction = semaphoreContract.verifyProof(
11,
merkleTreeDepth,
1,
0,
message,
0,
[0, 0, 0, 0, 0, 0, 0, 0]
)
const transaction = semaphoreContract.verifyProof(11, fullProof)
await expect(transaction).to.be.revertedWithCustomError(semaphoreContract, "Semaphore__GroupDoesNotExist")
})
it("Should not verify a proof if the Merkle tree root is not part of the group", async () => {
const transaction = semaphoreContract.verifyProof(
groupId,
merkleTreeDepth,
1,
0,
message,
0,
[0, 0, 0, 0, 0, 0, 0, 0]
)
const transaction = semaphoreContract.verifyProof(groupId, { ...fullProof, merkleTreeRoot: 1 })
await expect(transaction).to.be.revertedWithCustomError(
semaphoreContract,
@@ -257,15 +241,7 @@ describe("Semaphore", () => {
})
it("Should verify a proof for an onchain group", async () => {
const validProof = await semaphoreContract.verifyProof(
groupId,
fullProof.merkleTreeDepth,
fullProof.merkleTreeRoot,
fullProof.nullifier,
fullProof.message,
fullProof.merkleTreeRoot,
fullProof.proof
)
const validProof = await semaphoreContract.verifyProof(groupId, fullProof)
expect(validProof).to.equal(true)
})
@@ -279,15 +255,7 @@ describe("Semaphore", () => {
const fullProof = await generateProof(identity, group, message, group.root as string, merkleTreeDepth)
const transaction = semaphoreContract.verifyProof(
groupId,
fullProof.merkleTreeDepth,
fullProof.merkleTreeRoot,
fullProof.nullifier,
fullProof.message,
fullProof.merkleTreeRoot,
fullProof.proof
)
const transaction = semaphoreContract.verifyProof(groupId, fullProof)
await expect(transaction).to.be.revertedWithCustomError(
semaphoreContract,
@@ -327,29 +295,13 @@ describe("Semaphore", () => {
})
it("Should throw an exception if the proof is not valid", async () => {
const transaction = semaphoreContract.validateProof(
groupId,
fullProof.merkleTreeDepth,
fullProof.merkleTreeRoot,
fullProof.nullifier,
fullProof.message,
0,
fullProof.proof
)
const transaction = semaphoreContract.validateProof(groupId, { ...fullProof, scope: 0 })
await expect(transaction).to.be.revertedWithCustomError(semaphoreContract, "Semaphore__InvalidProof")
})
it("Should validate a proof for an onchain group with one member correctly", async () => {
const transaction = semaphoreContract.validateProof(
groupOneMemberId,
fullProof.merkleTreeDepth,
fullProofOneMember.merkleTreeRoot,
fullProofOneMember.nullifier,
fullProofOneMember.message,
fullProofOneMember.merkleTreeRoot,
fullProofOneMember.proof
)
const transaction = semaphoreContract.validateProof(groupOneMemberId, fullProofOneMember)
await expect(transaction)
.to.emit(semaphoreContract, "ProofValidated")
@@ -365,15 +317,7 @@ describe("Semaphore", () => {
})
it("Should validate a proof for an onchain group with more than one member correctly", async () => {
const transaction = semaphoreContract.validateProof(
groupId,
fullProof.merkleTreeDepth,
fullProof.merkleTreeRoot,
fullProof.nullifier,
fullProof.message,
fullProof.merkleTreeRoot,
fullProof.proof
)
const transaction = semaphoreContract.validateProof(groupId, fullProof)
await expect(transaction)
.to.emit(semaphoreContract, "ProofValidated")
@@ -389,15 +333,7 @@ describe("Semaphore", () => {
})
it("Should not validate the same proof for an onchain group twice", async () => {
const transaction = semaphoreContract.validateProof(
groupId,
fullProof.merkleTreeDepth,
fullProof.merkleTreeRoot,
fullProof.nullifier,
fullProof.message,
fullProof.merkleTreeRoot,
fullProof.proof
)
const transaction = semaphoreContract.validateProof(groupId, fullProof)
await expect(transaction).to.be.revertedWithCustomError(
semaphoreContract,