mirror of
https://github.com/luxfi/precompile.git
synced 2026-09-24 00:26:21 +00:00
244 lines
6.6 KiB
Go
244 lines
6.6 KiB
Go
// Copyright (C) 2025, Lux Industries, Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package blake3
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"testing"
|
|
|
|
"github.com/luxfi/geth/common"
|
|
"github.com/luxfi/precompile/precompileconfig"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type fakeConfig struct{}
|
|
|
|
func (f *fakeConfig) Key() string { return "fake" }
|
|
func (f *fakeConfig) Timestamp() *uint64 { return nil }
|
|
func (f *fakeConfig) IsDisabled() bool { return false }
|
|
func (f *fakeConfig) Equal(precompileconfig.Config) bool { return false }
|
|
func (f *fakeConfig) Verify(precompileconfig.ChainConfig) error { return nil }
|
|
|
|
type testChainCfg struct{}
|
|
|
|
func (t *testChainCfg) IsDurango(uint64) bool { return true }
|
|
|
|
func TestConfigLifecycle(t *testing.T) {
|
|
cfg := &Config{}
|
|
require.Equal(t, ConfigKey, cfg.Key())
|
|
require.Nil(t, cfg.Timestamp())
|
|
require.False(t, cfg.IsDisabled())
|
|
require.NoError(t, cfg.Verify(&testChainCfg{}))
|
|
require.True(t, cfg.Equal(&Config{}))
|
|
require.False(t, cfg.Equal(&fakeConfig{}))
|
|
|
|
ts := uint64(42)
|
|
cfg2 := &Config{Upgrade: precompileconfig.Upgrade{BlockTimestamp: &ts}}
|
|
require.Equal(t, &ts, cfg2.Timestamp())
|
|
|
|
cfg3 := &Config{Upgrade: precompileconfig.Upgrade{Disable: true}}
|
|
require.True(t, cfg3.IsDisabled())
|
|
require.False(t, cfg.Equal(cfg3))
|
|
}
|
|
|
|
func TestConfigurator(t *testing.T) {
|
|
c := &configurator{}
|
|
cfg := c.MakeConfig()
|
|
require.NotNil(t, cfg)
|
|
require.Equal(t, ConfigKey, cfg.Key())
|
|
require.NoError(t, c.Configure(&testChainCfg{}, cfg, nil, nil))
|
|
}
|
|
|
|
func TestModuleRegistered(t *testing.T) {
|
|
require.Equal(t, ConfigKey, Module.ConfigKey)
|
|
require.Equal(t, ContractAddress, Module.Address)
|
|
}
|
|
|
|
// --- Run paths for full coverage ---
|
|
|
|
func TestRunEmptyInput(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
_, _, err := p.Run(nil, common.Address{}, ContractAddress, []byte{}, 1000000, true)
|
|
require.Error(t, err)
|
|
require.Equal(t, ErrInvalidInput, err)
|
|
}
|
|
|
|
func TestRunHash256(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
input := append([]byte{OpHash256}, []byte("hello world")...)
|
|
ret, gas, err := p.Run(nil, common.Address{}, ContractAddress, input, 1000000, true)
|
|
require.NoError(t, err)
|
|
require.Len(t, ret, DigestLength32)
|
|
require.Less(t, gas, uint64(1000000))
|
|
}
|
|
|
|
func TestRunHash512(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
input := append([]byte{OpHash512}, []byte("hello world")...)
|
|
ret, _, err := p.Run(nil, common.Address{}, ContractAddress, input, 1000000, true)
|
|
require.NoError(t, err)
|
|
require.Len(t, ret, DigestLength64)
|
|
}
|
|
|
|
func TestRunHashXOF(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
data := make([]byte, 5+10)
|
|
data[0] = OpHashXOF
|
|
binary.BigEndian.PutUint32(data[1:5], 64) // output 64 bytes
|
|
copy(data[5:], []byte("test input"))
|
|
ret, _, err := p.Run(nil, common.Address{}, ContractAddress, data, 1000000, true)
|
|
require.NoError(t, err)
|
|
require.Len(t, ret, 64)
|
|
}
|
|
|
|
func TestRunHashWithDomain(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
domain := "test.domain"
|
|
payload := []byte("data")
|
|
data := make([]byte, 1+1+len(domain)+len(payload))
|
|
data[0] = OpHashWithDomain
|
|
data[1] = byte(len(domain))
|
|
copy(data[2:], domain)
|
|
copy(data[2+len(domain):], payload)
|
|
ret, _, err := p.Run(nil, common.Address{}, ContractAddress, data, 1000000, true)
|
|
require.NoError(t, err)
|
|
require.Len(t, ret, DigestLength32)
|
|
}
|
|
|
|
func TestRunMerkleRoot(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
data := make([]byte, 1+4+3*32)
|
|
data[0] = OpMerkleRoot
|
|
binary.BigEndian.PutUint32(data[1:5], 3) // 3 leaves (odd)
|
|
for i := 0; i < 3; i++ {
|
|
h := p.hash256([]byte{byte(i)})
|
|
copy(data[5+i*32:], h)
|
|
}
|
|
ret, _, err := p.Run(nil, common.Address{}, ContractAddress, data, 1000000, true)
|
|
require.NoError(t, err)
|
|
require.Len(t, ret, DigestLength32)
|
|
}
|
|
|
|
func TestRunDeriveKey(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
ctx := "my.context"
|
|
key := make([]byte, 32)
|
|
data := make([]byte, 1+1+len(ctx)+32)
|
|
data[0] = OpDeriveKey
|
|
data[1] = byte(len(ctx))
|
|
copy(data[2:], ctx)
|
|
copy(data[2+len(ctx):], key)
|
|
ret, _, err := p.Run(nil, common.Address{}, ContractAddress, data, 1000000, true)
|
|
require.NoError(t, err)
|
|
require.Len(t, ret, DigestLength32)
|
|
}
|
|
|
|
// --- RequiredGas edge cases ---
|
|
|
|
func TestRequiredGasEdgeCases(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
|
|
// Empty
|
|
require.Equal(t, uint64(0), p.RequiredGas(nil))
|
|
|
|
// XOF with short input
|
|
require.Equal(t, uint64(0), p.RequiredGas([]byte{OpHashXOF, 0, 0}))
|
|
|
|
// MerkleRoot short
|
|
require.Equal(t, uint64(0), p.RequiredGas([]byte{OpMerkleRoot, 0, 0}))
|
|
|
|
// Unknown op
|
|
require.Equal(t, uint64(0), p.RequiredGas([]byte{0xFF}))
|
|
|
|
// EvaluatePolynomial (OpEvaluatePolynomial is not defined in blake3)
|
|
}
|
|
|
|
// --- hash256 large input ---
|
|
|
|
func TestHash256LargeInput(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
// Input exceeding MaxInputLength
|
|
large := make([]byte, MaxInputLength+100)
|
|
for i := range large {
|
|
large[i] = byte(i)
|
|
}
|
|
result := p.hash256(large)
|
|
require.Len(t, result, DigestLength32)
|
|
}
|
|
|
|
// --- hash512 large input ---
|
|
|
|
func TestHash512LargeInput(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
large := make([]byte, MaxInputLength+100)
|
|
result := p.hash512(large)
|
|
require.Len(t, result, DigestLength64)
|
|
}
|
|
|
|
// --- hashXOF errors ---
|
|
|
|
func TestHashXOFErrors(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
// Short data
|
|
_, _, err := p.hashXOF([]byte{0, 0})
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// --- hashWithDomain errors ---
|
|
|
|
func TestHashWithDomainErrors(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
// Empty
|
|
_, _, err := p.hashWithDomain(nil)
|
|
require.Error(t, err)
|
|
|
|
// Domain length exceeds data
|
|
_, _, err = p.hashWithDomain([]byte{10}) // says 10 bytes but only 0 follow
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// --- merkleRoot errors ---
|
|
|
|
func TestMerkleRootErrors(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
// Short
|
|
_, _, err := p.merkleRoot([]byte{0, 0})
|
|
require.Error(t, err)
|
|
|
|
// Data too short for declared leaves
|
|
data := make([]byte, 4+10)
|
|
binary.BigEndian.PutUint32(data[:4], 5) // says 5 leaves but only 10 bytes follow
|
|
_, _, err = p.merkleRoot(data)
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// --- deriveKey errors ---
|
|
|
|
func TestDeriveKeyErrors(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
// Empty
|
|
_, _, err := p.deriveKey(nil)
|
|
require.Error(t, err)
|
|
|
|
// Context length exceeds data
|
|
_, _, err = p.deriveKey([]byte{50}) // says 50 bytes context but nothing follows
|
|
require.Error(t, err)
|
|
}
|
|
|
|
// --- computeMerkleRoot edge ---
|
|
|
|
func TestComputeMerkleRootSingleLeaf(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
leaf := make([]byte, 32)
|
|
copy(leaf, []byte("single leaf"))
|
|
result := p.computeMerkleRoot([][]byte{leaf})
|
|
require.Equal(t, leaf, result)
|
|
}
|
|
|
|
func TestComputeMerkleRootEmpty(t *testing.T) {
|
|
p := &blake3Precompile{}
|
|
result := p.computeMerkleRoot(nil)
|
|
require.Len(t, result, DigestLength32)
|
|
}
|