Commit 0fb6fdd7eb

Frank Denis <github@pureftpd.org>
2020-10-19 21:39:09
Support variable-time edwards25519 scalar multiplication
This is useful to save some CPU cycles when the scalar is public, such as when verifying signatures.
1 parent ff658ab
Changed files (2)
lib
lib/std/crypto/25519/ed25519.zig
@@ -108,8 +108,8 @@ pub const Ed25519 = struct {
         h.final(&hram64);
         const hram = Curve.scalar.reduce64(hram64);
 
-        const ah = try a.neg().mul(hram);
-        const sb_ah = (try Curve.basePoint.mul(s.*)).add(ah);
+        const ah = try a.neg().mulPublic(hram);
+        const sb_ah = (try Curve.basePoint.mulPublic(s.*)).add(ah);
         if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| {
             return error.InvalidSignature;
         } else |_| {}
@@ -170,18 +170,18 @@ pub const Ed25519 = struct {
 
         var zr = Curve.neutralElement;
         for (z_batch) |z, i| {
-            zr = zr.add(try expected_r_batch[i].mul(z));
+            zr = zr.add(try expected_r_batch[i].mulPublic(z));
         }
         zr = zr.clearCofactor();
 
         var zah = Curve.neutralElement;
         for (z_batch) |z, i| {
             const zh = Curve.scalar.mul(z, hram_batch[i]);
-            zah = zah.add(try a_batch[i].mul(zh));
+            zah = zah.add(try a_batch[i].mulPublic(zh));
         }
         zah = zah.clearCofactor();
 
-        const zsb = try Curve.basePoint.mul(zs_sum);
+        const zsb = try Curve.basePoint.mulPublic(zs_sum);
         if (zr.add(zah).sub(zsb).rejectIdentity()) |_| {
             return error.InvalidSignature;
         } else |_| {}
lib/std/crypto/25519/edwards25519.zig
@@ -149,13 +149,19 @@ pub const Edwards25519 = struct {
         return t;
     }
 
-    fn pcMul(pc: [16]Edwards25519, s: [32]u8) !Edwards25519 {
+    fn pcMul(pc: [16]Edwards25519, s: [32]u8, comptime vartime: bool) !Edwards25519 {
         var q = Edwards25519.identityElement;
         var pos: usize = 252;
         while (true) : (pos -= 4) {
             q = q.dbl().dbl().dbl().dbl();
             const bit = (s[pos >> 3] >> @truncate(u3, pos)) & 0xf;
-            q = q.add(pcSelect(pc, bit));
+            if (vartime) {
+                if (bit != 0) {
+                    q = q.add(pc[bit]);
+                }
+            } else {
+                q = q.add(pcSelect(pc, bit));
+            }
             if (pos == 0) break;
         }
         try q.rejectIdentity();
@@ -185,7 +191,21 @@ pub const Edwards25519 = struct {
             pc = precompute(p);
             pc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
         }
-        return pcMul(pc, s);
+        return pcMul(pc, s, false);
+    }
+
+    /// Multiply an Edwards25519 point by a *PUBLIC* scalar *IN VARIABLE TIME*
+    /// This can be used for signature verification.
+    pub fn mulPublic(p: Edwards25519, s: [32]u8) !Edwards25519 {
+        var pc: [16]Edwards25519 = undefined;
+        if (p.is_base) {
+            @setEvalBranchQuota(10000);
+            pc = comptime precompute(Edwards25519.basePoint);
+        } else {
+            pc = precompute(p);
+            pc[4].rejectIdentity() catch |_| return error.WeakPublicKey;
+        }
+        return pcMul(pc, s, true);
     }
 
     /// Multiply an Edwards25519 point by a scalar after "clamping" it.