Skip to content

Commit

Permalink
fourth exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
therealyingtong committed Jun 13, 2019
1 parent 5804fe2 commit 906cb15
Show file tree
Hide file tree
Showing 11 changed files with 579 additions and 5 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ input.json
proof.json
public.json
circuit.json
package-lock.json
package-lock.json
debug.js
9 changes: 6 additions & 3 deletions 2_verify_eddsa/sample_circuit.circom
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ include "../circomlib/circuits/eddsamimc.circom";
include "../circomlib/circuits/mimc.circom";

template VerifyEdDSAMiMC(k) {

// k is length of preimage

signal input from_x;
signal input from_y;
signal input R8x;
Expand All @@ -10,9 +13,9 @@ template VerifyEdDSAMiMC(k) {
signal private input preimage[k];

component M = MultiMiMC7(k,91);
M.in[0] <== preimage[0];
M.in[1] <== preimage[1];
M.in[2] <== preimage[2];
for (var i = 0; i < k; i++){
M.in[i] <== preimage[i];
}

component verifier = EdDSAMiMCVerifier();
verifier.enabled <== 1;
Expand Down
33 changes: 33 additions & 0 deletions 3_verify_merkle/sample_leaf_existence.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
include "./get_merkle_root.circom";
include "../circomlib/circuits/mimc.circom";

// checks for existence of leaf in tree of depth k

template LeafExistence(k, l){
// k is depth of tree
// l is length of preimage of leaf

signal private input preimage[l];
signal input root;
signal input paths2_root_pos[k];
signal input paths2_root[k];

component leaf = MultiMiMC7(l,91);
for (var i = 0; i < l; i++){
leaf.in[i] <== preimage[i];
}

component computed_root = GetMerkleRoot(k);
computed_root.leaf <== leaf.out;

for (var w = 0; w < k; w++){
computed_root.paths2_root[w] <== paths2_root[w];
computed_root.paths2_root_pos[w] <== paths2_root_pos[w];
}

// equality constraint: input tx root === computed tx root
root === computed_root.out;

}

component main = LeafExistence(2, 3);
192 changes: 192 additions & 0 deletions 4_single_tx/MiMCMerkle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
const mimcjs = require("../circomlib/src/mimc7.js");
const bigInt = require("snarkjs").bigInt;


module.exports = {

// cache empty tree values
getZeroCache: function(zeroLeafHash, depth){
var zeroCache = new Array(depth)
zeroCache[0] = zeroLeafHash
for (var i = 1; i < depth; i++){
zeroCache[i] = mimcjs.multiHash([zeroCache[i-1],zeroCache[i-1]])
}
return zeroCache
},

getProof: function(leafIdx, tree, leaves){
depth = tree.length;
proofIdx = module.exports.proofIdx(leafIdx, depth);
proof = new Array(depth);
proof[0] = leaves[proofIdx[0]]
for (i = 1; i < depth; i++){
proof[i] = tree[depth - i][proofIdx[i]]
}
return proof;
},

getProofEmpty: function(height, zeroCache){
const depth = zeroCache.length
if (height < depth){
return zeroCache.slice(height, depth + 1)
} else {
return []
}
},

verifyProof: function(leaf, idx, proof, root){
computed_root = module.exports.rootFromLeafAndPath(leaf, idx, proof)
return (root == computed_root)
},

rootFromLeafAndPath: function(leaf, idx, merkle_path){
if (merkle_path.length > 0){
const depth = merkle_path.length
const merkle_path_pos = module.exports.idxToBinaryPos(idx, depth)
var root = new Array(depth);
left = bigInt(leaf) - bigInt(merkle_path_pos[0])*(bigInt(leaf) - bigInt(merkle_path[0]));
right = bigInt(merkle_path[0]) - bigInt(merkle_path_pos[0])*(bigInt(merkle_path[0]) - bigInt(leaf));
root[0] = mimcjs.multiHash([left, right]);
var i;
for (i = 1; i < depth; i++) {
left = root[i-1] - bigInt(merkle_path_pos[i])*(root[i-1] - bigInt(merkle_path[i]));
right = bigInt(merkle_path[i]) - bigInt(merkle_path_pos[i])*(bigInt(merkle_path[i]) - root[i-1]);
root[i] = mimcjs.multiHash([left, right]);
}

return root[depth - 1];
} else {
return leaf
}

},

// fill a leaf array with zero leaves until it is a power of 2
padLeafArray: function(leafArray, zeroLeaf, fillerLength){
if (Array.isArray(leafArray)){
var arrayClone = leafArray.slice(0)
const nearestPowerOfTwo = Math.ceil(module.exports.getBase2Log(leafArray.length))
const diff = fillerLength || 2**nearestPowerOfTwo - leafArray.length
for (var i = 0; i < diff; i++){
arrayClone.push(zeroLeaf)
}
return arrayClone
} else {
console.log("please enter pubKeys as an array")
}
},


// fill a leaf hash array with zero leaf hashes until it is a power of 2
padLeafHashArray: function(leafHashArray, zeroLeafHash, fillerLength){
if (Array.isArray(leafHashArray)){
var arrayClone = leafHashArray.slice(0)
const nearestPowerOfTwo = Math.ceil(module.exports.getBase2Log(leafHashArray.length))
const diff = fillerLength || 2**nearestPowerOfTwo - leafHashArray.length
for (var i = 0; i < diff; i++){
arrayClone.push(zeroLeafHash)
}
return arrayClone
} else {
console.log("please enter pubKeys as an array")
}
},

treeFromLeafArray: function(leafArray){
depth = module.exports.getBase2Log(leafArray.length);
tree = Array(depth);

tree[depth - 1] = module.exports.pairwiseHash(leafArray)

for (j = depth - 2; j >= 0; j--){
tree[j] = module.exports.pairwiseHash(tree[j+1])
}

// return treeRoot[depth-1]
return tree
},

rootFromLeafArray: function(leafArray){
return module.exports.treeFromLeafArray(leafArray)[0][0]
},

pairwiseHash: function(array){
if (array.length % 2 == 0){
arrayHash = []
for (i = 0; i < array.length; i = i + 2){
arrayHash.push(mimcjs.multiHash(
[array[i].toString(),array[i+1].toString()]
))
}
return arrayHash
} else {
console.log('array must have even number of elements')
}
},

generateMerklePosArray: function(depth){
merklePosArray = [];
for (i = 0; i < 2**depth; i++){
binPos = module.exports.idxToBinaryPos(i, depth)
merklePosArray.push(binPos)
}
return merklePosArray;
},

generateMerkleProofArray: function(txTree, txLeafHashes){
txProofs = new Array(txLeafHashes.length)
for (jj = 0; jj < txLeafHashes.length; jj++){
txProofs[jj] = module.exports.getProof(jj, txTree, txLeafHashes)
}
return txProofs;
},

///////////////////////////////////////////////////////////////////////
// HELPER FUNCTIONS
///////////////////////////////////////////////////////////////////////

getBase2Log: function(y){
return Math.log(y) / Math.log(2);
},

binaryPosToIdx: function(binaryPos){
var idx = 0;
for (i = 0; i < binaryPos.length; i++){
idx = idx + binaryPos[i]*(2**i)
}
return idx;
},

idxToBinaryPos: function(idx, binLength){

binString = idx.toString(2);
binPos = Array(binLength).fill(0)
for (j = 0; j < binString.length; j++){
binPos[j] = Number(binString.charAt(binString.length - j - 1));
}
return binPos;
},

proofIdx: function(leafIdx, treeDepth){
proofIdxArray = new Array(treeDepth);
proofPos = module.exports.idxToBinaryPos(leafIdx, treeDepth);
// console.log('proofPos', proofPos)

if (leafIdx % 2 == 0){
proofIdxArray[0] = leafIdx + 1;
} else {
proofIdxArray[0] = leafIdx - 1;
}

for (i = 1; i < treeDepth; i++){
if (proofPos[i] == 1){
proofIdxArray[i] = Math.floor(proofIdxArray[i - 1] / 2) - 1;
} else {
proofIdxArray[i] = Math.floor(proofIdxArray[i - 1] / 2) + 1;
}
}

return(proofIdxArray)
}

}
93 changes: 93 additions & 0 deletions 4_single_tx/generate_circuit_input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const fs = require("fs");
const eddsa = require("../circomlib/src/eddsa.js");
const mimcjs = require("../circomlib/src/mimc7.js");

const alicePrvKey = Buffer.from('1'.toString().padStart(64,'0'), "hex");
const alicePubKey = eddsa.prv2pub(alicePrvKey);
const bobPrvKey = Buffer.from('2'.toString().padStart(64,'0'), "hex");
const bobPubKey = eddsa.prv2pub(bobPrvKey);

// accounts
const Alice = {
pubkey: alicePubKey,
balance: 500
}
const aliceHash = mimcjs.multiHash(
[Alice.pubkey[0], Alice.pubkey[1], Alice.balance]
);

const Bob = {
pubkey: bobPubKey,
balance: 0
}
const bobHash = mimcjs.multiHash(
[Bob.pubkey[0], Bob.pubkey[1], Bob.balance]
);

const accounts_root = mimcjs.multiHash([aliceHash, bobHash])

// transaction
const tx = {
from: Alice.pubkey,
to: Bob.pubkey,
amount: 500
}

// Alice sign tx
const txHash = mimcjs.multiHash(
[tx.from[0], tx.from[1], tx.to[0], tx.to[1], tx.amount]
);
const signature = eddsa.signMiMC(alicePrvKey, txHash)

// update Alice account
const newAlice = {
pubkey: alicePubKey,
balance: 0
}
const newAliceHash = mimcjs.multiHash(
[newAlice.pubkey[0], newAlice.pubkey[1], newAlice.balance]
);

// update intermediate root
const intermediate_root = mimcjs.multiHash([newAliceHash, bobHash])

// update Bob account
const newBob = {
pubkey: bobPubKey,
balance: 500
}
const newBobHash = mimcjs.multiHash(
[newBob.pubkey[0], newBob.pubkey[1], newBob.balance]
);

// update final root
const final_root = mimcjs.multiHash([newAliceHash, newBobHash])


const inputs = {
"accounts_root": accounts_root.toString(),
"intermediate_root": intermediate_root.toString(),
"accounts_pubkeys": [
[Alice.pubkey[0].toString(), Alice.pubkey[1].toString()],
[Bob.pubkey[0].toString(), Bob.pubkey[1].toString()]
],
"accounts_balances": [Alice.balance, Bob.balance],
"sender_pubkey": [Alice.pubkey[0].toString(), Alice.pubkey[1].toString()],
"sender_balance": Alice.balance,
"receiver_pubkey": [Bob.pubkey[0].toString(), Bob.pubkey[1].toString()],
"receiver_balance": Bob.balance,
"amount": tx.amount,
"signature_R8x": signature['R8'][0].toString(),
"signature_R8y": signature['R8'][1].toString(),
"signature_S": signature['S'].toString(),
"sender_proof": [bobHash.toString()],
"sender_proof_pos": [1],
"receiver_proof": [newAliceHash.toString()],
"receiver_proof_pos": [0]
}

fs.writeFileSync(
"./input.json",
JSON.stringify(inputs),
"utf-8"
);
29 changes: 29 additions & 0 deletions 4_single_tx/get_merkle_root.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
include "../circomlib/circuits/mimc.circom";

template GetMerkleRoot(k){
// k is depth of tree

signal input leaf;
signal input paths2_root[k];
signal input paths2_root_pos[k];

signal output out;

// hash of first two entries in tx Merkle proof
component merkle_root[k];
merkle_root[0] = MultiMiMC7(2,91);
merkle_root[0].in[0] <== paths2_root[0] - paths2_root_pos[0]* (paths2_root[0] - leaf);
merkle_root[0].in[1] <== leaf - paths2_root_pos[0]* (leaf - paths2_root[0]);

// hash of all other entries in tx Merkle proof
for (var v = 1; v < k; v++){
merkle_root[v] = MultiMiMC7(2,91);
merkle_root[v].in[0] <== paths2_root[v] - paths2_root_pos[v]* (paths2_root[v] - merkle_root[v-1].out);
merkle_root[v].in[1] <== merkle_root[v-1].out - paths2_root_pos[v]* (merkle_root[v-1].out - paths2_root[v]);

}

// output computed Merkle root
out <== merkle_root[k-1].out;

}
Loading

0 comments on commit 906cb15

Please sign in to comment.