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 {...@@ -108,8 +108,8 @@ pub const Ed25519 = struct {
108 h.final(&hram64);108 h.final(&hram64);
109 const hram = Curve.scalar.reduce64(hram64);109 const hram = Curve.scalar.reduce64(hram64);
110110
111 const ah = try a.neg().mul(hram);111 const ah = try a.neg().mulPublic(hram);
112 const sb_ah = (try Curve.basePoint.mul(s.*)).add(ah);112 const sb_ah = (try Curve.basePoint.mulPublic(s.*)).add(ah);
113 if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| {113 if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| {
114 return error.InvalidSignature;114 return error.InvalidSignature;
115 } else |_| {}115 } else |_| {}
...@@ -170,18 +170,18 @@ pub const Ed25519 = struct {...@@ -170,18 +170,18 @@ pub const Ed25519 = struct {
170170
171 var zr = Curve.neutralElement;171 var zr = Curve.neutralElement;
172 for (z_batch) |z, i| {172 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));
174 }174 }
175 zr = zr.clearCofactor();175 zr = zr.clearCofactor();
176176
177 var zah = Curve.neutralElement;177 var zah = Curve.neutralElement;
178 for (z_batch) |z, i| {178 for (z_batch) |z, i| {
179 const zh = Curve.scalar.mul(z, hram_batch[i]);179 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));
181 }181 }
182 zah = zah.clearCofactor();182 zah = zah.clearCofactor();
183183
184 const zsb = try Curve.basePoint.mul(zs_sum);184 const zsb = try Curve.basePoint.mulPublic(zs_sum);
185 if (zr.add(zah).sub(zsb).rejectIdentity()) |_| {185 if (zr.add(zah).sub(zsb).rejectIdentity()) |_| {
186 return error.InvalidSignature;186 return error.InvalidSignature;
187 } else |_| {}187 } else |_| {}
lib/std/crypto/25519/edwards25519.zig+23-3
...@@ -149,13 +149,19 @@ pub const Edwards25519 = struct {...@@ -149,13 +149,19 @@ pub const Edwards25519 = struct {
149 return t;149 return t;
150 }150 }
151151
152 fn pcMul(pc: [16]Edwards25519, s: [32]u8) !Edwards25519 {152 fn pcMul(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) !Edwards25519 {
153 var q = Edwards25519.identityElement;153 var q = Edwards25519.identityElement;
154 var pos: usize = 252;154 var pos: usize = 252;
155 while (true) : (pos -= 4) {155 while (true) : (pos -= 4) {
156 q = q.dbl().dbl().dbl().dbl();156 q = q.dbl().dbl().dbl().dbl();
157 const bit = (s[pos >> 3] >> @truncate(u3, pos)) & 0xf;157 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 }
159 if (pos == 0) break;165 if (pos == 0) break;
160 }166 }
161 try q.rejectIdentity();167 try q.rejectIdentity();
...@@ -185,7 +191,21 @@ pub const Edwards25519 = struct {...@@ -185,7 +191,21 @@ pub const Edwards25519 = struct {
185 pc = precompute(p);191 pc = precompute(p);
186 pc[4].rejectIdentity() catch |_| return error.WeakPublicKey;192 pc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
187 }193 }
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);
189 }209 }
190210
191 /// Multiply an Edwards25519 point by a scalar after "clamping" it.211 /// Multiply an Edwards25519 point by a scalar after "clamping" it.