Skip to content

Commit

Permalink
interop: add keccak256 implementation
Browse files Browse the repository at this point in the history
Port neo-project/neo#2925.

Closes #3295

Signed-off-by: Ekaterina Pavlova <ekt@morphbits.io>
  • Loading branch information
AliceInHunterland committed Jan 25, 2024
1 parent ef99a7a commit 8b005d6
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions pkg/compiler/native_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ func TestNativeHelpersCompile(t *testing.T) {
{"bls12381Add", []string{"crypto.Bls12381Point{}", "crypto.Bls12381Point{}"}},
{"bls12381Mul", []string{"crypto.Bls12381Point{}", "[]byte{1, 2, 3}", "true"}},
{"bls12381Pairing", []string{"crypto.Bls12381Point{}", "crypto.Bls12381Point{}"}},
{"keccak256", []string{"[]byte{1, 2, 3}"}},
})
runNativeTestCases(t, cs.Std.ContractMD, "std", []nativeTestCase{
{"serialize", []string{"[]byte{1, 2, 3}"}},
Expand Down
19 changes: 19 additions & 0 deletions pkg/core/native/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
"github.com/twmb/murmur3"
"golang.org/x/crypto/sha3"
)

// Crypto represents CryptoLib contract.
Expand Down Expand Up @@ -101,6 +102,10 @@ func newCrypto() *Crypto {
md = newMethodAndPrice(c.bls12381Pairing, 1<<23, callflag.NoneFlag)
c.AddMethod(md, desc)

desc = newDescriptor("keccak256", smartcontract.ByteArrayType,
manifest.NewParameter("data", smartcontract.ByteArrayType))
md = newMethodAndPrice(c.sha256, 1<<15, callflag.NoneFlag)
c.AddMethod(md, desc)
return c
}

Expand Down Expand Up @@ -285,6 +290,20 @@ func (c *Crypto) bls12381Pairing(_ *interop.Context, args []stackitem.Item) stac
return stackitem.NewInterop(p)
}

func (c *Crypto) keccak256(_ *interop.Context, args []stackitem.Item) stackitem.Item {
bs, err := args[0].TryBytes()
if err != nil {
panic(err)
}

digest := sha3.NewLegacyKeccak256()
_, err = digest.Write(bs)
if err != nil {
panic(err)
}
return stackitem.NewByteArray(digest.Sum(nil))
}

// Metadata implements the Contract interface.
func (c *Crypto) Metadata() *interop.ContractMD {
return &c.ContractMD
Expand Down
64 changes: 64 additions & 0 deletions pkg/core/native/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,70 @@ func TestSha256(t *testing.T) {
require.Equal(t, "47dc540c94ceb704a23875c11273e16bb0b8a87aed84de911f2133568115f254", hex.EncodeToString(c.sha256(ic, []stackitem.Item{stackitem.NewByteArray([]byte{1, 0})}).Value().([]byte)))
})
}
func TestKeccak256(t *testing.T) {
c := newCrypto()
ic := &interop.Context{VM: vm.New()}

t.Run("bad arg type", func(t *testing.T) {
require.Panics(t, func() {
c.keccak256(ic, []stackitem.Item{stackitem.NewInterop(nil)})
})
})
t.Run("good", func(t *testing.T) {
// 0x0100 hashes to 628bf3596747d233f1e6533345700066bf458fa48daedaf04a7be6c392902476
require.Equal(t, "628bf3596747d233f1e6533345700066bf458fa48daedaf04a7be6c392902476", hex.EncodeToString(c.keccak256(ic, []stackitem.Item{stackitem.NewByteArray([]byte{1, 0})}).Value().([]byte)))
})

t.Run("hello world", func(t *testing.T) {
inputData := []byte("Hello, World!")
expectedHashHex := "acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f"

result := c.keccak256(ic, []stackitem.Item{stackitem.NewByteArray(inputData)}).Value().([]byte)
outputHashHex := hex.EncodeToString(result)

require.Equal(t, expectedHashHex, outputHashHex)
})

t.Run("cryptography", func(t *testing.T) {
inputData := []byte("Cryptography")
expectedHashHex := "53d49d225dd2cfe77d8c5e2112bcc9efe77bea1c7aa5e5ede5798a36e99e2d29"

result := c.keccak256(ic, []stackitem.Item{stackitem.NewByteArray(inputData)}).Value().([]byte)
outputHashHex := hex.EncodeToString(result)

require.Equal(t, expectedHashHex, outputHashHex)
})

t.Run("testing123", func(t *testing.T) {
inputData := []byte("Testing123")
expectedHashHex := "3f82db7b16b0818a1c6b2c6152e265f682d5ebcf497c9aad776ad38bc39cb6ca"

result := c.keccak256(ic, []stackitem.Item{stackitem.NewByteArray(inputData)}).Value().([]byte)
outputHashHex := hex.EncodeToString(result)

require.Equal(t, expectedHashHex, outputHashHex)
})

t.Run("long string", func(t *testing.T) {
inputData := []byte("This is a longer string for Keccak256 testing purposes.")
expectedHashHex := "24115e5c2359f85f6840b42acd2f7ea47bc239583e576d766fa173bf711bdd2f"

result := c.keccak256(ic, []stackitem.Item{stackitem.NewByteArray(inputData)}).Value().([]byte)
outputHashHex := hex.EncodeToString(result)

require.Equal(t, expectedHashHex, outputHashHex)
})

t.Run("blanc string", func(t *testing.T) {
inputData := []byte("")
expectedHashHex := "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"

result := c.keccak256(ic, []stackitem.Item{stackitem.NewByteArray(inputData)}).Value().([]byte)
outputHashHex := hex.EncodeToString(result)

require.Equal(t, expectedHashHex, outputHashHex)
})
}

func TestRIPEMD160(t *testing.T) {
c := newCrypto()
Expand Down
5 changes: 5 additions & 0 deletions pkg/interop/native/crypto/crypto.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,8 @@ func Bls12381Mul(x Bls12381Point, mul []byte, neg bool) Bls12381Point {
func Bls12381Pairing(g1, g2 Bls12381Point) Bls12381Point {
return neogointernal.CallWithToken(Hash, "bls12381Pairing", int(contract.NoneFlag), g1, g2).(Bls12381Point)
}

// Keccak256 calls `keccak256` method of native CryptoLib contract and computes Keccak256 hash of b.
func Keccak256(b []byte) interop.Hash256 {
return neogointernal.CallWithToken(Hash, "keccak256", int(contract.NoneFlag), b).(interop.Hash256)
}

0 comments on commit 8b005d6

Please sign in to comment.