From 90beffbaf80aa2a0b7b6d79c933f37741dab3af5 Mon Sep 17 00:00:00 2001
From: Guillaume Ballet <3272758+gballet@users.noreply.github.com>
Date: Mon, 22 Sep 2025 18:06:58 +0200
Subject: [PATCH] core/vm, crypto: add crypto package for hashing
---
core/vm/evm.go | 3 +-
crypto/platcrypto/keccak.go | 42 +++++++++++++
crypto/platcrypto/keccak_ziren.go | 101 ++++++++++++++++++++++++++++++
trie/secure_trie.go | 24 +++----
4 files changed, 157 insertions(+), 13 deletions(-)
create mode 100644 crypto/platcrypto/keccak.go
create mode 100644 crypto/platcrypto/keccak_ziren.go
diff --git a/core/vm/evm.go b/core/vm/evm.go
index 88ef1cf121..0874fbe4ee 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/crypto/platcrypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
@@ -144,7 +145,7 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
jumpDests: newMapJumpDests(),
- hasher: crypto.NewKeccakState(),
+ hasher: platcrypto.NewKeccakState(),
}
evm.precompiles = activePrecompiledContracts(evm.chainRules)
diff --git a/crypto/platcrypto/keccak.go b/crypto/platcrypto/keccak.go
new file mode 100644
index 0000000000..a070e8c453
--- /dev/null
+++ b/crypto/platcrypto/keccak.go
@@ -0,0 +1,42 @@
+// Copyright 2025 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+//go:build !ziren
+
+package platcrypto
+
+import (
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+)
+
+// Keccak256 calculates and returns the Keccak256 hash using the standard implementation.
+// This is used for geth, evm, and other regular programs.
+func Keccak256(data ...[]byte) []byte {
+ return crypto.Keccak256(data...)
+}
+
+// Keccak256Hash calculates and returns the Keccak256 hash as a Hash using the standard implementation.
+// This is used for geth, evm, and other regular programs.
+func Keccak256Hash(data ...[]byte) common.Hash {
+ return crypto.Keccak256Hash(data...)
+}
+
+// NewKeccakState returns a new keccak state hasher using the standard implementation.
+// This is used for geth, evm, and other regular programs.
+func NewKeccakState() crypto.KeccakState {
+ return crypto.NewKeccakState()
+}
diff --git a/crypto/platcrypto/keccak_ziren.go b/crypto/platcrypto/keccak_ziren.go
new file mode 100644
index 0000000000..b0fa74ae6c
--- /dev/null
+++ b/crypto/platcrypto/keccak_ziren.go
@@ -0,0 +1,101 @@
+// Copyright 2025 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+//go:build ziren
+
+package platcrypto
+
+import (
+ "errors"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/crypto"
+ zkruntime "github.com/zkMIPS/zkMIPS/crates/go-runtime/zkm_runtime"
+)
+
+// zirenKeccak implements keccak256 using the ziren platform precompile
+func zirenKeccak(data []byte) []byte {
+ return zkruntime.Keccak(data)
+}
+
+// zirenKeccakState wraps the ziren platform keccak precompile to implement crypto.KeccakState interface
+type zirenKeccakState struct {
+ data []byte
+}
+
+func (k *zirenKeccakState) Reset() {
+ k.data = k.data[:0]
+}
+
+func (k *zirenKeccakState) Clone() crypto.KeccakState {
+ clone := &zirenKeccakState{
+ data: make([]byte, len(k.data)),
+ }
+ copy(clone.data, k.data)
+ return clone
+}
+
+func (k *zirenKeccakState) Write(data []byte) (int, error) {
+ k.data = append(k.data, data...)
+ return len(data), nil
+}
+
+func (k *zirenKeccakState) Read(hash []byte) (int, error) {
+ if len(hash) < 32 {
+ return 0, errors.New("hash slice too short")
+ }
+
+ result := zirenKeccak(k.data)
+ copy(hash[:32], result)
+ return 32, nil
+}
+
+func (k *zirenKeccakState) Sum(data []byte) []byte {
+ hash := make([]byte, 32)
+ k.Read(hash)
+ return append(data, hash...)
+}
+
+func (k *zirenKeccakState) Size() int {
+ return 32
+}
+
+func (k *zirenKeccakState) BlockSize() int {
+ return 136 // keccak256 block size
+}
+
+// Keccak256 calculates and returns the Keccak256 hash using the ziren platform precompile.
+func Keccak256(data ...[]byte) []byte {
+ hasher := &zirenKeccakState{}
+ for _, b := range data {
+ hasher.Write(b)
+ }
+ hash := make([]byte, 32)
+ hasher.Read(hash)
+ return hash
+}
+
+// Keccak256Hash calculates and returns the Keccak256 hash as a Hash using the ziren platform precompile.
+func Keccak256Hash(data ...[]byte) (h common.Hash) {
+ hash := Keccak256(data...)
+ copy(h[:], hash)
+ return h
+}
+
+// NewKeccakState returns a new keccak state hasher using the ziren platform precompile.
+func NewKeccakState() crypto.KeccakState {
+ return &zirenKeccakState{}
+}
diff --git a/trie/secure_trie.go b/trie/secure_trie.go
index 7c7bd184bf..588ca698eb 100644
--- a/trie/secure_trie.go
+++ b/trie/secure_trie.go
@@ -19,7 +19,7 @@ package trie
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/crypto/platcrypto"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/triedb/database"
@@ -102,14 +102,14 @@ func NewStateTrie(id *ID, db database.NodeDatabase) (*StateTrie, error) {
// This function will omit any encountered error but just
// print out an error message.
func (t *StateTrie) MustGet(key []byte) []byte {
- return t.trie.MustGet(crypto.Keccak256(key))
+ return t.trie.MustGet(platcrypto.Keccak256(key))
}
// GetAccount attempts to retrieve an account with provided account address.
// If the specified account is not in the trie, nil will be returned.
// If a trie node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
- res, err := t.trie.Get(crypto.Keccak256(address.Bytes()))
+ res, err := t.trie.Get(platcrypto.Keccak256(address.Bytes()))
if res == nil || err != nil {
return nil, err
}
@@ -136,7 +136,7 @@ func (t *StateTrie) GetAccountByHash(addrHash common.Hash) (*types.StateAccount,
func (t *StateTrie) PrefetchAccount(addresses []common.Address) error {
var keys [][]byte
for _, addr := range addresses {
- keys = append(keys, crypto.Keccak256(addr.Bytes()))
+ keys = append(keys, platcrypto.Keccak256(addr.Bytes()))
}
return t.trie.Prefetch(keys)
}
@@ -146,7 +146,7 @@ func (t *StateTrie) PrefetchAccount(addresses []common.Address) error {
// If the specified storage slot is not in the trie, nil will be returned.
// If a trie node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
- enc, err := t.trie.Get(crypto.Keccak256(key))
+ enc, err := t.trie.Get(platcrypto.Keccak256(key))
if err != nil || len(enc) == 0 {
return nil, err
}
@@ -159,7 +159,7 @@ func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
func (t *StateTrie) PrefetchStorage(_ common.Address, keys [][]byte) error {
var keylist [][]byte
for _, key := range keys {
- keylist = append(keylist, crypto.Keccak256(key))
+ keylist = append(keylist, platcrypto.Keccak256(key))
}
return t.trie.Prefetch(keylist)
}
@@ -182,7 +182,7 @@ func (t *StateTrie) GetNode(path []byte) ([]byte, int, error) {
// This function will omit any encountered error but just print out an
// error message.
func (t *StateTrie) MustUpdate(key, value []byte) {
- hk := crypto.Keccak256(key)
+ hk := platcrypto.Keccak256(key)
t.trie.MustUpdate(hk, value)
if t.preimages != nil {
t.secKeyCache[common.Hash(hk)] = common.CopyBytes(key)
@@ -198,7 +198,7 @@ func (t *StateTrie) MustUpdate(key, value []byte) {
//
// If a node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
- hk := crypto.Keccak256(key)
+ hk := platcrypto.Keccak256(key)
v, _ := rlp.EncodeToBytes(value)
err := t.trie.Update(hk, v)
if err != nil {
@@ -212,7 +212,7 @@ func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
// UpdateAccount will abstract the write of an account to the secure trie.
func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount, _ int) error {
- hk := crypto.Keccak256(address.Bytes())
+ hk := platcrypto.Keccak256(address.Bytes())
data, err := rlp.EncodeToBytes(acc)
if err != nil {
return err
@@ -233,7 +233,7 @@ func (t *StateTrie) UpdateContractCode(_ common.Address, _ common.Hash, _ []byte
// MustDelete removes any existing value for key from the trie. This function
// will omit any encountered error but just print out an error message.
func (t *StateTrie) MustDelete(key []byte) {
- hk := crypto.Keccak256(key)
+ hk := platcrypto.Keccak256(key)
if t.preimages != nil {
delete(t.secKeyCache, common.Hash(hk))
}
@@ -244,7 +244,7 @@ func (t *StateTrie) MustDelete(key []byte) {
// If the specified trie node is not in the trie, nothing will be changed.
// If a node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
- hk := crypto.Keccak256(key)
+ hk := platcrypto.Keccak256(key)
if t.preimages != nil {
delete(t.secKeyCache, common.Hash(hk))
}
@@ -253,7 +253,7 @@ func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
// DeleteAccount abstracts an account deletion from the trie.
func (t *StateTrie) DeleteAccount(address common.Address) error {
- hk := crypto.Keccak256(address.Bytes())
+ hk := platcrypto.Keccak256(address.Bytes())
if t.preimages != nil {
delete(t.secKeyCache, common.Hash(hk))
}