// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved. // See the file LICENSE for licensing terms. package modules import ( "bytes" "fmt" "slices" "github.com/luxfi/geth/common" ) // AddressRange represents a continuous range of addresses type AddressRange struct { Start common.Address End common.Address } // Contains returns true iff [addr] is contained within the (inclusive) // range of addresses defined by [a]. func (a *AddressRange) Contains(addr common.Address) bool { addrBytes := addr.Bytes() return bytes.Compare(addrBytes, a.Start[:]) >= 0 && bytes.Compare(addrBytes, a.End[:]) <= 0 } // BlackholeAddr is the address where assets are burned var BlackholeAddr = common.Address{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, } var ( // registeredModules is a list of Module to preserve order // for deterministic iteration registeredModules = make([]Module, 0) // Reserved address ranges for stateful precompiles // // HIGH-BYTE RANGES (legacy format: 0xXX00...0000): // 0x0100-0x01FF: Warp/Teleport messaging // 0x0200-0x02FF: Chain config (AllowLists, FeeManager, etc.) // 0x0300-0x03FF: AI Mining (sole owner; pre-LP-4200 quasar stubs retired) // 0x0400-0x04FF: DEX (Uniswap v4-style) // 0x0500-0x05FF: Graph/Query layer // 0x0600-0x06FF: Post-quantum crypto // 0x0700-0x07FF: Privacy/Encryption // 0x0800-0x08FF: Threshold signatures // 0x0900-0x09FF: ZK proofs // 0x0A00-0x0AFF: Curves (secp256r1, etc.) // // LOW-BYTE RANGES (EIP-collision-free: 0x0000...XXXX): // 0x8000-0x8FFF: Lux Core System (AI Mining at 0x8100) // 0x9000-0x9FFF: Lux Crypto Privacy (HPKE, ECIES, FHE) // 0xA000-0xAFFF: Lux Hashing & ZK (Poseidon2, Blake3, STARK) // 0xB000-0xBFFF: Lux KZG Extensions reservedRanges = []AddressRange{ // Warp/Teleport (0x0100-0x01FF) { Start: common.HexToAddress("0x0100000000000000000000000000000000000000"), End: common.HexToAddress("0x01000000000000000000000000000000000000ff"), }, // Chain Config (0x0200-0x02FF) { Start: common.HexToAddress("0x0200000000000000000000000000000000000000"), End: common.HexToAddress("0x02000000000000000000000000000000000000ff"), }, // AI Mining (0x0300-0x03FF). Sole owner of this range — // the pre-LP-4200 quasar precompiles at 0x0300..20-25 // (forgeable Verkle stub + classical BLS/Hybrid) were // retired in favor of the LP-4200 0x012200 block. { Start: common.HexToAddress("0x0300000000000000000000000000000000000000"), End: common.HexToAddress("0x03000000000000000000000000000000000000ff"), }, // DEX - Uniswap v4-style (0x0400-0x04FF) { Start: common.HexToAddress("0x0400000000000000000000000000000000000000"), End: common.HexToAddress("0x04000000000000000000000000000000000000ff"), }, // Graph/Query Layer (0x0500-0x05FF) { Start: common.HexToAddress("0x0500000000000000000000000000000000000000"), End: common.HexToAddress("0x05000000000000000000000000000000000000ff"), }, // Post-Quantum Crypto (0x0600-0x06FF) { Start: common.HexToAddress("0x0600000000000000000000000000000000000000"), End: common.HexToAddress("0x06000000000000000000000000000000000000ff"), }, // Privacy/Encryption (0x0700-0x07FF) { Start: common.HexToAddress("0x0700000000000000000000000000000000000000"), End: common.HexToAddress("0x07000000000000000000000000000000000000ff"), }, // Threshold Signatures (0x0800-0x08FF) { Start: common.HexToAddress("0x0800000000000000000000000000000000000000"), End: common.HexToAddress("0x08000000000000000000000000000000000000ff"), }, // ZK Proofs (0x0900-0x09FF) { Start: common.HexToAddress("0x0900000000000000000000000000000000000000"), End: common.HexToAddress("0x09000000000000000000000000000000000000ff"), }, // Curves - secp256r1, etc. (0x0A00-0x0AFF) { Start: common.HexToAddress("0x0A00000000000000000000000000000000000000"), End: common.HexToAddress("0x0A000000000000000000000000000000000000ff"), }, // ===================================================================== // LP-ALIGNED RANGES (Low-byte format: 0x0000...LPNUM) // Address = LP number directly, e.g., LP-9010 = 0x...9010 // See precompile/registry/registry.go for full scheme documentation // ===================================================================== // LP-2xxx: PQ Identity (0x0..2000 - 0x0..2FFF) { Start: common.HexToAddress("0x0000000000000000000000000000000000002000"), End: common.HexToAddress("0x0000000000000000000000000000000000002fff"), }, // LP-3xxx: EVM/Crypto (0x0..3000 - 0x0..3FFF) { Start: common.HexToAddress("0x0000000000000000000000000000000000003000"), End: common.HexToAddress("0x0000000000000000000000000000000000003fff"), }, // LP-4xxx: Privacy/ZK (0x0..4000 - 0x0..4FFF) { Start: common.HexToAddress("0x0000000000000000000000000000000000004000"), End: common.HexToAddress("0x0000000000000000000000000000000000004fff"), }, // LP-5xxx: Threshold/MPC (0x0..5000 - 0x0..5FFF) { Start: common.HexToAddress("0x0000000000000000000000000000000000005000"), End: common.HexToAddress("0x0000000000000000000000000000000000005fff"), }, // LP-6xxx: Bridges (0x0..6000 - 0x0..6FFF) { Start: common.HexToAddress("0x0000000000000000000000000000000000006000"), End: common.HexToAddress("0x0000000000000000000000000000000000006fff"), }, // LP-7xxx: AI (0x0..7000 - 0x0..7FFF) { Start: common.HexToAddress("0x0000000000000000000000000000000000007000"), End: common.HexToAddress("0x0000000000000000000000000000000000007fff"), }, // LP-9xxx: DEX/Markets (0x0..9000 - 0x0..9FFF) { Start: common.HexToAddress("0x0000000000000000000000000000000000009000"), End: common.HexToAddress("0x0000000000000000000000000000000000009fff"), }, // LP-12xxx: Unified PQCrypto block (0x0..12000 - 0x0..12fff) // LP-3500/LP-3501/LP-4200: // 0x12201 = ML-KEM (Module-LWE KEM, FIPS 203) // 0x12202 = ML-DSA (Module-LWE single-sig, FIPS 204) // 0x12203 = SLH-DSA (hash-based signature, FIPS 205) // 0x12204 = Pulsar (Module-LWE threshold, FIPS 204 byte-equal) // 0x12205 = P3Q (rollup-commit PQ verifier; kind-byte dispatch // to Pulsar/Corona/Magnetar — LP-218) // 0x12206 = Corona (Module-LWE threshold) // 0x12207 = Magnetar (hash-based threshold, FIPS 205 byte-equal) // 0x12208 = HQC (code-based KEM, family-disjoint backup) // 0x12220 = STARK-FRI (strict-PQ STARK / FRI verifier — LP-221) { Start: common.HexToAddress("0x0000000000000000000000000000000000012000"), End: common.HexToAddress("0x0000000000000000000000000000000000012fff"), }, // ===================================================================== // LOW-BYTE RANGES (EIP-collision-free addresses) // ===================================================================== // Lux Core System (0x8000-0x8FFF) - AI Mining, etc. { Start: common.HexToAddress("0x0000000000000000000000000000000000008000"), End: common.HexToAddress("0x0000000000000000000000000000000000008fff"), }, // Lux Crypto Privacy (0x9000-0x9FFF) - HPKE, ECIES, FHE { Start: common.HexToAddress("0x0000000000000000000000000000000000009000"), End: common.HexToAddress("0x0000000000000000000000000000000000009fff"), }, // Lux Hashing & ZK (0xA000-0xAFFF) - Poseidon2, Blake3, STARK, etc. { Start: common.HexToAddress("0x000000000000000000000000000000000000a000"), End: common.HexToAddress("0x000000000000000000000000000000000000afff"), }, // Lux KZG Extensions (0xB000-0xBFFF) { Start: common.HexToAddress("0x000000000000000000000000000000000000b000"), End: common.HexToAddress("0x000000000000000000000000000000000000bfff"), }, // Standard EVM Precompiles (0x01-0x11) // Includes: ECRECOVER, SHA256, RIPEMD160, IDENTITY, MODEXP, BN254, // BLAKE2F, KZG, BLS12-381 (EIP-2537) { Start: common.HexToAddress("0x0000000000000000000000000000000000000001"), End: common.HexToAddress("0x00000000000000000000000000000000000000ff"), }, // EIP-7212 secp256r1 / P256 verify (0x100) // Reserved post-EVM-standard band 0x100-0x1FF for upstream-EIP // precompiles that EVM clients converge on (RIP-7212 picked 0x100 // for P256 verify). Keeping the range tight (one /248 of the 20- // byte space) means future EIPs slot in here without colliding // with anything Lux uses. { Start: common.HexToAddress("0x0000000000000000000000000000000000000100"), End: common.HexToAddress("0x00000000000000000000000000000000000001ff"), }, // High-byte EVM/Crypto page (LP-3xxx classical signatures) // Per precompile/registry/registry.go PCII scheme: P=3 (EVM/Crypto) // at high-byte format 0x3PCC0000...0000. Reserved for the classical- // signature sub-page so ed25519 (LP-3211 at 0x3211...0000), ECDSA // extensions (LP-3210), BLS12-381 (LP-3212), VRF (LP-3213), etc. // can register without each subsystem extending the table. { Start: common.HexToAddress("0x3200000000000000000000000000000000000000"), End: common.HexToAddress("0x32ff000000000000000000000000000000000000"), }, // Dead/Burn Addresses (LP-0150) // 0x0000...0000 - Zero address { Start: common.HexToAddress("0x0000000000000000000000000000000000000000"), End: common.HexToAddress("0x0000000000000000000000000000000000000000"), }, // 0x0000...dEaD - Common dead address { Start: common.HexToAddress("0x000000000000000000000000000000000000dEaD"), End: common.HexToAddress("0x000000000000000000000000000000000000dEaD"), }, // 0xdEaD...0000 - Full dead address prefix { Start: common.HexToAddress("0xdEaD000000000000000000000000000000000000"), End: common.HexToAddress("0xdEaD000000000000000000000000000000000000"), }, } ) // ReservedAddress returns true if [addr] is in a reserved range for custom precompiles func ReservedAddress(addr common.Address) bool { for _, reservedRange := range reservedRanges { if reservedRange.Contains(addr) { return true } } return false } // RegisterModule registers a stateful precompile module func RegisterModule(stm Module) error { address := stm.Address key := stm.ConfigKey if address == BlackholeAddr { return fmt.Errorf("address %s overlaps with blackhole address", address) } if !ReservedAddress(address) { return fmt.Errorf("address %s not in a reserved range", address) } for _, registeredModule := range registeredModules { if registeredModule.ConfigKey == key { return fmt.Errorf( "precompile config key collision: %q already registered by %s — "+ "each precompile must have a globally unique ConfigKey", key, registeredModule.Address) } if registeredModule.Address == address { return fmt.Errorf( "precompile address collision: %s already used by %q — "+ "trying to register %q at the same address (import-order-independent fail-fast)", address, registeredModule.ConfigKey, key) } } // sort by address to ensure deterministic iteration registeredModules = insertSortedByAddress(registeredModules, stm) return nil } func GetPrecompileModuleByAddress(address common.Address) (Module, bool) { for _, stm := range registeredModules { if stm.Address == address { return stm, true } } return Module{}, false } func GetPrecompileModule(key string) (Module, bool) { for _, stm := range registeredModules { if stm.ConfigKey == key { return stm, true } } return Module{}, false } func RegisteredModules() []Module { return registeredModules } // AlwaysOnModules returns the registered modules marked AlwaysOn — precompiles that // are active on every chain from genesis with NO config entry. The host activates // these unconditionally (EXTCODESIZE marker at genesis + Run dispatch on every block), // independent of genesisPrecompiles / precompileUpgrades. Returned in the same // deterministic address order as RegisteredModules. func AlwaysOnModules() []Module { out := make([]Module, 0, len(registeredModules)) for _, m := range registeredModules { if m.AlwaysOn { out = append(out, m) } } return out } func insertSortedByAddress(data []Module, stm Module) []Module { data = append(data, stm) slices.SortFunc(data, func(a, b Module) int { return bytes.Compare(a.Address.Bytes(), b.Address.Bytes()) }) return data }