authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2020-10-25 21:55:05+01:00
committergravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2020-10-25 21:55:05+01:00
log0c7a99b38d2fb881cde5125ef0729ff0427c06a6
tree5d9fef96a97108ab487d3ab1713a0a13a7dbf339
parent28fb97f1885ea54dd2a1ee2d06b2a73b009b1850

Move ed25519 key pairs to a KeyPair structure


2 files changed, 65 insertions(+), 63 deletions(-)

lib/std/crypto/25519/ed25519.zig+60-50
...@@ -5,6 +5,7 @@...@@ -5,6 +5,7 @@
5// and substantial portions of the software.5// and substantial portions of the software.
6const std = @import("std");6const std = @import("std");
7const crypto = std.crypto;7const crypto = std.crypto;
8const debug = std.debug;
8const fmt = std.fmt;9const fmt = std.fmt;
9const mem = std.mem;10const mem = std.mem;
10const Sha512 = std.crypto.hash.sha2.Sha512;11const Sha512 = std.crypto.hash.sha2.Sha512;
...@@ -15,8 +16,8 @@ pub const Ed25519 = struct {...@@ -15,8 +16,8 @@ pub const Ed25519 = struct {
15 pub const Curve = @import("edwards25519.zig").Edwards25519;16 pub const Curve = @import("edwards25519.zig").Edwards25519;
16 /// Length (in bytes) of a seed required to create a key pair.17 /// Length (in bytes) of a seed required to create a key pair.
17 pub const seed_length = 32;18 pub const seed_length = 32;
18 /// Length (in bytes) of a compressed key pair.19 /// Length (in bytes) of a compressed secret key.
19 pub const keypair_length = 64;20 pub const secret_length = 64;
20 /// Length (in bytes) of a compressed public key.21 /// Length (in bytes) of a compressed public key.
21 pub const public_length = 32;22 pub const public_length = 32;
22 /// Length (in bytes) of a signature.23 /// Length (in bytes) of a signature.
...@@ -24,46 +25,61 @@ pub const Ed25519 = struct {...@@ -24,46 +25,61 @@ pub const Ed25519 = struct {
24 /// Length (in bytes) of optional random bytes, for non-deterministic signatures.25 /// Length (in bytes) of optional random bytes, for non-deterministic signatures.
25 pub const noise_length = 32;26 pub const noise_length = 32;
2627
27 /// Derive a key pair from a secret seed.28 /// An Ed25519 key pair.
28 ///29 pub const KeyPair = struct {
29 /// As in RFC 8032, an Ed25519 public key is generated by hashing30 /// Public part.
30 /// the secret key using the SHA-512 function, and interpreting the31 public_key: [public_length]u8,
31 /// bit-swapped, clamped lower-half of the output as the secret scalar.32 /// Secret part. What we expose as a secret key is, under the hood, the concatenation of the seed and the public key.
32 ///33 secret_key: [secret_length]u8,
33 /// For this reason, an EdDSA secret key is commonly called a seed,
34 /// from which the actual secret is derived.
35 pub fn createKeyPair(seed: ?[seed_length]u8) ![keypair_length]u8 {
36 const sk = seed orelse sk: {
37 var random_seed: [seed_length]u8 = undefined;
38 try crypto.randomBytes(&random_seed);
39 break :sk random_seed;
40 };
41 var az: [Sha512.digest_length]u8 = undefined;
42 var h = Sha512.init(.{});
43 h.update(&sk);
44 h.final(&az);
45 const p = try Curve.basePoint.clampedMul(az[0..32].*);
46 var keypair: [keypair_length]u8 = undefined;
47 mem.copy(u8, &keypair, &sk);
48 mem.copy(u8, keypair[seed_length..], &p.toBytes());
49 return keypair;
50 }
5134
52 /// Return the public key for a given key pair.35 /// Derive a key pair from an optional secret seed.
53 pub fn publicKey(key_pair: [keypair_length]u8) [public_length]u8 {36 ///
54 var public_key: [public_length]u8 = undefined;37 /// As in RFC 8032, an Ed25519 public key is generated by hashing
55 mem.copy(u8, public_key[0..], key_pair[seed_length..]);38 /// the secret key using the SHA-512 function, and interpreting the
56 return public_key;39 /// bit-swapped, clamped lower-half of the output as the secret scalar.
57 }40 ///
41 /// For this reason, an EdDSA secret key is commonly called a seed,
42 /// from which the actual secret is derived.
43 pub fn create(seed: ?[seed_length]u8) !KeyPair {
44 const ss = seed orelse ss: {
45 var random_seed: [seed_length]u8 = undefined;
46 try crypto.randomBytes(&random_seed);
47 break :ss random_seed;
48 };
49 var az: [Sha512.digest_length]u8 = undefined;
50 var h = Sha512.init(.{});
51 h.update(&ss);
52 h.final(&az);
53 const p = try Curve.basePoint.clampedMul(az[0..32].*);
54 var sk: [secret_length]u8 = undefined;
55 mem.copy(u8, &sk, &ss);
56 const pk = p.toBytes();
57 mem.copy(u8, sk[seed_length..], &pk);
58
59 return KeyPair{ .public_key = pk, .secret_key = sk };
60 }
61
62 /// Create a KeyPair from a secret key.
63 pub fn fromSecretKey(secret_key: [secret_length]u8) KeyPair {
64 return KeyPair{
65 .secret_key = secret_key,
66 .public_key = secret_key[seed_length..].*,
67 };
68 }
69 };
5870
59 /// Sign a message using a key pair, and optional random noise.71 /// Sign a message using a key pair, and optional random noise.
60 /// Having noise creates non-standard, non-deterministic signatures,72 /// Having noise creates non-standard, non-deterministic signatures,
61 /// but has been proven to increase resilience against fault attacks.73 /// but has been proven to increase resilience against fault attacks.
62 pub fn sign(msg: []const u8, key_pair: [keypair_length]u8, noise: ?[noise_length]u8) ![signature_length]u8 {74 pub fn sign(msg: []const u8, key_pair: KeyPair, noise: ?[noise_length]u8) ![signature_length]u8 {
63 const public_key = key_pair[32..];75 const seed = key_pair.secret_key[0..seed_length];
76 const public_key = key_pair.secret_key[seed_length..];
77 if (!mem.eql(u8, public_key, &key_pair.public_key)) {
78 return error.KeyMismatch;
79 }
64 var az: [Sha512.digest_length]u8 = undefined;80 var az: [Sha512.digest_length]u8 = undefined;
65 var h = Sha512.init(.{});81 var h = Sha512.init(.{});
66 h.update(key_pair[0..seed_length]);82 h.update(seed);
67 h.final(&az);83 h.final(&az);
6884
69 h = Sha512.init(.{});85 h = Sha512.init(.{});
...@@ -192,50 +208,44 @@ pub const Ed25519 = struct {...@@ -192,50 +208,44 @@ pub const Ed25519 = struct {
192test "ed25519 key pair creation" {208test "ed25519 key pair creation" {
193 var seed: [32]u8 = undefined;209 var seed: [32]u8 = undefined;
194 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");210 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
195 const key_pair = try Ed25519.createKeyPair(seed);211 const key_pair = try Ed25519.KeyPair.create(seed);
196 var buf: [256]u8 = undefined;212 var buf: [256]u8 = undefined;
197 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");213 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.secret_key}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
198214 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{key_pair.public_key}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
199 const public_key = Ed25519.publicKey(key_pair);
200 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{public_key}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
201}215}
202216
203test "ed25519 signature" {217test "ed25519 signature" {
204 var seed: [32]u8 = undefined;218 var seed: [32]u8 = undefined;
205 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");219 try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
206 const key_pair = try Ed25519.createKeyPair(seed);220 const key_pair = try Ed25519.KeyPair.create(seed);
207221
208 const sig = try Ed25519.sign("test", key_pair, null);222 const sig = try Ed25519.sign("test", key_pair, null);
209 var buf: [128]u8 = undefined;223 var buf: [128]u8 = undefined;
210 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{sig}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");224 std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{X}", .{sig}), "10A442B4A80CC4225B154F43BEF28D2472CA80221951262EB8E0DF9091575E2687CC486E77263C3418C757522D54F84B0359236ABBBD4ACD20DC297FDCA66808");
211 const public_key = Ed25519.publicKey(key_pair);225 try Ed25519.verify(sig, "test", key_pair.public_key);
212 try Ed25519.verify(sig, "test", public_key);226 std.testing.expectError(error.InvalidSignature, Ed25519.verify(sig, "TEST", key_pair.public_key));
213 std.testing.expectError(error.InvalidSignature, Ed25519.verify(sig, "TEST", public_key));
214}227}
215228
216test "ed25519 batch verification" {229test "ed25519 batch verification" {
217 var i: usize = 0;230 var i: usize = 0;
218 while (i < 100) : (i += 1) {231 while (i < 100) : (i += 1) {
219 var seed: [32]u8 = undefined;232 const key_pair = try Ed25519.KeyPair.create(null);
220 try std.crypto.randomBytes(&seed);
221 const key_pair = try Ed25519.createKeyPair(seed);
222 var msg1: [32]u8 = undefined;233 var msg1: [32]u8 = undefined;
223 var msg2: [32]u8 = undefined;234 var msg2: [32]u8 = undefined;
224 try std.crypto.randomBytes(&msg1);235 try std.crypto.randomBytes(&msg1);
225 try std.crypto.randomBytes(&msg2);236 try std.crypto.randomBytes(&msg2);
226 const sig1 = try Ed25519.sign(&msg1, key_pair, null);237 const sig1 = try Ed25519.sign(&msg1, key_pair, null);
227 const sig2 = try Ed25519.sign(&msg2, key_pair, null);238 const sig2 = try Ed25519.sign(&msg2, key_pair, null);
228 const public_key = Ed25519.publicKey(key_pair);
229 var signature_batch = [_]Ed25519.BatchElement{239 var signature_batch = [_]Ed25519.BatchElement{
230 Ed25519.BatchElement{240 Ed25519.BatchElement{
231 .sig = sig1,241 .sig = sig1,
232 .msg = &msg1,242 .msg = &msg1,
233 .public_key = public_key,243 .public_key = key_pair.public_key,
234 },244 },
235 Ed25519.BatchElement{245 Ed25519.BatchElement{
236 .sig = sig2,246 .sig = sig2,
237 .msg = &msg2,247 .msg = &msg2,
238 .public_key = public_key,248 .public_key = key_pair.public_key,
239 },249 },
240 };250 };
241 try Ed25519.verifyBatch(2, signature_batch);251 try Ed25519.verifyBatch(2, signature_batch);
lib/std/crypto/benchmark.zig+5-13
...@@ -124,10 +124,8 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c...@@ -124,10 +124,8 @@ pub fn benchmarkKeyExchange(comptime DhKeyExchange: anytype, comptime exchange_c
124const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};124const signatures = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
125125
126pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {126pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
127 var seed: [Signature.seed_length]u8 = undefined;
128 prng.random.bytes(seed[0..]);
129 const msg = [_]u8{0} ** 64;127 const msg = [_]u8{0} ** 64;
130 const key_pair = try Signature.createKeyPair(seed);128 const key_pair = try Signature.KeyPair.create(null);
131129
132 var timer = try Timer.start();130 var timer = try Timer.start();
133 const start = timer.lap();131 const start = timer.lap();
...@@ -149,11 +147,8 @@ pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count...@@ -149,11 +147,8 @@ pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count
149const signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};147const signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
150148
151pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {149pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
152 var seed: [Signature.seed_length]u8 = undefined;
153 prng.random.bytes(seed[0..]);
154 const msg = [_]u8{0} ** 64;150 const msg = [_]u8{0} ** 64;
155 const key_pair = try Signature.createKeyPair(seed);151 const key_pair = try Signature.KeyPair.create(null);
156 const public_key = Signature.publicKey(key_pair);
157 const sig = try Signature.sign(&msg, key_pair, null);152 const sig = try Signature.sign(&msg, key_pair, null);
158153
159 var timer = try Timer.start();154 var timer = try Timer.start();
...@@ -161,7 +156,7 @@ pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime sign...@@ -161,7 +156,7 @@ pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime sign
161 {156 {
162 var i: usize = 0;157 var i: usize = 0;
163 while (i < signatures_count) : (i += 1) {158 while (i < signatures_count) : (i += 1) {
164 try Signature.verify(sig, &msg, public_key);159 try Signature.verify(sig, &msg, key_pair.public_key);
165 mem.doNotOptimizeAway(&sig);160 mem.doNotOptimizeAway(&sig);
166 }161 }
167 }162 }
...@@ -176,16 +171,13 @@ pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime sign...@@ -176,16 +171,13 @@ pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime sign
176const batch_signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};171const batch_signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
177172
178pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {173pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
179 var seed: [Signature.seed_length]u8 = undefined;
180 prng.random.bytes(seed[0..]);
181 const msg = [_]u8{0} ** 64;174 const msg = [_]u8{0} ** 64;
182 const key_pair = try Signature.createKeyPair(seed);175 const key_pair = try Signature.KeyPair.create(null);
183 const public_key = Signature.publicKey(key_pair);
184 const sig = try Signature.sign(&msg, key_pair, null);176 const sig = try Signature.sign(&msg, key_pair, null);
185177
186 var batch: [64]Signature.BatchElement = undefined;178 var batch: [64]Signature.BatchElement = undefined;
187 for (batch) |*element| {179 for (batch) |*element| {
188 element.* = Signature.BatchElement{ .sig = sig, .msg = &msg, .public_key = public_key };180 element.* = Signature.BatchElement{ .sig = sig, .msg = &msg, .public_key = key_pair.public_key };
189 }181 }
190182
191 var timer = try Timer.start();183 var timer = try Timer.start();