From af002f818564b786eb70889d73ff4f3d23afe502 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 30 Oct 2024 22:32:31 -0400 Subject: [PATCH 1/6] feat(libp2p): multi signature schemes & session signing --- crates/torii/libp2p/src/errors.rs | 4 + crates/torii/libp2p/src/server/mod.rs | 104 ++++++++++++++++++-------- crates/torii/libp2p/src/tests.rs | 4 +- crates/torii/libp2p/src/types.rs | 15 +++- 4 files changed, 93 insertions(+), 34 deletions(-) diff --git a/crates/torii/libp2p/src/errors.rs b/crates/torii/libp2p/src/errors.rs index 72cff2e808..ec615b88d7 100644 --- a/crates/torii/libp2p/src/errors.rs +++ b/crates/torii/libp2p/src/errors.rs @@ -4,6 +4,7 @@ use std::io; use libp2p::gossipsub::{PublishError, SubscriptionError}; #[cfg(not(target_arch = "wasm32"))] use libp2p::noise; +use starknet::providers::ProviderError; use thiserror::Error; #[derive(Error, Debug)] @@ -45,4 +46,7 @@ pub enum Error { #[error("Invalid type provided: {0}")] InvalidTypeError(String), + + #[error(transparent)] + ProviderError(#[from] ProviderError), } diff --git a/crates/torii/libp2p/src/server/mod.rs b/crates/torii/libp2p/src/server/mod.rs index 5682c8ac54..45ece6ebcd 100644 --- a/crates/torii/libp2p/src/server/mod.rs +++ b/crates/torii/libp2p/src/server/mod.rs @@ -38,7 +38,7 @@ mod events; use crate::server::events::ServerEvent; use crate::typed_data::{parse_value_to_ty, PrimitiveType, TypedData}; -use crate::types::Message; +use crate::types::{Message, Signature, TypedDataHash}; pub(crate) const LOG_TARGET: &str = "torii::relay::server"; @@ -302,37 +302,15 @@ impl Relay

