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

Implemented Mova folding scheme #161

Merged
merged 13 commits into from
Oct 23, 2024

Conversation

NiDimi
Copy link
Contributor

@NiDimi NiDimi commented Sep 19, 2024

Added code for the Mova folding scheme (as specified in the https://eprint.iacr.org/2024/1220) into the list of the folding-schemes supported.

This PR addresses issue: #133

NiDimi and others added 3 commits September 19, 2024 17:18
@CPerezz
Copy link
Member

CPerezz commented Sep 23, 2024

Aiming for a review next week. Would you be interested @arnaucube on reading the paper + reviewing this as a pair task? @dmpierre you're welcome too ofc!

@arnaucube
Copy link
Collaborator

@CPerezz sure, happy to do a call over it. I must say that this past weekend I went trough the paper to get ready to review this PR, was planning to do a first pass of review this week. But let's coordinate to comment it in a call too.

There is another thing, which may affect this PR, which is the refactor of the Arith traits that @winderica is doing in #162 . Since #162 might be faster to review and unlocks other PRs that @winderica has in the pipeline, might get merged before this PR (#161), and might bring some git conflicts to it. But I think that the changes should not bring much trouble, since would be adapting the Mova code to do a similar thing than what the Nova update is doing in the #162.

@CPerezz
Copy link
Member

CPerezz commented Sep 25, 2024

Agree!!
Let's unblock @winderica and refactor this accordingly then.
That will also give me time to actually read the paper and be able to pair-review!

@NiDimi
Copy link
Contributor Author

NiDimi commented Sep 25, 2024

Feel free to let me know if you need any help from me.

Copy link
Collaborator

@arnaucube arnaucube 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 for this addition! ^^

Just left two small comments in the code.

Two topics (first one is a comment for the future, second one is a question):

  1. Since Mova and Ova are variations that build from Nova I think that it will make sense to have a shared codebase (current Nova's one) with Mova & Ova being some kind of flag options there, which basically affect on which strategy is applied on the error/slack terms (E) and its commitment (or the respective representation, ie MLE), but with most of the rest of the logic remaining the same, avoiding most of duplicated code (not only in the current NIFS implementation but also on future circuits & IVC & Decider implementation). And this will be easier now that @winderica improved the Arith related traits in Refactor Arith trait #162.

But I think that for a first iteration we're good with having a separated Mova code as it is in this PR, and we can do the abstractions in a next iteration.

  1. One question, this PR implements the Mova's NIFS logic, and the following steps would be implementing the circuit that does the NIFS.Verify logic (in-circuit) in order to then build an IVC out of it so that we can do IVC with Mova.
    I'm checking the Nethermint Mova impl and I'm only finding the NIFS implementation there too.
    Is implementing the circuit (with the NIFS.V) and the IVC logic something that you plan to do? Since the Mova implementation was done to accompany the paper, I was assuming that it will stay as it is, but I'm asking just to avoid understanding it wrong and duplicating efforts.

I'm asking, not to put pressure on you (don't feel any pressure, really), but just in terms of high level planning, to see if it would make sense for us at some point to go into that. I think that then it would make sense to merge this PR, then the @CPerezz 's PR adding the Ova NIFS, and then doing the abstraction mentioned at the beginning of this message (point 1), so that then building the IVC with Mova (and Ova too) is more straightforward over the already existing Nova codebase, since most of the logic needed will be shared except for the approach related to the E and its commitment or MLE, and same for the Decider circuits and Decider logic.

===

UPDATE: the abstraction has been made at a07e17e , and Mova ported to the abstraction at 54e6b60 .

folding-schemes/src/folding/mova/mod.rs Outdated Show resolved Hide resolved
folding-schemes/src/folding/mova/mod.rs Outdated Show resolved Hide resolved
@arnaucube arnaucube requested a review from CPerezz September 30, 2024 11:38
Copy link
Member

@CPerezz CPerezz left a comment

Choose a reason for hiding this comment

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

A couple of comments.

Also, interested on seeing your thoughts about @arnaucube's proposal.

Comment on lines 30 to 41
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Witness<C: CurveGroup> {
pub E: Vec<C::ScalarField>,
pub W: Vec<C::ScalarField>,
pub rW: C::ScalarField,
}

#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct InstanceWitness<C: CurveGroup> {
pub ci: CommittedInstance<C>,
pub w: Witness<C>,
}
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we could add some comments for these structs. Specially since both have w inside. So would be nice to refer to the paper to understand the diffs etc..

