mirror of
https://github.com/semaphore-protocol/semaphore.git
synced 2026-04-28 03:00:41 -04:00
fix+feat: fixes some aliasing bugs, adds an optional permissioning to broadcast (#23)
* fixes aliasing bugs, adds optional permissioning to broadcast * fixes nullifiers hash, makes permissioning work with tests * fix: clears cache * fix: adds another account for ci testing * fix: addresses comments
This commit is contained in:
@@ -19,14 +19,14 @@ jobs:
|
||||
- restore_cache:
|
||||
name: restore-npm-cache
|
||||
keys:
|
||||
- v1.8-dependencies-{{ checksum "package-lock.json" }}
|
||||
- v1.9-dependencies-{{ checksum "package-lock.json" }}
|
||||
|
||||
- run: npm install
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- node_modules
|
||||
key: v1.8-dependencies-{{ checksum "package-lock.json" }}
|
||||
key: v1.9-dependencies-{{ checksum "package-lock.json" }}
|
||||
|
||||
# checksum the snarks definitions
|
||||
- run:
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
- restore_cache:
|
||||
name: restore-snark-cache
|
||||
keys:
|
||||
- v1.8-dependencies-{{ checksum "build/.snark_checksum" }}
|
||||
- v1.9-dependencies-{{ checksum "build/.snark_checksum" }}
|
||||
|
||||
# build snarks
|
||||
- run:
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
# cache generated snark circuit and keys
|
||||
- save_cache:
|
||||
key: v1.8-dependencies-{{ checksum "build/.snark_checksum" }}
|
||||
key: v1.9-dependencies-{{ checksum "build/.snark_checksum" }}
|
||||
paths:
|
||||
- build/circuit.json
|
||||
- build/proving_key.bin
|
||||
|
||||
@@ -27,6 +27,7 @@ import "./Ownable.sol";
|
||||
contract Semaphore is Verifier, MultipleMerkleTree, Ownable {
|
||||
uint256 public external_nullifier;
|
||||
uint8 public id_tree_index;
|
||||
bool public is_broadcast_permissioned = true;
|
||||
|
||||
mapping (uint256 => bool) root_history;
|
||||
uint8 current_root_index = 0;
|
||||
@@ -38,17 +39,17 @@ contract Semaphore is Verifier, MultipleMerkleTree, Ownable {
|
||||
|
||||
event SignalBroadcast(bytes signal, uint256 nullifiers_hash, uint256 external_nullifier);
|
||||
|
||||
modifier onlyOwnerIfPermissioned() {
|
||||
require(!is_broadcast_permissioned || isOwner(), "Semaphore: broadcast permission denied");
|
||||
_;
|
||||
}
|
||||
|
||||
constructor(uint8 tree_levels, uint256 zero_value, uint256 external_nullifier_in) Ownable() public
|
||||
{
|
||||
external_nullifier = external_nullifier_in;
|
||||
id_tree_index = init_tree(tree_levels, zero_value);
|
||||
}
|
||||
|
||||
event Funded(uint256 amount);
|
||||
|
||||
function fund() public payable {
|
||||
emit Funded(msg.value);
|
||||
}
|
||||
|
||||
function insertIdentity(uint256 leaf) public onlyOwner {
|
||||
insert(id_tree_index, leaf);
|
||||
@@ -89,9 +90,6 @@ contract Semaphore is Verifier, MultipleMerkleTree, Ownable {
|
||||
uint[4] memory input,
|
||||
uint256 signal_hash
|
||||
) public {
|
||||
// Note that we only verify the broadcaster's address (input[4]) in the
|
||||
// snark via verifyProof().
|
||||
|
||||
require(hasNullifier(input[1]) == false, "Semaphore: nullifier already seen");
|
||||
require(signal_hash == input[2], "Semaphore: signal hash mismatch");
|
||||
require(external_nullifier == input[3], "Semaphore: external nullifier mismatch");
|
||||
@@ -104,10 +102,10 @@ contract Semaphore is Verifier, MultipleMerkleTree, Ownable {
|
||||
uint[2] memory a,
|
||||
uint[2][2] memory b,
|
||||
uint[2] memory c,
|
||||
uint[4] memory input // [root, nullifiers_hash, signal_hash, external_nullifier]
|
||||
) public {
|
||||
uint[4] memory input // (root, nullifiers_hash, signal_hash, external_nullifier)
|
||||
) public onlyOwnerIfPermissioned {
|
||||
// Hash the signal
|
||||
uint256 signal_hash = uint256(sha256(signal)) >> 8;
|
||||
uint256 signal_hash = uint256(keccak256(signal)) >> 8;
|
||||
|
||||
// Check the inputs
|
||||
preBroadcastRequire(a, b, c, input, signal_hash);
|
||||
@@ -136,4 +134,8 @@ contract Semaphore is Verifier, MultipleMerkleTree, Ownable {
|
||||
function setExternalNullifier(uint256 new_external_nullifier) public onlyOwner {
|
||||
external_nullifier = new_external_nullifier;
|
||||
}
|
||||
|
||||
function setPermissioning(bool _newPermission) public onlyOwner {
|
||||
is_broadcast_permissioned = _newPermission;
|
||||
}
|
||||
}
|
||||
|
||||
2
semaphorejs/package-lock.json
generated
2
semaphorejs/package-lock.json
generated
@@ -3505,7 +3505,7 @@
|
||||
"integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8="
|
||||
},
|
||||
"ethereumjs-abi": {
|
||||
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#8431eab7b3384e65e8126a4602520b78031666fb",
|
||||
"version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#572d4bafe08a8a231137e1f9daeb0f8a23f197d2",
|
||||
"from": "git+https://github.com/ethereumjs/ethereumjs-abi.git",
|
||||
"requires": {
|
||||
"bn.js": "^4.11.8",
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"circomlib": "0.0.10",
|
||||
"cors": "^2.8.5",
|
||||
"del": "^4.1.0",
|
||||
"ethers": "^4.0.33",
|
||||
"file-saver": "^2.0.1",
|
||||
"ganache-cli": "^6.4.1",
|
||||
"ganache-core": "^2.5.3",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
echo "Working directory: `pwd`"
|
||||
|
||||
npx mocha --recursive ../test/circuits
|
||||
../node_modules/.bin/ganache-cli -p 7545 -l 8800000 -i 5777 --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21,100000000000000000000000000' --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21,10000000000000000000000000' -q &
|
||||
../node_modules/.bin/ganache-cli -p 7545 -l 8800000 -i 5777 --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21,100000000000000000000000000' --account='0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd22,10000000000000000000000000' -q &
|
||||
../node_modules/.bin/truffle migrate --reset --network=local
|
||||
../node_modules/.bin/truffle test ../test/contracts/* --network=local
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export CHAIN_ID=5777
|
||||
export NODE_URL=http://localhost:7545
|
||||
export SERVER_NODE_URL=http://localhost:7545
|
||||
export DEPLOY_TO=local
|
||||
export SLEEP_TIME=7
|
||||
export SLEEP_TIME=10
|
||||
|
||||
if [ "$1" == "goerli" ]; then
|
||||
CHAIN_ID=5
|
||||
@@ -66,6 +66,6 @@ IDENTITY_COMMITMENT=`cat ./semaphore_identity.json | jq '.identity_commitment' |
|
||||
echo ${IDENTITY_COMMITMENT}
|
||||
|
||||
tmux \
|
||||
new-session "source ~/.bashrc; export CONFIG_ENV=true LOG_LEVEL=${LOG_LEVEL} CHAIN_ID=${CHAIN_ID} CONTRACT_ADDRESS=$ADDRESS NODE_URL=${SERVER_NODE_URL} SEMAPHORE_PORT=3000 FROM_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 FROM_PRIVATE_KEY=0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21 TRANSACTION_CONFIRMATION_BLOCKS=1 CREATION_HASH=${CREATION_HASH}; npx semaphorejs-server fund; npx semaphorejs-server; bash -i" \; \
|
||||
new-session "source ~/.bashrc; export CONFIG_ENV=true LOG_LEVEL=${LOG_LEVEL} CHAIN_ID=${CHAIN_ID} CONTRACT_ADDRESS=$ADDRESS NODE_URL=${SERVER_NODE_URL} SEMAPHORE_PORT=3000 FROM_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 FROM_PRIVATE_KEY=0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21 TRANSACTION_CONFIRMATION_BLOCKS=1 CREATION_HASH=${CREATION_HASH}; npx semaphorejs-server disable_permissioning; npx semaphorejs-server; bash -i" \; \
|
||||
split-window -h -t 0 "source ~/.bashrc; sleep ${SLEEP_TIME}; LOG_LEVEL=${LOG_LEVEL} curl http://localhost:3000/add_identity -X POST -d'{\"leaf\": \"${IDENTITY_COMMITMENT}\"}' -H 'Content-Type: application/json'; bash -i" \; \
|
||||
split-window -t 0 "source ~/.bashrc; sleep ${SLEEP_TIME}; ./wait_for_element.sh ${IDENTITY_COMMITMENT}; LOG_LEVEL=${LOG_LEVEL} TRANSACTION_CONFIRMATION_BLOCKS=1 CHAIN_ID=${CHAIN_ID} CONTRACT_ADDRESS=$ADDRESS FROM_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 FROM_PRIVATE_KEY=0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21 NODE_URL=${NODE_URL} EXTERNAL_NULLIFIER=12312 SEMAPHORE_SERVER_URL=http://localhost:3000 BROADCASTER_ADDRESS=0x1929c15f4e818abf2549510622a50c440c474223 CONFIG_ENV=true BASE_DIR=`pwd`/.. npx semaphorejs-client signal `shuf -i 1-100000000 -n 1`; bash -i"
|
||||
|
||||
@@ -76,17 +76,26 @@ template Semaphore(jubjub_field_size, n_levels, n_rounds) {
|
||||
// END signals
|
||||
|
||||
|
||||
component identity_nullifier_bits = Num2Bits(256);
|
||||
component identity_nullifier_bits = Num2Bits(248);
|
||||
identity_nullifier_bits.in <== identity_nullifier;
|
||||
|
||||
component identity_pk_0_bits = Num2Bits(256);
|
||||
component identity_pk_0_bits = Num2Bits_strict();
|
||||
identity_pk_0_bits.in <== dbl3.xout;
|
||||
|
||||
component identity_commitment = Pedersen(2*256);
|
||||
// BEGIN identity commitment
|
||||
for (var i = 0; i < 256; i++) {
|
||||
identity_commitment.in[i] <== identity_pk_0_bits.out[i];
|
||||
identity_commitment.in[i + 256] <== identity_nullifier_bits.out[i];
|
||||
if (i < 254) {
|
||||
identity_commitment.in[i] <== identity_pk_0_bits.out[i];
|
||||
} else {
|
||||
identity_commitment.in[i] <== 0;
|
||||
}
|
||||
|
||||
if (i < 248) {
|
||||
identity_commitment.in[i + 256] <== identity_nullifier_bits.out[i];
|
||||
} else {
|
||||
identity_commitment.in[i + 256] <== 0;
|
||||
}
|
||||
}
|
||||
// END identity commitment
|
||||
|
||||
@@ -115,21 +124,24 @@ template Semaphore(jubjub_field_size, n_levels, n_rounds) {
|
||||
// END tree
|
||||
|
||||
// BEGIN nullifiers
|
||||
component external_nullifier_bits = Num2Bits(256);
|
||||
component external_nullifier_bits = Num2Bits(232);
|
||||
external_nullifier_bits.in <== external_nullifier;
|
||||
|
||||
component nullifiers_hasher = Blake2s(512, 0);
|
||||
for (var i = 0; i < 256; i++) {
|
||||
for (var i = 0; i < 248; i++) {
|
||||
nullifiers_hasher.in_bits[i] <== identity_nullifier_bits.out[i];
|
||||
if (i < 224) {
|
||||
nullifiers_hasher.in_bits[256 + i] <== external_nullifier_bits.out[i];
|
||||
} else {
|
||||
if ( (i-224) < n_levels ) {
|
||||
nullifiers_hasher.in_bits[256 + i] <== identity_path_index[i - 224];
|
||||
} else {
|
||||
nullifiers_hasher.in_bits[256 + i] <== 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < 232; i++) {
|
||||
nullifiers_hasher.in_bits[248 + i] <== external_nullifier_bits.out[i];
|
||||
}
|
||||
|
||||
for (var i = 0; i < n_levels; i++) {
|
||||
nullifiers_hasher.in_bits[248 + 232 + i] <== identity_path_index[i];
|
||||
}
|
||||
|
||||
for (var i = (248 + 232 + n_levels); i < 512; i++) {
|
||||
nullifiers_hasher.in_bits[i] <== 0;
|
||||
}
|
||||
|
||||
component nullifiers_hash_num = Bits2Num(253);
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
const crypto = require('crypto');
|
||||
const path = require('path');
|
||||
const {unstringifyBigInts, stringifyBigInts} = require('websnark/tools/stringifybigint.js');
|
||||
const blake2 = require('blakejs');
|
||||
|
||||
const chai = require('chai');
|
||||
const assert = chai.assert;
|
||||
@@ -40,6 +39,8 @@ const fetch = require('node-fetch');
|
||||
|
||||
const Web3 = require('web3');
|
||||
|
||||
const ethers = require('ethers');
|
||||
|
||||
let logger;
|
||||
|
||||
/* uint8array to hex */
|
||||
@@ -112,7 +113,6 @@ class SemaphoreClient {
|
||||
|
||||
this.chain_id = chain_id;
|
||||
this.server_broadcast = server_broadcast;
|
||||
this.broadcaster_address = server_broadcast_address;
|
||||
}
|
||||
|
||||
async broadcast_signal(signal_str) {
|
||||
@@ -132,11 +132,16 @@ class SemaphoreClient {
|
||||
external_nullifier = bigInt(this.external_nullifier);
|
||||
}
|
||||
const signal_to_contract = this.web3.utils.asciiToHex(signal_str);
|
||||
const signal_hash_raw = crypto.createHash('sha256').update(signal_to_contract.slice(2), 'hex').digest();
|
||||
const signal_hash = beBuff2int(signal_hash_raw.slice(0, 31));
|
||||
const broadcaster_address = bigInt(this.broadcaster_address);
|
||||
const signal_to_contract_bytes = new Buffer(signal_to_contract.slice(2), 'hex');
|
||||
|
||||
const msg = mimcsponge.multiHash([external_nullifier, signal_hash, broadcaster_address]);
|
||||
const signal_hash_raw = ethers.utils.solidityKeccak256(
|
||||
['bytes'],
|
||||
[signal_to_contract_bytes],
|
||||
);
|
||||
const signal_hash_raw_bytes = new Buffer(signal_hash_raw.slice(2), 'hex');
|
||||
const signal_hash = beBuff2int(signal_hash_raw_bytes.slice(0, 31));
|
||||
|
||||
const msg = mimcsponge.multiHash([external_nullifier, signal_hash]);
|
||||
const signature = eddsa.signMiMCSponge(prvKey, msg);
|
||||
|
||||
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
|
||||
@@ -174,7 +179,6 @@ class SemaphoreClient {
|
||||
identity_nullifier,
|
||||
identity_path_elements,
|
||||
identity_path_index,
|
||||
broadcaster_address,
|
||||
};
|
||||
const w = this.circuit.calculateWitness(inputs);
|
||||
const witness_bin = proof_util.convertWitness(snarkjs.stringifyBigInts(w));
|
||||
@@ -196,8 +200,8 @@ class SemaphoreClient {
|
||||
|
||||
logger.debug(`publicSignals: ${publicSignals}`);
|
||||
|
||||
// publicSignals = (root, nullifiers_hash, signal_hash, external_nullifier, broadcaster_address)
|
||||
const public_signals_to_broadcast = [ publicSignals[0].toString(), publicSignals[1].toString(), publicSignals[2].toString(), publicSignals[3].toString(), publicSignals[4].toString() ];
|
||||
// publicSignals = (root, nullifiers_hash, signal_hash, external_nullifier)
|
||||
const public_signals_to_broadcast = [ publicSignals[0].toString(), publicSignals[1].toString(), publicSignals[2].toString(), publicSignals[3].toString() ];
|
||||
const proof_to_broadcast = [
|
||||
[ proof.pi_a[0].toString(), proof.pi_a[1].toString() ],
|
||||
[ [ proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString() ], [ proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString() ] ],
|
||||
|
||||
@@ -350,6 +350,11 @@ async function fund() {
|
||||
);
|
||||
}
|
||||
|
||||
async function disablePermissioning() {
|
||||
const encoded = await semaphore.contract.methods.disablePermissioning().encodeABI();
|
||||
await send_transaction(encoded);
|
||||
}
|
||||
|
||||
if (process.argv[2] == 'fund') {
|
||||
fund()
|
||||
.then(() => {
|
||||
@@ -359,6 +364,15 @@ if (process.argv[2] == 'fund') {
|
||||
logger.error(`error funding: ${err.stack}`);
|
||||
process.exit(1);
|
||||
});
|
||||
} else if (process.argv[2] == 'disable_permissioning') {
|
||||
disablePermissioning()
|
||||
.then(() => {
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((err) => {
|
||||
logger.error(`error funding: ${err.stack}`);
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
const express = require('express');
|
||||
var cors = require('cors');
|
||||
|
||||
@@ -29,6 +29,8 @@ const path = require('path');
|
||||
const snarkjs = require('snarkjs');
|
||||
const circomlib = require('circomlib');
|
||||
|
||||
const ethers = require('ethers');
|
||||
|
||||
const test_util = require('../../src/test_util');
|
||||
|
||||
const bigInt = snarkjs.bigInt;
|
||||
@@ -77,6 +79,7 @@ const cutDownBits = function(b, bits) {
|
||||
|
||||
contract('Semaphore', function (accounts) {
|
||||
let semaphore;
|
||||
let identity_commitment1;
|
||||
|
||||
before(async () => {
|
||||
semaphore = await Semaphore.deployed();
|
||||
@@ -96,9 +99,16 @@ contract('Semaphore', function (accounts) {
|
||||
|
||||
const external_nullifier = bigInt('12312');
|
||||
const signal_str = 'hello!';
|
||||
const signal_hash_raw = crypto.createHash('sha256').update(signal_str, 'utf8').digest();
|
||||
const signal_hash = beBuff2int(signal_hash_raw.slice(0, 31));
|
||||
const signal_to_contract = web3.utils.asciiToHex(signal_str);
|
||||
const signal_to_contract_bytes = new Buffer(signal_to_contract.slice(2), 'hex');
|
||||
|
||||
const signal_hash_raw = ethers.utils.solidityKeccak256(
|
||||
['bytes'],
|
||||
[signal_to_contract_bytes],
|
||||
);
|
||||
const signal_hash_raw_bytes = new Buffer(signal_hash_raw.slice(2), 'hex');
|
||||
const signal_hash = beBuff2int(signal_hash_raw_bytes.slice(0, 31));
|
||||
|
||||
const accounts = await web3.eth.getAccounts();
|
||||
|
||||
const msg = mimcsponge.multiHash([bigInt(external_nullifier), bigInt(signal_hash)]);
|
||||
@@ -106,7 +116,7 @@ contract('Semaphore', function (accounts) {
|
||||
|
||||
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
|
||||
|
||||
const identity_nullifier = bigInt('230');
|
||||
const identity_nullifier = bigInt('231');
|
||||
|
||||
const storage_path = '/tmp/rocksdb_semaphore_test';
|
||||
if (fs.existsSync(storage_path)) {
|
||||
@@ -134,18 +144,18 @@ contract('Semaphore', function (accounts) {
|
||||
);
|
||||
|
||||
const identity_commitment = pedersenHash([bigInt(circomlib.babyJub.mulPointEscalar(pubKey, 8)[0]), bigInt(identity_nullifier)]);
|
||||
identity_commitment1 = identity_commitment;
|
||||
|
||||
const semaphore = await Semaphore.deployed();
|
||||
const receipt = await semaphore.insertIdentity(identity_commitment.toString());
|
||||
assert.equal(receipt.logs[0].event, 'LeafAdded');
|
||||
const next_index = parseInt(receipt.logs[0].args.leaf_index.toString());
|
||||
await semaphore.fund({value: web3.utils.toWei('10')});
|
||||
|
||||
await tree.update(next_index, identity_commitment.toString());
|
||||
await memTree.update(next_index, identity_commitment.toString());
|
||||
const identity_path = await tree.path(next_index);
|
||||
const mem_identity_path = await memTree.path(next_index);
|
||||
|
||||
|
||||
assert.equal(JSON.stringify(identity_path), JSON.stringify(mem_identity_path))
|
||||
|
||||
const identity_path_elements = identity_path.path_elements;
|
||||
@@ -244,4 +254,163 @@ contract('Semaphore', function (accounts) {
|
||||
console.log(evs);
|
||||
*/
|
||||
});
|
||||
|
||||
it('tests permissioning', async () => {
|
||||
const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname,'../../build/circuit.json')).toString());
|
||||
circuit = new snarkjs.Circuit(cirDef);
|
||||
|
||||
const prvKey = Buffer.from('0001020304050607080900010203040506070809000102030405060708080001', 'hex');
|
||||
|
||||
const pubKey = eddsa.prv2pub(prvKey);
|
||||
|
||||
const external_nullifier = bigInt('12312');
|
||||
const signal_str = 'hello!';
|
||||
const signal_to_contract = web3.utils.asciiToHex(signal_str);
|
||||
const signal_to_contract_bytes = new Buffer(signal_to_contract.slice(2), 'hex');
|
||||
|
||||
const signal_hash_raw = ethers.utils.solidityKeccak256(
|
||||
['bytes'],
|
||||
[signal_to_contract_bytes],
|
||||
);
|
||||
const signal_hash_raw_bytes = new Buffer(signal_hash_raw.slice(2), 'hex');
|
||||
const signal_hash = beBuff2int(signal_hash_raw_bytes.slice(0, 31));
|
||||
|
||||
const accounts = await web3.eth.getAccounts();
|
||||
|
||||
const msg = mimcsponge.multiHash([bigInt(external_nullifier), bigInt(signal_hash)]);
|
||||
const signature = eddsa.signMiMCSponge(prvKey, msg);
|
||||
|
||||
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
|
||||
|
||||
const identity_nullifier = bigInt('230');
|
||||
|
||||
const storage_path = '/tmp/rocksdb_semaphore_test';
|
||||
if (fs.existsSync(storage_path)) {
|
||||
del.sync(storage_path, { force: true });
|
||||
}
|
||||
const default_value = '0';
|
||||
const storage = new RocksDb(storage_path);
|
||||
const memStorage = new MemStorage();
|
||||
const hasher = new MimcSpongeHasher();
|
||||
const prefix = 'semaphore';
|
||||
const tree = new MerkleTree(
|
||||
prefix,
|
||||
storage,
|
||||
hasher,
|
||||
20,
|
||||
default_value,
|
||||
);
|
||||
|
||||
const memTree = new MerkleTree(
|
||||
prefix,
|
||||
memStorage,
|
||||
hasher,
|
||||
20,
|
||||
default_value,
|
||||
);
|
||||
|
||||
|
||||
const identity_commitment = pedersenHash([bigInt(circomlib.babyJub.mulPointEscalar(pubKey, 8)[0]), bigInt(identity_nullifier)]);
|
||||
|
||||
const semaphore = await Semaphore.deployed();
|
||||
const receipt = await semaphore.insertIdentity(identity_commitment.toString());
|
||||
assert.equal(receipt.logs[0].event, 'LeafAdded');
|
||||
const next_index = parseInt(receipt.logs[0].args.leaf_index.toString());
|
||||
|
||||
await tree.update(0, identity_commitment1.toString());
|
||||
await memTree.update(0, identity_commitment1.toString());
|
||||
await tree.update(next_index, identity_commitment.toString());
|
||||
await memTree.update(next_index, identity_commitment.toString());
|
||||
const identity_path = await tree.path(next_index);
|
||||
const mem_identity_path = await memTree.path(next_index);
|
||||
|
||||
assert.equal(JSON.stringify(identity_path), JSON.stringify(mem_identity_path))
|
||||
|
||||
const identity_path_elements = identity_path.path_elements;
|
||||
const identity_path_index = identity_path.path_index;
|
||||
|
||||
//console.log(identity_commitment.toString());
|
||||
//console.log(identity_path_elements, identity_path_index, identity_path.root);
|
||||
|
||||
const w = circuit.calculateWitness({
|
||||
'identity_pk[0]': pubKey[0],
|
||||
'identity_pk[1]': pubKey[1],
|
||||
'auth_sig_r[0]': signature.R8[0],
|
||||
'auth_sig_r[1]': signature.R8[1],
|
||||
auth_sig_s: signature.S,
|
||||
signal_hash,
|
||||
external_nullifier,
|
||||
identity_nullifier,
|
||||
identity_path_elements,
|
||||
identity_path_index,
|
||||
});
|
||||
|
||||
const root = w[circuit.getSignalIdx('main.root')];
|
||||
const nullifiers_hash = w[circuit.getSignalIdx('main.nullifiers_hash')];
|
||||
assert(circuit.checkWitness(w));
|
||||
assert.equal(w[circuit.getSignalIdx('main.root')].toString(), identity_path.root);
|
||||
|
||||
//console.log(w[circuit.getSignalIdx('main.root')]);
|
||||
|
||||
/*
|
||||
console.log(tree[0]);
|
||||
console.log(w[circuit.getSignalIdx('main.signal_hash')]);
|
||||
console.log(w[circuit.getSignalIdx('main.external_nullifier')]);
|
||||
console.log(w[circuit.getSignalIdx('main.root')]);
|
||||
console.log(w[circuit.getSignalIdx('main.nullifiers_hash')]);
|
||||
console.log(w[circuit.getSignalIdx('main.identity_commitment.out')]);
|
||||
*/
|
||||
|
||||
const vk_proof = fs.readFileSync(path.join(__dirname,'../../build/proving_key.bin'));
|
||||
const witness_bin = proof_util.convertWitness(snarkjs.stringifyBigInts(w));
|
||||
const publicSignals = w.slice(1, circuit.nPubInputs + circuit.nOutputs+1);
|
||||
const proof = await proof_util.prove(witness_bin.buffer, vk_proof.buffer);
|
||||
let failed = false;
|
||||
let reason = '';
|
||||
|
||||
await semaphore.transferOwnership(accounts[1]);
|
||||
assert.equal(await semaphore.owner(), accounts[1]);
|
||||
|
||||
failed = false;
|
||||
try {
|
||||
await semaphore.broadcastSignal(
|
||||
|
||||
signal_to_contract,
|
||||
[ proof.pi_a[0].toString(), proof.pi_a[1].toString() ],
|
||||
[ [ proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString() ], [ proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString() ] ],
|
||||
[ proof.pi_c[0].toString(), proof.pi_c[1].toString() ],
|
||||
[ publicSignals[0].toString(), publicSignals[1].toString(), publicSignals[2].toString(), publicSignals[3].toString() ],
|
||||
);
|
||||
} catch(e) {
|
||||
failed = true;
|
||||
reason = e.reason
|
||||
}
|
||||
assert.equal(failed, true);
|
||||
assert.equal(reason, 'Semaphore: broadcast permission denied');
|
||||
|
||||
await semaphore.setPermissioning(false, { from: accounts[1] });
|
||||
|
||||
const a = [ proof.pi_a[0].toString(), proof.pi_a[1].toString() ]
|
||||
const b = [ [ proof.pi_b[0][1].toString(), proof.pi_b[0][0].toString() ], [ proof.pi_b[1][1].toString(), proof.pi_b[1][0].toString() ] ]
|
||||
const c = [ proof.pi_c[0].toString(), proof.pi_c[1].toString() ]
|
||||
const input = [ publicSignals[0].toString(), publicSignals[1].toString(), publicSignals[2].toString(), publicSignals[3].toString() ]
|
||||
|
||||
const check = await semaphore.preBroadcastCheck(a, b, c, input, bigInt(signal_hash).toString())
|
||||
assert.isTrue(check)
|
||||
|
||||
const broadcastTx = await semaphore.broadcastSignal(
|
||||
signal_to_contract,
|
||||
a, b, c, input
|
||||
);
|
||||
|
||||
assert.isTrue(broadcastTx.receipt.status)
|
||||
|
||||
/*
|
||||
const evs = await semaphore.getPastEvents('allEvents', {
|
||||
fromBlock: 0,
|
||||
toBlock: 'latest'
|
||||
});
|
||||
console.log(evs);
|
||||
*/
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user