Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

schnorr signature batch verification #2961

Merged
merged 5 commits into from
Sep 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions chain/src/txhashset/txhashset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1339,28 +1339,30 @@ impl<'a> Extension<'a> {

fn verify_kernel_signatures(&self, status: &dyn TxHashsetWriteStatus) -> Result<(), Error> {
let now = Instant::now();
const KERNEL_BATCH_SIZE: usize = 5_000;

let mut kern_count = 0;
let total_kernels = pmmr::n_leaves(self.kernel_pmmr.unpruned_size());
let mut tx_kernels: Vec<TxKernel> = Vec::with_capacity(KERNEL_BATCH_SIZE);
for n in 1..self.kernel_pmmr.unpruned_size() + 1 {
if pmmr::is_leaf(n) {
let kernel = self
.kernel_pmmr
.get_data(n)
.ok_or::<Error>(ErrorKind::TxKernelNotFound.into())?;

kernel.verify()?;
kern_count += 1;
tx_kernels.push(kernel.kernel);
}

if kern_count % 20 == 0 {
status.on_validation(kern_count, total_kernels, 0, 0);
}
if kern_count % 1_000 == 0 {
debug!(
"txhashset: verify_kernel_signatures: verified {} signatures",
kern_count,
);
}
if tx_kernels.len() >= KERNEL_BATCH_SIZE || n >= self.kernel_pmmr.unpruned_size() {
TxKernel::batch_sig_verify(&tx_kernels)?;
kern_count += tx_kernels.len() as u64;
tx_kernels.clear();
status.on_validation(kern_count, total_kernels, 0, 0);
debug!(
"txhashset: verify_kernel_signatures: verified {} signatures",
kern_count,
);
}
}

Expand All @@ -1377,8 +1379,8 @@ impl<'a> Extension<'a> {
fn verify_rangeproofs(&self, status: &dyn TxHashsetWriteStatus) -> Result<(), Error> {
let now = Instant::now();

let mut commits: Vec<Commitment> = vec![];
let mut proofs: Vec<RangeProof> = vec![];
let mut commits: Vec<Commitment> = Vec::with_capacity(1_000);
let mut proofs: Vec<RangeProof> = Vec::with_capacity(1_000);

let mut proof_count = 0;
let total_rproofs = pmmr::n_leaves(self.output_pmmr.unpruned_size());
Expand Down Expand Up @@ -1409,7 +1411,7 @@ impl<'a> Extension<'a> {
);
}

if proof_count % 20 == 0 {
if proof_count % 1_000 == 0 {
status.on_validation(0, 0, proof_count, total_rproofs);
}
}
Expand Down
29 changes: 24 additions & 5 deletions core/src/core/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,29 @@ impl TxKernel {
Ok(())
}

/// Batch signature verification.
pub fn batch_sig_verify(tx_kernels: &Vec<TxKernel>) -> Result<(), Error> {
let len = tx_kernels.len();
let mut sigs: Vec<secp::Signature> = Vec::with_capacity(len);
let mut pubkeys: Vec<secp::key::PublicKey> = Vec::with_capacity(len);
let mut msgs: Vec<secp::Message> = Vec::with_capacity(len);

let secp = static_secp_instance();
let secp = secp.lock();

for tx_kernel in tx_kernels {
sigs.push(tx_kernel.excess_sig);
pubkeys.push(tx_kernel.excess.to_pubkey(&secp)?);
msgs.push(tx_kernel.msg_to_sign()?);
}

if !secp::aggsig::verify_batch(&secp, &sigs, &msgs, &pubkeys) {
return Err(Error::IncorrectSignature);
}

Ok(())
}

/// Build an empty tx kernel with zero values.
pub fn empty() -> TxKernel {
TxKernel {
Expand Down Expand Up @@ -852,11 +875,7 @@ impl TransactionBody {
};

// Verify the unverified tx kernels.
// No ability to batch verify these right now
// so just do them individually.
for x in &kernels {
x.verify()?;
}
TxKernel::batch_sig_verify(&kernels)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing we are fine just batching them all up like this in the context of a block.
But is there a limit to how many we can batch?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The limit should be big enough. At least 100,000 batching is OK:

running 1 test
Verifying aggsig batch of 100000
100000 signatures verified in 6408.601ms
test aggsig::tests::test_aggsig_batch ... ok


// Cache the successful verification results for the new outputs and kernels.
{
Expand Down