<commit_before>//
//  BRCryptoKey.swift
//  BRCrypto
//
//  Created by <NAME> on 7/22/19.
//  Copyright © 2019 Breadwinner AG. All rights reserved.
//

import Foundation // Data
import BRCryptoC

public final class Key {
    static public var wordList: [String]?

    static public func createFrom (phrase: String, words: [String]? = wordList) -> Key? {
        guard var words = words?.map ({ UnsafePointer<Int8> (strdup($0)) }) else { return nil }
        defer { words.forEach { free(UnsafeMutablePointer (mutating: $0)) } }

        guard 1 == BRBIP39PhraseIsValid (&words, phrase) else { return nil }

        var seed = UInt512.self.init()

        BRBIP39DeriveKey (&seed, phrase, nil)
        defer { seed = UInt512() }

        var smallSeed = UInt256 (u64: (seed.u64.0, seed.u64.1, seed.u64.2, seed.u64.3))
        defer { smallSeed = UInt256() }

        return Key (secret: smallSeed)
    }

    static public func createFromSerialization (asPrivate data: Data) -> Key? {
        let str = String (data: data, encoding: .utf8)!

        return str.withCString { (strPtr: UnsafePointer<Int8>) -> Key? in
            guard 1 == BRPrivKeyIsValid (strPtr) else { return nil }

            var key = BRKey()
            defer { BRKeyClean (&key) }

            BRKeySetPrivKey (&key, strPtr)

            return Key (core: key, needPublicKey: true, compressedPublicKey: false)
        }
    }

    static public func createFromSerialization (asPublic data: Data) -> Key? {
        var data = data

        let dataCount = data.count
        return data.withUnsafeMutableBytes { (dataBytes: UnsafeMutableRawBufferPointer) -> Key? in
            let dataAddr = dataBytes.baseAddress?.assumingMemoryBound(to: UInt8.self)

            var key = BRKey()
            defer { BRKeyClean (&key) }


            return (1 == BRKeySetPubKey (&key, dataAddr, dataCount)
                ? Key (core: key, needPublicKey: false, compressedPublicKey: false)
                : nil)
        }
    }

    static public func createForPigeonFrom (key: Key, nonce: Data) -> Key {
        return nonce.withUnsafeBytes { (nonceBytes: UnsafeRawBufferPointer) -> Key in
            let nonceAddr  = nonceBytes.baseAddress?.assumingMemoryBound(to: UInt8.self)

            var pairingKey = BRKey()
            defer { BRKeyClean (&pairingKey) }

            var privateKey = key.core

            BRKeyPigeonPairingKey (&privateKey, &pairingKey, nonceAddr, nonce.count)

            return Key (core: pairingKey, needPublicKey: true, compressedPublicKey: false)
        }
    }

    static public func createForBIP32ApiAuth (phrase: String, words: [String]? = wordList) -> Key? {
        guard var words = words?.map ({ UnsafePointer<Int8> (strdup($0)) }) else { return nil }
        defer { words.forEach { free(UnsafeMutablePointer (mutating: $0)) } }

        guard 1 == BRBIP39PhraseIsValid (&words, phrase) else { return nil }

        var seed = UInt512.self.init()
        var key  = BRKey.self.init()

        BRBIP39DeriveKey (&seed, phrase, nil)
        defer { seed = UInt512() }

        BRBIP32APIAuthKey (&key, &seed, MemoryLayout<UInt512>.size)
        defer { BRKeyClean (&key) }

        //        BRBIP39DeriveKey(&seed, phrase, nil)
        //        BRBIP32APIAuthKey(&key, &seed, MemoryLayout<UInt512>.size)
        //        seed = UInt512() // clear seed
        //        let pkLen = BRKeyPrivKey(&key, nil, 0)
        //        var pkData = CFDataCreateMutable(secureAllocator, pkLen) as Data
        //        pkData.count = pkLen
        //        guard pkData.withUnsafeMutableBytes({ BRKeyPrivKey(&key, $0.baseAddress?.assumingMemoryBound(to: Int8.self), pkLen) }) == pkLen else { return nil }
        //        key.clean()

        return Key (core: key, needPublicKey: true, compressedPublicKey: false)
    }

