mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
Under the enable-everything precompile policy these verify-only precompiles are no longer refused under strict-PQ, so any divergence between the luxfi/accel GPU/SIMD path and the pure-CPU path is a LIVE consensus split: GPU-equipped and CPU-only validators would return different verify verdicts on the same input and the chain forks. Several accel paths were also outright wrong-primitive forgery surfaces. LAW applied: the GPU verdict must be byte-identical to the CPU verdict on every input, or the accel path is a consensus hazard and is removed. CPU (pure-Go, CGO_ENABLED=0) is now the single source of truth for every on-chain verdict. None of these GPU kernels can be proven byte-identical here, and several are provably NOT, so every verdict-trusting accel branch is deleted and routed to the canonical CPU verifier. Determinism over speed. Active forgery/wrong-output in the DEFAULT build (accelcrypto CPU fallback leaked non-CPU semantics, err==nil): - sr25519: verified via the accel Ed25519 kernel -> a valid Ed25519 signature was ACCEPTED as a valid sr25519/Schnorrkel signature (wrong-curve forgery). - blake3: accelcrypto.Hash(HashBlake3) returns BLAKE2b, not BLAKE3; the "real blake3" fallback was dead code. OpHash256 + MerkleRoot emitted BLAKE2b. Latent splits (reachable only under -tags accel + a GPU backend): - frost: FROST-Schnorr verified through the SigECDSA kernel (wrong primitive + 32B x-only key mis-framed as a 33B ECDSA key). - cggmp21: SigECDSA kernel truncated the 65B key to 33B and skipped the CPU path's recover-and-compare binding (ignored the v byte). - ed25519: GPU Ed25519 kernel not proven byte-identical to the canonical verifier on cofactor / non-canonical-S / small-order edge cases. - secp256r1: P-256 inputs sent to the fixed-curve secp256k1 ECDSA kernel. - mldsa: GPU verified with EMPTY context; precompile binds the FIPS-204 ctx "lux-evm-precompile-mldsa-v1" -> different mu, different verdict. - bls12381 / zk(groth16): GPU MSM result trusted without re-verification and with no curve binding carried to the kernel. - kzg4844: GPU commitment used the backend's OWN embedded trusted setup (empty SRS) instead of the canonical EIP-4844 SRS -> breaks KZG binding. - ai_mining (BatchVerifyMLDSA/BatchAccumulator): accel batch kernel truncates messages to 32 bytes and is mode-fixed -> diverges from VerifyMLDSA. - fhe: GPU computed BFV arithmetic while CPU computes TFHE (different scheme, incompatible ciphertext, nil relin key) -> corrupt + divergent ciphertext. Cleanups (no split, vestigial): removed dead mlkem encapsulateGPU; removed the hpke GPU pre-warm that discarded its result and returned the CPU output anyway. slhdsa was already CPU-only (prior identical fix). Tests (differential / forgery proofs, all green CGO_ENABLED=0 and CGO -race): - sr25519: a valid Ed25519 sig is now REJECTED; real sr25519 still verifies. - blake3: OpHash256/MerkleRoot output == BLAKE3 and != BLAKE2b. - cggmp21: flipped recovery byte is rejected (recover-compare authoritative). - frost: a valid ECDSA sig is rejected as FROST-Schnorr. - ed25519: verdict matches the canonical ed25519.Verify oracle over 64x4 vectors. - mldsa: empty-ctx sig (the accel framing) rejected; precompileCtx sig accepted. Net -593 LOC. No consensus code touched.
80 lines
2.6 KiB
Go
80 lines
2.6 KiB
Go
// Copyright (C) 2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package blake3
|
|
|
|
import (
|
|
"testing"
|
|
|
|
refblake3 "github.com/luxfi/crypto/hash/blake3"
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/crypto/blake2b"
|
|
)
|
|
|
|
// blake3Ref computes the canonical BLAKE3-256 digest the precompile must emit.
|
|
func blake3Ref(data []byte) []byte {
|
|
h := refblake3.New()
|
|
h.Write(data)
|
|
out := make([]byte, DigestLength32)
|
|
h.Reader().Read(out)
|
|
return out
|
|
}
|
|
|
|
// blake2bRef computes BLAKE2b-256 -- the WRONG digest the removed accel
|
|
// "HashBlake3" path actually returned (accel/ops/crypto/crypto_cpu.go).
|
|
func blake2bRef(data []byte) []byte {
|
|
h, _ := blake2b.New256(nil)
|
|
h.Write(data)
|
|
return h.Sum(nil)
|
|
}
|
|
|
|
// TestBlake3_Hash256IsRealBlake3NotBlake2b is the regression proof for the
|
|
// wrong-hash accel divergence. accelcrypto.Hash(HashBlake3, ...) returned a
|
|
// BLAKE2b digest (its GPU branch has no BLAKE3 kernel and its CPU branch calls
|
|
// blake2b), and -- because accelcrypto.Hash returns a nil error on that CPU
|
|
// fallback -- the precompile's "real BLAKE3" branch was dead code in EVERY
|
|
// build. The OpHash256 output must now be BLAKE3 and must differ from BLAKE2b.
|
|
func TestBlake3_Hash256IsRealBlake3NotBlake2b(t *testing.T) {
|
|
cases := [][]byte{
|
|
{},
|
|
[]byte("abc"),
|
|
[]byte("the quick brown fox jumps over the lazy dog"),
|
|
make([]byte, 1000),
|
|
}
|
|
for _, data := range cases {
|
|
input := append([]byte{OpHash256}, data...)
|
|
gas := Blake3Precompile.RequiredGas(input)
|
|
out, _, err := Blake3Precompile.Run(
|
|
nil, common.Address{}, ContractAddress, input, gas, true,
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
want := blake3Ref(data)
|
|
require.Equal(t, want, out,
|
|
"OpHash256 must output canonical BLAKE3 for len=%d", len(data))
|
|
require.NotEqual(t, blake2bRef(data), out,
|
|
"OpHash256 must NOT output BLAKE2b (the accel divergence) for len=%d", len(data))
|
|
}
|
|
}
|
|
|
|
// TestBlake3_MerkleRootUsesBlake3 proves the Merkle path is BLAKE3 too: the
|
|
// removed accel branch would have built the tree from BLAKE2b node hashes.
|
|
func TestBlake3_MerkleRootUsesBlake3(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
leafA := make([]byte, DigestLength32)
|
|
leafB := make([]byte, DigestLength32)
|
|
for i := range leafA {
|
|
leafA[i] = byte(i)
|
|
leafB[i] = byte(255 - i)
|
|
}
|
|
|
|
got := p.computeMerkleRoot([][]byte{leafA, leafB})
|
|
|
|
// Reference parent = BLAKE3(leafA || leafB).
|
|
want := blake3Ref(append(append([]byte{}, leafA...), leafB...))
|
|
require.Equal(t, want, got, "merkle parent must be BLAKE3(left||right)")
|
|
require.NotEqual(t, blake2bRef(append(append([]byte{}, leafA...), leafB...)), got,
|
|
"merkle parent must NOT be BLAKE2b")
|
|
}
|