diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 81958dba2c..5c76b62b6b 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -422,7 +422,7 @@ jobs: runs-on, runner=64cpu-linux-x64, spot=false, - hdd=150, + hdd=80, "run-id=${{ github.run_id }}", ] env: diff --git a/Cargo.lock b/Cargo.lock index 2a9ba70be9..acc6379b1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,7 +188,7 @@ dependencies = [ "alloy-sol-types", "serde", "serde_json", - "thiserror", + "thiserror 1.0.68", "tracing", ] @@ -210,7 +210,7 @@ dependencies = [ "async-trait", "auto_impl", "futures-utils-wasm", - "thiserror", + "thiserror 1.0.68", ] [[package]] @@ -317,7 +317,7 @@ dependencies = [ "auto_impl", "elliptic-curve", "k256", - "thiserror", + "thiserror 1.0.68", ] [[package]] @@ -333,7 +333,7 @@ dependencies = [ "async-trait", "k256", "rand 0.8.5", - "thiserror", + "thiserror 1.0.68", ] [[package]] @@ -494,6 +494,54 @@ dependencies = [ "backtrace", ] +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-crypto-primitives" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" +dependencies = [ + "ark-ec", + "ark-ff 0.4.2", + "ark-relations", + "ark-serialize 0.4.2", + "ark-snark", + "ark-std 0.4.0", + "blake2", + "derivative", + "digest 0.10.7", + "rayon", + "sha2 0.10.8", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff 0.4.2", + "ark-poly", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "rayon", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -528,6 +576,7 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "paste", + "rayon", "rustc_version 0.4.1", "zeroize", ] @@ -577,6 +626,48 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-groth16" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" +dependencies = [ + "ark-crypto-primitives", + "ark-ec", + "ark-ff 0.4.2", + "ark-poly", + "ark-relations", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "rayon", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "rayon", +] + +[[package]] +name = "ark-relations" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" +dependencies = [ + "ark-ff 0.4.2", + "ark-std 0.4.0", + "tracing", + "tracing-subscriber 0.2.25", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -593,11 +684,35 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ + "ark-serialize-derive", "ark-std 0.4.0", "digest 0.10.7", "num-bigint 0.4.6", ] +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-snark" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" +dependencies = [ + "ark-ff 0.4.2", + "ark-relations", + "ark-serialize 0.4.2", + "ark-std 0.4.0", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -616,6 +731,7 @@ checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", "rand 0.8.5", + "rayon", ] [[package]] @@ -1192,7 +1308,7 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "thiserror", + "thiserror 1.0.68", ] [[package]] @@ -2497,6 +2613,15 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -4014,7 +4139,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", - "thiserror", + "thiserror 1.0.68", "ucd-trie", ] @@ -4360,7 +4485,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.16", "socket2", - "thiserror", + "thiserror 1.0.68", "tokio", "tracing", ] @@ -4377,7 +4502,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.16", "slab", - "thiserror", + "thiserror 1.0.68", "tinyvec", "tracing", ] @@ -4538,7 +4663,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.68", ] [[package]] @@ -4646,7 +4771,7 @@ dependencies = [ "http 1.1.0", "reqwest", "serde", - "thiserror", + "thiserror 1.0.68", "tower-service", ] @@ -5130,7 +5255,7 @@ checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ "percent-encoding", "serde", - "thiserror", + "thiserror 1.0.68", ] [[package]] @@ -5439,7 +5564,7 @@ dependencies = [ "sp1-zkvm", "strum", "strum_macros", - "thiserror", + "thiserror 1.0.68", "tiny-keccak", "tracing", "typenum", @@ -5486,11 +5611,11 @@ dependencies = [ "strum", "strum_macros", "tempfile", - "thiserror", + "thiserror 1.0.68", "tiny-keccak", "tracing", "tracing-forest", - "tracing-subscriber", + "tracing-subscriber 0.3.18", "typenum", "web-time", ] @@ -5647,9 +5772,9 @@ dependencies = [ "sp1-recursion-core", "sp1-recursion-gnark-ffi", "sp1-stark", - "thiserror", + "thiserror 1.0.68", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -5742,7 +5867,7 @@ dependencies = [ "sp1-primitives", "sp1-stark", "static_assertions", - "thiserror", + "thiserror 1.0.68", "tracing", "vec_map", "zkhash", @@ -5825,7 +5950,7 @@ dependencies = [ "strum", "strum_macros", "tempfile", - "thiserror", + "thiserror 1.0.68", "tokio", "tonic", "tracing", @@ -5870,6 +5995,11 @@ dependencies = [ name = "sp1-verifier" version = "3.0.0" dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.4.2", + "ark-groth16", + "ark-serialize 0.4.2", "hex", "lazy_static", "num-bigint 0.4.6", @@ -5877,7 +6007,7 @@ dependencies = [ "sha2 0.10.8", "sp1-sdk", "substrate-bn-succinct", - "thiserror-no-std", + "thiserror 2.0.3", ] [[package]] @@ -6226,7 +6356,16 @@ version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.68", +] + +[[package]] +name = "thiserror" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", ] [[package]] @@ -6241,23 +6380,14 @@ dependencies = [ ] [[package]] -name = "thiserror-impl-no-std" -version = "2.0.2" +name = "thiserror-impl" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", -] - -[[package]] -name = "thiserror-no-std" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" -dependencies = [ - "thiserror-impl-no-std", + "syn 2.0.87", ] [[package]] @@ -6618,9 +6748,9 @@ checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" dependencies = [ "ansi_term", "smallvec", - "thiserror", + "thiserror 1.0.68", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.18", ] [[package]] @@ -6644,6 +6774,15 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -6682,7 +6821,7 @@ dependencies = [ "log", "rand 0.8.5", "sha1 0.10.6", - "thiserror", + "thiserror 1.0.68", "url", "utf-8", ] @@ -6712,7 +6851,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror", + "thiserror 1.0.68", "tokio", "tower 0.5.1", "url", diff --git a/crates/verifier/Cargo.toml b/crates/verifier/Cargo.toml index 63690ec55a..c2b861b16d 100644 --- a/crates/verifier/Cargo.toml +++ b/crates/verifier/Cargo.toml @@ -12,10 +12,17 @@ categories = { workspace = true } [dependencies] bn = { version = "0.6.0", package = "substrate-bn-succinct" } sha2 = { version = "0.10.8", default-features = false } -thiserror-no-std = "2.0.2" +thiserror = { version = "2", default-features = false } hex = { version = "0.4.3", default-features = false, features = ["alloc"] } lazy_static = { version = "1.5.0", default-features = false } +# arkworks +ark-bn254 = { version = "0.4.0", optional = true } +ark-serialize = { version = "0.4.2", optional = true } +ark-ff = { version = "0.4.2", optional = true } +ark-groth16 = { version = "0.4.0", optional = true } +ark-ec = { version = "0.4.0", optional = true } + [dev-dependencies] sp1-sdk = { workspace = true } num-bigint = "0.4.6" @@ -23,4 +30,5 @@ num-traits = "0.2.19" [features] default = ["std"] -std = ["thiserror-no-std/std"] +std = ["thiserror/std"] +ark = ["ark-bn254", "ark-serialize", "ark-ff", "ark-groth16", "ark-ec"] diff --git a/crates/verifier/src/error.rs b/crates/verifier/src/error.rs index 2d37bceac9..1f30633fde 100644 --- a/crates/verifier/src/error.rs +++ b/crates/verifier/src/error.rs @@ -1,5 +1,5 @@ use bn::{CurveError, FieldError, GroupError}; -use thiserror_no_std::Error; +use thiserror::Error; #[derive(Error, Debug)] pub enum Error { diff --git a/crates/verifier/src/groth16/ark_converter.rs b/crates/verifier/src/groth16/ark_converter.rs new file mode 100644 index 0000000000..2554585597 --- /dev/null +++ b/crates/verifier/src/groth16/ark_converter.rs @@ -0,0 +1,196 @@ +use ark_bn254::{Bn254, Fr, G1Affine, G2Affine}; +use ark_ec::AffineRepr; +use ark_ff::PrimeField; +use ark_groth16::{Proof, VerifyingKey}; +use ark_serialize::{CanonicalDeserialize, Compress, Validate}; +use thiserror::Error; + +const GNARK_MASK: u8 = 0b11 << 6; +const GNARK_COMPRESSED_POSITIVE: u8 = 0b10 << 6; +const GNARK_COMPRESSED_NEGATIVE: u8 = 0b11 << 6; +const GNARK_COMPRESSED_INFINITY: u8 = 0b01 << 6; + +const ARK_MASK: u8 = 0b11 << 6; +const ARK_COMPRESSED_POSITIVE: u8 = 0b00 << 6; +const ARK_COMPRESSED_NEGATIVE: u8 = 0b10 << 6; +const ARK_COMPRESSED_INFINITY: u8 = 0b01 << 6; + +#[derive(Error, Debug)] +pub enum ArkGroth16Error { + #[error("G1 compression error")] + G1CompressionError, + #[error("G2 compression error")] + G2CompressionError, + #[error("Invalid input")] + InvalidInput, +} + +/// Convert the endianness of a byte array, chunk by chunk. +/// +/// Taken from https://github.com/anza-xyz/agave/blob/c54d840/curves/bn254/src/compression.rs#L176-L189 +fn convert_endianness( + bytes: &[u8; ARRAY_SIZE], +) -> [u8; ARRAY_SIZE] { + let reversed: [_; ARRAY_SIZE] = bytes + .chunks_exact(CHUNK_SIZE) + .flat_map(|chunk| chunk.iter().rev().copied()) + .enumerate() + .fold([0u8; ARRAY_SIZE], |mut acc, (i, v)| { + acc[i] = v; + acc + }); + reversed +} + +/// Decompress a G1 point. +/// +/// Taken from https://github.com/anza-xyz/agave/blob/c54d840/curves/bn254/src/compression.rs#L219 +fn decompress_g1(g1_bytes: &[u8; 32]) -> Result { + let g1_bytes = gnark_compressed_x_to_ark_compressed_x(g1_bytes)?; + let g1_bytes = convert_endianness::<32, 32>(&g1_bytes.as_slice().try_into().unwrap()); + let decompressed_g1 = G1Affine::deserialize_with_mode( + convert_endianness::<32, 32>(&g1_bytes).as_slice(), + Compress::Yes, + Validate::No, + ) + .map_err(|_| ArkGroth16Error::G1CompressionError)?; + Ok(decompressed_g1) +} + +/// Decompress a G2 point. +/// +/// Adapted from https://github.com/anza-xyz/agave/blob/c54d840/curves/bn254/src/compression.rs#L255 +fn decompress_g2(g2_bytes: &[u8; 64]) -> Result { + let g2_bytes = gnark_compressed_x_to_ark_compressed_x(g2_bytes)?; + let g2_bytes = convert_endianness::<64, 64>(&g2_bytes.as_slice().try_into().unwrap()); + let decompressed_g2 = G2Affine::deserialize_with_mode( + convert_endianness::<64, 64>(&g2_bytes).as_slice(), + Compress::Yes, + Validate::No, + ) + .map_err(|_| ArkGroth16Error::G2CompressionError)?; + Ok(decompressed_g2) +} + +fn gnark_flag_to_ark_flag(msb: u8) -> Result { + let gnark_flag = msb & GNARK_MASK; + + let ark_flag = match gnark_flag { + GNARK_COMPRESSED_POSITIVE => ARK_COMPRESSED_POSITIVE, + GNARK_COMPRESSED_NEGATIVE => ARK_COMPRESSED_NEGATIVE, + GNARK_COMPRESSED_INFINITY => ARK_COMPRESSED_INFINITY, + _ => { + return Err(ArkGroth16Error::InvalidInput); + } + }; + + Ok(msb & !ARK_MASK | ark_flag) +} + +fn gnark_compressed_x_to_ark_compressed_x(x: &[u8]) -> Result, ArkGroth16Error> { + if x.len() != 32 && x.len() != 64 { + return Err(ArkGroth16Error::InvalidInput); + } + let mut x_copy = x.to_owned(); + + let msb = gnark_flag_to_ark_flag(x_copy[0])?; + x_copy[0] = msb; + + x_copy.reverse(); + Ok(x_copy) +} + +/// Deserialize a gnark decompressed affine G1 point to an arkworks decompressed affine G1 point. +fn gnark_decompressed_g1_to_ark_decompressed_g1( + buf: &[u8; 64], +) -> Result { + let buf = convert_endianness::<32, 64>(buf); + if buf == [0u8; 64] { + return Ok(G1Affine::zero()); + } + let g1 = G1Affine::deserialize_with_mode( + &*[&buf[..], &[0u8][..]].concat(), + Compress::No, + Validate::Yes, + ) + .map_err(|_| ArkGroth16Error::G1CompressionError)?; + Ok(g1) +} + +/// Deserialize a gnark decompressed affine G2 point to an arkworks decompressed affine G2 point. +fn gnark_decompressed_g2_to_ark_decompressed_g2( + buf: &[u8; 128], +) -> Result { + let buf = convert_endianness::<64, 128>(buf); + if buf == [0u8; 128] { + return Ok(G2Affine::zero()); + } + let g2 = G2Affine::deserialize_with_mode( + &*[&buf[..], &[0u8][..]].concat(), + Compress::No, + Validate::Yes, + ) + .map_err(|_| ArkGroth16Error::G2CompressionError)?; + Ok(g2) +} + +/// Load a Groth16 proof from bytes in the arkworks format. +pub fn load_ark_proof_from_bytes(buffer: &[u8]) -> Result, ArkGroth16Error> { + Ok(Proof:: { + a: gnark_decompressed_g1_to_ark_decompressed_g1(buffer[..64].try_into().unwrap())?, + b: gnark_decompressed_g2_to_ark_decompressed_g2(buffer[64..192].try_into().unwrap())?, + c: gnark_decompressed_g1_to_ark_decompressed_g1(&buffer[192..256].try_into().unwrap())?, + }) +} + +/// Load a Groth16 verifying key from bytes in the arkworks format. +pub fn load_ark_groth16_verifying_key_from_bytes( + buffer: &[u8], +) -> Result, ArkGroth16Error> { + // Note that g1_beta and g1_delta are not used in the verification process. + let alpha_g1 = decompress_g1(buffer[..32].try_into().unwrap())?; + let beta_g2 = decompress_g2(buffer[64..128].try_into().unwrap())?; + let gamma_g2 = decompress_g2(buffer[128..192].try_into().unwrap())?; + let delta_g2 = decompress_g2(buffer[224..288].try_into().unwrap())?; + + let num_k = u32::from_be_bytes([buffer[288], buffer[289], buffer[290], buffer[291]]); + let mut k = Vec::new(); + let mut offset = 292; + for _ in 0..num_k { + let point = decompress_g1(&buffer[offset..offset + 32].try_into().unwrap())?; + k.push(point); + offset += 32; + } + + let num_of_array_of_public_and_commitment_committed = u32::from_be_bytes([ + buffer[offset], + buffer[offset + 1], + buffer[offset + 2], + buffer[offset + 3], + ]); + offset += 4; + for _ in 0..num_of_array_of_public_and_commitment_committed { + let num = u32::from_be_bytes([ + buffer[offset], + buffer[offset + 1], + buffer[offset + 2], + buffer[offset + 3], + ]); + offset += 4; + for _ in 0..num { + offset += 4; + } + } + + Ok(VerifyingKey { alpha_g1, beta_g2, gamma_g2, delta_g2, gamma_abc_g1: k }) +} + +/// Load the public inputs from the bytes in the arkworks format. +/// +/// This reads the vkey hash and the committed values digest as big endian Fr elements. +pub fn load_ark_public_inputs_from_bytes( + vkey_hash: &[u8; 32], + committed_values_digest: &[u8; 32], +) -> [Fr; 2] { + [Fr::from_be_bytes_mod_order(vkey_hash), Fr::from_be_bytes_mod_order(committed_values_digest)] +} diff --git a/crates/verifier/src/groth16/error.rs b/crates/verifier/src/groth16/error.rs index 36952cb749..18d8e2dcbe 100644 --- a/crates/verifier/src/groth16/error.rs +++ b/crates/verifier/src/groth16/error.rs @@ -1,4 +1,4 @@ -use thiserror_no_std::Error; +use thiserror::Error; #[derive(Debug, Error)] pub enum Groth16Error { diff --git a/crates/verifier/src/groth16/mod.rs b/crates/verifier/src/groth16/mod.rs index 4dfe4796b4..f8c03bbe29 100644 --- a/crates/verifier/src/groth16/mod.rs +++ b/crates/verifier/src/groth16/mod.rs @@ -13,6 +13,9 @@ use crate::{decode_sp1_vkey_hash, error::Error, hash_public_inputs}; use alloc::vec::Vec; use sha2::{Digest, Sha256}; +#[cfg(feature = "ark")] +pub mod ark_converter; + /// A verifier for Groth16 zero-knowledge proofs. #[derive(Debug)] pub struct Groth16Verifier; diff --git a/crates/verifier/src/lib.rs b/crates/verifier/src/lib.rs index 045bb49a0d..84d5d157a6 100644 --- a/crates/verifier/src/lib.rs +++ b/crates/verifier/src/lib.rs @@ -27,6 +27,9 @@ pub use groth16::error::Groth16Error; pub use groth16::Groth16Verifier; mod groth16; +#[cfg(feature = "ark")] +pub use groth16::ark_converter::*; + pub use plonk::error::PlonkError; pub use plonk::PlonkVerifier; mod plonk; diff --git a/crates/verifier/src/plonk/error.rs b/crates/verifier/src/plonk/error.rs index 1d33e503d6..e744cb844a 100644 --- a/crates/verifier/src/plonk/error.rs +++ b/crates/verifier/src/plonk/error.rs @@ -1,4 +1,4 @@ -use thiserror_no_std::Error; +use thiserror::Error; #[derive(Error, Debug)] pub enum PlonkError { diff --git a/crates/verifier/src/tests.rs b/crates/verifier/src/tests.rs index e99d71ebd9..c6d9a853c6 100644 --- a/crates/verifier/src/tests.rs +++ b/crates/verifier/src/tests.rs @@ -1,7 +1,5 @@ use sp1_sdk::{install::try_install_circuit_artifacts, SP1ProofWithPublicValues}; -extern crate std; - #[test] fn test_verify_groth16() { // Location of the serialized SP1ProofWithPublicValues. See README.md for more information. @@ -50,3 +48,35 @@ fn test_vkeys() { let s3_vkey_bytes = std::fs::read(s3_vkey_path).unwrap(); assert_eq!(s3_vkey_bytes, *crate::PLONK_VK_BYTES); } + +#[test] +#[cfg(feature = "ark")] +fn test_ark_groth16() { + use ark_bn254::Bn254; + use ark_groth16::{r1cs_to_qap::LibsnarkReduction, Groth16}; + + use crate::{decode_sp1_vkey_hash, groth16::ark_converter::*, hash_public_inputs}; + + // Location of the serialized SP1ProofWithPublicValues. See README.md for more information. + let proof_file = "test_binaries/fibonacci-groth16.bin"; + + // Load the saved proof and extract the proof and public inputs. + let sp1_proof_with_public_values = SP1ProofWithPublicValues::load(proof_file).unwrap(); + + let proof = sp1_proof_with_public_values.bytes(); + let public_inputs = sp1_proof_with_public_values.public_values.to_vec(); + + // This vkey hash was derived by calling `vk.bytes32()` on the verifying key. + let vkey_hash = "0x00e60860c07bfc6e4c480286c0ddbb879674eb47f84b4ef041cf858b17aa0ed1"; + + let proof = load_ark_proof_from_bytes(&proof[4..]).unwrap(); + let vkey = load_ark_groth16_verifying_key_from_bytes(&crate::GROTH16_VK_BYTES).unwrap(); + + let public_inputs = load_ark_public_inputs_from_bytes( + &decode_sp1_vkey_hash(vkey_hash).unwrap(), + &hash_public_inputs(&public_inputs), + ); + + Groth16::::verify_proof(&vkey.into(), &proof, &public_inputs) + .unwrap(); +}