diff --git a/cli/src/init/gnark.rs b/cli/src/init/gnark.rs index 82005d0a..0570704b 100644 --- a/cli/src/init/gnark.rs +++ b/cli/src/init/gnark.rs @@ -11,6 +11,6 @@ impl ProvingSystem for Gnark { const ADAPTER: Adapter = Adapter::Gnark; const DEPENDENCIES: &'static str = r#" -rust-gnark = "0.0.2" +rust-gnark = "0.0.3" "#; } diff --git a/cli/src/template/gnark/lib.rs b/cli/src/template/gnark/lib.rs index 184fd0b0..f81863c9 100644 --- a/cli/src/template/gnark/lib.rs +++ b/cli/src/template/gnark/lib.rs @@ -1,26 +1,36 @@ #[cfg(not(target_arch = "wasm32"))] mod gnark; #[cfg(not(target_arch = "wasm32"))] -pub use gnark::{generate_gnark_proof, verify_gnark_proof, GnarkProofResult}; +pub use gnark::{ + generate_gnark_proof, generate_gnark_plonk_proof, + verify_gnark_proof, verify_gnark_plonk_proof, + GnarkProofResult, GnarkPlonkProofResult, +}; #[cfg(test)] #[cfg(not(target_arch = "wasm32"))] mod gnark_tests { - use crate::gnark::{generate_gnark_proof, verify_gnark_proof}; + use crate::gnark::{ + generate_gnark_proof, generate_gnark_plonk_proof, + verify_gnark_proof, verify_gnark_plonk_proof, + }; const R1CS_PATH: &str = "./test-vectors/gnark/cubic_circuit.r1cs"; - const PK_PATH: &str = "./test-vectors/gnark/cubic_circuit.pk"; - const VK_PATH: &str = "./test-vectors/gnark/cubic_circuit.vk"; + const GROTH16_PK_PATH: &str = "./test-vectors/gnark/cubic_circuit.pk"; + const GROTH16_VK_PATH: &str = "./test-vectors/gnark/cubic_circuit.vk"; - #[test] - fn test_gnark_cubic_circuit() { - // x=3: x^3 + x + 5 = 27 + 3 + 5 = 35 - let witness_json = r#"{"X": "3", "Y": "35"}"#.to_string(); + const SCS_PATH: &str = "./test-vectors/gnark/cubic_circuit_plonk.scs"; + const PLONK_PK_PATH: &str = "./test-vectors/gnark/cubic_circuit_plonk.pk"; + const PLONK_VK_PATH: &str = "./test-vectors/gnark/cubic_circuit_plonk.vk"; + + const WITNESS_JSON: &str = r#"{"X": "3", "Y": "35"}"#; + #[test] + fn test_gnark_groth16_cubic_circuit() { let result = generate_gnark_proof( R1CS_PATH.to_string(), - PK_PATH.to_string(), - witness_json, + GROTH16_PK_PATH.to_string(), + WITNESS_JSON.to_string(), ); assert!(result.is_ok(), "Proof generation should succeed"); @@ -33,7 +43,32 @@ mod gnark_tests { let valid = verify_gnark_proof( R1CS_PATH.to_string(), - VK_PATH.to_string(), + GROTH16_VK_PATH.to_string(), + proof_result, + ); + assert!(valid.is_ok(), "Verification should not error"); + assert!(valid.unwrap(), "Proof should be valid"); + } + + #[test] + fn test_gnark_plonk_cubic_circuit() { + let result = generate_gnark_plonk_proof( + SCS_PATH.to_string(), + PLONK_PK_PATH.to_string(), + WITNESS_JSON.to_string(), + ); + assert!(result.is_ok(), "PLONK proof generation should succeed"); + + let proof_result = result.unwrap(); + assert!(!proof_result.proof.is_empty(), "Proof should not be empty"); + assert!( + !proof_result.public_inputs.is_empty(), + "Public inputs should not be empty" + ); + + let valid = verify_gnark_plonk_proof( + SCS_PATH.to_string(), + PLONK_VK_PATH.to_string(), proof_result, ); assert!(valid.is_ok(), "Verification should not error"); diff --git a/cli/src/template/init/src/gnark.rs b/cli/src/template/init/src/gnark.rs index 1ea719ef..664a6a9a 100644 --- a/cli/src/template/init/src/gnark.rs +++ b/cli/src/template/init/src/gnark.rs @@ -79,3 +79,57 @@ pub fn verify_gnark_proof( rust_gnark::groth16_verify(&r1cs_path, &vk_path, &inner) .map_err(|e| MoproError::GnarkError(e.to_string())) } + +/// Result of a gnark PLONK BN254 proof generation. +#[derive(Debug, Clone)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +pub struct GnarkPlonkProofResult { + pub proof: String, + pub public_inputs: String, +} + +/// Generate a PLONK BN254 proof using gnark. +/// +/// # Arguments +/// +/// * `scs_path` - Path to the `.scs` file (sparse constraint system) +/// * `pk_path` - Path to the `.pk` file (PLONK proving key) +/// * `witness_json` - JSON object mapping circuit field names to decimal string values +#[cfg_attr(feature = "uniffi", uniffi::export)] +pub fn generate_gnark_plonk_proof( + scs_path: String, + pk_path: String, + witness_json: String, +) -> Result { + GNARK_INIT.call_once(|| { + rust_gnark::init().expect("Failed to initialize gnark runtime"); + }); + + let result = rust_gnark::plonk_prove(&scs_path, &pk_path, &witness_json) + .map_err(|e| MoproError::GnarkError(e.to_string()))?; + + Ok(GnarkPlonkProofResult { + proof: result.proof, + public_inputs: result.public_inputs, + }) +} + +/// Verify a PLONK BN254 proof using gnark. +#[cfg_attr(feature = "uniffi", uniffi::export)] +pub fn verify_gnark_plonk_proof( + scs_path: String, + vk_path: String, + proof_result: GnarkPlonkProofResult, +) -> Result { + GNARK_INIT.call_once(|| { + rust_gnark::init().expect("Failed to initialize gnark runtime"); + }); + + let inner = rust_gnark::PlonkProofResult { + proof: proof_result.proof, + public_inputs: proof_result.public_inputs, + }; + + rust_gnark::plonk_verify(&scs_path, &vk_path, &inner) + .map_err(|e| MoproError::GnarkError(e.to_string())) +} diff --git a/cli/src/template/init/src/stubs.rs b/cli/src/template/init/src/stubs.rs index 33e11b02..dacda384 100644 --- a/cli/src/template/init/src/stubs.rs +++ b/cli/src/template/init/src/stubs.rs @@ -180,7 +180,36 @@ macro_rules! gnark_stub { ) -> Result { panic!("Gnark is not enabled in this build. Please select \"gnark\" adapter when initializing the project."); } + + #[derive(Debug, Clone)] + #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] + pub struct GnarkPlonkProofResult { + pub proof: String, + pub public_inputs: String, + } + + #[cfg_attr(feature = "uniffi", uniffi::export)] + pub fn generate_gnark_plonk_proof( + _scs_path: String, + _pk_path: String, + _witness_json: String, + ) -> Result { + panic!("Gnark is not enabled in this build. Please select \"gnark\" adapter when initializing the project."); + } + + #[cfg_attr(feature = "uniffi", uniffi::export)] + pub fn verify_gnark_plonk_proof( + _scs_path: String, + _vk_path: String, + _proof_result: GnarkPlonkProofResult, + ) -> Result { + panic!("Gnark is not enabled in this build. Please select \"gnark\" adapter when initializing the project."); + } } - pub use gnark_stub::{generate_gnark_proof, verify_gnark_proof, GnarkProofResult}; + pub use gnark_stub::{ + generate_gnark_proof, generate_gnark_plonk_proof, + verify_gnark_proof, verify_gnark_plonk_proof, + GnarkProofResult, GnarkPlonkProofResult, + }; }; } diff --git a/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.pk b/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.pk new file mode 100644 index 00000000..7c3198de Binary files /dev/null and b/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.pk differ diff --git a/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.scs b/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.scs new file mode 100644 index 00000000..0ef04368 Binary files /dev/null and b/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.scs differ diff --git a/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.vk b/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.vk new file mode 100644 index 00000000..ab7015e2 Binary files /dev/null and b/cli/src/template/init/test-vectors/gnark/cubic_circuit_plonk.vk differ diff --git a/cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.kts b/cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.kts index 481a1466..8df33674 100644 --- a/cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.kts +++ b/cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.kts @@ -2,20 +2,31 @@ try { val r1csPath = "./test-vectors/gnark/cubic_circuit.r1cs" - val pkPath = "./test-vectors/gnark/cubic_circuit.pk" - val vkPath = "./test-vectors/gnark/cubic_circuit.vk" + val groth16PkPath = "./test-vectors/gnark/cubic_circuit.pk" + val groth16VkPath = "./test-vectors/gnark/cubic_circuit.vk" + + val scsPath = "./test-vectors/gnark/cubic_circuit_plonk.scs" + val plonkPkPath = "./test-vectors/gnark/cubic_circuit_plonk.pk" + val plonkVkPath = "./test-vectors/gnark/cubic_circuit_plonk.vk" // x=3: x^3 + x + 5 = 35 val witnessJson = "{\"X\": \"3\", \"Y\": \"35\"}" - // Generate proof - val proofResult = generateGnarkProof(r1csPath, pkPath, witnessJson) - assert(proofResult.proof.isNotEmpty()) { "Proof should not be empty" } - assert(proofResult.publicInputs.isNotEmpty()) { "Public inputs should not be empty" } + // --- Groth16 --- + val groth16Result = generateGnarkProof(r1csPath, groth16PkPath, witnessJson) + assert(groth16Result.proof.isNotEmpty()) { "Groth16 proof should not be empty" } + assert(groth16Result.publicInputs.isNotEmpty()) { "Groth16 public inputs should not be empty" } + + val groth16Valid = verifyGnarkProof(r1csPath, groth16VkPath, groth16Result) + assert(groth16Valid) { "Groth16 proof is invalid" } + + // --- PLONK --- + val plonkResult = generateGnarkPlonkProof(scsPath, plonkPkPath, witnessJson) + assert(plonkResult.proof.isNotEmpty()) { "PLONK proof should not be empty" } + assert(plonkResult.publicInputs.isNotEmpty()) { "PLONK public inputs should not be empty" } - // Verify proof - val isValid = verifyGnarkProof(r1csPath, vkPath, proofResult) - assert(isValid) { "Proof is invalid" } + val plonkValid = verifyGnarkPlonkProof(scsPath, plonkVkPath, plonkResult) + assert(plonkValid) { "PLONK proof is invalid" } } catch (e: Exception) { println(e) diff --git a/cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.swift b/cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.swift index 07b2bfe1..f91bdc73 100644 --- a/cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.swift +++ b/cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.swift @@ -3,22 +3,35 @@ import Foundation do { let r1csPath = "../../../test-vectors/gnark/cubic_circuit.r1cs" - let pkPath = "../../../test-vectors/gnark/cubic_circuit.pk" - let vkPath = "../../../test-vectors/gnark/cubic_circuit.vk" + let groth16PkPath = "../../../test-vectors/gnark/cubic_circuit.pk" + let groth16VkPath = "../../../test-vectors/gnark/cubic_circuit.vk" + + let scsPath = "../../../test-vectors/gnark/cubic_circuit_plonk.scs" + let plonkPkPath = "../../../test-vectors/gnark/cubic_circuit_plonk.pk" + let plonkVkPath = "../../../test-vectors/gnark/cubic_circuit_plonk.vk" // x=3: x^3 + x + 5 = 35 let witnessJson = "{\"X\": \"3\", \"Y\": \"35\"}" - // Generate Proof - let proofResult = try generateGnarkProof( - r1csPath: r1csPath, pkPath: pkPath, witnessJson: witnessJson) - assert(!proofResult.proof.isEmpty, "Proof should not be empty") - assert(!proofResult.publicInputs.isEmpty, "Public inputs should not be empty") + // --- Groth16 --- + let groth16Result = try generateGnarkProof( + r1csPath: r1csPath, pkPath: groth16PkPath, witnessJson: witnessJson) + assert(!groth16Result.proof.isEmpty, "Groth16 proof should not be empty") + assert(!groth16Result.publicInputs.isEmpty, "Groth16 public inputs should not be empty") + + let groth16Valid = try verifyGnarkProof( + r1csPath: r1csPath, vkPath: groth16VkPath, proofResult: groth16Result) + assert(groth16Valid, "Groth16 proof verification should succeed") + + // --- PLONK --- + let plonkResult = try generateGnarkPlonkProof( + scsPath: scsPath, pkPath: plonkPkPath, witnessJson: witnessJson) + assert(!plonkResult.proof.isEmpty, "PLONK proof should not be empty") + assert(!plonkResult.publicInputs.isEmpty, "PLONK public inputs should not be empty") - // Verify Proof - let isValid = try verifyGnarkProof( - r1csPath: r1csPath, vkPath: vkPath, proofResult: proofResult) - assert(isValid, "Proof verification should succeed") + let plonkValid = try verifyGnarkPlonkProof( + scsPath: scsPath, vkPath: plonkVkPath, proofResult: plonkResult) + assert(plonkValid, "PLONK proof verification should succeed") } catch let error as MoproError { print("MoproError: \(error)")