mirror of
https://github.com/luxfi/precompile.git
synced 2026-07-27 03:33:45 +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.
ML-KEM Precompile
Post-quantum key encapsulation mechanism precompile implementing FIPS 203 (ML-KEM).
Address
0x0200000000000000000000000000000000000007
Specification
See LP-4318: ML-KEM Post-Quantum Key Encapsulation
Operations
Encapsulate (0x01)
Generate a shared secret and ciphertext from a public key.
Input:
| Offset | Size | Description |
|---|---|---|
| 0 | 1 | Operation (0x01) |
| 1 | 1 | Mode (0x00=512, 0x01=768, 0x02=1024) |
| 2 | varies | Public key |
Output:
| Offset | Size | Description |
|---|---|---|
| 0 | varies | Ciphertext |
| varies | 32 | Shared secret |
Decapsulate (0x02)
Recover the shared secret from a ciphertext using a private key.
Input:
| Offset | Size | Description |
|---|---|---|
| 0 | 1 | Operation (0x02) |
| 1 | 1 | Mode (0x00=512, 0x01=768, 0x02=1024) |
| 2 | varies | Private key |
| varies | varies | Ciphertext |
Output:
| Offset | Size | Description |
|---|---|---|
| 0 | 32 | Shared secret |
Key Sizes
| Mode | Public Key | Private Key | Ciphertext | Shared Secret |
|---|---|---|---|---|
| ML-KEM-512 | 800 | 1632 | 768 | 32 |
| ML-KEM-768 | 1184 | 2400 | 1088 | 32 |
| ML-KEM-1024 | 1568 | 3168 | 1568 | 32 |
Gas Costs
| Operation | ML-KEM-512 | ML-KEM-768 | ML-KEM-1024 |
|---|---|---|---|
| Encapsulate | 50,000 | 75,000 | 100,000 |
| Decapsulate | 60,000 | 90,000 | 120,000 |
Security Levels
- ML-KEM-512: 128-bit security (NIST Level 1)
- ML-KEM-768: 192-bit security (NIST Level 3) - Recommended
- ML-KEM-1024: 256-bit security (NIST Level 5)
Usage Example (Solidity)
import {MLKEMCaller} from "./IMLKEM.sol";
contract QuantumSecureExchange {
using MLKEMCaller for *;
function establishSecret(bytes calldata recipientPubKey)
external view
returns (bytes memory ciphertext, bytes32 sharedSecret)
{
return MLKEMCaller.encapsulate768(recipientPubKey);
}
function recoverSecret(
bytes calldata privateKey,
bytes calldata ciphertext
) external view returns (bytes32 sharedSecret) {
return MLKEMCaller.decapsulate768(privateKey, ciphertext);
}
}