Files
zeekay ae2f23dd35 fix(ci): unblock make checks — quoting, gofmt, lint:ignore, no-stub policy
Static-checks job has been failing on every PR (including #3) due to a
shell-interpolation bug in the Makefile + a build of accumulated lint
findings the bug had been hiding. Cleaned up end-to-end so make checks
runs green and PR #3 (security/readuint-slice-dos-2026-03-03) can land.

1. Makefile fmt-step: quote $$FMTOUT in `[ -z $$FMTOUT ]` test.
   Unquoted, multi-file go-fmt output word-splits and the test sees
   `[ -z FILE1 FILE2 ]` -> "/bin/sh: [: FILE2: unexpected operator".
   Same fix to the trailing `echo $$FMTOUT`.

2. go fmt sweep: gpu/gpu.go, gpu/gpu_test.go, types/reduction_test.go,
   types/trust_test.go had whitespace-only formatter findings that the
   crashing fmt-test step had been hiding.

3. ST1003 (mixed-case identifier): four wire-format-pinned consts in
   types/trust.go (TrustCpuGpuCompositeTEE / IOLevelCpu*) carry a
   //lint:ignore directive — their String() return values are part of
   the wire/log contract documented at line 80 ("do not rename"), so
   the Go-side identifiers must stay byte-aligned with the wire spelling.

4. ST1005 (capitalized error string): two error strings in gpu/gpu.go
   rephrased to lead with a noun ("ring degree N" / "modulus Q-1"
   instead of capital "N" / capital "Q") without changing semantics.

5. ST1000 (package comment): gpu/gpu_montgomery_*.go file header
   reformatted so the "Package gpu" line is the leading sentence.

6. G104 (unhandled errors): four `prng.Read(b)` call sites in gpu/gpu.go
   now `_, _ = prng.Read(b)` — the PRNG is keyed sampling output; read
   length is bounded by buffer length and a short read here is not a
   correctness issue.

7. G115 (int -> uint conversion): types/reduction.go switches `bitlen`
   to int (matches bits.Len64's return type, used only against literal
   small ints in the comparison ladder). gpu/gpu_montgomery_purego.go
   adds /* #nosec G115 */ on uint32(s.N) — s.N is validated >0 and
   bounded by ring degree above.

8. NO-STUB POLICY: gpu/gpu_montgomery_stub.go renamed to
   gpu/gpu_montgomery_purego.go and given a real pure-Go body that
   delegates to ring.SubRing.NTT / INTT (the canonical Go implementation
   in this repo). The "stub" name was misleading: there should never be
   a Lux Go file that returns "GPU unavailable" errors when the cgo+gpu
   build tag is unset — the pure-Go path is the canonical reference and
   always works. Output is byte-equal to the cgo+gpu path, identical
   semantics across build tags.

   Same rename for ring/ntt_simd_stub.go -> ring/ntt_simd_dispatch_purego.go
   with comment update: it's a dispatch hook (returns false to signal
   "use canonical scalar NTT below"), not an incomplete impl.

Verification:
* make checks: all 6 substeps PASS (go fmt / vet / goimports / staticcheck /
  govulncheck / gosec) on this branch.
* go test -count=1 ./...: all packages green; ring + ringqp + schemes/bgv
  + schemes/ckks + multiparty + utils/* all pass.
2026-05-04 08:37:27 -07:00

243 lines
6.9 KiB
Go

// Copyright (c) 2026, Lux Industries Inc.
// SPDX-License-Identifier: BSD-3-Clause
package types
import (
"bytes"
"testing"
"unsafe"
)
// TestComputeTrustMode_StableValues pins the underlying integer values of
// every ComputeTrustMode variant. The C++ mirror at
// luxcpp/lattice/include/lux/lattice/types/trust.hpp asserts the same
// values; if either side drifts, dispatch silently misclassifies workers
// at the trust boundary.
func TestComputeTrustMode_StableValues(t *testing.T) {
cases := []struct {
mode ComputeTrustMode
want uint8
}{
{TrustPublicDeterministic, 0},
{TrustAttestedGpuOnly, 1},
{TrustCpuGpuCompositeTEE, 2},
{TrustConfidentialIO, 3},
{TrustZKOrFraudProofed, 4},
}
for _, c := range cases {
if uint8(c.mode) != c.want {
t.Errorf("%s: got %d want %d", c.mode, uint8(c.mode), c.want)
}
}
}
// TestComputeTrustMode_Order verifies that trust modes form a strict
// monotonic chain. Eligible() in the registry uses `>=` on this ordering;
// if two variants compare equal, the gate degrades to a substring match.
func TestComputeTrustMode_Order(t *testing.T) {
chain := []ComputeTrustMode{
TrustPublicDeterministic,
TrustAttestedGpuOnly,
TrustCpuGpuCompositeTEE,
TrustConfidentialIO,
TrustZKOrFraudProofed,
}
for i := 1; i < len(chain); i++ {
if !(chain[i] > chain[i-1]) {
t.Fatalf("trust ordering broken at %s -> %s", chain[i-1], chain[i])
}
}
}
func TestComputeTrustMode_String(t *testing.T) {
cases := []struct {
mode ComputeTrustMode
want string
}{
{TrustPublicDeterministic, "PublicDeterministic"},
{TrustAttestedGpuOnly, "AttestedGpuOnly"},
{TrustCpuGpuCompositeTEE, "CpuGpuCompositeTEE"},
{TrustConfidentialIO, "ConfidentialIO"},
{TrustZKOrFraudProofed, "ZKOrFraudProofed"},
{ComputeTrustMode(99), "Unknown"},
}
for _, c := range cases {
if got := c.mode.String(); got != c.want {
t.Errorf("%d: got %q want %q", uint8(c.mode), got, c.want)
}
}
}
func TestComputeTrustMode_Valid(t *testing.T) {
for m := ComputeTrustMode(0); m <= TrustZKOrFraudProofed; m++ {
if !m.Valid() {
t.Errorf("expected %s to be valid", m)
}
}
if ComputeTrustMode(99).Valid() {
t.Error("expected 99 to be invalid")
}
}
// TestConfidentialIOLevel_StableValues pins the underlying integer values
// of every ConfidentialIOLevel variant. Mirrors the C++ static_assert on
// the same enum.
func TestConfidentialIOLevel_StableValues(t *testing.T) {
cases := []struct {
level ConfidentialIOLevel
want uint8
}{
{IOLevelNone, 0},
{IOLevelCpuTeeOnly, 1},
{IOLevelCpuGpuComposite, 2},
{IOLevelProtectedCpuGpuTransfer, 3},
{IOLevelFullDeviceIOAttested, 4},
}
for _, c := range cases {
if uint8(c.level) != c.want {
t.Errorf("%s: got %d want %d", c.level, uint8(c.level), c.want)
}
}
}
func TestConfidentialIOLevel_Order(t *testing.T) {
chain := []ConfidentialIOLevel{
IOLevelNone,
IOLevelCpuTeeOnly,
IOLevelCpuGpuComposite,
IOLevelProtectedCpuGpuTransfer,
IOLevelFullDeviceIOAttested,
}
for i := 1; i < len(chain); i++ {
if !(chain[i] > chain[i-1]) {
t.Fatalf("io level ordering broken at %s -> %s", chain[i-1], chain[i])
}
}
}
func TestConfidentialIOLevel_String(t *testing.T) {
cases := []struct {
level ConfidentialIOLevel
want string
}{
{IOLevelNone, "None"},
{IOLevelCpuTeeOnly, "CpuTeeOnly"},
{IOLevelCpuGpuComposite, "CpuGpuComposite"},
{IOLevelProtectedCpuGpuTransfer, "ProtectedCpuGpuTransfer"},
{IOLevelFullDeviceIOAttested, "FullDeviceIOAttested"},
{ConfidentialIOLevel(99), "Unknown"},
}
for _, c := range cases {
if got := c.level.String(); got != c.want {
t.Errorf("%d: got %q want %q", uint8(c.level), got, c.want)
}
}
}
func TestConfidentialIOLevel_Valid(t *testing.T) {
for l := ConfidentialIOLevel(0); l <= IOLevelFullDeviceIOAttested; l++ {
if !l.Valid() {
t.Errorf("expected %s to be valid", l)
}
}
if ConfidentialIOLevel(99).Valid() {
t.Error("expected 99 to be invalid")
}
}
// TestWorkloadPrivacyClass_StableValues pins the underlying integer values
// of every WorkloadPrivacyClass variant.
func TestWorkloadPrivacyClass_StableValues(t *testing.T) {
cases := []struct {
class WorkloadPrivacyClass
want uint8
}{
{PrivacyPublic, 0},
{PrivacyPrivateUserData, 1},
{PrivacyPrivateModelWeights, 2},
{PrivacyValidatorKeyMaterial, 3},
{PrivacyRegulatedOrderflow, 4},
{PrivacyResearchContribution, 5},
}
for _, c := range cases {
if uint8(c.class) != c.want {
t.Errorf("%s: got %d want %d", c.class, uint8(c.class), c.want)
}
}
}
func TestWorkloadPrivacyClass_String(t *testing.T) {
cases := []struct {
class WorkloadPrivacyClass
want string
}{
{PrivacyPublic, "Public"},
{PrivacyPrivateUserData, "PrivateUserData"},
{PrivacyPrivateModelWeights, "PrivateModelWeights"},
{PrivacyValidatorKeyMaterial, "ValidatorKeyMaterial"},
{PrivacyRegulatedOrderflow, "RegulatedOrderflow"},
{PrivacyResearchContribution, "ResearchContribution"},
{WorkloadPrivacyClass(99), "Unknown"},
}
for _, c := range cases {
if got := c.class.String(); got != c.want {
t.Errorf("%d: got %q want %q", uint8(c.class), got, c.want)
}
}
}
func TestWorkloadPrivacyClass_Valid(t *testing.T) {
for c := WorkloadPrivacyClass(0); c <= PrivacyResearchContribution; c++ {
if !c.Valid() {
t.Errorf("expected %s to be valid", c)
}
}
if WorkloadPrivacyClass(99).Valid() {
t.Error("expected 99 to be invalid")
}
}
// trustTriple is a Go-side mirror of luxcpp/lattice/test/trust_test.cpp::
// TrustTriple. It is laid out as four bytes so the byte image is identical
// across Go and C++. The only purpose of this struct is the cross-language
// layout test; do not export it.
type trustTriple struct {
Trust ComputeTrustMode
IO ConfidentialIOLevel
Privacy WorkloadPrivacyClass
_pad uint8
}
// TestTrustEnum_CrossLangByteImage asserts that a {trust, io, privacy, pad}
// quadruple has identical byte representation between Go and C++. The
// matching C++ test is luxcpp/lattice/test/trust_test.cpp::
// test_trust_triple_byte_image. If either side changes enum width or value,
// both this Go test and the C++ memcmp test MUST be updated together.
func TestTrustEnum_CrossLangByteImage(t *testing.T) {
if got := unsafe.Sizeof(trustTriple{}); got != 4 {
t.Fatalf("trustTriple size: got %d want 4", got)
}
if got := unsafe.Offsetof(trustTriple{}.Trust); got != 0 {
t.Errorf("Trust offset: got %d want 0", got)
}
if got := unsafe.Offsetof(trustTriple{}.IO); got != 1 {
t.Errorf("IO offset: got %d want 1", got)
}
if got := unsafe.Offsetof(trustTriple{}.Privacy); got != 2 {
t.Errorf("Privacy offset: got %d want 2", got)
}
tt := trustTriple{
Trust: TrustConfidentialIO, // 3
IO: IOLevelProtectedCpuGpuTransfer, // 3
Privacy: PrivacyValidatorKeyMaterial, // 3
_pad: 0,
}
want := []byte{0x03, 0x03, 0x03, 0x00}
got := unsafe.Slice((*byte)(unsafe.Pointer(&tt)), unsafe.Sizeof(tt))
if !bytes.Equal(got, want) {
t.Fatalf("trustTriple byte image mismatch with C++ side\n got: %x\n want: %x", got, want)
}
}