package consensushashing_test import ( "encoding/hex" "fmt" "testing" "github.com/kaspanet/go-secp256k1" "github.com/kaspanet/kaspad/domain/consensus/utils/consensushashing" "github.com/kaspanet/kaspad/domain/consensus/utils/txscript" "github.com/kaspanet/kaspad/domain/consensus/utils/utxo" "github.com/kaspanet/kaspad/domain/dagconfig" "github.com/kaspanet/kaspad/util" "github.com/kaspanet/kaspad/domain/consensus/model/externalapi" ) // shortened versions of SigHash types to fit in single line of test case const ( all = consensushashing.SigHashAll none = consensushashing.SigHashNone single = consensushashing.SigHashSingle allAnyoneCanPay = consensushashing.SigHashAll | consensushashing.SigHashAnyOneCanPay noneAnyoneCanPay = consensushashing.SigHashNone | consensushashing.SigHashAnyOneCanPay singleAnyoneCanPay = consensushashing.SigHashSingle | consensushashing.SigHashAnyOneCanPay ) func modifyOutput(outputIndex int) func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { return func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { clone := tx.Clone() clone.Outputs[outputIndex].Value = 100 return clone } } func modifyInput(inputIndex int) func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { return func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { clone := tx.Clone() clone.Inputs[inputIndex].PreviousOutpoint.Index = 2 return clone } } func modifyAmountSpent(inputIndex int) func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { return func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { clone := tx.Clone() utxoEntry := clone.Inputs[inputIndex].UTXOEntry clone.Inputs[inputIndex].UTXOEntry = utxo.NewUTXOEntry(666, utxoEntry.ScriptPublicKey(), false, 100) return clone } } func modifyScriptPublicKey(inputIndex int) func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { return func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { clone := tx.Clone() utxoEntry := clone.Inputs[inputIndex].UTXOEntry scriptPublicKey := utxoEntry.ScriptPublicKey() scriptPublicKey.Script = append(scriptPublicKey.Script, 1, 2, 3) clone.Inputs[inputIndex].UTXOEntry = utxo.NewUTXOEntry(utxoEntry.Amount(), scriptPublicKey, false, 100) return clone } } func modifySequence(inputIndex int) func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { return func(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { clone := tx.Clone() clone.Inputs[inputIndex].Sequence = 12345 return clone } } func modifyPayload(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { clone := tx.Clone() clone.Payload = []byte{6, 6, 6, 4, 2, 0, 1, 3, 3, 7} return clone } func modifyGas(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { clone := tx.Clone() clone.Gas = 1234 return clone } func modifySubnetworkID(tx *externalapi.DomainTransaction) *externalapi.DomainTransaction { clone := tx.Clone() clone.SubnetworkID = externalapi.DomainSubnetworkID{6, 6, 6, 4, 2, 0, 1, 3, 3, 7} return clone } func TestCalculateSignatureHashSchnorr(t *testing.T) { nativeTx, subnetworkTx, err := generateTxs() if err != nil { t.Fatalf("Error from generateTxs: %+v", err) } // Note: Expected values were generated by the same code that they test, // As long as those were not verified using 3rd-party code they only check for regression, not correctness tests := []struct { name string tx *externalapi.DomainTransaction hashType consensushashing.SigHashType inputIndex int modificationFunction func(*externalapi.DomainTransaction) *externalapi.DomainTransaction expectedSignatureHash string }{ // native transactions // sigHashAll {name: "native-all-0", tx: nativeTx, hashType: all, inputIndex: 0, expectedSignatureHash: "3e4a8effa6903dea5f762754ec410d732114ec2907e5bcbae7b6dd8d3f309a10"}, {name: "native-all-0-modify-input-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifyInput(1), // should change the hash expectedSignatureHash: "0bd2947383101f9708d94d5799626c69c1b8472d2de66523c90c4a674e99cc51"}, {name: "native-all-0-modify-output-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifyOutput(1), // should change the hash expectedSignatureHash: "ae69aa1372e958f069bf52d2628ead7ee789f195340b615ff0bcb6f01a995810"}, {name: "native-all-0-modify-sequence-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifySequence(1), // should change the hash expectedSignatureHash: "51295575e7efc1fe1c2e741ade49089e3d780d15d26e9a0b18b3d90e35caf795"}, {name: "native-all-anyonecanpay-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, expectedSignatureHash: "0a13d3cab42a6cf3a7ef96f7b28c9bb0d98c209a3032ff85a6bfa7dac520f2c2"}, {name: "native-all-anyonecanpay-0-modify-input-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifyInput(0), // should change the hash expectedSignatureHash: "aeaa56f5bc99daea0be5ed4b047808ce0123a81ac89c6089b72fa7199f5cd1c6"}, {name: "native-all-anyonecanpay-0-modify-input-1", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifyInput(1), // shouldn't change the hash expectedSignatureHash: "0a13d3cab42a6cf3a7ef96f7b28c9bb0d98c209a3032ff85a6bfa7dac520f2c2"}, {name: "native-all-anyonecanpay-0-modify-sequence", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash expectedSignatureHash: "0a13d3cab42a6cf3a7ef96f7b28c9bb0d98c209a3032ff85a6bfa7dac520f2c2"}, // sigHashNone {name: "native-none-0", tx: nativeTx, hashType: none, inputIndex: 0, expectedSignatureHash: "da53f7c726b55357adb1b644265fe7b9b7897cadde91a942d6127195c2ce99dc"}, {name: "native-none-0-modify-output-1", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifyOutput(1), // shouldn't change the hash expectedSignatureHash: "da53f7c726b55357adb1b644265fe7b9b7897cadde91a942d6127195c2ce99dc"}, {name: "native-none-0-modify-sequence-0", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifySequence(0), // should change the hash expectedSignatureHash: "72c07c152a3792fb863d2de219ab4e863fe6779dc970a5c3958e26b3a3b9f139"}, {name: "native-none-0-modify-sequence-1", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash expectedSignatureHash: "da53f7c726b55357adb1b644265fe7b9b7897cadde91a942d6127195c2ce99dc"}, {name: "native-none-anyonecanpay-0", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, expectedSignatureHash: "18eb79df328a516708f792cadfc4bf2be21b6add35fb6637a20347d532b1dce1"}, {name: "native-none-anyonecanpay-0-modify-amount-spent", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, modificationFunction: modifyAmountSpent(0), // should change the hash expectedSignatureHash: "674a8e6effa0bbfdb3df3ca45a7b17ab695cc0f9b3e0519e5bff165de13604e2"}, {name: "native-none-anyonecanpay-0-modify-script-public-key", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, modificationFunction: modifyScriptPublicKey(0), // should change the hash expectedSignatureHash: "7a879d339c9b948c5264f1c0b8463f551221b2dcd575623f178cbbfcf7e01987"}, // sigHashSingle {name: "native-single-0", tx: nativeTx, hashType: single, inputIndex: 0, expectedSignatureHash: "99c0a4a381fed9dbd651450d6ca969a6e8cdd941e9d73be086a1ba6c90fb630f"}, {name: "native-single-0-modify-output-0", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifyOutput(0), // should change the hash expectedSignatureHash: "92189a32391ca50a454d1853efed55acb1c49993911a1201df9891c866c483ee"}, {name: "native-single-0-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifyOutput(1), // shouldn't change the hash expectedSignatureHash: "99c0a4a381fed9dbd651450d6ca969a6e8cdd941e9d73be086a1ba6c90fb630f"}, {name: "native-single-0-modify-sequence-0", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifySequence(0), // should change the hash expectedSignatureHash: "765e2289df98b3a5269f112d4b36d57fe32c74d42e04a3046c6a3c8dd78a4121"}, {name: "native-single-0-modify-sequence-1", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash expectedSignatureHash: "99c0a4a381fed9dbd651450d6ca969a6e8cdd941e9d73be086a1ba6c90fb630f"}, {name: "native-single-2-no-corresponding-output", tx: nativeTx, hashType: single, inputIndex: 2, expectedSignatureHash: "43de18c04d7fde81f49a40228d8730b4ceb0c66c77841c22622f59554769dd13"}, {name: "native-single-2-no-corresponding-output-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 2, modificationFunction: modifyOutput(1), // shouldn't change the hash expectedSignatureHash: "43de18c04d7fde81f49a40228d8730b4ceb0c66c77841c22622f59554769dd13"}, {name: "native-single-anyonecanpay-0", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 0, expectedSignatureHash: "2e270f86fd68f780a5aa8d250364ab6786d990040268e5d561d09dde365dfab7"}, {name: "native-single-anyonecanpay-2-no-corresponding-output", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 2, expectedSignatureHash: "afc05dd6b4a530cc3a4d7d23126548bd1f31c793e9282cbbfa27ff5566219501"}, // subnetwork transaction {name: "subnetwork-all-0", tx: subnetworkTx, hashType: all, inputIndex: 0, expectedSignatureHash: "5a67423ee048e067b94e2d4fc2960f62eceff6aa8b6c5ad71e3b7b7e5ff6bad7"}, {name: "subnetwork-all-modify-payload", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifyPayload, // should change the hash expectedSignatureHash: "0d3bc5914da8dc8df081945fea1255359f380ca9baa8b31dfb3657c1e3c6038a"}, {name: "subnetwork-all-modify-gas", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifyGas, // should change the hash expectedSignatureHash: "70abe9f947d0a0f5d735f9a063db8af41fe5902940f2693a1782119063097094"}, {name: "subnetwork-all-subnetwork-id", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifySubnetworkID, // should change the hash expectedSignatureHash: "571a0b7ea905b7a6ff7ab825b72d23f911bac0bfaa7c4c97a4887a3d090925d4"}, } for _, test := range tests { tx := test.tx if test.modificationFunction != nil { tx = test.modificationFunction(tx) } actualSignatureHash, err := consensushashing.CalculateSignatureHashSchnorr( tx, test.inputIndex, test.hashType, &consensushashing.SighashReusedValues{}) if err != nil { t.Errorf("%s: Error from CalculateSignatureHashSchnorr: %+v", test.name, err) continue } if actualSignatureHash.String() != test.expectedSignatureHash { t.Errorf("%s: expected signature hash: '%s'; but got: '%s'", test.name, test.expectedSignatureHash, actualSignatureHash) } } } func TestCalculateSignatureHashECDSA(t *testing.T) { nativeTx, subnetworkTx, err := generateTxs() if err != nil { t.Fatalf("Error from generateTxs: %+v", err) } // Note: Expected values were generated by the same code that they test, // As long as those were not verified using 3rd-party code they only check for regression, not correctness tests := []struct { name string tx *externalapi.DomainTransaction hashType consensushashing.SigHashType inputIndex int modificationFunction func(*externalapi.DomainTransaction) *externalapi.DomainTransaction expectedSignatureHash string }{ // native transactions // sigHashAll {name: "native-all-0", tx: nativeTx, hashType: all, inputIndex: 0, expectedSignatureHash: "150a2bcd0296f76a3395a4a9982df46bf24ce93f955bc39c10ffc95b6c524eb3"}, {name: "native-all-0-modify-input-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifyInput(1), // should change the hash expectedSignatureHash: "8fb5304e181b003e0c123ea6f6677abc3704feec47054e8a1c218b827bf57ca0"}, {name: "native-all-0-modify-output-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifyOutput(1), // should change the hash expectedSignatureHash: "180cb36454aa80822694decde4fc711104e35a4bddf92286a83877f2b8d0aabb"}, {name: "native-all-0-modify-sequence-1", tx: nativeTx, hashType: all, inputIndex: 0, modificationFunction: modifySequence(1), // should change the hash expectedSignatureHash: "5b5f1c42a3c3c16bb4922777e2963c00e6a2cce39afa1980d2288053378f9632"}, {name: "native-all-anyonecanpay-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, expectedSignatureHash: "9473ffbe0db4914f2cd8fe5d67479224a02eb031882d9170b785d0d2c7bfcd1b"}, {name: "native-all-anyonecanpay-0-modify-input-0", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifyInput(0), // should change the hash expectedSignatureHash: "1208491d564c138d613f51b997394dbad23feca7c0ca88c7f36cdf6b9173327d"}, {name: "native-all-anyonecanpay-0-modify-input-1", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifyInput(1), // shouldn't change the hash expectedSignatureHash: "9473ffbe0db4914f2cd8fe5d67479224a02eb031882d9170b785d0d2c7bfcd1b"}, {name: "native-all-anyonecanpay-0-modify-sequence", tx: nativeTx, hashType: allAnyoneCanPay, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash expectedSignatureHash: "9473ffbe0db4914f2cd8fe5d67479224a02eb031882d9170b785d0d2c7bfcd1b"}, // sigHashNone {name: "native-none-0", tx: nativeTx, hashType: none, inputIndex: 0, expectedSignatureHash: "6e427f26e4a9c1a7fc556a8aabdedb8799a897bc5d42a0a18615e5a0f7639d8f"}, {name: "native-none-0-modify-output-1", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifyOutput(1), // shouldn't change the hash expectedSignatureHash: "6e427f26e4a9c1a7fc556a8aabdedb8799a897bc5d42a0a18615e5a0f7639d8f"}, {name: "native-none-0-modify-sequence-0", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifySequence(0), // should change the hash expectedSignatureHash: "57d76e2568cd3fc3426b4f8836fe900a2d20e740fad744949126651fd549f75e"}, {name: "native-none-0-modify-sequence-1", tx: nativeTx, hashType: none, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash expectedSignatureHash: "6e427f26e4a9c1a7fc556a8aabdedb8799a897bc5d42a0a18615e5a0f7639d8f"}, {name: "native-none-anyonecanpay-0", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, expectedSignatureHash: "ef97a0f89d623302619f9aa2a00fce1522e72d4d255e6c6d3ed225ffc02f38ff"}, {name: "native-none-anyonecanpay-0-modify-amount-spent", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, modificationFunction: modifyAmountSpent(0), // should change the hash expectedSignatureHash: "043a2a943f02607be126ac6609ab2324aae389d784a4147f27101e7da379311a"}, {name: "native-none-anyonecanpay-0-modify-script-public-key", tx: nativeTx, hashType: noneAnyoneCanPay, inputIndex: 0, modificationFunction: modifyScriptPublicKey(0), // should change the hash expectedSignatureHash: "f2cd43d0d047cdcfbf8b6e12a86cfbf250f1e2c34dc5e631675a5f5b867bd9e6"}, // sigHashSingle {name: "native-single-0", tx: nativeTx, hashType: single, inputIndex: 0, expectedSignatureHash: "1cf376b9f180f59a1b9a5e420390198c20e1ba79c39349271632145fda175247"}, {name: "native-single-0-modify-output-0", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifyOutput(0), // should change the hash expectedSignatureHash: "c2c7e77516a15f0f47f886b14cc47af2045eea15f176a9a560a9d47d8866958f"}, {name: "native-single-0-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifyOutput(1), // shouldn't change the hash expectedSignatureHash: "1cf376b9f180f59a1b9a5e420390198c20e1ba79c39349271632145fda175247"}, {name: "native-single-0-modify-sequence-0", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifySequence(0), // should change the hash expectedSignatureHash: "2034eec2acc08c49d3896cc1bda214904ca850fc5989518885465b5a3154ee7f"}, {name: "native-single-0-modify-sequence-1", tx: nativeTx, hashType: single, inputIndex: 0, modificationFunction: modifySequence(1), // shouldn't change the hash expectedSignatureHash: "1cf376b9f180f59a1b9a5e420390198c20e1ba79c39349271632145fda175247"}, {name: "native-single-2-no-corresponding-output", tx: nativeTx, hashType: single, inputIndex: 2, expectedSignatureHash: "84ae3bb03202efc587d97e5aea7b80581b82242b969e6dea13b8daa32d24c0c1"}, {name: "native-single-2-no-corresponding-output-modify-output-1", tx: nativeTx, hashType: single, inputIndex: 2, modificationFunction: modifyOutput(1), // shouldn't change the hash expectedSignatureHash: "84ae3bb03202efc587d97e5aea7b80581b82242b969e6dea13b8daa32d24c0c1"}, {name: "native-single-anyonecanpay-0", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 0, expectedSignatureHash: "b2ccf259a65c3231d741a03420967b95563c3928cc15d3d15e8e795f383ab48b"}, {name: "native-single-anyonecanpay-2-no-corresponding-output", tx: nativeTx, hashType: singleAnyoneCanPay, inputIndex: 2, expectedSignatureHash: "652c8cd0ac050e41aad347ea09ee788360eec70908ba22fe5bba5bdde49b8ae1"}, // subnetwork transaction {name: "subnetwork-all-0", tx: subnetworkTx, hashType: all, inputIndex: 0, expectedSignatureHash: "2e828c04f5f03e4ce4b3de1fa5303400da5fa504291b760f5f6d4e98fc24597f"}, {name: "subnetwork-all-modify-payload", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifyPayload, // should change the hash expectedSignatureHash: "d5f3993aa8b7f47df52f78f2be9965f928c9cca9ac9e9542f1190b9d5ed6c17d"}, {name: "subnetwork-all-modify-gas", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifyGas, // should change the hash expectedSignatureHash: "e74d4a9fa5cdf476299ebdfa03f3c8021a157f814731ea11f6a6d606dc5cd439"}, {name: "subnetwork-all-subnetwork-id", tx: subnetworkTx, hashType: all, inputIndex: 0, modificationFunction: modifySubnetworkID, // should change the hash expectedSignatureHash: "ca8bf9bc42cda2ec3ce8bee090011072e56ff4d0d8616d5c20cefe5f84d7fb37"}, } for _, test := range tests { tx := test.tx if test.modificationFunction != nil { tx = test.modificationFunction(tx) } actualSignatureHash, err := consensushashing.CalculateSignatureHashECDSA( tx, test.inputIndex, test.hashType, &consensushashing.SighashReusedValues{}) if err != nil { t.Errorf("%s: Error from CalculateSignatureHashECDSA: %+v", test.name, err) continue } if actualSignatureHash.String() != test.expectedSignatureHash { t.Errorf("%s: expected signature hash: '%s'; but got: '%s'", test.name, test.expectedSignatureHash, actualSignatureHash) } } } func generateTxs() (nativeTx, subnetworkTx *externalapi.DomainTransaction, err error) { genesisCoinbase := dagconfig.SimnetParams.GenesisBlock.Transactions[0] genesisCoinbaseTransactionID := consensushashing.TransactionID(genesisCoinbase) address1Str := "kaspasim:qzpj2cfa9m40w9m2cmr8pvfuqpp32mzzwsuw6ukhfduqpp32mzzws59e8fapc" address1, err := util.DecodeAddress(address1Str, util.Bech32PrefixKaspaSim) if err != nil { return nil, nil, fmt.Errorf("error decoding address1: %+v", err) } address1ToScript, err := txscript.PayToAddrScript(address1) if err != nil { return nil, nil, fmt.Errorf("error generating script: %+v", err) } address2Str := "kaspasim:qr7w7nqsdnc3zddm6u8s9fex4ysk95hm3v30q353ymuqpp32mzzws59e8fapc" address2, err := util.DecodeAddress(address2Str, util.Bech32PrefixKaspaSim) if err != nil { return nil, nil, fmt.Errorf("error decoding address2: %+v", err) } address2ToScript, err := txscript.PayToAddrScript(address2) if err != nil { return nil, nil, fmt.Errorf("error generating script: %+v", err) } txIns := []*externalapi.DomainTransactionInput{ { PreviousOutpoint: *externalapi.NewDomainOutpoint(genesisCoinbaseTransactionID, 0), Sequence: 0, UTXOEntry: utxo.NewUTXOEntry(100, address1ToScript, false, 0), }, { PreviousOutpoint: *externalapi.NewDomainOutpoint(genesisCoinbaseTransactionID, 1), Sequence: 1, UTXOEntry: utxo.NewUTXOEntry(200, address2ToScript, false, 0), }, { PreviousOutpoint: *externalapi.NewDomainOutpoint(genesisCoinbaseTransactionID, 2), Sequence: 2, UTXOEntry: utxo.NewUTXOEntry(300, address2ToScript, false, 0), }, } txOuts := []*externalapi.DomainTransactionOutput{ { Value: 300, ScriptPublicKey: address2ToScript, }, { Value: 300, ScriptPublicKey: address1ToScript, }, } nativeTx = &externalapi.DomainTransaction{ Version: 0, Inputs: txIns, Outputs: txOuts, LockTime: 1615462089000, SubnetworkID: externalapi.DomainSubnetworkID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, } subnetworkTx = &externalapi.DomainTransaction{ Version: 0, Inputs: txIns, Outputs: txOuts, LockTime: 1615462089000, SubnetworkID: externalapi.DomainSubnetworkID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, Gas: 250, Payload: []byte{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, } return nativeTx, subnetworkTx, nil } func BenchmarkCalculateSignatureHashSchnorr(b *testing.B) { sigHashTypes := []consensushashing.SigHashType{ consensushashing.SigHashAll, consensushashing.SigHashNone, consensushashing.SigHashSingle, consensushashing.SigHashAll | consensushashing.SigHashAnyOneCanPay, consensushashing.SigHashNone | consensushashing.SigHashAnyOneCanPay, consensushashing.SigHashSingle | consensushashing.SigHashAnyOneCanPay} for _, size := range []int{10, 100, 1000} { tx := generateTransaction(b, sigHashTypes, size) b.Run(fmt.Sprintf("%d-inputs-and-outputs", size), func(b *testing.B) { for i := 0; i < b.N; i++ { reusedValues := &consensushashing.SighashReusedValues{} for inputIndex := range tx.Inputs { sigHashType := sigHashTypes[inputIndex%len(sigHashTypes)] _, err := consensushashing.CalculateSignatureHashSchnorr(tx, inputIndex, sigHashType, reusedValues) if err != nil { b.Fatalf("Error from CalculateSignatureHashSchnorr: %+v", err) } } } }) } } func generateTransaction(b *testing.B, sigHashTypes []consensushashing.SigHashType, inputAndOutputSizes int) *externalapi.DomainTransaction { sourceScript := getSourceScript(b) tx := &externalapi.DomainTransaction{ Version: 0, Inputs: generateInputs(inputAndOutputSizes, sourceScript), Outputs: generateOutputs(inputAndOutputSizes, sourceScript), LockTime: 123456789, SubnetworkID: externalapi.DomainSubnetworkID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, Gas: 125, Payload: []byte{9, 8, 7, 6, 5, 4, 3, 2, 1}, Fee: 0, Mass: 0, ID: nil, } signTx(b, tx, sigHashTypes) return tx } func signTx(b *testing.B, tx *externalapi.DomainTransaction, sigHashTypes []consensushashing.SigHashType) { sourceAddressPKStr := "a4d85b7532123e3dd34e58d7ce20895f7ca32349e29b01700bb5a3e72d2570eb" privateKeyBytes, err := hex.DecodeString(sourceAddressPKStr) if err != nil { b.Fatalf("Error parsing private key hex: %+v", err) } keyPair, err := secp256k1.DeserializeSchnorrPrivateKeyFromSlice(privateKeyBytes) if err != nil { b.Fatalf("Error deserializing private key: %+v", err) } for i, txIn := range tx.Inputs { signatureScript, err := txscript.SignatureScript( tx, i, sigHashTypes[i%len(sigHashTypes)], keyPair, &consensushashing.SighashReusedValues{}) if err != nil { b.Fatalf("Error from SignatureScript: %+v", err) } txIn.SignatureScript = signatureScript } } func generateInputs(size int, sourceScript *externalapi.ScriptPublicKey) []*externalapi.DomainTransactionInput { inputs := make([]*externalapi.DomainTransactionInput, size) for i := 0; i < size; i++ { inputs[i] = &externalapi.DomainTransactionInput{ PreviousOutpoint: *externalapi.NewDomainOutpoint( externalapi.NewDomainTransactionIDFromByteArray(&[32]byte{12, 3, 4, 5}), 1), SignatureScript: nil, Sequence: uint64(i), UTXOEntry: utxo.NewUTXOEntry(uint64(i), sourceScript, false, 12), } } return inputs } func getSourceScript(b *testing.B) *externalapi.ScriptPublicKey { sourceAddressStr := "kaspasim:qz6f9z6l3x4v3lf9mgf0t934th4nx5kgzu663x9yjh" sourceAddress, err := util.DecodeAddress(sourceAddressStr, util.Bech32PrefixKaspaSim) if err != nil { b.Fatalf("Error from DecodeAddress: %+v", err) } sourceScript, err := txscript.PayToAddrScript(sourceAddress) if err != nil { b.Fatalf("Error from PayToAddrScript: %+v", err) } return sourceScript } func generateOutputs(size int, script *externalapi.ScriptPublicKey) []*externalapi.DomainTransactionOutput { outputs := make([]*externalapi.DomainTransactionOutput, size) for i := 0; i < size; i++ { outputs[i] = &externalapi.DomainTransactionOutput{ Value: uint64(i), ScriptPublicKey: script, } } return outputs }