Skip to content

Commit

Permalink
Add signature verification methods (#1050)
Browse files Browse the repository at this point in the history
## tl;dr

- Implements part of #1033
- Sets up the infrastructure for verifying `UnverifiedSignature`s from `UnverifiedIdentityUpdate`s
  • Loading branch information
neekolas committed Sep 11, 2024
1 parent 328e4e3 commit dacdf4f
Show file tree
Hide file tree
Showing 4 changed files with 341 additions and 67 deletions.
1 change: 1 addition & 0 deletions xmtp_id/src/associations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod state;
pub mod test_utils;
pub mod unsigned_actions;
mod unverified;
mod verified_signature;

pub use self::association_log::*;
pub use self::hashes::generate_inbox_id;
Expand Down
68 changes: 5 additions & 63 deletions xmtp_id/src/associations/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,6 @@ impl std::fmt::Display for SignatureKind {
}
}

#[derive(Debug, Clone)]
pub struct VerifiedSignature {
pub signer: MemberIdentifier,
pub kind: SignatureKind,
pub raw_bytes: Vec<u8>,
}

impl VerifiedSignature {
pub fn new(signer: MemberIdentifier, kind: SignatureKind, raw_bytes: Vec<u8>) -> Self {
Self {
signer,
kind,
raw_bytes,
}
}
}

