-
Notifications
You must be signed in to change notification settings - Fork 36
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
Add MLKZG support (Nova forward port) #172
Conversation
9f29b52
to
473b5d1
Compare
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.
All of the house-keeping relating to the unification with ZM seem good with me!
There are a lot of missed optimizations in MLKZG, both in terms of parallelization and at the protocol-level. For the latter, many elements are added to the transcript multiple times.
It also seems reasonable to factor out the batch KZG opening into its own sub-protocol.
let kzg_verify_batch = |vk: &KZGVerifierKey<E>, | ||
C: &Vec<E::G1Affine>, | ||
W: &Vec<E::G1Affine>, | ||
u: &Vec<E::Fr>, | ||
v: &Vec<Vec<E::Fr>>, | ||
transcript: &mut <NE as NovaEngine>::TE| | ||
-> bool { |
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.
Both ZM and MLKZG use this the functionality for batching the evaluations of multiple polynomials at different points. A common code path would make sense.
|
||
// Compute the commitment to the batched polynomial B(X) | ||
let c_0: E::G1 = C[0].into(); | ||
let C_B = (c_0 + NE::GE::vartime_multiscalar_mul(&q_powers[1..k], &C[1..k])).preprocessed(); |
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 not required since it's only used as an intermediary computation for L
later on
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 in #231
// | ||
// We group terms to reduce the number of scalar mults (to seven): | ||
// In Rust, we could use MSMs for these, and speed up verification. | ||
let L = E::G1::from(C_B) * (E::Fr::ONE + d[0] + d[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.
Instead of computing C_B * (1 + d[0] + d[1])
, we should directly compute the MSM of C
with q_powers[..] * (1 + d[0] + d[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.
Fixed in #231
polys.push(hat_P.to_vec()); | ||
for i in 0..ell { | ||
let Pi_len = polys[i].len() / 2; | ||
let mut Pi = vec![E::Fr::ZERO; Pi_len]; | ||
|
||
#[allow(clippy::needless_range_loop)] | ||
for j in 0..Pi_len { | ||
Pi[j] = x[ell-i-1] * polys[i][2*j + 1] // Odd part of P^(i-1) | ||
+ (E::Fr::ONE - x[ell-i-1]) * polys[i][2*j]; // Even part of P^(i-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.
The Pi
s need to be computed sequentially, but their derivation can be parallelized.
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 in #233
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.
Great work!
Usually, when some performance numbers are presented, it is useful to also give information about system/computer where experiments were executed.
) -> E::Fr { | ||
transcript.absorb(b"C", C); | ||
transcript.absorb(b"y", y); | ||
transcript.absorb(b"c", &com.to_vec().as_slice()); |
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 is the expected size of com
slice (upper bound)?
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 should be log(N) where N is max of the number of entries in ABC, and the number of constraints, and 2 x number of variables.
v: &[Vec<E::Fr>], | ||
transcript: &mut impl TranscriptEngineTrait<NE>, | ||
) -> E::Fr { | ||
transcript.absorb(b"C", &C.to_vec().as_slice()); |
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.
ditto. I'm interesting in upper bounds of expected sizes for C
, u
, v
slices
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.
U is 3, v is 3*log(N)
45e0f9b
to
594bb10
Compare
* multilinear KZG PCS as a provider; builds * fix two tests * fix third test; cut duplicate code * Tidy up source code comments Signed-off-by: Greg Zaverucha <[email protected]> * impl PairingGroup for bn256 * remove unneeded imports * simplify CommitmentKey * fix build; migrate G1Affine * fmt * checkpoint * migrate G2Affine and pairing * fix clippy; use unimplemented! * switch to affine form for compressed commitments * add a test with mlkzg * cargo fmt * cleanup * go back to compressed group * address clippy * rename * cleanup * add an alias * deduplicate * Revert "add an alias" This reverts commit 97cade6c8751deacbc8b5b0e0df1579e3baa1477. * Use an alias for PreprocessedGroupElements Signed-off-by: Greg Zaverucha <[email protected]> * cargo fmt * update README.md --------- Signed-off-by: Greg Zaverucha <[email protected]> Co-authored-by: Greg Zaverucha <[email protected]>
Summary: - THe MLKZG implementation re-implements some group traits, so as to give it maximum generality and depende maximally on the Nova traits. - However, the way in which it imports a pairing (using pairing::Engine) already implicitly constrains perfrectly usable group implementations to be available on the same types. This commit therefore removes the boilerplate and uses those external traits. - Finally, so as to mutualize part of the pairing implementation, this commit also leverages the MultiMillerLoop trait, a subtrait of `pairing::Engine`. - In sum, this commit only moves types - no actual data was harmed in its making. In detail: - Removed the `PairingGroup` trait and its related implementations from the `traits.rs` and `bn256_grumpkin.rs` files. - Simplified the imports from `halo2curves::bn256` in `bn256_grumpkin.rs` and removed unused types such as `pairing`, `G2Affine`, `G2Compressed`, `Gt`, and `G2`. - Deleted substantial amount of code associated with `G2` from `bn256_grumpkin.rs`.
* make Minroot example generic over the supported curve cycles * upgrade version
…ipt_bytes` - Enhanced the functionality of `to_transcript_bytes` method in `TranscriptReprTrait` for `Affine` in both `pasta.rs` and `traits.rs`. - Combined the x and y coordinates with the `is_infinity_byte` into a single byte stream for ease of handling. - Integrated additional checks for 'infinity' conditions to ensure accurate extractions of coordinate values.
- Restructure the `provider` module by moving `msm` to the `util` subdirectory.
3612039
to
becaa7f
Compare
- chore: move comment - fix: standardize power sequences computation - fix: parallelize several poly computations refactor: Refactor `EvaluationArgument` struct in mlkzg.rs - Renamed several fields in `EvaluationArgument` struct within `src/provider/mlkzg.rs` for increased clarity. - Adjusted the `prove` and `verify` methods in `src/provider/mlkzg.rs` to reflect these name changes. - Modified test code to align with the updates in the `EvaluationArgument` structure.
becaa7f
to
0ccb6c8
Compare
Right, added to PR description. |
This forward-ports the following Nova PRs:
Warning
This is not just a typical forward port from Nova. The second commit includes a significant, opinionated refactor of the MLKZG computation traits to reduce redundancy and boilerplate code.
Note
Items left to address in a future PR include:
TranscriptReprTrait
bounds that have been left onDlogGroup
since Refactor traits that allows implementing different engines for the same curve cycle microsoft/Nova#263 are surprisingly hard to use and should probably be relocated,UniversalKZGParam
struct and abstracting it behind a trait, given the varying public parameter requirements in different schemes (e.g., MLKZG requires fewer G2 points).RenamingUVKZGProverKey
andUVKZGVerifierKey
as they serve dual roles in multiple multilinear schemes.Fixing the discrepancy betweenTranscriptReprTrait<G> for $name::Affine
andTranscriptReprTrait<E::GE> for Commitment<E>
andTranscriptReprTrait<E::G1> for UVKZGCommitment<E>
(only the last 2 agree with each other)Minroot tests
We get a slight performance improvement through the refactoring on the second commit, as seen on the Minroot example:
. The machine is an M1 Mac (CPU only), and the "dataset size" is the number of Minroot iterations in the folded circuit (multiply by roughly 10^3 to get the number of constraints, go see the full log to get exact numbers).
Minroot example highlights
The switch to the FBMSM also improves the generation time of the public parameters (despite needing to generate 2x the points as it's using the same universal setup data structure as Zeromorph):
Full logs: https://gist.github.com/huitseeker/ecd67d7fa6cd1640ed244dc6131fd73f