From 31d20cd7f304dfa148ad8540003402d1de9891a2 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:06:04 -0800 Subject: [PATCH 01/11] Add generic SymmetricKey container --- conversations/src/conversation/privatev1.rs | 13 +++--- crypto/src/keys.rs | 44 +++++++++++++++------ 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index e48c27c..1182ed9 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -39,7 +39,7 @@ struct BaseConvoId([u8; 18]); impl BaseConvoId { fn new(key: &SecretKey) -> Self { - let base = Blake2bMac::::new_with_salt_and_personal(key.as_slice(), b"", b"L-PV1-CID") + let base = Blake2bMac::::new_with_salt_and_personal(key.as_bytes(), b"", b"L-PV1-CID") .expect("fixed inputs should never fail"); Self(base.finalize_fixed().into()) } @@ -87,7 +87,7 @@ impl PrivateV1Convo { let remote_convo_id = base_convo_id.id_for_participant(Role::Initiator); // TODO: Danger - Fix double-ratchets types to Accept SecretKey - let dr_state = RatchetState::init_receiver(seed_key.as_bytes().to_owned(), dh_self); + let dr_state = RatchetState::init_receiver(seed_key.DANGER_to_bytes(), dh_self); Self { local_convo_id, @@ -234,14 +234,11 @@ mod tests { let seed_key = saro.diffie_hellman(&pub_raya); let send_content_bytes = vec![0, 2, 4, 6, 8]; - let mut sr_convo = - PrivateV1Convo::new_initiator(SecretKey::from(seed_key.to_bytes()), pub_raya); + let mut sr_convo = PrivateV1Convo::new_initiator(SymmetricKey32::from(&seed_key), pub_raya); let installation_key_pair = InstallationKeyPair::from(raya); - let mut rs_convo = PrivateV1Convo::new_responder( - SecretKey::from(seed_key.to_bytes()), - installation_key_pair, - ); + let mut rs_convo = + PrivateV1Convo::new_responder(SymmetricKey32::from(&seed_key), installation_key_pair); let send_frame = PrivateV1Frame { conversation_id: "_".into(), diff --git a/crypto/src/keys.rs b/crypto/src/keys.rs index 4eeccb1..6751f37 100644 --- a/crypto/src/keys.rs +++ b/crypto/src/keys.rs @@ -1,35 +1,53 @@ use std::fmt::Debug; pub use generic_array::{GenericArray, typenum::U32}; +use x25519_dalek::SharedSecret; use zeroize::{Zeroize, ZeroizeOnDrop}; +/// A Generic secret key container for symmetric keys. +/// SymmetricKey retains ownership of bytes to ensure they are Zeroized on drop. #[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq)] -pub struct SecretKey([u8; 32]); +pub struct SymmetricKey([u8; N]); -impl SecretKey { - pub fn as_slice(&self) -> &[u8] { +impl SymmetricKey { + pub fn as_bytes(&self) -> &[u8] { self.0.as_slice() } - pub fn as_bytes(&self) -> &[u8; 32] { - &self.0 + /// Returns internal [u8; N]. + /// This function by passes zeroize_on_drop, and will be deprecated once all consumers have been migrated + #[allow(nonstandard_style)] + pub fn DANGER_to_bytes(self) -> [u8; N] { + // TODO: (P3) Remove once DR ported to use safe keys. + self.0 } } -impl From<[u8; 32]> for SecretKey { - fn from(value: [u8; 32]) -> Self { - SecretKey(value) +impl From<[u8; N]> for SymmetricKey { + fn from(value: [u8; N]) -> Self { + SymmetricKey(value) } } -impl From> for SecretKey { +impl Debug for SymmetricKey { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "SymmetricKey(...{N} Bytes Redacted...)") + } +} + +// TODO: (P5) look into typenum::generic_const_mappings to avoid having to implment From +pub type SymmetricKey32 = SymmetricKey<32>; + +impl From> for SymmetricKey32 { fn from(value: GenericArray) -> Self { - SecretKey(value.into()) + SymmetricKey(value.into()) } } -impl Debug for SecretKey { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("SecretKey").field(&"<32 bytes>").finish() +impl From<&SharedSecret> for SymmetricKey32 { + // This relies on the feature 'zeroize' being set for x25519-dalek. + // If not the SharedSecret will need to manually zeroized + fn from(value: &SharedSecret) -> Self { + value.to_bytes().into() } } From 8eacee50304ec72b0186cf0ad491f3d6d07be1dd Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:07:40 -0800 Subject: [PATCH 02/11] Rename SecretKey to SymmetricKey32 --- conversations/src/conversation/privatev1.rs | 12 ++++++------ conversations/src/inbox/handler.rs | 4 ++-- conversations/src/inbox/handshake.rs | 8 ++++---- crypto/src/lib.rs | 2 +- crypto/src/x3dh.rs | 10 +++++----- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index 1182ed9..b67661f 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -6,7 +6,7 @@ use chat_proto::logoschat::{ convos::private_v1::{PrivateV1Frame, private_v1_frame::FrameType}, encryption::{Doubleratchet, EncryptedPayload, encrypted_payload::Encryption}, }; -use crypto::SecretKey; +use crypto::SymmetricKey32; use double_ratchets::{Header, InstallationKeyPair, RatchetState}; use prost::{Message, bytes::Bytes}; use std::fmt::Debug; @@ -38,7 +38,7 @@ impl Role { struct BaseConvoId([u8; 18]); impl BaseConvoId { - fn new(key: &SecretKey) -> Self { + fn new(key: &SymmetricKey32) -> Self { let base = Blake2bMac::::new_with_salt_and_personal(key.as_bytes(), b"", b"L-PV1-CID") .expect("fixed inputs should never fail"); Self(base.finalize_fixed().into()) @@ -60,12 +60,12 @@ pub struct PrivateV1Convo { } impl PrivateV1Convo { - pub fn new_initiator(seed_key: SecretKey, remote: PublicKey) -> Self { + pub fn new_initiator(seed_key: SymmetricKey32, remote: PublicKey) -> Self { let base_convo_id = BaseConvoId::new(&seed_key); let local_convo_id = base_convo_id.id_for_participant(Role::Initiator); let remote_convo_id = base_convo_id.id_for_participant(Role::Responder); - // TODO: Danger - Fix double-ratchets types to Accept SecretKey + // TODO: Danger - Fix double-ratchets types to Accept SymmetricKey32 // perhaps update the DH to work with cryptocrate. // init_sender doesn't take ownership of the key so a reference can be used. let shared_secret: [u8; 32] = seed_key.as_bytes().to_vec().try_into().unwrap(); @@ -79,14 +79,14 @@ impl PrivateV1Convo { } pub fn new_responder( - seed_key: SecretKey, + seed_key: SymmetricKey32, dh_self: InstallationKeyPair, // TODO: (P3) Rename; This accepts a Ephemeral key in most cases ) -> Self { let base_convo_id = BaseConvoId::new(&seed_key); let local_convo_id = base_convo_id.id_for_participant(Role::Responder); let remote_convo_id = base_convo_id.id_for_participant(Role::Initiator); - // TODO: Danger - Fix double-ratchets types to Accept SecretKey + // TODO: Danger - Fix double-ratchets types to Accept SymmetricKey32 let dr_state = RatchetState::init_receiver(seed_key.DANGER_to_bytes(), dh_self); Self { diff --git a/conversations/src/inbox/handler.rs b/conversations/src/inbox/handler.rs index a2fc472..c438c23 100644 --- a/conversations/src/inbox/handler.rs +++ b/conversations/src/inbox/handler.rs @@ -6,7 +6,7 @@ use rand_core::OsRng; use std::collections::HashMap; use std::rc::Rc; -use crypto::{PrekeyBundle, SecretKey}; +use crypto::{PrekeyBundle, SymmetricKey32}; use crate::context::Introduction; use crate::conversation::{ChatError, ConversationId, Convo, Id, PrivateV1Convo}; @@ -172,7 +172,7 @@ impl Inbox { ephemeral_key: &StaticSecret, header: proto::InboxHeaderV1, bytes: Bytes, - ) -> Result<(SecretKey, proto::InboxV1Frame), ChatError> { + ) -> Result<(SymmetricKey32, proto::InboxV1Frame), ChatError> { // Get PublicKeys from protobuf let initator_static = PublicKey::from( <[u8; 32]>::try_from(header.initiator_static.as_ref()) diff --git a/conversations/src/inbox/handshake.rs b/conversations/src/inbox/handshake.rs index eda7d00..5d8d0f3 100644 --- a/conversations/src/inbox/handshake.rs +++ b/conversations/src/inbox/handshake.rs @@ -2,7 +2,7 @@ use blake2::{ Blake2bMac, digest::{FixedOutput, consts::U32}, }; -use crypto::{DomainSeparator, PrekeyBundle, SecretKey, X3Handshake}; +use crypto::{DomainSeparator, PrekeyBundle, SymmetricKey32, X3Handshake}; use rand_core::{CryptoRng, RngCore}; use crate::crypto::{PublicKey, StaticSecret}; @@ -24,7 +24,7 @@ impl InboxHandshake { identity_keypair: &StaticSecret, recipient_bundle: &PrekeyBundle, rng: &mut R, - ) -> (SecretKey, PublicKey) { + ) -> (SymmetricKey32, PublicKey) { // Perform X3DH handshake to get shared secret let (shared_secret, ephemeral_public) = InboxKeyExchange::initator(identity_keypair, recipient_bundle, rng); @@ -47,7 +47,7 @@ impl InboxHandshake { onetime_prekey: Option<&StaticSecret>, initiator_identity: &PublicKey, initiator_ephemeral: &PublicKey, - ) -> SecretKey { + ) -> SymmetricKey32 { // Perform X3DH to get shared secret let shared_secret = InboxKeyExchange::responder( identity_keypair, @@ -61,7 +61,7 @@ impl InboxHandshake { } /// Derive keys from X3DH shared secret - fn derive_keys_from_shared_secret(shared_secret: SecretKey) -> SecretKey { + fn derive_keys_from_shared_secret(shared_secret: SymmetricKey32) -> SymmetricKey32 { let seed_key: [u8; 32] = Blake2bMac256::new_with_salt_and_personal( shared_secret.as_slice(), &[], // No salt - input already has high entropy diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index 3b8776b..d44231f 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -2,6 +2,6 @@ mod keys; mod x3dh; mod xeddsa_sign; -pub use keys::{GenericArray, SecretKey}; +pub use keys::{GenericArray, SymmetricKey32}; pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake}; pub use xeddsa_sign::{Ed25519Signature, SignatureError, xeddsa_sign, xeddsa_verify}; diff --git a/crypto/src/x3dh.rs b/crypto/src/x3dh.rs index b71c498..d942fbd 100644 --- a/crypto/src/x3dh.rs +++ b/crypto/src/x3dh.rs @@ -5,7 +5,7 @@ use rand_core::{CryptoRng, RngCore}; use sha2::Sha256; use x25519_dalek::{PublicKey, SharedSecret, StaticSecret}; -use crate::keys::SecretKey; +use crate::keys::SymmetricKey32; use crate::xeddsa_sign::Ed25519Signature; /// A prekey bundle containing the public keys needed to initiate an X3DH key exchange. @@ -36,7 +36,7 @@ impl X3Handshake { dh2: &SharedSecret, dh3: &SharedSecret, dh4: Option<&SharedSecret>, - ) -> SecretKey { + ) -> SymmetricKey32 { // Concatenate all DH outputs let mut km = Vec::new(); km.extend_from_slice(dh1.as_bytes()); @@ -53,7 +53,7 @@ impl X3Handshake { hk.expand(Self::domain_separator(), &mut output) .expect("32 bytes is valid HKDF output length"); - // Move into SecretKey so it gets zeroized on drop. + // Move into SymmetricKey32 so it gets zeroized on drop. output.into() } @@ -70,7 +70,7 @@ impl X3Handshake { identity_keypair: &StaticSecret, recipient_bundle: &PrekeyBundle, rng: &mut R, - ) -> (SecretKey, PublicKey) { + ) -> (SymmetricKey32, PublicKey) { // 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); @@ -107,7 +107,7 @@ impl X3Handshake { onetime_prekey: Option<&StaticSecret>, initiator_identity: &PublicKey, initiator_ephemeral: &PublicKey, - ) -> SecretKey { + ) -> SymmetricKey32 { let dh1 = signed_prekey.diffie_hellman(initiator_identity); let dh2 = identity_keypair.diffie_hellman(initiator_ephemeral); let dh3 = signed_prekey.diffie_hellman(initiator_ephemeral); From fdae24867fbd2a6c50711965f2732786c963c5dc Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Thu, 12 Feb 2026 15:08:07 -0800 Subject: [PATCH 03/11] Update SymmetricKey usage --- conversations/src/conversation/privatev1.rs | 2 +- conversations/src/inbox/handshake.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index b67661f..2711436 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -68,7 +68,7 @@ impl PrivateV1Convo { // TODO: Danger - Fix double-ratchets types to Accept SymmetricKey32 // perhaps update the DH to work with cryptocrate. // init_sender doesn't take ownership of the key so a reference can be used. - let shared_secret: [u8; 32] = seed_key.as_bytes().to_vec().try_into().unwrap(); + let shared_secret: [u8; 32] = seed_key.DANGER_to_bytes(); let dr_state = RatchetState::init_sender(shared_secret, remote); Self { diff --git a/conversations/src/inbox/handshake.rs b/conversations/src/inbox/handshake.rs index 5d8d0f3..8da581a 100644 --- a/conversations/src/inbox/handshake.rs +++ b/conversations/src/inbox/handshake.rs @@ -63,7 +63,7 @@ impl InboxHandshake { /// Derive keys from X3DH shared secret fn derive_keys_from_shared_secret(shared_secret: SymmetricKey32) -> SymmetricKey32 { let seed_key: [u8; 32] = Blake2bMac256::new_with_salt_and_personal( - shared_secret.as_slice(), + shared_secret.as_bytes(), &[], // No salt - input already has high entropy b"InboxV1-Seed", ) From bdef2b50797310270fee2dc745ea873cf1ae765c Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:59:57 -0800 Subject: [PATCH 04/11] Add PublicKey --- crypto/src/keys.rs | 40 +++++++++++++++++++++++++++++++++++++--- crypto/src/lib.rs | 2 +- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/crypto/src/keys.rs b/crypto/src/keys.rs index 6751f37..1465c20 100644 --- a/crypto/src/keys.rs +++ b/crypto/src/keys.rs @@ -1,9 +1,43 @@ -use std::fmt::Debug; - pub use generic_array::{GenericArray, typenum::U32}; -use x25519_dalek::SharedSecret; + +use std::fmt::Debug; +use x25519_dalek::{PublicKey as x25519_Pub, SharedSecret, StaticSecret}; +use xeddsa::xed25519::PublicKey as xed25519_Pub; use zeroize::{Zeroize, ZeroizeOnDrop}; +#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, Zeroize)] // TODO: (!) Zeroize only required by InstallationKeyPair +pub struct PublicKey(x25519_Pub); + +impl From for PublicKey { + fn from(value: x25519_Pub) -> Self { + Self(value) + } +} + +impl From<&StaticSecret> for PublicKey { + fn from(value: &StaticSecret) -> Self { + Self(x25519_Pub::from(value)) + } +} + +impl From<[u8; 32]> for PublicKey { + fn from(value: [u8; 32]) -> Self { + Self(x25519_Pub::from(value)) + } +} + +impl AsRef<[u8]> for PublicKey { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl From<&PublicKey> for xed25519_Pub { + fn from(value: &PublicKey) -> Self { + Self::from(&value.0) + } +} + /// A Generic secret key container for symmetric keys. /// SymmetricKey retains ownership of bytes to ensure they are Zeroized on drop. #[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq)] diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index d44231f..c654e7c 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -2,6 +2,6 @@ mod keys; mod x3dh; mod xeddsa_sign; -pub use keys::{GenericArray, SymmetricKey32}; +pub use keys::{GenericArray, PublicKey, SymmetricKey32}; pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake}; pub use xeddsa_sign::{Ed25519Signature, SignatureError, xeddsa_sign, xeddsa_verify}; From aaecd0b64745e18068fa80226ddf46a742ac52c8 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Fri, 13 Feb 2026 20:30:27 -0800 Subject: [PATCH 05/11] Update PublicKey uses --- conversations/src/conversation/privatev1.rs | 3 +-- conversations/src/inbox/introduction.rs | 4 ++-- crypto/src/x3dh.rs | 4 ++-- crypto/src/xeddsa_sign.rs | 3 ++- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index 2711436..bd7e608 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -6,11 +6,10 @@ use chat_proto::logoschat::{ convos::private_v1::{PrivateV1Frame, private_v1_frame::FrameType}, encryption::{Doubleratchet, EncryptedPayload, encrypted_payload::Encryption}, }; -use crypto::SymmetricKey32; +use crypto::{PublicKey, SymmetricKey32}; use double_ratchets::{Header, InstallationKeyPair, RatchetState}; use prost::{Message, bytes::Bytes}; use std::fmt::Debug; -use x25519_dalek::PublicKey; use crate::{ conversation::{ChatError, ConversationId, Convo, Id}, diff --git a/conversations/src/inbox/introduction.rs b/conversations/src/inbox/introduction.rs index 90b200c..ec56c4e 100644 --- a/conversations/src/inbox/introduction.rs +++ b/conversations/src/inbox/introduction.rs @@ -1,9 +1,9 @@ use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD}; use chat_proto::logoschat::intro::IntroBundle; -use crypto::Ed25519Signature; +use crypto::{Ed25519Signature, PublicKey}; use prost::Message; use rand_core::{CryptoRng, RngCore}; -use x25519_dalek::{PublicKey, StaticSecret}; +use x25519_dalek::StaticSecret; use crate::errors::ChatError; diff --git a/crypto/src/x3dh.rs b/crypto/src/x3dh.rs index d942fbd..6606c3e 100644 --- a/crypto/src/x3dh.rs +++ b/crypto/src/x3dh.rs @@ -3,9 +3,9 @@ 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::SymmetricKey32; +use crate::keys::{PublicKey, SymmetricKey32}; use crate::xeddsa_sign::Ed25519Signature; /// A prekey bundle containing the public keys needed to initiate an X3DH key exchange. diff --git a/crypto/src/xeddsa_sign.rs b/crypto/src/xeddsa_sign.rs index 8426a99..4dfb4be 100644 --- a/crypto/src/xeddsa_sign.rs +++ b/crypto/src/xeddsa_sign.rs @@ -3,8 +3,9 @@ //! This module provides generic XEdDSA sign and verify functions //! that allow signing arbitrary messages with X25519 keys. +use crate::PublicKey; use rand_core::{CryptoRng, RngCore}; -use x25519_dalek::{PublicKey, StaticSecret}; +use x25519_dalek::StaticSecret; use xeddsa::{Sign, Verify, xed25519}; /// A 64-byte XEdDSA signature over an Ed25519-compatible curve. From 25a8a031735f23b3cb962a17ac2ab3089f3cd543 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Fri, 13 Feb 2026 20:34:07 -0800 Subject: [PATCH 06/11] Add PrivateKey --- crypto/src/keys.rs | 63 ++++++++++++++++++++++++++++++++++++++++------ crypto/src/lib.rs | 2 +- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/crypto/src/keys.rs b/crypto/src/keys.rs index 1465c20..0634b72 100644 --- a/crypto/src/keys.rs +++ b/crypto/src/keys.rs @@ -1,8 +1,9 @@ -pub use generic_array::{GenericArray, typenum::U32}; +use generic_array::{GenericArray, typenum::U32}; -use std::fmt::Debug; -use x25519_dalek::{PublicKey as x25519_Pub, SharedSecret, StaticSecret}; -use xeddsa::xed25519::PublicKey as xed25519_Pub; +use rand_core::{CryptoRng, OsRng, RngCore}; +use std::{fmt::Debug, ops::Deref}; +use x25519_dalek::{PublicKey as x25519_Pub, SharedSecret, StaticSecret as x25519_Priv}; +use xeddsa::xed25519::{self, PublicKey as xed25519_Pub}; use zeroize::{Zeroize, ZeroizeOnDrop}; #[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, Zeroize)] // TODO: (!) Zeroize only required by InstallationKeyPair @@ -14,8 +15,8 @@ impl From for PublicKey { } } -impl From<&StaticSecret> for PublicKey { - fn from(value: &StaticSecret) -> Self { +impl From<&x25519_Priv> for PublicKey { + fn from(value: &x25519_Priv) -> Self { Self(x25519_Pub::from(value)) } } @@ -38,6 +39,54 @@ impl From<&PublicKey> for xed25519_Pub { } } +impl Deref for PublicKey { + type Target = x25519_Pub; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Clone, Zeroize, ZeroizeOnDrop)] +pub struct PrivateKey(x25519_Priv); + +impl PrivateKey { + pub fn random_from_rng(csprng: T) -> Self { + Self(x25519_Priv::random_from_rng(csprng)) + } + + //TODO: Remove. Force internal callers provide Rng to make deterministic testing possible + pub fn random() -> PrivateKey { + Self::random_from_rng(OsRng) + } + + pub fn diffie_hellman(&self, public_key: &PublicKey) -> SymmetricKey32 { + (&self.0.diffie_hellman(&public_key.0)).into() + } + + pub fn DANGER_to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } +} + +impl From<&PrivateKey> for xed25519::PrivateKey { + fn from(value: &PrivateKey) -> Self { + Self::from(&value.0) + } +} + +impl From<&PrivateKey> for PublicKey { + fn from(value: &PrivateKey) -> Self { + Self(x25519_Pub::from(&value.0)) + } +} + +impl From<[u8; 32]> for PrivateKey { + fn from(value: [u8; 32]) -> Self { + Self(x25519_Priv::from(value)) + } +} + /// A Generic secret key container for symmetric keys. /// SymmetricKey retains ownership of bytes to ensure they are Zeroized on drop. #[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq)] @@ -69,7 +118,7 @@ impl Debug for SymmetricKey { } } -// TODO: (P5) look into typenum::generic_const_mappings to avoid having to implment From +// TODO: (P5) look into typenum::generic_const_mappings to avoid having to implement From pub type SymmetricKey32 = SymmetricKey<32>; impl From> for SymmetricKey32 { diff --git a/crypto/src/lib.rs b/crypto/src/lib.rs index c654e7c..4b095ba 100644 --- a/crypto/src/lib.rs +++ b/crypto/src/lib.rs @@ -2,6 +2,6 @@ mod keys; mod x3dh; mod xeddsa_sign; -pub use keys::{GenericArray, PublicKey, SymmetricKey32}; +pub use keys::{PrivateKey, PublicKey, SymmetricKey32}; pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake}; pub use xeddsa_sign::{Ed25519Signature, SignatureError, xeddsa_sign, xeddsa_verify}; From 9d7f494c46e2caabd3478c588e8cdef48650c4e8 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Sun, 15 Feb 2026 16:56:04 -0800 Subject: [PATCH 07/11] Replace StaticSecret with PrivateKey --- conversations/src/conversation/privatev1.rs | 4 ++-- conversations/src/identity.rs | 8 +++---- conversations/src/inbox/handler.rs | 12 +++++----- conversations/src/inbox/handshake.rs | 16 ++++++------- conversations/src/inbox/introduction.rs | 8 +++---- crypto/src/x3dh.rs | 26 ++++++++++----------- crypto/src/xeddsa_sign.rs | 12 +++++----- 7 files changed, 43 insertions(+), 43 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index bd7e608..430e66f 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -226,8 +226,8 @@ mod tests { #[test] fn test_encrypt_roundtrip() { - let saro = StaticSecret::random(); - let raya = StaticSecret::random(); + let saro = PrivateKey::random(); + let raya = PrivateKey::random(); let pub_raya = PublicKey::from(&raya); diff --git a/conversations/src/identity.rs b/conversations/src/identity.rs index 44dd79e..de3be1e 100644 --- a/conversations/src/identity.rs +++ b/conversations/src/identity.rs @@ -1,9 +1,9 @@ use std::fmt; -use crate::crypto::{PublicKey, StaticSecret}; +use crate::crypto::{PrivateKey, PublicKey}; pub struct Identity { - secret: StaticSecret, + secret: PrivateKey, } impl fmt::Debug for Identity { @@ -18,7 +18,7 @@ impl fmt::Debug for Identity { impl Identity { pub fn new() -> Self { Self { - secret: StaticSecret::random(), + secret: PrivateKey::random(), } } @@ -26,7 +26,7 @@ impl Identity { PublicKey::from(&self.secret) } - pub fn secret(&self) -> &StaticSecret { + pub fn secret(&self) -> &PrivateKey { &self.secret } } diff --git a/conversations/src/inbox/handler.rs b/conversations/src/inbox/handler.rs index c438c23..504f812 100644 --- a/conversations/src/inbox/handler.rs +++ b/conversations/src/inbox/handler.rs @@ -10,7 +10,7 @@ use crypto::{PrekeyBundle, SymmetricKey32}; use crate::context::Introduction; use crate::conversation::{ChatError, ConversationId, Convo, Id, PrivateV1Convo}; -use crate::crypto::{CopyBytes, PublicKey, StaticSecret}; +use crate::crypto::{CopyBytes, PrivateKey, PublicKey}; use crate::identity::Identity; use crate::inbox::handshake::InboxHandshake; use crate::proto; @@ -25,7 +25,7 @@ fn delivery_address_for_installation(_: PublicKey) -> String { pub struct Inbox { ident: Rc, local_convo_id: String, - ephemeral_keys: HashMap, + ephemeral_keys: HashMap, } impl std::fmt::Debug for Inbox { @@ -47,12 +47,12 @@ impl Inbox { Self { ident, local_convo_id, - ephemeral_keys: HashMap::::new(), + ephemeral_keys: HashMap::::new(), } } pub fn create_intro_bundle(&mut self) -> Introduction { - let ephemeral = StaticSecret::random(); + let ephemeral = PrivateKey::random(); let ephemeral_key: PublicKey = (&ephemeral).into(); self.ephemeral_keys @@ -169,7 +169,7 @@ impl Inbox { fn perform_handshake( &self, - ephemeral_key: &StaticSecret, + ephemeral_key: &PrivateKey, header: proto::InboxHeaderV1, bytes: Bytes, ) -> Result<(SymmetricKey32, proto::InboxV1Frame), ChatError> { @@ -215,7 +215,7 @@ impl Inbox { Ok(frame) } - fn lookup_ephemeral_key(&self, key: &str) -> Result<&StaticSecret, ChatError> { + fn lookup_ephemeral_key(&self, key: &str) -> Result<&PrivateKey, ChatError> { self.ephemeral_keys .get(key) .ok_or(ChatError::UnknownEphemeralKey()) diff --git a/conversations/src/inbox/handshake.rs b/conversations/src/inbox/handshake.rs index 8da581a..8a93a5a 100644 --- a/conversations/src/inbox/handshake.rs +++ b/conversations/src/inbox/handshake.rs @@ -5,7 +5,7 @@ use blake2::{ use crypto::{DomainSeparator, PrekeyBundle, SymmetricKey32, X3Handshake}; use rand_core::{CryptoRng, RngCore}; -use crate::crypto::{PublicKey, StaticSecret}; +use crate::crypto::{PrivateKey, PublicKey}; type Blake2bMac256 = Blake2bMac; @@ -21,7 +21,7 @@ pub struct InboxHandshake {} impl InboxHandshake { /// Performs pub fn perform_as_initiator( - identity_keypair: &StaticSecret, + identity_keypair: &PrivateKey, recipient_bundle: &PrekeyBundle, rng: &mut R, ) -> (SymmetricKey32, PublicKey) { @@ -42,9 +42,9 @@ impl InboxHandshake { /// * `initiator_identity` - Initiator's identity public key /// * `initiator_ephemeral` - Initiator's ephemeral public key pub fn perform_as_responder( - identity_keypair: &StaticSecret, - signed_prekey: &StaticSecret, - onetime_prekey: Option<&StaticSecret>, + identity_keypair: &PrivateKey, + signed_prekey: &PrivateKey, + onetime_prekey: Option<&PrivateKey>, initiator_identity: &PublicKey, initiator_ephemeral: &PublicKey, ) -> SymmetricKey32 { @@ -85,12 +85,12 @@ mod tests { let mut rng = OsRng; // Alice (initiator) generates her identity key - let alice_identity = StaticSecret::random_from_rng(rng); + let alice_identity = PrivateKey::random_from_rng(rng); let alice_identity_pub = PublicKey::from(&alice_identity); // Bob (responder) generates his keys - let bob_identity = StaticSecret::random_from_rng(rng); - let bob_signed_prekey = StaticSecret::random_from_rng(rng); + let bob_identity = PrivateKey::random_from_rng(rng); + let bob_signed_prekey = PrivateKey::random_from_rng(rng); let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey); // Create Bob's prekey bundle diff --git a/conversations/src/inbox/introduction.rs b/conversations/src/inbox/introduction.rs index ec56c4e..50987e9 100644 --- a/conversations/src/inbox/introduction.rs +++ b/conversations/src/inbox/introduction.rs @@ -17,7 +17,7 @@ fn intro_binding_message(ephemeral: &PublicKey) -> Vec { } pub(crate) fn sign_intro_binding( - secret: &StaticSecret, + secret: &PrivateKey, ephemeral: &PublicKey, rng: R, ) -> Ed25519Signature { @@ -44,7 +44,7 @@ pub struct Introduction { impl Introduction { /// Create a new `Introduction` by signing the ephemeral key with the installation secret. pub(crate) fn new( - installation_secret: &StaticSecret, + installation_secret: &PrivateKey, ephemeral_key: PublicKey, rng: R, ) -> Self { @@ -147,9 +147,9 @@ mod tests { use rand_core::OsRng; fn create_test_introduction() -> Introduction { - let install_secret = StaticSecret::random_from_rng(OsRng); + let install_secret = PrivateKey::random_from_rng(OsRng); - let ephemeral_secret = StaticSecret::random_from_rng(OsRng); + let ephemeral_secret = PrivateKey::random_from_rng(OsRng); let ephemeral_pub: PublicKey = (&ephemeral_secret).into(); Introduction::new(&install_secret, ephemeral_pub, OsRng) diff --git a/crypto/src/x3dh.rs b/crypto/src/x3dh.rs index 6606c3e..d97f5b0 100644 --- a/crypto/src/x3dh.rs +++ b/crypto/src/x3dh.rs @@ -67,12 +67,12 @@ impl X3Handshake { /// # Returns /// A tuple of (shared secret bytes, ephemeral public key) pub fn initator( - identity_keypair: &StaticSecret, + identity_keypair: &PrivateKey, recipient_bundle: &PrekeyBundle, rng: &mut R, ) -> (SymmetricKey32, PublicKey) { - // Generate ephemeral key for this handshake (using StaticSecret for multiple DH operations) - let ephemeral_secret = StaticSecret::random_from_rng(rng); + // Generate ephemeral key for this handshake (using PrivateKey for multiple DH operations) + let ephemeral_secret = PrivateKey::random_from_rng(rng); let ephemeral_public = PublicKey::from(&ephemeral_secret); // Perform the 4 Diffie-Hellman operations @@ -102,9 +102,9 @@ impl X3Handshake { /// # Returns /// The derived shared secret bytes pub fn responder( - identity_keypair: &StaticSecret, - signed_prekey: &StaticSecret, - onetime_prekey: Option<&StaticSecret>, + identity_keypair: &PrivateKey, + signed_prekey: &PrivateKey, + onetime_prekey: Option<&PrivateKey>, initiator_identity: &PublicKey, initiator_ephemeral: &PublicKey, ) -> SymmetricKey32 { @@ -135,17 +135,17 @@ mod tests { let mut rng = OsRng; // Alice (initiator) generates her identity key - let alice_identity = StaticSecret::random_from_rng(rng); + let alice_identity = PrivateKey::random_from_rng(rng); let alice_identity_pub = PublicKey::from(&alice_identity); // Bob (responder) generates his keys - let bob_identity = StaticSecret::random_from_rng(rng); + let bob_identity = PrivateKey::random_from_rng(rng); let bob_identity_pub = PublicKey::from(&bob_identity); - let bob_signed_prekey = StaticSecret::random_from_rng(rng); + let bob_signed_prekey = PrivateKey::random_from_rng(rng); let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey); - let bob_onetime_prekey = StaticSecret::random_from_rng(rng); + let bob_onetime_prekey = PrivateKey::random_from_rng(rng); let bob_onetime_prekey_pub = PublicKey::from(&bob_onetime_prekey); // Create Bob's prekey bundle (with one-time prekey) @@ -178,14 +178,14 @@ mod tests { let mut rng = OsRng; // Alice (initiator) generates her identity key - let alice_identity = StaticSecret::random_from_rng(rng); + let alice_identity = PrivateKey::random_from_rng(rng); let alice_identity_pub = PublicKey::from(&alice_identity); // Bob (responder) generates his keys - let bob_identity = StaticSecret::random_from_rng(rng); + let bob_identity = PrivateKey::random_from_rng(rng); let bob_identity_pub = PublicKey::from(&bob_identity); - let bob_signed_prekey = StaticSecret::random_from_rng(rng); + let bob_signed_prekey = PrivateKey::random_from_rng(rng); let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey); // Create Bob's prekey bundle (without one-time prekey) diff --git a/crypto/src/xeddsa_sign.rs b/crypto/src/xeddsa_sign.rs index 4dfb4be..26c27ab 100644 --- a/crypto/src/xeddsa_sign.rs +++ b/crypto/src/xeddsa_sign.rs @@ -45,7 +45,7 @@ pub struct SignatureError; /// # Returns /// An `Ed25519Signature` pub fn xeddsa_sign( - secret: &StaticSecret, + secret: &PrivateKey, message: &[u8], mut rng: R, ) -> Ed25519Signature { @@ -80,7 +80,7 @@ mod tests { #[test] fn test_sign_and_verify_roundtrip() { - let secret = StaticSecret::random_from_rng(OsRng); + let secret = PrivateKey::random_from_rng(OsRng); let public = PublicKey::from(&secret); let message = b"test message"; @@ -91,12 +91,12 @@ mod tests { #[test] fn test_wrong_key_fails() { - let secret = StaticSecret::random_from_rng(OsRng); + let secret = PrivateKey::random_from_rng(OsRng); let message = b"test message"; let signature = xeddsa_sign(&secret, message, OsRng); - let wrong_secret = StaticSecret::random_from_rng(OsRng); + let wrong_secret = PrivateKey::random_from_rng(OsRng); let wrong_public = PublicKey::from(&wrong_secret); assert_eq!( @@ -107,7 +107,7 @@ mod tests { #[test] fn test_wrong_message_fails() { - let secret = StaticSecret::random_from_rng(OsRng); + let secret = PrivateKey::random_from_rng(OsRng); let public = PublicKey::from(&secret); let message = b"test message"; @@ -121,7 +121,7 @@ mod tests { #[test] fn test_corrupted_signature_fails() { - let secret = StaticSecret::random_from_rng(OsRng); + let secret = PrivateKey::random_from_rng(OsRng); let public = PublicKey::from(&secret); let message = b"test message"; From 0302b8c2e31911efe4f8ed4cd14bfe90e4f61a15 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Sun, 15 Feb 2026 16:57:23 -0800 Subject: [PATCH 08/11] Fix imports --- conversations/src/conversation/privatev1.rs | 4 ++-- conversations/src/crypto.rs | 2 +- conversations/src/inbox/introduction.rs | 3 +-- crypto/src/x3dh.rs | 4 ++-- crypto/src/xeddsa_sign.rs | 3 +-- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index 430e66f..1e88630 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -6,7 +6,7 @@ use chat_proto::logoschat::{ convos::private_v1::{PrivateV1Frame, private_v1_frame::FrameType}, encryption::{Doubleratchet, EncryptedPayload, encrypted_payload::Encryption}, }; -use crypto::{PublicKey, SymmetricKey32}; +use crypto::{PrivateKey, PublicKey, SymmetricKey32}; use double_ratchets::{Header, InstallationKeyPair, RatchetState}; use prost::{Message, bytes::Bytes}; use std::fmt::Debug; @@ -220,7 +220,7 @@ impl Debug for PrivateV1Convo { #[cfg(test)] mod tests { - use x25519_dalek::StaticSecret; + use crypto::PrivateKey; use super::*; diff --git a/conversations/src/crypto.rs b/conversations/src/crypto.rs index ff9531f..148529b 100644 --- a/conversations/src/crypto.rs +++ b/conversations/src/crypto.rs @@ -1,5 +1,5 @@ +pub use crypto::{PrivateKey, PublicKey}; use prost::bytes::Bytes; -pub use x25519_dalek::{PublicKey, StaticSecret}; pub trait CopyBytes { fn copy_to_bytes(&self) -> Bytes; diff --git a/conversations/src/inbox/introduction.rs b/conversations/src/inbox/introduction.rs index 50987e9..9f6f5c0 100644 --- a/conversations/src/inbox/introduction.rs +++ b/conversations/src/inbox/introduction.rs @@ -1,9 +1,8 @@ use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD}; use chat_proto::logoschat::intro::IntroBundle; -use crypto::{Ed25519Signature, PublicKey}; +use crypto::{Ed25519Signature, PrivateKey, PublicKey}; use prost::Message; use rand_core::{CryptoRng, RngCore}; -use x25519_dalek::StaticSecret; use crate::errors::ChatError; diff --git a/crypto/src/x3dh.rs b/crypto/src/x3dh.rs index d97f5b0..d5e5bff 100644 --- a/crypto/src/x3dh.rs +++ b/crypto/src/x3dh.rs @@ -3,9 +3,9 @@ use std::marker::PhantomData; use hkdf::Hkdf; use rand_core::{CryptoRng, RngCore}; use sha2::Sha256; -use x25519_dalek::{SharedSecret, StaticSecret}; +use x25519_dalek::SharedSecret; -use crate::keys::{PublicKey, SymmetricKey32}; +use crate::keys::{PrivateKey, PublicKey, SymmetricKey32}; use crate::xeddsa_sign::Ed25519Signature; /// A prekey bundle containing the public keys needed to initiate an X3DH key exchange. diff --git a/crypto/src/xeddsa_sign.rs b/crypto/src/xeddsa_sign.rs index 26c27ab..20dd3c0 100644 --- a/crypto/src/xeddsa_sign.rs +++ b/crypto/src/xeddsa_sign.rs @@ -3,11 +3,10 @@ //! This module provides generic XEdDSA sign and verify functions //! that allow signing arbitrary messages with X25519 keys. -use crate::PublicKey; use rand_core::{CryptoRng, RngCore}; -use x25519_dalek::StaticSecret; use xeddsa::{Sign, Verify, xed25519}; +use crate::{PrivateKey, PublicKey}; /// A 64-byte XEdDSA signature over an Ed25519-compatible curve. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Ed25519Signature(pub [u8; 64]); From 9810e11a05be388169ab6a3d531be26110580246 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:01:12 -0800 Subject: [PATCH 09/11] Remove InstallKey from constructors --- conversations/src/conversation/privatev1.rs | 11 ++++++----- conversations/src/inbox/handler.rs | 3 +-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index 1e88630..0c975fb 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -77,16 +77,17 @@ impl PrivateV1Convo { } } - pub fn new_responder( - seed_key: SymmetricKey32, - dh_self: InstallationKeyPair, // TODO: (P3) Rename; This accepts a Ephemeral key in most cases - ) -> Self { + pub fn new_responder(seed_key: SymmetricKey32, dh_self: &PrivateKey) -> Self { let base_convo_id = BaseConvoId::new(&seed_key); let local_convo_id = base_convo_id.id_for_participant(Role::Responder); let remote_convo_id = base_convo_id.id_for_participant(Role::Initiator); + // TODO: (P3) Rename; This accepts a Ephemeral key in most cases + let dh_self_installation_keypair = + InstallationKeyPair::from_secret_bytes(dh_self.DANGER_to_bytes()); // TODO: Danger - Fix double-ratchets types to Accept SymmetricKey32 - let dr_state = RatchetState::init_receiver(seed_key.DANGER_to_bytes(), dh_self); + let dr_state = + RatchetState::init_receiver(seed_key.DANGER_to_bytes(), dh_self_installation_keypair); Self { local_convo_id, diff --git a/conversations/src/inbox/handler.rs b/conversations/src/inbox/handler.rs index 504f812..f953cca 100644 --- a/conversations/src/inbox/handler.rs +++ b/conversations/src/inbox/handler.rs @@ -133,8 +133,7 @@ impl Inbox { match frame.frame_type.unwrap() { proto::inbox_v1_frame::FrameType::InvitePrivateV1(_invite_private_v1) => { - let mut convo = - PrivateV1Convo::new_responder(seed_key, ephemeral_key.clone().into()); + let mut convo = PrivateV1Convo::new_responder(seed_key, ephemeral_key); let Some(enc_payload) = _invite_private_v1.initial_message else { return Err(ChatError::Protocol("missing initial encpayload".into())); From 9928992f55813b674e43abe77c6242058661b123 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:03:09 -0800 Subject: [PATCH 10/11] Final integration --- conversations/src/conversation/privatev1.rs | 14 +++++++------- crypto/src/keys.rs | 1 + crypto/src/x3dh.rs | 9 ++++----- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index 0c975fb..c2966cc 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -68,7 +68,7 @@ impl PrivateV1Convo { // perhaps update the DH to work with cryptocrate. // init_sender doesn't take ownership of the key so a reference can be used. let shared_secret: [u8; 32] = seed_key.DANGER_to_bytes(); - let dr_state = RatchetState::init_sender(shared_secret, remote); + let dr_state = RatchetState::init_sender(shared_secret, *remote); Self { local_convo_id, @@ -135,7 +135,7 @@ impl PrivateV1Convo { // Build the Header that DR impl expects let header = Header { - dh_pub, + dh_pub: *dh_pub, msg_num: dr_header.msg_num, prev_chain_len: dr_header.prev_chain_len, }; @@ -232,13 +232,13 @@ mod tests { let pub_raya = PublicKey::from(&raya); - let seed_key = saro.diffie_hellman(&pub_raya); + let seed_key = saro.diffie_hellman(&pub_raya).DANGER_to_bytes(); + let seed_key_saro = SymmetricKey32::from(seed_key.clone()); + let seed_key_raya = SymmetricKey32::from(seed_key.clone()); let send_content_bytes = vec![0, 2, 4, 6, 8]; - let mut sr_convo = PrivateV1Convo::new_initiator(SymmetricKey32::from(&seed_key), pub_raya); - - let installation_key_pair = InstallationKeyPair::from(raya); + let mut sr_convo = PrivateV1Convo::new_initiator(seed_key_saro, pub_raya); let mut rs_convo = - PrivateV1Convo::new_responder(SymmetricKey32::from(&seed_key), installation_key_pair); + PrivateV1Convo::new_responder(SymmetricKey32::from(seed_key_raya), &raya); let send_frame = PrivateV1Frame { conversation_id: "_".into(), diff --git a/crypto/src/keys.rs b/crypto/src/keys.rs index 0634b72..24a7440 100644 --- a/crypto/src/keys.rs +++ b/crypto/src/keys.rs @@ -64,6 +64,7 @@ impl PrivateKey { (&self.0.diffie_hellman(&public_key.0)).into() } + #[allow(non_snake_case)] // All caps makes this standout more in reviews. pub fn DANGER_to_bytes(&self) -> [u8; 32] { self.0.to_bytes() } diff --git a/crypto/src/x3dh.rs b/crypto/src/x3dh.rs index d5e5bff..b5a9a73 100644 --- a/crypto/src/x3dh.rs +++ b/crypto/src/x3dh.rs @@ -3,7 +3,6 @@ use std::marker::PhantomData; use hkdf::Hkdf; use rand_core::{CryptoRng, RngCore}; use sha2::Sha256; -use x25519_dalek::SharedSecret; use crate::keys::{PrivateKey, PublicKey, SymmetricKey32}; use crate::xeddsa_sign::Ed25519Signature; @@ -32,10 +31,10 @@ impl X3Handshake { /// Derive the shared secret from DH outputs using HKDF-SHA256 fn derive_shared_secret( - dh1: &SharedSecret, - dh2: &SharedSecret, - dh3: &SharedSecret, - dh4: Option<&SharedSecret>, + dh1: &SymmetricKey32, + dh2: &SymmetricKey32, + dh3: &SymmetricKey32, + dh4: Option<&SymmetricKey32>, ) -> SymmetricKey32 { // Concatenate all DH outputs let mut km = Vec::new(); From 8f4647cfd000afd9db4143ea8f0b59dbfb6345c3 Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Sun, 15 Feb 2026 18:04:27 -0800 Subject: [PATCH 11/11] lint fixes --- conversations/src/conversation/privatev1.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conversations/src/conversation/privatev1.rs b/conversations/src/conversation/privatev1.rs index c2966cc..ccb809f 100644 --- a/conversations/src/conversation/privatev1.rs +++ b/conversations/src/conversation/privatev1.rs @@ -233,8 +233,8 @@ mod tests { let pub_raya = PublicKey::from(&raya); let seed_key = saro.diffie_hellman(&pub_raya).DANGER_to_bytes(); - let seed_key_saro = SymmetricKey32::from(seed_key.clone()); - let seed_key_raya = SymmetricKey32::from(seed_key.clone()); + let seed_key_saro = SymmetricKey32::from(seed_key); + let seed_key_raya = SymmetricKey32::from(seed_key); let send_content_bytes = vec![0, 2, 4, 6, 8]; let mut sr_convo = PrivateV1Convo::new_initiator(seed_key_saro, pub_raya); let mut rs_convo =