Add poseidon precompile

This commit is contained in:
Martin Ondejka 2023-04-05 21:48:52 +02:00
parent 37b5a40ab8
commit 7c5c706016
4 changed files with 74 additions and 4 deletions

View file

@ -104,11 +104,16 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{18}): &bls12381MapG2{},
}
var PrecompiledContractsMina = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{0x50}): &MinaPoseidon{},
}
var (
PrecompiledAddressesBerlin []common.Address
PrecompiledAddressesIstanbul []common.Address
PrecompiledAddressesByzantium []common.Address
PrecompiledAddressesHomestead []common.Address
PrecompiledAddressesMina []common.Address
)
func init() {
@ -124,19 +129,24 @@ func init() {
for k := range PrecompiledContractsBerlin {
PrecompiledAddressesBerlin = append(PrecompiledAddressesBerlin, k)
}
for k := range PrecompiledContractsMina {
PrecompiledAddressesMina = append(PrecompiledAddressesMina, k)
}
}
// ActivePrecompiles returns the precompiles enabled with the current configuration.
func ActivePrecompiles(rules params.Rules) []common.Address {
result := PrecompiledAddressesMina
switch {
case rules.IsBerlin:
return PrecompiledAddressesBerlin
return append(result, PrecompiledAddressesBerlin...)
case rules.IsIstanbul:
return PrecompiledAddressesIstanbul
return append(result, PrecompiledAddressesIstanbul...)
case rules.IsByzantium:
return PrecompiledAddressesByzantium
return append(result, PrecompiledAddressesByzantium...)
default:
return PrecompiledAddressesHomestead
return append(result, PrecompiledAddressesHomestead...)
}
}

View file

@ -42,6 +42,10 @@ type (
)
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
if p, ok := PrecompiledContractsMina[addr]; ok {
return p, ok
}
var precompiles map[common.Address]PrecompiledContract
switch {
case evm.chainRules.IsBerlin:
@ -53,6 +57,7 @@ func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
default:
precompiles = PrecompiledContractsHomestead
}
p, ok := precompiles[addr]
return p, ok
}

54
core/vm/mina_contracts.go Normal file
View file

@ -0,0 +1,54 @@
package vm
/*
#cgo LDFLAGS: mina/target/release/libmina.a -ldl
#include "../../mina/target/mina.h"
*/
import "C"
import (
"bytes"
"math/big"
"github.com/ethereum/go-ethereum/crypto"
)
type MinaPoseidon struct{}
func (c *MinaPoseidon) RequiredGas(input []byte) uint64 {
return 1000
}
// 0x1f831f84
var minaPoseidonSignature = crypto.Keccak256([]byte("poseidonHash(uint8,bytes32[])"))[:4]
const networkIdIndex = 0
const fieldsHeadIndex = networkIdIndex + 32
func (c *MinaPoseidon) Run(input []byte) ([]byte, error) {
if !bytes.Equal(input[:4], minaPoseidonSignature) {
return nil, ErrExecutionReverted
}
calldata := input[4:]
networkId := new(big.Int).SetBytes(getData(calldata, networkIdIndex, 32)).Uint64()
lenIndex := new(big.Int).SetBytes(getData(calldata, fieldsHeadIndex, 32)).Uint64()
fieldsLen := new(big.Int).SetBytes(getData(calldata, lenIndex, 32)).Uint64()
dataIndex := lenIndex + 32
fields := calldata[dataIndex : dataIndex+fieldsLen*32]
output_buffer := [32]byte{}
if !C.poseidon_hash(
uint32(networkId),
(*C.uint8_t)(&fields[0]),
C.uintptr_t(fieldsLen),
(*C.uint8_t)(&output_buffer[0]),
) {
return nil, ErrExecutionReverted
}
return output_buffer[:], nil
}

1
mina/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target