Commit Graph
22 Commits
Author SHA1 Message Date
zeekay 3b37aa2e7a consensus: route live cert-verify through VerifyUnderPolicy; delete dead engine/pq (Red H3 wiring)
Red proved H3's VerifyUnderPolicy was INERT: the live wire-level verifier
(QuantumPolicy.VerifyWithKeys -> QuasarCert.VerifyWithRealKeys) used the
implied-policy path (BLS-permissive), and the policy-driven path had ZERO
live callers. consensus/engine/pq (PostQuantum.SetCertPolicy) was dead —
nothing imported it.

Task 3 — make the LIVE path policy-driven from the SINGLE source of truth:
- config: ChainSecurityProfile.CertPolicy() — the one mapping from the
  chain's security profile to its cert posture. strict-PQ/FIPS -> Strict
  variant (BLS NOT a required leg) + Mode=PQ-strict (RequiredLegs =
  {Pulsar, Corona}); other profiles -> Hybrid (BLS retained alongside PQ).
- pkg/wire: QuantumPolicy carries that CertPolicy. New VerifyCertUnderPolicy
  is THE live verifier — routes through QuasarCert.VerifyUnderPolicy with
  the chain's policy + full CertKeys. VerifyWithKeys is now a thin adapter
  over it. NewQuantumPolicyForProfile derives the policy from the profile.
  Leg presence is policy-driven (VerifyUnderPolicy Gate 1), never
  cert-byte-driven: a CRQC that forges BLS and strips the PQ legs is
  rejected.
- Deleted consensus/engine/pq (10 files, zero importers — the whole package
  was dead, not just SetCertPolicy). The live verify is now the wire path.

Test (d): on a strict-PQ chain, the LIVE verifier rejects a BLS-only
(PQ-legs-stripped) cert even with a valid BLS key supplied; the policy is
Strict-variant (BLS not required, Corona required); the permissive default
is Hybrid (BLS required) — proving the switch is profile-driven, not
hardcoded. (The per-leg crypto half is covered in quasar/
cert_policy_verify_test.go.)
2026-06-19 13:45:00 -07:00
zeekay 6897c234ad consensus(quasar): verify-enforce QuasarCert AND via CertPolicy.RequiredLegs (Red H3)
The QuasarCert verifier made BLS mandatory and PQ legs optional/
cert-byte-driven: a CRQC that broke BLS-12-381 could ship a BLS-only
cert (omit every PQ leg) and verify true, while a legitimate pure-PQ
(no-BLS) cert was wrongly rejected. config.CertPolicy.RequiredLegs()
(the canonical leg-set authority) had zero production callers.

Wire it in:
- New cert_policy_verify.go: VerifyUnderPolicy(message, CertPolicy, CertKeys)
  is the canonical verifier. For every leg in RequiredLegs() it rejects
  unless the leg is BOTH present in the cert AND backed by a supplied key,
  BEFORE any signature math — leg presence is policy-driven, not
  attacker-controlled cert bytes. BLS is required iff the policy includes
  it (Variant=Hybrid); a Strict-variant policy yields a pure-PQ required
  set so a no-BLS cert verifies. Identity rollup is required under any PQ
  policy (downgrade-resistant), present-implies-verify otherwise.
- Decomplect leg crypto into verify{BLS,Corona,Magnetar,MLDSARollup}Leg
  helpers; VerifyWithRealKeys / VerifyWithRealKeysPolaris reimplemented on
  them with the BLS-mandatory bug fixed (BLS required iff key supplied;
  pure-PQ allowed; each PQ leg required iff its key supplied — an adversary
  cannot strip a leg the verifier was configured to check).
- Migrate callers to policy intent: engine/pq gains SetCertPolicy +
  policy-driven verify path; pkg/wire QuantumPolicy enforces requireRT
  (Corona key mandatory) when set.

Tests (real crypto, no stubs): leg-removal negatives for each required
leg reject; missing-key-for-required-leg rejects; pure-PQ cert verifies
under Strict-variant policy AND via VerifyWithRealKeysPolaris(nil BLS);
Red PoC (BLS-only cert + PQ keys configured) now rejected. Existing
ComposeAllThreeSchemes / cert roundtrip / CertBundle suites unchanged.

