Files
zeekay c0d4022c71 Cite the specs by the numbers they carry
LP-134 was renumbered LP-1340 (lp-1340-lux-chain-topology); 21 citations
across 16 files still named the old number, which resolves to nothing.

Corona rests on Module-LWE, not Ring-LWE — LP-4805 says so in three places
and b17e086 already corrected one file, leaving evm/main.go and
schain/SECURITY_review.md claiming the wrong hardness assumption. The
two-family argument in LP-4900 depends on which lattice problem this is.

P3Q at 0x012205 is kind-byte signature dispatch; STARK/FRI is starkfri at
0x012220 (LP-7050). Naming P3Q for a scheme at another slot describes a
precompile that is not the one being imported.

Carries the substance of 2f22fa2, the one commit the parallel line held that
this history did not.
2026-09-01 01:40:34 -07:00

78 lines
2.5 KiB
Go

// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package cert
import (
"crypto/sha256"
"errors"
)
// Roots is the set of upstream roots a Quasar 3.0 certificate_subject
// binds, mirroring the QuasarRoundDescriptor in LP-1340.
//
// All ten roots are required, including both MChain and FChain —
// this is the structural property that makes cross-chain replay
// impossible. The substrate does not let a caller skip a root: a zero
// value is still a value, and the chain that owns the root is
// expected to provide its current root on every round.
type Roots struct {
ParentBlock [32]byte
StateRoot [32]byte
ExecRoot [32]byte
PChainValidator [32]byte
QChainCeremony [32]byte
ZChainVK [32]byte
AChainAttestation [32]byte
BChainBridge [32]byte
MChainCeremony [32]byte
FChainFHE [32]byte
}
// BindSubject computes certificate_subject = H(... all roots ...).
// The hash domain is sha256 with a 1-byte version tag (0x01 for
// LP-1340 v3.1) so future descriptor extensions can change the input
// set without colliding.
func BindSubject(r Roots) [32]byte {
h := sha256.New()
h.Write([]byte{0x01}) // LP-1340 v3.1 descriptor version
h.Write(r.ParentBlock[:])
h.Write(r.StateRoot[:])
h.Write(r.ExecRoot[:])
h.Write(r.PChainValidator[:])
h.Write(r.QChainCeremony[:])
h.Write(r.ZChainVK[:])
h.Write(r.AChainAttestation[:])
h.Write(r.BChainBridge[:])
h.Write(r.MChainCeremony[:])
h.Write(r.FChainFHE[:])
var out [32]byte
copy(out[:], h.Sum(nil))
return out
}
// VerifySubject re-computes the subject from its inputs and checks it
// matches the value carried on the wire. Used by both M-Chain and
// F-Chain at certificate-ingress time.
func VerifySubject(claimed [32]byte, r Roots) error {
if BindSubject(r) != claimed {
return errors.New("subject: claimed certificate_subject does not match descriptor roots")
}
return nil
}
// RequireBothChains reports an error if either MChainCeremony or
// FChainFHE is zero — the LP-1340 invariant that every round binds
// **both** chain roots, even on rounds where one chain does not
// finalize a ceremony (the unchanged root from the previous round
// satisfies the binding).
func (r Roots) RequireBothChains() error {
if r.MChainCeremony == ([32]byte{}) {
return errors.New("subject: mchain_ceremony_root is zero — boot-time root not yet wired")
}
if r.FChainFHE == ([32]byte{}) {
return errors.New("subject: fchain_fhe_root is zero — boot-time root not yet wired")
}
return nil
}