Skip to content

Add RecursiveCircuit #204

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Add RecursiveCircuit #204

wants to merge 4 commits into from

Conversation

arnaucube
Copy link
Collaborator

@arnaucube arnaucube commented Apr 21, 2025

The RecursiveCircuit verifies N proofs of itself (N=arity), together with the logic defined at the InnerCircuit (in our case, used for the MainPodCircuit logic).

The arity defines the maximum amount of proofs of itself that the RecursiveCircuit verifies. When arity>1, using the RecursiveCircuit has the shape of a tree of the same arity.

                     π_root
                       ▲
               ┌───────┴────────┐
               │RecursiveCircuit│
               └─▲───▲───▲────▲─┘
         ┌───────┘  ┌┘   └┐   └──────┐
         │π''_1     │ ... │     π''_N│
┌────────┴───────┐ ┌┴┐┌─┐┌┴┐ ┌───────┴────────┐
│RecursiveCircuit│ │.││.││.│ │RecursiveCircuit│
└──▲─────────▲───┘ └─┘└─┘└─┘ └──▲─────────▲───┘
   │         │                  │         │
  π_1  ...  π_N               π'_1 ...  π'_N

where
N: arity of the RecursiveCircuit
π_i: plonky2 proof of the RecursiveCircuit

In the direction of #174 .

@arnaucube arnaucube force-pushed the recursion-circuit branch 4 times, most recently from 8b8501b to 19af95f Compare April 21, 2025 17:52
@arnaucube arnaucube marked this pull request as draft April 22, 2025 07:25
The RecursiveCircuit verifies N proofs of itself (N=arity), together with
the logic defined at the InnerCircuit (in our case, used for the
MainPodCircuit logic).

The arity defines the maximum amount of proofs of itself that the
RecursiveCircuit verifies. When arity>1, using the RecursiveCircuit has the
shape of a tree of the same arity.

                     π_root
                       ▲
               ┌───────┴────────┐
               │RecursiveCircuit│
               └─▲───▲───▲────▲─┘
         ┌───────┘  ┌┘   └┐   └──────┐
         │π''_1     │ ... │     π''_N│
┌────────┴───────┐ ┌┴┐┌─┐┌┴┐ ┌───────┴────────┐
│RecursiveCircuit│ │.││.││.│ │RecursiveCircuit│
└──▲─────────▲───┘ └─┘└─┘└─┘ └──▲─────────▲───┘
   │         │                  │         │
  π_1  ...  π_N               π'_1 ...  π'_N

where
N: arity of the RecursiveCircuit
π_i: plonky2 proof of the RecursiveCircuit
@arnaucube arnaucube force-pushed the recursion-circuit branch 4 times, most recently from bd6efce to 62a9f88 Compare April 23, 2025 09:43
@arnaucube arnaucube marked this pull request as ready for review April 23, 2025 09:43
@arnaucube
Copy link
Collaborator Author

(rebased to latest main branch changes & improved tests)

@arnaucube arnaucube requested review from ax0 and ed255 April 23, 2025 09:44
Copy link
Collaborator

@ed255 ed255 left a comment

Choose a reason for hiding this comment

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

I've done an initial review. I haven't reviewed the tests properly yet.

// used in the InnerCircuit
let pub_inp: Vec<Target> = proofs_targ
.iter()
.flat_map(|proof_pis| proof_pis.public_inputs.clone())
Copy link
Collaborator

Choose a reason for hiding this comment

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

These public inputs are built like this:
[inner_circuit_public, circuit_digest, constants_sigmas_cap].
We should do two things here:

  1. If the selectors_targ=true, then circuit_digest, constants_sigmas_cap from the proof should be equal to the values in verifier_data_targ. Or maybe we skip the conditional part and just connect, beacuse the dummy proof may use the same verifier data?
  2. Extract the inner_circuit_public and that's collected and passed to I::build

Copy link
Collaborator

Choose a reason for hiding this comment

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

1. If the `selectors_targ=true`, then `circuit_digest, constants_sigmas_cap` from the proof should be equal to the values in `verifier_data_targ`.  Or maybe we skip the conditional part and just connect, beacuse the dummy proof may use the same verifier data?

I learned that this is already being done through the combination of

builder.add_verifier_data_public_inputs()

and

builder.conditionally_verify_cyclic_proof_or_dummy()

https://github.com/0xPolygonZero/plonky2/blob/6a2c1b47b7b00864c2b65a44c18099b0152f550e/plonky2/src/recursion/cyclic_recursion.rs#L114-L117

public_inputs: Vec<Target>,
selectors: Vec<BoolTarget>,
) -> Result<Self>;

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we need a new method to return the public inputs so that we can pass them from InnerCircuit to RecursiveCircuit.
For example something like this:

pub trait InnerCircuit: Clone {
    type InputTarget: Flattenable;

    fn public_inputs(&self) -> Self::InputTarget;

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes, I've opened the issue #208 to tackle this

.collect(),
]
.concat()
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should add a verify function, because the verification of this proof is not just calling the plonky2 method, but we also need to check that the expected verifier_data is in the public inputs.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Agree, but probably this verify function will include also the logic to check the validity of the verifier_data, right? I would propose to map it into a separate issue for the entire task (which includes implementing one of the approaches that you described in the hackmd of the 'recursion family framework').

Copy link
Collaborator

Choose a reason for hiding this comment

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

The verifier_data must be equal to the one calculated via:

let circuit_data = RecursiveCircuit::<I>::circuit_data(&params, &inner_params)?;
let verifier_data = circuit_data.verifier_data();

That's the case if we consider a circuit that verifies itself. If the verifier data in the public inputs is not the verifier data of the outer circuit then it's not a circuit that verifies itself.

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.

3 participants