mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
128 lines
4.2 KiB
Go
128 lines
4.2 KiB
Go
// Copyright (C) 2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package slhdsa
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/luxfi/crypto/slhdsa"
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestSLHDSAVerify_AllModes exercises every one of the 12 FIPS 205 parameter
|
|
// sets end-to-end: generate key, sign, pass through the precompile, assert
|
|
// result == 1. Previously only SHA2_128s and SHAKE_128f were covered, leaving
|
|
// the 192-bit and 256-bit security levels entirely untested.
|
|
func TestSLHDSAVerify_AllModes(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
precompMode uint8
|
|
cryptoMode slhdsa.Mode
|
|
}{
|
|
// SHA2 family (0x00..0x05)
|
|
{"SHA2_128s", ModeSHA2_128s, slhdsa.SHA2_128s},
|
|
{"SHA2_128f", ModeSHA2_128f, slhdsa.SHA2_128f},
|
|
{"SHA2_192s", ModeSHA2_192s, slhdsa.SHA2_192s},
|
|
{"SHA2_192f", ModeSHA2_192f, slhdsa.SHA2_192f},
|
|
{"SHA2_256s", ModeSHA2_256s, slhdsa.SHA2_256s},
|
|
{"SHA2_256f", ModeSHA2_256f, slhdsa.SHA2_256f},
|
|
// SHAKE family (0x10..0x15)
|
|
{"SHAKE_128s", ModeSHAKE_128s, slhdsa.SHAKE_128s},
|
|
{"SHAKE_128f", ModeSHAKE_128f, slhdsa.SHAKE_128f},
|
|
{"SHAKE_192s", ModeSHAKE_192s, slhdsa.SHAKE_192s},
|
|
{"SHAKE_192f", ModeSHAKE_192f, slhdsa.SHAKE_192f},
|
|
{"SHAKE_256s", ModeSHAKE_256s, slhdsa.SHAKE_256s},
|
|
{"SHAKE_256f", ModeSHAKE_256f, slhdsa.SHAKE_256f},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
pk, signature, message, _ := createTestSignature(t, tc.cryptoMode)
|
|
input := prepareInputWithMode(tc.precompMode, pk, message, signature)
|
|
|
|
gas := SLHDSAVerifyPrecompile.RequiredGas(input)
|
|
result, _, err := SLHDSAVerifyPrecompile.Run(
|
|
nil, common.Address{}, ContractSLHDSAVerifyAddress,
|
|
input, gas, true,
|
|
)
|
|
|
|
require.NoError(t, err, "%s: Run returned error", tc.name)
|
|
require.Len(t, result, 32, "%s: result must be 32 bytes", tc.name)
|
|
require.Equal(t, byte(1), result[31],
|
|
"%s: signature should verify as valid", tc.name)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSLHDSAVerify_AllModes_Corrupted ensures every mode also rejects a
|
|
// tampered signature. Catches regressions where a mode's verify path returns
|
|
// success unconditionally.
|
|
func TestSLHDSAVerify_AllModes_Corrupted(t *testing.T) {
|
|
modes := []struct {
|
|
name string
|
|
precompMode uint8
|
|
cryptoMode slhdsa.Mode
|
|
}{
|
|
{"SHA2_128s", ModeSHA2_128s, slhdsa.SHA2_128s},
|
|
{"SHA2_128f", ModeSHA2_128f, slhdsa.SHA2_128f},
|
|
{"SHA2_192s", ModeSHA2_192s, slhdsa.SHA2_192s},
|
|
{"SHA2_192f", ModeSHA2_192f, slhdsa.SHA2_192f},
|
|
{"SHA2_256s", ModeSHA2_256s, slhdsa.SHA2_256s},
|
|
{"SHA2_256f", ModeSHA2_256f, slhdsa.SHA2_256f},
|
|
{"SHAKE_128s", ModeSHAKE_128s, slhdsa.SHAKE_128s},
|
|
{"SHAKE_128f", ModeSHAKE_128f, slhdsa.SHAKE_128f},
|
|
{"SHAKE_192s", ModeSHAKE_192s, slhdsa.SHAKE_192s},
|
|
{"SHAKE_192f", ModeSHAKE_192f, slhdsa.SHAKE_192f},
|
|
{"SHAKE_256s", ModeSHAKE_256s, slhdsa.SHAKE_256s},
|
|
{"SHAKE_256f", ModeSHAKE_256f, slhdsa.SHAKE_256f},
|
|
}
|
|
|
|
for _, tc := range modes {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
pk, signature, message, _ := createTestSignature(t, tc.cryptoMode)
|
|
signature[0] ^= 0xFF
|
|
input := prepareInputWithMode(tc.precompMode, pk, message, signature)
|
|
|
|
gas := SLHDSAVerifyPrecompile.RequiredGas(input)
|
|
result, _, err := SLHDSAVerifyPrecompile.Run(
|
|
nil, common.Address{}, ContractSLHDSAVerifyAddress,
|
|
input, gas, true,
|
|
)
|
|
|
|
require.NoError(t, err,
|
|
"%s: Run should not return error on invalid sig", tc.name)
|
|
require.Len(t, result, 32)
|
|
require.Equal(t, byte(0), result[31],
|
|
"%s: corrupted signature must NOT verify", tc.name)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSLHDSAVerify_ModeGasIncreasesWithSecurity sanity check: gas costs must
|
|
// grow with security level because signature sizes and SHA tree heights both
|
|
// increase. Catches regressions that would price 256-bit verify as cheap.
|
|
func TestSLHDSAVerify_ModeGasIncreasesWithSecurity(t *testing.T) {
|
|
levels := []struct {
|
|
mode uint8
|
|
bits int
|
|
}{
|
|
{ModeSHA2_128s, 128},
|
|
{ModeSHA2_192s, 192},
|
|
{ModeSHA2_256s, 256},
|
|
}
|
|
|
|
var prev uint64
|
|
for _, lv := range levels {
|
|
_, _, baseGas, _, err := getModeParams(lv.mode)
|
|
require.NoError(t, err, "getModeParams failed for %d-bit", lv.bits)
|
|
require.Greater(t, baseGas, prev,
|
|
fmt.Sprintf("%d-bit gas must be > previous level", lv.bits))
|
|
prev = baseGas
|
|
}
|
|
}
|