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 mimc7 = require("./mimc7");
6const poseidon = require("./poseidon.js");
7
8exports.prv2pub= prv2pub;
9exports.sign = sign;
10exports.signMiMC = signMiMC;
11exports.signPoseidon = signPoseidon;
12exports.verify = verify;
13exports.verifyMiMC = verifyMiMC;
14exports.verifyPoseidon = verifyPoseidon;
15exports.packSignature = packSignature;
16exports.unpackSignature = unpackSignature;
17exports.pruneBuffer = pruneBuffer;
18
19
20function pruneBuffer(_buff) {
21 const buff = Buffer.from(_buff);
22 buff[0] = buff[0] & 0xF8;
23 buff[31] = buff[31] & 0x7F;
24 buff[31] = buff[31] | 0x40;
25 return buff;
26}
27
28function prv2pub(prv) {
29 const sBuff = pruneBuffer(createBlakeHash("blake512").update(prv).digest().slice(0,32));
30 let s = bigInt.leBuff2int(sBuff);
31 const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
32 return A;
33}
34
35function sign(prv, msg) {
36 const h1 = createBlakeHash("blake512").update(prv).digest();
37 const sBuff = pruneBuffer(h1.slice(0,32));
38 const s = bigInt.leBuff2int(sBuff);
39 const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
40
41 const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msg])).digest();
42 let r = bigInt.leBuff2int(rBuff);
43 r = r.mod(babyJub.subOrder);
44 const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
45 const R8p = babyJub.packPoint(R8);
46 const Ap = babyJub.packPoint(A);
47 const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
48 const hm = bigInt.leBuff2int(hmBuff);
49 const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
50 return {
51 R8: R8,
52 S: S
53 };
54}
55
56function signMiMC(prv, msg) {
57 const h1 = createBlakeHash("blake512").update(prv).digest();
58 const sBuff = pruneBuffer(h1.slice(0,32));
59 const s = bigInt.leBuff2int(sBuff);
60 const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
61
62 const msgBuff = bigInt.leInt2Buff(msg, 32);
63 const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
64 let r = bigInt.leBuff2int(rBuff);
65 r = r.mod(babyJub.subOrder);
66 const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
67 const hm = mimc7.multiHash([R8[0], R8[1], A[0], A[1], msg]);
68 const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
69 return {
70 R8: R8,
71 S: S
72 };
73}
74
75
76function signPoseidon(prv, msg) {
77 const h1 = createBlakeHash("blake512").update(prv).digest();
78 const sBuff = pruneBuffer(h1.slice(0,32));
79 const s = bigInt.leBuff2int(sBuff);
80 const A = babyJub.mulPointEscalar(babyJub.Base8, s.shr(3));
81
82 const msgBuff = bigInt.leInt2Buff(msg, 32);
83 const rBuff = createBlakeHash("blake512").update(Buffer.concat([h1.slice(32,64), msgBuff])).digest();
84 let r = bigInt.leBuff2int(rBuff);
85 r = r.mod(babyJub.subOrder);
86 const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
87
88 const hash = poseidon.createHash(6, 8, 57);
89
90 const hm = hash([R8[0], R8[1], A[0], A[1], msg]);
91 const S = r.add(hm.mul(s)).mod(babyJub.subOrder);
92 return {
93 R8: R8,
94 S: S
95 };
96}
97
98function verify(msg, sig, A) {
99 // Check parameters
100 if (typeof sig != "object") return false;
101 if (!Array.isArray(sig.R8)) return false;
102 if (sig.R8.length!= 2) return false;
103 if (!babyJub.inCurve(sig.R8)) return false;
104 if (!Array.isArray(A)) return false;
105 if (A.length!= 2) return false;
106 if (!babyJub.inCurve(A)) return false;
107 if (sig.S>= babyJub.subOrder) return false;
108
109 const R8p = babyJub.packPoint(sig.R8);
110 const Ap = babyJub.packPoint(A);
111 const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
112 const hm = bigInt.leBuff2int(hmBuff);
113
114 const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
115 let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
116 Pright = babyJub.addPoint(sig.R8, Pright);
117
118 if (!Pleft[0].equals(Pright[0])) return false;
119 if (!Pleft[1].equals(Pright[1])) return false;
120 return true;
121}
122
123function verifyMiMC(msg, sig, A) {
124 // Check parameters
125 if (typeof sig != "object") return false;
126 if (!Array.isArray(sig.R8)) return false;
127 if (sig.R8.length!= 2) return false;
128 if (!babyJub.inCurve(sig.R8)) return false;
129 if (!Array.isArray(A)) return false;
130 if (A.length!= 2) return false;
131 if (!babyJub.inCurve(A)) return false;
132 if (sig.S>= babyJub.subOrder) return false;
133
134 const hm = mimc7.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
135
136 const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
137 let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
138 Pright = babyJub.addPoint(sig.R8, Pright);
139
140 if (!Pleft[0].equals(Pright[0])) return false;
141 if (!Pleft[1].equals(Pright[1])) return false;
142 return true;
143}
144
145
146function verifyPoseidon(msg, sig, A) {
147 // Check parameters
148 if (typeof sig != "object") return false;
149 if (!Array.isArray(sig.R8)) return false;
150 if (sig.R8.length!= 2) return false;
151 if (!babyJub.inCurve(sig.R8)) return false;
152 if (!Array.isArray(A)) return false;
153 if (A.length!= 2) return false;
154 if (!babyJub.inCurve(A)) return false;
155 if (sig.S>= babyJub.subOrder) return false;
156
157 const hash = poseidon.createHash(6, 8, 57);
158 const hm = hash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
159
160 const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
161 let Pright = babyJub.mulPointEscalar(A, hm.mul(bigInt("8")));
162 Pright = babyJub.addPoint(sig.R8, Pright);
163
164 if (!Pleft[0].equals(Pright[0])) return false;
165 if (!Pleft[1].equals(Pright[1])) return false;
166 return true;
167}
168
169function packSignature(sig) {
170 const R8p = babyJub.packPoint(sig.R8);
171 const Sp = bigInt.leInt2Buff(sig.S, 32);
172 return Buffer.concat([R8p, Sp]);
173}
174
175function unpackSignature(sigBuff) {
176 return {
177 R8: babyJub.unpackPoint(sigBuff.slice(0,32)),
178 S: bigInt.leBuff2int(sigBuff.slice(32,64))
179 };
180}
181
182