我的实现在 M1 Max 上生成比特币地址非常慢

问题描述 投票:0回答:0

我有一个为 macOS 制作的简单 VanityGen Swift 代码。它只是简单地生成比特币地址,直到找到一个以指定(最多 5 个)字符开头的地址,例如 1Test...

问题是在 M1 Max 上这不会超过每秒 25,000 个地址(如果我使用多线程,则为 70,000 个)。

相比之下,著名的 VanityGen(使用 CPU,而不是 GPU)使用 Intel/AMD CPU 平均每秒生成超过 100 万!所以我必须在这里做错事。

这里只是负责生成地址的函数(完整代码如下):

private func generateRandomBitcoinAddress() -> (address: String, key: String)? {
    //  Private key
    guard let privateKey = try? secp256k1.Signing.PrivateKey(format: .compressed) else { return nil }

    //  Public key
    let publicKey = privateKey.publicKey.rawRepresentation

    // SHA256 of PublicKey
    let sha256 = SHA256.hash(data: publicKey)

    // RIPEMD-160 of sha256
    let ripemd160 = RIPEMD160.hash(Data(sha256))

    // Add version byte
    var versionByte = 0x00
    var addingVersionBytesToRipemd160 = Data(bytes: &versionByte, count: 1)
    addingVersionBytesToRipemd160.append(contentsOf: ripemd160)

    // SHA256 of RIPEMD-160 with added version byte
    let shaOfRipe = SHA256.hash(data: addingVersionBytesToRipemd160)

    // Repeat sha256
    let doubleSha = SHA256.hash(data: Data(shaOfRipe))
            
    // Take first 4 bytes as checksum
    let checksum = doubleSha.bytes.prefix(4)

    // Add checksum to RIPEMD-160 with added version byte
    addingVersionBytesToRipemd160.append(contentsOf: checksum)
    let binaryBitcoinAddressByte = addingVersionBytesToRipemd160.bytes
            
    // Base58Check encoding
    let bitcoinAddress = Base58.base58Encode(binaryBitcoinAddressByte)

    return (bitcoinAddress, String(bytes: privateKey.rawRepresentation.bytes))
}

这里是 complete 和工作代码(只需为 macOS 11+ 创建一个 SwiftUI 项目并将此代码与注释包一起添加到 ContentView.swift 就足够了):

import SwiftUI
import secp256k1 // https://github.com/GigaBitcoin/secp256k1.swift.git (just secp256k1, without zkp)
import Base58Swift // https://github.com/keefertaylor/Base58Swift.git
import ripemd160_Swift // https://github.com/MiclausCorp/ripemd160-Swift.git

struct ContentView: View {
    @StateObject private var addressGenerator = AddressGenerator()
    @State private var vanityChars = ""
    @State private var started = false

    var body: some View {
        VStack {
            if !started {
                TextField("Looking for Address that starts with Chars (max 5 char):", text: $vanityChars)
            
                Button("Start") {
                    addressGenerator.startVanityGen(lookingFor: vanityChars)
                    started = true
                }
            } else {
                Text("Looking for: \(vanityChars)...").padding(.bottom)
            
                Text("Addresses Per Second: \(addressGenerator.addressesPerSecond)")
                Text("Total: \(addressGenerator.totalAddressesGenerated)")
            
                if addressGenerator.found {
                    Button("Found") {
                        NSWorkspace.shared.selectFile(nil, inFileViewerRootedAtPath: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].path)
                    }
                }
            }
        }
        .padding()
    }
}

class AddressGenerator: ObservableObject {
    @Published private(set) var totalAddressesGenerated = 0
    @Published private(set) var addressesPerSecond = 0
    @Published private(set) var found = false

    private var currentSecond: Int {
        Calendar.current.component(.second, from: Date())
    }

    func startVanityGen(lookingFor: String) {
        DispatchQueue.global(qos: .utility).async { [weak self] in
            guard let self else { return }
    
            var counter = 0
            var second = self.currentSecond
            while self.found == false {
                self.generateBitcoinAddressAndCompare(to: lookingFor)
            
                counter += 1
                if second != self.currentSecond {
                    let totalGenerated = counter
                    DispatchQueue.main.async {
                        self.addressesPerSecond = totalGenerated
                        self.totalAddressesGenerated += totalGenerated
                    }
                    counter = 0
                    second = self.currentSecond
                }
            }
        }
    }

    func generateBitcoinAddressAndCompare(to vanity: String) {
        guard let generated = generateRandomBitcoinAddress() else { return }
    
        let bitcoinAddress = generated.address
        let privateKey = generated.key
    
        if bitcoinAddress.prefix(vanity.count) == vanity && found == false {
            DispatchQueue.main.async {
                self.found = true
                self.saveToFile(address: bitcoinAddress, privateKey: privateKey)
            }
        }
    }

    private func generateRandomBitcoinAddress() -> (address: String, key: String)? {
        //  Private key
        guard let privateKey = try? secp256k1.Signing.PrivateKey(format: .compressed) else { return nil }

        //  Public key
        let publicKey = privateKey.publicKey.rawRepresentation
    
        // SHA256 of PublicKey
        let sha256 = SHA256.hash(data: publicKey)
    
        // RIPEMD-160 of sha256
        let ripemd160 = RIPEMD160.hash(Data(sha256))
    
        // Add version byte
        var versionByte = 0x00
        var addingVersionBytesToRipemd160 = Data(bytes: &versionByte, count: 1)
        addingVersionBytesToRipemd160.append(contentsOf: ripemd160)
    
        // SHA256 of RIPEMD-160 with added version byte
        let shaOfRipe = SHA256.hash(data: addingVersionBytesToRipemd160)
    
        // Repeat sha256
        let doubleSha = SHA256.hash(data: Data(shaOfRipe))
                
        // Take first 4 bytes as checksum
        let checksum = doubleSha.bytes.prefix(4)
    
        // Add checksum to RIPEMD-160 with added version byte
        addingVersionBytesToRipemd160.append(contentsOf: checksum)
        let binaryBitcoinAddressByte = addingVersionBytesToRipemd160.bytes
                
        // Base58Check encoding
        let bitcoinAddress = Base58.base58Encode(binaryBitcoinAddressByte)
    
        return (bitcoinAddress, String(bytes: privateKey.rawRepresentation.bytes))
    }

    func saveToFile(address: String, privateKey: String) {
        let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("\(address).txt")
        let fileContent = "Address: \(address) - Private Key: \(privateKey)"
    
        try? fileContent.write(to: url, atomically: true, encoding: String.Encoding.utf8)
    }
}

请帮助我了解我做错了什么以及如何提高速度。

swift macos swiftui hash bitcoin
© www.soinside.com 2019 - 2024. All rights reserved.