mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
ed25519: use double-base multiplication for signature verification
This makes single signature verification about 60% faster. Also check that R is not the identity point.
This commit is contained in:
parent
29e5e98eed
commit
7a793a9b9d
2 changed files with 48 additions and 6 deletions
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue