mirror of
https://github.com/luxfi/warp.git
synced 2026-10-30 15:13:04 +00:00
Decomplect the PQ finality lanes into a typed, impossible-to-confuse model where
KIND chooses the verifier and SUITE only chooses parameterization (fail-closed on
mismatch). Kills the prior conflation where the corona-backed lattice lane was
mislabeled "Pulse/Pulsar-SHA3".
Four strict evidence kinds — each its own verifier + suite + key registry:
beam-bls BLS12-381 aggregate (fast classical)
pulsar-threshold-mldsa threshold ML-DSA, verified as a STANDARD FIPS-204
ML-DSA signature under a group public key; the TALUS
dealerless machinery is entirely offline (VerifyPulsar
imports only mldsa65 — enforced by an import-hygiene test)
corona-ringtail Ringtail/Module-LWE lattice threshold (the corona kernel)
p3q-mldsa-rollup succinct rollup of independent ML-DSA-65 sigs; strict
ONLY when its proof system is PQ (classical SNARK gated)
Plus the raw mldsa-cert-set as a NON-strict availability/audit artifact.
Subject-agnostic verifiers take (subject, evidence, keyEra): one dispatch serves
the warp cross-chain digest D and the consensus finality subject
M = keccak256("QUASAR_FINALITY_V1" || chainID || height || round || blockID ||
stateRoot || signerSetID || keyEraID || generation || pChainHeight || policyID)
folding generation + pChainHeight + policyID so a signature binds its era, its
validator snapshot, and its tier (tier-downgrade replay fails closed).
Policy tiers (BLS_FAST / HYBRID_PQ_CHECKPOINT / STRICT_QUASAR / RECOVERY) select
which lanes are required — orthogonal to verification and to keys. PulsarKeyEra
and CoronaKeyEra are symmetric but DISTINCT registry types; P3Q/cert-set resolve a
per-validator SignerSetAuthority — no resolver can alias another's key material.
Offline signers (pulsard, coronad, P3Q prover) are interfaces only, never imported
by the verify path.
Wire unchanged: D, the Message c14n, messageDST, the ZAP magic and kind bytes are
byte-identical (forge Go<->Solidity equality holds; golden envelope SHA unchanged).
The corona lane DST is renamed pulseDST->coronaDST (no deployed corona sigs;
envelope KAT regenerated).
22 tests green: non-confusable dispatch, suite/kind fail-closed, Pulsar import
hygiene, subject-identity across lanes, policyID downgrade, key-era distinctness,
P3Q-classical-root strict gate.
268 lines
7.9 KiB
Go
268 lines
7.9 KiB
Go
// Copyright (c) 2025-2026 Lux Industries Inc.
|
|
// SPDX-License-Identifier: BSD-3-Clause-Eco
|
|
//
|
|
// envelope_kat_oracle — emits byte-equal KAT vectors for the Warp ZAP
|
|
// envelope. Drives warp.Envelope through its canonical ZAP
|
|
// serialization (magic "LWZP"||0x01 ‖ kind 0x02 ‖ Message ‖ Beam ‖
|
|
// CoronaSig ‖ MLDSACertSet).
|
|
//
|
|
// Wire format (per entry):
|
|
//
|
|
// name short label
|
|
// network_id Message.NetworkID
|
|
// source_chain_id_hex Message.SourceChainID
|
|
// payload_hex Message.Payload
|
|
// signers_indices Beam (BitSetSignature) signer indices
|
|
// signature_byte Pattern byte filling the 96-byte BLS sig
|
|
// source_nebula_root_hex Message.SourceNebulaRoot ([32]byte)
|
|
// source_key_era_id Message.SourceKeyEraID
|
|
// source_generation Message.SourceGeneration
|
|
// hash_suite_id Message.HashSuiteID ("" or "Pulsar-SHA3")
|
|
// pulsar_pulse_byte Pattern byte filling pulse bytes (0 = absent)
|
|
// pulsar_pulse_len Pulse byte length
|
|
// mldsa_cert_set_byte Pattern byte filling cert set bytes (0 = absent)
|
|
// mldsa_cert_set_len Cert set byte length
|
|
// envelope_wire_hex Full ZAP wire bytes (magic ‖ kind ‖ body)
|
|
// envelope_wire_sha256 sha256 of envelope_wire_hex (port fingerprint)
|
|
// envelope_id_hex Envelope.ID() = D (legacy-keccak)
|
|
//
|
|
// Determinism contract: every entry is byte-identical across hosts /
|
|
// builds / OSes. Cross-language ports consume (network_id,
|
|
// source_chain_id_hex, payload_hex, signers_indices, signature_byte,
|
|
// source_nebula_root_hex, source_key_era_id, source_generation,
|
|
// hash_suite_id, pulsar_pulse_*, mldsa_cert_set_*) and must reproduce
|
|
// envelope_wire_hex bit-for-bit.
|
|
//
|
|
// Output: scripts/kat/envelope_kat.json (path overridable via
|
|
// WARP_ENVELOPE_KAT_PATH or positional arg).
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/luxfi/crypto/bls"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/warp"
|
|
)
|
|
|
|
type Entry struct {
|
|
Name string `json:"name"`
|
|
NetworkID uint32 `json:"network_id"`
|
|
SourceChainIDHex string `json:"source_chain_id_hex"`
|
|
PayloadHex string `json:"payload_hex"`
|
|
SignersIndices []int `json:"signers_indices"`
|
|
SignatureByte byte `json:"signature_byte"`
|
|
SourceNebulaRootHex string `json:"source_nebula_root_hex"`
|
|
SourceKeyEraID uint64 `json:"source_key_era_id"`
|
|
SourceGeneration uint64 `json:"source_generation"`
|
|
HashSuiteID string `json:"hash_suite_id"`
|
|
PulsarPulseByte byte `json:"pulsar_pulse_byte"`
|
|
PulsarPulseLen int `json:"pulsar_pulse_len"`
|
|
MLDSACertSetByte byte `json:"mldsa_cert_set_byte"`
|
|
MLDSACertSetLen int `json:"mldsa_cert_set_len"`
|
|
EnvelopeWireHex string `json:"envelope_wire_hex"`
|
|
EnvelopeWireSHA256 string `json:"envelope_wire_sha256"`
|
|
EnvelopeIDHex string `json:"envelope_id_hex"`
|
|
}
|
|
|
|
type Output struct {
|
|
Spec string `json:"spec"`
|
|
Version string `json:"version"`
|
|
Entries []Entry `json:"entries"`
|
|
}
|
|
|
|
type fixture struct {
|
|
name string
|
|
networkID uint32
|
|
sourceChainID ids.ID
|
|
payload []byte
|
|
signers []int
|
|
signatureByte byte
|
|
sourceNebulaRoot [32]byte
|
|
sourceKeyEraID uint64
|
|
sourceGeneration uint64
|
|
hashSuiteID string
|
|
pulsarPulseByte byte
|
|
pulsarPulseLen int
|
|
mldsaCertSetByte byte
|
|
mldsaCertSetLen int
|
|
}
|
|
|
|
func build(f fixture) Entry {
|
|
message := warp.Message{
|
|
NetworkID: f.networkID,
|
|
SourceChainID: f.sourceChainID,
|
|
SourceNebulaRoot: f.sourceNebulaRoot,
|
|
SourceKeyEraID: f.sourceKeyEraID,
|
|
SourceGeneration: f.sourceGeneration,
|
|
HashSuiteID: f.hashSuiteID,
|
|
Payload: f.payload,
|
|
}
|
|
if err := message.Verify(); err != nil {
|
|
fail(err)
|
|
}
|
|
|
|
sigSet := warp.NewBitSet()
|
|
for _, idx := range f.signers {
|
|
sigSet.Add(idx)
|
|
}
|
|
var sigBytes [bls.SignatureLen]byte
|
|
copy(sigBytes[:], bytes.Repeat([]byte{f.signatureByte}, bls.SignatureLen))
|
|
beam := warp.NewBitSetSignature(sigSet, sigBytes)
|
|
|
|
var pulse []byte
|
|
if f.pulsarPulseLen > 0 {
|
|
pulse = bytes.Repeat([]byte{f.pulsarPulseByte}, f.pulsarPulseLen)
|
|
}
|
|
var cert []byte
|
|
if f.mldsaCertSetLen > 0 {
|
|
cert = bytes.Repeat([]byte{f.mldsaCertSetByte}, f.mldsaCertSetLen)
|
|
}
|
|
|
|
env, err := warp.NewEnvelope(&message, beam, pulse, cert)
|
|
if err != nil {
|
|
fail(err)
|
|
}
|
|
wire, err := env.Bytes()
|
|
if err != nil {
|
|
fail(err)
|
|
}
|
|
wireHash := sha256.Sum256(wire)
|
|
id := env.ID()
|
|
|
|
return Entry{
|
|
Name: f.name,
|
|
NetworkID: f.networkID,
|
|
SourceChainIDHex: hex.EncodeToString(f.sourceChainID[:]),
|
|
PayloadHex: hex.EncodeToString(f.payload),
|
|
SignersIndices: append([]int(nil), f.signers...),
|
|
SignatureByte: f.signatureByte,
|
|
SourceNebulaRootHex: hex.EncodeToString(f.sourceNebulaRoot[:]),
|
|
SourceKeyEraID: f.sourceKeyEraID,
|
|
SourceGeneration: f.sourceGeneration,
|
|
HashSuiteID: f.hashSuiteID,
|
|
PulsarPulseByte: f.pulsarPulseByte,
|
|
PulsarPulseLen: f.pulsarPulseLen,
|
|
MLDSACertSetByte: f.mldsaCertSetByte,
|
|
MLDSACertSetLen: f.mldsaCertSetLen,
|
|
EnvelopeWireHex: hex.EncodeToString(wire),
|
|
EnvelopeWireSHA256: hex.EncodeToString(wireHash[:]),
|
|
EnvelopeIDHex: hex.EncodeToString(id[:]),
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
chainA := ids.ID{0xA1, 0xA2, 0xA3, 0xA4}
|
|
chainB := ids.ID{0xB0, 0xB0, 0xB0, 0xB0}
|
|
nebulaA := [32]byte{0xDE, 0xAD, 0xBE, 0xEF}
|
|
nebulaZero := [32]byte{}
|
|
|
|
out := Output{
|
|
Spec: "Warp-2.0-envelope",
|
|
Version: "v1",
|
|
}
|
|
out.Entries = []Entry{
|
|
build(fixture{
|
|
name: "default-pulse-cert",
|
|
networkID: 1,
|
|
sourceChainID: chainA,
|
|
payload: []byte("envelope-test-payload"),
|
|
signers: []int{0, 2, 4},
|
|
signatureByte: 0xAB,
|
|
sourceNebulaRoot: nebulaA,
|
|
sourceKeyEraID: 7,
|
|
sourceGeneration: 11,
|
|
hashSuiteID: warp.MessageHashProfileTag,
|
|
pulsarPulseByte: 0x42,
|
|
pulsarPulseLen: 64,
|
|
mldsaCertSetByte: 0xC3,
|
|
mldsaCertSetLen: 192,
|
|
}),
|
|
build(fixture{
|
|
name: "no-pulse-no-cert",
|
|
networkID: 1,
|
|
sourceChainID: chainA,
|
|
payload: []byte("envelope-test-payload"),
|
|
signers: []int{0, 2, 4},
|
|
signatureByte: 0xAB,
|
|
sourceNebulaRoot: nebulaZero,
|
|
sourceKeyEraID: 0,
|
|
sourceGeneration: 0,
|
|
hashSuiteID: "",
|
|
pulsarPulseByte: 0,
|
|
pulsarPulseLen: 0,
|
|
mldsaCertSetByte: 0,
|
|
mldsaCertSetLen: 0,
|
|
}),
|
|
build(fixture{
|
|
name: "pulse-only",
|
|
networkID: 2,
|
|
sourceChainID: chainB,
|
|
payload: []byte("pulse-only-payload"),
|
|
signers: []int{1, 3, 5, 7},
|
|
signatureByte: 0x77,
|
|
sourceNebulaRoot: nebulaA,
|
|
sourceKeyEraID: 99,
|
|
sourceGeneration: 1,
|
|
hashSuiteID: warp.MessageHashProfileTag,
|
|
pulsarPulseByte: 0x33,
|
|
pulsarPulseLen: 96,
|
|
mldsaCertSetByte: 0,
|
|
mldsaCertSetLen: 0,
|
|
}),
|
|
build(fixture{
|
|
name: "cert-only",
|
|
networkID: 1,
|
|
sourceChainID: chainA,
|
|
payload: []byte{},
|
|
signers: []int{0},
|
|
signatureByte: 0x11,
|
|
sourceNebulaRoot: nebulaZero,
|
|
sourceKeyEraID: 0,
|
|
sourceGeneration: 0,
|
|
hashSuiteID: warp.MessageHashProfileTag,
|
|
pulsarPulseByte: 0,
|
|
pulsarPulseLen: 0,
|
|
mldsaCertSetByte: 0xEE,
|
|
mldsaCertSetLen: 128,
|
|
}),
|
|
}
|
|
|
|
outPath := filepath.Join(
|
|
os.Getenv("HOME"), "work", "lux", "warp", "scripts", "kat",
|
|
"envelope_kat.json",
|
|
)
|
|
if env := os.Getenv("WARP_ENVELOPE_KAT_PATH"); env != "" {
|
|
outPath = env
|
|
}
|
|
if len(os.Args) >= 2 {
|
|
outPath = os.Args[1]
|
|
}
|
|
if err := os.MkdirAll(filepath.Dir(outPath), 0o755); err != nil {
|
|
fail(err)
|
|
}
|
|
f, err := os.Create(outPath)
|
|
if err != nil {
|
|
fail(err)
|
|
}
|
|
defer f.Close()
|
|
enc := json.NewEncoder(f)
|
|
enc.SetIndent("", " ")
|
|
if err := enc.Encode(out); err != nil {
|
|
fail(err)
|
|
}
|
|
fmt.Fprintf(os.Stderr, "wrote envelope_kat.json (%d entries) → %s\n",
|
|
len(out.Entries), outPath)
|
|
}
|
|
|
|
func fail(err error) {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|