Pre-existing unrelated failure TestVerifyBLSAggregate_C1_ActualDeserialization
(witness_test.go) fails identically on origin — out of scope.
2026-06-19 12:48:06 -07:00
zeekay 52b8ef654b consensus(quasar): Z-lane rollup proof is strict-PQ STARK/FRI (P3Q), not Groth16
Rename the Z-Chain parallel-witness rollup proof system from
classical Groth16/bn254 (pairing-based, quantum-breakable) to the
post-quantum STARK/FRI path (P3Q: Plonky3 fork, cSHAKE256 Merkle over
Goldilocks, FRI; no KZG, no pairings, no trusted setup).

This is a comment/identifier rename only: QuasarCert.MLDSARollup is
opaque bytes and the consensus module has no proof-system dependency,
so the cert composition + ZWitnessProducer interface are unchanged.
The verifier and prover live in chains/zkvm.

- witness_producer.go: ZWitnessProducer doc + MLDSAGroth16->MLDSAStark;
  DisabledZWitnessProducer doc (STARK prover, AIR constraint count).
- types.go / polaris.go: MLDSARollup leg doc 'STARK/Groth16'->
  'strict-PQ STARK/FRI (P3Q)'; wire-layout comment.
- engine/pq/consensus.go: FinalityEvent.MLDSARollup doc.
- pkg/wire/candidate.go: PolicyQuantum/PolicyPZ/WitnessZ docs.

