mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-09 15:19:07 +00:00
std.crypto: make the key pair API creation consistent (#21955)
Our key pair creation API was ugly and inconsistent between ecdsa keys and other keys. The same `generate()` function can now be used to generate key pairs, and that function cannot fail. For deterministic keys, a `generateDeterministic()` function is available for all key types. Fix comments and compilation of the benchmark by the way. Fixes #21002
This commit is contained in:
parent
94be75a94f
commit
8a00bd4ce6
7 changed files with 102 additions and 66 deletions
|
|
@ -245,7 +245,9 @@ pub const Ed25519 = struct {
|
||||||
/// Secret scalar.
|
/// Secret scalar.
|
||||||
secret_key: SecretKey,
|
secret_key: SecretKey,
|
||||||
|
|
||||||
/// Derive a key pair from an optional secret seed.
|
/// Deterministically derive a key pair from a cryptograpically secure secret seed.
|
||||||
|
///
|
||||||
|
/// Except in tests, applications should generally call `generate()` instead of this function.
|
||||||
///
|
///
|
||||||
/// As in RFC 8032, an Ed25519 public key is generated by hashing
|
/// As in RFC 8032, an Ed25519 public key is generated by hashing
|
||||||
/// the secret key using the SHA-512 function, and interpreting the
|
/// the secret key using the SHA-512 function, and interpreting the
|
||||||
|
|
@ -253,20 +255,15 @@ pub const Ed25519 = struct {
|
||||||
///
|
///
|
||||||
/// For this reason, an EdDSA secret key is commonly called a seed,
|
/// For this reason, an EdDSA secret key is commonly called a seed,
|
||||||
/// from which the actual secret is derived.
|
/// from which the actual secret is derived.
|
||||||
pub fn create(seed: ?[seed_length]u8) IdentityElementError!KeyPair {
|
pub fn generateDeterministic(seed: [seed_length]u8) IdentityElementError!KeyPair {
|
||||||
const ss = seed orelse ss: {
|
|
||||||
var random_seed: [seed_length]u8 = undefined;
|
|
||||||
crypto.random.bytes(&random_seed);
|
|
||||||
break :ss random_seed;
|
|
||||||
};
|
|
||||||
var az: [Sha512.digest_length]u8 = undefined;
|
var az: [Sha512.digest_length]u8 = undefined;
|
||||||
var h = Sha512.init(.{});
|
var h = Sha512.init(.{});
|
||||||
h.update(&ss);
|
h.update(&seed);
|
||||||
h.final(&az);
|
h.final(&az);
|
||||||
const pk_p = Curve.basePoint.clampedMul(az[0..32].*) catch return error.IdentityElement;
|
const pk_p = Curve.basePoint.clampedMul(az[0..32].*) catch return error.IdentityElement;
|
||||||
const pk_bytes = pk_p.toBytes();
|
const pk_bytes = pk_p.toBytes();
|
||||||
var sk_bytes: [SecretKey.encoded_length]u8 = undefined;
|
var sk_bytes: [SecretKey.encoded_length]u8 = undefined;
|
||||||
sk_bytes[0..ss.len].* = ss;
|
sk_bytes[0..seed_length].* = seed;
|
||||||
sk_bytes[seed_length..].* = pk_bytes;
|
sk_bytes[seed_length..].* = pk_bytes;
|
||||||
return KeyPair{
|
return KeyPair{
|
||||||
.public_key = PublicKey.fromBytes(pk_bytes) catch unreachable,
|
.public_key = PublicKey.fromBytes(pk_bytes) catch unreachable,
|
||||||
|
|
@ -274,7 +271,22 @@ pub const Ed25519 = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a KeyPair from a secret key.
|
/// Generate a new, random key pair.
|
||||||
|
///
|
||||||
|
/// `crypto.random.bytes` must be supported by the target.
|
||||||
|
pub fn generate() KeyPair {
|
||||||
|
var random_seed: [seed_length]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
crypto.random.bytes(&random_seed);
|
||||||
|
return generateDeterministic(random_seed) catch {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a key pair from an existing secret key.
|
||||||
|
///
|
||||||
/// Note that with EdDSA, storing the seed, and recovering the key pair
|
/// Note that with EdDSA, storing the seed, and recovering the key pair
|
||||||
/// from it is recommended over storing the entire secret key.
|
/// from it is recommended over storing the entire secret key.
|
||||||
/// The seed of an exiting key pair can be obtained with
|
/// The seed of an exiting key pair can be obtained with
|
||||||
|
|
@ -285,7 +297,7 @@ pub const Ed25519 = struct {
|
||||||
// With runtime safety, we can still afford checking that the public key is correct.
|
// With runtime safety, we can still afford checking that the public key is correct.
|
||||||
if (std.debug.runtime_safety) {
|
if (std.debug.runtime_safety) {
|
||||||
const pk_p = try Curve.fromBytes(secret_key.publicKeyBytes());
|
const pk_p = try Curve.fromBytes(secret_key.publicKeyBytes());
|
||||||
const recomputed_kp = try create(secret_key.seed());
|
const recomputed_kp = try generateDeterministic(secret_key.seed());
|
||||||
debug.assert(mem.eql(u8, &recomputed_kp.public_key.toBytes(), &pk_p.toBytes()));
|
debug.assert(mem.eql(u8, &recomputed_kp.public_key.toBytes(), &pk_p.toBytes()));
|
||||||
}
|
}
|
||||||
return KeyPair{
|
return KeyPair{
|
||||||
|
|
@ -492,7 +504,7 @@ pub const Ed25519 = struct {
|
||||||
test "key pair creation" {
|
test "key pair creation" {
|
||||||
var seed: [32]u8 = undefined;
|
var seed: [32]u8 = undefined;
|
||||||
_ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
|
_ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
|
||||||
const key_pair = try Ed25519.KeyPair.create(seed);
|
const key_pair = try Ed25519.KeyPair.generateDeterministic(seed);
|
||||||
var buf: [256]u8 = undefined;
|
var buf: [256]u8 = undefined;
|
||||||
try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.secret_key.toBytes())}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
|
try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.secret_key.toBytes())}), "8052030376D47112BE7F73ED7A019293DD12AD910B654455798B4667D73DE1662D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
|
||||||
try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key.toBytes())}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
|
try std.testing.expectEqualStrings(try std.fmt.bufPrint(&buf, "{s}", .{std.fmt.fmtSliceHexUpper(&key_pair.public_key.toBytes())}), "2D6F7455D97B4A3A10D7293909D1A4F2058CB9A370E43FA8154BB280DB839083");
|
||||||
|
|
@ -501,7 +513,7 @@ test "key pair creation" {
|
||||||
test "signature" {
|
test "signature" {
|
||||||
var seed: [32]u8 = undefined;
|
var seed: [32]u8 = undefined;
|
||||||
_ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
|
_ = try fmt.hexToBytes(seed[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166");
|
||||||
const key_pair = try Ed25519.KeyPair.create(seed);
|
const key_pair = try Ed25519.KeyPair.generateDeterministic(seed);
|
||||||
|
|
||||||
const sig = try key_pair.sign("test", null);
|
const sig = try key_pair.sign("test", null);
|
||||||
var buf: [128]u8 = undefined;
|
var buf: [128]u8 = undefined;
|
||||||
|
|
@ -513,7 +525,7 @@ test "signature" {
|
||||||
test "batch verification" {
|
test "batch verification" {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < 100) : (i += 1) {
|
while (i < 100) : (i += 1) {
|
||||||
const key_pair = try Ed25519.KeyPair.create(null);
|
const key_pair = Ed25519.KeyPair.generate();
|
||||||
var msg1: [32]u8 = undefined;
|
var msg1: [32]u8 = undefined;
|
||||||
var msg2: [32]u8 = undefined;
|
var msg2: [32]u8 = undefined;
|
||||||
crypto.random.bytes(&msg1);
|
crypto.random.bytes(&msg1);
|
||||||
|
|
@ -645,7 +657,7 @@ test "with blind keys" {
|
||||||
const BlindKeyPair = Ed25519.key_blinding.BlindKeyPair;
|
const BlindKeyPair = Ed25519.key_blinding.BlindKeyPair;
|
||||||
|
|
||||||
// Create a standard Ed25519 key pair
|
// Create a standard Ed25519 key pair
|
||||||
const kp = try Ed25519.KeyPair.create(null);
|
const kp = Ed25519.KeyPair.generate();
|
||||||
|
|
||||||
// Create a random blinding seed
|
// Create a random blinding seed
|
||||||
var blind: [32]u8 = undefined;
|
var blind: [32]u8 = undefined;
|
||||||
|
|
@ -665,7 +677,7 @@ test "with blind keys" {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "signatures with streaming" {
|
test "signatures with streaming" {
|
||||||
const kp = try Ed25519.KeyPair.create(null);
|
const kp = Ed25519.KeyPair.generate();
|
||||||
|
|
||||||
var signer = try kp.signer(null);
|
var signer = try kp.signer(null);
|
||||||
signer.update("mes");
|
signer.update("mes");
|
||||||
|
|
@ -681,7 +693,7 @@ test "signatures with streaming" {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "key pair from secret key" {
|
test "key pair from secret key" {
|
||||||
const kp = try Ed25519.KeyPair.create(null);
|
const kp = Ed25519.KeyPair.generate();
|
||||||
const kp2 = try Ed25519.KeyPair.fromSecretKey(kp.secret_key);
|
const kp2 = try Ed25519.KeyPair.fromSecretKey(kp.secret_key);
|
||||||
try std.testing.expectEqualSlices(u8, &kp.secret_key.toBytes(), &kp2.secret_key.toBytes());
|
try std.testing.expectEqualSlices(u8, &kp.secret_key.toBytes(), &kp2.secret_key.toBytes());
|
||||||
try std.testing.expectEqualSlices(u8, &kp.public_key.toBytes(), &kp2.public_key.toBytes());
|
try std.testing.expectEqualSlices(u8, &kp.public_key.toBytes(), &kp2.public_key.toBytes());
|
||||||
|
|
|
||||||
|
|
@ -29,19 +29,29 @@ pub const X25519 = struct {
|
||||||
/// Secret part.
|
/// Secret part.
|
||||||
secret_key: [secret_length]u8,
|
secret_key: [secret_length]u8,
|
||||||
|
|
||||||
/// Create a new key pair using an optional seed.
|
/// Deterministically derive a key pair from a cryptograpically secure secret seed.
|
||||||
pub fn create(seed: ?[seed_length]u8) IdentityElementError!KeyPair {
|
///
|
||||||
const sk = seed orelse sk: {
|
/// Except in tests, applications should generally call `generate()` instead of this function.
|
||||||
var random_seed: [seed_length]u8 = undefined;
|
pub fn generateDeterministic(seed: [seed_length]u8) IdentityElementError!KeyPair {
|
||||||
crypto.random.bytes(&random_seed);
|
const kp = KeyPair{
|
||||||
break :sk random_seed;
|
.public_key = try X25519.recoverPublicKey(seed),
|
||||||
|
.secret_key = seed,
|
||||||
};
|
};
|
||||||
var kp: KeyPair = undefined;
|
|
||||||
kp.secret_key = sk;
|
|
||||||
kp.public_key = try X25519.recoverPublicKey(sk);
|
|
||||||
return kp;
|
return kp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a new, random key pair.
|
||||||
|
pub fn generate() KeyPair {
|
||||||
|
var random_seed: [seed_length]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
crypto.random.bytes(&random_seed);
|
||||||
|
return generateDeterministic(random_seed) catch {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a key pair from an Ed25519 key pair
|
/// Create a key pair from an Ed25519 key pair
|
||||||
pub fn fromEd25519(ed25519_key_pair: crypto.sign.Ed25519.KeyPair) (IdentityElementError || EncodingError)!KeyPair {
|
pub fn fromEd25519(ed25519_key_pair: crypto.sign.Ed25519.KeyPair) (IdentityElementError || EncodingError)!KeyPair {
|
||||||
const seed = ed25519_key_pair.secret_key.seed();
|
const seed = ed25519_key_pair.secret_key.seed();
|
||||||
|
|
@ -171,7 +181,7 @@ test "rfc7748 1,000,000 iterations" {
|
||||||
}
|
}
|
||||||
|
|
||||||
test "edwards25519 -> curve25519 map" {
|
test "edwards25519 -> curve25519 map" {
|
||||||
const ed_kp = try crypto.sign.Ed25519.KeyPair.create([_]u8{0x42} ** 32);
|
const ed_kp = try crypto.sign.Ed25519.KeyPair.generateDeterministic([_]u8{0x42} ** 32);
|
||||||
const mont_kp = try X25519.KeyPair.fromEd25519(ed_kp);
|
const mont_kp = try X25519.KeyPair.fromEd25519(ed_kp);
|
||||||
try htest.assertEqual("90e7595fc89e52fdfddce9c6a43d74dbf6047025ee0462d2d172e8b6a2841d6e", &mont_kp.secret_key);
|
try htest.assertEqual("90e7595fc89e52fdfddce9c6a43d74dbf6047025ee0462d2d172e8b6a2841d6e", &mont_kp.secret_key);
|
||||||
try htest.assertEqual("cc4f2cdb695dd766f34118eb67b98652fed1d8bc49c330b119bbfa8a64989378", &mont_kp.public_key);
|
try htest.assertEqual("cc4f2cdb695dd766f34118eb67b98652fed1d8bc49c330b119bbfa8a64989378", &mont_kp.public_key);
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ const signatures = [_]Crypto{
|
||||||
|
|
||||||
pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
||||||
const msg = [_]u8{0} ** 64;
|
const msg = [_]u8{0} ** 64;
|
||||||
const key_pair = try Signature.KeyPair.create(null);
|
const key_pair = Signature.KeyPair.generate();
|
||||||
|
|
||||||
var timer = try Timer.start();
|
var timer = try Timer.start();
|
||||||
const start = timer.lap();
|
const start = timer.lap();
|
||||||
|
|
@ -163,7 +163,7 @@ const signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .na
|
||||||
|
|
||||||
pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
||||||
const msg = [_]u8{0} ** 64;
|
const msg = [_]u8{0} ** 64;
|
||||||
const key_pair = try Signature.KeyPair.create(null);
|
const key_pair = Signature.KeyPair.generate();
|
||||||
const sig = try key_pair.sign(&msg, null);
|
const sig = try key_pair.sign(&msg, null);
|
||||||
|
|
||||||
var timer = try Timer.start();
|
var timer = try Timer.start();
|
||||||
|
|
@ -187,7 +187,7 @@ const batch_signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed2551
|
||||||
|
|
||||||
pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
pub fn benchmarkBatchSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
|
||||||
const msg = [_]u8{0} ** 64;
|
const msg = [_]u8{0} ** 64;
|
||||||
const key_pair = try Signature.KeyPair.create(null);
|
const key_pair = Signature.KeyPair.generate();
|
||||||
const sig = try key_pair.sign(&msg, null);
|
const sig = try key_pair.sign(&msg, null);
|
||||||
|
|
||||||
var batch: [64]Signature.BatchElement = undefined;
|
var batch: [64]Signature.BatchElement = undefined;
|
||||||
|
|
@ -219,7 +219,7 @@ const kems = [_]Crypto{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn benchmarkKem(comptime Kem: anytype, comptime kems_count: comptime_int) !u64 {
|
pub fn benchmarkKem(comptime Kem: anytype, comptime kems_count: comptime_int) !u64 {
|
||||||
const key_pair = try Kem.KeyPair.create(null);
|
const key_pair = Kem.KeyPair.generate();
|
||||||
|
|
||||||
var timer = try Timer.start();
|
var timer = try Timer.start();
|
||||||
const start = timer.lap();
|
const start = timer.lap();
|
||||||
|
|
@ -239,7 +239,7 @@ pub fn benchmarkKem(comptime Kem: anytype, comptime kems_count: comptime_int) !u
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn benchmarkKemDecaps(comptime Kem: anytype, comptime kems_count: comptime_int) !u64 {
|
pub fn benchmarkKemDecaps(comptime Kem: anytype, comptime kems_count: comptime_int) !u64 {
|
||||||
const key_pair = try Kem.KeyPair.create(null);
|
const key_pair = Kem.KeyPair.generate();
|
||||||
|
|
||||||
const e = key_pair.public_key.encaps(null);
|
const e = key_pair.public_key.encaps(null);
|
||||||
|
|
||||||
|
|
@ -266,7 +266,7 @@ pub fn benchmarkKemKeyGen(comptime Kem: anytype, comptime kems_count: comptime_i
|
||||||
{
|
{
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
while (i < kems_count) : (i += 1) {
|
while (i < kems_count) : (i += 1) {
|
||||||
const key_pair = try Kem.KeyPair.create(null);
|
const key_pair = Kem.KeyPair.generate();
|
||||||
mem.doNotOptimizeAway(&key_pair);
|
mem.doNotOptimizeAway(&key_pair);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -409,7 +409,7 @@ fn benchmarkPwhash(
|
||||||
comptime count: comptime_int,
|
comptime count: comptime_int,
|
||||||
) !f64 {
|
) !f64 {
|
||||||
const password = "testpass" ** 2;
|
const password = "testpass" ** 2;
|
||||||
const opts = .{
|
const opts = ty.HashOptions{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.params = @as(*const ty.Params, @ptrCast(@alignCast(params))).*,
|
.params = @as(*const ty.Params, @ptrCast(@alignCast(params))).*,
|
||||||
.encoding = .phc,
|
.encoding = .phc,
|
||||||
|
|
|
||||||
|
|
@ -296,21 +296,28 @@ pub fn Ecdsa(comptime Curve: type, comptime Hash: type) type {
|
||||||
/// Secret scalar.
|
/// Secret scalar.
|
||||||
secret_key: SecretKey,
|
secret_key: SecretKey,
|
||||||
|
|
||||||
/// Create a new random key pair. `crypto.random.bytes` must be supported for the target.
|
/// Deterministically derive a key pair from a cryptograpically secure secret seed.
|
||||||
pub fn generate() IdentityElementError!KeyPair {
|
///
|
||||||
var random_seed: [seed_length]u8 = undefined;
|
/// Except in tests, applications should generally call `generate()` instead of this function.
|
||||||
crypto.random.bytes(&random_seed);
|
pub fn generateDeterministic(seed: [seed_length]u8) IdentityElementError!KeyPair {
|
||||||
return create(random_seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new key pair. The seed must be secret and indistinguishable from random.
|
|
||||||
pub fn create(seed: [seed_length]u8) IdentityElementError!KeyPair {
|
|
||||||
const h = [_]u8{0x00} ** Hash.digest_length;
|
const h = [_]u8{0x00} ** Hash.digest_length;
|
||||||
const k0 = [_]u8{0x01} ** SecretKey.encoded_length;
|
const k0 = [_]u8{0x01} ** SecretKey.encoded_length;
|
||||||
const secret_key = deterministicScalar(h, k0, seed).toBytes(.big);
|
const secret_key = deterministicScalar(h, k0, seed).toBytes(.big);
|
||||||
return fromSecretKey(SecretKey{ .bytes = secret_key });
|
return fromSecretKey(SecretKey{ .bytes = secret_key });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a new, random key pair.
|
||||||
|
pub fn generate() KeyPair {
|
||||||
|
var random_seed: [seed_length]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
crypto.random.bytes(&random_seed);
|
||||||
|
return generateDeterministic(random_seed) catch {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the public key corresponding to the secret key.
|
/// Return the public key corresponding to the secret key.
|
||||||
pub fn fromSecretKey(secret_key: SecretKey) IdentityElementError!KeyPair {
|
pub fn fromSecretKey(secret_key: SecretKey) IdentityElementError!KeyPair {
|
||||||
const public_key = try Curve.basePoint.mul(secret_key.bytes, .big);
|
const public_key = try Curve.basePoint.mul(secret_key.bytes, .big);
|
||||||
|
|
@ -387,7 +394,7 @@ test "Basic operations over EcdsaP384Sha384" {
|
||||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||||
|
|
||||||
const Scheme = EcdsaP384Sha384;
|
const Scheme = EcdsaP384Sha384;
|
||||||
const kp = try Scheme.KeyPair.generate();
|
const kp = Scheme.KeyPair.generate();
|
||||||
const msg = "test";
|
const msg = "test";
|
||||||
|
|
||||||
var noise: [Scheme.noise_length]u8 = undefined;
|
var noise: [Scheme.noise_length]u8 = undefined;
|
||||||
|
|
@ -403,7 +410,7 @@ test "Basic operations over Secp256k1" {
|
||||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||||
|
|
||||||
const Scheme = EcdsaSecp256k1Sha256oSha256;
|
const Scheme = EcdsaSecp256k1Sha256oSha256;
|
||||||
const kp = try Scheme.KeyPair.generate();
|
const kp = Scheme.KeyPair.generate();
|
||||||
const msg = "test";
|
const msg = "test";
|
||||||
|
|
||||||
var noise: [Scheme.noise_length]u8 = undefined;
|
var noise: [Scheme.noise_length]u8 = undefined;
|
||||||
|
|
@ -419,7 +426,7 @@ test "Basic operations over EcdsaP384Sha256" {
|
||||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||||
|
|
||||||
const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256);
|
const Scheme = Ecdsa(crypto.ecc.P384, crypto.hash.sha2.Sha256);
|
||||||
const kp = try Scheme.KeyPair.generate();
|
const kp = Scheme.KeyPair.generate();
|
||||||
const msg = "test";
|
const msg = "test";
|
||||||
|
|
||||||
var noise: [Scheme.noise_length]u8 = undefined;
|
var noise: [Scheme.noise_length]u8 = undefined;
|
||||||
|
|
@ -893,7 +900,7 @@ test "Sec1 encoding/decoding" {
|
||||||
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
|
||||||
|
|
||||||
const Scheme = EcdsaP384Sha384;
|
const Scheme = EcdsaP384Sha384;
|
||||||
const kp = try Scheme.KeyPair.generate();
|
const kp = Scheme.KeyPair.generate();
|
||||||
const pk = kp.public_key;
|
const pk = kp.public_key;
|
||||||
const pk_compressed_sec1 = pk.toCompressedSec1();
|
const pk_compressed_sec1 = pk.toCompressedSec1();
|
||||||
const pk_recovered1 = try Scheme.PublicKey.fromSec1(&pk_compressed_sec1);
|
const pk_recovered1 = try Scheme.PublicKey.fromSec1(&pk_compressed_sec1);
|
||||||
|
|
|
||||||
|
|
@ -370,15 +370,10 @@ fn Kyber(comptime p: Params) type {
|
||||||
secret_key: SecretKey,
|
secret_key: SecretKey,
|
||||||
public_key: PublicKey,
|
public_key: PublicKey,
|
||||||
|
|
||||||
/// Create a new key pair.
|
/// Deterministically derive a key pair from a cryptograpically secure secret seed.
|
||||||
/// If seed is null, a random seed will be generated.
|
///
|
||||||
/// If a seed is provided, the key pair will be deterministic.
|
/// Except in tests, applications should generally call `generate()` instead of this function.
|
||||||
pub fn create(seed_: ?[seed_length]u8) !KeyPair {
|
pub fn generateDeterministic(seed: [seed_length]u8) !KeyPair {
|
||||||
const seed = seed_ orelse sk: {
|
|
||||||
var random_seed: [seed_length]u8 = undefined;
|
|
||||||
crypto.random.bytes(&random_seed);
|
|
||||||
break :sk random_seed;
|
|
||||||
};
|
|
||||||
var ret: KeyPair = undefined;
|
var ret: KeyPair = undefined;
|
||||||
ret.secret_key.z = seed[inner_seed_length..seed_length].*;
|
ret.secret_key.z = seed[inner_seed_length..seed_length].*;
|
||||||
|
|
||||||
|
|
@ -399,6 +394,18 @@ fn Kyber(comptime p: Params) type {
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate a new, random key pair.
|
||||||
|
pub fn generate() KeyPair {
|
||||||
|
var random_seed: [seed_length]u8 = undefined;
|
||||||
|
while (true) {
|
||||||
|
crypto.random.bytes(&random_seed);
|
||||||
|
return generateDeterministic(random_seed) catch {
|
||||||
|
@branchHint(.unlikely);
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Size of plaintexts of the in
|
// Size of plaintexts of the in
|
||||||
|
|
@ -1698,7 +1705,7 @@ test "Test happy flow" {
|
||||||
inline for (modes) |mode| {
|
inline for (modes) |mode| {
|
||||||
for (0..10) |i| {
|
for (0..10) |i| {
|
||||||
seed[0] = @as(u8, @intCast(i));
|
seed[0] = @as(u8, @intCast(i));
|
||||||
const kp = try mode.KeyPair.create(seed);
|
const kp = try mode.KeyPair.generateDeterministic(seed);
|
||||||
const sk = try mode.SecretKey.fromBytes(&kp.secret_key.toBytes());
|
const sk = try mode.SecretKey.fromBytes(&kp.secret_key.toBytes());
|
||||||
try testing.expectEqual(sk, kp.secret_key);
|
try testing.expectEqual(sk, kp.secret_key);
|
||||||
const pk = try mode.PublicKey.fromBytes(&kp.public_key.toBytes());
|
const pk = try mode.PublicKey.fromBytes(&kp.public_key.toBytes());
|
||||||
|
|
@ -1745,7 +1752,7 @@ test "NIST KAT test" {
|
||||||
g2.fill(kseed[0..32]);
|
g2.fill(kseed[0..32]);
|
||||||
g2.fill(kseed[32..64]);
|
g2.fill(kseed[32..64]);
|
||||||
g2.fill(&eseed);
|
g2.fill(&eseed);
|
||||||
const kp = try mode.KeyPair.create(kseed);
|
const kp = try mode.KeyPair.generateDeterministic(kseed);
|
||||||
const e = kp.public_key.encaps(eseed);
|
const e = kp.public_key.encaps(eseed);
|
||||||
const ss2 = try kp.secret_key.decaps(&e.ciphertext);
|
const ss2 = try kp.secret_key.decaps(&e.ciphertext);
|
||||||
try testing.expectEqual(ss2, e.shared_secret);
|
try testing.expectEqual(ss2, e.shared_secret);
|
||||||
|
|
|
||||||
|
|
@ -535,7 +535,7 @@ pub const SealedBox = struct {
|
||||||
/// `c` must be `seal_length` bytes larger than `m`, so that the required metadata can be added.
|
/// `c` must be `seal_length` bytes larger than `m`, so that the required metadata can be added.
|
||||||
pub fn seal(c: []u8, m: []const u8, public_key: [public_length]u8) (WeakPublicKeyError || IdentityElementError)!void {
|
pub fn seal(c: []u8, m: []const u8, public_key: [public_length]u8) (WeakPublicKeyError || IdentityElementError)!void {
|
||||||
debug.assert(c.len == m.len + seal_length);
|
debug.assert(c.len == m.len + seal_length);
|
||||||
var ekp = try KeyPair.create(null);
|
var ekp = KeyPair.generate();
|
||||||
const nonce = createNonce(ekp.public_key, public_key);
|
const nonce = createNonce(ekp.public_key, public_key);
|
||||||
c[0..public_length].* = ekp.public_key;
|
c[0..public_length].* = ekp.public_key;
|
||||||
try Box.seal(c[Box.public_length..], m, nonce, public_key, ekp.secret_key);
|
try Box.seal(c[Box.public_length..], m, nonce, public_key, ekp.secret_key);
|
||||||
|
|
@ -607,8 +607,8 @@ test "xsalsa20poly1305 box" {
|
||||||
crypto.random.bytes(&msg);
|
crypto.random.bytes(&msg);
|
||||||
crypto.random.bytes(&nonce);
|
crypto.random.bytes(&nonce);
|
||||||
|
|
||||||
const kp1 = try Box.KeyPair.create(null);
|
const kp1 = Box.KeyPair.generate();
|
||||||
const kp2 = try Box.KeyPair.create(null);
|
const kp2 = Box.KeyPair.generate();
|
||||||
try Box.seal(boxed[0..], msg[0..], nonce, kp1.public_key, kp2.secret_key);
|
try Box.seal(boxed[0..], msg[0..], nonce, kp1.public_key, kp2.secret_key);
|
||||||
try Box.open(msg2[0..], boxed[0..], nonce, kp2.public_key, kp1.secret_key);
|
try Box.open(msg2[0..], boxed[0..], nonce, kp2.public_key, kp1.secret_key);
|
||||||
}
|
}
|
||||||
|
|
@ -619,7 +619,7 @@ test "xsalsa20poly1305 sealedbox" {
|
||||||
var boxed: [msg.len + SealedBox.seal_length]u8 = undefined;
|
var boxed: [msg.len + SealedBox.seal_length]u8 = undefined;
|
||||||
crypto.random.bytes(&msg);
|
crypto.random.bytes(&msg);
|
||||||
|
|
||||||
const kp = try Box.KeyPair.create(null);
|
const kp = Box.KeyPair.generate();
|
||||||
try SealedBox.seal(boxed[0..], msg[0..], kp.public_key);
|
try SealedBox.seal(boxed[0..], msg[0..], kp.public_key);
|
||||||
try SealedBox.open(msg2[0..], boxed[0..], kp);
|
try SealedBox.open(msg2[0..], boxed[0..], kp);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1649,10 +1649,10 @@ const KeyShare = struct {
|
||||||
|
|
||||||
fn init(seed: [112]u8) error{IdentityElement}!KeyShare {
|
fn init(seed: [112]u8) error{IdentityElement}!KeyShare {
|
||||||
return .{
|
return .{
|
||||||
.ml_kem768_kp = try .create(null),
|
.ml_kem768_kp = .generate(),
|
||||||
.secp256r1_kp = try .create(seed[0..32].*),
|
.secp256r1_kp = try .generateDeterministic(seed[0..32].*),
|
||||||
.secp384r1_kp = try .create(seed[32..80].*),
|
.secp384r1_kp = try .generateDeterministic(seed[32..80].*),
|
||||||
.x25519_kp = try .create(seed[80..112].*),
|
.x25519_kp = try .generateDeterministic(seed[80..112].*),
|
||||||
.sk_buf = undefined,
|
.sk_buf = undefined,
|
||||||
.sk_len = 0,
|
.sk_len = 0,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue