mirror of
https://github.com/arnaucube/circomlib.git
synced 2026-02-07 03:06:44 +01:00
eddsa done
This commit is contained in:
@@ -1,11 +1,15 @@
|
|||||||
|
include "compconstant.circom";
|
||||||
include "../node_modules/circom/circuits/bitify.circom";
|
include "pointbits.circom";
|
||||||
include "../node_modules/circom/circuits/comparators.circom";
|
include "pedersen2.circom";
|
||||||
include "escalarmulany.circom";
|
include "escalarmulany.circom";
|
||||||
|
include "escalarmulfix.circom";
|
||||||
|
|
||||||
|
/*
|
||||||
|
include "../node_modules/circom/circuits/bitify.circom";
|
||||||
include "babyjub.circom";
|
include "babyjub.circom";
|
||||||
|
*/
|
||||||
|
|
||||||
|
template EdDSAVerifier(n) {
|
||||||
templete EdDSAVerfier(n) {
|
|
||||||
signal input msg[n];
|
signal input msg[n];
|
||||||
|
|
||||||
signal input A[256];
|
signal input A[256];
|
||||||
@@ -24,12 +28,12 @@ templete EdDSAVerfier(n) {
|
|||||||
|
|
||||||
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
|
component compConstant = CompConstant(2736030358979909402780800718157159386076813972158567259200215660948447373040);
|
||||||
|
|
||||||
for (var i=0; i<254; i++) {
|
for (i=0; i<254; i++) {
|
||||||
S[i] ==> compConstant.in[i];
|
S[i] ==> compConstant.in[i];
|
||||||
}
|
}
|
||||||
compConstant.out === 0;
|
compConstant.out === 0;
|
||||||
|
S[254] === 0;
|
||||||
S[255] === 0;
|
S[255] === 0;
|
||||||
S[256] === 0;
|
|
||||||
|
|
||||||
// Convert A to Field elements (And verify A)
|
// Convert A to Field elements (And verify A)
|
||||||
|
|
||||||
@@ -56,13 +60,17 @@ templete EdDSAVerfier(n) {
|
|||||||
component hash = Pedersen(512+n);
|
component hash = Pedersen(512+n);
|
||||||
|
|
||||||
for (i=0; i<256; i++) {
|
for (i=0; i<256; i++) {
|
||||||
hash.in[i] <== R[i];
|
hash.in[i] <== R8[i];
|
||||||
hash.in[256+i] <== A[i];
|
hash.in[256+i] <== A[i];
|
||||||
}
|
}
|
||||||
for (i=0; i<n; i++) {
|
for (i=0; i<n; i++) {
|
||||||
hash.in[512+i] <== msg[i];
|
hash.in[512+i] <== msg[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component point2bitsH = Point2Bits_Strict();
|
||||||
|
point2bitsH.in[0] <== hash.out[0];
|
||||||
|
point2bitsH.in[1] <== hash.out[1];
|
||||||
|
|
||||||
// Calculate second part of the right side: right2 = h*8*A
|
// 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
|
// Multiply by 8 by adding it 3 times. This also ensure that the result is in
|
||||||
@@ -71,11 +79,11 @@ templete EdDSAVerfier(n) {
|
|||||||
dbl1.x <== Ax;
|
dbl1.x <== Ax;
|
||||||
dbl1.y <== Ay;
|
dbl1.y <== Ay;
|
||||||
component dbl2 = BabyDbl();
|
component dbl2 = BabyDbl();
|
||||||
dbl2.x <== dbl1.outx;
|
dbl2.x <== dbl1.xout;
|
||||||
dbl2.y <== dbl1.outy;
|
dbl2.y <== dbl1.yout;
|
||||||
component dbl3 = BabyDbl();
|
component dbl3 = BabyDbl();
|
||||||
dbl3.x <== dbl2.outx;
|
dbl3.x <== dbl2.xout;
|
||||||
dbl3.y <== dbl2.outy;
|
dbl3.y <== dbl2.yout;
|
||||||
|
|
||||||
// We check that A is not zero.
|
// We check that A is not zero.
|
||||||
component isZero = IsZero();
|
component isZero = IsZero();
|
||||||
@@ -84,10 +92,10 @@ templete EdDSAVerfier(n) {
|
|||||||
|
|
||||||
component mulAny = EscalarMulAny(256);
|
component mulAny = EscalarMulAny(256);
|
||||||
for (i=0; i<256; i++) {
|
for (i=0; i<256; i++) {
|
||||||
mulAny.e[i] <== hash.out[i];
|
mulAny.e[i] <== point2bitsH.out[i];
|
||||||
}
|
}
|
||||||
mulAny.p[0] <== dbl3.outx;
|
mulAny.p[0] <== dbl3.xout;
|
||||||
mulAny.p[1] <== dbl3.outy;
|
mulAny.p[1] <== dbl3.yout;
|
||||||
|
|
||||||
|
|
||||||
// Compute the right side: right = R8 + right2
|
// Compute the right side: right = R8 + right2
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ template Multiplexor2() {
|
|||||||
out[1] <== (in[1][1] - in[0][1])*sel + in[0][1];
|
out[1] <== (in[1][1] - in[0][1])*sel + in[0][1];
|
||||||
}
|
}
|
||||||
|
|
||||||
template BitElement() {
|
template BitElementMulAny() {
|
||||||
signal input sel;
|
signal input sel;
|
||||||
signal input dblIn[2];
|
signal input dblIn[2];
|
||||||
signal input addIn[2];
|
signal input addIn[2];
|
||||||
@@ -47,7 +47,7 @@ template BitElement() {
|
|||||||
// returns out in twisted edwards
|
// returns out in twisted edwards
|
||||||
// Double is in montgomery to be linked;
|
// Double is in montgomery to be linked;
|
||||||
|
|
||||||
template Segment(n) {
|
template SegmentMulAny(n) {
|
||||||
signal input e[n];
|
signal input e[n];
|
||||||
signal input p[2];
|
signal input p[2];
|
||||||
signal output out[2];
|
signal output out[2];
|
||||||
@@ -62,7 +62,7 @@ template Segment(n) {
|
|||||||
|
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
bits[0] = BitElement();
|
bits[0] = BitElementMulAny();
|
||||||
e2m.out[0] ==> bits[0].dblIn[0]
|
e2m.out[0] ==> bits[0].dblIn[0]
|
||||||
e2m.out[1] ==> bits[0].dblIn[1]
|
e2m.out[1] ==> bits[0].dblIn[1]
|
||||||
e2m.out[0] ==> bits[0].addIn[0]
|
e2m.out[0] ==> bits[0].addIn[0]
|
||||||
@@ -70,7 +70,7 @@ template Segment(n) {
|
|||||||
e[1] ==> bits[0].sel;
|
e[1] ==> bits[0].sel;
|
||||||
|
|
||||||
for (i=1; i<n-1; i++) {
|
for (i=1; i<n-1; i++) {
|
||||||
bits[i] = BitElement();
|
bits[i] = BitElementMulAny();
|
||||||
|
|
||||||
bits[i-1].dblOut[0] ==> bits[i].dblIn[0]
|
bits[i-1].dblOut[0] ==> bits[i].dblIn[0]
|
||||||
bits[i-1].dblOut[1] ==> bits[i].dblIn[1]
|
bits[i-1].dblOut[1] ==> bits[i].dblIn[1]
|
||||||
@@ -129,7 +129,7 @@ template EscalarMulAny(n) {
|
|||||||
|
|
||||||
nseg = (s < nsegments-1) ? 148 : nlastsegment;
|
nseg = (s < nsegments-1) ? 148 : nlastsegment;
|
||||||
|
|
||||||
segments[s] = Segment(nseg);
|
segments[s] = SegmentMulAny(nseg);
|
||||||
|
|
||||||
for (i=0; i<nseg; i++) {
|
for (i=0; i<nseg; i++) {
|
||||||
e[s*148+i] ==> segments[s].e[i];
|
e[s*148+i] ==> segments[s].e[i];
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ template Pedersen(n) {
|
|||||||
adders[i].y2 <== segments[1].out[1];
|
adders[i].y2 <== segments[1].out[1];
|
||||||
} else {
|
} else {
|
||||||
adders[i].x1 <== adders[i-1].xout;
|
adders[i].x1 <== adders[i-1].xout;
|
||||||
adders[i].y1 <== adders[i-1].xout;
|
adders[i].y1 <== adders[i-1].yout;
|
||||||
adders[i].x2 <== segments[i+1].out[0];
|
adders[i].x2 <== segments[i+1].out[0];
|
||||||
adders[i].y2 <== segments[i+1].out[1];
|
adders[i].y2 <== segments[i+1].out[1];
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/eddsa.js
15
src/eddsa.js
@@ -21,6 +21,7 @@ function pruneBuffer(_buff) {
|
|||||||
buff[0] = buff[0] & 0xF8;
|
buff[0] = buff[0] & 0xF8;
|
||||||
buff[31] = buff[31] & 0x7F;
|
buff[31] = buff[31] & 0x7F;
|
||||||
buff[31] = buff[31] | 0x40;
|
buff[31] = buff[31] | 0x40;
|
||||||
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prv2pub(prv) {
|
function prv2pub(prv) {
|
||||||
@@ -36,13 +37,13 @@ function sign(prv, msg) {
|
|||||||
const s = bigInt.leBuff2int(sBuff);
|
const s = bigInt.leBuff2int(sBuff);
|
||||||
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
|
const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
|
||||||
|
|
||||||
const rBuff = createBlakeHash("blake512").update(Buffer.concat(h1.slice(32,64), msg)).digest();
|
const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest();
|
||||||
let r = bigInt.leBuff2int(rBuff);
|
let r = bigInt.leBuff2int(rBuff);
|
||||||
r = r.mod(babyJub.subOrder);
|
r = r.mod(babyJub.subOrder);
|
||||||
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
|
const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
|
||||||
const R8p = babyJub.packPoint(R8);
|
const R8p = babyJub.packPoint(R8);
|
||||||
const Ap = babyJub.packPoint(A);
|
const Ap = babyJub.packPoint(A);
|
||||||
const hmBuff = pedersenHash(Buffer.concat(R8p, Ap, msg));
|
const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
|
||||||
const hm = bigInt.leBuff2int(hmBuff);
|
const hm = bigInt.leBuff2int(hmBuff);
|
||||||
const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
|
const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
|
||||||
return {
|
return {
|
||||||
@@ -59,17 +60,17 @@ function verify(msg, sig, A) {
|
|||||||
if (!babyJub.inCurve(sig.R8)) return false;
|
if (!babyJub.inCurve(sig.R8)) return false;
|
||||||
if (!Array.isArray(A)) return false;
|
if (!Array.isArray(A)) return false;
|
||||||
if (A.length!= 2) return false;
|
if (A.length!= 2) return false;
|
||||||
if (!babyJub.inCurve(sig.A)) return false;
|
if (!babyJub.inCurve(A)) return false;
|
||||||
if (sig.S>= babyJub.subOrder) return false;
|
if (sig.S>= babyJub.subOrder) return false;
|
||||||
|
|
||||||
const R8p = babyJub.packPoint(sig.R8);
|
const R8p = babyJub.packPoint(sig.R8);
|
||||||
const Ap = babyJub.packPoint(A);
|
const Ap = babyJub.packPoint(A);
|
||||||
const hmBuff = pedersenHash(Buffer.concat(R8p, Ap, msg));
|
const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
|
||||||
const hm = bigInt.leBuff2int(hmBuff);
|
const hm = bigInt.leBuff2int(hmBuff);
|
||||||
|
|
||||||
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
|
const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
|
||||||
let Pright = babyJub.mulPointEscalar(A, hm.mul(8));
|
let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
|
||||||
Pright = babyJub.addaddPoint(sig.R8, Pright);
|
Pright = babyJub.addPoint(sig.R8, Pright);
|
||||||
|
|
||||||
if (!Pleft[0].equals(Pright[0])) return false;
|
if (!Pleft[0].equals(Pright[0])) return false;
|
||||||
if (!Pleft[1].equals(Pright[1])) return false;
|
if (!Pleft[1].equals(Pright[1])) return false;
|
||||||
@@ -79,7 +80,7 @@ function verify(msg, sig, A) {
|
|||||||
function packSignature(sig) {
|
function packSignature(sig) {
|
||||||
const R8p = babyJub.packPoint(sig.R8);
|
const R8p = babyJub.packPoint(sig.R8);
|
||||||
const Sp = bigInt.leInt2Buff(sig.S, 32);
|
const Sp = bigInt.leInt2Buff(sig.S, 32);
|
||||||
return Buffer.concat(R8p, Sp);
|
return Buffer.concat([R8p, Sp]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unpackSignature(sigBuff) {
|
function unpackSignature(sigBuff) {
|
||||||
|
|||||||
122243
test/circuits/circuit.json
122243
test/circuits/circuit.json
File diff suppressed because one or more lines are too long
3
test/circuits/eddsa_test.circom
Normal file
3
test/circuits/eddsa_test.circom
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
include "../../circuit/eddsa.circom";
|
||||||
|
|
||||||
|
component main = EdDSAVerifier(80);
|
||||||
73
test/eddsa.js
Normal file
73
test/eddsa.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
const path = require("path");
|
||||||
|
const snarkjs = require("snarkjs");
|
||||||
|
const compiler = require("circom");
|
||||||
|
|
||||||
|
const eddsa = require("../src/eddsa.js");
|
||||||
|
const babyJub = require("../src/babyjub.js");
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
const bigInt = snarkjs.bigInt;
|
||||||
|
|
||||||
|
function print(circuit, w, s) {
|
||||||
|
console.log(s + ": " + w[circuit.getSignalIdx(s)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buffer2bits(buff) {
|
||||||
|
const res = [];
|
||||||
|
for (let i=0; i<buff.length; i++) {
|
||||||
|
for (let j=0; j<8; j++) {
|
||||||
|
if ((buff[i]>>j)&1) {
|
||||||
|
res.push(bigInt.one);
|
||||||
|
} else {
|
||||||
|
res.push(bigInt.zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
describe("EdDSA test", function () {
|
||||||
|
let circuit;
|
||||||
|
|
||||||
|
this.timeout(100000);
|
||||||
|
|
||||||
|
before( async () => {
|
||||||
|
const cirDef = await compiler(path.join(__dirname, "circuits", "eddsa_test.circom"));
|
||||||
|
|
||||||
|
circuit = new snarkjs.Circuit(cirDef);
|
||||||
|
|
||||||
|
console.log("NConstrains EdDSA: " + circuit.nConstraints);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Sign a single 10 bytes from 0 to 9", async () => {
|
||||||
|
const msg = Buffer.from("00010203040506070809", "hex");
|
||||||
|
|
||||||
|
// const prvKey = eddsa.cratePrvKey();
|
||||||
|
|
||||||
|
const prvKey = Buffer.from("0001020304050607080900010203040506070809000102030405060708090001", "hex");
|
||||||
|
|
||||||
|
const pubKey = eddsa.prv2pub(prvKey);
|
||||||
|
|
||||||
|
const pPubKey = babyJub.packPoint(pubKey);
|
||||||
|
|
||||||
|
const signature = eddsa.sign(prvKey, msg);
|
||||||
|
|
||||||
|
const pSignature = eddsa.packSignature(signature);
|
||||||
|
const uSignature = eddsa.unpackSignature(pSignature);
|
||||||
|
|
||||||
|
assert(eddsa.verify(msg, uSignature, pubKey));
|
||||||
|
|
||||||
|
const msgBits = buffer2bits(msg);
|
||||||
|
const r8Bits = buffer2bits(pSignature.slice(0, 32));
|
||||||
|
const sBits = buffer2bits(pSignature.slice(32, 64));
|
||||||
|
const aBits = buffer2bits(pPubKey);
|
||||||
|
|
||||||
|
const w = circuit.calculateWitness({A: aBits, R8: r8Bits, S: sBits, msg: msgBits});
|
||||||
|
|
||||||
|
assert(circuit.checkWitness(w));
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user