Skip to content

Commit

Permalink
Merge pull request iden3#1 from kobigurk/feature/mimcsponge
Browse files Browse the repository at this point in the history
Adds a sponge variant of MiMC
  • Loading branch information
kobigurk authored Jun 27, 2019
2 parents d689f73 + 9e078dc commit 4c3d7cf
Show file tree
Hide file tree
Showing 13 changed files with 799 additions and 0 deletions.
123 changes: 123 additions & 0 deletions circuits/eddsamimcsponge.circom
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
Copyright 2018 0KIMS association.
This file is part of circom (Zero Knowledge Circuit Compiler).
circom is a 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.
circom 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 circom. If not, see <https://www.gnu.org/licenses/>.
*/

include "compconstant.circom";
include "pointbits.circom";
include "mimcsponge.circom";
include "bitify.circom";
include "escalarmulany.circom";
include "escalarmulfix.circom";

template EdDSAMiMCSpongeVerifier() {
signal input enabled;
signal input Ax;
signal input Ay;

signal input S;
signal input R8x;
signal input R8y;

signal input M;

var i;

// Ensure S<Subgroup Order

component snum2bits = Num2Bits(253);
snum2bits.in <== S;

component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);

for (i=0; i<253; i++) {
snum2bits.out[i] ==> compConstant.in[i];
}
compConstant.in[253] <== 0;
compConstant.out === 0;

// Calculate the h = H(R,A, msg)

component hash = MiMCSponge(5, 220, 1);
hash.ins[0] <== R8x;
hash.ins[1] <== R8y;
hash.ins[2] <== Ax;
hash.ins[3] <== Ay;
hash.ins[4] <== M;
hash.k <== 0;

component h2bits = Num2Bits_strict();
h2bits.in <== hash.outs[0];

// Calculate second part of the right side: right2 = h*8*A

// Multiply by 8 by adding it 3 times. This also ensure that the result is in
// the subgroup.
component dbl1 = BabyDbl();
dbl1.x <== Ax;
dbl1.y <== Ay;
component dbl2 = BabyDbl();
dbl2.x <== dbl1.xout;
dbl2.y <== dbl1.yout;
component dbl3 = BabyDbl();
dbl3.x <== dbl2.xout;
dbl3.y <== dbl2.yout;

// We check that A is not zero.
component isZero = IsZero();
isZero.in <== dbl3.x;
isZero.out === 0;

component mulAny = EscalarMulAny(254);
for (i=0; i<254; i++) {
mulAny.e[i] <== h2bits.out[i];
}
mulAny.p[0] <== dbl3.xout;
mulAny.p[1] <== dbl3.yout;


// Compute the right side: right = R8 + right2

component addRight = BabyAdd();
addRight.x1 <== R8x;
addRight.y1 <== R8y;
addRight.x2 <== mulAny.out[0];
addRight.y2 <== mulAny.out[1];

// Calculate left side of equation left = S*B8

var BASE8 = [
17777552123799933955779906779655732241715742912184938656739573121738514868268,
2626589144620713026669568689430873010625803728049924121243784502389097019475
];
component mulFix = EscalarMulFix(253, BASE8);
for (i=0; i<253; i++) {
mulFix.e[i] <== snum2bits.out[i];
}

// Do the comparation left == right if enabled;

component eqCheckX = ForceEqualIfEnabled();
eqCheckX.enabled <== enabled;
eqCheckX.in[0] <== mulFix.out[0];
eqCheckX.in[1] <== addRight.xout;

component eqCheckY = ForceEqualIfEnabled();
eqCheckY.enabled <== enabled;
eqCheckY.in[0] <== mulFix.out[1];
eqCheckY.in[1] <== addRight.yout;
}
283 changes: 283 additions & 0 deletions circuits/mimcsponge.circom

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
exports.smt = require("./src/smt");
exports.eddsa = require("./src/eddsa");
exports.mimc7 = require("./src/mimc7");
exports.mimcsponge = require("./src/mimcsponge");
exports.babyJub = require("./src/babyjub");
44 changes: 44 additions & 0 deletions src/eddsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ const bigInt = require("snarkjs").bigInt;
const babyJub = require("./babyjub");
const pedersenHash = require("./pedersenHash").hash;
const mimc7 = require("./mimc7");
const mimcsponge = require("./mimcsponge");

exports.prv2pub= prv2pub;
exports.sign = sign;
exports.signMiMC = signMiMC;
exports.signMiMCSponge = signMiMCSponge;
exports.verify = verify;
exports.verifyMiMC = verifyMiMC;
exports.verifyMiMCSponge = verifyMiMCSponge;
exports.packSignature = packSignature;
exports.unpackSignature = unpackSignature;
exports.pruneBuffer = pruneBuffer;
Expand Down Expand Up @@ -69,6 +72,25 @@ function signMiMC(prv, msg) {
};
}

