crypto: remove crypto.Verifiable interface
We can now verify any hash.Hashable thing.
This commit is contained in:
parent
04e0ea2c0f
commit
df12adaa9e
14 changed files with 61 additions and 28 deletions
|
@ -6,6 +6,7 @@ import (
|
|||
"sync/atomic"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer/services"
|
||||
|
@ -14,7 +15,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/native"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"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/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -49,7 +50,7 @@ func NewFakeChain() *FakeChain {
|
|||
blocks: make(map[util.Uint256]*block.Block),
|
||||
hdrHashes: make(map[uint32]util.Uint256),
|
||||
txs: make(map[util.Uint256]*transaction.Transaction),
|
||||
ProtocolConfiguration: config.ProtocolConfiguration{P2PNotaryRequestPayloadPoolSize: 10},
|
||||
ProtocolConfiguration: config.ProtocolConfiguration{Magic: netmode.UnitTestNet, P2PNotaryRequestPayloadPoolSize: 10},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -393,7 +394,7 @@ func (chain *FakeChain) VerifyTx(*transaction.Transaction) error {
|
|||
}
|
||||
|
||||
// VerifyWitness implements Blockchainer interface.
|
||||
func (chain *FakeChain) VerifyWitness(util.Uint160, crypto.Verifiable, *transaction.Witness, int64) error {
|
||||
func (chain *FakeChain) VerifyWitness(util.Uint160, hash.Hashable, *transaction.Witness, int64) error {
|
||||
if chain.VerifyWitnessF != nil {
|
||||
return chain.VerifyWitnessF()
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/internal/fakechain"
|
||||
"github.com/nspcc-dev/neo-go/pkg/compiler"
|
||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||
|
@ -186,7 +187,8 @@ func TestAppCall(t *testing.T) {
|
|||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
ic := interop.NewContext(trigger.Application, nil, dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, false), contractGetter, nil, nil, nil, zaptest.NewLogger(t))
|
||||
fc := fakechain.NewFakeChain()
|
||||
ic := interop.NewContext(trigger.Application, fc, dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, false), contractGetter, nil, nil, nil, zaptest.NewLogger(t))
|
||||
|
||||
t.Run("valid script", func(t *testing.T) {
|
||||
src := getAppCallScript(fmt.Sprintf("%#v", ih.BytesBE()))
|
||||
|
|
|
@ -79,7 +79,7 @@ func TestConsensusPayload_Setters(t *testing.T) {
|
|||
func TestConsensusPayload_Serializable(t *testing.T) {
|
||||
for _, mt := range messageTypes {
|
||||
p := randomPayload(t, mt)
|
||||
actual := new(Payload)
|
||||
actual := &Payload{Extensible: npayload.Extensible{Network: netmode.UnitTestNet}}
|
||||
data, err := testserdes.EncodeBinary(p)
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, testserdes.DecodeBinary(data, &actual.Extensible))
|
||||
|
@ -158,6 +158,7 @@ func randomPayload(t *testing.T, mt messageType) *Payload {
|
|||
payload: randomMessage(t, mt),
|
||||
},
|
||||
Extensible: npayload.Extensible{
|
||||
Network: netmode.UnitTestNet,
|
||||
Witness: transaction.Witness{
|
||||
InvocationScript: random.Bytes(3),
|
||||
VerificationScript: []byte{byte(opcode.PUSH0)},
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/stateroot"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/storage"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"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/encoding/bigint"
|
||||
|
@ -1742,7 +1741,7 @@ func (bc *Blockchain) InitVerificationVM(v *vm.VM, getContract func(util.Uint160
|
|||
}
|
||||
|
||||
// VerifyWitness checks that w is a correct witness for c signed by h.
|
||||
func (bc *Blockchain) VerifyWitness(h util.Uint160, c crypto.Verifiable, w *transaction.Witness, gas int64) error {
|
||||
func (bc *Blockchain) VerifyWitness(h util.Uint160, c hash.Hashable, w *transaction.Witness, gas int64) error {
|
||||
ic := bc.newInteropContext(trigger.Verification, bc.dao, nil, nil)
|
||||
ic.Container = c
|
||||
_, err := bc.verifyHashAgainstScript(h, w, ic, gas)
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/mempool"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"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/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -71,7 +71,7 @@ type Blockchainer interface {
|
|||
SubscribeForNotifications(ch chan<- *state.NotificationEvent)
|
||||
SubscribeForTransactions(ch chan<- *transaction.Transaction)
|
||||
VerifyTx(*transaction.Transaction) error
|
||||
VerifyWitness(util.Uint160, crypto.Verifiable, *transaction.Witness, int64) error
|
||||
VerifyWitness(util.Uint160, hash.Hashable, *transaction.Witness, int64) error
|
||||
GetMemPool() *mempool.Pool
|
||||
UnsubscribeFromBlocks(ch chan<- *block.Block)
|
||||
UnsubscribeFromExecutions(ch chan<- *state.AppExecResult)
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
|
||||
|
@ -34,7 +34,8 @@ const (
|
|||
// Context represents context in which interops are executed.
|
||||
type Context struct {
|
||||
Chain blockchainer.Blockchainer
|
||||
Container crypto.Verifiable
|
||||
Container hash.Hashable
|
||||
Network uint32
|
||||
Natives []Contract
|
||||
Trigger trigger.Type
|
||||
Block *block.Block
|
||||
|
@ -55,6 +56,7 @@ func NewContext(trigger trigger.Type, bc blockchainer.Blockchainer, d dao.DAO,
|
|||
nes := make([]state.NotificationEvent, 0)
|
||||
return &Context{
|
||||
Chain: bc,
|
||||
Network: uint32(bc.GetConfig().Magic),
|
||||
Natives: natives,
|
||||
Trigger: trigger,
|
||||
Block: block,
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"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"
|
||||
)
|
||||
|
@ -14,7 +15,6 @@ import (
|
|||
// ECDSASecp256r1CheckMultisig checks multiple ECDSA signatures at once using
|
||||
// Secp256r1 elliptic curve.
|
||||
func ECDSASecp256r1CheckMultisig(ic *interop.Context) error {
|
||||
hashToCheck := ic.Container.GetSignedHash()
|
||||
pkeys, err := ic.VM.Estack().PopSigElements()
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong parameters: %w", err)
|
||||
|
@ -31,21 +31,20 @@ func ECDSASecp256r1CheckMultisig(ic *interop.Context) error {
|
|||
if len(pkeys) < len(sigs) {
|
||||
return errors.New("more signatures than there are keys")
|
||||
}
|
||||
sigok := vm.CheckMultisigPar(ic.VM, elliptic.P256(), hashToCheck.BytesBE(), pkeys, sigs)
|
||||
sigok := vm.CheckMultisigPar(ic.VM, elliptic.P256(), hash.NetSha256(ic.Network, ic.Container).BytesBE(), pkeys, sigs)
|
||||
ic.VM.Estack().PushVal(sigok)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ECDSASecp256r1CheckSig checks ECDSA signature using Secp256r1 elliptic curve.
|
||||
func ECDSASecp256r1CheckSig(ic *interop.Context) error {
|
||||
hashToCheck := ic.Container.GetSignedHash()
|
||||
keyb := ic.VM.Estack().Pop().Bytes()
|
||||
signature := ic.VM.Estack().Pop().Bytes()
|
||||
pkey, err := keys.NewPublicKeyFromBytes(keyb, elliptic.P256())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res := pkey.Verify(signature, hashToCheck.BytesBE())
|
||||
res := pkey.VerifyHashable(signature, ic.Network, ic.Container)
|
||||
ic.VM.Estack().PushVal(res)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -67,6 +67,7 @@ func initCheckMultisigVMNoArgs(container *transaction.Transaction) *vm.VM {
|
|||
binary.LittleEndian.PutUint32(buf[1:], neoCryptoCheckMultisigID)
|
||||
|
||||
ic := &interop.Context{
|
||||
Network: uint32(netmode.UnitTestNet),
|
||||
Trigger: trigger.Verification,
|
||||
Container: container,
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ func TestCheckSig(t *testing.T) {
|
|||
|
||||
verifyFunc := ECDSASecp256r1CheckSig
|
||||
d := dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, false)
|
||||
ic := &interop.Context{DAO: dao.NewCached(d)}
|
||||
ic := &interop.Context{Network: uint32(netmode.UnitTestNet), DAO: dao.NewCached(d)}
|
||||
runCase := func(t *testing.T, isErr bool, result interface{}, args ...interface{}) {
|
||||
ic.SpawnVM()
|
||||
for i := range args {
|
||||
|
|
|
@ -2,11 +2,34 @@ package hash
|
|||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"golang.org/x/crypto/ripemd160"
|
||||
)
|
||||
|
||||
// Hashable represents an object which can be hashed. Usually these objects
|
||||
// are io.Serializable and signable. They tend to cache the hash inside for
|
||||
// effectiveness, providing this accessor method. Anything that can be
|
||||
// identified with a hash can then be signed and verified.
|
||||
type Hashable interface {
|
||||
Hash() util.Uint256
|
||||
}
|
||||
|
||||
func getSignedData(net uint32, hh Hashable) []byte {
|
||||
var b = make([]byte, 4+32)
|
||||
binary.LittleEndian.PutUint32(b, net)
|
||||
h := hh.Hash()
|
||||
copy(b[4:], h[:])
|
||||
return b
|
||||
}
|
||||
|
||||
// NetSha256 calculates network-specific hash of Hashable item that can then
|
||||
// be signed/verified.
|
||||
func NetSha256(net uint32, hh Hashable) util.Uint256 {
|
||||
return Sha256(getSignedData(net, hh))
|
||||
}
|
||||
|
||||
// Sha256 hashes the incoming byte slice
|
||||
// using the sha256 algorithm.
|
||||
func Sha256(data []byte) util.Uint256 {
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/rfc6979"
|
||||
)
|
||||
|
@ -154,6 +155,12 @@ func (p *PrivateKey) SignHash(digest util.Uint256) []byte {
|
|||
return getSignatureSlice(p.PrivateKey.Curve, r, s)
|
||||
}
|
||||
|
||||
// SignHashable signs some Hashable item for the network specified using
|
||||
// hash.NetSha256() with the private key.
|
||||
func (p *PrivateKey) SignHashable(net uint32, hh hash.Hashable) []byte {
|
||||
return p.SignHash(hash.NetSha256(net, hh))
|
||||
}
|
||||
|
||||
func getSignatureSlice(curve elliptic.Curve, r, s *big.Int) []byte {
|
||||
params := curve.Params()
|
||||
curveOrderByteSize := params.P.BitLen() / 8
|
||||
|
|
|
@ -343,6 +343,13 @@ func (p *PublicKey) Verify(signature []byte, hash []byte) bool {
|
|||
return ecdsa.Verify(&pk, hash, rBytes, sBytes)
|
||||
}
|
||||
|
||||
// VerifyHashable returns true if the signature is valid and corresponds
|
||||
// to the hash and public key.
|
||||
func (p *PublicKey) VerifyHashable(signature []byte, net uint32, hh hash.Hashable) bool {
|
||||
var digest = hash.NetSha256(net, hh)
|
||||
return p.Verify(signature, digest[:])
|
||||
}
|
||||
|
||||
// IsInfinity checks if the key is infinite (null, basically).
|
||||
func (p *PublicKey) IsInfinity() bool {
|
||||
return p.X == nil && p.Y == nil
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
package crypto
|
||||
|
||||
import "github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
||||
// Verifiable represents an object which can be verified.
|
||||
type Verifiable interface {
|
||||
GetSignedPart() []byte
|
||||
GetSignedHash() util.Uint256
|
||||
}
|
||||
|
||||
// VerifiableDecodable represents an object which can be verified and
|
||||
// those hashable part can be encoded/decoded.
|
||||
type VerifiableDecodable interface {
|
||||
Verifiable
|
||||
EncodeHashableFields() ([]byte, error)
|
||||
DecodeHashableFields([]byte) error
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/blockchainer"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -93,7 +93,7 @@ func newTestChain() *testChain {
|
|||
},
|
||||
}
|
||||
}
|
||||
func (c *testChain) VerifyWitness(u util.Uint160, _ crypto.Verifiable, _ *transaction.Witness, _ int64) error {
|
||||
func (c *testChain) VerifyWitness(u util.Uint160, _ hash.Hashable, _ *transaction.Witness, _ int64) error {
|
||||
if !c.verifyWitness(u) {
|
||||
return errVerification
|
||||
}
|
||||
|
|
|
@ -119,7 +119,7 @@ func TestParameterContext_AddSignatureMultisig(t *testing.T) {
|
|||
}
|
||||
|
||||
func newTestVM(w *transaction.Witness, tx *transaction.Transaction) *vm.VM {
|
||||
ic := &interop.Context{Container: tx}
|
||||
ic := &interop.Context{Network: uint32(netmode.UnitTestNet), Container: tx}
|
||||
crypto.Register(ic)
|
||||
v := ic.SpawnVM()
|
||||
v.LoadScript(w.VerificationScript)
|
||||
|
|
Loading…
Reference in a new issue