{ // to prevent replay attacks. // Verify the signature - let message_hash = - if let Ok(message) = data.message.encode(entity_identity) { - message - } else { - info!( - target: LOG_TARGET, - "Encoding message." - ); - continue; - }; - - let mut calldata = vec![message_hash]; - calldata.push(Felt::from(data.signature.len())); - - calldata.extend(data.signature); - if !match self - .provider - .call( - FunctionCall { - contract_address: entity_identity, - entry_point_selector: get_selector_from_name( - "is_valid_signature", - ) - .unwrap(), - calldata, - }, - BlockId::Tag(BlockTag::Pending), - ) - .await + if !match validate_signature( + &self.provider, + entity_identity, + &data.message, + &data.signature, + ) + .await { - Ok(res) => res[0] != Felt::ZERO, + Ok(res) => res, Err(e) => { warn!( target: LOG_TARGET, @@ -432,6 +410,70 @@ impl Relay

{ } } +async fn validate_signature( + provider: &P, + entity_identity: Felt, + message: &TypedData, + signature: &Signature, +) -> Result { + match signature { + Signature::Starknet(signature) => { + let message_hash = message.encode(entity_identity)?; + + let calldata = vec![message_hash, signature.0, signature.1]; + provider + .call( + FunctionCall { + contract_address: entity_identity, + entry_point_selector: get_selector_from_name("is_valid_signature").unwrap(), + calldata, + }, + BlockId::Tag(BlockTag::Pending), + ) + .await + .map_err(Error::ProviderError) + .map(|res| res[0] != Felt::ZERO) + } + Signature::Webauthn(signature) => { + let message_hash = message.encode(entity_identity)?; + let mut calldata = vec![message_hash, Felt::from(signature.len())]; + calldata.extend(signature); + provider + .call( + FunctionCall { + contract_address: entity_identity, + entry_point_selector: get_selector_from_name("is_valid_signature").unwrap(), + calldata, + }, + BlockId::Tag(BlockTag::Pending), + ) + .await + .map_err(Error::ProviderError) + .map(|res| res[0] != Felt::ZERO) + } + Signature::Session(signature) => { + let mut calldata = vec![]; + signature.0.iter().for_each(|TypedDataHash { type_hash, typed_data_hash }| { + calldata.extend_from_slice(&[*type_hash, *typed_data_hash]); + }); + calldata.extend_from_slice(&signature.1); + provider + .call( + FunctionCall { + contract_address: entity_identity, + entry_point_selector: get_selector_from_name("is_session_sigature_valid") + .unwrap(), + calldata, + }, + BlockId::Tag(BlockTag::Pending), + ) + .await + .map_err(Error::ProviderError) + .map(|res| res[0] != Felt::ZERO) + } + } +} + fn ty_keys(ty: &Ty) -> Result, Error> { if let Ty::Struct(s) = &ty { let mut keys = Vec::new(); diff --git a/crates/torii/libp2p/src/tests.rs b/crates/torii/libp2p/src/tests.rs index e862f11667..bb80d179ad 100644 --- a/crates/torii/libp2p/src/tests.rs +++ b/crates/torii/libp2p/src/tests.rs @@ -545,7 +545,7 @@ mod test { use crate::server::Relay; use crate::typed_data::{Domain, Field, SimpleField, TypedData}; - use crate::types::Message; + use crate::types::{Message, Signature}; let _ = tracing_subscriber::fmt() .with_env_filter("torii::relay::client=debug,torii::relay::server=debug") @@ -683,7 +683,7 @@ mod test { client .command_sender - .publish(Message { message: typed_data, signature: vec![signature.r, signature.s] }) + .publish(Message { message: typed_data, signature: Signature::Starknet((signature.r, signature.s)) }) .await?; sleep(std::time::Duration::from_secs(2)).await; diff --git a/crates/torii/libp2p/src/types.rs b/crates/torii/libp2p/src/types.rs index 1122f046fe..d2f2f999d1 100644 --- a/crates/torii/libp2p/src/types.rs +++ b/crates/torii/libp2p/src/types.rs @@ -3,8 +3,21 @@ use starknet::core::types::Felt; use crate::typed_data::TypedData; +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TypedDataHash { + pub type_hash: Felt, + pub typed_data_hash: Felt, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum Signature { + Webauthn(Vec), + Starknet((Felt, Felt)), + Session((Vec, Vec)), +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Message { pub message: TypedData, - pub signature: Vec, + pub signature: Signature, } From e0801fa209eeb6af64b5febf28b4596ab0766af1 Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 30 Oct 2024 22:41:15 -0400 Subject: [PATCH 2/6] clean up session sig scheme --- crates/torii/libp2p/src/server/mod.rs | 19 +++++++++++-------- crates/torii/libp2p/src/types.rs | 8 +------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/crates/torii/libp2p/src/server/mod.rs b/crates/torii/libp2p/src/server/mod.rs index 45ece6ebcd..3f14f7885b 100644 --- a/crates/torii/libp2p/src/server/mod.rs +++ b/crates/torii/libp2p/src/server/mod.rs @@ -37,8 +37,8 @@ use crate::errors::Error; mod events; use crate::server::events::ServerEvent; -use crate::typed_data::{parse_value_to_ty, PrimitiveType, TypedData}; -use crate::types::{Message, Signature, TypedDataHash}; +use crate::typed_data::{encode_type, parse_value_to_ty, PrimitiveType, TypedData}; +use crate::types::{Message, Signature}; pub(crate) const LOG_TARGET: &str = "torii::relay::server"; @@ -416,6 +416,8 @@ async fn validate_signature( message: &TypedData, signature: &Signature, ) -> Result { + let message_hash = message.encode(entity_identity)?; + match signature { Signature::Starknet(signature) => { let message_hash = message.encode(entity_identity)?; @@ -435,7 +437,6 @@ async fn validate_signature( .map(|res| res[0] != Felt::ZERO) } Signature::Webauthn(signature) => { - let message_hash = message.encode(entity_identity)?; let mut calldata = vec![message_hash, Felt::from(signature.len())]; calldata.extend(signature); provider @@ -452,11 +453,13 @@ async fn validate_signature( .map(|res| res[0] != Felt::ZERO) } Signature::Session(signature) => { - let mut calldata = vec![]; - signature.0.iter().for_each(|TypedDataHash { type_hash, typed_data_hash }| { - calldata.extend_from_slice(&[*type_hash, *typed_data_hash]); - }); - calldata.extend_from_slice(&signature.1); + let mut calldata = vec![ + get_selector_from_name(&encode_type(&message.primary_type, &message.types)?).map_err( + |e| Error::InvalidMessageError(e.to_string()), + )?, + message_hash, + ]; + calldata.extend_from_slice(&signature); provider .call( FunctionCall { diff --git a/crates/torii/libp2p/src/types.rs b/crates/torii/libp2p/src/types.rs index d2f2f999d1..982cfca056 100644 --- a/crates/torii/libp2p/src/types.rs +++ b/crates/torii/libp2p/src/types.rs @@ -3,17 +3,11 @@ use starknet::core::types::Felt; use crate::typed_data::TypedData; -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct TypedDataHash { - pub type_hash: Felt, - pub typed_data_hash: Felt, -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Signature { Webauthn(Vec), Starknet((Felt, Felt)), - Session((Vec, Vec)), + Session(Vec), } #[derive(Debug, Clone, Serialize, Deserialize)] From 513a5bcea13eeb26bbceac1aef5bed8d3a28388a Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 30 Oct 2024 22:44:19 -0400 Subject: [PATCH 3/6] fmt --- crates/torii/libp2p/src/server/mod.rs | 5 ++--- crates/torii/libp2p/src/tests.rs | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/torii/libp2p/src/server/mod.rs b/crates/torii/libp2p/src/server/mod.rs index 3f14f7885b..99a706e586 100644 --- a/crates/torii/libp2p/src/server/mod.rs +++ b/crates/torii/libp2p/src/server/mod.rs @@ -454,9 +454,8 @@ async fn validate_signature( } Signature::Session(signature) => { let mut calldata = vec![ - get_selector_from_name(&encode_type(&message.primary_type, &message.types)?).map_err( - |e| Error::InvalidMessageError(e.to_string()), - )?, + get_selector_from_name(&encode_type(&message.primary_type, &message.types)?) + .map_err(|e| Error::InvalidMessageError(e.to_string()))?, message_hash, ]; calldata.extend_from_slice(&signature); diff --git a/crates/torii/libp2p/src/tests.rs b/crates/torii/libp2p/src/tests.rs index bb80d179ad..fbda28c05d 100644 --- a/crates/torii/libp2p/src/tests.rs +++ b/crates/torii/libp2p/src/tests.rs @@ -683,7 +683,10 @@ mod test { client .command_sender - .publish(Message { message: typed_data, signature: Signature::Starknet((signature.r, signature.s)) }) + .publish(Message { + message: typed_data, + signature: Signature::Starknet((signature.r, signature.s)), + }) .await?; sleep(std::time::Duration::from_secs(2)).await; From 857009275b4cb4851a2988b376d251c2f647262b Mon Sep 17 00:00:00 2001 From: Nasr Date: Wed, 30 Oct 2024 22:45:06 -0400 Subject: [PATCH 4/6] chore --- crates/torii/libp2p/src/server/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/torii/libp2p/src/server/mod.rs b/crates/torii/libp2p/src/server/mod.rs index 99a706e586..ab65a6bd6b 100644 --- a/crates/torii/libp2p/src/server/mod.rs +++ b/crates/torii/libp2p/src/server/mod.rs @@ -458,7 +458,7 @@ async fn validate_signature( .map_err(|e| Error::InvalidMessageError(e.to_string()))?, message_hash, ]; - calldata.extend_from_slice(&signature); + calldata.extend(signature); provider .call( FunctionCall { From 4073ce78de026454c07d20c4094776e0950ed236 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 31 Oct 2024 14:56:08 -0400 Subject: [PATCH 5/6] fix: tests --- crates/torii/libp2p/src/server/mod.rs | 19 +------------------ crates/torii/libp2p/src/tests.rs | 2 +- crates/torii/libp2p/src/types.rs | 3 +-- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/crates/torii/libp2p/src/server/mod.rs b/crates/torii/libp2p/src/server/mod.rs index ab65a6bd6b..da0f49db58 100644 --- a/crates/torii/libp2p/src/server/mod.rs +++ b/crates/torii/libp2p/src/server/mod.rs @@ -419,24 +419,7 @@ async fn validate_signature( let message_hash = message.encode(entity_identity)?; match signature { - Signature::Starknet(signature) => { - let message_hash = message.encode(entity_identity)?; - - let calldata = vec![message_hash, signature.0, signature.1]; - provider - .call( - FunctionCall { - contract_address: entity_identity, - entry_point_selector: get_selector_from_name("is_valid_signature").unwrap(), - calldata, - }, - BlockId::Tag(BlockTag::Pending), - ) - .await - .map_err(Error::ProviderError) - .map(|res| res[0] != Felt::ZERO) - } - Signature::Webauthn(signature) => { + Signature::Account(signature) => { let mut calldata = vec![message_hash, Felt::from(signature.len())]; calldata.extend(signature); provider diff --git a/crates/torii/libp2p/src/tests.rs b/crates/torii/libp2p/src/tests.rs index fbda28c05d..e033d6c5fb 100644 --- a/crates/torii/libp2p/src/tests.rs +++ b/crates/torii/libp2p/src/tests.rs @@ -685,7 +685,7 @@ mod test { .command_sender .publish(Message { message: typed_data, - signature: Signature::Starknet((signature.r, signature.s)), + signature: Signature::Account(vec![signature.r, signature.s]), }) .await?; diff --git a/crates/torii/libp2p/src/types.rs b/crates/torii/libp2p/src/types.rs index 982cfca056..f4c3bfce15 100644 --- a/crates/torii/libp2p/src/types.rs +++ b/crates/torii/libp2p/src/types.rs @@ -5,8 +5,7 @@ use crate::typed_data::TypedData; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Signature { - Webauthn(Vec), - Starknet((Felt, Felt)), + Account(Vec), Session(Vec), } From d6ad202717985ff2bdf7d94b56195f3a02a8e0d2 Mon Sep 17 00:00:00 2001 From: Nasr Date: Thu, 31 Oct 2024 15:00:23 -0400 Subject: [PATCH 6/6] fix: session sig --- crates/torii/libp2p/src/server/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/torii/libp2p/src/server/mod.rs b/crates/torii/libp2p/src/server/mod.rs index da0f49db58..85b81ade16 100644 --- a/crates/torii/libp2p/src/server/mod.rs +++ b/crates/torii/libp2p/src/server/mod.rs @@ -437,9 +437,11 @@ async fn validate_signature( } Signature::Session(signature) => { let mut calldata = vec![ + Felt::ONE, get_selector_from_name(&encode_type(&message.primary_type, &message.types)?) .map_err(|e| Error::InvalidMessageError(e.to_string()))?, message_hash, + signature.len().into(), ]; calldata.extend(signature); provider