diff --git a/Cargo.toml b/Cargo.toml index 7d46f832..8c5fc6ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,9 @@ edition = "2021" [package.metadata.docs.rs] rustdoc-args = [ "--html-in-header", "katex-header.html" ] +[dependencies] +sp1_precompiles = { git = "https://github.com/succinctlabs/sp1.git", package = "sp1-precompiles" } + [dev-dependencies] csv = ">= 1.0, < 1.2" # csv 1.2 has MSRV 1.60 criterion = "0.3" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index de43b230..3a306210 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.56.0" -components = [ "clippy", "rustfmt" ] +channel = "nightly-2024-04-17" +components = ["llvm-tools", "rustc-dev"] \ No newline at end of file diff --git a/src/g1.rs b/src/g1.rs index 1ffa8ad5..bb28e290 100644 --- a/src/g1.rs +++ b/src/g1.rs @@ -10,7 +10,7 @@ use group::{ }; use rand_core::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; - +use sp1_precompiles::bls12381::decompress_pubkey; #[cfg(feature = "alloc")] use group::WnafGroup; @@ -330,9 +330,11 @@ impl G1Affine { /// for details about how group elements are serialized. pub fn from_compressed(bytes: &[u8; 48]) -> CtOption { // We already know the point is on the curve because this is established - // by the y-coordinate recovery procedure in from_compressed_unchecked(). + // by the y-coordinate recovery procedure in decompress_pubkey(). + let decompressed = decompress_pubkey(bytes).unwrap(); - Self::from_compressed_unchecked(bytes).and_then(|p| CtOption::new(p, p.is_torsion_free())) + // Extra checks do not have to be done because because the precompile already does it for us. + G1Affine::from_uncompressed_unchecked(&decompressed) } /// Attempts to deserialize an uncompressed element, not checking if the diff --git a/src/scalar.rs b/src/scalar.rs index 59be5dca..a3753d89 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -335,6 +335,28 @@ impl Scalar { pub const fn from_raw(val: [u64; 4]) -> Self { (&Scalar(val)).mul(&R2) } + + /// Converts from a hex string into its `Scalar` representation. + pub fn from_hex(hex: &str) -> Option { + if hex.len() != 64 { + return None; + } + + let mut raw = [0u64; 4]; + for (i, chunk) in hex.as_bytes().chunks(16).enumerate().take(4) { + if let Ok(hex_chunk) = core::str::from_utf8(chunk) { + if let Ok(value) = u64::from_str_radix(hex_chunk, 16) { + raw[3 - i] = value.to_le(); + } else { + return None; + } + } else { + return None; + } + } + + Some(Scalar::from_raw(raw)) + } /// Squares this element. #[inline]