prover/src/channel.rs (143 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. // // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. use air::{ proof::{Commitments, Context, OodFrame, Queries, StarkProof}, Air, ConstraintCompositionCoefficients, DeepCompositionCoefficients, EvaluationFrame, }; use core::marker::PhantomData; use crypto::{ElementHasher, RandomCoin}; use fri::{self, FriProof}; use math::FieldElement; use utils::{collections::Vec, Serializable}; #[cfg(feature = "concurrent")] use utils::iterators::*; // TYPES AND INTERFACES // ================================================================================================ pub struct ProverChannel<'a, A, E, H> where A: Air, E: FieldElement<BaseField = A::BaseField>, H: ElementHasher<BaseField = A::BaseField>, { air: &'a A, public_coin: RandomCoin<A::BaseField, H>, context: Context, commitments: Commitments, ood_frame: OodFrame, pow_nonce: u64, _field_element: PhantomData<E>, } // PROVER CHANNEL IMPLEMENTATION // ================================================================================================ impl<'a, A, E, H> ProverChannel<'a, A, E, H> where A: Air, E: FieldElement<BaseField = A::BaseField>, H: ElementHasher<BaseField = A::BaseField>, { // CONSTRUCTOR // -------------------------------------------------------------------------------------------- /// Creates a new prover channel for the specified `air` and public inputs. pub fn new(air: &'a A, pub_inputs_bytes: Vec<u8>) -> Self { let context = Context::new::<A::BaseField>(air.trace_info(), air.options().clone()); // build a seed for the public coin; the initial seed is the hash of public inputs and proof // context, but as the protocol progresses, the coin will be reseeded with the info sent to // the verifier let mut coin_seed = pub_inputs_bytes; context.write_into(&mut coin_seed); ProverChannel { air, public_coin: RandomCoin::new(&coin_seed), context, commitments: Commitments::default(), ood_frame: OodFrame::default(), pow_nonce: 0, _field_element: PhantomData, } } // COMMITMENT METHODS // -------------------------------------------------------------------------------------------- /// Commits the prover the extended execution trace. pub fn commit_trace(&mut self, trace_root: H::Digest) { self.commitments.add::<H>(&trace_root); self.public_coin.reseed(trace_root); } /// Commits the prover to the evaluations of the constraint composition polynomial. pub fn commit_constraints(&mut self, constraint_root: H::Digest) { self.commitments.add::<H>(&constraint_root); self.public_coin.reseed(constraint_root); } /// Saves the out-of-domain evaluation frame. This also reseeds the public coin with the /// hashes of the evaluation frame states. pub fn send_ood_evaluation_frame(&mut self, frame: &EvaluationFrame<E>) { self.ood_frame.set_evaluation_frame(frame); self.public_coin.reseed(H::hash_elements(frame.current())); self.public_coin.reseed(H::hash_elements(frame.next())); } /// Saves the evaluations of constraint composition polynomial columns at the out-of-domain /// point. This also reseeds the public coin wit the hash of the evaluations. pub fn send_ood_constraint_evaluations(&mut self, evaluations: &[E]) { self.ood_frame.set_constraint_evaluations(evaluations); self.public_coin.reseed(H::hash_elements(evaluations)); } // PUBLIC COIN METHODS // -------------------------------------------------------------------------------------------- /// Returns a set of coefficients for constructing a constraint composition polynomial drawn /// from the public coin. pub fn get_constraint_composition_coeffs(&mut self) -> ConstraintCompositionCoefficients<E> { self.air .get_constraint_composition_coefficients(&mut self.public_coin) .expect("failed to draw composition coefficients") } /// Returns an out-of-domain point drawn from the public coin. pub fn get_ood_point(&mut self) -> E { self.public_coin.draw().expect("failed to draw OOD point") } /// Returns a set of coefficients for constructing a DEEP composition polynomial drawn from /// the public coin. pub fn get_deep_composition_coeffs(&mut self) -> DeepCompositionCoefficients<E> { self.air .get_deep_composition_coefficients(&mut self.public_coin) .expect("failed to draw DEEP composition coefficients") } /// Returns a set of positions in the LDE domain against which the evaluations of trace and /// constraint composition polynomials should be queried. pub fn get_query_positions(&mut self) -> Vec<usize> { let num_queries = self.context.options().num_queries(); let lde_domain_size = self.context.lde_domain_size(); self.public_coin .draw_integers(num_queries, lde_domain_size) .expect("failed to draw query position") } /// Determines a nonce, which when hashed with the current seed of the public coin results /// in a new seed with the number of leading zeros equal to the grinding_factor specified /// in the proof options. pub fn grind_query_seed(&mut self) { let grinding_factor = self.context.options().grinding_factor(); #[cfg(not(feature = "concurrent"))] let nonce = (1..u64::MAX) .find(|&nonce| self.public_coin.check_leading_zeros(nonce) >= grinding_factor) .expect("nonce not found"); #[cfg(feature = "concurrent")] let nonce = (1..u64::MAX) .into_par_iter() .find_any(|&nonce| self.public_coin.check_leading_zeros(nonce) >= grinding_factor) .expect("nonce not found"); self.pow_nonce = nonce; self.public_coin.reseed_with_int(nonce); } // PROOF BUILDER // -------------------------------------------------------------------------------------------- /// Builds a proof from the previously committed values as well as values passed into /// this method. pub fn build_proof( self, trace_queries: Queries, constraint_queries: Queries, fri_proof: FriProof, ) -> StarkProof { StarkProof { context: self.context, commitments: self.commitments, ood_frame: self.ood_frame, trace_queries, constraint_queries, fri_proof, pow_nonce: self.pow_nonce, } } } // FRI PROVER CHANNEL IMPLEMENTATION // ================================================================================================ impl<'a, A, E, H> fri::ProverChannel<E> for ProverChannel<'a, A, E, H> where A: Air, E: FieldElement<BaseField = A::BaseField>, H: ElementHasher<BaseField = A::BaseField>, { type Hasher = H; /// Commits the prover to a FRI layer. fn commit_fri_layer(&mut self, layer_root: H::Digest) { self.commitments.add::<H>(&layer_root); self.public_coin.reseed(layer_root); } /// Returns a new alpha drawn from the public coin. fn draw_fri_alpha(&mut self) -> E { self.public_coin.draw().expect("failed to draw FRI alpha") } }