Skip to content

Commit

Permalink
Merge pull request #10 from barryWhiteHat/master
Browse files Browse the repository at this point in the history
merge with master
  • Loading branch information
kendricktan committed Jan 11, 2020
2 parents cc4b776 + 132ee8f commit e2bd68a
Show file tree
Hide file tree
Showing 26 changed files with 10,923 additions and 333 deletions.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
# MACI
Minimal Anti-Collusion Infrastructure
# Minimal Anti-Collusion Infrastructure

This project is based upon https://ethresear.ch/t/minimal-anti-collusion-infrastructure
Please refer to the [implementation
spec](./SPEC.md) for technical details, and the
original
[ethresear.ch post](https://ethresear.ch/t/minimal-anti-collusion-infrastructure/5413)
for a high-level view.

We welcome contributions to this project. Please join our
[Telegram group](https://t.me/joinchat/LUgOpE7J2gstRcZqdERyvw) to discuss.

# Developing on MACI

Expand Down
686 changes: 686 additions & 0 deletions SPEC.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions app/utils/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const crypto = require('crypto')
const { bigInt } = require('snarkjs')
const { babyJub, eddsa, mimcsponge } = require('circomlib')
const { babyJub, eddsa, mimc7, mimcsponge } = require('circomlib')

const bigInt2Buffer = (i: BigInt): Buffer => {
return Buffer.from(i.toString())
Expand Down Expand Up @@ -93,10 +93,10 @@ const encrypt = (
): Array<BigInt> => {
// Encrypts a message
const sharedKey = ecdh(priv, pub)
const iv = multiHash(msg)
const iv = mimc7.multiHash(msg, BigInt(0))
return [
iv, ...msg.map((e: BigInt, i: Number): BigInt => {
return e + hash(sharedKey, iv + bigInt(i))
return e + mimc7.hash(sharedKey, iv + bigInt(i))
})
]
}
Expand All @@ -110,7 +110,7 @@ const decrypt = (
const sharedKey = ecdh(priv, pub)
const iv = msg[0]
return msg.slice(1).map((e: BigInt, i: Number): BigInt => {
return e - hash(sharedKey, iv + bigInt(i))
return e - mimc7.hash(sharedKey, iv + bigInt(i))
})
}

Expand Down
10 changes: 9 additions & 1 deletion app/utils/merkletree.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class MerkleTree {
// Values to create the hash values of the leaves
// NOTE: encryptedValues contains values of the encrypted values
this.encryptedValues = []

// TODO: WJ suggests that we separate encryption code from Merkle Tree code

// Public keys used to decrypt the encrypted values
// (decryption key is generated via ecdh)
this.ecdhPublicKeys = []
Expand Down Expand Up @@ -113,7 +116,12 @@ class MerkleTree {

this.root = currentLevelHash
this.leaves.push(leaf)
this.leavesRaw.push(rawValue || {})

if (rawValue === undefined) {
this.leavesRaw.push(null)
} else {
this.leavesRaw.push(rawValue)
}
}

/* Updates merkletree leaf at `leafIndex` with `newLeafValue` */
Expand Down
13 changes: 8 additions & 5 deletions circuits/decrypt.circom
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
include "./hasher.circom";
include "../node_modules/circomlib/circuits/mimc.circom";
include "../node_modules/circomlib/circuits/escalarmulany.circom";


template Decrypt(N) {
// Where N is the length of the
// decrypted message output of the
signal input message[N+1];
signal input private_key;
signal output out[N];

component hasher[N];

// iv is message[0]
for(var i=0; i<N; i++) {
hasher[i] = Hasher(1);
hasher[i].in[0] <== private_key;
hasher[i].key <== message[0] + i;
out[i] <== message[i+1] - hasher[i].hash
hasher[i] = MiMC7(91);
hasher[i].x_in <== private_key;
hasher[i].k <== message[0] + i;
out[i] <== message[i+1] - hasher[i].out;
}
}
77 changes: 5 additions & 72 deletions circuits/ecdh.circom
Original file line number Diff line number Diff line change
@@ -1,76 +1,9 @@
include "./hasher.circom";
include "../node_modules/circomlib/circuits/bitify.circom";
include "../node_modules/circomlib/circuits/escalarmulfix.circom";
include "../node_modules/circomlib/circuits/escalarmulany.circom";

template EscalarMulFix_patch(n) {
// Patch to fix EscalarMulFix
// as BASE can't be a signal input

signal input e[n]; // Input in binary format
signal input BASE[2];
signal output out[2]; // Point (Twisted format)

var nsegments = (n-1)\246 +1; // 249 probably would work. But I'm not sure and for security I keep 246
var nlastsegment = n - (nsegments-1)*249;

component segments[nsegments];

component m2e[nsegments-1];
component adders[nsegments-1];

var s;
var i;
var nseg;
var nWindows;

for (s=0; s<nsegments; s++) {
nseg = (s < nsegments-1) ? 249 : nlastsegment;
nWindows = ((nseg - 1)\3)+1;

segments[s] = SegmentMulFix(nWindows);

for (i=0; i<nseg; i++) {
segments[s].e[i] <== e[s*249+i];
}

for (i = nseg; i<nWindows*3; i++) {
segments[s].e[i] <== 0;
}

if (s==0) {
segments[s].base[0] <== BASE[0];
segments[s].base[1] <== BASE[1];
} else {
m2e[s-1] = Montgomery2Edwards();
adders[s-1] = BabyAdd();

segments[s-1].dbl[0] ==> m2e[s-1].in[0];
segments[s-1].dbl[1] ==> m2e[s-1].in[1];

m2e[s-1].out[0] ==> segments[s].base[0];
m2e[s-1].out[1] ==> segments[s].base[1];

if (s==1) {
segments[s-1].out[0] ==> adders[s-1].x1;
segments[s-1].out[1] ==> adders[s-1].y1;
} else {
adders[s-2].xout ==> adders[s-1].x1;
adders[s-2].yout ==> adders[s-1].y1;
}
segments[s].out[0] ==> adders[s-1].x2;
segments[s].out[1] ==> adders[s-1].y2;
}
}

if (nsegments == 1) {
segments[0].out[0] ==> out[0];
segments[0].out[1] ==> out[1];
} else {
adders[nsegments-2].xout ==> out[0];
adders[nsegments-2].yout ==> out[1];
}
}

// TODO: Check if public key is on the point
template Ecdh() {
// Note: private key
// Needs to be hashed, and then pruned before
Expand All @@ -83,9 +16,9 @@ template Ecdh() {
component privBits = Num2Bits(253);
privBits.in <== private_key;

component mulFix = EscalarMulFix_patch(253);
mulFix.BASE[0] <== public_key[0];
mulFix.BASE[1] <== public_key[1];
component mulFix = EscalarMulAny(253);
mulFix.p[0] <== public_key[0];
mulFix.p[1] <== public_key[1];

for (var i = 0; i < 253; i++) {
mulFix.e[i] <== privBits.out[i];
Expand Down
64 changes: 63 additions & 1 deletion circuits/merkletree.circom
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ template UpdateSelector() {
signal rightSelector1;
signal rightSelector2;

// Ensure that path_index is either 0 or 1
path_index * (1-path_index) === 0

leftSelector1 <== (1 - path_index) * input_element;
Expand All @@ -32,7 +33,7 @@ template UpdateSelector() {
template MerkleTreeUpdate(levels) {
// Computes new merkletree root on update
// NOTE: path_elements and path_index can be
// obtained from merkletree.js `getPath` function
// obtained from merkletree.js's `getPathUpdate` function
signal input leaf;

signal private input path_elements[levels];
Expand Down Expand Up @@ -148,3 +149,64 @@ template LeafExists(levels){

root === merkletree.root;
}

template CheckRoot(levels) {
// Given a Merkle root and a list of leaves, check if the root is the
// correct result of inserting all the leaves into the tree (in the given
// order)

// Circom has some perticularities which limit the code patterns we can
// use.

// You can only assign a value to a signal once.

// A component's input signal must only be wired to another component's output
// signal.

// Variables are only used for loops, declaring sizes of things, and anything
// that is not related to inputs of a circuit.

// The total number of leaves
var totalLeaves = 2 ** levels;

// The number of HashLeftRight components which will be used to hash the
// leaves
var numLeafHashers = totalLeaves / 2;

// The number of HashLeftRight components which will be used to hash the
// output of the leaf hasher components
var numIntermediateHashers = numLeafHashers - 1;

// Inputs to the snark
signal private input leaves[totalLeaves];

// The output
signal output root;

// The total number of hashers
var numHashers = totalLeaves - 1;
component hashers[numHashers];

// Instantiate all hashers
var i;
for (i=0; i < numHashers; i++) {
hashers[i] = HashLeftRight();
}

// Wire the leaf values into the leaf hashers
for (i=0; i < numLeafHashers; i++){
hashers[i].left <== leaves[i*2];
hashers[i].right <== leaves[i*2+1];
}

// Wire the outputs of the leaf hashers to the intermediate hasher inputs
var k = 0;
for (i=numLeafHashers; i<numLeafHashers + numIntermediateHashers; i++) {
hashers[i].left <== hashers[k*2].hash;
hashers[i].right <== hashers[k*2+1].hash;
k++;
}

// Wire the output of the final hash to this circuit's output
root <== hashers[numHashers-1].hash;
}

0 comments on commit e2bd68a

Please sign in to comment.