1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
// Copyright 2023 RISC Zero, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{
core::log2_ceil,
hal::{Buffer, Hal},
prove::merkle::MerkleTreeProver,
INV_RATE, QUERIES,
};
/// A PolyGroup represents a group of polynomials, all of the same maximum
/// degree, as well as the evaluation of those polynomials over some domain that
/// is larger than that degree by some invRate. Additionally, it includes a
/// dense Merkle tree, where each entry is a single point of the domain, and the
/// leaf hash is a simple linear hash of all of the values at that point. That
/// is, if we have 100 polynomials evaluated on 2^16 points, the merkle tree has
/// 2^16 entries, each being a hash of 100 values. The size of the domain is
/// always a power of 2 so that we can use NTTs.
///
/// The primary purpose of the PolyGroup is for use in the DEEP-ALI protocol,
/// which basically needs 4 methods during proof generation, specifically we
/// need to: 1) Resolve queries (i.e. make MerkleColProofs)
/// 2) Do evaluation of the polynomials at 'randomly' chosen points
/// 3) Mix the polynomials via a random set of linear coefficients
/// 4) Access the raw values in the evaluation domain to 'evaluate' the
/// constraint polynomial
///
/// The poly group holds 3 buffers:
/// 1) The per-polynomial coefficients, used for evaluation + mixing
/// 2) The points evaluated on the domain in question (for the 'col' part of
/// merkle proofs) 3) The Merkle tree itself.
///
/// PolyGroups are constructed from two basic sources: steps of a computations,
/// and a single higher degree polynomial that has been split into lower degree
/// parts. In the case of computations, the resulting steps must be padded
/// (possibly with randomized data), which is presumed to be done by the caller.
/// The constructor additionally 'shifts' the polynomial so that f(x) -> f(3*x),
/// which means that the normal NTT evaluation domain does not reveal anything
/// about the original datapoints (i.e. is zero knowledge) so long as the number
/// of queries is less than the randomized padding.
pub struct PolyGroup<'a, H: Hal> {
pub coeffs: &'a H::BufferElem,
pub count: usize,
pub evaluated: H::BufferElem,
pub merkle: MerkleTreeProver<H>,
}
impl<'a, H: Hal> PolyGroup<'a, H> {
#[tracing::instrument(name = "PolyGroup", skip_all, fields(name = _name))]
pub fn new(
hal: &H,
coeffs: &'a H::BufferElem,
count: usize,
size: usize,
_name: &'static str,
) -> Self {
assert_eq!(coeffs.size(), count * size);
let domain = size * INV_RATE;
let evaluated = hal.alloc_elem("evaluated", count * domain);
hal.batch_expand(&evaluated, &coeffs, count);
hal.batch_evaluate_ntt(&evaluated, count, log2_ceil(INV_RATE));
hal.batch_bit_reverse(&coeffs, count);
let merkle = MerkleTreeProver::new(hal, &evaluated, domain, count, QUERIES);
PolyGroup {
coeffs,
count,
evaluated,
merkle,
}
}
}