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

feat: add signature verification for delegated accounts #5255

Merged
merged 19 commits into from
Feb 19, 2025

Conversation

akaladarshi
Copy link
Contributor

@akaladarshi akaladarshi commented Feb 8, 2025

Summary of changes

Changes introduced in this pull request:

  • Add signature verification for delegated accounts

Reference issue to close (if applicable)

Closes #5242

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

@akaladarshi akaladarshi requested a review from a team as a code owner February 8, 2025 06:08
@akaladarshi akaladarshi requested review from lemmih and LesnyRumcajs and removed request for a team February 8, 2025 06:08
Copy link
Member

@LesnyRumcajs LesnyRumcajs left a comment

Choose a reason for hiding this comment

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

Thanks. Some technical comments, otherwise LGTM.

Comment on lines 225 to 238
if addr.protocol() != Delegated {
return Err(format!(
"cannot validate a delegated signature against a {} address expected",
addr.protocol(),
));
}

if signature.len() != SECP_SIG_LEN {
return Err(format!(
"invalid delegated signature length. Was {}, must be {}",
signature.len(),
SECP_SIG_LEN
));
}
Copy link
Member

Choose a reason for hiding this comment

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

nit: there's a nice macro anyhow::ensure that makes such validations more expressive.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

signature: &[u8],
data: &[u8],
addr: &crate::shim::address::Address,
) -> Result<(), String> {
Copy link
Member

Choose a reason for hiding this comment

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

Let's use anyhow::Result<()>. String itself should rarely be an error class.

Copy link
Contributor Author

@akaladarshi akaladarshi Feb 10, 2025

Choose a reason for hiding this comment

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

But then we will have to refactor existing functions: as you can see here.

Also the fvm_shared: verify_bls_sig, verify_secp256k1_sig returns Result<(), String>.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, it would need to be refactored, and it would be a good change. From briefly looking at the calls, it shouldn't be too complex.

The functions from fvm_shared should also be refactored (historical trivia: those were likely copied from Forest in 2021). However, given that it's a library's public interface, they should rather use a more constrained error type enumeration. Of course, refactoring ref-fvm methods is out of the scope of this issue, but it might be interesting to do so in the future.

Copy link
Contributor Author

@akaladarshi akaladarshi Feb 10, 2025

Choose a reason for hiding this comment

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

If that's the case then I will update the existing verify function to use anyhow and we can raise a separate issue for updating ref_evm functions.

Copy link
Member

Choose a reason for hiding this comment

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

Excellent, thanks @akaladarshi!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Comment on lines 250 to 255
// check address against recovered address
if rec_addr == *addr {
Ok(())
} else {
Err("Delegated signature verification failed".to_owned())
}
Copy link
Member

Choose a reason for hiding this comment

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

ensure! could be used here as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

@elmattic
Copy link
Contributor

@akaladarshi You can enable "format on save" in your favorite editor to prevent those pesky linter errors.

@LesnyRumcajs
Copy link
Member

@akaladarshi You can enable "format on save" in your favorite editor to prevent those pesky linter errors.

Either that or run make lint before submitting to ensure no lints fail during CI. You might need to install some additional tooling.

lint: license clean lint-clippy

@LesnyRumcajs
Copy link
Member

@akaladarshi, did you try running the node locally with your changes? If you look at the logs for calibnet RPC checks for Forest, you will see:

2025-02-11T16:20:30.441807Z WARN forest::chain_sync::tipset_syncer: Validating block [CID = bafy2bzacedyionjhebhdnqox3qd77vvdd3mvqrwhk27mqnvyl4tkr6qkzf6f2] in EPOCH = 2398815 failed: Validation error: Processing error: Error calculating weight: Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid=bafy2bzaceaepph3yqaewolhvxsgisqjctlse3qtled37khcofkgsny33uw7uu, state_root_version=unknown, Processing error: Could not update state: Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid=bafy2bzaceaepph3yqaewolhvxsgisqjctlse3qtled37khcofkgsny33uw7uu, state_root_version=unknown, Processing error: Failed to calculate state: Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid=bafy2bzaceaepph3yqaewolhvxsgisqjctlse3qtled37khcofkgsny33uw7uu, state_root_version=unknown, Validation error: Consensus error: StateManager error: Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid=bafy2bzaceaepph3yqaewolhvxsgisqjctlse3qtled37khcofkgsny33uw7uu, state_root_version=unknown, Consensus error: Power actor not found

@akaladarshi
Copy link
Contributor Author

@akaladarshi, did you try running the node locally with your changes? If you look at the logs for calibnet RPC checks for Forest, you will see:

2025-02-11T16:20:30.441807Z WARN forest::chain_sync::tipset_syncer: Validating block [CID = bafy2bzacedyionjhebhdnqox3qd77vvdd3mvqrwhk27mqnvyl4tkr6qkzf6f2] in EPOCH = 2398815 failed: Validation error: Processing error: Error calculating weight: Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid=bafy2bzaceaepph3yqaewolhvxsgisqjctlse3qtled37khcofkgsny33uw7uu, state_root_version=unknown, Processing error: Could not update state: Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid=bafy2bzaceaepph3yqaewolhvxsgisqjctlse3qtled37khcofkgsny33uw7uu, state_root_version=unknown, Processing error: Failed to calculate state: Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid=bafy2bzaceaepph3yqaewolhvxsgisqjctlse3qtled37khcofkgsny33uw7uu, state_root_version=unknown, Validation error: Consensus error: StateManager error: Can't create a valid state tree from the given root. This error may indicate unsupported version. state_root_cid=bafy2bzaceaepph3yqaewolhvxsgisqjctlse3qtled37khcofkgsny33uw7uu, state_root_version=unknown, Consensus error: Power actor not found

@LesnyRumcajs Yeah it was mentioned in the issue as well, that we are able to verify the signature by comparing with lotus signature but while syncing it's failing #5242 (comment)

@akaladarshi
Copy link
Contributor Author

I am looking into this behaviour only why it is happening.

@akaladarshi
Copy link
Contributor Author

@LesnyRumcajs Based on my investigation, I found out that there were few issues in how we were processing Ethereum tx -> Filecoin message vice versa i.e (method params was supposed to be encoded in CBOR). Also few functions were missing so I have updated the code accordingly. Please review the changes.

Meanwhile I will try to add few unit tests for the new changes.

@LesnyRumcajs
Copy link
Member

@LesnyRumcajs Based on my investigation, I found out that there were few issues in how we were processing Ethereum tx -> Filecoin message vice versa i.e (method params was supposed to be encoded in CBOR). Also few functions were missing so I have updated the code accordingly. Please review the changes.

Meanwhile I will try to add few unit tests for the new changes.

@elmattic would you mind looking taking a look?

@elmattic
Copy link
Contributor

@LesnyRumcajs Based on my investigation, I found out that there were few issues in how we were processing Ethereum tx -> Filecoin message vice versa i.e (method params was supposed to be encoded in CBOR). Also few functions were missing so I have updated the code accordingly. Please review the changes.
Meanwhile I will try to add few unit tests for the new changes.

@elmattic would you mind looking taking a look?

Of course.

@elmattic
Copy link
Contributor

@akaladarshi Looks like test_eip_1559 is failing.

@akaladarshi
Copy link
Contributor Author

@akaladarshi Looks like test_eip_1559 is failing.

I am looking into adding more unit tests and fixing/updating existing once, just wanted to get few comments on the changes.

Copy link
Contributor

@elmattic elmattic left a comment

Choose a reason for hiding this comment

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

Great work, looks good. Just a few nits, and consider adding tests for functions like verify_delegated_sig and authenticate_msg.

src/shim/crypto.rs Show resolved Hide resolved
src/shim/crypto.rs Outdated Show resolved Hide resolved
@elmattic
Copy link
Contributor

There are also a few small typos to fix, it's delegated, not delegate. For example:

fn delegate_sign() {

Search for occurrences of delegate_ in the codebase.

@akaladarshi
Copy link
Contributor Author

akaladarshi commented Feb 17, 2025

@elmattic one more thing, I guess test is failing because perviously we were checking self.chain_id != chain_id here , and which was working because in tests, since we are providing different chain id's ( ETH_CHAIN_ID should have been set as calibnet::ETH_CHAIN_ID because that's what we are expecting here)

@akaladarshi akaladarshi requested a review from elmattic February 18, 2025 19:31
@elmattic
Copy link
Contributor

@akaladarshi Great! Can you just fix the small lint error? Thanks! 🙏

@akaladarshi akaladarshi requested a review from elmattic February 19, 2025 09:39
let delegated_key_info = KeyInfo::new(SignatureType::Delegated, delegated_priv_key);
let delegated_key = Key::try_from(delegated_key_info).unwrap();
let addr = delegated_key.address;
println!("addr: {}", addr);
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
println!("addr: {}", addr);

leftover?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed.

msg: &SignedMessage,
addr: &crate::shim::address::Address,
) -> anyhow::Result<()> {
let mut sig = self.clone();
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need to clone the entire instance? Does it need to always be cloned?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

self is a Signature itself, cloning it, so we can update the signature bytes in line 157, without actually affecting the self.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

 match self.sig_type {
            SignatureType::Delegated => {
                ...
                let sig = Signature {
                    bytes: eth_tx.to_verifiable_signature(Vec::from(self.bytes()), eth_chain_id)?,
                    ..*self
                };
                let digest = eth_tx.rlp_unsigned_message(eth_chain_id)?;
                sig.verify(&digest, addr)
            }
            _ => {
                let digest = msg.message().cid().to_bytes();
                self.verify(&digest, addr)
            }
        }

@elmattic are you talking about something like this ?.

Copy link
Member

Choose a reason for hiding this comment

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

Let me re-phrase. Do you think cloning (a relatively costly operation; you need to heap-allocate the entire vector) is necessary in case the signature type is not Delegated (which is the case most of the time)?

Copy link
Contributor

@elmattic elmattic Feb 19, 2025

Choose a reason for hiding this comment

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

are you talking about something like this ?.

Yes, that's it, this will only clone in case of Delegated sig. and doing ..*self should be cheap here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@LesnyRumcajs Thanks for pointing it out, I think you're right it doesn't make sense at all. I will update it as per my last comment.

Copy link
Member

@LesnyRumcajs LesnyRumcajs left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@elmattic elmattic added this pull request to the merge queue Feb 19, 2025
Merged via the queue into ChainSafe:main with commit fb4f407 Feb 19, 2025
42 checks passed
@akaladarshi akaladarshi deleted the akaladarshi/delegated-verify branch February 19, 2025 16:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wallet signature is not working properly
3 participants