Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RecoverableEcdsaSignature #642

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev/gen_protos.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ if ! cargo install --list | grep "protoc-gen-prost-crate" > /dev/null; then
fi
fi

if ! buf generate https://github.com/xmtp/proto.git#branch=main,subdir=proto; then
if ! buf generate https://github.com/xmtp/proto.git#branch=nm/prototype-identity-apis,subdir=proto; then
echo "Failed to generate protobuf definitions"
exit 1
fi
Expand Down
25 changes: 12 additions & 13 deletions xmtp_id/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
[package]
edition = "2021"
name = "xmtp_id"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
async-trait.workspace = true
chrono.workspace = true
futures.workspace = true
hex.workspace = true
log.workspace = true
tracing.workspace = true
thiserror.workspace = true
xmtp_cryptography.workspace = true
xmtp_mls.workspace = true
xmtp_proto.workspace = true
openmls_traits.workspace = true
openmls.workspace = true
openmls_basic_credential.workspace = true
openmls_rust_crypto.workspace = true
openmls_traits.workspace = true
prost.workspace = true
chrono.workspace = true
rand.workspace = true
serde.workspace = true
async-trait.workspace = true
futures.workspace = true
sha2 = "0.10.8"
rand.workspace = true
hex.workspace = true

thiserror.workspace = true
tracing.workspace = true
xmtp_cryptography.workspace = true
xmtp_mls.workspace = true
xmtp_proto.workspace = true
42 changes: 37 additions & 5 deletions xmtp_id/src/associations/association_log.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
use super::hashes::generate_inbox_id;
use super::member::{Member, MemberIdentifier, MemberKind};
use super::serialization::{
from_identity_update_proto, to_identity_update_proto, DeserializationError, SerializationError,
};
use super::signature::{Signature, SignatureError, SignatureKind};
use super::state::AssociationState;

use thiserror::Error;
use xmtp_proto::xmtp::identity::associations::IdentityUpdate as IdentityUpdateProto;

#[derive(Debug, Error, PartialEq)]
pub enum AssociationError {
Expand All @@ -23,6 +27,8 @@ pub enum AssociationError {
LegacySignatureReuse,
#[error("The new member identifier does not match the signer")]
NewMemberIdSignatureMismatch,
#[error("Wrong inbox_id specified on association")]
WrongInboxId,
#[error("Signature not allowed for role {0:?} {1:?}")]
SignatureNotAllowed(String, String),
#[error("Replay detected")]
Expand Down Expand Up @@ -90,7 +96,7 @@ impl IdentityAction for CreateInbox {

/// AddAssociation Action
pub struct AddAssociation {
pub client_timestamp_ns: u64,
pub inbox_id: String,
pub new_member_signature: Box<dyn Signature>,
pub new_member_identifier: MemberIdentifier,
pub existing_member_signature: Box<dyn Signature>,
Expand All @@ -103,6 +109,7 @@ impl IdentityAction for AddAssociation {
) -> Result<AssociationState, AssociationError> {
let existing_state = maybe_existing_state.ok_or(AssociationError::NotCreated)?;
self.replay_check(&existing_state)?;
ensure_matching_inbox_id(&self.inbox_id, existing_state.inbox_id())?;

// Validate the new member signature and get the recovered signer
let new_member_address = self.new_member_signature.recover_signer()?;
Expand Down Expand Up @@ -187,7 +194,7 @@ impl IdentityAction for AddAssociation {

/// RevokeAssociation Action
pub struct RevokeAssociation {
pub client_timestamp_ns: u64,
pub inbox_id: String,
pub recovery_address_signature: Box<dyn Signature>,
pub revoked_member: MemberIdentifier,
}
Expand All @@ -199,6 +206,7 @@ impl IdentityAction for RevokeAssociation {
) -> Result<AssociationState, AssociationError> {
let existing_state = maybe_existing_state.ok_or(AssociationError::NotCreated)?;
self.replay_check(&existing_state)?;
ensure_matching_inbox_id(&self.inbox_id, existing_state.inbox_id())?;

if is_legacy_signature(&self.recovery_address_signature) {
return Err(AssociationError::SignatureNotAllowed(
Expand Down Expand Up @@ -240,7 +248,7 @@ impl IdentityAction for RevokeAssociation {

/// ChangeRecoveryAddress Action
pub struct ChangeRecoveryAddress {
pub client_timestamp_ns: u64,
pub inbox_id: String,
pub recovery_address_signature: Box<dyn Signature>,
pub new_recovery_address: String,
}
Expand All @@ -252,6 +260,7 @@ impl IdentityAction for ChangeRecoveryAddress {
) -> Result<AssociationState, AssociationError> {
let existing_state = existing_state.ok_or(AssociationError::NotCreated)?;
self.replay_check(&existing_state)?;
ensure_matching_inbox_id(&self.inbox_id, existing_state.inbox_id())?;

if is_legacy_signature(&self.recovery_address_signature) {
return Err(AssociationError::SignatureNotAllowed(
Expand Down Expand Up @@ -306,12 +315,24 @@ impl IdentityAction for Action {

/// An `IdentityUpdate` contains one or more Actions that can be applied to the AssociationState
pub struct IdentityUpdate {
pub client_timestamp_ns: u64,
pub actions: Vec<Action>,
}

impl IdentityUpdate {
pub fn new(actions: Vec<Action>) -> Self {
Self { actions }
pub fn new(actions: Vec<Action>, client_timestamp_ns: u64) -> Self {
Self {
actions,
client_timestamp_ns,
}
}

pub fn to_proto(&self) -> Result<IdentityUpdateProto, SerializationError> {
to_identity_update_proto(self)
}

pub fn from_proto(proto: IdentityUpdateProto) -> Result<Self, DeserializationError> {
from_identity_update_proto(proto)
}
}

Expand Down Expand Up @@ -362,6 +383,17 @@ fn allowed_association(
Ok(())
}

fn ensure_matching_inbox_id(
action_inbox_id: &String,
state_inbox_id: &String,
) -> Result<(), AssociationError> {
if action_inbox_id.ne(state_inbox_id) {
return Err(AssociationError::WrongInboxId);
}

Ok(())
}

// Ensure that the type of signature matches the new entity's role.
fn allowed_signature_for_kind(
role: &MemberKind,
Expand Down
Loading
Loading