From c157ae2957e317afd2f5d9095e1450abbd5f1ef9 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 14 Jul 2026 10:41:10 +0200 Subject: [PATCH] crypto.x25519: recoverPublicKey and generateDeterministic cannot fail This performs a scalar multiplication of the base point by a clamped scalar (a multiple of 8, so we end up in the prime order group), so these functions cannot return an error. Fixes #36154 --- lib/std/crypto/25519/x25519.zig | 22 ++++++++-------------- lib/std/crypto/tls/Client.zig | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/lib/std/crypto/25519/x25519.zig b/lib/std/crypto/25519/x25519.zig index 93155644e9b06a9e01fe442e36fff47c2c47b2c8..3e43acf8f6fcc81b2ed490ec57b6db4784fae01f 100644 --- a/lib/std/crypto/25519/x25519.zig +++ b/lib/std/crypto/25519/x25519.zig @@ -32,24 +32,18 @@ pub const X25519 = struct { /// Deterministically derive a key pair from a cryptograpically secure secret seed. /// /// Except in tests, applications should generally call `generate()` instead of this function. - pub fn generateDeterministic(seed: [seed_length]u8) IdentityElementError!KeyPair { - const kp = KeyPair{ - .public_key = try X25519.recoverPublicKey(seed), + pub fn generateDeterministic(seed: [seed_length]u8) KeyPair { + return .{ + .public_key = X25519.recoverPublicKey(seed), .secret_key = seed, }; - return kp; } /// Generate a new, random key pair. pub fn generate(io: std.Io) KeyPair { var random_seed: [seed_length]u8 = undefined; - while (true) { - io.random(&random_seed); - return generateDeterministic(random_seed) catch { - @branchHint(.unlikely); - continue; - }; - } + io.random(&random_seed); + return generateDeterministic(random_seed); } /// Create a key pair from an Ed25519 key pair @@ -68,8 +62,8 @@ pub const X25519 = struct { }; /// Compute the public key for a given private key. - pub fn recoverPublicKey(secret_key: [secret_length]u8) IdentityElementError![public_length]u8 { - const q = try Curve.basePoint.clampedMul(secret_key); + pub fn recoverPublicKey(secret_key: [secret_length]u8) [public_length]u8 { + const q = Curve.basePoint.clampedMul(secret_key) catch unreachable; return q.toBytes(); } @@ -96,7 +90,7 @@ test "public key calculation from secret key" { var pk_expected: [32]u8 = undefined; _ = try fmt.hexToBytes(sk[0..], "8052030376d47112be7f73ed7a019293dd12ad910b654455798b4667d73de166"); _ = try fmt.hexToBytes(pk_expected[0..], "f1814f0e8ff1043d8a44d25babff3cedcae6c22c3edaa48f857ae70de2baae50"); - const pk_calculated = try X25519.recoverPublicKey(sk); + const pk_calculated = X25519.recoverPublicKey(sk); try std.testing.expectEqual(pk_calculated, pk_expected); } diff --git a/lib/std/crypto/tls/Client.zig b/lib/std/crypto/tls/Client.zig index b3e2efd07a9df8bcb5ca7ed6cb51cff83d845772..4935e0c497182b92171f8475d652245420a2bf84 100644 --- a/lib/std/crypto/tls/Client.zig +++ b/lib/std/crypto/tls/Client.zig @@ -1370,7 +1370,7 @@ const KeyShare = struct { .ml_kem768_kp = try .generateDeterministic(seed[0..64].*), .secp256r1_kp = try .generateDeterministic(seed[64..96].*), .secp384r1_kp = try .generateDeterministic(seed[96..144].*), - .x25519_kp = try .generateDeterministic(seed[144..176].*), + .x25519_kp = .generateDeterministic(seed[144..176].*), .sk_buf = undefined, .sk_len = 0, }; -- 2.54.0