Merge branch 'master' into sighash_update
This commit is contained in:
commit
fb2c60f61b
|
@ -117,6 +117,7 @@ name = "bitcrypto"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)",
|
"blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)",
|
||||||
|
"bn 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"primitives 0.1.0",
|
"primitives 0.1.0",
|
||||||
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -157,6 +158,21 @@ dependencies = [
|
||||||
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bn"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
|
@ -778,6 +794,7 @@ dependencies = [
|
||||||
name = "network"
|
name = "network"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bitcrypto 0.1.0",
|
||||||
"chain 0.1.0",
|
"chain 0.1.0",
|
||||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"primitives 0.1.0",
|
"primitives 0.1.0",
|
||||||
|
@ -1641,6 +1658,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||||
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)" = "<none>"
|
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc.git?branch=persona)" = "<none>"
|
||||||
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "<none>"
|
"checksum blake2-rfc 0.2.18 (git+https://github.com/gtank/blake2-rfc?rev=7a5b5fc99ae483a0043db7547fb79a6fa44b88a9)" = "<none>"
|
||||||
|
"checksum bn 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "110f279b7f5e161fa755841785d5c4181510b31287dc0b47d09ed6d158975906"
|
||||||
|
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
|
||||||
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
|
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
|
||||||
"checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6"
|
"checksum bytes 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d828f97b58cc5de3e40c421d0cf2132d6b2da4ee0e11b8632fa838f0f9333ad6"
|
||||||
"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
|
"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
|
||||||
|
|
|
@ -8,3 +8,4 @@ blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", branch = "person
|
||||||
rust-crypto = "0.2.36"
|
rust-crypto = "0.2.36"
|
||||||
siphasher = "0.1.1"
|
siphasher = "0.1.1"
|
||||||
primitives = { path = "../primitives" }
|
primitives = { path = "../primitives" }
|
||||||
|
bn = "0.4"
|
||||||
|
|
|
@ -2,6 +2,9 @@ extern crate blake2_rfc;
|
||||||
extern crate crypto as rcrypto;
|
extern crate crypto as rcrypto;
|
||||||
extern crate primitives;
|
extern crate primitives;
|
||||||
extern crate siphasher;
|
extern crate siphasher;
|
||||||
|
extern crate bn;
|
||||||
|
|
||||||
|
mod pghr13;
|
||||||
|
|
||||||
pub use rcrypto::digest::Digest;
|
pub use rcrypto::digest::Digest;
|
||||||
pub use blake2_rfc::blake2b::Blake2b;
|
pub use blake2_rfc::blake2b::Blake2b;
|
||||||
|
@ -13,6 +16,11 @@ use rcrypto::ripemd160::Ripemd160;
|
||||||
use siphasher::sip::SipHasher24;
|
use siphasher::sip::SipHasher24;
|
||||||
use primitives::hash::{H32, H160, H256};
|
use primitives::hash::{H32, H160, H256};
|
||||||
|
|
||||||
|
pub use pghr13::{
|
||||||
|
VerifyingKey as Pghr13VerifyingKey, Proof as Pghr13Proof, verify as pghr13_verify,
|
||||||
|
G1, G2, Fr, Group,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct DHash160 {
|
pub struct DHash160 {
|
||||||
sha256: Sha256,
|
sha256: Sha256,
|
||||||
ripemd: Ripemd160,
|
ripemd: Ripemd160,
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
pub use bn::{Fr, G1, G2, Group};
|
||||||
|
use bn::pairing;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct VerifyingKey {
|
||||||
|
pub a: G2,
|
||||||
|
pub b: G1,
|
||||||
|
pub c: G2,
|
||||||
|
pub z: G2,
|
||||||
|
pub gamma: G2,
|
||||||
|
pub gamma_beta_1: G1,
|
||||||
|
pub gamma_beta_2: G2,
|
||||||
|
pub ic: Vec<G1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Debug for VerifyingKey {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
write!(f, "[Verifying Key: TODO]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Proof {
|
||||||
|
pub a: G1,
|
||||||
|
pub a_prime: G1,
|
||||||
|
pub b: G2,
|
||||||
|
pub b_prime: G1,
|
||||||
|
pub c: G1,
|
||||||
|
pub c_prime: G1,
|
||||||
|
pub k: G1,
|
||||||
|
pub h: G1,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(vk: &VerifyingKey, primary_input: &[Fr], proof: &Proof) -> bool {
|
||||||
|
let p2 = G2::one();
|
||||||
|
|
||||||
|
// 1. compute accumulated input circuit (evaluate the polynomial)
|
||||||
|
let mut acc = vk.ic[0];
|
||||||
|
for (&x, &ic) in primary_input.iter().zip(vk.ic[1..].iter()) {
|
||||||
|
acc = acc + (ic * x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. check validity of knowledge commitments for A, B, C:
|
||||||
|
pairing(proof.a, vk.a) == pairing(proof.a_prime, p2) &&
|
||||||
|
pairing(vk.b, proof.b) == pairing(proof.b_prime, p2) &&
|
||||||
|
pairing(proof.c, vk.c) == pairing(proof.c_prime, p2) &&
|
||||||
|
|
||||||
|
// 3. check same coefficients were used:
|
||||||
|
pairing(proof.k, vk.gamma) ==
|
||||||
|
pairing(acc + proof.a + proof.c, vk.gamma_beta_2) * pairing(vk.gamma_beta_1, proof.b) &&
|
||||||
|
|
||||||
|
// 4. check QAP divisibility
|
||||||
|
pairing(acc + proof.a, proof.b) == pairing(proof.h, vk.z) * pairing(proof.c, p2)
|
||||||
|
}
|
|
@ -8,4 +8,5 @@ lazy_static = "1.0"
|
||||||
chain = { path = "../chain" }
|
chain = { path = "../chain" }
|
||||||
primitives = { path = "../primitives" }
|
primitives = { path = "../primitives" }
|
||||||
serialization = { path = "../serialization" }
|
serialization = { path = "../serialization" }
|
||||||
|
bitcrypto = { path = "../crypto" }
|
||||||
rustc-hex = "2"
|
rustc-hex = "2"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use {Network, Magic, Deployment};
|
use {Network, Magic, Deployment, crypto};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
/// Parameters that influence chain consensus.
|
/// Parameters that influence chain consensus.
|
||||||
|
@ -42,6 +42,73 @@ pub struct ConsensusParams {
|
||||||
|
|
||||||
/// Equihash (N, K) parameters.
|
/// Equihash (N, K) parameters.
|
||||||
pub equihash_params: Option<(u32, u32)>,
|
pub equihash_params: Option<(u32, u32)>,
|
||||||
|
|
||||||
|
/// Active key for pghr13 joinsplit verification
|
||||||
|
pub joinsplit_verification_key: crypto::Pghr13VerifyingKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mainnet_pghr_verification_key() -> crypto::Pghr13VerifyingKey {
|
||||||
|
use crypto::{G1, G2, Group};
|
||||||
|
|
||||||
|
// TODO: Actually use group elements from ceremony
|
||||||
|
crypto::Pghr13VerifyingKey {
|
||||||
|
a: G2::one(),
|
||||||
|
b: G1::one(),
|
||||||
|
c: G2::one(),
|
||||||
|
z: G2::one(),
|
||||||
|
gamma: G2::one(),
|
||||||
|
gamma_beta_1: G1::one(),
|
||||||
|
gamma_beta_2: G2::one(),
|
||||||
|
ic: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn testnet_pghr_verification_key() -> crypto::Pghr13VerifyingKey {
|
||||||
|
use crypto::{G1, G2, Group};
|
||||||
|
|
||||||
|
// TODO: Actually use group elements for testnet
|
||||||
|
crypto::Pghr13VerifyingKey {
|
||||||
|
a: G2::one(),
|
||||||
|
b: G1::one(),
|
||||||
|
c: G2::one(),
|
||||||
|
z: G2::one(),
|
||||||
|
gamma: G2::one(),
|
||||||
|
gamma_beta_1: G1::one(),
|
||||||
|
gamma_beta_2: G2::one(),
|
||||||
|
ic: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn regtest_pghr_verification_key() -> crypto::Pghr13VerifyingKey {
|
||||||
|
use crypto::{G1, G2, Group};
|
||||||
|
|
||||||
|
// TODO: Actually use group elements for regtests
|
||||||
|
crypto::Pghr13VerifyingKey {
|
||||||
|
a: G2::one(),
|
||||||
|
b: G1::one(),
|
||||||
|
c: G2::one(),
|
||||||
|
z: G2::one(),
|
||||||
|
gamma: G2::one(),
|
||||||
|
gamma_beta_1: G1::one(),
|
||||||
|
gamma_beta_2: G2::one(),
|
||||||
|
ic: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unitest_pghr_verification_key() -> crypto::Pghr13VerifyingKey {
|
||||||
|
use crypto::{G1, G2, Group};
|
||||||
|
|
||||||
|
// TODO: Actually use group elements for unit tests
|
||||||
|
crypto::Pghr13VerifyingKey {
|
||||||
|
a: G2::one(),
|
||||||
|
b: G1::one(),
|
||||||
|
c: G2::one(),
|
||||||
|
z: G2::one(),
|
||||||
|
gamma: G2::one(),
|
||||||
|
gamma_beta_1: G1::one(),
|
||||||
|
gamma_beta_2: G2::one(),
|
||||||
|
ic: Vec::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConsensusParams {
|
impl ConsensusParams {
|
||||||
|
@ -66,6 +133,8 @@ impl ConsensusParams {
|
||||||
pow_target_spacing: (2.5 * 60.0) as u32,
|
pow_target_spacing: (2.5 * 60.0) as u32,
|
||||||
|
|
||||||
equihash_params: Some((200, 9)),
|
equihash_params: Some((200, 9)),
|
||||||
|
|
||||||
|
joinsplit_verification_key: mainnet_pghr_verification_key(),
|
||||||
},
|
},
|
||||||
Network::Testnet => ConsensusParams {
|
Network::Testnet => ConsensusParams {
|
||||||
network: network,
|
network: network,
|
||||||
|
@ -86,6 +155,8 @@ impl ConsensusParams {
|
||||||
pow_target_spacing: (2.5 * 60.0) as u32,
|
pow_target_spacing: (2.5 * 60.0) as u32,
|
||||||
|
|
||||||
equihash_params: Some((200, 9)),
|
equihash_params: Some((200, 9)),
|
||||||
|
|
||||||
|
joinsplit_verification_key: testnet_pghr_verification_key(),
|
||||||
},
|
},
|
||||||
Network::Regtest => ConsensusParams {
|
Network::Regtest => ConsensusParams {
|
||||||
network: network,
|
network: network,
|
||||||
|
@ -106,6 +177,8 @@ impl ConsensusParams {
|
||||||
pow_target_spacing: (2.5 * 60.0) as u32,
|
pow_target_spacing: (2.5 * 60.0) as u32,
|
||||||
|
|
||||||
equihash_params: Some((200, 9)),
|
equihash_params: Some((200, 9)),
|
||||||
|
|
||||||
|
joinsplit_verification_key: regtest_pghr_verification_key(),
|
||||||
},
|
},
|
||||||
Network::Unitest => ConsensusParams {
|
Network::Unitest => ConsensusParams {
|
||||||
network: network,
|
network: network,
|
||||||
|
@ -126,6 +199,8 @@ impl ConsensusParams {
|
||||||
pow_target_spacing: (2.5 * 60.0) as u32,
|
pow_target_spacing: (2.5 * 60.0) as u32,
|
||||||
|
|
||||||
equihash_params: None,
|
equihash_params: None,
|
||||||
|
|
||||||
|
joinsplit_verification_key: unitest_pghr_verification_key(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ extern crate lazy_static;
|
||||||
extern crate chain;
|
extern crate chain;
|
||||||
extern crate primitives;
|
extern crate primitives;
|
||||||
extern crate serialization;
|
extern crate serialization;
|
||||||
|
extern crate bitcrypto as crypto;
|
||||||
extern crate rustc_hex as hex;
|
extern crate rustc_hex as hex;
|
||||||
|
|
||||||
mod consensus;
|
mod consensus;
|
||||||
|
|
|
@ -20,7 +20,7 @@ pub struct Nullifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait to query existing nullifier.
|
/// Trait to query existing nullifier.
|
||||||
pub trait NullifierTracker {
|
pub trait NullifierTracker : Sync {
|
||||||
fn contains_nullifier(&self, nullifier: Nullifier) -> bool;
|
fn contains_nullifier(&self, nullifier: Nullifier) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ impl<'a> ChainAcceptor<'a> {
|
||||||
.map(|(tx_index, tx)| TransactionAcceptor::new(
|
.map(|(tx_index, tx)| TransactionAcceptor::new(
|
||||||
store.as_transaction_meta_provider(),
|
store.as_transaction_meta_provider(),
|
||||||
output_store,
|
output_store,
|
||||||
|
store.as_nullifier_tracker(),
|
||||||
consensus,
|
consensus,
|
||||||
tx,
|
tx,
|
||||||
verification_level,
|
verification_level,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use ser::Serializable;
|
use ser::Serializable;
|
||||||
use storage::{TransactionMetaProvider, TransactionOutputProvider};
|
use storage::{TransactionMetaProvider, TransactionOutputProvider, Nullifier, NullifierTag, NullifierTracker};
|
||||||
use network::{ConsensusParams};
|
use network::{ConsensusParams};
|
||||||
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner};
|
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner};
|
||||||
use duplex_store::DuplexTransactionOutputProvider;
|
use duplex_store::DuplexTransactionOutputProvider;
|
||||||
|
@ -7,8 +7,10 @@ use deployments::BlockDeployments;
|
||||||
use sapling::accept_sapling;
|
use sapling::accept_sapling;
|
||||||
use sigops::transaction_sigops;
|
use sigops::transaction_sigops;
|
||||||
use canon::CanonTransaction;
|
use canon::CanonTransaction;
|
||||||
use constants::{COINBASE_MATURITY};
|
use constants::COINBASE_MATURITY;
|
||||||
use error::TransactionError;
|
use error::TransactionError;
|
||||||
|
use primitives::hash::H256;
|
||||||
|
use chain::SAPLING_TX_VERSION_GROUP_ID;
|
||||||
use VerificationLevel;
|
use VerificationLevel;
|
||||||
|
|
||||||
pub struct TransactionAcceptor<'a> {
|
pub struct TransactionAcceptor<'a> {
|
||||||
|
@ -20,6 +22,7 @@ pub struct TransactionAcceptor<'a> {
|
||||||
pub overspent: TransactionOverspent<'a>,
|
pub overspent: TransactionOverspent<'a>,
|
||||||
pub double_spent: TransactionDoubleSpend<'a>,
|
pub double_spent: TransactionDoubleSpend<'a>,
|
||||||
pub eval: TransactionEval<'a>,
|
pub eval: TransactionEval<'a>,
|
||||||
|
pub join_split: Option<JoinSplitVerification<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TransactionAcceptor<'a> {
|
impl<'a> TransactionAcceptor<'a> {
|
||||||
|
@ -29,6 +32,7 @@ impl<'a> TransactionAcceptor<'a> {
|
||||||
// previous transaction outputs
|
// previous transaction outputs
|
||||||
// in case of block validation, that's database and currently processed block
|
// in case of block validation, that's database and currently processed block
|
||||||
output_store: DuplexTransactionOutputProvider<'a>,
|
output_store: DuplexTransactionOutputProvider<'a>,
|
||||||
|
nullifier_tracker: &'a NullifierTracker,
|
||||||
consensus: &'a ConsensusParams,
|
consensus: &'a ConsensusParams,
|
||||||
transaction: CanonTransaction<'a>,
|
transaction: CanonTransaction<'a>,
|
||||||
verification_level: VerificationLevel,
|
verification_level: VerificationLevel,
|
||||||
|
@ -47,6 +51,9 @@ impl<'a> TransactionAcceptor<'a> {
|
||||||
overspent: TransactionOverspent::new(transaction, output_store),
|
overspent: TransactionOverspent::new(transaction, output_store),
|
||||||
double_spent: TransactionDoubleSpend::new(transaction, output_store),
|
double_spent: TransactionDoubleSpend::new(transaction, output_store),
|
||||||
eval: TransactionEval::new(transaction, output_store, consensus, verification_level, height, time, deployments),
|
eval: TransactionEval::new(transaction, output_store, consensus, verification_level, height, time, deployments),
|
||||||
|
join_split: transaction.join_split().map(|js| {
|
||||||
|
JoinSplitVerification::new(transaction.raw.version_group_id, js, nullifier_tracker)
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,6 +448,47 @@ impl<'a> TransactionSize<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check the joinsplit proof of the transaction
|
||||||
|
pub struct JoinSplitProof<'a> {
|
||||||
|
_join_split: &'a chain::JoinSplit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> JoinSplitProof<'a> {
|
||||||
|
fn new(join_split: &'a chain::JoinSplit) -> Self { JoinSplitProof { _join_split: join_split }}
|
||||||
|
|
||||||
|
fn check(&self) -> Result<(), TransactionError> {
|
||||||
|
// TODO: Zero-knowledge proof
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if nullifiers are unique
|
||||||
|
pub struct Nullifiers<'a> {
|
||||||
|
tag: NullifierTag,
|
||||||
|
tracker: &'a NullifierTracker,
|
||||||
|
join_split: &'a chain::JoinSplit,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Nullifiers<'a> {
|
||||||
|
fn new(tag: NullifierTag, tracker: &'a NullifierTracker, join_split: &'a chain::JoinSplit) -> Self {
|
||||||
|
Nullifiers { tag: tag, tracker: tracker, join_split: join_split }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check(&self) -> Result<(), TransactionError> {
|
||||||
|
for description in self.join_split.descriptions.iter() {
|
||||||
|
for nullifier in &description.nullifiers[..] {
|
||||||
|
let check = Nullifier::new(self.tag, H256::from(&nullifier[..]));
|
||||||
|
|
||||||
|
if self.tracker.contains_nullifier(check) {
|
||||||
|
return Err(TransactionError::JoinSplitDeclared(*check.hash()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks that sapling signatures/proofs are valid.
|
/// Checks that sapling signatures/proofs are valid.
|
||||||
pub struct TransactionSaplingValid<'a> {
|
pub struct TransactionSaplingValid<'a> {
|
||||||
transaction: CanonTransaction<'a>,
|
transaction: CanonTransaction<'a>,
|
||||||
|
@ -464,6 +512,31 @@ impl<'a> TransactionSaplingValid<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Join split verification
|
||||||
|
pub struct JoinSplitVerification<'a> {
|
||||||
|
proof: JoinSplitProof<'a>,
|
||||||
|
nullifiers: Nullifiers<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> JoinSplitVerification<'a> {
|
||||||
|
pub fn new(tx_version_group: u32, join_split: &'a chain::JoinSplit, tracker: &'a NullifierTracker)
|
||||||
|
-> Self
|
||||||
|
{
|
||||||
|
let tag = if tx_version_group == SAPLING_TX_VERSION_GROUP_ID
|
||||||
|
{ NullifierTag::Sapling } else { NullifierTag::Sprout };
|
||||||
|
|
||||||
|
JoinSplitVerification {
|
||||||
|
proof: JoinSplitProof::new(join_split),
|
||||||
|
nullifiers: Nullifiers::new(tag, tracker, join_split),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check(&self) -> Result<(), TransactionError> {
|
||||||
|
self.proof.check()?;
|
||||||
|
self.nullifiers.check()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,10 @@ impl<'a> CanonTransaction<'a> {
|
||||||
transaction: transaction,
|
transaction: transaction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn join_split(&self) -> Option<&'a chain::JoinSplit> {
|
||||||
|
self.transaction.raw.join_split.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ops::Deref for CanonTransaction<'a> {
|
impl<'a> ops::Deref for CanonTransaction<'a> {
|
||||||
|
|
|
@ -125,10 +125,13 @@ pub enum TransactionError {
|
||||||
/// Transaction has duplicate inputs. Inputs indexes are provided.
|
/// Transaction has duplicate inputs. Inputs indexes are provided.
|
||||||
DuplicateInput(usize, usize),
|
DuplicateInput(usize, usize),
|
||||||
/// Transaction has join split descriptions with duplicate nullifiers.
|
/// Transaction has join split descriptions with duplicate nullifiers.
|
||||||
|
///
|
||||||
/// Join split descriptions indexes are provided.
|
/// Join split descriptions indexes are provided.
|
||||||
DuplicateJoinSplitNullifier(usize, usize),
|
DuplicateJoinSplitNullifier(usize, usize),
|
||||||
/// Transaction has sapling spends with duplicate nullifiers. Sapling spends indexes are provided.
|
/// Transaction has sapling spends with duplicate nullifiers. Sapling spends indexes are provided.
|
||||||
DuplicateSaplingSpendNullifier(usize, usize),
|
DuplicateSaplingSpendNullifier(usize, usize),
|
||||||
|
/// Join split already declared earlier in the chain.
|
||||||
|
JoinSplitDeclared(H256),
|
||||||
/// Transaction sapling verification has failed.
|
/// Transaction sapling verification has failed.
|
||||||
InvalidSapling,
|
InvalidSapling,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue