diff --git a/benches/commitment.rs b/benches/commitment.rs new file mode 100644 index 00000000..1e42daba --- /dev/null +++ b/benches/commitment.rs @@ -0,0 +1,33 @@ +// Copyright 2019. The Tari Project +// SPDX-License-Identifier: BSD-3-Clause + +use std::time::Duration; + +use criterion::{criterion_group, Criterion}; +use rand::thread_rng; +use tari_crypto::{ + commitment::HomomorphicCommitmentFactory, + keys::SecretKey, + ristretto::{ + pedersen::commitment_factory::PedersenCommitmentFactory, + RistrettoSecretKey, + }, +}; + +pub fn commit_default(c: &mut Criterion) { + let factory = PedersenCommitmentFactory::default(); + let mut rng = thread_rng(); + + c.bench_function("commit_default key pair", |b| { + // Commitment value and mask + let v = RistrettoSecretKey::random(&mut rng); + let m = RistrettoSecretKey::random(&mut rng); + b.iter(|| factory.commit(&m, &v)); + }); +} + +criterion_group!( +name = commitment; +config = Criterion::default().warm_up_time(Duration::from_millis(500)); +targets = commit_default +); diff --git a/benches/mod.rs b/benches/mod.rs index 5ab07a48..1f42fad0 100644 --- a/benches/mod.rs +++ b/benches/mod.rs @@ -5,10 +5,12 @@ use criterion::criterion_main; +pub mod commitment; pub mod range_proof; pub mod signatures; +use commitment::commitment; use range_proof::range_proofs; use signatures::signatures; -criterion_main!(signatures, range_proofs); +criterion_main!(commitment, signatures, range_proofs); diff --git a/src/ristretto/constants.rs b/src/ristretto/constants.rs index 5662bc08..a4257e25 100644 --- a/src/ristretto/constants.rs +++ b/src/ristretto/constants.rs @@ -1,16 +1,18 @@ // Copyright 2019. The Tari Project // SPDX-License-Identifier: BSD-3-Clause -//! Constant [NUMS](https://tools.ietf.org/id/draft-black-numscurves-02.html) points for the Ristretto curve. There are 10 provided, but this library currently only +//! Constant [NUMS](https://www.ietf.org/archive/id/draft-black-numscurves-02.txt) points for the Ristretto curve. There are 10 provided, but this library currently only //! uses the first -use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint}; +use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint, RistrettoBasepointTable}; + +const NUMBER_NUMS_POINTS: usize = 10; /// These points on the Ristretto curve have been created by hashing domain separation labels with SHA512 and converting /// the hash output to a Ristretto generator point by using the byte string representation of the hash as input into the /// `from_uniform_bytes` constructor in [RistrettoPoint](Struct.RistrettoPoint.html). This process is validated with the /// `check_nums_points` test below. -pub const RISTRETTO_NUMS_POINTS_COMPRESSED: [CompressedRistretto; 10] = [ +pub const RISTRETTO_NUMS_POINTS_COMPRESSED: [CompressedRistretto; NUMBER_NUMS_POINTS] = [ CompressedRistretto([ 206, 56, 152, 65, 192, 200, 105, 138, 185, 91, 112, 36, 42, 238, 166, 72, 64, 177, 234, 197, 246, 68, 183, 208, 8, 172, 5, 135, 207, 71, 29, 112, @@ -55,24 +57,27 @@ pub const RISTRETTO_NUMS_POINTS_COMPRESSED: [CompressedRistretto; 10] = [ lazy_static! { /// A static array of pre-generated NUMS points - pub static ref RISTRETTO_NUMS_POINTS: [RistrettoPoint; 10] = { - let mut arr = [RistrettoPoint::default(); 10]; - for i in 0..10 { + pub static ref RISTRETTO_NUMS_POINTS: [RistrettoPoint; NUMBER_NUMS_POINTS] = { + let mut arr = [RistrettoPoint::default(); NUMBER_NUMS_POINTS]; + for i in 0..NUMBER_NUMS_POINTS { arr[i] = RISTRETTO_NUMS_POINTS_COMPRESSED[i].decompress().unwrap(); } arr }; + + /// Precomputation table for the first point, which is used as the default commitment generator + pub static ref RISTRETTO_NUMS_TABLE_0: RistrettoBasepointTable = RistrettoBasepointTable::create(&RISTRETTO_NUMS_POINTS[0]); } #[cfg(test)] mod test { use curve25519_dalek::{ constants::{RISTRETTO_BASEPOINT_COMPRESSED, RISTRETTO_BASEPOINT_POINT}, - ristretto::{CompressedRistretto, RistrettoPoint}, + ristretto::{CompressedRistretto, RistrettoPoint}, scalar::Scalar, traits::Identity, }; use sha2::{Digest, Sha512}; - use crate::ristretto::constants::{RISTRETTO_NUMS_POINTS, RISTRETTO_NUMS_POINTS_COMPRESSED}; + use crate::ristretto::constants::{RISTRETTO_NUMS_POINTS, RISTRETTO_NUMS_POINTS_COMPRESSED, RISTRETTO_NUMS_TABLE_0}; /// Generate a set of NUMS points by hashing domain separation labels and converting the hash output to a Ristretto /// generator point. By using `RistrettoPoint::from_uniform_bytes`, the resulting point is a NUMS point if the input @@ -116,4 +121,15 @@ mod test { } } } + + /// Check that precomputation works as expected + #[test] + pub fn check_tables() { + // Perform test multiplications + assert_eq!(&*RISTRETTO_NUMS_TABLE_0 * &Scalar::zero(), RistrettoPoint::identity()); + + for j in 0..15u8 { + assert_eq!(&*RISTRETTO_NUMS_TABLE_0 * &Scalar::from(j), RISTRETTO_NUMS_POINTS[0] * Scalar::from(j)); + } +} } diff --git a/src/ristretto/pedersen/commitment_factory.rs b/src/ristretto/pedersen/commitment_factory.rs index 007e25ac..e3fe2cba 100644 --- a/src/ristretto/pedersen/commitment_factory.rs +++ b/src/ristretto/pedersen/commitment_factory.rs @@ -4,6 +4,7 @@ //! Pedersen commitment types and factories for Ristretto use curve25519_dalek::{ + constants::RISTRETTO_BASEPOINT_TABLE, ristretto::RistrettoPoint, traits::{Identity, MultiscalarMul}, }; @@ -11,6 +12,7 @@ use curve25519_dalek::{ use crate::{ commitment::{HomomorphicCommitment, HomomorphicCommitmentFactory}, ristretto::{ + constants::RISTRETTO_NUMS_TABLE_0, pedersen::{PedersenCommitment, RISTRETTO_PEDERSEN_G, RISTRETTO_PEDERSEN_H}, RistrettoPublicKey, RistrettoSecretKey, @@ -45,8 +47,14 @@ impl Default for PedersenCommitmentFactory { impl HomomorphicCommitmentFactory for PedersenCommitmentFactory { type P = RistrettoPublicKey; + #[allow(non_snake_case)] fn commit(&self, k: &RistrettoSecretKey, v: &RistrettoSecretKey) -> PedersenCommitment { - let c = RistrettoPoint::multiscalar_mul(&[v.0, k.0], &[self.H, self.G]); + // If we're using the default generators, speed it up using precomputation tables + let c = if (self.G, self.H) == (RISTRETTO_PEDERSEN_G, *RISTRETTO_PEDERSEN_H) { + &RISTRETTO_BASEPOINT_TABLE * &k.0 + &*RISTRETTO_NUMS_TABLE_0 * &v.0 + } else { + RistrettoPoint::multiscalar_mul(&[v.0, k.0], &[self.H, self.G]) + }; HomomorphicCommitment(RistrettoPublicKey::new_from_pk(c)) }