Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Unify circuit types names and interfaces #937

Merged
merged 1 commit into from
Nov 30, 2022
Merged

Conversation

ed255
Copy link
Member

@ed255 ed255 commented Nov 25, 2022

Given a circuit Foo:

  • Unify the struct that contains the columns to FooCircuitConfig
  • Unify the struct that contains the witness to FooCircuit
  • Unify the config constructor to FooCircuitConfig::new, following the new SubCircuitConfig trait
  • Unify the creation of a circuit from a block to FooCircuit::new_from_block following the new SubCircuit trait
  • Unify the loading of fixed internal tables to load_aux_tables
  • Unify the synthesis step of subcircuits to synthesize_sub following the new SubCircuit trait
  • Remove generic associated const from circuit+config types as much as possible - Only possible in TxCircuit. Not possible in PiCircuit due to halo2 Circuit trait
  • Implement the Circuit trait to all subcircuits uniformly
  • Move circuit tunning parameters to CircuitParams so that they can be taken from a single source
  • Add an instance function to all circuits following the new SubCircuit trait

@github-actions github-actions bot added crate-bus-mapping Issues related to the bus-mapping workspace member crate-circuit-benchmarks Issues related to the circuit-benchmarks workspace member crate-eth-types Issues related to the eth-types workspace member crate-integration-tests Issues related to the integration-tests workspace member crate-zkevm-circuits Issues related to the zkevm-circuits workspace member T-bench Type: benchmark improvements labels Nov 25, 2022
@ed255 ed255 force-pushed the feature/unify-circuits branch from d67ad20 to 3355b4d Compare November 25, 2022 16:21
@ed255 ed255 requested review from lispc and pinkiebell November 25, 2022 16:51
@ed255
Copy link
Member Author

ed255 commented Nov 25, 2022

Currently some testool unit tests are failing with the error EthTypeError(Signature(InvalidSignature)). I've added the calculation of all the keccak inputs in the witness::block_convert (so that all circuits can consume the witness from a single source), which requires processing the transactions signatures. I believe the failing tests in the testool have invalid signatures (which were not processed before), and that's why they are failing.

The rest of the tests should be passing.

Please if you have some time, take a look at the changes made and comment if you agree with this proposal or open a discussion to change! Basically I've added this new traits and implemented them for all subcircuits:

/// SubCircuit is a circuit that performs the verification of a specific part of
/// the full Ethereum block verification.  The SubCircuit's interact with each
/// other via lookup tables and/or shared public inputs.  This type must contain
/// all the inputs required to synthesize this circuit (and the contained
/// table(s) if any).
pub trait SubCircuit<F: Field> {
    /// Configuration of the SubCircuit.
    type Config: SubCircuitConfig<F>;

    /// Create a new SubCircuit from a witness Block
    fn new_from_block(block: &witness::Block<F>) -> Self;

    /// Returns the instance columns required for this circuit.
    fn instance(&self) -> Vec<Vec<F>> {
        vec![]
    }
    /// Assign only the columns used by this sub-circuit.  This includes the
    /// columns that belong to the exposed lookup table contained within, if
    /// any; and excludes external tables that this sub-circuit does lookups
    /// to.
    fn synthesize_sub(
        &self,
        config: &Self::Config,
        challenges: &Challenges<Value<F>>,
        layouter: &mut impl Layouter<F>,
    ) -> Result<(), Error>;
}

/// SubCircuit configuration
pub trait SubCircuitConfig<F: Field> {
    /// Config constructor arguments
    type ConfigArgs;

    /// Type constructor
    fn new(meta: &mut ConstraintSystem<F>, args: Self::ConfigArgs) -> Self;
}

@ed255 ed255 force-pushed the feature/unify-circuits branch from 51f681b to f2dca8f Compare November 25, 2022 17:01
Copy link
Contributor

@pinkiebell pinkiebell left a comment

Choose a reason for hiding this comment

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

Looks great so far 💪 . This will simplify a lot and I hope we can get rid of const generics in the future too 😁

zkevm-circuits/src/tx_circuit.rs Outdated Show resolved Hide resolved
zkevm-circuits/src/witness/block.rs Outdated Show resolved Hide resolved
zkevm-circuits/Cargo.toml Show resolved Hide resolved
zkevm-circuits/src/super_circuit.rs Show resolved Hide resolved
@pinkiebell
Copy link
Contributor

Currently some testool unit tests are failing with the error EthTypeError(Signature(InvalidSignature))

Yes, I think the ethereum tests suite include invalid signatures too. So we must handle those somehow

@adria0
Copy link
Member

adria0 commented Nov 29, 2022

It seems a very good interface @ed255 !

Let's me try to check what's happening with the testool checks

@ed255
Copy link
Member Author

