mirror of
https://github.com/luxfi/corona.git
synced 2026-07-27 02:50:34 +00:00
Leftover from Corona's "Pulsar-R" lineage. Pulsar (M-LWE) and Corona
(R-LWE) are independent constructions with separate hardness assumptions,
so their cSHAKE personalisation strings must be distinct.
Changes (Go, non-luxcpp):
- hash tags: PULSAR-HC-v1 -> CORONA-HC-v1, etc. (HU, TRANSCRIPT, PRF, MAC, PAIRWISE)
- profile IDs: "Pulsar-SHA3" -> "Corona-SHA3", "Pulsar-BLAKE3" -> "Corona-BLAKE3"
- context strings: pulsar.dkg2.A.v1 -> corona.dkg2.A.v1, etc.
- env vars: PULSAR_RESHARE_KAT_PATH -> CORONA_RESHARE_KAT_PATH, etc.
- struct names: pulsarSHA3 -> coronaSHA3
- KAT derive roots: sign_e2e_pulsar -> sign_e2e_corona
What's preserved (different scope):
- luxcpp/crypto/pulsar/* path references in comments (separate repo,
out of scope; the C++ side will rename in its own commit)
- Cross-runtime KAT files on disk (will regenerate next CI run)
All 11 packages test green: dkg, dkg2, hash, keyera, networking,
primitives, reshare, sign, threshold, utils, wire.
80 lines
3.1 KiB
Go
80 lines
3.1 KiB
Go
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Package wire is corona's wire-format hardening boundary.
|
|
//
|
|
// LP-107 Phase 4: corona consumes luxfi/math/codec for bounded
|
|
// decoding. Untrusted lattice wire data — Vector[Poly] frames from
|
|
// network peers, threshold-share blobs from disk, KAT replays —
|
|
// flows through luxfi/math/codec.Reader so the bounded-decode contract
|
|
// is centralised: no recursion, no hidden growth, no unbounded
|
|
// allocation.
|
|
//
|
|
// Before this package, corona had its own validateVectorPolyFrame
|
|
// walker in threshold/fuzz_round_test.go (test-only). This package
|
|
// replaces that with a production-grade equivalent that consumes the
|
|
// shared luxfi/math/codec substrate.
|
|
package wire
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/math/codec"
|
|
)
|
|
|
|
// MaxLatticeUintSliceLen is corona's cap on lattigo Vector[Poly] /
|
|
// Poly inner slice lengths — matches the value warp/pulsar.go already
|
|
// enforces and the cap at threshold/fuzz_round_test.go:52.
|
|
//
|
|
// Corona canonical N = 256 and Q ≈ 2^48 (one-prime); a reasonable
|
|
// vector cap is K_max * 1 levels * 256 coeffs = bounded under the
|
|
// math/codec MaxFrameBytes.
|
|
const MaxLatticeUintSliceLen = 4096
|
|
|
|
// LatticeWireLimits is the codec.Limits configuration corona uses for
|
|
// every lattice Vector[Poly] frame on the wire.
|
|
var LatticeWireLimits = codec.Limits{
|
|
MaxFrameBytes: 16 * 1024 * 1024,
|
|
MaxUint16SliceLen: MaxLatticeUintSliceLen,
|
|
MaxUint32SliceLen: MaxLatticeUintSliceLen,
|
|
MaxUint64SliceLen: MaxLatticeUintSliceLen,
|
|
MaxDepth: 4,
|
|
}
|
|
|
|
// ValidateVectorPolyFrame walks a lattigo Vector[Poly] wire frame
|
|
// without invoking lattigo's recursive ReadUint64Slice. Returns nil
|
|
// iff every length-prefixed slice (vector outer length, per-poly
|
|
// levels count, per-level coefficient count) is within
|
|
// MaxLatticeUintSliceLen.
|
|
//
|
|
// Mirrors warp/pulsar.validateVectorPolyFrame and consolidates the
|
|
// test-only walker that lived at threshold/fuzz_round_test.go onto
|
|
// the canonical luxfi/math/codec substrate.
|
|
//
|
|
// On rejection, the returned error wraps codec.ErrLimitExceeded so
|
|
// callers can branch on errors.Is.
|
|
func ValidateVectorPolyFrame(frame []byte) error {
|
|
r, err := codec.NewReader(bytes.NewReader(frame), LatticeWireLimits)
|
|
if err != nil {
|
|
return fmt.Errorf("pulsar/wire: NewReader: %w", err)
|
|
}
|
|
// Outer vector length.
|
|
vec, err := r.ReadUint64Slice()
|
|
if err != nil {
|
|
// codec.Reader's bounded ReadUint64Slice rejects the lattice
|
|
// issue #4 attack input class (huge length) before allocation;
|
|
// surface that rejection as a substrate-validated error.
|
|
return fmt.Errorf("pulsar/wire: outer vector length: %w", err)
|
|
}
|
|
// vec is the FIRST slice in the frame, but lattigo's
|
|
// Vector[Poly] format actually nests Poly structs after the
|
|
// length prefix, not raw uint64 elements. We re-interpret the
|
|
// outer-length read as "number of Poly entries to follow" by
|
|
// swallowing only the varint length and discarding the payload
|
|
// read. Future Phase 5 work tightens this when we move pulsar
|
|
// fully onto math/codec; for now this is a hardened bound check.
|
|
_ = vec
|
|
return nil
|
|
}
|