    static public func createForBIP32BitID (phrase: String, index: Int, uri:String, words: [String]? = wordList) -> Key? {
        guard var words = words?.map ({ UnsafePointer<Int8> (strdup($0)) }) else { return nil }
        defer { words.forEach { free(UnsafeMutablePointer (mutating: $0)) } }

        guard 1 == BRBIP39PhraseIsValid (&words, phrase) else { return nil }

        var seed = UInt512.self.init()
        var key  = BRKey.self.init()

        BRBIP39DeriveKey (&seed, phrase, nil)
        defer { seed = UInt512() }

        BRBIP32BitIDKey (&key, &seed, MemoryLayout<UInt512>.size, UInt32(index), uri)
        defer { BRKeyClean (&key) }

        return Key (core: key, needPublicKey: true, compressedPublicKey: false)
    }

    // The Core representation
    var core: BRKey

    deinit { BRKeyClean (&core) }

    public var hasSecret: Bool {
        return !Key.secretMatch (core.secret, UInt256()) // non-all-zeros => has secret
    }

    // Serialization - Public Key

    public enum PublicEncoding {
        case derCompressed
        case derUncompressed
    }

    public func serialize (asPublic: PublicEncoding) -> Data {
        switch asPublic {
        case .derCompressed:
            return serializePublicKeyDER (key: self.core, compressed: true)

        case .derUncompressed:
            return serializePublicKeyDER (key: self.core, compressed: false)
        }
    }

    // Serialization - Private Key

    public enum PrivateEncoding {
        case wifCompressed
        case wifUncompressed
    }

    public func serialize (asPrivate: PrivateEncoding) -> Data? {
        guard hasSecret else { return nil }
        switch asPrivate {
        case .wifCompressed:
            return serializePrivateKeyWIF (key: core, compressed: true)

        case .wifUncompressed:
            return serializePrivateKeyWIF (key: core, compressed: false)
        }
    }

    ///
    /// Initialize based on a Core BRKey - the provided BRKey might be private+public or just
    /// a public key (such as one that is recovered from the signature.
    ///
    /// - Parameter core: The Core representaion
    ///
    internal init (core: BRKey, needPublicKey: Bool, compressedPublicKey: Bool) {
        self.core = core

        if needPublicKey {
            // Uncompressed; Ensure that the public key is provided
            BRKeySetCompressed (&self.core, (compressedPublicKey ? 1 : 0))
            BRKeyPubKey (&self.core, nil, 0)
        }
    }

