#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
use std_shims::{sync::LazyLock, vec::Vec};
use sha3::{Digest, Keccak256};
use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, edwards::EdwardsPoint};
use monero_io::{write_varint, decompress_point};
mod hash_to_point;
pub use hash_to_point::hash_to_point;
#[cfg(test)]
mod tests;
fn keccak256(data: &[u8]) -> [u8; 32] {
Keccak256::digest(data).into()
}
#[allow(non_snake_case)]
pub static H: LazyLock<EdwardsPoint> = LazyLock::new(|| {
decompress_point(keccak256(&ED25519_BASEPOINT_POINT.compress().to_bytes()))
.unwrap()
.mul_by_cofactor()
});
static H_POW_2_CELL: LazyLock<[EdwardsPoint; 64]> = LazyLock::new(|| {
let mut res = [*H; 64];
for i in 1 .. 64 {
res[i] = res[i - 1] + res[i - 1];
}
res
});
#[allow(non_snake_case)]
pub fn H_pow_2() -> &'static [EdwardsPoint; 64] {
&H_POW_2_CELL
}
pub const MAX_COMMITMENTS: usize = 16;
pub const COMMITMENT_BITS: usize = 64;
pub const LOG_COMMITMENT_BITS: usize = 6; #[allow(non_snake_case)]
pub struct Generators {
pub G: Vec<EdwardsPoint>,
pub H: Vec<EdwardsPoint>,
}
pub fn bulletproofs_generators(dst: &'static [u8]) -> Generators {
const MAX_MN: usize = MAX_COMMITMENTS * COMMITMENT_BITS;
let mut preimage = H.compress().to_bytes().to_vec();
preimage.extend(dst);
let mut res = Generators { G: Vec::with_capacity(MAX_MN), H: Vec::with_capacity(MAX_MN) };
for i in 0 .. MAX_MN {
let i = 2 * i;
let mut even = preimage.clone();
write_varint(&i, &mut even).unwrap();
res.H.push(hash_to_point(keccak256(&even)));
let mut odd = preimage.clone();
write_varint(&(i + 1), &mut odd).unwrap();
res.G.push(hash_to_point(keccak256(&odd)));
}
res
}