mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
The pre-2026 adversarial test sized the FHE Mul gas (750_000) against a
30M block gas limit, but the real Lux primary-network C-Chain genesis
gasLimit is 12_000_000 (genesis/configs/mainnet/cchain.json line 16).
At 750k gas/Mul + 12M block limit, 16 Muls fit per tx; at ~78s per Mul
on commodity ARM (Apple M1 Max, measured 2026-06-01), one tx stalls a
validator for >20 minutes against a 2s block-target. Sustained: chain
halt at <0.4 LUX cost.
Fix is two-axis and bench-driven:
1. Re-derive every FHE Gas* constant against measured wall-clock and a
1ms-per-(12_000-gas) calibration. New GasMul = 936_000_000 (78s ×
12k); GasAdd = 180_000_000 (15s × 12k); etc. These exceed the 12M
block-gas-limit, which is the protection: zero Muls fit per block,
so no DoS surface remains.
2. Add an activation gate in fhe.module.Configure that refuses fheConfig
when the chain's effective gasLimit < GasMul × MinSafeGasMulRatio.
The gate uses a new feature-detection interface
contract.FeeConfigReporter (mirrors the StrictPQReporter pattern):
ChainConfigs that implement it engage the gate; those that don't
(cross-chain integrators) remain permissive. The error type is
contract.ErrFHEUnsafeGasLimit.
Tests:
- adversarial_test.go reworked into three explicit fixtures:
TestFHEGasCost_Mul_DoSResistance_{30M_Reference,12M_Mainnet,
20M_PostFeeManager}. Each asserts max ops/block × per-op-ms <= budget.
- module_test.go: 7 activation-gate cases (refuses at 12M/20M/30M;
permits at >= GasMul; permissive without FeeConfigReporter; nil chain
config; wrong config type).
- dos_audit.go + dos_audit_test.go: in-tree cross-precompile DoS audit
table walked by tests at both 12M and 20M gasLimit. ML-DSA, SLH-DSA,
Magnetar, Pulsar, BLS12-381 pairing, ZK Groth16, FROST, CGGMP21, VRF,
HQC, P3Q all measured safe; FHE rows priced out (the activation gate
is what surfaces them explicitly).
- bench_test.go: BenchmarkFHE{Mul,Add}_Uint8 — the canonical
measurement-derivation hooks. Re-run on each arch to regenerate
WallClockMs* constants.
- contract/feeconfig_test.go: 8 cases for RequireGasLimit (no reporter;
nil chainConfig; reporter above/at/below threshold; reporter
abstains; time-aware feeConfigManagerConfig flip; nil block context).
The e2e/fhe_private_auction test was pinning the OLD gas constants
verbatim; updated to assert the bench-derived calibration so a future
constant drift surfaces as test failure rather than silent regression.
NO CAVEAT. Either the gas is sufficient (gasLimit >= GasMul ×
MinSafeGasMulRatio) OR the precompile refuses to activate. The FHE
precompile is currently in the "refuses to activate" regime on real
mainnet C-Chain (gasLimit=12M < 936M required). Recovery is operator-
side: raise gasLimit via feeConfigManagerConfig OR land a faster TFHE
evaluator (see memory/vulkan_tfhe_pbs_fast_path.md — 20.4x landed,
need 78x to close the gap).
55 lines
1.6 KiB
Go
55 lines
1.6 KiB
Go
//go:build cgo
|
|
|
|
// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Benchmark suite measuring real wall-clock per FHE op on commodity hardware.
|
|
// Used to derive gas-cost floors for DoS resistance under realistic mainnet
|
|
// fee config (12M gas limit on Lux C-Chain).
|
|
//
|
|
// Re-run on each target arch to validate the gas-cost re-derivation:
|
|
// go test -run NONE -bench BenchmarkFHE -benchtime=1x ./fhe/...
|
|
|
|
package fhe
|
|
|
|
import (
|
|
"math/big"
|
|
"testing"
|
|
)
|
|
|
|
// BenchmarkFHEMul_Uint8 — schoolbook O(n^2) bootstrapping multiply.
|
|
// On Apple M1 Max (high-end ARM commodity): ~78 s/op. This sets the
|
|
// upper bound on per-op wall-clock and dominates the gas-floor derivation.
|
|
func BenchmarkFHEMul_Uint8(b *testing.B) {
|
|
if err := initTFHE(); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
ctA := tfheTrivialEncrypt(big.NewInt(3), TypeEuint8)
|
|
ctB := tfheTrivialEncrypt(big.NewInt(4), TypeEuint8)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
result := tfheMul(ctA, ctB, TypeEuint8)
|
|
if result == nil {
|
|
b.Fatal("nil result")
|
|
}
|
|
}
|
|
}
|
|
|
|
// BenchmarkFHEAdd_Uint8 — linear bootstrapping add. Two orders of magnitude
|
|
// faster than mul on the same parameters, but still dominated by FHE
|
|
// bootstrap latency.
|
|
func BenchmarkFHEAdd_Uint8(b *testing.B) {
|
|
if err := initTFHE(); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
ctA := tfheTrivialEncrypt(big.NewInt(3), TypeEuint8)
|
|
ctB := tfheTrivialEncrypt(big.NewInt(4), TypeEuint8)
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
result := tfheAdd(ctA, ctB, TypeEuint8)
|
|
if result == nil {
|
|
b.Fatal("nil result")
|
|
}
|
|
}
|
|
}
|