tendermint/vm/native.go

90 lines
2.2 KiB
Go

package vm
import (
"code.google.com/p/go.crypto/ripemd160"
"crypto/sha256"
. "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/vm/secp256k1"
"github.com/tendermint/tendermint/vm/sha3"
)
var nativeContracts = make(map[Word256]NativeContract)
func init() {
nativeContracts[Uint64ToWord256(1)] = ecrecoverFunc
nativeContracts[Uint64ToWord256(2)] = sha256Func
nativeContracts[Uint64ToWord256(3)] = ripemd160Func
nativeContracts[Uint64ToWord256(4)] = identityFunc
}
//-----------------------------------------------------------------------------
type NativeContract func(input []byte, gas *uint64) (output []byte, err error)
func ecrecoverFunc(input []byte, gas *uint64) (output []byte, err error) {
// Deduct gas
gasRequired := GasEcRecover
if *gas < gasRequired {
return nil, ErrInsufficientGas
} else {
*gas -= gasRequired
}
// Recover
hash := input[:32]
v := byte(input[32] - 27) // ignore input[33:64], v is small.
sig := append(input[64:], v)
recovered, err := secp256k1.RecoverPubkey(hash, sig)
if err != nil {
return nil, err
}
hashed := sha3.Sha3(recovered[1:])
return RightPadBytes(hashed, 32), nil
}
func sha256Func(input []byte, gas *uint64) (output []byte, err error) {
// Deduct gas
gasRequired := uint64((len(input)+31)/32)*GasSha256Word + GasSha256Base
if *gas < gasRequired {
return nil, ErrInsufficientGas
} else {
*gas -= gasRequired
}
// Hash
hasher := sha256.New()
_, err = hasher.Write(input)
if err != nil {
panic(err)
}
return hasher.Sum(nil), nil
}
func ripemd160Func(input []byte, gas *uint64) (output []byte, err error) {
// Deduct gas
gasRequired := uint64((len(input)+31)/32)*GasRipemd160Word + GasRipemd160Base
if *gas < gasRequired {
return nil, ErrInsufficientGas
} else {
*gas -= gasRequired
}
// Hash
hasher := ripemd160.New()
_, err = hasher.Write(input)
if err != nil {
panic(err)
}
return RightPadBytes(hasher.Sum(nil), 32), nil
}
func identityFunc(input []byte, gas *uint64) (output []byte, err error) {
// Deduct gas
gasRequired := uint64((len(input)+31)/32)*GasIdentityWord + GasIdentityBase
if *gas < gasRequired {
return nil, ErrInsufficientGas
} else {
*gas -= gasRequired
}
// Return identity
return input, nil
}