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}