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)) }