Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
36c388e
feat(crypto)!: track leanVM main (internalized XMSS + reworked aggreg…
MegaRedHand Jul 24, 2026
6b41823
build(deps): pin leanVM to main HEAD (a73ab11) instead of tracking th…
MegaRedHand Jul 24, 2026
5e67159
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Jul 24, 2026
cd293eb
build(deps): bump leanVM pin to c83b40f
MegaRedHand Jul 27, 2026
d68b246
feat(crypto)!: keep pubkeys off the proof wire
MegaRedHand Jul 27, 2026
db7bc13
fix(crypto): use leanVM's facade and prove one at a time
TomWambsgans Jul 27, 2026
02e7099
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Jul 28, 2026
29a858e
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Jul 29, 2026
fcd4a42
refactor(types): drop xmss dep, static-assert wire sizes in crypto
MegaRedHand Jul 29, 2026
7fb26d2
refactor(crypto): report both sizes when the XMSS wire-size guard fires
MegaRedHand Jul 29, 2026
80080a0
build(deps): track leanVM a5909d1 and prove on the system allocator
MegaRedHand Jul 30, 2026
64b109a
refactor(crypto): hand out prover setup and the permit together
MegaRedHand Jul 30, 2026
97cbe1d
refactor(crypto): hold the prover permit only across the prove call
MegaRedHand Jul 30, 2026
80930d2
refactor(crypto): let the decoding paths acquire the prover up front
MegaRedHand Jul 30, 2026
3760b9d
feat(crypto): make the prover arena an opt-in
MegaRedHand Jul 30, 2026
31817c8
feat(cli): add --prover-arena to opt into the leanVM arena
MegaRedHand Jul 30, 2026
e2a66a8
refactor(crypto): initialize leanVM once at startup instead of lazily
MegaRedHand Jul 30, 2026
afe5e67
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Jul 30, 2026
a93b49e
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Jul 31, 2026
c2fa7ae
Merge remote-tracking branch 'origin/main' into build/leanvm-track-main
MegaRedHand Aug 4, 2026
8f6a6b6
fix(tests): size placeholder pubkeys from PUBLIC_KEY_SIZE
MegaRedHand Aug 4, 2026
b834663
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 4, 2026
37f5c48
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 4, 2026
116e473
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 4, 2026
691df39
fix(tests): size the merged placeholder pubkeys from PUBLIC_KEY_SIZE
MegaRedHand Aug 4, 2026
86d5cb8
Merge remote-tracking branch 'origin/main' into build/leanvm-track-main
MegaRedHand Aug 5, 2026
2e18b3c
Merge remote-tracking branch 'origin/main' into build/leanvm-track-main
MegaRedHand Aug 5, 2026
08aa352
Merge remote-tracking branch 'origin/main' into build/leanvm-track-main
MegaRedHand Aug 7, 2026
c5e0173
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 10, 2026
abf11f9
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 12, 2026
5ed24c3
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 13, 2026
f2586bf
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 19, 2026
ff7d0cc
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 19, 2026
2e1d4bc
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 25, 2026
c959352
Merge remote-tracking branch 'origin/main' into build/leanvm-track-main
MegaRedHand Aug 26, 2026
998142e
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Aug 26, 2026
c6902bb
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Sep 1, 2026
5d9f136
fix(bin): repair the benchmark corpus and stale crypto references aft…
MegaRedHand Sep 1, 2026
29e03d3
Merge branch 'main' into build/leanvm-track-main
MegaRedHand Sep 2, 2026
9c6e66f
build(deps): track leanVM main's unified aggregation API
MegaRedHand Sep 3, 2026
ef10521
build: enable carryless multiply on aarch64 targets
MegaRedHand Sep 3, 2026
27a90c1
feat(cli): accept a `keygen` sub-command for validator keys
MegaRedHand Sep 3, 2026
c6ed47b
Merge branch 'main' into build/leanvm-unified-aggregate-api
MegaRedHand Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# leanVM proves over a binary field tower, whose multiplication is a carryless
# multiply. Both entries below have to enable it, or the prover falls back to
# scalar bit-twiddling: `+pclmulqdq` on x86, and on aarch64 the `aes` feature,
# which is what LLVM gates PMULL behind.
#
# The aarch64 entry is not symmetry for its own sake. `aarch64-unknown-linux-gnu`
# defaults to `neon` alone, while `aarch64-apple-darwin` defaults to a CPU that
# already has `aes`, so a Linux container on an Apple-silicon host was the one
# build with no carryless multiply. Measured on an M4 Max, one aggregation proof
# went from ~30 s without this to well under a second with it, which is the
# difference between a local devnet that cannot fill a slot and one that can.

[target.x86_64-unknown-linux-gnu]
rustflags = [
"-Ctarget-cpu=x86-64-v3",
"-Ctarget-feature=+avx2,+sse2,+ssse3,+sse4.1,+sse4.2,+bmi1,+lzcnt,+pclmulqdq",
]

[target.aarch64-unknown-linux-gnu]
rustflags = [
# Baseline armv8.2 (the floor for Apple silicon and Neoverse N1/V1), plus the
# crypto extensions carrying PMULL and SHA-2.
"-Ctarget-cpu=neoverse-n1",
"-Ctarget-feature=+aes,+sha2,+neon",
]
40 changes: 35 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ crates/
└─ src/metrics.rs # State transition timing + counters
common/
├─ types/ # Core types (State, Block, Attestation, Checkpoint)
├─ crypto/ # XMSS aggregation (leansig wrapper)
├─ crypto/ # XMSS sign/verify + aggregation (leanVM wrapper)
├─ metrics/ # Prometheus re-exports, TimingGuard, gather utilities
└─ test-fixtures/ # Spec-fixture loading (prod dep of rpc's Hive test driver)
net/
Expand Down Expand Up @@ -262,9 +262,37 @@ actual_slot = finalized_slot + 1 + relative_index

**XMSS (eXtended Merkle Signature Scheme):**
- Post-quantum signature scheme
- 52-byte public keys, 2536-byte signatures (`SIGNATURE_SIZE` in `common/types/src/signature.rs`)
- Wire sizes: `PUBLIC_KEY_SIZE` (`common/types/src/state.rs`) and `SIGNATURE_SIZE`
(`common/types/src/attestation.rs`), static-asserted against leanVM's scheme
constants in `common/crypto/src/signature.rs`
- Epoch-based to prevent reuse
- Aggregation via leanVM (previously leanMultisig) for efficiency
- Signing, verification, and aggregation all come from leanVM, which internalized
XMSS in its own `xmss` crate; there is no external leanSig dependency
- BLAKE2s over binary fields, not Poseidon over KoalaBear: a leanVM `main` bump
across that rewrite invalidates every genesis key and every stored proof, even
when the wire sizes happen to match
- `ethlambda_crypto::init_leanvm(use_arena)` must run once at startup, before any
proving or proof decoding. `--prover-arena` opts into leanVM's bump arena,
which recycles the prover's large buffers across proofs instead of re-faulting
them, so its pages stay resident for the node's lifetime
- `ethlambda keygen` generates genesis validator keys through the same
`ValidatorSecretKey` the node loads them with, so a key set cannot be built
against a different leanVM than the client reading it. Keys are only usable by
a client on the matching revision, and no file size changes when the scheme
does, so the manifest records `leanvm_rev`. See [`docs/keygen.md`](docs/keygen.md)

**Aggregation shape (one leanVM `AggregateSignature`, grouped by epoch):**
- Type-1 and Type-2 are the same object: one `XmssGroup` per slot, carrying the
one message signed at it and that group's sorted, deduplicated keys
- **A slot carries one message.** Two distinct `AttestationData` at one slot
cannot share an aggregate; `ethlambda_crypto::ConflictingMessages` says so, and
nothing below it can work around the constraint
- **The binding is off the wire.** `to_bytes_without_pubkeys()` carries neither
the keys nor the `(slot, message)` pairs, so every decode rebuilds the whole
signer set from a `SignerSet` per claim. A wrong set, message or slot decodes
fine and fails inside the SNARK verifier, so there is no cheap binding check
- Narrowing replaces splitting: re-aggregate the parent with a `declare` naming
the group to keep (`split_type_2_by_message`)

**Signature Aggregation (Two-Phase):**
1. **Gossip signatures**: Fresh XMSS from network → aggregate via leanVM
Expand Down Expand Up @@ -309,7 +337,7 @@ one port is supported and not a misconfiguration. See [`docs/rpc.md`](docs/rpc.m
GENESIS_TIME: 1770407233
MILLISECONDS_PER_SLOT: 4000 # optional, defaults to DEFAULT_MILLISECONDS_PER_SLOT
GENESIS_VALIDATORS:
- attestation_pubkey: "cd323f232b34ab26d6db7402c886e74ca81cfd3a..." # 52-byte XMSS pubkeys (hex)
- attestation_pubkey: "cd323f232b34ab26d6db7402c886e74ca81cfd3a..." # XMSS pubkeys, hex, PUBLIC_KEY_SIZE bytes
proposal_pubkey: "b7b0f72e24801b02bda64073cb4de6699a416b37..."
```
- Validator indices are assigned sequentially (0, 1, 2, ...) based on array order
Expand Down Expand Up @@ -400,7 +428,9 @@ behavior.
## External Dependencies

**Critical:**
- `leansig`: XMSS signatures (leanEthereum project)
- `leanvm`: XMSS signatures and recursive aggregation, taken from leanVM's facade
crate (which re-exports `xmss`, `rec_aggregation` and its `rand`) and pinned to
one `main` revision (leanEthereum project)
- `libssz` / `libssz-derive` / `libssz-types`: SSZ serialization
- `libssz-merkle`: Merkle tree hashing (`hash_tree_root()`)
- `spawned-concurrency`: Actor model
Expand Down
Loading
Loading