Skip to content
Draft
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
2 changes: 1 addition & 1 deletion cli/src/init/gnark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
"#;
}
57 changes: 46 additions & 11 deletions cli/src/template/gnark/lib.rs
Original file line number Diff line number Diff line change
@@ -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");

Expand All @@ -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");
Expand Down
54 changes: 54 additions & 0 deletions cli/src/template/init/src/gnark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<GnarkPlonkProofResult, MoproError> {
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<bool, MoproError> {
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()))
}
31 changes: 30 additions & 1 deletion cli/src/template/init/src/stubs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,36 @@ macro_rules! gnark_stub {
) -> Result<bool, MoproError> {
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<GnarkPlonkProofResult, MoproError> {
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<bool, MoproError> {
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,
};
};
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
29 changes: 20 additions & 9 deletions cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
35 changes: 24 additions & 11 deletions cli/src/template/init/tests/bindings/gnark/test_gnark_cubic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)")
Expand Down
Loading