Compare commits

..

7 commits

8 changed files with 294 additions and 53 deletions

View file

@ -7,13 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.5.5.0]
### Added
- Added unction to decode Transparent Address in Human Readable Format
- TransparentAddress type refactored
- TransparentReceiver added to replace old TransparentAddress
- sha256 Functionmoved outside of encodeTransparentReceiver
### Changed
- `TransparentAddress` type refactored
- `TransparentReceiver` added to replace old `TransparentAddress`
- `sha256` Function moved outside of `encodeTransparentReceiver`
## [0.5.4.1]
### Added
- Functions to handle Sapling commitment trees, incremental witnesses and note positions
## [0.5.4.0]
### Added
- Function to decode Orchard actions with a spending key
- Functions for Bech32 encoding
- Function to encode a Sapling address

View file

@ -6,7 +6,8 @@ use std::{
marker::PhantomData,
io::{
Write,
Cursor
Cursor,
Error
},
};
@ -23,11 +24,20 @@ use haskell_ffi::{
FromHaskell, HaskellSize, ToHaskell
};
use incrementalmerkletree::frontier::CommitmentTree;
use incrementalmerkletree::{
frontier::CommitmentTree,
witness::IncrementalWitness
};
use zip32;
use zcash_primitives::{
merkle_tree::{
read_commitment_tree,
write_commitment_tree,
read_incremental_witness,
write_incremental_witness
},
zip32::{
Scope as SaplingScope,
ChildIndex,
@ -57,6 +67,7 @@ use zcash_primitives::{
MerklePath,
NOTE_COMMITMENT_TREE_DEPTH as SAPLING_DEPTH,
PaymentAddress,
note::ExtractedNoteCommitment as SaplingNoteCommitment,
keys::{
PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey,
ExpandedSpendingKey,
@ -188,6 +199,14 @@ pub struct Hhex {
bytes: Vec<u8>
}
impl<RW> ToHaskell<RW> for Hhex {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Haction {
nf: Hhex,
@ -221,7 +240,8 @@ impl Haction {
pub struct Hnote {
note: u64,
recipient: Vec<u8>,
memo: Vec<u8>
memo: Vec<u8>,
nullifier: Vec<u8>
}
impl<RW> ToHaskell<RW> for Hnote {
@ -713,6 +733,7 @@ pub extern "C" fn rust_wrapper_sapling_esk_decrypt(
note_len: usize,
external: bool,
net: bool,
pos: u64,
out: *mut u8,
out_len: &mut usize
){
@ -740,24 +761,24 @@ pub extern "C" fn rust_wrapper_sapling_esk_decrypt(
else {zcash_note_encryption::try_note_decryption(&test_domain, &pivk, &action2)};
match result {
Some((n, r, m)) => {
//let nullifier = n.nf(&nk, MerklePath<Node::from_cmu(&n.cmu()), SAPLING_DEPTH>.position());
let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec() };
let nullifier = n.nf(&nk, pos);
let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec(), nullifier: nullifier.to_vec() };
marshall_to_haskell_var(&hn, out, out_len, RW);
},
None => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]};
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]};
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
},
Err(_e1) => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0] };
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
},
Err(_e) => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0] };
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
@ -787,23 +808,23 @@ pub extern "C" fn rust_wrapper_sapling_note_decrypt_v2(
let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action3);
match result {
Some((n, r, m)) => {
let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec()};
let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec(), nullifier: vec![0]};
marshall_to_haskell_var(&hn, out, out_len, RW);
}
None => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]};
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]};
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
},
Err(_e1) => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] , nullifier: vec![0]};
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
}
Err(_e) => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]};
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]};
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
@ -837,17 +858,17 @@ pub extern "C" fn rust_wrapper_orchard_note_decrypt(
let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action);
match result {
Some((n, r, m)) => {
let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec()};
let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec(), nullifier: vec![0]};
marshall_to_haskell_var(&hn, out, out_len, RW);
}
None => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]};
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]};
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
},
None => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]};
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]};
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
@ -885,11 +906,11 @@ pub extern "C" fn rust_wrapper_orchard_note_decrypt_sk(
let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action);
match result {
Some((n, r, m)) => {
let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec()};
let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec(), nullifier: vec![0]};
marshall_to_haskell_var(&hn, out, out_len, RW);
}
None => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]};
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0]};
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
@ -1147,3 +1168,77 @@ pub extern "C" fn rust_wrapper_bech32_encode(
marshall_to_haskell_var(&string, out, out_len, RW);
}
#[no_mangle]
pub extern "C" fn rust_wrapper_read_sapling_commitment_tree(
tree: *const u8,
tree_len: usize,
node: *const u8,
node_len: usize,
out: *mut u8,
out_len: &mut usize
){
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
let tree_reader = Cursor::new(tree_in);
let mut ct: CommitmentTree<Node, SAPLING_DEPTH> = read_commitment_tree(tree_reader).unwrap();
let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW);
let n = Node::from_cmu(&SaplingNoteCommitment::from_bytes(&to_array(node_in)).unwrap());
ct.append(n);
let mut out_bytes: Vec<u8> = Vec::new();
let result = write_commitment_tree(&ct, &mut out_bytes );
match result {
Ok(()) => {
let h = Hhex { bytes: out_bytes};
marshall_to_haskell_var(&h, out, out_len, RW);
},
Err(_e) => {
let h0 = Hhex { bytes: vec![0]};
marshall_to_haskell_var(&h0, out, out_len, RW);
}
}
}
#[no_mangle]
pub extern "C" fn rust_wrapper_read_sapling_witness(
tree: *const u8,
tree_len: usize,
out: *mut u8,
out_len: &mut usize
){
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
let tree_reader = Cursor::new(tree_in);
let ct: CommitmentTree<Node, SAPLING_DEPTH> = read_commitment_tree(tree_reader).unwrap();
let inc_wit = IncrementalWitness::from_tree(ct);
let mut out_bytes: Vec<u8> = Vec::new();
let result = write_incremental_witness(&inc_wit, &mut out_bytes);
match result {
Ok(()) => {
let h = Hhex { bytes: out_bytes};
marshall_to_haskell_var(&h, out, out_len, RW);
},
Err(_e) => {
let h0 = Hhex { bytes: vec![0]};
marshall_to_haskell_var(&h0, out, out_len, RW);
}
}
}
#[no_mangle]
pub extern "C" fn rust_wrapper_read_sapling_position(
wit: *const u8,
wit_len: usize,
) -> u64 {
let wit_in: Vec<u8> = marshall_from_haskell_var(wit, wit_len, RW);
let wit_reader = Cursor::new(wit_in);
let iw: IncrementalWitness<Node, SAPLING_DEPTH> = read_incremental_witness(wit_reader).unwrap();
let path = iw.path();
match path {
Some(p) => {
let pos = p.position();
return u64::from(pos);
},
None => {
return 0;
}
}
}

