Merge pull request #857 from nspcc-dev/neo3/verifiable

core,crypto: implement Verifiable interface
This commit is contained in:
Roman Khimov 2020-04-17 13:06:55 +03:00 committed by GitHub
commit ab8296bc57
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 58 additions and 14 deletions

View file

@ -20,7 +20,7 @@ var _ block.Block = (*neoBlock)(nil)
// Sign implements block.Block interface. // Sign implements block.Block interface.
func (n *neoBlock) Sign(key crypto.PrivateKey) error { func (n *neoBlock) Sign(key crypto.PrivateKey) error {
data := n.Base.GetHashableData() data := n.Base.GetSignedPart()
sig, err := key.Sign(data[:]) sig, err := key.Sign(data[:])
if err != nil { if err != nil {
return err return err
@ -33,7 +33,7 @@ func (n *neoBlock) Sign(key crypto.PrivateKey) error {
// Verify implements block.Block interface. // Verify implements block.Block interface.
func (n *neoBlock) Verify(key crypto.PublicKey, sign []byte) error { func (n *neoBlock) Verify(key crypto.PublicKey, sign []byte) error {
data := n.Base.GetHashableData() data := n.Base.GetSignedPart()
return key.Verify(data, sign) return key.Verify(data, sign)
} }

View file

@ -186,7 +186,7 @@ func (p *Payload) EncodeBinary(w *io.BinWriter) {
// Sign signs payload using the private key. // Sign signs payload using the private key.
// It also sets corresponding verification and invocation scripts. // It also sets corresponding verification and invocation scripts.
func (p *Payload) Sign(key *privateKey) error { func (p *Payload) Sign(key *privateKey) error {
sig, err := key.Sign(p.MarshalUnsigned()) sig, err := key.Sign(p.GetSignedPart())
if err != nil { if err != nil {
return err return err
} }
@ -197,6 +197,11 @@ func (p *Payload) Sign(key *privateKey) error {
return nil return nil
} }
// GetSignedPart implements crypto.Verifiable interface.
func (p *Payload) GetSignedPart() []byte {
return p.MarshalUnsigned()
}
// Verify verifies payload using provided Witness. // Verify verifies payload using provided Witness.
func (p *Payload) Verify(scriptHash util.Uint160) bool { func (p *Payload) Verify(scriptHash util.Uint160) bool {
verification, err := core.ScriptFromWitness(scriptHash, &p.Witness) verification, err := core.ScriptFromWitness(scriptHash, &p.Witness)
@ -205,7 +210,7 @@ func (p *Payload) Verify(scriptHash util.Uint160) bool {
} }
v := vm.New() v := vm.New()
h := sha256.Sum256(p.MarshalUnsigned()) h := sha256.Sum256(p.GetSignedPart())
v.SetCheckedHash(h[:]) v.SetCheckedHash(h[:])
v.LoadScript(verification) v.LoadScript(verification)

View file

@ -90,8 +90,8 @@ func (b *Base) EncodeBinary(bw *io.BinWriter) {
b.Script.EncodeBinary(bw) b.Script.EncodeBinary(bw)
} }
// GetHashableData returns serialized hashable data of the block. // GetSignedPart returns serialized hashable data of the block.
func (b *Base) GetHashableData() []byte { func (b *Base) GetSignedPart() []byte {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
// No error can occure while encoding hashable fields. // No error can occure while encoding hashable fields.
b.encodeHashableFields(buf.BinWriter) b.encodeHashableFields(buf.BinWriter)
@ -106,7 +106,7 @@ func (b *Base) GetHashableData() []byte {
// Since MerkleRoot already contains the hash value of all transactions, // Since MerkleRoot already contains the hash value of all transactions,
// the modification of transaction will influence the hash value of the block. // the modification of transaction will influence the hash value of the block.
func (b *Base) createHash() { func (b *Base) createHash() {
bb := b.GetHashableData() bb := b.GetSignedPart()
b.verificationHash = hash.Sha256(bb) b.verificationHash = hash.Sha256(bb)
b.hash = hash.Sha256(b.verificationHash.BytesBE()) b.hash = hash.Sha256(b.verificationHash.BytesBE())
} }

View file

@ -2057,5 +2057,12 @@ func (bc *Blockchain) secondsPerBlock() int {
} }
func (bc *Blockchain) newInteropContext(trigger trigger.Type, d dao.DAO, block *block.Block, tx *transaction.Transaction) *interop.Context { func (bc *Blockchain) newInteropContext(trigger trigger.Type, d dao.DAO, block *block.Block, tx *transaction.Transaction) *interop.Context {
return interop.NewContext(trigger, bc, d, block, tx, bc.log) ic := interop.NewContext(trigger, bc, d, block, tx, bc.log)
switch {
case tx != nil:
ic.Container = tx
case block != nil:
ic.Container = block
}
return ic
} }

View file

@ -79,7 +79,7 @@ func newBlock(cfg config.ProtocolConfiguration, index uint32, prev util.Uint256,
if err != nil { if err != nil {
panic(err) panic(err)
} }
b := b.GetHashableData() b := b.GetSignedPart()
sig := pKey.Sign(b) sig := pKey.Sign(b)
if len(sig) != 64 { if len(sig) != 64 {
panic("wrong signature length") panic("wrong signature length")

View file

@ -6,6 +6,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/state" "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/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"go.uber.org/zap" "go.uber.org/zap"
@ -14,6 +15,7 @@ import (
// Context represents context in which interops are executed. // Context represents context in which interops are executed.
type Context struct { type Context struct {
Chain blockchainer.Blockchainer Chain blockchainer.Blockchainer
Container crypto.Verifiable
Trigger trigger.Type Trigger trigger.Type
Block *block.Block Block *block.Block
Tx *transaction.Transaction Tx *transaction.Transaction

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "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/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "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"
@ -48,10 +49,18 @@ func ECDSACheckMultisig(ic *interop.Context, v *vm.VM) error {
return nil return nil
} }
func getMessage(_ *interop.Context, item vm.StackItem) []byte { func getMessage(ic *interop.Context, item vm.StackItem) []byte {
msg, err := item.TryBytes() var msg []byte
if err != nil { switch val := item.(type) {
panic(err) case *vm.InteropItem:
msg = val.Value().(crypto.Verifiable).GetSignedPart()
case vm.NullItem:
msg = ic.Container.GetSignedPart()
default:
var err error
if msg, err = val.TryBytes(); err != nil {
return nil
}
} }
return msg return msg
} }

View file

@ -273,6 +273,21 @@ func TestECDSAVerify(t *testing.T) {
runCase(t, false, true, sign, priv.PublicKey().Bytes(), msg) runCase(t, false, true, sign, priv.PublicKey().Bytes(), msg)
}) })
t.Run("signed interop item", func(t *testing.T) {
tx := transaction.NewInvocationTX([]byte{0, 1, 2}, 1)
msg := tx.GetSignedPart()
sign := priv.Sign(msg)
runCase(t, false, true, sign, priv.PublicKey().Bytes(), vm.NewInteropItem(tx))
})
t.Run("signed script container", func(t *testing.T) {
tx := transaction.NewInvocationTX([]byte{0, 1, 2}, 1)
msg := tx.GetSignedPart()
sign := priv.Sign(msg)
ic.Container = tx
runCase(t, false, true, sign, priv.PublicKey().Bytes(), vm.NullItem{})
})
t.Run("missing arguments", func(t *testing.T) { t.Run("missing arguments", func(t *testing.T) {
runCase(t, true, false) runCase(t, true, false)
sign := priv.Sign(msg) sign := priv.Sign(msg)

View file

@ -246,7 +246,7 @@ func txGetHash(ic *interop.Context, v *vm.VM) error {
// engineGetScriptContainer returns transaction that contains the script being // engineGetScriptContainer returns transaction that contains the script being
// run. // run.
func engineGetScriptContainer(ic *interop.Context, v *vm.VM) error { func engineGetScriptContainer(ic *interop.Context, v *vm.VM) error {
v.Estack().PushVal(vm.NewInteropItem(ic.Tx)) v.Estack().PushVal(vm.NewInteropItem(ic.Container))
return nil return nil
} }

6
pkg/crypto/verifiable.go Normal file
View file

@ -0,0 +1,6 @@
package crypto
// Verifiable represents an object which can be verified.
type Verifiable interface {
GetSignedPart() []byte
}