Merge branch 'master' into sighash_update

This commit is contained in:
Svyatoslav Nikolsky 2018-12-07 12:13:12 +03:00
commit fb2c60f61b
12 changed files with 244 additions and 4 deletions

19
Cargo.lock generated
View File

@ -117,6 +117,7 @@ name = "bitcrypto"
version = "0.1.0"
dependencies = [
"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",
"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)",
@ -157,6 +158,21 @@ dependencies = [
"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]]
name = "byteorder"
version = "1.2.3"
@ -778,6 +794,7 @@ dependencies = [
name = "network"
version = "0.1.0"
dependencies = [
"bitcrypto 0.1.0",
"chain 0.1.0",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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 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 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 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"

View File

@ -8,3 +8,4 @@ blake2-rfc = { git = "https://github.com/gtank/blake2-rfc.git", branch = "person
rust-crypto = "0.2.36"
siphasher = "0.1.1"
primitives = { path = "../primitives" }
bn = "0.4"

View File

@ -2,6 +2,9 @@ extern crate blake2_rfc;
extern crate crypto as rcrypto;
extern crate primitives;
extern crate siphasher;
extern crate bn;
mod pghr13;
pub use rcrypto::digest::Digest;
pub use blake2_rfc::blake2b::Blake2b;
@ -13,6 +16,11 @@ use rcrypto::ripemd160::Ripemd160;
use siphasher::sip::SipHasher24;
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 {
sha256: Sha256,
ripemd: Ripemd160,

54
crypto/src/pghr13.rs Normal file
View File

@ -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)
}

View File

@ -8,4 +8,5 @@ lazy_static = "1.0"
chain = { path = "../chain" }
primitives = { path = "../primitives" }
serialization = { path = "../serialization" }
bitcrypto = { path = "../crypto" }
rustc-hex = "2"

View File

@ -1,4 +1,4 @@
use {Network, Magic, Deployment};
use {Network, Magic, Deployment, crypto};
#[derive(Debug, Clone)]
/// Parameters that influence chain consensus.
@ -42,6 +42,73 @@ pub struct ConsensusParams {
/// Equihash (N, K) parameters.
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 {
@ -66,6 +133,8 @@ impl ConsensusParams {
pow_target_spacing: (2.5 * 60.0) as u32,
equihash_params: Some((200, 9)),
joinsplit_verification_key: mainnet_pghr_verification_key(),
},
Network::Testnet => ConsensusParams {
network: network,
@ -86,6 +155,8 @@ impl ConsensusParams {
pow_target_spacing: (2.5 * 60.0) as u32,
equihash_params: Some((200, 9)),
joinsplit_verification_key: testnet_pghr_verification_key(),
},
Network::Regtest => ConsensusParams {
network: network,
@ -106,6 +177,8 @@ impl ConsensusParams {
pow_target_spacing: (2.5 * 60.0) as u32,
equihash_params: Some((200, 9)),
joinsplit_verification_key: regtest_pghr_verification_key(),
},
Network::Unitest => ConsensusParams {
network: network,
@ -126,6 +199,8 @@ impl ConsensusParams {
pow_target_spacing: (2.5 * 60.0) as u32,
equihash_params: None,
joinsplit_verification_key: unitest_pghr_verification_key(),
},
}
}

View File

@ -4,6 +4,7 @@ extern crate lazy_static;
extern crate chain;
extern crate primitives;
extern crate serialization;
extern crate bitcrypto as crypto;
extern crate rustc_hex as hex;
mod consensus;

View File

@ -20,7 +20,7 @@ pub struct Nullifier {
}
/// Trait to query existing nullifier.
pub trait NullifierTracker {
pub trait NullifierTracker : Sync {
fn contains_nullifier(&self, nullifier: Nullifier) -> bool;
}

View File

@ -31,6 +31,7 @@ impl<'a> ChainAcceptor<'a> {
.map(|(tx_index, tx)| TransactionAcceptor::new(
store.as_transaction_meta_provider(),
output_store,
store.as_nullifier_tracker(),
consensus,
tx,
verification_level,

View File

@ -1,5 +1,5 @@
use ser::Serializable;
use storage::{TransactionMetaProvider, TransactionOutputProvider};
use storage::{TransactionMetaProvider, TransactionOutputProvider, Nullifier, NullifierTag, NullifierTracker};
use network::{ConsensusParams};
use script::{Script, verify_script, VerificationFlags, TransactionSignatureChecker, TransactionInputSigner};
use duplex_store::DuplexTransactionOutputProvider;
@ -7,8 +7,10 @@ use deployments::BlockDeployments;
use sapling::accept_sapling;
use sigops::transaction_sigops;
use canon::CanonTransaction;
use constants::{COINBASE_MATURITY};
use constants::COINBASE_MATURITY;
use error::TransactionError;
use primitives::hash::H256;
use chain::SAPLING_TX_VERSION_GROUP_ID;
use VerificationLevel;
pub struct TransactionAcceptor<'a> {
@ -20,6 +22,7 @@ pub struct TransactionAcceptor<'a> {
pub overspent: TransactionOverspent<'a>,
pub double_spent: TransactionDoubleSpend<'a>,
pub eval: TransactionEval<'a>,
pub join_split: Option<JoinSplitVerification<'a>>,
}
impl<'a> TransactionAcceptor<'a> {
@ -29,6 +32,7 @@ impl<'a> TransactionAcceptor<'a> {
// previous transaction outputs
// in case of block validation, that's database and currently processed block
output_store: DuplexTransactionOutputProvider<'a>,
nullifier_tracker: &'a NullifierTracker,
consensus: &'a ConsensusParams,
transaction: CanonTransaction<'a>,
verification_level: VerificationLevel,
@ -47,6 +51,9 @@ 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: 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.
pub struct TransactionSaplingValid<'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)]
mod tests {

View File

@ -72,6 +72,10 @@ impl<'a> CanonTransaction<'a> {
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> {

View File

@ -125,10 +125,13 @@ pub enum TransactionError {
/// Transaction has duplicate inputs. Inputs indexes are provided.
DuplicateInput(usize, usize),
/// Transaction has join split descriptions with duplicate nullifiers.
///
/// Join split descriptions indexes are provided.
DuplicateJoinSplitNullifier(usize, usize),
/// Transaction has sapling spends with duplicate nullifiers. Sapling spends indexes are provided.
DuplicateSaplingSpendNullifier(usize, usize),
/// Join split already declared earlier in the chain.
JoinSplitDeclared(H256),
/// Transaction sapling verification has failed.
InvalidSapling,
}