mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-02-11 17:55:46 +00:00
ZIP 143
This commit is contained in:
parent
e490b79907
commit
2d8b1fe504
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -704,6 +704,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "zcash_primitives"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)",
|
||||
"byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pairing 0.14.2",
|
||||
|
@ -10,3 +10,7 @@ byteorder = "1"
|
||||
lazy_static = "1"
|
||||
pairing = { path = "../pairing" }
|
||||
sapling-crypto = { path = "../sapling-crypto" }
|
||||
|
||||
[dependencies.blake2-rfc]
|
||||
git = "https://github.com/gtank/blake2-rfc"
|
||||
rev = "7a5b5fc99ae483a0043db7547fb79a6fa44b88a9"
|
||||
|
@ -1,6 +1,7 @@
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
extern crate blake2_rfc;
|
||||
extern crate byteorder;
|
||||
extern crate pairing;
|
||||
extern crate sapling_crypto;
|
||||
|
@ -23,7 +23,7 @@ const ZC_NUM_JS_OUTPUTS: usize = 2;
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Amount(pub i64);
|
||||
|
||||
struct Script(Vec<u8>);
|
||||
pub struct Script(pub Vec<u8>);
|
||||
|
||||
impl Script {
|
||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||
@ -36,7 +36,7 @@ impl Script {
|
||||
}
|
||||
}
|
||||
|
||||
struct OutPoint {
|
||||
pub struct OutPoint {
|
||||
hash: [u8; 32],
|
||||
n: u32,
|
||||
}
|
||||
@ -56,9 +56,9 @@ impl OutPoint {
|
||||
}
|
||||
|
||||
pub struct TxIn {
|
||||
prevout: OutPoint,
|
||||
pub prevout: OutPoint,
|
||||
script_sig: Script,
|
||||
sequence: u32,
|
||||
pub sequence: u32,
|
||||
}
|
||||
|
||||
impl TxIn {
|
||||
|
@ -4,7 +4,8 @@ use std::io::{self, Read, Write};
|
||||
|
||||
use serialize::Vector;
|
||||
|
||||
mod components;
|
||||
pub mod components;
|
||||
mod sighash;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
174
zcash_primitives/src/transaction/sighash.rs
Normal file
174
zcash_primitives/src/transaction/sighash.rs
Normal file
@ -0,0 +1,174 @@
|
||||
use blake2_rfc::blake2b::Blake2b;
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
|
||||
use super::{
|
||||
components::{Amount, Script},
|
||||
Transaction, OVERWINTER_VERSION_GROUP_ID, SAPLING_TX_VERSION,
|
||||
};
|
||||
|
||||
const ZCASH_SIGHASH_PERSONALIZATION_PREFIX: &'static [u8; 12] = b"ZcashSigHash";
|
||||
const ZCASH_PREVOUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashPrevoutHash";
|
||||
const ZCASH_SEQUENCE_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashSequencHash";
|
||||
const ZCASH_OUTPUTS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashOutputsHash";
|
||||
const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &'static [u8; 16] = b"ZcashJSplitsHash";
|
||||
|
||||
pub const SIGHASH_ALL: u32 = 1;
|
||||
const SIGHASH_NONE: u32 = 2;
|
||||
const SIGHASH_SINGLE: u32 = 3;
|
||||
const SIGHASH_MASK: u32 = 0x1f;
|
||||
const SIGHASH_ANYONECANPAY: u32 = 0x80;
|
||||
|
||||
macro_rules! update_u32 {
|
||||
($h:expr, $value:expr, $tmp:expr) => {
|
||||
(&mut $tmp[..4]).write_u32::<LittleEndian>($value).unwrap();
|
||||
$h.update(&$tmp[..4]);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! update_hash {
|
||||
($h:expr, $cond:expr, $value:expr) => {
|
||||
if $cond {
|
||||
$h.update(&$value);
|
||||
} else {
|
||||
$h.update(&[0; 32]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum SigHashVersion {
|
||||
Sprout,
|
||||
Overwinter,
|
||||
}
|
||||
|
||||
impl SigHashVersion {
|
||||
fn from_tx(tx: &Transaction) -> Self {
|
||||
if tx.overwintered {
|
||||
match tx.version_group_id {
|
||||
OVERWINTER_VERSION_GROUP_ID => SigHashVersion::Overwinter,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
} else {
|
||||
SigHashVersion::Sprout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prevout_hash(tx: &Transaction) -> Vec<u8> {
|
||||
let mut data = Vec::with_capacity(tx.vin.len() * 36);
|
||||
for t_in in &tx.vin {
|
||||
t_in.prevout.write(&mut data).unwrap();
|
||||
}
|
||||
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_PREVOUTS_HASH_PERSONALIZATION);
|
||||
h.update(&data);
|
||||
h.finalize().as_ref().to_vec()
|
||||
}
|
||||
|
||||
fn sequence_hash(tx: &Transaction) -> Vec<u8> {
|
||||
let mut data = Vec::with_capacity(tx.vin.len() * 4);
|
||||
for t_in in &tx.vin {
|
||||
(&mut data)
|
||||
.write_u32::<LittleEndian>(t_in.sequence)
|
||||
.unwrap();
|
||||
}
|
||||
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_SEQUENCE_HASH_PERSONALIZATION);
|
||||
h.update(&data);
|
||||
h.finalize().as_ref().to_vec()
|
||||
}
|
||||
|
||||
fn outputs_hash(tx: &Transaction) -> Vec<u8> {
|
||||
let mut data = Vec::with_capacity(tx.vout.len() * (4 + 1));
|
||||
for t_out in &tx.vout {
|
||||
t_out.write(&mut data).unwrap();
|
||||
}
|
||||
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION);
|
||||
h.update(&data);
|
||||
h.finalize().as_ref().to_vec()
|
||||
}
|
||||
|
||||
fn joinsplits_hash(tx: &Transaction) -> Vec<u8> {
|
||||
let mut data = Vec::with_capacity(
|
||||
tx.joinsplits.len() * if tx.version < SAPLING_TX_VERSION {
|
||||
1802 // JSDescription with PHGR13 proof
|
||||
} else {
|
||||
1698 // JSDescription with Groth16 proof
|
||||
},
|
||||
);
|
||||
for js in &tx.joinsplits {
|
||||
js.write(&mut data).unwrap();
|
||||
}
|
||||
data.extend_from_slice(&tx.joinsplit_pubkey);
|
||||
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_JOINSPLITS_HASH_PERSONALIZATION);
|
||||
h.update(&data);
|
||||
h.finalize().as_ref().to_vec()
|
||||
}
|
||||
|
||||
pub fn signature_hash(
|
||||
tx: &Transaction,
|
||||
consensus_branch_id: u32,
|
||||
hash_type: u32,
|
||||
transparent_input: Option<(usize, Script, Amount)>,
|
||||
) -> Vec<u8> {
|
||||
let sigversion = SigHashVersion::from_tx(tx);
|
||||
match sigversion {
|
||||
SigHashVersion::Overwinter => {
|
||||
let hash_outputs = if (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE
|
||||
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE
|
||||
{
|
||||
outputs_hash(tx)
|
||||
} else if (hash_type & SIGHASH_MASK) == SIGHASH_SINGLE
|
||||
&& transparent_input.is_some()
|
||||
&& transparent_input.as_ref().unwrap().0 < tx.vout.len()
|
||||
{
|
||||
let mut data = vec![];
|
||||
tx.vout[transparent_input.as_ref().unwrap().0]
|
||||
.write(&mut data)
|
||||
.unwrap();
|
||||
let mut h = Blake2b::with_params(32, &[], &[], ZCASH_OUTPUTS_HASH_PERSONALIZATION);
|
||||
h.update(&data);
|
||||
h.finalize().as_ref().to_vec()
|
||||
} else {
|
||||
vec![0; 32]
|
||||
};
|
||||
|
||||
let mut personal = [0; 16];
|
||||
(&mut personal[..12]).copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX);
|
||||
(&mut personal[12..])
|
||||
.write_u32::<LittleEndian>(consensus_branch_id)
|
||||
.unwrap();
|
||||
|
||||
let mut h = Blake2b::with_params(32, &[], &[], &personal);
|
||||
let mut tmp = [0; 8];
|
||||
|
||||
update_u32!(h, tx.header(), tmp);
|
||||
update_u32!(h, tx.version_group_id, tmp);
|
||||
update_hash!(h, hash_type & SIGHASH_ANYONECANPAY == 0, prevout_hash(tx));
|
||||
update_hash!(
|
||||
h,
|
||||
hash_type & SIGHASH_ANYONECANPAY == 0
|
||||
&& (hash_type & SIGHASH_MASK) != SIGHASH_SINGLE
|
||||
&& (hash_type & SIGHASH_MASK) != SIGHASH_NONE,
|
||||
sequence_hash(tx)
|
||||
);
|
||||
h.update(&hash_outputs);
|
||||
update_hash!(h, !tx.joinsplits.is_empty(), joinsplits_hash(tx));
|
||||
update_u32!(h, tx.lock_time, tmp);
|
||||
update_u32!(h, tx.expiry_height, tmp);
|
||||
update_u32!(h, hash_type, tmp);
|
||||
|
||||
if let Some((n, script_code, amount)) = transparent_input {
|
||||
let mut data = vec![];
|
||||
tx.vin[n].prevout.write(&mut data).unwrap();
|
||||
script_code.write(&mut data).unwrap();
|
||||
(&mut data).write_i64::<LittleEndian>(amount.0).unwrap();
|
||||
(&mut data)
|
||||
.write_u32::<LittleEndian>(tx.vin[n].sequence)
|
||||
.unwrap();
|
||||
h.update(&data);
|
||||
}
|
||||
|
||||
h.finalize().as_ref().to_vec()
|
||||
}
|
||||
SigHashVersion::Sprout => unimplemented!(),
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user