half stubbed join split verification
This commit is contained in:
parent
3b984adfd0
commit
79887986a9
|
@ -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};
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -150,5 +150,7 @@ pub enum TransactionError {
|
|||
Expired,
|
||||
/// Transaction overwintered flag is invalid.
|
||||
InvalidOverwintered,
|
||||
/// Invalid joinsplit statement
|
||||
InvalidJoinSplit(usize),
|
||||
}
|
||||
|
||||
|
|
|
@ -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"),
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue