forked from TrueCloudLab/neoneo-go
Merge pull request #857 from nspcc-dev/neo3/verifiable
core,crypto: implement Verifiable interface
This commit is contained in:
commit
ab8296bc57
10 changed files with 58 additions and 14 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
6
pkg/crypto/verifiable.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
package crypto
|
||||||
|
|
||||||
|
// Verifiable represents an object which can be verified.
|
||||||
|
type Verifiable interface {
|
||||||
|
GetSignedPart() []byte
|
||||||
|
}
|
Loading…
Reference in a new issue