[dependencies]ed25519-dalek = { version = "=3.0.0", features = ["pkcs8", "pem"] }hex = "=0.4.3"use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey};use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey}; fn main() -> Result<(), Box<dyn std::error::Error>> { // PKCS#8 "BEGIN PRIVATE KEY" and SPKI "BEGIN PUBLIC KEY" let signing_key = SigningKey::from_pkcs8_pem(&std::fs::read_to_string("key.pem")?)?; let verifying_key = VerifyingKey::from_public_key_pem(&std::fs::read_to_string("pub.pem")?)?; let message = std::fs::read("message.txt")?; let signature: Signature = signing_key.sign(&message); std::fs::write("sig.bin", signature.to_bytes())?; println!("signature: {}", hex::encode(signature.to_bytes())); // verify_strict also rejects small-order keys and non-canonical signatures let received = Signature::from_slice(&std::fs::read("sig.bin")?)?; println!("valid: {}", verifying_key.verify_strict(&message, &received).is_ok()); println!("tampered message valid: {}", verifying_key.verify(b"hello ed25520", &received).is_ok()); Ok(())}How it works
- The
pkcs8feature brings theDecodePrivateKeyandDecodePublicKeytraits;pemadds thefrom_pkcs8_pemandfrom_public_key_pemconstructors used here. SigningKey::signcomes from theSignertrait and returns aSignature;to_bytes()gives the 64-byte encoding every other language uses.Signature::from_sliceparses received bytes and returns an error for a wrong length instead of panicking.verify_strictalso rejects weak (small-order) public keys and non-canonical signatures that plainverifyaccepts; prefer it unless you must accept everything other implementations accept.
Gotchas
- Many examples online target ed25519-dalek 1.x, whose
Keypair,SecretKeyandPublicKeytypes were renamed toSigningKeyandVerifyingKeyin 2.0; they no longer compile. Pin the version, as the=3.0.0above does. SigningKey::from_bytestakes the 32-byte seed. A 64-byte libsodium-style secret key goes throughSigningKey::from_keypair_bytes, which also checks that the second half is the matching public key (Mismatched Keypair detectedotherwise).- With only the
pkcs8feature, the build fails withno associated function or constant named from_pkcs8_pem found for struct SigningKey— an error that points at your code, not at Cargo.toml. The PEM constructors need thepemfeature as well. - Signatures from this crate are deterministic, so tests may compare bytes against a fixture — but the same test against a randomized implementation such as Apple CryptoKit must verify instead.