Use generalized signature_hash for transaction builder.
This commit is contained in:
parent
55d1090f70
commit
1a5aad723b
|
@ -8,6 +8,7 @@ use crate::encoding::{
|
|||
};
|
||||
|
||||
/// An address that funds can be sent to.
|
||||
// TODO: rename to ParsedAddress
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum RecipientAddress {
|
||||
Shielded(PaymentAddress),
|
||||
|
|
|
@ -44,7 +44,7 @@ pub fn decrypt_transaction<P: consensus::Parameters>(
|
|||
) -> Vec<DecryptedOutput> {
|
||||
let mut decrypted = vec![];
|
||||
|
||||
if let Some(bundle) = tx.sapling_bundle().as_ref() {
|
||||
if let Some(bundle) = tx.sapling_bundle() {
|
||||
for (account, extfvk) in extfvks.iter() {
|
||||
let ivk = extfvk.fvk.vk.ivk();
|
||||
let ovk = extfvk.fvk.ovk;
|
||||
|
|
|
@ -489,7 +489,7 @@ impl<'a, P: consensus::Parameters> WalletWrite for DataConnStmtCache<'a, P> {
|
|||
//
|
||||
// Assumes that create_spend_to_address() will never be called in parallel, which is a
|
||||
// reasonable assumption for a light client such as a mobile phone.
|
||||
if let Some(bundle) = sent_tx.tx.sapling_bundle().as_ref() {
|
||||
if let Some(bundle) = sent_tx.tx.sapling_bundle() {
|
||||
for spend in &bundle.shielded_spends {
|
||||
wallet::mark_spent(up, tx_ref, &spend.nullifier)?;
|
||||
}
|
||||
|
|
|
@ -631,8 +631,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
let output =
|
||||
&tx.sapling_bundle().as_ref().unwrap().shielded_outputs[output_index as usize];
|
||||
let output = &tx.sapling_bundle().unwrap().shielded_outputs[output_index as usize];
|
||||
|
||||
try_sapling_output_recovery(
|
||||
&network,
|
||||
|
|
|
@ -10,7 +10,7 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
blake2b_simd = "0.5"
|
||||
zcash_primitives = { version = "0.5", path = "../zcash_primitives", features = ["zfuture"] }
|
||||
zcash_primitives = { version = "0.5", path = "../zcash_primitives", features = ["zfuture", "test-dependencies"] }
|
||||
|
||||
[dev-dependencies]
|
||||
ff = "0.10"
|
||||
|
|
|
@ -85,7 +85,7 @@ impl<'a> demo::Context for Context<'a> {
|
|||
}
|
||||
|
||||
fn tx_tze_outputs(&self) -> &[TzeOut] {
|
||||
if let Some(bundle) = &self.tx.tze_bundle() {
|
||||
if let Some(bundle) = self.tx.tze_bundle() {
|
||||
&bundle.vout
|
||||
} else {
|
||||
&[]
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
//! Structs for building transactions.
|
||||
|
||||
use rand::{rngs::OsRng, CryptoRng, RngCore};
|
||||
use std::array;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use orchard::bundle::{self as orchard};
|
||||
#[cfg(not(feature = "zfuture"))]
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use rand::{rngs::OsRng, CryptoRng, RngCore};
|
||||
|
||||
use crate::{
|
||||
consensus::{self, BlockHeight, BranchId},
|
||||
|
@ -27,16 +29,13 @@ use crate::{
|
|||
},
|
||||
transparent::{self, builder::TransparentBuilder},
|
||||
},
|
||||
sighash::{SignableInput, SIGHASH_ALL},
|
||||
sighash_v4::v4_signature_hash,
|
||||
sighash::{signature_hash, SignableInput, SIGHASH_ALL},
|
||||
txid::TxIdDigester,
|
||||
Transaction, TransactionData, TxVersion, Unauthorized,
|
||||
},
|
||||
zip32::ExtendedSpendingKey,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "zfuture"))]
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
use crate::{legacy::Script, transaction::components::transparent::TxOut};
|
||||
|
||||
|
@ -280,11 +279,6 @@ impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
|
|||
///
|
||||
/// Upon success, returns a tuple containing the final transaction, and the
|
||||
/// [`SaplingMetadata`] generated during the build process.
|
||||
///
|
||||
/// `consensus_branch_id` must be valid for the block height that this transaction is
|
||||
/// targeting. An invalid `consensus_branch_id` will *not* result in an error from
|
||||
/// this function, and instead will generate a transaction that will be rejected by
|
||||
/// the network.
|
||||
pub fn build(
|
||||
mut self,
|
||||
prover: &impl TxProver,
|
||||
|
@ -343,7 +337,7 @@ impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
|
|||
|
||||
let unauthed_tx = TransactionData {
|
||||
version,
|
||||
consensus_branch_id,
|
||||
consensus_branch_id: BranchId::for_height(&self.params, self.target_height),
|
||||
lock_time: 0,
|
||||
expiry_height: self.expiry_height,
|
||||
transparent_bundle,
|
||||
|
@ -357,18 +351,32 @@ impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
|
|||
//
|
||||
// Signatures -- everything but the signatures must already have been added.
|
||||
//
|
||||
|
||||
let mut sighash = [0u8; 32];
|
||||
sighash.copy_from_slice(
|
||||
&v4_signature_hash(&unauthed_tx, SignableInput::Shielded, SIGHASH_ALL).as_ref(),
|
||||
);
|
||||
let txid_parts = unauthed_tx.digest(TxIdDigester);
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
let transparent_sigs = self.transparent_builder.create_signatures(&unauthed_tx);
|
||||
let transparent_sigs = self
|
||||
.transparent_builder
|
||||
.create_signatures(&unauthed_tx, &txid_parts);
|
||||
|
||||
// the commitment being signed is shared across all Sapling inputs; once
|
||||
// V4 transactions are deprecated this should just be the txid, but
|
||||
// for now we need to continue to compute it here.
|
||||
let shielded_sig_commitment = signature_hash(
|
||||
&unauthed_tx,
|
||||
SignableInput::Shielded,
|
||||
&txid_parts,
|
||||
SIGHASH_ALL,
|
||||
);
|
||||
|
||||
let sapling_sigs = self
|
||||
.sapling_builder
|
||||
.create_signatures(prover, &mut ctx, &mut self.rng, &sighash, &tx_metadata)
|
||||
.create_signatures(
|
||||
prover,
|
||||
&mut ctx,
|
||||
&mut self.rng,
|
||||
shielded_sig_commitment.as_ref(),
|
||||
&tx_metadata,
|
||||
)
|
||||
.map_err(Error::SaplingBuild)?;
|
||||
|
||||
#[cfg(feature = "zfuture")]
|
||||
|
@ -380,10 +388,9 @@ impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
|
|||
Ok((
|
||||
Self::apply_signatures(
|
||||
unauthed_tx,
|
||||
sapling_sigs,
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
transparent_sigs,
|
||||
sapling_sigs,
|
||||
None,
|
||||
#[cfg(feature = "zfuture")]
|
||||
tze_witnesses,
|
||||
)
|
||||
|
@ -392,26 +399,18 @@ impl<'a, P: consensus::Parameters, R: RngCore> Builder<'a, P, R> {
|
|||
))
|
||||
}
|
||||
|
||||
fn apply_signatures(
|
||||
pub fn apply_signatures(
|
||||
unauthed_tx: TransactionData<Unauthorized>,
|
||||
#[cfg(feature = "transparent-inputs")] transparent_sigs: Option<Vec<Script>>,
|
||||
sapling_sigs: Option<(Vec<redjubjub::Signature>, redjubjub::Signature)>,
|
||||
_orchard_auth: Option<(
|
||||
Vec<<orchard::Authorized as orchard::Authorization>::SpendAuth>,
|
||||
orchard::Authorized,
|
||||
)>,
|
||||
#[cfg(feature = "transparent-inputs")] transparent_sigs: Option<Vec<Script>>,
|
||||
#[cfg(feature = "zfuture")] tze_witnesses: Option<Vec<AuthData>>,
|
||||
) -> io::Result<Transaction> {
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
let transparent_bundle = match (unauthed_tx.transparent_bundle, transparent_sigs) {
|
||||
(Some(bundle), Some(script_sigs)) => Some(bundle.apply_signatures(script_sigs)),
|
||||
(None, None) => None,
|
||||
(b, s) => {
|
||||
panic!(
|
||||
"Mismatch between transparent bundle ({}) and signatures ({}).",
|
||||
b.is_some(),
|
||||
s.is_some()
|
||||
);
|
||||
_ => {
|
||||
panic!("Mismatch between transparent bundle and signatures.");
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -526,19 +525,19 @@ mod tests {
|
|||
transaction::components::{
|
||||
amount::{Amount, DEFAULT_FEE},
|
||||
sapling::builder::{self as build_s},
|
||||
transparent::builder::{self as transparent},
|
||||
transparent::builder::{self as build_t},
|
||||
},
|
||||
zip32::{ExtendedFullViewingKey, ExtendedSpendingKey},
|
||||
};
|
||||
|
||||
use super::{Builder, Error, SaplingBuilder, DEFAULT_TX_EXPIRY_DELTA};
|
||||
|
||||
#[cfg(not(feature = "zfuture"))]
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[cfg(feature = "zfuture")]
|
||||
use super::TzeBuilder;
|
||||
|
||||
#[cfg(not(feature = "zfuture"))]
|
||||
use std::marker::PhantomData;
|
||||
|
||||
#[test]
|
||||
fn fails_on_negative_output() {
|
||||
let extsk = ExtendedSpendingKey::master(&[]);
|
||||
|
@ -642,7 +641,7 @@ mod tests {
|
|||
&TransparentAddress::PublicKey([0; 20]),
|
||||
Amount::from_i64(-1).unwrap(),
|
||||
),
|
||||
Err(Error::TransparentBuild(transparent::Error::InvalidAmount))
|
||||
Err(Error::TransparentBuild(build_t::Error::InvalidAmount))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
use std::fmt;
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
use blake2b_simd::Hash as Blake2bHash;
|
||||
|
||||
use crate::{
|
||||
legacy::TransparentAddress,
|
||||
transaction::components::{
|
||||
|
@ -15,9 +18,8 @@ use crate::{
|
|||
legacy::Script,
|
||||
transaction::{
|
||||
components::OutPoint,
|
||||
sighash::{SignableInput, SIGHASH_ALL},
|
||||
sighash_v4::v4_signature_hash,
|
||||
TransactionData, Unauthorized,
|
||||
sighash::{signature_hash, SignableInput, SIGHASH_ALL},
|
||||
TransactionData, TxDigests, Unauthorized,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -154,7 +156,11 @@ impl TransparentBuilder {
|
|||
}
|
||||
|
||||
#[cfg(feature = "transparent-inputs")]
|
||||
pub fn create_signatures(self, mtx: &TransactionData<Unauthorized>) -> Option<Vec<Script>> {
|
||||
pub fn create_signatures(
|
||||
self,
|
||||
mtx: &TransactionData<Unauthorized>,
|
||||
txid_parts_cache: &TxDigests<Blake2bHash>,
|
||||
) -> Option<Vec<Script>> {
|
||||
if self.inputs.is_empty() && self.vout.is_empty() {
|
||||
None
|
||||
} else {
|
||||
|
@ -163,18 +169,15 @@ impl TransparentBuilder {
|
|||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, info)| {
|
||||
let mut sighash = [0u8; 32];
|
||||
sighash.copy_from_slice(
|
||||
&v4_signature_hash(
|
||||
mtx,
|
||||
SignableInput::transparent(
|
||||
i,
|
||||
&info.coin.script_pubkey,
|
||||
info.coin.value,
|
||||
),
|
||||
SIGHASH_ALL,
|
||||
)
|
||||
.as_ref(),
|
||||
let sighash = signature_hash(
|
||||
mtx,
|
||||
SignableInput::transparent(
|
||||
i,
|
||||
&info.coin.script_pubkey,
|
||||
info.coin.value,
|
||||
),
|
||||
txid_parts_cache,
|
||||
SIGHASH_ALL,
|
||||
);
|
||||
|
||||
let msg =
|
||||
|
|
Loading…
Reference in New Issue