From c1abc82f283eab0e7a4272a4b6d89a8780ae489d Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Fri, 30 Jan 2026 10:53:31 -0800 Subject: [PATCH] replace PublicKey with PublicKey32 --- conversations/src/crypto.rs | 6 ++-- conversations/src/identity.rs | 7 +++-- conversations/src/inbox/handshake.rs | 16 +++++------ conversations/src/inbox/inbox.rs | 10 +++---- conversations/src/inbox/introduction.rs | 10 +++---- crypto/src/keys.rs | 37 ++++++++++++++++++++++++- crypto/src/lib.rs | 2 +- crypto/src/x3dh.rs | 32 ++++++++++----------- 8 files changed, 79 insertions(+), 41 deletions(-) diff --git a/conversations/src/crypto.rs b/conversations/src/crypto.rs index ecf0d11..d02976a 100644 --- a/conversations/src/crypto.rs +++ b/conversations/src/crypto.rs @@ -1,13 +1,15 @@ pub use blake2::Digest; use blake2::{Blake2b, digest}; use prost::bytes::Bytes; -pub use x25519_dalek::{PublicKey, StaticSecret}; + +pub use crypto::PublicKey32; +pub use x25519_dalek::StaticSecret; pub trait CopyBytes { fn copy_to_bytes(&self) -> Bytes; } -impl CopyBytes for PublicKey { +impl CopyBytes for PublicKey32 { fn copy_to_bytes(&self) -> Bytes { Bytes::copy_from_slice(self.as_bytes()) } diff --git a/conversations/src/identity.rs b/conversations/src/identity.rs index c5646a7..9cc5f70 100644 --- a/conversations/src/identity.rs +++ b/conversations/src/identity.rs @@ -1,7 +1,8 @@ use blake2::{Blake2b512, Digest}; use std::fmt; -use crate::crypto::{PublicKey, StaticSecret}; +use crate::crypto::{PublicKey32, StaticSecret}; +use x25519_dalek::PublicKey; pub struct Identity { secret: StaticSecret, @@ -27,8 +28,8 @@ impl Identity { hex::encode(Blake2b512::digest(self.public_key())) } - pub fn public_key(&self) -> PublicKey { - PublicKey::from(&self.secret) + pub fn public_key(&self) -> PublicKey32 { + PublicKey::from(&self.secret).into() } pub fn secret(&self) -> &StaticSecret { diff --git a/conversations/src/inbox/handshake.rs b/conversations/src/inbox/handshake.rs index ff8c195..b94d7e8 100644 --- a/conversations/src/inbox/handshake.rs +++ b/conversations/src/inbox/handshake.rs @@ -5,7 +5,7 @@ use blake2::{ use crypto::{DomainSeparator, PrekeyBundle, SecretKey32, X3Handshake}; use rand_core::{CryptoRng, RngCore}; -use crate::crypto::{PublicKey, StaticSecret}; +use crate::crypto::{PublicKey32, StaticSecret}; type Blake2bMac256 = Blake2bMac; @@ -24,13 +24,13 @@ impl InboxHandshake { identity_keypair: &StaticSecret, recipient_bundle: &PrekeyBundle, rng: &mut R, - ) -> (SecretKey32, PublicKey) { + ) -> (SecretKey32, PublicKey32) { // Perform X3DH handshake to get shared secret let (shared_secret, ephemeral_public) = InboxKeyExchange::initator(identity_keypair, recipient_bundle, rng); let seed_key = Self::derive_keys_from_shared_secret(shared_secret); - (seed_key, ephemeral_public) + (seed_key, ephemeral_public.into()) } /// Perform the Inbox Handshake after receiving a keyBundle @@ -45,8 +45,8 @@ impl InboxHandshake { identity_keypair: &StaticSecret, signed_prekey: &StaticSecret, onetime_prekey: Option<&StaticSecret>, - initiator_identity: &PublicKey, - initiator_ephemeral: &PublicKey, + initiator_identity: &PublicKey32, + initiator_ephemeral: &PublicKey32, ) -> SecretKey32 { // Perform X3DH to get shared secret let shared_secret = InboxKeyExchange::responder( @@ -86,16 +86,16 @@ mod tests { // Alice (initiator) generates her identity key let alice_identity = StaticSecret::random_from_rng(&mut rng); - let alice_identity_pub = PublicKey::from(&alice_identity); + let alice_identity_pub = PublicKey32::from(&alice_identity); // Bob (responder) generates his keys let bob_identity = StaticSecret::random_from_rng(&mut rng); let bob_signed_prekey = StaticSecret::random_from_rng(&mut rng); - let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey); + let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey); // Create Bob's prekey bundle let bob_bundle = PrekeyBundle { - identity_key: PublicKey::from(&bob_identity), + identity_key: PublicKey32::from(&bob_identity), signed_prekey: bob_signed_prekey_pub, signature: [0u8; 64], onetime_prekey: None, diff --git a/conversations/src/inbox/inbox.rs b/conversations/src/inbox/inbox.rs index 9d7e75f..2a025ac 100644 --- a/conversations/src/inbox/inbox.rs +++ b/conversations/src/inbox/inbox.rs @@ -9,14 +9,14 @@ use crypto::{PrekeyBundle, SecretKey32}; use crate::context::Introduction; use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, PrivateV1Convo}; -use crate::crypto::{Blake2b128, CopyBytes, Digest, PublicKey, StaticSecret}; +use crate::crypto::{Blake2b128, CopyBytes, Digest, PublicKey32, StaticSecret}; use crate::identity::Identity; use crate::inbox::handshake::InboxHandshake; use crate::proto; use crate::types::{AddressedEncryptedPayload, ContentData}; /// Compute the deterministic Delivery_address for an installation -fn delivery_address_for_installation(_: PublicKey) -> String { +fn delivery_address_for_installation(_: PublicKey32) -> String { // TODO: Implement Delivery Address "delivery_address".into() } @@ -58,7 +58,7 @@ impl Inbox { pub fn create_bundle(&mut self) -> PrekeyBundle { let ephemeral = StaticSecret::random(); - let signed_prekey = PublicKey::from(&ephemeral); + let signed_prekey = PublicKey32::from(&ephemeral); self.ephemeral_keys .insert(hex::encode(signed_prekey.as_bytes()), ephemeral); @@ -149,12 +149,12 @@ impl Inbox { let ephemeral_key = self.lookup_ephemeral_key(&pubkey_hex)?; - let initator_static = PublicKey::from( + let initator_static = PublicKey32::from( <[u8; 32]>::try_from(header.initiator_static.as_ref()) .map_err(|_| ChatError::BadBundleValue("wrong size - initator static".into()))?, ); - let initator_ephemeral = PublicKey::from( + let initator_ephemeral = PublicKey32::from( <[u8; 32]>::try_from(header.initiator_ephemeral.as_ref()) .map_err(|_| ChatError::BadBundleValue("wrong size - initator ephemeral".into()))?, ); diff --git a/conversations/src/inbox/introduction.rs b/conversations/src/inbox/introduction.rs index 0955e11..8d5ea63 100644 --- a/conversations/src/inbox/introduction.rs +++ b/conversations/src/inbox/introduction.rs @@ -1,12 +1,12 @@ use crypto::PrekeyBundle; -use x25519_dalek::PublicKey; +use crate::crypto::PublicKey32; use crate::errors::ChatError; /// Supplies remote participants with the required keys to use Inbox protocol pub struct Introduction { - pub installation_key: PublicKey, - pub ephemeral_key: PublicKey, + pub installation_key: PublicKey32, + pub ephemeral_key: PublicKey32, } impl From for Introduction { @@ -48,13 +48,13 @@ impl TryFrom<&[u8]> for Introduction { .map_err(|_| ChatError::BadParsing("installation_key"))? .try_into() .map_err(|_| ChatError::InvalidKeyLength)?; - let installation_key = PublicKey::from(installation_bytes); + let installation_key = PublicKey32::from(installation_bytes); let ephemeral_bytes: [u8; 32] = hex::decode(parts[1]) .map_err(|_| ChatError::BadParsing("ephemeral_key"))? .try_into() .map_err(|_| ChatError::InvalidKeyLength)?; - let ephemeral_key = PublicKey::from(ephemeral_bytes); + let ephemeral_key = PublicKey32::from(ephemeral_bytes); Ok(Introduction { installation_key, diff --git a/crypto/src/keys.rs b/crypto/src/keys.rs index 95477d0..aebb0b0 100644 --- a/crypto/src/keys.rs +++ b/crypto/src/keys.rs @@ -1,7 +1,42 @@ use generic_array::{GenericArray, typenum::U32}; -use std::fmt::Debug; +use std::{fmt::Debug, ops::Deref}; +use x25519_dalek; use zeroize::{Zeroize, ZeroizeOnDrop}; +#[derive(Debug, Copy, Clone)] +pub struct PublicKey32(x25519_dalek::PublicKey); + +impl From for PublicKey32 { + fn from(value: x25519_dalek::PublicKey) -> Self { + Self(value) + } +} + +impl From<&x25519_dalek::StaticSecret> for PublicKey32 { + fn from(value: &x25519_dalek::StaticSecret) -> Self { + Self(x25519_dalek::PublicKey::from(value)) + } +} + +impl From<[u8; 32]> for PublicKey32 { + fn from(value: [u8; 32]) -> Self { + Self(x25519_dalek::PublicKey::from(value)) + } +} + +impl Deref for PublicKey32 { + type Target = x25519_dalek::PublicKey; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl AsRef<[u8]> for PublicKey32 { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + #[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq)] pub struct SecretKey32([u8; 32]); diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 3e0f53c..8dbdc72 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -1,5 +1,5 @@ mod keys; mod x3dh; -pub use keys::SecretKey32; +pub use keys::{PublicKey32, SecretKey32}; pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake}; diff --git a/crypto/src/x3dh.rs b/crypto/src/x3dh.rs index a3b911c..b91505a 100644 --- a/crypto/src/x3dh.rs +++ b/crypto/src/x3dh.rs @@ -3,17 +3,17 @@ use std::marker::PhantomData; use hkdf::Hkdf; use rand_core::{CryptoRng, RngCore}; use sha2::Sha256; -use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; +use x25519_dalek::{SharedSecret, StaticSecret}; -use crate::keys::SecretKey32; +use crate::keys::{PublicKey32, SecretKey32}; /// A prekey bundle containing the public keys needed to initiate an X3DH key exchange. #[derive(Clone, Debug)] pub struct PrekeyBundle { - pub identity_key: PublicKey, - pub signed_prekey: PublicKey, + pub identity_key: PublicKey32, + pub signed_prekey: PublicKey32, pub signature: [u8; 64], - pub onetime_prekey: Option, + pub onetime_prekey: Option, } pub trait DomainSeparator { @@ -69,10 +69,10 @@ impl X3Handshake { identity_keypair: &StaticSecret, recipient_bundle: &PrekeyBundle, rng: &mut R, - ) -> (SecretKey32, PublicKey) { + ) -> (SecretKey32, PublicKey32) { // Generate ephemeral key for this handshake (using StaticSecret for multiple DH operations) let ephemeral_secret = StaticSecret::random_from_rng(rng); - let ephemeral_public = PublicKey::from(&ephemeral_secret); + let ephemeral_public = PublicKey32::from(&ephemeral_secret); // Perform the 4 Diffie-Hellman operations let dh1 = identity_keypair.diffie_hellman(&recipient_bundle.signed_prekey); @@ -104,8 +104,8 @@ impl X3Handshake { identity_keypair: &StaticSecret, signed_prekey: &StaticSecret, onetime_prekey: Option<&StaticSecret>, - initiator_identity: &PublicKey, - initiator_ephemeral: &PublicKey, + initiator_identity: &PublicKey32, + initiator_ephemeral: &PublicKey32, ) -> SecretKey32 { let dh1 = signed_prekey.diffie_hellman(initiator_identity); let dh2 = identity_keypair.diffie_hellman(initiator_ephemeral); @@ -135,17 +135,17 @@ mod tests { // Alice (initiator) generates her identity key let alice_identity = StaticSecret::random_from_rng(&mut rng); - let alice_identity_pub = PublicKey::from(&alice_identity); + let alice_identity_pub = PublicKey32::from(&alice_identity); // Bob (responder) generates his keys let bob_identity = StaticSecret::random_from_rng(&mut rng); - let bob_identity_pub = PublicKey::from(&bob_identity); + let bob_identity_pub = PublicKey32::from(&bob_identity); let bob_signed_prekey = StaticSecret::random_from_rng(&mut rng); - let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey); + let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey); let bob_onetime_prekey = StaticSecret::random_from_rng(&mut rng); - let bob_onetime_prekey_pub = PublicKey::from(&bob_onetime_prekey); + let bob_onetime_prekey_pub = PublicKey32::from(&bob_onetime_prekey); // Create Bob's prekey bundle (with one-time prekey) let bob_bundle = PrekeyBundle { @@ -178,14 +178,14 @@ mod tests { // Alice (initiator) generates her identity key let alice_identity = StaticSecret::random_from_rng(&mut rng); - let alice_identity_pub = PublicKey::from(&alice_identity); + let alice_identity_pub = PublicKey32::from(&alice_identity); // Bob (responder) generates his keys let bob_identity = StaticSecret::random_from_rng(&mut rng); - let bob_identity_pub = PublicKey::from(&bob_identity); + let bob_identity_pub = PublicKey32::from(&bob_identity); let bob_signed_prekey = StaticSecret::random_from_rng(&mut rng); - let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey); + let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey); // Create Bob's prekey bundle (without one-time prekey) let bob_bundle = PrekeyBundle {