authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2020-10-19 21:39:09+02:00
committergravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2020-10-22 09:58:26+02:00
log0fb6fdd7eb8c9ec7057e2ecb2d0d4506cddc6dd1
treef88547541eded0d3c924956e7cf9dcededdb64c7
parentff658abe790890c3f4e6f7fee34e52da4755a93c

Support variable-time edwards25519 scalar multiplication

This is useful to save some CPU cycles when the scalar is public, such as when verifying signatures.

2 files changed, 28 insertions(+), 8 deletions(-)

lib/std/crypto/25519/ed25519.zig+5-5
......@@ -108,8 +108,8 @@ pub const Ed25519 = struct {
108108 h.final(&hram64);
109109 const hram = Curve.scalar.reduce64(hram64);
110110
111 const ah = try a.neg().mul(hram);
112 const sb_ah = (try Curve.basePoint.mul(s.*)).add(ah);
111 const ah = try a.neg().mulPublic(hram);
112 const sb_ah = (try Curve.basePoint.mulPublic(s.*)).add(ah);
113113 if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| {
114114 return error.InvalidSignature;
115115 } else |_| {}
......@@ -170,18 +170,18 @@ pub const Ed25519 = struct {
170170
171171 var zr = Curve.neutralElement;
172172 for (z_batch) |z, i| {
173 zr = zr.add(try expected_r_batch[i].mul(z));
173 zr = zr.add(try expected_r_batch[i].mulPublic(z));
174174 }
175175 zr = zr.clearCofactor();
176176
177177 var zah = Curve.neutralElement;
178178 for (z_batch) |z, i| {
179179 const zh = Curve.scalar.mul(z, hram_batch[i]);
180 zah = zah.add(try a_batch[i].mul(zh));
180 zah = zah.add(try a_batch[i].mulPublic(zh));
181181 }
182182 zah = zah.clearCofactor();
183183
184 const zsb = try Curve.basePoint.mul(zs_sum);
184 const zsb = try Curve.basePoint.mulPublic(zs_sum);
185185 if (zr.add(zah).sub(zsb).rejectIdentity()) |_| {
186186 return error.InvalidSignature;
187187 } else |_| {}
lib/std/crypto/25519/edwards25519.zig+23-3
......@@ -149,13 +149,19 @@ pub const Edwards25519 = struct {
149149 return t;
150150 }
151151
152 fn pcMul(pc: [16]Edwards25519, s: [32]u8) !Edwards25519 {
152 fn pcMul(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) !Edwards25519 {
153153 var q = Edwards25519.identityElement;
154154 var pos: usize = 252;
155155 while (true) : (pos -= 4) {
156156 q = q.dbl().dbl().dbl().dbl();
157157 const bit = (s[pos >> 3] >> @truncate(u3, pos)) & 0xf;
158 q = q.add(pcSelect(pc, bit));
158 if (vartime) {
159 if (bit != 0) {
160 q = q.add(pc[bit]);
161 }
162 } else {
163 q = q.add(pcSelect(pc, bit));
164 }
159165 if (pos == 0) break;
160166 }
161167 try q.rejectIdentity();
......@@ -185,7 +191,21 @@ pub const Edwards25519 = struct {
185191 pc = precompute(p);
186192 pc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
187193 }
188 return pcMul(pc, s);
194 return pcMul(pc, s, false);
195 }
196
197 /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME*
198 /// This can be used for signature verification.
199 pub fn mulPublic(p: Edwards25519, s: [32]u8) !Edwards25519 {
200 var pc: [16]Edwards25519 = undefined;
201 if (p.is_base) {
202 @setEvalBranchQuota(10000);
203 pc = comptime precompute(Edwards25519.basePoint);
204 } else {
205 pc = precompute(p);
206 pc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
207 }
208 return pcMul(pc, s, true);
189209 }
190210
191211 /// Multiply an Edwards25519 point by a scalar after "clamping" it.