|
| 1 | +package native_test |
| 2 | + |
| 3 | +import ( |
| 4 | + "math/big" |
| 5 | + "testing" |
| 6 | + |
| 7 | + "github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames" |
| 8 | + "github.com/nspcc-dev/neo-go/pkg/core/native" |
| 9 | + "github.com/nspcc-dev/neo-go/pkg/core/native/nativenames" |
| 10 | + "github.com/nspcc-dev/neo-go/pkg/core/state" |
| 11 | + "github.com/nspcc-dev/neo-go/pkg/core/transaction" |
| 12 | + "github.com/nspcc-dev/neo-go/pkg/crypto/hash" |
| 13 | + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" |
| 14 | + "github.com/nspcc-dev/neo-go/pkg/io" |
| 15 | + "github.com/nspcc-dev/neo-go/pkg/neotest" |
| 16 | + "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" |
| 17 | + "github.com/nspcc-dev/neo-go/pkg/util" |
| 18 | + "github.com/nspcc-dev/neo-go/pkg/vm/emit" |
| 19 | + "github.com/nspcc-dev/neo-go/pkg/vm/opcode" |
| 20 | + "github.com/stretchr/testify/require" |
| 21 | +) |
| 22 | + |
| 23 | +// TestCryptoLib_KoblitzVerificationScript builds transaction with custom witness that contains |
| 24 | +// the Koblitz tx signature bytes and Koblitz signature verification script. |
| 25 | +// This test ensures that transaction signed by Koblitz key passes verification and can |
| 26 | +// be successfully accepted to the chain. |
| 27 | +func TestCryptoLib_KoblitzVerificationScript(t *testing.T) { |
| 28 | + check := func( |
| 29 | + t *testing.T, |
| 30 | + buildVerificationScript func(t *testing.T, pub *keys.PublicKey) []byte, |
| 31 | + constructMsg func(t *testing.T, magic uint32, tx hash.Hashable) []byte, |
| 32 | + ) { |
| 33 | + c := newGasClient(t) |
| 34 | + gasInvoker := c.WithSigners(c.Committee) |
| 35 | + e := c.Executor |
| 36 | + |
| 37 | + // Consider the user that is able to sign txs only with Secp256k1 private key. |
| 38 | + // Let this user build, sign and push a GAS transfer transaction from its account |
| 39 | + // to some other account. |
| 40 | + pk, err := keys.NewSecp256k1PrivateKey() |
| 41 | + require.NoError(t, err) |
| 42 | + |
| 43 | + // Firstly, we need to build the N3 user's account address based on the user's public key. |
| 44 | + // The address itself is Hash160 from the verification script corresponding to the user's public key. |
| 45 | + // Since user's private key belongs to Koblitz curve, we can't use System.Crypto.CheckSig interop |
| 46 | + // in the verification script. Likely, we have a 'verifyWithECDsa' method in native CriptoLib contract |
| 47 | + // that is able to check Koblitz signature. So let's build custom verification script based on this call. |
| 48 | + // The script should call 'verifyWithECDsa' method of native CriptoLib contract with Koblitz curve identifier |
| 49 | + // and check the provided message signature against the user's Koblitz public key. |
| 50 | + vrfBytes := buildVerificationScript(t, pk.PublicKey()) |
| 51 | + |
| 52 | + // Construct the user's account script hash. It's effectively a verification script hash. |
| 53 | + from := hash.Hash160(vrfBytes) |
| 54 | + |
| 55 | + // Supply this account with some initial balance so that the user is able to pay for his transactions. |
| 56 | + gasInvoker.Invoke(t, true, "transfer", c.Committee.ScriptHash(), from, 10000_0000_0000, nil) |
| 57 | + |
| 58 | + // Construct transaction that transfers 5 GAS from the user's account to some other account. |
| 59 | + to := util.Uint160{1, 2, 3} |
| 60 | + amount := 5 |
| 61 | + tx := gasInvoker.PrepareInvokeNoSign(t, "transfer", from, to, amount, nil) |
| 62 | + tx.Signers = []transaction.Signer{ |
| 63 | + { |
| 64 | + Account: from, |
| 65 | + Scopes: transaction.CalledByEntry, |
| 66 | + }, |
| 67 | + } |
| 68 | + neotest.AddNetworkFee(t, e.Chain, tx) |
| 69 | + neotest.AddSystemFee(e.Chain, tx, -1) |
| 70 | + |
| 71 | + // Add some more network fee to pay for the witness verification. This value may be calculated precisely, |
| 72 | + // but let's keep some inaccurate value for the test. |
| 73 | + tx.NetworkFee += 540_0000 |
| 74 | + |
| 75 | + // This transaction (along with the network magic) should be signed by the user's Koblitz private key. |
| 76 | + msg := constructMsg(t, uint32(e.Chain.GetConfig().Magic), tx) |
| 77 | + // Note: unlike N3 standard signing scheme, the user has to sign the **hash of the hash** of the [magic+txHash] |
| 78 | + // since during witness verification only transaction hash is available in the execution |
| 79 | + // context (not the whole serialized transaction bytes). And CryptoLib's 'verifyWithECDsa' method |
| 80 | + // takes as an argument unhashed message and then takes sha256 hash of this message. |
| 81 | + signature := pk.SignHash(hash.Sha256(msg)) |
| 82 | + |
| 83 | + // Ensure that signature verification passes. This line here is just for testing purposes, |
| 84 | + // it won't be present in the real code. |
| 85 | + require.True(t, pk.PublicKey().Verify(signature, hash.Sha256(msg).BytesBE())) |
| 86 | + |
| 87 | + // Build invocation witness script for the user's account. |
| 88 | + invBytes := buildKoblitzInvocationScript(t, signature) |
| 89 | + |
| 90 | + // Construct witness for signer #0 (the user itself). |
| 91 | + tx.Scripts = []transaction.Witness{ |
| 92 | + { |
| 93 | + InvocationScript: invBytes, |
| 94 | + VerificationScript: vrfBytes, |
| 95 | + }, |
| 96 | + } |
| 97 | + |
| 98 | + // Add transaction to the chain. No error is expected on new block addition. Note, that this line performs |
| 99 | + // all those checks that are executed during transaction acceptance in the real network. |
| 100 | + e.AddNewBlock(t, tx) |
| 101 | + |
| 102 | + // Double-check: ensure funds have been transferred. |
| 103 | + e.CheckGASBalance(t, to, big.NewInt(int64(amount))) |
| 104 | + } |
| 105 | + |
| 106 | + // N3 compatible witness verification script has larger constant length and higher execution cost |
| 107 | + // (186 bytes, 5116020 GAS including Invocation script execution). |
| 108 | + check(t, buildKoblitzVerificationScriptCompat, constructMessageCompat) |
| 109 | + // N3 incompatible witness verification script has lower variable length and lower execution cost |
| 110 | + // (136 bytes, 4120620 GAS including Invocation script execution). |
| 111 | + check(t, buildKoblitzVerificationScriptSimple, constructMessageSimple) |
| 112 | +} |
| 113 | + |
| 114 | +// buildKoblitzVerificationScript builds custom verification script for the provided Koblitz public key. |
| 115 | +// It checks that the following message is signed by the provided public key: |
| 116 | +// |
| 117 | +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]) |
| 118 | +// |
| 119 | +// It produces constant-length verification script (186 bytes) independently of the network parameters. |
| 120 | +func buildKoblitzVerificationScriptCompat(t *testing.T, pub *keys.PublicKey) []byte { |
| 121 | + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) |
| 122 | + |
| 123 | + // vrf is witness verification script corresponding to the pub. |
| 124 | + vrf := io.NewBufBinWriter() |
| 125 | + emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. |
| 126 | + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. |
| 127 | + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. |
| 128 | + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, |
| 129 | + // i.e. msg = Sha256([4-bytes-network-magic-LE, tx.Hash()]) |
| 130 | + // Firstly, convert network magic (uint32) to LE buffer. |
| 131 | + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic. |
| 132 | + // First byte: n & 0xFF |
| 133 | + emit.Opcodes(vrf.BinWriter, opcode.DUP) |
| 134 | + emit.Int(vrf.BinWriter, 0xFF) // TODO: this can be optimize in order not to allocate 0xFF every time, but need to compare execution price. |
| 135 | + emit.Opcodes(vrf.BinWriter, opcode.AND, |
| 136 | + opcode.SWAP, // Swap with the original network n. |
| 137 | + opcode.PUSH8, |
| 138 | + opcode.SHR) |
| 139 | + // Second byte: n >> 8 & 0xFF |
| 140 | + emit.Opcodes(vrf.BinWriter, opcode.DUP) |
| 141 | + emit.Int(vrf.BinWriter, 0xFF) |
| 142 | + emit.Opcodes(vrf.BinWriter, opcode.AND, |
| 143 | + opcode.SWAP, // Swap with the n >> 8. |
| 144 | + opcode.PUSH8, |
| 145 | + opcode.SHR) |
| 146 | + // Third byte: n >> 16 & 0xFF |
| 147 | + emit.Opcodes(vrf.BinWriter, opcode.DUP) |
| 148 | + emit.Int(vrf.BinWriter, 0xFF) |
| 149 | + emit.Opcodes(vrf.BinWriter, opcode.AND, |
| 150 | + opcode.SWAP, // Swap with the n >> 16. |
| 151 | + opcode.PUSH8, |
| 152 | + opcode.SHR) |
| 153 | + // Fourth byte: n >> 24 & 0xFF |
| 154 | + emit.Int(vrf.BinWriter, 0xFF) // no DUP is needed since it's the last shift. |
| 155 | + emit.Opcodes(vrf.BinWriter, opcode.AND) |
| 156 | + // Put these 4 bytes into buffer. |
| 157 | + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.NEWBUFFER) // allocate new 4-bytes-length buffer. |
| 158 | + emit.Opcodes(vrf.BinWriter, |
| 159 | + // Set fourth byte. |
| 160 | + opcode.DUP, opcode.PUSH3, |
| 161 | + opcode.PUSH3, opcode.ROLL, |
| 162 | + opcode.SETITEM, |
| 163 | + // Set third byte. |
| 164 | + opcode.DUP, opcode.PUSH2, |
| 165 | + opcode.PUSH3, opcode.ROLL, |
| 166 | + opcode.SETITEM, |
| 167 | + // Set second byte. |
| 168 | + opcode.DUP, opcode.PUSH1, |
| 169 | + opcode.PUSH3, opcode.ROLL, |
| 170 | + opcode.SETITEM, |
| 171 | + // Set first byte. |
| 172 | + opcode.DUP, opcode.PUSH0, |
| 173 | + opcode.PUSH3, opcode.ROLL, |
| 174 | + opcode.SETITEM) |
| 175 | + // Retrieve executing transaction hash. |
| 176 | + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). |
| 177 | + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM, // pick 0-th transaction item (the transaction hash). |
| 178 | + opcode.CAT, // concatenate network magic and transaction hash. |
| 179 | + opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). |
| 180 | + opcode.PACK) // pack arguments for 'sha256' call. |
| 181 | + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.All) // emit the call to 'sha256' itself. |
| 182 | + // Continue construction of 'verifyWithECDsa' call. |
| 183 | + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. |
| 184 | + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. |
| 185 | + require.NoError(t, vrf.Err) |
| 186 | + |
| 187 | + return vrf.Bytes() |
| 188 | + // Here's an example of the resulting witness verification script (186 bytes length, always constant length): |
| 189 | + // NEO-GO-VM 0 > loadbase64 ABZQDCECYn75w2MePMuPvExbbEnjjM7eWnmvseGwcI+7lYp4AtdBxfug4EoB/wCRUBipSgH/AJFQGKlKAf8AkVAYqQH/AJEUiEoTE1LQShITUtBKERNS0EoQE1LQQS1RCDAQzosRwB8MBnNoYTI1NgwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUhTAHwwPdmVyaWZ5V2l0aEVDRHNhDBQb9XWrEYlohBNhCjWhKIbN4LZsckFifVtS |
| 190 | + // READY: loaded 186 instructions |
| 191 | + // NEO-GO-VM 0 > ops |
| 192 | + // INDEX OPCODE PARAMETER |
| 193 | + // 0 PUSHINT8 22 (16) << |
| 194 | + // 2 SWAP |
| 195 | + // 3 PUSHDATA1 02627ef9c3631e3ccb8fbc4c5b6c49e38ccede5a79afb1e1b0708fbb958a7802d7 |
| 196 | + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) |
| 197 | + // 43 DUP |
| 198 | + // 44 PUSHINT16 255 (ff00) |
| 199 | + // 47 AND |
| 200 | + // 48 SWAP |
| 201 | + // 49 PUSH8 |
| 202 | + // 50 SHR |
| 203 | + // 51 DUP |
| 204 | + // 52 PUSHINT16 255 (ff00) |
| 205 | + // 55 AND |
| 206 | + // 56 SWAP |
| 207 | + // 57 PUSH8 |
| 208 | + // 58 SHR |
| 209 | + // 59 DUP |
| 210 | + // 60 PUSHINT16 255 (ff00) |
| 211 | + // 63 AND |
| 212 | + // 64 SWAP |
| 213 | + // 65 PUSH8 |
| 214 | + // 66 SHR |
| 215 | + // 67 PUSHINT16 255 (ff00) |
| 216 | + // 70 AND |
| 217 | + // 71 PUSH4 |
| 218 | + // 72 NEWBUFFER |
| 219 | + // 73 DUP |
| 220 | + // 74 PUSH3 |
| 221 | + // 75 PUSH3 |
| 222 | + // 76 ROLL |
| 223 | + // 77 SETITEM |
| 224 | + // 78 DUP |
| 225 | + // 79 PUSH2 |
| 226 | + // 80 PUSH3 |
| 227 | + // 81 ROLL |
| 228 | + // 82 SETITEM |
| 229 | + // 83 DUP |
| 230 | + // 84 PUSH1 |
| 231 | + // 85 PUSH3 |
| 232 | + // 86 ROLL |
| 233 | + // 87 SETITEM |
| 234 | + // 88 DUP |
| 235 | + // 89 PUSH0 |
| 236 | + // 90 PUSH3 |
| 237 | + // 91 ROLL |
| 238 | + // 92 SETITEM |
| 239 | + // 93 SYSCALL System.Runtime.GetScriptContainer (2d510830) |
| 240 | + // 98 PUSH0 |
| 241 | + // 99 PICKITEM |
| 242 | + // 100 CAT |
| 243 | + // 101 PUSH1 |
| 244 | + // 102 PACK |
| 245 | + // 103 PUSH15 |
| 246 | + // 104 PUSHDATA1 736861323536 ("sha256") |
| 247 | + // 112 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") |
| 248 | + // 134 SYSCALL System.Contract.Call (627d5b52) |
| 249 | + // 139 PUSH4 |
| 250 | + // 140 PACK |
| 251 | + // 141 PUSH15 |
| 252 | + // 142 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") |
| 253 | + // 159 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") |
| 254 | + // 181 SYSCALL System.Contract.Call (627d5b52) |
| 255 | +} |
| 256 | + |
| 257 | +// buildKoblitzVerificationScriptSimple builds witness verification script for Koblitz public key. |
| 258 | +// This method differs from buildKoblitzVerificationScriptCompat in that it checks |
| 259 | +// |
| 260 | +// sha256([var-bytes-network-magic, txHash-bytes-BE]) |
| 261 | +// |
| 262 | +// instead of |
| 263 | +// |
| 264 | +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]). |
| 265 | +// |
| 266 | +// Note, that in this way of signing the length of var-network-magic-bytes is non-constant and depends |
| 267 | +// on the network value (but around 136 bytes). This way of signing differs from the standard and thus, |
| 268 | +// requires minor compatibility changes from the wallet SDK. |
| 269 | +func buildKoblitzVerificationScriptSimple(t *testing.T, pub *keys.PublicKey) []byte { |
| 270 | + criptoLibH := state.CreateNativeContractHash(nativenames.CryptoLib) |
| 271 | + |
| 272 | + // vrf is witness verification script corresponding to the pub. |
| 273 | + // vrf is witness verification script corresponding to the pk. |
| 274 | + vrf := io.NewBufBinWriter() |
| 275 | + emit.Int(vrf.BinWriter, int64(native.Secp256k1)) // push Koblitz curve identifier. |
| 276 | + emit.Opcodes(vrf.BinWriter, opcode.SWAP) // swap curve identifier with the signature. |
| 277 | + emit.Bytes(vrf.BinWriter, pub.Bytes()) // emit the caller's public key. |
| 278 | + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, |
| 279 | + // i.e. msg = Sha256([network-magic-bytes, tx.Hash()]) |
| 280 | + // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). |
| 281 | + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetNetwork) // push network magic. |
| 282 | + // Retrieve executing transaction hash. |
| 283 | + emit.Syscall(vrf.BinWriter, interopnames.SystemRuntimeGetScriptContainer) // push the script container (executing transaction, actually). |
| 284 | + emit.Opcodes(vrf.BinWriter, opcode.PUSH0, opcode.PICKITEM, // pick 0-th transaction item (the transaction hash). |
| 285 | + opcode.CAT, // concatenate network magic and transaction hash; this instruction will convert network magic to bytes using BigInteger rules of conversion. |
| 286 | + opcode.PUSH1, // push 1 (the number of arguments of 'sha256' method of native CryptoLib). |
| 287 | + opcode.PACK) // pack arguments for 'sha256' call. |
| 288 | + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "sha256", callflag.All) // emit the call to 'sha256' itself. |
| 289 | + // Continue construction of 'verifyWithECDsa' call. |
| 290 | + emit.Opcodes(vrf.BinWriter, opcode.PUSH4, opcode.PACK) // pack arguments for 'verifyWithECDsa' call. |
| 291 | + emit.AppCallNoArgs(vrf.BinWriter, criptoLibH, "verifyWithECDsa", callflag.All) // emit the call to 'verifyWithECDsa' itself. |
| 292 | + require.NoError(t, vrf.Err) |
| 293 | + |
| 294 | + return vrf.Bytes() |
| 295 | + // Here's an example of the resulting witness verification script (136 bytes length, but the length depends on the network magic value): |
| 296 | + // NEO-GO-VM 0 > loadbase64 ABZQDCEDp38Tevu0to16RQqloo/jNfgExYmoCElLS2JuuYcH831Bxfug4EEtUQgwEM6LEcAfDAZzaGEyNTYMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1IUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUg== |
| 297 | + // READY: loaded 136 instructions |
| 298 | + // NEO-GO-VM 0 > ops |
| 299 | + // INDEX OPCODE PARAMETER |
| 300 | + // 0 PUSHINT8 22 (16) << |
| 301 | + // 2 SWAP |
| 302 | + // 3 PUSHDATA1 03a77f137afbb4b68d7a450aa5a28fe335f804c589a808494b4b626eb98707f37d |
| 303 | + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) |
| 304 | + // 43 SYSCALL System.Runtime.GetScriptContainer (2d510830) |
| 305 | + // 48 PUSH0 |
| 306 | + // 49 PICKITEM |
| 307 | + // 50 CAT |
| 308 | + // 51 PUSH1 |
| 309 | + // 52 PACK |
| 310 | + // 53 PUSH15 |
| 311 | + // 54 PUSHDATA1 736861323536 ("sha256") |
| 312 | + // 62 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") |
| 313 | + // 84 SYSCALL System.Contract.Call (627d5b52) |
| 314 | + // 89 PUSH4 |
| 315 | + // 90 PACK |
| 316 | + // 91 PUSH15 |
| 317 | + // 92 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") |
| 318 | + // 109 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") |
| 319 | + // 131 SYSCALL System.Contract.Call (627d5b52) |
| 320 | +} |
| 321 | + |
| 322 | +// buildKoblitzInvocationScript builds witness invocation script for the transaction signature. The signature |
| 323 | +// itself may be produced by public key over any curve (not required Koblitz, the algorithm is the same). |
| 324 | +func buildKoblitzInvocationScript(t *testing.T, signature []byte) []byte { |
| 325 | + //Exactly like during standard |
| 326 | + // signature verification, the resulting script pushes Koblitz signature bytes onto stack. |
| 327 | + inv := io.NewBufBinWriter() |
| 328 | + emit.Bytes(inv.BinWriter, signature) // message signatre bytes. |
| 329 | + require.NoError(t, inv.Err) |
| 330 | + |
| 331 | + return inv.Bytes() |
| 332 | + // Here's an example of the resulting witness invocation script (66 bytes length, always constant length): |
| 333 | + // NEO-GO-VM > loadbase64 DEBMGKU/MdSizlzaVNDUUbd1zMZQJ43eTaZ4vBCpmkJ/wVh1TYrAWEbFyHhkqq+aYxPCUS43NKJdJTXavcjB8sTP |
| 334 | + // READY: loaded 66 instructions |
| 335 | + // NEO-GO-VM 0 > ops |
| 336 | + // INDEX OPCODE PARAMETER |
| 337 | + // 0 PUSHDATA1 4c18a53f31d4a2ce5cda54d0d451b775ccc650278dde4da678bc10a99a427fc158754d8ac05846c5c87864aaaf9a6313c2512e3734a25d2535dabdc8c1f2c4cf << |
| 338 | +} |
| 339 | + |
| 340 | +// constructMessageCompat constructs message for signing following the N3 rules: |
| 341 | +// |
| 342 | +// sha256([4-bytes-network-magic-LE, txHash-bytes-BE]) |
| 343 | +func constructMessageCompat(t *testing.T, magic uint32, tx hash.Hashable) []byte { |
| 344 | + return hash.NetSha256(magic, tx).BytesBE() |
| 345 | +} |
| 346 | + |
| 347 | +// constructMessageCompat constructs message for signing that does not follow N3 rules, |
| 348 | +// but entails smaller verification script size and smaller verification price: |
| 349 | +// |
| 350 | +// sha256([var-bytes-network-magic, txHash-bytes-BE]) |
| 351 | +func constructMessageSimple(t *testing.T, magic uint32, tx hash.Hashable) []byte { |
| 352 | + m := big.NewInt(int64(magic)) |
| 353 | + return hash.Sha256(append(m.Bytes(), tx.Hash().BytesBE()...)).BytesBE() |
| 354 | +} |
0 commit comments