diff --git a/.github/workflows/clippy-check.yml b/.github/workflows/clippy-check.yml
index a1135adc..d1b963ca 100644
--- a/.github/workflows/clippy-check.yml
+++ b/.github/workflows/clippy-check.yml
@@ -13,6 +13,13 @@ jobs:
components: clippy, rustfmt
toolchain: nightly
override: true
+ - name: Toolchain thumbv8m.main-none-eabi
+ uses: actions-rs/toolchain@v1
+ with:
+ profile: minimal
+ toolchain: nightly
+ target: thumbv8m.main-none-eabi
+ override: true
- name: Check formatting
uses: actions-rs/cargo@v1
with:
@@ -35,3 +42,16 @@ jobs:
with:
command: check
args: --release --all-targets
+ - name: Cargo check no default
+ uses: actions-rs/cargo@v1
+ with:
+ command: check
+ args: --release --no-default-features
+ # This check here is to ensure that it builds for no-std rust targets
+ - name: Cargo check for no-std
+ uses: actions-rs/cargo@v1
+ with:
+ command: check
+ toolchain: nightly
+ args: --no-default-features --target=thumbv8m.main-none-eabi -Zavoid-dev-deps
+
diff --git a/Cargo.toml b/Cargo.toml
index 1eca71b6..baaddf7b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,35 +11,38 @@ version = "0.17.0"
edition = "2018"
[dependencies]
-tari_utilities = { version = "0.5", features = ["zero", "std"] }
-blake2 = { version = "0.10" }
-borsh = { version = "0.10" , optional = true }
-bulletproofs_plus = { package = "tari_bulletproofs_plus", version = "0.3" }
-curve25519-dalek = { package = "tari-curve25519-dalek", version = "4.0.3", default-features = false, features = ["serde", "alloc", "rand_core", "precomputed-tables"] }
-digest = { version = "0.10" }
-lazy_static = { version = "1.3" }
-log = { version = "0.4" }
-once_cell = { version = "1.8" }
-rand_chacha = { version = "0.3" }
-rand_core = { version = "0.6" }
-serde = { version = "1.0" }
-sha3 = { version = "0.10" }
-thiserror = { version = "1.0" }
-zeroize = {version = "1" }
-rand = { version = "0.8" }
+tari_utilities = { version = "0.5", default-features = false, features = ["zero"] }
+blake2 = { version = "0.10", default-features = false }
+borsh = { version = "0.10" , optional = true , default-features = false}
+bulletproofs_plus = { package = "tari_bulletproofs_plus", version = "0.3", optional = true }
+curve25519-dalek = { package = "tari-curve25519-dalek", version = "4.0.3", default-features = false, features = [ "alloc", "rand_core", "precomputed-tables", "zeroize"] }
+digest = { version = "0.10", default-features = false }
+log = { version = "0.4" , default-features = false}
+once_cell = { version = "1.8", default-features = false, features = ["critical-section"] }
+rand_chacha = { version = "0.3", default-features = false }
+rand_core = { version = "0.6" , default-features = false}
+serde = { version = "1.0", optional = true }
+sha3 = { version = "0.10", default-features = false }
+snafu = { version = "0.7", default-features = false}
+zeroize = {version = "1" , default-features = false}
[dev-dependencies]
+tari_utilities = { version = "0.5", features = ["std"] }
+serde = { version = "1.0"}
bincode = { version = "1.1" }
criterion = { version = "0.5", default-features = false }
sha2 = { version = "0.10" }
+rand = { version = "0.8" }
[features]
+default = ["bulletproofs_plus", "serde", "precomputed_tables", "borsh"]
+precomputed_tables = []
[lib]
# Disable benchmarks to allow Criterion to take over
bench = false
-crate-type = ["lib", "cdylib", "staticlib"]
+crate-type = ["lib", "cdylib"]
[[bench]]
name = "benches"
diff --git a/README.md b/README.md
index 24f2765a..d01bf378 100644
--- a/README.md
+++ b/README.md
@@ -11,9 +11,26 @@ Major features of this library include:
- Pedersen commitments
- Schnorr Signatures
- Generic Public and Secret Keys
+- no-std support
The `tari_crypto` crate makes heavy use of the excellent [Dalek](https://github.com/dalek-cryptography/curve25519-dalek)
libraries. The default implementation for Tari ECC is the [Ristretto255 curve](https://ristretto.group).
+
+# Feature flags
+### bulletproofs_plus
+This adds in support for rangeproofs using the tari bulletproof plus library
+### serde
+This adds serialise and deserialize support for all structs using the serde library
+### borsh
+This adds serialise and deserialize support for all structs using the borsh library
+### precomputed_tables
+This uses optimised precomputed tables for calculations. While this is faster than straight-up calculations, this requires large memory to store which is not ideal for small no_std devices
+
+# WASM and FFI support
+TariCrypto has external WASM and FFI wrappers available here
+WASM: https://github.com/tari-project/tari-crypto-wasm
+FFI: https://github.com/tari-project/tari-crypto-ffi
+
# Benchmarks
To run the benchmarks:
diff --git a/benches/signatures.rs b/benches/signatures.rs
index e8c4755f..224bd554 100644
--- a/benches/signatures.rs
+++ b/benches/signatures.rs
@@ -5,6 +5,7 @@ use std::time::Duration;
use criterion::{criterion_group, BatchSize, Criterion};
use rand::{thread_rng, RngCore};
+use rand_core::OsRng;
use tari_crypto::{
keys::{PublicKey, SecretKey},
ristretto::{RistrettoPublicKey, RistrettoSchnorr, RistrettoSecretKey},
@@ -45,7 +46,7 @@ fn sign_message(c: &mut Criterion) {
b.iter_batched(
gen_keypair,
|d| {
- let _sig = RistrettoSchnorr::sign_message(&d.k, d.m).unwrap();
+ let _sig = RistrettoSchnorr::sign_message(&d.k, d.m, &mut OsRng).unwrap();
},
BatchSize::SmallInput,
);
@@ -59,7 +60,7 @@ fn verify_message(c: &mut Criterion) {
b.iter_batched(
|| {
let d = gen_keypair();
- let s = RistrettoSchnorr::sign_message(&d.k, d.m).unwrap();
+ let s = RistrettoSchnorr::sign_message(&d.k, d.m, &mut OsRng).unwrap();
(d, s)
},
|(d, s)| assert!(s.verify_message(&d.p, d.m)),
diff --git a/src/commitment.rs b/src/commitment.rs
index faa8c13b..84561da0 100644
--- a/src/commitment.rs
+++ b/src/commitment.rs
@@ -6,17 +6,17 @@
//! envelope and reveal its contents. Also it's a special envelope that can only be opened by a special opener that
//! you keep safe in your drawer.
-use std::{
+use core::{
cmp::Ordering,
convert::TryFrom,
hash::{Hash, Hasher},
ops::{Add, Mul, Sub},
};
-use serde::{Deserialize, Serialize};
use tari_utilities::{ByteArray, ByteArrayError};
use crate::{
+ alloc::string::ToString,
errors::CommitmentError,
keys::{PublicKey, SecretKey},
};
@@ -32,20 +32,21 @@ use crate::{
/// C_2 &= v_2.H + k_2.G \\\\
/// \therefore C_1 + C_2 &= (v_1 + v_2)H + (k_1 + k_2)G
/// \end{aligned} $$
-#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+#[derive(Debug, Clone, Default)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HomomorphicCommitment
(pub(crate) P);
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for HomomorphicCommitment {
- fn deserialize_reader(reader: &mut R) -> Result
- where R: std::io::Read {
+ fn deserialize_reader(reader: &mut R) -> Result
+ where R: borsh::maybestd::io::Read {
Ok(Self(P::deserialize_reader(reader)?))
}
}
#[cfg(feature = "borsh")]
impl borsh::BorshSerialize for HomomorphicCommitment {
- fn serialize(&self, writer: &mut W) -> std::io::Result<()> {
+ fn serialize(&self, writer: &mut W) -> borsh::maybestd::io::Result<()> {
self.0.serialize(writer)
}
}
@@ -251,9 +252,9 @@ impl ExtensionDegree {
4 => Ok(ExtensionDegree::AddThreeBasePoints),
5 => Ok(ExtensionDegree::AddFourBasePoints),
6 => Ok(ExtensionDegree::AddFiveBasePoints),
- _ => Err(CommitmentError::ExtensionDegree(
- "Extension degree not valid".to_string(),
- )),
+ _ => Err(CommitmentError::CommitmentExtensionDegree {
+ reason: "Extension degree not valid".to_string(),
+ }),
}
}
}
diff --git a/src/deterministic_randomizer.rs b/src/deterministic_randomizer.rs
index 94f6ab7e..be56e46b 100644
--- a/src/deterministic_randomizer.rs
+++ b/src/deterministic_randomizer.rs
@@ -4,7 +4,8 @@
//! A deterministic randomizer with utility functions for operating on numbers and arrays in a reproducible and
//! platform-indepdent way.
-use std::convert::TryFrom;
+use alloc::vec::Vec;
+use core::convert::TryFrom;
use rand_core::{CryptoRng, RngCore, SeedableRng};
diff --git a/src/dhke.rs b/src/dhke.rs
index 06450f15..ea409ba0 100644
--- a/src/dhke.rs
+++ b/src/dhke.rs
@@ -9,7 +9,7 @@
//! clone the byte array without a very good reason. If you need the underlying public key itself, you probably should
//! be using something else.
-use std::ops::Mul;
+use core::ops::Mul;
use zeroize::Zeroize;
diff --git a/src/errors.rs b/src/errors.rs
index 6a0b440a..db0e623c 100644
--- a/src/errors.rs
+++ b/src/errors.rs
@@ -3,65 +3,90 @@
//! Errors used in the Tari Crypto crate
-use serde::{Deserialize, Serialize};
-use tari_utilities::ByteArrayError;
-use thiserror::Error;
+use alloc::string::String;
+use snafu::prelude::*;
/// Errors encountered when creating of verifying range proofs
-#[derive(Debug, Clone, Error, PartialEq, Eq, Deserialize, Serialize)]
+#[derive(Debug, Clone, Snafu, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum RangeProofError {
/// Cold not construct a range proof
- #[error("Could not construct range proof: `{0}`")]
- ProofConstructionError(String),
+ #[snafu(display("Could not construct range proof: `{reason}'"))]
+ ProofConstructionError {
+ /// The reason for the error
+ reason: String,
+ },
/// The deserialization of the range proof failed
- #[error("The deserialization of the range proof failed")]
- InvalidProof,
+ #[snafu(display("The deserialization of the range proof failed"))]
+ InvalidProof {},
/// Invalid input was provided to the RangeProofService constructor
- #[error("Invalid input was provided to the RangeProofService constructor: `{0}`")]
- InitializationError(String),
+ #[snafu(display("Invalid input was provided to the RangeProofService constructor: `{reason}'"))]
+ InitializationError {
+ /// The reason for the error
+ reason: String,
+ },
/// Invalid range proof provided
- #[error("Invalid range proof provided: `{0}`")]
- InvalidRangeProof(String),
+ #[snafu(display("Invalid range proof provided: `{reason}"))]
+ InvalidRangeProof {
+ /// The reason for the error
+ reason: String,
+ },
/// Invalid range proof rewind, the rewind keys provided must be invalid
- #[error("Invalid range proof rewind, the rewind keys provided must be invalid")]
- InvalidRewind(String),
+ #[snafu(display("Invalid range proof rewind, the rewind keys provided must be invalid: `{reason}'"))]
+ InvalidRewind {
+ /// The reason for the error
+ reason: String,
+ },
/// Inconsistent extension degree
- #[error("Inconsistent extension degree: `{0}`")]
- ExtensionDegree(String),
+ #[snafu(display("Inconsistent extension degree: `{reason}'"))]
+ RPExtensionDegree {
+ /// The reason for the error
+ reason: String,
+ },
}
/// Errors encountered when committing values
-#[derive(Debug, Clone, Error, PartialEq, Eq, Deserialize, Serialize)]
+#[derive(Debug, Clone, Snafu, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CommitmentError {
/// Inconsistent extension degree
- #[error("Inconsistent extension degree: `{0}`")]
- ExtensionDegree(String),
+ #[snafu(display("Inconsistent extension degree: `{reason}'"))]
+ CommitmentExtensionDegree {
+ /// The reason for the error
+ reason: String,
+ },
}
/// Errors encountered when hashing
-#[derive(Debug, Error, PartialEq, Eq)]
+#[derive(Debug, Snafu, PartialEq, Eq)]
pub enum HashingError {
/// The input to the hashing function is too short
- #[error("The input to the hashing function is too short.")]
- InputTooShort,
+ #[snafu(display("The input to the hashing function is too short."))]
+ InputTooShort {},
/// Converting a byte string into a secret key failed
- #[error("Converting a byte string into a secret key failed: {0}")]
- ConversionFromBytes(String),
+ #[snafu(display("Converting a byte string into a secret key failed. `{reason}'"))]
+ ConversionFromBytes {
+ /// The reason for the error
+ reason: String,
+ },
/// The digest does not produce enough output
- #[error("The digest does produce enough output. {0} bytes are required.")]
- DigestTooShort(usize),
-}
-
-impl From for HashingError {
- fn from(byte_error: ByteArrayError) -> Self {
- HashingError::ConversionFromBytes(byte_error.to_string())
- }
+ #[snafu(display("The digest does produce enough output.`{bytes}' bytes are required."))]
+ DigestTooShort {
+ /// The number of bytes required
+ bytes: usize,
+ },
}
/// Errors encountered when copying to a buffer
-#[derive(Debug, Clone, Error, PartialEq, Eq, Serialize, Deserialize)]
+#[derive(Debug, Clone, Snafu, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SliceError {
/// The requested fixed slice length exceeds the available slice length
- #[error("Cannot create fixed slice of length {0} from a slice of length {1}.")]
- CopyFromSlice(usize, usize),
+ #[snafu(display("Cannot create fixed slice of length '{target}' from a slice of length '{provided}'"))]
+ CopyFromSlice {
+ /// The requested fixed slice length
+ target: usize,
+ /// The available slice length
+ provided: usize,
+ },
}
diff --git a/src/extended_range_proof.rs b/src/extended_range_proof.rs
index f8c17887..7850dc25 100644
--- a/src/extended_range_proof.rs
+++ b/src/extended_range_proof.rs
@@ -3,6 +3,8 @@
//! Extended range proofs
+use std::{string::ToString, vec::Vec};
+
use crate::{
commitment::{ExtensionDegree, HomomorphicCommitment},
errors::RangeProofError,
@@ -110,9 +112,9 @@ where K: SecretKey
/// Construct a new extended mask
pub fn assign(extension_degree: ExtensionDegree, secrets: Vec) -> Result, RangeProofError> {
if secrets.is_empty() || secrets.len() != extension_degree as usize {
- Err(RangeProofError::InitializationError(
- "Extended mask length must correspond to the extension degree".to_string(),
- ))
+ Err(RangeProofError::InitializationError {
+ reason: "Extended mask length must correspond to the extension degree".to_string(),
+ })
} else {
Ok(Self { secrets })
}
@@ -152,9 +154,9 @@ where PK: PublicKey
/// - `statements` must be a power of 2 as mandated by the `bulletproofs_plus` implementation
pub fn init(statements: Vec>) -> Result {
if !statements.len().is_power_of_two() {
- return Err(RangeProofError::InitializationError(
- "Number of commitments must be a power of two".to_string(),
- ));
+ return Err(RangeProofError::InitializationError {
+ reason: "Number of commitments must be a power of two".to_string(),
+ });
}
Ok(Self { statements })
}
@@ -180,14 +182,14 @@ where PK: PublicKey
/// - mask recovery is not supported with an aggregated statement/proof
pub fn init(statements: Vec>, recovery_seed_nonce: Option) -> Result {
if recovery_seed_nonce.is_some() && statements.len() > 1 {
- return Err(RangeProofError::InitializationError(
- "Mask recovery is not supported with an aggregated statement".to_string(),
- ));
+ return Err(RangeProofError::InitializationError {
+ reason: "Mask recovery is not supported with an aggregated statement".to_string(),
+ });
}
if !statements.len().is_power_of_two() {
- return Err(RangeProofError::InitializationError(
- "Number of commitments must be a power of two".to_string(),
- ));
+ return Err(RangeProofError::InitializationError {
+ reason: "Number of commitments must be a power of two".to_string(),
+ });
}
Ok(Self {
statements,
diff --git a/src/hashing.rs b/src/hashing.rs
index 903f9b0a..be1b29b5 100644
--- a/src/hashing.rs
+++ b/src/hashing.rs
@@ -28,7 +28,8 @@
//!
//! [hmac]: https://en.wikipedia.org/wiki/HMAC#Design_principles "HMAC: Design principles"
-use std::{marker::PhantomData, ops::Deref};
+use alloc::string::String;
+use core::{marker::PhantomData, ops::Deref};
use blake2::{Blake2b, Blake2bVar};
use digest::{consts::U32, Digest, FixedOutput, FixedOutputReset, Output, OutputSizeUser, Update};
@@ -36,6 +37,7 @@ use sha3::Sha3_256;
use tari_utilities::ByteArray;
use crate::{
+ alloc::string::ToString,
errors::{HashingError, SliceError},
keys::SecretKey,
};
@@ -305,7 +307,10 @@ pub trait AsFixedBytes: AsRef<[u8]> {
let hash_vec = self.as_ref();
if hash_vec.is_empty() || hash_vec.len() < I {
let hash_vec_length = if hash_vec.is_empty() { 0 } else { hash_vec.len() };
- return Err(SliceError::CopyFromSlice(I, hash_vec_length));
+ return Err(SliceError::CopyFromSlice {
+ target: I,
+ provided: hash_vec_length,
+ });
}
let mut buffer: [u8; I] = [0; I];
buffer.copy_from_slice(&hash_vec[..I]);
@@ -567,7 +572,8 @@ pub trait DerivedKeyDomain: DomainSeparation {
.chain(primary_key)
.chain(data)
.finalize();
- let derived_key = Self::DerivedKeyType::from_bytes(hash.as_ref())?;
+ let derived_key = Self::DerivedKeyType::from_bytes(hash.as_ref())
+ .map_err(|e| HashingError::ConversionFromBytes { reason: e.to_string() })?;
Ok(derived_key)
}
}
diff --git a/src/keys.rs b/src/keys.rs
index 6c4ef25d..14f8e250 100644
--- a/src/keys.rs
+++ b/src/keys.rs
@@ -6,10 +6,9 @@
//! implementation of ECC curve). The idea being that we can swap out the underlying
//! implementation without worrying too much about the impact on upstream code.
-use std::ops::Add;
+use core::ops::Add;
-use rand::{CryptoRng, Rng};
-use serde::{de::DeserializeOwned, ser::Serialize};
+use rand_core::{CryptoRng, RngCore};
use tari_utilities::ByteArray;
use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -39,7 +38,7 @@ pub trait SecretKey:
}
/// Generates a random secret key
- fn random(rng: &mut R) -> Self;
+ fn random(rng: &mut R) -> Self;
}
//---------------------------------------- Public Keys ----------------------------------------//
@@ -48,9 +47,7 @@ pub trait SecretKey:
/// implementations need to implement this trait for them to be used in Tari.
///
/// See [SecretKey](trait.SecretKey.html) for an example.
-pub trait PublicKey:
- ByteArray + Add + Clone + PartialOrd + Ord + Default + Serialize + DeserializeOwned + Zeroize
-{
+pub trait PublicKey: ByteArray + Add + Clone + PartialOrd + Ord + Default + Zeroize {
/// The length of the byte encoding of a key, in bytes
const KEY_LEN: usize;
@@ -71,7 +68,7 @@ pub trait PublicKey:
fn batch_mul(scalars: &[Self::K], points: &[Self]) -> Self;
/// Generate a random public and secret key
- fn random_keypair(rng: &mut R) -> (Self::K, Self) {
+ fn random_keypair(rng: &mut R) -> (Self::K, Self) {
let k = Self::K::random(rng);
let pk = Self::from_secret_key(&k);
(k, pk)
diff --git a/src/lib.rs b/src/lib.rs
index 7cc5862e..7f524aa7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,9 +2,15 @@
// SPDX-License-Identifier: BSD-3-Clause
//! Tari-Crypto
+#![no_std]
+#[allow(unused_imports)]
#[macro_use]
-extern crate lazy_static;
+extern crate alloc;
+
+#[cfg(any(feature = "bulletproofs_plus", test))]
+#[macro_use]
+extern crate std;
#[macro_use]
mod macros;
@@ -13,7 +19,9 @@ pub mod deterministic_randomizer;
pub mod dhke;
pub mod hashing;
pub mod keys;
+#[cfg(feature = "bulletproofs_plus")]
pub mod range_proof;
+#[cfg(feature = "bulletproofs_plus")]
pub mod rewindable_range_proof;
pub mod signatures;
@@ -22,6 +30,7 @@ pub mod signatures;
pub mod ristretto;
pub mod errors;
+#[cfg(feature = "bulletproofs_plus")]
pub mod extended_range_proof;
// Re-export tari_utils
diff --git a/src/ristretto/bulletproofs_plus.rs b/src/ristretto/bulletproofs_plus.rs
index 7c5be256..48e6f96b 100644
--- a/src/ristretto/bulletproofs_plus.rs
+++ b/src/ristretto/bulletproofs_plus.rs
@@ -3,6 +3,7 @@
//! Bulletproofs+ implementation
+use alloc::vec::Vec;
use std::convert::TryFrom;
pub use bulletproofs_plus::ristretto::RistrettoRangeProof;
@@ -20,6 +21,7 @@ use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar};
use log::*;
use crate::{
+ alloc::string::ToString,
commitment::{ExtensionDegree as CommitmentExtensionDegree, HomomorphicCommitment},
errors::RangeProofError,
extended_range_proof,
@@ -73,10 +75,10 @@ impl TryFrom<&BulletproofsExtendedMask> for RistrettoExtendedMask {
fn try_from(extended_mask: &BulletproofsExtendedMask) -> Result {
let secrets = extended_mask
.blindings()
- .map_err(|e| RangeProofError::ExtensionDegree(e.to_string()))?;
+ .map_err(|e| RangeProofError::RPExtensionDegree { reason: e.to_string() })?;
RistrettoExtendedMask::assign(
CommitmentExtensionDegree::try_from_size(secrets.len())
- .map_err(|e| RangeProofError::ExtensionDegree(e.to_string()))?,
+ .map_err(|e| RangeProofError::RPExtensionDegree { reason: e.to_string() })?,
secrets.iter().map(|k| RistrettoSecretKey(*k)).collect(),
)
}
@@ -87,9 +89,9 @@ impl TryFrom<&RistrettoExtendedMask> for BulletproofsExtendedMask {
fn try_from(extended_mask: &RistrettoExtendedMask) -> Result {
let extension_degree = BulletproofsExtensionDegree::try_from_size(extended_mask.secrets().len())
- .map_err(|e| RangeProofError::ExtensionDegree(e.to_string()))?;
+ .map_err(|e| RangeProofError::RPExtensionDegree { reason: e.to_string() })?;
BulletproofsExtendedMask::assign(extension_degree, Vec::try_from(extended_mask)?)
- .map_err(|e| RangeProofError::ExtensionDegree(e.to_string()))
+ .map_err(|e| RangeProofError::RPExtensionDegree { reason: e.to_string() })
}
}
@@ -108,9 +110,9 @@ impl BulletproofsPlusService {
g_base_vec: factory.g_base_vec,
g_base_compressed_vec: factory.g_base_compressed_vec,
extension_degree: BulletproofsExtensionDegree::try_from_size(factory.extension_degree as usize)
- .map_err(|e| RangeProofError::InitializationError(e.to_string()))?,
+ .map_err(|e| RangeProofError::InitializationError { reason: e.to_string() })?,
})
- .map_err(|e| RangeProofError::InitializationError(e.to_string()))?,
+ .map_err(|e| RangeProofError::InitializationError { reason: e.to_string() })?,
transcript_label: "Tari Bulletproofs+",
})
}
@@ -123,9 +125,9 @@ impl BulletproofsPlusService {
/// Helper function to return the serialized proof's extension degree
pub fn extension_degree(serialized_proof: &[u8]) -> Result {
let extension_degree = RistrettoRangeProof::extension_degree_from_proof_bytes(serialized_proof)
- .map_err(|e| RangeProofError::InvalidRangeProof(e.to_string()))?;
+ .map_err(|e| RangeProofError::InvalidRangeProof { reason: e.to_string() })?;
CommitmentExtensionDegree::try_from_size(extension_degree as usize)
- .map_err(|e| RangeProofError::InvalidRangeProof(e.to_string()))
+ .map_err(|e| RangeProofError::InvalidRangeProof { reason: e.to_string() })
}
/// Helper function to prepare a batch of public range statements
@@ -187,15 +189,16 @@ impl BulletproofsPlusService {
) -> Result>, RangeProofError> {
let mut range_proofs = Vec::with_capacity(proofs.len());
for (i, proof) in proofs.iter().enumerate() {
- match RistrettoRangeProof::from_bytes(proof).map_err(|e| RangeProofError::InvalidRangeProof(e.to_string()))
+ match RistrettoRangeProof::from_bytes(proof)
+ .map_err(|e| RangeProofError::InvalidRangeProof { reason: e.to_string() })
{
Ok(rp) => {
range_proofs.push(rp);
},
Err(e) => {
- return Err(RangeProofError::InvalidRangeProof(format!(
- "Range proof at index '{i}' could not be deserialized ({e})"
- )));
+ return Err(RangeProofError::InvalidRangeProof {
+ reason: format!("Range proof at index '{i}' could not be deserialized ({e})"),
+ });
},
}
}
@@ -213,21 +216,23 @@ impl RangeProofService for BulletproofsPlusService {
.generators
.pc_gens()
.commit(&Scalar::from(value), &[key.0])
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
let opening = CommitmentOpening::new(value, vec![key.0]);
- let witness =
- RangeWitness::init(vec![opening]).map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ let witness = RangeWitness::init(vec![opening])
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
let statement = RangeStatement::init(self.generators.clone(), vec![commitment], vec![None], None)
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
let proof = RistrettoRangeProof::prove(self.transcript_label, &statement, &witness)
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
Ok(proof.to_bytes())
}
fn verify(&self, proof: &Self::Proof, commitment: &HomomorphicCommitment) -> bool {
- match RistrettoRangeProof::from_bytes(proof).map_err(|e| RangeProofError::InvalidRangeProof(e.to_string())) {
+ match RistrettoRangeProof::from_bytes(proof)
+ .map_err(|e| RangeProofError::InvalidRangeProof { reason: e.to_string() })
+ {
Ok(rp) => {
let statement = RangeStatement {
generators: self.generators.clone(),
@@ -289,20 +294,20 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
.generators
.pc_gens()
.commit(&Scalar::from(value), &[mask.0])
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
let opening = CommitmentOpening::new(value, vec![mask.0]);
- let witness =
- RangeWitness::init(vec![opening]).map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ let witness = RangeWitness::init(vec![opening])
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
let statement = RangeStatement::init(
self.generators.clone(),
vec![commitment],
vec![None],
Some(seed_nonce.0),
)
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
let proof = RistrettoRangeProof::prove(self.transcript_label, &statement, &witness)
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
Ok(proof.to_bytes())
}
@@ -313,9 +318,9 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
seed_nonce: Option,
) -> Result {
if extended_witnesses.is_empty() {
- return Err(RangeProofError::ProofConstructionError(
- "Extended witness vector cannot be empty".to_string(),
- ));
+ return Err(RangeProofError::ProofConstructionError {
+ reason: "Extended witness vector cannot be empty".to_string(),
+ });
}
let mut commitments = Vec::with_capacity(extended_witnesses.len());
let mut openings = Vec::with_capacity(extended_witnesses.len());
@@ -325,23 +330,23 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
self.generators
.pc_gens()
.commit(&Scalar::from(witness.value), &Vec::try_from(&witness.mask)?)
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?,
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?,
);
openings.push(CommitmentOpening::new(witness.value, Vec::try_from(&witness.mask)?));
min_value_promises.push(witness.minimum_value_promise);
}
- let witness =
- RangeWitness::init(openings).map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ let witness = RangeWitness::init(openings)
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
let statement = RangeStatement::init(
self.generators.clone(),
commitments,
min_value_promises.iter().map(|v| Some(*v)).collect(),
seed_nonce.map(|s| s.0),
)
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
let proof = RistrettoRangeProof::prove(self.transcript_label, &statement, &witness)
- .map_err(|e| RangeProofError::ProofConstructionError(e.to_string()))?;
+ .map_err(|e| RangeProofError::ProofConstructionError { reason: e.to_string() })?;
Ok(proof.to_bytes())
}
@@ -368,9 +373,9 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
Ok(recovered_masks) => {
if recovered_masks.is_empty() {
// A mask vector should always be returned so this is a valid error condition
- return Err(RangeProofError::InvalidRewind(
- "Range proof(s) verified Ok, but no mask vector returned".to_string(),
- ));
+ return Err(RangeProofError::InvalidRewind {
+ reason: "Range proof(s) verified Ok, but no mask vector returned".to_string(),
+ });
} else {
for recovered_mask in recovered_masks {
if let Some(mask) = &recovered_mask {
@@ -382,9 +387,9 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
}
},
Err(e) => {
- return Err(RangeProofError::InvalidRangeProof(format!(
- "Internal range proof(s) error ({e})"
- )))
+ return Err(RangeProofError::InvalidRangeProof {
+ reason: format!("Internal range proof(s) error ({e})"),
+ })
},
};
Ok(recovered_extended_masks)
@@ -409,9 +414,9 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
VerifyAction::VerifyOnly,
) {
Ok(_) => Ok(()),
- Err(e) => Err(RangeProofError::InvalidRangeProof(format!(
- "Internal range proof(s) error ({e})"
- ))),
+ Err(e) => Err(RangeProofError::InvalidRangeProof {
+ reason: format!("Internal range proof(s) error ({e})"),
+ }),
}
}
@@ -421,7 +426,9 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
commitment: &HomomorphicCommitment,
seed_nonce: &Self::K,
) -> Result {
- match RistrettoRangeProof::from_bytes(proof).map_err(|e| RangeProofError::InvalidRangeProof(e.to_string())) {
+ match RistrettoRangeProof::from_bytes(proof)
+ .map_err(|e| RangeProofError::InvalidRangeProof { reason: e.to_string() })
+ {
Ok(rp) => {
let statement = RangeStatement {
generators: self.generators.clone(),
@@ -440,28 +447,28 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
) {
Ok(recovered_mask) => {
if recovered_mask.is_empty() {
- Err(RangeProofError::InvalidRewind(
- "Mask could not be recovered".to_string(),
- ))
+ Err(RangeProofError::InvalidRewind {
+ reason: "Mask could not be recovered".to_string(),
+ })
} else if let Some(mask) = &recovered_mask[0] {
Ok(RistrettoSecretKey(
mask.blindings()
- .map_err(|e| RangeProofError::InvalidRewind(e.to_string()))?[0],
+ .map_err(|e| RangeProofError::InvalidRewind { reason: e.to_string() })?[0],
))
} else {
- Err(RangeProofError::InvalidRewind(
- "Mask could not be recovered".to_string(),
- ))
+ Err(RangeProofError::InvalidRewind {
+ reason: "Mask could not be recovered".to_string(),
+ })
}
},
- Err(e) => Err(RangeProofError::InvalidRangeProof(format!(
- "Internal range proof error ({e})"
- ))),
+ Err(e) => Err(RangeProofError::InvalidRangeProof {
+ reason: format!("Internal range proof error ({e})"),
+ }),
}
},
- Err(e) => Err(RangeProofError::InvalidRangeProof(format!(
- "Range proof could not be deserialized ({e})"
- ))),
+ Err(e) => Err(RangeProofError::InvalidRangeProof {
+ reason: format!("Range proof could not be deserialized ({e})"),
+ }),
}
}
@@ -470,7 +477,9 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
proof: &Self::Proof,
statement: &RistrettoAggregatedPrivateStatement,
) -> Result, RangeProofError> {
- match RistrettoRangeProof::from_bytes(proof).map_err(|e| RangeProofError::InvalidRangeProof(e.to_string())) {
+ match RistrettoRangeProof::from_bytes(proof)
+ .map_err(|e| RangeProofError::InvalidRangeProof { reason: e.to_string() })
+ {
Ok(rp) => {
// Prepare the range statement
let range_statements = self.prepare_private_range_statements(vec![statement]);
@@ -490,14 +499,14 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
Ok(None)
}
},
- Err(e) => Err(RangeProofError::InvalidRangeProof(format!(
- "Internal range proof error ({e})"
- ))),
+ Err(e) => Err(RangeProofError::InvalidRangeProof {
+ reason: format!("Internal range proof error ({e})"),
+ }),
}
},
- Err(e) => Err(RangeProofError::InvalidRangeProof(format!(
- "Range proof could not be deserialized ({e})"
- ))),
+ Err(e) => Err(RangeProofError::InvalidRangeProof {
+ reason: format!("Range proof could not be deserialized ({e})"),
+ }),
}
}
@@ -511,7 +520,7 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
.generators
.pc_gens()
.commit(&Scalar::from(value), &[mask.0])
- .map_err(|e| RangeProofError::ExtensionDegree(e.to_string()))
+ .map_err(|e| RangeProofError::RPExtensionDegree { reason: e.to_string() })
{
Ok(val) => Ok(val == commitment.0.point()),
Err(e) => Err(e),
@@ -528,7 +537,7 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
.generators
.pc_gens()
.commit(&Scalar::from(value), &Vec::try_from(extended_mask)?)
- .map_err(|e| RangeProofError::ExtensionDegree(e.to_string()))
+ .map_err(|e| RangeProofError::RPExtensionDegree { reason: e.to_string() })
{
Ok(val) => Ok(val == commitment.0.point()),
Err(e) => Err(e),
@@ -538,7 +547,7 @@ impl ExtendedRangeProofService for BulletproofsPlusService {
#[cfg(test)]
mod test {
- use std::collections::HashMap;
+ use std::{collections::HashMap, vec::Vec};
use bulletproofs_plus::protocols::scalar_protocol::ScalarProtocol;
use curve25519_dalek::scalar::Scalar;
diff --git a/src/ristretto/constants.rs b/src/ristretto/constants.rs
index 1588cc53..8e65f0d1 100644
--- a/src/ristretto/constants.rs
+++ b/src/ristretto/constants.rs
@@ -6,6 +6,7 @@
//! Tests the correctness of the NUMS construction.
use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoBasepointTable, RistrettoPoint};
+use once_cell::sync::OnceCell;
const NUMBER_NUMS_POINTS: usize = 10;
@@ -56,22 +57,28 @@ pub const RISTRETTO_NUMS_POINTS_COMPRESSED: [CompressedRistretto; NUMBER_NUMS_PO
]),
];
-lazy_static! {
- /// A static array of pre-generated NUMS points
- pub static ref RISTRETTO_NUMS_POINTS: [RistrettoPoint; NUMBER_NUMS_POINTS] = {
+/// A static array of pre-generated NUMS points
+pub fn ristretto_nums_points() -> &'static [RistrettoPoint; NUMBER_NUMS_POINTS] {
+ static INSTANCE: OnceCell<[RistrettoPoint; NUMBER_NUMS_POINTS]> = OnceCell::new();
+ INSTANCE.get_or_init(|| {
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]);
+/// Precomputation table for the first point, which is used as the default commitment generator
+pub fn ristretto_nums_table_0() -> &'static RistrettoBasepointTable {
+ static INSTANCE: OnceCell = OnceCell::new();
+ INSTANCE.get_or_init(|| RistrettoBasepointTable::create(&ristretto_nums_points()[0]))
}
#[cfg(test)]
mod test {
+ use alloc::vec::Vec;
+
use curve25519_dalek::{
constants::{RISTRETTO_BASEPOINT_COMPRESSED, RISTRETTO_BASEPOINT_POINT},
ristretto::{CompressedRistretto, RistrettoPoint},
@@ -81,9 +88,9 @@ mod test {
use sha2::{Digest, Sha512};
use crate::ristretto::constants::{
- RISTRETTO_NUMS_POINTS,
+ ristretto_nums_points,
+ ristretto_nums_table_0,
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
@@ -105,25 +112,27 @@ mod test {
(points, compressed_points)
}
- /// Confirm that the [RISTRETTO_NUM_POINTS array](Const.RISTRETTO_NUMS_POINTS.html) is generated with Nothing Up
+ /// Confirm that the [RISTRETTO_NUM_POINTS array](Const.ristretto_nums_points().html) is generated with Nothing Up
/// My Sleeve (NUMS), unique, not equal to the identity value and not equal to the Ristretto base point.
#[test]
pub fn check_nums_points() {
let n = RISTRETTO_NUMS_POINTS_COMPRESSED.len();
let calculated_nums_points = nums_ristretto(n);
+ #[allow(clippy::needless_range_loop)]
for i in 0..n {
// Should be equal to the NUMS constants
- assert_eq!(calculated_nums_points.0[i], RISTRETTO_NUMS_POINTS[i]);
+ assert_eq!(calculated_nums_points.0[i], ristretto_nums_points()[i]);
assert_eq!(calculated_nums_points.1[i], RISTRETTO_NUMS_POINTS_COMPRESSED[i]);
// Should not be equal to the identity values
- assert_ne!(RistrettoPoint::default(), RISTRETTO_NUMS_POINTS[i]);
+ assert_ne!(RistrettoPoint::default(), ristretto_nums_points()[i]);
assert_ne!(CompressedRistretto::default(), RISTRETTO_NUMS_POINTS_COMPRESSED[i]);
// Should not be equal to the Ristretto base point
- assert_ne!(RISTRETTO_BASEPOINT_POINT, RISTRETTO_NUMS_POINTS[i]);
+ assert_ne!(RISTRETTO_BASEPOINT_POINT, ristretto_nums_points()[i]);
assert_ne!(RISTRETTO_BASEPOINT_COMPRESSED, RISTRETTO_NUMS_POINTS_COMPRESSED[i]);
// Should all be unique
+ #[allow(clippy::needless_range_loop)]
for j in i + 1..n {
- assert_ne!(RISTRETTO_NUMS_POINTS[i], RISTRETTO_NUMS_POINTS[j]);
+ assert_ne!(ristretto_nums_points()[i], ristretto_nums_points()[j]);
assert_ne!(RISTRETTO_NUMS_POINTS_COMPRESSED[i], RISTRETTO_NUMS_POINTS_COMPRESSED[j]);
}
}
@@ -133,12 +142,12 @@ mod test {
#[test]
pub fn check_tables() {
// Perform test multiplications
- assert_eq!(&*RISTRETTO_NUMS_TABLE_0 * &Scalar::ZERO, RistrettoPoint::identity());
+ 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)
+ ristretto_nums_table_0() * &Scalar::from(j),
+ ristretto_nums_points()[0] * Scalar::from(j)
);
}
}
diff --git a/src/ristretto/mod.rs b/src/ristretto/mod.rs
index 169a61b5..af3102db 100644
--- a/src/ristretto/mod.rs
+++ b/src/ristretto/mod.rs
@@ -3,6 +3,7 @@
//! This module contains implementations using the Ristretto curve.
+#[cfg(feature = "bulletproofs_plus")]
pub mod bulletproofs_plus;
pub mod constants;
pub mod pedersen;
@@ -10,6 +11,7 @@ mod ristretto_com_and_pub_sig;
mod ristretto_com_sig;
pub mod ristretto_keys;
mod ristretto_sig;
+#[cfg(feature = "serde")]
pub mod serialize;
pub mod utils;
diff --git a/src/ristretto/pedersen/commitment_factory.rs b/src/ristretto/pedersen/commitment_factory.rs
index edae45a1..0cc112ed 100644
--- a/src/ristretto/pedersen/commitment_factory.rs
+++ b/src/ristretto/pedersen/commitment_factory.rs
@@ -8,15 +8,12 @@ use curve25519_dalek::{
traits::{Identity, MultiscalarMul},
};
+#[cfg(feature = "precomputed_tables")]
+use crate::ristretto::pedersen::scalar_mul_with_pre_computation_tables;
use crate::{
commitment::{HomomorphicCommitment, HomomorphicCommitmentFactory},
ristretto::{
- pedersen::{
- scalar_mul_with_pre_computation_tables,
- PedersenCommitment,
- RISTRETTO_PEDERSEN_G,
- RISTRETTO_PEDERSEN_H,
- },
+ pedersen::{ristretto_pedersen_h, PedersenCommitment, RISTRETTO_PEDERSEN_G},
RistrettoPublicKey,
RistrettoSecretKey,
},
@@ -43,7 +40,7 @@ impl PedersenCommitmentFactory {
impl Default for PedersenCommitmentFactory {
/// The default Ristretto Commitment factory uses the Base point for x25519 and its first Blake256 hash.
fn default() -> Self {
- PedersenCommitmentFactory::new(RISTRETTO_PEDERSEN_G, *RISTRETTO_PEDERSEN_H)
+ PedersenCommitmentFactory::new(RISTRETTO_PEDERSEN_G, *ristretto_pedersen_h())
}
}
@@ -53,8 +50,15 @@ impl HomomorphicCommitmentFactory for PedersenCommitmentFactory {
#[allow(non_snake_case)]
fn commit(&self, k: &RistrettoSecretKey, v: &RistrettoSecretKey) -> PedersenCommitment {
// If we're using the default generators, speed it up using pre-computation tables
- let c = if (self.G, self.H) == (RISTRETTO_PEDERSEN_G, *RISTRETTO_PEDERSEN_H) {
- scalar_mul_with_pre_computation_tables(&k.0, &v.0)
+ let c = if (self.G, self.H) == (RISTRETTO_PEDERSEN_G, *ristretto_pedersen_h()) {
+ #[cfg(feature = "precomputed_tables")]
+ {
+ scalar_mul_with_pre_computation_tables(&k.0, &v.0)
+ }
+ #[cfg(not(feature = "precomputed_tables"))]
+ {
+ RistrettoPoint::multiscalar_mul(&[v.0, k.0], &[self.H, self.G])
+ }
} else {
RistrettoPoint::multiscalar_mul(&[v.0, k.0], &[self.H, self.G])
};
@@ -83,6 +87,7 @@ impl HomomorphicCommitmentFactory for PedersenCommitmentFactory {
#[cfg(test)]
mod test {
+ use alloc::vec::Vec;
use std::{
collections::hash_map::DefaultHasher,
convert::From,
@@ -90,7 +95,6 @@ mod test {
};
use curve25519_dalek::scalar::Scalar;
- use tari_utilities::message_format::MessageFormat;
use super::*;
use crate::{
@@ -103,7 +107,7 @@ mod test {
fn check_default_base() {
let base = PedersenCommitmentFactory::default();
assert_eq!(base.G, RISTRETTO_PEDERSEN_G);
- assert_eq!(base.H, *RISTRETTO_PEDERSEN_H)
+ assert_eq!(base.H, *ristretto_pedersen_h())
}
#[test]
@@ -111,7 +115,7 @@ mod test {
fn check_zero() {
let c = RistrettoPoint::multiscalar_mul(&[Scalar::ZERO, Scalar::ZERO], &[
RISTRETTO_PEDERSEN_G,
- *RISTRETTO_PEDERSEN_H,
+ *ristretto_pedersen_h(),
]);
let factory = PedersenCommitmentFactory::default();
assert_eq!(
@@ -126,7 +130,7 @@ mod test {
#[allow(non_snake_case)]
fn check_open() {
let factory = PedersenCommitmentFactory::default();
- let H = *RISTRETTO_PEDERSEN_H;
+ let H = *ristretto_pedersen_h();
let mut rng = rand::thread_rng();
for _ in 0..100 {
let v = RistrettoSecretKey::random(&mut rng);
@@ -220,9 +224,10 @@ mod test {
assert!(commitment_factory.open(&k_sum, &v_sum, &c_sum));
assert_eq!(c_sum, commitments.iter().sum());
}
-
+ #[cfg(feature = "serde")]
#[test]
fn serialize_deserialize() {
+ use tari_utilities::message_format::MessageFormat;
let mut rng = rand::thread_rng();
let factory = PedersenCommitmentFactory::default();
let k = RistrettoSecretKey::random(&mut rng);
diff --git a/src/ristretto/pedersen/extended_commitment_factory.rs b/src/ristretto/pedersen/extended_commitment_factory.rs
index 5c55beaf..232b24ce 100644
--- a/src/ristretto/pedersen/extended_commitment_factory.rs
+++ b/src/ristretto/pedersen/extended_commitment_factory.rs
@@ -3,7 +3,8 @@
//! Extended commitments are commitments that have more than one blinding factor.
-use std::{borrow::Borrow, iter::once};
+use alloc::vec::Vec;
+use core::{borrow::Borrow, iter::once};
use curve25519_dalek::{
ristretto::{CompressedRistretto, RistrettoPoint},
@@ -11,7 +12,10 @@ use curve25519_dalek::{
traits::{Identity, MultiscalarMul},
};
+#[cfg(feature = "precomputed_tables")]
+use crate::ristretto::pedersen::scalar_mul_with_pre_computation_tables;
use crate::{
+ alloc::string::ToString,
commitment::{
ExtendedHomomorphicCommitmentFactory,
ExtensionDegree,
@@ -20,14 +24,13 @@ use crate::{
},
errors::CommitmentError,
ristretto::{
- constants::{RISTRETTO_NUMS_POINTS, RISTRETTO_NUMS_POINTS_COMPRESSED},
+ constants::{ristretto_nums_points, RISTRETTO_NUMS_POINTS_COMPRESSED},
pedersen::{
- scalar_mul_with_pre_computation_tables,
+ ristretto_pedersen_h,
+ ristretto_pedersen_h_compressed,
PedersenCommitment,
RISTRETTO_PEDERSEN_G,
RISTRETTO_PEDERSEN_G_COMPRESSED,
- RISTRETTO_PEDERSEN_H,
- RISTRETTO_PEDERSEN_H_COMPRESSED,
},
RistrettoPublicKey,
RistrettoSecretKey,
@@ -56,24 +59,24 @@ impl ExtendedPedersenCommitmentFactory {
/// Create a new Extended Pedersen Ristretto Commitment factory for the required extension degree using
/// pre-calculated compressed constants - we only hold references to the static generator points.
pub fn new_with_extension_degree(extension_degree: ExtensionDegree) -> Result {
- if extension_degree as usize > RISTRETTO_NUMS_POINTS.len() ||
+ if extension_degree as usize > ristretto_nums_points().len() ||
extension_degree as usize > RISTRETTO_NUMS_POINTS_COMPRESSED.len()
{
- return Err(CommitmentError::ExtensionDegree(
- "Not enough Ristretto NUMS points to construct the extended commitment factory".to_string(),
- ));
+ return Err(CommitmentError::CommitmentExtensionDegree {
+ reason: "Not enough Ristretto NUMS points to construct the extended commitment factory".to_string(),
+ });
}
- let g_base_vec = std::iter::once(&RISTRETTO_PEDERSEN_G)
- .chain(RISTRETTO_NUMS_POINTS[1..extension_degree as usize].iter())
+ let g_base_vec = once(&RISTRETTO_PEDERSEN_G)
+ .chain(ristretto_nums_points()[1..extension_degree as usize].iter())
.copied()
.collect();
- let g_base_compressed_vec = std::iter::once(&RISTRETTO_PEDERSEN_G_COMPRESSED)
+ let g_base_compressed_vec = once(&RISTRETTO_PEDERSEN_G_COMPRESSED)
.chain(RISTRETTO_NUMS_POINTS_COMPRESSED[1..extension_degree as usize].iter())
.copied()
.collect();
Ok(Self {
- h_base: *RISTRETTO_PEDERSEN_H,
- h_base_compressed: *RISTRETTO_PEDERSEN_H_COMPRESSED,
+ h_base: *ristretto_pedersen_h(),
+ h_base_compressed: *ristretto_pedersen_h_compressed(),
g_base_vec,
g_base_compressed_vec,
extension_degree,
@@ -90,11 +93,23 @@ impl ExtendedPedersenCommitmentFactory {
for<'a> &'a Scalar: Borrow,
{
if blinding_factors.is_empty() || blinding_factors.len() > self.extension_degree as usize {
- Err(CommitmentError::ExtensionDegree("blinding vector".to_string()))
+ Err(CommitmentError::CommitmentExtensionDegree {
+ reason: "blinding vector".to_string(),
+ })
} else if blinding_factors.len() == 1 &&
- (self.g_base_vec[0], self.h_base) == (RISTRETTO_PEDERSEN_G, *RISTRETTO_PEDERSEN_H)
+ (self.g_base_vec[0], self.h_base) == (RISTRETTO_PEDERSEN_G, *ristretto_pedersen_h())
{
- Ok(scalar_mul_with_pre_computation_tables(&blinding_factors[0], value))
+ #[cfg(feature = "precomputed_tables")]
+ {
+ Ok(scalar_mul_with_pre_computation_tables(&blinding_factors[0], value))
+ }
+ #[cfg(not(feature = "precomputed_tables"))]
+ {
+ let scalars = once(value).chain(blinding_factors);
+ let g_base_head = self.g_base_vec.iter().take(blinding_factors.len());
+ let points = once(&self.h_base).chain(g_base_head);
+ Ok(RistrettoPoint::multiscalar_mul(scalars, points))
+ }
} else {
let scalars = once(value).chain(blinding_factors);
let g_base_head = self.g_base_vec.iter().take(blinding_factors.len());
@@ -168,7 +183,7 @@ impl ExtendedHomomorphicCommitmentFactory for ExtendedPedersenCommitmentFactory
) -> Result {
let c_test = self
.commit_extended(k_vec, v)
- .map_err(|e| CommitmentError::ExtensionDegree(e.to_string()))?;
+ .map_err(|e| CommitmentError::CommitmentExtensionDegree { reason: e.to_string() })?;
Ok(commitment == &c_test)
}
@@ -194,6 +209,7 @@ impl ExtendedHomomorphicCommitmentFactory for ExtendedPedersenCommitmentFactory
#[cfg(test)]
mod test {
+ use alloc::vec::Vec;
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
@@ -201,7 +217,6 @@ mod test {
use curve25519_dalek::{ristretto::RistrettoPoint, scalar::Scalar, traits::MultiscalarMul};
use rand::rngs::ThreadRng;
- use tari_utilities::message_format::MessageFormat;
use crate::{
commitment::{
@@ -212,13 +227,12 @@ mod test {
},
keys::{PublicKey, SecretKey},
ristretto::{
- constants::RISTRETTO_NUMS_POINTS,
+ constants::ristretto_nums_points,
pedersen::{
commitment_factory::PedersenCommitmentFactory,
extended_commitment_factory::ExtendedPedersenCommitmentFactory,
- PedersenCommitment,
+ ristretto_pedersen_h,
RISTRETTO_PEDERSEN_G,
- RISTRETTO_PEDERSEN_H,
},
RistrettoPublicKey,
RistrettoSecretKey,
@@ -238,7 +252,7 @@ mod test {
fn check_default_base() {
let factory = ExtendedPedersenCommitmentFactory::default();
assert_eq!(factory.g_base_vec[0], RISTRETTO_PEDERSEN_G);
- assert_eq!(factory.h_base, *RISTRETTO_PEDERSEN_H);
+ assert_eq!(factory.h_base, *ristretto_pedersen_h());
assert_eq!(
factory,
ExtendedPedersenCommitmentFactory::new_with_extension_degree(ExtensionDegree::DefaultPedersen).unwrap()
@@ -291,7 +305,7 @@ mod test {
#[test]
#[allow(non_snake_case)]
fn check_open_both_traits() {
- let H = *RISTRETTO_PEDERSEN_H;
+ let H = *ristretto_pedersen_h();
let mut rng = rand::thread_rng();
for extension_degree in EXTENSION_DEGREE {
let factory = ExtendedPedersenCommitmentFactory::new_with_extension_degree(extension_degree).unwrap();
@@ -300,8 +314,9 @@ mod test {
let k_vec = vec![RistrettoSecretKey::random(&mut rng); extension_degree as usize];
let c_extended = factory.commit_extended(&k_vec, &v).unwrap();
let mut c_calc: RistrettoPoint = v.0 * H + k_vec[0].0 * RISTRETTO_PEDERSEN_G;
+ #[allow(clippy::needless_range_loop)]
for i in 1..(extension_degree as usize) {
- c_calc += k_vec[i].0 * RISTRETTO_NUMS_POINTS[i];
+ c_calc += k_vec[i].0 * ristretto_nums_points()[i];
}
assert_eq!(RistrettoPoint::from(c_extended.as_public_key()), c_calc);
@@ -539,42 +554,49 @@ mod test {
}
}
- #[test]
- fn serialize_deserialize_singular() {
- let mut rng = rand::thread_rng();
- let factory = ExtendedPedersenCommitmentFactory::default();
- let k = RistrettoSecretKey::random(&mut rng);
- let c = factory.commit_value(&k, 420);
- // Base64
- let ser_c = c.to_base64().unwrap();
- let c2 = PedersenCommitment::from_base64(&ser_c).unwrap();
- assert!(factory.open_value(&k, 420, &c2));
- // MessagePack
- let ser_c = c.to_binary().unwrap();
- let c2 = PedersenCommitment::from_binary(&ser_c).unwrap();
- assert!(factory.open_value(&k, 420, &c2));
- // Invalid Base64
- assert!(PedersenCommitment::from_base64("bad@ser$").is_err());
- }
+ #[cfg(feature = "serde")]
+ mod test_serialize {
+ use tari_utilities::message_format::MessageFormat;
- #[test]
- fn serialize_deserialize_extended() {
- let mut rng = rand::thread_rng();
- for extension_degree in EXTENSION_DEGREE {
- let factory = ExtendedPedersenCommitmentFactory::new_with_extension_degree(extension_degree).unwrap();
- let k_vec = vec![RistrettoSecretKey::random(&mut rng); extension_degree as usize];
- let c = factory.commit_value_extended(&k_vec, 420).unwrap();
+ use super::*;
+ use crate::ristretto::pedersen::PedersenCommitment;
+ #[test]
+ fn serialize_deserialize_singular() {
+ let mut rng = rand::thread_rng();
+ let factory = ExtendedPedersenCommitmentFactory::default();
+ let k = RistrettoSecretKey::random(&mut rng);
+ let c = factory.commit_value(&k, 420);
// Base64
let ser_c = c.to_base64().unwrap();
let c2 = PedersenCommitment::from_base64(&ser_c).unwrap();
- assert!(factory.open_value_extended(&k_vec, 420, &c2).unwrap());
+ assert!(factory.open_value(&k, 420, &c2));
// MessagePack
let ser_c = c.to_binary().unwrap();
let c2 = PedersenCommitment::from_binary(&ser_c).unwrap();
- assert!(factory.open_value_extended(&k_vec, 420, &c2).unwrap());
+ assert!(factory.open_value(&k, 420, &c2));
// Invalid Base64
assert!(PedersenCommitment::from_base64("bad@ser$").is_err());
}
+
+ #[test]
+ fn serialize_deserialize_extended() {
+ let mut rng = rand::thread_rng();
+ for extension_degree in EXTENSION_DEGREE {
+ let factory = ExtendedPedersenCommitmentFactory::new_with_extension_degree(extension_degree).unwrap();
+ let k_vec = vec![RistrettoSecretKey::random(&mut rng); extension_degree as usize];
+ let c = factory.commit_value_extended(&k_vec, 420).unwrap();
+ // Base64
+ let ser_c = c.to_base64().unwrap();
+ let c2 = PedersenCommitment::from_base64(&ser_c).unwrap();
+ assert!(factory.open_value_extended(&k_vec, 420, &c2).unwrap());
+ // MessagePack
+ let ser_c = c.to_binary().unwrap();
+ let c2 = PedersenCommitment::from_binary(&ser_c).unwrap();
+ assert!(factory.open_value_extended(&k_vec, 420, &c2).unwrap());
+ // Invalid Base64
+ assert!(PedersenCommitment::from_base64("bad@ser$").is_err());
+ }
+ }
}
#[test]
diff --git a/src/ristretto/pedersen/mod.rs b/src/ristretto/pedersen/mod.rs
index 8e7c2af0..1230c05c 100644
--- a/src/ristretto/pedersen/mod.rs
+++ b/src/ristretto/pedersen/mod.rs
@@ -3,18 +3,22 @@
//! Pederson commitments utilities
-use std::{borrow::Borrow, iter::Sum};
+use core::{borrow::Borrow, iter::Sum};
+#[cfg(feature = "precomputed_tables")]
+use curve25519_dalek::{constants::RISTRETTO_BASEPOINT_TABLE, scalar::Scalar};
use curve25519_dalek::{
- constants::{RISTRETTO_BASEPOINT_COMPRESSED, RISTRETTO_BASEPOINT_POINT, RISTRETTO_BASEPOINT_TABLE},
+ constants::{RISTRETTO_BASEPOINT_COMPRESSED, RISTRETTO_BASEPOINT_POINT},
ristretto::{CompressedRistretto, RistrettoPoint},
- scalar::Scalar,
};
+use once_cell::sync::OnceCell;
+#[cfg(feature = "precomputed_tables")]
+use crate::ristretto::constants::ristretto_nums_table_0;
use crate::{
commitment::HomomorphicCommitment,
ristretto::{
- constants::{RISTRETTO_NUMS_POINTS, RISTRETTO_NUMS_POINTS_COMPRESSED, RISTRETTO_NUMS_TABLE_0},
+ constants::{ristretto_nums_points, RISTRETTO_NUMS_POINTS_COMPRESSED},
RistrettoPublicKey,
},
};
@@ -26,11 +30,15 @@ pub mod extended_commitment_factory;
pub const RISTRETTO_PEDERSEN_G: RistrettoPoint = RISTRETTO_BASEPOINT_POINT;
/// The default generator on a Pedersen commitment used for the blinding factor in a compressed form
pub const RISTRETTO_PEDERSEN_G_COMPRESSED: CompressedRistretto = RISTRETTO_BASEPOINT_COMPRESSED;
-lazy_static! {
- /// The default generator on a Pedersen commitment used for the value
- pub static ref RISTRETTO_PEDERSEN_H: RistrettoPoint = RISTRETTO_NUMS_POINTS[0];
- /// The default generator on a Pedersen commitment used for the value in a compressed form
- pub static ref RISTRETTO_PEDERSEN_H_COMPRESSED: CompressedRistretto = RISTRETTO_NUMS_POINTS_COMPRESSED[0];
+/// The default generator on a Pedersen commitment used for the value
+pub fn ristretto_pedersen_h() -> &'static RistrettoPoint {
+ static INSTANCE: OnceCell = OnceCell::new();
+ INSTANCE.get_or_init(|| ristretto_nums_points()[0])
+}
+/// The default generator on a Pedersen commitment used for the value in a compressed form
+pub fn ristretto_pedersen_h_compressed() -> &'static CompressedRistretto {
+ static INSTANCE: OnceCell = OnceCell::new();
+ INSTANCE.get_or_init(|| RISTRETTO_NUMS_POINTS_COMPRESSED[0])
}
/// The Pedersen commitment
@@ -51,8 +59,9 @@ where T: Borrow
}
}
+#[cfg(feature = "precomputed_tables")]
pub(crate) fn scalar_mul_with_pre_computation_tables(k: &Scalar, v: &Scalar) -> RistrettoPoint {
- RISTRETTO_BASEPOINT_TABLE * k + &*RISTRETTO_NUMS_TABLE_0 * v
+ RISTRETTO_BASEPOINT_TABLE * k + ristretto_nums_table_0() * v
}
#[cfg(test)]
@@ -66,9 +75,9 @@ mod test {
pedersen::{
commitment_factory::PedersenCommitmentFactory,
extended_commitment_factory::ExtendedPedersenCommitmentFactory,
+ ristretto_pedersen_h,
PedersenCommitment,
RISTRETTO_PEDERSEN_G,
- RISTRETTO_PEDERSEN_H,
},
RistrettoPublicKey,
RistrettoSecretKey,
@@ -99,7 +108,7 @@ mod test {
#[test]
fn check_g_ne_h() {
- assert_ne!(RISTRETTO_PEDERSEN_G, *RISTRETTO_PEDERSEN_H);
+ assert_ne!(RISTRETTO_PEDERSEN_G, *ristretto_pedersen_h());
}
#[test]
diff --git a/src/ristretto/ristretto_keys.rs b/src/ristretto/ristretto_keys.rs
index 2eade9cc..6a53b287 100644
--- a/src/ristretto/ristretto_keys.rs
+++ b/src/ristretto/ristretto_keys.rs
@@ -2,15 +2,14 @@
// SPDX-License-Identifier: BSD-3-Clause
//! The Tari-compatible implementation of Ristretto based on the curve25519-dalek implementation
-use std::{
+use alloc::{string::ToString, vec::Vec};
+use core::{
borrow::Borrow,
cmp::Ordering,
fmt,
hash::{Hash, Hasher},
ops::{Add, Mul, Sub},
};
-#[cfg(feature = "borsh")]
-use std::{io, io::Write};
use blake2::Blake2b;
use curve25519_dalek::{
@@ -21,7 +20,7 @@ use curve25519_dalek::{
};
use digest::{consts::U64, Digest};
use once_cell::sync::OnceCell;
-use rand::{CryptoRng, Rng};
+use rand_core::{CryptoRng, RngCore};
use tari_utilities::{hex::Hex, ByteArray, ByteArrayError, Hashable};
use zeroize::{Zeroize, ZeroizeOnDrop};
@@ -57,17 +56,18 @@ pub struct RistrettoSecretKey(pub(crate) Scalar);
#[cfg(feature = "borsh")]
impl borsh::BorshSerialize for RistrettoSecretKey {
- fn serialize(&self, writer: &mut W) -> io::Result<()> {
+ fn serialize(&self, writer: &mut W) -> borsh::maybestd::io::Result<()> {
borsh::BorshSerialize::serialize(&self.as_bytes(), writer)
}
}
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for RistrettoSecretKey {
- fn deserialize_reader(reader: &mut R) -> Result
- where R: io::Read {
+ fn deserialize_reader(reader: &mut R) -> Result
+ where R: borsh::maybestd::io::Read {
let bytes: Vec = borsh::BorshDeserialize::deserialize_reader(reader)?;
- Self::from_bytes(bytes.as_slice()).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.to_string()))
+ Self::from_bytes(bytes.as_slice())
+ .map_err(|e| borsh::maybestd::io::Error::new(borsh::maybestd::io::ErrorKind::InvalidInput, e.to_string()))
}
}
@@ -76,7 +76,7 @@ impl SecretKey for RistrettoSecretKey {
const KEY_LEN: usize = 32;
/// Return a random secret key on the `ristretto255` curve using the supplied CSPRNG.
- fn random(rng: &mut R) -> Self {
+ fn random(rng: &mut R) -> Self {
RistrettoSecretKey(Scalar::random(rng))
}
}
@@ -263,17 +263,18 @@ pub struct RistrettoPublicKey {
#[cfg(feature = "borsh")]
impl borsh::BorshSerialize for RistrettoPublicKey {
- fn serialize(&self, writer: &mut W) -> io::Result<()> {
+ fn serialize(&self, writer: &mut W) -> borsh::maybestd::io::Result<()> {
borsh::BorshSerialize::serialize(&self.as_bytes(), writer)
}
}
#[cfg(feature = "borsh")]
impl borsh::BorshDeserialize for RistrettoPublicKey {
- fn deserialize_reader(reader: &mut R) -> Result
- where R: io::Read {
+ fn deserialize_reader(reader: &mut R) -> Result
+ where R: borsh::maybestd::io::Read {
let bytes: Vec = borsh::BorshDeserialize::deserialize_reader(reader)?;
- Self::from_bytes(bytes.as_slice()).map_err(|e| io::Error::new(io::ErrorKind::InvalidInput, e.to_string()))
+ Self::from_bytes(bytes.as_slice())
+ .map_err(|e| borsh::maybestd::io::Error::new(borsh::maybestd::io::ErrorKind::InvalidInput, e.to_string()))
}
}
@@ -298,7 +299,7 @@ impl RistrettoPublicKey {
// This function requires 512 bytes of data, so let's be opinionated here and use blake2b
let hash = DomainSeparatedHasher::, RistrettoGeneratorPoint>::new_with_label(label).finalize();
if hash.as_ref().len() < 64 {
- return Err(HashingError::DigestTooShort(64));
+ return Err(HashingError::DigestTooShort { bytes: 64 });
}
let mut bytes = [0u8; 64];
bytes.copy_from_slice(hash.as_ref());
@@ -429,7 +430,7 @@ impl RistrettoPublicKey {
let right = hex.len() - (w - left - 3);
f.write_str(format!("{}...{}", &hex[..left], &hex[right..]).as_str())
},
- _ => std::fmt::Display::fmt(&hex, f),
+ _ => core::fmt::Display::fmt(&hex, f),
}
}
}
@@ -598,7 +599,7 @@ impl From for CompressedRistretto {
#[cfg(test)]
mod test {
use digest::consts::U32;
- use tari_utilities::{message_format::MessageFormat, ByteArray};
+ use tari_utilities::ByteArray;
use super::*;
use crate::{keys::PublicKey, ristretto::test_common::get_keypair};
@@ -807,7 +808,7 @@ mod test {
// can fail in release mode, even though the values were effectively scrubbed.
if cfg!(debug_assertions) {
unsafe {
- use std::slice;
+ use core::slice;
assert_eq!(slice::from_raw_parts(ptr, 32), zero);
}
}
@@ -831,44 +832,48 @@ mod test {
"00e1f50500000000000000000000000000000000000000000000000000000000"
);
}
+ #[cfg(feature = "serde")]
+ mod test_serialize {
+ use tari_utilities::message_format::MessageFormat;
- #[test]
- fn serialize_deserialize_base64() {
- let mut rng = rand::thread_rng();
- let (k, pk) = RistrettoPublicKey::random_keypair(&mut rng);
- let ser_k = k.to_base64().unwrap();
- let ser_pk = pk.to_base64().unwrap();
- let k2: RistrettoSecretKey = RistrettoSecretKey::from_base64(&ser_k).unwrap();
- assert_eq!(k, k2, "Deserialised secret key");
- let pk2: RistrettoPublicKey = RistrettoPublicKey::from_base64(&ser_pk).unwrap();
- assert_completely_equal(&pk, &pk2);
- }
+ use super::*;
+ #[test]
+ fn serialize_deserialize_base64() {
+ let mut rng = rand::thread_rng();
+ let (k, pk) = RistrettoPublicKey::random_keypair(&mut rng);
+ let ser_k = k.to_base64().unwrap();
+ let ser_pk = pk.to_base64().unwrap();
+ let k2: RistrettoSecretKey = RistrettoSecretKey::from_base64(&ser_k).unwrap();
+ assert_eq!(k, k2, "Deserialised secret key");
+ let pk2: RistrettoPublicKey = RistrettoPublicKey::from_base64(&ser_pk).unwrap();
+ assert_completely_equal(&pk, &pk2);
+ }
- #[test]
- fn serialize_deserialize_json() {
- let mut rng = rand::thread_rng();
- let (k, pk) = RistrettoPublicKey::random_keypair(&mut rng);
- let ser_k = k.to_json().unwrap();
- let ser_pk = pk.to_json().unwrap();
- println!("JSON pubkey: {ser_pk} privkey: {ser_k}");
- let k2: RistrettoSecretKey = RistrettoSecretKey::from_json(&ser_k).unwrap();
- assert_eq!(k, k2, "Deserialised secret key");
- let pk2: RistrettoPublicKey = RistrettoPublicKey::from_json(&ser_pk).unwrap();
- assert_completely_equal(&pk, &pk2);
- }
+ #[test]
+ fn serialize_deserialize_json() {
+ let mut rng = rand::thread_rng();
+ let (k, pk) = RistrettoPublicKey::random_keypair(&mut rng);
+ let ser_k = k.to_json().unwrap();
+ let ser_pk = pk.to_json().unwrap();
+ println!("JSON pubkey: {ser_pk} privkey: {ser_k}");
+ let k2: RistrettoSecretKey = RistrettoSecretKey::from_json(&ser_k).unwrap();
+ assert_eq!(k, k2, "Deserialised secret key");
+ let pk2: RistrettoPublicKey = RistrettoPublicKey::from_json(&ser_pk).unwrap();
+ assert_completely_equal(&pk, &pk2);
+ }
- #[test]
- fn serialize_deserialize_binary() {
- let mut rng = rand::thread_rng();
- let (k, pk) = RistrettoPublicKey::random_keypair(&mut rng);
- let ser_k = k.to_binary().unwrap();
- let ser_pk = pk.to_binary().unwrap();
- let k2: RistrettoSecretKey = RistrettoSecretKey::from_binary(&ser_k).unwrap();
- assert_eq!(k, k2);
- let pk2: RistrettoPublicKey = RistrettoPublicKey::from_binary(&ser_pk).unwrap();
- assert_completely_equal(&pk, &pk2);
+ #[test]
+ fn serialize_deserialize_binary() {
+ let mut rng = rand::thread_rng();
+ let (k, pk) = RistrettoPublicKey::random_keypair(&mut rng);
+ let ser_k = k.to_binary().unwrap();
+ let ser_pk = pk.to_binary().unwrap();
+ let k2: RistrettoSecretKey = RistrettoSecretKey::from_binary(&ser_k).unwrap();
+ assert_eq!(k, k2);
+ let pk2: RistrettoPublicKey = RistrettoPublicKey::from_binary(&ser_pk).unwrap();
+ assert_completely_equal(&pk, &pk2);
+ }
}
-
#[test]
fn display_and_debug() {
let hex = "e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76";
@@ -964,7 +969,7 @@ mod test {
#[test]
fn kdf_key_too_short() {
let err = RistrettoKdf::generate::>(b"this_key_is_too_short", b"data", "test").err();
- assert!(matches!(err, Some(HashingError::InputTooShort)));
+ assert!(matches!(err, Some(HashingError::InputTooShort {})));
}
#[test]
@@ -1036,6 +1041,8 @@ mod test {
#[cfg(feature = "borsh")]
mod borsh {
+ use alloc::vec::Vec;
+
use borsh::{BorshDeserialize, BorshSerialize};
use crate::ristretto::{test_common::get_keypair, RistrettoPublicKey, RistrettoSecretKey};
diff --git a/src/ristretto/ristretto_sig.rs b/src/ristretto/ristretto_sig.rs
index 245c949c..9e1c152e 100644
--- a/src/ristretto/ristretto_sig.rs
+++ b/src/ristretto/ristretto_sig.rs
@@ -42,6 +42,7 @@ use crate::{
/// # use tari_crypto::keys::*;
/// # use tari_crypto::signatures::SchnorrSignature;
/// # use digest::Digest;
+/// # use rand::{Rng, thread_rng};
///
/// fn get_keypair() -> (RistrettoSecretKey, RistrettoPublicKey) {
/// let mut rng = rand::thread_rng();
@@ -53,7 +54,8 @@ use crate::{
/// #[allow(non_snake_case)]
/// let (k, P) = get_keypair();
/// let msg = "Small Gods";
-/// let sig = RistrettoSchnorr::sign_message(&k, &msg);
+/// let mut rng = thread_rng();
+/// let sig = RistrettoSchnorr::sign_message(&k, &msg, &mut rng);
/// ```
///
/// # Verifying signatures
@@ -68,6 +70,7 @@ use crate::{
/// # use tari_utilities::hex::*;
/// # use tari_utilities::ByteArray;
/// # use digest::Digest;
+/// # use rand::{Rng, thread_rng};
///
/// let msg = "Maskerade";
/// let k = RistrettoSecretKey::from_hex(
@@ -76,8 +79,9 @@ use crate::{
/// .unwrap();
/// # #[allow(non_snake_case)]
/// let P = RistrettoPublicKey::from_secret_key(&k);
+/// let mut rng = thread_rng();
/// let sig: SchnorrSignature =
-/// SchnorrSignature::sign_message(&k, msg).unwrap();
+/// SchnorrSignature::sign_message(&k, msg, &mut rng).unwrap();
/// assert!(sig.verify_message(&P, msg));
/// ```
pub type RistrettoSchnorr = SchnorrSignature;
@@ -94,6 +98,7 @@ pub type RistrettoSchnorr = SchnorrSignature =
-/// SchnorrSignature::sign_message(&k, msg).unwrap();
+/// SchnorrSignature::sign_message(&k, msg, &mut rng).unwrap();
/// assert!(sig.verify_message(&P, msg));
/// ```
pub type RistrettoSchnorrWithDomain = SchnorrSignature;
@@ -261,7 +267,8 @@ mod test {
fn sign_and_verify_message() {
let mut rng = rand::thread_rng();
let (k, P) = RistrettoPublicKey::random_keypair(&mut rng);
- let sig = RistrettoSchnorr::sign_message(&k, "Queues are things that happen to other people").unwrap();
+ let sig =
+ RistrettoSchnorr::sign_message(&k, "Queues are things that happen to other people", &mut rng).unwrap();
assert!(sig.verify_message(&P, "Queues are things that happen to other people"));
assert!(!sig.verify_message(&P, "Qs are things that happen to other people"));
assert!(!sig.verify_message(&(&P + &P), "Queues are things that happen to other people"));
diff --git a/src/ristretto/serialize.rs b/src/ristretto/serialize.rs
index 8054102f..6d7aafba 100644
--- a/src/ristretto/serialize.rs
+++ b/src/ristretto/serialize.rs
@@ -22,7 +22,8 @@
//! }
//! ```
-use std::fmt;
+use alloc::string::String;
+use core::fmt;
use serde::{
de::{self, Visitor},
diff --git a/src/ristretto/utils.rs b/src/ristretto/utils.rs
index 7ac8cf58..dfc2684a 100644
--- a/src/ristretto/utils.rs
+++ b/src/ristretto/utils.rs
@@ -3,7 +3,10 @@
//! Handy utility functions for use in tests and demo scripts
+use alloc::vec::Vec;
+
use digest::Digest;
+use rand_core::{CryptoRng, RngCore};
use tari_utilities::ByteArray;
use crate::{
@@ -33,12 +36,12 @@ pub struct SignatureSet {
since = "0.16.0",
note = "Use SchnorrSignature::sign_message instead. This method will be removed in v1.0.0"
)]
-pub fn sign(
+pub fn sign(
private_key: &RistrettoSecretKey,
message: &[u8],
+ rng: &mut R,
) -> Result {
- let mut rng = rand::thread_rng();
- let (nonce, public_nonce) = RistrettoPublicKey::random_keypair(&mut rng);
+ let (nonce, public_nonce) = RistrettoPublicKey::random_keypair(rng);
let message = D::new()
.chain_update(public_nonce.as_bytes())
.chain_update(message)
diff --git a/src/signatures/commitment_and_public_key_signature.rs b/src/signatures/commitment_and_public_key_signature.rs
index 942d7290..a02d6ccc 100644
--- a/src/signatures/commitment_and_public_key_signature.rs
+++ b/src/signatures/commitment_and_public_key_signature.rs
@@ -1,27 +1,29 @@
// Copyright 2021. The Tari Project
// SPDX-License-Identifier: BSD-3-Clause
-use std::{
+use alloc::vec::Vec;
+use core::{
cmp::Ordering,
hash::{Hash, Hasher},
ops::{Add, Mul},
};
-use rand::{CryptoRng, RngCore};
-use serde::{Deserialize, Serialize};
+use rand_core::{CryptoRng, RngCore};
+use snafu::prelude::*;
use tari_utilities::ByteArray;
-use thiserror::Error;
use crate::{
+ alloc::borrow::ToOwned,
commitment::{HomomorphicCommitment, HomomorphicCommitmentFactory},
keys::{PublicKey, SecretKey},
};
/// An error when creating a commitment signature
-#[derive(Clone, Debug, Error, PartialEq, Eq, Deserialize, Serialize)]
+#[derive(Clone, Debug, Snafu, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum CommitmentAndPublicKeySignatureError {
- #[error("An invalid challenge was provided")]
+ #[snafu(display("An invalid challenge was provided"))]
InvalidChallenge,
}
@@ -53,8 +55,9 @@ pub enum CommitmentAndPublicKeySignatureError {
/// The use of efficient multiscalar multiplication algorithms may also be useful for efficiency.
/// The use of precomputation tables for `G` and `H` may also be useful for efficiency.
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CommitmentAndPublicKeySignature {
ephemeral_commitment: HomomorphicCommitment
,
ephemeral_pubkey: P,
diff --git a/src/signatures/commitment_signature.rs b/src/signatures/commitment_signature.rs
index ed8d2e93..a114f425 100644
--- a/src/signatures/commitment_signature.rs
+++ b/src/signatures/commitment_signature.rs
@@ -1,15 +1,15 @@
// Copyright 2021. The Tari Project
// SPDX-License-Identifier: BSD-3-Clause
-use std::{
+use alloc::vec::Vec;
+use core::{
cmp::Ordering,
hash::{Hash, Hasher},
ops::{Add, Mul},
};
-use serde::{Deserialize, Serialize};
+use snafu::prelude::*;
use tari_utilities::{ByteArray, ByteArrayError};
-use thiserror::Error;
use crate::{
commitment::{HomomorphicCommitment, HomomorphicCommitmentFactory},
@@ -17,10 +17,11 @@ use crate::{
};
/// An error when creating a commitment signature
-#[derive(Clone, Debug, Error, PartialEq, Eq, Deserialize, Serialize)]
+#[derive(Clone, Debug, Snafu, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum CommitmentSignatureError {
- #[error("An invalid challenge was provided")]
+ #[snafu(display("An invalid challenge was provided"))]
InvalidChallenge,
}
@@ -46,8 +47,9 @@ pub enum CommitmentSignatureError {
/// S =? R + e.C ... (final verification)
#[allow(non_snake_case)]
-#[derive(Debug, Clone, Serialize, Deserialize)]
+#[derive(Debug, Clone)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshDeserialize, borsh::BorshSerialize))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CommitmentSignature
{
public_nonce: HomomorphicCommitment
,
u: K,
diff --git a/src/signatures/schnorr.rs b/src/signatures/schnorr.rs
index 5047e413..e9447a14 100644
--- a/src/signatures/schnorr.rs
+++ b/src/signatures/schnorr.rs
@@ -5,7 +5,7 @@
//! This module defines generic traits for handling the digital signature operations, agnostic
//! of the underlying elliptic curve implementation
-use std::{
+use core::{
cmp::Ordering,
hash::{Hash, Hasher},
marker::PhantomData,
@@ -14,9 +14,9 @@ use std::{
use blake2::Blake2b;
use digest::{consts::U32, Digest};
-use serde::{Deserialize, Serialize};
+use rand_core::{CryptoRng, RngCore};
+use snafu::prelude::*;
use tari_utilities::ByteArray;
-use thiserror::Error;
use crate::{
hash_domain,
@@ -28,10 +28,11 @@ use crate::{
hash_domain!(SchnorrSigChallenge, "com.tari.schnorr_signature", 1);
/// An error occurred during construction of a SchnorrSignature
-#[derive(Clone, Debug, Error, PartialEq, Eq, Deserialize, Serialize)]
+#[derive(Clone, Debug, Snafu, PartialEq, Eq)]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[allow(missing_docs)]
pub enum SchnorrSignatureError {
- #[error("An invalid challenge was provided")]
+ #[snafu(display("An invalid challenge was provided"))]
InvalidChallenge,
}
@@ -42,12 +43,13 @@ pub enum SchnorrSignatureError {
///
/// More details on Schnorr signatures can be found at [TLU](https://tlu.tarilabs.com/cryptography/introduction-schnorr-signatures).
#[allow(non_snake_case)]
-#[derive(Copy, Debug, Clone, Serialize, Deserialize)]
+#[derive(Copy, Debug, Clone)]
#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))]
+#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct SchnorrSignature
{
public_nonce: P,
signature: K,
- #[serde(skip)]
+ #[cfg_attr(feature = "serde", serde(skip))]
_phantom: PhantomData,
}
@@ -121,12 +123,16 @@ where
///
/// it is possible to customise the challenge by using [`construct_domain_separated_challenge`] and [`sign_raw`]
/// yourself, or even use [`sign_raw`] using a completely custom challenge.
- pub fn sign_message<'a, B>(secret: &'a K, message: B) -> Result
+ pub fn sign_message<'a, B, R: RngCore + CryptoRng>(
+ secret: &'a K,
+ message: B,
+ rng: &mut R,
+ ) -> Result
where
K: Add + Mul<&'a K, Output = K>,
B: AsRef<[u8]>,
{
- let nonce = K::random(&mut rand::thread_rng());
+ let nonce = K::random(rng);
Self::sign_with_nonce_and_message(secret, nonce, message)
}