| author | |
| committer | |
| log | 7a793a9b9d38adc6800834d2dc11a1037b1aef4d |
| tree | fbeadcb17b07399c000d1723706d48ca3a6c4e26 |
| parent | 29e5e98eed2161c37edbce41b96c2999eb1f3177 |
This makes single signature verification about 60% faster.
Also check that R is not the identity point.2 files changed, 48 insertions(+), 6 deletions(-)
lib/std/crypto/25519/ed25519.zig+5-4| ... | ... | @@ -129,6 +129,7 @@ pub const Ed25519 = struct { |
| 129 | 129 | try a.rejectIdentity(); |
| 130 | 130 | try Curve.rejectNonCanonical(r.*); |
| 131 | 131 | const expected_r = try Curve.fromBytes(r.*); |
| 132 | try expected_r.rejectIdentity(); | |
| 132 | 133 | |
| 133 | 134 | var h = Sha512.init(.{}); |
| 134 | 135 | h.update(r); |
| ... | ... | @@ -138,8 +139,7 @@ pub const Ed25519 = struct { |
| 138 | 139 | h.final(&hram64); |
| 139 | 140 | const hram = Curve.scalar.reduce64(hram64); |
| 140 | 141 | |
| 141 | const ah = try a.neg().mulPublic(hram); | |
| 142 | const sb_ah = (try Curve.basePoint.mulPublic(s.*)).add(ah); | |
| 142 | const sb_ah = try Curve.basePoint.mulDoubleBasePublic(s.*, a.neg(), hram); | |
| 143 | 143 | if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| { |
| 144 | 144 | return error.SignatureVerificationFailed; |
| 145 | 145 | } else |_| {} |
| ... | ... | @@ -168,6 +168,7 @@ pub const Ed25519 = struct { |
| 168 | 168 | try a.rejectIdentity(); |
| 169 | 169 | try Curve.rejectNonCanonical(r.*); |
| 170 | 170 | const expected_r = try Curve.fromBytes(r.*); |
| 171 | try expected_r.rejectIdentity(); | |
| 171 | 172 | expected_r_batch[i] = expected_r; |
| 172 | 173 | r_batch[i] = r.*; |
| 173 | 174 | s_batch[i] = s.*; |
| ... | ... | @@ -324,13 +325,13 @@ test "ed25519 test vectors" { |
| 324 | 325 | .msg_hex = "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", |
| 325 | 326 | .public_key_hex = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", |
| 326 | 327 | .sig_hex = "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03be9678ac102edcd92b0210bb34d7428d12ffc5df5f37e359941266a4e35f0f", |
| 327 | .expected = error.SignatureVerificationFailed, // 8 - non-canonical R | |
| 328 | .expected = error.IdentityElement, // 8 - non-canonical R | |
| 328 | 329 | }, |
| 329 | 330 | Vec{ |
| 330 | 331 | .msg_hex = "9bedc267423725d473888631ebf45988bad3db83851ee85c85e241a07d148b41", |
| 331 | 332 | .public_key_hex = "f7badec5b8abeaf699583992219b7b223f1df3fbbea919844e3f7c554a43dd43", |
| 332 | 333 | .sig_hex = "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffca8c5b64cd208982aa38d4936621a4775aa233aa0505711d8fdcfdaa943d4908", |
| 333 | .expected = null, // 9 - non-canonical R | |
| 334 | .expected = error.IdentityElement, // 9 - non-canonical R | |
| 334 | 335 | }, |
| 335 | 336 | Vec{ |
| 336 | 337 | .msg_hex = "e96b7021eb39c1a163b6da4e3093dcd3f21387da4cc4572be588fafae23c155b", |
lib/std/crypto/25519/edwards25519.zig+43-2| ... | ... | @@ -238,6 +238,11 @@ pub const Edwards25519 = struct { |
| 238 | 238 | break :pc precompute(Edwards25519.basePoint, 15); |
| 239 | 239 | }; |
| 240 | 240 | |
| 241 | const basePointPc8 = comptime pc: { | |
| 242 | @setEvalBranchQuota(10000); | |
| 243 | break :pc precompute(Edwards25519.basePoint, 8); | |
| 244 | }; | |
| 245 | ||
| 241 | 246 | /// Multiply an Edwards25519 point by a scalar without clamping it. |
| 242 | 247 | /// Return error.WeakPublicKey if the base generates a small-order group, |
| 243 | 248 | /// and error.IdentityElement if the result is the identity element. |
| ... | ... | @@ -262,14 +267,50 @@ pub const Edwards25519 = struct { |
| 262 | 267 | } |
| 263 | 268 | } |
| 264 | 269 | |
| 270 | /// Double-base multiplication of public parameters - Compute (p1*s1)+(p2*s2) *IN VARIABLE TIME* | |
| 271 | /// This can be used for signature verification. | |
| 272 | pub fn mulDoubleBasePublic(p1: Edwards25519, s1: [32]u8, p2: Edwards25519, s2: [32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 { | |
| 273 | const pc1 = if (p1.is_base) basePointPc8 else pc: { | |
| 274 | const xpc = precompute(p1, 8); | |
| 275 | xpc[4].rejectIdentity() catch return error.WeakPublicKey; | |
| 276 | break :pc xpc; | |
| 277 | }; | |
| 278 | const pc2 = if (p2.is_base) basePointPc8 else pc: { | |
| 279 | const xpc = precompute(p2, 8); | |
| 280 | xpc[4].rejectIdentity() catch return error.WeakPublicKey; | |
| 281 | break :pc xpc; | |
| 282 | }; | |
| 283 | const e1 = nonAdjacentForm(s1); | |
| 284 | const e2 = nonAdjacentForm(s2); | |
| 285 | var q = Edwards25519.identityElement; | |
| 286 | var pos: usize = 2 * 32 - 1; | |
| 287 | while (true) : (pos -= 1) { | |
| 288 | const slot1 = e1[pos]; | |
| 289 | if (slot1 > 0) { | |
| 290 | q = q.add(pc1[@intCast(usize, slot1)]); | |
| 291 | } else if (slot1 < 0) { | |
| 292 | q = q.sub(pc1[@intCast(usize, -slot1)]); | |
| 293 | } | |
| 294 | const slot2 = e2[pos]; | |
| 295 | if (slot2 > 0) { | |
| 296 | q = q.add(pc2[@intCast(usize, slot2)]); | |
| 297 | } else if (slot2 < 0) { | |
| 298 | q = q.sub(pc2[@intCast(usize, -slot2)]); | |
| 299 | } | |
| 300 | if (pos == 0) break; | |
| 301 | q = q.dbl().dbl().dbl().dbl(); | |
| 302 | } | |
| 303 | try q.rejectIdentity(); | |
| 304 | return q; | |
| 305 | } | |
| 306 | ||
| 265 | 307 | /// Multiscalar multiplication *IN VARIABLE TIME* for public data |
| 266 | 308 | /// Computes ps0*ss0 + ps1*ss1 + ps2*ss2... faster than doing many of these operations individually |
| 267 | 309 | pub fn mulMulti(comptime count: usize, ps: [count]Edwards25519, ss: [count][32]u8) (IdentityElementError || WeakPublicKeyError)!Edwards25519 { |
| 268 | 310 | var pcs: [count][9]Edwards25519 = undefined; |
| 269 | 311 | for (ps) |p, i| { |
| 270 | 312 | if (p.is_base) { |
| 271 | @setEvalBranchQuota(10000); | |
| 272 | pcs[i] = comptime precompute(Edwards25519.basePoint, 8); | |
| 313 | pcs[i] = basePointPc8; | |
| 273 | 314 | } else { |
| 274 | 315 | pcs[i] = precompute(p, 8); |
| 275 | 316 | pcs[i][4].rejectIdentity() catch |_| return error.WeakPublicKey; |