Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch version 0.9.6 #10

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 62 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ pkcs8 = { version = "0.10.2", default-features = false, features = ["alloc"] }
signature = { version = ">2.0, <2.3", default-features = false , features = ["alloc", "digest", "rand_core"] }
spki = { version = "0.7.3", default-features = false, features = ["alloc"] }
zeroize = { version = "1.5", features = ["alloc"] }
crypto-bigint = "0.5.5"
cfg-if = "1.0.0"
bytemuck = { version = "1.16.1", features = ["derive"] }

[target.'cfg(all(target_os = "zkvm", target_vendor = "succinct"))'.dependencies]
sp1-lib = { git = "https://github.com/succinctlabs/sp1.git", branch = "dev" }



# optional dependencies
sha1 = { version = "0.10.5", optional = true, default-features = false, features = ["oid"] }
Expand Down
121 changes: 121 additions & 0 deletions src/algorithms/rsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ use num_integer::{sqrt, Integer};
use num_traits::{FromPrimitive, One, Pow, Signed, Zero};
use rand_core::CryptoRngCore;
use zeroize::{Zeroize, Zeroizing};
use bytemuck::cast_ref;
#[cfg(all(target_os = "zkvm", target_vendor = "succinct"))]
use sp1_lib::io::hint_slice;
use crypto_bigint::{Integer as CryptoInteger, NonZero, Encoding, U2048, U256, U4096};
use core::convert::TryInto;

use crate::errors::{Error, Result};
use crate::traits::{PrivateKeyParts, PublicKeyParts};
Expand All @@ -19,9 +24,125 @@ use crate::traits::{PrivateKeyParts, PublicKeyParts};
/// or signature scheme. See the [module-level documentation][crate::hazmat] for more information.
#[inline]
pub fn rsa_encrypt<K: PublicKeyParts>(key: &K, m: &BigUint) -> Result<BigUint> {
// Ok(m.modpow(key.e(), key.n()))
cfg_if::cfg_if! {
if #[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] {
let m_u2048 = from_biguint_to_u2048(m);
let e_u2048 = from_biguint_to_u2048(key.e());
let n_u2048 = from_biguint_to_u2048(key.n());
return Ok(custom_modpow_u2048(&m_u2048, &e_u2048, &n_u2048));
}
}
Ok(m.modpow(key.e(), key.n()))
}

cfg_if::cfg_if! {
if #[cfg(all(target_os = "zkvm", target_vendor = "succinct"))] {
/// Performs modular exponentiation of `base` to the power of `exp` modulo `modulus`.
/// This function takes in U2048 operands and returns the result as a BigUint.
fn custom_modpow_u2048(base: &U2048, exp: &U2048, modulus: &U2048) -> BigUint {
if *modulus == U2048::ONE {
return BigUint::zero();
}

let mut result = U2048::ONE;
let modulus_nonzero = NonZero::new(*modulus).unwrap(); // Convert modulus to NonZero
let mut base = base.rem(&modulus_nonzero);


let mut exp = *exp;
while exp > U2048::ZERO {
if exp.is_odd().into() {
result = mul_mod_u2048(&result, &base, &modulus_nonzero);
}
exp = exp.shr(1);
base = mul_mod_u2048(&base, &base, &modulus_nonzero);
}

let result_biguint = BigUint::from_bytes_le(&result.to_le_bytes());
result_biguint

}


/// Performs modular multiplication of `a` and `b` with `modulus`.
/// It calculates the quotient and remainder in unconstrained.
fn mul_mod_u2048(a: &U2048, b: &U2048, modulus: &U2048) -> U2048 {
let prod = mul_u2048(*a, *b);
sp1_lib::unconstrained! {
let modulus_u4096 = U4096::from(modulus);
let modulus_u4096_nonzero = NonZero::new(modulus_u4096).unwrap(); // Convert modulus to NonZero
let (quotient, result) = prod.div_rem(&modulus_u4096_nonzero);
let result_bytes = result.to_le_bytes();
let quotient_bytes = quotient.to_le_bytes();

hint_slice(&result_bytes);
hint_slice(&quotient_bytes[..256]);
}

let result_bytes: [u8; 512] = sp1_lib::io::read_vec().try_into().unwrap();
let quotient_bytes: [u8; 256] = sp1_lib::io::read_vec().try_into().unwrap();

let q_array = U2048::from_le_slice(&quotient_bytes);
let result_u4096 = U4096::from_le_slice(&result_bytes);
let result_u2048 = U2048::from_le_slice(&result_bytes[..256]);

assert!(prod.wrapping_sub(&mul_u2048(q_array, *modulus)).wrapping_sub(&result_u4096) == U4096::ZERO);
result_u2048
}



/// Performs multiplication of `a` and `b`, which are both U2048,
/// and returns a U4096.
fn mul_u2048(a_array: U2048, b_array: U2048) -> U4096 {
let mut sum = U4096::ZERO;
let a_words = a_array.to_words();

for i in 0..8 {
let chunk = a_words[i*8..(i+1)*8].try_into().unwrap();
let a_chunk: U256 = U256::from_words(chunk);
let mut prod = mul_array(a_chunk, b_array);
let mut shifted_words = [0u32; 128];
shifted_words[i*8..].copy_from_slice(&prod.to_words()[..(128 - 8*i)]);
let shifted_prod = U4096::from_words(shifted_words);
sum = sum.wrapping_add(&shifted_prod);
}

sum
}

/// Performs multiplication of `a` a U256 and `b` which is a U2048.
fn mul_array(a: U256, b_array: U2048) -> U4096 {
let mut result_words = [0u32; 128];
let result_ptr = result_words.as_mut_ptr();
unsafe {
sp1_lib::syscall_u256x2048_mul(
cast_ref(&a.to_words()),
cast_ref(&b_array.to_words()),
result_ptr as *mut [u32; 64],
result_ptr.add(64) as *mut [u32; 8],
);
}

U4096::from_words(result_words)
}

/// Converts a BigUint to a U2048.
fn from_biguint_to_u2048(value: &BigUint) -> U2048 {
let mut padded_bytes = [0u8; 256];
let a_bytes = value.to_bytes_le();
for (i, &byte) in a_bytes.iter().enumerate() {
if i >= 256 { break; }
padded_bytes[i] = byte;
}

U2048::from_le_slice(&padded_bytes)
}
}
}


/// ⚠️ Performs raw RSA decryption with no padding or error checking.
///
/// Returns a plaintext `BigUint`. Performs RSA blinding if an `Rng` is passed.
Expand Down