diff --git a/lib/std/crypto/25519/ed25519.zig b/lib/std/crypto/25519/ed25519.zig index 999b099bc6..b48cc24b4b 100644 --- a/lib/std/crypto/25519/ed25519.zig +++ b/lib/std/crypto/25519/ed25519.zig @@ -129,6 +129,7 @@ pub const Ed25519 = struct { try a.rejectIdentity(); try Curve.rejectNonCanonical(r.*); const expected_r = try Curve.fromBytes(r.*); + try expected_r.rejectIdentity(); var h = Sha512.init(.{}); h.update(r); @@ -138,8 +139,7 @@ pub const Ed25519 = struct { h.final(&hram64); const hram = Curve.scalar.reduce64(hram64); - const ah = try a.neg().mulPublic(hram); - const sb_ah = (try Curve.basePoint.mulPublic(s.*)).add(ah); + const sb_ah = try Curve.basePoint.mulDoubleBasePublic(s.*, a.neg(), hram); if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| { return error.SignatureVerificationFailed; } else |_| {} @@ -168,6 +168,7 @@ pub const Ed25519 = struct { try a.rejectIdentity(); try Curve.rejectNonCanonical(r.*); const expected_r = try Curve.fromBytes(r.*); + try expected_r.rejectIdentity(); expected_r_batch[i] = expected_r; r_batch[i] = r.*; s_batch[i] = s.*; @@ -324,13 +325,13 @@ test "ed25519 test vectors" { .msg_hex = "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", .public_key_hex = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", .sig_hex = "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f", - .expected = error.SignatureVerificationFailed, // 8 - non-canonical R + .expected = error.IdentityElement, // 8 - non-canonical R }, Vec{ .msg_hex = "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", .public_key_hex = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", .sig_hex = "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908", - .expected = null, // 9 - non-canonical R + .expected = error.IdentityElement, // 9 - non-canonical R }, Vec{ .msg_hex = "e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b", diff --git a/lib/std/crypto/25519/edwards25519.zig b/lib/std/crypto/25519/edwards25519.zig index c147bed597..e8163a3960 100644 --- a/lib/std/crypto/25519/edwards25519.zig +++ b/lib/std/crypto/25519/edwards25519.zig @@ -238,6 +238,11 @@ pub const Edwards25519 = struct { break :pc precompute(Edwards25519.basePoint, 15); }; + const basePointPc8 = comptime pc: { + @setEvalBranchQuota(10000); + break :pc precompute(Edwards25519.basePoint, 8); + }; + /// Multiply an Edwards25519 point by a scalar without clamping it. /// Return error.WeakPublicKey if the base generates a small-order group, /// and error.IdentityElement if the result is the identity element. @@ -262,14 +267,50 @@ pub const Edwards25519 = struct { } } + /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME* + /// This can be used for signature verification. + pub fn mulDoubleBasePublic(p1: Edwards25519, s1: [32]u8, p2: Edwards25519, s2: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 { + const pc1 = if (p1.is_base) basePointPc8 else pc: { + const xpc = precompute(p1, 8); + xpc[4].rejectIdentity() catch return error.WeakPublicKey; + break :pc xpc; + }; + const pc2 = if (p2.is_base) basePointPc8 else pc: { + const xpc = precompute(p2, 8); + xpc[4].rejectIdentity() catch return error.WeakPublicKey; + break :pc xpc; + }; + const e1 = nonAdjacentForm(s1); + const e2 = nonAdjacentForm(s2); + var q = Edwards25519.identityElement; + var pos: usize = 2 * 32 - 1; + while (true) : (pos -= 1) { + const slot1 = e1[pos]; + if (slot1 > 0) { + q = q.add(pc1[@intCast(usize, slot1)]); + } else if (slot1 < 0) { + q = q.sub(pc1[@intCast(usize, -slot1)]); + } + const slot2 = e2[pos]; + if (slot2 > 0) { + q = q.add(pc2[@intCast(usize, slot2)]); + } else if (slot2 < 0) { + q = q.sub(pc2[@intCast(usize, -slot2)]); + } + if (pos == 0) break; + q = q.dbl().dbl().dbl().dbl(); + } + try q.rejectIdentity(); + return q; + } + /// Multiscalar multiplication *IN VARIABLE TIME* for public data /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 { var pcs: [count][9]Edwards25519 = undefined; for (ps) |p, i| { if (p.is_base) { - @setEvalBranchQuota(10000); - pcs[i] = comptime precompute(Edwards25519.basePoint, 8); + pcs[i] = basePointPc8; } else { pcs[i] = precompute(p, 8); pcs[i][4].rejectIdentity() catch |_| return error.WeakPublicKey;