Merge pull request #267 from dauTT/dauTT/vm-crypto-opcode-194

VM: Implement SHA1, SHA256, HASH160, HASH256 opcode, closes #268.

Implemented
1) SHA1
2) SHA256
3) HASH160
4) HASH256
This commit is contained in:
Roman Khimov 2019-08-12 12:40:18 +03:00 committed by GitHub
commit cdb92ebaa2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 211 additions and 0 deletions

View file

@ -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,

106
pkg/vm/vmopscrypto.go Normal file
View file

@ -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
}

101
pkg/vm/vmopscrypto_test.go Normal file
View file

@ -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()))
}