mirror of
https://github.com/semaphore-protocol/semaphore.git
synced 2026-04-28 03:00:41 -04:00
14
deploy/01_poseidon_t3.js
Normal file
14
deploy/01_poseidon_t3.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { poseidon_gencontract: poseidonGenContract } = require('circomlibjs');
|
||||
|
||||
module.exports = async ({ getNamedAccounts, deployments }) => {
|
||||
const { deploy } = deployments;
|
||||
const { deployer } = await getNamedAccounts();
|
||||
|
||||
await deploy("PoseidonT3", {
|
||||
from: deployer,
|
||||
log: true,
|
||||
abi: poseidonGenContract.generateABI(2),
|
||||
bytecode: poseidonGenContract.createCode(2)
|
||||
});
|
||||
};
|
||||
module.exports.tags = ['poseidon-t3', 'poseidon'];
|
||||
14
deploy/02_poseidon_t6.js
Normal file
14
deploy/02_poseidon_t6.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const { poseidon_gencontract: poseidonGenContract } = require('circomlibjs');
|
||||
|
||||
module.exports = async ({ getNamedAccounts, deployments }) => {
|
||||
const { deploy } = deployments;
|
||||
const { deployer } = await getNamedAccounts();
|
||||
|
||||
await deploy("PoseidonT3", {
|
||||
from: deployer,
|
||||
log: true,
|
||||
abi: poseidonGenContract.generateABI(5),
|
||||
bytecode: poseidonGenContract.createCode(5)
|
||||
});
|
||||
};
|
||||
module.exports.tags = ['poseidon-t6', 'poseidon'];
|
||||
39
deploy/1_complete.js
Normal file
39
deploy/1_complete.js
Normal file
@@ -0,0 +1,39 @@
|
||||
const { poseidon_gencontract: poseidonGenContract } = require('circomlibjs');
|
||||
const { genExternalNullifier } = require('../utils');
|
||||
|
||||
module.exports = async ({ getNamedAccounts, deployments }) => {
|
||||
const { deploy } = deployments;
|
||||
const { deployer } = await getNamedAccounts();
|
||||
|
||||
const poseidonT3 = await deploy("PoseidonT3", {
|
||||
from: deployer,
|
||||
log: true,
|
||||
abi: poseidonGenContract.generateABI(2),
|
||||
bytecode: poseidonGenContract.createCode(2)
|
||||
});
|
||||
|
||||
const poseidonT6 = await deploy("PoseidonT6", {
|
||||
from: deployer,
|
||||
log: true,
|
||||
abi: poseidonGenContract.generateABI(5),
|
||||
bytecode: poseidonGenContract.createCode(5)
|
||||
});
|
||||
|
||||
const externalNullifier = genExternalNullifier('test-voting');
|
||||
const semaphore = await deploy('Semaphore', {
|
||||
from: deployer,
|
||||
log: true,
|
||||
args: [20, externalNullifier],
|
||||
libraries: {
|
||||
PoseidonT3: poseidonT3.address,
|
||||
PoseidonT6: poseidonT6.address
|
||||
}
|
||||
});
|
||||
|
||||
await deploy('SemaphoreClient', {
|
||||
from: deployer,
|
||||
log: true,
|
||||
args: [semaphore.address],
|
||||
});
|
||||
};
|
||||
module.exports.tags = ['complete'];
|
||||
@@ -1,4 +1,5 @@
|
||||
require("@nomiclabs/hardhat-waffle");
|
||||
require('hardhat-deploy');
|
||||
|
||||
// This is a sample Hardhat task. To learn how to create your own go to
|
||||
// https://hardhat.org/guides/create-task.html
|
||||
@@ -24,4 +25,12 @@ module.exports = {
|
||||
allowUnlimitedContractSize: true,
|
||||
},
|
||||
},
|
||||
namedAccounts: {
|
||||
deployer: 0,
|
||||
tokenOwner: 1,
|
||||
},
|
||||
paths: {
|
||||
deploy: 'deploy',
|
||||
deployments: 'deployments',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
350d6b1fa2a2537ad0a0585a837479fa82459080
|
||||
15bb0cac2b8d3091fe503a0783186b5051ebf07f
|
||||
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"name": "semaphore",
|
||||
"version": "1.0.0",
|
||||
"version": "2.0.0",
|
||||
"description": "Solidity contracts, zk-SNARK circuits, and test scripts for the Semaphore zero-knowledge signalling gadget. This version uses the Poseidon hash and does not use EdDSA signatures.",
|
||||
"scripts": {
|
||||
"test": "ts-node test/verify.ts"
|
||||
"test": "npx hardhat test",
|
||||
"compile": "npx hardhat compile",
|
||||
"develop": "npx hardhat node",
|
||||
"deploy": "npx hardhat deploy --tags complete",
|
||||
"deployPoseidon": "npx hardhat deploy --tags poseidon"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -20,6 +24,7 @@
|
||||
"@libsem/identity": "^1.0.8",
|
||||
"@libsem/protocols": "^1.0.9",
|
||||
"circomlib": "^0.5.3",
|
||||
"hardhat-deploy": "^0.9.4",
|
||||
"web3": "^1.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -20,7 +20,7 @@ npx snarkjs zkey contribute semaphore_0000.zkey semaphore_final.zkey
|
||||
|
||||
npx snarkjs zkey export verificationkey semaphore_final.zkey verification_key.json
|
||||
|
||||
snarkjs zkey export solidityverifier semaphore_final.zkey verifier.sol
|
||||
npx snarkjs zkey export solidityverifier semaphore_final.zkey verifier.sol
|
||||
|
||||
mv verifier.sol ../contracts/Verifier.sol
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// We require the Hardhat Runtime Environment explicitly here. This is optional
|
||||
// but useful for running the script in a standalone fashion through `node <script>`.
|
||||
//
|
||||
// When running the script with `npx hardhat run <script>` you'll find the Hardhat
|
||||
// Runtime Environment's members available in the global scope.
|
||||
const hre = require("hardhat");
|
||||
|
||||
async function main() {
|
||||
// Hardhat always runs the compile task when running scripts with its command
|
||||
// line interface.
|
||||
//
|
||||
// If this script is run directly using `node` you may want to call compile
|
||||
// manually to make sure everything is compiled
|
||||
// await hre.run('compile');
|
||||
|
||||
// We get the contract to deploy
|
||||
const Greeter = await hre.ethers.getContractFactory("Greeter");
|
||||
const greeter = await Greeter.deploy("Hello, Hardhat!");
|
||||
|
||||
await greeter.deployed();
|
||||
|
||||
console.log("Greeter deployed to:", greeter.address);
|
||||
}
|
||||
|
||||
// We recommend this pattern to be able to use async/await everywhere
|
||||
// and properly handle errors.
|
||||
main()
|
||||
.then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
cd ../zkeyFiles
|
||||
http-server -p 8000 --cors
|
||||
@@ -1,122 +0,0 @@
|
||||
const poseidonGenContract = require('circomlib/src/poseidon_gencontract.js');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const Web3 = require('web3');
|
||||
|
||||
const ZERO_VALUE = BigInt(ethers.utils.solidityKeccak256(['bytes'], [ethers.utils.toUtf8Bytes('Semaphore')]));
|
||||
const SNARK_FIELD_SIZE = BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||
|
||||
const { ZkIdentity } = require('@libsem/identity');
|
||||
const { Semaphore, genExternalNullifier, genSignalHash, generateMerkleProof } = require('@libsem/protocols');
|
||||
const { expect } = require('chai');
|
||||
|
||||
describe("Semaphore", function () {
|
||||
it("Should broadcast signal", async function () {
|
||||
const PoseidonT3 = await ethers.getContractFactory(
|
||||
poseidonGenContract.generateABI(2),
|
||||
poseidonGenContract.createCode(2)
|
||||
)
|
||||
const poseidonT3 = await PoseidonT3.deploy();
|
||||
await poseidonT3.deployed();
|
||||
|
||||
|
||||
const PoseidonT6 = await ethers.getContractFactory(
|
||||
poseidonGenContract.generateABI(5),
|
||||
poseidonGenContract.createCode(5)
|
||||
);
|
||||
const poseidonT6 = await PoseidonT6.deploy();
|
||||
await poseidonT6.deployed();
|
||||
|
||||
const Hasher = await ethers.getContractFactory("Hasher", {
|
||||
libraries: {
|
||||
PoseidonT3: poseidonT3.address,
|
||||
PoseidonT6: poseidonT6.address,
|
||||
},
|
||||
});
|
||||
const hasher = await Hasher.deploy();
|
||||
await hasher.deployed();
|
||||
|
||||
const externalNullifier = genExternalNullifier("voting-1");
|
||||
|
||||
const SemaphoreContract = await ethers.getContractFactory("Semaphore", {
|
||||
libraries: {
|
||||
PoseidonT3: poseidonT3.address,
|
||||
PoseidonT6: poseidonT6.address,
|
||||
}
|
||||
});
|
||||
const semaphore = await SemaphoreContract.deploy(20, externalNullifier);
|
||||
await semaphore.deployed();
|
||||
|
||||
const leafIndex = 4;
|
||||
|
||||
const idCommitments = [];
|
||||
|
||||
for (let i=0; i<leafIndex;i++) {
|
||||
const tmpIdentity = ZkIdentity.genIdentity();
|
||||
const tmpCommitment = ZkIdentity.genIdentityCommitment(tmpIdentity);
|
||||
idCommitments.push(tmpCommitment);
|
||||
}
|
||||
|
||||
const promises = idCommitments.map(async (id) => {
|
||||
const index = await semaphore.insertIdentity(id);
|
||||
return index;
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
|
||||
|
||||
const identity = ZkIdentity.genIdentity();
|
||||
let signal = 'yes';
|
||||
signal = Web3.utils.utf8ToHex(signal);
|
||||
const signalHash = genSignalHash(signal);
|
||||
const nullifiersHash = Semaphore.genNullifierHash(externalNullifier, identity.identityNullifier, 20);
|
||||
const identityCommitment = ZkIdentity.genIdentityCommitment(identity);
|
||||
|
||||
await semaphore.insertIdentity(identityCommitment);
|
||||
idCommitments.push(identityCommitment);
|
||||
|
||||
const merkleProof = generateMerkleProof(20, ZERO_VALUE, 5, idCommitments, identityCommitment);
|
||||
const witness = Semaphore.genWitness(identity, merkleProof, externalNullifier, signal);
|
||||
|
||||
const wasmFilePath = path.join('./zkeyFiles', 'semaphore.wasm');
|
||||
const finalZkeyPath = path.join('./zkeyFiles', 'semaphore_final.zkey');
|
||||
|
||||
const fullProof = await Semaphore.genProof(witness, wasmFilePath, finalZkeyPath);
|
||||
|
||||
const solidityProof = Semaphore.packToSolidityProof(fullProof);
|
||||
const packedProof = await semaphore.packProof(
|
||||
solidityProof.a,
|
||||
solidityProof.b,
|
||||
solidityProof.c,
|
||||
);
|
||||
|
||||
const preBroadcastCheck = await semaphore.preBroadcastCheck(
|
||||
ethers.utils.hexlify(ethers.utils.toUtf8Bytes(signal)),
|
||||
packedProof,
|
||||
merkleProof.root,
|
||||
nullifiersHash,
|
||||
signalHash,
|
||||
externalNullifier
|
||||
)
|
||||
|
||||
expect(preBroadcastCheck).to.be.true;
|
||||
|
||||
const res = await semaphore.broadcastSignal(
|
||||
ethers.utils.hexlify(ethers.utils.toUtf8Bytes(signal)),
|
||||
packedProof,
|
||||
merkleProof.root,
|
||||
nullifiersHash,
|
||||
externalNullifier
|
||||
)
|
||||
|
||||
expect(res.hash).to.be.an('string');
|
||||
|
||||
// const verificationRes = await semaphore.verifyProof(
|
||||
// solidityProof.a,
|
||||
// solidityProof.b,
|
||||
// solidityProof.c,
|
||||
// solidityProof.inputs
|
||||
// );
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1,52 +0,0 @@
|
||||
const snarkjs = require("snarkjs");
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { ZkIdentity, Identity } from '@libsem/identity';
|
||||
import { Semaphore, MerkleProof, IProof, generateMerkleProof, genExternalNullifier, genSignalHash } from '@libsem/protocols';
|
||||
import * as ethers from 'ethers';
|
||||
|
||||
const ZERO_VALUE = BigInt(ethers.utils.solidityKeccak256(['bytes'], [ethers.utils.toUtf8Bytes('Semaphore')]));
|
||||
|
||||
async function run() {
|
||||
const identityCommitments: Array<bigint> = [];
|
||||
const leafIndex = 3;
|
||||
|
||||
for (let i=0; i<leafIndex;i++) {
|
||||
const tmpIdentity = ZkIdentity.genIdentity();
|
||||
const tmpCommitment: bigint = ZkIdentity.genIdentityCommitment(tmpIdentity);
|
||||
identityCommitments.push(tmpCommitment);
|
||||
}
|
||||
|
||||
const identity: Identity = ZkIdentity.genIdentity();
|
||||
const externalNullifier: string = genExternalNullifier("voting_1");
|
||||
const signal = '0x111';
|
||||
const identityCommitment: bigint = ZkIdentity.genIdentityCommitment(identity);
|
||||
const nullifierHash: bigint = Semaphore.genNullifierHash(externalNullifier, identity.identityNullifier, 20);
|
||||
|
||||
const commitments: Array<bigint> = Object.assign([], identityCommitments);
|
||||
commitments.push(identityCommitment);
|
||||
|
||||
const merkleProof: MerkleProof = generateMerkleProof(20, BigInt(0), 5, commitments, identityCommitment);
|
||||
const witness: IProof = Semaphore.genWitness(identity, merkleProof, externalNullifier, signal);
|
||||
|
||||
const publicSignals: Array<bigint | string> = [merkleProof.root, nullifierHash, genSignalHash(signal), externalNullifier];
|
||||
|
||||
const vkeyPath: string = path.join('./zkeyFiles', 'verification_key.json');
|
||||
const vKey = JSON.parse(fs.readFileSync(vkeyPath, 'utf-8'));
|
||||
|
||||
const wasmFilePath: string = path.join('./zkeyFiles', 'semaphore.wasm');
|
||||
const finalZkeyPath: string = path.join('./zkeyFiles', 'semaphore_final.zkey');
|
||||
|
||||
const fullProof: IProof = await Semaphore.genProof(witness, wasmFilePath, finalZkeyPath);
|
||||
const res: boolean = await Semaphore.verifyProof(vKey, { proof: fullProof.proof, publicSignals });
|
||||
|
||||
if(res) {
|
||||
console.log('VERIFICATION OK');
|
||||
} else {
|
||||
console.log('VERIFICATION FAILED');
|
||||
}
|
||||
}
|
||||
|
||||
run().then(() => {
|
||||
process.exit(0);
|
||||
});
|
||||
15
utils/index.js
Normal file
15
utils/index.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const { ethers } = require('ethers');
|
||||
|
||||
const genExternalNullifier = (plaintext) => {
|
||||
const _cutOrExpandHexToBytes = (hexStr, bytes) => {
|
||||
const len = bytes * 2;
|
||||
|
||||
const h = hexStr.slice(2, len + 2);
|
||||
return "0x" + h.padStart(len, "0");
|
||||
};
|
||||
|
||||
const hashed = ethers.utils.solidityKeccak256(["string"], [plaintext]);
|
||||
return _cutOrExpandHexToBytes("0x" + hashed.slice(8), 32);
|
||||
};
|
||||
|
||||
module.exports = { genExternalNullifier }
|
||||
Reference in New Issue
Block a user