1use secp256k1::{PublicKey, SecretKey};
12use serde::{Deserialize, Serialize};
13use utoipa::ToSchema;
14
15use crate::{
16 amount::{generate_random_string, Amount},
17 dhke::Dhke,
18 error::MokshaCoreError,
19};
20
21#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
22pub struct BlindedSignature {
23 pub amount: u64,
24 #[serde(rename = "C_")]
25 #[schema(value_type=String)]
26 pub c_: PublicKey,
27 pub id: Option<String>,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
31pub struct BlindedMessage {
32 pub amount: u64,
33 #[serde(rename = "B_")]
34 #[schema(value_type=String)]
35 pub b_: PublicKey,
36 pub id: String,
37}
38
39impl BlindedMessage {
40 pub fn blank(
41 fee_reserve: Amount,
42 keyset_id: String,
43 ) -> Result<Vec<(Self, SecretKey, String)>, MokshaCoreError> {
44 if fee_reserve.0 == 0 {
45 return Ok(vec![]);
46 }
47
48 let fee_reserve_float = fee_reserve.0 as f64;
49 let count = (fee_reserve_float.log2().ceil() as u64).max(1);
50 let dhke = Dhke::new();
51
52 let blinded_messages = (0..count)
53 .map(|_| {
54 let secret = generate_random_string();
55 let (b_, alice_secret_key) = dhke.step1_alice(secret.clone(), None).unwrap(); (
57 Self {
58 amount: 1,
59 b_,
60 id: keyset_id.clone(),
61 },
62 alice_secret_key,
63 secret,
64 )
65 })
66 .collect::<Vec<(Self, SecretKey, String)>>();
67
68 Ok(blinded_messages)
69 }
70}
71
72pub trait TotalAmount {
73 fn total_amount(&self) -> u64;
74}
75
76impl TotalAmount for Vec<BlindedSignature> {
77 fn total_amount(&self) -> u64 {
78 self.iter().fold(0, |acc, x| acc + x.amount)
79 }
80}
81
82impl TotalAmount for Vec<BlindedMessage> {
83 fn total_amount(&self) -> u64 {
84 self.iter().fold(0, |acc, x| acc + x.amount)
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn test_1000_sats() {
94 let result = BlindedMessage::blank(1000.into(), "00ffd48b8f5ecf80".to_owned());
95 println!("{:?}", result);
96 assert!(result.is_ok());
97 let result = result.unwrap();
98 assert!(result.len() == 10);
99 assert!(result.first().unwrap().0.amount == 1);
100 }
101
102 #[test]
103 fn test_zero_sats() {
104 let result = BlindedMessage::blank(0.into(), "00ffd48b8f5ecf80".to_owned());
105 println!("{:?}", result);
106 assert!(result.is_ok());
107 assert!(result.unwrap().is_empty());
108 }
109
110 #[test]
111 fn test_serialize() -> anyhow::Result<()> {
112 let result = BlindedMessage::blank(4000.into(), "00ffd48b8f5ecf80".to_owned())?;
113 for (blinded_message, _, _) in result {
114 let out = serde_json::to_string(&blinded_message)?;
115 assert!(!out.is_empty());
116 }
117 Ok(())
118 }
119}