use crate::error::{Error, Result};
use cdk::nuts::{BlindedMessage, Id};
use hex;
use rand::RngCore;
use secp256k1::{Secp256k1, SecretKey};
use std::collections::HashMap;
use std::str::FromStr;
pub fn calculate_optimal_denominations(amount: u64) -> HashMap<u64, u32> {
let mut denominations = HashMap::new();
let mut remaining = amount;
let denoms = [
16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1,
];
for &denom in &denoms {
if remaining >= denom {
let count = remaining / denom;
denominations.insert(denom, count as u32);
remaining -= denom * count;
}
}
denominations
}
pub fn create_blinded_messages_for_amount(
amount: u64,
keyset_id: &str,
) -> Result<Vec<BlindedMessage>> {
let mut outputs = Vec::new();
let denominations = calculate_optimal_denominations(amount);
for (&denom, &count) in &denominations {
for _ in 0..count {
let blinded_msg = create_simple_blinded_message(denom, keyset_id)?;
outputs.push(blinded_msg);
}
}
Ok(outputs)
}
fn create_simple_blinded_message(amount: u64, keyset_id: &str) -> Result<BlindedMessage> {
let secp = Secp256k1::new();
let mut rng = rand::rng();
let mut secret_bytes = [0u8; 32];
rng.fill_bytes(&mut secret_bytes);
let secret_key = SecretKey::from_byte_array(secret_bytes)
.map_err(|e| Error::custom(&format!("Failed to create secret key: {}", e)))?;
let public_key = secret_key.public_key(&secp);
let compressed_pubkey = public_key.serialize();
let keyset_id_parsed =
Id::from_str(keyset_id).map_err(|e| Error::custom(&format!("Invalid keyset ID: {}", e)))?;
let blinded_msg = BlindedMessage {
amount: amount.into(),
keyset_id: keyset_id_parsed,
blinded_secret: cdk::nuts::PublicKey::from_hex(hex::encode(compressed_pubkey))
.map_err(|e| Error::custom(&format!("Failed to create blinded secret: {}", e)))?,
witness: None,
};
Ok(blinded_msg)
}
pub fn generate_random_secret() -> String {
let mut rng = rand::rng();
let mut secret_bytes = [0u8; 32];
rng.fill_bytes(&mut secret_bytes);
hex::encode(secret_bytes)
}