circomlib/src/eddsa.js
src/eddsa.jsRaw
1const createBlakeHash = require("blake-hash");
2const bigInt = require("snarkjs").bigInt;
3const babyJub = require("./babyjub");
4const pedersenHash = require("./pedersenHash").hash;
5const crypto = require("crypto");
6
7exports.cratePrvKey = cratePrvKey;
8exports.prv2pub= prv2pub;
9exports.sign = sign;
10exports.verify = verify;
11exports.packSignature = packSignature;
12exports.unpackSignature = unpackSignature;
13
14
15function cratePrvKey() {
16 return crypto.randomBytes(32);
17}
18
19function pruneBuffer(_buff) {
20 const buff = Buffer.from(_buff);
21 buff[0] = buff[0] & 0xF8;
22 buff[31] = buff[31] & 0x7F;
23 buff[31] = buff[31] | 0x40;
24}
25
26function prv2pub(prv) {
27 const sBuff = pruneBuffer(createBlakeHash("blake512").update(prv).digest().slice(0,32));
28 let s = bigInt.leBuff2int(sBuff);
29 const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
30 return A;
31}
32
33function sign(prv, msg) {
34 const h1 = createBlakeHash("blake512").update(prv).digest();
35 const sBuff = pruneBuffer(h1.slice(0,32));
36 const s = bigInt.leBuff2int(sBuff);
37 const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
38
39 const rBuff = createBlakeHash("blake512").update(Buffer.concat(h1.slice(32,64), msg)).digest();
40 let r = bigInt.leBuff2int(rBuff);
41 r = r.mod(babyJub.subOrder);
42 const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
43 const R8p = babyJub.packPoint(R8);
44 const Ap = babyJub.packPoint(A);
45 const hmBuff = pedersenHash(Buffer.concat(R8p, Ap, msg));
46 const hm = bigInt.leBuff2int(hmBuff);
47 const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
48 return {
49 R8: R8,
50 S: S
51 };
52}
53
54function verify(msg, sig, A) {
55 // Check parameters
56 if (typeof sig != "object") return false;
57 if (!Array.isArray(sig.R8)) return false;
58 if (sig.R8.length!= 2) return false;
59 if (!babyJub.inCurve(sig.R8)) return false;
60 if (!Array.isArray(A)) return false;
61 if (A.length!= 2) return false;
62 if (!babyJub.inCurve(sig.A)) return false;
63 if (sig.S>= babyJub.subOrder) return false;
64
65 const R8p = babyJub.packPoint(sig.R8);
66 const Ap = babyJub.packPoint(A);
67 const hmBuff = pedersenHash(Buffer.concat(R8p, Ap, msg));
68 const hm = bigInt.leBuff2int(hmBuff);
69
70 const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
71 let Pright = babyJub.mulPointEscalar(A, hm.mul(8));
72 Pright = babyJub.addaddPoint(sig.R8, Pright);
73
74 if (!Pleft[0].equals(Pright[0])) return false;
75 if (!Pleft[1].equals(Pright[1])) return false;
76 return true;
77}
78
79function packSignature(sig) {
80 const R8p = babyJub.packPoint(sig.R8);
81 const Sp = bigInt.leInt2Buff(sig.S, 32);
82 return Buffer.concat(R8p, Sp);
83}
84
85function unpackSignature(sigBuff) {
86 return {
87 R8: babyJub.unpackPoint(sigBuff.slice(0,32)),
88 S: bigInt.leBuff2int(sigBuff.slice(32,64))
89 };
90}
91
92