Files
zeekay c649652286 LP-107 Phase 3 (cycle-free): lattice consumes luxfi/math/codec
wire/wire.go — lattice's wire-format hardening boundary. luxfi/math/
codec has no lattice imports so this is a safe one-way dependency.

LatticeConsensusWireLimits (4096 cap, 16 MiB frame) for Pulsar-class
data; LatticeFHEWireLimits (16384 cap, 32 MiB frame) for FHE-class.
ValidateUintSliceFrame routes the chosen Limits to math/codec.Reader.

Phase 3 inversion FULL form (lattice/ring delegating to luxfi/math/
ntt for the canonical NTT body) already landed in main via 26f52514
(modular_reduction shim). This wire/ package is the remaining cycle-
free portion not covered by that shim — codec hardening lives once
in luxfi/math/codec and is now reused uniformly across pulsar, lens,
fhe, AND lattice. The same lattice issue #4 attack input is rejected
identically by all four consumers.

Refiled from #6 (stale go.mod bump to math v1.3.0); main is already
on luxfi/math v1.4.1 (no go.mod change needed).

Tests:
* TestValidateUintSliceFrame_RejectsHugeLength — regression for
  lattice issue #4 attack input (70-trillion-element length).
* TestValidateUintSliceFrame_FHELimits_AcceptsLarger — confirms
  FHE limits accept 8192 (FHE cap 16384), consensus limits reject
  8192 (consensus cap 4096).

GOWORK=off go test ./wire/ → PASS
GOWORK=off go build ./...   → clean
2026-05-17 10:20:04 -07:00

58 lines
1.8 KiB
Go

// Copyright (c) 2026 Lux Industries Inc.
// SPDX-License-Identifier: BSD-3-Clause
package wire
import (
"bytes"
"errors"
"testing"
"github.com/luxfi/math/codec"
)
func encodeUvarint(out *bytes.Buffer, v uint64) {
for v >= 0x80 {
out.WriteByte(byte(v) | 0x80)
v >>= 7
}
out.WriteByte(byte(v))
}
// TestValidateUintSliceFrame_RejectsHugeLength is the regression test
// for lattice issue #4 (Vector[T].ReadFrom unbounded allocation),
// now centralized through luxfi/math/codec.Reader. The lattice repo
// itself can now reject the same attack input class through the
// substrate — completing the LP-107 cycle: pulsar, lens, fhe, AND
// lattice all reject the same byte input identically.
func TestValidateUintSliceFrame_RejectsHugeLength(t *testing.T) {
const huge = uint64(70_368_955_777_453)
var buf bytes.Buffer
encodeUvarint(&buf, huge)
err := ValidateUintSliceFrame(buf.Bytes(), LatticeConsensusWireLimits)
if err == nil {
t.Fatal("ValidateUintSliceFrame returned nil for huge length")
}
if !errors.Is(err, codec.ErrLimitExceeded) {
t.Errorf("err is not ErrLimitExceeded: %v", err)
}
}
func TestValidateUintSliceFrame_FHELimits_AcceptsLarger(t *testing.T) {
// FHE limits accept up to 16384; consensus limits cap at 4096.
// A frame requesting 8192 should pass FHE limits, fail consensus.
var buf bytes.Buffer
encodeUvarint(&buf, 8192)
// Provide payload bytes (not strictly required if reading errors
// before exhausting the buffer, but completeness).
buf.Write(make([]byte, 8192*8))
if err := ValidateUintSliceFrame(buf.Bytes(), LatticeFHEWireLimits); err != nil {
t.Errorf("FHE limits should accept 8192: %v", err)
}
// Same bytes via consensus limits → should reject.
if err := ValidateUintSliceFrame(buf.Bytes(), LatticeConsensusWireLimits); err == nil {
t.Error("consensus limits should reject 8192")
}
}