| author | |
| committer | |
| log | bcef123d902b9d1d8a27b0414932b1b92f6f1a7e |
| tree | 22ad97205c0a529cc5d832ba21ec709d11442843 |
| parent | 263c44473896597346bc244d82a2b436d7d2da02 |
5 files changed, 49 insertions(+), 54 deletions(-)
lib/std/crypto/25519/curve25519.zig+3-5| ... | @@ -19,10 +19,8 @@ pub const Curve25519 = struct { | ... | @@ -19,10 +19,8 @@ pub const Curve25519 = struct { |
| 19 | return p.x.toBytes(); | 19 | return p.x.toBytes(); |
| 20 | } | 20 | } |
| 21 | 21 | ||
| 22 | /// Return the Curve25519 base point. | 22 | /// The Curve25519 base point. |
| 23 | pub inline fn basePoint() Curve25519 { | 23 | pub const basePoint = Curve25519{ .x = Fe.curve25519BasePoint }; |
| 24 | return .{ .x = Fe.curve25519BasePoint }; | ||
| 25 | } | ||
| 26 | 24 | ||
| 27 | /// Check that the encoding of a Curve25519 point is canonical. | 25 | /// Check that the encoding of a Curve25519 point is canonical. |
| 28 | pub fn rejectNonCanonical(s: [32]u8) !void { | 26 | pub fn rejectNonCanonical(s: [32]u8) !void { |
| ... | @@ -103,7 +101,7 @@ pub const Curve25519 = struct { | ... | @@ -103,7 +101,7 @@ pub const Curve25519 = struct { |
| 103 | 101 | ||
| 104 | test "curve25519" { | 102 | test "curve25519" { |
| 105 | var s = [32]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 }; | 103 | var s = [32]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8 }; |
| 106 | const p = try Curve25519.basePoint().clampedMul(s); | 104 | const p = try Curve25519.basePoint.clampedMul(s); |
| 107 | try p.rejectIdentity(); | 105 | try p.rejectIdentity(); |
| 108 | var buf: [128]u8 = undefined; | 106 | var buf: [128]u8 = undefined; |
| 109 | std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145"); | 107 | std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E6F2A4D1C28EE5C7AD0329268255A468AD407D2672824C0C0EB30EA6EF450145"); |
lib/std/crypto/25519/ed25519.zig+10-3| ... | @@ -19,12 +19,19 @@ pub const Ed25519 = struct { | ... | @@ -19,12 +19,19 @@ pub const Ed25519 = struct { |
| 19 | pub const noise_length = 32; | 19 | pub const noise_length = 32; |
| 20 | 20 | ||
| 21 | /// Derive a key pair from a secret seed. | 21 | /// Derive a key pair from a secret seed. |
| 22 | /// | ||
| 23 | /// As in RFC 8032, an Ed25519 public key is generated by hashing | ||
| 24 | /// the secret key using the SHA-512 function, and interpreting the | ||
| 25 | /// bit-swapped, clamped lower-half of the output as the secret scalar. | ||
| 26 | /// | ||
| 27 | /// For this reason, an EdDSA secret key is commonly called a seed, | ||
| 28 | /// from which the actual secret is derived. | ||
| 22 | pub fn createKeyPair(seed: [seed_length]u8) ![keypair_length]u8 { | 29 | pub fn createKeyPair(seed: [seed_length]u8) ![keypair_length]u8 { |
| 23 | var az: [Sha512.digest_length]u8 = undefined; | 30 | var az: [Sha512.digest_length]u8 = undefined; |
| 24 | var h = Sha512.init(); | 31 | var h = Sha512.init(); |
| 25 | h.update(&seed); | 32 | h.update(&seed); |
| 26 | h.final(&az); | 33 | h.final(&az); |
| 27 | const p = try Curve.basePoint().clampedMul(az[0..32].*); | 34 | const p = try Curve.basePoint.clampedMul(az[0..32].*); |
| 28 | var keypair: [keypair_length]u8 = undefined; | 35 | var keypair: [keypair_length]u8 = undefined; |
| 29 | mem.copy(u8, &keypair, &seed); | 36 | mem.copy(u8, &keypair, &seed); |
| 30 | mem.copy(u8, keypair[seed_length..], &p.toBytes()); | 37 | mem.copy(u8, keypair[seed_length..], &p.toBytes()); |
| ... | @@ -57,7 +64,7 @@ pub const Ed25519 = struct { | ... | @@ -57,7 +64,7 @@ pub const Ed25519 = struct { |
| 57 | var nonce64: [64]u8 = undefined; | 64 | var nonce64: [64]u8 = undefined; |
| 58 | h.final(&nonce64); | 65 | h.final(&nonce64); |
| 59 | const nonce = Curve.scalar.reduce64(nonce64); | 66 | const nonce = Curve.scalar.reduce64(nonce64); |
| 60 | const r = try Curve.basePoint().mul(nonce); | 67 | const r = try Curve.basePoint.mul(nonce); |
| 61 | 68 | ||
| 62 | var sig: [signature_length]u8 = undefined; | 69 | var sig: [signature_length]u8 = undefined; |
| 63 | mem.copy(u8, sig[0..32], &r.toBytes()); | 70 | mem.copy(u8, sig[0..32], &r.toBytes()); |
| ... | @@ -95,7 +102,7 @@ pub const Ed25519 = struct { | ... | @@ -95,7 +102,7 @@ pub const Ed25519 = struct { |
| 95 | const hram = Curve.scalar.reduce64(hram64); | 102 | const hram = Curve.scalar.reduce64(hram64); |
| 96 | 103 | ||
| 97 | const p = try a.neg().mul(hram); | 104 | const p = try a.neg().mul(hram); |
| 98 | const check = (try Curve.basePoint().mul(s.*)).add(p).toBytes(); | 105 | const check = (try Curve.basePoint.mul(s.*)).add(p).toBytes(); |
| 99 | if (mem.eql(u8, &check, r) == false) { | 106 | if (mem.eql(u8, &check, r) == false) { |
| 100 | return error.InvalidSignature; | 107 | return error.InvalidSignature; |
| 101 | } | 108 | } |
lib/std/crypto/25519/edwards25519.zig+20-28| ... | @@ -50,20 +50,16 @@ pub const Edwards25519 = struct { | ... | @@ -50,20 +50,16 @@ pub const Edwards25519 = struct { |
| 50 | return Fe.rejectNonCanonical(s, true); | 50 | return Fe.rejectNonCanonical(s, true); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | /// Return the Edwards25519 base point. | 53 | /// The edwards25519 base point. |
| 54 | pub inline fn basePoint() Edwards25519 { | 54 | pub const basePoint = Edwards25519{ |
| 55 | return .{ | 55 | .x = Fe{ .limbs = .{ 3990542415680775, 3398198340507945, 4322667446711068, 2814063955482877, 2839572215813860 } }, |
| 56 | .x = Fe{ .limbs = .{ 3990542415680775, 3398198340507945, 4322667446711068, 2814063955482877, 2839572215813860 } }, | 56 | .y = Fe{ .limbs = .{ 1801439850948184, 1351079888211148, 450359962737049, 900719925474099, 1801439850948198 } }, |
| 57 | .y = Fe{ .limbs = .{ 1801439850948184, 1351079888211148, 450359962737049, 900719925474099, 1801439850948198 } }, | 57 | .z = Fe.one, |
| 58 | .z = Fe.one, | 58 | .t = Fe{ .limbs = .{ 1841354044333475, 16398895984059, 755974180946558, 900171276175154, 1821297809914039 } }, |
| 59 | .t = Fe{ .limbs = .{ 1841354044333475, 16398895984059, 755974180946558, 900171276175154, 1821297809914039 } }, | 59 | .is_base = true, |
| 60 | .is_base = true, | 60 | }; |
| 61 | }; | ||
| 62 | } | ||
| 63 | 61 | ||
| 64 | inline fn identityElement() Edwards25519 { | 62 | const identityElement = Edwards25519{ .x = Fe.zero, .y = Fe.one, .z = Fe.one, .t = Fe.zero }; |
| 65 | return .{ .x = Fe.zero, .y = Fe.one, .z = Fe.one, .t = Fe.zero }; | ||
| 66 | } | ||
| 67 | 63 | ||
| 68 | /// Reject the neutral element. | 64 | /// Reject the neutral element. |
| 69 | pub fn rejectIdentity(p: Edwards25519) !void { | 65 | pub fn rejectIdentity(p: Edwards25519) !void { |
| ... | @@ -121,16 +117,16 @@ pub const Edwards25519 = struct { | ... | @@ -121,16 +117,16 @@ pub const Edwards25519 = struct { |
| 121 | } | 117 | } |
| 122 | 118 | ||
| 123 | inline fn pcSelect(pc: [16]Edwards25519, b: u8) Edwards25519 { | 119 | inline fn pcSelect(pc: [16]Edwards25519, b: u8) Edwards25519 { |
| 124 | var t = Edwards25519.identityElement(); | 120 | var t = Edwards25519.identityElement; |
| 125 | comptime var i: u8 = 0; | 121 | comptime var i: u8 = 0; |
| 126 | inline while (i < 16) : (i += 1) { | 122 | inline while (i < 16) : (i += 1) { |
| 127 | t.cMov(pc[i], ((@as(usize, (b ^ i)) -% 1) >> 8) & 1); | 123 | t.cMov(pc[i], ((@as(usize, b ^ i) -% 1) >> 8) & 1); |
| 128 | } | 124 | } |
| 129 | return t; | 125 | return t; |
| 130 | } | 126 | } |
| 131 | 127 | ||
| 132 | fn pcMul(pc: [16]Edwards25519, s: [32]u8) !Edwards25519 { | 128 | fn pcMul(pc: [16]Edwards25519, s: [32]u8) !Edwards25519 { |
| 133 | var q = Edwards25519.identityElement(); | 129 | var q = Edwards25519.identityElement; |
| 134 | var pos: usize = 252; | 130 | var pos: usize = 252; |
| 135 | while (true) : (pos -= 4) { | 131 | while (true) : (pos -= 4) { |
| 136 | q = q.dbl().dbl().dbl().dbl(); | 132 | q = q.dbl().dbl().dbl().dbl(); |
| ... | @@ -144,7 +140,7 @@ pub const Edwards25519 = struct { | ... | @@ -144,7 +140,7 @@ pub const Edwards25519 = struct { |
| 144 | 140 | ||
| 145 | fn precompute(p: Edwards25519) [16]Edwards25519 { | 141 | fn precompute(p: Edwards25519) [16]Edwards25519 { |
| 146 | var pc: [16]Edwards25519 = undefined; | 142 | var pc: [16]Edwards25519 = undefined; |
| 147 | pc[0] = Edwards25519.identityElement(); | 143 | pc[0] = Edwards25519.identityElement; |
| 148 | pc[1] = p; | 144 | pc[1] = p; |
| 149 | var i: usize = 2; | 145 | var i: usize = 2; |
| 150 | while (i < 16) : (i += 1) { | 146 | while (i < 16) : (i += 1) { |
| ... | @@ -153,11 +149,14 @@ pub const Edwards25519 = struct { | ... | @@ -153,11 +149,14 @@ pub const Edwards25519 = struct { |
| 153 | return pc; | 149 | return pc; |
| 154 | } | 150 | } |
| 155 | 151 | ||
| 156 | fn _mul(p: Edwards25519, s: [32]u8) !Edwards25519 { | 152 | /// Multiply an Edwards25519 point by a scalar without clamping it. |
| 153 | /// Return error.WeakPublicKey if the resulting point is | ||
| 154 | /// the identity element. | ||
| 155 | pub fn mul(p: Edwards25519, s: [32]u8) !Edwards25519 { | ||
| 157 | var pc: [16]Edwards25519 = undefined; | 156 | var pc: [16]Edwards25519 = undefined; |
| 158 | if (p.is_base) { | 157 | if (p.is_base) { |
| 159 | @setEvalBranchQuota(10000); | 158 | @setEvalBranchQuota(10000); |
| 160 | pc = comptime precompute(Edwards25519.basePoint()); | 159 | pc = comptime precompute(Edwards25519.basePoint); |
| 161 | } else { | 160 | } else { |
| 162 | pc = precompute(p); | 161 | pc = precompute(p); |
| 163 | pc[4].rejectIdentity() catch |_| return error.WeakPublicKey; | 162 | pc[4].rejectIdentity() catch |_| return error.WeakPublicKey; |
| ... | @@ -174,20 +173,13 @@ pub const Edwards25519 = struct { | ... | @@ -174,20 +173,13 @@ pub const Edwards25519 = struct { |
| 174 | pub fn clampedMul(p: Edwards25519, s: [32]u8) !Edwards25519 { | 173 | pub fn clampedMul(p: Edwards25519, s: [32]u8) !Edwards25519 { |
| 175 | var t: [32]u8 = s; | 174 | var t: [32]u8 = s; |
| 176 | scalar.clamp(&t); | 175 | scalar.clamp(&t); |
| 177 | return _mul(p, t); | 176 | return mul(p, t); |
| 178 | } | ||
| 179 | |||
| 180 | /// Multiply an Edwards25519 point by a scalar without clamping it. | ||
| 181 | /// Return error.WeakPublicKey if the resulting point is | ||
| 182 | /// the identity element. | ||
| 183 | pub fn mul(p: Edwards25519, s: [32]u8) !Edwards25519 { | ||
| 184 | return _mul(p, s); | ||
| 185 | } | 177 | } |
| 186 | }; | 178 | }; |
| 187 | 179 | ||
| 188 | test "edwards25519 packing/unpacking" { | 180 | test "edwards25519 packing/unpacking" { |
| 189 | const s = [_]u8{170} ++ [_]u8{0} ** 31; | 181 | const s = [_]u8{170} ++ [_]u8{0} ** 31; |
| 190 | var b = Edwards25519.basePoint(); | 182 | var b = Edwards25519.basePoint; |
| 191 | const pk = try b.mul(s); | 183 | const pk = try b.mul(s); |
| 192 | var buf: [128]u8 = undefined; | 184 | var buf: [128]u8 = undefined; |
| 193 | std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{pk.toBytes()}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6"); | 185 | std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{pk.toBytes()}), "074BC7E0FCBD587FDBC0969444245FADC562809C8F6E97E949AF62484B5B81A6"); |
lib/std/crypto/25519/ristretto255.zig+3-5| ... | @@ -43,10 +43,8 @@ pub const Ristretto255 = struct { | ... | @@ -43,10 +43,8 @@ pub const Ristretto255 = struct { |
| 43 | return p.p.rejectIdentity(); | 43 | return p.p.rejectIdentity(); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | /// Return the base point (Ristretto is a curve in desguise). | 46 | /// The base point (Ristretto is a curve in desguise). |
| 47 | pub inline fn basePoint() Ristretto255 { | 47 | pub const basePoint = Ristretto255{ .p = Curve.basePoint }; |
| 48 | return .{ .p = Curve.basePoint() }; | ||
| 49 | } | ||
| 50 | 48 | ||
| 51 | /// Decode a Ristretto255 representative. | 49 | /// Decode a Ristretto255 representative. |
| 52 | pub fn fromBytes(s: [32]u8) !Ristretto255 { | 50 | pub fn fromBytes(s: [32]u8) !Ristretto255 { |
| ... | @@ -130,7 +128,7 @@ pub const Ristretto255 = struct { | ... | @@ -130,7 +128,7 @@ pub const Ristretto255 = struct { |
| 130 | }; | 128 | }; |
| 131 | 129 | ||
| 132 | test "ristretto255" { | 130 | test "ristretto255" { |
| 133 | const p = Ristretto255.basePoint(); | 131 | const p = Ristretto255.basePoint; |
| 134 | var buf: [256]u8 = undefined; | 132 | var buf: [256]u8 = undefined; |
| 135 | std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76"); | 133 | std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{p.toBytes()}), "E2F2AE0A6ABC4E71A884A961C500515F58E30B6AA582DD8DB6A65945E08D2D76"); |
| 136 | 134 |
lib/std/crypto/25519/x25519.zig+13-13| ... | @@ -17,7 +17,7 @@ pub const X25519 = struct { | ... | @@ -17,7 +17,7 @@ pub const X25519 = struct { |
| 17 | std.debug.assert(public_key.len >= minimum_key_length); | 17 | std.debug.assert(public_key.len >= minimum_key_length); |
| 18 | var s: [32]u8 = undefined; | 18 | var s: [32]u8 = undefined; |
| 19 | mem.copy(u8, &s, private_key[0..32]); | 19 | mem.copy(u8, &s, private_key[0..32]); |
| 20 | if (Curve.basePoint().clampedMul(s)) |q| { | 20 | if (Curve.basePoint.clampedMul(s)) |q| { |
| 21 | mem.copy(u8, public_key, q.toBytes()[0..]); | 21 | mem.copy(u8, public_key, q.toBytes()[0..]); |
| 22 | return true; | 22 | return true; |
| 23 | } else |_| { | 23 | } else |_| { |
| ... | @@ -52,7 +52,7 @@ test "x25519 public key calculation from secret key" { | ... | @@ -52,7 +52,7 @@ test "x25519 public key calculation from secret key" { |
| 52 | try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); | 52 | try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); |
| 53 | try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50"); | 53 | try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50"); |
| 54 | std.testing.expect(X25519.createPublicKey(pk_calculated[0..], &sk)); | 54 | std.testing.expect(X25519.createPublicKey(pk_calculated[0..], &sk)); |
| 55 | std.testing.expect(std.mem.eql(u8, &pk_calculated, &pk_expected)); | 55 | std.testing.expectEqual(pk_calculated, pk_expected); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | test "x25519 rfc7748 vector1" { | 58 | test "x25519 rfc7748 vector1" { |
| ... | @@ -64,7 +64,7 @@ test "x25519 rfc7748 vector1" { | ... | @@ -64,7 +64,7 @@ test "x25519 rfc7748 vector1" { |
| 64 | var output: [32]u8 = undefined; | 64 | var output: [32]u8 = undefined; |
| 65 | 65 | ||
| 66 | std.testing.expect(X25519.create(output[0..], secret_key[0..], public_key[0..])); | 66 | std.testing.expect(X25519.create(output[0..], secret_key[0..], public_key[0..])); |
| 67 | std.testing.expect(std.mem.eql(u8, &output, expected_output[0..])); | 67 | std.testing.expectEqual(output, expected_output); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | test "x25519 rfc7748 vector2" { | 70 | test "x25519 rfc7748 vector2" { |
| ... | @@ -76,7 +76,7 @@ test "x25519 rfc7748 vector2" { | ... | @@ -76,7 +76,7 @@ test "x25519 rfc7748 vector2" { |
| 76 | var output: [32]u8 = undefined; | 76 | var output: [32]u8 = undefined; |
| 77 | 77 | ||
| 78 | std.testing.expect(X25519.create(output[0..], secret_key[0..], public_key[0..])); | 78 | std.testing.expect(X25519.create(output[0..], secret_key[0..], public_key[0..])); |
| 79 | std.testing.expect(std.mem.eql(u8, &output, expected_output[0..])); | 79 | std.testing.expectEqual(output, expected_output); |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | test "x25519 rfc7748 one iteration" { | 82 | test "x25519 rfc7748 one iteration" { |
| ... | @@ -91,11 +91,11 @@ test "x25519 rfc7748 one iteration" { | ... | @@ -91,11 +91,11 @@ test "x25519 rfc7748 one iteration" { |
| 91 | var output: [32]u8 = undefined; | 91 | var output: [32]u8 = undefined; |
| 92 | std.testing.expect(X25519.create(output[0..], &k, &u)); | 92 | std.testing.expect(X25519.create(output[0..], &k, &u)); |
| 93 | 93 | ||
| 94 | std.mem.copy(u8, u[0..], k[0..]); | 94 | mem.copy(u8, u[0..], k[0..]); |
| 95 | std.mem.copy(u8, k[0..], output[0..]); | 95 | mem.copy(u8, k[0..], output[0..]); |
| 96 | } | 96 | } |
| 97 | 97 | ||
| 98 | std.testing.expect(std.mem.eql(u8, k[0..], expected_output[0..])); | 98 | std.testing.expectEqual(k, expected_output); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | test "x25519 rfc7748 1,000 iterations" { | 101 | test "x25519 rfc7748 1,000 iterations" { |
| ... | @@ -115,11 +115,11 @@ test "x25519 rfc7748 1,000 iterations" { | ... | @@ -115,11 +115,11 @@ test "x25519 rfc7748 1,000 iterations" { |
| 115 | var output: [32]u8 = undefined; | 115 | var output: [32]u8 = undefined; |
| 116 | std.testing.expect(X25519.create(output[0..], &k, &u)); | 116 | std.testing.expect(X25519.create(output[0..], &k, &u)); |
| 117 | 117 | ||
| 118 | std.mem.copy(u8, u[0..], k[0..]); | 118 | mem.copy(u8, u[0..], k[0..]); |
| 119 | std.mem.copy(u8, k[0..], output[0..]); | 119 | mem.copy(u8, k[0..], output[0..]); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | std.testing.expect(std.mem.eql(u8, k[0..], expected_output)); | 122 | std.testing.expectEqual(k, expected_output); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | test "x25519 rfc7748 1,000,000 iterations" { | 125 | test "x25519 rfc7748 1,000,000 iterations" { |
| ... | @@ -138,9 +138,9 @@ test "x25519 rfc7748 1,000,000 iterations" { | ... | @@ -138,9 +138,9 @@ test "x25519 rfc7748 1,000,000 iterations" { |
| 138 | var output: [32]u8 = undefined; | 138 | var output: [32]u8 = undefined; |
| 139 | std.testing.expect(X25519.create(output[0..], &k, &u)); | 139 | std.testing.expect(X25519.create(output[0..], &k, &u)); |
| 140 | 140 | ||
| 141 | std.mem.copy(u8, u[0..], k[0..]); | 141 | mem.copy(u8, u[0..], k[0..]); |
| 142 | std.mem.copy(u8, k[0..], output[0..]); | 142 | mem.copy(u8, k[0..], output[0..]); |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | std.testing.expect(std.mem.eql(u8, k[0..], expected_output)); | 145 | std.testing.expectEqual(k[0..], expected_output); |
| 146 | } | 146 | } |