-
Notifications
You must be signed in to change notification settings - Fork 58
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
chore: folding-schemes
docs + lint
#188
base: main
Are you sure you want to change the base?
chore: folding-schemes
docs + lint
#188
Conversation
f579363
to
ca885c0
Compare
Leaving off for here now. |
Pinging here real quick. Note commits What do maintainers think? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this PR, it really improves the code quality and it's docs! Also the removal of several clones is a nice improvement.
Left some comments, some of them are more questions to understand better the possibilities.
#[derive(Debug, Clone, Eq, PartialEq)] | ||
pub struct IPA<C: CurveGroup, const H: bool = false> { | ||
/// The inner [`CurveGroup`] type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure on how much needed these comments are. Like, what is describing is something that is clear at simple sight. If clippy is complaining about them maybe clippy is set to hardcore?
Or maybe it is just a matter of following the official rust style, since at the end is not so bad (eg. does not complicate the readability) and in this way the code is more aligned with the official rust style? and so that in this way despite cases like this one where the comment does not bring much new info to the code, this enforces that in other cases where it's not so clear to have a comment we would be enforced to put the comment and thus improving readability for future readers of that more complex part.
/// | ||
/// Returns a tuple (w, x) containing: | ||
/// * w: The witness assignment vector | ||
/// * x: The public input vector (excluding the constant 1) | ||
pub fn extract_w_x<F: PrimeField>(cs: &ConstraintSystem<F>) -> (Vec<F>, Vec<F>) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q1)
Is there some standard way for the new method comments?
in some cases it lists the 'returned parameters', eg:
/// # Returns
///
/// Returns a tuple (w, x) containing:
/// * w: The witness assignment vector
/// * x: The public input vector (excluding the constant 1)
pub fn extract_w_x<F: PrimeField>(cs: &ConstraintSystem<F>) -> (Vec<F>, Vec<F>) {
but in others only mentions the 'returned Error cases', without listing the 'returned parameter' (R1CS<F>
in the following case), eg:
/// # Errors
///
/// Returns an error if:
/// * The constraint system matrices haven't been generated yet
/// * The conversion between matrix formats fails
pub fn extract_r1cs<F: PrimeField>(cs: &ConstraintSystem<F>) -> Result<R1CS<F>, Error> {
And some others (eg. comitment/mod.rs methods) include also the Arguments
section.
Q2) Related to #188 (comment) , what I'm not sure is about 'maintainibility' of the style of the comments, like, when somebody will open a new PR adding a feature, how do we keep coherence of the new code style with the previous existing code, without a human not missing any spot in the PR review. Like, if there is any automated way (eg. clippy (?)) that can ensure that the new code follows the same structure for the comments.
/// Returns the number of witness variables | ||
#[inline] | ||
pub fn num_witnesses(&self) -> usize { | ||
pub const fn num_witnesses(&self) -> usize { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q1) One question from my Rust style ignorance: how of a 'must' are those comments? looks like in these cases the name of the method is already self-descriptive and the comment does not bring any new information, right?
I insist that this question comes from my Rust-style ignorance, if it's a must to have all those comments I don't have any objection, but want to understand if it is really a 'must'.
Q2) Also, I wonder, in case we incorporate all those comments, how do we enforce it for future PRs, without depending on a human not missing any new function without its respective comment. --> would this be just a matter of increasing Clippy's severity?
/// i. <s, b> computation is done in log time following a modification of the equation 3 in section | ||
/// 3.2 from the paper. | ||
/// ii. s computation is done in 2^{k+1}-2 instead of k*2^k. | ||
//! IPA implements the modified Inner Product Argument described in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updating the ///
from the top of the modules into //!
is a good point, cool!
let r: Vec<C::ScalarField>; | ||
if H { | ||
let (l, r) = if H { | ||
let rng = rng.ok_or(Error::MissingRandomness)?; | ||
l = std::iter::repeat_with(|| C::ScalarField::rand(rng)) | ||
.take(k) | ||
.collect(); | ||
r = std::iter::repeat_with(|| C::ScalarField::rand(rng)) | ||
.take(k) | ||
.collect(); | ||
( | ||
std::iter::repeat_with(|| C::ScalarField::rand(rng)) | ||
.take(k) | ||
.collect(), | ||
std::iter::repeat_with(|| C::ScalarField::rand(rng)) | ||
.take(k) | ||
.collect(), | ||
) | ||
} else { | ||
l = vec![]; | ||
r = vec![]; | ||
} | ||
(vec![], vec![]) | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh right! much better this way ^^
//! - [Nova: Recursive Zero-Knowledge Arguments from Folding Schemes](https://eprint.iacr.org/2021/370) | ||
//! - [HyperNova: Recursive Arguments for Customizable Constraint Systems](https://eprint.iacr.org/2023/573) | ||
//! - [CycleFold: Folding-scheme-based Recursive Arguments over Different Curves](https://eprint.iacr.org/2023/1192) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also ProtoGalaxy ^^
[ProtoGalaxy: Efficient ProtoStar-style folding of multiple instances](https://eprint.iacr.org/2023/1106)
let poseidon_config = poseidon_canonical_config::<Fr>(); | ||
|
||
let f_circuit = FC::new(())?; | ||
|
||
let prep_param = NovaPreprocessorParam::new(poseidon_config.clone(), f_circuit); | ||
test_serialize_ivc_opt::<G1, G2, FC, N>("nova", &prep_param)?; | ||
test_serialize_ivc_opt::<G1, G2, FC, HN>("hypernova", &prep_param)?; | ||
|
||
let prep_param = (poseidon_config, f_circuit); | ||
test_serialize_ivc_opt::<G1, G2, FC, P>("protogalaxy".to_string(), prep_param)?; | ||
test_serialize_ivc_opt::<G1, G2, FC, P>("protogalaxy", &prep_param)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh nice, this reorg makes it more clear!
//! * [Nova: Recursive Zero-Knowledge Arguments from Folding Schemes](https://eprint.iacr.org/2021/370) | ||
//! * [HyperNova: Recursive Arguments for Customizable Constraint Systems](https://eprint.iacr.org/2023/573) | ||
//! * [CycleFold: Folding-scheme-based Recursive Arguments over Different Curves](https://eprint.iacr.org/2023/1192) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also ProtoGalaxy ^^
[ProtoGalaxy: Efficient ProtoStar-style folding of multiple instances](https://eprint.iacr.org/2023/1106)
@@ -1,6 +1,51 @@ | |||
//! Sonobe is a library implementing various folding schemes for recursive SNARKs (Succinct Non-interactive ARguments of Knowledge) | |||
//! and IVC (Incremental Verifiable Computation). It provides a modular, extensible framework for working with different folding | |||
//! schemes including Nova, HyperNova, and other variants. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably worth mentioning ProtoGalaxy here.
The main 3 folding schemes we have now are Nova,HyperNova,ProtoGalaxy, the 3 of them with CycleFold, and additionally there are a couple of variations of Nova which are not finished yet but probably no need to mention them already here, which are Mova and Ova (variations in the sense that they are Nova with a modification in how to deal with the E term of the RelaxedR1CS).
@@ -77,6 +92,7 @@ impl<C: CurveGroup, const H: bool> CommitmentScheme<C, H> for Pedersen<C, H> { | |||
Ok(params.h.mul(r) + C::msm_unchecked(¶ms.generators[..v.len()], v)) | |||
} | |||
|
|||
// TODO (autoparallel): I'm guessing `_rng` is marked with prefix `_` because it goes unused always and it is planned for the future? Otherwise we should remove that prefix. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case (Pedersen), it is not used, but in an other implementation of the CommitmentScheme
trait (ie. IPA) it is used.
@arnaucube thank you for the feedback! Let me address some of the comments about docs more generally prior to addressing the review comments directly. OverviewIn the #![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![warn(missing_docs, clippy::missing_docs_in_private_items)] // new from me With clippy running in CI and failing with warnings (or, we can set up #![warn(missing_docs)] and the second Rust StyleThe general Rust style so that docs.rs is consistent usually relies on what Furthermore, cargo docs do have some implicit formatting structure guidance. These include: #![warn(clippy::missing_errors_doc)]
#![warn(clippy::missing_panic_doc)]
#![warn(clippy::missing_safety_doc)] Respectively, these trigger if you don't include why a function that returns You can go as to others such as as: #![warn(rustdoc::missing_doc_code_examples)] to trigger when a public component doesn't also provide an example of usage. Final CommentsMy suggestion is to have a lint workflow (this repo already does) and to set warning attributes for what is deemed acceptable. I do think the two I added are nice and I am happy to finish this crate with it completely. Moving forward, it would then force contributors to write docs for what they add or change. The extra cargo/rustdoc style lints are maybe too pedantic especially to drop all at once, but are also worth consideration in my mind. If at the end of the day we prefer not to lint these at all, I still use them when I'm writing the docs to tell me where I need them :) As a side note, in my rust analyzer, I have set clippy to be pedantic. I think this is overkill for a crate itself, but it does point towards some things. It may be interesting for others to try this setting to see what kind of stuff gets caught in their crates! |
In this PR
Here's what I'm doing:
Docs
Working to adding more documentation adhering to the crate level attributes:
Personally, I enjoy having these lint warnings appear as they keep me honest in keeping well documented code. I do have to say, Sonobe is pretty well documented already! But this has helped me find some spots to add to, and
docs_in_private_items
is really nice for other developers.Lint
I usually have my clippy set to
pedantic
so I get a bunch of... pedantic lint warnings! These have helped me catch things like redundant clones, methods that don't need to returnResult
, and also catch spots where we cast intousize
from types likeu64
.TODO
sI've added various
TODO
s around the modules I've touched with my name on them. I've just noticed a few things that could be addressed (e.g., some possible panics that could be avoided andusize
casting I already mentioned). Also just a few spots that could be cleaned up or have some other oddities.Notes
I'm going to leave some notes here that may be good to turn into issues if we come to agreement on them.
CommitmentScheme
traitBasically I think that there should likely be two implementations for
CommitmentScheme<G>
,one that is hiding, and one that is not (as opposed to the const generic
H
in the trait itself define two versions). We could have inheritance like soHidingCommitmentScheme: CommitmentScheme
.Then, if we impl, for example,
CommitmentScheme<G> for KZG<'a, E, H>
, then we can implHidingCommitmentScheme for KZG<'a, E, true>
. The implementation ofHidingCommitmentScheme
would be super straight forward as it would just add the blinding factor to the output of the "super"
CommitmentScheme
commit
andprove
methods. Then thosemethods on
CommitmentScheme
do not have to take inblind: Option<E::ScalarField>
or thedyn Rng
.This would mean no need for user to handle
Option
and no potential erroneous inputs (i.e.,H == true
but alsoblinding.is_none() == true
). This would just provide comptime assurance of the API.Prelude
I think the
folding-schemes
crate could use aprelude
module that is not only used throughout the crate itself, but would be convenient for those who bring this crate in externally. There's a lot of traits to track otherwise. The one issue here would be that some trait names interfere with struct names (e.g.,Decider
).This PR is still a WIP. I will continue to add to it and flush out the
folding-schemes
crate prior to marking ready to review.