Skip to content

Commit ce355e0

Browse files
authored
Add ML-DSA post-quantum signatures (#25862)
ML-DSA is a post-quantum signature scheme that was recently standardized by NIST. Keys and signatures are pretty large, not making it a drop-in replacement for classical signature schemes. But if you are shipping keys that may still be used in 10 years or whenever large quantum computers able to break ECC arrive, it that ever happens, and you don't have the ability to replace these keys, ML-DSA is for you. Performance is great, verification is faster than Ed25519 / ECDSA. I tried manual vectorization, but it wasn't worth it, the compiler does at good job at auto-vectorization already.
1 parent cde865e commit ce355e0

File tree

4 files changed

+3612
-2
lines changed

4 files changed

+3612
-2
lines changed

lib/std/crypto.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ pub const pwhash = struct {
197197
pub const sign = struct {
198198
pub const Ed25519 = @import("crypto/25519/ed25519.zig").Ed25519;
199199
pub const ecdsa = @import("crypto/ecdsa.zig");
200+
pub const mldsa = @import("crypto/ml_dsa.zig");
200201
};
201202

202203
/// Stream ciphers. These do not provide any kind of authentication.

lib/std/crypto/benchmark.zig

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ const signatures = [_]Crypto{
166166
Crypto{ .ty = crypto.sign.ecdsa.EcdsaP256Sha256, .name = "ecdsa-p256" },
167167
Crypto{ .ty = crypto.sign.ecdsa.EcdsaP384Sha384, .name = "ecdsa-p384" },
168168
Crypto{ .ty = crypto.sign.ecdsa.EcdsaSecp256k1Sha256, .name = "ecdsa-secp256k1" },
169+
Crypto{ .ty = crypto.sign.mldsa.MLDSA44, .name = "ml-dsa-44" },
170+
Crypto{ .ty = crypto.sign.mldsa.MLDSA65, .name = "ml-dsa-65" },
171+
Crypto{ .ty = crypto.sign.mldsa.MLDSA87, .name = "ml-dsa-87" },
169172
};
170173

171174
pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
@@ -189,7 +192,12 @@ pub fn benchmarkSignature(comptime Signature: anytype, comptime signatures_count
189192
return throughput;
190193
}
191194

192-
const signature_verifications = [_]Crypto{Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" }};
195+
const signature_verifications = [_]Crypto{
196+
Crypto{ .ty = crypto.sign.Ed25519, .name = "ed25519" },
197+
Crypto{ .ty = crypto.sign.mldsa.MLDSA44, .name = "ml-dsa-44" },
198+
Crypto{ .ty = crypto.sign.mldsa.MLDSA65, .name = "ml-dsa-65" },
199+
Crypto{ .ty = crypto.sign.mldsa.MLDSA87, .name = "ml-dsa-87" },
200+
};
193201

194202
pub fn benchmarkSignatureVerification(comptime Signature: anytype, comptime signatures_count: comptime_int) !u64 {
195203
const msg = [_]u8{0} ** 64;

lib/std/crypto/errors.zig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,8 @@ pub const WeakPublicKeyError = error{WeakPublicKey};
3434
/// Point is not in the prime order group
3535
pub const UnexpectedSubgroupError = error{UnexpectedSubgroup};
3636

37+
/// Context string is too long
38+
pub const ContextTooLongError = error{ContextTooLong};
39+
3740
/// Any error related to cryptography operations
38-
pub const Error = AuthenticationError || OutputTooLongError || IdentityElementError || EncodingError || SignatureVerificationError || KeyMismatchError || NonCanonicalError || NotSquareError || PasswordVerificationError || WeakParametersError || WeakPublicKeyError || UnexpectedSubgroupError;
41+
pub const Error = AuthenticationError || OutputTooLongError || IdentityElementError || EncodingError || SignatureVerificationError || KeyMismatchError || NonCanonicalError || NotSquareError || PasswordVerificationError || WeakParametersError || WeakPublicKeyError || UnexpectedSubgroupError || ContextTooLongError;

0 commit comments

Comments
 (0)