ZIP 243
This commit is contained in:
parent
2d8b1fe504
commit
0c81695731
|
@ -1,9 +1,10 @@
|
||||||
use blake2_rfc::blake2b::Blake2b;
|
use blake2_rfc::blake2b::Blake2b;
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
use byteorder::{LittleEndian, WriteBytesExt};
|
||||||
|
use pairing::{PrimeField, PrimeFieldRepr};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
components::{Amount, Script},
|
components::{Amount, Script},
|
||||||
Transaction, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION,
|
Transaction, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION, SAPLING_VERSION_GROUP_ID,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash";
|
const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash";
|
||||||
|
@ -11,6 +12,8 @@ const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHas
|
||||||
const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash";
|
const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash";
|
||||||
const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash";
|
const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash";
|
||||||
const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash";
|
const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash";
|
||||||
|
const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSSpendsHash";
|
||||||
|
const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSOutputHash";
|
||||||
|
|
||||||
pub const SIGHASH_ALL: u32 = 1;
|
pub const SIGHASH_ALL: u32 = 1;
|
||||||
const SIGHASH_NONE: u32 = 2;
|
const SIGHASH_NONE: u32 = 2;
|
||||||
|
@ -25,6 +28,13 @@ macro_rules! update_u32 {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! update_i64 {
|
||||||
|
($h:expr, $value:expr, $tmp:expr) => {
|
||||||
|
(&mut $tmp[..8]).write_i64::<LittleEndian>($value).unwrap();
|
||||||
|
$h.update(&$tmp[..8]);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! update_hash {
|
macro_rules! update_hash {
|
||||||
($h:expr, $cond:expr, $value:expr) => {
|
($h:expr, $cond:expr, $value:expr) => {
|
||||||
if $cond {
|
if $cond {
|
||||||
|
@ -39,6 +49,7 @@ macro_rules! update_hash {
|
||||||
enum SigHashVersion {
|
enum SigHashVersion {
|
||||||
Sprout,
|
Sprout,
|
||||||
Overwinter,
|
Overwinter,
|
||||||
|
Sapling,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SigHashVersion {
|
impl SigHashVersion {
|
||||||
|
@ -46,6 +57,7 @@ impl SigHashVersion {
|
||||||
if tx.overwintered {
|
if tx.overwintered {
|
||||||
match tx.version_group_id {
|
match tx.version_group_id {
|
||||||
OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter,
|
OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter,
|
||||||
|
SAPLING_VERSION_GROUP_ID => SigHashVersion::Sapling,
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,6 +115,30 @@ fn joinsplits_hash(tx: &Transaction) -> Vec<u8> {
|
||||||
h.finalize().as_ref().to_vec()
|
h.finalize().as_ref().to_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn shielded_spends_hash(tx: &Transaction) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(tx.shielded_spends.len() * 384);
|
||||||
|
for s_spend in &tx.shielded_spends {
|
||||||
|
s_spend.cv.write(&mut data).unwrap();
|
||||||
|
s_spend.anchor.into_repr().write_le(&mut data).unwrap();
|
||||||
|
data.extend_from_slice(&s_spend.nullifier);
|
||||||
|
s_spend.rk.write(&mut data).unwrap();
|
||||||
|
data.extend_from_slice(&s_spend.zkproof);
|
||||||
|
}
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shielded_outputs_hash(tx: &Transaction) -> Vec<u8> {
|
||||||
|
let mut data = Vec::with_capacity(tx.shielded_outputs.len() * 948);
|
||||||
|
for s_out in &tx.shielded_outputs {
|
||||||
|
s_out.write(&mut data).unwrap();
|
||||||
|
}
|
||||||
|
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION);
|
||||||
|
h.update(&data);
|
||||||
|
h.finalize().as_ref().to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn signature_hash(
|
pub fn signature_hash(
|
||||||
tx: &Transaction,
|
tx: &Transaction,
|
||||||
consensus_branch_id: u32,
|
consensus_branch_id: u32,
|
||||||
|
@ -111,7 +147,7 @@ pub fn signature_hash(
|
||||||
) -> Vec<u8> {
|
) -> Vec<u8> {
|
||||||
let sigversion = SigHashVersion::from_tx(tx);
|
let sigversion = SigHashVersion::from_tx(tx);
|
||||||
match sigversion {
|
match sigversion {
|
||||||
SigHashVersion::Overwinter => {
|
SigHashVersion::Overwinter | SigHashVersion::Sapling => {
|
||||||
let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE
|
let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE
|
||||||
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE
|
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE
|
||||||
{
|
{
|
||||||
|
@ -152,8 +188,19 @@ pub fn signature_hash(
|
||||||
);
|
);
|
||||||
h.update(&hash_outputs);
|
h.update(&hash_outputs);
|
||||||
update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx));
|
update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx));
|
||||||
|
if sigversion == SigHashVersion::Sapling {
|
||||||
|
update_hash!(h, !tx.shielded_spends.is_empty(), shielded_spends_hash(tx));
|
||||||
|
update_hash!(
|
||||||
|
h,
|
||||||
|
!tx.shielded_outputs.is_empty(),
|
||||||
|
shielded_outputs_hash(tx)
|
||||||
|
);
|
||||||
|
}
|
||||||
update_u32!(h, tx.lock_time, tmp);
|
update_u32!(h, tx.lock_time, tmp);
|
||||||
update_u32!(h, tx.expiry_height, tmp);
|
update_u32!(h, tx.expiry_height, tmp);
|
||||||
|
if sigversion == SigHashVersion::Sapling {
|
||||||
|
update_i64!(h, tx.value_balance.0, tmp);
|
||||||
|
}
|
||||||
update_u32!(h, hash_type, tmp);
|
update_u32!(h, hash_type, tmp);
|
||||||
|
|
||||||
if let Some((n, script_code, amount)) = transparent_input {
|
if let Some((n, script_code, amount)) = transparent_input {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue