diff --git a/Cargo.lock b/Cargo.lock index 657b7a62c..96fdafd86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3079,7 +3079,7 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "mavros-artifacts" version = "0.1.0" -source = "git+https://github.com/reilabs/mavros?rev=a4f2a3d7aa430a27238bef401f772bfb9b2d0d01#a4f2a3d7aa430a27238bef401f772bfb9b2d0d01" +source = "git+https://github.com/reilabs/mavros?rev=42b6c5aead8a18d67a3f760520886f9cf8a01fb8#42b6c5aead8a18d67a3f760520886f9cf8a01fb8" dependencies = [ "ark-bn254", "ark-ff", @@ -3094,12 +3094,12 @@ dependencies = [ [[package]] name = "mavros-limb-arith" version = "0.1.0" -source = "git+https://github.com/reilabs/mavros?rev=a4f2a3d7aa430a27238bef401f772bfb9b2d0d01#a4f2a3d7aa430a27238bef401f772bfb9b2d0d01" +source = "git+https://github.com/reilabs/mavros?rev=42b6c5aead8a18d67a3f760520886f9cf8a01fb8#42b6c5aead8a18d67a3f760520886f9cf8a01fb8" [[package]] name = "mavros-opcode-gen" version = "0.1.0" -source = "git+https://github.com/reilabs/mavros?rev=a4f2a3d7aa430a27238bef401f772bfb9b2d0d01#a4f2a3d7aa430a27238bef401f772bfb9b2d0d01" +source = "git+https://github.com/reilabs/mavros?rev=42b6c5aead8a18d67a3f760520886f9cf8a01fb8#42b6c5aead8a18d67a3f760520886f9cf8a01fb8" dependencies = [ "proc-macro2", "quote", @@ -3110,7 +3110,7 @@ dependencies = [ [[package]] name = "mavros-vm" version = "0.1.0" -source = "git+https://github.com/reilabs/mavros?rev=a4f2a3d7aa430a27238bef401f772bfb9b2d0d01#a4f2a3d7aa430a27238bef401f772bfb9b2d0d01" +source = "git+https://github.com/reilabs/mavros?rev=42b6c5aead8a18d67a3f760520886f9cf8a01fb8#42b6c5aead8a18d67a3f760520886f9cf8a01fb8" dependencies = [ "ark-ff", "mavros-artifacts", diff --git a/Cargo.toml b/Cargo.toml index 75a9d4588..996c09f85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -207,8 +207,8 @@ ark-ff = { version = "0.6", features = ["asm", "std"] } ark-poly = "0.6" ark-serialize = "0.6" ark-std = { version = "0.6", features = ["std"] } -mavros-vm = { git = "https://github.com/reilabs/mavros", rev = "a4f2a3d7aa430a27238bef401f772bfb9b2d0d01" } -mavros-artifacts = { git = "https://github.com/reilabs/mavros", rev = "a4f2a3d7aa430a27238bef401f772bfb9b2d0d01" } +mavros-vm = { git = "https://github.com/reilabs/mavros", rev = "42b6c5aead8a18d67a3f760520886f9cf8a01fb8" } +mavros-artifacts = { git = "https://github.com/reilabs/mavros", rev = "42b6c5aead8a18d67a3f760520886f9cf8a01fb8" } spongefish = { package = "provekit-spongefish", version = "=0.2.0", features = [ "ark-ff", "sha2", diff --git a/README.md b/README.md index e12415887..d0f6919c8 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ graph LR Recursive --> Groth16[Groth16 proof] ``` -The default Noir frontend reads a package, produces ACIR, lowers that ACIR into R1CS, and writes `.pkp`/`.pkv` key files. Circuits that benefit from a direct R1CS frontend can use [`mavros`](https://github.com/reilabs/mavros) with `prepare --compiler mavros` and an explicit `--r1cs` file. Build the Mavros CLI from the `mavros-vm` revision pinned in `Cargo.toml` to ensure artifact compatibility. +The default Noir frontend reads a package, produces ACIR, lowers that ACIR into R1CS, and writes `.pkp`/`.pkv` key files. Circuits that benefit from a direct R1CS frontend can use [`mavros`](https://github.com/reilabs/mavros) with `prepare --compiler mavros` on the `.mavros` artifact it writes. Build the Mavros CLI from the `mavros-vm` revision pinned in `Cargo.toml` to ensure artifact compatibility. ## Example Circuit @@ -114,7 +114,7 @@ Swift, Kotlin, troubleshooting, and deployment checklists, see ## Advanced Usage -- **Direct R1CS frontend:** after generating Mavros artifacts, call `provekit-cli prepare --compiler mavros --r1cs `. The circuit computes its return; a `return` entry in `Prover.toml` is optional and, when present, checked against it. The Mavros R1CS digest carried by `r1cs.bin` is verified on load and bound into every proof's transcript. Use `scripts/mavros_parity.sh` to compare both frontends. +- **Direct R1CS frontend:** after `mavros compile`, call `provekit-cli prepare --compiler mavros `. The circuit computes its return; a `return` entry in `Prover.toml` is optional and, when present, checked against it. The artifact's digests are verified on load and its circuit digest is bound into every proof's transcript. Use `scripts/mavros_parity.sh` to compare both frontends. - **Recursive verifier inputs:** `provekit-cli generate-gnark-inputs ` writes `params_for_recursive_verifier` and `r1cs.json` by default; use `--params` and `--r1cs` to override those paths. - **Inspection commands:** use `circuit-stats` for Noir ACIR/R1CS structure, `analyze-pkp` for Noir prover-key size breakdowns, and `show-inputs` for public inputs. - **FFI integration:** start in [`tooling/provekit-ffi/`](tooling/provekit-ffi/) for C ABI headers, mobile build targets, and host-language examples. diff --git a/noir-examples/power/.gitignore b/noir-examples/power/.gitignore deleted file mode 100644 index f5caa355c..000000000 --- a/noir-examples/power/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -!basic.json -!r1cs.bin diff --git a/noir-examples/power/basic.json b/noir-examples/power/basic.json deleted file mode 100644 index 32996ca30..000000000 --- a/noir-examples/power/basic.json +++ /dev/null @@ -1,317 +0,0 @@ -{ - "abi": { - "error_types": {}, - "parameters": [ - { - "name": "x", - "type": { - "kind": "field" - }, - "visibility": "private" - }, - { - "name": "y", - "type": { - "kind": "field" - }, - "visibility": "public" - } - ], - "return_type": { - "abi_type": { - "kind": "field" - }, - "visibility": "public" - } - }, - "binary": [ - 5566825525924812365, - 4, - 1, - 1, - 14, - 0, - 0, - 0, - 0, - 12, - 0, - 0, - 4, - 12436184717236109307, - 3962172157175319849, - 7381016538464732718, - 1011752739694698287, - 0, - 2, - 2, - 22, - 67, - 18446744073709551615, - 28, - 122, - 10, - 0, - 4, - 8, - 14, - 0, - 8, - 15, - 1, - 6, - 10, - 84, - 16, - 2, - 15, - 4, - 2, - 6, - 16, - 84, - 20, - 2, - 14, - 4, - 2, - 6, - 20, - 2, - 162, - 2, - 4, - 20, - 4, - 16, - 24, - 6, - 24, - 5, - 24, - 10, - 24, - 3, - 18446744073709551615, - 16, - 122, - 2, - 0, - 4, - 94, - 6, - 89, - 6, - 94, - 7, - 94, - 8, - 2, - 33, - 2, - 1, - 8, - 1, - 7, - 9, - 94, - 10, - 95, - 11, - 2, - 93, - 12, - 90, - 9, - 12, - 89, - 9, - 91, - 11, - 12, - 89, - 11, - 92, - 10, - 12, - 89, - 10, - 3, - 18446744073709551615, - 27, - 122, - 4, - 0, - 4, - 8, - 8, - 0, - 8, - 9, - 10, - 8, - 10, - 1, - 95, - 11, - 4, - 88, - 11, - 1, - 9, - 12, - 8, - 1, - 9, - 13, - 11, - 1, - 0, - 2, - 40, - 14, - 12, - 9, - 1, - 14, - 27, - 4, - 89, - 2, - 93, - 15, - 90, - 13, - 15, - 89, - 13, - 91, - 11, - 15, - 89, - 11, - 92, - 3, - 15, - 10, - 0, - 0, - 3, - 1, - 3, - 94, - 19, - 93, - 20, - 90, - 13, - 20, - 89, - 13, - 91, - 2, - 20, - 92, - 19, - 20, - 11, - 24, - 12, - 10, - 32, - 9, - 25, - 24, - 1, - 9, - 26, - 19, - 1, - 9, - 12, - 25, - 1, - 9, - 13, - 26, - 1, - 0, - 18446744073709551549, - 18446744073709551615, - 33, - 122, - 10, - 0, - 4, - 8, - 14, - 0, - 8, - 15, - 10, - 8, - 16, - 1, - 9, - 17, - 14, - 1, - 9, - 18, - 10, - 4, - 0, - 2, - 40, - 22, - 17, - 15, - 1, - 22, - 14, - 4, - 5, - 18, - 10, - 6, - 10, - 0, - 0, - 6, - 4, - 3, - 70, - 23, - 18, - 2, - 6, - 23, - 5, - 18, - 2, - 23, - 11, - 27, - 17, - 16, - 32, - 9, - 28, - 27, - 1, - 9, - 29, - 23, - 4, - 9, - 17, - 28, - 1, - 9, - 18, - 29, - 4, - 0, - 18446744073709551567 - ] -} \ No newline at end of file diff --git a/noir-examples/power/program.mavros b/noir-examples/power/program.mavros new file mode 100644 index 000000000..12b874c7f Binary files /dev/null and b/noir-examples/power/program.mavros differ diff --git a/noir-examples/power/r1cs.bin b/noir-examples/power/r1cs.bin deleted file mode 100644 index b2bae4cb3..000000000 Binary files a/noir-examples/power/r1cs.bin and /dev/null differ diff --git a/provekit/backend/bn254/src/scheme/mavros.rs b/provekit/backend/bn254/src/scheme/mavros.rs index 061980c9c..c016fc801 100644 --- a/provekit/backend/bn254/src/scheme/mavros.rs +++ b/provekit/backend/bn254/src/scheme/mavros.rs @@ -225,6 +225,7 @@ mod wasm_stubs { pub algebraic_size: usize, pub multiplicities_size: usize, pub challenges_size: usize, + pub logup_repetitions: usize, pub tables_data_size: usize, pub lookups_data_size: usize, } diff --git a/provekit/r1cs-compiler/src/noir_proof_scheme.rs b/provekit/r1cs-compiler/src/noir_proof_scheme.rs index 8ed7c6275..f41b2b044 100644 --- a/provekit/r1cs-compiler/src/noir_proof_scheme.rs +++ b/provekit/r1cs-compiler/src/noir_proof_scheme.rs @@ -1,14 +1,13 @@ use { crate::{noir_to_r1cs, witness_generator::NoirWitnessGeneratorBuilder}, anyhow::{ensure, Context as _, Result}, - mavros_artifacts::{ArtifactError, R1CSArtifact, R1CS as MavrosR1CS}, + mavros_artifacts::{Artifact, ArtifactError, ArtifactParts, R1CS as MavrosR1CS}, noirc_artifacts::program::ProgramArtifact, provekit_backend_bn254::{ witness::WitnessBuilder, Bn254Field, MavrosColumnMap, MavrosSchemeData, NoirProofScheme, NoirSchemeData, NoirWitnessGenerator, PrintAbi, }, provekit_common::WhirR1CSScheme, - serde::Deserialize, std::{collections::HashSet, fs::File, path::Path}, tracing::{info, instrument}, }; @@ -188,55 +187,48 @@ impl NoirCompiler { } } -#[derive(Deserialize)] -struct BasicArtifacts { - abi: noirc_abi::Abi, - binary: Vec, -} - pub struct MavrosCompiler; impl MavrosCompiler { #[instrument(skip_all)] pub fn compile( - basic_path: impl AsRef + std::fmt::Debug, - r1cs_path: impl AsRef + std::fmt::Debug, + artifact_path: impl AsRef + std::fmt::Debug, hash_config: provekit_common::HashConfig, witness_mode: provekit_common::WitnessCommitmentMode, ) -> Result { provekit_backend_bn254::register(); - info!("Reading basic artifacts from {:?}", basic_path); - let basic_file = File::open(&basic_path).context("while opening basic artifacts")?; - let basic: BasicArtifacts = - serde_json::from_reader(basic_file).context("while reading basic artifacts")?; - let abi = basic.abi; - - info!("Reading R1CS from {:?}", r1cs_path); - let r1cs_bytes = std::fs::read(r1cs_path.as_ref()).context("while reading R1CS file")?; - let artifact = - R1CSArtifact::::from_bytes(&r1cs_bytes) - .map_err(|err| match err { - ArtifactError::MissingHeader | ArtifactError::UnsupportedVersion(_) => { - anyhow::anyhow!( - "{err}; recompile the circuit with the Mavros revision pinned in the \ - workspace `Cargo.toml`" - ) - } - other => anyhow::Error::new(other), - }) - .with_context(|| format!("while reading the Mavros R1CS artifact {r1cs_path:?}"))?; - let mavros_digest = artifact.digest(); - let (_, manifest, mavros_r1cs) = artifact.into_parts(); + info!("Reading Mavros artifact from {:?}", artifact_path); + let bytes = + std::fs::read(artifact_path.as_ref()).context("while reading the Mavros artifact")?; + let artifact = Artifact::::from_bytes(&bytes) + .map_err(|err| match err { + ArtifactError::MissingHeader | ArtifactError::UnsupportedVersion { .. } => { + anyhow::anyhow!( + "{err}; recompile the circuit with the Mavros revision pinned in the \ + workspace `Cargo.toml`" + ) + } + other => anyhow::Error::new(other), + }) + .with_context(|| format!("while reading the Mavros artifact {artifact_path:?}"))?; + let abi: noirc_abi::Abi = serde_json::from_slice(artifact.abi()) + .context("while decoding the ABI in the Mavros artifact")?; + let mavros_digest = artifact.circuit_digest(); + let ArtifactParts { + compiler, + manifest, + r1cs: mavros_r1cs, + bytecode: binary, + .. + } = artifact.into_parts(); info!( - "R1CS: {} constraints, witness layout: algebraic={}, challenges={}, digest={}", + "Mavros {compiler} R1CS: {} constraints, witness layout: algebraic={}, challenges={}, \ + circuit digest={}", mavros_r1cs.constraints.len(), mavros_r1cs.witness_layout.algebraic_size, mavros_r1cs.witness_layout.challenges_size, - mavros_digest - .iter() - .map(|b| format!("{b:02x}")) - .collect::(), + mavros_artifacts::hex(&mavros_digest), ); let column_map = @@ -263,7 +255,7 @@ impl MavrosCompiler { abi, num_public_inputs, whir_for_witness, - binary: basic.binary, + binary, r1cs, constraints_layout: mavros_r1cs.constraints_layout, witness_layout: mavros_r1cs.witness_layout, diff --git a/scripts/mavros_parity.sh b/scripts/mavros_parity.sh index 867bd868b..c301a5e90 100755 --- a/scripts/mavros_parity.sh +++ b/scripts/mavros_parity.sh @@ -44,7 +44,7 @@ run_frontend() { "$CLI" prepare "$dir" --pkp "$pkp" --pkv "$pkv" >>"$log" 2>&1 || { echo "fail - -"; return; } else (cd "$dir" && "$MAVROS" compile) >>"$log" 2>&1 || { echo "fail - -"; return; } - "$CLI" prepare --compiler mavros "$dir/target/basic.json" --r1cs "$dir/target/r1cs.bin" \ + "$CLI" prepare --compiler mavros "$dir/target/program.mavros" \ --pkp "$pkp" --pkv "$pkv" >>"$log" 2>&1 || { echo "fail - -"; return; } fi local t0 t1 diff --git a/tooling/cli/src/cmd/prepare.rs b/tooling/cli/src/cmd/prepare.rs index 4d38e352b..c3c390cb1 100644 --- a/tooling/cli/src/cmd/prepare.rs +++ b/tooling/cli/src/cmd/prepare.rs @@ -46,15 +46,11 @@ impl argh::FromArgValue for Compiler { #[derive(FromArgs, PartialEq, Eq, Debug)] #[argh(subcommand, name = "prepare")] pub struct Args { - /// directory containing Nargo.toml for noir, or path to the basic - /// artifacts JSON for mavros (default: current directory) + /// directory containing Nargo.toml for noir, or path to the `.mavros` + /// artifact for mavros (default: current directory) #[argh(positional, default = "PathBuf::from(\".\")")] program_path: PathBuf, - /// path to the R1CS file (required for mavros compiler) - #[argh(option, long = "r1cs")] - r1cs_path: Option, - /// compiler backend to use: "noir" (default) or "mavros" #[argh(option, long = "compiler", default = "Compiler::Noir")] compiler: Compiler, @@ -236,13 +232,8 @@ impl Args { hash_config: HashConfig, witness_mode: WitnessCommitmentMode, ) -> Result<()> { - let r1cs_path = self - .r1cs_path - .as_ref() - .context("--r1cs is required when using the mavros compiler")?; - let scheme = - MavrosCompiler::compile(&self.program_path, r1cs_path, hash_config, witness_mode) - .context("while compiling with Mavros")?; + let scheme = MavrosCompiler::compile(&self.program_path, hash_config, witness_mode) + .context("while compiling with Mavros")?; let spark_setup = self.maybe_build_spark(&scheme, hash_config)?; let pkp_path = resolve_key_path(self.pkp_path.as_deref(), "pkp")?; let pkv_path = resolve_key_path(self.pkv_path.as_deref(), "pkv")?; diff --git a/tooling/cli/tests/mavros_public_inputs.rs b/tooling/cli/tests/mavros_public_inputs.rs index 9c4bfe3ba..eb9138a4c 100644 --- a/tooling/cli/tests/mavros_public_inputs.rs +++ b/tooling/cli/tests/mavros_public_inputs.rs @@ -1,8 +1,7 @@ //! Public-input and return regressions on `noir-examples/power` -//! (`fn main(x: Field, y: pub Field) -> pub Field`), whose Mavros artifacts -//! are committed next to it. Regenerate them with the pinned Mavros revision: -//! `mavros compile --r1cs-output /r1cs.bin --binary-output -//! /basic.json`. +//! (`fn main(x: Field, y: pub Field) -> pub Field`), whose Mavros artifact is +//! committed next to it. Regenerate it with the pinned Mavros revision: +//! `mavros compile --output /program.mavros`. use { anyhow::Result, @@ -19,8 +18,7 @@ use { fn fixture_scheme() -> NoirProofScheme { let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../noir-examples/power"); MavrosCompiler::compile( - dir.join("basic.json"), - dir.join("r1cs.bin"), + dir.join("program.mavros"), HashConfig::Sha256, WitnessCommitmentMode::default(), )