ed255 commented Nov 29, 2022

Let's me try to check what's happening with the testool checks

I just found it! The signatures of the transactions were not being propagated to the transaction types passed to the rest of the code.

@ed255 ed255 force-pushed the feature/unify-circuits branch from 2152555 to 5e014b5 Compare November 29, 2022 13:34
@pinkiebell
Copy link
Contributor

Let's me try to check what's happening with the testool checks

I just found it! The signatures of the transactions were not being propagated to the transaction types passed to the rest of the code.

Great! Does that mean we don't test/support invalid signatures yet?

@ed255 ed255 force-pushed the feature/unify-circuits branch from 5e014b5 to bddb217 Compare November 29, 2022 14:15
@ed255
Copy link
Member Author

ed255 commented Nov 29, 2022

Great! Does that mean we don't test/support invalid signatures yet?

The circuit that checks the transaction signatures is the TxCircuit. Currently it doesn't support invalid signatures. For proof of validity, invalid signatures support should not be required; but for a rollup we may require it. As an extra note, the signature verification uses the EcdsaChip from halow2rong, which currently doesn't support invalid signatures.

So strictly speaking, only tests that contain the TxCircuit need signed signatures; for the rest of the tests (other circuits) the txs signatures are not needed. Nevertheless in this PR I added the calculation of all keccak inputs required to proof a full block as part of the circuit's input block preparation. And part of the keccak inputs involves recovering the sender public key from the signature transaction (this is because the Tx Circuit proves that the signature of the tx was signed with a public key, that when hashed gives the sender address). And this is the step that was giving errors.

For the testool this was easy to solve, because the transactions are signed, but in a conversion step the signature was not being propagated.

