neoneo-go/pkg/core/native/crypto.go
Anna Shaleva d0718a680f core: add InitializeCache method to Contract interface
Make the contracts cache initialization unified. The order of cache
iniitialization is not important and Nottary contract is added to the
bc.contracts.Contracts wrt P2PSigExtensions setting, thus no functional
changes, just refactoring for future applications.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-08-01 17:30:01 +03:00

164 lines
4.6 KiB
Go

package native
import (
"crypto/elliptic"
"encoding/binary"
"errors"
"fmt"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/twmb/murmur3"
)
// Crypto represents CryptoLib contract.
type Crypto struct {
interop.ContractMD
}
// NamedCurve identifies named elliptic curves.
type NamedCurve byte
// Various named elliptic curves.
const (
Secp256k1 NamedCurve = 22
Secp256r1 NamedCurve = 23
)
const cryptoContractID = -3
func newCrypto() *Crypto {
c := &Crypto{ContractMD: *interop.NewContractMD(nativenames.CryptoLib, cryptoContractID)}
defer c.UpdateHash()
desc := newDescriptor("sha256", smartcontract.ByteArrayType,
manifest.NewParameter("data", smartcontract.ByteArrayType))
md := newMethodAndPrice(c.sha256, 1<<15, callflag.NoneFlag)
c.AddMethod(md, desc)
desc = newDescriptor("ripemd160", smartcontract.ByteArrayType,
manifest.NewParameter("data", smartcontract.ByteArrayType))
md = newMethodAndPrice(c.ripemd160, 1<<15, callflag.NoneFlag)
c.AddMethod(md, desc)
desc = newDescriptor("murmur32", smartcontract.ByteArrayType,
manifest.NewParameter("data", smartcontract.ByteArrayType),
manifest.NewParameter("seed", smartcontract.IntegerType))
md = newMethodAndPrice(c.murmur32, 1<<13, callflag.NoneFlag)
c.AddMethod(md, desc)
desc = newDescriptor("verifyWithECDsa", smartcontract.BoolType,
manifest.NewParameter("message", smartcontract.ByteArrayType),
manifest.NewParameter("pubkey", smartcontract.ByteArrayType),
manifest.NewParameter("signature", smartcontract.ByteArrayType),
manifest.NewParameter("curve", smartcontract.IntegerType))
md = newMethodAndPrice(c.verifyWithECDsa, 1<<15, callflag.NoneFlag)
c.AddMethod(md, desc)
return c
}
func (c *Crypto) sha256(_ *interop.Context, args []stackitem.Item) stackitem.Item {
bs, err := args[0].TryBytes()
if err != nil {
panic(err)
}
return stackitem.NewByteArray(hash.Sha256(bs).BytesBE())
}
func (c *Crypto) ripemd160(_ *interop.Context, args []stackitem.Item) stackitem.Item {
bs, err := args[0].TryBytes()
if err != nil {
panic(err)
}
return stackitem.NewByteArray(hash.RipeMD160(bs).BytesBE())
}
func (c *Crypto) murmur32(_ *interop.Context, args []stackitem.Item) stackitem.Item {
bs, err := args[0].TryBytes()
if err != nil {
panic(err)
}
seed := toUint32(args[1])
h := murmur3.SeedSum32(seed, bs)
result := make([]byte, 4)
binary.LittleEndian.PutUint32(result, h)
return stackitem.NewByteArray(result)
}
func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stackitem.Item {
msg, err := args[0].TryBytes()
if err != nil {
panic(fmt.Errorf("invalid message stackitem: %w", err))
}
hashToCheck := hash.Sha256(msg)
pubkey, err := args[1].TryBytes()
if err != nil {
panic(fmt.Errorf("invalid pubkey stackitem: %w", err))
}
signature, err := args[2].TryBytes()
if err != nil {
panic(fmt.Errorf("invalid signature stackitem: %w", err))
}
curve, err := curveFromStackitem(args[3])
if err != nil {
panic(fmt.Errorf("invalid curve stackitem: %w", err))
}
pkey, err := keys.NewPublicKeyFromBytes(pubkey, curve)
if err != nil {
panic(fmt.Errorf("failed to decode pubkey: %w", err))
}
res := pkey.Verify(signature, hashToCheck.BytesBE())
return stackitem.NewBool(res)
}
func curveFromStackitem(si stackitem.Item) (elliptic.Curve, error) {
curve, err := si.TryInteger()
if err != nil {
return nil, err
}
if !curve.IsInt64() {
return nil, errors.New("not an int64")
}
c := curve.Int64()
switch c {
case int64(Secp256k1):
return secp256k1.S256(), nil
case int64(Secp256r1):
return elliptic.P256(), nil
default:
return nil, errors.New("unsupported curve type")
}
}
// Metadata implements the Contract interface.
func (c *Crypto) Metadata() *interop.ContractMD {
return &c.ContractMD
}
// Initialize implements the Contract interface.
func (c *Crypto) Initialize(ic *interop.Context) error {
return nil
}
// InitializeCache implements the Contract interface.
func (c *Crypto) InitializeCache(blockHeight uint32, d *dao.Simple) error {
return nil
}
// OnPersist implements the Contract interface.
func (c *Crypto) OnPersist(ic *interop.Context) error {
return nil
}
// PostPersist implements the Contract interface.
func (c *Crypto) PostPersist(ic *interop.Context) error {
return nil
}