Migrate to ZIP 316 UFVKs

This also brings in various associated changes to the FFI methods in
zcash-light-client-kit as a result of moving to the main branch of
zcash/librustzcash.
This commit is contained in:
Jack Grigg 2022-06-28 22:40:52 +01:00 committed by Kris Nuttycombe
parent b0343d4c38
commit def779e5bc
21 changed files with 191 additions and 196 deletions

View File

@ -44,7 +44,11 @@ class MigrationManager {
}
func performMigration(ufvks: [UnifiedFullViewingKey]) throws {
try migrateDataDb(ufvks: ufvks)
// TODO: DataDB migrations will be handled by rustBackend.initDataDb
// once https://github.com/zcash/librustzcash/pull/600 merges, and in
// the interim the old migrations here will fail if we try to run them
// due to changes to table column names in zcash/librustzcash.
//try migrateDataDb(ufvks: ufvks)
try migrateCacheDb()
try migratePendingDb()
}
@ -115,7 +119,8 @@ class MigrationManager {
let derivationTool = DerivationTool(networkType: self.network)
for tuple in zip(accounts, viewingKeys) {
let tAddr = try derivationTool.deriveTransparentAddressFromPublicKey(tuple.1.extpub)
// TODO: Should the v1 migration be changed to "migrate from pre-v1 database to v2"?
let tAddr = try derivationTool.deriveTransparentAddressFromPublicKey(tuple.1.encoding)
var account = tuple.0
account.transparentAddress = tAddr
try accountsDao.update(account)

View File

@ -1287,7 +1287,7 @@ private struct UnifiedAddressShim {
}
extension UnifiedAddressShim: UnifiedAddress {
var tAddress: TransparentAddress {
var encoding: String {
account.transparentAddress
}
@ -1334,7 +1334,6 @@ extension CompactBlockProcessor {
do {
try self.rustBackend.putUnspentTransparentOutput(
dbData: dataDb,
address: utxo.address,
txid: utxo.txid.bytes,
index: utxo.index,
script: utxo.script.bytes,

View File

@ -84,7 +84,6 @@ class FetchUnspentTxOutputsOperation: ZcashOperation {
do {
try self.rustbackend.putUnspentTransparentOutput(
dbData: dataDb,
address: utxo.address,
txid: utxo.txid.bytes,
index: utxo.index,
script: utxo.script.bytes,

View File

@ -9,7 +9,7 @@ import Foundation
protocol AccountEntity {
var account: Int { get set }
var extfvk: String { get set }
var ufvk: String { get set }
var address: String { get set }
var transparentAddress: String { get set }
}
@ -17,14 +17,14 @@ protocol AccountEntity {
struct Account: AccountEntity, Encodable, Decodable {
enum CodingKeys: String, CodingKey {
case account
case extfvk
case ufvk
case address
case transparentAddress = "transparent_address"
}
var account: Int
var extfvk: String
var ufvk: String
var address: String
@ -32,22 +32,13 @@ struct Account: AccountEntity, Encodable, Decodable {
}
extension Account: UnifiedAddress {
var tAddress: TransparentAddress {
get {
transparentAddress
}
set {
transparentAddress = newValue
}
}
var zAddress: SaplingShieldedAddress {
var encoding: String {
get {
address
}
// swiftlint:disable unused_setter_value
set {
address = transparentAddress
address = encoding
}
}
}
@ -55,7 +46,7 @@ extension Account: UnifiedAddress {
extension Account: Hashable {
func hash(into hasher: inout Hasher) {
hasher.combine(account)
hasher.combine(extfvk)
hasher.combine(ufvk)
hasher.combine(address)
hasher.combine(transparentAddress)
}
@ -63,7 +54,7 @@ extension Account: Hashable {
static func == (lhs: Self, rhs: Self) -> Bool {
guard
lhs.account == rhs.account,
lhs.extfvk == rhs.extfvk,
lhs.ufvk == rhs.ufvk,
lhs.address == rhs.address,
lhs.transparentAddress == rhs.transparentAddress
else { return false }

View File

@ -8,6 +8,7 @@
import Foundation
public protocol UnspentTransactionOutputEntity {
// TODO: Remove address field?
var address: String { get set }
var txid: Data { get set }
var index: Int { get set }

View File

@ -234,6 +234,8 @@ public class Initializer {
}
} catch RustWeldingError.dataDbNotEmpty {
// this is fine
} catch RustWeldingError.malformedStringInput {
throw RustWeldingError.malformedStringInput
} catch {
throw rustBackend.lastError() ?? InitializerError.accountInitFailed
}

View File

@ -5,29 +5,19 @@
// Created by Francisco Gindre on 4/6/21.
//
/**
Groups a Sapling Extended Full Viewing Key an a tranparent address extended public key.
*/
public typealias ExtendedFullViewingKey = String
public typealias ExtendedPublicKey = String
/**
A ZIP 316 Unified Full Viewing Key.
TODO: Use the correct ZIP 316 format.
*/
public protocol UnifiedFullViewingKey {
var extfvk: ExtendedFullViewingKey { get set }
var extpub: ExtendedPublicKey { get set }
var account: UInt32 { get set }
var encoding: String { get set }
}
public typealias TransparentAddress = String
public typealias SaplingShieldedAddress = String
public protocol UnifiedAddress {
var tAddress: TransparentAddress { get }
var zAddress: SaplingShieldedAddress { get }
var encoding: String { get }
}
public struct WalletBalance: Equatable {

View File

@ -93,6 +93,21 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return true
}
static func isValidUnifiedFullViewingKey(_ key: String, networkType: NetworkType) throws -> Bool {
guard !key.containsCStringNullBytesBeforeStringEnding() else {
return false
}
guard zcashlc_is_valid_unified_full_viewing_key([CChar](key.utf8CString), networkType.networkId) else {
if let error = lastError() {
throw error
}
return false
}
return true
}
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32, networkType: NetworkType) -> [String]? {
let dbData = dbData.osStr()
@ -116,27 +131,20 @@ class ZcashRustBackend: ZcashRustBackendWelding {
var ffiUfvks: [FFIUnifiedViewingKey] = []
for ufvk in ufvks {
guard !ufvk.extfvk.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput
}
guard !ufvk.extpub.containsCStringNullBytesBeforeStringEnding() else {
guard !ufvk.encoding.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput
}
guard try self.isValidExtendedFullViewingKey(ufvk.extfvk, networkType: networkType) else {
guard try self.isValidUnifiedFullViewingKey(ufvk.encoding, networkType: networkType) else { // TODO Fix
throw RustWeldingError.malformedStringInput
}
let extfvkCStr = [CChar](String(ufvk.extfvk).utf8CString)
let ufvkCStr = [CChar](String(ufvk.encoding).utf8CString)
let extfvkPtr = UnsafeMutablePointer<CChar>.allocate(capacity: extfvkCStr.count)
extfvkPtr.initialize(from: extfvkCStr, count: extfvkCStr.count)
let ufvkPtr = UnsafeMutablePointer<CChar>.allocate(capacity: ufvkCStr.count)
ufvkPtr.initialize(from: ufvkCStr, count: ufvkCStr.count)
let extpubCStr = [CChar](String(ufvk.extpub).utf8CString)
let extpubPtr = UnsafeMutablePointer<CChar>.allocate(capacity: extpubCStr.count)
extpubPtr.initialize(from: extpubCStr, count: extpubCStr.count)
ffiUfvks.append(FFIUnifiedViewingKey(extfvk: extfvkPtr, extpub: extpubPtr))
ffiUfvks.append(FFIUnifiedViewingKey(account_id: ufvk.account, encoding: ufvkPtr))
}
var result = false
@ -151,8 +159,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
defer {
for ufvk in ffiUfvks {
ufvk.extfvk.deallocate()
ufvk.extpub.deallocate()
ufvk.encoding.deallocate()
}
}
@ -262,17 +269,12 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return result
}
static func putUnspentTransparentOutput(dbData: URL, address: String, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight, networkType: NetworkType) throws -> Bool {
static func putUnspentTransparentOutput(dbData: URL, txid: [UInt8], index: Int, script: [UInt8], value: Int64, height: BlockHeight, networkType: NetworkType) throws -> Bool {
let dbData = dbData.osStr()
guard !address.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput
}
guard zcashlc_put_utxo(
dbData.0,
dbData.1,
[CChar](address.utf8CString),
txid,
UInt(txid.count),
Int32(index),
@ -387,7 +389,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
dbCache: URL,
dbData: URL,
account: Int32,
tsk: String,
xprv: String,
extsk: String,
memo: String?,
spendParamsPath: String,
@ -401,7 +403,7 @@ class ZcashRustBackend: ZcashRustBackendWelding {
dbData.0,
dbData.1,
account,
[CChar](tsk.utf8CString),
[CChar](xprv.utf8CString),
[CChar](extsk.utf8CString),
[CChar](memoBytes.utf8CString),
spendParamsPath,
@ -490,11 +492,11 @@ class ZcashRustBackend: ZcashRustBackendWelding {
static func deriveUnifiedFullViewingKeyFromSeed(
_ seed: [UInt8],
numberOfAccounts: Int,
numberOfAccounts: Int32,
networkType: NetworkType
) throws -> [UnifiedFullViewingKey] {
guard
let ufvksStruct = zcashlc_derive_unified_viewing_keys_from_seed(
let ufvksStruct = zcashlc_derive_unified_full_viewing_keys_from_seed(
seed,
UInt(seed.count),
Int32(numberOfAccounts),
@ -518,15 +520,11 @@ class ZcashRustBackend: ZcashRustBackendWelding {
for item in 0 ..< Int(ufvksSize) {
let itemPointer = ufvksArrayPointer.advanced(by: item)
guard let extfvk = String(validatingUTF8: itemPointer.pointee.extfvk) else {
guard let encoding = String(validatingUTF8: itemPointer.pointee.encoding) else {
throw RustWeldingError.unableToDeriveKeys
}
guard let extpub = String(validatingUTF8: itemPointer.pointee.extpub) else {
throw RustWeldingError.unableToDeriveKeys
}
ufvks.append(UFVK(extfvk: extfvk, extpub: extpub))
ufvks.append(UFVK(account: UInt32(item), encoding: encoding))
}
zcashlc_free_uvk_array(ufvksStruct)
@ -534,13 +532,13 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return ufvks
}
static func deriveShieldedAddressFromSeed(
static func deriveUnifiedAddressFromSeed(
seed: [UInt8],
accountIndex: Int32,
networkType: NetworkType
) throws -> String? {
guard
let zaddrCStr = zcashlc_derive_shielded_address_from_seed(
let uaddrCStr = zcashlc_derive_unified_address_from_seed(
seed,
UInt(seed.count),
accountIndex,
@ -552,23 +550,23 @@ class ZcashRustBackend: ZcashRustBackendWelding {
}
return nil
}
let zAddr = String(validatingUTF8: zaddrCStr)
let uAddr = String(validatingUTF8: uaddrCStr)
zcashlc_string_free(zaddrCStr)
zcashlc_string_free(uaddrCStr)
return zAddr
return uAddr
}
static func deriveShieldedAddressFromViewingKey(
_ extfvk: String,
static func deriveUnifiedAddressFromViewingKey(
_ ufvk: String,
networkType: NetworkType
) throws -> String? {
guard !extfvk.containsCStringNullBytesBeforeStringEnding() else {
guard !ufvk.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput
}
guard
let zaddrCStr = zcashlc_derive_shielded_address_from_viewing_key(
[CChar](extfvk.utf8CString),
let zaddrCStr = zcashlc_derive_unified_address_from_viewing_key(
[CChar](ufvk.utf8CString),
networkType.networkId
)
else {
@ -577,11 +575,11 @@ class ZcashRustBackend: ZcashRustBackendWelding {
}
return nil
}
let zAddr = String(validatingUTF8: zaddrCStr)
let uAddr = String(validatingUTF8: zaddrCStr)
zcashlc_string_free(zaddrCStr)
return zAddr
return uAddr
}
static func deriveTransparentAddressFromSeed(
@ -610,18 +608,16 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return tAddr
}
static func deriveTransparentPrivateKeyFromSeed(
static func deriveTransparentAccountPrivateKeyFromSeed(
seed: [UInt8],
account: Int,
index: Int,
networkType: NetworkType
) throws -> String? {
guard
let skCStr = zcashlc_derive_transparent_private_key_from_seed(
let skCStr = zcashlc_derive_transparent_account_private_key_from_seed(
seed,
UInt(seed.count),
Int32(account),
Int32(index),
networkType.networkId
)
else {
@ -659,12 +655,20 @@ class ZcashRustBackend: ZcashRustBackendWelding {
return tAddr
}
static func deriveTransparentAddressFromSecretKey(_ tsk: String, networkType: NetworkType) throws -> String? {
static func deriveTransparentAddressFromAccountPrivateKey(
_ tsk: String,
index: Int,
networkType: NetworkType
) throws -> String? {
guard !tsk.containsCStringNullBytesBeforeStringEnding() else {
throw RustWeldingError.malformedStringInput
}
guard let tAddrCStr = zcashlc_derive_transparent_address_from_secret_key([CChar](tsk.utf8CString), networkType.networkId) else {
guard let tAddrCStr = zcashlc_derive_transparent_address_from_account_private_key(
[CChar](tsk.utf8CString),
Int32(index),
networkType.networkId
) else {
if let error = lastError() {
throw error
}
@ -688,8 +692,8 @@ class ZcashRustBackend: ZcashRustBackendWelding {
}
private struct UFVK: UnifiedFullViewingKey {
var extfvk: ExtendedFullViewingKey
var extpub: ExtendedPublicKey
var account: UInt32
var encoding: String
}
private extension ZcashRustBackend {

View File

@ -57,6 +57,12 @@ public protocol ZcashRustBackendWelding {
*/
static func isValidExtendedFullViewingKey(_ key: String, networkType: NetworkType) throws -> Bool
/**
- Returns: true when the address is valid and a UFVK. false in any other case
- Throws: Error when there's another problem not related to validity of the string in question
*/
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) throws -> Bool
/**
initialize the accounts table from a given seed and a number of accounts
- Parameters:
@ -67,7 +73,7 @@ public protocol ZcashRustBackendWelding {
static func initAccountsTable(dbData: URL, seed: [UInt8], accounts: Int32, networkType: NetworkType) -> [String]?
/**
initialize the accounts table from a set of unified viewing keys
initialize the accounts table from a set of unified full viewing keys
- Parameters:
- dbData: location of the data db
- ufvks: an array of UnifiedFullViewingKeys
@ -203,7 +209,6 @@ public protocol ZcashRustBackendWelding {
puts a UTXO into the data db database
- Parameters:
- dbData: location of the data db file
- address: the address of the UTXO
- txid: the txid bytes for the UTXO
- index: the index of the UTXO
- value: the value of the UTXO
@ -212,7 +217,6 @@ public protocol ZcashRustBackendWelding {
*/
static func putUnspentTransparentOutput(
dbData: URL,
address: String,
txid: [UInt8],
index: Int,
script: [UInt8],
@ -289,7 +293,7 @@ public protocol ZcashRustBackendWelding {
- dbCache: URL for the Cache DB
- dbData: URL for the Data DB
- account: the account index that will originate the transaction
- tsk: transparent Secret Key for the shielded funds.
- xprv: transparent account private key for the shielded funds.
- extsk: extended spending key string
- memo: the memo string for this transaction
- spendParamsPath: path escaped String for the filesystem locations where the spend parameters are located
@ -300,7 +304,7 @@ public protocol ZcashRustBackendWelding {
dbCache: URL,
dbData: URL,
account: Int32,
tsk: String,
xprv: String,
extsk: String,
memo: String?,
spendParamsPath: String,
@ -335,21 +339,21 @@ public protocol ZcashRustBackendWelding {
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32, networkType: NetworkType) throws -> [String]?
/**
Derives a shielded address from a seed
Derives a unified address from a seed
- Parameter seed: an array of bytes of the seed
- Parameter accountIndex: the index of the account you want the address for
- Returns: an optional String containing the Shielded address
- Throws: RustBackendError if fatal error occurs
*/
static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String?
static func deriveUnifiedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String?
/**
Derives a shielded address from an Extended Full Viewing Key
- Parameter extfvk: a string containing the extended full viewing key
Derives a unified address from a Unified Full Viewing Key
- Parameter ufvk: a string containing the extended full viewing key
- Returns: an optional String containing the Shielded address
- Throws: RustBackendError if fatal error occurs
*/
static func deriveShieldedAddressFromViewingKey(_ extfvk: String, networkType: NetworkType) throws -> String?
static func deriveUnifiedAddressFromViewingKey(_ ufvk: String, networkType: NetworkType) throws -> String?
/**
Derives a shielded address from an Extended Full Viewing Key
@ -360,18 +364,18 @@ public protocol ZcashRustBackendWelding {
static func deriveTransparentAddressFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String?
/**
Derives a transparent secret key from Seed
Derives a transparent account private key from Seed
- Parameter seed: an array of bytes containing the seed
- Returns: an optional String containing the transparent secret (private) key
*/
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String?
static func deriveTransparentAccountPrivateKeyFromSeed(seed: [UInt8], account: Int, networkType: NetworkType) throws -> String?
/**
Derives a transparent address from a secret key
- Parameter tsk: a hex string containing the Secret Key
- Returns: an optional String containing the transparent address.
*/
static func deriveTransparentAddressFromSecretKey(_ tsk: String, networkType: NetworkType) throws -> String?
static func deriveTransparentAddressFromAccountPrivateKey(_ tsk: String, index: Int, networkType: NetworkType) throws -> String?
/**
Derives a tranparent address from a public key
@ -379,7 +383,7 @@ public protocol ZcashRustBackendWelding {
*/
static func derivedTransparentAddressFromPublicKey(_ pubkey: String, networkType: NetworkType) throws -> String
static func deriveUnifiedFullViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int, networkType: NetworkType) throws -> [UnifiedFullViewingKey]
static func deriveUnifiedFullViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int32, networkType: NetworkType) throws -> [UnifiedFullViewingKey]
/**
Gets the consensus branch id for the given height

View File

@ -144,12 +144,12 @@ public protocol Synchronizer {
/// Sends zatoshi.
/// - Parameter spendingKey: the key that allows spends to occur.
/// - Parameter transparentSecretKey: the key that allows to spend transaprent funds
/// - Parameter transparentAccountPrivateKey: the key that allows to spend transparent funds
/// - Parameter memo: the optional memo to include as part of the transaction.
/// - Parameter accountIndex: the optional account id that will be used to shield your funds to. By default, the first account is used.
func shieldFunds(
spendingKey: String,
transparentSecretKey: String,
transparentAccountPrivateKey: String,
memo: String?,
from accountIndex: Int,
resultBlock: @escaping (_ result: Result<PendingTransactionEntity, Error>) -> Void

View File

@ -505,7 +505,7 @@ public class SDKSynchronizer: Synchronizer {
public func shieldFunds(
spendingKey: String,
transparentSecretKey: String,
transparentAccountPrivateKey: String,
memo: String?,
from accountIndex: Int,
resultBlock: @escaping (Result<PendingTransactionEntity, Error>) -> Void
@ -514,7 +514,7 @@ public class SDKSynchronizer: Synchronizer {
let derivationTool = DerivationTool(networkType: self.network.networkType)
do {
let tAddr = try derivationTool.deriveTransparentAddressFromPrivateKey(transparentSecretKey)
let tAddr = try derivationTool.deriveTransparentAddressFromAccountPrivateKey(transparentAccountPrivateKey, index: 0) // TODO: FIX
let tBalance = try utxoRepository.balance(address: tAddr, latestHeight: self.latestDownloadedHeight())
// Verify that at least there are funds for the fee. Ideally this logic will be improved by the shielding wallet.
@ -523,13 +523,13 @@ public class SDKSynchronizer: Synchronizer {
return
}
let viewingKey = try derivationTool.deriveViewingKey(spendingKey: spendingKey)
let zAddr = try derivationTool.deriveShieldedAddress(viewingKey: viewingKey)
let uAddr = try derivationTool.deriveUnifiedAddress(viewingKey: viewingKey)
let shieldingSpend = try transactionManager.initSpend(zatoshi: tBalance.verified, toAddress: zAddr, memo: memo, from: 0)
let shieldingSpend = try transactionManager.initSpend(zatoshi: tBalance.verified, toAddress: uAddr, memo: memo, from: 0)
transactionManager.encodeShieldingTransaction(
spendingKey: spendingKey,
tsk: transparentSecretKey,
xprv: transparentAccountPrivateKey,
pendingTransaction: shieldingSpend
) { [weak self] result in
guard let self = self else { return }

View File

@ -48,7 +48,7 @@ public protocol KeyDeriving {
func deriveSpendingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [String]
/**
Given a seed and account index, return the associated address.
Given a seed and account index, return the associated unified address.
- Parameter seed: the seed from which to derive the address.
- Parameter accountIndex: the index of the account to use for deriving the address. Multiple
@ -56,17 +56,17 @@ public protocol KeyDeriving {
- Returns: the address that corresponds to the seed and account index.
*/
func deriveShieldedAddress(seed: [UInt8], accountIndex: Int) throws -> String
func deriveUnifiedAddress(seed: [UInt8], accountIndex: Int) throws -> String
/**
Given a viewing key string, return the associated address.
Given a unified viewing key string, return the associated unified address.
- Parameter viewingKey: the viewing key to use for deriving the address. The viewing key is tied to
a specific account so no account index is required.
- Returns: the address that corresponds to the viewing key.
*/
func deriveShieldedAddress(viewingKey: String) throws -> String
func deriveUnifiedAddress(viewingKey: String) throws -> String
/**
Derives a transparent address from seedbytes, specifying account and index
@ -74,14 +74,14 @@ public protocol KeyDeriving {
func deriveTransparentAddress(seed: [UInt8], account: Int, index: Int) throws -> String
/**
Derives a SecretKey to spend transparent funds from a transparent secret key wif encoded
Derives the account private key to spend transparent funds from a specific seed and account
*/
func deriveTransparentPrivateKey(seed: [UInt8], account: Int, index: Int) throws -> String
func deriveTransparentAccountPrivateKey(seed: [UInt8], account: Int) throws -> String
/**
Derives a transparent address from the given transparent Secret Key
Derives a transparent address from the given transparent account private key
*/
func deriveTransparentAddressFromPrivateKey(_ tsk: String) throws -> String
func deriveTransparentAddressFromAccountPrivateKey(_ xprv: String, index: Int) throws -> String
func deriveTransparentAddressFromPublicKey(_ pubkey: String) throws -> String
@ -127,8 +127,11 @@ public class DerivationTool: KeyDeriving {
}
do {
guard let keys = try rustwelding.deriveExtendedFullViewingKeys(seed: seed, accounts: numberOfAccounts, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive
let ufvks = try rustwelding.deriveUnifiedFullViewingKeyFromSeed(seed, numberOfAccounts: numberOfAccounts, networkType: networkType)
var keys: [String] = []
for ufvk in ufvks {
keys.append(ufvk.encoding)
}
return keys
} catch {
@ -178,7 +181,7 @@ public class DerivationTool: KeyDeriving {
}
/**
Given a seed and account index, return the associated address.
Given a seed and account index, return the associated unified address.
- Parameter seed: the seed from which to derive the address.
- Parameter accountIndex: the index of the account to use for deriving the address. Multiple
@ -186,13 +189,13 @@ public class DerivationTool: KeyDeriving {
- Returns: the address that corresponds to the seed and account index.
*/
public func deriveShieldedAddress(seed: [UInt8], accountIndex: Int) throws -> String {
public func deriveUnifiedAddress(seed: [UInt8], accountIndex: Int) throws -> String {
guard accountIndex >= 0, let accountIndex = Int32(exactly: accountIndex) else {
throw KeyDerivationErrors.invalidInput
}
do {
guard let address = try rustwelding.deriveShieldedAddressFromSeed(seed: seed, accountIndex: accountIndex, networkType: networkType) else {
guard let address = try rustwelding.deriveUnifiedAddressFromSeed(seed: seed, accountIndex: accountIndex, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive
}
return address
@ -202,16 +205,16 @@ public class DerivationTool: KeyDeriving {
}
/**
Given a viewing key string, return the associated address.
Given a unified viewing key string, return the associated unified address.
- Parameter viewingKey: the viewing key to use for deriving the address. The viewing key is tied to
a specific account so no account index is required.
- Returns: the address that corresponds to the viewing key.
*/
public func deriveShieldedAddress(viewingKey: String) throws -> String {
public func deriveUnifiedAddress(viewingKey: String) throws -> String {
do {
guard let zaddr = try rustwelding.deriveShieldedAddressFromViewingKey(viewingKey, networkType: networkType) else {
guard let zaddr = try rustwelding.deriveUnifiedAddressFromViewingKey(viewingKey, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive
}
return zaddr
@ -237,7 +240,7 @@ public class DerivationTool: KeyDeriving {
}
public func deriveUnifiedFullViewingKeysFromSeed(_ seed: [UInt8], numberOfAccounts: Int) throws -> [UnifiedFullViewingKey] {
guard numberOfAccounts > 0 else {
guard numberOfAccounts > 0, let numberOfAccounts = Int32(exactly: numberOfAccounts) else {
throw KeyDerivationErrors.invalidInput
}
do {
@ -252,9 +255,8 @@ public class DerivationTool: KeyDeriving {
*/
public func deriveUnifiedAddressFromUnifiedFullViewingKey(_ ufvk: UnifiedFullViewingKey) throws -> UnifiedAddress {
do {
let tAddress = try deriveTransparentAddressFromPublicKey(ufvk.extpub)
let zAddress = try deriveShieldedAddress(viewingKey: ufvk.extfvk)
return ConcreteUnifiedAddress(tAddress: tAddress, zAddress: zAddress)
let encoding = try deriveUnifiedAddress(viewingKey: ufvk.encoding)
return ConcreteUnifiedAddress(encoding: encoding)
} catch {
throw KeyDerivationErrors.unableToDerive
}
@ -273,17 +275,16 @@ public class DerivationTool: KeyDeriving {
}
/**
Derives the transparent funds private key from the given seed
Derives the transparent funds account private key from the given seed
- Throws:
- KeyDerivationErrors.derivationError with the underlying error when it fails
- KeyDerivationErrors.unableToDerive when there's an unknown error
*/
public func deriveTransparentPrivateKey(seed: [UInt8], account: Int = 0, index: Int = 0) throws -> String {
public func deriveTransparentAccountPrivateKey(seed: [UInt8], account: Int = 0) throws -> String {
do {
guard let seedKey = try rustwelding.deriveTransparentPrivateKeyFromSeed(
guard let seedKey = try rustwelding.deriveTransparentAccountPrivateKeyFromSeed(
seed: seed,
account: account,
index: index,
networkType: networkType
) else {
throw KeyDerivationErrors.unableToDerive
@ -321,14 +322,14 @@ extension DerivationTool: KeyValidation {
}
/**
Derives the transparent address from a WIF Private Key
Derives the transparent address from an account private key
- Throws:
- KeyDerivationErrors.derivationError with the underlying error when it fails
- KeyDerivationErrors.unableToDerive when there's an unknown error
*/
public func deriveTransparentAddressFromPrivateKey(_ tsk: String) throws -> String {
public func deriveTransparentAddressFromAccountPrivateKey(_ xprv: String, index: Int) throws -> String {
do {
guard let tAddr = try rustwelding.deriveTransparentAddressFromSecretKey(tsk, networkType: networkType) else {
guard let tAddr = try rustwelding.deriveTransparentAddressFromAccountPrivateKey(xprv, index: index, networkType: networkType) else {
throw KeyDerivationErrors.unableToDerive
}
return tAddr
@ -339,6 +340,5 @@ extension DerivationTool: KeyValidation {
}
private struct ConcreteUnifiedAddress: UnifiedAddress {
var tAddress: TransparentAddress
var zAddress: SaplingShieldedAddress
var encoding: String
}

View File

@ -66,7 +66,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
func encodeShieldingTransaction(
spendingKey: String,
tsk: String,
xprv: String,
pendingTransaction: PendingTransactionEntity,
result: @escaping (Result<PendingTransactionEntity, Error>) -> Void
) {
@ -77,7 +77,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
guard
let viewingKey = try? derivationTool.deriveViewingKey(spendingKey: spendingKey),
let zAddr = try? derivationTool.deriveShieldedAddress(viewingKey: viewingKey)
let uAddr = try? derivationTool.deriveUnifiedAddress(viewingKey: viewingKey)
else {
result(
.failure(
@ -90,7 +90,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
return
}
guard pendingTransaction.toAddress == zAddr else {
guard pendingTransaction.toAddress == uAddr else {
result(
.failure(
TransactionManagerError.shieldingEncodingFailed(
@ -111,7 +111,7 @@ class PersistentTransactionManager: OutboundTransactionManager {
do {
let encodedTransaction = try self.encoder.createShieldingTransaction(
spendingKey: spendingKey,
tSecretKey: tsk,
tAccountPrivateKey: xprv,
memo: pendingTransaction.memo?.asZcashTransactionMemo(),
from: pendingTransaction.accountIndex
)

View File

@ -71,7 +71,7 @@ protocol TransactionEncoder {
- Parameters:
- Parameter spendingKey: a string containing the spending key
- Parameter tSecretKey: transparent secret key to spend the UTXOs
- Parameter tAccountPrivateKey: transparent account private key to spend the UTXOs
- Parameter memo: string containing the memo (optional)
- Parameter accountIndex: index of the account that will be used to send the funds
@ -79,7 +79,7 @@ protocol TransactionEncoder {
*/
func createShieldingTransaction(
spendingKey: String,
tSecretKey: String,
tAccountPrivateKey: String,
memo: String?,
from accountIndex: Int
) throws -> EncodedTransaction
@ -91,7 +91,7 @@ protocol TransactionEncoder {
- Parameters:
- Parameter spendingKey: a string containing the spending key
- Parameter tSecretKey: transparent secret key to spend the UTXOs
- Parameter tAccountPrivateKey: transparent account private key to spend the UTXOs
- Parameter memo: string containing the memo (optional)
- Parameter accountIndex: index of the account that will be used to send the funds
@ -100,7 +100,7 @@ protocol TransactionEncoder {
func createShieldingTransaction(
spendingKey: String,
tSecretKey: String,
tAccountPrivateKey: String,
memo: String?,
from accountIndex: Int,
result: @escaping TransactionEncoderResultBlock

View File

@ -16,7 +16,7 @@ transactions through to completion.
protocol OutboundTransactionManager {
func initSpend(zatoshi: Zatoshi, toAddress: String, memo: String?, from accountIndex: Int) throws -> PendingTransactionEntity
func encodeShieldingTransaction(spendingKey: String, tsk: String, pendingTransaction: PendingTransactionEntity, result: @escaping (Result<PendingTransactionEntity, Error>) -> Void)
func encodeShieldingTransaction(spendingKey: String, xprv: String, pendingTransaction: PendingTransactionEntity, result: @escaping (Result<PendingTransactionEntity, Error>) -> Void)
func encode(spendingKey: String, pendingTransaction: PendingTransactionEntity, result: @escaping (Result<PendingTransactionEntity, Error>) -> Void)

View File

@ -133,13 +133,13 @@ class WalletTransactionEncoder: TransactionEncoder {
func createShieldingTransaction(
spendingKey: String,
tSecretKey: String,
tAccountPrivateKey: String,
memo: String?,
from accountIndex: Int
) throws -> EncodedTransaction {
let txId = try createShieldingSpend(
spendingKey: spendingKey,
tsk: tSecretKey,
xprv: tAccountPrivateKey,
memo: memo,
accountIndex: accountIndex
)
@ -160,7 +160,7 @@ class WalletTransactionEncoder: TransactionEncoder {
func createShieldingTransaction(
spendingKey: String,
tSecretKey: String,
tAccountPrivateKey: String,
memo: String?,
from accountIndex: Int,
result: @escaping TransactionEncoderResultBlock
@ -170,7 +170,7 @@ class WalletTransactionEncoder: TransactionEncoder {
}
}
func createShieldingSpend(spendingKey: String, tsk: String, memo: String?, accountIndex: Int) throws -> Int {
func createShieldingSpend(spendingKey: String, xprv: String, memo: String?, accountIndex: Int) throws -> Int {
guard ensureParams(spend: self.spendParamsURL, output: self.spendParamsURL) else {
throw TransactionEncoderError.missingParams
}
@ -179,7 +179,7 @@ class WalletTransactionEncoder: TransactionEncoder {
dbCache: self.cacheDbURL,
dbData: self.dataDbURL,
account: Int32(accountIndex),
tsk: tsk,
xprv: xprv,
extsk: spendingKey,
memo: memo,
spendParamsPath: self.spendParamsURL.path,

View File

@ -195,13 +195,12 @@ class ShieldFundsTests: XCTestCase {
// 9. shield the funds
let shieldFundsExpectation = XCTestExpectation(description: "shield funds")
let transparentSecretKey = try DerivationTool(
let transparentAccountPrivateKey = try DerivationTool(
networkType: network.networkType
)
.deriveTransparentPrivateKey(
.deriveTransparentAccountPrivateKey(
seed: TestSeed().seed(),
account: 0,
index: 0
account: 0
)
shouldContinue = false
@ -211,7 +210,7 @@ class ShieldFundsTests: XCTestCase {
// shield the funds
coordinator.synchronizer.shieldFunds(
spendingKey: coordinator.spendingKey,
transparentSecretKey: transparentSecretKey,
transparentAccountPrivateKey: transparentAccountPrivateKey,
memo: "shield funds",
from: 0
) { result in

View File

@ -20,8 +20,8 @@ class BlockScanOperationTests: XCTestCase {
var dataDbURL: URL!
var ufvk = UFVFakeKey(
extfvk: "zxviewtestsapling1qw88ayg8qqqqpqyhg7jnh9mlldejfqwu46pm40ruwstd8znq3v3l4hjf33qcu2a5e36katshcfhcxhzgyfugj2lkhmt40j45cv38rv3frnghzkxcx73k7m7afw9j7ujk7nm4dx5mv02r26umxqgar7v3x390w2h3crqqgjsjly7jy4vtwzrmustm5yudpgcydw7x78awca8wqjvkqj8p8e3ykt7lrgd7xf92fsfqjs5vegfsja4ekzpfh5vtccgvs5747xqm6qflmtqpr8s9u", // swiftlint:disable:this line_length
extpub: "02075a7f5f7507d64022dad5954849f216b0f1b09b2d588be663d8e7faeb5aaf61"
account: 0,
encoding: "uviewtest1q48t999peecrfkq7ykcxckfkjt77w3lckk5mptlrtuy7xltjnzg8fm5434cxe9p9838ljs24yv83rluhk33ew098dkarapzyj4vk5kfxp5zn2jp3ww74jwd48r05aqjvgqxzx3nqn6zfqh3cmwdtmz0mc5624tvdza55q7mguxrehwcy4y0uktcpp4tkpex4qhazddux4yt6hr0sc9fkqmfr5tyz6ldd7yrq93tyj7446u4kst3vhmd40uga636p56hr0hjfdhgp07qyh90kmsl3qnmld6c8h7u06vekkjywmxv07mqzz9muwcl6weczrn5vf3p27uc9ufrumdp64zdzulzvc373wx3gl0yntntujhcsjhrwk9xwyjpvyuf0s8q3mgjs7uy3pg960w40dthpngcnauhgg9xq8cdcyfkq7ctnngqg4nkp5eh9knd4ckwjyd9czdd240lumul96r2fuerlvjeha6cyn9ftm7gr6xqjmq0zy6tv" // swiftlint:disable:this line_length
)
var walletBirthDay = Checkpoint.birthday(
@ -260,6 +260,6 @@ extension BlockScanOperationTests: CompactBlockProgressDelegate {
}
struct UFVFakeKey: UnifiedFullViewingKey {
var extfvk: ExtendedFullViewingKey
var extpub: ExtendedPublicKey
var account: UInt32
var encoding: String
}

View File

@ -12,11 +12,12 @@ import XCTest
class DerivatioToolTestnetTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
let testRecipientAddress = "ztestsapling1475xtm56czrzmleqzzlu4cxvjjfsy2p6rv78q07232cpsx5ee52k0mn5jyndq09mampkgvrxnwg" //TODO: Parameterize this from environment
let testRecipientAddress = "utest1uqmec4a2njqz2z2rwppchsd06qe7a0jh4jmsqr0yy99m9er9646zlxunf3v8qr0hncgv86e8a62vxy0qa32qzetmj8s57yudmyx9zav6f52nurclsqjkqtjtpz6vg679p6wkczpl2wu" //TODO: Parameterize this from environment
let expectedSpendingKey = "secret-extended-key-test1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6lk8xce3d4jw7s8ln5yjp6fqv2g0nzue2hc0kv5t004vklvlenncscq9flwh5vf5qnv0hnync72n7gjn70u47765v3kyrxytx50g730svvmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqe49swv"
let expectedViewingKey = "zxviewtestsapling1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6l5smlqrckkl2x5rnrauzc4gp665q3zyw0qf2sfdsx5wpp832htfavqk72uchuuvq2dpmgk8jfaza5t5l56u66fpx0sr8ewp9s3wj2txavmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqgegsaj"
let expectedViewingKey = "uviewtest16dqd5q7zd3xfxlcm2jm5k95zd92ed3qcm5jr9uq6yl5y2h6vuwfpxlnndckv5hpwsajgvq26xgdcdns8mqclecl0zh4sph45t4ncfnhcsus0k6sashfknsp9ltxrxlf096ljkwmp7psh3z2vmcd3rcc72qaujsl2y23ajexhr7qza29u9k95frs8qqgvy83rgymt7mmw09a02a5ytjpa502tshlsgl2j736jlfuzt27gezlajrs2tw9c99uqxrj5sx942vdr7w6yk2ltz96yq7n96fd9nr48c59dh9znqtwtm0nt9tmt7vzwhdwzt00tgp57mn85hpe6w00upmjv52kct9y"
let expectedSaplingExtendedViewingKey = "zxviewtestsapling1qdxykmuaqqqqpqqg3x5c02p4rhw0rtszr8ln4xl7g6wg6qzsqgn445qsu3cq4vd6l5smlqrckkl2x5rnrauzc4gp665q3zyw0qf2sfdsx5wpp832htfavqk72uchuuvq2dpmgk8jfaza5t5l56u66fpx0sr8ewp9s3wj2txavmhhlazn5rj8mshh470fkrmzg4xarhrqlygg8f486307ujhndwhsw2h7ddzf89k3534aeu0ypz2tjgrzlcqtat380vhe8awm03f58cqgegsaj"
let derivationTool = DerivationTool(networkType: NetworkType.testnet)
let expectedTransparentAddress = "tmXuTnE11JojToagTqxXUn6KvdxDE3iLKbp"
@ -36,7 +37,7 @@ class DerivatioToolTestnetTests: XCTestCase {
}
func testDeriveViewingKeyFromSpendingKeys() throws {
XCTAssertEqual(expectedViewingKey, try derivationTool.deriveViewingKey(spendingKey: expectedSpendingKey))
XCTAssertEqual(expectedSaplingExtendedViewingKey, try derivationTool.deriveViewingKey(spendingKey: expectedSpendingKey))
}
func testDeriveSpendingKeysFromSeed() throws {
@ -54,15 +55,15 @@ class DerivatioToolTestnetTests: XCTestCase {
}
func testDeriveShieldedAddressFromSeed() throws {
func testDeriveUnifiedAddressFromSeed() throws {
let seedBytes = [UInt8](seedData)
let shieldedAddress = try derivationTool.deriveShieldedAddress(seed: seedBytes, accountIndex: 0)
let shieldedAddress = try derivationTool.deriveUnifiedAddress(seed: seedBytes, accountIndex: 0)
XCTAssertEqual(shieldedAddress, testRecipientAddress)
}
func testDeriveShieldedAddressFromViewingKey() throws {
XCTAssertEqual(try derivationTool.deriveShieldedAddress(viewingKey: expectedViewingKey), testRecipientAddress)
func testDeriveUnifiedAddressFromViewingKey() throws {
XCTAssertEqual(try derivationTool.deriveUnifiedAddress(viewingKey: expectedViewingKey), testRecipientAddress)
}
func testDeriveTransparentAddressFromSeed() throws {
@ -70,30 +71,28 @@ class DerivatioToolTestnetTests: XCTestCase {
}
func testIsValidViewingKey() throws {
XCTAssertTrue(try derivationTool.isValidExtendedViewingKey(self.expectedViewingKey))
XCTAssertTrue(try derivationTool.isValidExtendedViewingKey(self.expectedSaplingExtendedViewingKey))
XCTAssertFalse(try derivationTool.isValidExtendedViewingKey("zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy"))
}
func testDeriveSecretKeyFromSeed() throws {
XCTAssertEqual(try derivationTool.deriveTransparentPrivateKey(seed: [UInt8](seedData)), "L2BCTxmSDiBRb33kGFd4pwGhp9r3FZqG3LZihgTkkg1J14vwtDbq")
func testDeriveTransparentAccountPrivateKeyFromSeed() throws {
XCTAssertEqual(try derivationTool.deriveTransparentAccountPrivateKey(seed: [UInt8](seedData)), "xprv9yURYog8Ds8XB36PVzPadbVaCPwVm4CZVMejW9bPPTqBCY8oLssPbe1MhJhPzSbVeg7cWZtuXxuUy2urADuAJUaN27c5f9nErx68SQokG1b")
}
func testDeriveUnifiedKeysFromSeed() throws {
let unifiedKeys = try derivationTool.deriveUnifiedFullViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 1)
XCTAssertEqual(unifiedKeys.count, 1)
XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey)
XCTAssertEqual(expectedTransparentAddress, try derivationTool.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub))
XCTAssertEqual(unifiedKeys[0].account, 0)
XCTAssertEqual(unifiedKeys[0].encoding, expectedViewingKey)
}
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
let unifiedKeys = try derivationTool.deriveUnifiedFullViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 10)
XCTAssertEqual(unifiedKeys.count, 10)
XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey)
XCTAssertEqual(expectedTransparentAddress, try derivationTool.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub))
XCTAssertEqual(unifiedKeys[0].account, 0)
XCTAssertEqual(unifiedKeys[0].encoding, expectedViewingKey)
}
}

View File

@ -11,11 +11,12 @@ import ZcashLightClientKit
class DerivationToolMainnetTests: XCTestCase {
var seedPhrase = "still champion voice habit trend flight survey between bitter process artefact blind carbon truly provide dizzy crush flush breeze blouse charge solid fish spread" //TODO: Parameterize this from environment?
var seedData: Data = Data(base64Encoded: "9VDVOZZZOWWHpZtq1Ebridp3Qeux5C+HwiRR0g7Oi7HgnMs8Gfln83+/Q1NnvClcaSwM4ADFL1uZHxypEWlWXg==")!
let testRecipientAddress = "zs1vp7kvlqr4n9gpehztr76lcn6skkss9p8keqs3nv8avkdtjrcctrvmk9a7u494kluv756jeee5k0" //TODO: Parameterize this from environment
let testRecipientAddress = "u1l9f0l4348negsncgr9pxd9d3qaxagmqv3lnexcplmufpq7muffvfaue6ksevfvd7wrz7xrvn95rc5zjtn7ugkmgh5rnxswmcj30y0pw52pn0zjvy38rn2esfgve64rj5pcmazxgpyuj" //TODO: Parameterize this from environment
let expectedSpendingKey = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv"
let expectedViewingKey = "zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy"
let expectedViewingKey = "uview1jpddskrm73gpgrsx00y4dryapkhjlzrm5wfdcue77a26u3e7u28qu0xfsgzwt72rs60rjnwujr93al6sxchste78p8vvrlperlvladfwkyryakdutykdcqgqn9dfn9my6k3aka5ej78leksj6aptqs9yzcysszwzwr6zmrcqycxxlg87ten6ers6urmxthe3pvvh07ga7t4uz92a5y0jgej94a7u9q3nezjqj4zm634x2wc2d8d39nu74jew79phf9u025p82d8qshq0pnzcjcnke0g72gva28qsx0wvtad7qjwld5khgudwlxmx24av2mq4k5k9zypheeppcpnujc9rqpm"
let expectedSaplingExtendedViewingKey = "zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy"
let derivationTool = DerivationTool(networkType: NetworkType.mainnet)
let expectedTransparentAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz"
@ -35,7 +36,7 @@ class DerivationToolMainnetTests: XCTestCase {
}
func testDeriveViewingKeyFromSpendingKeys() throws {
XCTAssertEqual(expectedViewingKey, try derivationTool.deriveViewingKey(spendingKey: expectedSpendingKey))
XCTAssertEqual(expectedSaplingExtendedViewingKey, try derivationTool.deriveViewingKey(spendingKey: expectedSpendingKey))
}
func testDeriveSpendingKeysFromSeed() throws {
@ -53,15 +54,15 @@ class DerivationToolMainnetTests: XCTestCase {
}
func testDeriveShieldedAddressFromSeed() throws {
func testDeriveUnifiedAddressFromSeed() throws {
let seedBytes = [UInt8](seedData)
let shieldedAddress = try derivationTool.deriveShieldedAddress(seed: seedBytes, accountIndex: 0)
let shieldedAddress = try derivationTool.deriveUnifiedAddress(seed: seedBytes, accountIndex: 0)
XCTAssertEqual(shieldedAddress, testRecipientAddress)
}
func testDeriveShieldedAddressFromViewingKey() throws {
XCTAssertEqual(try derivationTool.deriveShieldedAddress(viewingKey: expectedViewingKey), testRecipientAddress)
func testDeriveUnifiedAddressFromViewingKey() throws {
XCTAssertEqual(try derivationTool.deriveUnifiedAddress(viewingKey: expectedViewingKey), testRecipientAddress)
}
func testDeriveTransparentAddressFromSeed() throws {
@ -74,26 +75,24 @@ class DerivationToolMainnetTests: XCTestCase {
XCTAssertFalse(try derivationTool.isValidExtendedViewingKey("zxviews1q0dm7hkzky5skvnd9ldwj2u8fz2ry94s5q8p9lyp3j96yckudmp087d2jr2rnfuvjp7f56v78vpe658vljjddj7s645q399jd7"))
}
func testDeriveSecretKeyFromSeed() throws {
XCTAssertEqual(try derivationTool.deriveTransparentPrivateKey(seed: [UInt8](seedData)), "KwqfQoTCuQdCLvzpAEtkt1o8J62WJuZXD3cGRAf1bgmPWuLamHLo")
func testDeriveTransparentAccountPrivateKeyFromSeed() throws {
XCTAssertEqual(try derivationTool.deriveTransparentAccountPrivateKey(seed: [UInt8](seedData)), "xprv9yCTU6giJ1qZ1DLC5rc7KMzwY9s8rSRXYqmoAKffAExpUVUKLhcdvN9ERdxjEW8tQq4pxerLKZE3WcNUKZCeX19rVTxpV2msTyNMNiFT3Nw")
}
func testDeriveUnifiedKeysFromSeed() throws {
let unifiedKeys = try derivationTool.deriveUnifiedFullViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 1)
XCTAssertEqual(unifiedKeys.count, 1)
XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey)
XCTAssertEqual(expectedTransparentAddress, try derivationTool.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub))
XCTAssertEqual(unifiedKeys[0].account, 0)
XCTAssertEqual(unifiedKeys[0].encoding, expectedViewingKey)
}
func testDeriveQuiteALotOfUnifiedKeysFromSeed() throws {
let unifiedKeys = try derivationTool.deriveUnifiedFullViewingKeysFromSeed([UInt8](seedData), numberOfAccounts: 10)
XCTAssertEqual(unifiedKeys.count, 10)
XCTAssertEqual(unifiedKeys[0].extfvk, expectedViewingKey)
XCTAssertEqual(expectedTransparentAddress, try derivationTool.deriveTransparentAddressFromPublicKey(unifiedKeys[0].extpub))
XCTAssertEqual(unifiedKeys[0].account, 0)
XCTAssertEqual(unifiedKeys[0].encoding, expectedViewingKey)
}
func testShouldFailOnInvalidChecksumAddresses() throws {

View File

@ -103,7 +103,6 @@ class MockRustBackend: ZcashRustBackendWelding {
static func putUnspentTransparentOutput(
dbData: URL,
address: String,
txid: [UInt8],
index: Int,
script: [UInt8],
@ -136,7 +135,7 @@ class MockRustBackend: ZcashRustBackendWelding {
dbCache: URL,
dbData: URL,
account: Int32,
tsk: String,
xprv: String,
extsk: String,
memo: String?,
spendParamsPath: String,
@ -150,11 +149,11 @@ class MockRustBackend: ZcashRustBackendWelding {
throw KeyDerivationErrors.unableToDerive
}
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], account: Int, index: Int, networkType: NetworkType) throws -> String? {
static func deriveTransparentAccountPrivateKeyFromSeed(seed: [UInt8], account: Int, networkType: NetworkType) throws -> String? {
throw KeyDerivationErrors.unableToDerive
}
static func deriveTransparentAddressFromSecretKey(_ tsk: String, networkType: NetworkType) throws -> String? {
static func deriveTransparentAddressFromAccountPrivateKey(_ xprv: String, index: Int, networkType: NetworkType) throws -> String? {
throw KeyDerivationErrors.unableToDerive
}
@ -162,7 +161,7 @@ class MockRustBackend: ZcashRustBackendWelding {
throw KeyDerivationErrors.unableToDerive
}
static func deriveUnifiedFullViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int, networkType: NetworkType) throws -> [UnifiedFullViewingKey] {
static func deriveUnifiedFullViewingKeyFromSeed(_ seed: [UInt8], numberOfAccounts: Int32, networkType: NetworkType) throws -> [UnifiedFullViewingKey] {
throw KeyDerivationErrors.unableToDerive
}
@ -170,6 +169,10 @@ class MockRustBackend: ZcashRustBackendWelding {
false
}
static func isValidUnifiedFullViewingKey(_ ufvk: String, networkType: NetworkType) throws -> Bool {
false
}
static func deriveTransparentPrivateKeyFromSeed(seed: [UInt8], networkType: NetworkType) throws -> String? {
nil
}
@ -190,11 +193,11 @@ class MockRustBackend: ZcashRustBackendWelding {
nil
}
static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String? {
static func deriveUnifiedAddressFromSeed(seed: [UInt8], accountIndex: Int32, networkType: NetworkType) throws -> String? {
nil
}
static func deriveShieldedAddressFromViewingKey(_ extfvk: String, networkType: NetworkType) throws -> String? {
static func deriveUnifiedAddressFromViewingKey(_ ufvk: String, networkType: NetworkType) throws -> String? {
nil
}