2022-09-29 05:25:29 -04:00
|
|
|
//! Generators used by Monero in both its Pedersen commitments and Bulletproofs(+).
|
2023-06-28 21:16:33 -04:00
|
|
|
//!
|
2022-09-29 05:25:29 -04:00
|
|
|
//! An implementation of Monero's `ge_fromfe_frombytes_vartime`, simply called
|
|
|
|
|
//! `hash_to_point` here, is included, as needed to generate generators.
|
|
|
|
|
|
2023-04-22 04:38:47 -04:00
|
|
|
#![cfg_attr(not(feature = "std"), no_std)]
|
|
|
|
|
|
2023-06-28 21:16:33 -04:00
|
|
|
use core::cell::OnceCell;
|
|
|
|
|
use std_shims::sync::Mutex;
|
2022-08-21 06:36:53 -04:00
|
|
|
|
2022-09-29 08:08:49 -04:00
|
|
|
use sha3::{Digest, Keccak256};
|
2022-08-21 06:36:53 -04:00
|
|
|
|
2023-04-22 04:38:47 -04:00
|
|
|
use curve25519_dalek::edwards::{EdwardsPoint as DalekPoint, CompressedEdwardsY};
|
2022-08-21 06:36:53 -04:00
|
|
|
|
2023-04-22 04:38:47 -04:00
|
|
|
use group::{Group, GroupEncoding};
|
2022-08-21 06:36:53 -04:00
|
|
|
use dalek_ff_group::EdwardsPoint;
|
|
|
|
|
|
|
|
|
|
mod varint;
|
|
|
|
|
use varint::write_varint;
|
|
|
|
|
|
|
|
|
|
mod hash_to_point;
|
|
|
|
|
pub use hash_to_point::hash_to_point;
|
|
|
|
|
|
|
|
|
|
fn hash(data: &[u8]) -> [u8; 32] {
|
2022-09-29 08:08:49 -04:00
|
|
|
Keccak256::digest(data).into()
|
2022-08-21 06:36:53 -04:00
|
|
|
}
|
|
|
|
|
|
2023-06-28 21:16:33 -04:00
|
|
|
/// Monero alternate generator `H`, used for amounts in Pedersen commitments.
|
|
|
|
|
static H_CELL: Mutex<OnceCell<DalekPoint>> = Mutex::new(OnceCell::new());
|
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
pub fn H() -> DalekPoint {
|
|
|
|
|
*H_CELL.lock().get_or_init(|| {
|
2023-04-22 04:38:47 -04:00
|
|
|
CompressedEdwardsY(hash(&EdwardsPoint::generator().to_bytes()))
|
2022-08-21 06:36:53 -04:00
|
|
|
.decompress()
|
|
|
|
|
.unwrap()
|
2023-06-28 21:16:33 -04:00
|
|
|
.mul_by_cofactor()
|
|
|
|
|
})
|
2022-08-21 06:36:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MAX_M: usize = 16;
|
|
|
|
|
const N: usize = 64;
|
|
|
|
|
const MAX_MN: usize = MAX_M * N;
|
|
|
|
|
|
2022-09-28 07:44:49 -05:00
|
|
|
/// Container struct for Bulletproofs(+) generators.
|
2022-08-21 06:36:53 -04:00
|
|
|
#[allow(non_snake_case)]
|
|
|
|
|
pub struct Generators {
|
|
|
|
|
pub G: [EdwardsPoint; MAX_MN],
|
|
|
|
|
pub H: [EdwardsPoint; MAX_MN],
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-28 07:44:49 -05:00
|
|
|
/// Generate generators as needed for Bulletproofs(+), as Monero does.
|
|
|
|
|
pub fn bulletproofs_generators(dst: &'static [u8]) -> Generators {
|
2022-08-21 06:36:53 -04:00
|
|
|
let mut res =
|
|
|
|
|
Generators { G: [EdwardsPoint::identity(); MAX_MN], H: [EdwardsPoint::identity(); MAX_MN] };
|
|
|
|
|
for i in 0 .. MAX_MN {
|
|
|
|
|
let i = 2 * i;
|
|
|
|
|
|
2023-06-28 21:16:33 -04:00
|
|
|
let mut even = H().compress().to_bytes().to_vec();
|
2022-09-28 07:44:49 -05:00
|
|
|
even.extend(dst);
|
2022-08-21 06:36:53 -04:00
|
|
|
let mut odd = even.clone();
|
|
|
|
|
|
|
|
|
|
write_varint(&i.try_into().unwrap(), &mut even).unwrap();
|
|
|
|
|
write_varint(&(i + 1).try_into().unwrap(), &mut odd).unwrap();
|
|
|
|
|
res.H[i / 2] = EdwardsPoint(hash_to_point(hash(&even)));
|
|
|
|
|
res.G[i / 2] = EdwardsPoint(hash_to_point(hash(&odd)));
|
|
|
|
|
}
|
|
|
|
|
res
|
|
|
|
|
}
|