    ///
    /// Initialize based on `secret` to produce a private+public key pair
    ///
    /// - Parameter secret: the secret
    ///
    internal convenience init (secret: UInt256) {
        var core = BRKey.init()
        defer { BRKeyClean (&core) }

        var secret = secret
        defer { secret = UInt256() }

        BRKeySetSecret (&core, &secret, 1)<commit_msg>CORE-439: Add key interfaces<commit_after>//
//  BRCryptoKey.swift
//  BRCrypto
//
//  Created by <NAME> on 7/22/19.
//  Copyright © 2019 Breadwinner AG. All rights reserved.
//

import Foundation // Data
import BRCryptoC

public final class Key {
    static public var wordList: [String]?

    static public func isWIFPrivateKey (key: Data) -> Bool {
        let keyStr = String (data: key, encoding: .utf8)!

        return keyStr.withCString { (keyPtr: UnsafePointer<Int8>) -> Bool in
            return 1 == BRPrivKeyIsValid (keyPtr)
        }
    }

    static public func isBIP38PrivateKey (key: Data) -> Bool {
        let keyStr = String (data: key, encoding: .utf8)!

        return keyStr.withCString { (keyPtr: UnsafePointer<Int8>) -> Bool in
            return 1 == BRBIP38KeyIsValid (keyPtr)
        }
    }

    static public func createFrom (phrase: String, words: [String]? = wordList) -> Key? {
        guard var words = words?.map ({ UnsafePointer<Int8> (strdup($0)) }) else { return nil }
        defer { words.forEach { free(UnsafeMutablePointer (mutating: $0)) } }

        guard 1 == BRBIP39PhraseIsValid (&words, phrase) else { return nil }

        var seed = UInt512.self.init()

        BRBIP39DeriveKey (&seed, phrase, nil)
        defer { seed = UInt512() }

        var smallSeed = UInt256 (u64: (seed.u64.0, seed.u64.1, seed.u64.2, seed.u64.3))
        defer { smallSeed = UInt256() }

        return Key (secret: smallSeed)
    }

    static public func createFromSerialization (asPrivate data: Data) -> Key? {
        let str = String (data: data, encoding: .utf8)!

        return str.withCString { (strPtr: UnsafePointer<Int8>) -> Key? in
            guard 1 == BRPrivKeyIsValid (strPtr) else { return nil }

            var key = BRKey()
            defer { BRKeyClean (&key) }

            BRKeySetPrivKey (&key, strPtr)

            return Key (core: key, needPublicKey: true, compressedPublicKey: false)
        }
    }

    static public func createFromSerialization (asPublic data: Data) -> Key? {
        var data = data

        let dataCount = data.count
        return data.withUnsafeMutableBytes { (dataBytes: UnsafeMutableRawBufferPointer) -> Key? in
            let dataAddr = dataBytes.baseAddress?.assumingMemoryBound(to: UInt8.self)

            var key = BRKey()
            defer { BRKeyClean (&key) }


            return (1 == BRKeySetPubKey (&key, dataAddr, dataCount)
                ? Key (core: key, needPublicKey: false, compressedPublicKey: false)
                : nil)
        }
    }

    static public func createFromBIP38Key(bip38Key: Data, passphrase: String) -> Key? {
        let bip38KeyStr = String (data: bip38Key, encoding: .utf8)!

        return passphrase.withCString { (passphrasePtr: UnsafePointer<Int8>) -> Key? in
            return bip38KeyStr.withCString { (bip38KeyPtr: UnsafePointer<Int8>) -> Key? in
                guard 1 == BRBIP38KeyIsValid (bip38KeyPtr) else { return nil }

                var key = BRKey()
                defer { BRKeyClean (&key) }

                BRKeySetBIP38Key (&key, bip38KeyPtr, passphrasePtr)

                return Key (core: key, needPublicKey: true, compressedPublicKey: false)
            }
        }
    }

    static public func createForPigeonFrom (key: Key, nonce: Data) -> Key {
        return nonce.withUnsafeBytes { (nonceBytes: UnsafeRawBufferPointer) -> Key in
            let nonceAddr  = nonceBytes.baseAddress?.assumingMemoryBound(to: UInt8.self)

            var pairingKey = BRKey()
            defer { BRKeyClean (&pairingKey) }

            var privateKey = key.core

            BRKeyPigeonPairingKey (&privateKey, &pairingKey, nonceAddr, nonce.count)

            return Key (core: pairingKey, needPublicKey: true, compressedPublicKey: false)
        }
    }

    static public func createForBIP32ApiAuth (phrase: String, words: [String]? = wordList) -> Key? {
        guard var words = words?.map ({ UnsafePointer<Int8> (strdup($0)) }) else { return nil }
        defer { words.forEach { free(UnsafeMutablePointer (mutating: $0)) } }

        guard 1 == BRBIP39PhraseIsValid (&words, phrase) else { return nil }

        var seed = UInt512.self.init()
        var key  = BRKey.self.init()

        BRBIP39DeriveKey (&seed, phrase, nil)
        defer { seed = UInt512() }

        BRBIP32APIAuthKey (&key, &seed, MemoryLayout<UInt512>.size)
        defer { BRKeyClean (&key) }

        //        BRBIP39DeriveKey(&seed, phrase, nil)
        //        BRBIP32APIAuthKey(&key, &seed, MemoryLayout<UInt512>.size)
        //        seed = UInt512() // clear seed
        //        let pkLen = BRKeyPrivKey(&key, nil, 0)
        //        var pkData = CFDataCreateMutable(secureAllocator, pkLen) as Data
        //        pkData.count = pkLen
        //        guard pkData.withUnsafeMutableBytes({ BRKeyPrivKey(&key, $0.baseAddress?.assumingMemoryBound(to: Int8.self), pkLen) }) == pkLen else { return nil }
        //        key.clean()

        return Key (core: key, needPublicKey: true, compressedPublicKey: false)
    }

    static public func createForBIP32BitID (phrase: String, index: Int, uri:String, words: [String]? = wordList) -> Key? {
        guard var words = words?.map ({ UnsafePointer<Int8> (strdup($0)) }) else { return nil }
        defer { words.forEach { free(UnsafeMutablePointer (mutating: $0)) } }

        guard 1 == BRBIP39PhraseIsValid (&words, phrase) else { return nil }

        var seed = UInt512.self.init()
        var key  = BRKey.self.init()

        BRBIP39DeriveKey (&seed, phrase, nil)
        defer { seed = UInt512() }

        BRBIP32BitIDKey (&key, &seed, MemoryLayout<UInt512>.size, UInt32(index), uri)
        defer { BRKeyClean (&key) }

        return Key (core: key, needPublicKey: true, compressedPublicKey: false)
    }

    // The Core representation
    var core: BRKey

    deinit { BRKeyClean (&core) }

    public var hasSecret: Bool {
        return !Key.secretMatch (core.secret, UInt256()) // non-all-zeros => has secret
    }

    // Serialization - Public Key

    public enum PublicEncoding {
        case derCompressed
        case derUncompressed
    }

    public func serialize (asPublic: PublicEncoding) -> Data {
        switch asPublic {
        case .derCompressed:
            return serializePublicKeyDER (key: self.core, compressed: true)

        case .derUncompressed:
            return serializePublicKeyDER (key: self.core, compressed: false)
        }
    }

    // Serialization - Private Key

    public enum PrivateEncoding {
        case wifCompressed
        case wifUncompressed
    }

    public func serialize (asPrivate: PrivateEncoding) -> Data? {
        guard hasSecret else { return nil }
        switch asPrivate {
        case .wifCompressed:
            return serializePrivateKeyWIF (key: core, compressed: true)

        case .wifUncompressed:
            return serializePrivateKeyWIF (key: core, compressed: false)
        }
    }

    public func address (legacy: Bool) -> String? {
        var addr = [CChar](repeating: 0, count: MemoryLayout<BRAddress>.size)
        if legacy {
            guard BRKeyLegacyAddr(&core, &addr, addr.count) > 0 else { return nil }
        } else {
            guard BRKeyAddress(&core, &addr, addr.count) > 0 else { return nil }
        }
        return String(cString: addr)
    }

    ///
    /// Initialize based on a Core BRKey - the provided BRKey might be private+public or just
    /// a public key (such as one that is recovered from the signature.
    ///
    /// - Parameter core: The Core representaion
    ///
    internal init (core: BRKey, needPublicKey: Bool, compressedPublicKey: Bool) {
        self.core = core

        if needPublicKey {
            // Uncompressed; Ensure that the public key is provided
            BRKeySetCompressed (&self.core, (compressedPublicKey ? 1 : 0))
            BRKeyPubKey (&self.core, nil, 0)
        }
    }

    ///
    /// Initialize based on `secret` to produce a private+public key pair
    ///
    /// - Parameter secret: the secret
    ///
    internal convenience init (secret: UInt256) {
        var core = BRKey.init()
        defer { BRKeyClean (&core) }

        var secret = secret
        defer { secret = UInt256() }

        BRKeySetSecret (&core, &secret, 1)
{'fraction_non_alphanumeric': 0.10815141197676748, 'fraction_numerical': 0.0185593163762601, 'mean_word_length': 2.26860135282566, 'pattern_counts': {'":': 0, '<': 24, '<?xml version=': 0, '>': 58, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1674585', 'n_tokens_mistral': 4734, 'n_tokens_neox': 4368, 'n_words': 1264}