mirror of
https://github.com/luxfi/crypto.git
synced 2026-07-27 01:54:50 +00:00
luxfi/crypto becomes the single Go entry point for ALL Lux-family crypto. Every public function in this module now dispatches between three implementations through a runtime-selectable backend: - vanilla: pure-Go reference (always available) - cgo: native binding (blst, libsecp256k1, ckzg) where present - gpu: batch acceleration via github.com/luxfi/accel The dispatcher reads LUX_CRYPTO_BACKEND (auto|vanilla|cgo|gpu); auto picks the most capable backend the binary was compiled and linked with. New canonical packages: backend/ runtime backend selector (env + programmatic) internal/gpuhost/ accel session lifecycle, single per-process keccak/ Keccak-256 with batch GPU dispatch sha256/ SHA-256 with batch GPU dispatch sha3/ SHA3 / SHAKE family ripemd160/ RIPEMD-160 (Bitcoin/Lux address derivation) ed25519/ Ed25519 with batch GPU verify bn254/ canonical alias for bn256 (matches FIPS naming) modexp/ canonical alias for bigmodexp evm256/ EIP-196/197 precompile ABI wrappers poseidon/ Poseidon2 hash via gnark-crypto pedersen/ Pedersen commitments over BN254 ntt/ Number-Theoretic Transform reference polymul/ negacyclic polynomial multiplication Extended existing packages with batch GPU paths: bls/batch.go BatchVerify routes through accel.BLSVerifyBatch mldsa/batch.go BatchVerify (ML-DSA-65) via accel.DilithiumVerifyBatch mlkem/batch.go BatchEncapsulate / BatchDecapsulate via Kyber kernels secp256k1/batch.go BatchVerifySignature via accel.ECDSAVerifyBatch GPU dispatch is gated on (a) backend.Default(), (b) batch size threshold, and (c) accel.Available(). When any gate fails the call falls through to the vanilla CPU path; output is byte-identical. The legacy gpu/ stub is replaced with a thin probe surface (Available, Backend, Devices, Version) that delegates to the same gpuhost session. Tests show vanilla and gpu backends produce identical outputs across all batch entry points (-race clean). See AUDIT.md for the per-algorithm state matrix and honest gaps.
105 lines
2.6 KiB
Go
105 lines
2.6 KiB
Go
package backend
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
func TestParse(t *testing.T) {
|
|
cases := []struct {
|
|
in string
|
|
want Backend
|
|
ok bool
|
|
}{
|
|
{"", Auto, true},
|
|
{"auto", Auto, true},
|
|
{"AUTO", Auto, true},
|
|
{"vanilla", Vanilla, true},
|
|
{"go", Vanilla, true},
|
|
{"pure", Vanilla, true},
|
|
{"cgo", CGo, true},
|
|
{"c", CGo, true},
|
|
{"native", CGo, true},
|
|
{"gpu", GPU, true},
|
|
{"accel", GPU, true},
|
|
{"banana", Auto, false},
|
|
}
|
|
for _, tc := range cases {
|
|
got, ok := Parse(tc.in)
|
|
if got != tc.want || ok != tc.ok {
|
|
t.Errorf("Parse(%q) = (%v, %v); want (%v, %v)", tc.in, got, ok, tc.want, tc.ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDefaultAndSetDefault(t *testing.T) {
|
|
t.Cleanup(func() { SetDefault(Auto) })
|
|
for _, b := range []Backend{Auto, Vanilla, CGo, GPU} {
|
|
SetDefault(b)
|
|
if got := Default(); got != b {
|
|
t.Errorf("after SetDefault(%v) Default() = %v", b, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResolveVanillaAlwaysAvailable(t *testing.T) {
|
|
t.Cleanup(func() { SetDefault(Auto) })
|
|
SetDefault(Auto)
|
|
if got := Resolve(false, false); got != Vanilla {
|
|
t.Fatalf("Resolve(false, false) = %v; want Vanilla", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveAutoPrefersGPU(t *testing.T) {
|
|
t.Cleanup(func() { SetDefault(Auto) })
|
|
SetDefault(Auto)
|
|
if got := Resolve(true, true); got != GPU {
|
|
t.Fatalf("Resolve(true, true) auto = %v; want GPU", got)
|
|
}
|
|
if got := Resolve(false, true); got != CGo {
|
|
t.Fatalf("Resolve(false, true) auto = %v; want CGo", got)
|
|
}
|
|
}
|
|
|
|
func TestResolveExplicitForcesFallback(t *testing.T) {
|
|
t.Cleanup(func() { SetDefault(Auto) })
|
|
SetDefault(GPU)
|
|
if got := Resolve(false, true); got != CGo {
|
|
t.Fatalf("Resolve(false, true) gpu-forced = %v; want CGo (fallback)", got)
|
|
}
|
|
if got := Resolve(false, false); got != Vanilla {
|
|
t.Fatalf("Resolve(false, false) gpu-forced = %v; want Vanilla (fallback)", got)
|
|
}
|
|
SetDefault(CGo)
|
|
if got := Resolve(true, false); got != Vanilla {
|
|
t.Fatalf("Resolve(true, false) cgo-forced = %v; want Vanilla (fallback)", got)
|
|
}
|
|
}
|
|
|
|
func TestStringRoundTrip(t *testing.T) {
|
|
for _, b := range []Backend{Auto, Vanilla, CGo, GPU} {
|
|
got, ok := Parse(b.String())
|
|
if !ok || got != b {
|
|
t.Errorf("round-trip %v: Parse(%q) = (%v, %v)", b, b.String(), got, ok)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestEnvOverride(t *testing.T) {
|
|
// Saved current state.
|
|
prev := Default()
|
|
t.Cleanup(func() { SetDefault(prev) })
|
|
|
|
// We cannot re-trigger init() without process restart; emulate by
|
|
// re-parsing here just like init does.
|
|
t.Setenv("LUX_CRYPTO_BACKEND", "vanilla")
|
|
if v, ok := os.LookupEnv("LUX_CRYPTO_BACKEND"); ok {
|
|
if b, parsed := Parse(v); parsed {
|
|
SetDefault(b)
|
|
}
|
|
}
|
|
if got := Default(); got != Vanilla {
|
|
t.Errorf("env override: Default() = %v; want Vanilla", got)
|
|
}
|
|
}
|