Wednesday, November 30, 2022
HomeBitcoinCreate signature for uncooked bitcoin transaction by hand utilizing Swift

Create signature for uncooked bitcoin transaction by hand utilizing Swift


I’ve a

  • bitcoinWalletAddress in bitcoin testnet (beginning with tb1)
  • publicKey already in hex format
  • privateKey in P2WPKH format trying like cTS...

By following this information and this one I created the uncooked transaction by hand minus the scriptSig. And I am a bit bit caught on that.

  1. IDK, the way to appropriately get the hash from personal key utilizing Swift.
  2. By studying totally different sources I haven’t got an understanding, the way to create CORRECTLY the script for signature for P2WPKH notably.
  3. Then, when i’ve p.1 and p.2 how can I signal the script with personal key utilizing Swift?

Please assist discovering the reply! I am very new to bitcoin “insides”)

P.s. what i’ve 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(dimension: Int) -> [[Element]] {
        return stride(from: 0, to: depend, by: dimension).map {
            Array(self[$0 ..< Swift.min($0 + size, count)])
        }
    }
}

extension String {
    func chunks(dimension: Int) -> [String] {
        map { $0 }.chunks(dimension: dimension).compactMap { String($0) }
    }
    
    func leftPaddingZeros(toLength: Int) -> String {
        guard toLength > self.depend else { return self }
        
        let padding = String(repeating: "0", depend: toLength - self.depend)
        return padding + self
    }
    
    func reversedByBytes() -> String {
        return self.chunks(dimension: 2)
            .reversed()
            .joined(separator: "")
    }
    
    /// An information illustration of the hexadecimal bytes on this string.
    var hexDecodedData: Information {
        // Get the UTF8 characters of this string
        let chars = Array(utf8)
        // Maintain the bytes in an UInt8 array and later convert it to Information
        var bytes = [UInt8]()
        bytes.reserveCapacity(depend / 2)
        // It's a lot sooner to make use of a lookup map as a substitute 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
        ]
        // Seize two characters at a time, map them and switch it right into a byte
        for i in stride(from: 0, to: depend, by: 2)  map[index2])
        
        return Information(bytes)
    }
}

extension Digest {
    var bytes: [UInt8] { Array(makeIterator()) }
    var information: Information { Information(bytes) }

    var hexStr: String {
        bytes.map { String(format: "%02x", $0) }.joined()
    }
}

extension Information {
    func hexEncodedString() -> String {
        return self.map { String(format: "%02x", $0) }.joined()
    }
}

And wrote features to construct uncooked transaction minus ScriptSig

    public static func getTransVersion() -> String {
        return getFourByteString(quantity: model)
    }
    
    public static func getTransInputs() -> String {
        return getHexString(quantity: inputsNumber)
    }

    public static func getTransHash() -> String {
        return prevTransHash.reversedByBytes()
    }
    
    public static func getPrevOutputIndexx() -> String {
        return getFourByteString(quantity: prevOutputIndex)
    }
    
    /// Setting up ScriptPubKey from preliminary key
    /// by subsequent algo:
    /// OP_0 OP_PUSHBYTES_20 <key> (ASM) ->
    /// 0014<key> (HEX)
    /// - Returns: scriptPubKey of the output we wish to redeem
    public static func getScriptPubKey(handle: String) throws -> String {
        let addrHash = attempt getAddressHash(handle: handle)
        return "00" + getHexString(quantity: addrHash.depend / 2) + addrHash
        
    }
    
    /// That is at all times set to 0xffffffff
    /// - Returns: four-byte area denoting the sequence
    public static func getSequence() -> String {
        return String(repeating: "f", depend: 8)
    }
    
    /// Convert outputsNumber to hex string
    /// - Returns: one-byte varint containing the variety of outputs in new transaction
    public static func getOutputsNumber() -> String {
        return getHexString(quantity: outputsNumber)
    }
    
    public static func getOutputAmount(satoshis: Int64) -> String {
        return getEightByteString(quantity: satoshis)
    }
    
    public static func getAddressHash(handle: String) throws -> String {
        let (_, information) = attempt SegwitAddrCoder().decode(hrp: "tb", addr: handle)
        return information.hexEncodedString()
    }
    
    public static func getLockTime() -> String {
        return String(repeating: "0", depend: 8)
    }
    
    public static func getSigHash() -> String {
        return getFourByteString(quantity: sigHash)
    }

    public static func getHexString(quantity: Int) -> String {
        return NSString(format:"%02x", quantity) as String
    }
    
    public static func getFullTransaction() throws -> String {
        let transHash = attempt RawTransaction.getScriptPubKey(handle: RawTransaction.output2Address)
        let transHash2 = attempt RawTransaction.getScriptPubKey(handle: RawTransaction.output1Address)
        
        return RawTransaction.getTransVersion()
            + RawTransaction.getTransInputs()
            + RawTransaction.getTransHash()
            + RawTransaction.getPrevOutputIndexx()
            + RawTransaction.getHexString(quantity: transHash.depend / 2)
            + transHash
            + RawTransaction.getSequence()
            + RawTransaction.getOutputsNumber()
            + RawTransaction.getOutputAmount(satoshis: RawTransaction.output2Amount)
            + RawTransaction.getHexString(quantity: transHash.depend / 2)
            + transHash
            + RawTransaction.getOutputAmount(satoshis: RawTransaction.output1Amount)
            + RawTransaction.getHexString(quantity: transHash2.depend / 2)
            + transHash2
            + RawTransaction.getLockTime()
            + RawTransaction.getSigHash()
    }
    
    public static func getDoubleSha(initialString: String) {
        let digest = SHA256.hash(information: initialString.hexDecodedData)
        let digest2 = SHA256.hash(information: digest.information)
        print(digest2.hexStr.reversedByBytes())
        print(digest2.hexStr + "n")
    }
    
    public static func getPrivateKeyHex() -> String {
        let decode = Base58.base58CheckDecode(RawTransaction.privateKey)!
        let str = Information(decode).hexEncodedString()
        print(str)
        return str
    }
    
    personal static func getHexString(quantity: Int64) -> String {
        return NSString(format:"%2x", quantity) as String
    }
    
    personal static func getFourByteString(quantity: Int) -> String {
        return getHexString(quantity: quantity)
            .leftPaddingZeros(toLength: 8)
            .reversedByBytes()
    }
    
    personal static func getEightByteString(quantity: Int64) -> String {
        return getHexString(quantity: quantity)
            .leftPaddingZeros(toLength: 16)
            .reversedByBytes()
    }

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments