# Sin7Y Tech Review (25): STARK - An Indepth Technical Analysis ![](https://i.imgur.com/3u2vXKD.png) ## Step1 - Build trace (fib2-example) | <span style="color:red">1</span>| <span style="color:red">1</span> | | -------- | -------- | | 2 | 3 | |5 |8 | | 13 | 21 | | 34 |55 | | 89 | 144 | | 233 |377 | |610 | <span style="color:red">987</span> | The numbers marked in <span style="color:red">red</span> are public info ``` Some assertion: Form: [register, step, value] examples: [0,0,1], [1,0,1],[1,7,987] ``` ## Step2 - Prover for Trace Selection of the protocol parameter: ``` pub struct ProofOptions { num_queries: u8, // number of queries to increase reliability blowup_factor: u8, // domain extension factor grinding_factor: u8, // ?nonce security parameter, for the security selection of query position hash_fn: HashFunction, // Hash Function blake3-259/192, sha3-256 field_extension: FieldExtension, // Whether the field extension is conducted fri_folding_factor: u8, // The folding factor of Fri protocol 4-8-16 fri_max_remainder_size: u8, // The max remainder of Fri protocol } ``` ### 1. AIR Instantiation ``` FibAir { context: AirContext::new(trace_info, degrees, options), result: pub_inputs, } AirContext { options, // protocol parameters trace_info, // trace parameters: row number and col number transition_constraint_degrees, // transition the constraint degree, and if the multiplication of two registers is involved, then degree = 2; similarly, if the multiplication of three registers is involved, then degree = 3; if periodic column exists, then degree = base + period.length – 1 ce_blowup_factor, // constraint computational domain extension factor trace_domain < ce_domain < lde_domain trace_domain_generator: B::get_root_of_unity(log2(trace_length)), lde_domain_generator: B::get_root_of_unity(log2(lde_domain_size)), } ``` #### 2. Verify the consistency of AIR and Trace (Debug module) #### 2.1 Verify basic parameters ``` Trace.width = air.trace_width ``` #### 2.2 Verify the validity of assertion (boundary cs) ``` Trace[assertion_i.register][assertion_i.step] = assertion_i.value ``` #### 2.3 Verify if Trace holds transition cs(Debug module) ``` Loop: For every two adjacent rows: pub struct EvaluationFrame<E: FieldElement> { current: Vec<E>, next: Vec<E>, } Holds: next[0] == cur[0] + cur[1] next[1] == next[0] + cur[1] The number of times of Loop: Trace.length - 1 ``` #### Transcript ``` write.into(air, public info) ``` ### 3. Commit for trace Domain parameter selection: ``` StarkDomain { trace_twiddles, /ntt twiddle factor ce_domain_size: air.ce_domain_size(), //constraint computational domain ce_to_lde_blowup: air.lde_domain_size() / air.ce_domain_size(), // LDE domain domain_offset: air.domain_offset(), //domain offset } ``` #### 3.1 Interpolate -> LDE -> evaluate over LDE-domain ![](https://i.imgur.com/yTogPgb.png) #### 3.2 Commitment ![](https://i.imgur.com/LDJhVo5.png) #### Transcript ``` write.into(cm_to_trace) ``` ### 4.Evaluate CS #### 4.1 Obtain Linear Composition Coefficients ``` Ok(ConstraintCompositionCoefficients { transition: t_coefficients, boundary: b_coefficients, }) ``` The number of coefficients is consistent with that of constraints In this example (fib2-example), there are 2 transition cs and 3 boundary cs. #### 4.2 Establish the evaluator for t-cs and b-cs ##### 4.2.1 t-cs ``` 1. Obtain the degree of t-cs (In this example, the degree is [1,1], refer to Chapter 2.3) 2. Establish the t-cs group (record the parameters needed for reaching the object of degree -> compose degree(ce_domain_size - 1) Loop: Calculate the evaluate-degree = base * (trace.length - 1) + tracce.length / period.cycle *(period.length - 1) of every t-cs Establish the t-cs group according to the degree: TransitionConstraintGroup { degree, // the degree of t-cs degree_adjustment, // The space to reach the object degree, target_degree = composition_degree + trace_poly_degree(vanish poly-degree), degree_adjustment = (target_degree - evaluation_degree) indexes: vec![], coefficients: vec![], } Record index and distribution coefficient “coef” Cycle each t-cs (In fib2-example, cycle twice) 3. Establish the period value table 4. Set the divisor for t-cs, with all t-cs having the same form z(x) = x^n-1 / x - g^{n-1} // The last value does not satisfy the condition ``` ##### 4.2.2 b-cs ``` 1. The divisor of each b-cs is not necessarily the same 2. Judge that if the number of assertions is the same as the number of coefficients to be distributed assertion.len() == coefficients.len() 3. Establish the b-cs group Loop: Obtain the type and initial step of the assertion Establish the b-cs group BoundaryConstraintGroup { constraints: Vec::new(), divisor, // The divisor corresponding to the boundary degree_adjustment, target//The space to reach the object degree, target_degree = composition_degree + divisor.degree(),degree_adjustment = (target_degree - trace_poly_degree) } Add b-cs forms air::BoundaryConstraint { register: assertion.register, // Corresponding register index poly, // assertion value polynomial, interpolation is required for multiple values; otherwise, it is a single value poly_offset, //offset information. If the assert is in the first step, it is [0,1], otherwise it is [1, T] cc, // Coefficient distributed to this b-cs } prover::BoundaryConstraintGroup { degree_adjustment: group.degree_adjustment(), single_value_constraints: Vec::new(),// corresponding Sigle value assertion small_poly_constraints: Vec::new(),//assertion whose assertion value num is smaller than 63 large_poly_constraints: Vec::new(),//assertion whose assertion value num is larger than 63, the values in ce_domain are needed to conduct Pre_compute }; ``` #### 4.3 Evaluate t/s-cs over ce_domain ##### 4.3.1 Define evaluator table ``` ConstraintEvaluationTable<B: StarkField, E: FieldElement<BaseField = B>> { evaluations: Vec<Vec<E>>, //[ce_domain_size][t_cs_merge_value (0): b_cs_values(1...)] divisors: Vec<ConstraintDivisor<B>>, // [t-cs divisor, b-cs divisor] domain_offset: B, trace_length: usize, #[cfg(debug_assertions)] t_evaluations: Vec<Vec<B>>, #[cfg(debug_assertions)] t_expected_degrees: Vec<usize>, } evaluations[step_i][0] += sum_{j}(evaluation[j] * (coefficients.0 + coefficients.1 * xp) // The divisor is identical. evaluations[step_i][j] += (evframe.cur().state[register] - value) * (coefficients.0 + coefficients.1 * xp) // for single assertion evaluations[step_i][j] += (evframe.cur().state[register] - polynom::eval(&self.poly, x * self.x_offset)) * (coefficients.0 + coefficients.1 * xp) // for multiassertion // for multi-assertion evaluations[step_i][j] += (evframe.cur().state[register] - self.values[values_index]) * (coefficients.0 + coefficients.1 * xp) // for multiassertion // for multi-assertion large poly ``` ### 5. Commitment to Evaluate CS #### 5.1 Establish constraints composition polynomial ![](https://i.imgur.com/4LQ5jqP.png) #### 5.2 commitment to composition poly Example: Compose_poly = a * x^3 + b * x^2 + c * x + d = (a * x^2 + c) * x^ + (b * x^2 + d) (a * x^2 + c) and (b *x^2 +d) correspond to two columns, respectively. ![](https://i.imgur.com/UFMx9gj.png) ### 6. Establish DEEP composition polynomial The general formal: f(x) = q(x)* t(x) Need check at random z 1. f(z) = q(z) * t(z) 2. f(x),q(x),t(x) indeed equal respectively f(z), q(z), t(z) 3. calculate Deep_composition = (q(x) - q(z)) / (x - z) 4. Check LDT for q_q(x) #### 6.1 Select z which out of domain(ood) Draw an out-of-domain point z. Depending on the type of E, the point is drawn either from the base field or from an extension field defined by E. The purpose of sampling from the extension field here (instead of the base field) is to increase security #### 6.2 evaluate trace and constraint polynomials at the OOD point z ##### 6.2.1 trace_poly at z & z * g | <span style="color:red">1</span>| <span style="color:red">1</span> | | -------- | -------- | | 2 | 3 | |5 |8 | | 13 | 21 | | 34 |55 | | 89 | 144 | | 233 |377 | |610 | <span style="color:red">987</span> | | trace_poly_0 |trace_poly_1 | ``` ood_frame = {cur: [trace_poly_0(z), trace_poly_1(z)], next: [trace_poly_0(z * g), trace_poly_1(z * g)]} ``` ##### 6.2.2 composition poly at z ``` iter!(self.columns).map(|p| polynom::eval(p, z^m)).collect() // m is the column num of the composition poly ``` #### 6.3 Establish Deep composition polynomial ##### 6.3.1 Generate random numbers ``` pub struct DeepCompositionCoefficients<E: FieldElement> { /// Trace polynomial composition coefficients $\alpha_i$, $\beta_i$, and $\gamma_i$. pub trace: Vec<(E, E, E)>, /// Constraint column polynomial composition coefficients $\delta_j$. pub constraints: Vec<E>, /// Degree adjustment composition coefficients $\lambda$ and $\mu$. pub degree: (E, E), } ``` ##### 6.3.2 cal quotient poly ``` => for trace polynomial T`(x) = alpha * (T(x) - T(z)) // degree = trace.length - 1 T``(x) = beta * (T(x) - T(z * g)) T```(x) = gamma * (T(x) - T(z_conjugate)) merge_trace_composition_poly = T(x) / (x - z) + T``(x) / (x - z * g) + T```(x) / (x - z_conjugate) Degree = trace.lengh - 2 => for composition polynomial compute H'_i(x) = (H_i(x) - H_i(z^m)) / (x - z^m) sum(H`_i(x) * cc_i) Deep_composition_polynomial = merge_trace_composition_poly + sum(H`_i(x) * cc_i) Degree = trace.length - 2 => Deep_composition_polynomial degree adjustment Deep_composition_polynomial = Deep_composition_polynomial * (cc_0 + x * cc_1) Degree = trace.length – 1 ``` #### 6.4 Evaluate Deep over LDE ``` deep_evaluations<lde_domain_size> = deep_composition_poly.evaluate(&domain); ``` ### 7. Calculate the FRI Layer num of Deep ``` trace.length() = fold_factor ^ Layer_num + remainder_size; fold_factor = {4, 8, 16} remainder_size < remainder_max_size == 256 ``` ![](https://i.imgur.com/k3m21If.png) ### 8. Determine positions of the query Select multiple positions of the query from lde_domain. ``` fold_position = source_position % (fold_domain) fold_domain = source_domain / fold_factor ``` ### 9. Establish proof objects #### 9.1 Generate FRI proof ``` pub struct FriProof { layers: Vec<FriProofLayer>, remainder: Vec<u8>, // last poly <all coefficients> num_partitions: u8, // stored as power of 2 } pub struct FriProofLayer { values: Vec<u8>, paths: Vec<u8>, } ``` ![](https://i.imgur.com/rnksZVM.png) #### 9.2 Query trace poly at above positions Similar to the above ``` Queries::new(trace_proof, trace_states) ``` #### 9.3 Query constraint poly at above positions Similar to the above ``` Queries::new(merkle_proof, evaluations) ``` #### 9.4 Establish the STARK Proof ``` StarkProof { context: self.context, commitments: self.commitments, ood_frame: self.ood_frame, trace_queries, constraint_queries, fri_proof, pow_nonce: self.pow_nonce, } ``` ## Step3 - Verify the proof Read pub-info from the transcript to obtain relevant data, and then to execute the verification process. ### 1.Ood consistency check Verify the consistency of the mathematical relationship described in Chapter 5.2 ``` => for Boundary b(z) = q_b(x) * b_divisor(z) => for composition poly t(z) = q_z(x) * t_divisor(z) ``` ### 2. Instantiate the FRI-verifier object ``` pub struct FriVerifier<B, E, C, H> where B: StarkField, E: FieldElement<BaseField = B>, C: VerifierChannel<E, Hasher = H>, H: ElementHasher<BaseField = B>, { max_poly_degree: usize, domain_size: usize, domain_generator: B, layer_commitments: Vec<H::Digest>, //flod_poly commitment layer_alphas: Vec<E>, // random numbers options: FriOptions, num_partitions: usize, _channel: PhantomData<C>, } ``` ### 3. Calculate Deep poly on query positions The calculating method is the same as that in Chapter 6.4 ### 4. Execute the FRI VERIFY process ![](https://i.imgur.com/rIXsHSe.png) ![](https://i.imgur.com/rglOJ2R.png)