function signMiMCSponge(prv, msg) {
const h1 = createBlakeHash("blake512").update(prv).digest();
const sBuff = pruneBuffer(h1.slice(0,32));
const s = bigInt.leBuff2int(sBuff);
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));

const msgBuff = bigInt.leInt2Buff(msg, 32);
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
let r = bigInt.leBuff2int(rBuff);
r = r.mod(babyJub.subOrder);
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
const hm = mimcsponge.multiHash([R8[0], R8[1], A[0], A[1], msg]);
const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
return {
R8: R8,
S: S
};
}

function verify(msg, sig, A) {
// Check parameters
if (typeof sig != "object") return false;
Expand Down Expand Up @@ -116,6 +138,28 @@ function verifyMiMC(msg, sig, A) {
return true;
}

function verifyMiMCSponge(msg, sig, A) {
// Check parameters
if (typeof sig != "object") return false;
if (!Array.isArray(sig.R8)) return false;
if (sig.R8.length!= 2) return false;
if (!babyJub.inCurve(sig.R8)) return false;
if (!Array.isArray(A)) return false;
if (A.length!= 2) return false;
if (!babyJub.inCurve(A)) return false;
if (sig.S>= babyJub.subOrder) return false;

const hm = mimcsponge.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);

const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
Pright = babyJub.addPoint(sig.R8, Pright);

if (!Pleft[0].equals(Pright[0])) return false;
if (!Pleft[1].equals(Pright[1])) return false;
return true;
}

function packSignature(sig) {
const R8p = babyJub.packPoint(sig.R8);
const Sp = bigInt.leInt2Buff(sig.S, 32);
Expand Down
File renamed without changes.
81 changes: 81 additions & 0 deletions src/mimcsponge.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
const bn128 = require("snarkjs").bn128;
const bigInt = require("snarkjs").bigInt;
const Web3Utils = require("web3-utils");
const F = bn128.Fr;

const SEED = "mimcsponge";
const NROUNDS = 220;

exports.getIV = (seed) => {
if (typeof seed === "undefined") seed = SEED;
const c = Web3Utils.keccak256(seed+"_iv");
const cn = bigInt(Web3Utils.toBN(c).toString());
const iv = cn.mod(F.q);
return iv;
};

exports.getConstants = (seed, nRounds) => {
if (typeof seed === "undefined") seed = SEED;
if (typeof nRounds === "undefined") nRounds = NROUNDS;
const cts = new Array(nRounds);
let c = Web3Utils.keccak256(SEED);
for (let i=1; i<nRounds; i++) {
c = Web3Utils.keccak256(c);

const n1 = Web3Utils.toBN(c).mod(Web3Utils.toBN(F.q.toString()));
const c2 = Web3Utils.padLeft(Web3Utils.toHex(n1), 64);
cts[i] = bigInt(Web3Utils.toBN(c2).toString());
}
cts[0] = bigInt(0);
return cts;
};

const cts = exports.getConstants(SEED, 220);

exports.hash = (_xL_in, _xR_in, _k) =>{
let xL = bigInt(_xL_in);
let xR = bigInt(_xR_in);
const k = bigInt(_k);
for (let i=0; i<NROUNDS; i++) {
const c = cts[i];
const t = (i==0) ? F.add(xL, k) : F.add(F.add(xL, k), c);
const xR_tmp = bigInt(xR);
xR = xL;
xL = F.add(xR_tmp, F.exp(t, 5));
}
return {
xL: F.affine(xL),
xR: F.affine(xR),
};
};

exports.multiHash = (arr, key, numOutputs) => {
if (typeof(numOutputs) === "undefined") {
numOutputs = 1;
}
if (typeof(key) === "undefined") {
key = F.zero;
}

let R = F.zero;
let C = F.zero;

for (let i=0; i<arr.length; i++) {
R = F.add(R, bigInt(arr[i]));
const S = exports.hash(R, C, key);
R = S.xL;
C = S.xR;
}
let outputs = [R];
for (let i=1; i < numOutputs; i++) {
const S = exports.hash(R, C, key);
R = S.xL;
C = S.xR;
outputs.push(R);
}
if (numOutputs == 1) {
return F.affine(outputs[0]);
} else {
return outputs.map(x => F.affine(x));
}
};
Loading

0 comments on commit 4c3d7cf

Please sign in to comment.