Circuit updates (#8)

* feat: moves code to use mimcsponge, uses blake2s for commitment

* fix: makes ci timeout larger

* fix: updates sbmtjs's reference to circomlib to mimcsponge

* fix: replaces rinkeby sponge address

* fix: moves to a wasm compatible blake2 library

* fix: attempts removing blake2.wasm from webpack

* fix: moves to native js blake2

* fix: fixes webpack config to remove blake2

* fix: makes generate_identity sync

* fix: changes mimc7 to mimcsponge in client_web

* fix: updates websnark for smaller memory

* fix: updates websnark for smaller memory

* fix: adds enlarged heap for compilation

* fix: adds enlarged heap for compilation

* fix: makes tests pass

* fix: makes MerkleTree use mimc sponge

* feat: adds position to the nullifiers hash

* feat: makes identity_nullifier 256 bits again, and makes external_nullifier 224 bits to make room for position

* fix: makes sure that we index identity_path_index correctly in hash

* feat: moves back to iden3's websnark version

* feat: uses (8*pk).x for identity commitment

* fix: changes identity_commitment to match circuit

* fix: fixes contract end-to-end test to use new primitives

* fix: ci uses local version of zkp-sbmtjs

* feat: updates package versions

* fix: removes npm link from ci

* fix: changes tests to use MimcSpongeHasher

* feat: attempts storing artifacts

* feat: updates rinkeby contract address

* feat: updates package-lock
This commit is contained in:
Kobi Gurkan
2019-06-26 18:36:34 +03:00
committed by GitHub
parent 96923d2ede
commit 63ff1f5fa1
28 changed files with 277 additions and 172 deletions

View File

@@ -38,4 +38,8 @@ jobs:
- run:
name: end-to-end
command: cd scripts && ./ci.sh
no_output_timeout: 30m
no_output_timeout: 600m
- store_artifacts:
path: ~/semaphore/semaphorejs/build

View File

@@ -1,6 +1,6 @@
{
"name": "zkp-sbmtjs",
"version": "0.2.0",
"version": "0.2.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -340,6 +340,7 @@
"requires": {
"blake-hash": "^1.1.0",
"snarkjs": "0.1.11",
"typedarray-to-buffer": "^3.1.5",
"web3": "^1.0.0-beta.36"
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "zkp-sbmtjs",
"version": "0.2.1",
"version": "0.3.0",
"description": "Storage-backed Merkle tree",
"main": "index.js",
"scripts": {
@@ -16,7 +16,7 @@
"await-lock": "^1.1.3",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"circomlib": "git+https://github.com/kobigurk/circomlib.git",
"circomlib": "git+https://github.com/kobigurk/circomlib.git#f4a7f30faa9867be77522aea42332585338c235d",
"del": "^4.0.0",
"level-rocksdb": "^3.0.1",
"snarkjs": "^0.1.11",

View File

@@ -0,0 +1,33 @@
/*
* sbmtjs - Storage-backed Merkle tree
* Copyright (C) 2019 Kobi Gurkan <kobigurk@gmail.com>
*
* This file is part of sbmtjs.
*
* sbmtjs is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* sbmtjs is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with sbmtjs. If not, see <http://www.gnu.org/licenses/>.
*/
const circomlib = require('circomlib');
const mimcsponge = circomlib.mimcsponge;
const snarkjs = require('snarkjs');
const bigInt = snarkjs.bigInt;
class MimcSpongeHasher {
hash(level, left, right) {
return mimcsponge.multiHash([bigInt(left), bigInt(right)]).toString();
}
}
module.exports = MimcSpongeHasher;

View File

@@ -21,7 +21,7 @@
pragma solidity >=0.4.21;
library MiMC {
function MiMCpe7(uint256 in_x, uint256 in_k) pure public returns (uint256 out_x);
function MiMCSponge(uint256 in_xL, uint256 in_xR, uint256 in_k) pure public returns (uint256 xL, uint256 xR);
}
contract MerkleTree {
@@ -52,12 +52,16 @@ contract MerkleTree {
function HashLeftRight(uint256 left, uint256 right) public pure returns (uint256 mimc_hash) {
uint256 k = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 r0 = 0;
uint256 h0 = MiMC.MiMCpe7(left, r0);
uint256 r1 = addmod(r0, addmod(left, h0, k), k);
uint256 h1 = MiMC.MiMCpe7(right, r1);
uint256 r2 = addmod(r1, addmod(right, h1, k), k);
mimc_hash = r2;
uint256 R = 0;
uint256 C = 0;
R = addmod(R, left, k);
(R, C) = MiMC.MiMCSponge(R, C, 0);
R = addmod(R, right, k);
(R, C) = MiMC.MiMCSponge(R, C, 0);
mimc_hash = R;
}
function insert(uint256 leaf) internal {
@@ -90,34 +94,14 @@ contract MerkleTree {
emit LeafAdded(leaf, leaf_index);
}
function update(uint256 old_leaf, uint256 leaf, uint32 leaf_index, uint256[] memory old_path, uint256[] memory path) internal {
function update(uint256 leaf, uint32 leaf_index, uint256[] memory path) internal {
uint32 current_index = leaf_index;
uint256 current_level_hash = old_leaf;
uint256 current_level_hash = leaf;
uint256 left;
uint256 right;
for (uint8 i = 0; i < levels; i++) {
if (current_index % 2 == 0) {
left = current_level_hash;
right = old_path[i];
} else {
left = old_path[i];
right = current_level_hash;
}
current_level_hash = HashLeftRight(left, right);
current_index /= 2;
}
require(root == current_level_hash);
current_index = leaf_index;
current_level_hash = leaf;
for (i = 0; i < levels; i++) {
if (current_index % 2 == 0) {
left = current_level_hash;
right = path[i];
@@ -131,8 +115,6 @@ contract MerkleTree {
current_index /= 2;
}
root = current_level_hash;
emit LeafUpdated(leaf, leaf_index);
}
}

View File

@@ -21,7 +21,7 @@
pragma solidity >=0.4.21;
library MiMC {
function MiMCpe7(uint256 in_x, uint256 in_k) pure public returns (uint256 out_x);
function MiMCSponge(uint256 in_xL, uint256 in_xR, uint256 in_k) pure public returns (uint256 xL, uint256 xR);
}
contract MultipleMerkleTree {
@@ -61,12 +61,16 @@ contract MultipleMerkleTree {
function HashLeftRight(uint256 left, uint256 right) public pure returns (uint256 mimc_hash) {
uint256 k = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
uint256 r0 = 0;
uint256 h0 = MiMC.MiMCpe7(left, r0);
uint256 r1 = addmod(r0, addmod(left, h0, k), k);
uint256 h1 = MiMC.MiMCpe7(right, r1);
uint256 r2 = addmod(r1, addmod(right, h1, k), k);
mimc_hash = r2;
uint256 R = 0;
uint256 C = 0;
R = addmod(R, left, k);
(R, C) = MiMC.MiMCSponge(R, C, 0);
R = addmod(R, right, k);
(R, C) = MiMC.MiMCSponge(R, C, 0);
mimc_hash = R;
}
function insert(uint8 tree_index, uint256 leaf) internal {

View File

@@ -20,10 +20,10 @@
const path = require('path');
const mimcGenContract = require('circomlib/src/mimc_gencontract.js');
const mimcGenContract = require('circomlib/src/mimcsponge_gencontract.js');
const Artifactor = require('truffle-artifactor');
const SEED = 'mimc';
const SEED = 'mimcsponge';
module.exports = function(deployer) {
@@ -34,7 +34,7 @@ module.exports = function(deployer) {
await artifactor.save({
contractName: mimcContractName,
abi: mimcGenContract.abi,
unlinked_binary: mimcGenContract.createCode(SEED, 91),
unlinked_binary: mimcGenContract.createCode(SEED, 220),
})
.then(async () => {
const MiMC = artifacts.require(mimcContractName);

View File

@@ -1,6 +1,6 @@
{
"name": "zkp-semaphorejs",
"version": "0.2.1",
"version": "0.3.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -1302,6 +1302,11 @@
"nan": "^2.2.1"
}
},
"blakejs": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz",
"integrity": "sha1-ad+S75U6qIylGjLfarHFShVfx6U="
},
"block-stream": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
@@ -1757,8 +1762,8 @@
}
},
"circomlib": {
"version": "git+https://github.com/iden3/circomlib.git#d91afa804ace6481f4468eebc0bf55229771e24c",
"from": "git+https://github.com/iden3/circomlib.git#d91afa804ace6481f4468eebc0bf55229771e24c",
"version": "git+https://github.com/kobigurk/circomlib.git#f4a7f30faa9867be77522aea42332585338c235d",
"from": "git+https://github.com/kobigurk/circomlib.git#f4a7f30faa9867be77522aea42332585338c235d",
"requires": {
"blake-hash": "^1.1.0",
"snarkjs": "0.1.11",
@@ -12271,9 +12276,9 @@
}
},
"node-abi": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.8.0.tgz",
"integrity": "sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==",
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.9.0.tgz",
"integrity": "sha512-jmEOvv0eanWjhX8dX1pmjb7oJl1U1oR4FOh0b2GnvALwSYoOdU7sj+kLDSAyjo4pfC9aj/IxkloxdLJQhSSQBA==",
"requires": {
"semver": "^5.4.1"
}
@@ -16461,8 +16466,8 @@
}
},
"websnark": {
"version": "git+https://github.com/kobigurk/websnark.git#30a4b3d7fba78421aaf9e6b11e6c8b399eacced2",
"from": "git+https://github.com/kobigurk/websnark.git#30a4b3d7fba78421aaf9e6b11e6c8b399eacced2",
"version": "git+https://github.com/iden3/websnark.git#3b6cf0c77e48ab0867a2d710c0b35794b16bde7d",
"from": "git+https://github.com/iden3/websnark.git",
"requires": {
"big-integer": "^1.6.42"
}
@@ -16752,43 +16757,18 @@
}
},
"zkp-sbmtjs": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/zkp-sbmtjs/-/zkp-sbmtjs-0.2.1.tgz",
"integrity": "sha512-v2xSE1Wm3qA+hyh3g+wCEQNM6xGH3q9FauZDGd9q6NI0h3z07GuVADpEVNYs2BEKj5t8ZrGuJLGhpFaMALcZCg==",
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/zkp-sbmtjs/-/zkp-sbmtjs-0.3.0.tgz",
"integrity": "sha512-0x+o+JEJBFDTnupf9H2RyC2JufEA7OgRJfZ8unzqq2/fjgmMzZiai1T7+McucyEvpuE76hMvVwGmFy8ZFBUa+A==",
"requires": {
"await-lock": "^1.1.3",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"circomlib": "git+https://github.com/kobigurk/circomlib.git",
"circomlib": "git+https://github.com/kobigurk/circomlib.git#f4a7f30faa9867be77522aea42332585338c235d",
"del": "^4.0.0",
"level-rocksdb": "^3.0.1",
"snarkjs": "^0.1.11",
"uuid": "^3.3.2"
},
"dependencies": {
"circomlib": {
"version": "git+https://github.com/kobigurk/circomlib.git#b254beaa50db7857ff6d8163c24d579c3f338f4b",
"from": "git+https://github.com/kobigurk/circomlib.git",
"requires": {
"blake-hash": "^1.1.0",
"snarkjs": "0.1.11",
"web3": "^1.0.0-beta.36"
},
"dependencies": {
"snarkjs": {
"version": "0.1.11",
"resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.11.tgz",
"integrity": "sha512-NoMNn03Uwbt18V340ZlHSZscyfIu8F6fMOL7LT9Xr1zQY/nmzScM8442ATyJfzSI5bDTAz1QQGbCerP2BCKljA==",
"requires": {
"big-integer": "^1.6.35",
"chai": "^4.1.2",
"escape-string-regexp": "^1.0.5",
"eslint": "^5.3.0",
"yargs": "^12.0.2"
}
}
}
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "zkp-semaphorejs",
"version": "0.2.5",
"version": "0.3.0",
"description": "Zero-knowledge signaling on Ethereum",
"main": "index.js",
"scripts": {
@@ -18,8 +18,9 @@
"url": "https://github.com/kobigurk/semaphore.git"
},
"dependencies": {
"blakejs": "^1.1.0",
"circom": "0.0.27",
"circomlib": "git+https://github.com/iden3/circomlib.git#d91afa804ace6481f4468eebc0bf55229771e24c",
"circomlib": "git+https://github.com/kobigurk/circomlib.git#f4a7f30faa9867be77522aea42332585338c235d",
"cors": "^2.8.5",
"del": "^4.1.0",
"file-saver": "^2.0.1",
@@ -39,7 +40,7 @@
"webpack": "^4.30.0",
"websnark": "git+https://github.com/iden3/websnark.git",
"winston": "^3.2.1",
"zkp-sbmtjs": "^0.2.1"
"zkp-sbmtjs": "^0.3.0"
},
"devDependencies": {
"npm-update-git-deps": "^1.2.4",

View File

@@ -24,6 +24,7 @@ echo "Working directory: `pwd`"
./do_setup.sh
./convert_to_wasm.sh
./build_verifier.sh
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/truffle migrate --reset

View File

@@ -22,5 +22,6 @@
mkdir -p ../build
cd ../build
export NODE_OPTIONS=--max-old-space-size=4096
npx circom ../snark/semaphore.circom

View File

@@ -19,5 +19,6 @@
# along with semaphorejs. If not, see <http://www.gnu.org/licenses/>.
#
export NODE_OPTIONS=--max-old-space-size=4096
node ../node_modules/websnark/tools/buildpkey.js -i ../build/proving_key.json -o ../build/proving_key.bin

View File

@@ -22,5 +22,6 @@
mkdir -p ../build
cd ../build
export NODE_OPTIONS=--max-old-space-size=4096
npx snarkjs setup --protocol groth

View File

@@ -63,6 +63,7 @@ CREATION_HASH=`cat ../build/contracts/Semaphore.json | jq ".networks.\"${CHAIN_I
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 CONFIG_ENV=true BASE_DIR=../.. npx semaphorejs-client generate_identity
IDENTITY_COMMITMENT=`cat ./semaphore_identity.json | jq '.identity_commitment' | sed 's/"//g'`
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" \; \

View File

@@ -122,10 +122,12 @@ template Blake2sCompression(t, f) {
}
signal v_pass_1[16][32];
component v_12_xor = Uint32Xor();
component v_13_xor = Uint32Xor();
component v_14_xor = Uint32Xor();
for (var i = 0; i < 16; i++) {
if (i == 12) {
component v_12_xor = Uint32Xor();
for (var j = 0; j < 32; j++) {
v_12_xor.a_bits[j] <== v_h[i][j];
v_12_xor.b_bits[j] <== (t >> j) & 1;
@@ -134,7 +136,6 @@ template Blake2sCompression(t, f) {
v_pass_1[i][j] <== v_12_xor.out_bits[j];
}
} else if (i == 13) {
component v_13_xor = Uint32Xor();
for (var j = 0; j < 32; j++) {
v_13_xor.a_bits[j] <== v_h[i][j];
v_13_xor.b_bits[j] <== (t >> (32 + j)) & 1;
@@ -142,14 +143,23 @@ template Blake2sCompression(t, f) {
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_13_xor.out_bits[j];
}
} else if ((i == 14) && (f == 1)) {
component v_14_xor = Uint32Xor();
for (var j = 0; j < 32; j++) {
v_14_xor.a_bits[j] <== v_h[i][j];
v_14_xor.b_bits[j] <== 1;
}
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_14_xor.out_bits[j];
} else if ((i == 14)) {
if (f == 1) {
for (var j = 0; j < 32; j++) {
v_14_xor.a_bits[j] <== v_h[i][j];
v_14_xor.b_bits[j] <== 1;
}
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_14_xor.out_bits[j];
}
} else {
for (var j = 0; j < 32; j++) {
v_14_xor.a_bits[j] <== v_h[i][j];
v_14_xor.b_bits[j] <== 0;
}
for (var j = 0; j < 32; j++) {
v_pass_1[i][j] <== v_h[i][j];
}
}
} else {
for (var j = 0; j < 32; j++) {
@@ -352,7 +362,7 @@ template Blake2s(n_bits, personalization) {
}
}
for (var l = 0; l < 16; l++) {
current_bit = 32*l + j;
current_bit = 512*i + 32*l + j;
if (current_bit < n_bits) {
compressions[i].in_m[l][j] <== in_bits[current_bit];
} else {

View File

@@ -1,6 +1,6 @@
include "../node_modules/circomlib/circuits/mimc.circom";
include "../node_modules/circomlib/circuits/mimcsponge.circom";
include "../node_modules/circomlib/circuits/bitify.circom";
include "../node_modules/circomlib/circuits/eddsamimc.circom";
include "../node_modules/circomlib/circuits/eddsamimcsponge.circom";
include "./blake2s/blake2s.circom";
template HashLeftRight(n_rounds) {
@@ -9,12 +9,12 @@ template HashLeftRight(n_rounds) {
signal output hash;
component hasher = MultiMiMC7(2, n_rounds);
left ==> hasher.in[0];
right ==> hasher.in[1];
component hasher = MiMCSponge(2, n_rounds, 1);
left ==> hasher.ins[0];
right ==> hasher.ins[1];
hasher.k <== 0;
hash <== hasher.out;
hash <== hasher.outs[0];
}
template Selector() {
@@ -51,7 +51,6 @@ template Semaphore(jubjub_field_size, n_levels, n_rounds) {
// mimc vector commitment
signal private input identity_pk[2];
signal private input identity_nullifier;
signal private input identity_r;
signal private input identity_path_elements[n_levels];
signal private input identity_path_index[n_levels];
@@ -59,20 +58,36 @@ template Semaphore(jubjub_field_size, n_levels, n_rounds) {
signal private input auth_sig_r[2];
signal private input auth_sig_s;
// get a prime subgroup element derived from identity_pk
component dbl1 = BabyDbl();
dbl1.x <== identity_pk[0];
dbl1.y <== identity_pk[1];
component dbl2 = BabyDbl();
dbl2.x <== dbl1.xout;
dbl2.y <== dbl1.yout;
component dbl3 = BabyDbl();
dbl3.x <== dbl2.xout;
dbl3.y <== dbl2.yout;
// mimc hash
signal output root;
signal output nullifiers_hash;
// END signals
component identity_commitment = MultiMiMC7(4, n_rounds);
component identity_nullifier_bits = Num2Bits(256);
identity_nullifier_bits.in <== identity_nullifier;
component identity_pk_0_bits = Num2Bits(256);
identity_pk_0_bits.in <== dbl3.xout;
component identity_commitment = Blake2s(2*256, 0);
// BEGIN identity commitment
identity_commitment.in[0] <== identity_pk[0];
identity_commitment.in[1] <== identity_pk[1];
identity_commitment.in[2] <== identity_nullifier;
identity_commitment.in[3] <== identity_r;
identity_commitment.k <== 0;
for (var i = 0; i < 256; i++) {
identity_commitment.in_bits[i] <== identity_pk_0_bits.out[i];
identity_commitment.in_bits[i + 256] <== identity_nullifier_bits.out[i];
}
// END identity commitment
// BEGIN tree
@@ -90,7 +105,12 @@ template Semaphore(jubjub_field_size, n_levels, n_rounds) {
selectors[i].right ==> hashers[i].right;
}
identity_commitment.out ==> selectors[0].input_elem;
component identity_commitment_num = Bits2Num(253);
for (var i = 0; i < 253; i++) {
identity_commitment_num.in[i] <== identity_commitment.out[i];
}
identity_commitment_num.out ==> selectors[0].input_elem;
for (var i = 1; i < n_levels; i++) {
hashers[i-1].hash ==> selectors[i].input_elem;
@@ -100,15 +120,21 @@ template Semaphore(jubjub_field_size, n_levels, n_rounds) {
// END tree
// BEGIN nullifiers
component identity_nullifier_bits = Num2Bits(254);
identity_nullifier_bits.in <== identity_nullifier;
component external_nullifier_bits = Num2Bits(254);
component external_nullifier_bits = Num2Bits(256);
external_nullifier_bits.in <== external_nullifier;
component nullifiers_hasher = Blake2s(508, 248018401820981);
for (var i = 0; i < 254; i++) {
component nullifiers_hasher = Blake2s(512, 0);
for (var i = 0; i < 256; i++) {
nullifiers_hasher.in_bits[i] <== identity_nullifier_bits.out[i];
nullifiers_hasher.in_bits[254 + i] <== external_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;
}
}
}
component nullifiers_hash_num = Bits2Num(253);
@@ -121,20 +147,20 @@ template Semaphore(jubjub_field_size, n_levels, n_rounds) {
// END nullifiers
// BEGIN verify sig
component msg_hasher = MultiMiMC7(3, n_rounds);
msg_hasher.in[0] <== external_nullifier;
msg_hasher.in[1] <== signal_hash;
msg_hasher.in[2] <== broadcaster_address;
component msg_hasher = MiMCSponge(3, n_rounds, 1);
msg_hasher.ins[0] <== external_nullifier;
msg_hasher.ins[1] <== signal_hash;
msg_hasher.ins[2] <== broadcaster_address;
msg_hasher.k <== 0;
component sig_verifier = EdDSAMiMCVerifier();
component sig_verifier = EdDSAMiMCSpongeVerifier();
1 ==> sig_verifier.enabled;
identity_pk[0] ==> sig_verifier.Ax;
identity_pk[1] ==> sig_verifier.Ay;
auth_sig_r[0] ==> sig_verifier.R8x;
auth_sig_r[1] ==> sig_verifier.R8y;
auth_sig_s ==> sig_verifier.S;
msg_hasher.out ==> sig_verifier.M;
msg_hasher.outs[0] ==> sig_verifier.M;
// END verify sig
}

View File

@@ -1,3 +1,3 @@
include "./semaphore-base.circom";
component main = Semaphore(251, 20, 91);
component main = Semaphore(251, 20, 220);

View File

@@ -35,7 +35,6 @@ const circomlib = require('circomlib');
const bigInt = snarkjs.bigInt;
const eddsa = circomlib.eddsa;
const mimc7 = circomlib.mimc7;
const groth = snarkjs.groth;

View File

@@ -21,7 +21,7 @@
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;
@@ -32,7 +32,7 @@ const circomlib = require('circomlib');
const bigInt = snarkjs.bigInt;
const eddsa = circomlib.eddsa;
const mimc7 = circomlib.mimc7;
const mimcsponge = circomlib.mimcsponge;
const proof_util = require('../util');
@@ -42,6 +42,20 @@ const Web3 = require('web3');
let logger;
/* uint8array to hex */
function hex(byteArray) {
return Array.prototype.map.call(byteArray, function(byte) {
return ('0' + (byte & 0xFF).toString(16)).slice(-2);
}).join('');
}
const cutDownBits = function(b, bits) {
let mask = bigInt(1);
mask = mask.shl(bits).sub(bigInt(1));
return b.and(mask);
}
beBuff2int = function(buff) {
let res = bigInt.zero;
for (let i=0; i<buff.length; i++) {
@@ -74,10 +88,12 @@ class SemaphoreClient {
const pubKey = eddsa.prv2pub(prvKey);
this.identity_nullifier = loaded_identity.identity_nullifier;
this.identity_r = loaded_identity.identity_r;
this.identity_commitment = mimc7.multiHash([bigInt(pubKey[0]), bigInt(pubKey[1]), bigInt(this.identity_nullifier), bigInt(this.identity_r)]);
logger.verbose(`identity_commitment: ${this.identity_commitment}`);
const identity_commitment_ints = [bigInt(circomlib.babyJub.mulPointEscalar(pubKey, 8)[0]), bigInt(this.identity_nullifier)];
const identity_commitment_buffer = Buffer.concat(
identity_commitment_ints.map(x => x.leInt2Buff(32))
);
this.identity_commitment_buffer = identity_commitment_buffer;
this.web3 = new Web3(node_url);
this.web3.eth.transactionConfirmationBlocks = transaction_confirmation_blocks;
@@ -98,6 +114,13 @@ class SemaphoreClient {
async broadcast_signal(signal_str) {
logger.info(`broadcasting signal ${signal_str}`);
const identity_commitment_digest = blake2.blake2sHex(this.identity_commitment_buffer);
logger.verbose(`identity_commitment digest: ${identity_commitment_digest}`);
const identity_commitment_uncut = beBuff2int(new Buffer(identity_commitment_digest, 'hex'));
logger.verbose(`identity_commitment_uncut: ${identity_commitment_uncut}`);
this.identity_commitment = cutDownBits(identity_commitment_uncut, 253);
logger.verbose(`identity_commitment: ${this.identity_commitment}`);
//const prvKey = Buffer.from('0001020304050607080900010203040506070809000102030405060708090001', 'hex');
const prvKey = Buffer.from(this.private_key, 'hex');
@@ -115,13 +138,12 @@ class SemaphoreClient {
const signal_hash = beBuff2int(signal_hash_raw.slice(0, 31));
const broadcaster_address = bigInt(this.broadcaster_address);
const msg = mimc7.multiHash([external_nullifier, signal_hash, broadcaster_address]);
const signature = eddsa.signMiMC(prvKey, msg);
const msg = mimcsponge.multiHash([external_nullifier, signal_hash, broadcaster_address]);
const signature = eddsa.signMiMCSponge(prvKey, msg);
assert(eddsa.verifyMiMC(msg, signature, pubKey));
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
const identity_nullifier = this.identity_nullifier;
const identity_r = this.identity_r;
let identity_path;
if (this.identity_index === null) {
@@ -152,7 +174,6 @@ class SemaphoreClient {
signal_hash,
external_nullifier,
identity_nullifier,
identity_r,
identity_path_elements,
identity_path_index,
broadcaster_address,
@@ -165,6 +186,7 @@ class SemaphoreClient {
const root = w[this.circuit.getSignalIdx('main.root')];
const nullifiers_hash = w[this.circuit.getSignalIdx('main.nullifiers_hash')];
assert(this.circuit.checkWitness(w));
logger.info(`identity commitment from proof: ${w[this.circuit.getSignalIdx('main.identity_commitment_num.out')].toString()}`);
assert.equal(w[this.circuit.getSignalIdx('main.root')].toString(), identity_path.root);
logger.info(`generating proof (started at ${Date.now()})`);
@@ -253,21 +275,24 @@ class SemaphoreClient {
}
function generate_identity(logger) {
const private_key = crypto.randomBytes(32).toString('hex');
const prvKey = Buffer.from(private_key, 'hex');
const pubKey = eddsa.prv2pub(prvKey);
const identity_nullifier = '0x' + crypto.randomBytes(31).toString('hex');
const identity_r = '0x' + crypto.randomBytes(31).toString('hex');
logger.info(`generate identity from (private_key, public_key[0], public_key[1], identity_nullifier, identity_r): (${private_key}, ${pubKey[0]}, ${pubKey[1]}, ${identity_nullifier}, ${identity_r})`);
logger.info(`generate identity from (private_key, public_key[0], public_key[1], identity_nullifier): (${private_key}, ${pubKey[0]}, ${pubKey[1]}, ${identity_nullifier})`);
const identity_commitment = mimc7.multiHash([bigInt(pubKey[0]), bigInt(pubKey[1]), bigInt(identity_nullifier), bigInt(identity_r)]);
const identity_commitment_ints = [bigInt(circomlib.babyJub.mulPointEscalar(pubKey, 8)[0]), bigInt(identity_nullifier)];
const identity_commitment_buffer = Buffer.concat(
identity_commitment_ints.map(x => x.leInt2Buff(32))
);
const identity_commitment = cutDownBits(beBuff2int(new Buffer(blake2.blake2sHex(identity_commitment_buffer), 'hex')), 253);
logger.info(`identity_commitment : ${identity_commitment}`);
const generated_identity = {
private_key,
identity_nullifier: identity_nullifier.toString(),
identity_r: identity_r.toString(),
identity_commitment: identity_commitment.toString(),
};

View File

@@ -22,7 +22,7 @@
const RocksDb = require('zkp-sbmtjs/src/storage/rocksdb');
const MerkleTree = require('zkp-sbmtjs/src/tree');
const Mimc7Hasher = require('zkp-sbmtjs/src/hasher/mimc7');
const MimcSpongeHasher = require('zkp-sbmtjs/src/hasher/mimcsponge');
const Web3 = require('web3');
const SemaphoreABI = require('../../build/contracts/Semaphore.json');
@@ -284,7 +284,7 @@ class SemaphoreServer {
const prefix = 'semaphore';
const storage = new RocksDb(server_config.DB_PATH || 'semaphore_server.db');
const hasher = new Mimc7Hasher();
const hasher = new MimcSpongeHasher();
const default_value = '0';
const tree = new MerkleTree(

View File

@@ -24,7 +24,7 @@ const circomlib = require('circomlib');
const bigInt = snarkjs.bigInt;
const mimc7 = circomlib.mimc7;
const mimcsponge = circomlib.mimcsponge;
let build_merkle_tree_example = (n_levels, identity_commitment) => {
let current_index = 0;
@@ -33,7 +33,7 @@ let build_merkle_tree_example = (n_levels, identity_commitment) => {
let current_element = identity_commitment;
for (let i = 0; i < n_levels; i++) {
path_elements.push(bigInt(0));
current_element = mimc7.multiHash([ bigInt(current_element), bigInt(0) ]);
current_element = mimcsponge.multiHash([ bigInt(current_element), bigInt(0) ]);
path_index.push(current_index % 2);
current_index = Math.floor(current_index / 2);
@@ -60,7 +60,7 @@ let build_full_merkle_tree_example = (n_levels, index, identity_commitment) => {
tree_level.push(bigInt(j));
}
} else {
tree_level.push(mimc7.multiHash([ tree[i-1][2*j], tree[i-1][2*j+1] ]));
tree_level.push(mimcsponge.multiHash([ tree[i-1][2*j], tree[i-1][2*j+1] ]));
}
}
if (current_index % 2 == 0) {
@@ -73,7 +73,7 @@ let build_full_merkle_tree_example = (n_levels, index, identity_commitment) => {
current_index = Math.floor(current_index / 2);
}
const root = mimc7.multiHash([ tree[n_levels - 1][0], tree[n_levels - 1][1] ]);
const root = mimcsponge.multiHash([ tree[n_levels - 1][0], tree[n_levels - 1][1] ]);
return [root, tree, path_elements, path_index];
};

View File

@@ -29,7 +29,7 @@ const snarkjs = require('snarkjs');
const bigInt = snarkjs.bigInt;
const eddsa = require('circomlib/src/eddsa');
const mimc7 = require('circomlib/src/mimc7');
const mimcsponge = require('circomlib/src/mimcsponge');
const groth = snarkjs.groth;
@@ -136,7 +136,7 @@ const SemaphoreABI = require('../../build/contracts/Semaphore.json');
left = data.path.path_elements[i];
right = current_hash;
}
current_hash = bigInt(mimc7.multiHash([bigInt(left), bigInt(right)]));
current_hash = bigInt(mimcsponge.multiHash([bigInt(left), bigInt(right)]));
}
const expected_root = '0x' + current_hash.toString(16);
const signals_root = $('#s_signals_root').text();

View File

@@ -106,7 +106,7 @@
external_nullifier: 'auto',
semaphore_server_url: 'https://semaphore-server.kobi.one',
semaphore_server_address: '0x1929c15f4e818abf2549510622a50c440c474223',
semaphore_contract_address: '0xde297a7213b238F4a65F0a5B65F19C25c165dB38',
semaphore_contract_address: '0x7A1f706D1051b320E876088cB38E28001f3E6130',
from_private_key: '0x6738837df169e8d6ffc6e33a2947e58096d644fa4aa6d74358c8d9d57c12cd21',
from_address: '0x1929c15f4e818abf2549510622a50c440c474223',
chain_id: '4',

View File

@@ -33,15 +33,15 @@ describe("blake2s test", () => {
}).timeout(1000000);
it("Should run blake2s", async () => {
const cirDef = await compiler(path.join(__dirname, "blake2s_test.circom"));
fs.writeFileSync('blake2sdef.json', JSON.stringify(cirDef));
//const cirDef = JSON.parse(fs.readFileSync('blake2sdef.json'));
const cirDef = await compiler(path.join(__dirname, "blake2s_test.circom"));
fs.writeFileSync('blake2sdef.json', JSON.stringify(cirDef));
//const cirDef = JSON.parse(fs.readFileSync('blake2sdef.json'));
const circuit = new snarkjs.Circuit(cirDef);
console.log("Vars: "+circuit.nVars);
console.log("Constraints: "+circuit.nConstraints);
const bits = '00001000001110010010000001101001110100110001101010001101011010110001011101100001111111100000010000000000101010111001101001011110010100001111101011000010010000011010001111010100110100011001000110010001000000001001100011111011110010100000010000101011011000010000010111100110110011110111000100110110000101100100011011010010011010100110100101000010111010100000011101101011100000110111100011100000100000101110100011001101100001100100111011111111110011111101011110001011011001010011011100011000010111111001111010101010';
const bits = '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
const inputs = {};
for (let i = 0; i < bits.length; i++) {
inputs[`in_bits[${i}]`] = bigInt(bits[i]);
@@ -56,7 +56,7 @@ describe("blake2s test", () => {
coeff = coeff.shl(1);
}
console.log(`blake2s hash: 0x${result.toString(16)}`);
assert.equal(result.toString(16), '96dbac58ccef5c10e5226b1da1b20b44ea0ca52aa21abe80279a85686e838118');
assert.equal(result.toString(16), 'c8a7a6e87d10557e3214979b2dda05b16a0e845a7367bcacb1890bfed50aaa97');
for (let i = 0; i < witness.length; i++) {
//console.log(circuit.signalNames(i));

View File

@@ -1,6 +1,6 @@
include "../../../snark/blake2s/blake2s.circom";
component main = Blake2s(512, 248018401820981);
component main = Blake2s(1024, 0);
/*
49 * 2**(0*8) +
50 * 2**(1*8) +

View File

@@ -24,6 +24,7 @@ const snarkjs = require('snarkjs');
const compiler = require('circom');
const fs = require('fs');
const circomlib = require('circomlib');
const blake2 = require('blakejs');
const test_util = require('../../../src/test_util');
const build_merkle_tree_example = test_util.build_merkle_tree_example;
@@ -33,7 +34,24 @@ const assert = chai.assert;
const bigInt = snarkjs.bigInt;
const eddsa = circomlib.eddsa;
const mimc7 = circomlib.mimc7;
const mimcsponge = circomlib.mimcsponge;
const cutDownBits = function(b, bits) {
let mask = bigInt(1);
mask = mask.shl(bits).sub(bigInt(1));
return b.and(mask);
}
beBuff2int = function(buff) {
let res = bigInt.zero;
for (let i=0; i<buff.length; i++) {
const n = bigInt(buff[buff.length - i - 1]);
res = res.add(n.shl(i*8));
}
return res;
};
describe('circuit test', function () {
let circuit;
@@ -56,14 +74,20 @@ describe('circuit test', function () {
const signal_hash = bigInt('5');
const broadcaster_address = bigInt('0xBB9bc244D798123fDe783fCc1C72d3Bb8C189413');
const msg = mimc7.multiHash([bigInt(external_nullifier), bigInt(signal_hash), bigInt(broadcaster_address)]);
const signature = eddsa.signMiMC(prvKey, msg);
const msg = mimcsponge.multiHash([bigInt(external_nullifier), bigInt(signal_hash), bigInt(broadcaster_address)]);
const signature = eddsa.signMiMCSponge(prvKey, msg);
assert(eddsa.verifyMiMC(msg, signature, pubKey));
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
const identity_nullifier = bigInt('230');
const identity_r = bigInt('12311');
const tree = build_merkle_tree_example(20, mimc7.multiHash([bigInt(pubKey[0]), bigInt(pubKey[1]), bigInt(identity_nullifier), bigInt(identity_r)]));
const identity_commitment_ints = [bigInt(circomlib.babyJub.mulPointEscalar(pubKey, 8)[0]), bigInt(identity_nullifier)];
const identity_commitment_buffer = Buffer.concat(
identity_commitment_ints.map(x => x.leInt2Buff(32))
);
const identity_commitment = cutDownBits(beBuff2int(new Buffer(blake2.blake2sHex(identity_commitment_buffer), 'hex')), 253);
const tree = build_merkle_tree_example(20, identity_commitment);
const identity_path_elements = tree[1];
const identity_path_index = tree[2];
@@ -78,7 +102,6 @@ describe('circuit test', function () {
signal_hash,
external_nullifier,
identity_nullifier,
identity_r,
identity_path_elements,
identity_path_index,
broadcaster_address,

View File

@@ -32,7 +32,7 @@ const MerkleTreeTester = artifacts.require('MerkleTreeTester');
const RocksDb = require('zkp-sbmtjs/src/storage/rocksdb');
const MerkleTreeLib = require('zkp-sbmtjs/src/tree');
const Mimc7Hasher = require('zkp-sbmtjs/src/hasher/mimc7');
const MimcSpongeHasher = require('zkp-sbmtjs/src/hasher/mimcsponge');
@@ -44,7 +44,7 @@ contract('MerkleTree', () => {
}
const default_value = '4';
const storage = new RocksDb(storage_path);
const hasher = new Mimc7Hasher();
const hasher = new MimcSpongeHasher();
const prefix = 'semaphore';
const tree = new MerkleTreeLib(
prefix,
@@ -67,7 +67,7 @@ contract('MerkleTree', () => {
}
const default_value = '4';
const storage = new RocksDb(storage_path);
const hasher = new Mimc7Hasher();
const hasher = new MimcSpongeHasher();
const prefix = 'semaphore';
const tree = new MerkleTreeLib(
prefix,

View File

@@ -34,7 +34,7 @@ const test_util = require('../../src/test_util');
const bigInt = snarkjs.bigInt;
const eddsa = circomlib.eddsa;
const mimc7 = circomlib.mimc7;
const mimcsponge = circomlib.mimcsponge;
const groth = snarkjs.groth;
const {unstringifyBigInts} = require('snarkjs/src/stringifybigint.js');
@@ -47,7 +47,9 @@ const proof_util = require('../../src/util');
const RocksDb = require('zkp-sbmtjs/src/storage/rocksdb');
const MerkleTree = require('zkp-sbmtjs/src/tree');
const Mimc7Hasher = require('zkp-sbmtjs/src/hasher/mimc7');
const MimcSpongeHasher = require('zkp-sbmtjs/src/hasher/mimcsponge');
const blake2 = require('blakejs');
beBuff2int = function(buff) {
let res = bigInt.zero;
@@ -58,6 +60,12 @@ beBuff2int = function(buff) {
return res;
};
const cutDownBits = function(b, bits) {
let mask = bigInt(1);
mask = mask.shl(bits).sub(bigInt(1));
return b.and(mask);
}
contract('Semaphore', function () {
it('tests proof', async () => {
const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname,'../../build/circuit.json')).toString());
@@ -75,13 +83,12 @@ contract('Semaphore', function () {
const accounts = await web3.eth.getAccounts();
const broadcaster_address = bigInt(accounts[0].toString());
const msg = mimc7.multiHash([bigInt(external_nullifier), bigInt(signal_hash), bigInt(broadcaster_address)]);
const signature = eddsa.signMiMC(prvKey, msg);
const msg = mimcsponge.multiHash([bigInt(external_nullifier), bigInt(signal_hash), bigInt(broadcaster_address)]);
const signature = eddsa.signMiMCSponge(prvKey, msg);
assert(eddsa.verifyMiMC(msg, signature, pubKey));
assert(eddsa.verifyMiMCSponge(msg, signature, pubKey));
const identity_nullifier = bigInt('230');
const identity_r = bigInt('12311');
const storage_path = '/tmp/rocksdb_semaphore_test';
if (fs.existsSync(storage_path)) {
@@ -89,7 +96,7 @@ contract('Semaphore', function () {
}
const default_value = '0';
const storage = new RocksDb(storage_path);
const hasher = new Mimc7Hasher();
const hasher = new MimcSpongeHasher();
const prefix = 'semaphore';
const tree = new MerkleTree(
prefix,
@@ -99,7 +106,13 @@ contract('Semaphore', function () {
default_value,
);
const identity_commitment = mimc7.multiHash([bigInt(pubKey[0]), bigInt(pubKey[1]), bigInt(identity_nullifier), bigInt(identity_r)]);
const identity_commitment_ints = [bigInt(circomlib.babyJub.mulPointEscalar(pubKey, 8)[0]), bigInt(identity_nullifier)];
const identity_commitment_buffer = Buffer.concat(
identity_commitment_ints.map(x => x.leInt2Buff(32))
);
const identity_commitment = cutDownBits(beBuff2int(new Buffer(blake2.blake2sHex(identity_commitment_buffer), 'hex')), 253);
const semaphore = await Semaphore.deployed();
const receipt = await semaphore.insertIdentity(identity_commitment.toString());
assert.equal(receipt.logs[0].event, 'LeafAdded');
@@ -124,7 +137,6 @@ contract('Semaphore', function () {
signal_hash,
external_nullifier,
identity_nullifier,
identity_r,
identity_path_elements,
identity_path_index,
broadcaster_address,