winter_air/air/transition/degree.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;
7use core::cmp;
8
9use super::{super::super::ProofOptions, MIN_CYCLE_LENGTH};
10
11// TRANSITION CONSTRAINT DEGREE
12// ================================================================================================
13/// Degree descriptor of a transition constraint.
14///
15/// Describes constraint degree as a combination of multiplications of periodic and trace
16/// columns. For example, degree of a constraint which requires multiplication of two trace
17/// columns can be described as: `base: 2, cycles: []`. A constraint which requires
18/// multiplication of 3 trace columns and a periodic column with a period of 32 steps can be
19/// described as: `base: 3, cycles: [32]`.
20#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct TransitionConstraintDegree {
22 base: usize,
23 cycles: Vec<usize>,
24}
25
26impl TransitionConstraintDegree {
27 /// Creates a new transition constraint degree descriptor for constraints which involve
28 /// multiplications of trace columns only.
29 ///
30 /// For example, if a constraint involves multiplication of two trace columns, `degree`
31 /// should be set to 2. If a constraint involves multiplication of three trace columns,
32 /// `degree` should be set to 3 etc.
33 ///
34 /// # Panics
35 /// Panics if the provided `degree` is zero.
36 pub fn new(degree: usize) -> Self {
37 assert!(degree > 0, "transition constraint degree must be at least one, but was zero");
38 TransitionConstraintDegree { base: degree, cycles: vec![] }
39 }
40
41 /// Creates a new transition degree descriptor for constraints which involve multiplication
42 /// of trace columns and periodic columns.
43 ///
44 /// For example, if a constraint involves multiplication of two trace columns and one
45 /// periodic column with a period length of 32 steps, `base_degree` should be set to 2,
46 /// and `cycles` should be set to `vec![32]`.
47 ///
48 /// # Panics
49 /// Panics if:
50 /// * `base_degree` is zero.
51 /// * Any of the values in the `cycles` vector is smaller than two or is not powers of two.
52 pub fn with_cycles(base_degree: usize, cycles: Vec<usize>) -> Self {
53 assert!(
54 base_degree > 0,
55 "transition constraint degree must be at least one, but was zero"
56 );
57 for (i, &cycle) in cycles.iter().enumerate() {
58 assert!(
59 cycle >= MIN_CYCLE_LENGTH,
60 "cycle length must be at least {MIN_CYCLE_LENGTH}, but was {cycle} for cycle {i}"
61 );
62 assert!(
63 cycle.is_power_of_two(),
64 "cycle length must be a power of two, but was {cycle} for cycle {i}"
65 );
66 }
67 TransitionConstraintDegree { base: base_degree, cycles }
68 }
69
70 /// Computes a degree to which this degree description expands in the context of execution
71 /// trace of the specified length.
72 ///
73 /// The expanded degree is computed as follows:
74 ///
75 /// $$
76 /// b \cdot (n - 1) + \sum_{i = 0}^{k - 1}{\frac{n \cdot (c_i - 1)}{c_i}}
77 /// $$
78 ///
79 /// where: $b$ is the base degree, $n$ is the `trace_length`, $c_i$ is a cycle length of
80 /// periodic column $i$, and $k$ is the total number of periodic columns for this degree
81 /// descriptor.
82 ///
83 /// Thus, evaluation degree of a transition constraint which involves multiplication of two
84 /// trace columns and one periodic column with a period length of 32 steps when evaluated
85 /// over an execution trace of 64 steps would be:
86 ///
87 /// $$
88 /// 2 \cdot (64 - 1) + \frac{64 \cdot (32 - 1)}{32} = 126 + 62 = 188
89 /// $$
90 pub fn get_evaluation_degree(&self, trace_length: usize) -> usize {
91 let mut result = self.base * (trace_length - 1);
92 for cycle_length in self.cycles.iter() {
93 result += (trace_length / cycle_length) * (cycle_length - 1);
94 }
95 result
96 }
97
98 /// Returns a minimum blowup factor needed to evaluate constraint of this degree.
99 ///
100 /// This is guaranteed to be a power of two, greater than one.
101 pub fn min_blowup_factor(&self) -> usize {
102 // The blowup factor needs to be a power of two large enough to accommodate degree of
103 // transition constraints defined by rational functions `C(x) / z(x)` where `C(x)` is the
104 // constraint polynomial and `z(x)` is the transition constraint divisor.
105 //
106 // Degree of `C(x)` is always smaller than or equal to `[self.base + self.cycles.len()] * [trace_length - 1]`.
107 // Degree of `z(x)` is `[trace_length - 1]`. Thus, the degree of `C(x) / z(x)` is
108 // `[self.base + self.cycles.len() - 1] * [trace_length - 1]` and the blowup factor needed
109 // to accommodate this degree can be estimated as `self.base + self.cycles.len() - 1`.
110 //
111 // For example, if degree of our constraints is 6, the blowup factor would need to be 8.
112 // However, if the degree is 5, the blowup factor could be as small as 4.
113 let degree_bound = self.base + self.cycles.len() - 1;
114 cmp::max(degree_bound.next_power_of_two(), ProofOptions::MIN_BLOWUP_FACTOR)
115 }
116}