Sapling Spending keys and receivers #27
10 changed files with 323 additions and 167 deletions
|
@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Constants for Zcash protocol
|
- Constants for Zcash protocol
|
||||||
- Types for Spending Keys and Receivers for Sapling and Orchard
|
- Types for Spending Keys and Receivers for Sapling and Orchard
|
||||||
- Function to generate an Orchard receiver
|
- Function to generate an Orchard receiver
|
||||||
|
- Function to generate a Sapling receiver
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
1
librustzcash-wrapper/Cargo.lock
generated
1
librustzcash-wrapper/Cargo.lock
generated
|
@ -1314,7 +1314,6 @@ dependencies = [
|
||||||
"borsh 0.10.3",
|
"borsh 0.10.3",
|
||||||
"f4jumble",
|
"f4jumble",
|
||||||
"haskell-ffi",
|
"haskell-ffi",
|
||||||
"nom",
|
|
||||||
"orchard 0.7.1",
|
"orchard 0.7.1",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"zcash_address 0.2.0",
|
"zcash_address 0.2.0",
|
||||||
|
|
|
@ -17,7 +17,6 @@ zcash_primitives = "0.13.0"
|
||||||
zcash_client_backend = "0.10.0"
|
zcash_client_backend = "0.10.0"
|
||||||
zip32 = "0.1.0"
|
zip32 = "0.1.0"
|
||||||
proc-macro2 = "1.0.66"
|
proc-macro2 = "1.0.66"
|
||||||
nom = "7.1.3"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
capi = []
|
capi = []
|
||||||
|
|
|
@ -24,15 +24,23 @@ use haskell_ffi::{
|
||||||
use zip32;
|
use zip32;
|
||||||
|
|
||||||
use zcash_primitives::{
|
use zcash_primitives::{
|
||||||
zip32::Scope as SaplingScope,
|
zip32::{
|
||||||
|
Scope as SaplingScope,
|
||||||
|
sapling_find_address,
|
||||||
|
sapling::DiversifierKey
|
||||||
|
},
|
||||||
zip339::{Count, Mnemonic},
|
zip339::{Count, Mnemonic},
|
||||||
transaction::components::sapling::{
|
transaction::components::sapling::{
|
||||||
GrothProofBytes,
|
GrothProofBytes,
|
||||||
OutputDescription,
|
OutputDescription
|
||||||
},
|
},
|
||||||
sapling::{
|
sapling::{
|
||||||
PaymentAddress,
|
PaymentAddress,
|
||||||
keys::PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey,
|
keys::{
|
||||||
|
PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey,
|
||||||
|
ExpandedSpendingKey,
|
||||||
|
FullViewingKey as SaplingFullViewingKey
|
||||||
|
},
|
||||||
note_encryption::SaplingDomain
|
note_encryption::SaplingDomain
|
||||||
},
|
},
|
||||||
transaction::Transaction,
|
transaction::Transaction,
|
||||||
|
@ -49,13 +57,12 @@ use zcash_address::{
|
||||||
ZcashAddress
|
ZcashAddress
|
||||||
};
|
};
|
||||||
|
|
||||||
use zcash_client_backend::keys::{
|
use zcash_client_backend::keys::sapling::{
|
||||||
sapling,
|
ExtendedFullViewingKey,
|
||||||
sapling::ExtendedFullViewingKey,
|
ExtendedSpendingKey
|
||||||
sapling::ExtendedSpendingKey};
|
};
|
||||||
|
|
||||||
use zcash_primitives::zip32::{ AccountId, DiversifierIndex };
|
use zcash_primitives::zip32::{ AccountId, DiversifierIndex };
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
use orchard::{
|
use orchard::{
|
||||||
Action,
|
Action,
|
||||||
|
@ -624,7 +631,6 @@ pub extern "C" fn rust_wrapper_sapling_spendingkey(
|
||||||
out: *mut u8,
|
out: *mut u8,
|
||||||
out_len: &mut usize
|
out_len: &mut usize
|
||||||
){
|
){
|
||||||
println!("Starting extended spending key generation....");
|
|
||||||
let seed: Vec<u8> = marshall_from_haskell_var(iseed, iseed_len, RW);
|
let seed: Vec<u8> = marshall_from_haskell_var(iseed, iseed_len, RW);
|
||||||
if ( seed.len() != 64 ) {
|
if ( seed.len() != 64 ) {
|
||||||
// invalid seed length
|
// invalid seed length
|
||||||
|
@ -634,8 +640,7 @@ pub extern "C" fn rust_wrapper_sapling_spendingkey(
|
||||||
// Returns a byte array (169 bytes)
|
// Returns a byte array (169 bytes)
|
||||||
let su8 = &seed;
|
let su8 = &seed;
|
||||||
let seedu8 : &[u8] = &su8;
|
let seedu8 : &[u8] = &su8;
|
||||||
println!("Seed : {:?}\n", &seedu8);
|
let extsk: ExtendedSpendingKey = ExtendedSpendingKey::master(&seedu8);
|
||||||
let extsk: ExtendedSpendingKey = sapling::ExtendedSpendingKey::master(&seedu8);
|
|
||||||
let extsk_bytes = extsk.to_bytes().to_vec();
|
let extsk_bytes = extsk.to_bytes().to_vec();
|
||||||
marshall_to_haskell_var(&extsk_bytes, out, out_len, RW);
|
marshall_to_haskell_var(&extsk_bytes, out, out_len, RW);
|
||||||
}
|
}
|
||||||
|
@ -645,41 +650,22 @@ pub extern "C" fn rust_wrapper_sapling_spendingkey(
|
||||||
pub extern "C" fn rust_wrapper_sapling_paymentaddress(
|
pub extern "C" fn rust_wrapper_sapling_paymentaddress(
|
||||||
extspk: *const u8,
|
extspk: *const u8,
|
||||||
extspk_len: usize,
|
extspk_len: usize,
|
||||||
// divIx: u32,
|
div_ix: u32,
|
||||||
out: *mut u8,
|
out: *mut u8,
|
||||||
out_len: &mut usize
|
out_len: &mut usize
|
||||||
){
|
){
|
||||||
let divIx : u32 = 2;
|
let extspk: Vec<u8> = marshall_from_haskell_var(extspk, extspk_len, RW);
|
||||||
println!("Starting paymentAddress generation....");
|
let expsk = ExpandedSpendingKey::from_spending_key(&extspk);
|
||||||
let extspkb: Vec<u8> = marshall_from_haskell_var(extspk, extspk_len, RW);
|
let fvk = SaplingFullViewingKey::from_expanded_spending_key(&expsk);
|
||||||
if ( extspkb.len() != 169 ) {
|
let dk = DiversifierKey::master(&extspk);
|
||||||
// invalid ExtendedSpenndingKey Array length
|
let result = sapling_find_address(&fvk, &dk, DiversifierIndex::from(div_ix));
|
||||||
println!("Invalid ExtendedSpendingKey....");
|
match result {
|
||||||
marshall_to_haskell_var(&vec![0], out, out_len, RW);
|
Some((_d, p_address)) => {
|
||||||
} else {
|
marshall_to_haskell_var(&p_address.to_bytes().to_vec(), out, out_len, RW);
|
||||||
// Process
|
},
|
||||||
println!("Extended Spending Key validated, continue ....");
|
None => {
|
||||||
let extspkbu8 = &extspkb;
|
marshall_to_haskell_var(&vec![0], out, out_len, RW);
|
||||||
let xsku8 : &[u8] = &extspkbu8;
|
}
|
||||||
let xsk = match sapling::ExtendedSpendingKey::from_bytes(&xsku8) {
|
|
||||||
Ok ( x ) => x,
|
|
||||||
Err ( err ) => {
|
|
||||||
// Error recovering ExtendedSpendingKey from bytes
|
|
||||||
marshall_to_haskell_var(&vec![0], out, out_len, RW);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Obtain the DiversifiableFullViewingKey from ExtendedSpendingKey
|
|
||||||
let dfvk = xsk.to_diversifiable_full_viewing_key();
|
|
||||||
// Obtain the Address from the DiversifiableFullViewingKey
|
|
||||||
// println!("dfvk -> \n{:?}", dfvk);
|
|
||||||
// let divIndex : DiversifierIndex = divIx.into();
|
|
||||||
// println!("divIndex -> {:?}", divIndex);
|
|
||||||
let (divIx, paddress) = dfvk.default_address();
|
|
||||||
println!("Rust pmtAddress - \n{:?}\n\nRust Diversifier - \n{:?}\n", paddress, divIx);
|
|
||||||
let pmtAddress = paddress.to_bytes();
|
|
||||||
println!("\nRust pntAddress as byte array -\n{:?}\n", pmtAddress);
|
|
||||||
marshall_to_haskell_var(&pmtAddress.to_vec(), out, out_len, RW);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,8 +141,9 @@ import ZcashHaskell.Types
|
||||||
-> `()'
|
-> `()'
|
||||||
#}
|
#}
|
||||||
|
|
||||||
{# fun unsafe rust_wrapper_sapling_paymentaddress as rustWrapperPaymentAddress
|
{# fun unsafe rust_wrapper_sapling_paymentaddress as rustWrapperSaplingPaymentAddress
|
||||||
{ toBorshVar* `BS.ByteString'&
|
{ toBorshVar* `BS.ByteString'&
|
||||||
|
, `Word32'
|
||||||
, getVarBuffer `Buffer (BS.ByteString)'&
|
, getVarBuffer `Buffer (BS.ByteString)'&
|
||||||
}
|
}
|
||||||
-> `()'
|
-> `()'
|
||||||
|
|
|
@ -21,14 +21,13 @@ import C.Zcash
|
||||||
( rustWrapperIsShielded
|
( rustWrapperIsShielded
|
||||||
, rustWrapperSaplingCheck
|
, rustWrapperSaplingCheck
|
||||||
, rustWrapperSaplingNoteDecode
|
, rustWrapperSaplingNoteDecode
|
||||||
|
, rustWrapperSaplingPaymentAddress
|
||||||
, rustWrapperSaplingSpendingkey
|
, rustWrapperSaplingSpendingkey
|
||||||
, rustWrapperPaymentAddress
|
|
||||||
, rustWrapperSaplingVkDecode
|
, rustWrapperSaplingVkDecode
|
||||||
, rustWrapperTxParse
|
, rustWrapperTxParse
|
||||||
)
|
)
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import qualified Data.ByteString as BS
|
import qualified Data.ByteString as BS
|
||||||
import Data.ByteString.Lazy as BL
|
|
||||||
import Data.HexString (HexString(..), toBytes)
|
import Data.HexString (HexString(..), toBytes)
|
||||||
import Data.Word
|
import Data.Word
|
||||||
import Foreign.Rust.Marshall.Variable
|
import Foreign.Rust.Marshall.Variable
|
||||||
|
@ -36,16 +35,18 @@ import Foreign.Rust.Marshall.Variable
|
||||||
, withPureBorshVarBuffer
|
, withPureBorshVarBuffer
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( DecodedNote(..)
|
( AccountId
|
||||||
|
, CoinType
|
||||||
|
, DecodedNote(..)
|
||||||
, RawData(..)
|
, RawData(..)
|
||||||
, RawTxResponse(..)
|
, RawTxResponse(..)
|
||||||
, SaplingSKeyParams(..)
|
, SaplingReceiver
|
||||||
|
, SaplingSpendingKey(..)
|
||||||
|
, Seed(..)
|
||||||
, ShieldedOutput(..)
|
, ShieldedOutput(..)
|
||||||
, decodeHexText
|
, decodeHexText
|
||||||
, AccountId
|
|
||||||
, CoinType
|
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Utils
|
import ZcashHaskell.Utils (decodeBech32)
|
||||||
|
|
||||||
-- | Check if given bytesting is a valid encoded shielded address
|
-- | Check if given bytesting is a valid encoded shielded address
|
||||||
isValidShieldedAddress :: BS.ByteString -> Bool
|
isValidShieldedAddress :: BS.ByteString -> Bool
|
||||||
|
@ -91,16 +92,26 @@ instance FromJSON RawTxResponse where
|
||||||
Just o' -> do
|
Just o' -> do
|
||||||
a <- o' .: "actions"
|
a <- o' .: "actions"
|
||||||
pure $ RawTxResponse i h (getShieldedOutputs h) a ht c b
|
pure $ RawTxResponse i h (getShieldedOutputs h) a ht c b
|
||||||
|
|
||||||
--
|
--
|
||||||
-- | Attempts to obtain a sapling SpendinKey using a HDSeed, a Coin Type and an Account ID
|
-- | Attempts to obtain a sapling SpendingKey using a HDSeed
|
||||||
genSaplingSpendingKey :: BS.ByteString -> BS.ByteString
|
genSaplingSpendingKey :: Seed -> Maybe SaplingSpendingKey
|
||||||
genSaplingSpendingKey seed = do
|
genSaplingSpendingKey seed = do
|
||||||
let res = withPureBorshVarBuffer (rustWrapperSaplingSpendingkey seed )
|
if BS.length res == 196
|
||||||
res
|
then Just res
|
||||||
|
else Nothing
|
||||||
|
where
|
||||||
|
res = withPureBorshVarBuffer (rustWrapperSaplingSpendingkey seed)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- | Attempts to generate a sapling Payment Address using an ExtendedSpendingKey
|
-- | Attempts to generate a sapling Payment Address using an ExtendedSpendingKey
|
||||||
-- | and a Diversifier Index
|
-- | and a Diversifier Index
|
||||||
genSaplingPaymentAddress :: BS.ByteString -> BS.ByteString
|
genSaplingPaymentAddress :: SaplingSpendingKey -> Int -> Maybe SaplingReceiver
|
||||||
genSaplingPaymentAddress extspk = do
|
genSaplingPaymentAddress extspk i =
|
||||||
let pmtaddress = withPureBorshVarBuffer (rustWrapperPaymentAddress extspk )
|
if BS.length res == 43
|
||||||
pmtaddress
|
then Just res
|
||||||
|
else Nothing
|
||||||
|
where
|
||||||
|
res =
|
||||||
|
withPureBorshVarBuffer
|
||||||
|
(rustWrapperSaplingPaymentAddress extspk (fromIntegral i))
|
||||||
|
|
|
@ -346,16 +346,6 @@ data DecodedNote = DecodedNote
|
||||||
deriving anyclass (Data.Structured.Show)
|
deriving anyclass (Data.Structured.Show)
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct DecodedNote
|
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct DecodedNote
|
||||||
|
|
||||||
-- } Type to represent parameters to call rust zcash library
|
|
||||||
data SaplingSKeyParams = SaplingSKeyParams
|
|
||||||
{ hdseed :: BS.ByteString -- ^ seed required for sappling spending key generation
|
|
||||||
, coin_type :: Word32 -- ^ coin_type
|
|
||||||
, account_id :: Word32 -- ^ account id
|
|
||||||
} deriving stock (Eq, Prelude.Show, GHC.Generic)
|
|
||||||
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
|
|
||||||
deriving anyclass (Data.Structured.Show)
|
|
||||||
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct SaplingSKeyParams
|
|
||||||
|
|
||||||
-- * Helpers
|
-- * Helpers
|
||||||
-- | Helper function to turn a hex-encoded string to bytestring
|
-- | Helper function to turn a hex-encoded string to bytestring
|
||||||
decodeHexText :: String -> BS.ByteString
|
decodeHexText :: String -> BS.ByteString
|
||||||
|
|
|
@ -37,8 +37,8 @@ import Foreign.Marshal.Array (allocaArray, peekArray)
|
||||||
import Foreign.Ptr (Ptr)
|
import Foreign.Ptr (Ptr)
|
||||||
|
|
||||||
import Data.Word
|
import Data.Word
|
||||||
-- |
|
|
||||||
|
|
||||||
|
-- |
|
||||||
-- | Decode the given bytestring using Bech32
|
-- | Decode the given bytestring using Bech32
|
||||||
decodeBech32 :: BS.ByteString -> RawData
|
decodeBech32 :: BS.ByteString -> RawData
|
||||||
decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode
|
decodeBech32 = withPureBorshVarBuffer . rustWrapperBech32Decode
|
||||||
|
@ -88,13 +88,3 @@ makeZebraCall host port m params = do
|
||||||
setRequestHost (E.encodeUtf8 host) $
|
setRequestHost (E.encodeUtf8 host) $
|
||||||
setRequestMethod "POST" defaultRequest
|
setRequestMethod "POST" defaultRequest
|
||||||
httpJSON myRequest
|
httpJSON myRequest
|
||||||
|
|
||||||
|
|
||||||
-- + Misc functions
|
|
||||||
-- Convert an array of Word8 to a ByteString
|
|
||||||
word8ArrayToByteString :: [Word8] -> BS.ByteString
|
|
||||||
word8ArrayToByteString = BS.pack
|
|
||||||
|
|
||||||
-- Convert [Word8] to String
|
|
||||||
word8ToString :: [Word8] -> String
|
|
||||||
word8ToString = map (toEnum . fromEnum)
|
|
||||||
|
|
347
test/Spec.hs
347
test/Spec.hs
|
@ -41,18 +41,21 @@ import ZcashHaskell.Keys (generateWalletSeedPhrase, getWalletSeed)
|
||||||
import ZcashHaskell.Orchard
|
import ZcashHaskell.Orchard
|
||||||
import ZcashHaskell.Sapling
|
import ZcashHaskell.Sapling
|
||||||
( decodeSaplingOutput
|
( decodeSaplingOutput
|
||||||
|
, genSaplingPaymentAddress
|
||||||
|
, genSaplingSpendingKey
|
||||||
, getShieldedOutputs
|
, getShieldedOutputs
|
||||||
, isValidSaplingViewingKey
|
, isValidSaplingViewingKey
|
||||||
, isValidShieldedAddress
|
, isValidShieldedAddress
|
||||||
, matchSaplingAddress
|
, matchSaplingAddress
|
||||||
, genSaplingSpendingKey
|
|
||||||
, genSaplingPaymentAddress
|
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Transparent
|
import ZcashHaskell.Transparent
|
||||||
--(encodeTransparent)
|
--(encodeTransparent)
|
||||||
|
|
||||||
import ZcashHaskell.Types
|
import ZcashHaskell.Types
|
||||||
( BlockResponse(..)
|
( AccountId
|
||||||
|
, BlockResponse(..)
|
||||||
, CoinType(..)
|
, CoinType(..)
|
||||||
|
, CoinType
|
||||||
, DecodedNote(..)
|
, DecodedNote(..)
|
||||||
, OrchardAction(..)
|
, OrchardAction(..)
|
||||||
, Phrase(..)
|
, Phrase(..)
|
||||||
|
@ -62,19 +65,16 @@ import ZcashHaskell.Types
|
||||||
, UnifiedAddress(..)
|
, UnifiedAddress(..)
|
||||||
, UnifiedFullViewingKey(..)
|
, UnifiedFullViewingKey(..)
|
||||||
, decodeHexText
|
, decodeHexText
|
||||||
, AccountId
|
|
||||||
, CoinType
|
|
||||||
, getValue
|
, getValue
|
||||||
)
|
)
|
||||||
import ZcashHaskell.Utils
|
import ZcashHaskell.Utils
|
||||||
|
|
||||||
import Foreign.C.Types
|
|
||||||
import Data.Word
|
import Data.Word
|
||||||
|
import Foreign.C.Types
|
||||||
import Haskoin.Crypto.Keys.Extended
|
import Haskoin.Crypto.Keys.Extended
|
||||||
|
|
||||||
m2bs :: Maybe BS.ByteString -> BS.ByteString
|
m2bs :: Maybe BS.ByteString -> BS.ByteString
|
||||||
m2bs x = fromMaybe "" x
|
m2bs x = fromMaybe "" x
|
||||||
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
@ -483,83 +483,251 @@ main = do
|
||||||
msg `shouldBe` "t1LPWuQnjCRH7JAeEErSXKixcUteLJRJjKD"
|
msg `shouldBe` "t1LPWuQnjCRH7JAeEErSXKixcUteLJRJjKD"
|
||||||
describe "Transparent Private and Publicc Key Generation" $ do
|
describe "Transparent Private and Publicc Key Generation" $ do
|
||||||
it "Obtain a transparent extended private key from HDSeed" $ do
|
it "Obtain a transparent extended private key from HDSeed" $ do
|
||||||
let hdseed = [206, 61, 120, 38,
|
let hdseed =
|
||||||
206, 40, 201, 62,
|
[ 206
|
||||||
83, 175, 151, 131,
|
, 61
|
||||||
218, 141, 206, 254,
|
, 120
|
||||||
28, 244, 172, 213,
|
, 38
|
||||||
128, 248, 156, 45,
|
, 206
|
||||||
204, 44, 169, 3,
|
, 40
|
||||||
162, 188, 16, 173,
|
, 201
|
||||||
192, 164, 96, 148,
|
, 62
|
||||||
91, 52, 244, 83,
|
, 83
|
||||||
149, 169, 82, 196,
|
, 175
|
||||||
199, 53, 177, 170,
|
, 151
|
||||||
1, 6, 0, 120,
|
, 131
|
||||||
170, 2, 238, 219,
|
, 218
|
||||||
241, 243, 172, 178,
|
, 141
|
||||||
104, 81, 159, 144
|
, 206
|
||||||
] :: [Word8]
|
, 254
|
||||||
let xtpvk = genTransparentPrvKey (word8ArrayToByteString hdseed)
|
, 28
|
||||||
let testpvk = XPrvKey 0 "0000000000" 0 "fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb" "46aa0cd24a6e05709591426a4e682dd5406de4e75a39c0f410ee790403880943"
|
, 244
|
||||||
xtpvk `shouldBe` testpvk
|
, 172
|
||||||
-- describe "Obtain transparent public key from private key" $ do
|
, 213
|
||||||
it "Obtain a transparent extended public key from private key" $ do
|
, 128
|
||||||
let testpvk = XPrvKey 0 "0000000000" 0 "fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb" "46aa0cd24a6e05709591426a4e682dd5406de4e75a39c0f410ee790403880943"
|
, 248
|
||||||
let testpbk = XPubKey 0 "00000000" 0 "fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb" "279bda9c704f6da479cedb12c7cf773b3a348569dc1cfa6002526bad67674fd737b84a2bdb1199ecab1c9fed1b9a38aba5ba19259c1510d733a2376118515cd8"
|
, 156
|
||||||
let xtpubkIO = genTransparentPubKey testpvk
|
, 45
|
||||||
xtpubk <- xtpubkIO
|
, 204
|
||||||
|
, 44
|
||||||
|
, 169
|
||||||
|
, 3
|
||||||
|
, 162
|
||||||
|
, 188
|
||||||
|
, 16
|
||||||
|
, 173
|
||||||
|
, 192
|
||||||
|
, 164
|
||||||
|
, 96
|
||||||
|
, 148
|
||||||
|
, 91
|
||||||
|
, 52
|
||||||
|
, 244
|
||||||
|
, 83
|
||||||
|
, 149
|
||||||
|
, 169
|
||||||
|
, 82
|
||||||
|
, 196
|
||||||
|
, 199
|
||||||
|
, 53
|
||||||
|
, 177
|
||||||
|
, 170
|
||||||
|
, 1
|
||||||
|
, 6
|
||||||
|
, 0
|
||||||
|
, 120
|
||||||
|
, 170
|
||||||
|
, 2
|
||||||
|
, 238
|
||||||
|
, 219
|
||||||
|
, 241
|
||||||
|
, 243
|
||||||
|
, 172
|
||||||
|
, 178
|
||||||
|
, 104
|
||||||
|
, 81
|
||||||
|
, 159
|
||||||
|
, 144
|
||||||
|
] :: [Word8]
|
||||||
|
let xtpvk = genTransparentPrvKey (BS.pack hdseed)
|
||||||
|
let testpvk =
|
||||||
|
XPrvKey
|
||||||
|
0
|
||||||
|
"0000000000"
|
||||||
|
0
|
||||||
|
"fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb"
|
||||||
|
"46aa0cd24a6e05709591426a4e682dd5406de4e75a39c0f410ee790403880943"
|
||||||
|
xtpvk `shouldBe` testpvk
|
||||||
|
it "Obtain a transparent extended public key from private key" $ do
|
||||||
|
let testpvk =
|
||||||
|
XPrvKey
|
||||||
|
0
|
||||||
|
"0000000000"
|
||||||
|
0
|
||||||
|
"fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb"
|
||||||
|
"46aa0cd24a6e05709591426a4e682dd5406de4e75a39c0f410ee790403880943"
|
||||||
|
let testpbk =
|
||||||
|
XPubKey
|
||||||
|
0
|
||||||
|
"00000000"
|
||||||
|
0
|
||||||
|
"fb5b9b89d3e9dfdebeaabd15de8fbc7e9a140b7f2de2b4034c2573425d39aceb"
|
||||||
|
"279bda9c704f6da479cedb12c7cf773b3a348569dc1cfa6002526bad67674fd737b84a2bdb1199ecab1c9fed1b9a38aba5ba19259c1510d733a2376118515cd8"
|
||||||
|
let xtpubkIO = genTransparentPubKey testpvk
|
||||||
|
xtpubk <- xtpubkIO
|
||||||
---print $ show xtpubk
|
---print $ show xtpubk
|
||||||
xtpubk `shouldBe` testpbk
|
xtpubk `shouldBe` testpbk
|
||||||
describe "Sapling SpendingKey test" $ do
|
describe "Sapling SpendingKey test" $ do
|
||||||
it "Call function with parameters" $ do
|
let hdseed =
|
||||||
let hdseed = [206, 61, 120, 38,
|
BS.pack $
|
||||||
206, 40, 201, 62,
|
[ 206
|
||||||
83, 175, 151, 131,
|
, 61
|
||||||
218, 141, 206, 254,
|
, 120
|
||||||
28, 244, 172, 213,
|
, 38
|
||||||
128, 248, 156, 45,
|
, 206
|
||||||
204, 44, 169, 3,
|
, 40
|
||||||
162, 188, 16, 173,
|
, 201
|
||||||
192, 164, 96, 148,
|
, 62
|
||||||
91, 52, 244, 83,
|
, 83
|
||||||
149, 169, 82, 196,
|
, 175
|
||||||
199, 53, 177, 170,
|
, 151
|
||||||
1, 6, 0, 120,
|
, 131
|
||||||
170, 2, 238, 219,
|
, 218
|
||||||
241, 243, 172, 178,
|
, 141
|
||||||
104, 81, 159, 144
|
, 206
|
||||||
] :: [Word8]
|
, 254
|
||||||
let msg = genSaplingSpendingKey (word8ArrayToByteString hdseed)
|
, 28
|
||||||
let msgArr = BS.unpack msg
|
, 244
|
||||||
if (length msgArr) == 169
|
, 172
|
||||||
then True
|
, 213
|
||||||
else False
|
, 128
|
||||||
|
, 248
|
||||||
|
, 156
|
||||||
|
, 45
|
||||||
|
, 204
|
||||||
|
, 44
|
||||||
|
, 169
|
||||||
|
, 3
|
||||||
|
, 162
|
||||||
|
, 188
|
||||||
|
, 16
|
||||||
|
, 173
|
||||||
|
, 192
|
||||||
|
, 164
|
||||||
|
, 96
|
||||||
|
, 148
|
||||||
|
, 91
|
||||||
|
, 52
|
||||||
|
, 244
|
||||||
|
, 83
|
||||||
|
, 149
|
||||||
|
, 169
|
||||||
|
, 82
|
||||||
|
, 196
|
||||||
|
, 199
|
||||||
|
, 53
|
||||||
|
, 177
|
||||||
|
, 170
|
||||||
|
, 1
|
||||||
|
, 6
|
||||||
|
, 0
|
||||||
|
, 120
|
||||||
|
, 170
|
||||||
|
, 2
|
||||||
|
, 238
|
||||||
|
, 219
|
||||||
|
, 241
|
||||||
|
, 243
|
||||||
|
, 172
|
||||||
|
, 178
|
||||||
|
, 104
|
||||||
|
, 81
|
||||||
|
, 159
|
||||||
|
, 144
|
||||||
|
]
|
||||||
|
--xit "Call function with parameters" $ do
|
||||||
|
--let msg = genSaplingSpendingKey (word8ArrayToByteString hdseed)
|
||||||
|
--let msgArr = BS.unpack msg
|
||||||
|
--if (length msgArr) == 169
|
||||||
|
--then True
|
||||||
|
--else False
|
||||||
|
it "Generate Sapling spending key" $ do
|
||||||
|
p <- generateWalletSeedPhrase
|
||||||
|
let s = getWalletSeed p
|
||||||
|
genSaplingSpendingKey <$> s `shouldNotBe` Nothing
|
||||||
describe "Sapling Payment Address generation test" $ do
|
describe "Sapling Payment Address generation test" $ do
|
||||||
it "Call genSaplingPaymentAddress" $ do
|
it "Call genSaplingPaymentAddress" $ do
|
||||||
let hdseed1 = [206, 61, 120, 38,
|
let hdseed1 =
|
||||||
206, 40, 201, 62,
|
[ 206
|
||||||
83, 175, 151, 131,
|
, 61
|
||||||
218, 141, 206, 254,
|
, 120
|
||||||
28, 244, 172, 213,
|
, 38
|
||||||
128, 248, 156, 45,
|
, 206
|
||||||
204, 44, 169, 3,
|
, 40
|
||||||
162, 188, 16, 173,
|
, 201
|
||||||
192, 164, 96, 148,
|
, 62
|
||||||
91, 52, 244, 83,
|
, 83
|
||||||
149, 169, 82, 196,
|
, 175
|
||||||
199, 53, 177, 170,
|
, 151
|
||||||
1, 6, 0, 120,
|
, 131
|
||||||
170, 2, 238, 219,
|
, 218
|
||||||
241, 243, 172, 178,
|
, 141
|
||||||
104, 81, 159, 144
|
, 206
|
||||||
] :: [Word8]
|
, 254
|
||||||
let msg1 = genSaplingSpendingKey (word8ArrayToByteString hdseed1)
|
, 28
|
||||||
let pmtaddress = genSaplingPaymentAddress msg1 --(word8ArrayToByteString hdseed1)
|
, 244
|
||||||
let msgArr = BS.unpack pmtaddress
|
, 172
|
||||||
if (length msgArr) == 43
|
, 213
|
||||||
then True
|
, 128
|
||||||
else False
|
, 248
|
||||||
|
, 156
|
||||||
|
, 45
|
||||||
|
, 204
|
||||||
|
, 44
|
||||||
|
, 169
|
||||||
|
, 3
|
||||||
|
, 162
|
||||||
|
, 188
|
||||||
|
, 16
|
||||||
|
, 173
|
||||||
|
, 192
|
||||||
|
, 164
|
||||||
|
, 96
|
||||||
|
, 148
|
||||||
|
, 91
|
||||||
|
, 52
|
||||||
|
, 244
|
||||||
|
, 83
|
||||||
|
, 149
|
||||||
|
, 169
|
||||||
|
, 82
|
||||||
|
, 196
|
||||||
|
, 199
|
||||||
|
, 53
|
||||||
|
, 177
|
||||||
|
, 170
|
||||||
|
, 1
|
||||||
|
, 6
|
||||||
|
, 0
|
||||||
|
, 120
|
||||||
|
, 170
|
||||||
|
, 2
|
||||||
|
, 238
|
||||||
|
, 219
|
||||||
|
, 241
|
||||||
|
, 243
|
||||||
|
, 172
|
||||||
|
, 178
|
||||||
|
, 104
|
||||||
|
, 81
|
||||||
|
, 159
|
||||||
|
, 144
|
||||||
|
] :: [Word8]
|
||||||
|
p <- generateWalletSeedPhrase
|
||||||
|
let s = getWalletSeed p
|
||||||
|
genSaplingPaymentAddress (fromMaybe "" s) 0 `shouldNotBe` Nothing
|
||||||
|
prop "Sapling receivers are valid" $
|
||||||
|
forAll genSapArgs $ \(i) -> prop_SaplingReceiver i
|
||||||
|
|
||||||
-- | Properties
|
-- | Properties
|
||||||
prop_PhraseLength :: Int -> Property
|
prop_PhraseLength :: Int -> Property
|
||||||
|
@ -590,6 +758,14 @@ prop_OrchardReceiver c i j =
|
||||||
let sk = genOrchardSpendingKey (fromMaybe "" s) c i
|
let sk = genOrchardSpendingKey (fromMaybe "" s) c i
|
||||||
return $ genOrchardReceiver j (fromMaybe "" sk) =/= Nothing
|
return $ genOrchardReceiver j (fromMaybe "" sk) =/= Nothing
|
||||||
|
|
||||||
|
prop_SaplingReceiver :: Int -> Property
|
||||||
|
prop_SaplingReceiver i =
|
||||||
|
ioProperty $ do
|
||||||
|
p <- generateWalletSeedPhrase
|
||||||
|
let s = getWalletSeed p
|
||||||
|
let sk = genSaplingSpendingKey (fromMaybe "" s)
|
||||||
|
return $ genSaplingPaymentAddress (fromMaybe "" sk) i =/= Nothing
|
||||||
|
|
||||||
-- | Generators
|
-- | Generators
|
||||||
genOrcArgs :: Gen (CoinType, Int, Int)
|
genOrcArgs :: Gen (CoinType, Int, Int)
|
||||||
genOrcArgs = do
|
genOrcArgs = do
|
||||||
|
@ -597,4 +773,7 @@ genOrcArgs = do
|
||||||
j <- arbitrarySizedNatural
|
j <- arbitrarySizedNatural
|
||||||
c <- elements [MainNetCoin, TestNetCoin, RegTestNetCoin]
|
c <- elements [MainNetCoin, TestNetCoin, RegTestNetCoin]
|
||||||
return (c, i, j)
|
return (c, i, j)
|
||||||
|
|
||||||
|
genSapArgs :: Gen Int
|
||||||
|
genSapArgs = choose (1, 50)
|
||||||
-- | Arbitrary instances
|
-- | Arbitrary instances
|
||||||
|
|
|
@ -5,7 +5,7 @@ cabal-version: 3.0
|
||||||
-- see: https://github.com/sol/hpack
|
-- see: https://github.com/sol/hpack
|
||||||
|
|
||||||
name: zcash-haskell
|
name: zcash-haskell
|
||||||
version: 0.4.4.0
|
version: 0.4.4.1
|
||||||
synopsis: Utilities to interact with the Zcash blockchain
|
synopsis: Utilities to interact with the Zcash blockchain
|
||||||
description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/zcash-haskell#readme>
|
description: Please see the README on the repo at <https://git.vergara.tech/Vergara_Tech/zcash-haskell#readme>
|
||||||
category: Blockchain
|
category: Blockchain
|
||||||
|
|
Loading…
Reference in a new issue