Compare commits

..

46 commits

Author SHA1 Message Date
dea960c2ac
Functions to handle commitment tree nodes for Sapling and Orchard (#100)
This PR includes the functions for hashing commitment nodes for both Sapling and Orchard. It also includes functions to validate tree roots and Merkle paths.

Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/100
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-11-15 18:48:36 +00:00
62cda9cc15
docs: version bump 2024-11-05 12:42:03 -06:00
5ce149c54f
Functions to create and manage Orchard commitment trees (#99)
This PR contains the functions to create, update and validate Orchard commitment trees.

Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/99
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-11-05 18:28:45 +00:00
6d4b6840d3
Optimize transaction creation (#98)
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/98
Co-authored-by: Rene Vergara <rene@vergara.network>
Co-committed-by: Rene Vergara <rene@vergara.network>
2024-10-30 16:47:11 +00:00
662a0d1148
Merge pull request 'Implement Frontier for Sapling' (#97) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/97
2024-10-18 19:40:35 +00:00
4608577c41
docs: version bump 2024-10-18 14:39:05 -05:00
5a9ed11c25
fix(rust): SaplingFrontier marshalling 2024-10-18 12:25:30 -05:00
96cfe3a52a
feat: use SaplingFrontier for witnesses 2024-10-18 09:43:02 -05:00
3203c7e8ff
feat: implement Frontier for Sapling witnesses 2024-10-18 08:47:52 -05:00
396f15140a
Merge pull request 'feat: add toJSON for BlockResponse' (#96) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/96
2024-10-11 13:19:08 +00:00
5a08c80285
feat: add toJSON for BlockResponse 2024-10-11 08:17:02 -05:00
003293cc3f
Merge pull request 'Orchard anchor and witness updates' (#95) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/95
2024-10-01 12:51:41 +00:00
612ce812ef
Merge branch 'milestone2' into rav001 2024-10-01 07:15:15 -05:00
3969490283
feat: Use the notes to determine anchors 2024-09-30 14:50:54 -05:00
38e4131daa
feat!: update Orchard witness calculation
Now uses Frontier
2024-09-30 13:18:47 -05:00
48afd81595
feat!: migrate Orchard commitment trees to Frontier 2024-09-30 12:11:47 -05:00
12296026a0
Merge pull request 'Improve witness update functions.' (#94) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/94
2024-09-25 19:47:43 +00:00
5de1844e9d
feat: improve witness updates 2024-09-25 14:43:11 -05:00
36fd2e59a4
Merge branch 'milestone2' into rav001 2024-09-23 10:20:10 -05:00
63a97b880c
Merge pull request 'Add block hash to BlockResponse' (#93) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/93
2024-09-23 15:19:31 +00:00
f24ea80cde
feat: add block hash to BlockResponse 2024-09-23 10:17:35 -05:00
9df346389a
Merge branch 'milestone2' into rav001 2024-09-18 07:30:27 -05:00
91e2ebbabd
Merge pull request 'Add privacy policy error to TxError' (#92) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/92
2024-09-18 12:29:35 +00:00
343495f6e7
feat: add privacy policy error to TxError 2024-09-18 07:27:53 -05:00
7350723801
Merge branch 'milestone2' into rav001 2024-09-17 13:09:54 -05:00
7965dc38c4
Merge pull request 'docs: update version' (#91) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/91
2024-09-17 18:08:09 +00:00
ee165de652
Merge branch 'milestone2' into rav001 2024-09-17 18:07:54 +00:00
1f1ca4e206
docs: update version 2024-09-17 13:06:28 -05:00
f1e1570b25
Merge pull request 'Implement wagyu-zcash-parameters in Rust bindings' (#90) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/90
2024-09-16 18:47:50 +00:00
5a8cd44fbc
feat: implement wagyu-zcash-parameters crate 2024-09-16 13:36:49 -05:00
cedc3a0cc1
Merge branch 'milestone2' into rav001 2024-08-30 11:19:07 -05:00
ce19e174cc
Merge pull request 'fix: decode unified addresses with no transparent receivers' (#89) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/89
2024-08-30 16:12:13 +00:00
85a4741dcb
fix: decode unified addresses with no transparent receivers
ensures that a unified address that does not contain a transparent
receiver is properly represented in the type
2024-08-30 11:02:52 -05:00
0b2fae2b5d
Merge pull request 'Add JSON instances for Transaction' (#88) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/88
2024-08-20 21:05:02 +00:00
b4069d6233
Merge branch 'milestone2' into rav001 2024-08-20 15:53:31 -05:00
c8f411fcdd
add JSON instances for Transaction 2024-08-20 15:50:07 -05:00
939ae687e8
Merge pull request 'Implement address comparison and validation' (#87) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/87
2024-08-14 17:35:27 +00:00
e1622a0d7f
Merge branch 'milestone2' into rav001 2024-08-14 17:35:03 +00:00
774e135aab
Fix data type 2024-08-14 12:32:48 -05:00
b7c91e10fe
Add functions to compare and validate addresses 2024-08-14 12:32:30 -05:00
cbbdfe42af
Merge pull request 'Add ValidAddress' (#86) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech///Vergara_Tech/zcash-haskell/pulls/86
2024-08-13 12:58:21 +00:00
9ca702a68e
Add ValidAddress 2024-08-13 07:56:25 -05:00
cc72fadef3
Merge pull request 'Add JSON instances for ZcashNet' (#85) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech/Vergara_Tech/zcash-haskell/pulls/85
2024-07-25 16:14:03 +00:00
7c79ee6163
Add JSON instances for ZcashNet 2024-07-25 11:09:17 -05:00
e8074419cf
Merge branch 'milestone2' of git.vergara.tech:Vergara_Tech/zcash-haskell into milestone2 2024-07-02 13:21:39 -05:00
90c8a7c302
Merge pull request 'Performance enhancement for transaction creation' (#83) from rav001 into milestone2
Reviewed-on: https://git.vergara.tech/Vergara_Tech/zcash-haskell/pulls/83
2024-05-16 15:45:20 +00:00
13 changed files with 496 additions and 904 deletions

View file

@ -5,35 +5,6 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.7.8.1]
### Changed
- Referenced libraries updated to use the new Vergara Tech git server
## [0.7.8.0]
### Added
- New `UnifiedIncomingViewingKey` type
- Functions to derive Orchard full viewing key
- Functions to derive Sapling full viewing key
- Functions to derive transparent "full viewing key"
- Functions to encode Unified Full Viewing Keys
- Functions to encode Unified Incoming Viewing Keys
## [0.7.7.0]
### Changed
- Updated Rust crates
## [0.7.6.0]
### Changed
- Removed workaround for missing `time` field in Zebra's `getblock` response.
## [0.7.5.0] ## [0.7.5.0]
### Added ### Added

View file

@ -4,10 +4,10 @@ with-compiler: ghc-9.6.5
source-repository-package source-repository-package
type: git type: git
location: https://code.vergara.tech/Vergara_Tech/haskell-foreign-rust.git location: https://git.vergara.tech/Vergara_Tech/haskell-foreign-rust.git
tag: 335e804454cd30da2c526457be37e477f71e4665 tag: 335e804454cd30da2c526457be37e477f71e4665
source-repository-package source-repository-package
type: git type: git
location: https://code.vergara.tech/Vergara_Tech/haskell-hexstring.git location: https://git.vergara.tech/Vergara_Tech/haskell-hexstring.git
tag: 39d8da7b11a80269454c2f134a5c834e0f3cb9a7 tag: 39d8da7b11a80269454c2f134a5c834e0f3cb9a7

File diff suppressed because it is too large Load diff

View file

@ -9,13 +9,13 @@ haskell-ffi.git = "https://github.com/BeFunctional/haskell-rust-ffi.git"
haskell-ffi.rev = "2bf292e2e56eac8e9fb0fb2e1450cf4a4bd01274" haskell-ffi.rev = "2bf292e2e56eac8e9fb0fb2e1450cf4a4bd01274"
f4jumble = "0.1" f4jumble = "0.1"
zcash_address = "0.2.0" zcash_address = "0.2.0"
borsh = "0.9" borsh = "0.10"
bech32 = "0.11" bech32 = "0.11"
orchard = "0.10.0" orchard = "0.10.0"
zcash_note_encryption = "0.4.0" zcash_note_encryption = "0.4.0"
zcash_primitives = { version = "0.21.0", features = ["transparent-inputs"]} zcash_primitives = { version = "0.19.0", features = ["transparent-inputs"]}
zcash_client_backend = "0.16.0" zcash_client_backend = "0.14.0"
sapling-crypto = "0.4" sapling-crypto = "0.3"
zip32 = "0.1.2" zip32 = "0.1.2"
proc-macro2 = "1.0.66" proc-macro2 = "1.0.66"
nonempty = "0.7.0" nonempty = "0.7.0"
@ -25,7 +25,6 @@ jubjub = "0.10.0"
rand_core = { version = "0.6.4", features = ["getrandom"]} rand_core = { version = "0.6.4", features = ["getrandom"]}
wagyu-zcash-parameters = "0.2.0" wagyu-zcash-parameters = "0.2.0"
bip0039 = "0.12.0" bip0039 = "0.12.0"
ahash = "0.7.8"
[features] [features]

View file

@ -1,4 +1,4 @@
[toolchain] [toolchain]
channel = "nightly" channel = "nightly-2024-02-04"
components = [ "rustfmt", "rustc-dev"] components = [ "rustfmt", "rustc-dev"]
profile = "minimal" profile = "minimal"

View file

@ -116,7 +116,6 @@ use zcash_primitives::{
}, },
transparent::{ transparent::{
Bundle as TransparentBundle, Bundle as TransparentBundle,
builder::TransparentSigningSet,
TxIn, TxIn,
TxOut, TxOut,
OutPoint, OutPoint,
@ -135,7 +134,7 @@ use zcash_primitives::{
use zcash_address::{ use zcash_address::{
Network, Network,
unified::{Address, Encoding, Ufvk, Uivk, Ivk, Container, Fvk, Receiver}, unified::{Address, Encoding, Ufvk, Container, Fvk, Receiver},
ZcashAddress ZcashAddress
}; };
@ -157,7 +156,7 @@ use orchard::{
Flags Flags
}, },
Action, Action,
keys::{SpendAuthorizingKey, SpendingKey, FullViewingKey, PreparedIncomingViewingKey, Scope}, keys::{SpendingKey, FullViewingKey, PreparedIncomingViewingKey, Scope},
note::{Rho, RandomSeed, Note, Nullifier, TransmittedNoteCiphertext, ExtractedNoteCommitment}, note::{Rho, RandomSeed, Note, Nullifier, TransmittedNoteCiphertext, ExtractedNoteCommitment},
note_encryption::OrchardDomain, note_encryption::OrchardDomain,
primitives::redpallas::{VerificationKey, SpendAuth, Signature}, primitives::redpallas::{VerificationKey, SpendAuth, Signature},
@ -690,35 +689,6 @@ impl Hufvk {
} }
} }
#[derive(Debug, BorshSerialize, BorshDeserialize)]
pub struct Huivk {
net: u8,
orchard: Vec<u8>,
sapling: Vec<u8>,
transparent: Vec<u8>
}
impl<RW> ToHaskell<RW> for Huivk {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
impl Huivk {
fn add_key_section(&mut self, ivk: &Ivk) {
if let Ivk::Orchard(v) = ivk {
self.orchard = v.to_vec();
}
if let Ivk::Sapling(w) = ivk {
self.sapling = w.to_vec();
}
if let Ivk::P2pkh(x) = ivk {
self.transparent = x.to_vec();
}
}
}
#[derive(Debug, BorshSerialize, BorshDeserialize)] #[derive(Debug, BorshSerialize, BorshDeserialize)]
pub struct Hsvk { pub struct Hsvk {
vk: Vec<u8>, vk: Vec<u8>,
@ -997,34 +967,6 @@ pub extern "C" fn rust_wrapper_ufvk_decode(
} }
} }
#[no_mangle]
pub extern "C" fn rust_wrapper_uivk_decode(
input: *const u8,
input_len: usize,
out: *mut u8,
out_len: &mut usize
) {
let input: String = marshall_from_haskell_var(input, input_len, RW);
let dec_key = Uivk::decode(&input);
match dec_key {
Ok((n, uivk)) => {
let x = match n {
Network::Main => 1,
Network::Test => 2,
Network::Regtest => 3
};
let mut hk = Huivk { net: x, orchard: vec![0], sapling: vec![0], transparent: vec![0] };
let ivks = uivk.items();
ivks.iter().for_each(|k| hk.add_key_section(k));
marshall_to_haskell_var(&hk, out, out_len, RW);
}
Err(_e) => {
let hk0 = Hufvk { net: 0, orchard: vec![0], sapling: vec![0], transparent: vec![0] };
marshall_to_haskell_var(&hk0, out, out_len, RW);
}
}
}
#[no_mangle] #[no_mangle]
pub extern "C" fn rust_wrapper_sapling_esk_decrypt( pub extern "C" fn rust_wrapper_sapling_esk_decrypt(
key: *const u8, key: *const u8,
@ -2231,13 +2173,12 @@ pub extern "C" fn rust_wrapper_create_transaction(
let mut main_builder = Builder::new(MainNetwork, BlockHeight::from(bl_height), build_config); let mut main_builder = Builder::new(MainNetwork, BlockHeight::from(bl_height), build_config);
let mut test_builder = Builder::new(TestNetwork, BlockHeight::from(bl_height), build_config); let mut test_builder = Builder::new(TestNetwork, BlockHeight::from(bl_height), build_config);
let trans_input: Vec<HtransparentInput> = marshall_from_haskell_var(t_input, t_input_len, RW); let trans_input: Vec<HtransparentInput> = marshall_from_haskell_var(t_input, t_input_len, RW);
let mut tss = TransparentSigningSet::new();
for t_in in trans_input { for t_in in trans_input {
if t_in.sk.len() > 1 { if t_in.sk.len() > 1 {
//println!("t inp: {:?}", t_in); //println!("t inp: {:?}", t_in);
let k = SecretKey::from_slice(&t_in.sk).unwrap(); let k = SecretKey::from_slice(&t_in.sk).unwrap();
if net { if net {
match main_builder.add_transparent_input(tss.add_key(k), t_in.utxo.unpack(), t_in.coin.unpack()) { match main_builder.add_transparent_input(k, t_in.utxo.unpack(), t_in.coin.unpack()) {
Ok(()) => { Ok(()) => {
//println!("added t-input in main"); //println!("added t-input in main");
continue; continue;
@ -2245,7 +2186,7 @@ pub extern "C" fn rust_wrapper_create_transaction(
Err(_e) => { println!("Error reading transparent input"); } Err(_e) => { println!("Error reading transparent input"); }
} }
} else { } else {
match test_builder.add_transparent_input(tss.add_key(k), t_in.utxo.unpack(), t_in.coin.unpack()) { match test_builder.add_transparent_input(k, t_in.utxo.unpack(), t_in.coin.unpack()) {
Ok(()) => { Ok(()) => {
//println!("added t-input in test"); //println!("added t-input in test");
continue; continue;
@ -2255,14 +2196,12 @@ pub extern "C" fn rust_wrapper_create_transaction(
} }
} }
} }
let mut sap_key_array = vec![];
for s_in in sap_input { for s_in in sap_input {
if s_in.sk.len() > 1 { if s_in.sk.len() > 1 {
//println!("s inp: {:?}", s_in); //println!("s inp: {:?}", s_in);
let sp_key = ExtendedSpendingKey::from_bytes(&s_in.sk); let sp_key = ExtendedSpendingKey::from_bytes(&s_in.sk);
match sp_key { match sp_key {
Ok(sk) => { Ok(sk) => {
sap_key_array.push(sk.clone());
let pay_addr = PaymentAddress::from_bytes(&to_array(s_in.note.recipient)).unwrap(); let pay_addr = PaymentAddress::from_bytes(&to_array(s_in.note.recipient)).unwrap();
let rseed = if s_in.note.rseed.kind == 1 { let rseed = if s_in.note.rseed.kind == 1 {
Rseed::BeforeZip212(Fr::from_bytes(&to_array(s_in.note.rseed.bytes)).unwrap()) Rseed::BeforeZip212(Fr::from_bytes(&to_array(s_in.note.rseed.bytes)).unwrap())
@ -2277,9 +2216,8 @@ pub extern "C" fn rust_wrapper_create_transaction(
Node::empty_leaf() Node::empty_leaf()
}).collect(), Position::from(u64::from(s_in.iw.position))); }).collect(), Position::from(u64::from(s_in.iw.position)));
let merkle_path = mk_path.unwrap(); let merkle_path = mk_path.unwrap();
let fvk = sk.to_diversifiable_full_viewing_key().fvk().clone();
if net { if net {
let mb = main_builder.add_sapling_spend::<String>(fvk, note, merkle_path); let mb = main_builder.add_sapling_spend::<String>(&sk, note, merkle_path);
match mb { match mb {
Ok(()) => { Ok(()) => {
continue; continue;
@ -2290,7 +2228,7 @@ pub extern "C" fn rust_wrapper_create_transaction(
} }
} }
} else { } else {
let tb = test_builder.add_sapling_spend::<String>(fvk, note, merkle_path); let tb = test_builder.add_sapling_spend::<String>(&sk, note, merkle_path);
match tb { match tb {
Ok(()) => { Ok(()) => {
continue; continue;
@ -2309,11 +2247,9 @@ pub extern "C" fn rust_wrapper_create_transaction(
} }
} }
} }
let mut orch_keys = vec![];
for o_in in orch_input { for o_in in orch_input {
if o_in.sk.len() > 1 { if o_in.sk.len() > 1 {
let sp_key = SpendingKey::from_bytes(o_in.sk[0..32].try_into().unwrap()).unwrap(); let sp_key = SpendingKey::from_bytes(o_in.sk[0..32].try_into().unwrap()).unwrap();
orch_keys.push(SpendAuthorizingKey::from(&sp_key));
let pay_addr = OrchardAddress::from_raw_address_bytes(&to_array(o_in.note.recipient)).unwrap(); let pay_addr = OrchardAddress::from_raw_address_bytes(&to_array(o_in.note.recipient)).unwrap();
let rho = Rho::from_bytes(&to_array(o_in.note.rho)).unwrap(); let rho = Rho::from_bytes(&to_array(o_in.note.rho)).unwrap();
let rseed = RandomSeed::from_bytes(to_array(o_in.note.rseed.bytes), &rho).unwrap(); let rseed = RandomSeed::from_bytes(to_array(o_in.note.rseed.bytes), &rho).unwrap();
@ -2328,7 +2264,7 @@ pub extern "C" fn rust_wrapper_create_transaction(
} }
).collect())); ).collect()));
if net { if net {
let mb = main_builder.add_orchard_spend::<String>(FullViewingKey::from(&sp_key), note, merkle_path); let mb = main_builder.add_orchard_spend::<String>(&sp_key, note, merkle_path);
match mb { match mb {
Ok(()) => { Ok(()) => {
//println!("added orchard inp: {:?}", val); //println!("added orchard inp: {:?}", val);
@ -2341,7 +2277,7 @@ pub extern "C" fn rust_wrapper_create_transaction(
} }
} }
} else { } else {
let tb = test_builder.add_orchard_spend::<String>(FullViewingKey::from(&sp_key), note, merkle_path); let tb = test_builder.add_orchard_spend::<String>(&sp_key, note, merkle_path);
match tb { match tb {
Ok(()) => { Ok(()) => {
//println!("added orchard inp: {:?}", val); //println!("added orchard inp: {:?}", val);
@ -2485,9 +2421,9 @@ pub extern "C" fn rust_wrapper_create_transaction(
let output_params_reader = Cursor::new(output_params_in); let output_params_reader = Cursor::new(output_params_in);
let output_prover = OutputParameters::read(output_params_reader, false).unwrap(); let output_prover = OutputParameters::read(output_params_reader, false).unwrap();
let result = if net { let result = if net {
main_builder.build(&tss, &sap_key_array, &orch_keys, OsRng, &spend_prover, &output_prover, &FeeRule::standard()) main_builder.build(OsRng, &spend_prover, &output_prover, &FeeRule::standard())
} else { } else {
test_builder.build(&tss, &sap_key_array, &orch_keys,OsRng, &spend_prover, &output_prover, &FeeRule::standard()) test_builder.build(OsRng, &spend_prover, &output_prover, &FeeRule::standard())
}; };
match result { match result {
Ok(r) => { Ok(r) => {
@ -2565,87 +2501,3 @@ pub extern "C" fn rust_wrapper_create_transaction(
} }
} }
} }
#[no_mangle]
pub extern "C" fn rust_wrapper_create_orchard_fvk(
orch_in: *const u8,
orch_in_len: usize,
out: *mut u8,
out_len: &mut usize
){
let input: Vec<u8> = marshall_from_haskell_var(orch_in, orch_in_len, RW);
let sk = SpendingKey::from_bytes(to_array(input));
if sk.is_some().into() {
let fvk = FullViewingKey::from(&sk.unwrap());
let x = Hhex {bytes: fvk.to_bytes().to_vec()};
marshall_to_haskell_var(&x, out, out_len, RW);
} else {
let x = Hhex {bytes: vec![0]};
marshall_to_haskell_var(&x, out, out_len, RW);
}
}
#[no_mangle]
pub extern "C" fn rust_wrapper_create_orchard_ivk(
orch_in: *const u8,
orch_in_len: usize,
out: *mut u8,
out_len: &mut usize
){
let input: Vec<u8> = marshall_from_haskell_var(orch_in, orch_in_len, RW);
let sk = SpendingKey::from_bytes(to_array(input));
if sk.is_some().into() {
let fvk = FullViewingKey::from(&sk.unwrap()).to_ivk(Scope::External);
let x = Hhex {bytes: fvk.to_bytes().to_vec()};
marshall_to_haskell_var(&x, out, out_len, RW);
} else {
let x = Hhex {bytes: vec![0]};
marshall_to_haskell_var(&x, out, out_len, RW);
}
}
#[no_mangle]
pub extern "C" fn rust_wrapper_create_sapling_fvk(
sap_in: *const u8,
sap_in_len: usize,
out: *mut u8,
out_len: &mut usize
){
let input: Vec<u8> = marshall_from_haskell_var(sap_in, sap_in_len, RW);
let in_bytes: [u8; 169] = to_array(input);
let sk = ExtendedSpendingKey::from_bytes(&in_bytes);
match sk {
Ok(k) => {
let fvk = k.to_diversifiable_full_viewing_key();
let x = Hhex {bytes: fvk.to_bytes().to_vec()};
marshall_to_haskell_var(&x, out, out_len, RW);
},
Err(_e) => {
let x = Hhex {bytes: vec![0]};
marshall_to_haskell_var(&x, out, out_len, RW);
}
}
}
#[no_mangle]
pub extern "C" fn rust_wrapper_create_sapling_ivk(
sap_in: *const u8,
sap_in_len: usize,
out: *mut u8,
out_len: &mut usize
){
let input: Vec<u8> = marshall_from_haskell_var(sap_in, sap_in_len, RW);
let in_bytes: [u8; 169] = to_array(input);
let sk = ExtendedSpendingKey::from_bytes(&in_bytes);
match sk {
Ok(k) => {
let ivk = k.to_diversifiable_full_viewing_key().to_external_ivk();
let x = Hhex {bytes: ivk.to_bytes().to_vec()};
marshall_to_haskell_var(&x, out, out_len, RW);
},
Err(_e) => {
let x = Hhex {bytes: vec![0]};
marshall_to_haskell_var(&x, out, out_len, RW);
}
}
}

View file

@ -120,13 +120,6 @@ import ZcashHaskell.Types
-> `()' -> `()'
#} #}
{# fun unsafe rust_wrapper_uivk_decode as rustWrapperUivkDecode
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer UnifiedIncomingViewingKey'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_orchard_note_decrypt as rustWrapperOrchardNoteDecode {# fun unsafe rust_wrapper_orchard_note_decrypt as rustWrapperOrchardNoteDecode
{ toBorshVar* `BS.ByteString'& { toBorshVar* `BS.ByteString'&
, toBorshVar* `OrchardAction'& , toBorshVar* `OrchardAction'&
@ -417,31 +410,3 @@ import ZcashHaskell.Types
} }
-> `()' -> `()'
#} #}
{# fun unsafe rust_wrapper_create_orchard_fvk as rustWrapperCreateOrchardFvk
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_create_orchard_ivk as rustWrapperCreateOrchardIvk
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_create_sapling_fvk as rustWrapperCreateSaplingFvk
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_create_sapling_ivk as rustWrapperCreateSaplingIvk
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer HexString'&
}
-> `()'
#}

View file

@ -15,42 +15,13 @@
module ZcashHaskell.Keys where module ZcashHaskell.Keys where
import C.Zcash (rustWrapperGenSeedPhrase, rustWrapperGetSeed) import C.Zcash (rustWrapperGenSeedPhrase, rustWrapperGetSeed)
import Crypto.Secp256k1 (createContext)
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
import Data.HexString (hexBytes)
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Data.Word (Word8(..))
import Foreign.Rust.Marshall.Variable import Foreign.Rust.Marshall.Variable
( withBorshVarBuffer ( withBorshVarBuffer
, withPureBorshVarBuffer , withPureBorshVarBuffer
) )
import Haskoin.Address.Base58 (decodeBase58) import ZcashHaskell.Types (Phrase, Seed(..), ToBytes(..))
import Haskoin.Crypto.Keys.Extended
( DerivPath(..)
, DerivPathI(..)
, XPubKey(..)
, derivePath
, deriveXPubKey
, xPubExport
)
import Haskoin.Network.Constants (btc)
import ZcashHaskell.Orchard (deriveOrchardFvk, deriveOrchardIvk)
import ZcashHaskell.Sapling (deriveSaplingFvk, deriveSaplingIvk)
import ZcashHaskell.Types
( OrchardSpendingKey(..)
, Phrase
, SaplingSpendingKey(..)
, Seed(..)
, ToBytes(..)
, TransparentSpendingKey(..)
, ZcashNet(..)
, uniFullViewingKeyHrp
, uniIncomingViewingKeyHrp
, uniTestFullViewingKeyHrp
, uniTestIncomingViewingKeyHrp
)
import ZcashHaskell.Utils (encodeBech32m, f4Jumble)
-- | Generate a random seed that can be used to generate private keys for shielded addresses and transparent addresses. -- | Generate a random seed that can be used to generate private keys for shielded addresses and transparent addresses.
generateWalletSeedPhrase :: IO Phrase generateWalletSeedPhrase :: IO Phrase
@ -65,97 +36,3 @@ getWalletSeed p =
where where
result :: Seed result :: Seed
result = (withPureBorshVarBuffer . rustWrapperGetSeed) p result = (withPureBorshVarBuffer . rustWrapperGetSeed) p
-- | Derive a transparent root node for unified viewing keys
deriveFullTransparentNode :: TransparentSpendingKey -> IO BS.ByteString
deriveFullTransparentNode sk = do
ioCtx <- createContext
let tPubKey = deriveXPubKey ioCtx sk
let tPubKeyBytes = decodeBase58 $ xPubExport btc ioCtx tPubKey
case tPubKeyBytes of
Nothing -> fail "Unable to get transparent key bytes"
Just pb -> return $ BS.takeEnd 65 pb
-- | Derive a transparent incoming root node for unified incoming viewing keys
deriveIncomingTransparentNode :: TransparentSpendingKey -> IO BS.ByteString
deriveIncomingTransparentNode sk = do
ioCtx <- createContext
let path = Deriv :/ 0 :: DerivPath
let childPrvKey = derivePath ioCtx path sk
let tPubKey = deriveXPubKey ioCtx childPrvKey
let tPubKeyBytes = decodeBase58 $ xPubExport btc ioCtx tPubKey
case tPubKeyBytes of
Nothing -> fail "Unable to get transparent key bytes"
Just pb -> return $ BS.takeEnd 65 pb
-- | Derive a Unified Full Viewing Key
deriveUfvk ::
ZcashNet
-> OrchardSpendingKey
-> SaplingSpendingKey
-> TransparentSpendingKey
-> IO T.Text
deriveUfvk net okey skey tkey = do
tSec <- deriveFullTransparentNode tkey
let oSec = deriveOrchardFvk okey
let sSec = deriveSaplingFvk skey
case oSec of
Nothing -> fail "Unable to derive Orchard viewing key"
Just oSec' -> do
case sSec of
Nothing -> fail "Unable to derive Sapling viewing key"
Just sSec' ->
return $ encodeVK (hexBytes oSec') (hexBytes sSec') tSec net True
-- | Derive a Unified Incoming Viewing Key
deriveUivk ::
ZcashNet
-> OrchardSpendingKey
-> SaplingSpendingKey
-> TransparentSpendingKey
-> IO T.Text
deriveUivk net okey skey tkey = do
tSec <- deriveIncomingTransparentNode tkey
let oSec = deriveOrchardIvk okey
let sSec = deriveSaplingIvk skey
case oSec of
Nothing -> fail "Unable to derive Orchard viewing key"
Just oSec' -> do
case sSec of
Nothing -> fail "Unable to derive Sapling viewing key"
Just sSec' ->
return $ encodeVK (hexBytes oSec') (hexBytes sSec') tSec net False
-- | Encode a Unified Viewing Key per [ZIP-316](https://zips.z.cash/zip-0316)
encodeVK ::
BS.ByteString -- ^ Orchard FVK
-> BS.ByteString -- ^ Sapling FVK
-> BS.ByteString -- ^ Transparent root node
-> ZcashNet -- ^ Network
-> Bool -- ^ Full?
-> T.Text
encodeVK ovk svk tvk net full = encodeBech32m (E.encodeUtf8 hr) b
where
tReceiver = packReceiver 0x00 $ Just tvk
b = f4Jumble $ tReceiver <> sReceiver <> oReceiver <> padding
hr =
if full
then case net of
MainNet -> uniFullViewingKeyHrp
TestNet -> uniTestFullViewingKeyHrp
else case net of
MainNet -> uniIncomingViewingKeyHrp
TestNet -> uniTestIncomingViewingKeyHrp
sReceiver = packReceiver 0x02 $ Just svk
oReceiver = packReceiver 0x03 $ Just ovk
padding = E.encodeUtf8 $ T.justifyLeft 16 '\NUL' hr
packReceiver :: Word8 -> Maybe BS.ByteString -> BS.ByteString
packReceiver typeCode receiver' =
case receiver' of
Just receiver ->
if BS.length receiver > 1
then BS.singleton typeCode `BS.append`
(BS.singleton . toEnum . BS.length) receiver `BS.append`
receiver
else BS.empty
Nothing -> BS.empty

View file

@ -19,8 +19,6 @@ module ZcashHaskell.Orchard where
import C.Zcash import C.Zcash
( rustWrapperCombineOrchardNodes ( rustWrapperCombineOrchardNodes
, rustWrapperCreateOrchardFvk
, rustWrapperCreateOrchardIvk
, rustWrapperGenOrchardReceiver , rustWrapperGenOrchardReceiver
, rustWrapperGenOrchardSpendKey , rustWrapperGenOrchardSpendKey
, rustWrapperGetOrchardRootTest , rustWrapperGetOrchardRootTest
@ -39,7 +37,6 @@ import C.Zcash
, rustWrapperReadOrchardWitnessAnchor , rustWrapperReadOrchardWitnessAnchor
, rustWrapperUADecode , rustWrapperUADecode
, rustWrapperUfvkDecode , rustWrapperUfvkDecode
, rustWrapperUivkDecode
, rustWrapperUpdateOrchardWitness , rustWrapperUpdateOrchardWitness
) )
import qualified Data.ByteString as BS import qualified Data.ByteString as BS
@ -160,15 +157,6 @@ decodeUfvk str =
where where
decodedKey = (withPureBorshVarBuffer . rustWrapperUfvkDecode) str decodedKey = (withPureBorshVarBuffer . rustWrapperUfvkDecode) str
-- | Attempts to decode the given bytestring into a Unified Full Viewing Key
decodeUivk :: BS.ByteString -> Maybe UnifiedIncomingViewingKey
decodeUivk str =
case i_net decodedKey of
0 -> Nothing
_ -> Just decodedKey
where
decodedKey = (withPureBorshVarBuffer . rustWrapperUivkDecode) str
-- | Check if the given UVK matches the UA given -- | Check if the given UVK matches the UA given
matchOrchardAddress :: BS.ByteString -> BS.ByteString -> Bool matchOrchardAddress :: BS.ByteString -> BS.ByteString -> Bool
matchOrchardAddress = rustWrapperOrchardCheck matchOrchardAddress = rustWrapperOrchardCheck
@ -349,25 +337,3 @@ compareAddress a u =
Sapling s -> s_rec u == Just (sa_receiver s) && ua_net u == net_type s Sapling s -> s_rec u == Just (sa_receiver s) && ua_net u == net_type s
Transparent t -> t_rec u == Just (ta_receiver t) && ua_net u == ta_network t Transparent t -> t_rec u == Just (ta_receiver t) && ua_net u == ta_network t
Exchange x -> False Exchange x -> False
-- | Derive an Orchard Full Viewing Key
deriveOrchardFvk ::
OrchardSpendingKey -- ^ The Orchard spending key
-> Maybe HexString
deriveOrchardFvk sk =
if BS.length (hexBytes r) > 1
then Just r
else Nothing
where
r = withPureBorshVarBuffer $ rustWrapperCreateOrchardFvk $ getBytes sk
-- | Derive an Orchard Incoming Viewing Key
deriveOrchardIvk ::
OrchardSpendingKey -- ^ The Orchard spending key
-> Maybe HexString
deriveOrchardIvk sk =
if BS.length (hexBytes r) > 1
then Just r
else Nothing
where
r = withPureBorshVarBuffer $ rustWrapperCreateOrchardIvk $ getBytes sk

View file

@ -19,8 +19,6 @@ module ZcashHaskell.Sapling where
import C.Zcash import C.Zcash
( rustWrapperCombineSaplingNodes ( rustWrapperCombineSaplingNodes
, rustWrapperCreateSaplingFvk
, rustWrapperCreateSaplingIvk
, rustWrapperDecodeSaplingAddress , rustWrapperDecodeSaplingAddress
, rustWrapperGetSaplingRootTest , rustWrapperGetSaplingRootTest
, rustWrapperIsShielded , rustWrapperIsShielded
@ -320,25 +318,3 @@ decodeSaplingAddress sapling_address = do
where where
sa = sa =
withPureBorshVarBuffer $ rustWrapperDecodeSaplingAddress sapling_address withPureBorshVarBuffer $ rustWrapperDecodeSaplingAddress sapling_address
-- | Derive a Sapling Full Viewing Key
deriveSaplingFvk ::
SaplingSpendingKey -- ^ The Sapling spending key
-> Maybe HexString
deriveSaplingFvk sk =
if BS.length (hexBytes r) > 1
then Just r
else Nothing
where
r = withPureBorshVarBuffer $ rustWrapperCreateSaplingFvk $ getBytes sk
-- | Derive a Sapling Incoming Viewing Key
deriveSaplingIvk ::
SaplingSpendingKey -- ^ The Sapling spending key
-> Maybe HexString
deriveSaplingIvk sk =
if BS.length (hexBytes r) > 1
then Just r
else Nothing
where
r = withPureBorshVarBuffer $ rustWrapperCreateSaplingIvk $ getBytes sk

View file

@ -268,10 +268,10 @@ instance FromJSON BlockResponse where
withObject "BlockResponse" $ \obj -> do withObject "BlockResponse" $ \obj -> do
c <- obj .: "confirmations" c <- obj .: "confirmations"
h <- obj .: "height" h <- obj .: "height"
t <- obj .: "time" t <- obj .:? "time"
txs <- obj .: "tx" txs <- obj .: "tx"
hash <- obj .: "hash" hash <- obj .: "hash"
pure $ BlockResponse hash c h t txs pure $ BlockResponse hash c h (fromMaybe 0 t) txs
instance ToJSON BlockResponse where instance ToJSON BlockResponse where
toJSON (BlockResponse h c ht t txs) = toJSON (BlockResponse h c ht t txs) =
@ -696,18 +696,6 @@ data UnifiedFullViewingKey = UnifiedFullViewingKey
deriving anyclass (Data.Structured.Show) deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct UnifiedFullViewingKey deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct UnifiedFullViewingKey
-- | Type to represent a Unified Incoming Viewing Key
data UnifiedIncomingViewingKey = UnifiedIncomingViewingKey
{ i_net :: !Word8 -- ^ Number representing the network the key belongs to. @1@ for @mainnet@, @2@ for @testnet@ and @3@ for @regtestnet@.
, i_o_key :: !BS.ByteString -- ^ Raw bytes of the Orchard Incoming Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
, i_s_key :: !BS.ByteString -- ^ Raw bytes of the Sapling Incoming Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
, i_t_key :: !BS.ByteString -- ^ Raw bytes of the P2PKH chain code and public key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct
UnifiedIncomingViewingKey
-- | Type to represent an Orchard Action as provided by the @getrawtransaction@ RPC method of @zcashd@, and defined in the [Zcash Protocol](https://zips.z.cash/protocol/protocol.pdf) -- | Type to represent an Orchard Action as provided by the @getrawtransaction@ RPC method of @zcashd@, and defined in the [Zcash Protocol](https://zips.z.cash/protocol/protocol.pdf)
data OrchardAction = OrchardAction data OrchardAction = OrchardAction
{ nf :: !HexString -- ^ The nullifier of the input note { nf :: !HexString -- ^ The nullifier of the input note

View file

@ -45,12 +45,7 @@ import Test.HUnit
import Test.Hspec import Test.Hspec
import Test.Hspec.QuickCheck import Test.Hspec.QuickCheck
import Test.QuickCheck import Test.QuickCheck
import ZcashHaskell.Keys import ZcashHaskell.Keys (generateWalletSeedPhrase, getWalletSeed)
( deriveUfvk
, deriveUivk
, generateWalletSeedPhrase
, getWalletSeed
)
import ZcashHaskell.Orchard import ZcashHaskell.Orchard
import ZcashHaskell.Sapling import ZcashHaskell.Sapling
( decodeSaplingAddress ( decodeSaplingAddress
@ -1167,33 +1162,77 @@ main = do
Just addr -> do Just addr -> do
let eadr = decodeExchangeAddress (E.encodeUtf8 addr) let eadr = decodeExchangeAddress (E.encodeUtf8 addr)
eadr `shouldNotBe` Nothing eadr `shouldNotBe` Nothing
describe "Generate Viewing Keys" $ do describe "Tree updates" $ do
let p = it "Orchard" $ do
Phrase let tree =
"cloth swing left trap random tornado have great onion element until make shy dad success art tuition canvas thunder apple decade elegant struggle invest" OrchardCommitmentTree $
let seed = getWalletSeed p hexString
let oK = genOrchardSpendingKey (fromJust seed) MainNetCoin 0 "0136a7886d7d73bc1845223165fd9cb0cef02046c707e8f88a7f61564720bd0f3501dca1fbdd7b5ba92a0809af5e85874626ce0db14d0532a48e41dde6f0f81b46011f0001fb48c27bd07e68f27aba47cd6e93fa961e0ef8c63f993963a614e56855d2013c0001ea572db9c5c2d24c7ad9132ae32b27179466bf67a580d59901d13b281d3f530b01c160348f10b9ad893d9731317ebe36ac8665e01c52cbe15a56aa9b72e4e6c41e000001cd7695156de2debdc5b13ea84d32e4e3ac020fb0aa7cd372c57ce765103bd70401746e6bc066a10e7f80a9ff8993dcb25c819edd64f2ca10ac248ef7848d41450500011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000"
let sK = genSaplingSpendingKey (fromJust seed) MainNetCoin 0 let cmx1 =
it "Generate FVK" $ do hexString
tK <- genTransparentPrvKey (fromJust seed) MainNetCoin 0 "1712ead46028d4349e234abf59e94e0640fe7a0829e2e2e17e1a931631810400"
case oK of let cmx2 =
Nothing -> assertFailure "Failed to generate Orchard SK" hexString
Just o -> "39f5ad39817fb432fa07c5feb3a957189fbe7662a4b5555ca95093b6d853cf07"
case sK of let cmx3 =
Nothing -> assertFailure "Failed to generate Sapling SK" hexString
Just s -> do "84f7fbc4b9f87215c653078d7fdd90756c3ba370c745065167da9eb73a65a83f"
fvk <- deriveUfvk MainNet o s tK let cmx4 =
decodeUfvk (E.encodeUtf8 fvk) `shouldNotBe` Nothing hexString
it "Generate IVK" $ do "e55ad64e1ea2b261893fdea6ad0509b66e5f62d3142f351298c7135c4498d429"
tK <- genTransparentPrvKey (fromJust seed) MainNetCoin 0 let finalTree =
case oK of getOrchardFrontier $
Nothing -> assertFailure "Failed to generate Orchard SK" OrchardCommitmentTree $
Just o -> hexString
case sK of "0184f7fbc4b9f87215c653078d7fdd90756c3ba370c745065167da9eb73a65a83f01e55ad64e1ea2b261893fdea6ad0509b66e5f62d3142f351298c7135c4498d4291f0000014b1a76d3820087b26cd087ca84e17f3067a25ebed82ad23a93fa485affb5530b01ea572db9c5c2d24c7ad9132ae32b27179466bf67a580d59901d13b281d3f530b01c160348f10b9ad893d9731317ebe36ac8665e01c52cbe15a56aa9b72e4e6c41e000001cd7695156de2debdc5b13ea84d32e4e3ac020fb0aa7cd372c57ce765103bd70401746e6bc066a10e7f80a9ff8993dcb25c819edd64f2ca10ac248ef7848d41450500011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000"
Nothing -> assertFailure "Failed to generate Sapling SK" case getOrchardFrontier tree of
Just s -> do Nothing -> assertFailure "Failed to get frontier"
ivk <- deriveUivk MainNet o s tK Just t1 ->
decodeUivk (E.encodeUtf8 ivk) `shouldNotBe` Nothing case updateOrchardCommitmentTree t1 cmx1 of
Nothing -> assertFailure "Failed to update frontier with cmx"
Just t2 -> do
case getOrchardWitness t2 of
Nothing -> assertFailure "Failed to get witness"
Just wit -> do
let uWit = updateOrchardWitness wit [cmx2, cmx3, cmx4]
Just (getOrchardWitnessAnchor uWit) `shouldBe`
getOrchardTreeAnchor <$>
finalTree
describe "Witness updates" $ do
it "Sapling" $ do
let wit =
SaplingWitness $
hexString
"01bd8a3f3cfc964332a2ada8c09a0da9dfc24174befb938abb086b9be5ca049e49013607f5e51826c8e5f660571ddfae14cd6fb1dc026bcd6855459b4e9339b20521100000019f0d7efb00169bb2202152d3266059d208ab17d14642c3339f9075e997160657000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39038cd7f6e2238d16ef49420963348dd4e4c7d23d5e5dac69507fba8937f63eb626f6856115bea2fa8db3a65a0ab294db41c51435d3b7ea27c7b2835aca28e82a2c1d9634efe07449a47c251518ac6f92c49f3a1ef119948f6a824d1e7ff7d0443e0101e57ec972a9b9383dc9cb228980d2d7752bb2abebc4a604ca48c5457039d2e05b000301392bed8592185dde5ab7fc81aed75e98fcf041f1a3fda55ad0b0b139ba9380130001808304b4d7c4fc407f5ce28247a7119013aeaaf1481902419c42bc8b21575c15"
let cmus =
[ hexString
"958ccdc752f2f593f6c1c8e2d7201348cd896e54c6d3c92200bdbe8b859eac44"
, hexString
"e49992fdd071d90bf56242d1aa625bbe267a34e0debd4307818a686d05b45447"
, hexString
"0c4b26766d89bf6cdb4fd3b0317b4e9a2fb3850f6a24869f32fe7cb0fd512e18"
]
updateSaplingWitness wit cmus `shouldBe`
SaplingWitness
(hexString
"01bd8a3f3cfc964332a2ada8c09a0da9dfc24174befb938abb086b9be5ca049e49013607f5e51826c8e5f660571ddfae14cd6fb1dc026bcd6855459b4e9339b20521100000019f0d7efb00169bb2202152d3266059d208ab17d14642c3339f9075e997160657000000012f4f72c03f8c937a94919a01a07f21165cc8394295291cb888ca91ed003810390107114fe4bb4cd08b47f6ae47477c182d5da9fe5c189061808c1091e9bf3b4524000001447d6b9100cddd5f80c8cf4ddee2b87eba053bd987465aec2293bd0514e68b0d015f6c95e75f4601a0a31670a7deb970fc8988c611685161d2e1629d0a1a0ebd07015f8b9205e0514fa235d75c150b87e23866b882b39786852d1ab42aab11d31a4a0117ddeb3a5f8d2f6b2d0a07f28f01ab25e03a05a9319275bb86d72fcaef6fc01501f08f39275112dd8905b854170b7f247cf2df18454d4fa94e6e4f9320cca05f24011f8322ef806eb2430dc4a7a41c1b344bea5be946efc7b4349c1c9edb14ff9d39038cd7f6e2238d16ef49420963348dd4e4c7d23d5e5dac69507fba8937f63eb626f6856115bea2fa8db3a65a0ab294db41c51435d3b7ea27c7b2835aca28e82a2c1d9634efe07449a47c251518ac6f92c49f3a1ef119948f6a824d1e7ff7d0443e0101e49992fdd071d90bf56242d1aa625bbe267a34e0debd4307818a686d05b45447010c4b26766d89bf6cdb4fd3b0317b4e9a2fb3850f6a24869f32fe7cb0fd512e1803000121c06ee1f1584f79d50785797a694c742be2ded600367ab7d54f3ed49e3adf7201808304b4d7c4fc407f5ce28247a7119013aeaaf1481902419c42bc8b21575c15")
it "Orchard" $ do
let wit =
OrchardWitness $
hexString
"016225b41339a00dd764b452fca190a0245e7118224965942e3a6d798365c34631001f0000011d6f5da3f619bfaab957fc643c17eb144db0101c90f422da2fcbe0e80d74412e000000000001746e6bc066a10e7f80a9ff8993dcb25c819edd64f2ca10ac248ef7848d41450500011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000040e02c864db8b574f165f616d48e2f12eb25099b5c90186af26d9e50f5058863e0504bfbc12edc35e05042c16bbfb8fed591f01f18fe128eeb57f2c456c9eb222d6d261c549e95d9007bce4c6ae0b86bc865711cdd9f0fa92e2d5b5e149b51f3be127df3b1d2372adf6c811b2e456c1d64d0e9eb167a995f9c6b66a03c9cbda250101c094201bae3b4ef582a3e8654f65a72fbd41e20e1ec9a43d3f4101afc868731e000200019df5b9366d0f21caa678d1567390b5bfd3cfa0438271bcfe301b5558a2863301"
let cmxs =
[ hexString
"712ba86615ff4447e8d7c7b59f3873f03c03a173438b8e4c8d416756ed4fae10"
, hexString
"c094201bae3b4ef582a3e8654f65a72fbd41e20e1ec9a43d3f4101afc868731e"
, hexString
"ac20b8170b008888c19fc6e16f5e30a5ef1653e5219d0cd0c9353c3aa8f79823"
]
updateOrchardWitness wit cmxs `shouldBe`
OrchardWitness
(hexString
"016225b41339a00dd764b452fca190a0245e7118224965942e3a6d798365c34631001f0000011d6f5da3f619bfaab957fc643c17eb144db0101c90f422da2fcbe0e80d74412e000000000001746e6bc066a10e7f80a9ff8993dcb25c819edd64f2ca10ac248ef7848d41450500011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000040e02c864db8b574f165f616d48e2f12eb25099b5c90186af26d9e50f5058863e0504bfbc12edc35e05042c16bbfb8fed591f01f18fe128eeb57f2c456c9eb222d6d261c549e95d9007bce4c6ae0b86bc865711cdd9f0fa92e2d5b5e149b51f3be127df3b1d2372adf6c811b2e456c1d64d0e9eb167a995f9c6b66a03c9cbda250101c094201bae3b4ef582a3e8654f65a72fbd41e20e1ec9a43d3f4101afc868731e01ac20b8170b008888c19fc6e16f5e30a5ef1653e5219d0cd0c9353c3aa8f7982302010cfb50d8c877eb39e9c07082a032dd99d34be7c19fa7f30e9fecf5f14736240f019df5b9366d0f21caa678d1567390b5bfd3cfa0438271bcfe301b5558a2863301")
-- | Properties -- | Properties
prop_PhraseLength :: Property prop_PhraseLength :: Property

View file

@ -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.7.8.1 version: 0.7.5.0
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