149 lines
4.9 KiB
Rust
149 lines
4.9 KiB
Rust
//! Contains code that interfaces with the zcash_primitives crate from
|
|
//! librustzcash.
|
|
|
|
use std::{
|
|
convert::{TryFrom, TryInto},
|
|
io,
|
|
ops::Deref,
|
|
};
|
|
|
|
use crate::{
|
|
amount::{Amount, NonNegative},
|
|
parameters::NetworkUpgrade,
|
|
serialization::ZcashSerialize,
|
|
transaction::{AuthDigest, HashType, SigHash, Transaction},
|
|
transparent::{self, Script},
|
|
};
|
|
|
|
impl TryFrom<&Transaction> for zcash_primitives::transaction::Transaction {
|
|
type Error = io::Error;
|
|
|
|
/// Convert a Zebra transaction into a librustzcash one.
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If the transaction is not V5. (Currently there is no need for this
|
|
/// conversion for other versions.)
|
|
fn try_from(trans: &Transaction) -> Result<Self, Self::Error> {
|
|
let network_upgrade = match trans {
|
|
Transaction::V5 {
|
|
network_upgrade, ..
|
|
} => network_upgrade,
|
|
Transaction::V1 { .. }
|
|
| Transaction::V2 { .. }
|
|
| Transaction::V3 { .. }
|
|
| Transaction::V4 { .. } => panic!("Zebra only uses librustzcash for V5 transactions"),
|
|
};
|
|
|
|
convert_tx_to_librustzcash(trans, *network_upgrade)
|
|
}
|
|
}
|
|
|
|
pub(crate) fn convert_tx_to_librustzcash(
|
|
trans: &Transaction,
|
|
network_upgrade: NetworkUpgrade,
|
|
) -> Result<zcash_primitives::transaction::Transaction, io::Error> {
|
|
let serialized_tx = trans.zcash_serialize_to_vec()?;
|
|
let branch_id: u32 = network_upgrade
|
|
.branch_id()
|
|
.expect("Network upgrade must have a Branch ID")
|
|
.into();
|
|
// We've already parsed this transaction, so its network upgrade must be valid.
|
|
let branch_id: zcash_primitives::consensus::BranchId = branch_id
|
|
.try_into()
|
|
.expect("zcash_primitives and Zebra have the same branch ids");
|
|
let alt_tx = zcash_primitives::transaction::Transaction::read(&serialized_tx[..], branch_id)?;
|
|
Ok(alt_tx)
|
|
}
|
|
|
|
/// Convert a Zebra Amount into a librustzcash one.
|
|
impl TryFrom<Amount<NonNegative>> for zcash_primitives::transaction::components::Amount {
|
|
type Error = ();
|
|
|
|
fn try_from(amount: Amount<NonNegative>) -> Result<Self, Self::Error> {
|
|
zcash_primitives::transaction::components::Amount::from_u64(amount.into())
|
|
}
|
|
}
|
|
|
|
/// Convert a Zebra Script into a librustzcash one.
|
|
impl From<&Script> for zcash_primitives::legacy::Script {
|
|
fn from(script: &Script) -> Self {
|
|
zcash_primitives::legacy::Script(script.as_raw_bytes().to_vec())
|
|
}
|
|
}
|
|
|
|
/// Compute a signature hash using librustzcash.
|
|
///
|
|
/// # Inputs
|
|
///
|
|
/// - `transaction`: the transaction whose signature hash to compute.
|
|
/// - `hash_type`: the type of hash (SIGHASH) being used.
|
|
/// - `network_upgrade`: the network upgrade of the block containing the transaction.
|
|
/// - `input`: information about the transparent input for which this signature
|
|
/// hash is being computed, if any. A tuple with the matching output of the
|
|
/// previous transaction, the input itself, and the index of the input in
|
|
/// the transaction.
|
|
pub(crate) fn sighash(
|
|
trans: &Transaction,
|
|
hash_type: HashType,
|
|
network_upgrade: NetworkUpgrade,
|
|
input: Option<(&transparent::Output, &transparent::Input, usize)>,
|
|
) -> SigHash {
|
|
let alt_tx = convert_tx_to_librustzcash(trans, network_upgrade)
|
|
.expect("zcash_primitives and Zebra transaction formats must be compatible");
|
|
|
|
let script: zcash_primitives::legacy::Script;
|
|
let signable_input = match input {
|
|
Some((output, _, idx)) => {
|
|
script = (&output.lock_script).into();
|
|
zcash_primitives::transaction::sighash::SignableInput::Transparent(
|
|
zcash_primitives::transaction::sighash::TransparentInput::new(
|
|
idx,
|
|
&script,
|
|
output
|
|
.value
|
|
.try_into()
|
|
.expect("amount was previously validated"),
|
|
),
|
|
)
|
|
}
|
|
None => zcash_primitives::transaction::sighash::SignableInput::Shielded,
|
|
};
|
|
|
|
let txid_parts = alt_tx
|
|
.deref()
|
|
.digest(zcash_primitives::transaction::txid::TxIdDigester);
|
|
|
|
SigHash(
|
|
*zcash_primitives::transaction::sighash::signature_hash(
|
|
alt_tx.deref(),
|
|
hash_type.bits(),
|
|
&signable_input,
|
|
&txid_parts,
|
|
)
|
|
.as_ref(),
|
|
)
|
|
}
|
|
|
|
/// Compute the authorizing data commitment of this transaction as specified
|
|
/// in [ZIP-244].
|
|
///
|
|
/// # Panics
|
|
///
|
|
/// If passed a pre-v5 transaction.
|
|
///
|
|
/// [ZIP-244]: https://zips.z.cash/zip-0244.
|
|
pub(crate) fn auth_digest(trans: &Transaction) -> AuthDigest {
|
|
let alt_tx: zcash_primitives::transaction::Transaction = trans
|
|
.try_into()
|
|
.expect("zcash_primitives and Zebra transaction formats must be compatible");
|
|
|
|
let digest_bytes: [u8; 32] = alt_tx
|
|
.auth_commitment()
|
|
.as_ref()
|
|
.try_into()
|
|
.expect("digest has the correct size");
|
|
|
|
AuthDigest(digest_bytes)
|
|
}
|