2500 lines
88 KiB
Rust
2500 lines
88 KiB
Rust
// Copyright 2022-2024 Vergara Technologies LLC
|
|
//
|
|
// This file is part of Zcash-Haskell.
|
|
//
|
|
use std::{
|
|
marker::PhantomData,
|
|
io::{
|
|
Write,
|
|
Cursor
|
|
},
|
|
};
|
|
|
|
use nonempty::NonEmpty;
|
|
|
|
use rand_core::OsRng;
|
|
|
|
use f4jumble;
|
|
|
|
use borsh::{BorshDeserialize, BorshSerialize};
|
|
|
|
use haskell_ffi::{
|
|
error::Result,
|
|
from_haskell::marshall_from_haskell_var,
|
|
to_haskell::marshall_to_haskell_var,
|
|
FromHaskell, ToHaskell
|
|
};
|
|
|
|
use secp256k1::SecretKey;
|
|
|
|
use jubjub::Fr;
|
|
|
|
use incrementalmerkletree::{
|
|
Hashable,
|
|
Level,
|
|
Position,
|
|
frontier::{
|
|
CommitmentTree,
|
|
Frontier,
|
|
NonEmptyFrontier,
|
|
PathFiller
|
|
},
|
|
witness::IncrementalWitness
|
|
};
|
|
|
|
use zip32::{
|
|
Scope as SaplingScope
|
|
};
|
|
|
|
|
|
use sapling_crypto::{
|
|
NOTE_COMMITMENT_TREE_DEPTH as SAPLING_DEPTH,
|
|
Node,
|
|
MerklePath,
|
|
PaymentAddress,
|
|
Anchor as SaplingAnchor,
|
|
value::ValueCommitment as SaplingValueCommitment,
|
|
note::{
|
|
ExtractedNoteCommitment as SaplingNoteCommitment,
|
|
Note as SaplingNote,
|
|
Rseed
|
|
},
|
|
keys::{
|
|
PreparedIncomingViewingKey as SaplingPreparedIncomingViewingKey,
|
|
ExpandedSpendingKey,
|
|
FullViewingKey as SaplingFullViewingKey
|
|
},
|
|
note_encryption::{
|
|
SaplingDomain,
|
|
Zip212Enforcement
|
|
},
|
|
bundle::{
|
|
GrothProofBytes,
|
|
OutputDescription,
|
|
SpendDescription,
|
|
Authorized as SaplingAuthorized,
|
|
Bundle as SaplingBundle
|
|
},
|
|
value::NoteValue as SaplingNoteValue,
|
|
circuit::{
|
|
SpendParameters,
|
|
OutputParameters
|
|
},
|
|
zip32::{
|
|
sapling_find_address,
|
|
DiversifierKey
|
|
}
|
|
};
|
|
|
|
use bip0039::{Count, Mnemonic, English};
|
|
|
|
use zcash_primitives::{
|
|
merkle_tree::{
|
|
read_commitment_tree,
|
|
write_commitment_tree,
|
|
read_incremental_witness,
|
|
write_incremental_witness,
|
|
read_frontier_v1,
|
|
read_nonempty_frontier_v1
|
|
},
|
|
legacy::{
|
|
Script,
|
|
TransparentAddress
|
|
},
|
|
transaction::{
|
|
Transaction,
|
|
fees::zip317::FeeRule,
|
|
builder::{
|
|
Builder,
|
|
Error,
|
|
BuildConfig
|
|
},
|
|
components::{
|
|
amount::{
|
|
Amount,
|
|
NonNegativeAmount
|
|
},
|
|
transparent::{
|
|
Bundle as TransparentBundle,
|
|
TxIn,
|
|
TxOut,
|
|
OutPoint,
|
|
Authorized
|
|
}
|
|
}
|
|
},
|
|
memo::MemoBytes,
|
|
consensus::{
|
|
BranchId::Nu5,
|
|
MainNetwork,
|
|
TestNetwork,
|
|
BlockHeight
|
|
}
|
|
};
|
|
|
|
use zcash_address::{
|
|
Network,
|
|
unified::{Address, Encoding, Ufvk, Container, Fvk, Receiver},
|
|
ZcashAddress
|
|
};
|
|
|
|
use zcash_client_backend::encoding::decode_payment_address;
|
|
use zcash_client_backend::keys::sapling::{
|
|
spending_key,
|
|
ExtendedFullViewingKey,
|
|
ExtendedSpendingKey,
|
|
DiversifiableFullViewingKey
|
|
};
|
|
|
|
use zcash_primitives::zip32::DiversifierIndex;
|
|
|
|
use orchard::{
|
|
Address as OrchardAddress,
|
|
Bundle as OrchardBundle,
|
|
bundle::{
|
|
Authorized as OrchardAuthorized,
|
|
Flags
|
|
},
|
|
Action,
|
|
keys::{SpendingKey, FullViewingKey, PreparedIncomingViewingKey, Scope},
|
|
note::{Rho, RandomSeed, Note, Nullifier, TransmittedNoteCiphertext, ExtractedNoteCommitment},
|
|
note_encryption::OrchardDomain,
|
|
primitives::redpallas::{VerificationKey, SpendAuth, Signature},
|
|
tree::{
|
|
MerklePath as OrchardMerklePath,
|
|
MerkleHashOrchard,
|
|
Anchor as OrchardAnchor
|
|
},
|
|
value::{
|
|
ValueCommitment,
|
|
NoteValue
|
|
}
|
|
};
|
|
|
|
use bech32::{
|
|
Hrp,
|
|
Bech32,
|
|
Bech32m
|
|
};
|
|
|
|
use wagyu_zcash_parameters::load_sapling_parameters;
|
|
|
|
pub enum RW {}
|
|
pub const RW: PhantomData<RW> = PhantomData;
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct RawData {
|
|
hrp: Vec<u8>,
|
|
bytes: Vec<u8>
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for RawData {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
//impl<RW> FromHaskell<RW> for RawData {
|
|
//fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
//let x = RawData::deserialize(buf)?;
|
|
//Ok(x)
|
|
//}
|
|
//}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct HrawTx {
|
|
bytes: Vec<u8>,
|
|
s: bool,
|
|
o: bool
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for HrawTx {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct HshieldedOutput {
|
|
pub cv: Hhex,
|
|
cmu: Hhex,
|
|
eph_key: Hhex,
|
|
enc_txt: Hhex,
|
|
out_txt: Hhex,
|
|
proof: Hhex
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for HshieldedOutput {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = HshieldedOutput::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for HshieldedOutput {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
pub fn to_output_description(&mut self) -> Result<OutputDescription<GrothProofBytes>> {
|
|
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(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Hhex {
|
|
bytes: Vec<u8>
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Hhex {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for Hhex {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = Hhex::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Haction {
|
|
nf: Hhex,
|
|
rk: Hhex,
|
|
cmx: Hhex,
|
|
eph_key: Hhex,
|
|
enc_txt: Hhex,
|
|
out_txt: Hhex,
|
|
cv: Hhex,
|
|
auth: Hhex
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for Haction {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = Haction::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
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(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Hnote {
|
|
note: u64,
|
|
recipient: Vec<u8>,
|
|
memo: Vec<u8>,
|
|
nullifier: Vec<u8>,
|
|
rho: Vec<u8>,
|
|
rseed: Hrseed
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Hnote {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Hrseed {
|
|
kind: u8,
|
|
bytes: Vec<u8>
|
|
}
|
|
|
|
|
|
impl<RW> FromHaskell<RW> for Hrseed {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = Hrseed::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Hrseed {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Hua {
|
|
net: u8,
|
|
o_rec: Vec<u8>,
|
|
s_rec: Vec<u8>,
|
|
t_rec: Vec<u8>,
|
|
to_rec: Vec<u8>
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Hua {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Hua {
|
|
fn add_rec(&mut self, rec: &Receiver) {
|
|
if let Receiver::Orchard(x) = rec {
|
|
self.o_rec = x.to_vec();
|
|
}
|
|
if let Receiver::Sapling(y) = rec {
|
|
self.s_rec = y.to_vec();
|
|
}
|
|
if let Receiver::P2pkh(z) = rec {
|
|
self.t_rec = z.to_vec();
|
|
}
|
|
if let Receiver::P2sh(w) = rec {
|
|
self.to_rec = w.to_vec();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Htx {
|
|
txid: Vec<u8>,
|
|
locktime: u32,
|
|
expiry: u32,
|
|
t_bundle: HTBundle,
|
|
s_bundle: HSBundle,
|
|
o_bundle: HOBundle
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Htx {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct HTBundle {
|
|
empty: bool,
|
|
vin: Vec<HTxIn>,
|
|
vout: Vec<HTxOut>,
|
|
coinbase: bool
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for HTBundle {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl HTBundle {
|
|
pub fn from_bundle(b: &TransparentBundle<Authorized>) -> HTBundle {
|
|
HTBundle {empty: false, vin: b.vin.iter().map(HTxIn::pack).collect() , vout: b.vout.iter().map(HTxOut::pack).collect(), coinbase: b.is_coinbase()}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct HTxIn {
|
|
outpoint: Houtpoint,
|
|
script: Vec<u8>,
|
|
sequence: u32
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for HTxIn {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl HTxIn {
|
|
pub fn pack(t: &TxIn<Authorized>) -> HTxIn {
|
|
return HTxIn { outpoint: Houtpoint::pack(&t.prevout), script: t.script_sig.0.clone(), sequence: t.sequence}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct HTxOut {
|
|
amt: i64,
|
|
script: Vec<u8>
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for HTxOut {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = HTxOut::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for HTxOut {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl HTxOut {
|
|
pub fn pack(t: &TxOut) -> HTxOut {
|
|
return HTxOut { amt: i64::from_le_bytes(t.value.to_i64_le_bytes()) , script: t.script_pubkey.0.clone() }
|
|
}
|
|
pub fn unpack(&self) -> TxOut {
|
|
TxOut { value: NonNegativeAmount::from_nonnegative_i64(self.amt).unwrap(), script_pubkey: Script(self.script.clone())}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Houtpoint {
|
|
hash: Vec<u8>,
|
|
index: u32
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for Houtpoint {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = Houtpoint::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Houtpoint {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Houtpoint {
|
|
pub fn pack(o: &OutPoint) -> Houtpoint {
|
|
return Houtpoint {hash: o.hash().to_vec() , index: o.n() }
|
|
}
|
|
|
|
pub fn unpack(&self) -> OutPoint {
|
|
OutPoint::new(to_array(self.hash.clone()), self.index)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct HtransparentInput {
|
|
sk: Vec<u8>,
|
|
utxo: Houtpoint,
|
|
coin: HTxOut
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for HtransparentInput {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = HtransparentInput::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for HtransparentInput {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, 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, Amount>) -> 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()}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, 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 = 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
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct HsaplingInput {
|
|
sk: Vec<u8>,
|
|
note: Hnote,
|
|
iw: Vec<u8>
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for HsaplingInput {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = HsaplingInput::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct HorchardInput {
|
|
sk: Vec<u8>,
|
|
note: Hnote,
|
|
iw: Vec<u8>
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for HorchardInput {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = HorchardInput::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Houtput {
|
|
kind: u8,
|
|
ovk: Vec<u8>,
|
|
to: Vec<u8>,
|
|
amt: u64,
|
|
memo: Vec<u8>,
|
|
chg: bool
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for Houtput {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = Houtput::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, 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(Debug, 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(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Hufvk {
|
|
net: u8,
|
|
orchard: Vec<u8>,
|
|
sapling: Vec<u8>,
|
|
transparent: Vec<u8>
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Hufvk {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Hufvk {
|
|
fn add_key_section(&mut self, fvk: &Fvk) {
|
|
if let Fvk::Orchard(v) = fvk {
|
|
self.orchard = v.to_vec();
|
|
}
|
|
if let Fvk::Sapling(w) = fvk {
|
|
self.sapling = w.to_vec();
|
|
}
|
|
if let Fvk::P2pkh(x) = fvk {
|
|
self.transparent = x.to_vec();
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, BorshSerialize, BorshDeserialize)]
|
|
pub struct Hsvk {
|
|
vk: Vec<u8>,
|
|
ovk: Vec<u8>
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Hsvk {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(BorshSerialize, BorshDeserialize)]
|
|
pub struct Hfrontier {
|
|
position: u64,
|
|
leaf: Hhex,
|
|
ommers: Vec<Hhex>
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Hfrontier {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for Hfrontier {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = Hfrontier::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
#[derive(BorshSerialize, BorshDeserialize)]
|
|
pub struct Htree {
|
|
left: Hhex,
|
|
right: Hhex,
|
|
parents: Vec<Hhex>
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Htree {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for Htree {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = Htree::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
#[derive(BorshSerialize, BorshDeserialize)]
|
|
pub struct Hpath {
|
|
position: u32,
|
|
path: Vec<Hhex>
|
|
}
|
|
|
|
impl<RW> ToHaskell<RW> for Hpath {
|
|
fn to_haskell<W: Write>(&self, writer: &mut W, _tag: PhantomData<RW>) -> Result<()> {
|
|
self.serialize(writer)?;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl<RW> FromHaskell<RW> for Hpath {
|
|
fn from_haskell(buf: &mut &[u8], _tag: PhantomData<RW>) -> Result<Self> {
|
|
let x = Hpath::deserialize(buf)?;
|
|
Ok(x)
|
|
}
|
|
}
|
|
|
|
fn to_array<T, const N: usize>(v: Vec<T>) -> [T; N] {
|
|
v.try_into().unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_f4jumble(
|
|
input: *const u8,
|
|
input_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize) {
|
|
let input: Vec<u8> = marshall_from_haskell_var(input, input_len, RW);
|
|
let result = f4jumble::f4jumble(&input).unwrap();
|
|
marshall_to_haskell_var(&result, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_f4unjumble(
|
|
input: *const u8,
|
|
input_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize) {
|
|
let input: Vec<u8> = marshall_from_haskell_var(input, input_len, RW);
|
|
let result = f4jumble::f4jumble_inv(&input).unwrap();
|
|
marshall_to_haskell_var(&result, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_ua_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_addy = Address::decode(&input);
|
|
match dec_addy {
|
|
Ok((n, ua)) => {
|
|
let x = match n {
|
|
Network::Main => 1,
|
|
Network::Test => 2,
|
|
Network::Regtest => 3
|
|
};
|
|
let mut hk = Hua { net: x, o_rec: vec![0], s_rec: vec![0], t_rec: vec![0], to_rec: vec![0] };
|
|
let recvs = ua.items();
|
|
recvs.iter().for_each(|k| hk.add_rec(k));
|
|
marshall_to_haskell_var(&hk, out, out_len, RW);
|
|
}
|
|
Err(_e) => {
|
|
let hk0 = Hua { net: 0, o_rec: vec![0], s_rec: vec![0], t_rec: vec![0], to_rec: vec![0]};
|
|
marshall_to_haskell_var(&hk0, out, out_len, RW);
|
|
}
|
|
}
|
|
//marshall_to_haskell_var(&result, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_shielded_decode(
|
|
input: *const u8,
|
|
input_len: usize) -> bool {
|
|
let input: String = marshall_from_haskell_var(input, input_len, RW);
|
|
ZcashAddress::try_from_encoded(&input).is_ok()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_bech32decode(
|
|
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 decoded_bytes = bech32::decode(&input);
|
|
match decoded_bytes {
|
|
Ok((hrp, bytes)) => {
|
|
let rd = RawData {hrp: hrp.as_bytes().to_vec(), bytes};
|
|
marshall_to_haskell_var(&rd, out, out_len, RW);
|
|
}
|
|
Err(_e) => {
|
|
let rd1 = RawData {hrp: "fail".into(), bytes: vec![0]};
|
|
marshall_to_haskell_var(&rd1, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_bech32m_encode(
|
|
hr: *const u8,
|
|
hr_len: usize,
|
|
b: *const u8,
|
|
b_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
) {
|
|
let hr: String = marshall_from_haskell_var(hr, hr_len, RW);
|
|
let hrp = Hrp::parse(&hr).unwrap();
|
|
let b: Vec<u8> = marshall_from_haskell_var(b, b_len, RW);
|
|
let string = bech32::encode::<Bech32m>(hrp, &b).unwrap();
|
|
marshall_to_haskell_var(&string, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_svk_decode(
|
|
input: *const u8,
|
|
input_len: usize
|
|
) -> bool {
|
|
let input: Vec<u8> = marshall_from_haskell_var(input, input_len, RW);
|
|
let svk = ExtendedFullViewingKey::read(&*input);
|
|
match svk {
|
|
Ok(_k) => {
|
|
true
|
|
}
|
|
Err(e) => {
|
|
print!("{:?}", e);
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_svk_check_address(
|
|
key_input: *const u8,
|
|
key_input_len: usize,
|
|
address_input: *const u8,
|
|
address_input_len: usize
|
|
) -> bool {
|
|
let key_input: Vec<u8> = marshall_from_haskell_var(key_input, key_input_len, RW);
|
|
let address_input: Vec<u8> = marshall_from_haskell_var(address_input, address_input_len, RW);
|
|
let svk = ExtendedFullViewingKey::read(&*key_input);
|
|
let sa = PaymentAddress::from_bytes(&to_array(address_input)).unwrap();
|
|
match svk {
|
|
Ok(k) => {
|
|
let (_div_index, def_address) = k.default_address();
|
|
sa == def_address
|
|
}
|
|
Err(_e) => {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_ufvk_check_address(
|
|
key_input: *const u8,
|
|
key_input_len: usize,
|
|
address_input: *const u8,
|
|
address_input_len: usize
|
|
) -> bool {
|
|
let key: String = marshall_from_haskell_var(key_input, key_input_len, RW);
|
|
let addy: String = marshall_from_haskell_var(address_input, address_input_len, RW);
|
|
let dec_key = Ufvk::decode(&key);
|
|
let dec_addy = Address::decode(&addy);
|
|
match dec_key {
|
|
Ok((n, ufvk)) => {
|
|
let i = ufvk.items();
|
|
if let Fvk::Orchard(k) = i[0] {
|
|
let orch_key = FullViewingKey::from_bytes(&k).unwrap();
|
|
let orch_addy = orch_key.address_at(0u32, Scope::External).to_raw_address_bytes();
|
|
match dec_addy {
|
|
Ok((n, recs)) => {
|
|
let j = recs.items();
|
|
j[0] == Receiver::Orchard(orch_addy)
|
|
},
|
|
Err(_e) => {
|
|
false
|
|
}
|
|
}
|
|
} else {
|
|
false
|
|
}
|
|
},
|
|
Err(_e) => {
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_ufvk_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 = Ufvk::decode(&input);
|
|
match dec_key {
|
|
Ok((n, ufvk)) => {
|
|
let x = match n {
|
|
Network::Main => 1,
|
|
Network::Test => 2,
|
|
Network::Regtest => 3
|
|
};
|
|
let mut hk = Hufvk { net: x, orchard: vec![0], sapling: vec![0], transparent: vec![0] };
|
|
let fvks = ufvk.items();
|
|
fvks.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]
|
|
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,
|
|
pos: u64,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let sk: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
|
|
let mut note_input: HshieldedOutput = marshall_from_haskell_var(note,note_len,RW);
|
|
let esk = ExtendedSpendingKey::from_bytes(&sk);
|
|
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 {
|
|
SaplingScope::Internal
|
|
};
|
|
match esk {
|
|
Ok(k) => {
|
|
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 = zcash_note_encryption::try_note_decryption(&main_domain, &pivk, &action2);
|
|
match result {
|
|
Some((n, r, m)) => {
|
|
let nullifier = n.nf(&nk, pos);
|
|
let rseed = match n.rseed() {
|
|
Rseed::BeforeZip212(x) => {
|
|
Hrseed {kind: 1, bytes: x.to_bytes().to_vec()}
|
|
},
|
|
Rseed::AfterZip212(y) => {
|
|
Hrseed {kind: 2, bytes: y.to_vec()}
|
|
}
|
|
};
|
|
let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec(), nullifier: nullifier.to_vec(), rho: vec![0], rseed };
|
|
marshall_to_haskell_var(&hn, out, out_len, RW);
|
|
},
|
|
None => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0], rho: vec![0], rseed: Hrseed{ kind: 0, bytes: vec![0]}};
|
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
}
|
|
}
|
|
},
|
|
Err(_e1) => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0], rho: vec![0], rseed: Hrseed{ kind: 0, bytes: vec![0]} };
|
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
}
|
|
}
|
|
},
|
|
Err(_e) => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0], rho: vec![0], rseed: Hrseed{ kind: 0, bytes: 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,
|
|
key_len: usize,
|
|
note: *const u8,
|
|
note_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let evk: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
|
|
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::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);
|
|
let pivk = SaplingPreparedIncomingViewingKey::new(&fvk);
|
|
let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action3);
|
|
match result {
|
|
Some((n, r, m)) => {
|
|
let rseed = match n.rseed() {
|
|
Rseed::BeforeZip212(x) => {
|
|
Hrseed { kind: 1, bytes: x.to_bytes().to_vec()}
|
|
},
|
|
Rseed::AfterZip212(y) => {
|
|
Hrseed { kind: 2, bytes: y.to_vec()}
|
|
}
|
|
};
|
|
let hn = Hnote {note: n.value().inner(), recipient: r.to_bytes().to_vec(), memo: m.as_slice().to_vec(), nullifier: vec![0], rho: vec![0], rseed};
|
|
marshall_to_haskell_var(&hn, out, out_len, RW);
|
|
}
|
|
None => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0], rho: vec![0], rseed: Hrseed {kind: 0, bytes: vec![0]}};
|
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
}
|
|
}
|
|
},
|
|
Err(_e1) => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0] , nullifier: vec![0], rho: vec![0], rseed: Hrseed {kind: 0, bytes: vec![0]}};
|
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
Err(_e) => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0], rho: vec![0], rseed: Hrseed {kind: 0, bytes: vec![0]}};
|
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_orchard_note_decrypt(
|
|
key: *const u8,
|
|
key_len: usize,
|
|
note: *const u8,
|
|
note_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let fvk_input: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
|
|
let note_input: Haction = marshall_from_haskell_var(note, note_len, RW);
|
|
let action: Action<Signature<SpendAuth>> = Action::from_parts(
|
|
Nullifier::from_bytes(&to_array(note_input.nf.bytes)).unwrap(),
|
|
VerificationKey::try_from(to_array(note_input.rk.bytes)).unwrap(),
|
|
ExtractedNoteCommitment::from_bytes(&to_array(note_input.cmx.bytes)).unwrap(),
|
|
TransmittedNoteCiphertext {epk_bytes: to_array(note_input.eph_key.bytes), enc_ciphertext: to_array(note_input.enc_txt.bytes), out_ciphertext: to_array(note_input.out_txt.bytes)},
|
|
ValueCommitment::from_bytes(&to_array(note_input.cv.bytes)).unwrap(),
|
|
Signature::from(to_array(note_input.auth.bytes)));
|
|
let fvk_array = to_array(fvk_input);
|
|
let domain = OrchardDomain::for_action(&action);
|
|
let dec_fvk = FullViewingKey::from_bytes(&fvk_array);
|
|
match dec_fvk {
|
|
Some(fvk) => {
|
|
let ivk = fvk.to_ivk(Scope::External);
|
|
let pivk = PreparedIncomingViewingKey::new(&ivk);
|
|
let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action);
|
|
match result {
|
|
Some((n, r, m)) => {
|
|
let rho = n.rho().to_bytes().to_vec();
|
|
let rseed = Hrseed {kind: 3, bytes: n.rseed().as_bytes().to_vec()};
|
|
let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec(), nullifier: vec![0], rho, rseed};
|
|
marshall_to_haskell_var(&hn, out, out_len, RW);
|
|
}
|
|
None => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0], rho: vec![0], rseed: Hrseed {kind: 0, bytes: vec![0]}};
|
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
}
|
|
}
|
|
},
|
|
None => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0], rho: vec![0], rseed: Hrseed {kind: 0, bytes: vec![0]}};
|
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_orchard_note_decrypt_sk(
|
|
key: *const u8,
|
|
key_len: usize,
|
|
note: *const u8,
|
|
note_len: usize,
|
|
external: bool,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let sk_input: Vec<u8> = marshall_from_haskell_var(key, key_len, RW);
|
|
let note_input: Haction = marshall_from_haskell_var(note, note_len, RW);
|
|
let action: Action<Signature<SpendAuth>> = Action::from_parts(
|
|
Nullifier::from_bytes(&to_array(note_input.nf.bytes)).unwrap(),
|
|
VerificationKey::try_from(to_array(note_input.rk.bytes)).unwrap(),
|
|
ExtractedNoteCommitment::from_bytes(&to_array(note_input.cmx.bytes)).unwrap(),
|
|
TransmittedNoteCiphertext {epk_bytes: to_array(note_input.eph_key.bytes), enc_ciphertext: to_array(note_input.enc_txt.bytes), out_ciphertext: to_array(note_input.out_txt.bytes)},
|
|
ValueCommitment::from_bytes(&to_array(note_input.cv.bytes)).unwrap(),
|
|
Signature::from(to_array(note_input.auth.bytes)));
|
|
let sk_array = to_array(sk_input);
|
|
let domain = OrchardDomain::for_action(&action);
|
|
let dec_sk = SpendingKey::from_bytes(sk_array).unwrap();
|
|
let fvk = FullViewingKey::from(&dec_sk);
|
|
let ivk = if external {
|
|
fvk.to_ivk(Scope::External)
|
|
} else {
|
|
fvk.to_ivk(Scope::Internal)
|
|
};
|
|
let pivk = PreparedIncomingViewingKey::new(&ivk);
|
|
let result = zcash_note_encryption::try_note_decryption(&domain, &pivk, &action);
|
|
match result {
|
|
Some((n, r, m)) => {
|
|
let rho = n.rho().to_bytes().to_vec();
|
|
let rseed = Hrseed {kind: 3, bytes: n.rseed().as_bytes().to_vec()};
|
|
let hn = Hnote {note: n.value().inner(), recipient: r.to_raw_address_bytes().to_vec(), memo: m.to_vec(), nullifier: n.nullifier(&fvk).to_bytes().to_vec(), rho, rseed};
|
|
marshall_to_haskell_var(&hn, out, out_len, RW);
|
|
}
|
|
None => {
|
|
let hn0 = Hnote { note: 0, recipient: vec![0], memo: vec![0], nullifier: vec![0], rho: vec![0], rseed: Hrseed {kind: 0, bytes: vec![0]}};
|
|
marshall_to_haskell_var(&hn0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_tx_read(
|
|
tx: *const u8,
|
|
tx_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tx_input: Vec<u8> = marshall_from_haskell_var(tx, tx_len, RW);
|
|
let mut tx_reader = Cursor::new(tx_input);
|
|
let parsed_tx = Transaction::read(&mut tx_reader, Nu5);
|
|
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]}}}
|
|
}
|
|
};
|
|
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]}}
|
|
};
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_tx_parse(
|
|
tx: *const u8,
|
|
tx_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tx_input: Vec<u8> = marshall_from_haskell_var(tx, tx_len, RW);
|
|
let mut tx_reader = Cursor::new(tx_input);
|
|
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 s_output = HshieldedOutput::pack(b.shielded_outputs());
|
|
marshall_to_haskell_var(&s_output, out, out_len, RW);
|
|
},
|
|
None => {
|
|
let mut z = Vec::new();
|
|
z.push(vec![0]);
|
|
marshall_to_haskell_var(&z, out, out_len, RW);
|
|
}
|
|
}
|
|
|
|
},
|
|
Err(_e) => {
|
|
let mut y = Vec::new();
|
|
y.push(vec![0]);
|
|
marshall_to_haskell_var(&y, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_gen_seed_phrase(
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let mnemonic: Mnemonic<English> = Mnemonic::generate(Count::Words24);
|
|
let seed = mnemonic.phrase().as_bytes().to_vec();
|
|
marshall_to_haskell_var(&seed, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_recover_seed(
|
|
input: *const u8,
|
|
input_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let phrase: String = marshall_from_haskell_var(input, input_len, RW);
|
|
let mnemonic = <Mnemonic<English>>::from_phrase(phrase);
|
|
match mnemonic {
|
|
Ok(m) => {
|
|
let s = m.to_seed("").to_vec();
|
|
marshall_to_haskell_var(&s, out, out_len, RW);
|
|
},
|
|
Err(_e) => {
|
|
marshall_to_haskell_var(&vec![0], out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_sapling_spendingkey(
|
|
seed: *const u8,
|
|
seed_len: usize,
|
|
coin_type: u32,
|
|
acc_id: u32,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let s: Vec<u8> = marshall_from_haskell_var(seed, seed_len, RW);
|
|
let sk = spending_key(&s, coin_type, zcash_primitives::zip32::AccountId::try_from(acc_id).unwrap());
|
|
marshall_to_haskell_var(&sk.to_bytes().to_vec(), out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_sapling_paymentaddress(
|
|
extspk: *const u8,
|
|
extspk_len: usize,
|
|
div_ix: u32,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let extspk: Vec<u8> = marshall_from_haskell_var(extspk, extspk_len, RW);
|
|
if div_ix == 0 {
|
|
let sp_key = ExtendedSpendingKey::from_bytes(&extspk);
|
|
match sp_key {
|
|
Ok(sp_key_x) => {
|
|
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) => {
|
|
marshall_to_haskell_var(&vec![0], out, out_len, RW);
|
|
}
|
|
}
|
|
} else {
|
|
let expsk = ExpandedSpendingKey::from_spending_key(&extspk);
|
|
let fvk = SaplingFullViewingKey::from_expanded_spending_key(&expsk);
|
|
let dk = DiversifierKey::master(&extspk);
|
|
let result = sapling_find_address(&fvk, &dk, DiversifierIndex::from(div_ix));
|
|
match result {
|
|
Some((_d, p_address)) => {
|
|
marshall_to_haskell_var(&p_address.to_bytes().to_vec(), out, out_len, RW);
|
|
},
|
|
None => {
|
|
marshall_to_haskell_var(&vec![0], out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_sapling_chgpaymentaddress(
|
|
extspk: *const u8,
|
|
extspk_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let vexspk: Vec<u8> = marshall_from_haskell_var(extspk, extspk_len, RW);
|
|
let vexspkp = &vexspk;
|
|
let extspku8 : &[u8] = &vexspkp;
|
|
let extspk = match ExtendedSpendingKey::from_bytes(&extspku8) {
|
|
Ok( k ) => k,
|
|
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();
|
|
marshall_to_haskell_var(&cPmtAddress.to_bytes().to_vec(), out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_derive_orchard_spending_key(
|
|
seed: *const u8,
|
|
seed_len: usize,
|
|
coin_type: u32,
|
|
acc_id: u32,
|
|
out: *mut u8,
|
|
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, zip32::AccountId::try_from(acc_id).unwrap());
|
|
match sk {
|
|
Ok(key) => {
|
|
marshall_to_haskell_var(&key.to_bytes().to_vec(), out, out_len, RW);
|
|
},
|
|
Err(_e) => {
|
|
marshall_to_haskell_var(&vec![0], out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_derive_orchard_receiver(
|
|
spend_key: *const u8,
|
|
spend_key_len: usize,
|
|
add_id: u32,
|
|
scope: bool,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let sk_in: Vec<u8> = marshall_from_haskell_var(spend_key, spend_key_len, RW);
|
|
let sk = SpendingKey::from_bytes(sk_in[0..32].try_into().unwrap()).unwrap();
|
|
let fvk = FullViewingKey::from(&sk);
|
|
let sc = if scope {
|
|
Scope::External
|
|
} else {Scope::Internal};
|
|
let o_rec = fvk.address_at(add_id, sc);
|
|
marshall_to_haskell_var(&o_rec.to_raw_address_bytes().to_vec(), out, out_len, RW);
|
|
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_bech32_encode(
|
|
hr: *const u8,
|
|
hr_len: usize,
|
|
b: *const u8,
|
|
b_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
) {
|
|
let hr: String = marshall_from_haskell_var(hr, hr_len, RW);
|
|
let hrp = Hrp::parse(&hr).unwrap();
|
|
let b: Vec<u8> = marshall_from_haskell_var(b, b_len, RW);
|
|
let string = bech32::encode::<Bech32>(hrp, &b).unwrap();
|
|
marshall_to_haskell_var(&string, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_sapling_frontier(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let tree_reader = Cursor::new(tree_in);
|
|
let comm_tree: CommitmentTree<Node, SAPLING_DEPTH> = read_commitment_tree(tree_reader).unwrap();
|
|
//let comm_tree: Frontier<MerkleHashOrchard, 32> = read_frontier_v1(tree_reader).unwrap();
|
|
let frontier: Frontier<Node, SAPLING_DEPTH> = comm_tree.to_frontier();
|
|
match frontier.value() {
|
|
Some(f1) => {
|
|
let (pos, leaf, omm) = f1.clone().into_parts();
|
|
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()};
|
|
marshall_to_haskell_var(&f, out, out_len, RW);
|
|
},
|
|
None => {
|
|
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
|
|
marshall_to_haskell_var(&f0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_sapling_commitment_tree(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
node: *const u8,
|
|
node_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let leaf = Node::from_bytes(to_array(tree_in.leaf.bytes)).unwrap();
|
|
let mut comm_tree = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
|
|
let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW);
|
|
let sap_note_comm = SaplingNoteCommitment::from_bytes(&to_array(node_in));
|
|
if sap_note_comm.is_some().into() {
|
|
let n = Node::from_cmu(&sap_note_comm.unwrap());
|
|
comm_tree.append(n);
|
|
let (pos, leaf, omm) = comm_tree.into_parts();
|
|
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()};
|
|
marshall_to_haskell_var(&f, out, out_len, RW);
|
|
} else {
|
|
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
|
|
marshall_to_haskell_var(&f0, out, out_len, RW);
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_sapling_witness(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let leaf = Node::from_bytes(to_array(tree_in.leaf.bytes)).unwrap();
|
|
let frontier: Frontier<Node, SAPLING_DEPTH> = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| Node::from_bytes(to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
|
|
let ct: CommitmentTree<Node, SAPLING_DEPTH> = CommitmentTree::from_frontier(&frontier);
|
|
let inc_wit = IncrementalWitness::from_tree(ct);
|
|
let mut out_bytes: Vec<u8> = Vec::new();
|
|
let result = write_incremental_witness(&inc_wit, &mut out_bytes);
|
|
match result {
|
|
Ok(()) => {
|
|
let h = Hhex { bytes: out_bytes};
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
},
|
|
Err(_e) => {
|
|
let h0 = Hhex { bytes: vec![0]};
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_sapling_position(
|
|
wit: *const u8,
|
|
wit_len: usize,
|
|
) -> u64 {
|
|
let wit_in: Vec<u8> = marshall_from_haskell_var(wit, wit_len, RW);
|
|
let wit_reader = Cursor::new(wit_in);
|
|
let iw: IncrementalWitness<Node, SAPLING_DEPTH> = read_incremental_witness(wit_reader).unwrap();
|
|
let pos = iw.witnessed_position();
|
|
return u64::from(pos);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_update_sapling_witness(
|
|
wit: *const u8,
|
|
wit_len: usize,
|
|
cmus: *const u8,
|
|
cmus_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
) {
|
|
let wit_in: Vec<u8> = marshall_from_haskell_var(wit, wit_len, RW);
|
|
let wit_reader = Cursor::new(wit_in);
|
|
let mut iw: IncrementalWitness<Node, SAPLING_DEPTH> = read_incremental_witness(wit_reader).unwrap();
|
|
let cmu: Vec<Vec<u8>> = marshall_from_haskell_var(cmus, cmus_len, RW);
|
|
for c in cmu {
|
|
let sap_note_comm = SaplingNoteCommitment::from_bytes(&to_array(c));
|
|
if sap_note_comm.is_some().into() {
|
|
let n = Node::from_cmu(&sap_note_comm.unwrap());
|
|
iw.append(n);
|
|
}
|
|
}
|
|
let mut out_bytes: Vec<u8> = Vec::new();
|
|
let result = write_incremental_witness(&iw, &mut out_bytes);
|
|
match result {
|
|
Ok(()) => {
|
|
let h = Hhex { bytes: out_bytes};
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
},
|
|
Err(_e) => {
|
|
let h0 = Hhex { bytes: vec![0]};
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_sapling_node(
|
|
cmu: *const u8,
|
|
cmu_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let node_in: Vec<u8> = marshall_from_haskell_var(cmu, cmu_len, RW);
|
|
let sapling_note_comm = SaplingNoteCommitment::from_bytes(&to_array(node_in));
|
|
if sapling_note_comm.is_some().into() {
|
|
let n = Node::from_cmu(&sapling_note_comm.unwrap());
|
|
let h = Hhex { bytes: n.to_bytes().to_vec()};
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_combine_sapling_nodes(
|
|
level: u8,
|
|
left: *const u8,
|
|
left_len: usize,
|
|
right: *const u8,
|
|
right_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let left_in: Vec<u8> = marshall_from_haskell_var(left, left_len, RW);
|
|
let right_in: Vec<u8> = marshall_from_haskell_var(right, right_len, RW);
|
|
if left_in.len() == 1 {
|
|
let n = Node::combine(Level::new(level), &Node::empty_leaf(), &Node::empty_leaf());
|
|
let h = Hhex { bytes: n.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
} else {
|
|
let left_node = Node::from_bytes(to_array(left_in));
|
|
if left_node.is_some().into() {
|
|
if right_in.len() > 1 {
|
|
let right_node = Node::from_bytes(to_array(right_in));
|
|
if right_node.is_some().into() {
|
|
let n = Node::combine(Level::new(level), &left_node.unwrap(), &right_node.unwrap());
|
|
let h = Hhex { bytes: n.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
} else {
|
|
let n = Node::combine(Level::new(level), &left_node.unwrap(), &Node::empty_leaf());
|
|
let h = Hhex { bytes: n.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
}
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_get_sapling_root(
|
|
level: u8,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree: CommitmentTree<Node, 32> = CommitmentTree::empty();
|
|
let root = tree.root();
|
|
let h = Hhex { bytes: root.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_sapling_commitment_tree_parts(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let tree_reader = Cursor::new(tree_in);
|
|
let comm_tree = read_commitment_tree(tree_reader);
|
|
match comm_tree {
|
|
Ok::<CommitmentTree<Node, 32>, _>(c1) => {
|
|
let left = match c1.left() {
|
|
Some(x) => {
|
|
Hhex { bytes: x.to_bytes().to_vec() }
|
|
},
|
|
None => {
|
|
Hhex { bytes: vec![0] }
|
|
}
|
|
};
|
|
let right = match c1.right() {
|
|
Some(x) => {
|
|
Hhex { bytes: x.to_bytes().to_vec() }
|
|
},
|
|
None => {
|
|
Hhex { bytes: vec![0] }
|
|
}
|
|
};
|
|
let parents = c1.parents().iter().map(|x| match x {
|
|
Some(y) => {
|
|
Hhex { bytes: y.to_bytes().to_vec() }
|
|
},
|
|
None => {
|
|
Hhex { bytes: vec![0] }
|
|
}
|
|
}).collect();
|
|
let ht = Htree { left, right, parents};
|
|
marshall_to_haskell_var(&ht, out, out_len, RW);
|
|
},
|
|
Err(_e) => {
|
|
let ht0 = Htree { left: Hhex { bytes: vec![0] } , right: Hhex { bytes: vec![0] }, parents: vec![Hhex { bytes: vec![0] }]};
|
|
marshall_to_haskell_var(&ht0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_sapling_tree_anchor(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let tree_reader = Cursor::new(tree_in);
|
|
let comm_tree = read_commitment_tree(tree_reader);
|
|
match comm_tree {
|
|
Ok::<CommitmentTree<Node, 32>, _>(c1) => {
|
|
let root = c1.root();
|
|
let h = Hhex { bytes: root.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
},
|
|
Err(_) => {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_sapling_path_anchor(
|
|
path: *const u8,
|
|
path_len: usize,
|
|
cmx: *const u8,
|
|
cmx_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let path_in: Hpath = marshall_from_haskell_var(path, path_len, RW);
|
|
let cmx_in: Vec<u8> = marshall_from_haskell_var(cmx, cmx_len, RW);
|
|
let mk_path = sapling_crypto::MerklePath::from_parts(path_in.path.iter().map(|x| Node::from_bytes(to_array(x.bytes.clone())).unwrap()).collect(), Position::from(u64::from(path_in.position)));
|
|
match mk_path {
|
|
Ok(mp1) => {
|
|
let nc = SaplingNoteCommitment::from_bytes(&to_array(cmx_in));
|
|
if nc.is_some().into() {
|
|
let anchor = mp1.root(Node::from_cmu(&nc.unwrap()));
|
|
let h = Hhex { bytes: anchor.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
},
|
|
Err(_e) =>{
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_frontier(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let tree_reader = Cursor::new(tree_in);
|
|
let comm_tree = read_commitment_tree(tree_reader);
|
|
//let comm_tree = read_frontier_v1(tree_reader);
|
|
//let frontier: Frontier<MerkleHashOrchard, 32> = comm_tree.to_frontier();
|
|
match comm_tree {
|
|
Ok::<CommitmentTree<MerkleHashOrchard, 32>, _>(f1) => {
|
|
let frontier = f1.to_frontier();
|
|
match frontier.value() {
|
|
Some(f2) => {
|
|
let (pos, leaf, omm) = f2.clone().into_parts();
|
|
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()};
|
|
let comm_tree2: Frontier<MerkleHashOrchard,32> = Frontier::from_parts(Position::from(f.position), MerkleHashOrchard::from_bytes(&to_array(f.leaf.bytes.clone())).unwrap(), f.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
|
|
if f1.root() == comm_tree2.root() {
|
|
marshall_to_haskell_var(&f, out, out_len, RW);
|
|
} else {
|
|
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
|
|
marshall_to_haskell_var(&f0, out, out_len, RW);
|
|
}
|
|
},
|
|
None => {
|
|
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
|
|
marshall_to_haskell_var(&f0, out, out_len, RW);
|
|
}
|
|
}
|
|
},
|
|
Err(_e) => {
|
|
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
|
|
marshall_to_haskell_var(&f0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_tree_anchor(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let tree_reader = Cursor::new(tree_in);
|
|
let comm_tree = read_commitment_tree(tree_reader);
|
|
match comm_tree {
|
|
Ok::<CommitmentTree<MerkleHashOrchard, 32>, _>(c1) => {
|
|
let root = c1.root();
|
|
let h = Hhex { bytes: root.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
},
|
|
Err(_) => {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_commitment_tree_parts(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Vec<u8> = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let tree_reader = Cursor::new(tree_in);
|
|
let comm_tree = read_commitment_tree(tree_reader);
|
|
match comm_tree {
|
|
Ok::<CommitmentTree<MerkleHashOrchard, 32>, _>(c1) => {
|
|
let left = match c1.left() {
|
|
Some(x) => {
|
|
Hhex { bytes: x.to_bytes().to_vec() }
|
|
},
|
|
None => {
|
|
Hhex { bytes: vec![0] }
|
|
}
|
|
};
|
|
let right = match c1.right() {
|
|
Some(x) => {
|
|
Hhex { bytes: x.to_bytes().to_vec() }
|
|
},
|
|
None => {
|
|
Hhex { bytes: vec![0] }
|
|
}
|
|
};
|
|
let parents = c1.parents().iter().map(|x| match x {
|
|
Some(y) => {
|
|
Hhex { bytes: y.to_bytes().to_vec() }
|
|
},
|
|
None => {
|
|
Hhex { bytes: vec![0] }
|
|
}
|
|
}).collect();
|
|
let ht = Htree { left, right, parents};
|
|
marshall_to_haskell_var(&ht, out, out_len, RW);
|
|
},
|
|
Err(_e) => {
|
|
let ht0 = Htree { left: Hhex { bytes: vec![0] } , right: Hhex { bytes: vec![0] }, parents: vec![Hhex { bytes: vec![0] }]};
|
|
marshall_to_haskell_var(&ht0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_witness_anchor(
|
|
wit: *const u8,
|
|
wit_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
) {
|
|
let wit_in: Vec<u8> = marshall_from_haskell_var(wit, wit_len, RW);
|
|
let wit_reader = Cursor::new(wit_in);
|
|
let iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap();
|
|
let root = iw.root();
|
|
let h = Hhex { bytes: root.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_node(
|
|
cmx: *const u8,
|
|
cmx_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let node_in: Vec<u8> = marshall_from_haskell_var(cmx, cmx_len, RW);
|
|
let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in));
|
|
if orchard_note_comm.is_some().into() {
|
|
let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap());
|
|
let h = Hhex { bytes: n.to_bytes().to_vec()};
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_path_anchor(
|
|
path: *const u8,
|
|
path_len: usize,
|
|
cmx: *const u8,
|
|
cmx_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let path_in: Hpath = marshall_from_haskell_var(path, path_len, RW);
|
|
let cmx_in: Vec<u8> = marshall_from_haskell_var(cmx, cmx_len, RW);
|
|
let mk_path = orchard::tree::MerklePath::from_parts(path_in.position, to_array(path_in.path.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap()).collect()));
|
|
let nc = ExtractedNoteCommitment::from_bytes(&to_array(cmx_in));
|
|
if nc.is_some().into() {
|
|
let anchor = mk_path.root(nc.unwrap());
|
|
let h = Hhex { bytes: anchor.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_combine_orchard_nodes(
|
|
level: u8,
|
|
left: *const u8,
|
|
left_len: usize,
|
|
right: *const u8,
|
|
right_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let left_in: Vec<u8> = marshall_from_haskell_var(left, left_len, RW);
|
|
let right_in: Vec<u8> = marshall_from_haskell_var(right, right_len, RW);
|
|
if left_in.len() == 1 {
|
|
let n = MerkleHashOrchard::combine(Level::new(level), &MerkleHashOrchard::empty_leaf(), &MerkleHashOrchard::empty_leaf());
|
|
let h = Hhex { bytes: n.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
} else {
|
|
let left_node = MerkleHashOrchard::from_bytes(&to_array(left_in));
|
|
if left_node.is_some().into() {
|
|
if right_in.len() > 1 {
|
|
let right_node = MerkleHashOrchard::from_bytes(&to_array(right_in));
|
|
if right_node.is_some().into() {
|
|
let n = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &right_node.unwrap());
|
|
let h = Hhex { bytes: n.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
} else {
|
|
let n = MerkleHashOrchard::combine(Level::new(level), &left_node.unwrap(), &MerkleHashOrchard::empty_leaf());
|
|
let h = Hhex { bytes: n.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
}
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_get_orchard_root(
|
|
level: u8,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree: CommitmentTree<MerkleHashOrchard, 32> = CommitmentTree::empty();
|
|
let root = tree.root();
|
|
let h = Hhex { bytes: root.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_orchard_add_node(
|
|
level: u8,
|
|
node: *const u8,
|
|
node_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let mut tree: CommitmentTree<MerkleHashOrchard, 32> = CommitmentTree::empty();
|
|
let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW);
|
|
let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in));
|
|
if orchard_note_comm.is_some().into() {
|
|
let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap());
|
|
match tree.append(n) {
|
|
Ok(()) => {
|
|
let root = tree.root_at_depth(level, PathFiller::empty());
|
|
let h = Hhex { bytes: root.to_bytes().to_vec() };
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
},
|
|
Err(_) => {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
} else {
|
|
let h0 = Hhex { bytes: vec![0] };
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_commitment_tree(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
node: *const u8,
|
|
node_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW);
|
|
//let tree_reader = Cursor::new(tree_in);
|
|
//let mut comm_tree: CommitmentTree<MerkleHashOrchard, 32> = read_commitment_tree(tree_reader).unwrap();
|
|
//let mut comm_tree: Frontier<MerkleHashOrchard, 32> = read_frontier_v1(tree_reader).unwrap();
|
|
let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap();
|
|
let mut comm_tree: NonEmptyFrontier<MerkleHashOrchard> = NonEmptyFrontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
|
|
let node_in: Vec<u8> = marshall_from_haskell_var(node, node_len, RW);
|
|
let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(node_in));
|
|
if orchard_note_comm.is_some().into() {
|
|
let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap());
|
|
comm_tree.append(n);
|
|
let (pos, leaf, omm) = comm_tree.into_parts();
|
|
let f = Hfrontier { position: <u64>::from(pos), leaf: Hhex { bytes: leaf.to_bytes().to_vec()}, ommers: omm.iter().map(|&x| Hhex { bytes: x.to_bytes().to_vec()}).collect()};
|
|
marshall_to_haskell_var(&f, out, out_len, RW);
|
|
} else {
|
|
let f0 = Hfrontier { position: 0, leaf: Hhex { bytes: vec![0]}, ommers: vec![Hhex { bytes: vec![0]}]};
|
|
marshall_to_haskell_var(&f0, out, out_len, RW);
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_witness(
|
|
tree: *const u8,
|
|
tree_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
){
|
|
let tree_in: Hfrontier = marshall_from_haskell_var(tree, tree_len, RW);
|
|
let leaf = MerkleHashOrchard::from_bytes(&to_array(tree_in.leaf.bytes)).unwrap();
|
|
let frontier: Frontier<MerkleHashOrchard, 32> = Frontier::from_parts(Position::from(tree_in.position), leaf, tree_in.ommers.iter().map(|x| MerkleHashOrchard::from_bytes(&to_array(x.bytes.clone())).unwrap() ).collect()).unwrap();
|
|
let ct: CommitmentTree<MerkleHashOrchard, 32> = CommitmentTree::from_frontier(&frontier);
|
|
let inc_wit = IncrementalWitness::from_tree(ct);
|
|
let mut out_bytes: Vec<u8> = Vec::new();
|
|
let result = write_incremental_witness(&inc_wit, &mut out_bytes);
|
|
match result {
|
|
Ok(()) => {
|
|
let h = Hhex { bytes: out_bytes};
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
},
|
|
Err(_e) => {
|
|
let h0 = Hhex { bytes: vec![0]};
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_read_orchard_position(
|
|
wit: *const u8,
|
|
wit_len: usize,
|
|
) -> u64 {
|
|
let wit_in: Vec<u8> = marshall_from_haskell_var(wit, wit_len, RW);
|
|
let wit_reader = Cursor::new(wit_in);
|
|
let iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap();
|
|
let path = iw.path();
|
|
match path {
|
|
Some(p) => {
|
|
let pos = p.position();
|
|
return u64::from(pos);
|
|
},
|
|
None => {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_update_orchard_witness(
|
|
wit: *const u8,
|
|
wit_len: usize,
|
|
cm: *const u8,
|
|
cm_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize
|
|
) {
|
|
let wit_in: Vec<u8> = marshall_from_haskell_var(wit, wit_len, RW);
|
|
let wit_reader = Cursor::new(wit_in);
|
|
let mut iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap();
|
|
let cmu: Vec<Vec<u8>> = marshall_from_haskell_var(cm, cm_len, RW);
|
|
for c in cmu {
|
|
let orchard_note_comm = ExtractedNoteCommitment::from_bytes(&to_array(c));
|
|
if orchard_note_comm.is_some().into() {
|
|
let n = MerkleHashOrchard::from_cmx(&orchard_note_comm.unwrap());
|
|
iw.append(n);
|
|
}
|
|
}
|
|
let mut out_bytes: Vec<u8> = Vec::new();
|
|
let result = write_incremental_witness(&iw, &mut out_bytes);
|
|
match result {
|
|
Ok(()) => {
|
|
let h = Hhex { bytes: out_bytes};
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
},
|
|
Err(_e) => {
|
|
let h0 = Hhex { bytes: vec![0]};
|
|
marshall_to_haskell_var(&h0, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_decode_sapling_address(
|
|
sapling: *const u8,
|
|
sapling_len: usize,
|
|
out: *mut u8,
|
|
out_len: &mut usize){
|
|
let sapling_address_from_haskell : Vec<u8> = marshall_from_haskell_var(sapling, sapling_len, RW);
|
|
let sapling_address = std::str::from_utf8(&sapling_address_from_haskell).unwrap();
|
|
|
|
let mut netid = 0;
|
|
match sapling_address.find("1") {
|
|
Some(ix) => {
|
|
let netstr = &sapling_address[0..ix];
|
|
if netstr == "zs" {
|
|
netid = 1
|
|
} else {
|
|
if netstr == "ztestsapling" {
|
|
netid = 2
|
|
}
|
|
}
|
|
match decode_payment_address(netstr, sapling_address) {
|
|
Ok( t )=> {
|
|
let address_to_bytes = t.to_bytes();
|
|
let mut out_bytes_temp : [u8;44] = [0;44];
|
|
out_bytes_temp[0] = netid;
|
|
let mut iy = 1;
|
|
for ix in 0..43 {
|
|
out_bytes_temp[iy] = address_to_bytes[ix];
|
|
iy += 1;
|
|
}
|
|
let out_bytes: Vec<u8> = out_bytes_temp.to_vec();
|
|
marshall_to_haskell_var(&out_bytes, out, out_len, RW);
|
|
}
|
|
Err(_e) => {
|
|
let h = vec![0];
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
None => {
|
|
let h = vec![0];
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub extern "C" fn rust_wrapper_create_transaction(
|
|
sap_wit: *const u8,
|
|
sap_wit_len: usize,
|
|
orch_wit: *const u8,
|
|
orch_wit_len: usize,
|
|
t_input: *const u8,
|
|
t_input_len: usize,
|
|
s_input: *const u8,
|
|
s_input_len: usize,
|
|
o_input: *const u8,
|
|
o_input_len: usize,
|
|
out_list: *const u8,
|
|
out_list_len: usize,
|
|
net: bool,
|
|
bl_height: u32,
|
|
build: bool,
|
|
out: *mut u8,
|
|
out_len: &mut usize){
|
|
let sap_input: Vec<HsaplingInput> = marshall_from_haskell_var(s_input, s_input_len, RW);
|
|
let sap_anchor =
|
|
if sap_input.is_empty() {
|
|
let sap_wit_in: Vec<u8> = marshall_from_haskell_var(sap_wit, sap_wit_len, RW);
|
|
let sap_wit_reader = Cursor::new(sap_wit_in);
|
|
let sap_iw = read_commitment_tree::<Node, Cursor<Vec<u8>>, SAPLING_DEPTH>(sap_wit_reader);
|
|
match sap_iw {
|
|
Ok(s_iw) => {
|
|
Some(SaplingAnchor::from(s_iw.root()))
|
|
},
|
|
Err(_e) => {
|
|
None
|
|
}
|
|
}
|
|
} else {
|
|
let si = &sap_input[0];
|
|
let swit_reader = Cursor::new(&si.iw);
|
|
let iw: IncrementalWitness<Node, SAPLING_DEPTH> = read_incremental_witness(swit_reader).unwrap();
|
|
Some(SaplingAnchor::from(iw.root()))
|
|
};
|
|
//println!("{:?}", sap_anchor);
|
|
let orch_input: Vec<HorchardInput> = marshall_from_haskell_var(o_input, o_input_len, RW);
|
|
let orch_anchor =
|
|
if orch_input.is_empty() {
|
|
let orch_wit_in: Vec<u8> = marshall_from_haskell_var(orch_wit, orch_wit_len, RW);
|
|
let orch_wit_reader = Cursor::new(orch_wit_in);
|
|
let orch_iw = read_commitment_tree::<MerkleHashOrchard, Cursor<Vec<u8>>, 32>(orch_wit_reader);
|
|
match orch_iw {
|
|
Ok(o_iw) => {
|
|
Some(OrchardAnchor::from(o_iw.root()))
|
|
},
|
|
Err(_e) => {
|
|
None
|
|
}
|
|
}
|
|
} else {
|
|
let oi = &orch_input[0];
|
|
let wit_reader = Cursor::new(&oi.iw);
|
|
let iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap();
|
|
Some(OrchardAnchor::from(iw.root()))
|
|
};
|
|
let build_config = BuildConfig::Standard {sapling_anchor: sap_anchor, orchard_anchor: orch_anchor};
|
|
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 trans_input: Vec<HtransparentInput> = marshall_from_haskell_var(t_input, t_input_len, RW);
|
|
for t_in in trans_input {
|
|
if t_in.sk.len() > 1 {
|
|
//println!("t inp: {:?}", t_in);
|
|
let k = SecretKey::from_slice(&t_in.sk).unwrap();
|
|
if net {
|
|
match main_builder.add_transparent_input(k, t_in.utxo.unpack(), t_in.coin.unpack()) {
|
|
Ok(()) => {
|
|
//println!("added t-input in main");
|
|
continue;
|
|
},
|
|
Err(_e) => { println!("Error reading transparent input"); }
|
|
}
|
|
} else {
|
|
match test_builder.add_transparent_input(k, t_in.utxo.unpack(), t_in.coin.unpack()) {
|
|
Ok(()) => {
|
|
//println!("added t-input in test");
|
|
continue;
|
|
},
|
|
Err(_e) => { println!("Error reading transparent input"); }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for s_in in sap_input {
|
|
if s_in.sk.len() > 1 {
|
|
//println!("s inp: {:?}", s_in);
|
|
let sp_key = ExtendedSpendingKey::from_bytes(&s_in.sk);
|
|
match sp_key {
|
|
Ok(sk) => {
|
|
let pay_addr = PaymentAddress::from_bytes(&to_array(s_in.note.recipient)).unwrap();
|
|
let rseed = if s_in.note.rseed.kind == 1 {
|
|
Rseed::BeforeZip212(Fr::from_bytes(&to_array(s_in.note.rseed.bytes)).unwrap())
|
|
} else {
|
|
Rseed::AfterZip212(to_array(s_in.note.rseed.bytes))
|
|
};
|
|
let note = SaplingNote::from_parts(pay_addr, SaplingNoteValue::from_raw(s_in.note.note), rseed);
|
|
let wit_reader = Cursor::new(s_in.iw);
|
|
let iw: IncrementalWitness<Node, SAPLING_DEPTH> = read_incremental_witness(wit_reader).unwrap();
|
|
let merkle_path = iw.path().unwrap();
|
|
if net {
|
|
let mb = main_builder.add_sapling_spend::<String>(&sk, note, merkle_path);
|
|
match mb {
|
|
Ok(()) => {
|
|
continue;
|
|
},
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![5]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
} else {
|
|
let tb = test_builder.add_sapling_spend::<String>(&sk, note, merkle_path);
|
|
match tb {
|
|
Ok(()) => {
|
|
continue;
|
|
},
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![5]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![5]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
for o_in in orch_input {
|
|
if o_in.sk.len() > 1 {
|
|
let sp_key = SpendingKey::from_bytes(o_in.sk[0..32].try_into().unwrap()).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 rseed = RandomSeed::from_bytes(to_array(o_in.note.rseed.bytes), &rho).unwrap();
|
|
let val = NoteValue::from_raw(o_in.note.note);
|
|
//println!("o inp: {:?}", val);
|
|
let note = Note::from_parts(pay_addr, val, rho, rseed).unwrap();
|
|
let wit_reader = Cursor::new(o_in.iw);
|
|
let iw: IncrementalWitness<MerkleHashOrchard, 32> = read_incremental_witness(wit_reader).unwrap();
|
|
let merkle_path = OrchardMerklePath::from(iw.path().unwrap());
|
|
if net {
|
|
let mb = main_builder.add_orchard_spend::<String>(&sp_key, note, merkle_path);
|
|
match mb {
|
|
Ok(()) => {
|
|
continue;
|
|
},
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![7]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
} else {
|
|
let tb = test_builder.add_orchard_spend::<String>(&sp_key, note, merkle_path);
|
|
match tb {
|
|
Ok(()) => {
|
|
continue;
|
|
},
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![7]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
let outputs: Vec<Houtput> = marshall_from_haskell_var(out_list, out_list_len, RW);
|
|
for output in outputs {
|
|
match output.kind {
|
|
1 => {
|
|
let recipient = TransparentAddress::PublicKeyHash(to_array(output.to));
|
|
let val = NonNegativeAmount::from_u64(output.amt).unwrap();
|
|
//println!("t out: {:?} {:?}", val, output.chg);
|
|
if net {
|
|
let mb = main_builder.add_transparent_output(&recipient, val);
|
|
match mb {
|
|
Ok(()) => { continue; },
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![4]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
} else {
|
|
let tb = test_builder.add_transparent_output(&recipient, val);
|
|
match tb {
|
|
Ok(()) => { continue; },
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![4]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
2 => {
|
|
let recipient = TransparentAddress::ScriptHash(to_array(output.to));
|
|
let val = NonNegativeAmount::from_u64(output.amt).unwrap();
|
|
//println!("t out: {:?} {:?}", val, output.chg);
|
|
if net {
|
|
let mb = main_builder.add_transparent_output(&recipient, val);
|
|
match mb {
|
|
Ok(()) => { continue; },
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![4]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
} else {
|
|
let tb = test_builder.add_transparent_output(&recipient, val);
|
|
match tb {
|
|
Ok(()) => { continue; },
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![4]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
3 => {
|
|
let ovk = Some(ExpandedSpendingKey::from_spending_key(&output.ovk).ovk);
|
|
let recipient = PaymentAddress::from_bytes(&to_array(output.to)).unwrap();
|
|
let val = NonNegativeAmount::from_u64(output.amt).unwrap();
|
|
let memo = MemoBytes::from_bytes(&output.memo).unwrap();
|
|
//println!("s out: {:?} {:?}", val, output.chg);
|
|
if net {
|
|
let mb = main_builder.add_sapling_output::<String>(ovk, recipient, val, memo);
|
|
match mb {
|
|
Ok(()) => { continue; },
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![5]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
} else {
|
|
let tb = test_builder.add_sapling_output::<String>(ovk, recipient, val, memo);
|
|
match tb {
|
|
Ok(()) => { continue; },
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![5]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
//println!("add sap: {:?}", tb);
|
|
}
|
|
},
|
|
4 => {
|
|
let sk = SpendingKey::from_bytes(output.ovk[0..32].try_into().unwrap()).unwrap();
|
|
let ovk = if output.chg {
|
|
Some(FullViewingKey::from(&sk).to_ovk(Scope::Internal))
|
|
} else {
|
|
Some(FullViewingKey::from(&sk).to_ovk(Scope::External))
|
|
};
|
|
let recipient = OrchardAddress::from_raw_address_bytes(&to_array(output.to)).unwrap();
|
|
let val = output.amt;
|
|
//println!("o out: {:?} {:?}", val, output.chg);
|
|
let memo = MemoBytes::from_bytes(&output.memo).unwrap();
|
|
if net {
|
|
let mb = main_builder.add_orchard_output::<String>(ovk, recipient, val, memo);
|
|
match mb {
|
|
Ok(()) => { continue; },
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![6]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
} else {
|
|
let tb = test_builder.add_orchard_output::<String>(ovk, recipient, val, memo);
|
|
match tb {
|
|
Ok(()) => { continue; },
|
|
Err(_e) => {
|
|
let x = Hhex {bytes: vec![6]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
},
|
|
_ => {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
if build {
|
|
//let fee_result = if net {
|
|
//main_builder.get_fee(&FeeRule::standard())
|
|
//} else {
|
|
//test_builder.get_fee(&FeeRule::standard())
|
|
//};
|
|
//println!("fee: {:?}", fee_result);
|
|
let (spend_params_in, output_params_in) = load_sapling_parameters();
|
|
//let spend_params_in: Vec<u8> = marshall_from_haskell_var(sapspend, sapspend_len, RW);
|
|
let spend_params_reader = Cursor::new(spend_params_in);
|
|
let spend_prover = SpendParameters::read(spend_params_reader, false).unwrap();
|
|
//let output_params_in: Vec<u8> = marshall_from_haskell_var(sapoutput, sapoutput_len, RW);
|
|
let output_params_reader = Cursor::new(output_params_in);
|
|
let output_prover = OutputParameters::read(output_params_reader, false).unwrap();
|
|
let result = if net {
|
|
main_builder.build(OsRng, &spend_prover, &output_prover, &FeeRule::standard())
|
|
} else {
|
|
test_builder.build(OsRng, &spend_prover, &output_prover, &FeeRule::standard())
|
|
};
|
|
match result {
|
|
Ok(r) => {
|
|
let mut out_bytes: Vec<u8> = Vec::new();
|
|
let _t = r.transaction().write_v5(&mut out_bytes);
|
|
let h = Hhex {bytes: out_bytes};
|
|
marshall_to_haskell_var(&h, out, out_len, RW);
|
|
},
|
|
Err(e) => {
|
|
match e {
|
|
Error::InsufficientFunds(y) => {
|
|
let x = Hhex {bytes: vec![0]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::ChangeRequired(y1) => {
|
|
//println!("change req: {:?}", y1);
|
|
let x = Hhex {bytes: vec![1]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::Fee(_y2) => {
|
|
let x = Hhex {bytes: vec![2]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::Balance(y3) => {
|
|
let x = Hhex {bytes: vec![3]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::TransparentBuild(y4) => {
|
|
let x = Hhex {bytes: vec![4]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::SaplingBuild(y5) => {
|
|
let x = Hhex {bytes: vec![5]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::OrchardBuild(y7) => {
|
|
let x = Hhex {bytes: vec![6]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::OrchardSpend(y8) => {
|
|
let x = Hhex {bytes: vec![7]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::OrchardRecipient(y9) => {
|
|
let x = Hhex {bytes: vec![8]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::SaplingBuilderNotAvailable => {
|
|
let x = Hhex {bytes: vec![9]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Error::OrchardBuilderNotAvailable => {
|
|
let x = Hhex {bytes: vec![10]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
let result = if net {
|
|
main_builder.get_fee(&FeeRule::standard())
|
|
} else {
|
|
test_builder.get_fee(&FeeRule::standard())
|
|
};
|
|
match result {
|
|
Ok(r) => {
|
|
let x = Hhex {bytes: r.to_i64_le_bytes().to_vec()};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
},
|
|
Err(e) => {
|
|
let x = Hhex {bytes: vec![2]};
|
|
marshall_to_haskell_var(&x, out, out_len, RW);
|
|
}
|
|
}
|
|
}
|
|
}
|