View file

@ -21,6 +21,7 @@ import qualified Data.Text as T
import Data.Word
import Data.Int
import Data.Structured
import Data.HexString (HexString(..))
import Foreign.C.Types
import Foreign.Rust.Marshall.External
import Foreign.Rust.Marshall.Fixed
@ -106,6 +107,7 @@ import ZcashHaskell.Types
, toBorshVar* `BS.ByteString'&
, `Bool'
, `Bool'
, `Word64'
, getVarBuffer `Buffer DecodedNote'&
}
-> `()'
@ -201,6 +203,27 @@ import ZcashHaskell.Types
-> `()'
#}
{# fun unsafe rust_wrapper_read_sapling_commitment_tree as rustWrapperReadSaplingCommitmentTree
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_read_sapling_witness as rustWrapperReadSaplingWitness
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun pure unsafe rust_wrapper_read_sapling_position as rustWrapperReadSaplingPosition
{ toBorshVar* `BS.ByteString'&
}
-> `Word64'
#}
{# fun unsafe rust_wrapper_bech32_encode as rustWrapperBech32Encode
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&

View file

@ -19,6 +19,9 @@ module ZcashHaskell.Sapling where
import C.Zcash
( rustWrapperIsShielded
, rustWrapperReadSaplingCommitmentTree
, rustWrapperReadSaplingPosition
, rustWrapperReadSaplingWitness
, rustWrapperSaplingCheck
, rustWrapperSaplingChgPaymentAddress
, rustWrapperSaplingDecodeEsk
@ -30,7 +33,7 @@ import C.Zcash
)
import Data.Aeson
import qualified Data.ByteString as BS
import Data.HexString (HexString(..), fromText, toBytes, toText)
import Data.HexString (HexString(..), fromText, hexString, toBytes, toText)
import Data.Word
import Foreign.Rust.Marshall.Variable
( withPureBorshVarBuffer
@ -42,8 +45,10 @@ import ZcashHaskell.Types
, DecodedNote(..)
, RawData(..)
, RawTxResponse(..)
, SaplingCommitmentTree(..)
, SaplingReceiver(..)
, SaplingSpendingKey(..)
, SaplingWitness(..)
, Scope(..)
, Seed(..)
, ShieldedOutput(..)
@ -116,8 +121,9 @@ decodeSaplingOutputEsk ::
-> ShieldedOutput
-> ZcashNet
-> Scope
-> Integer
-> Maybe DecodedNote
decodeSaplingOutputEsk key out znet scope =
decodeSaplingOutputEsk key out znet scope pos =
case a_value decodedAction of
0 -> Nothing
_ -> Just decodedAction
@ -129,6 +135,7 @@ decodeSaplingOutputEsk key out znet scope =
(serializeShieldedOutput out)
(znet == MainNet)
(scope == External)
(fromIntegral pos)
-- | Attempts to obtain a sapling SpendingKey using a HDSeed
genSaplingSpendingKey :: Seed -> CoinType -> Int -> Maybe SaplingSpendingKey
@ -166,3 +173,35 @@ genSaplingInternalAddress sk =
where
res =
withPureBorshVarBuffer (rustWrapperSaplingChgPaymentAddress $ getBytes sk)
-- | Update a Sapling commitment tree
updateSaplingCommitmentTree ::
SaplingCommitmentTree -- ^ the base tree
-> HexString -- ^ the new note commitment
-> Maybe SaplingCommitmentTree
updateSaplingCommitmentTree tree cmu =
if BS.length (hexBytes updatedTree) > 1
then Just $ SaplingCommitmentTree updatedTree
else Nothing
where
updatedTree =
withPureBorshVarBuffer $
rustWrapperReadSaplingCommitmentTree
(hexBytes $ sapTree tree)
(hexBytes cmu)
-- | Get the Sapling incremental witness from a commitment tree
getSaplingWitness :: SaplingCommitmentTree -> Maybe SaplingWitness
getSaplingWitness tree =
if BS.length (hexBytes wit) > 1
then Just $ SaplingWitness wit
else Nothing
where
wit =
withPureBorshVarBuffer $
rustWrapperReadSaplingWitness (hexBytes $ sapTree tree)
-- | Get the Sapling note position from a witness
getSaplingNotePosition :: SaplingWitness -> Integer
getSaplingNotePosition =
fromIntegral . rustWrapperReadSaplingPosition . hexBytes . sapWit

View file

@ -20,12 +20,12 @@ import Crypto.Hash
import Crypto.Secp256k1
import qualified Data.ByteArray as BA
import qualified Data.ByteString as BS
import Data.ByteString.Base58 (bitcoinAlphabet, encodeBase58, decodeBase58)
import Data.ByteString.Base58 (bitcoinAlphabet, decodeBase58, encodeBase58)
import Data.Char (chr)
import Data.HexString
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Word
import Data.Char (chr)
import Haskoin.Address (Address(..))
import qualified Haskoin.Crypto.Hash as H
import Haskoin.Crypto.Keys.Extended
@ -35,8 +35,8 @@ import ZcashHaskell.Types
, Scope(..)
, Seed(..)
, ToBytes(..)
, TransparentReceiver(..)
, TransparentAddress(..)
, TransparentReceiver(..)
, TransparentSpendingKey(..)
, TransparentType(..)
, ZcashNet(..)
@ -111,21 +111,34 @@ decodeTransparentAddress taddress = do
let digest = BS.take 22 decoded
let chksum = BS.drop 22 decoded
let chksumd = BS.take 4 (sha256 $ sha256 digest)
if chksum /= chksum
if chksum /= chksumd
then Nothing -- Invalid address ( invalid checksum )
else do
-- build the TransparentAddress Object
else do
let addressType = BS.take 2 digest
let transparentReceiver = BS.drop 2 digest
let fb = BS.index addressType 0
let sb = BS.index addressType 1
case fb of
28 -> case sb of
189 -> Just $ TransparentAddress MainNet $ TransparentReceiver P2SH (fromRawBytes digest)
186 -> Just $ TransparentAddress TestNet $ TransparentReceiver P2SH (fromRawBytes digest)
184 -> Just $ TransparentAddress MainNet $ TransparentReceiver P2PKH (fromRawBytes digest)
28 ->
case sb of
189 ->
Just $
TransparentAddress MainNet $
TransparentReceiver P2SH (fromRawBytes digest)
186 ->
Just $
TransparentAddress TestNet $
TransparentReceiver P2SH (fromRawBytes digest)
184 ->
Just $
TransparentAddress MainNet $
TransparentReceiver P2PKH (fromRawBytes digest)
_ -> Nothing
29 -> if sb == 37
then Just $ TransparentAddress TestNet $ TransparentReceiver P2PKH (fromRawBytes digest)
29 ->
if sb == 37
then Just $
TransparentAddress TestNet $
TransparentReceiver P2PKH (fromRawBytes digest)
else Nothing
_ -> Nothing

View file

@ -525,6 +525,16 @@ instance FromJSON ShieldedOutput where
p <- obj .: "proof"
pure $ ShieldedOutput cv cmu ephKey encText outText p
-- | Type for a Sapling note commitment tree
newtype SaplingCommitmentTree = SaplingCommitmentTree
{ sapTree :: HexString
} deriving (Eq, Prelude.Show, Read)
-- | Type for a Sapling incremental witness
newtype SaplingWitness = SaplingWitness
{ sapWit :: HexString
} deriving (Eq, Prelude.Show, Read)
-- * Orchard
-- | A spending key for Orchard
newtype OrchardSpendingKey =

View file

@ -50,10 +50,13 @@ import ZcashHaskell.Sapling
, genSaplingInternalAddress
, genSaplingPaymentAddress
, genSaplingSpendingKey
, getSaplingNotePosition
, getSaplingWitness
, getShieldedOutputs
, isValidSaplingViewingKey
, isValidShieldedAddress
, matchSaplingAddress
, updateSaplingCommitmentTree
)
import ZcashHaskell.Transparent
import ZcashHaskell.Types
@ -71,15 +74,16 @@ import ZcashHaskell.Types
, RawTxOut(..)
, RawTxResponse(..)
, RawZebraTx(..)
, SaplingCommitmentTree(..)
, SaplingReceiver(..)
, SaplingSpendingKey(..)
, Scope(..)
, Seed(..)
, ShieldedOutput(..)
, ToBytes(..)
, TransparentReceiver(..)
, TransparentAddress(..)
, TransparentBundle(..)
, TransparentReceiver(..)
, TransparentType(..)
, UnifiedAddress(..)
, UnifiedFullViewingKey(..)
@ -843,18 +847,50 @@ main = do
Nothing -> assertFailure "Couldn't decode"
Just t' -> do
let tb = zt_tBundle t'
print tb
show tb `shouldNotBe` ""
describe "Sapling commitment trees" $ do
let tree =
SaplingCommitmentTree $
hexString
"01916df07670600aefa3b412a120d6b8d9a3d2ff9466a7ec770cd52d34ddb42313001000013c60b031a5e44650059fcc7101a3f551b807ab8b3a116a5a9c7fa0f3babbe735017c0d36686294ff19d59e58b6a2ac6a7ad607a804bc202c84012d8e94f233970c0128dbde5180af5304d8577376d78297130b615a327974c10881f6d876869aea05011b80b4ca60f74dfe33c78b062df73c84b8b44dab4604db16f5b61eea40134373010c96e4cc8a6a80fba0d41e4eb3070d80769104dc33fb61133b1304c15bf9e23e000107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
let cmu1 =
hexString
"45e47c5df6f5c5e48aa3526e977b2d1b57eda57214e36f06128008cb17b0125f"
let cmu2 =
hexString
"426ef44b3b22e0eeda7e4d2b62bac63966572b224e50f97ee56c9490cde4910d"
let tree2 =
hexString
"01a47029e9b43722c57143a5d07681bff3e2315c9a28ad49d69e7c1f2f6e81ac160010000000000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39"
it "Commitment tree is updated correctly" $ do
let t1 = updateSaplingCommitmentTree tree cmu1
t1 `shouldNotBe` Nothing
it "Incremental witness is generated" $ do
let t1 = updateSaplingCommitmentTree tree cmu1
case t1 of
Nothing -> assertFailure "Failed to append node to tree"
Just t -> getSaplingWitness t `shouldNotBe` Nothing
it "Position of note is obtained" $ do
let p =
getSaplingNotePosition <$>
(getSaplingWitness =<< updateSaplingCommitmentTree tree cmu1)
p `shouldBe` Just 129405
describe "Extract Sapling Address - UA Valid" $ do
let sr = getSaplingFromUA "u14a5c4ufn9feqvxssnvscep29j5cse4gjpg0w3w5vjhafn74hg9k73xgnxqv6m255n23weggr6j97c8kdwvn4pkz7rz6my52z8248gjmr7knlw536tcurs5km7knqnzez4cywudt3q6shr553hurduvljfeqvfzgegenfjashslkz3y4ykhxel6mrjp9gsm9xk7k6kdxn9y84kccmv8l"
let sr =
getSaplingFromUA
"u14a5c4ufn9feqvxssnvscep29j5cse4gjpg0w3w5vjhafn74hg9k73xgnxqv6m255n23weggr6j97c8kdwvn4pkz7rz6my52z8248gjmr7knlw536tcurs5km7knqnzez4cywudt3q6shr553hurduvljfeqvfzgegenfjashslkz3y4ykhxel6mrjp9gsm9xk7k6kdxn9y84kccmv8l"
it "Extract sapling address" $ do
case sr of
Nothing -> assertFailure "UA invalid or does not contain a Sapling receiver"
Nothing ->
assertFailure "UA invalid or does not contain a Sapling receiver"
Just t -> do
print t
t `shouldBe` "zs1waxrpde36rlrjdwfhnvw030sn29lzwmvmeupd8x2uuqgypaafx7mqcy0ep8yf2xtg30n5424t60"
t `shouldBe`
"zs1waxrpde36rlrjdwfhnvw030sn29lzwmvmeupd8x2uuqgypaafx7mqcy0ep8yf2xtg30n5424t60"
describe "Extract Sapling Address - UA Invalid" $ do
let sr = getSaplingFromUA "u14a5c4ufn9qfevxssnvscep29j5cse4gjpg0w3w5vjhafn74hg9k73xgnxqv6m255n23weggr6j97c8kdwvn4pkz7rz6my52z8248gjmr7knlw536tcurs5km7knqnzez4cywudt3q6shr553hurduvljfeqvfzgegenfjashslkz3y4ykhxel6mrjp9gsm9xk7k6kdxn9y84kccmv8l"
let sr =
getSaplingFromUA
"u14a5c4ufn9qfevxssnvscep29j5cse4gjpg0w3w5vjhafn74hg9k73xgnxqv6m255n23weggr6j97c8kdwvn4pkz7rz6my52z8248gjmr7knlw536tcurs5km7knqnzez4cywudt3q6shr553hurduvljfeqvfzgegenfjashslkz3y4ykhxel6mrjp9gsm9xk7k6kdxn9y84kccmv8l"
it "Try to extract sapling address from invalid UA" $ do
sr `shouldBe` Nothing
describe "Decode a Transparent Address" $ do
@ -862,6 +898,19 @@ main = do
it "Try to decode a valid Transparent Address" $ do
print ta
ta `shouldNotBe` Nothing
it "Encode and decode should be the same" $ do
let ua =
"u17n7hpwaujyq7ux8f9jpyymtnk5urw7pyrf60smp5mawy7jgz325hfvz3jn3zsfya8yxryf9q7ldk8nu8df0emra5wne28zq9d9nm2pu4x6qwjha565av9aze0xgujgslz74ufkj0c0cylqwjyrh9msjfh7jzal6d3qzrnhkkqy3pqm8j63y07jxj7txqeac982778rmt64f32aum94x"
case isValidUnifiedAddress ua of
Nothing -> assertFailure "Bad UA"
Just u -> do
let tAdd =
maybe
"No transparent"
(encodeTransparentReceiver (ua_net u)) $
t_rec u
(ta_receiver <$> decodeTransparentAddress (E.encodeUtf8 tAdd)) `shouldBe`
t_rec u
-- | Properties
prop_PhraseLength :: Property

View file

@ -5,7 +5,7 @@ cabal-version: 3.0
-- see: https://github.com/sol/hpack
name: zcash-haskell
version: 0.5.4.0
version: 0.5.5.0
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>
category: Blockchain