-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
therealyingtong
committed
Jun 13, 2019
1 parent
5804fe2
commit 906cb15
Showing
11 changed files
with
579 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,4 +6,5 @@ input.json | |
proof.json | ||
public.json | ||
circuit.json | ||
package-lock.json | ||
package-lock.json | ||
debug.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
|
||
} |
Oops, something went wrong.