Bitcoin Stack Exchange is a question and answer site for Bitcoin crypto-currency enthusiasts. It only takes a minute to sign up.
Sign up to join this communityAnybody can ask a question
Anybody can answer
The best answers are voted up and rise to the top
I have a
bitcoinWalletAddress
in bitcoin testnet (starting with tb1)publicKey
already in hex formatprivateKey
in P2WPKH format looking likecTS...
By following this guide and this one I created the raw transaction by hand minus the scriptSig. And I'm a little bit stuck on that.
- IDK, how to correctly get the hash from private key using Swift.
- By reading different sources I don't have an understanding, how to create CORRECTLY the script for signature for P2WPKH particularly.
- Then, when i have p.1 and p.2 how can I sign the script with private key using Swift?
Please help finding the answer! I'm very new to bitcoin "insides")
P.s. what i have for now:
I've imported two packages:
https://github.com/0xDEADP00L/Bech32
https://github.com/keefertaylor/Base58Swift.git
I've wrote extensions:
@testable import Bech32 import CryptoKit import Base58Swift extension Array { func chunks(size: Int) -> [[Element]] { return stride(from: 0, to: count, by: size).map { Array(self[$0 ..< Swift.min($0 + size, count)]) } } } extension String { func chunks(size: Int) -> [String] { map { $0 }.chunks(size: size).compactMap { String($0) } } func leftPaddingZeros(toLength: Int) -> String { guard toLength > self.count else { return self } let padding = String(repeating: "0", count: toLength - self.count) return padding + self } func reversedByBytes() -> String { return self.chunks(size: 2) .reversed() .joined(separator: "") } /// A data representation of the hexadecimal bytes in this string. var hexDecodedData: Data { // Get the UTF8 characters of this string let chars = Array(utf8) // Keep the bytes in an UInt8 array and later convert it to Data var bytes = [UInt8]() bytes.reserveCapacity(count / 2) // It is a lot faster to use a lookup map instead of stratal let map: [UInt8] = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>? 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // HIJKLMNO ] // Grab two characters at a time, map them and turn it into a byte for i in stride(from: 0, to: count, by: 2) { let index1 = Int(chars[i] & 0x1F ^ 0x10) let index2 = Int(chars[i + 1] & 0x1F ^ 0x10) bytes.append(map[index1] << 4 | map[index2]) } return Data(bytes) } } extension Digest { var bytes: [UInt8] { Array(makeIterator()) } var data: Data { Data(bytes) } var hexStr: String { bytes.map { String(format: "%02x", $0) }.joined() } } extension Data { func hexEncodedString() -> String { return self.map { String(format: "%02x", $0) }.joined() } }
And wrote functions to build raw transaction minus ScriptSig
public static func getTransVersion() -> String { return getFourByteString(number: version) } public static func getTransInputs() -> String { return getHexString(number: inputsNumber) } public static func getTransHash() -> String { return prevTransHash.reversedByBytes() } public static func getPrevOutputIndexx() -> String { return getFourByteString(number: prevOutputIndex) } /// Constructing ScriptPubKey from initial key /// by next algo: /// OP_0 OP_PUSHBYTES_20 <key> (ASM) -> /// 0014<key> (HEX) /// - Returns: scriptPubKey of the output we want to redeem public static func getScriptPubKey(address: String) throws -> String { let addrHash = try getAddressHash(address: address) return "00" + getHexString(number: addrHash.count / 2) + addrHash } /// This is always set to 0xffffffff /// - Returns: four-byte field denoting the sequence public static func getSequence() -> String { return String(repeating: "f", count: 8) } /// Convert outputsNumber to hex string /// - Returns: one-byte varint containing the number of outputs in new transaction public static func getOutputsNumber() -> String { return getHexString(number: outputsNumber) } public static func getOutputAmount(satoshis: Int64) -> String { return getEightByteString(number: satoshis) } public static func getAddressHash(address: String) throws -> String { let (_, data) = try SegwitAddrCoder().decode(hrp: "tb", addr: address) return data.hexEncodedString() } public static func getLockTime() -> String { return String(repeating: "0", count: 8) } public static func getSigHash() -> String { return getFourByteString(number: sigHash) } public static func getHexString(number: Int) -> String { return NSString(format:"%02x", number) as String } public static func getFullTransaction() throws -> String { let transHash = try RawTransaction.getScriptPubKey(address: RawTransaction.output2Address) let transHash2 = try RawTransaction.getScriptPubKey(address: RawTransaction.output1Address) return RawTransaction.getTransVersion() + RawTransaction.getTransInputs() + RawTransaction.getTransHash() + RawTransaction.getPrevOutputIndexx() + RawTransaction.getHexString(number: transHash.count / 2) + transHash + RawTransaction.getSequence() + RawTransaction.getOutputsNumber() + RawTransaction.getOutputAmount(satoshis: RawTransaction.output2Amount) + RawTransaction.getHexString(number: transHash.count / 2) + transHash + RawTransaction.getOutputAmount(satoshis: RawTransaction.output1Amount) + RawTransaction.getHexString(number: transHash2.count / 2) + transHash2 + RawTransaction.getLockTime() + RawTransaction.getSigHash() } public static func getDoubleSha(initialString: String) { let digest = SHA256.hash(data: initialString.hexDecodedData) let digest2 = SHA256.hash(data: digest.data) print(digest2.hexStr.reversedByBytes()) print(digest2.hexStr + "\n") } public static func getPrivateKeyHex() -> String { let decode = Base58.base58CheckDecode(RawTransaction.privateKey)! let str = Data(decode).hexEncodedString() print(str) return str } private static func getHexString(number: Int64) -> String { return NSString(format:"%2x", number) as String } private static func getFourByteString(number: Int) -> String { return getHexString(number: number) .leftPaddingZeros(toLength: 8) .reversedByBytes() } private static func getEightByteString(number: Int64) -> String { return getHexString(number: number) .leftPaddingZeros(toLength: 16) .reversedByBytes() }
You can get bonuses upto $100 FREE BONUS when you:
π° Install these recommended apps:
π² SocialGood - 100% Crypto Back on Everyday Shopping
π² xPortal - The DeFi For The Next Billion
π² CryptoTab Browser - Lightweight, fast, and ready to mine!
π° Register on these recommended exchanges:
π‘ Binanceπ‘ Bitfinexπ‘ Bitmartπ‘ Bittrexπ‘ Bitget
π‘ CoinExπ‘ Crypto.comπ‘ Gate.ioπ‘ Huobiπ‘ Kucoin.
Comments