mirror of
https://github.com/luxfi/fhe.git
synced 2026-07-26 23:16:08 +00:00
LP-107 Phase 5: fhe consumes luxfi/math/codec
wire/wire.go — fhe's wire-format hardening boundary. FHE wire formats nest deeper than pulsar's (CKKS ciphertext = Vec<Poly> over RNS chain of Vec<u64>) so MaxDepth = 5 + larger MaxFrameBytes (32 MiB) reflect the deeper polynomial structure. Tests: * TestValidateCiphertextFrame_RejectsHugeLength — regression for lattice issue #4 attack input class. Same substrate, same rejection. * TestValidateCiphertextFrame_OverCap — MaxFHESliceLen+1 rejected. go.mod adds luxfi/math v1.3.0 dependency. This completes Phase 5 of LP-107: every Lux Go protocol repo (pulsar, lens, fhe, lattice) now consumes the math substrate for bounded wire decoding. The same lattice issue #4 attack input is rejected identically across all four consumers.
This commit is contained in:
@@ -6,7 +6,8 @@ require (
|
|||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/hanzoai/base v0.39.1
|
github.com/hanzoai/base v0.39.1
|
||||||
github.com/luxfi/database v1.17.44
|
github.com/luxfi/database v1.17.44
|
||||||
github.com/luxfi/lattice/v7 v7.0.0
|
github.com/luxfi/lattice/v7 v7.1.0
|
||||||
|
github.com/luxfi/math v1.3.0
|
||||||
github.com/luxfi/mdns v0.1.0
|
github.com/luxfi/mdns v0.1.0
|
||||||
github.com/luxfi/metric v1.5.0
|
github.com/luxfi/metric v1.5.0
|
||||||
github.com/spf13/cobra v1.10.2
|
github.com/spf13/cobra v1.10.2
|
||||||
@@ -55,7 +56,6 @@ require (
|
|||||||
github.com/luxfi/crypto v1.17.45 // indirect
|
github.com/luxfi/crypto v1.17.45 // indirect
|
||||||
github.com/luxfi/ids v1.2.9 // indirect
|
github.com/luxfi/ids v1.2.9 // indirect
|
||||||
github.com/luxfi/log v1.4.1 // indirect
|
github.com/luxfi/log v1.4.1 // indirect
|
||||||
github.com/luxfi/math v1.2.3 // indirect
|
|
||||||
github.com/luxfi/math/big v0.1.0 // indirect
|
github.com/luxfi/math/big v0.1.0 // indirect
|
||||||
github.com/luxfi/mock v0.1.1 // indirect
|
github.com/luxfi/mock v0.1.1 // indirect
|
||||||
github.com/luxfi/zapdb/v4 v4.9.3 // indirect
|
github.com/luxfi/zapdb/v4 v4.9.3 // indirect
|
||||||
@@ -79,7 +79,7 @@ require (
|
|||||||
go.temporal.io/api v1.62.6 // indirect
|
go.temporal.io/api v1.62.6 // indirect
|
||||||
go.temporal.io/sdk v1.41.1 // indirect
|
go.temporal.io/sdk v1.41.1 // indirect
|
||||||
go.uber.org/mock v0.6.0 // indirect
|
go.uber.org/mock v0.6.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a // indirect
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 // indirect
|
||||||
golang.org/x/image v0.38.0 // indirect
|
golang.org/x/image v0.38.0 // indirect
|
||||||
golang.org/x/mod v0.34.0 // indirect
|
golang.org/x/mod v0.34.0 // indirect
|
||||||
golang.org/x/net v0.52.0 // indirect
|
golang.org/x/net v0.52.0 // indirect
|
||||||
|
|||||||
@@ -115,12 +115,12 @@ github.com/luxfi/geth v1.16.69 h1:CHO6xTZ+A+3itk94ts4uyVRJajNVP3RxWTjJp5qGOlk=
|
|||||||
github.com/luxfi/geth v1.16.69/go.mod h1:8eEO1hW5sa6OH2VeCMaCPnRz28JBxFvCPBCWPLsU2ck=
|
github.com/luxfi/geth v1.16.69/go.mod h1:8eEO1hW5sa6OH2VeCMaCPnRz28JBxFvCPBCWPLsU2ck=
|
||||||
github.com/luxfi/ids v1.2.9 h1:+yjdhXW99drnd2Zlp1u/p8k3G23W3/1btJQ4ogHawUI=
|
github.com/luxfi/ids v1.2.9 h1:+yjdhXW99drnd2Zlp1u/p8k3G23W3/1btJQ4ogHawUI=
|
||||||
github.com/luxfi/ids v1.2.9/go.mod h1:khJOEdOPxd22yn0jcVrnbX1ADa0GHn5Y74gvCzN5BYc=
|
github.com/luxfi/ids v1.2.9/go.mod h1:khJOEdOPxd22yn0jcVrnbX1ADa0GHn5Y74gvCzN5BYc=
|
||||||
github.com/luxfi/lattice/v7 v7.0.0 h1:d1vgan6mlb2KtwYfPc1g69uxVYaoVYZmlrIm4aCO88w=
|
github.com/luxfi/lattice/v7 v7.1.0 h1:mr3HvN6olNTS2LT/xAW/JBhTqfvpsGmsopDMeR7BSJs=
|
||||||
github.com/luxfi/lattice/v7 v7.0.0/go.mod h1:PFDdOkuGTQ0cbJMbKojzEJMGWUQmZW+wK9/wJ9F9fOs=
|
github.com/luxfi/lattice/v7 v7.1.0/go.mod h1:IaaUN+3ysnBG4BA8ILRYG0j80+qtYDP4C5lkaDb2pDE=
|
||||||
github.com/luxfi/log v1.4.1 h1:rIfFRodb9jrD/w7KayaUk0Oc+37PaQQdKEEMJCjR8gw=
|
github.com/luxfi/log v1.4.1 h1:rIfFRodb9jrD/w7KayaUk0Oc+37PaQQdKEEMJCjR8gw=
|
||||||
github.com/luxfi/log v1.4.1/go.mod h1:64IE3xRMJcpkQwnPUfJw3pDj7wU0kRS7BZ9wM7R72jk=
|
github.com/luxfi/log v1.4.1/go.mod h1:64IE3xRMJcpkQwnPUfJw3pDj7wU0kRS7BZ9wM7R72jk=
|
||||||
github.com/luxfi/math v1.2.3 h1:BgvIFw/srPXFLbcqtoDhLJOfmBsn86GPA1iWgsoyUb4=
|
github.com/luxfi/math v1.3.0 h1:KfHzmsVs4Xfcc3G8PaXotzHk0vkRpUdAna1/RXa9caM=
|
||||||
github.com/luxfi/math v1.2.3/go.mod h1:C8STnF2H+D6rqBPt248CiWY2TGuJgdtv/+4UqrT15iM=
|
github.com/luxfi/math v1.3.0/go.mod h1:VoHe/+0yRPNS0ouzMhCPh5ky+myqjVrrBq4qEXFBSGs=
|
||||||
github.com/luxfi/math/big v0.1.0 h1:Vz4c0RsZVPdIKPsHPgAJChH/R3p15WHRUz7LkLf+NIQ=
|
github.com/luxfi/math/big v0.1.0 h1:Vz4c0RsZVPdIKPsHPgAJChH/R3p15WHRUz7LkLf+NIQ=
|
||||||
github.com/luxfi/math/big v0.1.0/go.mod h1:BuxSu22RbO93xBLk5Eam5nldFponoJ73xDFz4uJ3Huk=
|
github.com/luxfi/math/big v0.1.0/go.mod h1:BuxSu22RbO93xBLk5Eam5nldFponoJ73xDFz4uJ3Huk=
|
||||||
github.com/luxfi/mdns v0.1.0 h1:VB3mQcETc9j5SY1S6lAgFtuGr/rjWuDgPYnxS+OKWMQ=
|
github.com/luxfi/mdns v0.1.0 h1:VB3mQcETc9j5SY1S6lAgFtuGr/rjWuDgPYnxS+OKWMQ=
|
||||||
@@ -204,8 +204,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
||||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
||||||
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a h1:ovFr6Z0MNmU7nH8VaX5xqw+05ST2uO1exVfZPVqRC5o=
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90 h1:jiDhWWeC7jfWqR9c/uplMOqJ0sbNlNWv0UkzE0vX1MA=
|
||||||
golang.org/x/exp v0.0.0-20260212183809-81e46e3db34a/go.mod h1:K79w1Vqn7PoiZn+TkNpx3BUWUQksGO3JcVX6qIjytmA=
|
golang.org/x/exp v0.0.0-20260312153236-7ab1446f8b90/go.mod h1:xE1HEv6b+1SCZ5/uscMRjUBKtIxworgEcEi+/n9NQDQ=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
|
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
|
||||||
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
|
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
// Package wire is fhe's wire-format hardening boundary.
|
||||||
|
//
|
||||||
|
// LP-107 Phase 5: fhe consumes luxfi/math/codec for bounded
|
||||||
|
// decoding of FHE ciphertext / key / param-pack frames. FHE wire
|
||||||
|
// formats nest more deeply than pulsar's lattice frames (a CKKS
|
||||||
|
// ciphertext is a Vec<Poly> over an RNS chain of Vec<u64>; an
|
||||||
|
// EvaluationKey is a tuple of those), so the bounded depth + size
|
||||||
|
// caps in luxfi/math/codec are essential.
|
||||||
|
package wire
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/luxfi/math/codec"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MaxFHESliceLen — FHE caps. PN11QP54 ring is 2048 coeffs/poly with
|
||||||
|
// up to ~10 levels in the RNS chain; 4096 is generous headroom.
|
||||||
|
const MaxFHESliceLen = 4096
|
||||||
|
|
||||||
|
// FHEWireLimits is the codec.Limits configuration FHE uses for
|
||||||
|
// every untrusted-input frame.
|
||||||
|
var FHEWireLimits = codec.Limits{
|
||||||
|
MaxFrameBytes: 32 * 1024 * 1024, // 32 MiB — accommodates EvaluationKey
|
||||||
|
MaxUint16SliceLen: MaxFHESliceLen,
|
||||||
|
MaxUint32SliceLen: MaxFHESliceLen,
|
||||||
|
MaxUint64SliceLen: MaxFHESliceLen,
|
||||||
|
MaxDepth: 5, // Vec<Poly> + Poly + RNS-Vec<u64> + scheme + chain
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateCiphertextFrame walks the outer length prefix of an FHE
|
||||||
|
// ciphertext wire frame. Returns an error wrapping codec.ErrLimitExceeded
|
||||||
|
// when the cap is exceeded.
|
||||||
|
//
|
||||||
|
// The bounded reader rejects the lattice issue #4 attack input class
|
||||||
|
// (huge varint length) before any allocation, sharing the substrate's
|
||||||
|
// hardening with pulsar and lens.
|
||||||
|
func ValidateCiphertextFrame(frame []byte) error {
|
||||||
|
r, err := codec.NewReader(bytes.NewReader(frame), FHEWireLimits)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("fhe/wire: NewReader: %w", err)
|
||||||
|
}
|
||||||
|
if _, err := r.ReadUint64Slice(); err != nil {
|
||||||
|
return fmt.Errorf("fhe/wire: outer length: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
||||||
|
// See the file LICENSE for licensing terms.
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateCiphertextFrame_RejectsHugeLength(t *testing.T) {
|
||||||
|
const huge = uint64(70_368_955_777_453)
|
||||||
|
var buf bytes.Buffer
|
||||||
|
encodeUvarint(&buf, huge)
|
||||||
|
err := ValidateCiphertextFrame(buf.Bytes())
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("ValidateCiphertextFrame returned nil for huge length")
|
||||||
|
}
|
||||||
|
if !errors.Is(err, codec.ErrLimitExceeded) {
|
||||||
|
t.Errorf("err is not ErrLimitExceeded: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateCiphertextFrame_OverCap(t *testing.T) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
encodeUvarint(&buf, uint64(MaxFHESliceLen+1))
|
||||||
|
err := ValidateCiphertextFrame(buf.Bytes())
|
||||||
|
if !errors.Is(err, codec.ErrLimitExceeded) {
|
||||||
|
t.Errorf("err is not ErrLimitExceeded: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user