QuasarCert composition gate test (TestQuasarCert_ComposesAllThreeSchemes)
still passes. No wire-format change.
2026-06-19 12:23:02 -07:00
zeekay 0142367b60 consensus: route corona + pulsar through threshold/protocols alias
Replaces every direct import of luxfi/corona/* and luxfi/pulsar/ref/go
in consensus with the canonical luxfi/threshold/protocols/{corona,pulsar}
alias surface. Pure import swap + go.mod bump; no behaviour change.

Files touched (16):

  bench/pq_modes_bench_test.go
  engine/pq/crypto.go
  engine/pq/engine.go
  pkg/wire/policies.go
  protocol/quasar/cert_size_compare_test.go
  protocol/quasar/corona_gob.go
  protocol/quasar/dual_threshold_test.go
  protocol/quasar/epoch.go
  protocol/quasar/epoch_test.go
  protocol/quasar/gpu_accel.go
  protocol/quasar/grouped_threshold.go
  protocol/quasar/quasar.go
  protocol/quasar/types.go
  protocol/quasar/wave_signer.go
  protocol/quasar/wave_signer_test.go
  protocol/quasar/witness.go
  protocol/quasar/witness_pulsar_test.go

Import path swaps:

  luxfi/corona/threshold        -> luxfi/threshold/protocols/corona
  luxfi/corona/keyera           -> luxfi/threshold/protocols/corona/keyera
  luxfi/corona/primitives       -> luxfi/threshold/protocols/corona/primitives
  luxfi/corona/reshare          -> luxfi/threshold/protocols/corona/reshare
  luxfi/corona/sign             -> luxfi/threshold/protocols/corona/sign
  luxfi/corona/gpu              -> luxfi/threshold/protocols/corona/gpu
  luxfi/pulsar/ref/go/pkg/pulsar -> luxfi/threshold/protocols/pulsar

The aliased package name "coronaThreshold" used by quasar / engine/pq /
pkg/wire identifiers is preserved at the call sites (it now refers to
the threshold/protocols/corona alias package). engine/pq/crypto.go is
the only file where the package was bare-imported as `threshold`; that
identifier was renamed to `corona` to match the new alias path.

go.mod:

  - luxfi/threshold bumped to a branch pseudo-version that carries the
    new alias subpackages; will pin to a stable tag once threshold's
    companion commit lands and a release is cut.
  - luxfi/corona and luxfi/pulsar drop to indirect (consensus now
    reaches them only via threshold/protocols).
  - luxfi/math v1.4.0 -> v1.4.1 and luxfi/metric v1.5.0 -> v1.5.7 are
    transitive minimum-version bumps pulled by the new threshold
    requirement; they are no-op for consensus call sites.

Comment-only references to "github.com/luxfi/corona/..." in bls.go,
round_digest.go, reshare_epoch.go, comprehensive_test.go,
engine_test.go, quasar_bench_test.go and config/pq_mode.go are
documentation pointers to where the underlying implementation lives;
they are accurate either way and are left unchanged (out of refactor
scope).

Layering shape after:

  consensus -> threshold/protocols/{corona,pulsar}  (stable alias)
                 |
                 v
              luxfi/corona, luxfi/pulsar  (primitive implementations)

Closes the 22-file layering violation flagged by the 2026-05-31
integration audit. Tests pass: ./engine/pq/..., ./pkg/wire/...,
./protocol/quasar/... (all key cases — TestEpochManager*,
TestRoundSigner*, TestVerifyPQFinality*, TestBLSThreshold*,
TestDualSigningFlow, TestCoronaCertSize* — green; the pre-existing
TestGroupedEpochManager_ParallelKeygen perf-bound flake on slow
machines was reproduced on unmodified main, so it is not a
regression).
2026-05-31 12:39:47 -07:00
zeekay 082e340c95 ci: gofmt pkg/wire/candidate.go (golangci-lint blocker on v1.23.26) 2026-05-16 18:30:51 -07:00
zeekay 2fdec23582 quasar/config/wire: track pulsarm → pulsar rename
Consumer-side rename to follow the luxfi/pulsar package drop of the
-M suffix. All 25 touched files migrate the import path
github.com/luxfi/pulsar/ref/go/pkg/pulsarm → .../pulsar and the
in-file symbol references pulsarm.* → pulsar.* (plus the local
witness_pulsarm_test.go filename → witness_pulsar_test.go).

Build: go build ./... PASS.
Test: full ./... sweep — 28 packages PASS (protocol/quasar 15.9s,
engine 10.7s, config 0.9s, pkg/wire 1.5s).
2026-05-15 13:50:29 -07:00
zeekay faf3f78756 gofmt: cleanup after Corona purge identifier renames 2026-05-12 14:53:30 -07:00
zeekay f6753f3b53 quasar: complete Corona purge — Corona (production R-LWE) + Nasua (academic upstream)
Followup to the QuasarCert field rename (commit d1c8a2cc). This sweeps
the remaining Corona identifiers and prose out of the consensus repo
entirely:

  - Identifiers (Go code):
    coronaThreshold   → coronaThreshold      (import alias)
    coronaGroupKey    → coronaGroupKey
    coronaSigners     → coronaSigners
    coronaShares      → coronaShares
    coronaGobEncode   → coronaGobEncode
    coronaGobDecode   → coronaGobDecode
    decodeCoronaSig   → decodeCoronaSig
    EncodeCoronaSig   → EncodeCoronaSig
    CoronaRound1{,Data,State} → CoronaRound1{,Data,State}
    CoronaGroupKey/Pub/Shares → Corona*

  - File rename:
    protocol/quasar/corona_gob.go → corona_gob.go

  - PQMode constants:
    PQModeCorona            → PQModeNasua
    SigSchemeCoronaAcademic → SigSchemeNasua
    "corona" / "corona-academic" string forms → "nasua"

  - Prose & comments throughout the repo: "Corona" → "Corona" when
    naming the production Ring-LWE library, "Nasua" when naming the
    historical academic upstream (luxfi/nasua, formerly luxfi/corona).

Canonical Pulsar family taxonomy after this rename:

  Nasua  — academic R-LWE 2-round threshold sig (Boschini et al,
           ePrint 2024/1113); trusted-dealer DKG; kept as historical
           reference fork only. NOT for an open public chain.
  Corona — production Ring-LWE threshold ML-DSA (Pedersen DKG over R_q
           + proactive resharing); `github.com/luxfi/corona`. The
           Ring-LWE leg of QuasarCert.
  Pulsar — production Module-LWE threshold ML-DSA (FIPS 204
           byte-equal); `github.com/luxfi/pulsar`. The Module-LWE
           leg of QuasarCert. Pure-PQ pair = Corona + Pulsar.

Wire-format unchanged. Tests: 28/28 packages green (-short suite,
quasar 29s, integration 58s, no regressions).
2026-05-12 08:58:51 -07:00
zeekay d1c8a2cc28 quasar: rename Corona→Corona, MLDSAProof→MLDSARollup, drop "triple"
The Quasar cert layers are the right cardinality of "Double Lattice +
Identity Rollup + optional Classical Fast-path", not "Triple Quantum":

  BLS-12-381  classical fast-path (pairing) — empty in pure-PQ
  Corona      Ring-LWE  threshold ML-DSA (luxfi/corona; production R-LWE)
  Pulsar      Module-LWE threshold ML-DSA (luxfi/pulsar; Class N1 byte-equal
                                            to FIPS 204)
  MLDSARollup per-validator ML-DSA-65 rolled into one STARK / Groth16 proof
                                            (Z-Chain → P3Q)

"Triple Quantum" misled because BLS is classical — at most one of three
legs was quantum in the historic BLS+Corona+ZK shape. The honest PQ
cardinality is **Double Lattice** (Ring + Module). Pure-PQ profiles
drop BLS entirely and rely on Corona + Pulsar.

Corona is the academic R-LWE construction with trusted-dealer DKG;
it stays out of any open public-chain path. Corona is the production
Ring-LWE library (Pedersen DKG over R_q + proactive resharing).

Surface (in protocol/quasar/types.go):
  QuasarCert.BLS         → unchanged (classical fast-path, optional)
  QuasarCert.Corona    → QuasarCert.Corona       (Ring-LWE threshold sig)
  QuasarCert.MLDSAProof  → QuasarCert.MLDSARollup  (succinct identity rollup)
  QuasarCert            now also has a Pulsar field (Module-LWE threshold sig,
                                                     populated when wired)

  QuasarSig.Corona     → QuasarSig.Corona  (also added Pulsar []byte)
  FinalityEvent.Corona / MLDSAProof → Corona / Pulsar / MLDSARollup

  New predicates:
    QuasarCert.IsDoubleLattice()       — Corona ∧ Pulsar (honest PQ count)
    QuasarCert.HasClassicalFastPath()  — len(BLS) > 0
    QuasarCert.HasIdentityRollup()     — len(MLDSARollup) > 0

The wire byte layout is unchanged (length-prefixed slots). Callers that
read the bytes don't notice. Source-level references that compiled
before the rename now compile against the new identifiers; bulk
rename swept the consensus repo (22 files, 219 insertions, 151
deletions) plus the engine/pq facing FinalityEvent.

Tests: GOWORK=off go test -short -count=1 ./... → all 28 packages green
(quasar suite 32s; integration 60s; no regressions).
2026-05-12 08:40:06 -07:00
zeekay 0144f80def consensus: collapse profile registry to strict / permissive / fips
PQ mode is binary. The profile registry is collapsed to three
canonical bundles:

  0x01 ProfileStrictPQ   ("STRICT")     — production PQ chains
  0x02 ProfilePermissive ("PERMISSIVE") — testnet / devnet
  0x03 ProfileFIPS       ("FIPS")       — FIPS-aligned superset

Removed pseudo-profiles: HybridProfile, ClassicalProfile, BLSProfile,
ZooStrictPQProfile, HanzoStrictPQProfile, QuasarStrictPQProfile,
AnnulusStrictPQProfile. Chains that need classical primitives pin
ForkClassicalCompatUnsafeProfile (0x80) at the byte layer and own
the audit consequence.

(*ChainSecurityProfile).IsPQ() is the single canonical predicate.
Profile string surface tracks the byte registry exactly: "strict",
"permissive", "fips".

Cross-brand scrub: dropped "Hanzo mesh" doc-comments in pq_mode.go
+ pq_mode_test.go + witness_floor_test.go in favor of "Lux mesh".
Dropped Lux/Zoo/Hanzo enumeration in account_id.go. account_id_test.go
uses fork byte (0x80) instead of zoo/hanzo profile IDs. qblock.go
references LP-0079 instead of cross-org HIP path.
2026-05-11 18:03:55 -07:00
zeekay 9555ccb19c consensus: flip pulsar (R-LWE) imports to corona
Cross-cutting family-rename consumer update. consensus's R-LWE
threshold path now imports github.com/luxfi/corona/{hash,keyera,
reshare,threshold} (was github.com/luxfi/pulsar/*). The M-LWE
github.com/luxfi/pulsar-m import is untouched -- that path stays
until pulsar-m archives in favour of luxfi/pulsar v0.2.0 (next
phase).

go.mod adds replace directives for the local-dev family:
  github.com/luxfi/pulsar     => ../pulsar    (R-LWE legacy, kept for transitive deps)
  github.com/luxfi/corona     => ../corona    (R-LWE post-rename)
  github.com/luxfi/threshold  => ../threshold (locally-flipped)

protocol/quasar + protocol/zchain test suites green.
2026-05-11 15:02:15 -07:00
zeekay ad4a44b908 consensus: locked ChainSecurityProfile + ZProofEnvelope + QBlock canonical
Many modes in the toolkit, ONE locked profile per chain. Zero-value-invalid
enums, profile-hash genesis pinning, defensive Lookup, 15-step fail-closed
verifier. Single canonical layout — no V1/V2 versioning.

config/
- security_profile.go      ChainSecurityProfile struct + canonical hash
- profiles.go              LuxStrictPQ / LuxPermissive / LuxFIPS /
                           ForkClassicalCompatUnsafe; MustComputeHash at init
- pq_mode.go               PQMode goes from doc-string to canonical table;
                           PQModeFromBool collapse; PostQuantum() helper
- *_test.go + redteam_*    locked-profile invariants pinned

protocol/zchain/
- ZProofEnvelope canonical wire shape (HashSuiteID, SigSchemeID,
  ProofSystemID, BackendID, Manifest reference)
- VerifierManifest registry — backend-versioned, manifest-hash-bound
- VerifyZProofUnderProfile — 15-step fail-closed verifier
- Production / dev verifier split via build tags
- redteam tests close F76 golden vector at
  098e6d5b...ab572fa2b8

protocol/quasar/
- ComputeRoundDigest canonical: binds HashSuiteID + SigSchemeID +
  ProofSystemID + chainID + networkID + height + parent_state
- QBlock canonical wire shape
- Witness-floor + redteam round-digest tests

pkg/wire/
- HashSuiteID + HashSuite TranscriptHash binding (closes F1: silent
  finality forks between hash-profile islands sharing the same PolicyID)

Red-team review: 24 findings F51-F91 closed; verdict SHIP.
Tests: 175 PASS across config + zchain + quasar + wire. -tags production clean.

Patch-bump.
2026-05-10 17:18:50 -07:00
zeekay f651395f50 Wire consensus PQ end-to-end: real BLS+Corona+ML-DSA
- protocol/quasar/types.go: QuasarCert MarshalBinary/UnmarshalBinary
  (length-prefixed wire layout, leading byte CertSchemeQuasar=0x04),
  VerifyWithRealKeys cryptographic verification, EncodeMLDSASigs helper
- protocol/quasar/corona_gob.go: gob serializer for pulsar/threshold
  Signature
- protocol/quasar/engine.go: Certifier.AttachSigner; generateCert drives
  signer.TripleSignRound1 (real BLS share + MLDSAProof). Falls back to
  legacy SHA-256 only when no signer attached
- engine/pq/engine.go: AttachSigner/AttachVerifyKeys; VerifyQuantumSignature
  decodes QuasarCert + runs VerifyWithRealKeys; GenerateQuantumProof
  emits serialized QuasarCert
- engine/pq/crypto.go: ML-DSA-65 keypair; real GeneratePQSignature
- engine/pq/consensus.go: PQMode field; resolves via config.PQModeFromEnv
- config/pq_mode.go: PQMode enum (BLSOnly | BLSPlusMLDSA | BLSPlusCorona
  | BLSPlusGroth16 | TripleQuantum), LUX_CONSENSUS_PQ_MODE env support
- pkg/wire/policies.go: QuantumPolicy serializes real QuasarCert into
  cert.Proof; Verify decodes via UnmarshalBinary; VerifyWithKeys does
  cryptographic verification
- engine/gpu_batch_pipeline.go: gpuAvailable() wired to accel.Available();
  verifyBLSBatchGPU calls accel.BLSBatchVerify
- bench/pq_modes_bench_test.go: 5 PQ mode benches with real BLS aggregate,
  real ML-DSA-65, real Corona 2-round threshold. Storage projection
  comparison.

1237 tests pass.

Bench results (Apple M1, n=21):
  Mode             Sign     Agg      Verify   Cert     Storage 10K
  bls              312µs    8.6ms    714µs    123 B    1.17 MB
  bls-mldsa        369µs    8.5ms    3.4ms    69 KB    665 MB
  bls-rt           39ms     3.3s     1.6ms    33 KB    318 MB
  triple           40ms     3.3s     4.3ms    102 KB   981 MB
2026-05-05 10:14:09 -07:00
zeekay 04ce8745ee consensus: Quasar cutover to LSS-Pulsar + post-Feb-28 batch
Squashed batch covering all post-Feb-28 consensus work, capped by the
LSS-Pulsar cutover (task #53):

- Quasar cutover from upstream Corona to LSS-Pulsar adapter:
    go.mod: drop direct require github.com/luxfi/corona; add
            github.com/luxfi/pulsar + github.com/luxfi/threshold;
            local replaces => ../pulsar, ../threshold
    epoch.go: InitializeEpoch → keyera.Bootstrap; RotateEpoch →
              lss.DynamicResharePulsar gated by activation cert
              verification under unchanged GroupKey
    quasar.go, grouped_threshold.go: import swap corona → pulsar
    reshare_epoch.go: production wiring; QUASAR-PULSAR-ACTIVATE-v1
                      domain prefix; ReshareEpoch + RefreshEpoch
    EpochKeys: gains KeyEraID, Generation, RollbackFrom (LP-105)
    BundleSigner: re-derives Lambda for participating subset
    258 quasar tests pass.

- Earlier post-Feb-28 work (gofmt linter fixes across protocol files,
  METASTABLE_SIGNED_QUERIES.md doc, MLDSAProof rename across 7 test
  files) included in the squash.

Hash profile: consensus passes nil to resolve to Pulsar-SHA3 default
(LP-105 / pulsar/hash). Activation message canonical bytes bind
chain_id, network_id, key_era_id, generation, group_id, epoch, set
hashes, thresholds, group_pk_hash, nebula_root, hash_suite_id,
implementation_version, variant, reshare_transcript_hash —
all under TupleHash256("PULSAR-TRANSCRIPT-v1", ...).

Vocabulary alignment with LP-105 (Lux Finality Stack lexicon):
  Photon (vote) → Beam (BLS) → ML-DSA (PQ identity) →
  Pulsar (PQ threshold kernel) → Pulse (cert over Nebula root) →
  Prism (composition verifier) → Horizon (finality boundary) →
  Quasar (full consensus).

Excluded from this commit: pkg/wire/{candidate,policies_test}.go
uncommitted diff (pre-existing local edits; stashed and restored).
Untracked protocol/quasar/witness_producer.go (mtime Apr 29; pre-task).
2026-03-03 12:00:00 -08:00
zeekay cbd186e04c refactor: add maxCandidates cap to wire policies
Bounds-check all 5 OnCandidate methods at 100K entries to prevent
unbounded memory growth from malicious or buggy peers.
2026-02-20 18:18:29 -08:00
zeekay 837e3998cf docs: Quasar not Triple, ZAP not libp2p 2026-02-16 17:50:22 -08:00
zeekay 299fa7336f clean: remove deprecated aliases, AI slop, backwards compat code
- Delete DeprecatedConfig/NewFromDeprecated in syncer (49 lines)
- Delete ChainVMWithNetwork/ChainVMWithHealth type aliases
- Delete QBlock, newSignerWithThreshold, VMState aliases
- Delete GetNetID (returned empty string)
- Remove all "In production" / "For now" / "placeholder" comments
- Fix examples: NewSimpleModel API, big.NewInt overflow
- Published deps for all examples (consensus v1.22.84, dex v1.4.1)
2026-02-15 14:08:02 -08:00
zeekay ef3f0541da fix: resolve staticcheck lint issues 2026-02-05 18:36:28 -08:00
zeekay 257cacb84a chore: sync dependencies and format code 2026-02-04 15:44:47 -08:00
zeekay 79eb047505 feat: unify Python SDK with MCP mesh consensus
Major changes:
- Merge pkg/wire Python types into pkg/python/lux_consensus
- Add MCP mesh consensus module (from hanzo-consensus)
- Add types.py with Candidate, Vote, Certificate for wire protocol
- Bridge functions for AI consensus -> blockchain interop
- Keep pkg/wire as Go-only wire protocol types

Python SDK now provides:
- lux_consensus: Core chain/block/vote types
- lux_consensus.types: Wire protocol (Candidate, WireVote, WireCertificate)
- lux_consensus.mcp: MCP mesh for agent-to-agent consensus

Also includes engine improvements:
- Chain syncer with persistence
- PQ crypto enhancements
- External sequencer finality example
- Protocol field/horizon/prism updates

All tests passing.
2026-01-13 09:49:03 -08:00
zeekay 38517004e7 restore: context package needed by protocol 2026-01-12 14:51:25 -08:00
zeekay 4d6f5562d9 chore: sync with node requirements, add runtime package 2026-01-12 14:44:26 -08:00