// signP2PKHTransaction signs a raw P2PKH transaction, given a private key and the scriptPubKey, inputTx and amount // to construct the final transaction. func signP2PKHTransaction(rawTransaction []byte, privateKey []byte, scriptPubKey []byte, inputTx string, amount int) ([]byte, error) { publicKey, err := btcutils.NewPublicKey(privateKey) if err != nil { return nil, err } signature, err := btcutils.NewSignature(rawTransaction, privateKey) if err != nil { return nil, err } hashCodeType, err := hex.DecodeString("01") if err != nil { return nil, err } //signatureLength is +1 to add hashCodeType signatureLength := byte(len(signature) + 1) //Create scriptSig var buffer bytes.Buffer buffer.WriteByte(signatureLength) buffer.Write(signature) buffer.WriteByte(hashCodeType[0]) buffer.WriteByte(byte(len(publicKey))) buffer.Write(publicKey) scriptSig := buffer.Bytes() //Finally create transaction with actual scriptSig signedRawTransaction, err := btcutils.NewRawTransaction(inputTx, amount, scriptSig, scriptPubKey) if err != nil { return nil, err } return signedRawTransaction, nil }
// signMultisigTransaction signs a raw P2PKH transaction, given slice of private keys and the scriptPubKey, inputTx, // redeemScript and amount to construct the final transaction. func signMultisigTransaction(rawTransaction []byte, orderedPrivateKeys [][]byte, scriptPubKey []byte, redeemScript []byte, inputTx string, amount int) ([]byte, error) { //Hash type SIGHASH_ALL hashCodeType, err := hex.DecodeString("01") if err != nil { return nil, err } //Generate signatures for each provided key signatures := make([][]byte, len(orderedPrivateKeys)) for i, privateKey := range orderedPrivateKeys { signatures[i], err = btcutils.NewSignature(rawTransaction, privateKey) if err != nil { return nil, err } } //redeemScript length. To allow redeemScript > 255 bytes, we use OP_PUSHDATA2 and use two bytes to specify length var redeemScriptLengthBytes []byte var requiredOP_PUSHDATA int if len(redeemScript) < 255 { requiredOP_PUSHDATA = btcutils.OP_PUSHDATA1 //OP_PUSHDATA1 specifies next *one byte* will be length to be pushed to stack redeemScriptLengthBytes = []byte{byte(len(redeemScript))} } else { requiredOP_PUSHDATA = btcutils.OP_PUSHDATA2 //OP_PUSHDATA2 specifies next *two bytes* will be length to be pushed to stack redeemScriptLengthBytes = make([]byte, 2) binary.LittleEndian.PutUint16(redeemScriptLengthBytes, uint16(len(redeemScript))) } //Create scriptSig var buffer bytes.Buffer buffer.WriteByte(byte(btcutils.OP_0)) //OP_0 for Multisig off-by-one error for _, signature := range signatures { buffer.WriteByte(byte(len(signature) + 1)) //PUSH each signature. Add one for hash type byte buffer.Write(signature) // Signature bytes buffer.WriteByte(hashCodeType[0]) //hash type } buffer.WriteByte(byte(requiredOP_PUSHDATA)) //OP_PUSHDATA1 or OP_PUSHDATA2 depending on size of redeemScript buffer.Write(redeemScriptLengthBytes) //PUSH redeemScript buffer.Write(redeemScript) //redeemScript scriptSig := buffer.Bytes() //Finally create transaction with actual scriptSig signedRawTransaction, err := btcutils.NewRawTransaction(inputTx, amount, scriptSig, scriptPubKey) if err != nil { return nil, err } return signedRawTransaction, nil }