From eaaffcb3ee88ba481f51c29e3c1f406b0af2f50e Mon Sep 17 00:00:00 2001 From: Jimmy Chu <898091+jimmychu0807@users.noreply.github.com> Date: Wed, 12 Nov 2025 19:23:54 +0800 Subject: [PATCH] Add support for zisk precompiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: agnusmor Co-authored-by: Héctor Masip Ardevol <68732820+hecmas@users.noreply.github.com> Co-authored-by: Artiom Tretjakovas --- Cargo.lock | 43 ++++++ Cargo.toml | 7 + src/fp.rs | 168 +++++++++++++++++++++++- src/fp12.rs | 4 + src/fp2.rs | 118 ++++++++++++++++- src/fp6.rs | 3 +- src/g1.rs | 251 +++++++++++++++++++++++++----------- src/g2.rs | 10 +- src/hash_to_curve/map_g1.rs | 10 ++ src/hash_to_curve/map_g2.rs | 9 ++ src/pairings.rs | 4 + src/scalar.rs | 202 ++++++++++++++++++++++------- 12 files changed, 695 insertions(+), 134 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8732f5e..fb4dc5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,6 +113,7 @@ dependencies = [ "sp1-lib", "subtle", "zeroize", + "ziskos", "zkm-lib", ] @@ -262,6 +263,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.6" @@ -462,6 +469,11 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lib-c" +version = "0.13.0" +source = "git+https://github.com/0xPolygonHermez/zisk.git?tag=v0.13.0#ea1ed4c518992a170fc59ec19f1228eb4829a9e1" + [[package]] name = "libc" version = "0.2.175" @@ -1113,6 +1125,12 @@ dependencies = [ "syn", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strength_reduce" version = "0.2.4" @@ -1151,6 +1169,15 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinytemplate" version = "1.2.1" @@ -1449,6 +1476,22 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +[[package]] +name = "ziskos" +version = "0.13.0" +source = "git+https://github.com/0xPolygonHermez/zisk.git?tag=v0.13.0#ea1ed4c518992a170fc59ec19f1228eb4829a9e1" +dependencies = [ + "cfg-if", + "getrandom", + "lazy_static", + "lib-c", + "num-bigint", + "num-traits", + "rand", + "static_assertions", + "tiny-keccak", +] + [[package]] name = "zkm-lib" version = "1.1.4" diff --git a/Cargo.toml b/Cargo.toml index 89a2ad6..da1877c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,10 @@ sp1-lib = { version = "5.0.0", default-features = false } [target.'cfg(all(target_os = "zkvm", target_vendor = "zkm"))'.dependencies] zkm-lib = { git = "https://github.com/ProjectZKM/Ziren.git", default-features = false } +# For Zisk +[target.'cfg(all(target_os = "zkvm", target_vendor = "zisk"))'.dependencies] +ziskos = { git = "https://github.com/0xPolygonHermez/zisk.git", tag = "v0.13.0" } + [dev-dependencies] csv = ">= 1.0, < 1.2" # csv 1.2 has MSRV 1.60 criterion = "0.3" @@ -85,3 +89,6 @@ required-features = ["groups"] name = "hash_to_curve" harness = false required-features = ["experimental"] + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_vendor, values("succinct", "risc0", "zisk", "zkm"))'] } diff --git a/src/fp.rs b/src/fp.rs index 4f7772f..729752b 100644 --- a/src/fp.rs +++ b/src/fp.rs @@ -36,6 +36,12 @@ use pico_patch_libs::{ unconstrained, }; +#[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] +use ziskos::zisklib::{ + add_fp_bls12_381_ptr, inv_fp_bls12_381_ptr, mul_fp_bls12_381, mul_fp_bls12_381_ptr, + neg_fp_bls12_381_ptr, sqrt_fp_bls12_381_ptr, square_fp_bls12_381_ptr, sub_fp_bls12_381_ptr, +}; + // The internal representation of this type is six 64-bit unsigned // integers in little-endian order. `Fp` values are always in // Montgomery form; i.e., Scalar(a) = aR mod p, with R = 2^384. @@ -57,6 +63,7 @@ use pico_patch_libs::{ any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", feature = "zkvm-pico" ) ), @@ -151,6 +158,7 @@ const INV: u64 = 0x89f3_fffc_fffc_fffd; any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -188,6 +196,7 @@ const R2: Fp = Fp([ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const R3: Fp = Fp([ @@ -262,6 +271,7 @@ impl Fp { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] { @@ -308,6 +318,7 @@ impl Fp { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] { @@ -328,6 +339,7 @@ impl Fp { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] let tmp = Fp::montgomery_reduce( @@ -393,6 +405,7 @@ impl Fp { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] return d0 * R2 + d1 * R3; @@ -416,6 +429,7 @@ impl Fp { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] let tmp = Fp::montgomery_reduce( @@ -447,7 +461,14 @@ impl Fp { Fp(v) } + #[inline] + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + pub const fn to_u64(&self) -> [u64; 6] { + self.0 + } + /// CPU version of the exponentiation operation. Necessary to prevent syscalls in unconstrained mode. + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] pub(crate) fn cpu_pow_vartime(&self, by: &[u64; 6]) -> Self { let mut res = Self::one(); for e in by.iter().rev() { @@ -481,6 +502,7 @@ impl Fp { #[inline] /// CPU version of the square-root operation. Necessary to prevent syscalls in unconstrained mode. + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] pub(crate) fn cpu_sqrt(&self) -> CtOption { // We use Shank's method, as p = 3 (mod 4). This means // we only need to exponentiate by (p+1)/4. This only @@ -594,10 +616,34 @@ impl Fp { } } } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + if self.is_zero().into() { + return CtOption::new(Self::zero(), Choice::from(1u8)); + } + + let mut out = self.clone(); + out.mul_r_inv_internal(); + + let mut is_qr: u8 = 0; + unsafe { + sqrt_fp_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64, &mut is_qr as *mut u8); + } + + if is_qr == 1 { + out.mul_r_internal(); + CtOption::new(out, Choice::from(1u8)) + } else { + CtOption::new(Fp::zero(), Choice::from(0u8)) + } + } } #[inline] /// CPU version of the inversion operation. Necessary to prevent syscalls in unconstrained mode. + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] pub(crate) fn cpu_invert(&self) -> CtOption { // Exponentiate by p - 2 let inv = self.cpu_pow_vartime(&[ @@ -686,6 +732,22 @@ impl Fp { CtOption::new(inv, (self * inv).ct_eq(&Fp::one())) } + + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + if self.is_zero().into() { + return CtOption::new(Self::zero(), Choice::from(0u8)); + } + + let mut out = self.clone(); + out.mul_r_inv_internal(); + unsafe { + inv_fp_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64); + } + out.mul_r_internal(); + + CtOption::new(out, Choice::from(1u8)) + } } #[inline] @@ -768,6 +830,16 @@ impl Fp { } out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + add_fp_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64, rhs.0.as_ptr() as *const u64); + } + out + } } #[cfg(all(target_os = "zkvm", target_vendor = "risc0", feature = "zkvm-risc0"))] @@ -835,6 +907,16 @@ impl Fp { } out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + neg_fp_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64); + } + out + } } #[inline] @@ -893,6 +975,16 @@ impl Fp { } out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + sub_fp_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64, rhs.0.as_ptr() as *const u64); + } + out + } } #[inline] @@ -1190,6 +1282,17 @@ impl Fp { out.mul_r_inv_internal(); out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + mul_fp_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64, rhs.0.as_ptr() as *const u64); + } + out.mul_r_inv_internal(); + out + } } /// Internal function to multiply the internal representation by `R_INV`, equivalent to transforming from @@ -1201,18 +1304,41 @@ impl Fp { any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] pub(crate) fn mul_r_inv_internal(&mut self) { - unsafe { - syscall_bls12381_fp_mulmod( - self.0.as_mut_ptr() as *mut u32, - R_INV.0.as_ptr() as *const u32, - ); + // non-Zisk + #[cfg(not(target_vendor = "zisk"))] + { + unsafe { + syscall_bls12381_fp_mulmod( + self.0.as_mut_ptr() as *mut u32, + R_INV.0.as_ptr() as *const u32, + ); + } + } + + // Zisk + #[cfg(target_vendor = "zisk")] + { + unsafe { + mul_fp_bls12_381_ptr( + self.0.as_mut_ptr() as *mut u64, + R_INV.0.as_ptr() as *const u64, + ); + } } } + #[inline] + #[allow(dead_code)] + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + pub(crate) fn mul_r_inv(&self) -> Fp { + Fp(mul_fp_bls12_381(&self.0, &R_INV.0)) + } + /// Internal function to multiply the internal representation by `R`, equivalent to transforming from /// a plain BigInt form back to the internal Montgomery form. /// Used as a bridge between the internal Montgomery representation and the zkvm precompiles. @@ -1222,12 +1348,28 @@ impl Fp { any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] pub(crate) fn mul_r_internal(&mut self) { - unsafe { - syscall_bls12381_fp_mulmod(self.0.as_mut_ptr() as *mut u32, R.0.as_ptr() as *const u32); + // non-Zisk + #[cfg(not(target_vendor = "zisk"))] + { + unsafe { + syscall_bls12381_fp_mulmod( + self.0.as_mut_ptr() as *mut u32, + R.0.as_ptr() as *const u32, + ); + } + } + + // Zisk + #[cfg(target_vendor = "zisk")] + { + unsafe { + mul_fp_bls12_381_ptr(self.0.as_mut_ptr() as *mut u64, R.0.as_ptr() as *const u64); + } } } @@ -1251,6 +1393,7 @@ impl Fp { } /// CPU version of the squaring operation. Necessary to prevent syscalls in unconstrained mode. + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] 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); @@ -1338,6 +1481,17 @@ impl Fp { out.mul_r_inv_internal(); out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + square_fp_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64); + } + out.mul_r_inv_internal(); + out + } } } diff --git a/src/fp12.rs b/src/fp12.rs index f46274e..c23888a 100644 --- a/src/fp12.rs +++ b/src/fp12.rs @@ -117,6 +117,7 @@ impl Fp12 { pub fn mul_by_014(&self, c0: &Fp2, c1: &Fp2, c4: &Fp2) -> Fp12 { #[cfg(any( not(target_os = "zkvm"), + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-risc0") ))] { @@ -233,6 +234,7 @@ impl Fp12 { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ), inline(always) @@ -246,6 +248,7 @@ impl Fp12 { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] let c1 = c1 @@ -338,6 +341,7 @@ impl Fp12 { pub fn square(&self) -> Self { #[cfg(any( not(target_os = "zkvm"), + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-risc0"), ))] { diff --git a/src/fp2.rs b/src/fp2.rs index e724650..e0b0357 100644 --- a/src/fp2.rs +++ b/src/fp2.rs @@ -34,6 +34,12 @@ use pico_patch_libs::{ unconstrained, }; +#[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] +use ziskos::zisklib::{ + add_fp2_bls12_381_ptr, inv_fp2_bls12_381_ptr, mul_fp2_bls12_381_ptr, neg_fp2_bls12_381_ptr, + square_fp2_bls12_381_ptr, sub_fp2_bls12_381_ptr, +}; + #[derive(Copy, Clone)] #[cfg_attr( all(target_os = "zkvm", target_vendor = "risc0", feature = "zkvm-risc0"), @@ -276,6 +282,15 @@ impl Fp2 { ) } + #[inline] + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + pub fn to_u64(&self) -> [u64; 12] { + let mut res = [0u64; 12]; + res[..6].copy_from_slice(&self.c0.to_u64()); + res[6..].copy_from_slice(&self.c1.to_u64()); + res + } + /// Internal function to multiply the internal representation by `R_INV`, equivalent to transforming from /// the internal Montgomery form to a plain BigInt form. /// Used as a bridge between the internal Montgomery representation and the zkvm precompiles. @@ -285,6 +300,7 @@ impl Fp2 { any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -293,6 +309,23 @@ impl Fp2 { self.c1.mul_r_inv_internal(); } + #[inline] + #[allow(dead_code)] + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + pub(crate) fn mul_r_inv(&self) -> Fp2 { + Fp2 { + c0: self.c0.mul_r_inv(), + c1: self.c1.mul_r_inv(), + } + } + + #[inline] + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + pub(crate) fn mul_r_internal(&mut self) { + self.c0.mul_r_internal(); + self.c1.mul_r_internal(); + } + #[inline] #[cfg(all( target_os = "zkvm", @@ -376,6 +409,17 @@ impl Fp2 { out.mul_r_inv_internal(); out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + square_fp2_bls12_381_ptr(out.c0.0.as_mut_ptr() as *mut u64); + } + out.mul_r_inv_internal(); + out + } } #[inline] @@ -457,6 +501,20 @@ impl Fp2 { out.mul_r_inv_internal(); out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + mul_fp2_bls12_381_ptr( + out.c0.0.as_mut_ptr() as *mut u64, + rhs.c0.0.as_ptr() as *const u64, + ); + } + out.mul_r_inv_internal(); + out + } } #[inline] @@ -543,6 +601,19 @@ impl Fp2 { } out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + add_fp2_bls12_381_ptr( + out.c0.0.as_mut_ptr() as *mut u64, + rhs.c0.0.as_ptr() as *const u64, + ); + } + out + } } #[inline] @@ -610,6 +681,19 @@ impl Fp2 { } out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + sub_fp2_bls12_381_ptr( + out.c0.0.as_mut_ptr() as *mut u64, + rhs.c0.0.as_ptr() as *const u64, + ); + } + out + } } /// CPU version of the negation operation. Necessary to prevent syscalls in unconstrained mode. @@ -654,6 +738,16 @@ impl Fp2 { } out } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + neg_fp2_bls12_381_ptr(out.c0.0.as_mut_ptr() as *mut u64); + } + out + } } /// CPU version of the square root operation. Necessary to prevent syscalls in unconstrained mode. @@ -716,7 +810,8 @@ impl Fp2 { // Original zkcrypto implementation. #[cfg(any( not(target_os = "zkvm"), - all(target_os = "zkvm", target_vendor = "risc0", feature = "zkvm-pico"), + target_vendor = "zisk", + all(target_vendor = "risc0", feature = "zkvm-pico"), ))] return self.cpu_sqrt(); @@ -855,6 +950,7 @@ impl Fp2 { /// element, returning None in the case that this element /// is zero. /// CPU version of the inversion operation. Necessary to prevent syscalls in unconstrained mode. + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] pub(crate) fn cpu_invert(&self) -> CtOption { // We wish to find the multiplicative inverse of a nonzero // element a + bu in Fp2. We leverage an identity @@ -879,6 +975,10 @@ impl Fp2 { } pub fn invert(&self) -> CtOption { + if self.is_zero().into() { + return CtOption::new(Fp2::zero(), Choice::from(0u8)); + } + #[cfg(not(target_os = "zkvm"))] return self.cpu_invert(); @@ -943,10 +1043,6 @@ impl Fp2 { // SP1 patched version #[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] { - if self.is_zero().into() { - return CtOption::new(Fp2::zero(), Choice::from(0u8)); - } - unconstrained! { // The element was previously checked to be non-zero if let Some(inv) = self.cpu_invert().into_option() { @@ -969,6 +1065,18 @@ impl Fp2 { CtOption::new(inv, (self * inv).ct_eq(&Fp2::one())) } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + out.mul_r_inv_internal(); + unsafe { + inv_fp2_bls12_381_ptr(out.c0.0.as_mut_ptr() as *mut u64); + } + out.mul_r_internal(); + CtOption::new(out, Choice::from(1u8)) + } } fn pow_vartime_constrained(&self, by: &[u64; 6]) -> Self { diff --git a/src/fp6.rs b/src/fp6.rs index 686bb79..425b213 100644 --- a/src/fp6.rs +++ b/src/fp6.rs @@ -215,6 +215,7 @@ impl Fp6 { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] { @@ -340,7 +341,7 @@ impl Fp6 { #[inline] fn mul_interleaved(&self, b: &Self) -> Self { // Original zkcrypto implementation - #[cfg(not(target_os = "zkvm"))] + #[cfg(any(not(target_os = "zkvm"), target_vendor = "zisk"))] { // The intuition for this algorithm is that we can look at F_p^6 as a direct // extension of F_p^2, and express the overall operations down to the base field diff --git a/src/g1.rs b/src/g1.rs index 7710646..5872aee 100644 --- a/src/g1.rs +++ b/src/g1.rs @@ -34,6 +34,9 @@ use zkm_lib::{bls12381::decompress_pubkey, syscall_bls12381_add, syscall_bls1238 #[cfg(all(target_os = "zkvm", target_vendor = "risc0", feature = "zkvm-pico"))] use pico_patch_libs::{bls12381::decompress_pubkey, syscall_bls12381_add, syscall_bls12381_double}; +#[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] +use ziskos::zisklib::{add_bls12_381_ptr, dbl_bls12_381_ptr}; + /// This is an element of $\mathbb{G}_1$ represented in the affine coordinate space. /// It is ideal to keep elements in this representation to reduce memory usage and /// improve performance through the use of mixed curve model arithmetic. @@ -195,6 +198,7 @@ impl_binops_additive_specify_output!(G1Affine, G1Projective, G1Projective); not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const B: Fp = Fp::from_raw_unchecked([ @@ -233,6 +237,7 @@ impl G1Affine { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] return G1Affine { @@ -546,6 +551,36 @@ impl G1Affine { assert!(self.y + rhs.y == Fp::zero()); Self::identity() } + } else if #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] { + if self.x != rhs.x { + // P != Q,-Q + let mut res = self.clone(); + res.x.mul_r_inv_internal(); + res.y.mul_r_inv_internal(); + let mut other = rhs.clone(); + other.x.mul_r_inv_internal(); + other.y.mul_r_inv_internal(); + unsafe { + add_bls12_381_ptr(res.x.0.as_mut_ptr() as *mut u64, other.x.0.as_mut_ptr() as *const u64); + } + res.x.mul_r_internal(); + res.y.mul_r_internal(); + res + } else if self.y == rhs.y { + // P == Q + let mut res = self.clone(); + res.x.mul_r_inv_internal(); + res.y.mul_r_inv_internal(); + unsafe { + dbl_bls12_381_ptr(res.x.0.as_mut_ptr() as *mut u64); + } + res.x.mul_r_internal(); + res.y.mul_r_internal(); + res + } else { + // P == -Q + Self::identity() + } } else { let proj = G1Projective::from(rhs); let res = proj + self; @@ -570,6 +605,15 @@ impl G1Affine { self.x.mul_r_internal(); self.y.mul_r_internal(); self + } else if #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] { + self.x.mul_r_inv_internal(); + self.y.mul_r_inv_internal(); + unsafe { + dbl_bls12_381_ptr(self.x.0.as_mut_ptr() as *mut u64); + } + self.x.mul_r_internal(); + self.y.mul_r_internal(); + self } else { let proj = G1Projective::from(self); let res = proj.double(); @@ -584,6 +628,7 @@ impl G1Affine { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] pub const BETA: Fp = Fp::from_raw_unchecked([ @@ -795,6 +840,7 @@ impl G1Projective { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] return G1Projective { @@ -842,78 +888,143 @@ impl G1Projective { /// Computes the doubling of this point. pub fn double(&self) -> G1Projective { - // Algorithm 9, https://eprint.iacr.org/2015/1060.pdf - - let t0 = self.y.square(); - let z3 = t0 + t0; - let z3 = z3 + z3; - let z3 = z3 + z3; - let t1 = self.y * self.z; - let t2 = self.z.square(); - let t2 = mul_by_3b(t2); - let x3 = t2 * z3; - let y3 = t0 + t2; - let z3 = t1 * z3; - let t1 = t2 + t2; - let t2 = t1 + t2; - let t0 = t0 - t2; - let y3 = t0 * y3; - let y3 = x3 + y3; - let t1 = self.x * self.y; - let x3 = t0 * t1; - let x3 = x3 + x3; + // non-Zisk + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] + { + // Algorithm 9, https://eprint.iacr.org/2015/1060.pdf + let t0 = self.y.square(); + let z3 = t0 + t0; + let z3 = z3 + z3; + let z3 = z3 + z3; + let t1 = self.y * self.z; + let t2 = self.z.square(); + let t2 = mul_by_3b(t2); + let x3 = t2 * z3; + let y3 = t0 + t2; + let z3 = t1 * z3; + let t1 = t2 + t2; + let t2 = t1 + t2; + let t0 = t0 - t2; + let y3 = t0 * y3; + let y3 = x3 + y3; + let t1 = self.x * self.y; + let x3 = t0 * t1; + let x3 = x3 + x3; + + let tmp = G1Projective { + x: x3, + y: y3, + z: z3, + }; - let tmp = G1Projective { - x: x3, - y: y3, - z: z3, - }; + G1Projective::conditional_select(&tmp, &G1Projective::identity(), self.is_identity()) + } - G1Projective::conditional_select(&tmp, &G1Projective::identity(), self.is_identity()) + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + if self.is_identity().into() { + return *self; + } + let mut self_affine = G1Affine::from(*self); + self_affine.x.mul_r_inv_internal(); + self_affine.y.mul_r_inv_internal(); + unsafe { + dbl_bls12_381_ptr(self_affine.x.0.as_mut_ptr() as *mut u64); + } + self_affine.x.mul_r_internal(); + self_affine.y.mul_r_internal(); + self_affine.into() + } } /// Adds this point to another point. pub fn add(&self, rhs: &G1Projective) -> G1Projective { - // Algorithm 7, https://eprint.iacr.org/2015/1060.pdf - - let t0 = self.x * rhs.x; - let t1 = self.y * rhs.y; - let t2 = self.z * rhs.z; - let t3 = self.x + self.y; - let t4 = rhs.x + rhs.y; - let t3 = t3 * t4; - let t4 = t0 + t1; - let t3 = t3 - t4; - let t4 = self.y + self.z; - let x3 = rhs.y + rhs.z; - let t4 = t4 * x3; - let x3 = t1 + t2; - let t4 = t4 - x3; - let x3 = self.x + self.z; - let y3 = rhs.x + rhs.z; - let x3 = x3 * y3; - let y3 = t0 + t2; - let y3 = x3 - y3; - let x3 = t0 + t0; - let t0 = x3 + t0; - let t2 = mul_by_3b(t2); - let z3 = t1 + t2; - let t1 = t1 - t2; - let y3 = mul_by_3b(y3); - let x3 = t4 * y3; - let t2 = t3 * t1; - let x3 = t2 - x3; - let y3 = y3 * t0; - let t1 = t1 * z3; - let y3 = t1 + y3; - let t0 = t0 * t3; - let z3 = z3 * t4; - let z3 = z3 + t0; + // non-Zisk + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] + { + // Algorithm 7, https://eprint.iacr.org/2015/1060.pdf + + let t0 = self.x * rhs.x; + let t1 = self.y * rhs.y; + let t2 = self.z * rhs.z; + let t3 = self.x + self.y; + let t4 = rhs.x + rhs.y; + let t3 = t3 * t4; + let t4 = t0 + t1; + let t3 = t3 - t4; + let t4 = self.y + self.z; + let x3 = rhs.y + rhs.z; + let t4 = t4 * x3; + let x3 = t1 + t2; + let t4 = t4 - x3; + let x3 = self.x + self.z; + let y3 = rhs.x + rhs.z; + let x3 = x3 * y3; + let y3 = t0 + t2; + let y3 = x3 - y3; + let x3 = t0 + t0; + let t0 = x3 + t0; + let t2 = mul_by_3b(t2); + let z3 = t1 + t2; + let t1 = t1 - t2; + let y3 = mul_by_3b(y3); + let x3 = t4 * y3; + let t2 = t3 * t1; + let x3 = t2 - x3; + let y3 = y3 * t0; + let t1 = t1 * z3; + let y3 = t1 + y3; + let t0 = t0 * t3; + let z3 = z3 * t4; + let z3 = z3 + t0; + + G1Projective { + x: x3, + y: y3, + z: z3, + } + } - G1Projective { - x: x3, - y: y3, - z: z3, + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + if self.is_identity().into() { + return *rhs; + } else if rhs.is_identity().into() { + return *self; + } + let mut self_affine = G1Affine::from(*self); + let mut rhs_affine = G1Affine::from(*rhs); + if self_affine.x != rhs_affine.x { + // P != Q,-Q + self_affine.x.mul_r_inv_internal(); + self_affine.y.mul_r_inv_internal(); + rhs_affine.x.mul_r_inv_internal(); + rhs_affine.y.mul_r_inv_internal(); + unsafe { + add_bls12_381_ptr( + self_affine.x.0.as_mut_ptr() as *mut u64, + rhs_affine.x.0.as_mut_ptr() as *const u64, + ); + } + self_affine.x.mul_r_internal(); + self_affine.y.mul_r_internal(); + self_affine.into() + } else if self_affine.y == rhs_affine.y { + // P == Q + self_affine.x.mul_r_inv_internal(); + self_affine.y.mul_r_inv_internal(); + unsafe { + dbl_bls12_381_ptr(self_affine.x.0.as_mut_ptr() as *mut u64); + } + self_affine.x.mul_r_internal(); + self_affine.y.mul_r_internal(); + self_affine.into() + } else { + // P == -Q + Self::identity() + } } } @@ -981,11 +1092,7 @@ impl G1Projective { /// Multiply `self` by `crate::BLS_X`, using double and add. fn mul_by_x(&self) -> G1Projective { - #[cfg(any( - not(target_os = "zkvm"), - target_vendor = "risc0", - all(target_vendor = "risc0", feature = "zkvm-pico"), - ))] + #[cfg(any(not(target_os = "zkvm"), target_vendor = "risc0"))] { let mut xself = G1Projective::identity(); // NOTE: in BLS12-381 we can just skip the first bit. @@ -1028,8 +1135,8 @@ impl G1Projective { xself.into() } - // ZKM patch - #[cfg(all(target_os = "zkvm", target_vendor = "zkm"))] + // ZKM & Zisk patch + #[cfg(all(target_os = "zkvm", any(target_vendor = "zkm", target_vendor = "zisk")))] { let mut xself = G1Affine::identity(); diff --git a/src/g2.rs b/src/g2.rs index 57919c6..f8732ee 100644 --- a/src/g2.rs +++ b/src/g2.rs @@ -178,6 +178,7 @@ impl_binops_additive_specify_output!(G2Affine, G2Projective, G2Projective); not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const B: Fp2 = Fp2 { @@ -223,6 +224,7 @@ const B: Fp2 = Fp2 { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const B3: Fp2 = Fp2 { @@ -280,7 +282,8 @@ impl G2Affine { #[cfg(any( not(target_os = "zkvm"), target_vendor = "succinct", - target_vendor = "zkm" + target_vendor = "zkm", + target_vendor = "zisk", ))] return G2Affine { x: Fp2 { @@ -800,6 +803,7 @@ impl G2Projective { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] return G2Projective { @@ -888,6 +892,7 @@ impl G2Projective { pub fn double(&self) -> G2Projective { #[cfg(any( not(target_os = "zkvm"), + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-risc0") ))] { @@ -968,6 +973,7 @@ impl G2Projective { pub fn add(&self, rhs: &G2Projective) -> G2Projective { #[cfg(any( not(target_os = "zkvm"), + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-risc0") ))] { @@ -1148,6 +1154,7 @@ impl G2Projective { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] { @@ -1244,6 +1251,7 @@ impl G2Projective { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] let psi2_coeff_x = Fp2 { diff --git a/src/hash_to_curve/map_g1.rs b/src/hash_to_curve/map_g1.rs index bcc3664..fe24638 100644 --- a/src/hash_to_curve/map_g1.rs +++ b/src/hash_to_curve/map_g1.rs @@ -18,6 +18,7 @@ use crate::generic_array::{ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico") ))] const ISO11_XNUM: [Fp; 12] = [ @@ -224,6 +225,7 @@ const ISO11_XNUM: [Fp; 12] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const ISO11_XDEN: [Fp; 11] = [ @@ -414,6 +416,7 @@ const ISO11_XDEN: [Fp; 11] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const ISO11_YNUM: [Fp; 16] = [ @@ -684,6 +687,7 @@ const ISO11_YNUM: [Fp; 16] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const ISO11_YDEN: [Fp; 16] = [ @@ -953,6 +957,7 @@ const ISO11_YDEN: [Fp; 16] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SSWU_ELLP_A: Fp = Fp::from_raw_unchecked([ @@ -978,6 +983,7 @@ const SSWU_ELLP_A: Fp = Fp::from_raw_unchecked([ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SSWU_ELLP_B: Fp = Fp::from_raw_unchecked([ @@ -1003,6 +1009,7 @@ const SSWU_ELLP_B: Fp = Fp::from_raw_unchecked([ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SSWU_XI: Fp = Fp::from_raw_unchecked([ @@ -1028,6 +1035,7 @@ const SSWU_XI: Fp = Fp::from_raw_unchecked([ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SQRT_M_XI_CUBED: Fp = Fp::from_raw_unchecked([ @@ -1062,6 +1070,7 @@ impl HashToField for Fp { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const F_2_256: Fp = Fp::from_raw_unchecked([ @@ -1095,6 +1104,7 @@ impl Sgn0 for Fp { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] let tmp = Fp::montgomery_reduce( diff --git a/src/hash_to_curve/map_g2.rs b/src/hash_to_curve/map_g2.rs index 3501ca7..64c31f3 100644 --- a/src/hash_to_curve/map_g2.rs +++ b/src/hash_to_curve/map_g2.rs @@ -17,6 +17,7 @@ use crate::{fp::Fp, fp2::Fp2, g2::G2Projective}; not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const ISO3_XNUM: [Fp2; 4] = [ @@ -147,6 +148,7 @@ const ISO3_XNUM: [Fp2; 4] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const ISO3_XDEN: [Fp2; 3] = [ @@ -221,6 +223,7 @@ const ISO3_XDEN: [Fp2; 3] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const ISO3_YNUM: [Fp2; 4] = [ @@ -351,6 +354,7 @@ const ISO3_YNUM: [Fp2; 4] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const ISO3_YDEN: [Fp2; 4] = [ @@ -460,6 +464,7 @@ const ISO3_YDEN: [Fp2; 4] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SSWU_ELLP_A: Fp2 = Fp2 { @@ -491,6 +496,7 @@ const SSWU_ELLP_A: Fp2 = Fp2 { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SSWU_ELLP_B: Fp2 = Fp2 { @@ -536,6 +542,7 @@ const SSWU_ELLP_B: Fp2 = Fp2 { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SSWU_XI: Fp2 = Fp2 { @@ -581,6 +588,7 @@ const SSWU_XI: Fp2 = Fp2 { not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SSWU_ETAS: [Fp2; 4] = [ @@ -738,6 +746,7 @@ const SSWU_ETAS: [Fp2; 4] = [ not(target_os = "zkvm"), target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ))] const SSWU_RV1: Fp2 = Fp2 { diff --git a/src/pairings.rs b/src/pairings.rs index 071b830..f07d49c 100644 --- a/src/pairings.rs +++ b/src/pairings.rs @@ -622,6 +622,7 @@ impl Group for Gt { any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -1077,6 +1078,7 @@ fn miller_loop(driver: &mut D) -> D::Output { fn ell(f: &Fp12, coeffs: &(Fp2, Fp2, Fp2), p: &G1Affine) -> Fp12 { #[cfg(any( not(target_os = "zkvm"), + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-risc0") ))] { @@ -1117,6 +1119,7 @@ fn ell(f: &Fp12, coeffs: &(Fp2, Fp2, Fp2), p: &G1Affine) -> Fp12 { fn doubling_step(r: &mut G2Projective) -> (Fp2, Fp2, Fp2) { #[cfg(any( not(target_os = "zkvm"), + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-risc0") ))] { @@ -1217,6 +1220,7 @@ fn doubling_step(r: &mut G2Projective) -> (Fp2, Fp2, Fp2) { fn addition_step(r: &mut G2Projective, q: &G2Affine) -> (Fp2, Fp2, Fp2) { #[cfg(any( not(target_os = "zkvm"), + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-risc0") ))] { diff --git a/src/scalar.rs b/src/scalar.rs index 324b30d..f6dea5d 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -19,6 +19,8 @@ cfg_if! { } else if #[cfg(all(target_os = "zkvm", target_vendor = "zkm"))] { use zkm_lib::sys_bigint; use zkm_lib::{io::{hint_slice, read_vec}, unconstrained}; + } else if #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] { + use ziskos::zisklib::{add_fr_bls12_381_ptr, mul_fr_bls12_381_ptr, square_fr_bls12_381_ptr, sub_fr_bls12_381_ptr, neg_fr_bls12_381_ptr, dbl_fr_bls12_381_ptr}; } } @@ -145,6 +147,14 @@ const R_INV: [u32; 8] = [ 0x1bbe_8693, ]; +#[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] +const R_INV: [u64; 4] = [ + 0x13f7_5b69_fe75_c040, + 0xab6f_ca8f_09dc_705f, + 0x7204_078a_4f77_266a, + 0x1bbe_8693_3000_9d57, +]; + // The number of bits needed to represent the modulus. const MODULUS_BITS: u32 = 255; @@ -154,6 +164,7 @@ const MODULUS_BITS: u32 = 255; any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -245,6 +256,7 @@ const R2: Scalar = Scalar([ any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -261,6 +273,7 @@ const R3: Scalar = Scalar([ any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -294,6 +307,7 @@ const S: u32 = 32; any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -318,6 +332,7 @@ const ROOT_OF_UNITY: Scalar = Scalar([ any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -343,6 +358,7 @@ const ROOT_OF_UNITY_INV: Scalar = Scalar([ any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", feature = "zkvm-pico" ) ))] @@ -386,6 +402,7 @@ impl Scalar { any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -399,8 +416,22 @@ impl Scalar { /// Doubles this field element. #[inline] pub fn double(&self) -> Scalar { - // TODO: This can be achieved more efficiently with a bitshift. - self.add(self) + // non-Zisk + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] + { + // TODO: This can be achieved more efficiently with a bitshift. + self.add(self) + } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + dbl_fr_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64); + } + out + } } /// Attempts to convert a little-endian byte representation of @@ -431,6 +462,7 @@ impl Scalar { any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -451,6 +483,7 @@ impl Scalar { any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -505,6 +538,7 @@ impl Scalar { any( target_vendor = "succinct", target_vendor = "zkm", + target_vendor = "zisk", all(target_vendor = "risc0", feature = "zkvm-pico"), ) ))] @@ -573,7 +607,13 @@ impl Scalar { field::modmul_256(&inp, &inp, &prime, &mut result); let ret: [u64; 4] = bytemuck::cast(result); Scalar(ret) - + } else if #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] { + let mut out = self.clone(); + unsafe { + square_fr_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64); + } + out.mul_r_inv_internal(); + out } else { let mut res = *self; res.mul_inp(self); @@ -719,7 +759,10 @@ impl Scalar { pub fn invert(&self) -> CtOption { cfg_if! { - if #[cfg(not(target_os = "zkvm"))] { + if #[cfg(any( + not(target_os = "zkvm"), + target_vendor = "zisk", + ))] { self.cpu_invert() } else if #[cfg(all(target_vendor = "risc0", feature = "zkvm-risc0"))] { @@ -830,23 +873,36 @@ impl Scalar { } #[inline] - #[cfg(all( - target_os = "zkvm", - any( - target_vendor = "succinct", - target_vendor = "zkm", - all(target_vendor = "risc0", feature = "zkvm-pico"), - ) - ))] + #[allow(dead_code)] pub(crate) fn mul_r_inv_internal(&mut self) { - unsafe { - sys_bigint( - self.0.as_mut_ptr() as *mut [u32; 8], - 0, - self.0.as_ptr() as *const [u32; 8], - &R_INV, - &MODULUS_LIMBS_32, - ); + #[cfg(all( + target_os = "zkvm", + any( + target_vendor = "succinct", + target_vendor = "zkm", + all(target_vendor = "risc0", feature = "zkvm-pico"), + ) + ))] + { + unsafe { + sys_bigint( + self.0.as_mut_ptr() as *mut [u32; 8], + 0, + self.0.as_ptr() as *const [u32; 8], + &R_INV, + &MODULUS_LIMBS_32, + ); + } + } + + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + unsafe { + mul_fr_bls12_381_ptr( + self.0.as_mut_ptr() as *mut u64, + R_INV.as_ptr() as *const u64, + ); + } } } @@ -934,24 +990,49 @@ impl Scalar { res.mul_inp(rhs); res } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + mul_fr_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64, rhs.0.as_ptr() as *const u64); + } + out.mul_r_inv_internal(); + out + } } /// Subtracts `rhs` from `self`, returning the result. #[inline] - pub const fn sub(&self, rhs: &Self) -> Self { - let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); - let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); - let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); - let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); - - // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise - // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. - let (d0, carry) = adc(d0, MODULUS.0[0] & borrow, 0); - let (d1, carry) = adc(d1, MODULUS.0[1] & borrow, carry); - let (d2, carry) = adc(d2, MODULUS.0[2] & borrow, carry); - let (d3, _) = adc(d3, MODULUS.0[3] & borrow, carry); - - Scalar([d0, d1, d2, d3]) + pub fn sub(&self, rhs: &Self) -> Self { + // non-Zisk + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] + { + let (d0, borrow) = sbb(self.0[0], rhs.0[0], 0); + let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); + let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); + let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); + + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. + let (d0, carry) = adc(d0, MODULUS.0[0] & borrow, 0); + let (d1, carry) = adc(d1, MODULUS.0[1] & borrow, carry); + let (d2, carry) = adc(d2, MODULUS.0[2] & borrow, carry); + let (d3, _) = adc(d3, MODULUS.0[3] & borrow, carry); + + Scalar([d0, d1, d2, d3]) + } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + sub_fr_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64, rhs.0.as_ptr() as *const u64); + } + out + } } /// Adds `rhs` to `self`, returning the result. @@ -989,24 +1070,49 @@ impl Scalar { let ret: [u64; 4] = bytemuck::cast(result); Scalar(ret) } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + add_fr_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64, rhs.0.as_ptr() as *const u64); + } + out + } } /// Negates `self`. #[inline] - pub const fn neg(&self) -> Self { - // Subtract `self` from `MODULUS` to negate. Ignore the final - // borrow because it cannot underflow; self is guaranteed to - // be in the field. - let (d0, borrow) = sbb(MODULUS.0[0], self.0[0], 0); - let (d1, borrow) = sbb(MODULUS.0[1], self.0[1], borrow); - let (d2, borrow) = sbb(MODULUS.0[2], self.0[2], borrow); - let (d3, _) = sbb(MODULUS.0[3], self.0[3], borrow); - - // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is - // zero if `self` was zero, and `u64::max_value()` if self was nonzero. - let mask = (((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0) as u64).wrapping_sub(1); - - Scalar([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) + pub fn neg(&self) -> Self { + // non-Zisk + #[cfg(not(all(target_os = "zkvm", target_vendor = "zisk")))] + { + // Subtract `self` from `MODULUS` to negate. Ignore the final + // borrow because it cannot underflow; self is guaranteed to + // be in the field. + let (d0, borrow) = sbb(MODULUS.0[0], self.0[0], 0); + let (d1, borrow) = sbb(MODULUS.0[1], self.0[1], borrow); + let (d2, borrow) = sbb(MODULUS.0[2], self.0[2], borrow); + let (d3, _) = sbb(MODULUS.0[3], self.0[3], borrow); + + // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is + // zero if `self` was zero, and `u64::max_value()` if self was nonzero. + let mask = + (((self.0[0] | self.0[1] | self.0[2] | self.0[3]) == 0) as u64).wrapping_sub(1); + + Scalar([d0 & mask, d1 & mask, d2 & mask, d3 & mask]) + } + + // Zisk + #[cfg(all(target_os = "zkvm", target_vendor = "zisk"))] + { + let mut out = self.clone(); + unsafe { + neg_fr_bls12_381_ptr(out.0.as_mut_ptr() as *mut u64); + } + out + } } #[inline]