Comment on lines 58 to 67
pub fn dummy(w_len: usize, e_len: usize) -> Self {
let rW = C::ScalarField::zero();
let w = vec![C::ScalarField::zero(); w_len];

Self {
E: vec![C::ScalarField::zero(); e_len],
W: w,
rW,
}
}
Copy link
Member

Choose a reason for hiding this comment

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

There's a trait for this which would likely make more sense to implement.

See: https://github.com/privacy-scaling-explorations/sonobe/blob/main/folding-schemes/src/folding/nova/mod.rs#L82

Comment on lines 94 to 95
impl<C: CurveGroup> CommittedInstance<C> {
pub fn dummy(io_len: usize) -> Self {
Copy link
Member

Choose a reason for hiding this comment

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

ditto.

Comment on lines 120 to 126
// We cannot call `to_native_sponge_field_elements(dest)` directly, as
// `to_native_sponge_field_elements` needs `F` to be `C::ScalarField`,
// but here `F` is a generic `PrimeField`.
self.cmW
.to_native_sponge_field_elements_as_vec()
.to_sponge_field_elements(dest);
}
Copy link
Member

Choose a reason for hiding this comment

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

We should change the trait bounds here @winderica @arnaucube right? It should not affect the rest of impls. We will just need to enforce the bounds sometimes.

Maybe @NiDimi can you file an issue for this?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry for missing your comment! This is in fact introduced by me in https://github.com/privacy-scaling-explorations/sonobe/blame/cb1b8e37aa07dda255d3f3651385a45613beed4e/folding-schemes/src/folding/nova/mod.rs#L112-L121. Let me check if this can be resolved by changing the trait bound. Will create an issue or PR in these days!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Issue opened: #170

Comment on lines 45 to 54
// Just a wrapper for Nova compute_T (compute cross-terms T) since the process is the same
pub fn compute_T(
r1cs: &R1CS<C::ScalarField>,
u1: C::ScalarField,
u2: C::ScalarField,
z1: &[C::ScalarField],
z2: &[C::ScalarField],
) -> Result<Vec<C::ScalarField>, Error> {
Nova::<C, CS, H>::compute_T(r1cs, u1, u2, z1, z2)
}
Copy link
Member

Choose a reason for hiding this comment

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

Can't you simply call the Nova NIFS then? It should not be an issue as it doesn't require &self as parameter.
You can import it with an alias just for the computation of T like: use folding::nova::..::NIFS as NovaNIFS;

mleE2_prime: &C::ScalarField,
mleT: &C::ScalarField,
) -> Result<CommittedInstance<C>, Error> {
let a2 = a * a;
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
let a2 = a * a;
let a_squared = a * a;

To avoid confusion with 1 and 2 indices in other variables names.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This change makes sense to me but I think it would make more sense if we switched all the usage of 2 after the letter to symbolise square (e.g. Mova's fold_witness, Nova's fold_witness and fold_committed_instance etc.)

Copy link
Collaborator

Choose a reason for hiding this comment

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

in this case I think there is no space for confusion, since it's clear that a2=a*a, and the usage is only right at the following line.

) = PointVsLine::<C, T>::prove(transcript, ci1, ci2, w1, w2)?;

// Protocol 7

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

Comment on lines 155 to 156
let alpha_scalar = C::ScalarField::from_le_bytes_mod_order(b"alpha");
transcript.absorb(&alpha_scalar);
Copy link
Member

Choose a reason for hiding this comment

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

Is this some kind of domain separator?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is actually not needed for Mova, so I removed it.

Comment on lines 181 to 183
/// [Mova](https://eprint.iacr.org/2024/1220.pdf)'s section 4. It verifies the results from the proof
/// Both the folding and the pt-vs-line proof
/// returns the folded committed instance
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
/// [Mova](https://eprint.iacr.org/2024/1220.pdf)'s section 4. It verifies the results from the proof
/// Both the folding and the pt-vs-line proof
/// returns the folded committed instance
/// [Mova](https://eprint.iacr.org/2024/1220.pdf)'s section 4.
/// It verifies the results from both the folding and the pt-vs-line proofs.
/// Returns the folded committed instance.

