neoneo-go/pkg/core/interop/crypto/ecdsa.go
2020-07-14 16:21:34 +03:00

98 lines
3.1 KiB
Go

package crypto
import (
"crypto/elliptic"
"errors"
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/crypto"
"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/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// ECDSAVerifyPrice is a gas price of a single verification.
const ECDSAVerifyPrice = 1000000
// ECDSASecp256r1Verify checks ECDSA signature using Secp256r1 elliptic curve.
func ECDSASecp256r1Verify(ic *interop.Context, v *vm.VM) error {
return ecdsaVerify(ic, v, elliptic.P256())
}
// ECDSASecp256k1Verify checks ECDSA signature using Secp256k1 elliptic curve
func ECDSASecp256k1Verify(ic *interop.Context, v *vm.VM) error {
return ecdsaVerify(ic, v, btcec.S256())
}
// ecdsaVerify is internal representation of ECDSASecp256k1Verify and
// ECDSASecp256r1Verify.
func ecdsaVerify(ic *interop.Context, v *vm.VM, curve elliptic.Curve) error {
msg := getMessage(ic, v.Estack().Pop().Item())
hashToCheck := hash.Sha256(msg).BytesBE()
keyb := v.Estack().Pop().Bytes()
signature := v.Estack().Pop().Bytes()
pkey, err := keys.NewPublicKeyFromBytes(keyb, curve)
if err != nil {
return err
}
res := pkey.Verify(signature, hashToCheck)
v.Estack().PushVal(res)
return nil
}
// ECDSASecp256r1CheckMultisig checks multiple ECDSA signatures at once using
// Secp256r1 elliptic curve.
func ECDSASecp256r1CheckMultisig(ic *interop.Context, v *vm.VM) error {
return ecdsaCheckMultisig(ic, v, elliptic.P256())
}
// ECDSASecp256k1CheckMultisig checks multiple ECDSA signatures at once using
// Secp256k1 elliptic curve.
func ECDSASecp256k1CheckMultisig(ic *interop.Context, v *vm.VM) error {
return ecdsaCheckMultisig(ic, v, btcec.S256())
}
// ecdsaCheckMultisig is internal representation of ECDSASecp256r1CheckMultisig and
// ECDSASecp256k1CheckMultisig
func ecdsaCheckMultisig(ic *interop.Context, v *vm.VM, curve elliptic.Curve) error {
msg := getMessage(ic, v.Estack().Pop().Item())
hashToCheck := hash.Sha256(msg).BytesBE()
pkeys, err := v.Estack().PopSigElements()
if err != nil {
return fmt.Errorf("wrong parameters: %s", err.Error())
}
if !v.AddGas(ECDSAVerifyPrice * int64(len(pkeys))) {
return errors.New("gas limit exceeded")
}
sigs, err := v.Estack().PopSigElements()
if err != nil {
return fmt.Errorf("wrong parameters: %s", err.Error())
}
// It's ok to have more keys than there are signatures (it would
// just mean that some keys didn't sign), but not the other way around.
if len(pkeys) < len(sigs) {
return errors.New("more signatures than there are keys")
}
sigok := vm.CheckMultisigPar(v, curve, hashToCheck, pkeys, sigs)
v.Estack().PushVal(sigok)
return nil
}
func getMessage(ic *interop.Context, item stackitem.Item) []byte {
var msg []byte
switch val := item.(type) {
case *stackitem.Interop:
msg = val.Value().(crypto.Verifiable).GetSignedPart()
case stackitem.Null:
msg = ic.Container.GetSignedPart()
default:
var err error
if msg, err = val.TryBytes(); err != nil {
return nil
}
}
return msg
}