From 8901d97c64559047700ede55d44849360efb4bb7 Mon Sep 17 00:00:00 2001 From: Rene Vergara Date: Mon, 29 Apr 2024 10:27:45 -0500 Subject: [PATCH] Upgrade of Zcash Rust crates --- CHANGELOG.md | 16 ++++ librustzcash-wrapper/Cargo.lock | 157 ++++++++++++++++++++++++++++---- librustzcash-wrapper/Cargo.toml | 7 +- librustzcash-wrapper/src/lib.rs | 142 +++++++++++++++-------------- src/C/Zcash.chs | 6 +- src/ZcashHaskell/Sapling.hs | 6 +- src/ZcashHaskell/Types.hs | 9 +- test/Spec.hs | 56 +++++++++++- zcash-haskell.cabal | 2 +- 9 files changed, 297 insertions(+), 104 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c13f62..f1a6082 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ 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/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.6.0.0] + +### Added + +- Rust crates: + - `sapling-crypto` 0.1.3 + +### Changed + +- Modified handling of `ShieldedOutput`s based on new Rust crates +- Upgraded Rust crates: + - `orchard` to 0.7.1 + - `zcash_primitives` to 0.14.0 + - `zcash_client_backend` to 0.11.1 + + ## [0.5.5.4] ### Added diff --git a/librustzcash-wrapper/Cargo.lock b/librustzcash-wrapper/Cargo.lock index 6a172d0..afcddf1 100644 --- a/librustzcash-wrapper/Cargo.lock +++ b/librustzcash-wrapper/Cargo.lock @@ -88,6 +88,27 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" +[[package]] +name = "bellman" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afceed28bac7f9f5a508bca8aeeff51cdfa4770c0b967ac55c621e2ddfd6171" +dependencies = [ + "bitvec", + "blake2s_simd", + "byteorder", + "crossbeam-channel", + "ff", + "group", + "lazy_static", + "log", + "num_cpus", + "pairing", + "rand_core", + "rayon", + "subtle", +] + [[package]] name = "bincode" version = "1.3.3" @@ -468,6 +489,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + [[package]] name = "either" version = "1.8.1" @@ -711,9 +741,9 @@ dependencies = [ [[package]] name = "incrementalmerkletree" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361c467824d4d9d4f284be4b2608800839419dccc4d4608f28345237fe354623" +checksum = "eb1872810fb725b06b8c153dde9e86f3ec26747b9b60096da7a869883b549cbe" dependencies = [ "either", ] @@ -807,6 +837,12 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + [[package]] name = "log" version = "0.4.19" @@ -935,9 +971,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "orchard" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d31e68534df32024dcc89a8390ec6d7bef65edd87d91b45cfb481a2eb2d77c5" +checksum = "1fb255c3ffdccd3c84fe9ebed72aef64fdc72e6a3e4180dd411002d47abaad42" dependencies = [ "aes", "bitvec", @@ -959,6 +995,8 @@ dependencies = [ "subtle", "tracing", "zcash_note_encryption", + "zcash_spec", + "zip32", ] [[package]] @@ -1218,6 +1256,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "redjubjub" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a60db2c3bc9c6fd1e8631fee75abc008841d27144be744951d6b9b75f9b569c" +dependencies = [ + "rand_core", + "reddsa", + "serde", + "thiserror", + "zeroize", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -1288,6 +1339,7 @@ dependencies = [ "nonempty", "orchard", "proc-macro2", + "sapling-crypto", "zcash_address 0.2.0", "zcash_client_backend", "zcash_note_encryption", @@ -1295,6 +1347,38 @@ dependencies = [ "zip32", ] +[[package]] +name = "sapling-crypto" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f4270033afcb0c74c5c7d59c73cfd1040367f67f224fe7ed9a919ae618f1b7" +dependencies = [ + "aes", + "bellman", + "bitvec", + "blake2b_simd", + "blake2s_simd", + "bls12_381", + "byteorder", + "document-features", + "ff", + "fpe", + "group", + "hex", + "incrementalmerkletree", + "jubjub", + "lazy_static", + "memuse", + "rand", + "rand_core", + "redjubjub", + "subtle", + "tracing", + "zcash_note_encryption", + "zcash_spec", + "zip32", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1356,9 +1440,9 @@ dependencies = [ [[package]] name = "shardtree" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19f96dde3a8693874f7e7c53d95616569b4009379a903789efbd448f4ea9cc7" +checksum = "dbf20c7a2747d9083092e3a3eeb9a7ed75577ae364896bebbc5e0bdcd4e97735" dependencies = [ "bitflags 2.4.2", "either", @@ -1701,24 +1785,27 @@ dependencies = [ [[package]] name = "zcash_client_backend" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6a382af39be9ee5a3788157145c404b7cd19acc440903f6c34b09fb44f0e991" +checksum = "001ec65dc2828ee648dc6d29f0944d7a877fe68ad06e001a203c11770ab1b3d4" dependencies = [ "base64", "bech32 0.9.1", "bls12_381", "bs58 0.5.0", "crossbeam-channel", + "document-features", "group", "hex", "incrementalmerkletree", "memuse", "nom", - "orchard", + "nonempty", "percent-encoding", "prost", + "rand_core", "rayon", + "sapling-crypto", "secrecy", "shardtree", "subtle", @@ -1728,8 +1815,10 @@ dependencies = [ "which", "zcash_address 0.3.1", "zcash_encoding", + "zcash_keys", "zcash_note_encryption", "zcash_primitives", + "zip32", ] [[package]] @@ -1742,6 +1831,29 @@ dependencies = [ "nonempty", ] +[[package]] +name = "zcash_keys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f22d3407fdd6992b49f037f23862ab376be6013be6f2d0bc85948a635edc1f5" +dependencies = [ + "bech32 0.9.1", + "bls12_381", + "bs58 0.5.0", + "document-features", + "group", + "memuse", + "nonempty", + "rand_core", + "sapling-crypto", + "subtle", + "tracing", + "zcash_address 0.3.1", + "zcash_encoding", + "zcash_primitives", + "zip32", +] + [[package]] name = "zcash_note_encryption" version = "0.4.0" @@ -1757,17 +1869,15 @@ dependencies = [ [[package]] name = "zcash_primitives" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d17e4c94ca8d69d2fcf2be97522da5732a580eb2125cda3b150761952f8df8e6" +checksum = "9070e084570bb78aed4f8d71fd6254492e62c87a5d01e084183980e98117092d" dependencies = [ "aes", "bip0039", - "bitvec", "blake2b_simd", - "blake2s_simd", - "bls12_381", "byteorder", + "document-features", "equihash", "ff", "fpe", @@ -1775,17 +1885,30 @@ dependencies = [ "hex", "incrementalmerkletree", "jubjub", - "lazy_static", "memuse", "nonempty", "orchard", "rand", "rand_core", + "redjubjub", + "sapling-crypto", "sha2 0.10.6", "subtle", + "tracing", "zcash_address 0.3.1", "zcash_encoding", "zcash_note_encryption", + "zcash_spec", + "zip32", +] + +[[package]] +name = "zcash_spec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a3bf58b673cb3dacd8ae09ba345998923a197ab0da70d6239d8e8838949e9b" +dependencies = [ + "blake2b_simd", ] [[package]] @@ -1810,9 +1933,9 @@ dependencies = [ [[package]] name = "zip32" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d724a63be4dfb50b7f3617e542984e22e4b4a5b8ca5de91f55613152885e6b22" +checksum = "4226d0aee9c9407c27064dfeec9d7b281c917de3374e1e5a2e2cfad9e09de19e" dependencies = [ "blake2b_simd", "memuse", diff --git a/librustzcash-wrapper/Cargo.toml b/librustzcash-wrapper/Cargo.toml index 73ee84c..5ae9b85 100644 --- a/librustzcash-wrapper/Cargo.toml +++ b/librustzcash-wrapper/Cargo.toml @@ -11,10 +11,11 @@ f4jumble = "0.1" zcash_address = "0.2.0" borsh = "0.10" bech32 = "0.11" -orchard = "0.6.0" +orchard = "0.7.1" zcash_note_encryption = "0.4.0" -zcash_primitives = "0.13.0" -zcash_client_backend = "0.10.0" +zcash_primitives = "0.14.0" +zcash_client_backend = "0.11.1" +sapling-crypto = "0.1.3" zip32 = "0.1.0" proc-macro2 = "1.0.66" nonempty = "0.7.0" diff --git a/librustzcash-wrapper/src/lib.rs b/librustzcash-wrapper/src/lib.rs index 985c3c4..4c43d75 100644 --- a/librustzcash-wrapper/src/lib.rs +++ b/librustzcash-wrapper/src/lib.rs @@ -6,8 +6,7 @@ use std::{ marker::PhantomData, io::{ Write, - Cursor, - Error + Cursor }, }; @@ -29,7 +28,40 @@ use incrementalmerkletree::{ witness::IncrementalWitness }; -use zip32; +use zip32::{ + Scope as SaplingScope, + ChildIndex +}; + + +use sapling_crypto::{ + NOTE_COMMITMENT_TREE_DEPTH as SAPLING_DEPTH, + Node, + MerklePath, + PaymentAddress, + value::ValueCommitment as SaplingValueCommitment, + note::ExtractedNoteCommitment as SaplingNoteCommitment, + keys::{ + PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey, + ExpandedSpendingKey, + FullViewingKey as SaplingFullViewingKey + }, + note_encryption::{ + SaplingDomain, + Zip212Enforcement + }, + bundle::{ + GrothProofBytes, + OutputDescription, + SpendDescription, + Authorized as SaplingAuthorized, + Bundle as SaplingBundle + }, + zip32::{ + sapling_find_address, + DiversifierKey + } +}; use zcash_primitives::{ merkle_tree::{ @@ -38,12 +70,6 @@ use zcash_primitives::{ read_incremental_witness, write_incremental_witness }, - zip32::{ - Scope as SaplingScope, - ChildIndex, - sapling_find_address, - sapling::DiversifierKey - }, zip339::{Count, Mnemonic}, transaction::components::{ amount::Amount, @@ -53,28 +79,8 @@ use zcash_primitives::{ TxOut, OutPoint, Authorized - }, - sapling::{ - GrothProofBytes, - OutputDescription, - SpendDescription, - Authorized as SaplingAuthorized, - Bundle as SaplingBundle } }, - sapling::{ - Node, - MerklePath, - NOTE_COMMITMENT_TREE_DEPTH as SAPLING_DEPTH, - PaymentAddress, - note::ExtractedNoteCommitment as SaplingNoteCommitment, - keys::{ - PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey, - ExpandedSpendingKey, - FullViewingKey as SaplingFullViewingKey - }, - note_encryption::SaplingDomain - }, transaction::Transaction, consensus::{ BranchId::Nu5, @@ -99,7 +105,6 @@ use zcash_client_backend::keys::sapling::{ }; use zcash_primitives::zip32::DiversifierIndex; -use zcash_primitives::block::BlockHeader; use orchard::{ Bundle as OrchardBundle, @@ -161,7 +166,7 @@ impl ToHaskell for HrawTx { #[derive(BorshSerialize, BorshDeserialize)] pub struct HshieldedOutput { - cv: Hhex, + pub cv: Hhex, cmu: Hhex, eph_key: Hhex, enc_txt: Hhex, @@ -194,6 +199,13 @@ impl HshieldedOutput { } return r } + pub fn to_output_description(&mut self) -> Result> { + let cv = SaplingValueCommitment::from_bytes_not_small_order(&to_array(self.cv.bytes.clone())).unwrap(); + let cmu = SaplingNoteCommitment::from_bytes(&to_array(self.cmu.bytes.clone())).unwrap(); + let eph_key = zcash_note_encryption::EphemeralKeyBytes::from(to_array(self.eph_key.bytes.clone())); + let x = OutputDescription::from_parts(cv, cmu, eph_key, to_array(self.enc_txt.bytes.clone()), to_array(self.out_txt.bytes.clone()), to_array(self.proof.bytes.clone())); + return Ok(x) + } } #[derive(BorshSerialize, BorshDeserialize)] @@ -400,10 +412,9 @@ impl ToHaskell for HSBundle { } impl HSBundle { - pub fn from_bundle(sb: &SaplingBundle) -> HSBundle { - let mut s: Vec = Vec::new(); - sb.authorization().binding_sig.write(&mut s).unwrap(); - return HSBundle {empty: false, spends: Hspend::pack(sb.shielded_spends()) , outputs: HshieldedOutput::pack(sb.shielded_outputs()) , value: i64::from(sb.value_balance()) , sig: s } + pub fn from_bundle(sb: &SaplingBundle) -> HSBundle { + let sig = <[u8; 64]>::from(sb.authorization().binding_sig); + return HSBundle {empty: false, spends: Hspend::pack(sb.shielded_spends()) , outputs: HshieldedOutput::pack(sb.shielded_outputs()) , value: i64::from(sb.value_balance()) , sig: sig.to_vec()} } } @@ -428,11 +439,9 @@ impl Hspend { pub fn pack(sp: &[SpendDescription]) -> Vec { let mut r = Vec::new(); for s in sp { - let mut rk = Vec::new(); - let mut authsig = Vec::new(); - s.rk().write(&mut rk).unwrap(); - s.spend_auth_sig().write(&mut authsig).unwrap(); - r.push(Hspend {cv: Hhex{bytes:s.cv().to_bytes().to_vec()}, anchor: Hhex{bytes:s.anchor().to_bytes().to_vec()}, nullifier: Hhex{bytes:s.nullifier().to_vec()}, rk: Hhex{bytes: rk}, proof: Hhex{bytes:s.zkproof().to_vec()}, authsig: Hhex{bytes:authsig}}); + let rk = s.rk().clone(); + let sig = s.spend_auth_sig().clone(); + r.push(Hspend {cv: Hhex{bytes:s.cv().to_bytes().to_vec()}, anchor: Hhex{bytes:s.anchor().to_bytes().to_vec()}, nullifier: Hhex{bytes:s.nullifier().to_vec()}, rk: Hhex{bytes: <[u8; 32]>::from(rk).to_vec()}, proof: Hhex{bytes:s.zkproof().to_vec()}, authsig: Hhex{bytes: <[u8; 64]>::from(sig).to_vec()}}); } return r } @@ -654,10 +663,10 @@ pub extern "C" fn rust_wrapper_svk_check_address( let sa = PaymentAddress::from_bytes(&to_array(address_input)).unwrap(); match svk { Ok(k) => { - let (div_index, def_address) = k.default_address(); + let (_div_index, def_address) = k.default_address(); sa == def_address } - Err(e) => { + Err(_e) => { false } } @@ -740,11 +749,10 @@ pub extern "C" fn rust_wrapper_sapling_esk_decrypt( out_len: &mut usize ){ let sk: Vec = marshall_from_haskell_var(key, key_len, RW); - let note_input: Vec = marshall_from_haskell_var(note,note_len,RW); - let mut note_reader = Cursor::new(note_input); + let mut note_input: HshieldedOutput = marshall_from_haskell_var(note,note_len,RW); let esk = ExtendedSpendingKey::from_bytes(&sk); - let main_domain = SaplingDomain::for_height(MainNetwork, BlockHeight::from_u32(2000000)); - let test_domain = SaplingDomain::for_height(TestNetwork, BlockHeight::from_u32(2000000)); + let main_domain = SaplingDomain::new(Zip212Enforcement::On); + //let test_domain = SaplingDomain::for_height(TestNetwork, BlockHeight::from_u32(2000000)); let scope = if external { SaplingScope::External } else { @@ -752,15 +760,14 @@ pub extern "C" fn rust_wrapper_sapling_esk_decrypt( }; match esk { Ok(k) => { - let action = OutputDescription::read(&mut note_reader); - match action { + let action = note_input.to_output_description(); + match action { Ok(action2) => { let dfvk = k.to_diversifiable_full_viewing_key(); let ivk = dfvk.to_ivk(scope); let nk = dfvk.to_nk(scope); let pivk = SaplingPreparedIncomingViewingKey::new(&ivk); - let result = if net { zcash_note_encryption::try_note_decryption(&main_domain, &pivk, &action2)} - else {zcash_note_encryption::try_note_decryption(&test_domain, &pivk, &action2)}; + let result = zcash_note_encryption::try_note_decryption(&main_domain, &pivk, &action2); match result { Some((n, r, m)) => { let nullifier = n.nf(&nk, pos); @@ -796,13 +803,12 @@ pub extern "C" fn rust_wrapper_sapling_note_decrypt_v2( out_len: &mut usize ){ let evk: Vec = marshall_from_haskell_var(key, key_len, RW); - let note_input: Vec = marshall_from_haskell_var(note,note_len,RW); - let mut note_reader = Cursor::new(note_input); + let mut note_input: HshieldedOutput = marshall_from_haskell_var(note,note_len,RW); let svk = ExtendedFullViewingKey::read(&*evk); match svk { Ok(k) => { - let domain = SaplingDomain::for_height(MainNetwork, BlockHeight::from_u32(2000000)); - let action2 = OutputDescription::read(&mut note_reader); + let domain = SaplingDomain::new(Zip212Enforcement::On); + let action2 = note_input.to_output_description(); match action2 { Ok(action3) => { let fvk = k.to_diversifiable_full_viewing_key().to_ivk(SaplingScope::External); @@ -976,22 +982,14 @@ pub extern "C" fn rust_wrapper_tx_parse( out_len: &mut usize ){ let tx_input: Vec = marshall_from_haskell_var(tx, tx_len, RW); - let tx_bytes: Vec = tx_input.clone(); let mut tx_reader = Cursor::new(tx_input); - let s_o = false; - let o_a = false; let parsed_tx = Transaction::read(&mut tx_reader, Nu5); match parsed_tx { Ok(t) => { let s_bundle = t.sapling_bundle(); match s_bundle { Some(b) => { - let mut s_output = Vec::new(); - for s_each_out in b.shielded_outputs().iter() { - let mut out_bytes = Vec::new(); - let _ = s_each_out.write_v4(&mut out_bytes); - s_output.push(out_bytes); - } + let s_output = HshieldedOutput::pack(b.shielded_outputs()); marshall_to_haskell_var(&s_output, out, out_len, RW); }, None => { @@ -1067,7 +1065,7 @@ pub extern "C" fn rust_wrapper_sapling_paymentaddress( let sp_key = ExtendedSpendingKey::from_bytes(&extspk); match sp_key { Ok(sp_key_x) => { - let (def_div, def_address) = sp_key_x.default_address(); + let (_def_div, def_address) = sp_key_x.default_address(); marshall_to_haskell_var(&def_address.to_bytes().to_vec(), out, out_len, RW); }, Err(_e) => { @@ -1102,14 +1100,14 @@ pub extern "C" fn rust_wrapper_sapling_chgpaymentaddress( let extspku8 : &[u8] = &vexspkp; let extspk = match ExtendedSpendingKey::from_bytes(&extspku8) { Ok( k ) => k, - Err( e ) => { + Err( _e ) => { // error recovering ExtendedSpendingKey marshall_to_haskell_var(&vec![0], out, out_len, RW); return } }; let dfvk = extspk.to_diversifiable_full_viewing_key(); - let ( divIx, cPmtAddress ) = dfvk.change_address(); + let ( _divIx, cPmtAddress ) = dfvk.change_address(); marshall_to_haskell_var(&cPmtAddress.to_bytes().to_vec(), out, out_len, RW); } @@ -1123,7 +1121,7 @@ pub extern "C" fn rust_wrapper_derive_orchard_spending_key( out_len: &mut usize ){ let s: Vec = marshall_from_haskell_var(seed, seed_len, RW); - let sk = SpendingKey::from_zip32_seed(&s, coin_type, u32::from(zip32::AccountId::try_from(acc_id).unwrap())); + let sk = SpendingKey::from_zip32_seed(&s, coin_type, zip32::AccountId::try_from(acc_id).unwrap()); match sk { Ok(key) => { marshall_to_haskell_var(&key.to_bytes().to_vec(), out, out_len, RW); @@ -1441,7 +1439,7 @@ pub extern "C" fn rust_wrapper_decode_sapling_address( let out_bytes: Vec = out_bytes_temp.to_vec(); marshall_to_haskell_var(&out_bytes, out, out_len, RW); } - Err(e) => { + Err(_e) => { let h = vec![0]; marshall_to_haskell_var(&h, out, out_len, RW); } @@ -1453,3 +1451,11 @@ pub extern "C" fn rust_wrapper_decode_sapling_address( } } } + +#[no_mangle] +pub extern "C" fn rust_wrapper_create_transaction( + sapling: *const u8, + sapling_len: usize, + out: *mut u8, + out_len: &mut usize){ +} diff --git a/src/C/Zcash.chs b/src/C/Zcash.chs index 0300865..6e0dff8 100644 --- a/src/C/Zcash.chs +++ b/src/C/Zcash.chs @@ -96,7 +96,7 @@ import ZcashHaskell.Types {# fun unsafe rust_wrapper_sapling_note_decrypt_v2 as rustWrapperSaplingNoteDecode { toBorshVar* `BS.ByteString'& - , toBorshVar* `BS.ByteString'& + , toBorshVar* `ShieldedOutput'& , getVarBuffer `Buffer DecodedNote'& } -> `()' @@ -104,7 +104,7 @@ import ZcashHaskell.Types {# fun unsafe rust_wrapper_sapling_esk_decrypt as rustWrapperSaplingDecodeEsk { toBorshVar* `BS.ByteString'& - , toBorshVar* `BS.ByteString'& + , toBorshVar* `ShieldedOutput'& , `Bool' , `Bool' , `Word64' @@ -138,7 +138,7 @@ import ZcashHaskell.Types #} {# fun unsafe rust_wrapper_tx_parse as rustWrapperTxParse { toBorshVar* `BS.ByteString'& - , getVarBuffer `Buffer [BS.ByteString]'& + , getVarBuffer `Buffer [ShieldedOutput]'& } -> `()' #} diff --git a/src/ZcashHaskell/Sapling.hs b/src/ZcashHaskell/Sapling.hs index 1b4e3bc..5ba501e 100644 --- a/src/ZcashHaskell/Sapling.hs +++ b/src/ZcashHaskell/Sapling.hs @@ -50,7 +50,7 @@ import ZcashHaskell.Utils (decodeBech32, encodeBech32, encodeBech32m) isValidShieldedAddress :: BS.ByteString -> Bool isValidShieldedAddress = rustWrapperIsShielded -getShieldedOutputs :: HexString -> [BS.ByteString] +getShieldedOutputs :: HexString -> [ShieldedOutput] getShieldedOutputs t = withPureBorshVarBuffer $ rustWrapperTxParse $ toBytes t serializeShieldedOutput :: ShieldedOutput -> BS.ByteString @@ -76,7 +76,7 @@ matchSaplingAddress :: BS.ByteString -> BS.ByteString -> Bool matchSaplingAddress = rustWrapperSaplingCheck -- | Attempt to decode the given raw tx with the given Sapling viewing key -decodeSaplingOutput :: BS.ByteString -> BS.ByteString -> Maybe DecodedNote +decodeSaplingOutput :: BS.ByteString -> ShieldedOutput -> Maybe DecodedNote decodeSaplingOutput key out = case a_value decodedAction of 0 -> Nothing @@ -119,7 +119,7 @@ decodeSaplingOutputEsk key out znet scope pos = withPureBorshVarBuffer $ rustWrapperSaplingDecodeEsk (getBytes key) - (serializeShieldedOutput out) + out (scope == External) (znet == MainNet) (fromIntegral pos) diff --git a/src/ZcashHaskell/Types.hs b/src/ZcashHaskell/Types.hs index 25bb43f..91ccae3 100644 --- a/src/ZcashHaskell/Types.hs +++ b/src/ZcashHaskell/Types.hs @@ -259,7 +259,7 @@ data RawTxResponse = RawTxResponse { rt_id :: !HexString , rt_hex :: !HexString , rt_shieldedSpends :: ![ShieldedSpend] - , rt_shieldedOutputs :: ![BS.ByteString] + , rt_shieldedOutputs :: ![ShieldedOutput] , rt_orchardActions :: ![OrchardAction] , rt_blockheight :: !Integer , rt_confirmations :: !Integer @@ -483,10 +483,9 @@ newtype SaplingReceiver = instance ToBytes SaplingReceiver where getBytes (SaplingReceiver s) = s -data SaplingAddress = SaplingAddress - { - net_type :: !ZcashNet - , sa_receiver :: !SaplingReceiver +data SaplingAddress = SaplingAddress + { net_type :: !ZcashNet + , sa_receiver :: !SaplingReceiver } deriving (Eq, Prelude.Show, Read) -- | Type to represent a Sapling Shielded Spend as provided by the @getrawtransaction@ RPC method diff --git a/test/Spec.hs b/test/Spec.hs index 19ca7a4..7b0aac0 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -25,6 +25,7 @@ import Control.Monad.IO.Class (liftIO) import Data.Aeson import Data.Bool (Bool(True)) import qualified Data.ByteString as BS +import qualified Data.ByteString.Char8 as C import Data.Either (isRight) import Data.Foldable (sequenceA_) import Data.HexString @@ -60,6 +61,7 @@ import ZcashHaskell.Sapling , isValidShieldedAddress , matchSaplingAddress , updateSaplingCommitmentTree + , updateSaplingWitness ) import ZcashHaskell.Transparent import ZcashHaskell.Types @@ -68,6 +70,7 @@ import ZcashHaskell.Types , CoinType(..) , DecodedNote(..) , OrchardAction(..) + , OrchardBundle(..) , OrchardCommitmentTree(..) , OrchardSpendingKey(..) , OrchardWitness(..) @@ -84,6 +87,7 @@ import ZcashHaskell.Types , SaplingCommitmentTree(..) , SaplingReceiver(..) , SaplingSpendingKey(..) + , SaplingWitness(..) , Scope(..) , Seed(..) , ShieldedOutput(..) @@ -438,7 +442,8 @@ main = do let a = decodeSaplingOutput (bytes rawKey) (head x) it "amount should match" $ do maybe 0 a_value a `shouldBe` 10000 it "memo should match" $ do - maybe "" a_memo a `shouldBe` "Tx with Sapling and Orchard" + C.filter (/= '\NUL') (maybe "" a_memo a) `shouldBe` + "Tx with Sapling and Orchard" describe "fails with incorrect key" $ do let a = decodeSaplingOutput (bytes badKey) (head x) it "amount should not match" $ do maybe 0 a_value a `shouldNotBe` 10000 @@ -829,11 +834,11 @@ main = do Nothing -> assertFailure "Couldn't decode" Just t1' -> do let tb1 = zt_tBundle t1' - print tb1 let txInHex = HexString "Km\237=.\228>T\DC3\\\EOT\249\163\ENQ\180s\215\215A\187\230\243\131\170cn\ETX\233Hp^\r" - toText txInHex `shouldBe` "Blank" + toText txInHex `shouldBe` + "4b6ded3d2ee43e54135c04f9a305b473d7d741bbe6f383aa636e03e948705e0d" it "Sapling component is read" $ do case t of Nothing -> assertFailure "Couldn't decode" @@ -868,6 +873,14 @@ main = do Just t' -> do let ob = zt_oBundle t' fromRawOBundle ob `shouldNotBe` Nothing + it "Orchard CMX is present" $ do + case t of + Nothing -> assertFailure "Couldn't decode" + Just t' -> do + let ob = zt_oBundle t' + case fromRawOBundle ob of + Nothing -> assertFailure "Couldn't open the orchard bundle" + Just s -> toBytes (cmx (head (obActions s))) `shouldNotBe` "" describe "Raw transaction with Transparent inputs" $ do let h = hexString @@ -1113,7 +1126,7 @@ main = do MainNet External p - dn `shouldBe` Nothing + dn `shouldNotBe` Nothing describe "Generate an ExchangeAddress (MainNet) from transparent address" $ do let ta = decodeTransparentAddress "t1dMjvesbzdG41xgKaGU3HgwYJwSgbCK54e" it "Try to generate valid ExchangeAddress from Transparent Address" $ do @@ -1132,6 +1145,41 @@ main = do Just addr -> do let eadr = decodeExchangeAddress addr eadr `shouldNotBe` Nothing + 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 + "016225b41339a00dd764b452fca190a0245e7118224965942e3a6d798365c34631001f0000011d6f5da3f619bfaab957fc643c17eb144db0101c90f422da2fcbe0e80d74412e000000000001746e6bc066a10e7f80a9ff8993dcb25c819edd64f2ca10ac248ef7848d41450500011e6191f91b3fceb62dc881a156e1b9d2e88e09dca25093cf9c4936c8869fb41a013bf8b923e4187754e85175748d9cce4824a6787e4258977b5bfe1ba59012c032000001f3bbdc62260c4fca5c84bf3487246d4542da48eeeec8ec40c1029b6908eef83c00000000000000000000000000000000040e02c864db8b574f165f616d48e2f12eb25099b5c90186af26d9e50f5058863e0504bfbc12edc35e05042c16bbfb8fed591f01f18fe128eeb57f2c456c9eb222d6d261c549e95d9007bce4c6ae0b86bc865711cdd9f0fa92e2d5b5e149b51f3be127df3b1d2372adf6c811b2e456c1d64d0e9eb167a995f9c6b66a03c9cbda250101c094201bae3b4ef582a3e8654f65a72fbd41e20e1ec9a43d3f4101afc868731e0002010cfb50d8c877eb39e9c07082a032dd99d34be7c19fa7f30e9fecf5f14736240f019df5b9366d0f21caa678d1567390b5bfd3cfa0438271bcfe301b5558a2863301") -- | Properties prop_PhraseLength :: Property diff --git a/zcash-haskell.cabal b/zcash-haskell.cabal index e8bff8c..e739a59 100644 --- a/zcash-haskell.cabal +++ b/zcash-haskell.cabal @@ -5,7 +5,7 @@ cabal-version: 3.0 -- see: https://github.com/sol/hpack name: zcash-haskell -version: 0.5.5.4 +version: 0.6.0.0 synopsis: Utilities to interact with the Zcash blockchain description: Please see the README on the repo at category: Blockchain