#[async_trait]
pub trait Signature: SignatureClone + std::fmt::Debug + Send + Sync + 'static {
async fn recover_signer(&self) -> Result<MemberIdentifier, SignatureError>;
Expand Down Expand Up @@ -347,8 +330,8 @@ impl Signature for InstallationKeySignature {

#[derive(Debug, Clone)]
pub struct LegacyDelegatedSignature {
legacy_key_signature: RecoverableEcdsaSignature, // signature from the legacy key(delegatee)
signed_public_key_proto: LegacySignedPublicKeyProto, // signature from the wallet(delegator)
pub(crate) legacy_key_signature: RecoverableEcdsaSignature, // signature from the legacy key(delegatee)
pub(crate) signed_public_key_proto: LegacySignedPublicKeyProto, // signature from the wallet(delegator)
}

impl LegacyDelegatedSignature {
Expand Down Expand Up @@ -499,52 +482,9 @@ mod tests {

use prost::Message;
use sha2::{Digest, Sha512};
use xmtp_proto::xmtp::message_contents::SignedPublicKey as LegacySignedPublicKeyProto;
use xmtp_v2::k256_helper::sign_sha256;

#[test]
fn validate_good_key_round_trip() {
let proto_bytes = vec![
10, 79, 8, 192, 195, 165, 174, 203, 153, 231, 213, 23, 26, 67, 10, 65, 4, 216, 84, 174,
252, 198, 225, 219, 168, 239, 166, 62, 233, 206, 108, 53, 155, 87, 132, 8, 43, 91, 36,
91, 81, 93, 213, 67, 241, 69, 5, 31, 249, 186, 129, 119, 144, 4, 44, 54, 76, 185, 95,
61, 23, 231, 72, 7, 169, 18, 70, 113, 79, 173, 82, 13, 37, 146, 201, 43, 174, 180, 33,
125, 43, 18, 70, 18, 68, 10, 64, 7, 136, 100, 172, 155, 247, 230, 255, 253, 247, 78,
50, 212, 226, 41, 78, 239, 183, 136, 247, 122, 88, 155, 245, 219, 183, 215, 202, 42,
89, 162, 128, 96, 96, 120, 131, 17, 70, 38, 231, 2, 27, 91, 29, 66, 110, 128, 140, 1,
42, 217, 185, 2, 181, 208, 100, 143, 143, 219, 159, 174, 1, 233, 191, 16, 1,
];
let account_address = "0x220ca99fb7fafa18cb623d924794dde47b4bc2e9";

let proto = LegacySignedPublicKeyProto::decode(proto_bytes.as_slice()).unwrap();
let validated_key = ValidatedLegacySignedPublicKey::try_from(proto)
.expect("Key should validate successfully");
let proto: LegacySignedPublicKeyProto = validated_key.into();
let validated_key = ValidatedLegacySignedPublicKey::try_from(proto)
.expect("Key should still validate successfully");
assert_eq!(validated_key.account_address(), account_address);
}

#[test]
fn validate_malformed_key() {
let proto_bytes = vec![
10, 79, 8, 192, 195, 165, 174, 203, 153, 231, 213, 23, 26, 67, 10, 65, 4, 216, 84, 174,
252, 198, 225, 219, 168, 239, 166, 62, 233, 206, 108, 53, 155, 87, 132, 8, 43, 91, 36,
91, 81, 93, 213, 67, 241, 69, 5, 31, 249, 186, 129, 119, 144, 4, 44, 54, 76, 185, 95,
61, 23, 231, 72, 7, 169, 18, 70, 113, 79, 173, 82, 13, 37, 146, 201, 43, 174, 180, 33,
125, 43, 18, 70, 18, 68, 10, 64, 7, 136, 100, 172, 155, 247, 230, 255, 253, 247, 78,
50, 212, 226, 41, 78, 239, 183, 136, 247, 122, 88, 155, 245, 219, 183, 215, 202, 42,
89, 162, 128, 96, 96, 120, 131, 17, 70, 38, 231, 2, 27, 91, 29, 66, 110, 128, 140, 1,
42, 217, 185, 2, 181, 208, 100, 143, 143, 219, 159, 174, 1, 233, 191, 16, 1,
];
let mut proto = LegacySignedPublicKeyProto::decode(proto_bytes.as_slice()).unwrap();
proto.key_bytes[0] += 1; // Corrupt the serialized key data
assert!(matches!(
ValidatedLegacySignedPublicKey::try_from(proto),
Err(super::SignatureError::Invalid)
));
}

// TODO:nm delete once fully deprecated
#[tokio::test]
async fn recover_signer_ecdsa() {
let wallet: LocalWallet = LocalWallet::new(&mut rand::thread_rng());
Expand Down Expand Up @@ -581,6 +521,7 @@ mod tests {
assert_eq!(expected, actual);
}

// TODO:nm delete once fully deprecated
#[tokio::test]
async fn recover_signer_installation() {
let signing_key: SigningKey = SigningKey::generate(&mut rand::thread_rng());
Expand All @@ -605,6 +546,7 @@ mod tests {
assert_eq!(expected, actual);
}

// TODO:nm delete once fully deprecated
// Test the happy path with LocalWallet & fail path with a secp256k1 signer.
#[tokio::test]
async fn recover_signer_legacy() {
Expand Down
33 changes: 29 additions & 4 deletions xmtp_id/src/associations/unverified.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ use super::{
UnsignedChangeRecoveryAddress, UnsignedCreateInbox, UnsignedIdentityUpdate,
UnsignedRevokeAssociation,
},
AccountId, SignatureError, VerifiedSignature,
verified_signature::VerifiedSignature,
AccountId, SignatureError,
};
use xmtp_proto::xmtp::message_contents::SignedPublicKey as LegacySignedPublicKeyProto;

Expand Down Expand Up @@ -129,10 +130,34 @@ pub enum UnverifiedSignature {
impl UnverifiedSignature {
async fn to_verified(
&self,
_signature_text: String,
_scw_verifier: &dyn SmartContractSignatureVerifier,
signature_text: String,
scw_verifier: &dyn SmartContractSignatureVerifier,
) -> Result<VerifiedSignature, SignatureError> {
todo!("not implemented")
match self {
UnverifiedSignature::InstallationKey(sig) => VerifiedSignature::from_installation_key(
signature_text,
&sig.signature_bytes,
&sig.verifying_key,
),
UnverifiedSignature::RecoverableEcdsa(sig) => {
VerifiedSignature::from_recoverable_ecdsa(signature_text, &sig.signature_bytes)
}
UnverifiedSignature::Erc6492(sig) => {
VerifiedSignature::from_smart_contract_wallet(
signature_text,
scw_verifier,
&sig.signature_bytes,
sig.account_id.clone(),
sig.block_number,
)
.await
}
UnverifiedSignature::LegacyDelegated(sig) => VerifiedSignature::from_legacy_delegated(
signature_text,
&sig.legacy_key_signature.signature_bytes,
sig.signed_public_key_proto.clone(),
),
}
}
}

Expand Down
Loading

0 comments on commit dacdf4f

Please sign in to comment.