Ghost is defined as the fastest non-Core code we can get. That definition reopens levers previously closed on cost/benefit — each was rejected because the fidelity spend was not worth the gain, and under "fastest wins" that reasoning no longer applies.
Baseline to beat: GHOST = 1,198,904,653 cycles, 11.467x, straggler 1.407, 5 cards (docs/BUILDS.md).
⏰ Ghost sits at 4.05 of 5 cards. A straggler of 1.35 instead of 1.407 makes it four. That is a 4% packing improvement worth 20% of the fleet, and it is the cheapest item here.
1 · Ghost packer calibration — do this first
Worth a card. Cheapest thing on the list. Never been done.
Ghost has never had its cost model calibrated. Core's refit took its straggler 1.557 → 1.311; the same refit applied to Ghost made it worse — 1.407 → 1.884, and 1.996 with the field backend.
The likely cause: I rescaled Ghost's Schnorr constant by the old 13.77x ECDSA ratio, but the liftx hint removes pubkey decompression from both curves (taproot key-path spends call lift_x too), so that ratio should have narrowed. Keeping it over-prices Schnorr inputs.
Method: HAZYNC_CHUNKS=16 HAZYNC_PROFILE_EXEC=1 host chunk-profile, least-squares fit (ecdsa, schnorr, bytes, inputs) → cycles — and this time fit the two curves separately rather than rescaling a stale ratio. The constants are already runtime-overridable (HAZYNC_COST_EC_OP etc.).
⛔ Also unmeasured: GHOST's straggler at default constants. It is assumed 1.407 from the no-backend arm. That assumption is what says 5 cards rather than 4.
2 · MSM batch verification
Previously: rejected. Sized at 9.24x over a whole block but 4.3x at chunk scale after the checks it cannot remove — worth one card, 5 → 4, in exchange for removing libsecp from per-signature verification and a Fiat-Shamir soundness argument needing outside review.
Now: that card counts. The primitive is already in-tree, tested, off by default (prover/methods/guest/src/msm.rs). → docs/history/MSM_BATCH_VERIFY.md
⚠ Interacts with (1): both target the same card. Do the calibration first and re-size MSM against what remains.
3 · Wholesale bigint2
Previously: the middle path was chosen because wholesale "buys at most ONE card" for 15% more speed. Now: 15% is 15%.
⚠ Re-measure rather than trust the old figure — it was taken before the field backend, which changes what the non-ECDSA residual costs.
4 · G3 Schnorr and scalar-inverse re-measure
Both were sized before the liftx hint landed. The hint changes the ECDSA:Schnorr cost ratio (see 1), so their contributions have moved and neither has been re-measured in the current build.
Method
Each lever measured independently against the pinned GHOST baseline, in execute mode on CPU, with:
- the journal digest byte-identical to
4fb3e3c5…4656d — a mismatch voids the arm
- a two-sided binary symbol assertion before any number counts. Eight silent no-ops were caught this way in one session; every one would have reported a moved
METHOD_ID and a clean digest while measuring nothing.
- the straggler read from measured cycles, never predicted
Wall-clock on a GPU confirms at the end, not per lever.
Ghost is defined as the fastest non-Core code we can get. That definition reopens levers previously closed on cost/benefit — each was rejected because the fidelity spend was not worth the gain, and under "fastest wins" that reasoning no longer applies.
Baseline to beat: GHOST = 1,198,904,653 cycles, 11.467x, straggler 1.407, 5 cards (
docs/BUILDS.md).⏰ Ghost sits at 4.05 of 5 cards. A straggler of 1.35 instead of 1.407 makes it four. That is a 4% packing improvement worth 20% of the fleet, and it is the cheapest item here.
1 · Ghost packer calibration — do this first
Worth a card. Cheapest thing on the list. Never been done.
Ghost has never had its cost model calibrated. Core's refit took its straggler 1.557 → 1.311; the same refit applied to Ghost made it worse — 1.407 → 1.884, and 1.996 with the field backend.
The likely cause: I rescaled Ghost's Schnorr constant by the old 13.77x ECDSA ratio, but the liftx hint removes pubkey decompression from both curves (taproot key-path spends call
lift_xtoo), so that ratio should have narrowed. Keeping it over-prices Schnorr inputs.Method:
HAZYNC_CHUNKS=16 HAZYNC_PROFILE_EXEC=1 host chunk-profile, least-squares fit(ecdsa, schnorr, bytes, inputs) → cycles— and this time fit the two curves separately rather than rescaling a stale ratio. The constants are already runtime-overridable (HAZYNC_COST_EC_OPetc.).⛔ Also unmeasured: GHOST's straggler at default constants. It is assumed 1.407 from the no-backend arm. That assumption is what says 5 cards rather than 4.
2 · MSM batch verification
Previously: rejected. Sized at 9.24x over a whole block but 4.3x at chunk scale after the checks it cannot remove — worth one card, 5 → 4, in exchange for removing libsecp from per-signature verification and a Fiat-Shamir soundness argument needing outside review.
Now: that card counts. The primitive is already in-tree, tested, off by default (
prover/methods/guest/src/msm.rs). →docs/history/MSM_BATCH_VERIFY.md⚠ Interacts with (1): both target the same card. Do the calibration first and re-size MSM against what remains.
3 · Wholesale bigint2
Previously: the middle path was chosen because wholesale "buys at most ONE card" for 15% more speed. Now: 15% is 15%.
⚠ Re-measure rather than trust the old figure — it was taken before the field backend, which changes what the non-ECDSA residual costs.
4 · G3 Schnorr and scalar-inverse re-measure
Both were sized before the liftx hint landed. The hint changes the ECDSA:Schnorr cost ratio (see 1), so their contributions have moved and neither has been re-measured in the current build.
Method
Each lever measured independently against the pinned GHOST baseline, in execute mode on CPU, with:
4fb3e3c5…4656d— a mismatch voids the armMETHOD_IDand a clean digest while measuring nothing.Wall-clock on a GPU confirms at the end, not per lever.