-
Notifications
You must be signed in to change notification settings - Fork 17
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
Refactor Ginger-Lib #144
Refactor Ginger-Lib #144
Conversation
… to Marlin and PolyCommit
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.
As this is a quite cross-over pull request, it's hard to give a summary. Please see my comments below.
#### Checking if the file contains Short Weierstrass parameters. If not, the check is interrupted. | ||
#### If there are Twisted Edwards and Montgomery parameters, they are discarded. | ||
if 'SWModelParameters' in readfile: | ||
if 'TEModelParameters' in readfile: | ||
to_be_removed = readfile[readfile.index('impl TEModelParameters'):readfile.index('impl SWModelParameters')] | ||
readfile = readfile.replace(to_be_removed,'') | ||
else: | ||
print("WARNING! THE FILE HAS NO SHORT WEIERSTRASS PARAMETERS!") | ||
sys.exit() |
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.
@DDT92 for now the script is only for SWModelParameters
. Would be cool to handle TEModelParameters
and MontgomeryModelParameters
too!
r1cs/gadgets/std/src/groups/curves/short_weierstrass/short_weierstrass_jacobian.rs
Show resolved
Hide resolved
r1cs/gadgets/std/src/groups/curves/short_weierstrass/short_weierstrass_projective.rs
Outdated
Show resolved
Hide resolved
Ok(()) | ||
let mut power = self.clone(); | ||
let mut acc = Self::zero(cs.ns(|| "alloc acc"))?; | ||
for (i, bit) in bits.enumerate() { |
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.
This is the ordinary double and add. We should check if there are improvements as we have for Weierstrass curves.
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 added a TODO
CS: ConstraintSystemAbstract<ConstraintF>, | ||
T: 'a + ToBitsGadget<ConstraintF> + ?Sized, | ||
I: Iterator<Item = &'a T>, | ||
B: Borrow<[TEExtended<P>]>, |
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.
As for the other msm gadgets. See my comments there.
@@ -1302,11 +914,12 @@ mod projective_impl { | |||
) -> Result<Self, SynthesisError> | |||
where | |||
FN: FnOnce() -> Result<T, SynthesisError>, | |||
T: Borrow<TEProjective<P>>, | |||
T: Borrow<TEExtended<P>>, |
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.
A general comment: why do we enforce curve membership for an input?
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 a leftover, but we do it also for SW curves. Can we safely remove such checks ?
algebra/src/groups/group_vec.rs
Outdated
use num_traits::Zero; | ||
use serde::*; | ||
|
||
#[derive(Clone, PartialEq, Eq, Debug, Hash, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize)] |
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.
The issue of trailing zeros pops up also regarding the PartialEq
and Eq
traits, which cannot be derived if we want to correctly take into account trailing zeros.
I would suggest the following implementation instead (disclaimer: untested and adds a dependency to the crate itertools
)
// The trait PartialEq cannot be simply derived, because this would cause wrong results when
// comparing vectors which are equal apart from a different number of trailing zeros (in
// particular when comparing different representations of the zero vector).
impl<G: Group> PartialEq<Self> for GroupVec<G> {
fn eq(&self, other: &Self) -> bool {
self.0
.iter()
.zip_longest(other.0.iter())
.all(|elems| match elems {
EitherOrBoth::Both(g1, g2) => g1 == g2,
EitherOrBoth::Left(g) => g.is_zero(),
EitherOrBoth::Right(g) => g.is_zero(),
})
}
}
impl<G: Group> Eq for GroupVec<G> {}
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.
To me, I would enforce the comparison only with Polynomials/GroupVec of the same length.
If they aren't they are not equal.
If they are, and they have trailing zeros, then they must have the same amount of trailing zeros
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'll do it. This 0 repr for Polynomial and GroupVec only affects the DomainExtendedPolyCommit.
For the moment let's handle problems individually. When we are going to refactor, removing the DomainExtended and assuming that Commitments are always segmented, probably we can do better.
algebra/src/fft/polynomial/dense.rs
Outdated
use std::ops::{Add, AddAssign, Deref, DerefMut, Div, Mul, Neg, Sub, SubAssign}; | ||
use std::io::{Read, Result as IoResult, Write}; | ||
use std::ops::{Add, AddAssign, Deref, DerefMut, Div, Mul, MulAssign, Neg, Sub, SubAssign}; | ||
use num_traits::Zero; | ||
|
||
/// Stores a polynomial in coefficient form. | ||
#[derive(Clone, PartialEq, Eq, Hash, Default, CanonicalSerialize, CanonicalDeserialize)] |
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 think that deriving PartialEq
and Eq
for DensePolynomial
leads to the same issue as for GroupVec
concerning the possible presence of trailing zeros. The problem could be solved in a similar way too.
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'll do. See my answer abovee
pub trait PedersenWindow: Clone { | ||
const WINDOW_SIZE: usize; | ||
const NUM_WINDOWS: 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.
Let us document here the definition of WINDOW_SIZE
and NUM_WINDOWS
, including security conditions.
algebra/src/curves/mod.rs
Outdated
@@ -29,6 +29,10 @@ pub mod tests; | |||
pub use self::models::*; | |||
|
|||
/// Projective representation of an elliptic curve point. | |||
/// This trait t serves curve-specific functions not covered |
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.
Typo? This trait t ...
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.
Fixed, thanks
r1cs/gadgets/std/src/groups/curves/short_weierstrass/short_weierstrass_jacobian.rs
Show resolved
Hide resolved
@@ -71,10 +75,10 @@ pub trait Curve: | |||
|
|||
/// Convert, if possible, a batch of `self` points to their affine equivalent. | |||
#[inline] | |||
fn batch_into_affine<'a>(vec_self: &'a [Self]) -> Result<Vec<Self::AffineRep>, Error> { | |||
fn batch_into_affine(vec_self: Vec<Self>) -> Result<Vec<Self::AffineRep>, Error> { |
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.
Is there a reason for having a Vec
instead of a slice, as in batch_from_affine()
?
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.
Logically yes: you are consuming Self to obtain an Affine (all the usages were like this in the end, and I don't see any reason why Projective and Affine are allowed to co-exist in the same piece of code at a given moment)
|
||
// Force deserialize test | ||
{ | ||
let a = Jacobian::<P>::rand(rng); |
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.
Why do we resample a
?
(Not the same, but related: Why is a
set zero in Line 373?)
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.
No particular reason, just to have more randomness. About the second comment a is not set to zero, are you looking at the correct diff ?
for _ in 0..ITERATIONS { | ||
let g = Jacobian::<P>::rand(&mut rng); | ||
let g_affine = g.try_into().unwrap(); | ||
let g_projective = Jacobian::<P>::from_affine(&g_affine); | ||
assert_eq!(g, g_projective); | ||
} |
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.
What happens if the sampled g
is the zero element? Is this excluded by our implementation of the rng?
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.
The rng works by sampling a random x and then plug it in the curve equation. I don't think it's possible to sample infinity
@@ -137,6 +160,16 @@ impl<G: Group> Neg for GroupVec<G> { | |||
} | |||
} | |||
|
|||
impl<'a, G: Group> Neg for &'a GroupVec<G> { |
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.
What exactly is the reason for this extra implementation of Neg
(and the other arithmetic traits below)?
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 think I needed mainly for re-using the group tests. Plus they don't harm, they provide additional capabilities
algebra/src/groups/group_vec.rs
Outdated
let (a, mut b) = { | ||
let rng = &mut thread_rng(); | ||
(GroupVec::<TweedleDee>::rand(MAX_LENGTH, rng), GroupVec::<TweedleDee>::rand(MAX_LENGTH, rng)) | ||
}; |
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.
Wouldn't it be more approriate to sample group vecs of different lengths?
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.
Done
algebra/src/linear_combination.rs
Outdated
} | ||
|
||
/// Initialize a random LC from a single batching scalar and a vector of points and checks that the result of combine is indeed | ||
/// given by (0 * point_0) + (scalar * point_1) + (scalar^2 * point_2) + ... + (scalar^n-1 * point_n-1) |
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.
given by (1 * point_0) + ...
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, done
let scalars = (0..MAX_LENGTH) | ||
.map(|_| Fr::rand(rng)) | ||
.collect::<Vec<_>>(); | ||
let points = (0..MAX_LENGTH) | ||
.map(|_| TweedleDee::rand(rng)) | ||
.collect::<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.
Why not choosing a different parameter for the number of samples? As I understand MAX_LENGTH
is the length of a group vec, and typically a quite small number.
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.
It is set to 10 currently, it's good enough I think
algebra/src/msm/variable_base.rs
Outdated
/// Given base points `G[i]` together with scalars `c[i]`, `i=1,..n`, we write | ||
/// c[i] = sum c[i,j] * D^j, | ||
/// s[j] = Sum_i c[i,j] * G[i], | ||
/// for each order `j`. | ||
/// The final result of the multi-scalar multiplication is then combined by | ||
/// s = Sum_j A^j * s[j], | ||
/// using double-and-add. |
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.
To me, this shortened explanation hides that the bucket method is applied to the digits from D
.
How about
/// Given base points `G[i]` together with scalars `c[i]`, `i=1,..n`, we write
/// c[i] = sum c[i,j] * D^j,
/// with digits `c[i,j]` from the interval `{0,...,D-1}`, and compute
/// s[j] = Sum_i c[i,j] * G[i],
/// for each order `j` using the Pippenger-Yao bucket method.
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.
Fine thanks !
This PR contains the refactored algebra module and adjustments for this refactoring in other modules. The details of this refactoring are described in document "Refactoring ginger-lib". Key changes:
Known Issues:
In algebra / secp256k1 unit tests there are hardcoded points in affine representation. Correct values for Jacobian representation should be placed. For now these UTs are broken and marked as ignored
In primitives / merkle_tree / optimized the UTs were switched from MNT curve to tweedle. The hardcoded expected output values should be updated with correct ones. For now these UTs are broken and marked as ignored
In proof-systems / darlin / tests inside TestCircuit there is a comment:
// This calculation is wrong, as enforce_equal allocates new variables.
// However, fixing this may cause unit tests to crash since num_constraints
// and num_variables are generated at random and an underflow may happen.
// Fix both
UTs can randomly failed or pass this part with error "substract with overflow"
Inside r1cs / gadgets / crypto / crh / pedersen the unit-test was switched from JubJub to Tweedle. But with tweedle this UT failed for some reason. This is not a refactoring related problem because in case of changing JubJub to Tweedle inside none-refactored ginger-lib we have the same issue with this UT. For now UT is marked as ignored