diff --git a/examples/engine/go.mod b/examples/engine/go.mod index b8c1f57b6..a3e1af0dc 100644 --- a/examples/engine/go.mod +++ b/examples/engine/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/engine go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/engine/go.sum b/examples/engine/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/engine/go.sum +++ b/examples/engine/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/events/go.mod b/examples/events/go.mod index b0bda4b37..8c9910e5a 100644 --- a/examples/events/go.mod +++ b/examples/events/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/events go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/events/go.sum b/examples/events/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/events/go.sum +++ b/examples/events/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/iterator/go.mod b/examples/iterator/go.mod index 2b3d13d3e..57de4a87e 100644 --- a/examples/iterator/go.mod +++ b/examples/iterator/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/iterator go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/iterator/go.sum b/examples/iterator/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/iterator/go.sum +++ b/examples/iterator/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/nft-d/go.mod b/examples/nft-d/go.mod index 42df68efc..87060a972 100644 --- a/examples/nft-d/go.mod +++ b/examples/nft-d/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/nft-d/go.sum b/examples/nft-d/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/nft-d/go.sum +++ b/examples/nft-d/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/nft-nd-nns/go.mod b/examples/nft-nd-nns/go.mod index 78522923e..249993a39 100644 --- a/examples/nft-nd-nns/go.mod +++ b/examples/nft-nd-nns/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb github.com/stretchr/testify v1.8.4 ) diff --git a/examples/nft-nd-nns/go.sum b/examples/nft-nd-nns/go.sum index bb122c9db..2e6044811 100644 --- a/examples/nft-nd-nns/go.sum +++ b/examples/nft-nd-nns/go.sum @@ -200,8 +200,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689 h1:WnEdGAQwaW0C8wnNnQZ+rM/JfFKZDSTOqwm8cS0TOdk= github.com/nspcc-dev/neo-go v0.102.1-0.20231020181554-d89c8801d689/go.mod h1:x+wmcYqpZYJwLp1l/pHZrqNp3RSWlkMymWGDij3/OPo= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= diff --git a/examples/nft-nd/go.mod b/examples/nft-nd/go.mod index e9f47c373..b84c32fb7 100644 --- a/examples/nft-nd/go.mod +++ b/examples/nft-nd/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/nft-nd go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/nft-nd/go.sum b/examples/nft-nd/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/nft-nd/go.sum +++ b/examples/nft-nd/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/oracle/go.mod b/examples/oracle/go.mod index cf5e26961..031ffbf68 100644 --- a/examples/oracle/go.mod +++ b/examples/oracle/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/oracle go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/oracle/go.sum b/examples/oracle/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/oracle/go.sum +++ b/examples/oracle/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/runtime/go.mod b/examples/runtime/go.mod index d49e669e2..a243086af 100644 --- a/examples/runtime/go.mod +++ b/examples/runtime/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/runtime go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/runtime/go.sum b/examples/runtime/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/runtime/go.sum +++ b/examples/runtime/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/storage/go.mod b/examples/storage/go.mod index 786d4d324..f4eca85b6 100644 --- a/examples/storage/go.mod +++ b/examples/storage/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/storage go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/storage/go.sum b/examples/storage/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/storage/go.sum +++ b/examples/storage/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/timer/go.mod b/examples/timer/go.mod index e00b24175..95043975b 100644 --- a/examples/timer/go.mod +++ b/examples/timer/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/timer go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/timer/go.sum b/examples/timer/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/timer/go.sum +++ b/examples/timer/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/token/go.mod b/examples/token/go.mod index 64494aad8..077dd8891 100644 --- a/examples/token/go.mod +++ b/examples/token/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/token go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/token/go.sum b/examples/token/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/token/go.sum +++ b/examples/token/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/examples/zkp/cubic_circuit/go.mod b/examples/zkp/cubic_circuit/go.mod index 54702a26a..bab4104c3 100644 --- a/examples/zkp/cubic_circuit/go.mod +++ b/examples/zkp/cubic_circuit/go.mod @@ -33,7 +33,7 @@ require ( github.com/mmcloughlin/addchain v0.4.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c // indirect - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 // indirect + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb // indirect github.com/nspcc-dev/rfc6979 v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.13.0 // indirect diff --git a/examples/zkp/cubic_circuit/go.sum b/examples/zkp/cubic_circuit/go.sum index 59d49427b..809bda2cb 100644 --- a/examples/zkp/cubic_circuit/go.sum +++ b/examples/zkp/cubic_circuit/go.sum @@ -216,8 +216,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20231123160306-3374ff1e7a3c/go.mod h github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/neo-go v0.103.1 h1:BfRBceHUu8jSc1KQy7CzmQ/pa+xzAmgcyteGf0/IGgM= github.com/nspcc-dev/neo-go v0.103.1/go.mod h1:MD7MPiyshUwrE5n1/LzxeandbItaa/iLW/bJb6gNs/U= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 h1:QOc8ZRN5DXlAeRPh5QG9u8rMLgoeRNiZF5/vL7QupWg= diff --git a/examples/zkp/xor_compat/go.mod b/examples/zkp/xor_compat/go.mod index a605846d1..8882b7ca2 100644 --- a/examples/zkp/xor_compat/go.mod +++ b/examples/zkp/xor_compat/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/examples/zkp/xor go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/examples/zkp/xor_compat/go.sum b/examples/zkp/xor_compat/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/examples/zkp/xor_compat/go.sum +++ b/examples/zkp/xor_compat/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/go.mod b/go.mod index 75cee142c..0b7590384 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/mr-tron/base58 v1.2.0 github.com/nspcc-dev/dbft v0.2.0 github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 - github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 + github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.11 github.com/nspcc-dev/rfc6979 v0.2.1 github.com/pierrec/lz4 v2.6.1+incompatible diff --git a/go.sum b/go.sum index b0e22e3b6..0b6fe0e15 100644 --- a/go.sum +++ b/go.sum @@ -94,8 +94,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 h1:jhuN8Ldqz7WApvUJRFY0bjRXE1R3iCkboMX5QVZhHVk= github.com/nspcc-dev/neofs-api-go/v2 v2.14.0/go.mod h1:DRIr0Ic1s+6QgdqmNFNLIqMqd7lNMJfYwkczlm1hDtM= github.com/nspcc-dev/neofs-crypto v0.4.0 h1:5LlrUAM5O0k1+sH/sktBtrgfWtq1pgpDs09fZo+KYi4= diff --git a/internal/contracts/oracle_contract/go.mod b/internal/contracts/oracle_contract/go.mod index 2fe0af1fd..f6959e04b 100644 --- a/internal/contracts/oracle_contract/go.mod +++ b/internal/contracts/oracle_contract/go.mod @@ -2,4 +2,4 @@ module github.com/nspcc-dev/neo-go/internal/examples/oracle go 1.20 -require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 +require github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb diff --git a/internal/contracts/oracle_contract/go.sum b/internal/contracts/oracle_contract/go.sum index 84d8058e4..0d9f2bcc7 100644 --- a/internal/contracts/oracle_contract/go.sum +++ b/internal/contracts/oracle_contract/go.sum @@ -1,2 +1,2 @@ -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7 h1:wULMfaNToxlinz9cYWyZA4kAy6CTUBtJ1yFHjCSgs10= -github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240322141543-1840c057bdd7/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb h1:yU1nu3dtytjkHWHNQBdSKnHs6jU9wtNcXn3Hn46EfNY= +github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240513071056-6e0926e59ffb/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY= diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go index 47a2a7433..249e6717e 100644 --- a/pkg/compiler/native_test.go +++ b/pkg/compiler/native_test.go @@ -74,8 +74,10 @@ func TestRoleManagementRole(t *testing.T) { } func TestCryptoLibNamedCurve(t *testing.T) { - require.EqualValues(t, native.Secp256k1, crypto.Secp256k1) - require.EqualValues(t, native.Secp256r1, crypto.Secp256r1) + require.EqualValues(t, native.Secp256k1Sha256, crypto.Secp256k1Sha256) + require.EqualValues(t, native.Secp256r1Sha256, crypto.Secp256r1Sha256) + require.EqualValues(t, native.Secp256k1Keccak256, crypto.Secp256k1Keccak256) + require.EqualValues(t, native.Secp256r1Keccak256, crypto.Secp256r1Keccak256) } func TestOracleContractValues(t *testing.T) { @@ -233,7 +235,7 @@ func TestNativeHelpersCompile(t *testing.T) { {"sha256", []string{"[]byte{1, 2, 3}"}}, {"ripemd160", []string{"[]byte{1, 2, 3}"}}, {"murmur32", []string{"[]byte{1, 2, 3}", "123"}}, - {"verifyWithECDsa", []string{"[]byte{1, 2, 3}", pub, sig, "crypto.Secp256k1"}}, + {"verifyWithECDsa", []string{"[]byte{1, 2, 3}", pub, sig, "crypto.Secp256k1Sha256"}}, {"bls12381Serialize", []string{"crypto.Bls12381Point{}"}}, {"bls12381Deserialize", []string{"[]byte{1, 2, 3}"}}, {"bls12381Equal", []string{"crypto.Bls12381Point{}", "crypto.Bls12381Point{}"}}, diff --git a/pkg/core/native/crypto.go b/pkg/core/native/crypto.go index 81979bfbd..d63a20c70 100644 --- a/pkg/core/native/crypto.go +++ b/pkg/core/native/crypto.go @@ -18,6 +18,7 @@ import ( "github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" + "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/twmb/murmur3" "golang.org/x/crypto/sha3" @@ -28,13 +29,18 @@ type Crypto struct { interop.ContractMD } -// NamedCurve identifies named elliptic curves. -type NamedCurve byte +// HashFunc is a delegate representing a hasher function with 256 bytes output length. +type HashFunc func([]byte) util.Uint256 -// Various named elliptic curves. +// NamedCurveHash identifies a pair of named elliptic curve and hash function. +type NamedCurveHash byte + +// Various pairs of named elliptic curves and hash functions. const ( - Secp256k1 NamedCurve = 22 - Secp256r1 NamedCurve = 23 + Secp256k1Sha256 NamedCurveHash = 22 + Secp256r1Sha256 NamedCurveHash = 23 + Secp256k1Keccak256 NamedCurveHash = 122 + Secp256r1Keccak256 NamedCurveHash = 123 ) const cryptoContractID = -3 @@ -63,7 +69,7 @@ func newCrypto() *Crypto { manifest.NewParameter("message", smartcontract.ByteArrayType), manifest.NewParameter("pubkey", smartcontract.ByteArrayType), manifest.NewParameter("signature", smartcontract.ByteArrayType), - manifest.NewParameter("curve", smartcontract.IntegerType)) + manifest.NewParameter("curveHash", smartcontract.IntegerType)) md = newMethodAndPrice(c.verifyWithECDsa, 1<<15, callflag.NoneFlag) c.AddMethod(md, desc) @@ -142,7 +148,6 @@ func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stac if err != nil { panic(fmt.Errorf("invalid message stackitem: %w", err)) } - hashToCheck := hash.Sha256(msg) pubkey, err := args[1].TryBytes() if err != nil { panic(fmt.Errorf("invalid pubkey stackitem: %w", err)) @@ -151,10 +156,11 @@ func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stac if err != nil { panic(fmt.Errorf("invalid signature stackitem: %w", err)) } - curve, err := curveFromStackitem(args[3]) + curve, hasher, err := curveHasherFromStackitem(args[3]) if err != nil { - panic(fmt.Errorf("invalid curve stackitem: %w", err)) + panic(fmt.Errorf("invalid curveHash stackitem: %w", err)) } + hashToCheck := hasher(msg) pkey, err := keys.NewPublicKeyFromBytes(pubkey, curve) if err != nil { panic(fmt.Errorf("failed to decode pubkey: %w", err)) @@ -163,22 +169,26 @@ func (c *Crypto) verifyWithECDsa(_ *interop.Context, args []stackitem.Item) stac return stackitem.NewBool(res) } -func curveFromStackitem(si stackitem.Item) (elliptic.Curve, error) { +func curveHasherFromStackitem(si stackitem.Item) (elliptic.Curve, HashFunc, error) { curve, err := si.TryInteger() if err != nil { - return nil, err + return nil, nil, err } if !curve.IsInt64() { - return nil, errors.New("not an int64") + return nil, nil, errors.New("not an int64") } c := curve.Int64() switch c { - case int64(Secp256k1): - return secp256k1.S256(), nil - case int64(Secp256r1): - return elliptic.P256(), nil + case int64(Secp256k1Sha256): + return secp256k1.S256(), hash.Sha256, nil + case int64(Secp256r1Sha256): + return elliptic.P256(), hash.Sha256, nil + case int64(Secp256k1Keccak256): + return secp256k1.S256(), Keccak256, nil + case int64(Secp256r1Keccak256): + return elliptic.P256(), Keccak256, nil default: - return nil, errors.New("unsupported curve type") + return nil, nil, errors.New("unsupported curve/hash type") } } @@ -295,13 +305,7 @@ func (c *Crypto) keccak256(_ *interop.Context, args []stackitem.Item) stackitem. if err != nil { panic(err) } - - digest := sha3.NewLegacyKeccak256() - _, err = digest.Write(bs) - if err != nil { - panic(err) - } - return stackitem.NewByteArray(digest.Sum(nil)) + return stackitem.NewByteArray(Keccak256(bs).BytesBE()) } // Metadata implements the Contract interface. @@ -333,3 +337,14 @@ func (c *Crypto) PostPersist(ic *interop.Context) error { func (c *Crypto) ActiveIn() *config.Hardfork { return nil } + +// Keccak256 hashes the incoming byte slice using the +// keccak256 algorithm. +func Keccak256(data []byte) util.Uint256 { + var hash util.Uint256 + hasher := sha3.NewLegacyKeccak256() + _, _ = hasher.Write(data) + + hasher.Sum(hash[:0]) + return hash +} diff --git a/pkg/core/native/crypto_test.go b/pkg/core/native/crypto_test.go index d5d79355e..0227a9da8 100644 --- a/pkg/core/native/crypto_test.go +++ b/pkg/core/native/crypto_test.go @@ -9,6 +9,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/nspcc-dev/neo-go/pkg/core/interop" + "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/vm" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" @@ -118,29 +119,44 @@ func TestMurmur32(t *testing.T) { } func TestCryptoLibVerifyWithECDsa(t *testing.T) { - t.Run("R1", func(t *testing.T) { - testECDSAVerify(t, Secp256r1) + t.Run("R1 sha256", func(t *testing.T) { + testECDSAVerify(t, Secp256r1Sha256) }) - t.Run("K1", func(t *testing.T) { - testECDSAVerify(t, Secp256k1) + t.Run("K1 sha256", func(t *testing.T) { + testECDSAVerify(t, Secp256k1Sha256) + }) + t.Run("R1 keccak256", func(t *testing.T) { + testECDSAVerify(t, Secp256r1Keccak256) + }) + t.Run("K1 keccak256", func(t *testing.T) { + testECDSAVerify(t, Secp256k1Keccak256) }) } -func testECDSAVerify(t *testing.T, curve NamedCurve) { +func testECDSAVerify(t *testing.T, curve NamedCurveHash) { var ( priv *keys.PrivateKey err error c = newCrypto() ic = &interop.Context{VM: vm.New()} actual stackitem.Item + hasher HashFunc ) switch curve { - case Secp256k1: + case Secp256k1Sha256: priv, err = keys.NewSecp256k1PrivateKey() - case Secp256r1: + hasher = hash.Sha256 + case Secp256r1Sha256: priv, err = keys.NewPrivateKey() + hasher = hash.Sha256 + case Secp256k1Keccak256: + priv, err = keys.NewSecp256k1PrivateKey() + hasher = Keccak256 + case Secp256r1Keccak256: + priv, err = keys.NewPrivateKey() + hasher = Keccak256 default: - t.Fatal("unknown curve") + t.Fatal("unknown curve/hash") } require.NoError(t, err) @@ -162,7 +178,7 @@ func testECDSAVerify(t *testing.T, curve NamedCurve) { } msg := []byte("test message") - sign := priv.Sign(msg) + sign := priv.SignHash(hasher(msg)) t.Run("bad message item", func(t *testing.T) { runCase(t, true, false, stackitem.NewInterop("cheburek"), priv.PublicKey().Bytes(), sign, int64(curve)) @@ -183,7 +199,7 @@ func testECDSAVerify(t *testing.T, curve NamedCurve) { runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, new(big.Int).Add(big.NewInt(math.MaxInt64), big.NewInt(1))) }) t.Run("unknown curve", func(t *testing.T) { - runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, int64(123)) + runCase(t, true, false, msg, priv.PublicKey().Bytes(), sign, int64(124)) }) t.Run("invalid signature", func(t *testing.T) { s := priv.Sign(msg) @@ -254,3 +270,13 @@ func TestCryptolib_ScalarFromBytes_Compat(t *testing.T) { }) } } + +func TestKeccak256(t *testing.T) { + input := []byte("hello") + data := Keccak256(input) + + expected := "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8" + actual := hex.EncodeToString(data.BytesBE()) + + require.Equal(t, expected, actual) +} diff --git a/pkg/core/native/native_test/cryptolib_verification_test.go b/pkg/core/native/native_test/cryptolib_verification_test.go new file mode 100644 index 000000000..2143a1217 --- /dev/null +++ b/pkg/core/native/native_test/cryptolib_verification_test.go @@ -0,0 +1,893 @@ +package native_test + +import ( + "math/big" + "sort" + "testing" + + "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" + "github.com/nspcc-dev/neo-go/pkg/core/native" + "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" + "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/crypto/hash" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" + "github.com/nspcc-dev/neo-go/pkg/io" + "github.com/nspcc-dev/neo-go/pkg/neotest" + "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" + "github.com/nspcc-dev/neo-go/pkg/util" + "github.com/nspcc-dev/neo-go/pkg/vm/emit" + "github.com/nspcc-dev/neo-go/pkg/vm/opcode" + "github.com/stretchr/testify/require" +) + +// TestCryptoLib_KoblitzVerificationScript builds transaction with custom witness that contains +// the Koblitz tx signature bytes and Koblitz signature verification script. +// This test ensures that transaction signed by Koblitz key passes verification and can +// be successfully accepted to the chain. +func TestCryptoLib_KoblitzVerificationScript(t *testing.T) { + check := func( + t *testing.T, + buildVerificationScript func(t *testing.T, pub *keys.PublicKey) []byte, + constructMsg func(t *testing.T, magic uint32, tx hash.Hashable) []byte, + ) { + c := newGasClient(t) + gasInvoker := c.WithSigners(c.Committee) + e := c.Executor + + // Consider the user that is able to sign txs only with Secp256k1 private key. + // Let this user build, sign and push a GAS transfer transaction from its account + // to some other account. + pk, err := keys.NewSecp256k1PrivateKey() + require.NoError(t, err) + + // Firstly, we need to build the N3 user's account address based on the user's public key. + // The address itself is Hash160 from the verification script corresponding to the user's public key. + // Since user's private key belongs to Koblitz curve, we can't use System.Crypto.CheckSig interop + // in the verification script. Likely, we have a 'verifyWithECDsa' method in native CriptoLib contract + // that is able to check Koblitz signature. So let's build custom verification script based on this call. + // The script should call 'verifyWithECDsa' method of native CriptoLib contract with Koblitz curve identifier + // and check the provided message signature against the user's Koblitz public key. + vrfBytes := buildVerificationScript(t, pk.PublicKey()) + + // Construct the user's account script hash. It's effectively a verification script hash. + from := hash.Hash160(vrfBytes) + + // Supply this account with some initial balance so that the user is able to pay for his transactions. + gasInvoker.Invoke(t, true, "transfer", c.Committee.ScriptHash(), from, 10000_0000_0000, nil) + + // Construct transaction that transfers 5 GAS from the user's account to some other account. + to := util.Uint160{1, 2, 3} + amount := 5 + tx := gasInvoker.PrepareInvokeNoSign(t, "transfer", from, to, amount, nil) + tx.Signers = []transaction.Signer{ + { + Account: from, + Scopes: transaction.CalledByEntry, + }, + } + neotest.AddNetworkFee(t, e.Chain, tx) + neotest.AddSystemFee(e.Chain, tx, -1) + + // Add some more network fee to pay for the witness verification. This value may be calculated precisely, + // but let's keep some inaccurate value for the test. + tx.NetworkFee += 540_0000 + + // This transaction (along with the network magic) should be signed by the user's Koblitz private key. + msg := constructMsg(t, uint32(e.Chain.GetConfig().Magic), tx) + + // The user has to sign the hash of the message by his Koblitz key. + // Please, note that this Keccak256 hash may easily be replaced by sha256 hash if needed. + signature := pk.SignHash(native.Keccak256(msg)) + + // Ensure that signature verification passes. This line here is just for testing purposes, + // it won't be present in the real code. + require.True(t, pk.PublicKey().Verify(signature, native.Keccak256(msg).BytesBE())) + + // Build invocation witness script for the user's account. + invBytes := buildKoblitzInvocationScript(t, [][]byte{signature}) + + // Construct witness for signer #0 (the user itself). + tx.Scripts = []transaction.Witness{ + { + InvocationScript: invBytes, + VerificationScript: vrfBytes, + }, + } + + // Add transaction to the chain. No error is expected on new block addition. Note, that this line performs + // all those checks that are executed during transaction acceptance in the real network. + e.AddNewBlock(t, tx) + + // Double-check: ensure funds have been transferred. + e.CheckGASBalance(t, to, big.NewInt(int64(amount))) + } + + // The proposed preferable witness verification script + // (110 bytes, 2154270 GAS including Invocation script execution). + // The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). + check(t, buildKoblitzVerificationScript, constructMessage) + + // Below presented some variations of verification scripts that were also considered, but + // they are not as good as the first one. + + // The simplest witness verification script with low length and low execution cost + // (98 bytes, 2092530 GAS including Invocation script execution). + // The user has to sign the keccak256([var-bytes-network-magic, txHash-bytes-BE]). + check(t, buildKoblitzVerificationScriptSimpleSingleHash, constructMessageNoHash) + + // Even more simple witness verification script with low length and low execution cost + // (95 bytes, 2092320 GAS including Invocation script execution). + // The user has to sign the keccak256([var-bytes-network-magic, txHash-bytes-BE]). + // The difference is that network magic is a static value, thus, both verification script and + // user address are network-specific. + check(t, buildKoblitzVerificationScriptSimpleSingleHashStaticMagic, constructMessageNoHash) + + // More complicated verification script with higher length and higher execution cost + // (136 bytes, 4120620 GAS including Invocation script execution). + // The user has to sign the keccak256(sha256([var-bytes-network-magic, txHash-bytes-BE])). + check(t, buildKoblitzVerificationScriptSimple, constructMessageSimple) + + // Witness verification script that follows the existing standard CheckSig account generation rules + // and has larger length and higher execution cost. + // (186 bytes, 5116020 GAS including Invocation script execution). + // The user has to sign the keccak256(sha256([4-bytes-network-magic-LE, txHash-bytes-BE])) + check(t, buildKoblitzVerificationScriptCompat, constructMessageCompat) +} + +// buildKoblitzVerificationScript builds witness verification script for Koblitz public key. +// This method checks +// +// keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]) +// +// instead of (comparing with N3) +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). +func buildKoblitzVerificationScript(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = [4-network-magic-bytes-LE, tx-hash-BE] + // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic (Integer stackitem), can have 0-5 bytes length serialized. + // Convert network magic to 4-bytes-length LE byte array representation. + emit.Int(vrf.BinWriter, 0x100000000) + emit.Opcodes(vrf.BinWriter, opcode.ADD, // some new number that is 5 bytes at least when serialized, but first 4 bytes are intact network value (LE). + opcode.PUSH4, opcode.LEFT) // cut the first 4 bytes out of a number that is at least 5 bytes long, the result is 4-bytes-length LE network representation. + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM) // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (110 bytes length, always constant length, with constant length of signed data): + // NEO-GO-VM > loadbase64 ABhQDCECoIi/qx5LS+3n1GJFcoYbQByyDDsU6QaHvYhiJypOYWZBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1I= + // READY: loaded 110 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 122 (7a) << + // 2 SWAP + // 3 PUSHDATA1 02a088bfab1e4b4bede7d4624572861b401cb20c3b14e90687bd8862272a4e6166 + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 PUSHINT64 4294967296 (0000000001000000) + // 52 ADD + // 53 PUSH4 + // 54 LEFT + // 55 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 60 PUSH0 + // 61 PICKITEM + // 62 CAT + // 63 PUSH4 + // 64 PACK + // 65 PUSH0 + // 66 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 83 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 105 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzVerificationScriptSimpleSingleHash builds witness verification script for Koblitz public key. +// This method differs from buildKoblitzVerificationScriptCompat in that it checks +// +// keccak256([var-bytes-network-magic, txHash-bytes-BE]) +// +// instead of (comparing with N3) +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). +func buildKoblitzVerificationScriptSimpleSingleHash(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + // vrf is witness verification script corresponding to the pk. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = [network-magic-bytes, tx.Hash()] + // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic. + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM) // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (98 bytes length, always constant length, with variable length of signed data): + // NEO-GO-VM > loadbase64 ABZQDCEDY9ekgSWnbN6m4JjJ8SjoKSDtQo5ftMrx1/gcFsrQwgVBxfug4EEtUQgwEM6LFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1I= + // READY: loaded 98 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 122 (7a) << + // 2 SWAP + // 3 PUSHDATA1 0363d7a48125a76cdea6e098c9f128e82920ed428e5fb4caf1d7f81c16cad0c205 + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 48 PUSH0 + // 49 PICKITEM + // 50 CAT + // 51 PUSH4 + // 52 PACK + // 53 PUSH0 + // 54 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 71 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 93 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzVerificationScriptSimpleSingleHashStaticMagic builds witness verification script for Koblitz public key. +// This method differs from buildKoblitzVerificationScriptCompat in that it checks +// +// keccak256([var-bytes-network-magic, txHash-bytes-BE]) +// +// instead of (comparing with N3) +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). +// +// and it uses static magic value (simple PUSHINT* + magic, or PUSHDATA1 + magicBytes is also possible) +// which results in network-specific verification script and, consequently, network-specific user address. +func buildKoblitzVerificationScriptSimpleSingleHashStaticMagic(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + // vrf is witness verification script corresponding to the pk. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = [network-magic-bytes, tx.Hash()] + // Firstly, push static network magic (it's 42 for unit test chain). + emit.Int(vrf.BinWriter, 42) + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM) // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (95 bytes length, always constant length, with variable length of signed data): + // NEO-GO-VM > loadbase64 ABZQDCECluEwgK3pKiq3IjOMKiSe6Ng6FPZJxoMhZkFl8GvREL0AKkEtUQgwEM6LFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1I= + // READY: loaded 95 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 122 (7a) << + // 2 SWAP + // 3 PUSHDATA1 0296e13080ade92a2ab722338c2a249ee8d83a14f649c68321664165f06bd110bd + // 38 PUSHINT8 42 (2a) + // 40 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 45 PUSH0 + // 46 PICKITEM + // 47 CAT + // 48 PUSH4 + // 49 PACK + // 50 PUSH0 + // 51 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 68 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 90 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzVerificationScriptSimple builds witness verification script for Koblitz public key. +// This method differs from buildKoblitzVerificationScriptCompat in that it checks +// +// keccak256(sha256([var-bytes-network-magic, txHash-bytes-BE])) +// +// instead of (comparing with N3) +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). +// +// It produces constant-length verification script (136 bytes) independently of the network parameters. +// However, the length of signed message is variable and depends on the network magic (since network +// magic Integer stackitem being converted to Buffer has the resulting byte slice length that depends on +// the magic). +func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + // vrf is witness verification script corresponding to the pk. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = Sha256([network-magic-bytes, tx.Hash()]) + // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic. + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM, // pick 0-th transaction item (the transaction hash). + opcode.CAT, // concatenate network magic and transaction hash; this instruction will convert network magic to bytes using BigInteger rules of conversion. + opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). + opcode.PACK) // pack arguments for 'sha256' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.NoneFlag) // emit the call to 'sha256' itself. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (136 bytes length, always constant length, with variable length of signed data): + // NEO-GO-VM 0 > loadbase64 ABZQDCEDp38Tevu0to16RQqloo/jNfgExYmoCElLS2JuuYcH831Bxfug4EEtUQgwEM6LEcAfDAZzaGEyNTYMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1IUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUg== + // READY: loaded 136 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 122 (7a) << + // 2 SWAP + // 3 PUSHDATA1 03a77f137afbb4b68d7a450aa5a28fe335f804c589a808494b4b626eb98707f37d + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 48 PUSH0 + // 49 PICKITEM + // 50 CAT + // 51 PUSH1 + // 52 PACK + // 53 PUSH0 + // 54 PUSHDATA1 736861323536 ("sha256") + // 62 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 84 SYSCALL System.Contract.Call (627d5b52) + // 89 PUSH4 + // 90 PACK + // 91 PUSH0 + // 92 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 109 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 131 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzVerificationScript builds custom verification script for the provided Koblitz public key. +// It checks that the following message is signed by the provided public key: +// +// keccak256(sha256([4-bytes-network-magic-LE, txHash-bytes-BE])) +// +// It produces constant-length verification script (186 bytes) independently of the network parameters. +func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []byte { + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // vrf is witness verification script corresponding to the pub. + vrf := io.NewBufBinWriter() + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = Sha256([4-bytes-network-magic-LE, tx.Hash()]) + // Firstly, convert network magic (uint32) to LE buffer. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic. + // First byte: n & 0xFF + emit.Opcodes(vrf.BinWriter, opcode.DUP) + emit.Int(vrf.BinWriter, 0xFF) // TODO: this can be optimize in order not to allocate 0xFF every time, but need to compare execution price. + emit.Opcodes(vrf.BinWriter, opcode.AND, + opcode.SWAP, // Swap with the original network n. + opcode.PUSH8, + opcode.SHR) + // Second byte: n >> 8 & 0xFF + emit.Opcodes(vrf.BinWriter, opcode.DUP) + emit.Int(vrf.BinWriter, 0xFF) + emit.Opcodes(vrf.BinWriter, opcode.AND, + opcode.SWAP, // Swap with the n >> 8. + opcode.PUSH8, + opcode.SHR) + // Third byte: n >> 16 & 0xFF + emit.Opcodes(vrf.BinWriter, opcode.DUP) + emit.Int(vrf.BinWriter, 0xFF) + emit.Opcodes(vrf.BinWriter, opcode.AND, + opcode.SWAP, // Swap with the n >> 16. + opcode.PUSH8, + opcode.SHR) + // Fourth byte: n >> 24 & 0xFF + emit.Int(vrf.BinWriter, 0xFF) // no DUP is needed since it's the last shift. + emit.Opcodes(vrf.BinWriter, opcode.AND) + // Put these 4 bytes into buffer. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.NEWBUFFER) // allocate new 4-bytes-length buffer. + emit.Opcodes(vrf.BinWriter, + // Set fourth byte. + opcode.DUP, opcode.PUSH3, + opcode.PUSH3, opcode.ROLL, + opcode.SETITEM, + // Set third byte. + opcode.DUP, opcode.PUSH2, + opcode.PUSH3, opcode.ROLL, + opcode.SETITEM, + // Set second byte. + opcode.DUP, opcode.PUSH1, + opcode.PUSH3, opcode.ROLL, + opcode.SETITEM, + // Set first byte. + opcode.DUP, opcode.PUSH0, + opcode.PUSH3, opcode.ROLL, + opcode.SETITEM) + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM, // pick 0-th transaction item (the transaction hash). + opcode.CAT, // concatenate network magic and transaction hash. + opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). + opcode.PACK) // pack arguments for 'sha256' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.NoneFlag) // emit the call to 'sha256' itself. + // Continue construction of 'verifyWithECDsa' call. + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. + require.NoError(t, vrf.Err) + + return vrf.Bytes() + // Here's an example of the resulting witness verification script (186 bytes length, always constant length, the length of signed data is also always constant): + // NEO-GO-VM 0 > loadbase64 ABZQDCECYn75w2MePMuPvExbbEnjjM7eWnmvseGwcI+7lYp4AtdBxfug4EoB/wCRUBipSgH/AJFQGKlKAf8AkVAYqQH/AJEUiEoTE1LQShITUtBKERNS0EoQE1LQQS1RCDAQzosRwB8MBnNoYTI1NgwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUhTAHwwPdmVyaWZ5V2l0aEVDRHNhDBQb9XWrEYlohBNhCjWhKIbN4LZsckFifVtS + // READY: loaded 186 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 122 (7a) << + // 2 SWAP + // 3 PUSHDATA1 02627ef9c3631e3ccb8fbc4c5b6c49e38ccede5a79afb1e1b0708fbb958a7802d7 + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 DUP + // 44 PUSHINT16 255 (ff00) + // 47 AND + // 48 SWAP + // 49 PUSH8 + // 50 SHR + // 51 DUP + // 52 PUSHINT16 255 (ff00) + // 55 AND + // 56 SWAP + // 57 PUSH8 + // 58 SHR + // 59 DUP + // 60 PUSHINT16 255 (ff00) + // 63 AND + // 64 SWAP + // 65 PUSH8 + // 66 SHR + // 67 PUSHINT16 255 (ff00) + // 70 AND + // 71 PUSH4 + // 72 NEWBUFFER + // 73 DUP + // 74 PUSH3 + // 75 PUSH3 + // 76 ROLL + // 77 SETITEM + // 78 DUP + // 79 PUSH2 + // 80 PUSH3 + // 81 ROLL + // 82 SETITEM + // 83 DUP + // 84 PUSH1 + // 85 PUSH3 + // 86 ROLL + // 87 SETITEM + // 88 DUP + // 89 PUSH0 + // 90 PUSH3 + // 91 ROLL + // 92 SETITEM + // 93 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 98 PUSH0 + // 99 PICKITEM + // 100 CAT + // 101 PUSH1 + // 102 PACK + // 103 PUSH0 + // 104 PUSHDATA1 736861323536 ("sha256") + // 112 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 134 SYSCALL System.Contract.Call (627d5b52) + // 139 PUSH4 + // 140 PACK + // 141 PUSH0 + // 142 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 159 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 181 SYSCALL System.Contract.Call (627d5b52) +} + +// buildKoblitzInvocationScript builds witness invocation script for the transaction signatures. The signature +// itself may be produced by public key over any curve (not required Koblitz, the algorithm is the same). +// The signatures expected to be sorted by public key (if multiple signatures are provided). +func buildKoblitzInvocationScript(t *testing.T, signatures [][]byte) []byte { + //Exactly like during standard + // signature verification, the resulting script pushes Koblitz signature bytes onto stack. + inv := io.NewBufBinWriter() + for _, sig := range signatures { + emit.Bytes(inv.BinWriter, sig) // message signature bytes. + } + require.NoError(t, inv.Err) + + return inv.Bytes() + // Here's an example of the resulting single witness invocation script (66 bytes length, always constant length): + // NEO-GO-VM > loadbase64 DEBMGKU/MdSizlzaVNDUUbd1zMZQJ43eTaZ4vBCpmkJ/wVh1TYrAWEbFyHhkqq+aYxPCUS43NKJdJTXavcjB8sTP + // READY: loaded 66 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHDATA1 4c18a53f31d4a2ce5cda54d0d451b775ccc650278dde4da678bc10a99a427fc158754d8ac05846c5c87864aaaf9a6313c2512e3734a25d2535dabdc8c1f2c4cf << + // + // Here's an example of the 3 out of 4 multisignature invocation script (66 * m bytes length, always constant length): + // NEO-GO-VM > loadbase64 DEBsPMY3+7sWyZf0gCVcqPzwZ79p+KpeylgtbYIrXp4Tdi6E/8q3DIrEgK7DdVe3YdbfE+VPrpwym/ufBb8MRTB6DED5B9OZDGWdJApRfuy9LeUTa2mLsXP7mBRa181g0Jo7beylWzVgDqHHF2PilECMcLmRbFRknmQm4KgiGkDE+O6ZDEAYt61O2dMfasJHiQD95M5b4mR6NBnDsMTo2e59H3y4YguroVLiUxnQSc4qu9LWvEIKr4/ytjCCuANXOkJmSw8C + // READY: loaded 198 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHDATA1 6c3cc637fbbb16c997f480255ca8fcf067bf69f8aa5eca582d6d822b5e9e13762e84ffcab70c8ac480aec37557b761d6df13e54fae9c329bfb9f05bf0c45307a << + // 66 PUSHDATA1 f907d3990c659d240a517eecbd2de5136b698bb173fb98145ad7cd60d09a3b6deca55b35600ea1c71763e294408c70b9916c54649e6426e0a8221a40c4f8ee99 + // 132 PUSHDATA1 18b7ad4ed9d31f6ac2478900fde4ce5be2647a3419c3b0c4e8d9ee7d1f7cb8620baba152e25319d049ce2abbd2d6bc420aaf8ff2b63082b803573a42664b0f02 +} + +// constructMessage constructs message for signing that consists of the +// unhashed constant 4-bytes length LE magic and transaction hash bytes: +// +// [4-bytes-network-magic-LE, txHash-bytes-BE] +func constructMessage(t *testing.T, magic uint32, tx hash.Hashable) []byte { + return hash.GetSignedData(magic, tx) +} + +// constructMessageNoHash constructs message for signing that consists of the +// unhashed magic and transaction hash bytes: +// +// [var-bytes-network-magic, txHash-bytes-BE] +func constructMessageNoHash(t *testing.T, magic uint32, tx hash.Hashable) []byte { + m := big.NewInt(int64(magic)) + return append(m.Bytes(), tx.Hash().BytesBE()...) +} + +// constructMessageCompat constructs message for signing that does not follow N3 rules, +// but entails smaller verification script size and smaller verification price: +// +// sha256([var-bytes-network-magic, txHash-bytes-BE]) +func constructMessageSimple(t *testing.T, magic uint32, tx hash.Hashable) []byte { + m := big.NewInt(int64(magic)) + return hash.Sha256(append(m.Bytes(), tx.Hash().BytesBE()...)).BytesBE() +} + +// constructMessageCompat constructs message for signing following the N3 rules: +// +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]) +func constructMessageCompat(t *testing.T, magic uint32, tx hash.Hashable) []byte { + return hash.NetSha256(magic, tx).BytesBE() +} + +// TestCryptoLib_KoblitzMultisigVerificationScript builds transaction with custom witness that contains +// the Koblitz tx multisignature bytes and Koblitz multisignature verification script. +// This test ensures that transaction signed by m out of n Koblitz keys passes verification and can +// be successfully accepted to the chain. +func TestCryptoLib_KoblitzMultisigVerificationScript(t *testing.T) { + check := func( + t *testing.T, + buildVerificationScript func(t *testing.T, m int, pub keys.PublicKeys) []byte, + constructMsg func(t *testing.T, magic uint32, tx hash.Hashable) []byte, + ) { + c := newGasClient(t) + gasInvoker := c.WithSigners(c.Committee) + e := c.Executor + + // Consider 4 users willing to sign 3/4 multisignature transaction Secp256k1 private keys. + const ( + n = 4 + m = 3 + ) + pks := make([]*keys.PrivateKey, n) + for i := range pks { + var err error + pks[i], err = keys.NewSecp256k1PrivateKey() + require.NoError(t, err) + } + // Sort private keys by their public keys. + sort.Slice(pks, func(i, j int) bool { + return pks[i].PublicKey().Cmp(pks[j].PublicKey()) < 0 + }) + + // Firstly, we need to build the N3 multisig account address based on the users' public keys. + // Pubs must be sorted, exactly like for the standard CheckMultisig. + pubs := make(keys.PublicKeys, n) + for i := range pks { + pubs[i] = pks[i].PublicKey() + } + vrfBytes := buildVerificationScript(t, m, pubs) + + // Construct the user's account script hash. It's effectively a verification script hash. + from := hash.Hash160(vrfBytes) + + // Supply this account with some initial balance so that the user is able to pay for his transactions. + gasInvoker.Invoke(t, true, "transfer", c.Committee.ScriptHash(), from, 10000_0000_0000, nil) + + // Construct transaction that transfers 5 GAS from the user's account to some other account. + to := util.Uint160{1, 2, 3} + amount := 5 + tx := gasInvoker.PrepareInvokeNoSign(t, "transfer", from, to, amount, nil) + tx.Signers = []transaction.Signer{ + { + Account: from, + Scopes: transaction.CalledByEntry, + }, + } + neotest.AddNetworkFee(t, e.Chain, tx) + neotest.AddSystemFee(e.Chain, tx, -1) + + // Add some more network fee to pay for the witness verification. This value may be calculated precisely, + // but let's keep some inaccurate value for the test. + tx.NetworkFee = 8995470 + + // This transaction (along with the network magic) should be signed by the user's Koblitz private key. + msg := constructMsg(t, uint32(e.Chain.GetConfig().Magic), tx) + + // The users have to sign the hash of the message by their Koblitz key. Collect m signatures from first m keys. + // Signatures must be sorted by public key. + sigs := make([][]byte, m) + for i := range sigs { + j := i + if i > 0 { + j++ // Add some shift to ensure that verification script works correctly. + } + if i > 3 { + j++ // Add more shift for large number of public keys for the same purpose. + } + sigs[i] = pks[j].SignHash(native.Keccak256(msg)) + } + + // Build invocation witness script for the signatures. + invBytes := buildKoblitzInvocationScript(t, sigs) + + // Construct witness for signer #0 (the multisig account itself). + tx.Scripts = []transaction.Witness{ + { + InvocationScript: invBytes, + VerificationScript: vrfBytes, + }, + } + + // Add transaction to the chain. No error is expected on new block addition. Note, that this line performs + // all those checks that are executed during transaction acceptance in the real network. + e.AddNewBlock(t, tx) + + // Double-check: ensure funds have been transferred. + e.CheckGASBalance(t, to, big.NewInt(int64(amount))) + } + + // The proposed multisig verification script. + // (264 bytes, 8390070 GAS including Invocation script execution for 3/4 multisig). + // The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). + check(t, buildKoblitzMultisigVerificationScript, constructMessage) +} + +// buildKoblitzMultisigVerificationScript builds witness verification script for m signatures out of n Koblitz public keys. +// Public keys must be sorted. Signatures (pushed by witness Invocation script) must be sorted by public keys. +// It checks m out of n multisignature of the following message: +// +// keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]) +func buildKoblitzMultisigVerificationScript(t *testing.T, m int, pubs keys.PublicKeys) []byte { + if len(pubs) == 0 { + t.Fatalf("empty pubs list") + } + if m > len(pubs) { + t.Fatalf("m must be not greater than the number of public keys") + } + + n := len(pubs) // public keys must be sorted. + cryptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) + + // In fact, the following algorithm is implemented via NeoVM instructions: + // + // func Check(sigs []interop.Signature) bool { + // if m != len(sigs) { + // return false + // } + // var pubs []interop.PublicKey = []interop.PublicKey{...} + // msg := append(convert.ToBytes(runtime.GetNetwork()), runtime.GetScriptContainer().Hash...) + // var sigCnt = 0 + // var pubCnt = 0 + // for ; sigCnt < m && pubCnt < n; { // sigs must be sorted by pub + // sigCnt += crypto.VerifyWithECDsa(msg, pubs[pubCnt], sigs[sigCnt], crypto.Secp256k1Keccak256) + // pubCnt++ + // } + // return sigCnt == m + // } + vrf := io.NewBufBinWriter() + + // Start the same way as regular multisig script. + emit.Int(vrf.BinWriter, int64(m)) // push m. + for _, pub := range pubs { + emit.Bytes(vrf.BinWriter, pub.Bytes()) // push public keys in compressed form. + } + emit.Int(vrf.BinWriter, int64(n)) // push n. + + // Initialize slots for local variables. Locals slot scheme: + // LOC0 -> sigs + // LOC1 -> pubs + // LOC2 -> msg (ByteString) + // LOC3 -> sigCnt (Integer) + // LOC4 -> pubCnt (Integer) + // LOC5 -> n + // LOC6 -> m + emit.InitSlot(vrf.BinWriter, 7, 0) + + // Store n. + emit.Opcodes(vrf.BinWriter, opcode.STLOC5) + + // Pack public keys and store at LOC1. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC5) + emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC1) + + // Store m. + emit.Opcodes(vrf.BinWriter, opcode.STLOC6) + + // Check the number of signatures is m. Abort the execution if not. + emit.Opcodes(vrf.BinWriter, opcode.DEPTH) // push the number of signatures onto stack. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // load m. + emit.Instruction(vrf.BinWriter, opcode.JMPEQ, []byte{0}) // here and below short jumps are sufficient. + sigsLenCheckEndOffset := vrf.Len() // offset of the signatures count check. + emit.Opcodes(vrf.BinWriter, opcode.ABORT) // abort execution if length of the signatures not equal to m. + + // Start the check. + checkStartOffset := vrf.Len() + + // Pack signatures and store at LOC0. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // load m. + emit.Opcodes(vrf.BinWriter, opcode.PACK, opcode.STLOC0) + + // Get message and store it at LOC2. + // msg = [4-network-magic-bytes-LE, tx-hash-BE] + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic (Integer stackitem), can have 0-5 bytes length serialized. + // Convert network magic to 4-bytes-length LE byte array representation. + emit.Int(vrf.BinWriter, 0x100000000) + emit.Opcodes(vrf.BinWriter, opcode.ADD, // some new number that is 5 bytes at least when serialized, but first 4 bytes are intact network value (LE). + opcode.PUSH4, opcode.LEFT) // cut the first 4 bytes out of a number that is at least 5 bytes long, the result is 4-bytes-length LE network representation. + // Retrieve executing transaction hash. + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM) // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + emit.Opcodes(vrf.BinWriter, opcode.CAT) // this instruction will convert network magic to bytes using BigInteger rules of conversion. + emit.Opcodes(vrf.BinWriter, opcode.STLOC2) // store msg as a local variable #2. + + // Initialize local variables: sigCnt, pubCnt. + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.STLOC3, // initialize sigCnt. + opcode.PUSH0, opcode.STLOC4) // initialize pubCnt. + + // Loop condition check. + loopStartOffset := vrf.Len() + emit.Opcodes(vrf.BinWriter, opcode.LDLOC3) // load sigCnt. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // push m. + emit.Opcodes(vrf.BinWriter, opcode.GE, // sigCnt >= m + opcode.LDLOC4) // load pubCnt + emit.Opcodes(vrf.BinWriter, opcode.LDLOC5) // push n. + emit.Opcodes(vrf.BinWriter, opcode.GE, // pubCnt >= n + opcode.OR) // sigCnt >= m || pubCnt >= n + emit.Instruction(vrf.BinWriter, opcode.JMPIF, []byte{0}) // jump to the end of the script if (sigCnt >= m || pubCnt >= n). + loopConditionOffset := vrf.Len() + + // Loop start. Prepare arguments and call CryptoLib's verifyWithECDsa. + emit.Int(vrf.BinWriter, int64(native.Secp256k1Keccak256)) // push Koblitz curve identifier. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC0, // load signatures. + opcode.LDLOC3, // load sigCnt. + opcode.PICKITEM, // pick signature at index sigCnt. + opcode.LDLOC1, // load pubs. + opcode.LDLOC4, // load pubCnt. + opcode.PICKITEM, // pick pub at index pubCnt. + opcode.LDLOC2, // load msg. + opcode.PUSH4, opcode.PACK) // pack 4 arguments for 'verifyWithECDsa' call. + emit.AppCallNoArgs(vrf.BinWriter, cryptoLibH, "verifyWithECDsa", callflag.NoneFlag) // emit the call to 'verifyWithECDsa' itself. + + // Update loop variables. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC3, opcode.ADD, opcode.STLOC3, // increment sigCnt if signature is valid. + opcode.LDLOC4, opcode.INC, opcode.STLOC4) // increment pubCnt. + + // End of the loop. + emit.Instruction(vrf.BinWriter, opcode.JMP, []byte{0}) // jump to the start of cycle. + loopEndOffset := vrf.Len() + + // Return condition: the number of valid signatures should be equal to m. + progRetOffset := vrf.Len() + emit.Opcodes(vrf.BinWriter, opcode.LDLOC3) // load sigCnt. + emit.Opcodes(vrf.BinWriter, opcode.LDLOC6) // push m. + emit.Opcodes(vrf.BinWriter, opcode.NUMEQUAL) // push m == sigCnt. + + require.NoError(t, vrf.Err) + script := vrf.Bytes() + + // Set JMP* instructions offsets. "-1" is for short JMP parameter offset. JMP parameters + // are relative offsets. + script[sigsLenCheckEndOffset-1] = byte(checkStartOffset - sigsLenCheckEndOffset + 2) + script[loopEndOffset-1] = byte(loopStartOffset - loopEndOffset + 2) + script[loopConditionOffset-1] = byte(progRetOffset - loopConditionOffset + 2) + + return script + // Here's an example of the resulting single witness invocation script (264 bytes length, the length may vary depending on m/n): + // NEO-GO-VM > loadbase64 EwwhAg1khs9yqTuG8R7dEj8/GhCqKwkL+6shSOczeaHENFo8DCECibz2wVNY1zRkRCbn+Qr87lQFjStnrQrwv1CSoea/91sMIQPiiV+wNGl5g5SVULR+BM/G2n6WO0WrGIsq+GBRqQHYwAwhAuwZz40NwnerrmSusUUgNqsZiv0WFj3KQE1BYd7lU7mDFFcHAHVtwHF2Q24oAzhuwHBBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LchBzEHRrbrhsbbiSJEIAGGhrzmlszmoUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUmuec2ycdCK5a26z + // READY: loaded 264 instructions + // NEO-GO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSH3 << + // 1 PUSHDATA1 020d6486cf72a93b86f11edd123f3f1a10aa2b090bfbab2148e73379a1c4345a3c + // 36 PUSHDATA1 0289bcf6c15358d734644426e7f90afcee54058d2b67ad0af0bf5092a1e6bff75b + // 71 PUSHDATA1 03e2895fb034697983949550b47e04cfc6da7e963b45ab188b2af86051a901d8c0 + // 106 PUSHDATA1 02ec19cf8d0dc277abae64aeb1452036ab198afd16163dca404d4161dee553b983 + // 141 PUSH4 + // 142 INITSLOT 7 local, 0 arg + // 145 STLOC5 + // 146 LDLOC5 + // 147 PACK + // 148 STLOC1 + // 149 STLOC6 + // 150 DEPTH + // 151 LDLOC6 + // 152 JMPEQ 155 (3/03) + // 154 ABORT + // 155 LDLOC6 + // 156 PACK + // 157 STLOC0 + // 158 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 163 PUSHINT64 4294967296 (0000000001000000) + // 172 ADD + // 173 PUSH4 + // 174 LEFT + // 175 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 180 PUSH0 + // 181 PICKITEM + // 182 CAT + // 183 STLOC2 + // 184 PUSH0 + // 185 STLOC3 + // 186 PUSH0 + // 187 STLOC4 + // 188 LDLOC3 + // 189 LDLOC6 + // 190 GE + // 191 LDLOC4 + // 192 LDLOC5 + // 193 GE + // 194 OR + // 195 JMPIF 261 (66/42) + // 197 PUSHINT8 122 (7a) + // 199 LDLOC0 + // 200 LDLOC3 + // 201 PICKITEM + // 202 LDLOC1 + // 203 LDLOC4 + // 204 PICKITEM + // 205 LDLOC2 + // 206 PUSH4 + // 207 PACK + // 208 PUSH0 + // 209 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 226 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 248 SYSCALL System.Contract.Call (627d5b52) + // 253 LDLOC3 + // 254 ADD + // 255 STLOC3 + // 256 LDLOC4 + // 257 INC + // 258 STLOC4 + // 259 JMP 188 (-71/b9) + // 261 LDLOC3 + // 262 LDLOC6 + // 263 NUMEQUAL +} diff --git a/pkg/core/native/native_test/management_test.go b/pkg/core/native/native_test/management_test.go index 6bba730fb..1818076f1 100644 --- a/pkg/core/native/native_test/management_test.go +++ b/pkg/core/native/native_test/management_test.go @@ -40,7 +40,7 @@ var ( defaultCSS = map[string]string{ nativenames.Management: `{"id":-1,"hash":"0xfffdc93764dbaddd97c48f252a53ea4643faa3fd","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"ContractManagement","abi":{"methods":[{"name":"deploy","offset":0,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Array","safe":false},{"name":"deploy","offset":7,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Array","safe":false},{"name":"destroy","offset":14,"parameters":[],"returntype":"Void","safe":false},{"name":"getContract","offset":21,"parameters":[{"name":"hash","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getContractById","offset":28,"parameters":[{"name":"id","type":"Integer"}],"returntype":"Array","safe":true},{"name":"getContractHashes","offset":35,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getMinimumDeploymentFee","offset":42,"parameters":[],"returntype":"Integer","safe":true},{"name":"hasMethod","offset":49,"parameters":[{"name":"hash","type":"Hash160"},{"name":"method","type":"String"},{"name":"pcount","type":"Integer"}],"returntype":"Boolean","safe":true},{"name":"setMinimumDeploymentFee","offset":56,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"update","offset":63,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","safe":false},{"name":"update","offset":70,"parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","safe":false}],"events":[{"name":"Deploy","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Update","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Destroy","parameters":[{"name":"Hash","type":"Hash160"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.StdLib: `{"id":-2,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"StdLib","abi":{"methods":[{"name":"atoi","offset":0,"parameters":[{"name":"value","type":"String"}],"returntype":"Integer","safe":true},{"name":"atoi","offset":7,"parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"base58CheckDecode","offset":14,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58CheckEncode","offset":21,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base58Decode","offset":28,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base58Encode","offset":35,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"base64Decode","offset":42,"parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"base64Encode","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"deserialize","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"itoa","offset":63,"parameters":[{"name":"value","type":"Integer"}],"returntype":"String","safe":true},{"name":"itoa","offset":70,"parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","safe":true},{"name":"jsonDeserialize","offset":77,"parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"jsonSerialize","offset":84,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"memoryCompare","offset":91,"parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":98,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":105,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":112,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","safe":true},{"name":"serialize","offset":119,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"strLen","offset":126,"parameters":[{"name":"str","type":"String"}],"returntype":"Integer","safe":true},{"name":"stringSplit","offset":133,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","safe":true},{"name":"stringSplit","offset":140,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, - nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":2135988409},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":42,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":63,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, + nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":2135988409},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":42,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":49,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":63,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.Ledger: `{"id":-4,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"LedgerContract","abi":{"methods":[{"name":"currentHash","offset":0,"parameters":[],"returntype":"Hash256","safe":true},{"name":"currentIndex","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getBlock","offset":14,"parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","safe":true},{"name":"getTransaction","offset":21,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","safe":true},{"name":"getTransactionFromBlock","offset":28,"parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","safe":true},{"name":"getTransactionHeight","offset":35,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","safe":true},{"name":"getTransactionSigners","offset":42,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","safe":true},{"name":"getTransactionVMState","offset":49,"parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.Neo: `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":65467259},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getGasPerBlock","offset":49,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":56,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":63,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":70,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":77,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":84,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":91,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":98,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":105,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":112,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":119,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":126,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.Gas: `{"id":-6,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"symbol","offset":14,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":28,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`, @@ -52,7 +52,7 @@ var ( // cockatriceCSS holds serialized native contract states built for genesis block (with UpdateCounter 0) // under assumption that hardforks from Aspidochelone to Cockatrice (included) are enabled. cockatriceCSS = map[string]string{ - nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"keccak256","offset":42,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":49,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":70,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, + nativenames.CryptoLib: `{"id":-3,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","abi":{"methods":[{"name":"bls12381Add","offset":0,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Deserialize","offset":7,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Equal","offset":14,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","safe":true},{"name":"bls12381Mul","offset":21,"parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Pairing","offset":28,"parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","safe":true},{"name":"bls12381Serialize","offset":35,"parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","safe":true},{"name":"keccak256","offset":42,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":49,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":56,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":70,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`, nativenames.Neo: `{"id":-5,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"NeoToken","abi":{"methods":[{"name":"balanceOf","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","safe":true},{"name":"decimals","offset":7,"parameters":[],"returntype":"Integer","safe":true},{"name":"getAccountState","offset":14,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","safe":true},{"name":"getAllCandidates","offset":21,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getCandidateVote","offset":28,"parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","safe":true},{"name":"getCandidates","offset":35,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommittee","offset":42,"parameters":[],"returntype":"Array","safe":true},{"name":"getCommitteeAddress","offset":49,"parameters":[],"returntype":"Hash160","safe":true},{"name":"getGasPerBlock","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"getNextBlockValidators","offset":63,"parameters":[],"returntype":"Array","safe":true},{"name":"getRegisterPrice","offset":70,"parameters":[],"returntype":"Integer","safe":true},{"name":"registerCandidate","offset":77,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"setGasPerBlock","offset":84,"parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setRegisterPrice","offset":91,"parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","safe":false},{"name":"symbol","offset":98,"parameters":[],"returntype":"String","safe":true},{"name":"totalSupply","offset":105,"parameters":[],"returntype":"Integer","safe":true},{"name":"transfer","offset":112,"parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","safe":false},{"name":"unclaimedGas","offset":119,"parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"unregisterCandidate","offset":126,"parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","safe":false},{"name":"vote","offset":133,"parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":["NEP-17"],"trusts":[],"extra":null},"updatecounter":0}`, } ) diff --git a/pkg/crypto/hash/hash.go b/pkg/crypto/hash/hash.go index a997a3514..999b291da 100644 --- a/pkg/crypto/hash/hash.go +++ b/pkg/crypto/hash/hash.go @@ -16,7 +16,10 @@ type Hashable interface { Hash() util.Uint256 } -func getSignedData(net uint32, hh Hashable) []byte { +// GetSignedData returns the concatenated byte slice containing of the network +// magic in constant-length 4-bytes LE representation and hashable item hash in BE +// representation. +func GetSignedData(net uint32, hh Hashable) []byte { var b = make([]byte, 4+util.Uint256Size) binary.LittleEndian.PutUint32(b, net) h := hh.Hash() @@ -27,7 +30,7 @@ func getSignedData(net uint32, hh Hashable) []byte { // NetSha256 calculates a network-specific hash of the Hashable item that can then // be signed/verified. func NetSha256(net uint32, hh Hashable) util.Uint256 { - return Sha256(getSignedData(net, hh)) + return Sha256(GetSignedData(net, hh)) } // Sha256 hashes the incoming byte slice diff --git a/pkg/interop/native/crypto/crypto.go b/pkg/interop/native/crypto/crypto.go index db0c3d750..b3574fcde 100644 --- a/pkg/interop/native/crypto/crypto.go +++ b/pkg/interop/native/crypto/crypto.go @@ -13,13 +13,15 @@ import ( // Hash represents CryptoLib contract hash. const Hash = "\x1b\xf5\x75\xab\x11\x89\x68\x84\x13\x61\x0a\x35\xa1\x28\x86\xcd\xe0\xb6\x6c\x72" -// NamedCurve represents a named elliptic curve. -type NamedCurve byte +// NamedCurveHash represents a pair of named elliptic curve and hash function. +type NamedCurveHash byte -// Various named elliptic curves. +// Various pairs of named elliptic curves and hash functions. const ( - Secp256k1 NamedCurve = 22 - Secp256r1 NamedCurve = 23 + Secp256k1Sha256 NamedCurveHash = 22 + Secp256r1Sha256 NamedCurveHash = 23 + Secp256k1Keccak256 NamedCurveHash = 122 + Secp256r1Keccak256 NamedCurveHash = 123 ) // Sha256 calls `sha256` method of native CryptoLib contract and computes SHA256 hash of b. @@ -40,8 +42,8 @@ func Murmur32(b []byte, seed int) []byte { // VerifyWithECDsa calls `verifyWithECDsa` method of native CryptoLib contract and checks that sig is // a correct msg's signature for the given pub (serialized public key on the given curve). -func VerifyWithECDsa(msg []byte, pub interop.PublicKey, sig interop.Signature, curve NamedCurve) bool { - return neogointernal.CallWithToken(Hash, "verifyWithECDsa", int(contract.NoneFlag), msg, pub, sig, curve).(bool) +func VerifyWithECDsa(msg []byte, pub interop.PublicKey, sig interop.Signature, curveHash NamedCurveHash) bool { + return neogointernal.CallWithToken(Hash, "verifyWithECDsa", int(contract.NoneFlag), msg, pub, sig, curveHash).(bool) } // Bls12381Point represents BLS12-381 curve point (G1 or G2 in the Affine or diff --git a/pkg/services/rpcsrv/server_test.go b/pkg/services/rpcsrv/server_test.go index 57e5ed4ef..f6c89d7fd 100644 --- a/pkg/services/rpcsrv/server_test.go +++ b/pkg/services/rpcsrv/server_test.go @@ -89,7 +89,7 @@ const ( faultedTxHashLE = "82279bfe9bada282ca0f8cb8e0bb124b921af36f00c69a518320322c6f4fef60" faultedTxBlock uint32 = 23 invokescriptContractAVM = "VwIADBQBDAMOBQYMDQIODw0DDgcJAAAAAErZMCQE2zBwaEH4J+yMqiYEEUAMFA0PAwIJAAIBAwcDBAUCAQAOBgwJStkwJATbMHFpQfgn7IyqJgQSQBNA" - block20StateRootLE = "397c69adbc0201d59623fa913bfff4a2da25c792c484d1d278c061709f2c21cf" + block20StateRootLE = "2d95b1149230d40c3043a84d42249b7b344f8755ea9fd0b2d95c5d011af85fc7" ) var ( @@ -3152,10 +3152,13 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) [] body := doRPCCall(`{"jsonrpc": "2.0", "id": 1, "method": "calculatenetworkfee", "params": ["bm90IGEgdHJhbnNhY3Rpb24K"]}"`, httpSrv.URL, t) _ = checkErrGetResult(t, body, true, neorpc.InvalidParamsCode, "Invalid params") }) - calcReq := func(t *testing.T, tx *transaction.Transaction) []byte { - rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "calculatenetworkfee", "params": ["%s"]}"`, base64.StdEncoding.EncodeToString(tx.Bytes())) + calcReqExactly := func(t *testing.T, tx string) []byte { + rpc := fmt.Sprintf(`{"jsonrpc": "2.0", "id": 1, "method": "calculatenetworkfee", "params": ["%s"]}"`, tx) return doRPCCall(rpc, httpSrv.URL, t) } + calcReq := func(t *testing.T, tx *transaction.Transaction) []byte { + return calcReqExactly(t, base64.StdEncoding.EncodeToString(tx.Bytes())) + } t.Run("non-contract with zero verification", func(t *testing.T) { tx := &transaction.Transaction{ Script: []byte{byte(opcode.RET)}, @@ -3235,6 +3238,13 @@ func testRPCProtocol(t *testing.T, doRPCCall func(string, string, *testing.T) [] } checkCalc(t, tx, 2315100) // Perfectly matches FeeIsMultiSigContract() C# test. }) + t.Run("Koblitz custom multisignature witness", func(t *testing.T) { + tx := "AAIAAACWP5gAAAAAAAAAAAAAAAAAAgAAAAEGyZgQyJQyWjzvqUZochi8rGE9RQEAVgsVDBQBAgMAAAAAAAAAAAAAAAAAAAAAAAwUBsmYEMiUMlo876lGaHIYvKxhPUUUwB8MCHRyYW5zZmVyDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtSAcYMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD9CAETDCECbSVpJ0BN2xiveIGNU0LzEz4V7FUAp1NV8s7YI4kq9eQMIQOaHY3bh+3OmXuU9t72Pj62loLM7gZDgXJwnBV2zO4u1wwhAsvP18ohoYHcHBPt4wwPqAOstOhazEegr4klYmDlWpzeDCED9EsK7L0qFMP1QpBBfKMMVXPLa894ONINLRtjtBLBM6oUVwcAdW3AcXZDbigDOG7AcEHF+6DgAwAAAAABAAAAnhSNQS1RCDAQzotyEHMQdGtuuGxtuJIkQgB6aGvOaWzOahTAEAwPdmVyaWZ5V2l0aEVDRHNhDBQb9XWrEYlohBNhCjWhKIbN4LZsckFifVtSa55zbJx0IrlrbrM=" + resp := checkErrGetResult(t, calcReqExactly(t, tx), false, 0) + res := new(result.NetworkFee) + require.NoError(t, json.Unmarshal(resp, res)) + require.Equal(t, int64(8992070), res.Value) + }) checkContract := func(t *testing.T, verAcc util.Uint160, invoc []byte, fee int64) { txScript, err := smartcontract.CreateCallWithAssertScript(chain.UtilityTokenHash(), "transfer", verAcc, verAcc, 1, nil) diff --git a/pkg/vm/emit/emit.go b/pkg/vm/emit/emit.go index a51e3f781..7a2b1033c 100644 --- a/pkg/vm/emit/emit.go +++ b/pkg/vm/emit/emit.go @@ -29,6 +29,11 @@ func Opcodes(w *io.BinWriter, ops ...opcode.Opcode) { } } +// InitSlot emits INITSLOT instruction with the specified size of locals/args slots. +func InitSlot(w *io.BinWriter, locals, args uint8) { + Instruction(w, opcode.INITSLOT, []byte{locals, args}) +} + // Bool emits a bool type to the given buffer. func Bool(w *io.BinWriter, ok bool) { var opVal = opcode.PUSHT