openvm_pairing_guest/pairing/
miller_step.rsuse core::ops::{Add, Mul, Neg, Sub};
use openvm_algebra_guest::{DivUnsafe, Field};
use openvm_ecc_guest::AffinePoint;
#[cfg(target_os = "zkvm")]
use {
crate::pairing::shifted_funct7,
crate::{PairingBaseFunct7, OPCODE, PAIRING_FUNCT3},
core::mem::MaybeUninit,
openvm_platform::custom_insn_r,
};
use super::{PairingIntrinsics, UnevaluatedLine};
pub trait MillerStep {
type Fp2;
fn miller_double_step(
s: &AffinePoint<Self::Fp2>,
) -> (AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>);
fn miller_add_step(
s: &AffinePoint<Self::Fp2>,
q: &AffinePoint<Self::Fp2>,
) -> (AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>);
#[allow(clippy::type_complexity)]
fn miller_double_and_add_step(
s: &AffinePoint<Self::Fp2>,
q: &AffinePoint<Self::Fp2>,
) -> (
AffinePoint<Self::Fp2>,
UnevaluatedLine<Self::Fp2>,
UnevaluatedLine<Self::Fp2>,
);
}
impl<P> MillerStep for P
where
P: PairingIntrinsics,
for<'a> &'a P::Fp2: Add<&'a P::Fp2, Output = P::Fp2>,
for<'a> &'a P::Fp2: Sub<&'a P::Fp2, Output = P::Fp2>,
for<'a> &'a P::Fp2: Mul<&'a P::Fp2, Output = P::Fp2>,
for<'a> &'a P::Fp2: Neg<Output = P::Fp2>,
{
type Fp2 = <P as PairingIntrinsics>::Fp2;
fn miller_double_step(
s: &AffinePoint<Self::Fp2>,
) -> (AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>) {
#[cfg(not(target_os = "zkvm"))]
{
let one = &Self::Fp2::ONE;
let two = &(one + one);
let three = &(one + two);
let x = &s.x;
let y = &s.y;
let lambda = &((three * x * x).div_unsafe(&(two * y)));
let x_2s = lambda * lambda - two * x;
let y_2s = lambda * &(x - &x_2s) - y;
let two_s = AffinePoint { x: x_2s, y: y_2s };
let b = Self::Fp2::ZERO - lambda;
let c = lambda * x - y;
(two_s, UnevaluatedLine { b, c })
}
#[cfg(target_os = "zkvm")]
{
let mut uninit: MaybeUninit<(AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>)> =
MaybeUninit::uninit();
custom_insn_r!(
OPCODE,
PAIRING_FUNCT3,
shifted_funct7::<P>(PairingBaseFunct7::MillerDoubleStep),
uninit.as_mut_ptr(),
s as *const _,
"x0"
);
unsafe { uninit.assume_init() }
}
}
fn miller_add_step(
s: &AffinePoint<Self::Fp2>,
q: &AffinePoint<Self::Fp2>,
) -> (AffinePoint<Self::Fp2>, UnevaluatedLine<Self::Fp2>) {
let x_s = &s.x;
let y_s = &s.y;
let x_q = &q.x;
let y_q = &q.y;
let x_delta = x_s - x_q;
let lambda = &((y_s - y_q).div_unsafe(&x_delta));
let x_s_plus_q = lambda * lambda - x_s - x_q;
let y_s_plus_q = lambda * &(x_q - &x_s_plus_q) - y_q;
let s_plus_q = AffinePoint {
x: x_s_plus_q,
y: y_s_plus_q,
};
let b = Self::Fp2::ZERO - lambda;
let c = lambda * x_s - y_s;
(s_plus_q, UnevaluatedLine { b, c })
}
fn miller_double_and_add_step(
s: &AffinePoint<Self::Fp2>,
q: &AffinePoint<Self::Fp2>,
) -> (
AffinePoint<Self::Fp2>,
UnevaluatedLine<Self::Fp2>,
UnevaluatedLine<Self::Fp2>,
) {
#[cfg(not(target_os = "zkvm"))]
{
let one = &Self::Fp2::ONE;
let two = &(one + one);
let x_s = &s.x;
let y_s = &s.y;
let x_q = &q.x;
let y_q = &q.y;
let lambda1 = &((y_s - y_q).div_unsafe(&(x_s - x_q)));
let x_s_plus_q = lambda1 * lambda1 - x_s - x_q;
let lambda2 =
&(Self::Fp2::ZERO - lambda1.clone() - (two * y_s).div_unsafe(&(&x_s_plus_q - x_s)));
let x_s_plus_q_plus_s = lambda2 * lambda2 - x_s - &x_s_plus_q;
let y_s_plus_q_plus_s = lambda2 * &(x_s - &x_s_plus_q_plus_s) - y_s;
let s_plus_q_plus_s = AffinePoint {
x: x_s_plus_q_plus_s,
y: y_s_plus_q_plus_s,
};
let b0 = Self::Fp2::ZERO - lambda1;
let c0 = lambda1 * x_s - y_s;
let b1 = Self::Fp2::ZERO - lambda2;
let c1 = lambda2 * x_s - y_s;
(
s_plus_q_plus_s,
UnevaluatedLine { b: b0, c: c0 },
UnevaluatedLine { b: b1, c: c1 },
)
}
#[cfg(target_os = "zkvm")]
{
let mut uninit: MaybeUninit<(
AffinePoint<Self::Fp2>,
UnevaluatedLine<Self::Fp2>,
UnevaluatedLine<Self::Fp2>,
)> = MaybeUninit::uninit();
custom_insn_r!(
OPCODE,
PAIRING_FUNCT3,
shifted_funct7::<P>(PairingBaseFunct7::MillerDoubleAndAddStep),
uninit.as_mut_ptr(),
s as *const _,
q as *const _
);
unsafe { uninit.assume_init() }
}
}
}