From 9b9b5ca996528d0b3b7a567fa109534a1b2252f8 Mon Sep 17 00:00:00 2001 From: Lorenz Leutgeb Date: Sun, 15 Feb 2026 12:33:59 +0100 Subject: [PATCH] cargo: Update `cyphernet` from 0.5.2 to 0.5.3 The main change that needs adjustment on our side is that `impl EcPk for ec25519::PublicKey` changed from `Compressed = [u8; 32]` to `Compressed = amplify::Bytes32`. Also remove `impl Deref for PublicKey` to avoid dependents of `radicle-crypto` depend on a particular implementation, and make the anonymous member private. See . --- Cargo.lock | 12 ++-- Cargo.toml | 4 +- crates/radicle-crypto/src/lib.rs | 73 +++++++++++---------- crates/radicle-crypto/src/ssh.rs | 4 +- crates/radicle-crypto/src/ssh/agent.rs | 7 +- crates/radicle-crypto/src/ssh/keystore.rs | 4 +- crates/radicle-crypto/src/test/arbitrary.rs | 2 +- crates/radicle-crypto/src/test/signer.rs | 4 +- crates/radicle-node/src/fingerprint.rs | 4 +- crates/radicle-protocol/src/wire.rs | 2 +- crates/radicle/src/test/arbitrary.rs | 3 +- 11 files changed, 63 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 494a9dea..7fee428e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -714,9 +714,9 @@ dependencies = [ [[package]] name = "cypheraddr" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5c54d2ad4ab9941383519471b75d12abc1a7b4779265e233168f2703a730d9" +checksum = "4204e8808fcdd40bed39e49371f13f56d6984c32bc03dcb577d2a40b989b9d68" dependencies = [ "amplify", "base32", @@ -738,9 +738,9 @@ dependencies = [ [[package]] name = "cyphernet" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac949369884a7a1d802cc669821269c707be8cec4d65043382e253733d2e62e1" +checksum = "2de2031ff4b9fc77e4dad022047341b55d285398164cc698e4082f4754b2e684" dependencies = [ "cypheraddr", "cyphergraphy", @@ -3977,9 +3977,9 @@ dependencies = [ [[package]] name = "socks5-client" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc7dcf6fab1d65d82d633006a4cc658d76ce436e01cf1a7c71873c0eeba324c" +checksum = "a87421b87207f5d39606da1ac9edd9a5333f4809d26a1fa9bbac58ca42913535" dependencies = [ "amplify", "cypheraddr", diff --git a/Cargo.toml b/Cargo.toml index f9b4330b..2672ff30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,8 +25,8 @@ bytes = "1.11.1" chrono = { version = "0.4.26", default-features = false } colored = "2.1.0" crossbeam-channel = "0.5.6" -cypheraddr = "0.4.0" -cyphernet = "0.5.2" +cypheraddr = "0.4.1" +cyphernet = "0.5.3" dunce = "1.0.5" fastrand = { version = "2.0.0", default-features = false } git2 = { version = "0.20.4", default-features = false, features = ["vendored-libgit2"] } diff --git a/crates/radicle-crypto/src/lib.rs b/crates/radicle-crypto/src/lib.rs index 60bd126b..a8d3ec4b 100644 --- a/crates/radicle-crypto/src/lib.rs +++ b/crates/radicle-crypto/src/lib.rs @@ -138,7 +138,7 @@ impl TryFrom for Signature { } /// The public/verification key. -#[derive(Hash, Serialize, Deserialize, PartialEq, Eq, Copy, Clone)] +#[derive(Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] #[serde(into = "String", try_from = "String")] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr( @@ -154,12 +154,28 @@ impl TryFrom for Signature { ]), ), )] -pub struct PublicKey(pub ed25519::PublicKey); +pub struct PublicKey(amplify::Bytes32); + +impl PublicKey { + /// Verify the signature for a given payload. + pub fn verify( + &self, + payload: impl AsRef<[u8]>, + signature: &ed25519::Signature, + ) -> Result<(), ed25519::Error> { + ed25519::PublicKey::new(self.0.to_byte_array()).verify(payload, signature) + } + + /// Returns a byte array representation of the public key. + #[inline] + pub fn to_byte_array(&self) -> [u8; 32] { + self.0.to_byte_array() + } +} impl signature::Verifier for PublicKey { fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), signature::Error> { - self.0 - .verify(msg, signature) + self.verify(msg, signature) .map_err(signature::Error::from_source) } } @@ -176,7 +192,7 @@ impl cyphernet::display::MultiDisplay for PublicKe #[cfg(feature = "ssh")] impl From for ssh_key::PublicKey { fn from(key: PublicKey) -> Self { - ssh_key::PublicKey::from(ssh_key::public::Ed25519PublicKey(**key)) + ssh_key::PublicKey::from(ssh_key::public::Ed25519PublicKey(key.to_byte_array())) } } @@ -185,24 +201,24 @@ impl cyphernet::EcPk for PublicKey { const COMPRESSED_LEN: usize = 32; const CURVE_NAME: &'static str = "Edwards25519"; - type Compressed = [u8; 32]; + type Compressed = amplify::Bytes32; fn base_point() -> Self { unimplemented!() } fn to_pk_compressed(&self) -> Self::Compressed { - *self.0.deref() + amplify::Bytes32::from_byte_array(self.to_byte_array()) } fn from_pk_compressed(pk: Self::Compressed) -> Result { - Ok(PublicKey::from(pk)) + Ok(PublicKey::from(pk.to_byte_array())) } fn from_pk_compressed_slice(slice: &[u8]) -> Result { ed25519::PublicKey::from_slice(slice) .map_err(|_| cyphernet::EcPkInvalid::default()) - .map(Self) + .map(Self::from) } } @@ -214,7 +230,8 @@ impl SecretKey { /// Elliptic-curve Diffie-Hellman. pub fn ecdh(&self, pk: &PublicKey) -> Result<[u8; 32], ed25519::Error> { let scalar = self.seed().scalar(); - let ge = edwards25519::GeP3::from_bytes_vartime(pk).ok_or(Error::InvalidPublicKey)?; + let ge = edwards25519::GeP3::from_bytes_vartime(&pk.to_byte_array()) + .ok_or(Error::InvalidPublicKey)?; Ok(edwards25519::ge_scalarmult(&scalar, &ge).to_bytes()) } @@ -291,18 +308,6 @@ pub enum PublicKeyError { InvalidKey(#[from] ed25519::Error), } -impl PartialOrd for PublicKey { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for PublicKey { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.as_ref().cmp(other.as_ref()) - } -} - impl fmt::Display for PublicKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.to_human()) @@ -323,13 +328,19 @@ impl fmt::Debug for PublicKey { impl From for PublicKey { fn from(other: ed25519::PublicKey) -> Self { - Self(other) + Self(amplify::Bytes32::from_byte_array(*other.deref())) + } +} + +impl From for ed25519::PublicKey { + fn from(val: PublicKey) -> Self { + ed25519::PublicKey::new(val.to_byte_array()) } } impl From<[u8; 32]> for PublicKey { fn from(other: [u8; 32]) -> Self { - Self(ed25519::PublicKey::new(other)) + Self(amplify::Bytes32::from_byte_array(other)) } } @@ -337,7 +348,7 @@ impl TryFrom<&[u8]> for PublicKey { type Error = ed25519::Error; fn try_from(other: &[u8]) -> Result { - ed25519::PublicKey::from_slice(other).map(Self) + ed25519::PublicKey::from_slice(other).map(Self::from) } } @@ -352,7 +363,7 @@ impl PublicKey { pub fn to_human(&self) -> String { let mut buf = [0; 2 + ed25519::PublicKey::BYTES]; buf[..2].copy_from_slice(&Self::MULTICODEC_TYPE); - buf[2..].copy_from_slice(self.0.deref()); + buf[2..].copy_from_slice(self.to_byte_array().as_slice()); multibase::encode(multibase::Base::Base58Btc, buf) } @@ -387,7 +398,7 @@ impl FromStr for PublicKey { if let Some(bytes) = bytes.strip_prefix(&Self::MULTICODEC_TYPE) { let key = ed25519::PublicKey::from_slice(bytes)?; - Ok(Self(key)) + Ok(key.into()) } else { Err(PublicKeyError::Multicodec(Self::MULTICODEC_TYPE)) } @@ -402,14 +413,6 @@ impl TryFrom for PublicKey { } } -impl Deref for PublicKey { - type Target = ed25519::PublicKey; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - #[cfg(feature = "git-ref-format-core")] impl From<&PublicKey> for git_ref_format_core::Component<'_> { fn from(id: &PublicKey) -> Self { diff --git a/crates/radicle-crypto/src/ssh.rs b/crates/radicle-crypto/src/ssh.rs index 9c1516bd..d6b436aa 100644 --- a/crates/radicle-crypto/src/ssh.rs +++ b/crates/radicle-crypto/src/ssh.rs @@ -43,7 +43,9 @@ impl ExtendedSignature { /// Convert to OpenSSH standard PEM format. pub fn to_pem(&self) -> Result { ssh_key::SshSig::new( - ssh_key::public::KeyData::from(ssh_key::public::Ed25519PublicKey(**self.key)), + ssh_key::public::KeyData::from(ssh_key::public::Ed25519PublicKey( + self.key.to_byte_array(), + )), String::from("radicle"), ssh_key::HashAlg::Sha256, ssh_key::Signature::new(ssh_key::Algorithm::Ed25519, **self.sig)?, diff --git a/crates/radicle-crypto/src/ssh/agent.rs b/crates/radicle-crypto/src/ssh/agent.rs index 93ea00b8..d5323a11 100644 --- a/crates/radicle-crypto/src/ssh/agent.rs +++ b/crates/radicle-crypto/src/ssh/agent.rs @@ -125,7 +125,7 @@ impl Agent { } fn key_data(key: &PublicKey) -> KeyData { - KeyData::Ed25519(Ed25519PublicKey(***key)) + KeyData::Ed25519(Ed25519PublicKey(key.to_byte_array())) } } @@ -191,7 +191,6 @@ mod test { use ssh_agent_lib::blocking::Client; use ssh_agent_lib::proto::SignRequest; use ssh_agent_lib::ssh_key::public::{Ed25519PublicKey, KeyData}; - use std::ops::Deref; #[test] fn test_agent_encoding_remove() { @@ -216,7 +215,7 @@ mod test { // since we are not actually connected to SSH agent. assert!( matches!(client.remove_identity(ssh_agent_lib::proto::RemoveIdentity { - pubkey: KeyData::Ed25519(Ed25519PublicKey(**pk.deref())), + pubkey: KeyData::Ed25519(Ed25519PublicKey(pk.to_byte_array())), }), Err( super::AgentError::Proto(ssh_agent_lib::proto::ProtoError::IO(err)), @@ -251,7 +250,7 @@ mod test { client .sign(SignRequest { - pubkey: KeyData::Ed25519(Ed25519PublicKey(**pk.deref())), + pubkey: KeyData::Ed25519(Ed25519PublicKey(pk.to_byte_array())), data, flags: 0, }) diff --git a/crates/radicle-crypto/src/ssh/keystore.rs b/crates/radicle-crypto/src/ssh/keystore.rs index 9e680dcd..860a092e 100644 --- a/crates/radicle-crypto/src/ssh/keystore.rs +++ b/crates/radicle-crypto/src/ssh/keystore.rs @@ -332,7 +332,7 @@ impl MemorySigner { .ok_or_else(|| MemorySignerError::NotFound(public_path.to_path_buf()))?; secret - .validate_public_key(&public) + .validate_public_key(&public.into()) .map_err(|_| MemorySignerError::KeyMismatch { secret: keystore.secret_key_path().to_path_buf(), public: public_path.to_path_buf(), @@ -345,7 +345,7 @@ impl MemorySigner { /// the public key from the secret key. pub fn from_secret(secret: Zeroizing) -> Self { Self { - public: PublicKey(secret.public_key()), + public: secret.public_key().into(), secret, } } diff --git a/crates/radicle-crypto/src/test/arbitrary.rs b/crates/radicle-crypto/src/test/arbitrary.rs index 43874c3e..fdc072f7 100644 --- a/crates/radicle-crypto/src/test/arbitrary.rs +++ b/crates/radicle-crypto/src/test/arbitrary.rs @@ -18,6 +18,6 @@ impl Arbitrary for PublicKey { let seed = Seed::new(bytes); let keypair = KeyPair::from_seed(seed); - PublicKey(keypair.pk) + keypair.pk.into() } } diff --git a/crates/radicle-crypto/src/test/signer.rs b/crates/radicle-crypto/src/test/signer.rs index 59507bfb..181eea1d 100644 --- a/crates/radicle-crypto/src/test/signer.rs +++ b/crates/radicle-crypto/src/test/signer.rs @@ -27,7 +27,9 @@ impl signature::Signer for MockSigner { impl signature::Verifier for MockSigner { fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), signature::Error> { - self.pk.verify(msg, signature) + self.pk + .verify(msg, signature) + .map_err(signature::Error::from_source) } } diff --git a/crates/radicle-node/src/fingerprint.rs b/crates/radicle-node/src/fingerprint.rs index 11c5c58c..cd765a93 100644 --- a/crates/radicle-node/src/fingerprint.rs +++ b/crates/radicle-node/src/fingerprint.rs @@ -68,7 +68,7 @@ impl Fingerprint { home: &Home, secret_key: &impl std::ops::Deref, ) -> Result<(), Error> { - let public_key = crypto::PublicKey(secret_key.deref().public_key()); + let public_key = secret_key.deref().public_key().into(); let mut file = std::fs::OpenOptions::new() .create_new(true) .write(true) @@ -86,7 +86,7 @@ impl Fingerprint { &self, secret_key: &impl std::ops::Deref, ) -> FingerprintVerification { - let public_key = crypto::PublicKey(secret_key.deref().public_key()); + let public_key = secret_key.deref().public_key().into(); if crypto::ssh::fmt::fingerprint(&public_key) == self.0 { FingerprintVerification::Match } else { diff --git a/crates/radicle-protocol/src/wire.rs b/crates/radicle-protocol/src/wire.rs index 214ae06b..d3b92626 100644 --- a/crates/radicle-protocol/src/wire.rs +++ b/crates/radicle-protocol/src/wire.rs @@ -175,7 +175,7 @@ impl Encode for u64 { impl Encode for PublicKey { fn encode(&self, buf: &mut impl BufMut) { - self.deref().encode(buf) + self.to_byte_array().encode(buf) } } diff --git a/crates/radicle/src/test/arbitrary.rs b/crates/radicle/src/test/arbitrary.rs index 449102d0..e6129cb7 100644 --- a/crates/radicle/src/test/arbitrary.rs +++ b/crates/radicle/src/test/arbitrary.rs @@ -238,7 +238,8 @@ impl Arbitrary for Address { AddressType::Onion => { let pk = PublicKey::arbitrary(g); let addr = OnionAddrV3::from( - cyphernet::ed25519::PublicKey::from_pk_compressed(**pk).unwrap(), + cyphernet::ed25519::PublicKey::from_pk_compressed(pk.to_byte_array()) + .unwrap(), ); cyphernet::addr::HostName::Tor(addr) }