@ -0,0 +1,122 @@ |
|||
/* |
|||
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 "mimc.circom"; |
|||
include "bitify.circom"; |
|||
include "escalarmulany.circom"; |
|||
include "escalarmulfix.circom"; |
|||
|
|||
template EdDSAMiMCVerifier() { |
|||
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 = MultiMiMC7(5, 91); |
|||
hash.in[0] <== R8x; |
|||
hash.in[1] <== R8y; |
|||
hash.in[2] <== Ax; |
|||
hash.in[3] <== Ay; |
|||
hash.in[4] <== M; |
|||
|
|||
component h2bits = Num2Bits_strict(); |
|||
h2bits.in <== hash.out; |
|||
|
|||
// 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; |
|||
} |
@ -0,0 +1,3 @@ |
|||
exports.smt = require("./src/smt"); |
|||
exports.eddsa = require("./src/eddsa"); |
|||
exports.mimc7 = require("./src/mimc7"); |
@ -1,43 +0,0 @@ |
|||
/* |
|||
fnc[0] fn[1] Function S1 S2 S3 S4 |
|||
0 0 NOP 0 0 0 0 |
|||
0 1 TRANSFER 0 1 0 1 |
|||
1 0 ENTRY 0 1 0 1 |
|||
1 1 EXIT 1 0 1 1 |
|||
|
|||
*/ |
|||
|
|||
template rollupTx(nLevels) { |
|||
signal input fromIdx; // 24 |
|||
signal input toIdx; // 24 |
|||
signal input fpTxAmount; // 24 |
|||
|
|||
signal input fnc[2]; // 2 |
|||
|
|||
signal oldRoot; |
|||
signal newRoot; |
|||
|
|||
signal input sigR8; |
|||
signal input sigS; |
|||
|
|||
// State 1 |
|||
signal input Ax1; |
|||
signal input Ay1; |
|||
signal input St1; |
|||
signal input siblings1[nlevels]; |
|||
|
|||
// Required for inserts and delete |
|||
signal input isOld0_1; // 1 |
|||
signal input oldKey; |
|||
signal input oldValue; |
|||
|
|||
// State 2 |
|||
signal input Ax2; |
|||
signal input Ay2; |
|||
signal input St2; |
|||
signal input siblings2[nlevels]; |
|||
signal input isOld0_1; // 1 |
|||
signal input oldKey; |
|||
signal input oldValue; |
|||
|
|||
} |
@ -0,0 +1,3 @@ |
|||
include "../../circuits/eddsamimc.circom"; |
|||
|
|||
component main = EdDSAMiMCVerifier(); |
@ -0,0 +1,98 @@ |
|||
const chai = require("chai"); |
|||
const path = require("path"); |
|||
const snarkjs = require("snarkjs"); |
|||
const compiler = require("circom"); |
|||
|
|||
const eddsa = require("../src/eddsa.js"); |
|||
|
|||
const assert = chai.assert; |
|||
|
|||
const bigInt = snarkjs.bigInt; |
|||
|
|||
describe("EdDSA test", function () { |
|||
let circuit; |
|||
|
|||
this.timeout(100000); |
|||
|
|||
before( async () => { |
|||
const cirDef = await compiler(path.join(__dirname, "circuits", "eddsamimc_test.circom")); |
|||
|
|||
circuit = new snarkjs.Circuit(cirDef); |
|||
|
|||
console.log("NConstrains EdDSA: " + circuit.nConstraints); |
|||
}); |
|||
|
|||
it("Sign a single number", async () => { |
|||
const msg = bigInt(1234); |
|||
|
|||
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); |
|||
|
|||
const pubKey = eddsa.prv2pub(prvKey); |
|||
|
|||
const signature = eddsa.signMiMC(prvKey, msg); |
|||
|
|||
assert(eddsa.verifyMiMC(msg, signature, pubKey)); |
|||
|
|||
const w = circuit.calculateWitness({ |
|||
enabled: 1, |
|||
Ax: pubKey[0], |
|||
Ay: pubKey[1], |
|||
R8x: signature.R8[0], |
|||
R8y: signature.R8[1], |
|||
S: signature.S, |
|||
M: msg}); |
|||
|
|||
assert(circuit.checkWitness(w)); |
|||
}); |
|||
|
|||
it("Detect Invalid signature", async () => { |
|||
const msg = bigInt(1234); |
|||
|
|||
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); |
|||
|
|||
const pubKey = eddsa.prv2pub(prvKey); |
|||
|
|||
|
|||
const signature = eddsa.signMiMC(prvKey, msg); |
|||
|
|||
assert(eddsa.verifyMiMC(msg, signature, pubKey)); |
|||
try { |
|||
const w = circuit.calculateWitness({ |
|||
enabled: 1, |
|||
Ax: pubKey[0], |
|||
Ay: pubKey[1], |
|||
R8x: signature.R8[0].add(bigInt(1)), |
|||
R8y: signature.R8[1], |
|||
S: signature.S, |
|||
M: msg}); |
|||
assert(false); |
|||
} catch(err) { |
|||
assert.equal(err.message, "Constraint doesn't match: 1 != 0"); |
|||
} |
|||
}); |
|||
|
|||
|
|||
it("Test a dissabled circuit with a bad signature", async () => { |
|||
const msg = bigInt(1234); |
|||
|
|||
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex"); |
|||
|
|||
const pubKey = eddsa.prv2pub(prvKey); |
|||
|
|||
|
|||
const signature = eddsa.signMiMC(prvKey, msg); |
|||
|
|||
assert(eddsa.verifyMiMC(msg, signature, pubKey)); |
|||
|
|||
const w = circuit.calculateWitness({ |
|||
enabled: 0, |
|||
Ax: pubKey[0], |
|||
Ay: pubKey[1], |
|||
R8x: signature.R8[0].add(bigInt(1)), |
|||
R8y: signature.R8[1], |
|||
S: signature.S, |
|||
M: msg}); |
|||
|
|||
assert(circuit.checkWitness(w)); |
|||
}); |
|||
}); |