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 {...@@ -39,6 +39,11 @@ pub const Curve25519 = struct {
39 }39 }
40 }40 }
4141
42 /// Multiply a point by the cofactor
43 pub fn clearCofactor(p: Edwards25519) Edwards25519 {
44 return p.dbl().dbl().dbl();
45 }
46
42 fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) !Curve25519 {47 fn ladder(p: Curve25519, s: [32]u8, comptime bits: usize) !Curve25519 {
43 var x1 = p.x;48 var x1 = p.x;
44 var x2 = Fe.one;49 var x2 = Fe.one;
lib/std/crypto/25519/ed25519.zig+5-4
...@@ -97,6 +97,7 @@ pub const Ed25519 = struct {...@@ -97,6 +97,7 @@ pub const Ed25519 = struct {
97 try Curve.rejectNonCanonical(public_key);97 try Curve.rejectNonCanonical(public_key);
98 const a = try Curve.fromBytes(public_key);98 const a = try Curve.fromBytes(public_key);
99 try a.rejectIdentity();99 try a.rejectIdentity();
100 const expected_r = try Curve.fromBytes(r.*);
100101
101 var h = Sha512.init(.{});102 var h = Sha512.init(.{});
102 h.update(r);103 h.update(r);
...@@ -106,11 +107,11 @@ pub const Ed25519 = struct {...@@ -106,11 +107,11 @@ pub const Ed25519 = struct {
106 h.final(&hram64);107 h.final(&hram64);
107 const hram = Curve.scalar.reduce64(hram64);108 const hram = Curve.scalar.reduce64(hram64);
108109
109 const p = try a.neg().mul(hram);110 const ah = try a.neg().mul(hram);
110 const check = (try Curve.basePoint.mul(s.*)).add(p).toBytes();111 const sb_ah = (try Curve.basePoint.mul(s.*)).add(ah);
111 if (mem.eql(u8, &check, r) == false) {112 if (expected_r.sub(sb_ah).clearCofactor().rejectIdentity()) |_| {
112 return error.InvalidSignature;113 return error.InvalidSignature;
113 }114 } else |_| {}
114 }115 }
115};116};
116117
lib/std/crypto/25519/edwards25519.zig+24
...@@ -73,6 +73,11 @@ pub const Edwards25519 = struct {...@@ -73,6 +73,11 @@ pub const Edwards25519 = struct {
73 }73 }
74 }74 }
7575
76 /// Multiply a point by the cofactor
77 pub fn clearCofactor(p: Edwards25519) Edwards25519 {
78 return p.dbl().dbl().dbl();
79 }
80
76 /// Flip the sign of the X coordinate.81 /// Flip the sign of the X coordinate.
77 pub inline fn neg(p: Edwards25519) Edwards25519 {82 pub inline fn neg(p: Edwards25519) Edwards25519 {
78 return .{ .x = p.x.neg(), .y = p.y, .z = p.z, .t = p.t.neg() };83 return .{ .x = p.x.neg(), .y = p.y, .z = p.z, .t = p.t.neg() };
...@@ -114,6 +119,11 @@ pub const Edwards25519 = struct {...@@ -114,6 +119,11 @@ pub const Edwards25519 = struct {
114 };119 };
115 }120 }
116121
122 /// Substract two Edwards25519 points.
123 pub fn sub(p: Edwards25519, q: Edwards25519) Edwards25519 {
124 return p.add(q.neg());
125 }
126
117 inline fn cMov(p: *Edwards25519, a: Edwards25519, c: u64) void {127 inline fn cMov(p: *Edwards25519, a: Edwards25519, c: u64) void {
118 p.x.cMov(a.x, c);128 p.x.cMov(a.x, c);
119 p.y.cMov(a.y, c);129 p.y.cMov(a.y, c);
...@@ -217,3 +227,17 @@ test "edwards25519 packing/unpacking" {...@@ -217,3 +227,17 @@ test "edwards25519 packing/unpacking" {
217 std.testing.expectError(error.WeakPublicKey, small_p.mul(s));227 std.testing.expectError(error.WeakPublicKey, small_p.mul(s));
218 }228 }
219}229}
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}