Compare commits

..

No commits in common. "1f8a4cbd2b723f8814c7dd5297af493c0dcfadf7" and "93a04c09d333b52109f2b51a9aab19e8a614d00e" have entirely different histories.

11 changed files with 109 additions and 484 deletions

View file

@ -5,16 +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/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.5.3.0]
### Added
- Function to decode Sapling outputs with a spending key
### Fixed
- Parsing of `TxIn` for FFI
## [0.5.2.0]
### Added

View file

@ -961,6 +961,36 @@ dependencies = [
"zcash_note_encryption",
]
[[package]]
name = "orchard"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb255c3ffdccd3c84fe9ebed72aef64fdc72e6a3e4180dd411002d47abaad42"
dependencies = [
"aes",
"bitvec",
"blake2b_simd",
"ff",
"fpe",
"group",
"halo2_gadgets",
"halo2_proofs",
"hex",
"incrementalmerkletree",
"lazy_static",
"memuse",
"nonempty",
"pasta_curves",
"rand",
"reddsa",
"serde",
"subtle",
"tracing",
"zcash_note_encryption",
"zcash_spec",
"zip32",
]
[[package]]
name = "pairing"
version = "0.23.0"
@ -1284,9 +1314,7 @@ dependencies = [
"borsh 0.10.3",
"f4jumble",
"haskell-ffi",
"incrementalmerkletree",
"nonempty",
"orchard",
"orchard 0.7.1",
"proc-macro2",
"zcash_address 0.2.0",
"zcash_client_backend",
@ -1715,7 +1743,7 @@ dependencies = [
"incrementalmerkletree",
"memuse",
"nom",
"orchard",
"orchard 0.6.0",
"percent-encoding",
"prost",
"rayon",
@ -1778,7 +1806,7 @@ dependencies = [
"lazy_static",
"memuse",
"nonempty",
"orchard",
"orchard 0.6.0",
"rand",
"rand_core",
"sha2 0.10.6",
@ -1788,6 +1816,15 @@ dependencies = [
"zcash_note_encryption",
]
[[package]]
name = "zcash_spec"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7a3bf58b673cb3dacd8ae09ba345998923a197ab0da70d6239d8e8838949e9b"
dependencies = [
"blake2b_simd",
]
[[package]]
name = "zeroize"
version = "1.6.0"

View file

@ -11,14 +11,12 @@ f4jumble = "0.1"
zcash_address = "0.2.0"
borsh = "0.10"
bech32 = "0.11"
orchard = "0.6.0"
orchard = "0.7.0"
zcash_note_encryption = "0.4.0"
zcash_primitives = "0.13.0"
zcash_client_backend = "0.10.0"
zip32 = "0.1.0"
proc-macro2 = "1.0.66"
nonempty = "0.7.0"
incrementalmerkletree = "0.5.0"
[features]

View file

@ -10,8 +10,6 @@ use std::{
},
};
use nonempty::NonEmpty;
use f4jumble;
use borsh::{BorshDeserialize, BorshSerialize};
@ -23,8 +21,6 @@ use haskell_ffi::{
FromHaskell, HaskellSize, ToHaskell
};
use incrementalmerkletree::frontier::CommitmentTree;
use zip32;
use zcash_primitives::{
@ -36,7 +32,6 @@ use zcash_primitives::{
},
zip339::{Count, Mnemonic},
transaction::components::{
amount::Amount,
transparent::{
Bundle as TransparentBundle,
TxIn,
@ -46,16 +41,10 @@ use zcash_primitives::{
},
sapling::{
GrothProofBytes,
OutputDescription,
SpendDescription,
Authorized as SaplingAuthorized,
Bundle as SaplingBundle
OutputDescription
}
},
sapling::{
Node,
MerklePath,
NOTE_COMMITMENT_TREE_DEPTH as SAPLING_DEPTH,
PaymentAddress,
keys::{
PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey,
@ -68,7 +57,6 @@ use zcash_primitives::{
consensus::{
BranchId::Nu5,
MainNetwork,
TestNetwork,
BlockHeight
}
};
@ -90,11 +78,6 @@ use zcash_primitives::zip32::DiversifierIndex;
use zcash_primitives::block::BlockHeader;
use orchard::{
Bundle as OrchardBundle,
bundle::{
Authorized as OrchardAuthorized,
Flags
},
Action,
keys::{SpendingKey, FullViewingKey, PreparedIncomingViewingKey, Scope},
note::{Nullifier, TransmittedNoteCiphertext, ExtractedNoteCommitment},
@ -147,12 +130,12 @@ impl<RW> ToHaskell<RW> for HrawTx {
#[derive(BorshSerialize, BorshDeserialize)]
pub struct HshieldedOutput {
cv: Hhex,
cmu: Hhex,
eph_key: Hhex,
enc_txt: Hhex,
out_txt: Hhex,
proof: Hhex
cv: Vec<u8>,
cmu: Vec<u8>,
eph_key: Vec<u8>,
enc_txt: Vec<u8>,
out_txt: Vec<u8>,
proof: Vec<u8>
}
impl<RW> FromHaskell<RW> for HshieldedOutput {
@ -170,15 +153,9 @@ impl<RW> ToHaskell<RW> for HshieldedOutput {
}
impl HshieldedOutput {
fn from_object(s: &OutputDescription<GrothProofBytes>) -> HshieldedOutput {
HshieldedOutput { cv: Hhex{ bytes: s.cv().to_bytes().to_vec()}, cmu: Hhex{ bytes: s.cmu().to_bytes().to_vec()}, eph_key: Hhex{ bytes: s.ephemeral_key().0.to_vec()}, enc_txt: Hhex{ bytes: s.enc_ciphertext().to_vec()}, out_txt: Hhex{ bytes: s.out_ciphertext().to_vec()}, proof: Hhex{ bytes: s.zkproof().to_vec()} }
}
pub fn pack(sp: &[OutputDescription<GrothProofBytes>]) -> Vec<HshieldedOutput> {
let mut r = Vec::new();
for s in sp {
r.push(HshieldedOutput::from_object(s));
}
return r
fn from_object(s: OutputDescription<GrothProofBytes>) -> Result<HshieldedOutput> {
let o = HshieldedOutput { cv: s.cv().to_bytes().to_vec(), cmu: s.cmu().to_bytes().to_vec(), eph_key: s.ephemeral_key().0.to_vec(), enc_txt: s.enc_ciphertext().to_vec(), out_txt: s.out_ciphertext().to_vec(), proof: s.zkproof().to_vec() };
Ok(o)
}
}
@ -206,16 +183,6 @@ impl<RW> FromHaskell<RW> for Haction {
}
}
impl Haction {
pub fn pack(sp: &NonEmpty<Action<Signature<SpendAuth>>>) -> Vec<Haction> {
let mut r = Vec::new();
for s in sp {
r.push(Haction {nf: Hhex { bytes: s.nullifier().to_bytes().to_vec()}, rk: Hhex { bytes: <[u8; 32]>::from(s.rk()).to_vec()}, cmx: Hhex{bytes: s.cmx().to_bytes().to_vec()}, eph_key: Hhex{ bytes: s.encrypted_note().epk_bytes.to_vec()}, enc_txt: Hhex {bytes: s.encrypted_note().enc_ciphertext.to_vec()}, out_txt: Hhex {bytes: s.encrypted_note().out_ciphertext.to_vec()}, cv: Hhex {bytes: s.cv_net().to_bytes().to_vec()}, auth: Hhex { bytes: <[u8; 64]>::from(s.authorization()).to_vec()}});
}
return r
}
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Hnote {
note: u64,
@ -268,9 +235,7 @@ pub struct Htx {
txid: Vec<u8>,
locktime: u32,
expiry: u32,
t_bundle: HTBundle,
s_bundle: HSBundle,
o_bundle: HOBundle
t_bundle: HTBundle
}
impl<RW> ToHaskell<RW> for Htx {
@ -360,105 +325,6 @@ impl Houtpoint {
}
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct HSBundle {
empty: bool,
spends: Vec<Hspend>,
outputs: Vec<HshieldedOutput> ,
value: i64,
sig: Vec<u8>
}
impl<RW> ToHaskell<RW> for HSBundle {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
impl HSBundle {
pub fn from_bundle(sb: &SaplingBundle<SaplingAuthorized>) -> HSBundle {
let s = Cursor::new(Vec::new());
sb.authorization().binding_sig.write(s.clone()).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.into_inner() }
}
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Hspend {
cv: Hhex,
anchor: Hhex,
nullifier: Hhex,
rk: Hhex,
proof: Hhex,
authsig: Hhex
}
impl<RW> ToHaskell<RW> for Hspend {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
impl Hspend {
pub fn pack(sp: &[SpendDescription<SaplingAuthorized>]) -> Vec<Hspend> {
let mut r = Vec::new();
for s in sp {
let rk = Cursor::new(Vec::new());
let authsig = Cursor::new(Vec::new());
s.rk().write(rk.clone()).unwrap();
s.spend_auth_sig().write(authsig.clone()).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.into_inner()}, proof: Hhex{bytes:s.zkproof().to_vec()}, authsig: Hhex{bytes:authsig.into_inner()}});
}
return r
}
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct HOBundle {
empty: bool,
actions: Vec<Haction>,
flags: Hflags,
value: i64,
anchor: Hhex,
proof: Hhex,
bindingsig: Hhex
}
impl<RW> ToHaskell<RW> for HOBundle {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
impl HOBundle {
pub fn from_bundle(b: &OrchardBundle<OrchardAuthorized, Amount>) -> HOBundle {
return HOBundle {empty: false, actions: Haction::pack(b.actions()), flags: Hflags::pack(b.flags()), value: i64::from(b.value_balance()), anchor: Hhex{ bytes: b.anchor().to_bytes().to_vec()}, proof: Hhex { bytes: b.authorization().proof().as_ref().to_vec()}, bindingsig: Hhex {bytes: <[u8; 64]>::from(b.authorization().binding_signature()).to_vec()}}
}
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Hflags {
spends: bool,
outputs: bool
}
impl<RW> ToHaskell<RW> for Hflags {
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
self.serialize(writer)?;
Ok(())
}
}
impl Hflags {
pub fn pack(f: &Flags) -> Hflags {
return Hflags {spends: f.spends_enabled(), outputs: f.outputs_enabled()}
}
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Hufvk {
net: u8,
@ -608,7 +474,7 @@ pub extern "C" fn rust_wrapper_svk_decode(
let input: Vec<u8> = marshall_from_haskell_var(input, input_len, RW);
let svk = ExtendedFullViewingKey::read(&*input);
match svk {
Ok(_k) => {
Ok(k) => {
true
}
Err(e) => {
@ -704,64 +570,6 @@ pub extern "C" fn rust_wrapper_ufvk_decode(
}
}
#[no_mangle]
pub extern "C" fn rust_wrapper_sapling_esk_decrypt(
key: *const u8,
key_len: usize,
note: *const u8,
note_len: usize,
external: bool,
net: bool,
out: *mut u8,
out_len: &mut usize
){
let sk: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
let note_input: Vec<u8> = marshall_from_haskell_var(note,note_len,RW);
let mut note_reader = Cursor::new(note_input);
let esk = ExtendedSpendingKey::from_bytes(&sk);
let main_domain = SaplingDomain::for_height(MainNetwork, BlockHeight::from_u32(419200));
let test_domain = SaplingDomain::for_height(TestNetwork, BlockHeight::from_u32(419200));
let scope = if external {
SaplingScope::External
} else {
SaplingScope::Internal
};
match esk {
Ok(k) => {
let action = OutputDescription::read(&mut note_reader);
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)};
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() };
marshall_to_haskell_var(&hn, out, out_len, RW);
},
None => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]};
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
},
Err(_e1) => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
},
Err(_e) => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
}
#[no_mangle]
pub extern "C" fn rust_wrapper_sapling_note_decrypt_v2(
key: *const u8,
@ -786,11 +594,11 @@ 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() };
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] };
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
@ -802,7 +610,7 @@ pub extern "C" fn rust_wrapper_sapling_note_decrypt_v2(
}
}
Err(_e) => {
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0]};
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] };
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
@ -836,17 +644,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() };
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] };
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] };
marshall_to_haskell_var(&hn0, out, out_len, RW);
}
}
@ -866,38 +674,19 @@ pub extern "C" fn rust_wrapper_tx_read(
match parsed_tx {
Ok(t) => {
let tb = t.transparent_bundle();
let sb = t.sapling_bundle();
let ob = t.orchard_bundle();
let h1 = Htx
{ txid: t.txid().as_ref().to_vec()
, locktime: t.lock_time()
, expiry: u32::from(t.expiry_height())
, t_bundle: match tb {
Some(tb1) => {HTBundle::from_bundle(tb1)},
None => {HTBundle {empty: true, vin: vec![HTxIn {outpoint: Houtpoint {hash: vec![0], index: 0}, script: vec![0], sequence: 0}], vout: vec![HTxOut {amt: 0, script: vec![0]}], coinbase: false}}}
, s_bundle: match sb {
Some(sb1) => {HSBundle::from_bundle(sb1)},
None => {HSBundle{empty: true, spends: vec![Hspend{cv:Hhex { bytes: vec![0]} , anchor:Hhex { bytes: vec![0]} , nullifier:Hhex { bytes: vec![0]} , rk:Hhex { bytes: vec![0]} , proof:Hhex { bytes: vec![0]} , authsig:Hhex { bytes: vec![0]} }], outputs: vec![HshieldedOutput {cv: Hhex { bytes: vec![0]}, cmu: Hhex { bytes: vec![0]}, eph_key: Hhex { bytes: vec![0]}, enc_txt: Hhex { bytes: vec![0]}, out_txt: Hhex { bytes: vec![0]}, proof: Hhex { bytes: vec![0]}}], value: 0, sig: vec![0]}} }
, o_bundle: match ob {
Some(ob1) => {HOBundle::from_bundle(ob1)},
None => {HOBundle{empty: true, actions: vec![Haction {nf:Hhex { bytes: vec![0]} , rk:Hhex { bytes: vec![0]} , cmx:Hhex { bytes: vec![0]} , eph_key:Hhex { bytes: vec![0]} , enc_txt:Hhex { bytes: vec![0]} , out_txt:Hhex { bytes: vec![0]} , cv:Hhex { bytes: vec![0]} , auth:Hhex { bytes: vec![0]} }], flags: Hflags{ spends:false, outputs:false}, value: 0, anchor: Hhex { bytes: vec![0]}, proof: Hhex { bytes: vec![0]} , bindingsig: Hhex { bytes: vec![0]}}}
match tb {
Some(my_tb) => {
let h = Htx {txid: t.txid().as_ref().to_vec(), locktime: t.lock_time(), expiry: u32::from(t.expiry_height()), t_bundle: HTBundle::from_bundle(my_tb) };
marshall_to_haskell_var(&h, out, out_len, RW);
},
None => {
let h0 = Htx {txid: t.txid().as_ref().to_vec(), locktime: t.lock_time(), expiry: u32::from(t.expiry_height()), t_bundle: HTBundle {empty: true, vin: vec![HTxIn {outpoint: Houtpoint {hash: vec![0], index: 0}, script: vec![0], sequence: 0}], vout: vec![HTxOut {amt: 0, script: vec![0]}], coinbase: true} };
marshall_to_haskell_var(&h0, out, out_len, RW);
}
};
marshall_to_haskell_var(&h1, out, out_len, RW);
}
},
Err(_e) => {
let h0 = Htx
{txid: vec![0],
locktime: 0,
expiry: 0,
t_bundle: HTBundle
{empty: true,
vin: vec![HTxIn {outpoint: Houtpoint {hash: vec![0], index: 0}, script: vec![0], sequence: 0}],
vout: vec![HTxOut {amt: 0, script: vec![0]}],
coinbase: true},
s_bundle: HSBundle{empty: true, spends: vec![Hspend{cv:Hhex { bytes: vec![0]} , anchor:Hhex { bytes: vec![0]} , nullifier:Hhex { bytes: vec![0]} , rk:Hhex { bytes: vec![0]} , proof:Hhex { bytes: vec![0]} , authsig:Hhex { bytes: vec![0]} }], outputs: vec![HshieldedOutput {cv: Hhex { bytes: vec![0]}, cmu: Hhex { bytes: vec![0]}, eph_key: Hhex { bytes: vec![0]}, enc_txt: Hhex { bytes: vec![0]}, out_txt: Hhex { bytes: vec![0]}, proof: Hhex { bytes: vec![0]}}], value: 0, sig: vec![0]},
o_bundle: HOBundle{empty: true, actions: vec![Haction {nf:Hhex { bytes: vec![0]} , rk:Hhex { bytes: vec![0]} , cmx:Hhex { bytes: vec![0]} , eph_key:Hhex { bytes: vec![0]} , enc_txt:Hhex { bytes: vec![0]} , out_txt:Hhex { bytes: vec![0]} , cv:Hhex { bytes: vec![0]} , auth:Hhex { bytes: vec![0]} }], flags: Hflags{ spends:false, outputs:false}, value: 0, anchor: Hhex { bytes: vec![0]}, proof: Hhex { bytes: vec![0]} , bindingsig: Hhex { bytes: vec![0]}}
};
let h0 = Htx {txid: vec![0], locktime: 0, expiry: 0, t_bundle: HTBundle {empty: true, vin: vec![HTxIn {outpoint: Houtpoint {hash: vec![0], index: 0}, script: vec![0], sequence: 0}], vout: vec![HTxOut {amt: 0, script: vec![0]}], coinbase: true} };
marshall_to_haskell_var(&h0, out, out_len, RW);
}
}
@ -1058,7 +847,7 @@ pub extern "C" fn rust_wrapper_derive_orchard_spending_key(
out_len: &mut usize
){
let s: Vec<u8> = 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);

View file

@ -101,16 +101,6 @@ import ZcashHaskell.Types
-> `()'
#}
{# fun unsafe rust_wrapper_sapling_esk_decrypt as rustWrapperSaplingDecodeEsk
{ toBorshVar* `BS.ByteString'&
, toBorshVar* `BS.ByteString'&
, `Bool'
, `Bool'
, getVarBuffer `Buffer DecodedNote'&
}
-> `()'
#}
{# fun unsafe rust_wrapper_ufvk_decode as rustWrapperUfvkDecode
{ toBorshVar* `BS.ByteString'&
, getVarBuffer `Buffer UnifiedFullViewingKey'&

View file

@ -153,21 +153,3 @@ decryptOrchardAction key encAction =
decodedAction =
withPureBorshVarBuffer $
rustWrapperOrchardNoteDecode (o_key key) encAction
chrToByteString :: [Char] -> C.ByteString
chrToByteString = C.pack
getSaplingFromUA :: BS.ByteString -> T.Text
getSaplingFromUA uadd = do
let a = isValidUnifiedAddress uadd
case a of
Nothing -> "xxx"
Just a -> do
let sraw = s_rec a
case sraw of
Nothing -> "xxx"
Just sraw -> do
let net = ua_net a
case net of
MainNet -> encodeBech32m (chrToByteString sapPaymentAddressHrp) ( getBytes sraw )
TestNet -> encodeBech32m (chrToByteString sapTestPaymentAddressHrp) ( getBytes sraw )

View file

@ -21,7 +21,6 @@ import C.Zcash
( rustWrapperIsShielded
, rustWrapperSaplingCheck
, rustWrapperSaplingChgPaymentAddress
, rustWrapperSaplingDecodeEsk
, rustWrapperSaplingNoteDecode
, rustWrapperSaplingPaymentAddress
, rustWrapperSaplingSpendingkey
@ -30,7 +29,7 @@ import C.Zcash
)
import Data.Aeson
import qualified Data.ByteString as BS
import Data.HexString (HexString(..), fromText, toBytes, toText)
import Data.HexString (HexString(..), toBytes)
import Data.Word
import Foreign.Rust.Marshall.Variable
( withPureBorshVarBuffer
@ -44,11 +43,9 @@ import ZcashHaskell.Types
, RawTxResponse(..)
, SaplingReceiver(..)
, SaplingSpendingKey(..)
, Scope(..)
, Seed(..)
, ShieldedOutput(..)
, ToBytes(..)
, ZcashNet(..)
, decodeHexText
, getValue
)
@ -61,15 +58,6 @@ isValidShieldedAddress = rustWrapperIsShielded
getShieldedOutputs :: HexString -> [BS.ByteString]
getShieldedOutputs t = withPureBorshVarBuffer $ rustWrapperTxParse $ toBytes t
serializeShieldedOutput :: ShieldedOutput -> BS.ByteString
serializeShieldedOutput so =
hexBytes . fromText $
toText (s_cv so) <>
toText (s_cmu so) <>
toText (s_ephKey so) <>
toText (s_encCipherText so) <>
toText (s_outCipherText so) <> toText (s_proof so)
-- | Check if given bytestring is a valid Sapling viewing key
isValidSaplingViewingKey :: BS.ByteString -> Bool
isValidSaplingViewingKey k =
@ -110,26 +98,6 @@ instance FromJSON RawTxResponse where
a <- o' .: "actions"
pure $ RawTxResponse i h sSpend (getShieldedOutputs h) a ht c b
-- | Attempt to decode the given raw tx with the given Sapling spending key
decodeSaplingOutputEsk ::
SaplingSpendingKey
-> ShieldedOutput
-> ZcashNet
-> Scope
-> Maybe DecodedNote
decodeSaplingOutputEsk key out znet scope =
case a_value decodedAction of
0 -> Nothing
_ -> Just decodedAction
where
decodedAction =
withPureBorshVarBuffer $
rustWrapperSaplingDecodeEsk
(getBytes key)
(serializeShieldedOutput out)
(znet == MainNet)
(scope == External)
-- | Attempts to obtain a sapling SpendingKey using a HDSeed
genSaplingSpendingKey :: Seed -> CoinType -> Int -> Maybe SaplingSpendingKey
genSaplingSpendingKey seed c i = do

View file

@ -129,8 +129,6 @@ data Transaction = Transaction
, tx_conf :: !Int
, tx_expiry :: !Int
, tx_transpBundle :: !(Maybe TransparentBundle)
, tx_saplingBundle :: !(Maybe SaplingBundle)
, tx_orchardBundle :: !(Maybe OrchardBundle)
} deriving (Prelude.Show, Eq, Read)
-- | The transparent portion of a Zcash transaction
@ -160,7 +158,7 @@ fromRawTxIn t = H.TxIn op (rti_script t) (rti_seq t)
then H.nullOutPoint
else H.OutPoint
((fromJust .
H.hexToTxHash . toText . fromRawBytes . rop_hash . rti_outpoint)
H.hexToTxHash . E.decodeUtf8Lenient . rop_hash . rti_outpoint)
t)
(rop_n $ rti_outpoint t)
@ -287,8 +285,6 @@ data RawZebraTx = RawZebraTx
, zt_locktime :: !Word32
, zt_expiry :: !Word32
, zt_tBundle :: !RawTBundle
, zt_sBundle :: !RawSBundle
, zt_oBundle :: !RawOBundle
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
@ -305,78 +301,6 @@ data RawTBundle = RawTBundle
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawTBundle
-- | Type for a raw deserialized Zebra Sapling bundle
data RawSBundle = RawSBundle
{ zsb_empty :: !Bool
, zsb_spends :: ![ShieldedSpend]
, zsb_outputs :: ![ShieldedOutput]
, zsb_value :: !Int64
, zsb_sig :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawSBundle
data SaplingBundle = SaplingBundle
{ sbSpends :: ![ShieldedSpend]
, sbOutputs :: ![ShieldedOutput]
, sbValue :: !Int64
, sbSig :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
fromRawSBundle :: RawSBundle -> Maybe SaplingBundle
fromRawSBundle b =
if zsb_empty b
then Nothing
else Just $
SaplingBundle (zsb_spends b) (zsb_outputs b) (zsb_value b) (zsb_sig b)
-- | Type for a raw deseralized Zebra Orchard bundle
data RawOBundle = RawOBundle
{ zob_empty :: !Bool
, zob_actions :: ![OrchardAction]
, zob_flags :: !OrchardFlags
, zob_value :: !Int64
, zob_anchor :: !HexString
, zob_proof :: !HexString
, zob_sig :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct RawOBundle
-- | Type for an Orchard Bundle
data OrchardBundle = OrchardBundle
{ obActions :: ![OrchardAction]
, obFlags :: !OrchardFlags
, obValue :: !Int64
, obAnchor :: !HexString
, obProof :: !HexString
, obSig :: !HexString
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
fromRawOBundle :: RawOBundle -> Maybe OrchardBundle
fromRawOBundle b =
if zob_empty b
then Nothing
else Just $
OrchardBundle
(zob_actions b)
(zob_flags b)
(zob_value b)
(zob_anchor b)
(zob_proof b)
(zob_sig b)
-- | Type for the Orchard bundle flags
data OrchardFlags = OrchardFlags
{ of_spends :: !Bool
, of_outputs :: !Bool
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct OrchardFlags
-- | Type for the response from the `zebrad` RPC method `getinfo`
data ZebraGetInfo = ZebraGetInfo
{ zgi_build :: !T.Text
@ -503,7 +427,7 @@ data ShieldedOutput = ShieldedOutput
, s_encCipherText :: !HexString -- ^ The output note encrypted to the recipient
, s_outCipherText :: !HexString -- ^ A ciphertext enabling the sender to recover the output note
, s_proof :: !HexString -- ^ Zero-knowledge proof using the Sapling Output circuit
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
deriving (BorshSize, ToBorsh, FromBorsh) via AsStruct ShieldedOutput
@ -558,10 +482,10 @@ data RawUA = RawUA
-- | Type to represent a Unified Full Viewing Key
data UnifiedFullViewingKey = UnifiedFullViewingKey
{ net :: !Word8 -- ^ Number representing the network the key belongs to. @1@ for @mainnet@, @2@ for @testnet@ and @3@ for @regtestnet@.
, o_key :: !BS.ByteString -- ^ Raw bytes of the Orchard Full Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
, s_key :: !BS.ByteString -- ^ Raw bytes of the Sapling Full Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
, 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)
{ net :: Word8 -- ^ Number representing the network the key belongs to. @1@ for @mainnet@, @2@ for @testnet@ and @3@ for @regtestnet@.
, o_key :: BS.ByteString -- ^ Raw bytes of the Orchard Full Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
, s_key :: BS.ByteString -- ^ Raw bytes of the Sapling Full Viewing Key as specified in [ZIP-316](https://zips.z.cash/zip-0316)
, 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)
@ -569,14 +493,14 @@ data UnifiedFullViewingKey = UnifiedFullViewingKey
-- | 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
{ nf :: !HexString -- ^ The nullifier of the input note
, rk :: !HexString -- ^ The randomized validating key for @auth@
, cmx :: !HexString -- ^ The x-coordinate of the note commitment for the output note
, eph_key :: !HexString -- ^ An encoding of an ephemeral Pallas public key
, enc_ciphertext :: !HexString -- ^ The output note encrypted to the recipient
, out_ciphertext :: !HexString -- ^ A ciphertext enabling the sender to recover the output note
, cv :: !HexString -- ^ A value commitment to the net value of the input note minus the output note
, auth :: !HexString -- ^ A signature authorizing the spend in this Action
{ nf :: HexString -- ^ The nullifier of the input note
, rk :: HexString -- ^ The randomized validating key for @auth@
, cmx :: HexString -- ^ The x-coordinate of the note commitment for the output note
, eph_key :: HexString -- ^ An encoding of an ephemeral Pallas public key
, enc_ciphertext :: HexString -- ^ The output note encrypted to the recipient
, out_ciphertext :: HexString -- ^ A ciphertext enabling the sender to recover the output note
, cv :: HexString -- ^ A value commitment to the net value of the input note minus the output note
, auth :: HexString -- ^ A signature authorizing the spend in this Action
} deriving stock (Eq, Prelude.Show, GHC.Generic, Read)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)
@ -597,9 +521,9 @@ instance FromJSON OrchardAction where
-- | Type to represent a decoded note
data DecodedNote = DecodedNote
{ a_value :: !Int64 -- ^ The amount of the transaction in _zatoshis_.
, a_recipient :: !BS.ByteString -- ^ The recipient Orchard receiver.
, a_memo :: !BS.ByteString -- ^ The decoded shielded memo field.
{ a_value :: Int64 -- ^ The amount of the transaction in _zatoshis_.
, a_recipient :: BS.ByteString -- ^ The recipient Orchard receiver.
, a_memo :: BS.ByteString -- ^ The decoded shielded memo field.
} deriving stock (Eq, Prelude.Show, GHC.Generic)
deriving anyclass (SOP.Generic, SOP.HasDatatypeInfo)
deriving anyclass (Data.Structured.Show)

View file

@ -115,4 +115,3 @@ readZebraTransaction hex =
else Just rawTx
where
rawTx = (withPureBorshVarBuffer . rustWrapperTxRead) $ hexBytes hex

File diff suppressed because one or more lines are too long

View file

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