Skip to content

Commit

Permalink
feat: use precompiles
Browse files Browse the repository at this point in the history
  • Loading branch information
0xWOLAND authored Aug 20, 2024
2 parents 6a396b0 + f930e89 commit 0d49c57
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 409 deletions.
54 changes: 34 additions & 20 deletions src/fp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,14 +324,15 @@ impl Fp {
Fp(v)
}

pub(crate) fn pow_vartime_unconstrained(&self, by: &[u64; 6]) -> Self {
/// CPU version of the exponentiation operation. Necessary to prevent syscalls in unconstrained mode.
pub(crate) fn cpu_pow_vartime(&self, by: &[u64; 6]) -> Self {
let mut res = Self::one();
for e in by.iter().rev() {
for i in (0..64).rev() {
res = res._mul(&res);
res = res.cpu_mul(&res);

if ((*e >> i) & 1) == 1 {
res = res._mul(self);
res = res.cpu_mul(self);
}
}
}
Expand All @@ -356,13 +357,14 @@ impl Fp {
}

#[inline]
pub(crate) fn _sqrt(&self) -> CtOption<Self> {
/// CPU version of the square-root operation. Necessary to prevent syscalls in unconstrained mode.
pub(crate) fn cpu_sqrt(&self) -> CtOption<Self> {
// We use Shank's method, as p = 3 (mod 4). This means
// we only need to exponentiate by (p+1)/4. This only
// works for elements that are actually quadratic residue,
// so we check that we got the correct result at the end.

let sqrt = self.pow_vartime(&[
let sqrt = self.cpu_pow_vartime(&[
0xee7f_bfff_ffff_eaab,
0x07aa_ffff_ac54_ffff,
0xd9cc_34a8_3dac_3d89,
Expand All @@ -371,7 +373,7 @@ impl Fp {
0x0680_447a_8e5f_f9a6,
]);

CtOption::new(sqrt, sqrt._square().ct_eq(self))
CtOption::new(sqrt, sqrt.cpu_square().ct_eq(self))
}

#[inline]
Expand All @@ -381,7 +383,7 @@ impl Fp {
// Compute the square root using the zkvm syscall
unconstrained! {
let mut buf = [0u8; 49]; // Allocate 49 bytes to include the flag
self._sqrt().map(|root| {
self.cpu_sqrt().map(|root| {
buf[0..48].copy_from_slice(&root.to_bytes());
buf[48] = 1; // Set the flag to 1 indicating the result is valid
});
Expand All @@ -400,14 +402,15 @@ impl Fp {
}
#[cfg(not(target_os = "zkvm"))]
{
self._sqrt()
self.cpu_sqrt()
}
}

#[inline]
pub(crate) fn _invert(&self) -> CtOption<Self> {
/// CPU version of the inversion operation. Necessary to prevent syscalls in unconstrained mode.
pub(crate) fn cpu_invert(&self) -> CtOption<Self> {
// Exponentiate by p - 2
let inv = self.pow_vartime_unconstrained(&[
let inv = self.cpu_pow_vartime(&[
0xb9fe_ffff_ffff_aaa9,
0x1eab_fffe_b153_ffff,
0x6730_d2a0_f6b0_f624,
Expand All @@ -425,7 +428,7 @@ impl Fp {
// Compute the inverse using the zkvm syscall
unconstrained! {
let mut buf = [0u8; 49];
self._invert().map(|inv| {
self.cpu_invert().map(|inv| {
buf[0..48].copy_from_slice(&inv.to_bytes());
buf[48] = 1;
});
Expand All @@ -444,7 +447,7 @@ impl Fp {
}
#[cfg(not(target_os = "zkvm"))]
{
self._invert()
self.cpu_invert()
}
}

Expand Down Expand Up @@ -480,7 +483,9 @@ impl Fp {
}
}

pub(crate) fn _add(&self, rhs: &Fp) -> Fp {
#[inline]
/// CPU version of the addition operation. Necessary to prevent syscalls in unconstrained mode.
pub(crate) fn cpu_add(&self, rhs: &Fp) -> Fp {
let (d0, carry) = adc(self.0[0], rhs.0[0], 0);
let (d1, carry) = adc(self.0[1], rhs.0[1], carry);
let (d2, carry) = adc(self.0[2], rhs.0[2], carry);
Expand All @@ -503,12 +508,13 @@ impl Fp {
}
out
} else {
self._add(rhs)
self.cpu_add(rhs)
}
}
}

pub(crate) fn _neg(&self) -> Fp {
/// CPU version of the negation operation. Necessary to prevent syscalls in unconstrained mode.
pub(crate) fn cpu_neg(&self) -> Fp {
let (d0, borrow) = sbb(MODULUS[0], self.0[0], 0);
let (d1, borrow) = sbb(MODULUS[1], self.0[1], borrow);
let (d2, borrow) = sbb(MODULUS[2], self.0[2], borrow);
Expand Down Expand Up @@ -542,7 +548,7 @@ impl Fp {
}
out
} else {
self._neg()
self.cpu_neg()
}
}
}
Expand Down Expand Up @@ -573,6 +579,12 @@ impl Fp {
}
}

#[inline]
/// CPU version of the subtraction operation. Necessary to prevent syscalls in unconstrained mode.
pub(crate) fn cpu_sub(&self, rhs: &Fp) -> Fp {
self.cpu_add(&rhs.cpu_neg())
}

/// Returns `c = a.zip(b).fold(0, |acc, (a_i, b_i)| acc + a_i * b_i)`.
///
/// Uses precompiles to calculate it naively but much more cheaply.
Expand Down Expand Up @@ -740,7 +752,8 @@ impl Fp {
}

#[inline]
pub(crate) fn _mul(&self, rhs: &Fp) -> Fp {
/// CPU version of the multiplication operation. Necessary to prevent syscalls in unconstrained mode.
pub(crate) fn cpu_mul(&self, rhs: &Fp) -> Fp {
let (t0, carry) = mac(0, self.0[0], rhs.0[0], 0);
let (t1, carry) = mac(0, self.0[0], rhs.0[1], carry);
let (t2, carry) = mac(0, self.0[0], rhs.0[2], carry);
Expand Down Expand Up @@ -797,7 +810,7 @@ impl Fp {
out.mul_r_inv_internal();
out
} else {
self._mul(rhs)
self.cpu_mul(rhs)
}
}
}
Expand Down Expand Up @@ -839,7 +852,8 @@ impl Fp {
self.mul_r_inv_internal();
}

pub(crate) fn _square(&self) -> Self {
/// CPU version of the squaring operation. Necessary to prevent syscalls in unconstrained mode.
pub(crate) fn cpu_square(&self) -> Self {
let (t1, carry) = mac(0, self.0[0], self.0[1], 0);
let (t2, carry) = mac(0, self.0[0], self.0[2], carry);
let (t3, carry) = mac(0, self.0[0], self.0[3], carry);
Expand Down Expand Up @@ -900,7 +914,7 @@ impl Fp {
out.mul_r_inv_internal();
out
} else {
self._square()
self.cpu_square()
}
}
}
Expand Down
33 changes: 6 additions & 27 deletions src/fp12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ use core::fmt;
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "pairings")]
use rand_core::RngCore;

#[cfg(target_os = "zkvm")]
use sp1_lib::{
io::{hint_slice, read_vec},
unconstrained,
};

#[cfg(feature = "pairings")]
use rand_core::RngCore;

/// This represents an element $c_0 + c_1 w$ of $\mathbb{F}_{p^12} = \mathbb{F}_{p^6} / w^2 - v$.
pub struct Fp12 {
pub c0: Fp6,
Expand Down Expand Up @@ -300,37 +300,16 @@ impl Fp12 {
Fp12 { c0, c1 }
}

pub(crate) fn _invert(&self) -> CtOption<Self> {
#[inline]
pub fn invert(&self) -> CtOption<Self> {
(self.c0.square() - self.c1.square().mul_by_nonresidue())
._invert()
.invert()
.map(|t| Fp12 {
c0: self.c0 * t,
c1: self.c1 * -t,
})
}

#[inline]
pub fn invert(&self) -> CtOption<Self> {
// #[cfg(target_os = "zkvm")]
// {
// // Compute the inverse using the zkvm syscall
// unconstrained! {
// let mut buf = [0u8; 576];
// buf.copy_from_slice(&self._invert().unwrap().to_bytes());
// hint_slice(&buf);
// }

// let byte_vec = read_vec();
// let bytes: [u8; 576] = byte_vec.try_into().unwrap();
// let inv = Fp12::from_bytes(&bytes).unwrap();
// CtOption::new(inv, !self.is_zero() & (self * inv).ct_eq(&Fp12::one()))
// }
// #[cfg(not(target_os = "zkvm"))]
{
self._invert()
}
}

#[inline]
pub fn to_bytes(&self) -> [u8; 576] {
let mut res = [0; 576];
Expand Down
Loading

0 comments on commit 0d49c57

Please sign in to comment.