Perf/ecsm affine selector - #879
Conversation
|
Benchmark Results for modified programs 🚀
|
|
/bench |
Benchmark — real block (
|
| Metric | main | PR | Δ |
|---|---|---|---|
| Peak heap | 47344 MB | 48765 MB | +1421 MB (+3.0%) ⚪ |
| Prove time | 136.925s | 135.495s | -1.430s (-1.0%) ⚪ |
✅ No significant change.
Prove-time spread 0.5% (135.495s / 135.139s / 135.832s)
Commit: f28788e · Baseline: cached · Runner: self-hosted bench
…affine-selector # Conflicts: # crypto/ethrex-crypto/src/tests/ecsm_tests.rs # executor/src/vm/instruction/execution.rs # prover/src/tables/cpu.rs # syscalls/src/syscalls.rs
|
/bench |
NotOnCurve and CoordinateOutOfRange both predate the affine ecall and named only xG: "ECSM xG is not a valid curve x-coordinate" and "ECSM xG must be < p". The affine path returns the same two variants for a caller-supplied yG that fails yG² ≡ xG³ + b or is >= p, so the messages pointed at the wrong operand. Rewords them and the variant docs to cover both entry points. Also hoists the modulus in prepare_with_y: it was rebuilt from P_BYTES five times per call (two range checks plus three reductions in the on-curve test). One BigUint either way against the scalar multiplication that follows, so this is for the reader, not the clock.
|
/bench |
1 similar comment
|
/bench |
|
/bench-gpu |
GPU Benchmark (ABBA) —
|
|
/bench |
|
/bench-gpu |
|
Automated review pass (low-effort, full-diff read). No findings. q: stacks on Not run at high effort yet — worth one before merge given this touches |
MauroToscano
left a comment
There was a problem hiding this comment.
Formally verify it, and make a spec for 3mi
|
/bench |
|
/bench |
What
Adds an affine variant of the ECSM ecall (
ECSM_AFFINE_SYSCALL_NUMBER = u64::MAX - 11): inputxG‖yG(64 B), outputxR‖yR(64 B), against the x-only variant's 32 B in/out. AnIS_AFFINEselector column lets one prover serve both ABIs, so existing x-only consumers (
ecsm.elf, bench,ASM
test_ecsm*) keep working unchanged.With x-only output the guest could not learn
y(k·P), so it recovered it from a second queryx((k+1)·P)plus the chord-addition law — two accelerator calls and a batch of field arithmeticper point. ethrex's ecrecover now takes
yfrom the chip: two ECSM queries per 2-term linearcombination instead of four, and
solve_yis gone.Details
executor/src/vm/instruction/execution.rs):ECSM_AFFINE_SYSCALL_NUMBERgetsits own handler branch (
scalar_mul_xy_with_y). Both operand buffers are 64 B, so theaddress-limb guard spans offset 63 for
xG/xR(31 for the scalar) and thexG/kdisjointness guard widens to 64 B. Validates
0 < k < N,xG < p,yG < pand that(xG, yG)is on the curve.IS_AFFINEselector (prover/src/tables/ecsm.rs, 667 → 684 columns, 413 → 423constraints): the
yG-read (4 dwords ataddr_xG + 32, ts) andyR-write (4 dwords ataddr_xR + 32, ts+3) MEMW buses fire withmult = IS_AFFINE, so they are inert on x-only rowsand on padding. The x-only path is untouched:
yGstays the canonical even lift andyRiswitnessed only for ECDAS.
yR < p(OverflowKind::YrLtP, +16 halfword columns and its carry chain): publishingyRis what makes its representation observable, and the byte range checks only bound it below
2^256.xRwas already forced canonical byXrLtP; this gives the other half of the outputthe same treatment.
ecsm_mul_affineinsyscalls/src/syscalls.rs, andlincomb2_with_oracleincrypto/ethrex-crypto/src/lib.rsnow does two oracle queries instead of four and dropssolve_yentirely. It still needs one field inverse for the final affine addition.ecsm_affine, plus a forged-yRrejection test.Measured (ethrex bench_20, bench server, baseline = the hint branch this sits on)
3 interleaved pairs, each side with its own prover and its own guest ELF, since this touches
both. All proofs verify.
Halving the accelerator calls is the structural part; prove time moves less because ECSM/ECDAS is
a fraction of the trace. An earlier measurement of this work reported −10.2%, on a baseline that
sat 14,466 cycles above
8 × 524,288and therefore carried a ninth CPU chunk the affine sidedropped — a boundary artifact, not the change. Pairs are interleaved rather than run as
sequential blocks, because cross-session drift on that machine exceeds the effect being measured.
Soundness
Returning
ymakes two things observable that were not:yGonly throughyG² ≡ xG³ + b, which holds for both+yGand−yG. On the x-only path that freedom is invisible (x(k·P) = x(k·(−P))), but onceyRis published a witness could pick−yGand get a correctly-computed multiple of adifferent point — indistinguishable to both the AIR (an on-curve check passes either way) and
the guest (it cannot know the parity of
k·Pwithout doing the multiplication it delegated).The
yGMEMW read closes it by pinning the witnessed column to the caller's own buffer.p, so withoutYrLtPawitness could publish
yR + pwheneveryR < 2^256 − p(~2^32), and such points areconstructible:
3 | p−1makes cubing 3-to-1, so a small targetyhas a cube-root preimageabout a third of the time.
IS_AFFINEitself is pinned by theEcallreceiver, whose syscall word isxonly + IS_AFFINE·(affine − xonly); the CPU sends the reala7, so a row claiming the wrongmode leaves the bus unbalanced.
IS_BIT(IS_AFFINE)andIS_AFFINE·(1 − µ) = 0keep it a bitthat is zero on padding. The written
yRinherits its byte range checks through the ECDAS bus,which carries the coordinate byte by byte and range-checks its own columns.
Removing the reconstruction also retires an argument rather than adding one: the x-only path had
to establish that the wrong sign of
yawas excluded by the scalar guards, which is what madek = 1andk = N−1degenerate. Withysupplied by the chip those scalars are ordinary —secp256k1 has cofactor 1 and prime
N, sok·P ≠ Ofor everyk ∈ (0, N).