diff --git a/docs/node-configuration.md b/docs/node-configuration.md
index f67aa6dfb2..d2afb3a55e 100644
--- a/docs/node-configuration.md
+++ b/docs/node-configuration.md
@@ -582,7 +582,7 @@ in development and can change in an incompatible way.
| `Cockatrice` | Introduces the ability to update native contracts. Includes a couple of new native smart contract APIs: `keccak256` of native CryptoLib contract and `getCommitteeAddress` of native NeoToken contract. | https://github.com/nspcc-dev/neo-go/pull/3402
https://github.com/neo-project/neo/pull/2942
https://github.com/nspcc-dev/neo-go/pull/3301
https://github.com/neo-project/neo/pull/2925
https://github.com/nspcc-dev/neo-go/pull/3362
https://github.com/neo-project/neo/pull/3154 |
| `Domovoi` | Makes node use executing contract state for the contract call permissions check instead of the state stored in the native Management contract. In C# also makes System.Runtime.GetNotifications interop properly count stack references of notification parameters which prevents users from creating objects that exceed MaxStackSize constraint, but NeoGo has never had this bug, thus proper behaviour is preserved even before HFDomovoi. It results in the fact that some T5 testnet transactions have different ApplicationLogs compared to the C# node, but the node states match. | https://github.com/nspcc-dev/neo-go/pull/3476
https://github.com/neo-project/neo/pull/3290
https://github.com/nspcc-dev/neo-go/pull/3473
https://github.com/neo-project/neo/pull/3290
https://github.com/neo-project/neo/pull/3301
https://github.com/nspcc-dev/neo-go/pull/3485 |
| `Echidna` | Introduces `Designation` event extension with `Old` and `New` roles data to native RoleManagement contract. Adds support for `base64UrlEncode` and `base64UrlDecode` methods to native StdLib contract. Extends the list of required call flags for `registerCandidate`, `unregisterCandidate`and `vote` methods of native NeoToken contract with AllowNotify flag. Enables `onNEP17Payment` method of NEO contract for candidate registration. Introduces constraint for maximum number of execution notifications. Adds support for `recoverSecp256K1` method of native CryptoLib contract. Introduces `setMillisecondsPerBlock` and `getMillisecondsPerBlock` methods of native Policy contract. Introduces support for NotaryAssisted transaction attribute and native Notary contract. | https://github.com/nspcc-dev/neo-go/pull/3554
https://github.com/nspcc-dev/neo-go/pull/3761
https://github.com/nspcc-dev/neo-go/pull/3554
https://github.com/neo-project/neo/pull/3597
https://github.com/nspcc-dev/neo-go/pull/3700
https://github.com/nspcc-dev/neo-go/pull/3640
https://github.com/neo-project/neo/pull/3548
https://github.com/nspcc-dev/neo-go/pull/3863
https://github.com/neo-project/neo/pull/3696
https://github.com/neo-project/neo/pull/3895
https://github.com/nspcc-dev/neo-go/pull/3835
https://github.com/nspcc-dev/neo-go/pull/3854
https://github.com/neo-project/neo/pull/3175
https://github.com/nspcc-dev/neo-go/pull/3478
https://github.com/neo-project/neo/pull/3178 |
-| `Faun` | Adds `getBlockedAccounts` method to native Policy contract. Adds `hexEncode` and `hexDecode` methods to native StdLib contract. | https://github.com/nspcc-dev/neo-go/pull/3932
https://github.com/nspcc-dev/neo-go/pull/4004
https://github.com/neo-project/neo/pull/4147
https://github.com/neo-project/neo/pull/4150 |
+| `Faun` | Adds `getBlockedAccounts` method to native Policy contract. Adds `hexEncode` and `hexDecode` methods to native StdLib contract. Adds `bn254Add`, `bn254Mul` and `bn254Pairing` methods to native CryptoLib contract. | https://github.com/nspcc-dev/neo-go/pull/3932
https://github.com/nspcc-dev/neo-go/pull/4004
https://github.com/neo-project/neo/pull/4147
https://github.com/neo-project/neo/pull/4150
https://github.com/nspcc-dev/neo-go/pull/4032
https://github.com/neo-project/neo/pull/4185 |
## DB compatibility
diff --git a/go.mod b/go.mod
index 600f1c4fa0..baee3829e8 100644
--- a/go.mod
+++ b/go.mod
@@ -72,3 +72,5 @@ require (
google.golang.org/grpc v1.75.1 // indirect
google.golang.org/protobuf v1.36.9 // indirect
)
+
+replace github.com/nspcc-dev/neo-go/pkg/interop => ./pkg/interop
diff --git a/pkg/compiler/native_test.go b/pkg/compiler/native_test.go
index 25b3032f2b..d22c280b71 100644
--- a/pkg/compiler/native_test.go
+++ b/pkg/compiler/native_test.go
@@ -250,6 +250,9 @@ func TestNativeHelpersCompile(t *testing.T) {
{"bls12381Mul", []string{"crypto.Bls12381Point{}", "[]byte{1, 2, 3}", "true"}},
{"bls12381Pairing", []string{"crypto.Bls12381Point{}", "crypto.Bls12381Point{}"}},
{"keccak256", []string{"[]byte{1, 2, 3}"}},
+ {"bn254Add", []string{"[]byte{1, 2, 3}"}},
+ {"bn254Mul", []string{"[]byte{1, 2, 3}"}},
+ {"bn254Pairing", []string{"[]byte{1, 2, 3}"}},
})
runNativeTestCases(t, *cs.ByName(nativenames.StdLib).Metadata(), "std", []nativeTestCase{
{"serialize", []string{"[]byte{1, 2, 3}"}},
diff --git a/pkg/config/hardfork.go b/pkg/config/hardfork.go
index 6579826fca..bb3de96217 100644
--- a/pkg/config/hardfork.go
+++ b/pkg/config/hardfork.go
@@ -52,7 +52,8 @@ const (
HFEchidna // Echidna
// HFFaun represents hard-fork introduced in #3931, #4004 (ported from
// https://github.com/neo-project/neo/pull/4147,
- // https://github.com/neo-project/neo/pull/4150).
+ // https://github.com/neo-project/neo/pull/4150), #4032 (ported from
+ // https://github.com/neo-project/neo/pull/4185).
HFFaun // Faun
// hfLast denotes the end of hardforks enum. Consider adding new hardforks
// before hfLast.
diff --git a/pkg/core/native/crypto.go b/pkg/core/native/crypto.go
index b2659efc90..d45b6558dc 100644
--- a/pkg/core/native/crypto.go
+++ b/pkg/core/native/crypto.go
@@ -9,6 +9,7 @@ import (
"math/big"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
+ "github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa"
"github.com/nspcc-dev/neo-go/pkg/config"
@@ -46,6 +47,12 @@ const (
Secp256r1Keccak256 NamedCurveHash = 123
)
+const (
+ FieldElementLength = 32
+ G1EncodedLength = 64
+ PairInputLength = 192
+)
+
func newCrypto() *Crypto {
c := &Crypto{ContractMD: *interop.NewContractMD(nativenames.CryptoLib, nativeids.CryptoLib)}
defer c.BuildHFSpecificMD(c.ActiveIn())
@@ -134,6 +141,22 @@ func newCrypto() *Crypto {
manifest.NewParameter("signature", smartcontract.ByteArrayType))
md = NewMethodAndPrice(c.recoverSecp256K1, 1<<15, callflag.NoneFlag, config.HFEchidna)
c.AddMethod(md, desc)
+
+ desc = NewDescriptor("bn254Add", smartcontract.ByteArrayType,
+ manifest.NewParameter("input", smartcontract.ByteArrayType))
+ md = NewMethodAndPrice(c.bn254Add, 1<<19, callflag.NoneFlag, config.HFFaun)
+ c.AddMethod(md, desc)
+
+ desc = NewDescriptor("bn254Mul", smartcontract.ByteArrayType,
+ manifest.NewParameter("input", smartcontract.ByteArrayType))
+ md = NewMethodAndPrice(c.bn254Mul, 1<<19, callflag.NoneFlag, config.HFFaun)
+ c.AddMethod(md, desc)
+
+ desc = NewDescriptor("bn254Pairing", smartcontract.ByteArrayType,
+ manifest.NewParameter("input", smartcontract.ByteArrayType))
+ md = NewMethodAndPrice(c.bn254Pairing, 1<<19, callflag.NoneFlag, config.HFFaun)
+ c.AddMethod(md, desc)
+
return c
}
@@ -278,6 +301,86 @@ func (c *Crypto) recoverSecp256K1(_ *interop.Context, args []stackitem.Item) sta
return stackitem.NewByteArray(pub.SerializeCompressed())
}
+func (c *Crypto) bn254Add(_ *interop.Context, args []stackitem.Item) stackitem.Item {
+ input, err := args[0].TryBytes()
+ if err != nil {
+ panic(fmt.Errorf("invalid input argument: %w", err))
+ }
+ if len(input) != 2*G1EncodedLength {
+ panic(fmt.Errorf("invalid BN254 add input length: want %d, got %d", 2*G1EncodedLength, len(input)))
+ }
+ var res, first, second bn254.G1Affine
+ if _, err = first.SetBytes(input[:G1EncodedLength]); err != nil {
+ return stackitem.NewByteArray(make([]byte, G1EncodedLength))
+ }
+ if _, err = second.SetBytes(input[G1EncodedLength:]); err != nil {
+ return stackitem.NewByteArray(make([]byte, G1EncodedLength))
+ }
+ res.Add(&first, &second)
+ bytes := res.RawBytes()
+ return stackitem.NewByteArray(bytes[:])
+}
+
+func (c *Crypto) bn254Mul(_ *interop.Context, args []stackitem.Item) stackitem.Item {
+ input, err := args[0].TryBytes()
+ if err != nil {
+ panic(fmt.Errorf("invalid input argument: %w", err))
+ }
+ if len(input) != G1EncodedLength+FieldElementLength {
+ panic(fmt.Errorf("invalid BN254 mul input length: want %d, got %d", G1EncodedLength+FieldElementLength, len(input)))
+ }
+ var (
+ res, basePoint bn254.G1Affine
+ scalar fr.Element
+ )
+ if _, err = basePoint.SetBytes(input[:G1EncodedLength]); err != nil {
+ return stackitem.NewByteArray(make([]byte, G1EncodedLength))
+ }
+ scalar.SetBytes(input[G1EncodedLength:])
+ res.ScalarMultiplication(&basePoint, scalar.BigInt(new(big.Int)))
+ bytes := res.RawBytes()
+ return stackitem.NewByteArray(bytes[:])
+}
+
+func (c *Crypto) bn254Pairing(_ *interop.Context, args []stackitem.Item) stackitem.Item {
+ input, err := args[0].TryBytes()
+ if err != nil {
+ panic(fmt.Errorf("invalid input argument: %w", err))
+ }
+ if len(input)%PairInputLength != 0 {
+ panic(errors.New("invalid BN254 pairing input length"))
+ }
+ var (
+ pairCount = len(input) / PairInputLength
+ P = make([]bn254.G1Affine, 0, pairCount)
+ Q = make([]bn254.G2Affine, 0, pairCount)
+ g1 bn254.G1Affine
+ g2 bn254.G2Affine
+ )
+ for i := range pairCount {
+ offset := i * PairInputLength
+ if _, err = g1.SetBytes(input[offset : offset+G1EncodedLength]); err != nil {
+ return stackitem.NewByteArray(make([]byte, FieldElementLength))
+ }
+ if _, err = g2.SetBytes(input[offset+G1EncodedLength : offset+3*G1EncodedLength]); err != nil {
+ return stackitem.NewByteArray(make([]byte, FieldElementLength))
+ }
+ if g1.IsInfinity() || g2.IsInfinity() {
+ continue
+ }
+ P = append(P, g1)
+ Q = append(Q, g2)
+ }
+ successWord := [FieldElementLength]byte{FieldElementLength - 1: 1}
+ if len(P) == 0 {
+ return stackitem.NewByteArray(successWord[:])
+ }
+ if ok, err := bn254.PairingCheck(P, Q); err != nil || !ok {
+ return stackitem.NewByteArray(make([]byte, FieldElementLength))
+ }
+ return stackitem.NewByteArray(successWord[:])
+}
+
// koblitzSigToCanonical converts compact Secp256K1 signature representation
// (https://eips.ethereum.org/EIPS/eip-2098#specification) to canonical
// form (https://www.secg.org/sec1-v2.pdf, section 4.1.6) and moves key recovery
diff --git a/pkg/core/native/crypto_test.go b/pkg/core/native/crypto_test.go
index 9c4ff3a975..896ac70a8f 100644
--- a/pkg/core/native/crypto_test.go
+++ b/pkg/core/native/crypto_test.go
@@ -7,6 +7,7 @@ import (
"math"
"math/big"
"slices"
+ "strings"
"testing"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
@@ -393,3 +394,130 @@ func TestKeccak256(t *testing.T) {
require.Equal(t, expected, actual)
}
+
+func TestBn254(t *testing.T) {
+ const (
+ Bn254G1X = "1"
+ Bn254G1Y = "2"
+ Bn254DoubleX = "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3"
+ Bn254DoubleY = "15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4"
+ Bn254G2XIm = "1800deef121f1e7641a819fe67140f7f8f87b140996fbbd1ba87fb145641f404"
+ Bn254G2XRe = "198e9393920d483a7260bfb731fb5db382322bc5b47fbf6c80f6321231df581"
+ Bn254G2YIm = "12c85ea5db8c6deb43baf7868f1c5341fd8ed84a82f89ed36e80b6a4a8dd22e1"
+ Bn254G2YRe = "090689d0585ff0756c27a122072274f89d4d1c6d2f9d3af03d86c6b29b53e2b"
+ Bn254PairingPositive = "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e104316c97997c17267a1bb67365523b4388e1306d66ea6e4d8f4a4a4b65f5c7d06e286b49c56f6293b2cea30764f0d5eabe5817905468a41f09b77588f692e8b081070efe3d4913dde35bba2513c426d065dee815c478700cef07180fb6146182432428b1490a4f25053d4c20c8723a73de6f0681bd3a8fca41008a6c3c288252d50f18403272e96c10135f96db0f8d0aec25033ebdffb88d2e7956c9bb198ec072462211ebc0a2f042f993d5bd76caf4adb5e99610dcf7c1d992595e6976aa3"
+ Bn254PairingNegative = "0x142c9123c08a0d7f66d95f3ad637a06b95700bc525073b75610884ef45416e1610104c796f40bfeef3588e996c040d2a88c0b4b85afd2578327b99413c6fe820198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d"
+ Bn254PairingInvalidG1 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000be00be00bebebebebebe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ )
+ crypto := newCrypto()
+
+ t.Run("Add", func(t *testing.T) {
+ input := make([]byte, 128)
+ writeBn254Field(t, Bn254G1X, input, 0)
+ writeBn254Field(t, Bn254G1Y, input, 32)
+ writeBn254Field(t, Bn254G1X, input, 64)
+ writeBn254Field(t, Bn254G1Y, input, 96)
+
+ resItem := crypto.bn254Add(nil, []stackitem.Item{stackitem.NewByteArray(input)})
+ resBytes, err := resItem.TryBytes()
+ require.NoError(t, err)
+
+ expected := make([]byte, 64)
+ writeBn254Field(t, Bn254DoubleX, expected, 0)
+ writeBn254Field(t, Bn254DoubleY, expected, 32)
+ require.Equal(t, expected, resBytes)
+ })
+
+ t.Run("Mul", func(t *testing.T) {
+ input := make([]byte, 96)
+ writeBn254Field(t, Bn254G1X, input, 0)
+ writeBn254Field(t, Bn254G1Y, input, 32)
+ writeBn254Field(t, "2", input, 64)
+
+ resItem := crypto.bn254Mul(nil, []stackitem.Item{stackitem.NewByteArray(input)})
+ resBytes, err := resItem.TryBytes()
+ require.NoError(t, err)
+
+ expected := make([]byte, 64)
+ writeBn254Field(t, Bn254DoubleX, expected, 0)
+ writeBn254Field(t, Bn254DoubleY, expected, 32)
+ require.Equal(t, expected, resBytes)
+ })
+
+ t.Run("PairingGenerator", func(t *testing.T) {
+ input := make([]byte, 192)
+ writeBn254Field(t, Bn254G1X, input, 0)
+ writeBn254Field(t, Bn254G1Y, input, 32)
+ writeBn254Field(t, Bn254G2XIm, input, 64)
+ writeBn254Field(t, Bn254G2XRe, input, 96)
+ writeBn254Field(t, Bn254G2YIm, input, 128)
+ writeBn254Field(t, Bn254G2YRe, input, 160)
+
+ resItem := crypto.bn254Pairing(nil, []stackitem.Item{stackitem.NewByteArray(input)})
+ resBytes, err := resItem.TryBytes()
+ require.NoError(t, err)
+ require.Equal(t, make([]byte, FieldElementLength), resBytes)
+ })
+
+ t.Run("PairingEmpty", func(t *testing.T) {
+ resItem := crypto.bn254Pairing(nil, []stackitem.Item{stackitem.NewByteArray(nil)})
+ resBytes, err := resItem.TryBytes()
+ require.NoError(t, err)
+ expected := [FieldElementLength]byte{FieldElementLength - 1: 1}
+ require.Equal(t, expected[:], resBytes)
+ })
+
+ t.Run("PairingVectors", func(t *testing.T) {
+ testCases := []struct {
+ hexStr string
+ lastByte byte
+ }{
+ {Bn254PairingPositive, 1},
+ {Bn254PairingNegative, 0},
+ {Bn254PairingInvalidG1, 0},
+ }
+
+ hexToBytes := func(hexStr string) []byte {
+ if strings.HasPrefix(strings.ToLower(hexStr), "0x") {
+ hexStr = hexStr[2:]
+ }
+ b, err := hex.DecodeString(hexStr)
+ require.NoError(t, err)
+ return b
+ }
+
+ for _, tc := range testCases {
+ input := hexToBytes(tc.hexStr)
+
+ resItem := crypto.bn254Pairing(nil, []stackitem.Item{stackitem.NewByteArray(input)})
+ resBytes, err := resItem.TryBytes()
+ require.NoError(t, err)
+
+ expected := [FieldElementLength]byte{FieldElementLength - 1: tc.lastByte}
+ require.Equal(t, expected[:], resBytes)
+ }
+ })
+
+ t.Run("InvalidInputs", func(t *testing.T) {
+ require.Panics(t, func() {
+ crypto.bn254Add(nil, []stackitem.Item{stackitem.NewByteArray(nil)})
+ })
+ require.Panics(t, func() {
+ crypto.bn254Mul(nil, []stackitem.Item{stackitem.NewByteArray(nil)})
+ })
+ require.Panics(t, func() {
+ crypto.bn254Pairing(nil, []stackitem.Item{stackitem.NewByteArray([]byte{0})})
+ })
+ })
+}
+
+func writeBn254Field(t *testing.T, hexStr string, buf []byte, offset int) {
+ if strings.HasPrefix(strings.ToLower(hexStr), "0x") {
+ hexStr = hexStr[2:]
+ }
+ require.LessOrEqual(t, len(hexStr), 2*FieldElementLength)
+ hexStr = strings.Repeat("0", 2*FieldElementLength-len(hexStr)) + hexStr
+ b, err := hex.DecodeString(hexStr)
+ require.NoError(t, err)
+ copy(buf[offset:offset+FieldElementLength], b)
+}
diff --git a/pkg/core/native/native_test/cryptolib_test.go b/pkg/core/native/native_test/cryptolib_test.go
index 327dc2b638..ec8c46c0f9 100644
--- a/pkg/core/native/native_test/cryptolib_test.go
+++ b/pkg/core/native/native_test/cryptolib_test.go
@@ -10,8 +10,10 @@ import (
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
+ "github.com/nspcc-dev/neo-go/pkg/compiler"
"github.com/nspcc-dev/neo-go/pkg/config"
"github.com/nspcc-dev/neo-go/pkg/core/native"
+ "github.com/nspcc-dev/neo-go/pkg/core/native/nativehashes"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/neotest"
@@ -595,3 +597,112 @@ func TestCryptoLib_RecoverSecp256K1_EIP2098Compat(t *testing.T) {
committeeInvoker.Invoke(t, pubBytes, "recoverSecp256K1", msgH, sigCompact)
}
}
+
+const (
+ Bn254G1X = "1"
+ Bn254G1Y = "2"
+ Bn254DoubleX = "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3"
+ Bn254DoubleY = "15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4"
+ Bn254G2XIm = "1800deef121f1e7641a819fe67140f7f8f87b140996fbbd1ba87fb145641f404"
+ Bn254G2XRe = "198e9393920d483a7260bfb731fb5db382322bc5b47fbf6c80f6321231df581"
+ Bn254G2YIm = "12c85ea5db8c6deb43baf7868f1c5341fd8ed84a82f89ed36e80b6a4a8dd22e1"
+ Bn254G2YRe = "090689d0585ff0756c27a122072274f89d4d1c6d2f9d3af03d86c6b29b53e2b"
+)
+
+func TestCryptoLib_Bn254(t *testing.T) {
+ bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
+ c.Hardforks = map[string]uint32{
+ config.HFFaun.String(): 2,
+ }
+ })
+ e := neotest.NewExecutor(t, bc, acc, acc)
+ p := e.CommitteeInvoker(nativehashes.CryptoLib)
+
+ p.InvokeFail(t, "method not found: bn254Add/1", "bn254Add", stackitem.NewByteArray([]byte{}))
+
+ input := make([]byte, 128)
+ writeBn254Field(t, Bn254G1X, input, 0)
+ writeBn254Field(t, Bn254G1Y, input, 32)
+ writeBn254Field(t, Bn254G1X, input, 64)
+ writeBn254Field(t, Bn254G1Y, input, 96)
+
+ expected := make([]byte, 64)
+ writeBn254Field(t, Bn254DoubleX, expected, 0)
+ writeBn254Field(t, Bn254DoubleY, expected, 32)
+
+ e.AddNewBlock(t)
+ p.Invoke(t, expected, "bn254Add", stackitem.NewByteArray(input))
+}
+
+func TestCryptoLib_Bn254InteropAPI(t *testing.T) {
+ bc, acc := chain.NewSingleWithCustomConfig(t, func(c *config.Blockchain) {
+ c.Hardforks = map[string]uint32{
+ config.HFFaun.String(): 0,
+ }
+ })
+ e := neotest.NewExecutor(t, bc, acc, acc)
+
+ src := `package testcryptolib
+ import "github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
+ func Bn254Add(input []byte) []byte {
+ return crypto.Bn254Add(input)
+ }
+ func Bn254Mul(input []byte) []byte {
+ return crypto.Bn254Mul(input)
+ }
+ func Bn254Pairing(input []byte) []byte {
+ return crypto.Bn254Pairing(input)
+ }`
+
+ ctr := neotest.CompileSource(t, e.Validator.ScriptHash(), strings.NewReader(src), &compiler.Options{
+ Name: "testcryptolib_contract",
+ })
+ e.DeployContract(t, ctr, nil)
+
+ ctrInvoker := e.NewInvoker(ctr.Hash, e.Committee)
+
+ t.Run("bn254Add", func(t *testing.T) {
+ input := make([]byte, 128)
+ writeBn254Field(t, Bn254G1X, input, 0)
+ writeBn254Field(t, Bn254G1Y, input, 32)
+ writeBn254Field(t, Bn254G1X, input, 64)
+ writeBn254Field(t, Bn254G1Y, input, 96)
+
+ expected := make([]byte, 64)
+ writeBn254Field(t, Bn254DoubleX, expected, 0)
+ writeBn254Field(t, Bn254DoubleY, expected, 32)
+ ctrInvoker.Invoke(t, expected, "bn254Add", stackitem.NewByteArray(input))
+ })
+
+ t.Run("bn254Mul", func(t *testing.T) {
+ input := make([]byte, 96)
+ writeBn254Field(t, Bn254G1X, input, 0)
+ writeBn254Field(t, Bn254G1Y, input, 32)
+ writeBn254Field(t, "2", input, 64)
+
+ expected := make([]byte, 64)
+ writeBn254Field(t, Bn254DoubleX, expected, 0)
+ writeBn254Field(t, Bn254DoubleY, expected, 32)
+ ctrInvoker.Invoke(t, expected, "bn254Mul", stackitem.NewByteArray(input))
+ })
+
+ t.Run("bn254Pairing", func(t *testing.T) {
+ input := make([]byte, 192)
+ writeBn254Field(t, Bn254G1X, input, 0)
+ writeBn254Field(t, Bn254G1Y, input, 32)
+ writeBn254Field(t, Bn254G2XIm, input, 64)
+ writeBn254Field(t, Bn254G2XRe, input, 96)
+ writeBn254Field(t, Bn254G2YIm, input, 128)
+ writeBn254Field(t, Bn254G2YRe, input, 160)
+
+ ctrInvoker.Invoke(t, make([]byte, 32), "bn254Pairing", stackitem.NewByteArray(input))
+ })
+}
+
+func writeBn254Field(t *testing.T, hexStr string, buf []byte, offset int) {
+ require.LessOrEqual(t, len(hexStr), 64)
+ hexStr = strings.Repeat("0", 64-len(hexStr)) + hexStr
+ b, err := hex.DecodeString(hexStr)
+ require.NoError(t, err)
+ copy(buf[offset:offset+32], b)
+}
diff --git a/pkg/core/native/native_test/management_test.go b/pkg/core/native/native_test/management_test.go
index c9bd259a6f..70bcb9edba 100644
--- a/pkg/core/native/native_test/management_test.go
+++ b/pkg/core/native/native_test/management_test.go
@@ -70,8 +70,9 @@ var (
// faunCSS holds serialized native contract states built for genesis block (with UpdateCounter 0)
// under assumption that hardforks from Aspidochelone to Faun (included) are enabled.
faunCSS = map[string]string{
- nativenames.StdLib: `{"id":-2,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":2426471238},"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":"base64UrlDecode","offset":56,"parameters":[{"name":"s","type":"String"}],"returntype":"String","safe":true},{"name":"base64UrlEncode","offset":63,"parameters":[{"name":"data","type":"String"}],"returntype":"String","safe":true},{"name":"deserialize","offset":70,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"hexDecode","offset":77,"parameters":[{"name":"str","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"hexEncode","offset":84,"parameters":[{"name":"bytes","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"itoa","offset":91,"parameters":[{"name":"value","type":"Integer"}],"returntype":"String","safe":true},{"name":"itoa","offset":98,"parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","safe":true},{"name":"jsonDeserialize","offset":105,"parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"jsonSerialize","offset":112,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"memoryCompare","offset":119,"parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":126,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":133,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":140,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","safe":true},{"name":"serialize","offset":147,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"strLen","offset":154,"parameters":[{"name":"str","type":"String"}],"returntype":"Integer","safe":true},{"name":"stringSplit","offset":161,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","safe":true},{"name":"stringSplit","offset":168,"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.Policy: `{"id":-7,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":2208257578},"manifest":{"name":"PolicyContract","abi":{"methods":[{"name":"blockAccount","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false},{"name":"getAttributeFee","offset":7,"parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"getBlockedAccounts","offset":14,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getExecFeeFactor","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"getFeePerByte","offset":28,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMaxTraceableBlocks","offset":35,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMaxValidUntilBlockIncrement","offset":42,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMillisecondsPerBlock","offset":49,"parameters":[],"returntype":"Integer","safe":true},{"name":"getStoragePrice","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"isBlocked","offset":63,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":true},{"name":"setAttributeFee","offset":70,"parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setExecFeeFactor","offset":77,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setFeePerByte","offset":84,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMaxTraceableBlocks","offset":91,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMaxValidUntilBlockIncrement","offset":98,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMillisecondsPerBlock","offset":105,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setStoragePrice","offset":112,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"unblockAccount","offset":119,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[{"name":"MillisecondsPerBlockChanged","parameters":[{"name":"old","type":"Integer"},{"name":"new","type":"Integer"}]}]},"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":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":2426471238},"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":"base64UrlDecode","offset":56,"parameters":[{"name":"s","type":"String"}],"returntype":"String","safe":true},{"name":"base64UrlEncode","offset":63,"parameters":[{"name":"data","type":"String"}],"returntype":"String","safe":true},{"name":"deserialize","offset":70,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"hexDecode","offset":77,"parameters":[{"name":"str","type":"String"}],"returntype":"ByteArray","safe":true},{"name":"hexEncode","offset":84,"parameters":[{"name":"bytes","type":"ByteArray"}],"returntype":"String","safe":true},{"name":"itoa","offset":91,"parameters":[{"name":"value","type":"Integer"}],"returntype":"String","safe":true},{"name":"itoa","offset":98,"parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","safe":true},{"name":"jsonDeserialize","offset":105,"parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","safe":true},{"name":"jsonSerialize","offset":112,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"memoryCompare","offset":119,"parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":126,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":133,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"memorySearch","offset":140,"parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","safe":true},{"name":"serialize","offset":147,"parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","safe":true},{"name":"strLen","offset":154,"parameters":[{"name":"str","type":"String"}],"returntype":"Integer","safe":true},{"name":"stringSplit","offset":161,"parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","safe":true},{"name":"stringSplit","offset":168,"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":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQA==","checksum":1841570703},"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":"bn254Add","offset":42,"parameters":[{"name":"input","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"bn254Mul","offset":49,"parameters":[{"name":"input","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"bn254Pairing","offset":56,"parameters":[{"name":"input","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"keccak256","offset":63,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"murmur32","offset":70,"parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","safe":true},{"name":"recoverSecp256K1","offset":77,"parameters":[{"name":"messageHash","type":"ByteArray"},{"name":"signature","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"ripemd160","offset":84,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"sha256","offset":91,"parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","safe":true},{"name":"verifyWithECDsa","offset":98,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","safe":true},{"name":"verifyWithEd25519","offset":105,"parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"}],"returntype":"Boolean","safe":true}],"events":[]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
+ nativenames.Policy: `{"id":-7,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":2208257578},"manifest":{"name":"PolicyContract","abi":{"methods":[{"name":"blockAccount","offset":0,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false},{"name":"getAttributeFee","offset":7,"parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","safe":true},{"name":"getBlockedAccounts","offset":14,"parameters":[],"returntype":"InteropInterface","safe":true},{"name":"getExecFeeFactor","offset":21,"parameters":[],"returntype":"Integer","safe":true},{"name":"getFeePerByte","offset":28,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMaxTraceableBlocks","offset":35,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMaxValidUntilBlockIncrement","offset":42,"parameters":[],"returntype":"Integer","safe":true},{"name":"getMillisecondsPerBlock","offset":49,"parameters":[],"returntype":"Integer","safe":true},{"name":"getStoragePrice","offset":56,"parameters":[],"returntype":"Integer","safe":true},{"name":"isBlocked","offset":63,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":true},{"name":"setAttributeFee","offset":70,"parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setExecFeeFactor","offset":77,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setFeePerByte","offset":84,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMaxTraceableBlocks","offset":91,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMaxValidUntilBlockIncrement","offset":98,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setMillisecondsPerBlock","offset":105,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"setStoragePrice","offset":112,"parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","safe":false},{"name":"unblockAccount","offset":119,"parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","safe":false}],"events":[{"name":"MillisecondsPerBlockChanged","parameters":[{"name":"old","type":"Integer"},{"name":"new","type":"Integer"}]}]},"features":{},"groups":[],"permissions":[{"contract":"*","methods":"*"}],"supportedstandards":[],"trusts":[],"extra":null},"updatecounter":0}`,
}
)
diff --git a/pkg/interop/native/crypto/crypto.go b/pkg/interop/native/crypto/crypto.go
index 45f0cefbbc..41f4871eed 100644
--- a/pkg/interop/native/crypto/crypto.go
+++ b/pkg/interop/native/crypto/crypto.go
@@ -115,3 +115,21 @@ func Bls12381Pairing(g1, g2 Bls12381Point) Bls12381Point {
func Keccak256(b []byte) interop.Hash256 {
return neogointernal.CallWithToken(Hash, "keccak256", int(contract.NoneFlag), b).(interop.Hash256)
}
+
+// Bn254Add represents `bn254Add` method of CryptoLib native contract.
+// Note that this method is available starting from [config.HFFaun] hardfork.
+func Bn254Add(input []byte) []byte {
+ return neogointernal.CallWithToken(Hash, "bn254Add", int(contract.NoneFlag), input).([]byte)
+}
+
+// Bn254Mul represents `bn254Mul` method of CryptoLib native contract.
+// Note that this method is available starting from [config.HFFaun] hardfork.
+func Bn254Mul(input []byte) []byte {
+ return neogointernal.CallWithToken(Hash, "bn254Mul", int(contract.NoneFlag), input).([]byte)
+}
+
+// Bn254Pairing represents `bn254Pairing` method of CryptoLib native contract.
+// Note that this method is available starting from [config.HFFaun] hardfork.
+func Bn254Pairing(input []byte) []byte {
+ return neogointernal.CallWithToken(Hash, "bn254Pairing", int(contract.NoneFlag), input).([]byte)
+}