mirror of
https://github.com/semaphore-protocol/semaphore.git
synced 2026-01-10 23:28:17 -05:00
refactor(contracts): create SemaphoreProof struct
Former-commit-id: 111bf43066
This commit is contained in:
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user