pq-mayo
A Rust implementation of the MAYO post-quantum signature scheme, submitted to the NIST PQC standardization process.
Includes the latest updates as suggested for Round 3 and MAYO team NIST update with the MAYO2 tweak.
NOTE: MAYO-2 signature size increased from 186 B to 216 B as a result of the Round 2 findings.
Supported Parameter Sets
| Parameter Set | Security Level | Signature Size | Public Key Size | Private Key Size |
|---|---|---|---|---|
| Mayo1 | 1 | 454 B | 1420 B | 24 B |
| Mayo2 | 1 | 216 B | 4368 B | 24 B |
| Mayo3 | 3 | 681 B | 2986 B | 32 B |
| Mayo5 | 5 | 964 B | 5554 B | 40 B |
Performance
Benchmarked with Criterion. Times are point estimates from local runs and will vary by CPU, compiler, and feature flags.
Apple Silicon (aarch64)
Benchmarked with -C target-cpu=native.
Use the compact key types for minimal memory and serialized storage. Use the
expanded/context types when repeatedly signing or verifying with the same key.
| Operation | Compact | Expanded | Context |
|---|---|---|---|
| Mayo1/keygen | 148 µs | - | - |
| Mayo2/keygen | 207 µs | - | - |
| Mayo3/keygen | 384 µs | - | - |
| Mayo5/keygen | 848 µs | - | - |
| Mayo1/sign | 526 µs | 344 µs | - |
| Mayo2/sign | 489 µs | 241 µs | - |
| Mayo3/sign | 1.23 ms | 734 µs | - |
| Mayo5/sign | 2.69 ms | 1.56 ms | - |
| Mayo1/verify | 128 µs | 98.3 µs | 91.5 µs |
| Mayo2/verify | 64.6 µs | 31.3 µs | 28.1 µs |
| Mayo3/verify | 288 µs | 203 µs | 192 µs |
| Mayo5/verify | 608 µs | 418 µs | 402 µs |
Linux (x86_64-unknown-linux-gnu)
Benchmarked with rustc 1.95.0.
| Operation | Compact | Expanded | Context |
|---|---|---|---|
| Mayo1/keygen | 78.8 µs | - | - |
| Mayo2/keygen | 103 µs | - | - |
| Mayo3/keygen | 220 µs | - | - |
| Mayo5/keygen | 469 µs | - | - |
| Mayo1/sign | 283 µs | 192 µs | - |
| Mayo2/sign | 246 µs | 127 µs | - |
| Mayo3/sign | 711 µs | 455 µs | - |
| Mayo5/sign | 1.54 ms | 949 µs | - |
| Mayo1/verify | 79.7 µs | 48.4 µs | 44.9 µs |
| Mayo2/verify | 37.4 µs | 15.1 µs | 13.7 µs |
| Mayo3/verify | 203 µs | 131 µs | 124 µs |
| Mayo5/verify | 405 µs | 279 µs | 265 µs |
Run your own benchmarks:
The expanded signing key stores secret-derived expanded material for faster repeated signing. The verification context stores public expanded material and mutable scratch buffers for faster repeated verification.
Usage
Basic Sign and Verify
use ;
use ;
let mut rng = rng;
let keypair = generate.expect;
let msg = b"hello world";
let sig = keypair.signing_key.try_sign.expect;
keypair.verifying_key.verify.expect;
Using Different Parameter Sets
use ;
use ;
let mut rng = rng;
// NIST security level 1, tweaked after the wedge attack analysis
let kp2 = generate.expect;
let sig2 = kp2.signing_key.try_sign.expect;
kp2.verifying_key.verify.expect;
// NIST security level 3
let kp3 = generate.expect;
// NIST security level 5
let kp5 = generate.expect;
Key Serialization
Keys and signatures implement AsRef<[u8]> and TryFrom<&[u8]> for raw byte serialization:
use ;
use ;
let mut rng = rng;
let keypair = generate.expect;
// Export keys as raw bytes
let sk_bytes: & = keypair.signing_key.as_ref;
let vk_bytes: & = keypair.verifying_key.as_ref;
// Reconstruct keys from bytes
let sk = try_from.expect;
let vk = try_from.expect;
// Sign with reconstructed key, verify with reconstructed key
let sig = sk.try_sign.expect;
vk.verify.expect;
// Signatures can also be serialized/deserialized
let sig_bytes: & = sig.as_ref;
let sig2 = try_from.expect;
Deriving a Verifying Key from a Signing Key
use ;
use ;
let mut rng = rng;
let keypair = generate.expect;
// Derive the verifying (public) key from the signing (secret) key
let vk = from;
let sig = keypair.signing_key.try_sign.expect;
vk.verify.expect;
Faster Repeated Signing
Use ExpandedSigningKey when signing many messages with the same key. The
compact SigningKey remains the default storage format; the expanded form
keeps additional secret-derived material in memory and zeroizes it on drop.
use ;
use ;
let mut rng = rng;
let keypair = generate.expect;
let expanded = from;
let sig = expanded.try_sign.expect;
keypair.verifying_key.verify.expect;
Faster Repeated Verification
Use ExpandedVerifyingKey to cache expanded public key material. Use
VerificationContext when verifying many signatures with the same public key;
it also reuses mutable scratch buffers, so verification takes &mut self.
use ;
use ;
let mut rng = rng;
let keypair = generate.expect;
let msg = b"message";
let sig = keypair.signing_key.try_sign.expect;
let expanded = from;
expanded.verify.expect;
let mut context = from;
context.verify.expect;
Serde Support
Enable the serde feature for JSON/binary serialization:
[]
= { = "0.5", = ["serde"] }
use ;
let mut rng = rng;
let keypair = generate.expect;
// Serialize to JSON
let json = to_string.expect;
let restored: = from_str.expect;
PKCS#8 and SPKI Support
Enable the pkcs8 feature for DER-encoded key serialization compatible with X.509 and PKCS#8 standards:
[]
= { = "0.5", = ["pkcs8"] }
This implements the standard RustCrypto key encoding traits:
EncodePrivateKey/DecodePrivateKeyforKeyPair(PKCS#8 DER)DecodePrivateKeyforSigningKey(PKCS#8 DER)EncodePublicKey/DecodePublicKeyforVerifyingKey(SPKI DER)
use ;
use DecodePrivateKey;
use EncodePrivateKey;
use ;
use ;
let mut rng = rng;
let keypair = generate.expect;
// Encode private key to PKCS#8 DER
let sk_der = keypair.to_pkcs8_der.expect;
// Decode private key from PKCS#8 DER
let restored = from_pkcs8_der.expect;
// Encode public key to SPKI DER
let vk_der = keypair.verifying_key.to_public_key_der.expect;
// Decode public key from SPKI DER
let restored_vk = from_public_key_der.expect;
// Sign and verify with round-tripped keys
let sig = restored.signing_key.try_sign.expect;
restored_vk.verify.expect;
Since MAYO has not yet been standardized by NIST, experimental OIDs from the
Open Quantum Safe project are used (1.3.9999.8.{1,2,3,5}.3).
These will be replaced with official NIST OIDs upon standardization.
WebAssembly Support
This crate compiles to wasm32-unknown-unknown using pure Rust implementations
for all cryptographic primitives. Enable the js feature to use the browser's
crypto.getRandomValues for randomness:
[]
= { = "0.5", = ["js"] }
Serialization
This crate has been tested against the following serde compatible formats:
- postcard
- ciborium
- serde_json
- noyalib
- toml
Mitigations
There is a known fault injection attack against MAYO described in MAYO Key Recovery by Fixing Vinegar Seeds. This code contains mitigations to these attacks.
License
Licensed under either of Apache License, Version 2.0 or MIT License at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.