github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/crypto/poseidon/codehash.go (about)

     1  package poseidon
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/scroll-tech/go-ethereum/common"
     7  )
     8  
     9  const defaultPoseidonChunk = 3
    10  const nBytesToFieldElement = 31
    11  
    12  func CodeHash(code []byte) (h common.Hash) {
    13  	nBytes := int64(len(code))
    14  
    15  	// step 1: pad code with 0x0 (STOP) so that len(code) % nBytesToFieldElement == 0
    16  	// step 2: for every nBytesToFieldElement bytes, convert to Fr, so that we get a Fr array
    17  	var length = (len(code) + nBytesToFieldElement - 1) / nBytesToFieldElement
    18  
    19  	Frs := make([]*big.Int, length)
    20  	ii := 0
    21  
    22  	for ii < length-1 {
    23  		Frs[ii] = big.NewInt(0)
    24  		Frs[ii].SetBytes(code[ii*nBytesToFieldElement : (ii+1)*nBytesToFieldElement])
    25  		ii++
    26  	}
    27  
    28  	if length > 0 {
    29  		Frs[ii] = big.NewInt(0)
    30  		bytes := make([]byte, nBytesToFieldElement)
    31  		copy(bytes, code[ii*nBytesToFieldElement:])
    32  		Frs[ii].SetBytes(bytes)
    33  	}
    34  
    35  	// step 3: apply the array onto a sponge process with the current poseidon scheme
    36  	// (3 Frs permutation and 1 Fr for output, so the throughout is 2 Frs)
    37  	// step 4: convert final root Fr to u256 (big-endian representation)
    38  	hash, err := HashWithCap(Frs, defaultPoseidonChunk, nBytes)
    39  	if err != nil {
    40  		return common.Hash{}
    41  	}
    42  	return common.BigToHash(hash)
    43  }