mirror of
https://github.com/luxfi/warp.git
synced 2026-10-30 15:13:04 +00:00
Implements the LP-021v2 / LP-105 §"Warp evolution" cross-chain envelope
that carries the Warp 1.x BLS Beam intact alongside transcript-binding
fields and two optional PQ lanes (Pulsar Pulse, ML-DSA cert set).
Wire format: leading 0x02 version byte + RLP-encoded EnvelopeV2 record
binding SourceNebulaRoot, SourceKeyEraID, SourceGeneration, HashSuiteID
(default "Pulsar-SHA3"), plus optional PulsarPulse and MLDSACertSet
lanes. Forward compatibility: ParseEnvelope decodes Warp 1.x bytes into
a v2 envelope with PQ lanes empty. Backward compatibility: v1 receivers
reject v2 bytes (the 0x02 leading byte is not a valid RLP-list prefix);
senders that need to reach v1-only verifiers emit Warp 1.x bytes on the
v1 channel. Replay protection is uniform: EnvelopeV2.ID() returns the
embedded Message.ID().
Verification: VerifyV2 checks structural invariants, hash-suite
consistency, BLS Beam (against the source-chain validator set), then
the optional ML-DSA cert-set and Pulsar Pulse lanes. VerifyPQLanes is
the standalone entrypoint for callers that already verified the Beam
through a separate code path.
Subpackage warp/pulsar holds the Pulse path:
- KernelVerifier consumes a GroupKeyResolver (the destination chain's
source-chain key registry) to fetch the source-chain GroupKey for
a given (KeyEraID, Generation) and verifies the Pulse via the
luxfi/pulsar kernel.
- BuildSigningBytes produces the canonical transcript bytes under the
WARP-PULSAR-ENVELOPE-v1 domain prefix (distinct from any Pulsar
consensus-side prefix to prevent cross-domain replay).
- HorizonFromEnvelope lifts a verified envelope into the LP-105
HorizonCertificate shape consumed by destination consensus / bridge
code.
Pulse byte format wraps the kernel Signature's C / Z / Delta components
in three little-endian length-prefixed frames so DeserializePulse can
dispatch each component into a fresh slice-backed lattigo buffer
(the recommended path for slice-backed reads).
Tests:
- envelope_test.go: roundtrip, optional-field defaulting, forward /
backward / unknown-version dispatch, ID stability, PQ-lane
verifier dispatch (Pulse, CertSet, required-but-absent flags).
- pulsar/pulsar_test.go: real t-of-n Pulsar ceremony, serialize /
deserialize roundtrip, KernelVerifier accept / reject paths
(transcript-tampering rejection, resolver failure, suite mismatch),
BuildSigningBytes binds every transcript field, Horizon assembly.
Module wiring: adds github.com/luxfi/pulsar (replace ../pulsar) and
github.com/luxfi/lattice/v7 to warp/go.mod. Restores the pinned
luxfi/precompile h1: hash so go test ./... resolves cleanly.
Documentation: README.md and SPECIFICATION.md rewritten to describe the
shipping v1.x + v2.0 + v2-Private versions, the dispatch flow, and the
Pulse transcript-binding rules.
LP refs: LP-021 (Warp 1.x), LP-021v2 (this work), LP-073 (Pulsar
kernel), LP-075 (BLS aggregate), LP-105 §"Warp evolution".
All warp tests pass: GOWORK=off go test ./...
135 lines
4.7 KiB
Go
135 lines
4.7 KiB
Go
// Copyright (C) 2019-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// classification.go — Horizon-final / PQ-root-of-trust classification
|
|
// helpers. The post-quantum lane structure is documented in
|
|
// LP-105 ("Lux stack lexicon", Proof-lane classification subsection)
|
|
// and proofs/definitions/finality-definitions.tex Definition
|
|
// ref:proof-lane and Remark ref:groth16-not-pq.
|
|
//
|
|
// Three classification predicates ship here:
|
|
//
|
|
// IsPQFinal(envelope) — true iff the envelope carries enough
|
|
// certificate-lane evidence to be Horizon-final under Prism. A
|
|
// Groth16 wrapper alone is NOT enough; a real Pulse is required.
|
|
//
|
|
// IsPQRootOfTrust(provingSystem) — true iff the named succinct-proof
|
|
// wrapper is post-quantum. Groth16 (pairing-based, broken under
|
|
// Shor) returns false. STARK / lattice-based wrappers return true.
|
|
//
|
|
// HorizonFinalErr(envelope) — returns an error explaining WHY an
|
|
// envelope is not Horizon-final, or nil if it is.
|
|
//
|
|
// These helpers do NOT verify signatures; they classify the envelope
|
|
// SHAPE. Use VerifyV2 / VerifyPQLanes to check the bytes.
|
|
|
|
package pulsar
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
|
|
"github.com/luxfi/warp"
|
|
)
|
|
|
|
// ErrNotHorizonFinal is returned when an envelope cannot be lifted into
|
|
// a Horizon-final certificate. It typically means the envelope is
|
|
// missing one or more of the Beam / ML-DSA / Pulse lanes that Prism
|
|
// requires (Definition ref:prism in finality-definitions.tex).
|
|
var ErrNotHorizonFinal = errors.New("warp pulsar: envelope is not Horizon-final")
|
|
|
|
// IsPQFinal reports whether the envelope carries enough evidence to
|
|
// be Horizon-final under Prism. The required shape, per
|
|
// proofs/definitions/finality-definitions.tex Definition
|
|
// ref:horizon-cert, is:
|
|
//
|
|
// - A v1 Beam (BLS aggregate over the v1 Message). Always present;
|
|
// the v1 Message field is non-nil.
|
|
// - An ML-DSA cert set (either raw FIPS-204 signatures or a
|
|
// compressed Groth16 rollup of those signatures). The shape is
|
|
// the same on the wire.
|
|
// - A Pulsar Pulse — a real lattice threshold signature over the
|
|
// envelope transcript. This is the PQ root of trust; without it
|
|
// the envelope is not Horizon-final, regardless of how impressive
|
|
// the wrapper proof attached to the ML-DSA lane is.
|
|
//
|
|
// In particular: an envelope carrying a Groth16 rollup of ML-DSA
|
|
// verification but no Pulse is NOT Horizon-final. The Groth16 wrapper
|
|
// is a classical compatibility / compression / privacy adapter (see
|
|
// IsPQRootOfTrust below); it does not contribute PQ liveness on its
|
|
// own.
|
|
func IsPQFinal(env *warp.EnvelopeV2) bool {
|
|
if env == nil || env.Message == nil {
|
|
return false
|
|
}
|
|
if !env.HasMLDSACertSet() {
|
|
return false
|
|
}
|
|
if !env.HasPulse() {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
// HorizonFinalErr returns nil when env is Horizon-final-shaped, or
|
|
// ErrNotHorizonFinal wrapping a structured reason string when it is
|
|
// not. Use this in receivers that want to distinguish between
|
|
// "envelope shape OK, signature failed" (returned by VerifyV2) and
|
|
// "envelope shape inadmissible".
|
|
func HorizonFinalErr(env *warp.EnvelopeV2) error {
|
|
if env == nil || env.Message == nil {
|
|
return ErrNotHorizonFinal
|
|
}
|
|
missing := make([]string, 0, 3)
|
|
if !env.HasMLDSACertSet() {
|
|
missing = append(missing, "MLDSACertSet")
|
|
}
|
|
if !env.HasPulse() {
|
|
missing = append(missing, "PulsarPulse")
|
|
}
|
|
if len(missing) > 0 {
|
|
return errors.New("warp pulsar: envelope missing required lanes: " + strings.Join(missing, ", "))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// IsPQRootOfTrust classifies a succinct-proof wrapper system by
|
|
// post-quantum status. Returns true iff the wrapper is BELIEVED to be
|
|
// post-quantum-secure under current cryptanalysis.
|
|
//
|
|
// Classification (per LP-105 Proof-lane classification table and
|
|
// proofs/definitions/finality-definitions.tex Definition
|
|
// ref:proof-lane):
|
|
//
|
|
// "groth16", "groth16-bls12-381", "snark-pairing"
|
|
// → false. Pairing-based; broken under Shor's algorithm.
|
|
//
|
|
// "stark-rescue", "stark-poseidon", "lattice-zk"
|
|
// → true. Hash- or lattice-based; PQ-friendly assumptions.
|
|
//
|
|
// "none" or empty string
|
|
// → true. No wrapper means the underlying signature itself is the
|
|
// evidence; if that signature is Pulsar / ML-DSA, the PQ
|
|
// root-of-trust lives in the signature directly.
|
|
//
|
|
// anything else → false (conservative).
|
|
//
|
|
// The function is case-insensitive on the system name.
|
|
func IsPQRootOfTrust(provingSystem string) bool {
|
|
switch strings.ToLower(strings.TrimSpace(provingSystem)) {
|
|
case "groth16",
|
|
"groth16-bls12-381",
|
|
"snark-pairing":
|
|
return false
|
|
case "stark-rescue",
|
|
"stark-poseidon",
|
|
"lattice-zk":
|
|
return true
|
|
case "none",
|
|
"":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|