0xMiden / 0xMiden/protocol

LocalTransactionProver proves precompile claims locally (prove_sync) instead of deferring them (prove_partial_sync)

Abierto
#3,835 10 comentarios 0 reacciones 1 asignado Reclamado por @PhilippGackstatter Ver en GitHub
Lenguaje dominante
Rust
Estrellas
132
Forks
167
Merge medio
1 d 23 h
PR fusionados (30 d)
110

Descripción

`LocalTransactionProver::prove` calls `miden_prover::prove_sync`, the final-proof API, so every local prove also generates the precompile-VM STARK for its deferred claims. Precompile proving is meant to happen at batch level; the local prover should call `prove_partial_sync` and ship the claims as a wire.

**Symptom.** A locally proven transaction whose auth verifies ECDSA signatures carries `DeferredProof::Stark` (~277 KB) next to the ~100 KB VM STARK, and that precompile STARK is 55-72% of local prove time.

**Repro.** Prove any ECDSA-authenticated transaction with `LocalTransactionProver::default()` and match on `proven.proof().deferred_proof()`: it is `Stark { .. }`. Cause: `crates/miden-tx/src/prover/mod.rs:17` imports `prove_sync` and `:148` calls it (same on `next` and 0.16.0-rc.9). `prove_partial_sync` is the documented API for claims "proved later by a delegated or batching prover" (miden-prover 0.29.4, `src/lib.rs:164`).

**Expected.** `DeferredProof::Wire`; the claims are checked natively by the verifier and proven at batch level. On `next` the verifier side already exists: `TransactionVerifier` handles `PrecompileStatus::Deferred` via `validate_deferred_witness` (`crates/miden-protocol/src/transaction/verifier.rs:76-95`), so there the fix is the prover switch plus tests.

**Impact.** Browser local proving (MT wasm, 6 threads) is 3.5x slower than necessary for guarded accounts and 2.8x for single-sig: with the one-line switch, guarded 7.99 s to 2.27 s and single-sig 4.58 s to 1.66 s; native guarded 1.68 s to 0.63 s. The proven transaction shrinks from 391 KB to 104 KB.

On 0.16.0-rc.9 (VM 0.29.4) the switch alone is not deployable: `miden_verifier::verify` returns `UnsupportedDeferredProof` for `Wire`, and both the node RPC (`crates/rpc/src/server/api/submit_proven_tx.rs:108`) and the validator (`bin/validator/src/tx_validation/mod.rs:52`) call `TransactionVerifier::verify`, so a client cannot opt in. Fixing 0.16 needs `TransactionVerifier` to accept partial proofs (`Verifier::verify_partial` exists in 0.29.4; rehydrating the wire re-evaluates every node under the registry, so native settlement is a root check) plus the node picking it up.

Evidence: runtime probes (0.16.0-rc.9 protocol crates, VM 0.29.4, web-sdk 0.16.0-rc.7)

Native, `LocalTransactionProver::default().prove(executed)`, printing `proven.proof().deferred_proof()`:

```
# 2 ECDSA claims (guarded multisig: 1 approver at threshold 1 + guardian)
tx: total_cycles=29095 auth_procedure=19847
DEFERRED_PROOF Stark { proof: 276768 bytes, public_root: Word([10652471043400787702, 12148757343284257120, 17083288024192604590, 7234156251587950621]) }
VM_PROOF 101663 bytes

# 1 ECDSA claim (BasicAuth)
tx: total_cycles=17720 auth_procedure=9865
DEFERRED_PROOF Stark { proof: 283680 bytes, public_root: Word([13415207134405930995, 16485817212495615892, 12092707907113953811, 2871210035726898790]) }
VM_PROOF 99711 bytes

# same two shapes after switching miden-tx to prove_partial_sync
DEFERRED_PROOF Wire (partial, claims NOT proven)
VM_PROOF 100447 bytes # 2 claims
VM_PROOF 100895 bytes # 1 claim
```

Browser, `client.proveTransaction(txResult, TransactionProver.newLocalProver())`, `proven.serialize().length`:

```
single-sig provenTxBytes 378589
guarded provenTxBytes 391045
guarded, prove_partial_sync build provenTxBytes 104118
```

Evidence: code pointers

- `crates/miden-tx/src/prover/mod.rs:17` `use miden_prover::{ExecutionProof, Word, prove_sync};` and `:148` `prove_sync(` (`next` at b5cbb343d; identical in 0.16.0-rc.9).
- miden-prover 0.29.4 `src/lib.rs:123` `prove_sync` (final), `:164` `prove_partial_sync`, `:235-241` `prove_deferred_state` inside the `precompile_vm` span, `:248-258` the wire variant.
- miden-core 0.29.4 `src/proof.rs:261-275` `DeferredProof::{Empty, Wire, Stark}`.
- miden-verifier 0.29.4 `src/lib.rs:177-188` `resolve_final_deferred_root`: `Wire` yields `UnsupportedDeferredProof`; `src/lib.rs:123-135` `verify_partial` returns `Unsettled(DeferredState)`.
- miden-protocol 0.16.0-rc.9 `src/transaction/verifier.rs:33` calls `miden_verifier::verify` (full).
- node `next`: `crates/rpc/src/server/api/submit_proven_tx.rs:108` and `bin/validator/src/tx_validation/mod.rs:52` call `TransactionVerifier::new(MIN_PROOF_SECURITY_LEVEL).verify`.
- web-sdk `crates/web-client/src/new_transactions.rs:713` `LocalTransactionProver::default()` for `newLocalProver()`.

Measurements (M5, 4P+6E; native concurrent; browser MT wasm at 6 threads, 9 timed proves per run after a discarded warm-up, medians)

| shape | prover | native prove | browser prove | proven tx |
|---|---|---|---|---|
| single-sig ECDSA | `prove_sync` (today) | 1376 ms | 4584 ms | 379 KB |
| single-sig ECDSA | `prove_partial_sync` | 602 ms | 1663 ms | ~104 KB |
| guarded (2 ECDSA claims) | `prove_sync` (today) | 1678 ms | 7987 ms | 391 KB |
| guarded (2 ECDSA claims) | `prove_partial_sync` | 630 ms | 2272 ms | 104 KB |

The native `precompile_vm` span accounts for the whole difference (744 ms and 998 ms respectively; 0 ms with the partial API). The guarded premium over single-sig drops from 302 ms to 28 ms, since only the main trace remains and both shapes pad to 2^15 rows.

The one-line switch used for the "partial" rows, applied to 0.16.0-rc.9 and reverted afterwards:

```diff
-use miden_prover::{ExecutionProof, Word, prove_sync};
+use miden_prover::{ExecutionProof, Word, prove_partial_sync};
...
- let (stack_outputs, proof) = prove_sync(
+ let (stack_outputs, proof) = prove_partial_sync(
```

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.