diff --git a/pkg/vm/vm_ops.go b/pkg/vm/vm_ops.go index 016aebd2e..32b938992 100644 --- a/pkg/vm/vm_ops.go +++ b/pkg/vm/vm_ops.go @@ -5,6 +5,10 @@ import "github.com/CityOfZion/neo-go/pkg/vm/stack" type stackInfo func(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) var opFunc = map[stack.Instruction]stackInfo{ + stack.HASH256: HASH256, + stack.HASH160: HASH160, + stack.SHA256: SHA256, + stack.SHA1: SHA1, stack.XOR: Xor, stack.OR: Or, stack.AND: And, diff --git a/pkg/vm/vmopscrypto.go b/pkg/vm/vmopscrypto.go new file mode 100644 index 000000000..e38ab7402 --- /dev/null +++ b/pkg/vm/vmopscrypto.go @@ -0,0 +1,106 @@ +package vm + +import ( + "crypto/sha1" + + "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/vm/stack" +) + +// SHA1 pops an item off of the stack and +// pushes a bytearray onto the stack whose value +// is obtained by applying the sha1 algorithm to +// the corresponding bytearray representation of the item. +// Returns an error if the Pop method cannot be execute or +// the popped item does not have a concrete bytearray implementation. +func SHA1(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + ba, err := ctx.Estack.PopByteArray() + if err != nil { + return FAULT, err + } + + alg := sha1.New() + alg.Write(ba.Value()) + hash := alg.Sum(nil) + res := stack.NewByteArray(hash) + + ctx.Estack.Push(res) + + return NONE, nil +} + +// SHA256 pops an item off of the stack and +// pushes a bytearray onto the stack whose value +// is obtained by applying the Sha256 algorithm to +// the corresponding bytearray representation of the item. +// Returns an error if the Pop method cannot be execute or +// the popped item does not have a concrete bytearray implementation. +func SHA256(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + ba, err := ctx.Estack.PopByteArray() + if err != nil { + return FAULT, err + } + + hash, err := hash.Sha256(ba.Value()) + if err != nil { + return FAULT, err + } + + res := stack.NewByteArray(hash.Bytes()) + + ctx.Estack.Push(res) + + return NONE, nil +} + +// HASH160 pops an item off of the stack and +// pushes a bytearray onto the stack whose value +// is obtained by applying the Hash160 algorithm to +// the corresponding bytearray representation of the item. +// Returns an error if the Pop method cannot be execute or +// the popped item does not have a concrete bytearray implementation. +func HASH160(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + ba, err := ctx.Estack.PopByteArray() + if err != nil { + return FAULT, err + } + + hash, err := hash.Hash160(ba.Value()) + if err != nil { + return FAULT, err + } + + res := stack.NewByteArray(hash.Bytes()) + + ctx.Estack.Push(res) + + return NONE, nil +} + +// HASH256 pops an item off of the stack and +// pushes a bytearray onto the stack whose value +// is obtained by applying the Hash256 algorithm to +// the corresponding bytearray representation of the item. +// Returns an error if the Pop method cannot be execute or +// the popped item does not have a concrete bytearray implementation. +func HASH256(op stack.Instruction, ctx *stack.Context, istack *stack.Invocation, rstack *stack.RandomAccess) (Vmstate, error) { + + ba, err := ctx.Estack.PopByteArray() + if err != nil { + return FAULT, err + } + + hash, err := hash.DoubleSha256(ba.Value()) + if err != nil { + return FAULT, err + } + + res := stack.NewByteArray(hash.Bytes()) + + ctx.Estack.Push(res) + + return NONE, nil +} diff --git a/pkg/vm/vmopscrypto_test.go b/pkg/vm/vmopscrypto_test.go new file mode 100644 index 000000000..08e26a786 --- /dev/null +++ b/pkg/vm/vmopscrypto_test.go @@ -0,0 +1,101 @@ +package vm + +import ( + "encoding/hex" + "testing" + + "github.com/CityOfZion/neo-go/pkg/vm/stack" + "github.com/stretchr/testify/assert" +) + +func TestSha1Op(t *testing.T) { + + v := VM{} + + ba1 := stack.NewByteArray([]byte("this is test string")) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(ba1) + + v.executeOp(stack.SHA1, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.Pop() + assert.Nil(t, err) + + ba2, err := item.ByteArray() + assert.Nil(t, err) + + assert.Equal(t, "62d40fe74cf301cbfbe55c2679b96352449fb26d", hex.EncodeToString(ba2.Value())) +} + +func TestSha256Op(t *testing.T) { + + v := VM{} + + ba1 := stack.NewByteArray([]byte("this is test string")) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(ba1) + + v.executeOp(stack.SHA256, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.Pop() + assert.Nil(t, err) + + ba2, err := item.ByteArray() + assert.Nil(t, err) + + assert.Equal(t, "8e76c5b9e6be2559bedccbd0ff104ebe02358ba463a44a68e96caf55f9400de5", hex.EncodeToString(ba2.Value())) +} + +func TestHash160Op(t *testing.T) { + + v := VM{} + + ba1 := stack.NewByteArray([]byte("this is test string")) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(ba1) + + v.executeOp(stack.HASH160, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.Pop() + assert.Nil(t, err) + + ba2, err := item.ByteArray() + assert.Nil(t, err) + + assert.Equal(t, "e9c052b05a762ca9961a975db52e5417d99d958c", hex.EncodeToString(ba2.Value())) +} + +func TestHash256Op(t *testing.T) { + + v := VM{} + + ba1 := stack.NewByteArray([]byte("this is test string")) + + ctx := stack.NewContext([]byte{}) + ctx.Estack.Push(ba1) + + v.executeOp(stack.HASH256, ctx) + + // Stack should have one item + assert.Equal(t, 1, ctx.Estack.Len()) + + item, err := ctx.Estack.Pop() + assert.Nil(t, err) + + ba2, err := item.ByteArray() + assert.Nil(t, err) + + assert.Equal(t, "90ef790ee2557a3f9a1ba0e6910a9ff0ea75af3767ea7380760d729ac9927a60", hex.EncodeToString(ba2.Value())) +}