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

building blocks for basefold pcs #133

Open
wants to merge 84 commits into
base: dev
Choose a base branch
from
Open

Conversation

zhenfeizhang
Copy link
Collaborator

@zhenfeizhang zhenfeizhang commented Oct 28, 2024

this PR adds required building blocks for basefold. include the following:

  • wrapper for plonky3's babybear -- this may needs further refactoring for our SIMD interfaces
  • implemented poseidon hash function for both babybear and mersenne
  • add classic sumcheck for arbitrary gate
  • add an implementation of merkle tree
  • refactoring APIs for univariate polynomials

@zhenfeizhang zhenfeizhang changed the title Zz/refactor sumchecks building blocks for basefold pcs Oct 29, 2024
@zhenfeizhang zhenfeizhang mentioned this pull request Oct 29, 2024
@zhenfeizhang zhenfeizhang marked this pull request as ready for review October 29, 2024 13:11
Copy link
Contributor

@tonyfloatersu tonyfloatersu left a comment

Choose a reason for hiding this comment

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

half way on tree, gkr and sumcheck to be read, dump the review comments for now

arith/babybear/src/baby_bear.rs Outdated Show resolved Hide resolved
arith/babybear/src/baby_bear.rs Outdated Show resolved Hide resolved
.github/workflows/ci.yml Show resolved Hide resolved
arith/polynomials/src/univariate/coeff.rs Show resolved Hide resolved
arith/polynomials/src/bivariate/lagrange.rs Outdated Show resolved Hide resolved
Cargo.toml Show resolved Hide resolved
Cargo.toml Show resolved Hide resolved
Cargo.toml Show resolved Hide resolved
Comment on lines +9 to +14
/// Represents a leaf in the Merkle tree, containing 64 bytes of data stored in a BabyBearx16.
#[derive(Debug, Copy, Clone, PartialEq, Default)]
pub struct Leaf<F: Field + FieldSerde> {
pub data: F,
}

Copy link
Contributor

@tonyfloatersu tonyfloatersu Nov 1, 2024

Choose a reason for hiding this comment

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

I have some thoughts here - as you mentioned here, the leaf contains 64 bytes of data, yet the type of leaf is F: Field + FieldSerde.

The reason why I wrote the octopos tree hash leaf from a chunk of bytes (https://github.com/cysic-labs/jolt-b/blob/master/octopos/src/hash.rs#L107) is that, I wanted to know explicitly how much data (oblivious of what type it is) can be written in the space, and given that we know what type the bytes should be deserialized to, it would be just fine to deserialize from the leaf.

Yet in this situation, though the field is generic, we somehow assume that the field serialize to 64 bytes, that has to be either Babybear_x16 or M31_x16.

What if we want to hash Orion codeword that works over GF(2) that is binary, then we probably need to construct some 512-length module of GF(2) to fit into the leaf, which seems a bit inconvenient here.

/// Builds a tree with the given leaves.
#[inline]
pub fn new_with_leaves(leaves: Vec<Leaf<F>>) -> Self {
let tree_height = log2(leaves.len() + 1);
Copy link
Contributor

Choose a reason for hiding this comment

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

i felt like this can be wrong - consider 7 leaves, then you need 8 leaves capacity, while the height from 7 leaves is different from the one from 8 leaves

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe they are assuming that the leaves are always being po2, s.t., the height is correct in this case

Copy link
Contributor

@tonyfloatersu tonyfloatersu left a comment

Choose a reason for hiding this comment

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

wrapping up on arbitrary_gate.res, some current code here needs some polishing

Comment on lines +185 to +187

#[cfg(test)]
mod test {}
Copy link
Contributor

Choose a reason for hiding this comment

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

unused code?

// append the prover's message to the transcript
// round_uni_poly.
// transcript.append_field_element(f);
println!("round_uni_poly: {:?}", round_uni_poly.coefficients.len());
Copy link
Contributor

Choose a reason for hiding this comment

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

I guess you want to say something related to the degree of the univariate poly in the round of response in sumcheck?

Comment on lines +157 to +159
if poly.degree() != degree_bound {
panic!("poly degree incorrect")
}
Copy link
Contributor

Choose a reason for hiding this comment

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

can just assert_eq! without using panic?

/// Returns (SumcheckInstanceProof, r_eval_point, final_evals)
/// - `r_eval_point`: Final random point of evaluation
/// - `final_evals`: Each of the polys evaluated at `r_eval_point`
pub fn prove_arbitrary<Func, T>(
Copy link
Contributor

Choose a reason for hiding this comment

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

a minor question regarding the naming - if I am guessing correctly, the naming suggests that it applies to arbitrary gate, i.e., the comb_func here. In a sense, this also suggests specialized sumchecks will be (or have been) implemented for certain cases, say some low degree common cases. Do these guesses sound reasonable to you?

Comment on lines +58 to +69
// eval 0: bound_func is A(low)
let params_zero: Vec<F> =
polys.iter().map(|poly| poly.coeffs[poly_term_i]).collect();
accum[0] += comb_func(&params_zero);

// TODO(#28): Can be computed from prev_round_claim - eval_point_0
let params_one: Vec<F> = polys
.iter()
.map(|poly| poly.coeffs[mle_half + poly_term_i])
.collect();
accum[1] += comb_func(&params_one);

Copy link
Contributor

Choose a reason for hiding this comment

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

it seems, the sumcheck summing sequence is from right to left, i.e., sumcheck reduces variables from the rightmost one to the leftmost one.

// ...
let mut existing_term = params_one;
for eval_i in accum.iter_mut().take(combined_degree + 1).skip(2) {
let mut poly_evals = vec![F::zero(); polys.len()];
Copy link
Contributor

Choose a reason for hiding this comment

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

move the declaration of poly_evals buffer outside the loop, eventually it gets overwritten each iteration from evaluation point being 2 to combine_degree + 1.

Copy link
Contributor

Choose a reason for hiding this comment

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

actually, why not just directly existing_term[poly_i] += (poly.coeffs[mle_half + poly_term_i] - poly.coeffs[poly_term_i]?

also, you can take advantage of the prior stage_zero and stage_one, so you don't have to search into poly's coeffs for the prior searched coefficients, which may help perf a bit...


let accum: Vec<Vec<F>> = (0..mle_half)
.map(|poly_term_i| {
let mut accum = vec![F::zero(); combined_degree + 1];
Copy link
Contributor

Choose a reason for hiding this comment

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

hmmm, please consider another name, not conflicting with outside accum - I guess this variable is keeping track of the comb_func evaluations over current point, while the summing variable need to be from 0 to combine-degree, s.t., this allows verifier to sample a random challenge and reduce the claimed summation for next round of sumcheck.

back to what I have proposed, please do consider another naming for this variable.

- poly.coeffs[poly_term_i];
}

*eval_i += comb_func(&poly_evals);
Copy link
Contributor

Choose a reason for hiding this comment

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

please consider for syntax simplicity, that just use assign here? this is the same case with prior accum[0] and accum[1] that only visited once and assigned once, so please just assign rather than add to the value...

Copy link
Contributor

Choose a reason for hiding this comment

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

a second thought after finishing code reading - can we take out the pcs trait to somewhere, s.t., pcs implementations afterwards can comply with the trait? #97 has 2 pcs traits in bi-kzg and basefold, should be just one pcs trait I guess?


println!("creat proof");
// Create the proof
let combined_degree = 2; // Sum of two linear polynomials has degree 2
Copy link
Contributor

Choose a reason for hiding this comment

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

is that right?

Comment on lines +50 to +54
if (i >> j) & 1 == 1 {
Fr::one()
} else {
Fr::zero()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe just Fr::from((i >> j) & 1) as u64)?

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.

2 participants