go-ethereum/crypto/poseidon/codehash.go
Péter Garamvölgyi 304af60f50
feat: change bytecode hash function from Keccak to Poseidon (#149)
* feat: change bytecode hash function from Keccak to Poseidon

* fix TestStateProcessorErrors

* rename files

* copy iden3's poseidon package to local

* update poseidon hash

* apply new hash in codehash

* extend hash method, use actual code size as cap

* prune keccak(nil) for empty code

* update empty code hash references to Poseidon

* add TestPoseidonCodeHash

* use keccak for empty code hash

* go mod tidy

* goimports

* use Poseidon code hash in state and sync tests

* run goimports

* run goimports

* remove unnecessary reallocation from CodeHash

* goimports

* move codehash API to separate module

* add missing package

* fix review comments

* improve comments

Co-authored-by: Ho Vei <noelwei@gmail.com>
2022-09-08 06:16:17 +08:00

47 lines
1.1 KiB
Go

package poseidon
import (
"math/big"
"github.com/scroll-tech/go-ethereum/common"
"github.com/scroll-tech/go-ethereum/crypto"
)
const defaultPoseidonChunk = 3
func CodeHash(code []byte) (h common.Hash) {
// special case for nil hash
if len(code) == 0 {
return crypto.Keccak256Hash(nil)
}
cap := int64(len(code))
// step 1: pad code with 0x0 (STOP) so that len(code) % 16 == 0
// step 2: for every 16 bytes, convert to Fr, so that we get a Fr array
var length = (len(code) + 15) / 16
Frs := make([]*big.Int, length)
ii := 0
for ii < length-1 {
Frs[ii] = big.NewInt(0)
Frs[ii].SetBytes(code[ii*16 : (ii+1)*16])
ii++
}
Frs[ii] = big.NewInt(0)
bytes := make([]byte, 16)
copy(bytes, code[ii*16:])
Frs[ii].SetBytes(bytes)
// step 3: apply the array onto a sponge process with the current poseidon scheme
// (3 Frs permutation and 1 Fr for output, so the throughout is 2 Frs)
// step 4: convert final root Fr to u256 (big-endian representation)
hash, _ := HashWithCap(Frs, defaultPoseidonChunk, cap)
codeHash := common.Hash{}
hash.FillBytes(codeHash[:])
return codeHash
}