circomlib/src/eddsa.js
src/eddsa.jsRaw
1const blake2b = require("blake2b");
2const Scalar = require("ffjavascript").Scalar;
3const F1Field = require("ffjavascript").F1Field;
4const babyJub = require("./babyjub");
5const utils = require("ffjavascript").utils;
6const pedersenHash = require("./pedersenHash").hash;
7const mimc7 = require("./mimc7");
8const poseidon = require("./poseidon.js");
9const mimcsponge = require("./mimcsponge");
10
11
12exports.prv2pub= prv2pub;
13exports.sign = sign;
14exports.signMiMC = signMiMC;
15exports.signPoseidon = signPoseidon;
16exports.signMiMCSponge = signMiMCSponge;
17exports.verify = verify;
18exports.verifyMiMC = verifyMiMC;
19exports.verifyPoseidon = verifyPoseidon;
20exports.verifyMiMCSponge = verifyMiMCSponge;
21exports.packSignature = packSignature;
22exports.unpackSignature = unpackSignature;
23exports.pruneBuffer = pruneBuffer;
24
25
26function pruneBuffer(_buff) {
27 const buff = Buffer.from(_buff);
28 buff[0] = buff[0] & 0xF8;
29 buff[31] = buff[31] & 0x7F;
30 buff[31] = buff[31] | 0x40;
31 return buff;
32}
33
34function prv2pub(prv) {
35 const sBuff = pruneBuffer(blake2b(64).update(prv).digest().slice(0,32));
36 let s = utils.leBuff2int(sBuff);
37 const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s,3));
38 return A;
39}
40
41function sign(prv, msg) {
42 const h1 = Buffer.from(blake2b(64).update(prv).digest());
43 const sBuff = pruneBuffer(h1.slice(0,32));
44 const s = utils.leBuff2int(sBuff);
45 const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
46
47 const rBuff = Buffer.from(blake2b(64).update(Buffer.concat([h1.slice(32,64), msg])).digest());
48 let r = utils.leBuff2int(rBuff);
49 const Fr = new F1Field(babyJub.subOrder);
50 r = Fr.e(r);
51 const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
52 const R8p = babyJub.packPoint(R8);
53 const Ap = babyJub.packPoint(A);
54 const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
55 const hm = utils.leBuff2int(hmBuff);
56 const S = Fr.add(r , Fr.mul(hm, s));
57 return {
58 R8: R8,
59 S: S
60 };
61}
62
63function signMiMC(prv, msg) {
64 const h1 = Buffer.from(blake2b(64).update(prv).digest());
65 const sBuff = pruneBuffer(h1.slice(0,32));
66 const s = utils.leBuff2int(sBuff);
67 const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
68
69 const msgBuff = utils.leInt2Buff(msg, 32);
70 const rBuff = Buffer.from(blake2b(64).update(Buffer.concat([h1.slice(32,64), msgBuff])).digest());
71 let r = utils.leBuff2int(rBuff);
72 const Fr = new F1Field(babyJub.subOrder);
73 r = Fr.e(r);
74 const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
75 const hm = mimc7.multiHash([R8[0], R8[1], A[0], A[1], msg]);
76 const S = Fr.add(r , Fr.mul(hm, s));
77 return {
78 R8: R8,
79 S: S
80 };
81}
82
83function signMiMCSponge(prv, msg) {
84 const h1 = Buffer.from(blake2b(64).update(prv).digest());
85 const sBuff = pruneBuffer(h1.slice(0,32));
86 const s = utils.leBuff2int(sBuff);
87 const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
88
89 const msgBuff = utils.leInt2Buff(msg, 32);
90 const rBuff = Buffer.from(blake2b(64).update(Buffer.concat([h1.slice(32,64), msgBuff])).digest());
91 let r = utils.leBuff2int(rBuff);
92 const Fr = new F1Field(babyJub.subOrder);
93 r = Fr.e(r);
94 const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
95 const hm = mimcsponge.multiHash([R8[0], R8[1], A[0], A[1], msg]);
96 const S = Fr.add(r , Fr.mul(hm, s));
97 return {
98 R8: R8,
99 S: S
100 };
101}
102
103function signPoseidon(prv, msg) {
104 const h1 = Buffer.from(blake2b(64).update(prv).digest());
105 const sBuff = pruneBuffer(h1.slice(0,32));
106 const s = utils.leBuff2int(sBuff);
107 const A = babyJub.mulPointEscalar(babyJub.Base8, Scalar.shr(s, 3));
108
109 const msgBuff = utils.leInt2Buff(msg, 32);
110 const rBuff = Buffer.from(blake2b(64).update(Buffer.concat([h1.slice(32,64), msgBuff])).digest());
111 let r = utils.leBuff2int(rBuff);
112 const Fr = new F1Field(babyJub.subOrder);
113 r = Fr.e(r);
114 const R8 = babyJub.mulPointEscalar(babyJub.Base8, r);
115 const hash = poseidon.createHash(6, 8, 57);
116 const hm = hash([R8[0], R8[1], A[0], A[1], msg]);
117 const S = Fr.add(r , Fr.mul(hm, s));
118 return {
119 R8: R8,
120 S: S
121 };
122}
123
124function verify(msg, sig, A) {
125 // Check parameters
126 if (typeof sig != "object") return false;
127 if (!Array.isArray(sig.R8)) return false;
128 if (sig.R8.length!= 2) return false;
129 if (!babyJub.inCurve(sig.R8)) return false;
130 if (!Array.isArray(A)) return false;
131 if (A.length!= 2) return false;
132 if (!babyJub.inCurve(A)) return false;
133 if (sig.S>= babyJub.subOrder) return false;
134
135 const R8p = babyJub.packPoint(sig.R8);
136 const Ap = babyJub.packPoint(A);
137 const hmBuff = pedersenHash(Buffer.concat([R8p, Ap, msg]));
138 const hm = utils.leBuff2int(hmBuff);
139
140 const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
141 let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm,8));
142 Pright = babyJub.addPoint(sig.R8, Pright);
143
144 if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
145 if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
146 return true;
147}
148
149function verifyMiMC(msg, sig, A) {
150 // Check parameters
151 if (typeof sig != "object") return false;
152 if (!Array.isArray(sig.R8)) return false;
153 if (sig.R8.length!= 2) return false;
154 if (!babyJub.inCurve(sig.R8)) return false;
155 if (!Array.isArray(A)) return false;
156 if (A.length!= 2) return false;
157 if (!babyJub.inCurve(A)) return false;
158 if (sig.S>= babyJub.subOrder) return false;
159
160 const hm = mimc7.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
161
162 const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
163 let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8));
164 Pright = babyJub.addPoint(sig.R8, Pright);
165
166 if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
167 if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
168 return true;
169}
170
171
172function verifyPoseidon(msg, sig, A) {
173 // Check parameters
174 if (typeof sig != "object") return false;
175 if (!Array.isArray(sig.R8)) return false;
176 if (sig.R8.length!= 2) return false;
177 if (!babyJub.inCurve(sig.R8)) return false;
178 if (!Array.isArray(A)) return false;
179 if (A.length!= 2) return false;
180 if (!babyJub.inCurve(A)) return false;
181 if (sig.S>= babyJub.subOrder) return false;
182
183 const hash = poseidon.createHash(6, 8, 57);
184 const hm = hash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
185
186 const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
187 let Pright = babyJub.mulPointEscalar(A, Scalar.mul(hm, 8));
188 Pright = babyJub.addPoint(sig.R8, Pright);
189
190 if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
191 if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
192 return true;
193}
194
195function verifyMiMCSponge(msg, sig, A) {
196 // Check parameters
197 if (typeof sig != "object") return false;
198 if (!Array.isArray(sig.R8)) return false;
199 if (sig.R8.length!= 2) return false;
200 if (!babyJub.inCurve(sig.R8)) return false;
201 if (!Array.isArray(A)) return false;
202 if (A.length!= 2) return false;
203 if (!babyJub.inCurve(A)) return false;
204 if (sig.S>= babyJub.subOrder) return false;
205
206 const hm = mimcsponge.multiHash([sig.R8[0], sig.R8[1], A[0], A[1], msg]);
207
208 const Pleft = babyJub.mulPointEscalar(babyJub.Base8, sig.S);
209 let Pright = babyJub.mulPointEscalar(A, hm.times(bigInt("8")));
210 Pright = babyJub.addPoint(sig.R8, Pright);
211
212 if (!babyJub.F.eq(Pleft[0],Pright[0])) return false;
213 if (!babyJub.F.eq(Pleft[1],Pright[1])) return false;
214 return true;
215}
216
217function packSignature(sig) {
218 const R8p = babyJub.packPoint(sig.R8);
219 const Sp = utils.leInt2Buff(sig.S, 32);
220 return Buffer.concat([R8p, Sp]);
221}
222
223function unpackSignature(sigBuff) {
224 return {
225 R8: babyJub.unpackPoint(sigBuff.slice(0,32)),
226 S: utils.leBuff2int(sigBuff.slice(32,64))
227 };
228}
229
230