Skip to content

Commit

Permalink
feat!: replace lazy_static with once_cell (#69)
Browse files Browse the repository at this point in the history
Extended commitment generators are currently
[produced](https://github.com/tari-project/bulletproofs-plus/blob/502ae9fa35a39afc5793210e4301023a7ca7ea60/src/ristretto.rs#L154-L179)
using the `lazy_static` macro. Unfortunately, `lazy_static` is [no
longer actively maintained](https://crates.io/crates/lazy_static). Other
repositories in the ecosystem are moving to `once_cell`, which is
[actively maintained](https://crates.io/crates/once_cell).

This PR migrates from `lazy_static` to `once_cell`. In the process, it
cleans up the construction. Specifically, it moves from using word-based
numbering (_e.g._ `ONE`, `TWO`) in hash inputs to numerals, which
simplifies the design. It also adds a useful test that asserts the
number of generators matches the size of `ExtensionDegree` to avoid
panics.

Closes #67.

BREAKING CHANGE: Modifies the construction of commitment generators.
  • Loading branch information
AaronFeickert committed Sep 20, 2023
1 parent 4102dea commit e01c380
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 122 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Expand Up @@ -14,8 +14,8 @@ derive_more = "0.99"
derivative = "2.2"
digest = { version = "0.10", default-features = false }
itertools = "0.6"
lazy_static = "1.4"
merlin = { version = "3", default-features = false }
once_cell = { version = "1", default-features = false, features = ["critical-section"] }
rand = "0.8"
# Note: toolchain must be at v1.60+ to support serde v1.0.150+
serde = "1.0"
Expand Down
40 changes: 35 additions & 5 deletions src/generators/pedersen_gens.rs
Expand Up @@ -36,23 +36,33 @@ pub struct PedersenGens<P: Compressable> {

/// The extension degree for extended commitments. Currently this is limited to 5 extension degrees, but in theory it
/// could be arbitrarily long, although practically, very few if any test cases will use more than 2 extension degrees.
/// These values MUST increment, or other functions may panic.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ExtensionDegree {
/// Default Pedersen commitment
DefaultPedersen = 1,
/// Pedersen commitment extended with one degree
AddOneBasePoint = 2,
AddOneBasePoint,
/// Pedersen commitment extended with two degrees
AddTwoBasePoints = 3,
AddTwoBasePoints,
/// Pedersen commitment extended with three degrees
AddThreeBasePoints = 4,
AddThreeBasePoints,
/// Pedersen commitment extended with four degrees
AddFourBasePoints = 5,
AddFourBasePoints,
/// Pedersen commitment extended with five degrees
AddFiveBasePoints = 6,
AddFiveBasePoints,
}

impl ExtensionDegree {
/// The total number of valid extension degrees
pub(crate) const COUNT: usize = ExtensionDegree::MAXIMUM - ExtensionDegree::MINIMUM + 1;
/// The highest numerical value corresponding to a valid extension degree
/// This MUST be correct, or other functions may panic
pub(crate) const MAXIMUM: usize = ExtensionDegree::AddFiveBasePoints as usize;
/// The lowest numerical value corresponding to a valid extension degree
/// This MUST be correct, or other functions may panic
pub(crate) const MINIMUM: usize = ExtensionDegree::DefaultPedersen as usize;

/// Helper function to convert a size into an extension degree
pub fn try_from_size(size: usize) -> Result<ExtensionDegree, ProofError> {
match size {
Expand Down Expand Up @@ -105,3 +115,23 @@ where P: Compressable + MultiscalarMul<Point = P> + Clone
}
}
}

#[cfg(test)]
mod test {
use super::ExtensionDegree;

#[test]
// Test the size range, assuming extension degree values are incremented
fn test_extension_degree_size() {
// Value is too low
assert!(ExtensionDegree::try_from_size(ExtensionDegree::MINIMUM - 1).is_err());

// Valid values
for i in ExtensionDegree::MINIMUM..=ExtensionDegree::MAXIMUM {
assert!(ExtensionDegree::try_from_size(i).is_ok());
}

// Value is too high
assert!(ExtensionDegree::try_from_size(ExtensionDegree::MAXIMUM + 1).is_err());
}
}
5 changes: 0 additions & 5 deletions src/lib.rs
Expand Up @@ -3,11 +3,6 @@

//! Bulletproofs+

#![recursion_limit = "1024"]

#[macro_use]
extern crate lazy_static;

/// Bulletproofs+ commitment opening
pub mod commitment_opening;
/// Bulletproofs+ error definitions
Expand Down
148 changes: 37 additions & 111 deletions src/ristretto.rs
Expand Up @@ -9,6 +9,7 @@ use curve25519_dalek::{
constants::{RISTRETTO_BASEPOINT_COMPRESSED, RISTRETTO_BASEPOINT_POINT},
ristretto::{CompressedRistretto, RistrettoPoint, VartimeRistrettoPrecomputation},
};
use once_cell::sync::OnceCell;

use crate::{
generators::pedersen_gens::ExtensionDegree,
Expand Down Expand Up @@ -71,111 +72,39 @@ pub fn create_pedersen_gens_with_extension_degree(extension_degree: ExtensionDeg
}
}

// Assign vectors only performing the number of lazy static base point calculations that is necessary, using
// on the fly compression for compressed base points otherwise
// Get masking points and compressed points based on extension degree
fn get_g_base(extension_degree: ExtensionDegree) -> (Vec<RistrettoPoint>, Vec<CompressedRistretto>) {
match extension_degree {
ExtensionDegree::DefaultPedersen => (vec![*RISTRETTO_BASEPOINT_POINT_BLINDING_1], vec![
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_1,
]),
ExtensionDegree::AddOneBasePoint => (
vec![
*RISTRETTO_BASEPOINT_POINT_BLINDING_1,
*RISTRETTO_BASEPOINT_POINT_BLINDING_2,
],
vec![
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_1,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_2,
],
),
ExtensionDegree::AddTwoBasePoints => (
vec![
*RISTRETTO_BASEPOINT_POINT_BLINDING_1,
*RISTRETTO_BASEPOINT_POINT_BLINDING_2,
*RISTRETTO_BASEPOINT_POINT_BLINDING_3,
],
vec![
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_1,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_2,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_3,
],
),
ExtensionDegree::AddThreeBasePoints => (
vec![
*RISTRETTO_BASEPOINT_POINT_BLINDING_1,
*RISTRETTO_BASEPOINT_POINT_BLINDING_2,
*RISTRETTO_BASEPOINT_POINT_BLINDING_3,
*RISTRETTO_BASEPOINT_POINT_BLINDING_4,
],
vec![
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_1,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_2,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_3,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_4,
],
),
ExtensionDegree::AddFourBasePoints => (
vec![
*RISTRETTO_BASEPOINT_POINT_BLINDING_1,
*RISTRETTO_BASEPOINT_POINT_BLINDING_2,
*RISTRETTO_BASEPOINT_POINT_BLINDING_3,
*RISTRETTO_BASEPOINT_POINT_BLINDING_4,
*RISTRETTO_BASEPOINT_POINT_BLINDING_5,
],
vec![
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_1,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_2,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_3,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_4,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_5,
],
),
ExtensionDegree::AddFiveBasePoints => (
vec![
*RISTRETTO_BASEPOINT_POINT_BLINDING_1,
*RISTRETTO_BASEPOINT_POINT_BLINDING_2,
*RISTRETTO_BASEPOINT_POINT_BLINDING_3,
*RISTRETTO_BASEPOINT_POINT_BLINDING_4,
*RISTRETTO_BASEPOINT_POINT_BLINDING_5,
*RISTRETTO_BASEPOINT_POINT_BLINDING_6,
],
vec![
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_1,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_2,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_3,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_4,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_5,
*RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_6,
],
),
}
(
ristretto_masking_basepoints()[..extension_degree as usize].to_vec(),
ristretto_compressed_masking_basepoints()[..extension_degree as usize].to_vec(),
)
}

/// A static array of pre-generated points
fn ristretto_masking_basepoints() -> &'static [RistrettoPoint; ExtensionDegree::COUNT] {
static INSTANCE: OnceCell<[RistrettoPoint; ExtensionDegree::COUNT]> = OnceCell::new();
INSTANCE.get_or_init(|| {
let mut arr = [RistrettoPoint::default(); ExtensionDegree::COUNT];
for (i, point) in (ExtensionDegree::MINIMUM..).zip(arr.iter_mut()) {
let label = "RISTRETTO_MASKING_BASEPOINT_".to_owned() + &i.to_string();
*point = RistrettoPoint::hash_from_bytes_sha3_512(label.as_bytes());
}

arr
})
}

lazy_static! {
static ref RISTRETTO_BASEPOINT_POINT_BLINDING_1: RistrettoPoint =
RistrettoPoint::hash_from_bytes_sha3_512(b"RISTRETTO_BASEPOINT_POINT_BLINDING_1 degree ZERO");
static ref RISTRETTO_BASEPOINT_POINT_BLINDING_2: RistrettoPoint =
RistrettoPoint::hash_from_bytes_sha3_512(b"RISTRETTO_BASEPOINT_POINT_BLINDING_2 degree ONE");
static ref RISTRETTO_BASEPOINT_POINT_BLINDING_3: RistrettoPoint =
RistrettoPoint::hash_from_bytes_sha3_512(b"RISTRETTO_BASEPOINT_POINT_BLINDING_3 degree TWO");
static ref RISTRETTO_BASEPOINT_POINT_BLINDING_4: RistrettoPoint =
RistrettoPoint::hash_from_bytes_sha3_512(b"RISTRETTO_BASEPOINT_POINT_BLINDING_4 degree THREE");
static ref RISTRETTO_BASEPOINT_POINT_BLINDING_5: RistrettoPoint =
RistrettoPoint::hash_from_bytes_sha3_512(b"RISTRETTO_BASEPOINT_POINT_BLINDING_5 degree FOUR");
static ref RISTRETTO_BASEPOINT_POINT_BLINDING_6: RistrettoPoint =
RistrettoPoint::hash_from_bytes_sha3_512(b"RISTRETTO_BASEPOINT_POINT_BLINDING_6 degree FIVE");
static ref RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_1: CompressedRistretto =
(*RISTRETTO_BASEPOINT_POINT_BLINDING_1).compress();
static ref RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_2: CompressedRistretto =
(*RISTRETTO_BASEPOINT_POINT_BLINDING_2).compress();
static ref RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_3: CompressedRistretto =
(*RISTRETTO_BASEPOINT_POINT_BLINDING_3).compress();
static ref RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_4: CompressedRistretto =
(*RISTRETTO_BASEPOINT_POINT_BLINDING_4).compress();
static ref RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_5: CompressedRistretto =
(*RISTRETTO_BASEPOINT_POINT_BLINDING_5).compress();
static ref RISTRETTO_BASEPOINT_COMPRESSED_BLINDING_6: CompressedRistretto =
(*RISTRETTO_BASEPOINT_POINT_BLINDING_6).compress();
/// A static array of compressed pre-generated points
fn ristretto_compressed_masking_basepoints() -> &'static [CompressedRistretto; ExtensionDegree::COUNT] {
static INSTANCE: OnceCell<[CompressedRistretto; ExtensionDegree::COUNT]> = OnceCell::new();
INSTANCE.get_or_init(|| {
let mut arr = [CompressedRistretto::default(); ExtensionDegree::COUNT];
for (i, point) in ristretto_masking_basepoints().iter().enumerate() {
arr[i] = point.compress();
}

arr
})
}

#[cfg(test)]
Expand All @@ -197,17 +126,14 @@ mod tests {
#[test]
fn test_constants() {
// Extended Pedersen generators with extension degree of zero to five
let lazy_statics = [
*RISTRETTO_BASEPOINT_POINT_BLINDING_1,
*RISTRETTO_BASEPOINT_POINT_BLINDING_2,
*RISTRETTO_BASEPOINT_POINT_BLINDING_3,
*RISTRETTO_BASEPOINT_POINT_BLINDING_4,
*RISTRETTO_BASEPOINT_POINT_BLINDING_5,
*RISTRETTO_BASEPOINT_POINT_BLINDING_6,
];
let masking_basepoints = ristretto_masking_basepoints();
for extension_degree in EXTENSION_DEGREE {
let pc_gens = create_pedersen_gens_with_extension_degree(extension_degree);
for (i, item) in lazy_statics.iter().enumerate().take(pc_gens.extension_degree as usize) {
for (i, item) in masking_basepoints
.iter()
.enumerate()
.take(pc_gens.extension_degree as usize)
{
assert_eq!(pc_gens.g_base_vec[i].compress(), pc_gens.g_base_compressed_vec[i]);
assert_eq!(item.compress(), pc_gens.g_base_compressed_vec[i]);
}
Expand Down

0 comments on commit e01c380

Please sign in to comment.