parent
f0ed01bb92
commit
328a18d898
|
@ -111,6 +111,12 @@ version = "0.2.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1"
|
||||
|
||||
[[package]]
|
||||
name = "base58"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.12.3"
|
||||
|
@ -295,9 +301,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.60"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"
|
||||
checksum = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
|
@ -571,6 +577,18 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hdwallet"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35b15cc3c181a2aace485d56c784568a4ae6e34322287a2499549d4cda7af3e1"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"rand",
|
||||
"ring",
|
||||
"secp256k1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
|
@ -601,6 +619,15 @@ version = "0.4.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jubjub"
|
||||
version = "0.5.1"
|
||||
|
@ -642,10 +669,16 @@ dependencies = [
|
|||
name = "libzcashlc"
|
||||
version = "0.0.5"
|
||||
dependencies = [
|
||||
"base58",
|
||||
"bs58",
|
||||
"cbindgen",
|
||||
"failure",
|
||||
"ffi_helpers",
|
||||
"hdwallet",
|
||||
"hex",
|
||||
"ripemd160",
|
||||
"secp256k1",
|
||||
"sha2 0.9.1",
|
||||
"zcash_client_backend",
|
||||
"zcash_client_sqlite",
|
||||
"zcash_primitives",
|
||||
|
@ -869,6 +902,32 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ba5a8ec64ee89a76c98c549af81ff14813df09c3e6dc4766c3856da48597a0c"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ripemd160"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eca4ecc81b7f313189bf73ce724400a07da2a6dac19588b03c8bd76a2dcc251"
|
||||
dependencies = [
|
||||
"block-buffer 0.9.0",
|
||||
"digest 0.9.0",
|
||||
"opaque-debug 0.3.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.24.1"
|
||||
|
@ -918,6 +977,24 @@ version = "1.0.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1"
|
||||
version = "0.17.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2932dc07acd2066ff2e3921a4419606b220ba6cd03a9935123856cc534877056"
|
||||
dependencies = [
|
||||
"secp256k1-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secp256k1-sys"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ab2c26f0d3552a0f12e639ae8a64afc2e3db9c52fe32f5fc6c289d38519f220"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
|
@ -1001,6 +1078,12 @@ version = "1.4.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "standback"
|
||||
version = "0.2.11"
|
||||
|
@ -1188,6 +1271,12 @@ version = "0.2.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.10"
|
||||
|
@ -1266,6 +1355,16 @@ version = "0.2.68"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307"
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
|
|
@ -15,6 +15,15 @@ zcash_client_backend = "0.4"
|
|||
zcash_client_sqlite = "0.2"
|
||||
zcash_primitives = "0.4"
|
||||
|
||||
#### Temporary additions: ####################################
|
||||
base58 = "0.1.0"
|
||||
sha2 = "0.9"
|
||||
bs58 = { version = "0.3", features = ["check"] }
|
||||
hdwallet = "0.2.2"
|
||||
ripemd160 = "0.9"
|
||||
secp256k1 = "0.17.2"
|
||||
##############################################################
|
||||
|
||||
[dependencies.zcash_proofs]
|
||||
version = "0.4"
|
||||
default-features = false
|
||||
|
|
|
@ -147,6 +147,6 @@ SPEC CHECKSUMS:
|
|||
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
|
||||
ZcashLightClientKit: aa2bfedb1cd48385d35113672b521a4bb47fbbf4
|
||||
|
||||
PODFILE CHECKSUM: 097fb38072a4f5011bd1e85186d6934583189378
|
||||
PODFILE CHECKSUM: 7d5095283dc02470f40ab06564d94076ba16d570
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
|
|
|
@ -208,9 +208,9 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
|||
return derived
|
||||
}
|
||||
|
||||
static func deriveExtendedFullViewingKeys(seed: String, accounts: Int32) throws -> [String]? {
|
||||
static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? {
|
||||
var capacity = UInt(0);
|
||||
guard let extsksCStr = zcashlc_derive_extended_full_viewing_keys(seed, UInt(seed.lengthOfBytes(using: .utf8)), accounts, &capacity) else {
|
||||
guard let extsksCStr = zcashlc_derive_extended_full_viewing_keys(seed, UInt(seed.count), accounts, &capacity) else {
|
||||
if let error = lastError() {
|
||||
throw error
|
||||
}
|
||||
|
@ -225,9 +225,9 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
|||
return extsks
|
||||
}
|
||||
|
||||
static func deriveExtendedSpendingKeys(seed: String, accounts: Int32) throws -> [String]? {
|
||||
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? {
|
||||
var capacity = UInt(0);
|
||||
guard let extsksCStr = zcashlc_derive_extended_spending_keys(seed, UInt(seed.lengthOfBytes(using: .utf8)), accounts, &capacity) else {
|
||||
guard let extsksCStr = zcashlc_derive_extended_spending_keys(seed, UInt(seed.count), accounts, &capacity) else {
|
||||
if let error = lastError() {
|
||||
throw error
|
||||
}
|
||||
|
@ -242,6 +242,52 @@ class ZcashRustBackend: ZcashRustBackendWelding {
|
|||
return extsks
|
||||
}
|
||||
|
||||
static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32) throws -> String? {
|
||||
guard let zaddrCStr = zcashlc_derive_shielded_address_from_seed(seed, UInt(seed.count), accountIndex) else {
|
||||
if let error = lastError() {
|
||||
throw error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
let zAddr = String(validatingUTF8: zaddrCStr)
|
||||
|
||||
zcashlc_string_free(zaddrCStr)
|
||||
|
||||
return zAddr
|
||||
}
|
||||
|
||||
static func deriveShieldedAddressFromViewingKey(_ extfvk: String) throws -> String? {
|
||||
guard !extfvk.containsCStringNullBytesBeforeStringEnding() else {
|
||||
throw RustWeldingError.malformedStringInput
|
||||
}
|
||||
|
||||
guard let zaddrCStr = zcashlc_derive_shielded_address_from_viewing_key([CChar](extfvk.utf8CString)) else {
|
||||
if let error = lastError() {
|
||||
throw error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
let zAddr = String(validatingUTF8: zaddrCStr)
|
||||
|
||||
zcashlc_string_free(zaddrCStr)
|
||||
|
||||
return zAddr
|
||||
}
|
||||
|
||||
static func deriveTransparentAddressFromSeed(seed: [UInt8]) throws -> String? {
|
||||
|
||||
guard let tAddrCStr = zcashlc_derive_transparent_address_from_seed(seed, UInt(seed.count)) else {
|
||||
if let error = lastError() {
|
||||
throw error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
let tAddr = String(validatingUTF8: tAddrCStr)
|
||||
|
||||
return tAddr
|
||||
}
|
||||
|
||||
static func consensusBranchIdFor(height: Int32) throws -> Int32 {
|
||||
let branchId = zcashlc_branch_id_for_height(height)
|
||||
|
||||
|
|
|
@ -190,7 +190,7 @@ public protocol ZcashRustBackendWelding {
|
|||
- Returns: an array containing the derived keys
|
||||
- Throws: RustBackendError if fatal error occurs
|
||||
*/
|
||||
static func deriveExtendedFullViewingKeys(seed: String, accounts: Int32) throws -> [String]?
|
||||
static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32) throws -> [String]?
|
||||
|
||||
/**
|
||||
Derives a set of full viewing keys from a seed
|
||||
|
@ -199,7 +199,32 @@ public protocol ZcashRustBackendWelding {
|
|||
- Returns: an array containing the spending keys
|
||||
- Throws: RustBackendError if fatal error occurs
|
||||
*/
|
||||
static func deriveExtendedSpendingKeys(seed: String, accounts: Int32) throws -> [String]?
|
||||
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32) throws -> [String]?
|
||||
|
||||
/**
|
||||
Derives a shielded 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) throws -> String?
|
||||
|
||||
/**
|
||||
Derives a shielded address from an Extended Full Viewing Key
|
||||
- Parameter extfvk: 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) throws -> String?
|
||||
|
||||
/**
|
||||
Derives a shielded address from an Extended Full Viewing Key
|
||||
- Parameter seed: an array of bytes of the seed
|
||||
- Returns: an optional String containing the transparent address
|
||||
- Throws: RustBackendError if fatal error occurs
|
||||
*/
|
||||
static func deriveTransparentAddressFromSeed(seed: [UInt8]) throws -> String?
|
||||
|
||||
/**
|
||||
Gets the consensus branch id for the given height
|
||||
|
|
|
@ -0,0 +1,207 @@
|
|||
//
|
||||
// DerivationTool.swift
|
||||
// Pods
|
||||
//
|
||||
// Created by Francisco Gindre on 10/8/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public protocol KeyDeriving {
|
||||
/**
|
||||
Given a seed and a number of accounts, return the associated viewing keys.
|
||||
|
||||
- Parameter seed: the seed from which to derive viewing keys.
|
||||
- Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the viewing keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
func deriveViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [String]
|
||||
/**
|
||||
Given a spending key, return the associated viewing key.
|
||||
|
||||
- Parameter spendingKey: the key from which to derive the viewing key.
|
||||
|
||||
- Returns: the viewing key that corresponds to the spending key.
|
||||
*/
|
||||
func deriveViewingKey(spendingKey: String) throws -> String
|
||||
/**
|
||||
Given a seed and a number of accounts, return the associated spending keys.
|
||||
|
||||
- Parameter seed: the seed from which to derive spending keys.
|
||||
- Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the spending keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
func deriveSpendingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [String]
|
||||
|
||||
/**
|
||||
Given a seed and account index, return the associated 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
|
||||
accounts are not fully supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the address that corresponds to the seed and account index.
|
||||
*/
|
||||
func deriveShieldedAddress(seed: [UInt8], accountIndex: Int) throws -> String
|
||||
|
||||
/**
|
||||
Given a viewing key string, return the associated 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
|
||||
// WIP probably shouldn't be used just yet. Why?
|
||||
// - because we need the private key associated with this seed and this function doesn't return it.
|
||||
// - the underlying implementation needs to be split out into a few lower-level calls
|
||||
func deriveTransparentAddress(seed: [UInt8]) throws -> String
|
||||
|
||||
func validateViewingKey(viewingKey: String) throws
|
||||
}
|
||||
|
||||
public enum KeyDerivationErrors: Error {
|
||||
case derivationError(underlyingError: Error)
|
||||
case unableToDerive
|
||||
case invalidInput
|
||||
}
|
||||
|
||||
public class DerivationTool: KeyDeriving {
|
||||
|
||||
var rustwelding: ZcashRustBackendWelding.Type = ZcashRustBackend.self
|
||||
|
||||
public static let `default` = DerivationTool()
|
||||
/**
|
||||
Given a seed and a number of accounts, return the associated viewing keys.
|
||||
|
||||
- Parameter seed: the seed from which to derive viewing keys.
|
||||
- Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the viewing keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
public func deriveViewingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [String] {
|
||||
guard numberOfAccounts > 0, let numberOfAccounts = Int32(exactly: numberOfAccounts) else {
|
||||
throw KeyDerivationErrors.invalidInput
|
||||
}
|
||||
|
||||
do {
|
||||
guard let keys = try rustwelding.deriveExtendedFullViewingKeys(seed: seed, accounts: numberOfAccounts) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return keys
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Given a spending key, return the associated viewing key.
|
||||
|
||||
- Parameter spendingKey: the key from which to derive the viewing key.
|
||||
|
||||
- Returns: the viewing key that corresponds to the spending key.
|
||||
*/
|
||||
public func deriveViewingKey(spendingKey: String) throws -> String {
|
||||
do {
|
||||
guard let key = try rustwelding.deriveExtendedFullViewingKey(spendingKey) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return key
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Given a seed and a number of accounts, return the associated spending keys.
|
||||
|
||||
- Parameter seed: the seed from which to derive spending keys.
|
||||
- Parameter numberOfAccounts: the number of accounts to use. Multiple accounts are not fully
|
||||
supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the spending keys that correspond to the seed, formatted as Strings.
|
||||
*/
|
||||
|
||||
public func deriveSpendingKeys(seed: [UInt8], numberOfAccounts: Int) throws -> [String] {
|
||||
guard numberOfAccounts > 0, let numberOfAccounts = Int32(exactly: numberOfAccounts) else {
|
||||
throw KeyDerivationErrors.invalidInput
|
||||
}
|
||||
do {
|
||||
guard let keys = try rustwelding.deriveExtendedSpendingKeys(seed: seed, accounts: numberOfAccounts) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return keys
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Given a seed and account index, return the associated 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
|
||||
accounts are not fully supported so the default value of 1 is recommended.
|
||||
|
||||
- Returns: the address that corresponds to the seed and account index.
|
||||
*/
|
||||
public func deriveShieldedAddress(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) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return address
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Given a viewing key string, return the associated 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 {
|
||||
do {
|
||||
guard let zaddr = try rustwelding.deriveShieldedAddressFromViewingKey(viewingKey) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return zaddr
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
// WIP probably shouldn't be used just yet. Why?
|
||||
// - because we need the private key associated with this seed and this function doesn't return it.
|
||||
// - the underlying implementation needs to be split out into a few lower-level calls
|
||||
public func deriveTransparentAddress(seed: [UInt8]) throws -> String {
|
||||
do {
|
||||
guard let zaddr = try rustwelding.deriveTransparentAddressFromSeed(seed: seed) else {
|
||||
throw KeyDerivationErrors.unableToDerive
|
||||
}
|
||||
return zaddr
|
||||
} catch {
|
||||
throw KeyDerivationErrors.derivationError(underlyingError: error)
|
||||
}
|
||||
}
|
||||
|
||||
public func validateViewingKey(viewingKey: String) throws {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
|
@ -50,6 +50,14 @@ char **zcashlc_derive_extended_spending_keys(const uint8_t *seed,
|
|||
int32_t accounts,
|
||||
uintptr_t *capacity_ret);
|
||||
|
||||
char *zcashlc_derive_shielded_address_from_seed(const uint8_t *seed,
|
||||
uintptr_t seed_len,
|
||||
int32_t account_index);
|
||||
|
||||
char *zcashlc_derive_shielded_address_from_viewing_key(const char *extfvk);
|
||||
|
||||
char *zcashlc_derive_transparent_address_from_seed(const uint8_t *seed, uintptr_t seed_len);
|
||||
|
||||
/**
|
||||
* Copies the last error message into the provided allocated buffer.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// DerivationToolTests.swift
|
||||
// ZcashLightClientKit-Unit-Tests
|
||||
//
|
||||
// Created by Francisco Gindre on 10/9/20.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import ZcashLightClientKit
|
||||
|
||||
class DerivationToolTests: 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 expectedSpendingKey = "secret-extended-key-main1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkyuegyhh5d4rdr8025nl7e0hm8r2txx3fuea5mquy3wnsr9tlajsg4wwvw0xcfk8357k4h850rgj72kt4rx3fjdz99zs9f4neda35cq8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszc7nc9vv"
|
||||
|
||||
let expectedViewingKey = "zxviews1qw28psv0qqqqpqr2ru0kss5equx6h0xjsuk5299xrsgdqnhe0cknkl8uqff34prwkysswfhjk79n8l99f2grd26dqg6dy3jcmxsaypxfsu6ara6vsk3x8l544uaksstx9zre879mdg7s9a7zurrx6pf5qg2n323js2s3zlu8tn3848yyvlg4w38gx75cyv9jdpve77x9eq6rtl6d9qyh8det4edevlnc70tg5kse670x50764gzhy60dta0yv3wsd4fsuaz686lgszcq7kwxy"
|
||||
|
||||
let expectedTransparentAddress = "t1dRJRY7GmyeykJnMH38mdQoaZtFhn1QmGz"
|
||||
func testDeriveViewingKeysFromSeed() throws {
|
||||
let accounts: Int = 1
|
||||
let seedBytes = [UInt8](seedData)
|
||||
let viewingKeys = try DerivationTool.default.deriveViewingKeys(seed: seedBytes, numberOfAccounts: accounts)
|
||||
|
||||
XCTAssertEqual(viewingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
|
||||
|
||||
guard let viewingKey = viewingKeys.first else {
|
||||
XCTFail("no viewing key generated")
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(expectedViewingKey, viewingKey)
|
||||
|
||||
}
|
||||
|
||||
func testDeriveViewingKeyFromSpendingKeys() throws {
|
||||
XCTAssertEqual(expectedViewingKey, try DerivationTool.default.deriveViewingKey(spendingKey: expectedSpendingKey))
|
||||
}
|
||||
|
||||
func testDeriveSpendingKeysFromSeed() throws {
|
||||
let accounts: Int = 1
|
||||
let seedBytes = [UInt8](seedData)
|
||||
|
||||
let spendingKeys = try DerivationTool.default.deriveSpendingKeys(seed: seedBytes, numberOfAccounts: accounts)
|
||||
XCTAssertEqual(spendingKeys.count, accounts, "the number of viewing keys have to match the number of account requested to derive")
|
||||
|
||||
guard let spendingKey = spendingKeys.first else {
|
||||
XCTFail("no viewing key generated")
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(expectedSpendingKey, spendingKey)
|
||||
|
||||
}
|
||||
|
||||
func testDeriveShieldedAddressFromSeed() throws {
|
||||
let seedBytes = [UInt8](seedData)
|
||||
|
||||
let shieldedAddress = try DerivationTool.default.deriveShieldedAddress(seed: seedBytes, accountIndex: 0)
|
||||
XCTAssertEqual(shieldedAddress, testRecipientAddress)
|
||||
}
|
||||
|
||||
func testDeriveShieldedAddressFromViewingKey() throws {
|
||||
XCTAssertEqual(try DerivationTool.default.deriveShieldedAddress(viewingKey: expectedViewingKey), testRecipientAddress)
|
||||
}
|
||||
|
||||
func testDeriveTransparentAddressFromSeed() throws {
|
||||
XCTAssertEqual(try DerivationTool.default.deriveTransparentAddress(seed: [UInt8](seedData)), expectedTransparentAddress)
|
||||
}
|
||||
|
||||
}
|
|
@ -38,7 +38,7 @@ class ZcashRustBackendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testDeriveExtendedSpendingKeys() {
|
||||
let seed = "testreferencealicetestreferencealice"
|
||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||
|
||||
var spendingKeys: [String]? = nil
|
||||
XCTAssertNoThrow(try { spendingKeys = try ZcashRustBackend.deriveExtendedSpendingKeys(seed: seed, accounts: 1) }())
|
||||
|
@ -49,7 +49,7 @@ class ZcashRustBackendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testDeriveExtendedFullViewingKeys() {
|
||||
let seed = "testreferencealicetestreferencealice"
|
||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||
|
||||
var fullViewingKeys: [String]? = nil
|
||||
XCTAssertNoThrow(try { fullViewingKeys = try ZcashRustBackend.deriveExtendedFullViewingKeys(seed: seed, accounts: 1) }())
|
||||
|
@ -59,7 +59,7 @@ class ZcashRustBackendTests: XCTestCase {
|
|||
}
|
||||
|
||||
func testDeriveExtendedFullViewingKey() {
|
||||
let seed = "testreferencealicetestreferencealice"
|
||||
let seed = Array("testreferencealicetestreferencealice".utf8)
|
||||
var fullViewingKey: String? = nil
|
||||
|
||||
|
||||
|
|
|
@ -77,6 +77,26 @@ extension LightWalletServiceMockResponse {
|
|||
}
|
||||
|
||||
class MockRustBackend: ZcashRustBackendWelding {
|
||||
static func deriveTransparentAddressFromSeed(seed: [UInt8]) throws -> String? {
|
||||
nil
|
||||
}
|
||||
|
||||
static func deriveExtendedFullViewingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? {
|
||||
nil
|
||||
}
|
||||
|
||||
static func deriveExtendedSpendingKeys(seed: [UInt8], accounts: Int32) throws -> [String]? {
|
||||
nil
|
||||
}
|
||||
|
||||
static func deriveShieldedAddressFromSeed(seed: [UInt8], accountIndex: Int32) throws -> String? {
|
||||
nil
|
||||
}
|
||||
|
||||
static func deriveShieldedAddressFromViewingKey(_ extfvk: String) throws -> String? {
|
||||
nil
|
||||
}
|
||||
|
||||
|
||||
static func consensusBranchIdFor(height: Int32) throws -> Int32 {
|
||||
-1
|
||||
|
|
141
rust/src/lib.rs
141
rust/src/lib.rs
|
@ -8,8 +8,8 @@ use std::slice;
|
|||
use std::str::FromStr;
|
||||
use zcash_client_backend::{
|
||||
encoding::{
|
||||
decode_extended_spending_key, encode_extended_full_viewing_key,
|
||||
encode_extended_spending_key,
|
||||
decode_extended_full_viewing_key, decode_extended_spending_key,
|
||||
encode_extended_full_viewing_key, encode_extended_spending_key, encode_payment_address,
|
||||
},
|
||||
keys::spending_key,
|
||||
};
|
||||
|
@ -43,14 +43,29 @@ use zcash_proofs::prover::LocalTxProver;
|
|||
#[cfg(feature = "mainnet")]
|
||||
use zcash_client_backend::constants::mainnet::{
|
||||
COIN_TYPE, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_EXTENDED_SPENDING_KEY,
|
||||
HRP_SAPLING_PAYMENT_ADDRESS,
|
||||
};
|
||||
#[cfg(not(feature = "mainnet"))]
|
||||
use zcash_client_backend::constants::testnet::{
|
||||
COIN_TYPE, HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, HRP_SAPLING_EXTENDED_SPENDING_KEY,
|
||||
HRP_SAPLING_PAYMENT_ADDRESS,
|
||||
};
|
||||
|
||||
use std::convert::TryFrom;
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Temporary Imports
|
||||
use base58::ToBase58;
|
||||
use sha2::{Digest, Sha256};
|
||||
// use zcash_primitives::legacy::TransparentAddress;
|
||||
use hdwallet::{ExtendedPrivKey, KeyIndex};
|
||||
use secp256k1::{PublicKey, Secp256k1};
|
||||
use zcash_client_backend::constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX;
|
||||
|
||||
// use crate::extended_key::{key_index::KeyIndex, ExtendedPrivKey, ExtendedPubKey, KeySeed};
|
||||
// /////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
fn unwrap_exc_or<T>(exc: Result<T, ()>, def: T) -> T {
|
||||
match exc {
|
||||
Ok(value) => value,
|
||||
|
@ -294,6 +309,58 @@ pub unsafe extern "C" fn zcashlc_derive_extended_full_viewing_key(
|
|||
unwrap_exc_or_null(res)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_seed(
|
||||
seed: *const u8,
|
||||
seed_len: usize,
|
||||
account_index: i32,
|
||||
) -> *mut c_char {
|
||||
let res = catch_panic(|| {
|
||||
let seed = slice::from_raw_parts(seed, seed_len);
|
||||
let account_index = if account_index >= 0 {
|
||||
account_index as u32
|
||||
} else {
|
||||
return Err(format_err!("accounts argument must be greater than zero"));
|
||||
};
|
||||
let address = spending_key(&seed, COIN_TYPE, account_index)
|
||||
.default_address()
|
||||
.unwrap()
|
||||
.1;
|
||||
let address_str = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &address);
|
||||
Ok(CString::new(address_str).unwrap().into_raw())
|
||||
});
|
||||
unwrap_exc_or_null(res)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn zcashlc_derive_shielded_address_from_viewing_key(
|
||||
extfvk: *const c_char,
|
||||
) -> *mut c_char {
|
||||
|
||||
let res = catch_panic(|| {
|
||||
let extfvk_string = CStr::from_ptr(extfvk).to_str()?;
|
||||
let extfvk = match decode_extended_full_viewing_key(
|
||||
HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
|
||||
&extfvk_string,
|
||||
) {
|
||||
Ok(Some(extfvk)) => extfvk,
|
||||
Ok(None) => {
|
||||
return Err(format_err!("Failed to parse viewing key string in order to derive the address. Deriving a viewing key from the string returned no results. Encoding was valid but type was incorrect."));
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(format_err!(
|
||||
"Error while deriving viewing key from string input: {}",
|
||||
e
|
||||
));
|
||||
}
|
||||
};
|
||||
let address = extfvk.default_address().unwrap().1;
|
||||
let address_str = encode_payment_address(HRP_SAPLING_PAYMENT_ADDRESS, &address);
|
||||
Ok(CString::new(address_str).unwrap().into_raw())
|
||||
});
|
||||
unwrap_exc_or_null(res)
|
||||
}
|
||||
|
||||
/// Returns the address for the account.
|
||||
///
|
||||
/// Call `zcashlc_string_free` on the returned pointer when you are finished with it.
|
||||
|
@ -715,3 +782,73 @@ pub extern "C" fn zcashlc_vec_string_free(v: *mut *mut c_char, len: usize, capac
|
|||
v.into_iter().map(|s| CString::from_raw(s)).for_each(drop);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//// TEST TEST 123 TEST
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn zcashlc_derive_transparent_address_from_seed(
|
||||
seed: *const u8,
|
||||
seed_len: usize,
|
||||
) -> *mut c_char {
|
||||
|
||||
let res = catch_panic(|| {
|
||||
let seed = slice::from_raw_parts(seed, seed_len);
|
||||
|
||||
// modified from: https://github.com/adityapk00/zecwallet-light-cli/blob/master/lib/src/lightwallet.rs
|
||||
|
||||
let ext_t_key = ExtendedPrivKey::with_seed(&seed).unwrap();
|
||||
let address_sk = ext_t_key
|
||||
.derive_private_key(KeyIndex::hardened_from_normalize_index(44).unwrap())
|
||||
.unwrap()
|
||||
.derive_private_key(KeyIndex::hardened_from_normalize_index(COIN_TYPE).unwrap())
|
||||
.unwrap()
|
||||
.derive_private_key(KeyIndex::hardened_from_normalize_index(0).unwrap())
|
||||
.unwrap()
|
||||
.derive_private_key(KeyIndex::Normal(0))
|
||||
.unwrap()
|
||||
.derive_private_key(KeyIndex::Normal(0))
|
||||
.unwrap()
|
||||
.private_key;
|
||||
let secp = Secp256k1::new();
|
||||
let pk = PublicKey::from_secret_key(&secp, &address_sk);
|
||||
let mut hash160 = ripemd160::Ripemd160::new();
|
||||
hash160.update(Sha256::digest(&pk.serialize()[..].to_vec()));
|
||||
let address_string = hash160
|
||||
.finalize()
|
||||
.to_base58check(&B58_PUBKEY_ADDRESS_PREFIX, &[]);
|
||||
|
||||
Ok(CString::new(address_string).unwrap().into_raw())
|
||||
});
|
||||
unwrap_exc_or_null(res)
|
||||
}
|
||||
|
||||
//
|
||||
// Helper code from: https://github.com/adityapk00/zecwallet-light-cli/blob/master/lib/src/lightwallet.rs
|
||||
//
|
||||
|
||||
/// A trait for converting a [u8] to base58 encoded string.
|
||||
pub trait ToBase58Check {
|
||||
/// Converts a value of `self` to a base58 value, returning the owned string.
|
||||
/// The version is a coin-specific prefix that is added.
|
||||
/// The suffix is any bytes that we want to add at the end (like the "iscompressed" flag for
|
||||
/// Secret key encoding)
|
||||
fn to_base58check(&self, version: &[u8], suffix: &[u8]) -> String;
|
||||
}
|
||||
impl ToBase58Check for [u8] {
|
||||
fn to_base58check(&self, version: &[u8], suffix: &[u8]) -> String {
|
||||
let mut payload: Vec<u8> = Vec::new();
|
||||
payload.extend_from_slice(version);
|
||||
payload.extend_from_slice(self);
|
||||
payload.extend_from_slice(suffix);
|
||||
|
||||
let checksum = double_sha256(&payload);
|
||||
payload.append(&mut checksum[..4].to_vec());
|
||||
payload.to_base58()
|
||||
}
|
||||
}
|
||||
pub fn double_sha256(payload: &[u8]) -> Vec<u8> {
|
||||
let h1 = Sha256::digest(&payload);
|
||||
let h2 = Sha256::digest(&h1);
|
||||
h2.to_vec()
|
||||
}
|
Loading…
Reference in New Issue