diff --git a/precompile/bls.go b/precompile/bls.go index c8ad974..e473358 100644 --- a/precompile/bls.go +++ b/precompile/bls.go @@ -8,6 +8,7 @@ package precompile import ( "encoding/binary" "errors" + "fmt" "math/big" bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381" @@ -28,6 +29,9 @@ var ( // BLS key operations BLSPublicKeyAggregateAddress = HexToAddress("0x0000000000000000000000000000000000000165") BLSHashToPointAddress = HexToAddress("0x0000000000000000000000000000000000000166") + + // Proof-of-possession + BLSVerifyPoPAddress = HexToAddress("0x0000000000000000000000000000000000000167") ) // Gas costs for BLS operations @@ -39,6 +43,7 @@ const ( blsThresholdCombineGas = 180000 blsPublicKeyAggregateGas = 50000 blsHashToPointGas = 80000 + blsVerifyPoPGas = 150000 // Per-item costs for aggregation blsPerSignatureGas = 30000 @@ -47,6 +52,11 @@ const ( // Point sizes g1Size = 48 g2Size = 96 + + // maxAggregateSigs caps the number of signatures in fast aggregate verify + // to bound gas consumption and prevent abuse. 64 covers any reasonable + // consensus committee size. + maxAggregateSigs = 64 ) // BLSVerify implements single BLS signature verification @@ -128,6 +138,9 @@ func (b *BLSAggregateVerify) Run(input []byte) ([]byte, error) { if numSigs == 0 { return nil, errors.New("no signatures") } + if numSigs > maxAggregateSigs { + return nil, fmt.Errorf("too many signatures: %d > %d", numSigs, maxAggregateSigs) + } // Parse aggregate signature var aggSig bls12381.G2Affine @@ -201,7 +214,13 @@ func (b *BLSAggregateVerify) Run(input []byte) ([]byte, error) { return result, nil } -// BLSFastAggregate verifies aggregate signature with same message +// BLSFastAggregate verifies aggregate signature with same message. +// +// SECURITY: All public keys used in aggregation MUST have a verified +// proof-of-possession (BLSVerifyPoP) before being included. Without PoP, +// an attacker can perform a rogue key attack by choosing a crafted public +// key that cancels out honest participants' keys. Verify PoP on-chain +// before calling this precompile. type BLSFastAggregate struct{} func (b *BLSFastAggregate) RequiredGas(input []byte) uint64 { @@ -222,6 +241,9 @@ func (b *BLSFastAggregate) Run(input []byte) ([]byte, error) { if numKeys == 0 { return nil, errors.New("no public keys") } + if numKeys > maxAggregateSigs { + return nil, fmt.Errorf("too many keys: %d > %d", numKeys, maxAggregateSigs) + } // Parse aggregate signature var aggSig bls12381.G2Affine @@ -540,6 +562,65 @@ func (b *BLSHashToPoint) Run(input []byte) ([]byte, error) { return bytes[:], nil } +// BLSVerifyPoP verifies proof-of-possession for a BLS public key. +// A PoP is a BLS signature over the serialized public key itself, proving the +// holder knows the corresponding secret key. This MUST be verified before any +// key is used in aggregation (BLSFastAggregate, BLSPublicKeyAggregate) to +// prevent rogue key attacks. +type BLSVerifyPoP struct{} + +func (b *BLSVerifyPoP) RequiredGas(input []byte) uint64 { + return blsVerifyPoPGas +} + +func (b *BLSVerifyPoP) Run(input []byte) ([]byte, error) { + // Input: [48 bytes public_key (G1)][96 bytes pop_signature (G2)] + if len(input) < g1Size+g2Size { + return nil, fmt.Errorf("input too short: need %d bytes, got %d", g1Size+g2Size, len(input)) + } + + pubKeyBytes := input[:g1Size] + popBytes := input[g1Size : g1Size+g2Size] + + // Parse public key (G1 point) + var pubKey bls12381.G1Affine + if _, err := pubKey.SetBytes(pubKeyBytes); err != nil { + return nil, errors.New("invalid public key point") + } + + // Parse PoP signature (G2 point) + var popSig bls12381.G2Affine + if _, err := popSig.SetBytes(popBytes); err != nil { + return nil, errors.New("invalid PoP signature point") + } + + // PoP = Sign(sk, pubkey_bytes). Verify by checking the BLS signature + // over the raw public key bytes using that same public key. + msgPoint, err := bls12381.HashToG2(pubKeyBytes, nil) + if err != nil { + return nil, errors.New("hash to curve failed") + } + + // Verify: e(pubKey, H(pubKeyBytes)) == e(G1, popSig) + _, _, g1Gen, _ := bls12381.Generators() + var negG1 bls12381.G1Affine + negG1.Neg(&g1Gen) + + valid, err := bls12381.PairingCheck( + []bls12381.G1Affine{pubKey, negG1}, + []bls12381.G2Affine{msgPoint, popSig}, + ) + if err != nil { + return nil, err + } + + result := make([]byte, 32) + if valid { + result[31] = 0x01 + } + return result, nil +} + // RegisterBLS registers all BLS precompiles func RegisterBLS(registry *Registry) { registry.Register(BLSVerifyAddress, &BLSVerify{}) @@ -549,6 +630,7 @@ func RegisterBLS(registry *Registry) { registry.Register(BLSThresholdCombineAddress, &BLSThresholdCombine{}) registry.Register(BLSPublicKeyAggregateAddress, &BLSPublicKeyAggregate{}) registry.Register(BLSHashToPointAddress, &BLSHashToPoint{}) + registry.Register(BLSVerifyPoPAddress, &BLSVerifyPoP{}) } func init() { diff --git a/precompile/export.go b/precompile/export.go index 4671ddd..a6ea691 100644 --- a/precompile/export.go +++ b/precompile/export.go @@ -8,17 +8,18 @@ import ( // "github.com/luxfi/crypto" // removed to avoid import cycle ) -// GetAllPostQuantumPrecompiles returns all post-quantum precompiles -// This includes SHAKE, Lamport, and the three NIST standards +// GetAllPostQuantumPrecompiles returns all post-quantum and BLS precompiles. +// This includes SHAKE, Lamport, the three NIST standards (verify/encapsulate +// only), and BLS12-381 operations. func GetAllPostQuantumPrecompiles() map[Address]PrecompiledContract { registry := NewRegistry() - // Register all precompile types RegisterSHAKE(registry) RegisterLamport(registry) RegisterMLDSA(registry) RegisterMLKEM(registry) RegisterSLHDSA(registry) + RegisterBLS(registry) return registry.Contracts() } @@ -54,17 +55,19 @@ func Info() map[string]interface{} { "cgo_enabled": EnableCGO(), "standards": []string{ "FIPS 202 (SHAKE)", - "FIPS 203 (ML-KEM)", - "FIPS 204 (ML-DSA)", - "FIPS 205 (SLH-DSA)", + "FIPS 203 (ML-KEM, encapsulate only)", + "FIPS 204 (ML-DSA, verify only)", + "FIPS 205 (SLH-DSA, verify only)", "Lamport OTS", + "BLS12-381", }, "address_ranges": map[string]string{ - "ml_dsa": "0x0110-0x0119", - "ml_kem": "0x0120-0x0129", - "slh_dsa": "0x0130-0x0139", + "ml_dsa": "0x0110-0x0112", + "ml_kem": "0x0120-0x0122", + "slh_dsa": "0x0130-0x0135", "shake": "0x0140-0x0149", "lamport": "0x0150-0x0159", + "bls": "0x0160-0x0167", }, "shake_precompiles": []string{ "SHAKE128 (variable)", diff --git a/precompile/mldsa.go b/precompile/mldsa.go index 5b10fef..28e438f 100644 --- a/precompile/mldsa.go +++ b/precompile/mldsa.go @@ -1,38 +1,31 @@ // Copyright (C) 2025, Lux Industries Inc. All rights reserved. // ML-DSA (FIPS 204) precompiled contracts for EVM // Provides on-chain post-quantum signature verification +// +// SECURITY: Only verification is exposed as a precompile. Signing and keygen +// are deliberately excluded — private key material must never appear in EVM +// calldata (it is visible to all nodes and permanently stored on-chain). package precompile import ( - "crypto/rand" "errors" "github.com/luxfi/crypto/mldsa" ) -// ML-DSA precompile addresses (0x0110-0x0119) +// ML-DSA verification precompile addresses (0x0110-0x0112) var ( - MLDSA44VerifyAddress = HexToAddress("0x0000000000000000000000000000000000000110") - MLDSA65VerifyAddress = HexToAddress("0x0000000000000000000000000000000000000111") - MLDSA87VerifyAddress = HexToAddress("0x0000000000000000000000000000000000000112") - MLDSA44SignAddress = HexToAddress("0x0000000000000000000000000000000000000113") - MLDSA65SignAddress = HexToAddress("0x0000000000000000000000000000000000000114") - MLDSA87SignAddress = HexToAddress("0x0000000000000000000000000000000000000115") - MLDSA44KeyGenAddress = HexToAddress("0x0000000000000000000000000000000000000116") - MLDSA65KeyGenAddress = HexToAddress("0x0000000000000000000000000000000000000117") - MLDSA87KeyGenAddress = HexToAddress("0x0000000000000000000000000000000000000118") + MLDSA44VerifyAddress = HexToAddress("0x0000000000000000000000000000000000000110") + MLDSA65VerifyAddress = HexToAddress("0x0000000000000000000000000000000000000111") + MLDSA87VerifyAddress = HexToAddress("0x0000000000000000000000000000000000000112") ) -// Gas costs for ML-DSA operations +// Gas costs for ML-DSA verification const ( mldsa44VerifyGas = 120000 mldsa65VerifyGas = 180000 mldsa87VerifyGas = 250000 - mldsa44SignGas = 200000 - mldsa65SignGas = 300000 - mldsa87SignGas = 400000 - mldsaKeyGenGas = 500000 ) // mldsaVerify implements ML-DSA signature verification for a given mode. @@ -70,77 +63,11 @@ func (v *mldsaVerify) Run(input []byte) ([]byte, error) { return result, nil } -// mldsaSign implements ML-DSA signing for a given mode. -type mldsaSign struct { - mode mldsa.Mode - gas uint64 -} - -func (s *mldsaSign) RequiredGas(input []byte) uint64 { return s.gas } - -func (s *mldsaSign) Run(input []byte) ([]byte, error) { - // Input: [private_key][message] - privKeySize := 0 - switch s.mode { - case mldsa.MLDSA44: - privKeySize = mldsa.MLDSA44PrivateKeySize - case mldsa.MLDSA65: - privKeySize = mldsa.MLDSA65PrivateKeySize - case mldsa.MLDSA87: - privKeySize = mldsa.MLDSA87PrivateKeySize - default: - return nil, errors.New("invalid ML-DSA mode") - } - - if len(input) < privKeySize+1 { - return nil, errors.New("input too short") - } - - privKeyBytes := input[:privKeySize] - message := input[privKeySize:] - - privKey, err := mldsa.PrivateKeyFromBytes(s.mode, privKeyBytes) - if err != nil { - return nil, err - } - - return privKey.Sign(rand.Reader, message, nil) -} - -// mldsaKeyGen implements ML-DSA key pair generation for a given mode. -type mldsaKeyGen struct { - mode mldsa.Mode -} - -func (k *mldsaKeyGen) RequiredGas(input []byte) uint64 { return mldsaKeyGenGas } - -func (k *mldsaKeyGen) Run(input []byte) ([]byte, error) { - privKey, err := mldsa.GenerateKey(rand.Reader, k.mode) - if err != nil { - return nil, err - } - - pubBytes := privKey.PublicKey.Bytes() - privBytes := privKey.Bytes() - - // Output: [public_key][private_key] - result := make([]byte, len(pubBytes)+len(privBytes)) - copy(result, pubBytes) - copy(result[len(pubBytes):], privBytes) - return result, nil -} - -// RegisterMLDSA registers all ML-DSA precompiles. +// RegisterMLDSA registers ML-DSA verification precompiles. func RegisterMLDSA(registry *Registry) { registry.Register(MLDSA44VerifyAddress, &mldsaVerify{mode: mldsa.MLDSA44, gas: mldsa44VerifyGas}) registry.Register(MLDSA65VerifyAddress, &mldsaVerify{mode: mldsa.MLDSA65, gas: mldsa65VerifyGas}) registry.Register(MLDSA87VerifyAddress, &mldsaVerify{mode: mldsa.MLDSA87, gas: mldsa87VerifyGas}) - registry.Register(MLDSA44SignAddress, &mldsaSign{mode: mldsa.MLDSA44, gas: mldsa44SignGas}) - registry.Register(MLDSA65SignAddress, &mldsaSign{mode: mldsa.MLDSA65, gas: mldsa65SignGas}) - registry.Register(MLDSA87SignAddress, &mldsaSign{mode: mldsa.MLDSA87, gas: mldsa87SignGas}) - registry.Register(MLDSA44KeyGenAddress, &mldsaKeyGen{mode: mldsa.MLDSA44}) - registry.Register(MLDSA65KeyGenAddress, &mldsaKeyGen{mode: mldsa.MLDSA65}) - registry.Register(MLDSA87KeyGenAddress, &mldsaKeyGen{mode: mldsa.MLDSA87}) } func init() { diff --git a/precompile/mlkem.go b/precompile/mlkem.go index 47381b7..0fa0b4a 100644 --- a/precompile/mlkem.go +++ b/precompile/mlkem.go @@ -1,6 +1,10 @@ // Copyright (C) 2025, Lux Industries Inc. All rights reserved. // ML-KEM (FIPS 203) precompiled contracts for EVM // Provides on-chain post-quantum key encapsulation +// +// SECURITY: Only encapsulation (public-key operation) is exposed. Decapsulation +// and keygen are deliberately excluded — private key material must never appear +// in EVM calldata (it is visible to all nodes and permanently stored on-chain). package precompile @@ -10,28 +14,18 @@ import ( "github.com/luxfi/crypto/mlkem" ) -// ML-KEM precompile addresses (0x0120-0x0129) +// ML-KEM encapsulation precompile addresses (0x0120-0x0122) var ( MLKEM512EncapsulateAddress = HexToAddress("0x0000000000000000000000000000000000000120") MLKEM768EncapsulateAddress = HexToAddress("0x0000000000000000000000000000000000000121") MLKEM1024EncapsulateAddress = HexToAddress("0x0000000000000000000000000000000000000122") - MLKEM512DecapsulateAddress = HexToAddress("0x0000000000000000000000000000000000000123") - MLKEM768DecapsulateAddress = HexToAddress("0x0000000000000000000000000000000000000124") - MLKEM1024DecapsulateAddress = HexToAddress("0x0000000000000000000000000000000000000125") - MLKEM512KeyGenAddress = HexToAddress("0x0000000000000000000000000000000000000126") - MLKEM768KeyGenAddress = HexToAddress("0x0000000000000000000000000000000000000127") - MLKEM1024KeyGenAddress = HexToAddress("0x0000000000000000000000000000000000000128") ) -// Gas costs for ML-KEM operations +// Gas costs for ML-KEM encapsulation const ( mlkem512EncapsulateGas = 80000 mlkem768EncapsulateGas = 100000 mlkem1024EncapsulateGas = 130000 - mlkem512DecapsulateGas = 80000 - mlkem768DecapsulateGas = 100000 - mlkem1024DecapsulateGas = 130000 - mlkemKeyGenGas = 200000 ) // mlkemEncapsulate implements ML-KEM encapsulation for a given mode. @@ -66,68 +60,11 @@ func (e *mlkemEncapsulate) Run(input []byte) ([]byte, error) { return result, nil } -// mlkemDecapsulate implements ML-KEM decapsulation for a given mode. -type mlkemDecapsulate struct { - mode mlkem.Mode - gas uint64 -} - -func (d *mlkemDecapsulate) RequiredGas(input []byte) uint64 { return d.gas } - -func (d *mlkemDecapsulate) Run(input []byte) ([]byte, error) { - // Input: [private_key][ciphertext] - privKeySize := mlkem.GetPrivateKeySize(d.mode) - ctSize := mlkem.GetCiphertextSize(d.mode) - - if len(input) != privKeySize+ctSize { - return nil, errors.New("invalid input size") - } - - privKeyBytes := input[:privKeySize] - ciphertext := input[privKeySize:] - - sk, err := mlkem.PrivateKeyFromBytes(privKeyBytes, d.mode) - if err != nil { - return nil, err - } - - return sk.Decapsulate(ciphertext) -} - -// mlkemKeyGen implements ML-KEM key pair generation for a given mode. -type mlkemKeyGen struct { - mode mlkem.Mode -} - -func (k *mlkemKeyGen) RequiredGas(input []byte) uint64 { return mlkemKeyGenGas } - -func (k *mlkemKeyGen) Run(input []byte) ([]byte, error) { - pk, sk, err := mlkem.GenerateKey(k.mode) - if err != nil { - return nil, err - } - - pubBytes := pk.Bytes() - privBytes := sk.Bytes() - - // Output: [public_key][private_key] - result := make([]byte, len(pubBytes)+len(privBytes)) - copy(result, pubBytes) - copy(result[len(pubBytes):], privBytes) - return result, nil -} - -// RegisterMLKEM registers all ML-KEM precompiles. +// RegisterMLKEM registers ML-KEM encapsulation precompiles. func RegisterMLKEM(registry *Registry) { registry.Register(MLKEM512EncapsulateAddress, &mlkemEncapsulate{mode: mlkem.MLKEM512, gas: mlkem512EncapsulateGas}) registry.Register(MLKEM768EncapsulateAddress, &mlkemEncapsulate{mode: mlkem.MLKEM768, gas: mlkem768EncapsulateGas}) registry.Register(MLKEM1024EncapsulateAddress, &mlkemEncapsulate{mode: mlkem.MLKEM1024, gas: mlkem1024EncapsulateGas}) - registry.Register(MLKEM512DecapsulateAddress, &mlkemDecapsulate{mode: mlkem.MLKEM512, gas: mlkem512DecapsulateGas}) - registry.Register(MLKEM768DecapsulateAddress, &mlkemDecapsulate{mode: mlkem.MLKEM768, gas: mlkem768DecapsulateGas}) - registry.Register(MLKEM1024DecapsulateAddress, &mlkemDecapsulate{mode: mlkem.MLKEM1024, gas: mlkem1024DecapsulateGas}) - registry.Register(MLKEM512KeyGenAddress, &mlkemKeyGen{mode: mlkem.MLKEM512}) - registry.Register(MLKEM768KeyGenAddress, &mlkemKeyGen{mode: mlkem.MLKEM768}) - registry.Register(MLKEM1024KeyGenAddress, &mlkemKeyGen{mode: mlkem.MLKEM1024}) } func init() { diff --git a/precompile/precompile_all_test.go b/precompile/precompile_all_test.go index 4eb5e3e..dd64c66 100644 --- a/precompile/precompile_all_test.go +++ b/precompile/precompile_all_test.go @@ -647,18 +647,18 @@ func TestPrecompileRegistry(t *testing.T) { t.Run("AllPrecompilesRegistered", func(t *testing.T) { // Check that all expected addresses are registered expectedAddresses := []string{ - // ML-DSA (FIPS 204) - "0x0110", "0x0111", "0x0112", "0x0113", "0x0114", "0x0115", "0x0116", "0x0117", "0x0118", - // ML-KEM (FIPS 203) - "0x0120", "0x0121", "0x0122", "0x0123", "0x0124", "0x0125", "0x0126", "0x0127", "0x0128", - // SLH-DSA (FIPS 205) - "0x0130", "0x0131", "0x0132", "0x0133", "0x0134", "0x0135", "0x0136", "0x0137", "0x0138", + // ML-DSA (FIPS 204) — verify only + "0x0110", "0x0111", "0x0112", + // ML-KEM (FIPS 203) — encapsulate only + "0x0120", "0x0121", "0x0122", + // SLH-DSA (FIPS 205) — verify only + "0x0130", "0x0131", "0x0132", "0x0133", "0x0134", "0x0135", // SHAKE "0x0140", "0x0141", "0x0142", "0x0143", "0x0144", "0x0145", "0x0146", "0x0147", "0x0148", // Lamport "0x0150", "0x0151", "0x0152", "0x0153", "0x0154", // BLS - "0x0160", "0x0161", "0x0162", "0x0163", "0x0164", "0x0165", "0x0166", + "0x0160", "0x0161", "0x0162", "0x0163", "0x0164", "0x0165", "0x0166", "0x0167", } for _, addr := range expectedAddresses { diff --git a/precompile/slhdsa.go b/precompile/slhdsa.go index 4a88a10..0a3d272 100644 --- a/precompile/slhdsa.go +++ b/precompile/slhdsa.go @@ -1,17 +1,20 @@ // Copyright (C) 2025, Lux Industries Inc. All rights reserved. // SLH-DSA (FIPS 205) precompiled contracts for EVM // Provides on-chain post-quantum stateless hash-based signature verification +// +// SECURITY: Only verification is exposed as a precompile. Signing is +// deliberately excluded — private key material must never appear in EVM +// calldata (it is visible to all nodes and permanently stored on-chain). package precompile import ( - "crypto/rand" "errors" "github.com/luxfi/crypto/slhdsa" ) -// SLH-DSA precompile addresses (0x0130-0x0139) +// SLH-DSA verification precompile addresses (0x0130-0x0135) var ( SLHDSA128sVerifyAddress = HexToAddress("0x0000000000000000000000000000000000000130") SLHDSA128fVerifyAddress = HexToAddress("0x0000000000000000000000000000000000000131") @@ -19,12 +22,9 @@ var ( SLHDSA192fVerifyAddress = HexToAddress("0x0000000000000000000000000000000000000133") SLHDSA256sVerifyAddress = HexToAddress("0x0000000000000000000000000000000000000134") SLHDSA256fVerifyAddress = HexToAddress("0x0000000000000000000000000000000000000135") - SLHDSA128sSignAddress = HexToAddress("0x0000000000000000000000000000000000000136") - SLHDSA192sSignAddress = HexToAddress("0x0000000000000000000000000000000000000137") - SLHDSA256sSignAddress = HexToAddress("0x0000000000000000000000000000000000000138") ) -// Gas costs for SLH-DSA operations +// Gas costs for SLH-DSA verification const ( slhdsa128sVerifyGas = 300000 slhdsa128fVerifyGas = 200000 @@ -32,7 +32,6 @@ const ( slhdsa192fVerifyGas = 300000 slhdsa256sVerifyGas = 500000 slhdsa256fVerifyGas = 400000 - slhdsaSignGas = 1000000 ) // slhdsaVerify implements SLH-DSA signature verification for a given mode. @@ -70,69 +69,14 @@ func (v *slhdsaVerify) Run(input []byte) ([]byte, error) { return result, nil } -// slhdsaSign implements SLH-DSA signing for a given mode. -type slhdsaSign struct { - mode slhdsa.Mode - gas uint64 -} - -func (s *slhdsaSign) RequiredGas(input []byte) uint64 { return s.gas } - -func (s *slhdsaSign) Run(input []byte) ([]byte, error) { - // Input: [private_key_bytes][message] - // SLH-DSA private keys are mode-dependent in size; we need the full - // serialized private key as produced by PrivateKey.Bytes(). - // Since we don't have a PrivateKeyFromBytes that detects size, callers - // must provide the correctly-sized key for the mode. - pubKeySize := slhdsa.GetPublicKeySize(s.mode) - if pubKeySize == 0 { - return nil, errors.New("invalid SLH-DSA mode") - } - - // SLH-DSA private key is 4*n bytes where n depends on security level: - // 128-bit: n=16 -> 64 bytes, 192-bit: n=24 -> 96 bytes, 256-bit: n=32 -> 128 bytes - var privKeySize int - switch s.mode { - case slhdsa.SHA2_128s, slhdsa.SHAKE_128s, slhdsa.SHA2_128f, slhdsa.SHAKE_128f: - privKeySize = 64 - case slhdsa.SHA2_192s, slhdsa.SHAKE_192s, slhdsa.SHA2_192f, slhdsa.SHAKE_192f: - privKeySize = 96 - case slhdsa.SHA2_256s, slhdsa.SHAKE_256s, slhdsa.SHA2_256f, slhdsa.SHAKE_256f: - privKeySize = 128 - default: - return nil, errors.New("invalid SLH-DSA mode") - } - - if len(input) < privKeySize+1 { - return nil, errors.New("input too short") - } - - privKeyBytes := input[:privKeySize] - message := input[privKeySize:] - - privKey, err := slhdsa.PrivateKeyFromBytes(s.mode, privKeyBytes) - if err != nil { - return nil, err - } - - return privKey.Sign(rand.Reader, message, nil) -} - -// RegisterSLHDSA registers all SLH-DSA precompiles. +// RegisterSLHDSA registers SLH-DSA verification precompiles. func RegisterSLHDSA(registry *Registry) { - // Verification precompiles (small and fast variants) registry.Register(SLHDSA128sVerifyAddress, &slhdsaVerify{mode: slhdsa.SHA2_128s, gas: slhdsa128sVerifyGas}) registry.Register(SLHDSA128fVerifyAddress, &slhdsaVerify{mode: slhdsa.SHA2_128f, gas: slhdsa128fVerifyGas}) registry.Register(SLHDSA192sVerifyAddress, &slhdsaVerify{mode: slhdsa.SHA2_192s, gas: slhdsa192sVerifyGas}) registry.Register(SLHDSA192fVerifyAddress, &slhdsaVerify{mode: slhdsa.SHA2_192f, gas: slhdsa192fVerifyGas}) registry.Register(SLHDSA256sVerifyAddress, &slhdsaVerify{mode: slhdsa.SHA2_256s, gas: slhdsa256sVerifyGas}) registry.Register(SLHDSA256fVerifyAddress, &slhdsaVerify{mode: slhdsa.SHA2_256f, gas: slhdsa256fVerifyGas}) - - // Signing precompiles (small signature variants only -- fast variants are for - // off-chain use where gas is irrelevant) - registry.Register(SLHDSA128sSignAddress, &slhdsaSign{mode: slhdsa.SHA2_128s, gas: slhdsaSignGas}) - registry.Register(SLHDSA192sSignAddress, &slhdsaSign{mode: slhdsa.SHA2_192s, gas: slhdsaSignGas}) - registry.Register(SLHDSA256sSignAddress, &slhdsaSign{mode: slhdsa.SHA2_256s, gas: slhdsaSignGas}) } func init() {