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

Fix legacy key recovery. #775

Merged
merged 6 commits into from
May 28, 2024
Merged

Fix legacy key recovery. #775

merged 6 commits into from
May 28, 2024

Conversation

37ng
Copy link
Contributor

@37ng 37ng commented May 23, 2024

Resolves this comment.

Derive address from legacy public key(instead of recovering the signature) and make sure it matches the address of the wallet that signed the legacy key.

Use ethers::LocalWallet to sign the message so that EIP-191 is abstracted away, which is the reason current signature cannot be recovered properly.

Moved sign_with_legacy_key from xmtp_mls to xmtp_id so that we can use it in tests without introducing circular dependencies.

@37ng 37ng added the inbox-id Support for Inbox ID label May 23, 2024
@37ng 37ng requested a review from a team as a code owner May 23, 2024 20:15
@37ng 37ng requested a review from neekolas May 23, 2024 20:15
@37ng 37ng changed the title Complete LegacyDelegatedSignature ::recover_signer & fix sign_with_legacy_key Fix recover_signer & sign_with_legacy_key May 23, 2024
@37ng 37ng mentioned this pull request May 23, 2024
Base automatically changed from identity-release to main May 24, 2024 20:33
@37ng 37ng force-pushed the 37ng/fix-sign branch from e2588c2 to 77cf853 Compare May 28, 2024 18:54
@37ng 37ng changed the title Fix recover_signer & sign_with_legacy_key Fix legacy key recovery. May 28, 2024
Comment on lines +395 to +397
let wallet: LocalWallet = hex::encode(legacy_private_key).parse::<LocalWallet>()?;
let signature = wallet.sign_message(signature_text.clone()).await?;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the old logic:

    let legacy_private_key = secp256k1.bytes;
    let (mut delegating_signature, recovery_id) = k256_helper::sign_sha256(
        &legacy_private_key, // secret_key
        // TODO: Verify this will create a verifiable signature
        signature_text.as_bytes(), // message
    )
    .map_err(IdentityError::LegacySignature)?;
    delegating_signature.push(recovery_id); // TODO: normalize recovery ID if necessary

Out of curiosity, what is the reason we need to change this to construct a LocalWallet out of the legacy_private_key here?

Copy link
Contributor Author

@37ng 37ng May 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because LocalWallet wraps the signature_text with EIP-191 text while old logic doesn't. EIP-191 is implemented by evm wallet like Metamask. If EIP-191 is not included here, we won't be able to recover the signature to the signer address properly.

We can add the EIP-191 to the old logic, but I feel it's better to abstract away EIP-191 from our codebase.

Copy link
Contributor Author

@37ng 37ng May 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ethers crate source code to add EIP-191 during signing, note the hash_message is used here and also in recovery logic.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhh that explains a lot, thank you!

@@ -183,7 +183,7 @@ mod tests {
async fn legacy_keys() {
// This test is supposed to be run with a fresh state where account_address has not been registered.
// Subsequent runs will use a different code path.
let account_address = "0x0bD00B21aF9a2D538103c3AAf95Cb507f8AF1B28".to_lowercase();
let account_address = "0x0bd00b21af9a2d538103c3aaf95cb507f8af1b28";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this test fail if we leave it with a mix of upper and lower case? It might almost be better to test it without normalizing the address

Copy link
Contributor Author

@37ng 37ng May 28, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes the current use of strings for account addresses is a bit hacky and I'm planning to replace all account addresses with ethers::types::Address which is a byte array with necessary type conversion logics. I think it'd be a better canonical type than string or lower case string.

Before we do that, I'm ok to leave these as is since they won't be used anyways. wdty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To answer your question, yes the test will fail because we have to_lowercase() all over the code base now.

xmtp_id/src/associations/signature.rs Show resolved Hide resolved
@37ng 37ng requested a review from richardhuaaa May 28, 2024 21:35
Copy link
Contributor

@richardhuaaa richardhuaaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! The changes to signing and verification are likely breaking changes - do we need to reset the dev network and/or give a heads up?

@37ng
Copy link
Contributor Author

37ng commented May 28, 2024

Looks good! The changes to signing and verification are likely breaking changes - do we need to reset the dev network and/or give a heads up?

I think we already use EIP-191 to sign & recover, LocalWallet is wrapped in InboxOwner. code here

Also we are using a new RecoverableEcdsaSignature instead of the old RecoverableSignature, which uses EIP191 nevertheless.

@richardhuaaa

@37ng 37ng merged commit 0237623 into main May 28, 2024
6 checks passed
@37ng 37ng deleted the 37ng/fix-sign branch May 28, 2024 22:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
inbox-id Support for Inbox ID
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants