half stubbed join split verification

This commit is contained in:
NikVolf 2019-03-28 18:33:18 +03:00
parent 3b984adfd0
commit 79887986a9
4 changed files with 118 additions and 26 deletions

View File

@ -34,7 +34,7 @@ pub use transaction::{OVERWINTER_TX_VERSION_GROUP_ID, SAPLING_TX_VERSION_GROUP_I
pub use block::Block;
pub use block_header::BlockHeader;
pub use solution::EquihashSolution;
pub use join_split::{JoinSplit, JoinSplitDescription};
pub use join_split::{JoinSplit, JoinSplitDescription, JoinSplitProof};
pub use merkle_root::{merkle_root, merkle_node_hash};
pub use sapling::{Sapling, SaplingSpendDescription, SaplingOutputDescription};
pub use transaction::{Transaction, TransactionInput, TransactionOutput, OutPoint};

View File

@ -55,7 +55,7 @@ impl<'a> TransactionAcceptor<'a> {
overspent: TransactionOverspent::new(transaction, output_store),
double_spent: TransactionDoubleSpend::new(transaction, output_store),
eval: TransactionEval::new(transaction, output_store, consensus, verification_level, height, time, deployments),
join_split: JoinSplitVerification::new(transaction, nullifier_tracker),
join_split: JoinSplitVerification::new(consensus, transaction, nullifier_tracker),
sapling: SaplingVerification::new(
nullifier_tracker,
consensus.sapling_spend_verifying_key,
@ -125,7 +125,7 @@ impl<'a> MemoryPoolTransactionAcceptor<'a> {
sigops: TransactionSigops::new(transaction, output_store, consensus, max_block_sigops, time),
double_spent: TransactionDoubleSpend::new(transaction, output_store),
eval: TransactionEval::new(transaction, output_store, consensus, VerificationLevel::Full, height, time, deployments),
join_split: JoinSplitVerification::new(transaction, nullifier_tracker),
join_split: JoinSplitVerification::new(consensus, transaction, nullifier_tracker),
sapling: SaplingVerification::new(
nullifier_tracker,
consensus.sapling_spend_verifying_key,
@ -571,14 +571,26 @@ impl<'a> TransactionVersion<'a> {
/// Check the joinsplit proof of the transaction
pub struct JoinSplitProof<'a> {
_transaction: CanonTransaction<'a>,
transaction: CanonTransaction<'a>,
consensus_params: &'a ConsensusParams,
}
impl<'a> JoinSplitProof<'a> {
fn new(transaction: CanonTransaction<'a>) -> Self { JoinSplitProof { _transaction: transaction }}
fn new(transaction: CanonTransaction<'a>, consensus_params: &'a ConsensusParams) -> Self {
JoinSplitProof {
transaction: transaction,
consensus_params: consensus_params,
}
}
fn check(&self) -> Result<(), TransactionError> {
// TODO: Zero-knowledge proof
use sprout;
if let Some(ref join_split) = self.transaction.raw.join_split {
sprout::verify(&[0u8;32], &join_split, &self.consensus_params.joinsplit_verification_key)
.map_err(|e| TransactionError::InvalidJoinSplit(e.index()))?;
}
Ok(())
}
}
@ -618,11 +630,11 @@ pub struct JoinSplitVerification<'a> {
}
impl<'a> JoinSplitVerification<'a> {
pub fn new(transaction: CanonTransaction<'a>, tracker: &'a NullifierTracker)
pub fn new(consensus_params: &'a ConsensusParams, transaction: CanonTransaction<'a>, tracker: &'a NullifierTracker)
-> Self
{
JoinSplitVerification {
proof: JoinSplitProof::new(transaction),
proof: JoinSplitProof::new(transaction, consensus_params),
nullifiers: JoinSplitNullifiers::new(tracker, transaction),
}
}

View File

@ -150,5 +150,7 @@ pub enum TransactionError {
Expired,
/// Transaction overwintered flag is invalid.
InvalidOverwintered,
/// Invalid joinsplit statement
InvalidJoinSplit(usize),
}

View File

@ -1,6 +1,36 @@
#![allow(dead_code)]
use chain::{JoinSplit, JoinSplitProof};
use crypto::{BnU256, Pghr13Proof, pghr13_verify};
/// Join split verification error kind
pub enum ErrorKind {
/// Invalid join split zkp statement
InvalidProof,
/// Invalid raw bytes econding of proof
InvalidEncoding,
}
/// Join split verification error
pub struct Error {
index: usize,
kind: ErrorKind,
}
impl Error {
pub fn proof(idx: usize) -> Self {
Error { kind: ErrorKind::InvalidProof, index: idx }
}
pub fn encoding(idx: usize) -> Self {
Error { kind: ErrorKind::InvalidEncoding, index: idx }
}
pub fn index(&self) -> usize { self.index }
}
// blake2 hash of (random_seed, nullifier[0], nullifier[1], pub_key_hash) with 'ZcashComputehSig' personal token
pub fn compute_hsig(random_seed: [u8; 32], nullifiers: [[u8; 32]; 2], pub_key_hash: [u8; 32]) -> [u8; 32] {
pub fn compute_hsig(random_seed: &[u8; 32], nullifiers: &[[u8; 32]; 2], pub_key_hash: &[u8; 32]) -> [u8; 32] {
use crypto::blake2::Params;
let res = Params::new()
@ -18,6 +48,50 @@ pub fn compute_hsig(random_seed: [u8; 32], nullifiers: [[u8; 32]; 2], pub_key_ha
result
}
pub fn verify(
root: &[u8; 32],
join_split: &JoinSplit,
verifying_key: &crypto::Pghr13VerifyingKey,
) -> Result<(), Error>
{
let mut desc_index = 0;
for desc in join_split.descriptions.iter() {
match desc.zkproof {
JoinSplitProof::PHGR(ref proof_raw) => {
let hsig = compute_hsig(&desc.random_seed, &desc.nullifiers, &join_split.pubkey.into());
let mut input = Input::new(1024);
input.push_hash(&root);
input.push_hash(&hsig);
input.push_hash(&desc.nullifiers[0]);
input.push_hash(&desc.macs[0]);
input.push_hash(&desc.nullifiers[1]);
input.push_hash(&desc.macs[1]);
input.push_hash(&desc.commitments[0]);
input.push_hash(&desc.commitments[1]);
input.push_u64(desc.value_pub_old);
input.push_u64(desc.value_pub_new);
let proof = Pghr13Proof::from_raw(proof_raw).map_err(|_| Error::encoding(desc_index))?;
if !pghr13_verify(verifying_key, &input.into_frs(), &proof) {
return Err(Error::proof(desc_index));
}
},
_ => continue,
}
desc_index += 1;
}
Ok(())
}
#[derive(Debug, Clone)]
pub struct Input {
bits: bitvec::BitVec,
@ -28,12 +102,16 @@ impl Input {
Input { bits: bitvec::BitVec::with_capacity(size) }
}
fn push_u256(&mut self, val: crypto::BnU256) {
fn push_u256(&mut self, val: BnU256) {
for i in 0..256 {
self.bits.push(val.get_bit(i).expect("for 0..256 index range will always return some; qeed"))
self.bits.push(val.get_bit(255-i).expect("for 0..256 index range will always return some; qeed"))
}
}
fn push_hash(&mut self, val: &[u8; 32]) {
self.push_u256(BnU256::from_slice(&val[..]).expect("has 32 elements in slice; qed"))
}
fn push_u64(&mut self, val: u64) {
for i in 0..64 {
self.bits.push(val & (1 << (63-i)) > 0)
@ -81,48 +159,48 @@ mod tests {
fn test_vectors() {
assert_eq!(
compute_hsig(
hash("6161616161616161616161616161616161616161616161616161616161616161"),
[
&hash("6161616161616161616161616161616161616161616161616161616161616161"),
&[
hash("6262626262626262626262626262626262626262626262626262626262626262"),
hash("6363636363636363636363636363636363636363636363636363636363636363"),
],
hash("6464646464646464646464646464646464646464646464646464646464646464"),
&hash("6464646464646464646464646464646464646464646464646464646464646464"),
),
hash("a8cba69f1fa329c055756b4af900f8a00b61e44f4cb8a1824ceb58b90a5b8113"),
);
assert_eq!(
compute_hsig(
hash("0000000000000000000000000000000000000000000000000000000000000000"),
[
&hash("0000000000000000000000000000000000000000000000000000000000000000"),
&[
hash("0000000000000000000000000000000000000000000000000000000000000000"),
hash("0000000000000000000000000000000000000000000000000000000000000000"),
],
hash("0000000000000000000000000000000000000000000000000000000000000000"),
&hash("0000000000000000000000000000000000000000000000000000000000000000"),
),
hash("697322276b5dd93b12fb1fcbd2144b2960f24c73aac6c6a0811447be1e7f1e19"),
);
assert_eq!(
compute_hsig(
hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
[
&hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
&[
hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
],
hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
&hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
),
hash("b61110ec162693bc3d9ca7fb0eec3afd2e278e2f41394b3ff11d7cb761ad4b27"),
);
assert_eq!(
compute_hsig(
hash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
[
&hash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
&[
hash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
hash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
],
hash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
&hash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
),
hash("4961048919f0ca79d49c9378c36a91a8767060001f4212fe6f7d426f3ccf9f32"),
);
@ -130,12 +208,12 @@ mod tests {
assert_eq!(
compute_hsig(
hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
[
&hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
&[
hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
],
hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
&hash("1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"),
),
hash("b61110ec162693bc3d9ca7fb0eec3afd2e278e2f41394b3ff11d7cb761ad4b27"),
);