For the unit tests this is a bit more complicated, because we have a block builder used to generate test inputs where we only specify the tx sender as an address (which means that the block builder doesn't know the private key and txs are not signed). I think in the future we could update the block builder to work with wallets, so that all generated transactions are signed; but that's a significant refactor. So for now I decided to skip generating the keccak inputs for the tx circuit for any tx that is not signed (and do a warn about it).

EDIT: Actually the block builder can be used to generate txs that can later be signed, but it requires generating wallets for sender accounts like this

let wallet_a = LocalWallet::new(&mut rng).with_chain_id(chain_id);
and doing an extra step to sign (whereas in many unit tests we're creating the block with a single call to TestContext::<_, _>::new

@ed255 ed255 force-pushed the feature/unify-circuits branch 2 times, most recently from 74ce21c to cc6a967 Compare November 29, 2022 16:30
@adria0
Copy link
Member

adria0 commented Nov 29, 2022

Let's me try to check what's happening with the testool checks

I just found it! The signatures of the transactions were not being propagated to the transaction types passed to the rest of the code.

Oh, I just found it now also, hehe

@ed255 ed255 force-pushed the feature/unify-circuits branch from cc6a967 to 55000db Compare November 29, 2022 16:38
@ed255 ed255 force-pushed the feature/unify-circuits branch from 55000db to 68a8807 Compare November 29, 2022 17:15
@pinkiebell
Copy link
Contributor

@ed255 Thanks that clears it up. Regarding the rollup, we can either recover the signatures or just do a cheaper pre-validation so that the ecdsa chip can recover a signature

zkevm-circuits/src/test_util.rs Outdated Show resolved Hide resolved
Copy link
Collaborator

@han0110 han0110 left a comment

Choose a reason for hiding this comment

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

LGTM! It's so clear now without those const generic in sub-circuits.

I think it'd be even better to move all impl Circuit for *Circuit into mod test, since they should never be used independently, then we never accidentally call *Circuit::synthesize (currently there are ExpCircuit, StateCircuit, TxCircuit, BytecodeCircuit and KeccakCircuit implemented not in mod test).

Edit: After chatted with Edu, since currently even zkevm-chain is using zkevm-circuits with feature test, it seems worth nothing to do this now, so this is moved to issue #953).

zkevm-circuits/src/copy_circuit.rs Outdated Show resolved Hide resolved
zkevm-circuits/src/pi_circuit.rs Show resolved Hide resolved
zkevm-circuits/src/keccak_circuit/keccak_packed_multi.rs Outdated Show resolved Hide resolved
@ed255
Copy link
Member Author

ed255 commented Nov 30, 2022

@ed255 Thanks that clears it up. Regarding the rollup, we can either recover the signatures or just do a cheaper pre-validation so that the ecdsa chip can recover a signature

Ah, sorry I didn't expand too much on the rollup story: In a rollup we may have a mechanism to include "forced" transactions to avoid censorship. That would be a transaction that is sent to L1 and the node is forced to include in a block. Since these transactions wouldn't be validated, they could contain an invalid signature that makes it impossible to recover the public key; but they must still be processed in the circuits. So the EcdsaChip would need to be extended to prove that a tx signature is invalid (currently the constraints won't pass with an invalid signature).

Given a circuit Foo:
- Unify the struct that contains the columns to FooCircuitConfig
- Unify the struct that contains the witness to FooCircuit
- Unify the config constructor to FooCircuitConfig::new, following the new SubCircuitConfig trait
- Unify the creation of a circuit from a block to FooCircuit::new_from_block following the new SubCircuit trait
- Unify the loading of fixed internal tables to load_aux_tables
- Unify the synthesis step of subcircuits to synthesize_sub following the new SubCircuit trait
- Remove generic associated const from circuit+config types as much as possible
    - Only possible in TxCircuit.  Not possible in PiCircuit due to halo2 Circuit trait
- Implement the Circuit trait to all subcircuits uniformly
- Move circuit tunning parameters to CircuitParams so that they can be taken from a single source
- Add an instance function to all circuits following the new SubCircuit trait

Clean up

Don't unwrap in non-test code

Address some comments from pinkie

Address some comments from pinkie and han
@kunxian-xia
Copy link
Contributor

kunxian-xia commented Dec 15, 2022

@ed255 Thanks that clears it up. Regarding the rollup, we can either recover the signatures or just do a cheaper pre-validation so that the ecdsa chip can recover a signature

Ah, sorry I didn't expand too much on the rollup story: In a rollup we may have a mechanism to include "forced" transactions to avoid censorship. That would be a transaction that is sent to L1 and the node is forced to include in a block. Since these transactions wouldn't be validated, they could contain an invalid signature that makes it impossible to recover the public key; but they must still be processed in the circuits. So the EcdsaChip would need to be extended to prove that a tx signature is invalid (currently the constraints won't pass with an invalid signature).

Why is that the L1 "forced" transaction will include an invalid signature? Do you mean that the L1 "forced" message might be triggered by a smart contract? @ed255

@ed255
Copy link
Member Author

ed255 commented Dec 16, 2022

Why is that the L1 "forced" transaction will include an invalid signature? Do you mean that the L1 "forced" message might be triggered by a smart contract? @ed255

Let me update on this. My thought was that an "L1" forced transaction would be sent by any L1 address (that may not be the same as the forcet_tx.from), and the L1 contract would not do any kind of validation, just keep it to be included in a future L2 block. This forced_tx would have a unverified signature, so the zkEVM would need to support having txs with invalid signatures that must be skipped.

But after a quick discussion with Haichen (scroll) and Brecth (taiko) I learned that this won't be necessary; because in both zkRollup projects they plan for the L1 contract to perform the signature verification and reject the forced_tx if the signature is invalid. So we won't have the case of encountering a tx with invalid signature included in a block.

jonathanpwang pushed a commit to jonathanpwang/zkevm-circuits that referenced this pull request Dec 29, 2022
…s#937)

Given a circuit Foo:
- Unify the struct that contains the columns to FooCircuitConfig
- Unify the struct that contains the witness to FooCircuit
- Unify the config constructor to FooCircuitConfig::new, following the new SubCircuitConfig trait
- Unify the creation of a circuit from a block to FooCircuit::new_from_block following the new SubCircuit trait
- Unify the loading of fixed internal tables to load_aux_tables
- Unify the synthesis step of subcircuits to synthesize_sub following the new SubCircuit trait
- Remove generic associated const from circuit+config types as much as possible
    - Only possible in TxCircuit.  Not possible in PiCircuit due to halo2 Circuit trait
- Implement the Circuit trait to all subcircuits uniformly
- Move circuit tunning parameters to CircuitParams so that they can be taken from a single source
- Add an instance function to all circuits following the new SubCircuit trait

Clean up

Don't unwrap in non-test code

Address some comments from pinkie

Address some comments from pinkie and han
@ed255 ed255 mentioned this pull request Jan 4, 2023
@ChihChengLiang ChihChengLiang deleted the feature/unify-circuits branch May 17, 2023 08:14
RainFallsSilent pushed a commit to dompute/zkevm-circuits that referenced this pull request Sep 14, 2023
* upgrade ethers from 0.17.0 to 2.0.7

* upgrade scroll's fork of ethers-rs

* cargo update

* fix clippy

* fmt

* enable scroll feature
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
crate-bus-mapping Issues related to the bus-mapping workspace member crate-circuit-benchmarks Issues related to the circuit-benchmarks workspace member crate-eth-types Issues related to the eth-types workspace member crate-integration-tests Issues related to the integration-tests workspace member crate-zkevm-circuits Issues related to the zkevm-circuits workspace member T-bench Type: benchmark improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants