tasm_lib/verifier/fri/collinear_y.rs
1use triton_vm::prelude::*;
2
3use crate::prelude::*;
4
5#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
6pub struct CollinearYXfe;
7
8impl BasicSnippet for CollinearYXfe {
9 fn inputs(&self) -> Vec<(DataType, String)> {
10 ["p_2_x", "p_1_y", "p_1_x", "p_0_y", "p_0_x"]
11 .map(|s| (DataType::Xfe, s.to_string()))
12 .to_vec()
13 }
14
15 fn outputs(&self) -> Vec<(DataType, String)> {
16 vec![(DataType::Xfe, "p_2_y".to_owned())]
17 }
18
19 fn entrypoint(&self) -> String {
20 "tasmlib_verifier_fri_collinear_y_xfe".to_owned()
21 }
22
23 // Original:
24 // let dy = p0.1 - p1.1;
25 // let dx = p0.0 - p1.0;
26 // let p2_y_times_dx = dy * (p2_x - p0.0) + dx * p0.1;
27
28 // // Can we implement this without division?
29 // p2_y_times_dx / dx
30
31 // let dy = a_y - b_y;
32 // let dx = a_x - b_x;
33 // let p2_y_times_dx = dy * (c_x - a_x) + dx * a_y;
34
35 // p2_y_times_dx / dx
36
37 // So we want:
38 // p2_y_times_dx = ((a_y - b_y) * (c_x - a_x) + (a_x - b_x) * a_y) / dx
39 // Calculate the inner parenthesis first.
40 // So first (a_y - b_y), then (c_x - a_x), then
41
42 fn code(&self, _library: &mut Library) -> Vec<LabelledInstruction> {
43 triton_asm!(
44 // BEFORE: _ [p2x; 3] [p1y; 3] [p1x; 3] [p0y; 3] [p0x; 3]
45 // AFTER: _ [p2y; 3]
46 {self.entrypoint()}:
47 swap 9 // _ [p2x; 3] p1y2 p1y1 p0x0 [p1x; 3] [p0y; 3] p0x2 p0x1 p1y0
48 swap 1 // _ [p2x; 3] p1y2 p1y1 p0x0 [p1x; 3] [p0y; 3] p0x2 p1y0 p0x1
49 swap 10 // _ [p2x; 3] p1y2 p0x1 p0x0 [p1x; 3] [p0y; 3] p0x2 p1y0 p1y1
50 swap 2 // _ [p2x; 3] p1y2 p0x1 p0x0 [p1x; 3] [p0y; 3] p1y1 p1y0 p0x2
51 swap 11 // _ [p2x; 3] [p0x; 3] [p1x; 3] [p0y; 3] p1y1 p1y0 p1y2
52 swap 2 // _ [p2x; 3] [p0x; 3] [p1x; 3] [p0y; 3] p1y2 p1y0 p1y1
53 swap 1 // _ [p2x; 3] [p0x; 3] [p1x; 3] [p0y; 3] [p1y; 3]
54 dup 5 dup 5 dup 5
55 // _ [p2x; 3] [p0x; 3] [p1x; 3] [p0y; 3] [p1y; 3] [p0y; 3]
56 push -1
57 xb_mul // _ [p2x; 3] [p0x; 3] [p1x; 3] [p0y; 3] [p1y; 3] [-p0y; 3]
58 xx_add // _ [p2x; 3] [p0x; 3] [p1x; 3] [p0y; 3] [p1y - p0y; 3]
59 push -1
60 xb_mul // dy = p0y - p1y
61 // _ [p2x; 3] [p0x; 3] [p1x; 3] [p0y; 3] [dy; 3]
62
63 swap 6 // _ [p2x; 3] [p0x; 3] p1x2 p1x1 dy0 [p0y; 3] dy2 dy1 p1x0
64 swap 1 // _ [p2x; 3] [p0x; 3] p1x2 p1x1 dy0 [p0y; 3] dy2 p1x0 dy1
65 swap 7 // _ [p2x; 3] [p0x; 3] p1x2 dy1 dy0 [p0y; 3] dy2 p1x0 p1x1
66 swap 2 // _ [p2x; 3] [p0x; 3] p1x2 dy1 dy0 [p0y; 3] p1x1 p1x0 dy2
67 swap 8 // _ [p2x; 3] [p0x; 3] [dy; 3] [p0y; 3] p1x1 p1x0 p1x2
68 swap 2 // _ [p2x; 3] [p0x; 3] [dy; 3] [p0y; 3] p1x2 p1x0 p1x1
69 swap 1 // _ [p2x; 3] [p0x; 3] [dy; 3] [p0y; 3] [p1x; 3]
70 dup 11 dup 11 dup 11
71 // _ [p2x; 3] [p0x; 3] [dy; 3] [p0y; 3] [p1x; 3] [p0x; 3]
72 push -1
73 xb_mul // _ [p2x; 3] [p0x; 3] [dy; 3] [p0y; 3] [p1x; 3] [-p0x; 3]
74 xx_add // _ [p2x; 3] [p0x; 3] [dy; 3] [p0y; 3] [p1x - p0x; 3]
75 push -1
76 xb_mul // dx = p0x - p1x
77 // _ [p2x; 3] [p0x; 3] [dy; 3] [p0y; 3] [dx; 3]
78
79 swap 12 swap 1 swap 13 swap 2 swap 14 swap 2 swap 1
80 // _ [dx; 3] [p0x; 3] [dy; 3] [p0y; 3] [p2x; 3]
81 swap 3 swap 1 swap 4 swap 2 swap 5 swap 2 swap 1
82 // _ [dx; 3] [p0x; 3] [dy; 3] [p2x; 3] [p0y; 3]
83 swap 12 swap 1 swap 13 swap 2 swap 14 swap 2 swap 1
84 // _ [p0y; 3] [p0x; 3] [dy; 3] [p2x; 3] [dx; 3]
85 swap 9 swap 1 swap 10 swap 2 swap 11 swap 2 swap 1
86 // _ [p0y; 3] [dx; 3] [dy; 3] [p2x; 3] [p0x; 3]
87 push -1
88 xb_mul
89 xx_add // _ [p0y; 3] [dx; 3] [dy; 3] [p2x - p0x; 3]
90 xx_mul // a = (p2x - p0x) * dy
91 // _ [p0y; 3] [dx; 3] [a; 3]
92
93 swap 6 swap 1 swap 7 swap 2 swap 8 swap 2 swap 1
94 // _ [a; 3] [dx; 3] [p0y; 3]
95 dup 5 dup 5 dup 5
96 // _ [a; 3] [dx; 3] [p0y; 3] [dx; 3]
97 xx_mul // b = p0y * dx
98 // _ [a; 3] [dx; 3] [b; 3]
99
100 swap 3 swap 1 swap 4 swap 2 swap 5 swap 2 swap 1
101 // _ [a; 3] [b; 3] [dx; 3]
102 swap 6 swap 1 swap 7 swap 2 swap 8 swap 2 swap 1
103 // _ [dx; 3] [b; 3] [a; 3]
104 xx_add // c = a + b
105 // _ [dx; 3] [c; 3]
106
107 x_invert // _ [dx; 3] [1/c; 3]
108 xx_mul // _ [dx/c; 3]
109 x_invert // _ [c/dx; 3]
110 // _ [p2y; 3]
111 return
112 )
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use twenty_first::math::polynomial::Polynomial;
119
120 use super::*;
121 use crate::test_prelude::*;
122
123 impl Closure for CollinearYXfe {
124 type Args = (
125 XFieldElement,
126 XFieldElement,
127 XFieldElement,
128 XFieldElement,
129 XFieldElement,
130 );
131
132 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
133 let (p2x, p1y, p1x, p0y, p0x) = pop_encodable::<Self::Args>(stack);
134 let p2y = Polynomial::get_colinear_y((p0x, p0y), (p1x, p1y), p2x);
135 push_encodable(stack, &p2y);
136 }
137
138 fn pseudorandom_args(&self, seed: [u8; 32], _: Option<BenchmarkCase>) -> Self::Args {
139 StdRng::from_seed(seed).random()
140 }
141 }
142
143 #[test]
144 fn test() {
145 ShadowedClosure::new(CollinearYXfe).test()
146 }
147}
148
149#[cfg(test)]
150mod bench {
151 use super::*;
152 use crate::test_prelude::*;
153
154 #[test]
155 fn benchmark() {
156 ShadowedClosure::new(CollinearYXfe).bench();
157 }
158}