From d7011c8417c1c05cebb0d7c3ac045c86a5ee26ba Mon Sep 17 00:00:00 2001 From: DyrellC Date: Mon, 25 Apr 2022 17:47:31 -0600 Subject: [PATCH 01/12] Move psk_store, remove Identifier::Psk --- examples/src/branching/did_author.rs | 3 +- examples/src/branching/multi_branch.rs | 8 +- .../src/api/key_store.rs | 46 +---- .../src/api/tangle/user.rs | 13 +- .../src/api/tangle/user_builder.rs | 94 +++++----- iota-streams-app-channels/src/api/user.rs | 175 +++++++++--------- .../src/message/keyload.rs | 85 ++++++--- iota-streams-app/src/id/identifier.rs | 46 +---- iota-streams-app/src/id/user_identity.rs | 78 ++------ 9 files changed, 241 insertions(+), 307 deletions(-) diff --git a/examples/src/branching/did_author.rs b/examples/src/branching/did_author.rs index 397e9f94..69a4bb84 100644 --- a/examples/src/branching/did_author.rs +++ b/examples/src/branching/did_author.rs @@ -110,8 +110,9 @@ pub async fn example(transport: Client) -> Result<()> { .with_transport(transport.clone()) .build()?; let mut subscriberC = UserBuilder::new() - .with_identity(UserIdentity::new_from_psk(pskid, psk)) + .with_identity(UserIdentity::new("SUBSCRIBERC9SEED")) .with_transport(transport.clone()) + .with_psk(pskid, psk) .build()?; let subA_xkey = subscriberA.key_exchange_public_key()?; diff --git a/examples/src/branching/multi_branch.rs b/examples/src/branching/multi_branch.rs index 6f8b3a74..5c3ec6b6 100644 --- a/examples/src/branching/multi_branch.rs +++ b/examples/src/branching/multi_branch.rs @@ -41,8 +41,9 @@ pub async fn example(transport: T, seed: &str) -> Result<()> { .with_transport(transport.clone()) .build()?; let mut subscriberC = UserBuilder::new() - .with_identity(UserIdentity::new_from_psk(pskid, psk)) + .with_identity(UserIdentity::new("SUBSCRIBERC9SEED")) .with_transport(transport.clone()) + .with_psk(pskid, psk) .build()?; let public_payload = Bytes("PUBLICPAYLOAD".as_bytes().to_vec()); @@ -327,7 +328,8 @@ pub async fn example(transport: T, seed: &str) -> Result<()> { println!("\nSubscriber C fetching transactions..."); utils::fetch_next_messages(&mut subscriberC).await?; - println!("\nAttempt Tagged packet 4 - SubscriberC"); + // TODO: reintegrate this part of the example once Idenityless Users are reintroduced + /*println!("\nAttempt Tagged packet 4 - SubscriberC"); let tp = subscriberC .send_tagged_packet(&tagged_packet_link, &public_payload, &masked_payload) .await; @@ -336,7 +338,7 @@ pub async fn example(transport: T, seed: &str) -> Result<()> { "Subscriber C is a PSK user and should not be able to send messages" ); println!("SubscriberC was not able to send tagged packet, as expected"); - + */ println!("\nAuthor fetching transactions..."); utils::fetch_next_messages(&mut author).await?; diff --git a/iota-streams-app-channels/src/api/key_store.rs b/iota-streams-app-channels/src/api/key_store.rs index db0f881b..d8cb7bad 100644 --- a/iota-streams-app-channels/src/api/key_store.rs +++ b/iota-streams-app-channels/src/api/key_store.rs @@ -10,16 +10,10 @@ use iota_streams_app::{ message::Cursor, }; use iota_streams_core::{ - err, prelude::{ HashMap, Vec, }, - psk::{ - Psk, - PskId, - }, - Errors::BadIdentifier, Result, }; @@ -28,7 +22,6 @@ pub struct KeyStore { /// a precalculated corresponding x25519 pk and some additional Cursor. cursors: HashMap>, keys: HashMap, - psks: HashMap, } impl KeyStore { @@ -36,7 +29,6 @@ impl KeyStore { Self { cursors: HashMap::new(), keys: HashMap::new(), - psks: HashMap::new(), } } } @@ -47,15 +39,10 @@ impl KeyStore { I: IntoIterator, { ids.into_iter() - .filter_map(|id| match &id { - Identifier::PskId(pskid) => self - .psks - .get_key_value(pskid) - .map(|(pskid, psk)| ((*pskid).into(), psk.to_vec())), - _ => self - .keys + .filter_map(|id| { + self.keys .get_key_value(id) - .map(|(id, pk)| (*id, pk.as_slice().to_vec())), + .map(|(id, pk)| (*id, pk.as_slice().to_vec())) }) .collect() } @@ -85,24 +72,6 @@ impl KeyStore { } } - pub fn contains_psk(&self, pskid: &PskId) -> bool { - self.psks.contains_key(pskid) - } - - pub fn get_psk(&self, pskid: &PskId) -> Option<&Psk> { - self.psks.get(pskid) - } - - pub fn insert_psk(&mut self, id: Identifier, psk: Psk) -> Result<()> { - match &id { - Identifier::PskId(pskid) => { - self.psks.insert(*pskid, psk); - Ok(()) - } - _ => err(BadIdentifier), - } - } - pub fn insert_keys(&mut self, id: Identifier, xkey: x25519::PublicKey) -> Result<()> { if !self.keys.contains_key(&id) { self.keys.insert(id, xkey); @@ -111,11 +80,7 @@ impl KeyStore { } pub fn exchange_keys(&self) -> Vec<(Identifier, Vec)> { - self.keys - .iter() - .map(|(id, pk)| (*id, pk.as_slice().to_vec())) - .chain(self.psks.iter().map(|(pskid, psk)| ((*pskid).into(), psk.to_vec()))) - .collect() + self.keys.iter().map(|(id, pk)| (*id, pk.as_slice().to_vec())).collect() } pub fn cursors(&self) -> impl Iterator)> { @@ -133,9 +98,6 @@ impl KeyStore { pub fn remove(&mut self, id: &Identifier) { self.cursors.borrow_mut().remove(id); self.keys.borrow_mut().remove(id); - if let Identifier::PskId(pskid) = id { - self.psks.borrow_mut().remove(pskid); - } } } diff --git a/iota-streams-app-channels/src/api/tangle/user.rs b/iota-streams-app-channels/src/api/tangle/user.rs index 163ef7f7..6ef367ca 100644 --- a/iota-streams-app-channels/src/api/tangle/user.rs +++ b/iota-streams-app-channels/src/api/tangle/user.rs @@ -142,7 +142,7 @@ impl User { /// /// # Arguments /// * `pskid` - An identifier representing a pre shared key - pub fn remove_psk(&mut self, pskid: PskId) -> Result<()> { + pub fn remove_psk(&mut self, pskid: PskId) { self.user.remove_psk(pskid) } @@ -273,11 +273,18 @@ impl User { /// # Arguments /// * `link_to` - Address of the message the keyload will be attached to /// * `keys` - Iterable of [`Identifier`] to be included in message - pub async fn send_keyload<'a, I>(&mut self, link_to: &Address, keys: I) -> Result<(Address, Option
)> + /// * `psks` - Iterable of [`PskId`] to be included in message + pub async fn send_keyload<'a, I, P>( + &mut self, + link_to: &Address, + keys: I, + pskids: P, + ) -> Result<(Address, Option
)> where I: IntoIterator, + P: IntoIterator, { - let msg = self.user.share_keyload(link_to, keys).await?; + let msg = self.user.share_keyload(link_to, keys, pskids).await?; self.send_message_sequenced(msg, link_to.rel(), MsgInfo::Keyload).await } diff --git a/iota-streams-app-channels/src/api/tangle/user_builder.rs b/iota-streams-app-channels/src/api/tangle/user_builder.rs index 43d3e404..65e2640b 100644 --- a/iota-streams-app-channels/src/api/tangle/user_builder.rs +++ b/iota-streams-app-channels/src/api/tangle/user_builder.rs @@ -11,25 +11,24 @@ use crate::api::{ use iota_streams_app::id::UserIdentity; use iota_streams_core::{ anyhow, + prelude::Vec, + psk::{ + Psk, + PskId, + }, Errors::UserIdentityMissing, Result, }; +#[derive(Default)] /// Builder instance for a Streams User pub struct UserBuilder { /// Base Identity that will be used to Identifier a Streams User pub id: Option>, /// Transport Client instance pub transport: Option, -} - -impl Default for UserBuilder { - fn default() -> Self { - UserBuilder { - id: None, - transport: None, - } - } + /// Pre Shared Keys + pub psks: Vec<(PskId, Psk)>, } impl UserBuilder { @@ -56,6 +55,46 @@ impl UserBuilder { self } + /// Inject a new Pre Shared Key and Id into the User Builder + /// + /// # Examples + /// ## Add Multiple Psks + /// ``` + /// use iota_streams_app_channels::{ + /// api::{ + /// psk_from_seed, + /// pskid_from_psk, + /// }, + /// UserBuilder, + /// }; + /// # use iota_streams_core::Result; + /// # use iota_streams_app_channels::api::BucketTransport; + /// + /// # #[tokio::main] + /// # async fn main() -> Result<()> { + /// # let transport = BucketTransport::new(); + /// let psk1 = psk_from_seed("Psk1".as_bytes()); + /// let psk2 = psk_from_seed("Psk2".as_bytes()); + /// let pskid1 = pskid_from_psk(&psk1); + /// let pskid2 = pskid_from_psk(&psk2); + /// + /// let user = UserBuilder::new() + /// # .with_transport(transport) + /// .with_psk(pskid1, psk1) + /// .with_psk(pskid2, psk2) + /// .build(); + /// # Ok(()) + /// # } + /// ``` + /// + /// # Arguments + /// * `pskid` - Pre Shared Key Identifier + /// * `psk` - Pre Shared Key shared outside of Streams scope + pub fn with_psk(mut self, pskid: PskId, psk: Psk) -> Self { + self.psks.push((pskid, psk)); + self + } + /// Build a [`User`] instance using the Builder parameters. /// /// If a [`Transport`] is not provided the builder will use a default client @@ -95,44 +134,9 @@ impl UserBuilder { /// # Ok(()) /// # } /// ``` - /// - /// ## User from PskId - /// ``` - /// use iota_streams_app_channels::{ - /// api::{ - /// psk_from_seed, - /// pskid_from_psk, - /// }, - /// Tangle, - /// UserBuilder, - /// UserIdentity, - /// }; - /// # use std::cell::RefCell; - /// # use iota_streams_core::{prelude::Rc, Result}; - /// # use iota_streams_app_channels::api::BucketTransport; - /// # - /// # #[tokio::main] - /// # async fn main() -> Result<()> { - /// let transport = Tangle::new_from_url("https://chrysalis-nodes.iota.org"); - /// # - /// # let transport = Rc::new(RefCell::new(BucketTransport::new())); - /// # - /// let psk_seed = "seed-for-pre-shared-key"; - /// let psk = psk_from_seed(psk_seed.as_bytes()); - /// let pskid = pskid_from_psk(&psk); - /// - /// let user_identity = UserIdentity::new_from_psk(pskid, psk); - /// let mut user = UserBuilder::new() - /// .with_identity(user_identity) - /// .with_transport(transport) - /// .build()?; - /// - /// # Ok(()) - /// # } - /// ``` pub fn build(self) -> Result> { let id = self.id.ok_or_else(|| anyhow!(UserIdentityMissing))?; - let user = crate::api::ApiUser::new(id); + let user = crate::api::ApiUser::new(id, &self.psks); let transport = self.transport.unwrap_or(Trans::default()); Ok(User { user, transport }) } diff --git a/iota-streams-app-channels/src/api/user.rs b/iota-streams-app-channels/src/api/user.rs index aaa80a44..39fedc35 100644 --- a/iota-streams-app-channels/src/api/user.rs +++ b/iota-streams-app-channels/src/api/user.rs @@ -26,13 +26,15 @@ use iota_streams_core::{ string::ToString, typenum::U32, Box, + HashMap, Vec, }, prng, psk::{ - self, Psk, PskId, + PskIdSize, + PskSize, }, sponge::prp::{ Inner, @@ -94,6 +96,9 @@ where /// Users' trusted public keys together with additional sequencing info: (msgid, seq_no). pub(crate) key_store: KeyStore, + /// Mapping of trusted pre shared keys and identifiers + pub(crate) psk_store: HashMap, + /// Author's public Id. pub(crate) author_id: Option, @@ -127,6 +132,7 @@ where _phantom: PhantomData, user_id: UserIdentity::default(), key_store: KeyStore::default(), + psk_store: HashMap::new(), author_id: None, author_ke_pk: x25519::PublicKey::from_bytes([0; x25519::PUBLIC_KEY_LENGTH]), link_gen: LG::default(), @@ -148,21 +154,21 @@ where LS: LinkStore + Default, { /// Create a new User, storing [`UserIdentity`]. - pub fn new(user_id: UserIdentity) -> Self { + pub fn new(user_id: UserIdentity, psks: &[(PskId, Psk)]) -> Self { // TODO: Remove different channel types, encoding and uniform payload let message_encoding = ENCODING.as_bytes().to_vec(); - let mut key_store = KeyStore::default(); - // If User is using a Psk as their base Identifier, store the Psk - if let Identifier::PskId(pskid) = &user_id.id { - // Unwraps shouldn't fail here due to the user containing a PskId type - key_store.insert_psk((*pskid).into(), user_id.psk().unwrap()).unwrap(); - } + let mut psk_store = HashMap::new(); + // Store any provided Psks + psks.iter().for_each(|(pskid, psk)| { + psk_store.insert(*pskid, *psk); + }); Self { _phantom: PhantomData, user_id, - key_store, + key_store: KeyStore::default(), + psk_store, author_id: None, author_ke_pk: x25519::PublicKey::from_bytes([0; x25519::PUBLIC_KEY_LENGTH]), link_gen: LG::default(), @@ -183,14 +189,9 @@ where self.link_gen.gen(&self.id().clone(), channel_idx); let appinst = self.link_gen.get(); - match self.id() { - Identifier::PskId(_pskid) => err(UnsupportedIdentifier)?, - _ => { - self.key_store - .insert_cursor(*self.id(), Cursor::new_at(appinst.rel().clone(), 0, INIT_MESSAGE_NUM)); - self.key_store.insert_keys(*self.id(), self.user_id.ke_kp()?.1)?; - } - } + self.key_store + .insert_cursor(*self.id(), Cursor::new_at(appinst.rel().clone(), 0, INIT_MESSAGE_NUM)); + self.key_store.insert_keys(*self.id(), self.user_id.ke_kp()?.1)?; self.author_id = Some(*self.id()); self.appinst = Some(appinst); Ok(()) @@ -297,18 +298,11 @@ where // At the moment the Author is free to choose any address, not tied to PK. let cursor = Cursor::new_at(link.rel().clone(), 0, INIT_MESSAGE_NUM); - match &author_id.id { - Identifier::PskId(_pskid) => err(UnsupportedIdentifier)?, - _ => { - self.key_store.insert_cursor(author_id.id, cursor.clone()); - self.key_store.insert_keys(author_id.id, author_ke_pk)?; - } - }; + self.key_store.insert_cursor(author_id.id, cursor.clone()); + self.key_store.insert_keys(author_id.id, author_ke_pk)?; - if !self.id().is_psk() { - self.key_store.insert_cursor(*self.id(), cursor); - self.key_store.insert_keys(*self.id(), self.user_id.ke_kp()?.1)?; - }; + self.key_store.insert_cursor(*self.id(), cursor); + self.key_store.insert_keys(*self.id(), self.user_id.ke_kp()?.1)?; // Reset link_gen self.link_gen.reset(link.clone()); @@ -453,6 +447,7 @@ where header: HDF, link_to: &'a Link::Rel, keys: Vec<(Identifier, Vec)>, + psks: Vec<(PskId, Psk)>, ) -> Result>> { let nonce = NBytes::from(prng::random_nonce()); let key = NBytes::from(prng::random_key()); @@ -461,19 +456,22 @@ where nonce, key, keys, + psks, user_id: &self.user_id, _phantom: PhantomData, }; Ok(PreparedMessage::new(header, content)) } - pub fn prepare_keyload<'a, 'b, I>( + pub fn prepare_keyload<'a, 'b, I, P>( &'a self, link_to: &'a Link, keys: I, + pskids: P, ) -> Result>> where I: IntoIterator, + P: IntoIterator, { match self.seq_no() { Some(seq_no) => { @@ -484,13 +482,23 @@ where .with_payload_length(1)? .with_seq_num(msg_cursor.seq_no) .with_identifier(self.id()); + let psks = self.filter_psks(pskids); let filtered_keys = self.key_store.filter(keys); - self.do_prepare_keyload(header, link_to.rel(), filtered_keys) + self.do_prepare_keyload(header, link_to.rel(), filtered_keys, psks) } None => err!(SeqNumRetrievalFailure), } } + fn filter_psks<'a, P>(&self, ids: P) -> Vec<(PskId, Psk)> + where + P: IntoIterator, + { + ids.into_iter() + .filter_map(|id| self.psk_store.get(id).map(|psk| (*id, *psk))) + .collect() + } + pub fn prepare_keyload_for_everyone<'a>( &'a self, link_to: &'a Link, @@ -505,7 +513,8 @@ where .with_seq_num(msg_cursor.seq_no) .with_identifier(self.id()); let keys = self.key_store.exchange_keys(); - self.do_prepare_keyload(header, link_to.rel(), keys) + let psks = self.psk_store.iter().map(|(pskid, psk)| (*pskid, *psk)).collect(); + self.do_prepare_keyload(header, link_to.rel(), keys, psks) } None => err!(SeqNumRetrievalFailure), } @@ -513,11 +522,19 @@ where /// Create keyload message with a new session key shared with recipients /// identified by pre-shared key IDs and by Ed25519 public keys. - pub async fn share_keyload<'a, I>(&mut self, link_to: &Link, keys: I) -> Result> + pub async fn share_keyload<'a, I, P>( + &mut self, + link_to: &Link, + keys: I, + pskids: P, + ) -> Result> where I: IntoIterator, + P: IntoIterator, { - self.prepare_keyload(link_to, keys)?.wrap(&self.link_store).await + self.prepare_keyload(link_to, keys, pskids)? + .wrap(&self.link_store) + .await } /// Create keyload message with a new session key shared with all Subscribers @@ -529,11 +546,10 @@ where pub async fn unwrap_keyload<'a>( &self, preparsed: PreparsedMessage<'_, F, Link>, - keys_lookup: KeysLookup<'a, F, Link>, + keys_lookup: &'a HashMap, own_keys: OwnKeys<'a, F>, author_id: UserIdentity, - ) -> Result, OwnKeys<'a, F>>>> - { + ) -> Result>>> { self.ensure_appinst(&preparsed)?; let content = keyload::ContentUnwrap::new(keys_lookup, own_keys, author_id); preparsed.unwrap(&self.link_store, content).await @@ -551,14 +567,13 @@ where let prev_link = Link::try_from_bytes(&preparsed.header.previous_msg_link.0)?; // We need to borrow self.key_store, self.sig_kp and self.ke_kp at this scope // to leverage https://doc.rust-lang.org/nomicon/borrow-splitting.html - let keys_lookup = KeysLookup::new(&self.key_store); let own_keys = OwnKeys(&self.user_id); let mut author_identity = UserIdentity::default(); author_identity.id = *author_id; let unwrapped = self - .unwrap_keyload(preparsed, keys_lookup, own_keys, author_identity) + .unwrap_keyload(preparsed, &self.psk_store, own_keys, author_identity) .await?; // Process a generic message containing the access right bool, also return the list of identifiers @@ -581,7 +596,7 @@ where // Store any unknown publishers if let Some(appinst) = &self.appinst { for identifier in keys { - if !identifier.is_psk() && !self.key_store.contains_subscriber(&identifier) { + if !self.key_store.contains_subscriber(&identifier) { // Store at state 2 since 0 and 1 are reserved states self.key_store .insert_cursor(identifier, Cursor::new_at(appinst.rel().clone(), 0, INIT_MESSAGE_NUM)); @@ -602,9 +617,6 @@ where public_payload: &'a Bytes, masked_payload: &'a Bytes, ) -> Result>> { - if self.id().is_psk() { - return err(MessageBuildFailure); - } match self.seq_no() { Some(seq_no) => { let msg_cursor = self.gen_link(self.id(), link_to.rel(), seq_no); @@ -830,30 +842,18 @@ where pub fn store_psk(&mut self, pskid: PskId, psk: Psk) -> Result<()> { match &self.appinst { Some(_) => { - if self.key_store.contains_psk(&pskid) { + if self.psk_store.contains_key(&pskid) { return err(PskAlreadyStored); } - self.key_store.insert_psk(pskid.into(), psk)?; + self.psk_store.insert(pskid, psk); Ok(()) } - None => { - if let Identifier::PskId(_) = self.id() { - self.key_store.insert_psk(pskid.into(), psk) - } else { - err(UserNotRegistered) - } - } + None => err(UserNotRegistered), } } - pub fn remove_psk(&mut self, pskid: PskId) -> Result<()> { - match self.key_store.contains_psk(&pskid) { - true => { - self.key_store.remove(&pskid.into()); - Ok(()) - } - false => err(UserNotRegistered), - } + pub fn remove_psk(&mut self, pskid: PskId) { + self.psk_store.remove(&pskid); } /// Generate the link of a message @@ -960,6 +960,7 @@ where let repeated_links = Size(self.link_store.len()); let keys = self.key_store.cursors(); let repeated_keys = Size(self.key_store.cursors_size()); + let repeated_psks = Size(self.psk_store.len()); ctx.absorb(repeated_links)?; for (link, (s, info)) in self.link_store.iter() { @@ -977,6 +978,13 @@ where .absorb(Uint32(cursor.branch_no))? .absorb(Uint32(cursor.seq_no))?; } + + ctx.absorb(repeated_psks)?; + for (pskid, psk) in self.psk_store.iter() { + ctx.absorb(&NBytes::::from(*pskid))? + .mask(&NBytes::::from(*psk))?; + } + ctx.commit()?.squeeze(Mac(32))?; Ok(ctx) } @@ -1018,6 +1026,7 @@ where let repeated_links = Size(self.link_store.len()); let keys = self.key_store.cursors(); let repeated_keys = Size(self.key_store.cursors_size()); + let repeated_psks = Size(self.psk_store.len()); ctx.absorb(repeated_links)?; for (link, (s, info)) in self.link_store.iter() { @@ -1035,6 +1044,13 @@ where .absorb(Uint32(cursor.branch_no))? .absorb(Uint32(cursor.seq_no))?; } + + ctx.absorb(repeated_psks)?; + for (pskid, psk) in self.psk_store.iter() { + ctx.absorb(&NBytes::::from(*pskid))? + .mask(&NBytes::::from(*psk))?; + } + ctx.commit()?.squeeze(Mac(32))?; Ok(ctx) } @@ -1112,6 +1128,16 @@ where key_store.insert_cursor(id, Cursor::new_at(link.0, branch_no.0, seq_no.0)); } + let mut repeated_psks = Size(0); + let mut psk_store = HashMap::new(); + ctx.absorb(&mut repeated_psks)?; + for _ in 0..repeated_psks.0 { + let mut pskid = NBytes::::default(); + let mut psk = NBytes::::default(); + ctx.absorb(&mut pskid)?.mask(&mut psk)?; + psk_store.insert(pskid.0, psk.0); + } + ctx.commit()?.squeeze(Mac(32))?; let sig_sk = ed25519::SecretKey::from_bytes(<[u8; 32]>::try_from(sig_sk_bytes.as_ref())?); @@ -1120,6 +1146,7 @@ where self.user_id = UserIdentity::from((sig_sk, sig_pk)); self.link_store = link_store; self.key_store = key_store; + self.psk_store = psk_store; self.author_id = author_id; if let Some(ref seed) = appinst { self.link_gen.reset(seed.clone()); @@ -1194,36 +1221,6 @@ where } } -// Newtype wrapper around KeyStore reference to be able to implement Lookup on it -// Direct implementation is not possible due to KeyStore trait having type parameters itself -pub struct KeysLookup<'a, F, Link>(&'a KeyStore, PhantomData, PhantomData) -where - F: PRP, - Link: HasLink; -impl<'a, F, Link> KeysLookup<'a, F, Link> -where - F: PRP, - Link: HasLink, -{ - fn new(key_store: &'a KeyStore) -> Self { - Self(key_store, PhantomData, PhantomData) - } -} - -impl Lookup<&Identifier, psk::Psk> for KeysLookup<'_, F, Link> -where - F: PRP, - Link: HasLink, -{ - fn lookup(&self, id: &Identifier) -> Option { - if let Identifier::PskId(pskid) = id { - self.0.get_psk(pskid).copied() - } else { - None - } - } -} - pub struct OwnKeys<'a, F>(&'a UserIdentity); impl<'a, F: PRP> Lookup<&Identifier, x25519::SecretKey> for OwnKeys<'a, F> { diff --git a/iota-streams-app-channels/src/message/keyload.rs b/iota-streams-app-channels/src/message/keyload.rs index cbbeea1e..f01cf11b 100644 --- a/iota-streams-app-channels/src/message/keyload.rs +++ b/iota-streams-app-channels/src/message/keyload.rs @@ -71,9 +71,15 @@ use iota_streams_core::{ prelude::{ typenum::Unsigned as _, Box, + HashMap, Vec, }, psk, + psk::{ + Psk, + PskId, + PskSize, + }, sponge::{ prp::PRP, spongos, @@ -100,6 +106,7 @@ where pub nonce: NBytes, pub key: NBytes, pub(crate) keys: Vec<(Identifier, Vec)>, + pub(crate) psks: Vec<(PskId, Psk)>, pub(crate) user_id: &'a UserIdentity, pub(crate) _phantom: core::marker::PhantomData<(F, Link)>, } @@ -114,19 +121,29 @@ where async fn sizeof<'c>(&self, ctx: &'c mut sizeof::Context) -> Result<&'c mut sizeof::Context> { let store = EmptyLinkStore::::Rel, ()>::default(); let repeated_keys = Size(self.keys.len()); + let repeated_psks = Size(self.psks.len()); ctx.join(&store, self.link)?.absorb(&self.nonce)?; // fork into new context in order to hash Identifiers { ctx.absorb(repeated_keys)?; // Loop through provided identifiers, masking the shared key for each one - for key_pair in self.keys.clone().into_iter() { - let (id, exchange_key) = key_pair; + for (id, exchange_key) in self.keys.clone().into_iter() { let receiver_id = UserIdentity::from(id); let ctx = receiver_id.id.sizeof(ctx).await?; // fork in order to skip the actual keyload data which may be unavailable to all recipients receiver_id.encrypt_sizeof(ctx, &exchange_key, &self.key).await?; } + + ctx.absorb(repeated_psks)?; + // Loop through PSK's, masking the shared key for each one + for (pskid, psk) in self.psks.clone().into_iter() { + ctx.mask(<&NBytes>::from(&pskid))?; + + ctx.absorb(External(<&NBytes>::from(&psk)))? + .commit()? + .mask(&self.key)?; + } } ctx.absorb(External(&self.key))?; @@ -152,6 +169,7 @@ where ) -> Result<&'c mut wrap::Context> { let mut id_hash = External(NBytes::::default()); let repeated_keys = Size(self.keys.len()); + let repeated_psks = Size(self.psks.len()); ctx.join(store, self.link)?.absorb(&self.nonce)?; // fork into new context in order to hash Identifiers @@ -159,8 +177,7 @@ where { ctx.absorb(repeated_keys)?; // Loop through provided identifiers, masking the shared key for each one - for key_pair in self.keys.clone().into_iter() { - let (id, exchange_key) = key_pair; + for (id, exchange_key) in self.keys.clone().into_iter() { let receiver_id = UserIdentity::from(id); let ctx = receiver_id.id.wrap(store, ctx).await?; @@ -169,6 +186,19 @@ where receiver_id.encrypt(ctx, &exchange_key, &self.key).await?; ctx.spongos = inner_fork; } + + ctx.absorb(repeated_psks)?; + // Loop through PSK's, masking the shared key for each one + for (pskid, psk) in self.psks.clone().into_iter() { + ctx.mask(<&NBytes>::from(&pskid))?; + + let inner_fork = ctx.spongos.fork(); + ctx.absorb(External(<&NBytes>::from(&psk)))? + .commit()? + .mask(&self.key)?; + ctx.spongos = inner_fork; + } + ctx.commit()?.squeeze(&mut id_hash)?; } ctx.spongos = saved_fork; @@ -183,13 +213,13 @@ where } } -pub struct ContentUnwrap +pub struct ContentUnwrap<'a, F, Link, KeSkStore> where Link: HasLink, { pub link: ::Rel, pub nonce: NBytes, // TODO: unify with spongos::Spongos::::NONCE_SIZE) - pub(crate) psk_store: PskStore, + pub(crate) psk_store: &'a HashMap, pub(crate) ke_sk_store: KeSkStore, pub(crate) key_ids: Vec, pub key: Option>, // TODO: unify with spongos::Spongos::::KEY_SIZE @@ -197,13 +227,13 @@ where _phantom: core::marker::PhantomData<(F, Link)>, } -impl<'a, 'b, F, Link, PskStore, KeSkStore> ContentUnwrap +impl<'a, 'b, F, Link, KeSkStore> ContentUnwrap<'a, F, Link, KeSkStore> where F: PRP, Link: HasLink, Link::Rel: Eq + Default + SkipFallback, { - pub fn new(psk_store: PskStore, ke_sk_store: KeSkStore, author_id: UserIdentity) -> Self { + pub fn new(psk_store: &'a HashMap, ke_sk_store: KeSkStore, author_id: UserIdentity) -> Self { Self { link: Default::default(), nonce: NBytes::default(), @@ -218,14 +248,12 @@ where } #[async_trait(?Send)] -impl<'a, 'b, F, Link, LStore, PskStore, KeSkStore> message::ContentUnwrap - for ContentUnwrap +impl<'a, 'b, F, Link, LStore, KeSkStore> message::ContentUnwrap for ContentUnwrap<'a, F, Link, KeSkStore> where F: PRP + Clone, Link: HasLink, Link::Rel: Eq + Default + SkipFallback, LStore: LinkStore, - PskStore: for<'c> Lookup<&'c Identifier, psk::Psk>, KeSkStore: for<'c> Lookup<&'c Identifier, x25519::SecretKey> + 'b, { async fn unwrap<'c, IS: io::IStream>( @@ -238,6 +266,8 @@ where { let mut id_hash = External(NBytes::::default()); let mut repeated_keys = Size(0); + let mut repeated_psks = Size(0); + ctx.join(store, &mut self.link)?.absorb(&mut self.nonce)?; // Fork to recover identifiers @@ -254,16 +284,6 @@ where let sender_id = UserIdentity::from(id); let mut key = NBytes::::default(); match &sender_id.id { - Identifier::PskId(_id) => { - if let Some(psk) = self.psk_store.lookup(&sender_id.id) { - sender_id.decrypt(ctx, &psk, &mut key).await?; - self.key = Some(key); - } else { - // Just drop the rest of the forked message so not to waste Spongos operations - let n = Size(spongos::KeySize::::USIZE); - ctx.drop(n)?; - } - } _ => { if let Some(ke_sk) = self.ke_sk_store.lookup(&id) { sender_id.decrypt(ctx, &ke_sk.to_bytes(), &mut key).await?; @@ -281,6 +301,29 @@ where ctx.spongos = internal_fork; } } + + ctx.absorb(&mut repeated_psks)?; + for _ in 0..repeated_psks.0 { + let mut pskid = NBytes::::default(); + ctx.mask(&mut pskid)?; + { + let internal_fork = ctx.spongos.fork(); + let mut key = NBytes::::default(); + if let Some(psk) = self.psk_store.get(&pskid.0) { + ctx.absorb(External(<&NBytes>::from(psk)))? + .commit()? + .mask(&mut key)?; + self.key = Some(key); + } else { + // Just drop the rest of the forked message so not to waste Spongos operations + let n = Size(spongos::KeySize::::USIZE); + ctx.drop(n)?; + } + + ctx.spongos = internal_fork; + } + } + ctx.commit()?.squeeze(&mut id_hash)?; ctx.spongos = saved_fork; } diff --git a/iota-streams-app/src/id/identifier.rs b/iota-streams-app/src/id/identifier.rs index a83e55f6..0293e03d 100644 --- a/iota-streams-app/src/id/identifier.rs +++ b/iota-streams-app/src/id/identifier.rs @@ -7,10 +7,6 @@ use iota_streams_core::{ Box, Vec, }, - psk::{ - self, - PskId, - }, sponge::prp::PRP, Errors::BadOneof, Result, @@ -45,7 +41,6 @@ use crate::message::*; #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] pub enum Identifier { EdPubKey(ed25519::PublicKey), - PskId(PskId), #[cfg(feature = "did")] DID(DIDWrap), } @@ -60,27 +55,22 @@ impl Identifier { pub fn as_bytes(&self) -> &[u8] { match self { Identifier::EdPubKey(public_key) => public_key.as_slice(), - Identifier::PskId(id) => id, #[cfg(feature = "did")] Identifier::DID(did) => did, } } pub fn pk(&self) -> Option<&ed25519::PublicKey> { - if let Identifier::EdPubKey(pk) = self { - Some(pk) - } else { - None + match self { + Identifier::EdPubKey(pk) => Some(pk), + #[cfg(feature = "did")] + _ => None, } } pub fn is_pub_key(&self) -> bool { matches!(self, Self::EdPubKey(_)) } - - pub fn is_psk(&self) -> bool { - matches!(self, Self::PskId(_)) - } } impl Default for Identifier { @@ -96,12 +86,6 @@ impl From for Identifier { } } -impl From for Identifier { - fn from(pskid: PskId) -> Self { - Identifier::PskId(pskid) - } -} - #[cfg(feature = "did")] impl From<&IotaDID> for Identifier { fn from(did: &IotaDID) -> Self { @@ -138,14 +122,9 @@ impl ContentSizeof for Identifier { ctx.mask(oneof)?.mask(pk)?; Ok(ctx) } - Identifier::PskId(pskid) => { - let oneof = Uint8(1); - ctx.mask(oneof)?.mask(<&NBytes>::from(pskid))?; - Ok(ctx) - } #[cfg(feature = "did")] Identifier::DID(did) => { - let oneof = Uint8(2); + let oneof = Uint8(1); ctx.mask(oneof)?.mask(<&NBytes>::from(did))?; Ok(ctx) } @@ -166,14 +145,9 @@ impl ContentWrap for Identifier { ctx.mask(oneof)?.mask(pk)?; Ok(ctx) } - Identifier::PskId(pskid) => { - let oneof = Uint8(1); - ctx.mask(oneof)?.mask(<&NBytes>::from(pskid))?; - Ok(ctx) - } #[cfg(feature = "did")] Identifier::DID(did) => { - let oneof = Uint8(2); + let oneof = Uint8(1); ctx.mask(oneof)?.mask(<&NBytes>::from(did))?; Ok(ctx) } @@ -209,14 +183,8 @@ impl ContentUnwrapNew for Identifier { let id = Identifier::EdPubKey(pk); Ok((id, ctx)) } - 1 => { - let mut pskid = PskId::default(); - ctx.mask(<&mut NBytes>::from(&mut pskid))?; - let id = Identifier::PskId(pskid); - Ok((id, ctx)) - } #[cfg(feature = "did")] - 2 => { + 1 => { let mut did_bytes = NBytes::::default(); ctx.mask(&mut did_bytes)?; let did_str = DID_CORE.to_string() + &encode_b58(&did_bytes.0); diff --git a/iota-streams-app/src/id/user_identity.rs b/iota-streams-app/src/id/user_identity.rs index 93ccc891..e7b182b2 100644 --- a/iota-streams-app/src/id/user_identity.rs +++ b/iota-streams-app/src/id/user_identity.rs @@ -15,18 +15,11 @@ use iota_streams_core::{ err, prelude::Box, prng, - psk::{ - Psk, - PskId, - PskSize, - }, sponge::prp::PRP, wrapped_err, Errors::{ BadIdentifier, BadOneof, - NoSignatureKeyPair, - NotAPskUser, }, Result, WrappedError, @@ -111,10 +104,7 @@ use iota_streams_core::{ #[cfg(feature = "did")] use iota_streams_ddml::types::Bytes; use iota_streams_ddml::{ - command::{ - Mask, - X25519, - }, + command::X25519, types::ArrayLength, }; @@ -126,7 +116,6 @@ pub struct KeyPairs { #[allow(clippy::large_enum_variant)] pub enum Keys { Keypair(KeyPairs), - Psk(Psk), #[cfg(feature = "did")] DID(DIDImpl), } @@ -182,16 +171,6 @@ impl UserIdentity { } } - pub fn new_from_psk(pskid: PskId, psk: Psk) -> UserIdentity { - UserIdentity { - id: pskid.into(), - keys: Keys::Psk(psk), - #[cfg(feature = "did")] - client: StreamsClient::default().to_did_client().unwrap(), - _phantom: Default::default(), - } - } - #[cfg(feature = "did")] pub fn new_with_did_private_key(did_info: DIDInfo) -> Result> { let did = did_info.did()?; @@ -217,7 +196,6 @@ impl UserIdentity { let public_key = secret_key.public_key(); Ok((secret_key, public_key)) } - Keys::Psk(_) => err(NoSignatureKeyPair), #[cfg(feature = "did")] Keys::DID(did) => match did { DIDImpl::PrivateKey(info) => Ok(info.ke_kp()), @@ -233,7 +211,6 @@ impl UserIdentity { let sk_bytes = keypairs.sig.0.to_bytes(); Ok(ed25519::SecretKey::from_bytes(sk_bytes)) } - Keys::Psk(_) => err(NoSignatureKeyPair), #[cfg(feature = "did")] Keys::DID(did) => match did { DIDImpl::PrivateKey(info) => { @@ -244,14 +221,6 @@ impl UserIdentity { } } - /// Retrieve the PSK from a user instance - pub fn psk(&self) -> Result { - match &self.keys { - Keys::Psk(psk) => Ok(*psk), - _ => err(NotAPskUser), - } - } - /// Sign the prehashed bytes of a message for ownership authentication /// /// # Arguments @@ -337,7 +306,6 @@ impl ContentSizeof for UserIdentity { ctx.ed25519(&keys.sig.0, HashSig)?; return Ok(ctx); } - Keys::Psk(_) => err(NoSignatureKeyPair), #[cfg(feature = "did")] Keys::DID(did_impl) => { match did_impl { @@ -367,7 +335,6 @@ impl ContentSign for UserIdentity { ctx.commit()?.squeeze(&mut hash)?.ed25519(&keys.sig.0, &hash)?; Ok(ctx) } - Keys::Psk(_) => err(NoSignatureKeyPair), #[cfg(feature = "did")] Keys::DID(did_impl) => { match did_impl { @@ -414,6 +381,7 @@ impl ContentVerify<'_, F, IS> for UserIdentity { ctx.commit()?.squeeze(&mut hash)?.ed25519(pub_key, &hash)?; Ok(ctx) } + #[cfg(feature = "did")] _ => err!(BadIdentifier), }, #[cfg(feature = "did")] @@ -468,16 +436,10 @@ impl ContentEncryptSizeOf for UserIdentity { exchange_key: &'c [u8], key: &'c NBytes, ) -> Result<&'c mut sizeof::Context> { - match &self.id { - Identifier::PskId(_) => ctx - .absorb(External(<&NBytes>::from(exchange_key)))? - .commit()? - .mask(key), - // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introdution) - _ => match <[u8; 32]>::try_from(exchange_key) { - Ok(slice) => ctx.x25519(&x25519::PublicKey::from(slice), key), - Err(e) => Err(wrapped_err(BadIdentifier, WrappedError(e))), - }, + // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introdution) + match <[u8; 32]>::try_from(exchange_key) { + Ok(slice) => ctx.x25519(&x25519::PublicKey::from(slice), key), + Err(e) => Err(wrapped_err(BadIdentifier, WrappedError(e))), } } } @@ -490,16 +452,10 @@ impl ContentEncrypt for UserIdentity { exchange_key: &'c [u8], key: &'c NBytes, ) -> Result<&'c mut wrap::Context> { - match &self.id { - Identifier::PskId(_) => ctx - .absorb(External(<&NBytes>::from(exchange_key)))? - .commit()? - .mask(key), - // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introdution) - _ => match <[u8; 32]>::try_from(exchange_key) { - Ok(slice) => ctx.x25519(&x25519::PublicKey::from(slice), key), - Err(e) => Err(wrapped_err(BadIdentifier, WrappedError(e))), - }, + // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introdution) + match <[u8; 32]>::try_from(exchange_key) { + Ok(slice) => ctx.x25519(&x25519::PublicKey::from(slice), key), + Err(e) => Err(wrapped_err(BadIdentifier, WrappedError(e))), } } } @@ -512,16 +468,10 @@ impl ContentDecrypt for UserIdentity { exchange_key: &'c [u8], key: &'c mut NBytes, ) -> Result<&'c mut unwrap::Context> { - match &self.id { - Identifier::PskId(_) => ctx - .absorb(External(<&NBytes>::from(exchange_key)))? - .commit()? - .mask(key), - // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introdution) - _ => match <[u8; 32]>::try_from(exchange_key) { - Ok(slice) => ctx.x25519(&x25519::SecretKey::from_bytes(slice), key), - Err(e) => Err(wrapped_err(BadIdentifier, WrappedError(e))), - }, + // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introdution) + match <[u8; 32]>::try_from(exchange_key) { + Ok(slice) => ctx.x25519(&x25519::SecretKey::from_bytes(slice), key), + Err(e) => Err(wrapped_err(BadIdentifier, WrappedError(e))), } } } From a573d434e1a1c94be4dc2c40c325bb1212cf46f4 Mon Sep 17 00:00:00 2001 From: DyrellC Date: Fri, 20 May 2022 11:33:25 -0600 Subject: [PATCH 02/12] fmt/clippy/test --- lets/src/id/identifier.rs | 6 +- lets/src/id/identity.rs | 3 +- lets/src/id/permission.rs | 22 ++++--- .../examples/full-example/scenarios/basic.rs | 2 +- .../examples/full-example/scenarios/did.rs | 6 +- streams/src/api/message.rs | 3 +- streams/src/api/user.rs | 19 +++--- streams/src/api/user_builder.rs | 58 +++++++------------ streams/src/message/announcement.rs | 14 +---- streams/src/message/keyload.rs | 4 +- streams/src/message/subscription.rs | 14 +---- 11 files changed, 53 insertions(+), 98 deletions(-) diff --git a/lets/src/id/identifier.rs b/lets/src/id/identifier.rs index f93f3994..cadeab60 100644 --- a/lets/src/id/identifier.rs +++ b/lets/src/id/identifier.rs @@ -255,7 +255,8 @@ where #[async_trait(?Send)] impl ContentEncryptSizeOf for sizeof::Context { async fn encrypt_sizeof(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> { - // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introdution) + // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey + // introdution) match <[u8; 32]>::try_from(exchange_key) { Ok(slice) => self.x25519(&x25519::PublicKey::from(slice), NBytes::new(key)), Err(e) => Err(anyhow!("Invalid x25519 key: {}", e)), @@ -270,7 +271,8 @@ where OS: io::OStream, { async fn encrypt(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> { - // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introdution) + // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey + // introdution) match <[u8; 32]>::try_from(exchange_key) { Ok(byte_array) => self.x25519(&x25519::PublicKey::from(byte_array), NBytes::new(key)), Err(e) => Err(anyhow!("Invalid x25519 key: {}", e)), diff --git a/lets/src/id/identity.rs b/lets/src/id/identity.rs index 92b95e20..cba82ebb 100644 --- a/lets/src/id/identity.rs +++ b/lets/src/id/identity.rs @@ -255,7 +255,8 @@ where IS: io::IStream, { async fn decrypt(&mut self, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self> { - // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey introduction) + // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey + // introduction) match <[u8; 32]>::try_from(exchange_key) { Ok(byte_array) => self.x25519(&x25519::SecretKey::from_bytes(byte_array), NBytes::new(key)), Err(e) => Err(anyhow!("Invalid x25519 key: {}", e)), diff --git a/lets/src/id/permission.rs b/lets/src/id/permission.rs index 4c711d39..c159e158 100644 --- a/lets/src/id/permission.rs +++ b/lets/src/id/permission.rs @@ -16,8 +16,7 @@ use spongos::{ }; // Local -use crate::id::identifier::Identifier; -use crate::id::PskId; +use crate::id::{identifier::Identifier, PskId}; #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] pub enum PermissionDuration { @@ -209,7 +208,6 @@ where } } - impl Mask<&Permissioned> for sizeof::Context { fn mask(&mut self, permission: &Permissioned) -> Result<&mut Self> { match permission { @@ -218,15 +216,15 @@ impl Mask<&Permissioned> for sizeof::Context { self.mask(oneof)?.mask(pskid)?; Ok(self) } - _ => return Err(anyhow!("Psk's can only be used as ReadOnly Permissioned")) + _ => return Err(anyhow!("Psk's can only be used as ReadOnly Permissioned")), } } } impl Mask<&Permissioned> for wrap::Context - where - F: PRP, - OS: io::OStream, +where + F: PRP, + OS: io::OStream, { fn mask(&mut self, permission: &Permissioned) -> Result<&mut Self> { match permission { @@ -235,15 +233,15 @@ impl Mask<&Permissioned> for wrap::Context self.mask(oneof)?.mask(pskid)?; Ok(self) } - _ => return Err(anyhow!("Psk's can only be used as ReadOnly Permissioned")) + _ => return Err(anyhow!("Psk's can only be used as ReadOnly Permissioned")), } } } impl Mask<&mut Permissioned> for unwrap::Context - where - F: PRP, - IS: io::IStream, +where + F: PRP, + IS: io::IStream, { fn mask(&mut self, permission: &mut Permissioned) -> Result<&mut Self> { let mut oneof = Uint8::new(0); @@ -254,7 +252,7 @@ impl Mask<&mut Permissioned> for unwrap::Context self.mask(&mut psk_id)?; *permission = Permissioned::Read(psk_id); } - o => return Err(anyhow!("{} is not a valid permission option", o)) + o => return Err(anyhow!("{} is not a valid permission option", o)), } Ok(self) } diff --git a/streams/examples/full-example/scenarios/basic.rs b/streams/examples/full-example/scenarios/basic.rs index d164b605..01ab4af2 100644 --- a/streams/examples/full-example/scenarios/basic.rs +++ b/streams/examples/full-example/scenarios/basic.rs @@ -267,7 +267,7 @@ pub(crate) async fn example(transport: T, author_seed: &str } }) .collect::>(), - vec![psk.to_pskid()], + [psk.to_pskid()], ) .await?; println!("> Subscriber A publishes signed packet"); diff --git a/streams/examples/full-example/scenarios/did.rs b/streams/examples/full-example/scenarios/did.rs index 397c29d7..b0ce6083 100644 --- a/streams/examples/full-example/scenarios/did.rs +++ b/streams/examples/full-example/scenarios/did.rs @@ -105,10 +105,8 @@ pub async fn example(transport: Rc>) -> Result<()> { let second_keyload_as_author = author .send_keyload( last_msg.address().relative(), - [ - Permissioned::Read(subscription_b_as_author.header().publisher()), - ], - [psk.to_pskid()] + [Permissioned::Read(subscription_b_as_author.header().publisher())], + [psk.to_pskid()], ) .await?; print_send_result(&second_keyload_as_author); diff --git a/streams/src/api/message.rs b/streams/src/api/message.rs index 758e7b89..3e777ae5 100644 --- a/streams/src/api/message.rs +++ b/streams/src/api/message.rs @@ -8,10 +8,9 @@ use alloc::vec::Vec; // Streams use lets::{ address::Address, - id::{Identifier, Permissioned}, + id::{Identifier, Permissioned, PskId}, message::{Message as LetsMessage, PreparsedMessage, TransportMessage, HDF}, }; -use lets::id::PskId; // Local use crate::message::{announcement, keyload, signed_packet, subscription, tagged_packet, unsubscription}; diff --git a/streams/src/api/user.rs b/streams/src/api/user.rs index f3e6263e..937784c7 100644 --- a/streams/src/api/user.rs +++ b/streams/src/api/user.rs @@ -86,12 +86,7 @@ impl User { psk_store.insert(*pskid, *psk); } - id_store.insert_key( - user_id.to_identifier(), - user_id - ._ke_sk() - .public_key(), - ); + id_store.insert_key(user_id.to_identifier(), user_id._ke_sk().public_key()); Self { transport, @@ -638,9 +633,9 @@ where .psk_store .get(&pskid) .ok_or_else(|| anyhow!("unkown psk '{:?}'", pskid))?, - )) + )) }) - .collect::>>()?; // collect to handle possible error + .collect::>>()?; // collect to handle possible error let content = PCF::new_final_frame().with_content(keyload::Wrap::new( &mut announcement_spongos, &subscribers_with_keys, @@ -676,25 +671,25 @@ where } pub async fn send_keyload_for_all(&mut self, link_to: MsgId) -> Result> { - let psks: Vec = self.state.psk_store.keys().map(|k| *k).collect(); + let psks: Vec = self.state.psk_store.keys().copied().collect(); self.send_keyload( link_to, // Alas, must collect to release the &self immutable borrow self.subscribers().map(Permissioned::Read).collect::>(), - psks + psks, ) .await } pub async fn send_keyload_for_all_rw(&mut self, link_to: MsgId) -> Result> { - let psks: Vec = self.state.psk_store.keys().map(|k| *k).collect(); + let psks: Vec = self.state.psk_store.keys().copied().collect(); self.send_keyload( link_to, // Alas, must collect to release the &self immutable borrow self.subscribers() .map(|s| Permissioned::ReadWrite(s, PermissionDuration::Perpetual)) .collect::>(), - psks + psks, ) .await } diff --git a/streams/src/api/user_builder.rs b/streams/src/api/user_builder.rs index 8eeada5b..0ebcaf18 100644 --- a/streams/src/api/user_builder.rs +++ b/streams/src/api/user_builder.rs @@ -8,7 +8,12 @@ use async_trait::async_trait; // IOTA // Streams -use lets::{address::Address, id::{PskId, Psk, Identity}, message::TransportMessage, transport::Transport}; +use lets::{ + address::Address, + id::{Identity, Psk, PskId}, + message::TransportMessage, + transport::Transport, +}; // Local use crate::api::user::User; @@ -64,7 +69,7 @@ impl UserBuilder { UserBuilder { transport: Some(transport), id: self.id, - psks: self.psks + psks: self.psks, } } @@ -84,23 +89,25 @@ impl UserBuilder { /// # Examples /// ## Add Multiple Psks /// ``` + /// # use std::cell::RefCell; + /// # use std::rc::Rc; /// # use anyhow::Result; /// # use streams::transport::bucket; - /// use streams::{id::Ed25519, transport::tangle, User}; /// use lets::id::Psk; + /// use streams::{id::Ed25519, transport::tangle, User}; /// # #[tokio::main] /// # async fn main() -> Result<()> { - /// # let transport = bucket::Client::new(); - /// let psk1 = "Psk1".as_bytes(); - /// let psk2 = psk_from_seed("Psk2".as_bytes()); - /// let pskid1 = pskid_from_psk(&psk1); - /// let pskid2 = pskid_from_psk(&psk2); - /// - /// let user = UserBuilder::new() + /// let author_seed = "author_secure_seed"; + /// let transport: tangle::Client = tangle::Client::for_node("https://chrysalis-nodes.iota.org").await?; + /// # let transport: Rc> = Rc::new(RefCell::new(bucket::Client::new())); + /// let psk1 = Psk::from_seed(b"Psk1"); + /// let psk2 = Psk::from_seed(b"Psk2"); + /// let user = User::builder() + /// # .with_identity(Ed25519::from_seed(author_seed)) /// # .with_transport(transport) - /// .with_psk(pskid1, psk1) - /// .with_psk(pskid2, psk2) - /// .build(); + /// .with_psk(psk1.to_pskid(), psk1) + /// .with_psk(psk2.to_pskid(), psk2) + /// .build()?; /// # Ok(()) /// # } /// ``` @@ -148,31 +155,6 @@ impl UserBuilder { /// # Ok(()) /// # } /// ``` - /// - /// ## User from Psk - /// ``` - /// # use std::cell::RefCell; - /// # use std::rc::Rc; - /// # use anyhow::Result; - /// # use streams::transport::bucket; - /// use streams::{id::Psk, transport::tangle, User}; - /// - /// # #[tokio::main] - /// # async fn main() -> Result<()> { - /// let transport: tangle::Client = tangle::Client::for_node("https://chrysalis-nodes.iota.org").await?; - /// # - /// # let transport: Rc> = Rc::new(RefCell::new(bucket::Client::new())); - /// # - /// let psk_seed = "seed-for-pre-shared-key"; - /// - /// let mut user = User::builder() - /// .with_identity(Psk::from_seed(psk_seed)) - /// .with_transport(transport) - /// .build()?; - /// - /// # Ok(()) - /// # } - /// ``` pub fn build(self) -> Result> { let id = self .id diff --git a/streams/src/message/announcement.rs b/streams/src/message/announcement.rs index fa2468d7..ace463a7 100644 --- a/streams/src/message/announcement.rs +++ b/streams/src/message/announcement.rs @@ -55,12 +55,7 @@ impl<'a> ContentSizeof> for sizeof::Context { async fn sizeof(&mut self, announcement: &Wrap<'a>) -> Result<&mut Self> { self.mask(&announcement.user_id.to_identifier())? // TODO: REMOVE ONCE KE IS ENCAPSULATED WITHIN IDENTITY - .absorb( - &announcement - .user_id - ._ke_sk() - .public_key(), - )? + .absorb(&announcement.user_id._ke_sk().public_key())? .sign_sizeof(announcement.user_id) .await? .commit()?; @@ -76,12 +71,7 @@ where async fn wrap(&mut self, announcement: &mut Wrap<'a>) -> Result<&mut Self> { self.mask(&announcement.user_id.to_identifier())? // TODO: REMOVE ONCE KE IS ENCAPSULATED WITHIN IDENTITY - .absorb( - &announcement - .user_id - ._ke_sk() - .public_key(), - )? + .absorb(&announcement.user_id._ke_sk().public_key())? .sign(announcement.user_id) .await? .commit()?; diff --git a/streams/src/message/keyload.rs b/streams/src/message/keyload.rs index 50fd44fc..fee8df13 100644 --- a/streams/src/message/keyload.rs +++ b/streams/src/message/keyload.rs @@ -230,7 +230,7 @@ where { async fn unwrap(&mut self, keyload: &mut Unwrap<'a>) -> Result<&mut Self> { let mut nonce = [0u8; NONCE_SIZE]; - let mut key: Option<[u8;KEY_SIZE]> = None; + let mut key: Option<[u8; KEY_SIZE]> = None; let mut n_subscribers = Size::default(); let mut n_psks = Size::default(); self.join(keyload.initial_state)? @@ -244,7 +244,7 @@ where fork.mask(&mut subscriber_id)?; if subscriber_id.identifier() == &keyload.user_id.to_identifier() { - fork.decrypt( keyload.user_ke_key, key.get_or_insert([0u8; KEY_SIZE])) + fork.decrypt(keyload.user_ke_key, key.get_or_insert([0u8; KEY_SIZE])) .await?; } else { // Key is meant for another subscriber, skip it diff --git a/streams/src/message/subscription.rs b/streams/src/message/subscription.rs index 0d9ee187..08cc1f64 100644 --- a/streams/src/message/subscription.rs +++ b/streams/src/message/subscription.rs @@ -79,12 +79,7 @@ impl<'a> ContentSizeof> for sizeof::Context { async fn sizeof(&mut self, subscription: &Wrap<'a>) -> Result<&mut Self> { self.x25519(subscription.author_ke_pk, NBytes::new(subscription.unsubscribe_key))? .mask(&subscription.subscriber_id.to_identifier())? - .absorb( - &subscription - .subscriber_id - ._ke_sk() - .public_key(), - )? + .absorb(&subscription.subscriber_id._ke_sk().public_key())? .sign_sizeof(subscription.subscriber_id) .await?; Ok(self) @@ -100,12 +95,7 @@ where self.join(subscription.initial_state)? .x25519(subscription.author_ke_pk, NBytes::new(subscription.unsubscribe_key))? .mask(&subscription.subscriber_id.to_identifier())? - .absorb( - &subscription - .subscriber_id - ._ke_sk() - .public_key(), - )? + .absorb(&subscription.subscriber_id._ke_sk().public_key())? .sign(subscription.subscriber_id) .await?; Ok(self) From 4770349be3f975136ebfb371da41c6786e494bc1 Mon Sep 17 00:00:00 2001 From: DyrellC Date: Wed, 25 May 2022 10:13:02 -0600 Subject: [PATCH 03/12] review changes --- lets/src/id/identifier.rs | 8 ++++---- lets/src/id/identity.rs | 19 ++----------------- lets/src/message/content.rs | 12 ++++++------ streams/src/api/key_store.rs | 4 ++-- streams/src/api/user.rs | 20 ++++++++++---------- streams/src/message/keyload.rs | 31 ++++++++++++++++--------------- 6 files changed, 40 insertions(+), 54 deletions(-) diff --git a/lets/src/id/identifier.rs b/lets/src/id/identifier.rs index cadeab60..44a74e23 100644 --- a/lets/src/id/identifier.rs +++ b/lets/src/id/identifier.rs @@ -253,8 +253,8 @@ where // TODO: Find a better way to represent this logic without the need for an additional trait #[async_trait(?Send)] -impl ContentEncryptSizeOf for sizeof::Context { - async fn encrypt_sizeof(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> { +impl ContentEncryptSizeOf for sizeof::Context { + async fn encrypt_sizeof(&mut self, _recipient: &Identifier, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> { // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey // introdution) match <[u8; 32]>::try_from(exchange_key) { @@ -265,12 +265,12 @@ impl ContentEncryptSizeOf for sizeof::Context { } #[async_trait(?Send)] -impl ContentEncrypt for wrap::Context +impl ContentEncrypt for wrap::Context where F: PRP, OS: io::OStream, { - async fn encrypt(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> { + async fn encrypt(&mut self, _recipient: &Identifier, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self> { // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey // introdution) match <[u8; 32]>::try_from(exchange_key) { diff --git a/lets/src/id/identity.rs b/lets/src/id/identity.rs index cba82ebb..691f0419 100644 --- a/lets/src/id/identity.rs +++ b/lets/src/id/identity.rs @@ -66,21 +66,6 @@ impl Identity { } } - // #[deprecated = "to be removed once key exchange is encapsulated within Identity"] - pub fn _ke(&self) -> [u8; 32] { - match self { - Self::Ed25519(ed25519) => { - let x_secret: x25519::SecretKey = ed25519.inner().into(); - x_secret.to_bytes() - } - #[cfg(feature = "did")] - Self::DID(DID::PrivateKey(info)) => info.ke_kp().0.to_bytes(), - #[cfg(feature = "did")] - Self::DID(DID::Default) => unreachable!(), - // TODO: Account implementation - } - } - pub fn to_identifier(&self) -> Identifier { match self { Self::Ed25519(ed25519) => ed25519.inner().public_key().into(), @@ -249,12 +234,12 @@ where } #[async_trait(?Send)] -impl ContentDecrypt for unwrap::Context +impl ContentDecrypt for unwrap::Context where F: PRP, IS: io::IStream, { - async fn decrypt(&mut self, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self> { + async fn decrypt(&mut self, _recipient: &Identity, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self> { // TODO: Replace with separate logic for EdPubKey and DID instances (pending Identity xkey // introduction) match <[u8; 32]>::try_from(exchange_key) { diff --git a/lets/src/message/content.rs b/lets/src/message/content.rs index 91c79f8b..be2014eb 100644 --- a/lets/src/message/content.rs +++ b/lets/src/message/content.rs @@ -44,16 +44,16 @@ pub trait ContentVerify { } #[async_trait(?Send)] -pub trait ContentEncryptSizeOf { - async fn encrypt_sizeof(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self>; +pub trait ContentEncryptSizeOf { + async fn encrypt_sizeof(&mut self, recipient: &T, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self>; } #[async_trait(?Send)] -pub trait ContentEncrypt { - async fn encrypt(&mut self, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self>; +pub trait ContentEncrypt { + async fn encrypt(&mut self, recipient: &T, exchange_key: &[u8], key: &[u8]) -> Result<&mut Self>; } #[async_trait(?Send)] -pub trait ContentDecrypt { - async fn decrypt(&mut self, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self>; +pub trait ContentDecrypt { + async fn decrypt(&mut self, recipient: &T, exchange_key: &[u8], key: &mut [u8]) -> Result<&mut Self>; } diff --git a/streams/src/api/key_store.rs b/streams/src/api/key_store.rs index 963ea345..3066f80c 100644 --- a/streams/src/api/key_store.rs +++ b/streams/src/api/key_store.rs @@ -61,8 +61,8 @@ impl KeyStore { self.keys.keys().copied() } - pub(crate) fn get_exchange_key(&self, identifier: &Identifier) -> Option<&[u8]> { - self.keys.get(identifier).map(AsRef::as_ref) + pub(crate) fn get_exchange_key(&self, identifier: &Identifier) -> Option<&x25519::PublicKey> { + self.keys.get(identifier) } } diff --git a/streams/src/api/user.rs b/streams/src/api/user.rs index 937784c7..f24688d4 100644 --- a/streams/src/api/user.rs +++ b/streams/src/api/user.rs @@ -158,7 +158,7 @@ impl User { } pub fn remove_psk(&mut self, pskid: PskId) -> bool { - self.state.psk_store.remove(&pskid).is_none() + self.state.psk_store.remove(&pskid).is_some() } pub(crate) async fn handle_message(&mut self, address: Address, msg: TransportMessage) -> Result { @@ -288,11 +288,9 @@ impl User { .expect("a subscriber that has received an stream announcement must keep its spongos in store"); // TODO: Remove Psk from Identity and Identifier, and manage it as a complementary permission - let user_ke_sk = self.state.user_id._ke(); let keyload = keyload::Unwrap::new( &mut announcement_spongos, &self.state.user_id, - &user_ke_sk, author_identifier, &self.state.psk_store, ); @@ -588,7 +586,7 @@ where ) -> Result> where Subscribers: IntoIterator> + Clone, - Psks: IntoIterator + Clone, + Psks: IntoIterator, { // Check conditions let stream_address = self @@ -624,7 +622,6 @@ where }) .collect::>>()?; // collect to handle possible error let psk_ids_with_psks = psk_ids - .clone() .into_iter() .map(|pskid| { Ok(( @@ -639,7 +636,7 @@ where let content = PCF::new_final_frame().with_content(keyload::Wrap::new( &mut announcement_spongos, &subscribers_with_keys, - psk_ids_with_psks, + &psk_ids_with_psks, encryption_key, nonce, &self.state.user_id, @@ -672,10 +669,11 @@ where pub async fn send_keyload_for_all(&mut self, link_to: MsgId) -> Result> { let psks: Vec = self.state.psk_store.keys().copied().collect(); + let subscribers: Vec> = self.subscribers().map(Permissioned::Read).collect(); self.send_keyload( link_to, // Alas, must collect to release the &self immutable borrow - self.subscribers().map(Permissioned::Read).collect::>(), + subscribers, psks, ) .await @@ -683,12 +681,14 @@ where pub async fn send_keyload_for_all_rw(&mut self, link_to: MsgId) -> Result> { let psks: Vec = self.state.psk_store.keys().copied().collect(); + let subscribers: Vec> = self + .subscribers() + .map(|s| Permissioned::ReadWrite(s, PermissionDuration::Perpetual)) + .collect(); self.send_keyload( link_to, // Alas, must collect to release the &self immutable borrow - self.subscribers() - .map(|s| Permissioned::ReadWrite(s, PermissionDuration::Perpetual)) - .collect::>(), + subscribers, psks, ) .await diff --git a/streams/src/message/keyload.rs b/streams/src/message/keyload.rs index fee8df13..df398c65 100644 --- a/streams/src/message/keyload.rs +++ b/streams/src/message/keyload.rs @@ -86,9 +86,9 @@ impl<'a, Subscribers, Psks> Wrap<'a, Subscribers, Psks> { author_id: &'a Identity, ) -> Self where - Subscribers: IntoIterator, &'a [u8])> + Clone, + Subscribers: IntoIterator, &'a x25519::PublicKey)> + Clone, Subscribers::IntoIter: ExactSizeIterator, - Psks: IntoIterator + Clone, + Psks: IntoIterator + Clone, Psks::IntoIter: ExactSizeIterator, { Self { @@ -105,9 +105,9 @@ impl<'a, Subscribers, Psks> Wrap<'a, Subscribers, Psks> { #[async_trait(?Send)] impl<'a, Subscribers, Psks> message::ContentSizeof> for sizeof::Context where - Subscribers: IntoIterator, &'a [u8])> + Clone, + Subscribers: IntoIterator, &'a x25519::PublicKey)> + Clone, Subscribers::IntoIter: ExactSizeIterator, - Psks: IntoIterator + Clone, + Psks: IntoIterator + Clone, Psks::IntoIter: ExactSizeIterator, { async fn sizeof(&mut self, keyload: &Wrap<'a, Subscribers, Psks>) -> Result<&mut sizeof::Context> { @@ -120,14 +120,14 @@ where for (subscriber, exchange_key) in subscribers { self.fork() .mask(subscriber)? - .encrypt_sizeof(exchange_key, &keyload.key) + .encrypt_sizeof(subscriber.identifier(), &exchange_key.to_bytes(), &keyload.key) .await?; } self.absorb(n_psks)?; // Loop through provided pskids, masking the shared key for each one for (pskid, psk) in psks { self.fork() - .mask(&pskid)? + .mask(pskid)? .absorb(External::new(&NBytes::new(psk)))? .commit()? .mask(NBytes::new(&keyload.key))?; @@ -143,9 +143,9 @@ where #[async_trait(?Send)] impl<'a, OS, Subscribers, Psks> message::ContentWrap> for wrap::Context where - Subscribers: IntoIterator, &'a [u8])> + Clone, + Subscribers: IntoIterator, &'a x25519::PublicKey)> + Clone, Subscribers::IntoIter: ExactSizeIterator, - Psks: IntoIterator + Clone, + Psks: IntoIterator + Clone, Psks::IntoIter: ExactSizeIterator, OS: io::OStream, { @@ -161,14 +161,14 @@ where for (subscriber, exchange_key) in subscribers { self.fork() .mask(subscriber)? - .encrypt(exchange_key, &keyload.key) + .encrypt(subscriber.identifier(), &exchange_key.to_bytes(), &keyload.key) .await?; } self.absorb(n_psks)?; // Loop through provided pskids, masking the shared key for each one for (pskid, psk) in psks { self.fork() - .mask(&pskid)? + .mask(pskid)? .absorb(External::new(&NBytes::new(psk)))? .commit()? .mask(NBytes::new(&keyload.key))?; @@ -188,14 +188,12 @@ pub(crate) struct Unwrap<'a> { psk_store: &'a HashMap, author_id: Identifier, user_id: &'a Identity, - user_ke_key: &'a [u8], } impl<'a> Unwrap<'a> { pub(crate) fn new( initial_state: &'a mut Spongos, user_id: &'a Identity, - user_ke_key: &'a [u8], author_id: Identifier, psk_store: &'a HashMap, ) -> Self { @@ -206,7 +204,6 @@ impl<'a> Unwrap<'a> { psk_store, author_id, user_id, - user_ke_key, } } @@ -244,8 +241,12 @@ where fork.mask(&mut subscriber_id)?; if subscriber_id.identifier() == &keyload.user_id.to_identifier() { - fork.decrypt(keyload.user_ke_key, key.get_or_insert([0u8; KEY_SIZE])) - .await?; + fork.decrypt( + keyload.user_id, + &keyload.user_id._ke_sk().to_bytes(), + key.get_or_insert([0u8; KEY_SIZE]), + ) + .await?; } else { // Key is meant for another subscriber, skip it fork.drop(KEY_SIZE + x25519::PUBLIC_KEY_LENGTH)?; From 7fef8c5f3342684daf0fcf38a1ea988462382ca6 Mon Sep 17 00:00:00 2001 From: DyrellC Date: Wed, 25 May 2022 10:23:17 -0600 Subject: [PATCH 04/12] Remove unused masks in permissions --- lets/src/id/permission.rs | 50 --------------------------------------- 1 file changed, 50 deletions(-) diff --git a/lets/src/id/permission.rs b/lets/src/id/permission.rs index c159e158..ee78a862 100644 --- a/lets/src/id/permission.rs +++ b/lets/src/id/permission.rs @@ -207,53 +207,3 @@ where Ok(self) } } - -impl Mask<&Permissioned> for sizeof::Context { - fn mask(&mut self, permission: &Permissioned) -> Result<&mut Self> { - match permission { - Permissioned::Read(pskid) => { - let oneof = Uint8::new(0); - self.mask(oneof)?.mask(pskid)?; - Ok(self) - } - _ => return Err(anyhow!("Psk's can only be used as ReadOnly Permissioned")), - } - } -} - -impl Mask<&Permissioned> for wrap::Context -where - F: PRP, - OS: io::OStream, -{ - fn mask(&mut self, permission: &Permissioned) -> Result<&mut Self> { - match permission { - Permissioned::Read(pskid) => { - let oneof = Uint8::new(0); - self.mask(oneof)?.mask(pskid)?; - Ok(self) - } - _ => return Err(anyhow!("Psk's can only be used as ReadOnly Permissioned")), - } - } -} - -impl Mask<&mut Permissioned> for unwrap::Context -where - F: PRP, - IS: io::IStream, -{ - fn mask(&mut self, permission: &mut Permissioned) -> Result<&mut Self> { - let mut oneof = Uint8::new(0); - self.mask(&mut oneof)?; - match oneof.inner() { - 0 => { - let mut psk_id = PskId::default(); - self.mask(&mut psk_id)?; - *permission = Permissioned::Read(psk_id); - } - o => return Err(anyhow!("{} is not a valid permission option", o)), - } - Ok(self) - } -} From aaf44c516c80097cdb94073c0faef92fe8499114 Mon Sep 17 00:00:00 2001 From: DyrellC Date: Wed, 25 May 2022 10:38:24 -0600 Subject: [PATCH 05/12] Update new --- lets/src/id/permission.rs | 2 +- streams/src/api/user.rs | 11 +++++++---- streams/src/api/user_builder.rs | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lets/src/id/permission.rs b/lets/src/id/permission.rs index ee78a862..712290c6 100644 --- a/lets/src/id/permission.rs +++ b/lets/src/id/permission.rs @@ -16,7 +16,7 @@ use spongos::{ }; // Local -use crate::id::{identifier::Identifier, PskId}; +use crate::id::identifier::Identifier; #[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] pub enum PermissionDuration { diff --git a/streams/src/api/user.rs b/streams/src/api/user.rs index f24688d4..95bf89bd 100644 --- a/streams/src/api/user.rs +++ b/streams/src/api/user.rs @@ -77,14 +77,17 @@ impl User<()> { } impl User { - pub(crate) fn new(user_id: Identity, psks: &[(PskId, Psk)], transport: T) -> Self { + pub(crate) fn new(user_id: Identity, psks: Psks, transport: T) -> Self + where + Psks: IntoIterator, + { let mut id_store = KeyStore::new(); let mut psk_store = HashMap::new(); // Store any pre shared keys - for (pskid, psk) in psks { - psk_store.insert(*pskid, *psk); - } + psks.into_iter().for_each(|(pskid, psk)| { + psk_store.insert(pskid, psk); + }); id_store.insert_key(user_id.to_identifier(), user_id._ke_sk().public_key()); diff --git a/streams/src/api/user_builder.rs b/streams/src/api/user_builder.rs index 0ebcaf18..8883c6fe 100644 --- a/streams/src/api/user_builder.rs +++ b/streams/src/api/user_builder.rs @@ -164,7 +164,7 @@ impl UserBuilder { .transport .ok_or_else(|| anyhow!("transport not specified, cannot build User without Transport"))?; - Ok(User::new(id, &self.psks, transport)) + Ok(User::new(id, self.psks, transport)) } /// Recover a user instance from the builder parameters. From ab7e79e6fbf601218081da5b6f143fece2dc6c56 Mon Sep 17 00:00:00 2001 From: DyrellC Date: Wed, 25 May 2022 12:16:35 -0600 Subject: [PATCH 06/12] Add psks to debug for user --- streams/src/api/user.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/streams/src/api/user.rs b/streams/src/api/user.rs index 95bf89bd..52c050bc 100644 --- a/streams/src/api/user.rs +++ b/streams/src/api/user.rs @@ -931,9 +931,14 @@ impl Debug for User { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!( f, - "\n* identifier: <{}>\n{:?}\n* messages:\n{}\n", + "\n* identifier: <{}>\n{:?}\n* PSKs: \n{}\n* messages:\n{}\n", self.identifier(), self.state.id_store, + self.state + .psk_store + .keys() + .map(|pskid| format!("\t<{:?}>\n", pskid)) + .collect::(), self.state .spongos_store .keys() From de371c4f027a5cb31172798c3132b0512d07c9df Mon Sep 17 00:00:00 2001 From: Arnau Orriols Date: Thu, 26 May 2022 11:58:50 +0200 Subject: [PATCH 07/12] Fix unused warning for `#[cfg_attr(test, macro_use)]` in `spongos/src/lib.rs` --- spongos/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spongos/src/lib.rs b/spongos/src/lib.rs index 2fe793e7..9bb7b7de 100644 --- a/spongos/src/lib.rs +++ b/spongos/src/lib.rs @@ -1,7 +1,7 @@ #![no_std] // Spongos requires heap allocation for Vectors and Strings -#[cfg_attr(test, macro_use)] +#[cfg_attr(all(test, not(feature = "std")), macro_use)] extern crate alloc; // Spongos requires the feature "std" for the Dump DDML command From 919a6a96ada6d079883a58df90c2c65c64608fbb Mon Sep 17 00:00:00 2001 From: DyrellC Date: Thu, 26 May 2022 08:58:28 -0600 Subject: [PATCH 08/12] Second Round review --- .../examples/full-example/scenarios/basic.rs | 4 +- streams/src/api/key_store.rs | 4 - streams/src/api/message.rs | 8 +- streams/src/api/user.rs | 4 +- streams/src/api/user_builder.rs | 22 ++---- streams/src/message/keyload.rs | 77 +++++++++---------- 6 files changed, 49 insertions(+), 70 deletions(-) diff --git a/streams/examples/full-example/scenarios/basic.rs b/streams/examples/full-example/scenarios/basic.rs index 01ab4af2..7449a69d 100644 --- a/streams/examples/full-example/scenarios/basic.rs +++ b/streams/examples/full-example/scenarios/basic.rs @@ -83,7 +83,7 @@ pub(crate) async fn example(transport: T, author_seed: &str keyload_as_a .as_keyload() .expect("expected keyload, found something else") - .includes(subscriber_a.identifier()) + .includes_subscriber(subscriber_a.identifier()) ); let keyload_as_b = subscriber_b .messages() @@ -95,7 +95,7 @@ pub(crate) async fn example(transport: T, author_seed: &str !keyload_as_b .as_keyload() .expect("expected keyload, found something else") - .includes(subscriber_b.identifier()) + .includes_subscriber(subscriber_b.identifier()) ); let keyload_as_c = subscriber_c .messages() diff --git a/streams/src/api/key_store.rs b/streams/src/api/key_store.rs index 3066f80c..70e6bac8 100644 --- a/streams/src/api/key_store.rs +++ b/streams/src/api/key_store.rs @@ -60,10 +60,6 @@ impl KeyStore { pub(crate) fn subscribers(&self) -> impl Iterator + Clone + '_ { self.keys.keys().copied() } - - pub(crate) fn get_exchange_key(&self, identifier: &Identifier) -> Option<&x25519::PublicKey> { - self.keys.get(identifier) - } } impl fmt::Debug for KeyStore { diff --git a/streams/src/api/message.rs b/streams/src/api/message.rs index 3e777ae5..d2120576 100644 --- a/streams/src/api/message.rs +++ b/streams/src/api/message.rs @@ -189,12 +189,12 @@ pub struct Keyload { } impl Keyload { - pub fn includes(&self, subscriber: Identifier) -> bool { + pub fn includes_subscriber(&self, subscriber: Identifier) -> bool { self.subscribers.iter().any(|s| s.identifier() == &subscriber) } pub fn includes_psk(&self, psk_id: &PskId) -> bool { - self.psks.iter().any(|id| id.eq(psk_id)) + self.psks.iter().any(|id| id == psk_id) } } @@ -258,8 +258,8 @@ impl<'a> From> for MessageContent { impl<'a> From> for MessageContent { fn from(keyload: keyload::Unwrap<'a>) -> Self { Self::Keyload(Keyload { - psks: keyload.psks().to_vec(), - subscribers: keyload.into_subscribers(), + psks: keyload.psks, + subscribers: keyload.subscribers, }) } } diff --git a/streams/src/api/user.rs b/streams/src/api/user.rs index 52c050bc..639930ed 100644 --- a/streams/src/api/user.rs +++ b/streams/src/api/user.rs @@ -303,7 +303,7 @@ impl User { self.state.spongos_store.insert(address.relative(), spongos); // Store message content into stores - for subscriber in message.payload().content().subscribers() { + for subscriber in &message.payload().content().subscribers { if self.should_store_cursor(subscriber) { self.state .id_store @@ -619,7 +619,7 @@ where subscriber, self.state .id_store - .get_exchange_key(subscriber.identifier()) + .get_key(subscriber.identifier()) .ok_or_else(|| anyhow!("unknown subscriber '{}'", subscriber.identifier()))?, )) }) diff --git a/streams/src/api/user_builder.rs b/streams/src/api/user_builder.rs index 8883c6fe..3960e51a 100644 --- a/streams/src/api/user_builder.rs +++ b/streams/src/api/user_builder.rs @@ -25,7 +25,7 @@ pub struct UserBuilder { /// Transport Client instance transport: Option, /// Pre Shared Keys - pub psks: Vec<(PskId, Psk)>, + psks: Vec<(PskId, Psk)>, } impl Default for UserBuilder { @@ -89,22 +89,18 @@ impl UserBuilder { /// # Examples /// ## Add Multiple Psks /// ``` - /// # use std::cell::RefCell; - /// # use std::rc::Rc; /// # use anyhow::Result; - /// # use streams::transport::bucket; /// use lets::id::Psk; /// use streams::{id::Ed25519, transport::tangle, User}; /// # #[tokio::main] /// # async fn main() -> Result<()> { /// let author_seed = "author_secure_seed"; - /// let transport: tangle::Client = tangle::Client::for_node("https://chrysalis-nodes.iota.org").await?; - /// # let transport: Rc> = Rc::new(RefCell::new(bucket::Client::new())); /// let psk1 = Psk::from_seed(b"Psk1"); /// let psk2 = Psk::from_seed(b"Psk2"); /// let user = User::builder() - /// # .with_identity(Ed25519::from_seed(author_seed)) - /// # .with_transport(transport) + /// .with_identity(Ed25519::from_seed(author_seed)) + /// .with_default_transport() + /// .await? /// .with_psk(psk1.to_pskid(), psk1) /// .with_psk(psk2.to_pskid(), psk2) /// .build()?; @@ -134,22 +130,16 @@ impl UserBuilder { /// # Examples /// ## User from Ed25519 /// ``` - /// # use std::cell::RefCell; - /// # use std::rc::Rc; /// # use anyhow::Result; - /// # use streams::transport::bucket; /// use streams::{id::Ed25519, transport::tangle, User}; /// /// # #[tokio::main] /// # async fn main() -> Result<()> { /// let user_seed = "cryptographically-secure-random-user-seed"; - /// let transport: tangle::Client = tangle::Client::for_node("https://chrysalis-nodes.iota.org").await?; - /// # - /// # let transport: Rc> = Rc::new(RefCell::new(bucket::Client::new())); - /// /// let mut user = User::builder() /// .with_identity(Ed25519::from_seed(user_seed)) - /// .with_transport(transport) + /// .with_default_transport() + /// .await? /// .build()?; /// /// # Ok(()) diff --git a/streams/src/message/keyload.rs b/streams/src/message/keyload.rs index df398c65..7f930776 100644 --- a/streams/src/message/keyload.rs +++ b/streams/src/message/keyload.rs @@ -183,8 +183,8 @@ where pub(crate) struct Unwrap<'a> { initial_state: &'a mut Spongos, - subscribers: Vec>, - psks: Vec, + pub(crate) subscribers: Vec>, + pub(crate) psks: Vec, psk_store: &'a HashMap, author_id: Identifier, user_id: &'a Identity, @@ -206,18 +206,6 @@ impl<'a> Unwrap<'a> { user_id, } } - - pub(crate) fn subscribers(&self) -> &[Permissioned] { - &self.subscribers - } - - pub(crate) fn into_subscribers(self) -> Vec> { - self.subscribers - } - - pub(crate) fn psks(&self) -> &[PskId] { - &self.psks - } } #[async_trait(?Send)] @@ -235,41 +223,46 @@ where .absorb(&mut n_subscribers)?; for _ in 0..n_subscribers.inner() { - let mut fork = self.fork(); - // Loop through provided number of identifiers and subsequent keys - let mut subscriber_id = Permissioned::::default(); - fork.mask(&mut subscriber_id)?; + if key.is_none() { + let mut fork = self.fork(); + // Loop through provided number of identifiers and subsequent keys + let mut subscriber_id = Permissioned::::default(); + fork.mask(&mut subscriber_id)?; - if subscriber_id.identifier() == &keyload.user_id.to_identifier() { - fork.decrypt( - keyload.user_id, - &keyload.user_id._ke_sk().to_bytes(), - key.get_or_insert([0u8; KEY_SIZE]), - ) - .await?; - } else { - // Key is meant for another subscriber, skip it - fork.drop(KEY_SIZE + x25519::PUBLIC_KEY_LENGTH)?; + if subscriber_id.identifier() == &keyload.user_id.to_identifier() { + fork.decrypt( + keyload.user_id, + &keyload.user_id._ke_sk().to_bytes(), + key.get_or_insert([0u8; KEY_SIZE]), + ) + .await?; + } else { + // Key is meant for another subscriber, skip it + fork.drop(KEY_SIZE + x25519::PUBLIC_KEY_LENGTH)?; + } + keyload.subscribers.push(subscriber_id); } - keyload.subscribers.push(subscriber_id); } self.absorb(&mut n_psks)?; for _ in 0..n_psks.inner() { - let mut fork = self.fork(); - // Loop thorugh provided psks and keys - let mut psk_id = PskId::default(); - fork.mask(&mut psk_id)?; + if key.is_none() { + let mut fork = self.fork(); + + // Loop thorugh provided psks and keys + let mut psk_id = PskId::default(); + fork.mask(&mut psk_id)?; - let mut masked_key = [0u8; KEY_SIZE]; - if let Some(psk) = keyload.psk_store.get(&psk_id) { - fork.absorb(External::new(&NBytes::new(psk)))? - .commit()? - .mask(NBytes::new(&mut masked_key))?; - key = Some(masked_key); - keyload.psks.push(psk_id); - } else { - fork.drop(KEY_SIZE)?; + let mut masked_key = [0u8; KEY_SIZE]; + if let Some(psk) = keyload.psk_store.get(&psk_id) { + fork.absorb(External::new(&NBytes::new(psk)))? + .commit()? + .mask(NBytes::new(&mut masked_key))?; + key = Some(masked_key); + keyload.psks.push(psk_id); + } else { + fork.drop(KEY_SIZE)?; + } } } From 6ad3f2493381f5da48e98305dffee57bb30c0d26 Mon Sep 17 00:00:00 2001 From: DyrellC Date: Thu, 26 May 2022 12:53:56 -0600 Subject: [PATCH 09/12] remove if key.is_none() --- streams/src/message/keyload.rs | 61 ++++++++++++++++------------------ 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/streams/src/message/keyload.rs b/streams/src/message/keyload.rs index 7f930776..fd33d6e7 100644 --- a/streams/src/message/keyload.rs +++ b/streams/src/message/keyload.rs @@ -223,46 +223,43 @@ where .absorb(&mut n_subscribers)?; for _ in 0..n_subscribers.inner() { - if key.is_none() { - let mut fork = self.fork(); - // Loop through provided number of identifiers and subsequent keys - let mut subscriber_id = Permissioned::::default(); - fork.mask(&mut subscriber_id)?; + let mut fork = self.fork(); + // Loop through provided number of identifiers and subsequent keys + let mut subscriber_id = Permissioned::::default(); + fork.mask(&mut subscriber_id)?; - if subscriber_id.identifier() == &keyload.user_id.to_identifier() { - fork.decrypt( - keyload.user_id, - &keyload.user_id._ke_sk().to_bytes(), - key.get_or_insert([0u8; KEY_SIZE]), - ) - .await?; - } else { - // Key is meant for another subscriber, skip it - fork.drop(KEY_SIZE + x25519::PUBLIC_KEY_LENGTH)?; - } - keyload.subscribers.push(subscriber_id); + if subscriber_id.identifier() == &keyload.user_id.to_identifier() { + fork.decrypt( + keyload.user_id, + &keyload.user_id._ke_sk().to_bytes(), + key.get_or_insert([0u8; KEY_SIZE]), + ) + .await?; + } else { + // Key is meant for another subscriber, skip it + fork.drop(KEY_SIZE + x25519::PUBLIC_KEY_LENGTH)?; } + keyload.subscribers.push(subscriber_id); } self.absorb(&mut n_psks)?; for _ in 0..n_psks.inner() { - if key.is_none() { - let mut fork = self.fork(); + let mut fork = self.fork(); + + // Loop thorugh provided psks and keys + let mut psk_id = PskId::default(); + fork.mask(&mut psk_id)?; - // Loop thorugh provided psks and keys - let mut psk_id = PskId::default(); - fork.mask(&mut psk_id)?; + let mut masked_key = [0u8; KEY_SIZE]; + if let Some(psk) = keyload.psk_store.get(&psk_id) { + fork.absorb(External::new(&NBytes::new(psk)))? + .commit()? + .mask(NBytes::new(&mut masked_key))?; + key = Some(masked_key); - let mut masked_key = [0u8; KEY_SIZE]; - if let Some(psk) = keyload.psk_store.get(&psk_id) { - fork.absorb(External::new(&NBytes::new(psk)))? - .commit()? - .mask(NBytes::new(&mut masked_key))?; - key = Some(masked_key); - keyload.psks.push(psk_id); - } else { - fork.drop(KEY_SIZE)?; - } + keyload.psks.push(psk_id); + } else { + fork.drop(KEY_SIZE)?; } } From 1761123c5fbb61af65e2e7c1264e03bd5b5bf7a7 Mon Sep 17 00:00:00 2001 From: DyrellC Date: Thu, 26 May 2022 14:56:45 -0600 Subject: [PATCH 10/12] update user builder default transport function --- streams/src/api/user_builder.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/streams/src/api/user_builder.rs b/streams/src/api/user_builder.rs index 3960e51a..ac321457 100644 --- a/streams/src/api/user_builder.rs +++ b/streams/src/api/user_builder.rs @@ -74,14 +74,19 @@ impl UserBuilder { } /// Use the default version of the Transport Client - pub async fn with_default_transport(mut self) -> Result + pub async fn with_default_transport(self) -> Result> where - T: for<'a> Transport<'a> + DefaultTransport, + NewTransport: for<'a> Transport<'a> + DefaultTransport, { // Separated as a method instead of defaulting at the build method to avoid requiring the bespoke // bound T: DefaultTransport for all transports - self.transport = Some(T::try_default().await?); - Ok(self) + Ok( + UserBuilder { + transport: Some(NewTransport::try_default().await?), + id: self.id, + psks: self.psks, + } + ) } /// Inject a new Pre Shared Key and Id into the User Builder @@ -99,7 +104,7 @@ impl UserBuilder { /// let psk2 = Psk::from_seed(b"Psk2"); /// let user = User::builder() /// .with_identity(Ed25519::from_seed(author_seed)) - /// .with_default_transport() + /// .with_default_transport::() /// .await? /// .with_psk(psk1.to_pskid(), psk1) /// .with_psk(psk2.to_pskid(), psk2) @@ -138,8 +143,9 @@ impl UserBuilder { /// let user_seed = "cryptographically-secure-random-user-seed"; /// let mut user = User::builder() /// .with_identity(Ed25519::from_seed(user_seed)) - /// .with_default_transport() + /// .with_default_transport::() /// .await? + /// .with_identity(Ed25519::from_seed(user_seed)) /// .build()?; /// /// # Ok(()) From a6f9914e93d50f60c0ab265b3bc43324805cdc87 Mon Sep 17 00:00:00 2001 From: DyrellC Date: Thu, 26 May 2022 14:59:36 -0600 Subject: [PATCH 11/12] fmt --- streams/src/api/user_builder.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/streams/src/api/user_builder.rs b/streams/src/api/user_builder.rs index ac321457..47847c78 100644 --- a/streams/src/api/user_builder.rs +++ b/streams/src/api/user_builder.rs @@ -80,13 +80,11 @@ impl UserBuilder { { // Separated as a method instead of defaulting at the build method to avoid requiring the bespoke // bound T: DefaultTransport for all transports - Ok( - UserBuilder { - transport: Some(NewTransport::try_default().await?), - id: self.id, - psks: self.psks, - } - ) + Ok(UserBuilder { + transport: Some(NewTransport::try_default().await?), + id: self.id, + psks: self.psks, + }) } /// Inject a new Pre Shared Key and Id into the User Builder From f17931e4d6c21835e5c39d6fe3a01b934fdb856f Mon Sep 17 00:00:00 2001 From: DyrellC Date: Mon, 30 May 2022 13:18:54 -0600 Subject: [PATCH 12/12] skip decrypting key in keyload if present --- streams/src/message/keyload.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/streams/src/message/keyload.rs b/streams/src/message/keyload.rs index fd33d6e7..5029463e 100644 --- a/streams/src/message/keyload.rs +++ b/streams/src/message/keyload.rs @@ -228,7 +228,9 @@ where let mut subscriber_id = Permissioned::::default(); fork.mask(&mut subscriber_id)?; - if subscriber_id.identifier() == &keyload.user_id.to_identifier() { + if key.is_some() { + fork.drop(KEY_SIZE + x25519::PUBLIC_KEY_LENGTH)?; + } else if subscriber_id.identifier() == &keyload.user_id.to_identifier() { fork.decrypt( keyload.user_id, &keyload.user_id._ke_sk().to_bytes(), @@ -250,16 +252,20 @@ where let mut psk_id = PskId::default(); fork.mask(&mut psk_id)?; - let mut masked_key = [0u8; KEY_SIZE]; - if let Some(psk) = keyload.psk_store.get(&psk_id) { - fork.absorb(External::new(&NBytes::new(psk)))? - .commit()? - .mask(NBytes::new(&mut masked_key))?; - key = Some(masked_key); - - keyload.psks.push(psk_id); - } else { + if key.is_some() { fork.drop(KEY_SIZE)?; + } else { + let mut masked_key = [0u8; KEY_SIZE]; + if let Some(psk) = keyload.psk_store.get(&psk_id) { + fork.absorb(External::new(&NBytes::new(psk)))? + .commit()? + .mask(NBytes::new(&mut masked_key))?; + key = Some(masked_key); + + keyload.psks.push(psk_id); + } else { + fork.drop(KEY_SIZE)?; + } } }