Commit Graph

246 Commits

Author SHA1 Message Date
Steve Wang
015d7bf736 first commit but can't compile due to clone issue 2025-09-08 13:17:31 +08:00
Steve Wang
2d68971f2d removed poly id to index function now that we have apc as part of api 2025-09-08 12:23:45 +08:00
Steve Wang
a47725027a added struct for dummy trace (value and width) 2025-09-08 11:50:43 +08:00
Steve Wang
22896742d6 remove original instruction entirely and use arc of apc in powdr executor 2025-09-08 11:43:50 +08:00
Steve Wang
065f710628 fix prior PR comments 2025-09-05 11:30:59 +08:00
Steve Wang
520b2b39e6 merge main 2025-09-05 11:15:06 +08:00
Steve Wang
bbffdfe4e6 fix commits and clippy 2025-09-05 11:06:13 +08:00
Steve Wang
7570d862d8 Simplify trace gen (#3245)
This will be a series of PRs that reduces trace gen code duplication in
multiple powdr APC clients, planned as the follows:
1. [This PR] Simplify OVM client trace gen code using existing
optimization in other client, also unifying data types for later PR.
2. [Next PR] Create `TraceHandler` trait for implementation in different
powdr APC clients, with trait functions mostly generating unified data
types across different clients. Add `TraceHandler` as an associated type
in `Adapter`.
3. [Another PR] Potentially cache `TraceHandler` outputs in the executor
for clients that run execution multiple times (so that we don't
recompute in `generate_trace` each time).
4. [Another PR] Further clean up including potentially revive things
like `is_valid_index`.
2025-09-04 10:27:53 +00:00
Steve Wang
b214cc8480 updated TraceHandler to allow function level life time to accommodate for owned and borrowed hashmap of dummy traces 2025-09-04 17:59:55 +08:00
Steve Wang
7a8eb6c192 first commit including TraceHandler trait and OVM implementation, though I wanted to move more contents to the trait 2025-09-04 15:29:50 +08:00
Steve Wang
3bf91006af first commit with passing keccak test 2025-09-04 11:59:57 +08:00
Thibaut Schaeffer
6dbb2710e3 Remove option in instruction handler trait (#3240)
We unwrap the returned value in side the autoprecompiles crate, so might
as well not return an option.
2025-09-02 06:09:53 +00:00
Leo
a210dde5d6 remove witgen opt (#3236)
The code removed here is an execution optimization to not have to
perform more computation than needed. However it relies on some
assumptions on the optimizer that don't always hold, therefore it's
safer to remove it.
This fixes some benchmarks that were broken on nightly.
2025-08-28 16:47:41 +00:00
ShuangWu121
71c3c3db71 k256 updated, ecc tests with larger input (#3217)
k256 is updated with the newer openvm-guest-hint and we can test ecc
with larger input 50

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-08-26 14:23:58 +00:00
ShuangWu121
9805874e20 New ecc manual guest, using msm without pippenger (#3219)
manual ecc using msm with the version that does not use pippenger, which
is cheaper

INFO │ ┝━ i [info]: total_trace_cells = 12_704_468 (excluding
preprocessed)
2025-08-26 14:16:03 +00:00
chriseth
349c742fcc Display for Block. (#3226)
It is much more convenient for debugging to have a `Display` available,
especially when debugging the generic code.
2025-08-26 10:27:48 +00:00
Georg Wiese
8700b12716 Candidate JSON: Pretty-print instructions (#3223)
We used to export instruction in their JSON format, e.g.
`{"opcode":512,"a":1879048082,"b":1879048082,"c":2013265793,"d":268435454,"e":268435454,"f":0,"g":0}`.

I changed this to be the pretty-printed string instead. I think this
makes more sense, because we don't reading them like this is hard and we
don't want to re-implement the pretty-printing in Python.

I checked that currently our Python scripts don't really read this
value, they only use the length of the list, so this PR doesn't break
them. In the future, I'm hoping to get Claude to generate an interactive
version of the effectiveness plot, so that we can also explore the
source code of each block.
2025-08-25 19:03:20 +00:00
chriseth
2748ac0579 Inline only at end (#3173)
Fixes https://github.com/powdr-labs/powdr/issues/3113

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
Co-authored-by: schaeff <thibaut@powdrlabs.com>
2025-08-25 15:41:02 +00:00
ShuangWu121
6c0d481b50 Add ecrecover guest (#3160)
Manual precompile: total_trace_cells = 15_368_081

ecrecover with PowdrAffinePoint:
APC=50: total_trace_cells = 228_239_394

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-08-22 23:16:30 +00:00
Thibaut Schaeffer
86c31acd9a Make powdr generic over the pgo method (#3188)
Introduce `PgoAdapter` which wraps `Adapter` and can call apc
generation. Removes the match statements over the pgo method. Breaking
change. Now the client can pick some pgo implementations like
`pgo::CellPgo` and use it like
`CellPgo::<MyAdapter>::new(pgo_data).generate_apcs(blocks)`. The client
can also implement `PgoAdapter<A: Adapter>` for its own pgo
implementation.
2025-08-22 13:59:23 +00:00
Georg Wiese
95e773400f Remove BusType::OpenVmBitwiseLookup (#3211)
After #3209, it is no longer necessary to list OpenVM's "bitwise lookup"
bus in the `BusType` enum, which lives in the VM-agnostic
`autoprecompiles` crate.
2025-08-22 11:19:53 +00:00
Georg Wiese
3422658efd Add ECC nightly test (#3207)
Built on #3203

This PR:
- Modifies the ECC tests to continue doing MSMs for a number of times
(passed as an input)
- Adds this as a benchmark to the nightly test

I got these results:

| filename | num_segments | app_proof_cells | app_proof_cols |
total_proof_time_ms | app_proof_time_ms | leaf_proof_time_ms |
inner_recursion_proof_time_ms |

|---------------------------------|--------------|-----------------|----------------|---------------------|-------------------|--------------------|-------------------------------|
| affine-hint-apc000/metrics.json | 4 | 3852743848 | 6044 | 69327 |
35904 | 12783 | 20640 |
| affine-hint-apc003/metrics.json | 3 | 3140411518 | 6219 | 50886 |
30551 | 9791 | 10544 |
| affine-hint-apc010/metrics.json | 2 | 1618931796 | 33742 | 51152 |
16193 | 25074 | 9885 |
| affine-hint-apc030/metrics.json | 1 | 1091031082 | 40436 | 40165 |
11166 | 23824 | 5175 |
| affine-hint-apc100/metrics.json | 1 | 944216106 | 54662 | 55193 |
10174 | 39800 | 5219 |
| manual/metrics.json | 1 | 1041144324 | 5618 | 21215 | 10090 | 6236 |
4889 |
| projective-apc000/metrics.json | 9 | 9622555316 | 12991 | 156526 |
88927 | 28593 | 39006 |
| projective-apc003/metrics.json | 2 | 3195273488 | 31100 | 64314 |
31006 | 23439 | 9869 |
| projective-apc010/metrics.json | 2 | 3644260624 | 33710 | 70673 |
35933 | 24873 | 9867 |
| projective-apc030/metrics.json | 1 | 1931874516 | 56279 | 62528 |
18945 | 38336 | 5247 |
| projective-apc100/metrics.json | 1 | 1806846164 | 70086 | 65856 |
18181 | 42434 | 5241 |

It shows that:
- Using `k256` out of the box without APCs takes 156s
- Switching to affine representation + using hints for the base field
inverse takes 69s
- Accelerating the resulting code using APCs takes 40s
- Using OpenVMs manual precompile takes 21s

The Hint + APC version is similar to the manual precompile in terms of
app prove time, but due to the much larger number of columns, recursion
becomes expensive.
2025-08-21 14:45:18 +00:00
ShuangWu121
16b5ccff53 Normalize the hint before sending to prover from host (#3210)
Normalize the hint before sending to prover from host
2025-08-21 14:42:39 +00:00
Georg Wiese
f4345b5304 Improve basic metrics summary (#3203)
Adds `app_proof_cols` and `total_proof_time_ms` columns to the result
CSV.
2025-08-21 14:09:12 +00:00
Georg Wiese
81ae444b4c Refactor run_guest_benches.sh (#3198)
I wanted to refactor the `run_guest_benches.sh` to make it a bit more
flexible. With this, it should be possible to test the ECC guest easily
(#3118), which actually has 3 guests (manual, out-of-the-box software,
hint-optimized software).

I also brought the matmul test back.

The file structure is not exactly the same as before, but similar (and
more organized):

https://github.com/powdr-labs/bench-results/tree/gh-pages/results/2025-08-20-1538

(which is from this run:
https://github.com/powdr-labs/powdr/actions/runs/17099625118/job/48492387082)

---------

Co-authored-by: chriseth <chris@ethereum.org>
2025-08-21 10:59:04 +00:00
chriseth
4fa8d35674 Remove variables that are only constrained by a simple solvable algebraic constraints. (#3196)
Fixes https://github.com/powdr-labs/powdr/issues/3113

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-08-20 15:20:43 +00:00
chriseth
5e83a8a93a Do not use bus field variables. (#3171)
Removes the special introduction and removal of bus variables because
the solver can now handle this on its own through the `LinearizedSolver`
component. It also has the benefit that we do not need to run the
optimizer twice any more (once with bus interaction variables and once
without).

Previously we would introduce a new variable type outside of the solver
and replace all bus interactions `bus_interaction(1, x + y * z)` by
`bus_interaction(1, bus_var_1)` and the algebraic constraint `bus_var_1
= x + y * z`.

Now the `LinearizedSolver` is a component inside the solver that
replaces all bus interaction fields (that are not already constants or
simple variables) and also replaces all non-linear components:

`bus_interaction(1, x + y * z)`

becomes

```
bus_interaction(1, v1)
v1 = x + v2
v2 = y * z
```

The reason behind also replacing non-linear parts is because range
constraints are only stored for variables, not for all sub-expressions.
Also if we find the same non-linear sub-expression multiple times, we
can now replace it directly by the same variable.

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-08-20 14:20:15 +00:00
ShuangWu121
3166a8e99f ECC guests using hint (#3118)
guest programs perform multi scalar multiplication: two scalar, two
points, add their results together.
the points and scalars are random, chosen by a [test
](912d939948/k256/src/arithmetic/mul.rs (L467))
of unmodified k256 that tests random point scalar multiplication with
random scalar.
some performance results:
- manual: 
`total_trace_cells = 38_567_392`

- affine with hint:
apc=0: `total_trace_cells = 295_963_682`
apc=10: `total_trace_cells = 87_338_018`
apc=100: `total_trace_cells = 58_438_434`
apc=200: `total_trace_cells = 55_226_498`

- projective:
apc=0: `total_trace_cells = 576_778_288 `
apc=100: `total_trace_cells = 84_235_440`

- affine without hint:
apc=0: 
```
INFO     │        ┝━ i [info]: total_trace_cells = 815_132_720 (excluding preprocessed)
INFO     │        ┝━ i [info]: total_trace_cells = 742_574_128 (excluding preprocessed)
INFO     │        ┝━ i [info]: total_trace_cells = 814_925_872 (excluding preprocessed)
INFO     │        ┝━ i [info]: total_trace_cells = 814_925_872 (excluding preprocessed)
INFO     │        ┝━ i [info]: total_trace_cells = 814_925_872 (excluding preprocessed)
INFO     │        ┝━ i [info]: total_trace_cells = 742_574_128 (excluding preprocessed)
INFO     │        ┝━ i [info]: total_trace_cells = 54_618_160 (excluding preprocessed)
```

apc=100: `total_trace_cells = 1_105_868_464`

---------

Co-authored-by: Georg Wiese <georgwiese@gmail.com>
2025-08-19 14:53:10 +00:00
chriseth
bb49beb9b6 Remove outer negation when converting a grouped expression to an algebraic constraint. (#3194) 2025-08-19 11:26:33 +00:00
chriseth
36bd7abec7 Ignore range constraint on output. (#3190)
Summary: We do not need to add the range constraint on the output
because the output is uniquely determined by the formula and the range
constraints on the inputs.

Details:

This slightly improves the "low degree bus interaction optimizer". It
replaces a bus interaction by an algebraic constraint and simple range
constraints in the following way:

1. It performs exhaustive search about which of the non-constant fields
in the bus interaction are inputs and which (only one) is the output
2. Determines currently-known range constraints on inputs and outputs
3. Using exhaustive search, chooses a candidate function and checks that
for all input values in the range constraints, the candidate computes
the same output as the bus interaction would (i.e. the bus interaction
also allows exactly one output compatible with the concrete values for
the inputs).
4. If such a candidate is function, it replaces the bus interaction by
the candidate turned into an algebraic constraint and simple range
constraints (the ones determined in the beginning)

This PR changes the mechanism in that it does not re-add range
constraints for the output, only for the inputs. The reason is that the
algebraic constraint directly computes the value for the output for all
inputs within the range constraints of the input. So the algebraic
constraint already enforces the range constraint on the output from the
range constraints on the inputs.
2025-08-19 09:52:23 +00:00
chriseth
908a3f7fb3 Improve test reporting. (#3191)
Previously, for successful tests, it would still update the expectation
file and print that it did so, even though the contents were the same.
Now the "update" message is only printed if the contents are actually
different.
2025-08-19 09:08:43 +00:00
chriseth
1b7c2816ab Fix strum dependency. (#3193)
The feature is actually used in the crate. It did not produce a build
error because we never compile crates individually and it's enough for
the feature to be enabled in some crate.
2025-08-18 17:14:13 +00:00
chriseth
5c2cc8f126 Add unit test for sha256 optimization (#3186) 2025-08-18 14:47:22 +00:00
Georg Wiese
bdf3a5fefa Low-degree bus interaction optimizer (#3130)
This PR adds a new optimizer: If a stateless bus interaction (a.k.a.
lookup) implements a low-degree function, it is replaced by a polynomial
constraint (and range constraints).

Some examples include:
- `xor(a, 0xff)` (logical `not` on bytes): This is a linear function
(`255 - a`)
- `xor(a, b)`, where `a` and `b` are known to not have the same bits
set: This equals `a + b`
- `xor(a, b)`, where `a` and `b` are known to be bit-valued: This is
equal to `a + b - 2 * a * b`

Doing this replacement has several advantages:
- A bus interaction is replaced with a polynomial constraint (which is
usually much cheaper)
- Because the output is equal to a low-degree expression of the inputs
(often linear), the inliner can inline it, so we don't have to commit to
it

Note that in addition to the linear function, a lookup always *also*
enforces a range constraint. These are added to the system by using the
API added with the range constraint optimizer (#3151). In many cases,
these constraints are redundant and can be removed again by the range
constraint optimizer (e.g. the inputs might come from memory, which can
be assumed to store byte-constrained words.

---------

Co-authored-by: Leo <leo@powdrlabs.com>
Co-authored-by: chriseth <chris@ethereum.org>
2025-08-15 10:47:55 +00:00
Georg Wiese
fe89374750 Ensure weakly normalized (#3176)
In the `hint_k256_inverse_field_10x26` and `hint_k256_sqrt_field_10x26`
functions, this PR ensures that the returned result actually consists of
26 bits limbs, as the name suggests. (Except for the most significant
limb, which is 22 bits.) This means that the field element is weakly
normalized and can be used safely by the guest program.
2025-08-14 08:04:02 +00:00
Georg Wiese
55186f487d Update Bus Interaction handler for the variable range checker bus (#3178)
Extracted from #3130 

See [this
comment](https://github.com/powdr-labs/powdr/pull/3130/files#r2268175800):
> If the bit value is not in range, `handle_variable_range_checker` will
return the expected range, and `handle_bus_interaction_checked` will
intersect it with the previous range constraint (a known number), notice
the ranges don't overlap, and return an error.

As part of #3130, it might happen that the brute-force algorithm tries
to set the `bits` field to an out-of-range value. As mentioned in the
comment above, this would anyway result in an error if
`handle_bus_interaction_checked` is used, so panicking here is overly
strict.
2025-08-13 19:45:13 +00:00
Georg Wiese
bb56087791 Use default OpenVM degree bounds (#3167)
Builds on #3166
2025-08-12 15:13:23 +00:00
Georg Wiese
a178517a9d Use expect-test in optimizer test (#3166)
Builds on #3164 (in queue)
2025-08-11 20:39:45 +00:00
Georg Wiese
46100870f5 Bug fix in filter_byte_constraints (#3164)
Fixes a soundness bug @chriseth
[found](https://github.com/powdr-labs/powdr/pull/3151/files#r2267259864)
that was introduced in #3151: I thought we can e.g. check `expr` to be 6
bit by checking `4 * expr` to be a byte. That is incorrect, e.g.
$4^{-1}$ would pass the check but should not.
2025-08-11 19:03:50 +00:00
Leo
f03aa041ff Fix default degree bound (#3155)
We used 5 for OpenVM's default constraint max degree bound for a long
time since that's what was in their SDK example, but they actually use
and suggest app log blowup = 1 for app proofs, which leads to max_degree
= 3. This PR changes the default to 3.

The basic PR is quite simple, see the first commit. A lot of the
`max_degree` propagation in the second commit is because of the
`get_air_metrics` function that needs it to call an OpenVM internal
function, and the max degree is not available in any existing data
structure at that point.

I thought the easiest was just to add it to these functions, and I had
to change one trait. But that felt easier/less invasive than changing
associated types/constants of other traits. @Schaeff let me know if this
is fine or if you prefer another route.
2025-08-11 15:19:45 +00:00
Leandro Pacheco
17e0e6d939 metrics for autoprecompiles (#2978)
collect the following metrics for autoprecompiles:
- `(before|after)_opt_(cols|constraints|interactions)`
- `total_apc_gen_time`
- `apc_gen_time` per autoprecompile
- `num_calls` per autoprecompile
2025-08-08 21:44:37 +00:00
Georg Wiese
c638bbf081 Read tuple range checker sizes from config (#3154)
We used the default tuple range checker sizes, but it should be read
from the config. For example, in the reth benchmarks, the sizes are
actually different, leading to potential soundness or completeness bugs.
2025-08-08 16:00:57 +00:00
Georg Wiese
71d821c427 Range constraint optimizer (#3151)
Fixes #3128

---------

Co-authored-by: Leo <leo@powdrlabs.com>
2025-08-08 14:05:05 +00:00
Georg Wiese
d9288baa02 Add test for single mul instruction (#3153)
While working on #3151, I realized that none of the tests uses OpenVM's
"tuple range checker". The `mul` instruction is an example.
2025-08-08 09:20:34 +00:00
Leo
6e0d2bc389 U256 guest (#3147)
Taken from https://github.com/powdr-labs/openvm/tree/main/examples/u256
but with larger matrices to make the benchmark more complicated.
2025-08-07 08:07:01 +00:00
chriseth
24ddce250d Prefer inlining last variable. (#3136) 2025-08-05 19:03:23 +00:00
Steve Wang
f22419f7af Fix nightly tests (#3142)
Currently we get a file not found error for input of
`effectiveness_plot.py`, because the `cargo prove` with no APC case
doesn't generate `apc_candidates.json` as input for the Python script
anymore after #3109.

This PR fixes this error and now `run_guest_benches.sh` runs on the
server, though I'm not sure if all nightly tests will be fixed that
aren't run on CI yet.
2025-08-05 12:09:28 +00:00
Georg Wiese
abb72c8581 Add list of columns when rendering symbolic machines (#3138)
Two reasons for this:
- When making changes to the optimizer, the diffs in the snapshots show
immediately which columns got removed
- When looking for more optimizations, it's also useful to go through
each column and ask "Why do we need this column?"
2025-08-04 21:10:50 +00:00
Leandro Pacheco
90d5d5b10b fix k256 sqrt hint (#3125)
When the input is non-square, the prover returns the square root of the
input times a predefined non-quadratic residue.
The idea is that the guest should also prove the non-square case, so it
must check that:
`result * result == input * PREDEFINED_NON_QR`.
Chose `3` as the predefined non_qr.
2025-08-04 14:14:16 +00:00
Steve Wang
4994f1aa68 Generalize block filter in Adapter (#3133)
As per @Schaeff's comment
https://github.com/powdr-labs/powdr/pull/3124#issuecomment-3144116469.

This can be orthogonal with #3124, which this PR can apply on top of.
Alternatively, if we don't want the CLI option of max number of basic
block instructions, we can apply this PR without #3124.
2025-08-04 07:55:51 +00:00