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

Barycentric Evaluation #266

Merged
merged 4 commits into from
Apr 23, 2024
Merged

Conversation

aszepieniec
Copy link
Collaborator

  • Include a new mathematical function in Fri: barycentric_evaluation, which takes a codeword and an out-of-domain indeterminate and extrapolates the codeword to its value there.
  • Define a new ProofItem type so that the prover can send the polynomial that corresponds to the last codeword in FRI, and so that the verifier can receive it.
  • Check the degree of the last polynomial.
  • Check that the last polynomial agrees with the last codeword through evaluation in a random point: once using Horner evaluation and once using the barycentric formula.
  • Sample the random point from the sponge state by squeezing, and mirror this squeeze operation on the prover side even though the yielded randomness is not used there.

@aszepieniec
Copy link
Collaborator Author

Previously, the last polynomial in FRI was computed by interpolating the last codeword using an iNTT. This step has been eliminated. Even though the asymptotic complexity dropped from $O(n \log n)$ to $O(n)$ I observed no performance difference. This might change with the length of the last codeword (for instance, if the expansion factor changes). That said, the selling point is the anticipated lower clock cycle count for the recursive verifier.

@Sword-Smith
Copy link
Collaborator

Sword-Smith commented Apr 22, 2024

Consider rewriting the domain calculation in the barycentric_evaluate to use scan. This removes acc from the scope of the function body.

let generator = BFieldElement::primitive_root_of_unity(codeword.len() as u64).unwrap();
let domain = (0..codeword.len())
    .scan(BFieldElement::one(), |acc, _| {
        let omegai = *acc;
        *acc *= generator;
        Some(omegai)
    })
    .collect_vec();

No performance change was observed on my laptop using benchmark
`prove_verify_halt` (11ms in both cases) but the main selling
point comes from the smaller anticipated clock cycle count in the
recursive verifier.

BREAKING CHANGE: Now the prover sends the last polynomial in addition to
the last codeword in FRI. The verifier verifies that the polynomial is
of low degree directly (without iNTTs!) and checks that it matches with
the codeword using the barycentric evaluation function and randomness
sampled from the proof stream's sponge state.

Closes #156
@jan-ferdinand jan-ferdinand linked an issue Apr 23, 2024 that may be closed by this pull request
@Sword-Smith
Copy link
Collaborator

Sword-Smith commented Apr 23, 2024

The barycentric_evaluate function can also be rewritten to function entirely without heap allocation, which is how I intend to implement it in tasm-lib. Also notice the use of type BFieldElement for domain_iter_elem.

    pub fn barycentric_evaluate(
        codeword: &[XFieldElement],
        indeterminate: XFieldElement,
    ) -> XFieldElement {
        let root_order = codeword.len().try_into().unwrap();
        let generator = BFieldElement::primitive_root_of_unity(root_order).unwrap();
        let mut numerator = xfe!(0);
        let mut denominator = xfe!(0);
        let mut domain_iter_elem = bfe!(1);
        for code_word_elem in codeword {
            let domain_shift_elem = indeterminate - domain_iter_elem;
            let domain_over_domain_shift_elem = domain_iter_elem.lift() / domain_shift_elem;
            numerator += domain_over_domain_shift_elem * *code_word_elem;
            denominator += domain_over_domain_shift_elem;
            domain_iter_elem *= generator;
        }

        numerator / denominator
    }

Due to the batch-inversion being used on the host machine, I can't tell which one is faster though. And for our domain sizes I'm pretty sure either implementation is maximum a few microseconds, so feel free to ignore this suggestion entirely and file it under "Red Herring".

@jan-ferdinand jan-ferdinand merged commit 991688a into master Apr 23, 2024
5 checks passed
@jan-ferdinand jan-ferdinand deleted the asz/156-barycentric-evaluation branch April 23, 2024 13:54
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.

Barycentric Low-degree Verification for FRI
3 participants