std/crypto/25519: do cofactored ed25519 verification

This is slightly slower but makes our verification function compatible
with batch signatures. Which, in turn, makes blockchain people happy.
And we want to make our users happy.

Add convenience functions to substract edwards25519 points and to
clear the cofactor.
This commit is contained in:
Frank Denis 2020-10-15 16:39:39 +02:00 committed by Andrew Kelley
parent ab585c680b
commit f3667e8a80
3 changed files with 34 additions and 4 deletions

View File

@ -39,6 +39,11 @@ pub const Curve25519 = struct {
}
}
/// Multiply a point by the cofactor
pub fn clearCofactor(p: Edwards25519) Edwards25519 {
return p.dbl().dbl().dbl();
}
fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) !Curve25519 {
var x1 = p.x;
var x2 = Fe.one;

View File

@ -97,6 +97,7 @@ pub const Ed25519 = struct {
try Curve.rejectNonCanonical(public_key);
const a = try Curve.fromBytes(public_key);
try a.rejectIdentity();
const expected_r = try Curve.fromBytes(r.*);
var h = Sha512.init(.{});
h.update(r);
@ -106,11 +107,11 @@ pub const Ed25519 = struct {
h.final(&hram64);
const hram = Curve.scalar.reduce64(hram64);
const p = try a.neg().mul(hram);
const check = (try Curve.basePoint.mul(s.*)).add(p).toBytes();
if (mem.eql(u8, &check, r) == false) {
const ah = try a.neg().mul(hram);
const sb_ah = (try Curve.basePoint.mul(s.*)).add(ah);
if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| {
return error.InvalidSignature;
}
} else |_| {}
}
};

View File

@ -73,6 +73,11 @@ pub const Edwards25519 = struct {
}
}
/// Multiply a point by the cofactor
pub fn clearCofactor(p: Edwards25519) Edwards25519 {
return p.dbl().dbl().dbl();
}
/// Flip the sign of the X coordinate.
pub inline fn neg(p: Edwards25519) Edwards25519 {
return .{ .x = p.x.neg(), .y = p.y, .z = p.z, .t = p.t.neg() };
@ -114,6 +119,11 @@ pub const Edwards25519 = struct {
};
}
/// Substract two Edwards25519 points.
pub fn sub(p: Edwards25519, q: Edwards25519) Edwards25519 {
return p.add(q.neg());
}
inline fn cMov(p: *Edwards25519, a: Edwards25519, c: u64) void {
p.x.cMov(a.x, c);
p.y.cMov(a.y, c);
@ -217,3 +227,17 @@ test "edwards25519 packing/unpacking" {
std.testing.expectError(error.WeakPublicKey, small_p.mul(s));
}
}
test "edwards25519 point addition/substraction" {
var s1: [32]u8 = undefined;
var s2: [32]u8 = undefined;
try std.crypto.randomBytes(&s1);
try std.crypto.randomBytes(&s2);
const p = try Edwards25519.basePoint.clampedMul(s1);
const q = try Edwards25519.basePoint.clampedMul(s2);
const r = p.add(q).add(q).sub(q).sub(q);
try r.rejectIdentity();
std.testing.expectError(error.IdentityElement, r.sub(p).rejectIdentity());
std.testing.expectError(error.IdentityElement, p.sub(p).rejectIdentity());
std.testing.expectError(error.IdentityElement, p.sub(q).add(q).sub(p).rejectIdentity());
}