| author | |
| committer | |
| log | f3667e8a8056765c460aa3da1fd3ea655b54bf25 |
| tree | e6331133a7882f783dc984da0d78ffaa21a7a48d |
| parent | ab585c680b3222b01c1520ac33d1233ba1ba5036 |
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 | } |
| 41 | 41 | ||
| 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.*); | ||
| 100 | 101 | ||
| 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); |
| 108 | 109 | ||
| 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 | }; |
| 116 | 117 |
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 | } |
| 75 | 75 | ||
| 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 | } |
| 116 | 121 | ||
| 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 | |||
| 231 | test "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 | } |