Skip to content

Commit

Permalink
DerivationTool.deriveUnifiedAddressFrom(ufvk)
Browse files Browse the repository at this point in the history
- a new public API for DerivationTool to derive UA from the UFVK added
  • Loading branch information
LukasKorba committed Dec 10, 2024
1 parent 32bb9ba commit 08e5a73
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this library adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Added
- `DerivationTool.deriveArbitraryWalletKey`
- `DerivationTool.deriveArbitraryAccountKey`
- `DerivationTool.deriveUnifiedAddressFrom(ufvk)`
- `SDKSynchronizer.listAccounts` Returns a list of the accounts in the wallet.
- `SDKSynchronizer.importAccount` Imports a new account for unified full viewing key.

Expand Down
6 changes: 6 additions & 0 deletions Sources/ZcashLightClientKit/Error/ZcashError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,10 @@ public enum ZcashError: Equatable, Error {
/// - `rustError` contains error generated by the rust layer.
/// ZRUST0067
case rustImportAccountUfvk(_ rustError: String)
/// Error from rust layer when calling ZcashRustBackend.deriveAddressFromUfvk
/// - `rustError` contains error generated by the rust layer.
/// ZRUST0068
case rustDeriveAddressFromUfvk(_ rustError: String)
/// SQLite query failed when fetching all accounts from the database.
/// - `sqliteError` is error produced by SQLite library.
/// ZADAO0001
Expand Down Expand Up @@ -737,6 +741,7 @@ public enum ZcashError: Equatable, Error {
case .rustDeriveArbitraryWalletKey: return "Error from rust layer when calling ZcashRustBackend.deriveArbitraryWalletKey"
case .rustDeriveArbitraryAccountKey: return "Error from rust layer when calling ZcashRustBackend.deriveArbitraryAccountKey"
case .rustImportAccountUfvk: return "Error from rust layer when calling ZcashRustBackend.importAccountUfvk"
case .rustDeriveAddressFromUfvk: return "Error from rust layer when calling ZcashRustBackend.deriveAddressFromUfvk"
case .accountDAOGetAll: return "SQLite query failed when fetching all accounts from the database."
case .accountDAOGetAllCantDecode: return "Fetched accounts from SQLite but can't decode them."
case .accountDAOFindBy: return "SQLite query failed when seaching for accounts in the database."
Expand Down Expand Up @@ -923,6 +928,7 @@ public enum ZcashError: Equatable, Error {
case .rustDeriveArbitraryWalletKey: return .rustDeriveArbitraryWalletKey
case .rustDeriveArbitraryAccountKey: return .rustDeriveArbitraryAccountKey
case .rustImportAccountUfvk: return .rustImportAccountUfvk
case .rustDeriveAddressFromUfvk: return .rustDeriveAddressFromUfvk
case .accountDAOGetAll: return .accountDAOGetAll
case .accountDAOGetAllCantDecode: return .accountDAOGetAllCantDecode
case .accountDAOFindBy: return .accountDAOFindBy
Expand Down
2 changes: 2 additions & 0 deletions Sources/ZcashLightClientKit/Error/ZcashErrorCode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ public enum ZcashErrorCode: String {
case rustDeriveArbitraryAccountKey = "ZRUST0066"
/// Error from rust layer when calling ZcashRustBackend.importAccountUfvk
case rustImportAccountUfvk = "ZRUST0067"
/// Error from rust layer when calling ZcashRustBackend.deriveAddressFromUfvk
case rustDeriveAddressFromUfvk = "ZRUST0068"
/// SQLite query failed when fetching all accounts from the database.
case accountDAOGetAll = "ZADAO0001"
/// Fetched accounts from SQLite but can't decode them.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,10 @@ enum ZcashErrorDefinition {
/// - `rustError` contains error generated by the rust layer.
// sourcery: code="ZRUST0067"
case rustImportAccountUfvk(_ rustError: String)
/// Error from rust layer when calling ZcashRustBackend.deriveAddressFromUfvk
/// - `rustError` contains error generated by the rust layer.
// sourcery: code="ZRUST0068"
case rustDeriveAddressFromUfvk(_ rustError: String)

// MARK: - Account DAO

Expand Down
16 changes: 16 additions & 0 deletions Sources/ZcashLightClientKit/Rust/ZcashKeyDerivationBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,22 @@ struct ZcashKeyDerivationBackend: ZcashKeyDerivationBackendWelding {

// MARK: Address Derivation

func deriveUnifiedAddressFrom(ufvk: String) throws -> UnifiedAddress {
let ffiAddressPtr = zcashlc_derive_address_ufvk(
networkType.networkId,
[CChar](ufvk.utf8CString),
nil
)

guard let ffiAddressPtr else {
throw ZcashError.rustDeriveAddressFromUfvk(ZcashKeyDerivationBackend.lastErrorMessage(fallback: "`deriveAddressFromUfvk` failed with unknown error"))
}

defer { zcashlc_free_ffi_address(ffiAddressPtr) }

return ffiAddressPtr.pointee.unsafeToUnifiedAddress(networkType)
}

func deriveUnifiedSpendingKey(
from seed: [UInt8],
accountIndex: Zip32AccountIndex
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ protocol ZcashKeyDerivationBackendWelding {
/// - Returns: true when the encoded string is a valid UFVK. false in any other case
func isValidUnifiedFullViewingKey(_ ufvk: String) -> Bool

/// Derives and returns a UnifiedAddress from a UnifiedFullViewingKey
/// - Parameter ufvk: UTF-8 encoded String to validate
/// - Returns: true `UnifiedAddress`
func deriveUnifiedAddressFrom(ufvk: String) throws -> UnifiedAddress

/// Derives and returns a unified spending key from the given seed and ZIP 32 account index.
/// Returns the binary encoding of the spending key. The caller should manage the memory of (and store, if necessary) the returned spending key in a secure fashion.
/// - Parameter seed: a Byte Array with the seed
Expand Down
10 changes: 9 additions & 1 deletion Sources/ZcashLightClientKit/Rust/ZcashRustBackend.swift
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ struct ZcashRustBackend: ZcashRustBackendWelding {

let treeStateBytes = try treeState.serializedData(partial: false).bytes

var kSource: [CChar]? = nil
var kSource: [CChar]?

if let keySource {
kSource = [CChar](keySource.utf8CString)
Expand Down Expand Up @@ -1036,6 +1036,14 @@ extension String {
}
}

extension FfiAddress {
/// converts an [`FfiAddress`] into a [`UnifiedAddress`]
/// - Note: This does not check that the converted value actually holds a valid UnifiedAddress
func unsafeToUnifiedAddress(_ networkType: NetworkType) -> UnifiedAddress {
.init(validatedEncoding: String(cString: address), networkType: networkType)
}
}

extension FfiAccount {
var uuidArray: [UInt8] {
withUnsafeBytes(of: uuid_bytes) { buf in
Expand Down
9 changes: 9 additions & 0 deletions Sources/ZcashLightClientKit/Tool/DerivationTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public protocol KeyValidation {
}

public protocol KeyDeriving {
/// Derives and returns a UnifiedAddress from a UnifiedFullViewingKey
/// - Parameter ufvk: UTF-8 encoded String to validate
/// - Returns: true `UnifiedAddress`
func deriveUnifiedAddressFrom(ufvk: String) throws -> UnifiedAddress

/// Given the seed bytes and ZIP 32 account index, return the corresponding UnifiedSpendingKey.
/// - Parameter seed: `[Uint8]` seed bytes
/// - Parameter accountIndex: the ZIP 32 index of the account
Expand Down Expand Up @@ -92,6 +97,10 @@ public class DerivationTool: KeyDeriving {
ZcashKeyDerivationBackend.getAddressMetadata(addr)
}

public func deriveUnifiedAddressFrom(ufvk: String) throws -> UnifiedAddress {
try backend.deriveUnifiedAddressFrom(ufvk: ufvk)
}

/// Given a spending key, return the associated viewing key.
/// - Parameter spendingKey: the `UnifiedSpendingKey` from which to derive the `UnifiedFullViewingKey` from.
/// - Returns: the viewing key that corresponds to the spending key.
Expand Down

0 comments on commit 08e5a73

Please sign in to comment.