Support variable-time edwards25519 scalar multiplication

This is useful to save some CPU cycles when the scalar is public,
such as when verifying signatures.
This commit is contained in:
Frank Denis 2020-10-19 21:39:09 +02:00
parent ff658abe79
commit 0fb6fdd7eb
2 changed files with 28 additions and 8 deletions

View File

@ -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 |_| {}

View File

@ -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.