DerivationTool + tests

Fixes #204
This commit is contained in:
Francisco Gindre 2020-10-09 17:58:36 -03:00
parent f0ed01bb92
commit 328a18d898
11 changed files with 635 additions and 14 deletions

103
Cargo.lock generated
View File

@ -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"

View File

@ -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

View File

@ -147,6 +147,6 @@ SPEC CHECKSUMS:
SwiftProtobuf: 4ef85479c18ca85b5482b343df9c319c62bda699
ZcashLightClientKit: aa2bfedb1cd48385d35113672b521a4bb47fbbf4
PODFILE CHECKSUM: 097fb38072a4f5011bd1e85186d6934583189378
PODFILE CHECKSUM: 7d5095283dc02470f40ab06564d94076ba16d570
COCOAPODS: 1.9.3

View File

@ -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)

View File

@ -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

View File

@ -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
}
}

View File

@ -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.
*/

View File

@ -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)
}
}

View File

@ -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

View File

@ -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

View File

@ -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()
}