diff --git a/fastcrypto-cli/Cargo.toml b/fastcrypto-cli/Cargo.toml index e67d1a4a13..23e7bd395b 100644 --- a/fastcrypto-cli/Cargo.toml +++ b/fastcrypto-cli/Cargo.toml @@ -10,7 +10,7 @@ repository = "https://github.com/MystenLabs/fastcrypto" [dependencies] clap = { version = "4.1.8", features = ["derive"] } -fastcrypto = { path = "../fastcrypto", features = ["copy_key"] } +fastcrypto = { path = "../fastcrypto" } fastcrypto-vdf = { path = "../fastcrypto-vdf", features = ["experimental"] } hex = "0.4.3" rand.workspace = true diff --git a/fastcrypto-cli/src/sigs_cli.rs b/fastcrypto-cli/src/sigs_cli.rs index 370c7ebe48..95e539585a 100644 --- a/fastcrypto-cli/src/sigs_cli.rs +++ b/fastcrypto-cli/src/sigs_cli.rs @@ -126,38 +126,38 @@ fn execute(cmd: Command) -> Result<(), FastCryptoError> { let (sk, pk) = match SignatureScheme::from_str(&arg.scheme) { Ok(SignatureScheme::Ed25519) => { let kp = Ed25519KeyPair::generate(rng); - ( - Hex::encode(kp.copy().private().as_ref()), - Hex::encode(kp.public().as_ref()), - ) + { + let pk = Hex::encode(kp.public().as_ref()); + (Hex::encode(kp.private().as_ref()), pk) + } } Ok(SignatureScheme::Secp256k1) | Ok(SignatureScheme::Secp256k1Recoverable) => { let kp = Secp256k1KeyPair::generate(rng); - ( - Hex::encode(kp.copy().private().as_ref()), - Hex::encode(kp.public().as_ref()), - ) + { + let pk = Hex::encode(kp.public().as_ref()); + (Hex::encode(kp.private().as_ref()), pk) + } } Ok(SignatureScheme::Secp256r1) | Ok(SignatureScheme::Secp256r1Recoverable) => { let kp = Secp256r1KeyPair::generate(rng); - ( - Hex::encode(kp.copy().private().as_ref()), - Hex::encode(kp.public().as_ref()), - ) + { + let pk = Hex::encode(kp.public().as_ref()); + (Hex::encode(kp.private().as_ref()), pk) + } } Ok(SignatureScheme::BLS12381MinSig) => { let kp = fastcrypto::bls12381::min_sig::BLS12381KeyPair::generate(rng); - ( - Hex::encode(kp.copy().private().as_ref()), - Hex::encode(kp.public().as_ref()), - ) + { + let pk = Hex::encode(kp.public().as_ref()); + (Hex::encode(kp.private().as_ref()), pk) + } } Ok(SignatureScheme::BLS12381MinPk) => { let kp = fastcrypto::bls12381::min_pk::BLS12381KeyPair::generate(rng); - ( - Hex::encode(kp.copy().private().as_ref()), - Hex::encode(kp.public().as_ref()), - ) + { + let pk = Hex::encode(kp.public().as_ref()); + (Hex::encode(kp.private().as_ref()), pk) + } } Err(_) => return Err(FastCryptoError::InvalidInput), }; diff --git a/fastcrypto-pq/Cargo.toml b/fastcrypto-pq/Cargo.toml index b5900fb09b..4042a24ef6 100644 --- a/fastcrypto-pq/Cargo.toml +++ b/fastcrypto-pq/Cargo.toml @@ -10,8 +10,7 @@ repository = "https://github.com/MystenLabs/fastcrypto" publish = false [dependencies] -# copy_key is not optional here -fastcrypto = { path = "../fastcrypto", features = ["copy_key"] } +fastcrypto = { path = "../fastcrypto" } fastcrypto-derive = { path = "../fastcrypto-derive", version = "0.1.4" } # The C backend (mldsa-native, pinned as a submodule inside the wrapper) mysten-mldsa-native-rs = { git = "https://github.com/MystenLabs/mysten-mldsa-native-rs.git", rev = "ea1a9794c7ad0c68b9410121964b7439540826bc", version = "0.1.0" } @@ -23,6 +22,11 @@ bincode.workspace = true zeroize.workspace = true [features] +# Forwards to fastcrypto's copy_key, which gates KeyPair::copy for every scheme. Optional +# here so that depending on this crate does not turn private key copying on for the rest of +# the dependency graph through feature unification. +copy_key = ["fastcrypto/copy_key"] + # Forwards to the wrapper's verified assembly backends: NEON on aarch64, AVX2 on x86_64 # behind a runtime CPU probe. Identical signatures either way, roughly 2.5x faster. native = ["mysten-mldsa-native-rs/native"] diff --git a/fastcrypto-pq/README.md b/fastcrypto-pq/README.md index 4b36392bf7..3e9ce58b14 100644 --- a/fastcrypto-pq/README.md +++ b/fastcrypto-pq/README.md @@ -55,7 +55,7 @@ smart-contract vaults rather than the native transaction path. ```bash # everything, both schemes -cargo test -p fastcrypto-pq --features native +cargo test -p fastcrypto-pq --all-features # only the SLH-DSA building blocks cargo test -p fastcrypto-pq sphincs diff --git a/fastcrypto-pq/src/mldsa65/mod.rs b/fastcrypto-pq/src/mldsa65/mod.rs index f3f269ead4..e388f9f4b6 100644 --- a/fastcrypto-pq/src/mldsa65/mod.rs +++ b/fastcrypto-pq/src/mldsa65/mod.rs @@ -177,7 +177,7 @@ impl KeyPair for MLDSA65KeyPair { self.private } - // Not cfg-gated on copy_key; this crate always enables fastcrypto/copy_key + #[cfg(feature = "copy_key")] fn copy(&self) -> Self { MLDSA65KeyPair { public: self.public.clone(), diff --git a/fastcrypto-pq/src/tests/mldsa65_tests.rs b/fastcrypto-pq/src/tests/mldsa65_tests.rs index 35310d43c0..8ecfd01a24 100644 --- a/fastcrypto-pq/src/tests/mldsa65_tests.rs +++ b/fastcrypto-pq/src/tests/mldsa65_tests.rs @@ -180,7 +180,7 @@ fn serialize_deserialize() { verify_serialization(&signature, Some(signature.as_ref())); // The secret side serializes as the 32-byte seed - let private = keypair.copy().private(); + let private = MLDSA65PrivateKey::from_bytes(keypair.as_ref()).unwrap(); verify_serialization(&private, Some(private.as_ref())); let kp_bytes = bincode::serialize(&keypair).unwrap(); assert_eq!(kp_bytes, keypair.as_ref()); @@ -241,6 +241,7 @@ fn keypair_from_str_roundtrip() { } #[test] +#[cfg(feature = "copy_key")] fn copy_key_pair_preserves_identity() { let keypair = keys().pop().unwrap(); let copied = keypair.copy(); @@ -290,7 +291,7 @@ fn debug_output_is_redacted_for_secrets() { let keypair = keys().pop().unwrap(); // Secret material must never appear in formatted output. - let private = keypair.copy().private(); + let private = MLDSA65PrivateKey::from_bytes(keypair.as_ref()).unwrap(); assert!(!format!("{private:?}").contains(&Base64::encode(keypair.as_ref()))); // Public types print their base64 form, which assertion failures rely on.