Comment on lines 20 to 21
}
/// Proof from step 1 protocol 6
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
}
/// Proof from step 1 protocol 6
}
/// Proof from step 1 protocol 6

arnaucube added a commit that referenced this pull request Oct 3, 2024
…defining a common interface between the three Nova variants

The recent Ova NIFS PR #163 (#163)
and Mova NIFS PR #161 (#161)
PRs add Nova NIFS variants implementations which differ from Nova in the
logic done for the `E` error terms of the instances.

The current Ova implementation (#163)
is based on the existing Nova NIFS code base and adds the modifications
to the `E` logic on top of it, and thus duplicating the code. Similarly
for the Mova NIFS impl.

The rest of the Mova & Ova schemes logic that is not yet implemented is
pretty similar to Nova one (ie. the IVC logic, the circuits and the
Decider), so ideally that can be done reusing most of the already
existing Nova code without duplicating it. This PR is a first step in
that direction for the existing Ova NIFS code.

This commit adds the NIFS trait abstraction with the idea of allowing to
reduce the amount of duplicated code for the Ova's NIFS impl on top of
the Nova's code.
github-merge-queue bot pushed a commit that referenced this pull request Oct 3, 2024
* add NIFS trait abstraction (based on the needs for Nova, Mova, Ova), defining a common interface between the three Nova variants

The recent Ova NIFS PR #163 (#163)
and Mova NIFS PR #161 (#161)
PRs add Nova NIFS variants implementations which differ from Nova in the
logic done for the `E` error terms of the instances.

The current Ova implementation (#163)
is based on the existing Nova NIFS code base and adds the modifications
to the `E` logic on top of it, and thus duplicating the code. Similarly
for the Mova NIFS impl.

The rest of the Mova & Ova schemes logic that is not yet implemented is
pretty similar to Nova one (ie. the IVC logic, the circuits and the
Decider), so ideally that can be done reusing most of the already
existing Nova code without duplicating it. This PR is a first step in
that direction for the existing Ova NIFS code.

This commit adds the NIFS trait abstraction with the idea of allowing to
reduce the amount of duplicated code for the Ova's NIFS impl on top of
the Nova's code.

* add Ova variant on top of the new NIFS trait abstraction

This is done from the existing Ova implementation at
`folding/ova/{mod.rs,nofs.rs}`, but removing when possible code that is not
needed or duplicated from the Nova logic.

* rm old Ova duplicated code

This commit combined with the other ones (add nifs abstraction & port
Ova to the nifs abstraction) allows to effectively get rid of ~400 lines
of code that were duplicated in the Ova NIFS impl from the Nova impl.

* small polishing & rebase to latest `main` branch updates
arnaucube and others added 6 commits October 22, 2024 21:56
* refactor NIFSTrait interface to fit Nova variants (Nova,Mova,Ova)

  Refactor NIFSTrait interface to fit Nova variants (Nova,Mova,Ova). The relevant
  change is instead of passing the challenge as input, now it passes the
  transcript and computes the challenges internally (Nova & Ova still compute a
  single challenge, but Mova computes multiple while absorbing at different
  steps).

* port Mova impl to the NIFSTrait

* remove unnecessary wrappers in the nova/zk.rs

* remove Nova NIFS methods that are no longer needed after the refactor

* put together the different NIFS implementations (Nova, Mova, Ova) so
  that they can interchanged at usage.

The idea is that Nova and its variants (Ova & Mova) share most of the
logic for the circuits & IVC & Deciders, so with the abstracted NIFS
interface we will be able to reuse most of the already existing Nova
code for having the Mova & Ova circuits, IVC, and Decider.
Refactor NIFSTrait & port Mova impl to it
adapt Nova's DeciderEth prepare_calldata & update examples to it
Copy link
Collaborator

@arnaucube arnaucube left a comment

Choose a reason for hiding this comment

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

With the latest commits integrating the NIFSTrait with the Mova implementation, I think that this PR is ready to be merged. LGTM!

@arnaucube arnaucube requested a review from CPerezz October 23, 2024 08:24
Copy link
Member

@CPerezz CPerezz 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 for this!

@arnaucube arnaucube added this pull request to the merge queue Oct 23, 2024
Merged via the queue into privacy-scaling-explorations:main with commit 6d8f297 Oct 23, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants