Skip to content

brevis-network/brevis-vera

Repository files navigation

Brevis Vera

ZK-powered media authenticity. Prove that an edited image derives from a real, hardware-signed original — without revealing the original image or transform parameters.

What it does

Brevis Vera takes a C2PA-signed photo, applies edits (crop, brighten, grayscale), and produces a compact proof package. Any verifier can confirm the edited image is a legitimate derivative of the signed original — without trusting the editor and without seeing the original.

Proven inside the ZK circuit:

  • The C2PA ECDSA P-256 signature over the COSE Sig_structure1 is valid under the committed public key
  • The signed claim authentically covers the JPEG file bytes (two-step C2PA asset binding hash chain)
  • The JPEG decodes to the committed original pixels
  • SHA-256 commitments over original and output pixels are correct
  • The output pixels were produced by running exactly the declared transforms on the original pixels
  • Transform parameters (crop coordinates, brightness delta) stay private

Checked by the verifier (outside ZK):

  • The edited image decodes to the exact output pixels the proof committed to (output_hash)
  • The c2pa_pubkey committed by the proof chains to a trusted root certificate (leaf pubkey binding, chain signature validity, cert validity period, root CA pinned against C2PA trust list + Brevis Vera root)

Privacy model: The original JPEG, transform parameters, C2PA protected headers, claim CBOR, and signature bytes are never committed to the proof's public values — only original_hash, output_hash, transforms_applied, and c2pa_pubkey are public outputs.

Project structure

bv-core/        Shared types, integer transform functions, CBOR encoder
bv-capture/     C2PA JUMBF/COSE extraction, RGBA decode, commitment hash
bv-edit/        Host-side editing pipeline (decode → transform → encode)
bv-zkvm/guest/  ZK circuit: ECDSA verification + transform replay (Pico RISC-V guest)
bv-zkvm/host/   Proof generation via Pico SDK
bv-cli/         CLI: `bv prove`, `bv edit`, `bv verify`, `bv sign`
bv-web/         Web prover + verifier: Axum server + browser UI

Prerequisites

  • Rust nightly-2025-08-04 (auto-selected via rust-toolchain.toml)
  • Pico CLI for building the guest ELF:
    cargo +nightly-2025-08-04 install --git https://github.com/brevis-network/pico pico-cli
    

Build

# Build the guest ELF (only needed once, or after changing guest code)
cd bv-zkvm/guest && cargo pico build && cd ../..

# Build the workspace
cargo build --release

Test

# Run all unit tests (excludes slow ZK proof tests)
cargo test --workspace --exclude bv-zkvm-host

# Run ZK proof integration tests (slow — generates real STARK proofs on small
# synthetic images plus an emulation test with C2PA ECDSA verification)
cargo test -p bv-zkvm-host

Test images

File Resolution Signer GPU full prove
assets/demo_mini.jpg 64×42 Brevis test CA
assets/demo_small.jpg 320×213 Brevis test CA 4.8s
assets/demo_mid.jpg 640×426 Brevis test CA 8.2s
assets/demo_large.jpg 1920×1280 Brevis test CA 41.4s
assets/sony_2.jpg 4320×2880 Sony ILCE-1 183s (~3 min)
assets/sony_1.jpg 8640×5760 Sony ILCE-1 827s (~13.8 min)

GPU times measured on the Brevis 8-GPU server with compressed STARK (full C2PA-in-ZK pipeline). See docs/scaling.md for cycle counts, CPU times, and future optimizations.

Source JPEGs (unsigned) for re-signing are in assets/demo_source/. Demo images are signed with our test CA (assets/certs/); Sony images carry real hardware C2PA provenance.

Usage

Dry-run: measure cycles without proving

Before committing to a long proof run, use --emulate to verify hashes and measure cycle counts in seconds:

# Fastest dry-run (~1.7s, 64×42)
cargo run --release -p bv-cli -- prove assets/demo_mini.jpg --emulate

# Reference demo (~4.8s, 640×426)
cargo run --release -p bv-cli -- prove assets/demo_mid.jpg --emulate

Example output (demo_mid.jpg):

[1/7] Reading original image...
      49152 bytes
[2/6] Decoding image to RGBA...
      640x426 (1090560 bytes RGBA)
[3/6] Applying transforms...
      2 transform(s): [Crop, Brighten]
      Output: 320x213
[4/6] Saving edited image to assets/demo_mid.edited.png...
      C2PA COSE: extracted (12 bytes protected, 847 bytes claim)
[6/6] Emulating guest program (no proof)...

Emulation complete in 4.8s
  Total cycles:    55715024
  Chunks:          214
  original_hash:   a3f1e2b4...
  output_hash:     7c9d8a12...
  transforms:      [Crop, Brighten]

No .bvproof written (emulation does not produce a proof).

Prove

Generate a ZK proof. The proof bundle contains the STARK proof bytes plus the guest's public outputs — the original JPEG is not included.

# Fast mode → demo_mid.fast.bvproof
cargo run --release -p bv-cli -- prove assets/demo_mid.jpg --fast

# Full prove pipeline → demo_mid.bvproof
cargo run --release -p bv-cli -- prove assets/demo_mid.jpg

# Custom transforms
cargo run --release -p bv-cli -- prove assets/demo_mid.jpg --fast \
  --transforms '[{"Crop":{"x":0,"y":0,"width":320,"height":213}},{"Brighten":{"value":15}}]'

Use --emulate for fast iteration — completes in seconds without generating a proof. See the Test images table above for emulation and GPU prove times.

The proof contains:

  • proof_bytes — STARK proof (cryptographic)
  • original_hash — SHA-256(width || height || RGBA pixels) of the original
  • output_hash — SHA-256(width || height || RGBA pixels) of the edited output
  • transforms_applied — list of transform kinds (Crop, Brighten, Grayscale)
  • c2pa_pubkey — uncompressed EC P-256 public key that signed the original (65 bytes)
  • cert_chain_pem — X.509 certificate chain for trust anchor verification

Not in the proof: original JPEG, original pixels, transform parameters, C2PA headers/claim/signature.

This outputs:

  • demo_mid.edited.png — the edited image
  • demo_mid.bvproof — proof bundle (or demo_mid.fast.bvproof with --fast)

Edit (no proof)

Apply transforms and save the edited PNG without generating a ZK proof. Useful for previewing edits locally or preparing files before proving on a remote GPU server.

# Default transforms (top-left quarter crop + brighten 10)
cargo run --release -p bv-cli -- edit assets/sony_1.jpg

# Custom transforms
cargo run --release -p bv-cli -- edit assets/sony_1.jpg \
  --transforms '[{"Crop":{"x":136,"y":56,"width":289,"height":226}},{"Brighten":{"value":33}}]'

# With downscale and custom output path
cargo run --release -p bv-cli -- edit assets/sony_1.jpg --max-dim 540 --output my_edit.png

Verify (CLI)

cargo run --release -p bv-cli -- verify assets/demo_mid.edited.png assets/demo_mid.bvproof

The verifier checks:

  1. ZK proof validity — cryptographic STARK proof verification (fast or full mode)
  2. Output binding — edited image commitment matches output_hash from verified proof
  3. C2PA trust chain — leaf cert pubkey matches c2pa_pubkey from proof; chain signatures valid; all certs within validity period; root CA pinned against the C2PA trust list (18 root/intermediate CAs) and Brevis Vera root (fails by default if root untrusted; use --allow-untrusted-root to override)

Prints VERDICT: AUTHENTIC or VERDICT: VERIFICATION FAILED.

Sign

Embed a C2PA manifest into a JPEG using your own certificate. The signed JPEG can then be used as input to bv prove.

cargo run --release -p bv-cli -- sign assets/demo_source.jpg assets/demo_signed.jpg \
  --cert assets/certs/ec_chain.pem \
  --key assets/certs/ec_key.pem \
  --claim-generator "BrevisVera/1.0"

The --claim-generator string follows the C2PA convention "ProductName/Version". The part before the first / is shown as the Device field in bv verify output. Defaults to "BrevisVera/1.0" if omitted.

The test certificate in assets/certs/ is a self-signed ES256 (ECDSA P-256) chain. bv verify will fail by default because the root CA is not in the public C2PA trust list. Use --allow-untrusted-root to override for demo/dev verification.

Web UI

cargo run --release -p bv-web
# → http://localhost:3000
# Verify: http://localhost:3000/
# Prove:  http://localhost:3000/prove

Supported transforms

Transform Parameters (private) Example
Crop x, y, width, height {"Crop":{"x":0,"y":0,"width":320,"height":213}}
Brighten value (i32, –255..255) {"Brighten":{"value":20}}
Grayscale none "Grayscale"

Architecture

Built on Pico ZKVM (RISC-V). The guest program performs four tasks inside the ZK circuit:

  1. ECDSA P-256 verification — reconstructs COSE Sig_structure1 = ["Signature1", protected_headers, b"", claim_cbor] using a hand-rolled CBOR encoder, then verifies the camera's ECDSA signature using standard p256 0.13 + ecdsa 0.16 (pure software, ~12M cycles). SHA-256 uses the Brevis-patched sha2 fork with SHA_EXTEND/SHA_COMPRESS precompile acceleration.

  2. C2PA asset binding — verifies the two-step hash chain linking the authenticated claim to the JPEG file bytes: SHA-256(data_hash_assertion_raw) appears in the ECDSA-signed claim CBOR, and SHA-256(jpeg_pre || jpeg_post) appears in the assertion. This proves the signed claim authentically covers the exact JPEG bytes passed to the guest.

  3. In-circuit JPEG decode — reconstructs the full JPEG from pre || post (bytes before and after the JUMBF manifest), decodes to RGBA using zune-jpeg (integer IDCT, no_std, no floats), ~6M cycles.

  4. Transform replay + canonical commitments — applies each transform in order using the same bv-core integer-arithmetic functions as the host, then commits SHA-256([width: u32 BE][height: u32 BE][RGBA bytes]) over original and output pixels.

Docs

Document Description
c2pa.md C2PA-in-ZK architecture, security model, and measured cycle costs
scaling.md Performance data, GPU/CPU benchmarks, future optimizations (P-256 precompile, Merkle commitment)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors