mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
Corona is the Ring-LWE threshold signature scheme (lattice flavor:
Ring-LWE, vs Pulsar's Module-LWE / ML-DSA). The pre-rename library
name was Corona. Sweep eliminates every Corona reference across
the precompile tree and gives the Ring-LWE threshold its own slot
in the LP-4200 PQCrypto block:
0x012201 = ML-KEM (Module-LWE KEM, FIPS 203)
0x012202 = ML-DSA (Module-LWE single-sig, FIPS 204)
0x012203 = SLH-DSA (hash-based signature, FIPS 205)
0x012204 = Pulsar (Module-LWE threshold, FIPS 204 byte-equal)
0x012205 = P3Q (strict-PQ STARK)
0x012206 = Corona (Ring-LWE threshold)
Pulsar previously squatted 0x012204 alone; Corona/Corona also
claimed 0x012204 — direct slot collision. Fixed by moving Corona
to its own slot 0x012206 since they're distinct primitives
(different lattice flavors).
- Directory: corona/ → corona/
- Package: coronathreshold → coronathreshold
- Type: coronaThresholdPrecompile → coronaThresholdPrecompile
- Var: CoronaThresholdPrecompile → CoronaThresholdPrecompile
- Address: 0x012204 → 0x012206
- Library: luxfi/corona/sign → luxfi/corona/sign
luxfi/corona/threshold → luxfi/corona/threshold
- Interface: ICoronaThreshold.sol → ICoronaThreshold.sol
- Registry: CoronaCChain → CoronaCChain, CORONA → CORONA
- Quasar: Corona* identifiers in quasar/contract.go renamed
- Bridge: docstring sweep
All affected packages build clean. All 5/6 PQ precompile tests pass
(one flaky on first run, green on retry). Bridge has a pre-existing
unrelated build break (ErrChainNameTooLong undefined).
152 lines
3.7 KiB
Go
152 lines
3.7 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
// Copyright (C) 2025, Lux Industries, Inc. All rights reserved.
|
|
|
|
package bridge
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/luxfi/geth/common"
|
|
|
|
"github.com/luxfi/precompile/contract"
|
|
"github.com/luxfi/precompile/modules"
|
|
"github.com/luxfi/precompile/precompileconfig"
|
|
)
|
|
|
|
var _ contract.Configurator = (*configurator)(nil)
|
|
|
|
// ConfigKey is the JSON key under which the registrar's config slots in.
|
|
const ConfigKey = "bridgeRegistrarConfig"
|
|
|
|
// Module registers the registrar precompile at 0x0446 so that
|
|
// modules.RegisteredModules() reports it.
|
|
var Module = modules.Module{
|
|
ConfigKey: ConfigKey,
|
|
Address: ContractRegistrarAddress,
|
|
Contract: RegistrarPrecompile,
|
|
Configurator: &configurator{},
|
|
}
|
|
|
|
type configurator struct{}
|
|
|
|
func init() {
|
|
if err := modules.RegisterModule(Module); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// Config carries the network-upgrade fields plus the initial governance set.
|
|
// The operators + threshold are required at activation — without them, every
|
|
// write call would revert with ErrUnauthorized. Tests that exercise the
|
|
// registrar in isolation should call SeedGovernance directly.
|
|
type Config struct {
|
|
Upgrade precompileconfig.Upgrade `json:"upgrade"`
|
|
Operators []string `json:"operators,omitempty"` // hex-encoded addresses
|
|
Threshold uint32 `json:"threshold,omitempty"`
|
|
}
|
|
|
|
func (c *Config) Key() string {
|
|
return ConfigKey
|
|
}
|
|
|
|
func (c *Config) Timestamp() *uint64 {
|
|
return c.Upgrade.Timestamp()
|
|
}
|
|
|
|
func (c *Config) IsDisabled() bool {
|
|
return c.Upgrade.Disable
|
|
}
|
|
|
|
func (c *Config) Equal(cfg precompileconfig.Config) bool {
|
|
other, ok := cfg.(*Config)
|
|
if !ok {
|
|
return false
|
|
}
|
|
if !c.Upgrade.Equal(&other.Upgrade) {
|
|
return false
|
|
}
|
|
if c.Threshold != other.Threshold {
|
|
return false
|
|
}
|
|
if len(c.Operators) != len(other.Operators) {
|
|
return false
|
|
}
|
|
for i := range c.Operators {
|
|
if c.Operators[i] != other.Operators[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (c *Config) Verify(chainConfig precompileconfig.ChainConfig) error {
|
|
if len(c.Operators) == 0 && c.Threshold == 0 {
|
|
return nil // permissibly empty; SeedGovernance must run later
|
|
}
|
|
if c.Threshold == 0 || int(c.Threshold) > len(c.Operators) {
|
|
return fmt.Errorf(
|
|
"registrar: invalid threshold %d for %d operators",
|
|
c.Threshold, len(c.Operators),
|
|
)
|
|
}
|
|
for _, op := range c.Operators {
|
|
if _, err := parseAddress(op); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (*configurator) MakeConfig() precompileconfig.Config {
|
|
return new(Config)
|
|
}
|
|
|
|
// Configure is called once when the upgrade activates. Seeds the operator
|
|
// set and threshold so subsequent write calls can be authorized.
|
|
func (*configurator) Configure(
|
|
chainConfig precompileconfig.ChainConfig,
|
|
cfg precompileconfig.Config,
|
|
state contract.StateDB,
|
|
blockContext contract.ConfigurationBlockContext,
|
|
) error {
|
|
c, ok := cfg.(*Config)
|
|
if !ok {
|
|
// Empty config means no governance is seeded at activation. The
|
|
// registrar is still registered; writes revert with ErrUnauthorized
|
|
// until SeedGovernance is invoked.
|
|
return nil
|
|
}
|
|
if len(c.Operators) == 0 || c.Threshold == 0 {
|
|
return nil
|
|
}
|
|
ops, err := parseOperators(c.Operators)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return SeedGovernance(state, ops, c.Threshold)
|
|
}
|
|
|
|
func parseOperators(hexAddrs []string) ([]common.Address, error) {
|
|
out := make([]common.Address, len(hexAddrs))
|
|
for i, h := range hexAddrs {
|
|
addr, err := parseAddress(h)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out[i] = addr
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
func parseAddress(h string) (common.Address, error) {
|
|
s := strings.TrimSpace(h)
|
|
if !strings.HasPrefix(s, "0x") {
|
|
s = "0x" + s
|
|
}
|
|
if len(s) != 42 {
|
|
return common.Address{}, fmt.Errorf("registrar: bad operator address %q", h)
|
|
}
|
|
return common.HexToAddress(s), nil
|
|
}
|