openvm_pairing_guest/pairing/
miller_step.rs
1use core::ops::{Add, Mul, Neg, Sub};
2
3use openvm_algebra_guest::{DivUnsafe, Field};
4use openvm_ecc_guest::AffinePoint;
5
6use super::{PairingIntrinsics, UnevaluatedLine};
7
8pub trait MillerStep {
10 type Fp2;
11
12 fn miller_double_step(
14 s: &AffinePoint<Self::Fp2>,
15 ) -> (AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>);
16
17 fn miller_add_step(
19 s: &AffinePoint<Self::Fp2>,
20 q: &AffinePoint<Self::Fp2>,
21 ) -> (AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>);
22
23 #[allow(clippy::type_complexity)]
25 fn miller_double_and_add_step(
26 s: &AffinePoint<Self::Fp2>,
27 q: &AffinePoint<Self::Fp2>,
28 ) -> (
29 AffinePoint<Self::Fp2>,
30 UnevaluatedLine<Self::Fp2>,
31 UnevaluatedLine<Self::Fp2>,
32 );
33}
34
35impl<P> MillerStep for P
36where
37 P: PairingIntrinsics,
38 for<'a> &'a P::Fp2: Add<&'a P::Fp2, Output = P::Fp2>,
39 for<'a> &'a P::Fp2: Sub<&'a P::Fp2, Output = P::Fp2>,
40 for<'a> &'a P::Fp2: Mul<&'a P::Fp2, Output = P::Fp2>,
41 for<'a> &'a P::Fp2: Neg<Output = P::Fp2>,
42{
43 type Fp2 = <P as PairingIntrinsics>::Fp2;
44
45 fn miller_double_step(
53 s: &AffinePoint<Self::Fp2>,
54 ) -> (AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>) {
55 let two: &Self::Fp2 = &<P as PairingIntrinsics>::FP2_TWO;
56 let three: &Self::Fp2 = &<P as PairingIntrinsics>::FP2_THREE;
57
58 let x = &s.x;
59 let y = &s.y;
60 let lambda = &((three * x * x).div_unsafe(&(two * y)));
62 let x_2s = lambda * lambda - two * x;
64 let y_2s = lambda * &(x - &x_2s) - y;
66 let two_s = AffinePoint { x: x_2s, y: y_2s };
67
68 let b = Self::Fp2::ZERO - lambda;
70 let c = lambda * x - y;
71
72 (two_s, UnevaluatedLine { b, c })
73 }
74
75 fn miller_add_step(
78 s: &AffinePoint<Self::Fp2>,
79 q: &AffinePoint<Self::Fp2>,
80 ) -> (AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>) {
81 let x_s = &s.x;
82 let y_s = &s.y;
83 let x_q = &q.x;
84 let y_q = &q.y;
85
86 let x_delta = x_s - x_q;
88 let lambda = &((y_s - y_q).div_unsafe(&x_delta));
89 let x_s_plus_q = lambda * lambda - x_s - x_q;
90 let y_s_plus_q = lambda * &(x_q - &x_s_plus_q) - y_q;
91
92 let s_plus_q = AffinePoint {
93 x: x_s_plus_q,
94 y: y_s_plus_q,
95 };
96
97 let b = Self::Fp2::ZERO - lambda;
99 let c = lambda * x_s - y_s;
100
101 (s_plus_q, UnevaluatedLine { b, c })
102 }
103
104 fn miller_double_and_add_step(
109 s: &AffinePoint<Self::Fp2>,
110 q: &AffinePoint<Self::Fp2>,
111 ) -> (
112 AffinePoint<Self::Fp2>,
113 UnevaluatedLine<Self::Fp2>,
114 UnevaluatedLine<Self::Fp2>,
115 ) {
116 let two = &Self::FP2_TWO;
117
118 let x_s = &s.x;
119 let y_s = &s.y;
120 let x_q = &q.x;
121 let y_q = &q.y;
122
123 let lambda1 = &((y_s - y_q).div_unsafe(&(x_s - x_q)));
125 let x_s_plus_q = lambda1 * lambda1 - x_s - x_q;
126
127 let lambda2 =
129 &(Self::Fp2::ZERO - lambda1.clone() - (two * y_s).div_unsafe(&(&x_s_plus_q - x_s)));
130 let x_s_plus_q_plus_s = lambda2 * lambda2 - x_s - &x_s_plus_q;
131 let y_s_plus_q_plus_s = lambda2 * &(x_s - &x_s_plus_q_plus_s) - y_s;
132
133 let s_plus_q_plus_s = AffinePoint {
134 x: x_s_plus_q_plus_s,
135 y: y_s_plus_q_plus_s,
136 };
137
138 let b0 = Self::Fp2::ZERO - lambda1;
140 let c0 = lambda1 * x_s - y_s;
141
142 let b1 = Self::Fp2::ZERO - lambda2;
144 let c1 = lambda2 * x_s - y_s;
145
146 (
147 s_plus_q_plus_s,
148 UnevaluatedLine { b: b0, c: c0 },
149 UnevaluatedLine { b: b1, c: c1 },
150 )
151 }
152}