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

[SOLVED]: Why can't we verify through a CPI? #6

Open
code-brewer opened this issue Feb 20, 2024 · 8 comments
Open

[SOLVED]: Why can't we verify through a CPI? #6

code-brewer opened this issue Feb 20, 2024 · 8 comments
Labels
explanation Explanation on how this program works

Comments

@code-brewer
Copy link

  1. After read your check_ed25519_data function, I wonder, Isn't it suffice to do verify {msg, signature, pubkey} without IX data ? To my expecience on Ethereum, we can recover public key from signature, and compare it agaist pubkey

  2. Your Tx compose from 2 instructions, first one is sig verification IX. I think this first IX do verification also, then, why do we need to check sig again in second IX ?

@GuidoDipietro
Copy link
Owner

Hello! I will briefly explain how this works and hopefully that will help answer both questions:

In Solana, a program that can verify Ed25519 signatures exists. This program can indeed verify (message, signature, pubkey), validating that the private key associated to that public key produced that signature over the given message. This is common procedure and works just as you know from Ethereum.

You can see this part of the code here.

The problem is that this program can verify signatures, but we cannot invoke it from our own program through a CPI! (Or, at least, by the time I created this example, and I assume this is still the same).
As we cannot add a call such as ed25519::verify(msg, sig, pubkey)?; on our program, we can only add a separate instruction that calls it from the outside (that is, when crafting the transaction).

Now the question is: how can we add custom logic in our program in order to assert that the instruction that was added before is indeed one that helps us prove that the signature that we want to verify was indeed verified correctly?
Here is where instruction introspection joins the game, and why the code in check_ed25519_data (here) is so big.

What we are basically doing is sending this:

Transaction group {
   Instruction 1 - Ed25519 verification
   Instruction 2 - Custom program instruction (our program)
}

And checking from "Instruction 2" that "Instruction 1" has everything that we expect it to have.
By sending it in the same transaction group, we can guarantee that either both instructions will be executed or none will.

Therefore, we need to solve this problem: how do we check that a previous instruction in the group has what we expect it to?
The answer is we use instruction introspection and load the previous transaction in the group through the use of the Instructions Solana sysvar as shown in that link.

By doing that, we recover the raw Instruction, which is made of three fields:

pub struct Instruction {
    pub program_id: Pubkey,
    pub accounts: Vec<AccountMeta>,
    pub data: Vec<u8>,
}

By checking, then, those three fields (in verify_ed25519_ix), we can assert that somebody sent exactly the instruction we needed in the same group!

As checking the data is more cumbersome due to the deserialization involved in it, I abstracted it to a different function called check_ed25519_data which is the one you pointed out.

Now that you understand this, refer to the README.md where I explain the possible scenarios and why this actually works.

I understand this might be shocking to see. How can verifying a custom signature be so complicated?! But I guess the answer is: Solana is meant to be a torture device for developers.

If you need any further help let me know!

@GuidoDipietro GuidoDipietro added the explanation Explanation on how this program works label Feb 20, 2024
@GuidoDipietro GuidoDipietro changed the title Some questions for help, not bug. [HELP]: Why can't we verify through a CPI? Feb 20, 2024
@GuidoDipietro
Copy link
Owner

I edited the name of the issue to help anybody that is trying to find this. Hope you don't mind

@GuidoDipietro GuidoDipietro pinned this issue Feb 20, 2024
@GuidoDipietro GuidoDipietro changed the title [HELP]: Why can't we verify through a CPI? [SOLVED]: Why can't we verify through a CPI? Feb 20, 2024
@code-brewer
Copy link
Author

I edited the name of the issue to help anybody that is trying to find this. Hope you don't mind

Not at all. Thanks for your reply.

@code-brewer
Copy link
Author

@GuidoDipietro I have just try scep256k1 test on devnet, it failed.
Here is my client code: https://gist.github.com/code-brewer/8b7edd86a0c327341fa6aff18171f0d2 Major modification is change the person account to be the same as provider wallet, by this we got less chance be block the airdrop rate limited.
Could you please take trouble to test it?

@GuidoDipietro
Copy link
Owner

GuidoDipietro commented Feb 22, 2024

Hey.
This repo was quite outdated so I just revamped it a bit, bumping Anchor to 0.29.0 too.

As I did it my tests started failing since I was catching the error in a rather weird way.
I still don't know of a better way to do it, but the error message changed a bit.

See here how I changed it for my tests to work now. I think that you can do this to help yours run too.

Let me know!

@code-brewer
Copy link
Author

Yeah, it success after changing the error match content in assert.ok( error.logs.join('').includes('....') ); in test case.

@code-brewer
Copy link
Author

In past days, I was thinking about why we can do sig verification by invoke secp256k1_program or ed25519_program through CPI.
Finally I got one reason: the CPI call can not return value from callee, right?

@zfedoran
Copy link

@code-brewer I had the same question, if you dig into the solana source, you'll find that you can't invoke because it results in a no-op (even if you could). This is unfortunately by design, the pre-compiled programs run outside the svm.

For more info:
solana-labs/solana#19930
solana-labs/solana#19843

Also here:
https://0xhagen.medium.com/wtf-is-a-pre-compile-ddc3ac7442aa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
explanation Explanation on how this program works
Projects
None yet
Development

No branches or pull requests

3 participants