1use ml_dsa::{Generate, Keypair, MlDsa65, Signer, SigningKey, Verifier, VerifyingKey};
2use pkcs8::DecodePublicKey;
3
4/// An ML-DSA-65 public key from an SPKI ("BEGIN PUBLIC KEY") file, e.g. written by OpenSSL 3.5.
5pub fn read_public_key(path: &str) -> Result<VerifyingKey<MlDsa65>, Box<dyn std::error::Error>> {
6 Ok(VerifyingKey::<MlDsa65>::from_public_key_pem(&std::fs::read_to_string(path)?)?)
7}
8
9pub fn sign_and_verify(message: &[u8]) -> Result<(), ml_dsa::Error> {
10 let signing_key = SigningKey::<MlDsa65>::generate(); // OS randomness ("getrandom" feature)
11 let verifying_key = signing_key.verifying_key();
12
13 let signature = signing_key.sign(message); // deterministic: Signer has no randomness
14 println!("public key {} bytes, signature {} bytes", verifying_key.encode().len(), signature.encode().len());
15 println!("verified: {}", verifying_key.verify(message, &signature).is_ok());
16 println!("tampered message: {}", verifying_key.verify(b"hello, post-quantum world!", &signature).is_ok());
17
18 // A context string: sign and verify with the same one
19 let context = b"invoice-v1";
20 let invoice_signature = signing_key.expanded_key().sign_deterministic(message, context)?;
21 println!(
22 "with the context: {}, without: {}",
23 verifying_key.verify_with_context(message, context, &invoice_signature),
24 verifying_key.verify(message, &invoice_signature).is_ok()
25 );
26 Ok(())
27}
28