authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2020-10-15 16:39:39+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-10-15 18:49:10-04:00
logf3667e8a8056765c460aa3da1fd3ea655b54bf25
treee6331133a7882f783dc984da0d78ffaa21a7a48d
parentab585c680b3222b01c1520ac33d1233ba1ba5036

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.

3 files changed, 34 insertions(+), 4 deletions(-)

lib/std/crypto/25519/curve25519.zig+5
......@@ -39,6 +39,11 @@ pub const Curve25519 = struct {
3939 }
4040 }
4141
42 /// Multiply a point by the cofactor
43 pub fn clearCofactor(p: Edwards25519) Edwards25519 {
44 return p.dbl().dbl().dbl();
45 }
46
4247 fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) !Curve25519 {
4348 var x1 = p.x;
4449 var x2 = Fe.one;
lib/std/crypto/25519/ed25519.zig+5-4
......@@ -97,6 +97,7 @@ pub const Ed25519 = struct {
9797 try Curve.rejectNonCanonical(public_key);
9898 const a = try Curve.fromBytes(public_key);
9999 try a.rejectIdentity();
100 const expected_r = try Curve.fromBytes(r.*);
100101
101102 var h = Sha512.init(.{});
102103 h.update(r);
......@@ -106,11 +107,11 @@ pub const Ed25519 = struct {
106107 h.final(&hram64);
107108 const hram = Curve.scalar.reduce64(hram64);
108109
109 const p = try a.neg().mul(hram);
110 const check = (try Curve.basePoint.mul(s.*)).add(p).toBytes();
111 if (mem.eql(u8, &check, r) == false) {
110 const ah = try a.neg().mul(hram);
111 const sb_ah = (try Curve.basePoint.mul(s.*)).add(ah);
112 if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| {
112113 return error.InvalidSignature;
113 }
114 } else |_| {}
114115 }
115116};
116117
lib/std/crypto/25519/edwards25519.zig+24
......@@ -73,6 +73,11 @@ pub const Edwards25519 = struct {
7373 }
7474 }
7575
76 /// Multiply a point by the cofactor
77 pub fn clearCofactor(p: Edwards25519) Edwards25519 {
78 return p.dbl().dbl().dbl();
79 }
80
7681 /// Flip the sign of the X coordinate.
7782 pub inline fn neg(p: Edwards25519) Edwards25519 {
7883 return .{ .x = p.x.neg(), .y = p.y, .z = p.z, .t = p.t.neg() };
......@@ -114,6 +119,11 @@ pub const Edwards25519 = struct {
114119 };
115120 }
116121
122 /// Substract two Edwards25519 points.
123 pub fn sub(p: Edwards25519, q: Edwards25519) Edwards25519 {
124 return p.add(q.neg());
125 }
126
117127 inline fn cMov(p: *Edwards25519, a: Edwards25519, c: u64) void {
118128 p.x.cMov(a.x, c);
119129 p.y.cMov(a.y, c);
......@@ -217,3 +227,17 @@ test "edwards25519 packing/unpacking" {
217227 std.testing.expectError(error.WeakPublicKey, small_p.mul(s));
218228 }
219229}
230
231test "edwards25519 point addition/substraction" {
232 var s1: [32]u8 = undefined;
233 var s2: [32]u8 = undefined;
234 try std.crypto.randomBytes(&s1);
235 try std.crypto.randomBytes(&s2);
236 const p = try Edwards25519.basePoint.clampedMul(s1);
237 const q = try Edwards25519.basePoint.clampedMul(s2);
238 const r = p.add(q).add(q).sub(q).sub(q);
239 try r.rejectIdentity();
240 std.testing.expectError(error.IdentityElement, r.sub(p).rejectIdentity());
241 std.testing.expectError(error.IdentityElement, p.sub(p).rejectIdentity());
242 std.testing.expectError(error.IdentityElement, p.sub(q).add(q).sub(p).rejectIdentity());
243}