winter_air/air/
coefficients.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6use alloc::vec::Vec;
7
8use crypto::{RandomCoin, RandomCoinError};
9use math::{get_power_series, FieldElement};
10
11// CONSTRAINT COMPOSITION COEFFICIENTS
12// ================================================================================================
13/// Coefficients used in construction of constraint composition polynomial.
14///
15/// These coefficients are created by the
16/// [Air::get_constraint_composition_coefficients()](crate::Air::get_constraint_composition_coefficients)
17/// function. In the interactive version of the protocol, the verifier either draws these
18/// coefficients uniformly at random from the extension field of the protocol or draws a single
19/// random extension field element $\alpha$ and defines the coefficients as $\alpha_i = \alpha^i$.
20/// We call the former way way of generating the alpha-s, and hence of batching the constraints,
21/// linear/affine batching while we call the latter algebraic/curve batching.
22///
23/// There is one coefficient for each constraint so that we can compute a random linear
24/// combination of constraints as:
25/// $$
26/// \sum_{i = 0}^k{\alpha_i \cdot C_i(x)}
27/// $$
28/// where:
29/// * $\alpha_i$ is the coefficient for the $i$th constraint.
30/// * $C_i(x)$ is an evaluation of the $i$th constraint at $x$.
31///
32/// The coefficients are separated into two lists: one for transition constraints and another one
33/// for boundary constraints. This separation is done for convenience only.
34///
35/// Note that the soundness error of the protocol will depend on the batching used when computing
36/// the constraint composition polynomial. More precisely, when using algebraic batching there
37/// might be a loss of log_2(C - 1) bits of RbR soundness of the protocol, where C is the total
38/// number of constraints.
39#[derive(Debug, Clone)]
40pub struct ConstraintCompositionCoefficients<E: FieldElement> {
41    pub transition: Vec<E>,
42    pub boundary: Vec<E>,
43}
44
45impl<E: FieldElement> ConstraintCompositionCoefficients<E> {
46    /// Returns new [ConstraintCompositionCoefficients] constructed by splitting the provided
47    /// coefficients into transition and boundary coefficients.
48    ///
49    /// The first `num_transition_constraints` values in the `coefficients` vector are assigned
50    /// to the transition coefficients and the remaining coefficients are assigned to boundary
51    /// coefficients.
52    fn new(mut coefficients: Vec<E>, num_transition_constraints: usize) -> Self {
53        let boundary = coefficients.split_off(num_transition_constraints);
54        let transition = coefficients;
55        Self { transition, boundary }
56    }
57
58    /// Generates the random values used in the construction of the constraint composition
59    /// polynomial when linear batching is used.
60    pub fn draw_linear(
61        public_coin: &mut impl RandomCoin<BaseField = E::BaseField>,
62        num_transition_constraints: usize,
63        num_boundary_constraints: usize,
64    ) -> Result<Self, RandomCoinError> {
65        let num_coefficients = num_transition_constraints + num_boundary_constraints;
66        let coefficients = draw_linear_coefficients(public_coin, num_coefficients)?;
67        Ok(Self::new(coefficients, num_transition_constraints))
68    }
69
70    /// Generates the random values used in the construction of the constraint composition
71    /// polynomial when algebraic batching is used.
72    pub fn draw_algebraic(
73        public_coin: &mut impl RandomCoin<BaseField = E::BaseField>,
74        num_transition_constraints: usize,
75        num_boundary_constraints: usize,
76    ) -> Result<Self, RandomCoinError> {
77        let num_coefficients = num_transition_constraints + num_boundary_constraints;
78        let coefficients = draw_algebraic_coefficients(public_coin, num_coefficients)?;
79        Ok(Self::new(coefficients, num_transition_constraints))
80    }
81
82    /// Generates the random values used in the construction of the constraint composition
83    /// polynomial when Horner-type batching is used.
84    pub fn draw_horner(
85        public_coin: &mut impl RandomCoin<BaseField = E::BaseField>,
86        num_transition_constraints: usize,
87        num_boundary_constraints: usize,
88    ) -> Result<Self, RandomCoinError> {
89        let num_coefficients = num_transition_constraints + num_boundary_constraints;
90        let mut coefficients = draw_algebraic_coefficients(public_coin, num_coefficients)?;
91        coefficients.reverse();
92        Ok(Self::new(coefficients, num_transition_constraints))
93    }
94}
95
96// DEEP COMPOSITION COEFFICIENTS
97// ================================================================================================
98/// Coefficients used in construction of DEEP composition polynomial.
99///
100/// These coefficients are created by the
101/// [Air::get_deep_composition_coefficients()](crate::Air::get_deep_composition_coefficients)
102/// function. In the interactive version of the protocol, the verifier draws these coefficients
103/// uniformly at random from the extension field of the protocol.
104///
105/// The coefficients are used in computing the DEEP composition polynomial as:
106/// $$
107/// Y(x) = \sum_{i=0}^k{(
108///     \alpha_i \cdot (\frac{T_i(x) - T_i(z)}{x - z} +
109///     \frac{T_i(x) - T_i(z \cdot g)}{x - z \cdot g})
110/// )} + \sum_{j=0}^m{\beta_j \cdot \frac{H_j(x) - H_j(z)}{x - z}}
111/// $$
112/// where:
113/// * $z$ is an out-of-domain point drawn randomly from the entire field. In the interactive version
114///   of the protocol, $z$ is provided by the verifier.
115/// * $g$ is the generator of the trace domain. This is the $n$th root of unity where $n$ is the
116///   length of the execution trace.
117/// * $T_i(x)$ is an evaluation of the $i$th trace polynomial at $x$, and $k$ is the total number of
118///   trace polynomials (which is equal to the width of the execution trace).
119/// * $H_i(x)$ is an evaluation of the $j$th constraint composition column polynomial at $x$, and
120///   $m$ is the total number of column polynomials.
121/// * $\alpha_i$ is a composition coefficient for the $i$th trace polynomial.
122/// * $\beta_j$ is a composition coefficient for the $j$th constraint column polynomial.
123///
124/// The soundness of the resulting protocol is given in Theorem 8 in https://eprint.iacr.org/2022/1216
125/// and it relies on the following points:
126///
127///
128/// 1. The evaluation proofs for each trace polynomial at $z$ and $g \cdot z$ can be batched using
129///    the non-normalized Lagrange kernel over the set $\{z, g \cdot z\}$. This, however, requires
130///    that the FRI protocol is run with a larger agreement parameter.
131/// 2. The resulting $Y(x)$ do not need to be degree adjusted but the soundness error of the
132///    protocol needs to be updated. For most combinations of batching parameters, this leads to a
133///    negligible increase in soundness error. The formula for the updated error can be found in
134///    Theorem 8 of https://eprint.iacr.org/2022/1216.
135/// 3. The error will depend on the batching used in building the DEEP polynomial. More precisely,
136///    when using algebraic batching there might be a loss of log_2(k + m - 1) bits of soundness.
137#[derive(Debug, Clone)]
138pub struct DeepCompositionCoefficients<E: FieldElement> {
139    /// Trace polynomial composition coefficients $\alpha_i$.
140    pub trace: Vec<E>,
141    /// Constraint column polynomial composition coefficients $\beta_j$.
142    pub constraints: Vec<E>,
143}
144
145impl<E: FieldElement> DeepCompositionCoefficients<E> {
146    /// Returns new [DeepCompositionCoefficients] constructed by splitting the provided
147    /// coefficients into transition and boundary coefficients.
148    ///
149    /// The first `trace_width` values in the `coefficients` vector are assigned to the trace
150    /// coefficients and the remaining coefficients are assigned to constraint coefficients.
151    fn new(mut coefficients: Vec<E>, trace_width: usize) -> Self {
152        let constraints = coefficients.split_off(trace_width);
153        let trace = coefficients;
154        Self { trace, constraints }
155    }
156
157    /// Generates the random values used in the construction of the DEEP polynomial when linear
158    /// batching is used.
159    pub fn draw_linear(
160        public_coin: &mut impl RandomCoin<BaseField = E::BaseField>,
161        trace_width: usize,
162        num_constraint_composition_columns: usize,
163    ) -> Result<Self, RandomCoinError> {
164        let num_coefficients = trace_width + num_constraint_composition_columns;
165        let coefficients = draw_linear_coefficients(public_coin, num_coefficients)?;
166        Ok(Self::new(coefficients, trace_width))
167    }
168
169    /// Generates the random values used in the construction of the DEEP polynomial when algebraic
170    /// batching is used.
171    pub fn draw_algebraic(
172        public_coin: &mut impl RandomCoin<BaseField = E::BaseField>,
173        trace_width: usize,
174        num_constraint_composition_columns: usize,
175    ) -> Result<Self, RandomCoinError> {
176        let num_coefficients = trace_width + num_constraint_composition_columns;
177        let coefficients = draw_algebraic_coefficients(public_coin, num_coefficients)?;
178        Ok(Self::new(coefficients, trace_width))
179    }
180
181    /// Generates the random values used in the construction of the DEEP polynomial when Horner-type
182    /// batching is used.
183    pub fn draw_horner(
184        public_coin: &mut impl RandomCoin<BaseField = E::BaseField>,
185        trace_width: usize,
186        num_constraint_composition_columns: usize,
187    ) -> Result<Self, RandomCoinError> {
188        let num_coefficients = trace_width + num_constraint_composition_columns;
189        let mut coefficients = draw_algebraic_coefficients(public_coin, num_coefficients)?;
190        coefficients.reverse();
191        Ok(Self::new(coefficients, trace_width))
192    }
193}
194
195// HELPER FUNCTIONS
196// ================================================================================================
197
198/// Returns a vector of coefficients built from the provided public coin.
199///
200/// The returned coefficients are drawn uniformly from the provided coin.
201fn draw_linear_coefficients<E: FieldElement>(
202    public_coin: &mut impl RandomCoin<BaseField = E::BaseField>,
203    num_coefficients: usize,
204) -> Result<Vec<E>, RandomCoinError> {
205    (0..num_coefficients).map(|_| public_coin.draw()).collect()
206}
207
208/// Returns a vector of coefficients built from the provided public coin.
209///
210/// A single random value alpha is drawn from the public coin, and the coefficients are computed as
211/// successive powers of this alpha.
212fn draw_algebraic_coefficients<E: FieldElement>(
213    public_coin: &mut impl RandomCoin<BaseField = E::BaseField>,
214    num_coefficients: usize,
215) -> Result<Vec<E>, RandomCoinError> {
216    let alpha: E = public_coin.draw()?;
217    Ok(get_power_series(alpha, num_coefficients))
218}