rustywallet_silent/
label.rs1use crate::error::{Result, SilentPaymentError};
4use secp256k1::{PublicKey, Secp256k1, SecretKey};
5use sha2::{Digest, Sha256};
6
7const LABEL_TAG: &[u8] = b"BIP0352/Label";
9
10#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct Label {
19 index: u32,
21 tweak: [u8; 32],
23}
24
25impl Label {
26 pub fn new(index: u32) -> Self {
28 let tweak = Self::compute_tweak(index);
29 Self { index, tweak }
30 }
31
32 fn compute_tweak(m: u32) -> [u8; 32] {
34 let tag_hash = Sha256::digest(LABEL_TAG);
36
37 let mut hasher = Sha256::new();
38 hasher.update(tag_hash);
39 hasher.update(tag_hash);
40 hasher.update(m.to_be_bytes());
41
42 let result = hasher.finalize();
43 let mut tweak = [0u8; 32];
44 tweak.copy_from_slice(&result);
45 tweak
46 }
47
48 pub fn index(&self) -> u32 {
50 self.index
51 }
52
53 pub fn tweak(&self) -> &[u8; 32] {
55 &self.tweak
56 }
57
58 pub fn apply_to_pubkey(&self, spend_pubkey: &[u8; 33]) -> Result<[u8; 33]> {
62 let secp = Secp256k1::new();
63
64 let b_spend = PublicKey::from_slice(spend_pubkey)
65 .map_err(|e| SilentPaymentError::InvalidPublicKey(e.to_string()))?;
66
67 let label_sk = SecretKey::from_slice(&self.tweak)
68 .map_err(|e| SilentPaymentError::CryptoError(e.to_string()))?;
69
70 let label_point = PublicKey::from_secret_key(&secp, &label_sk);
71
72 let b_m = b_spend
73 .combine(&label_point)
74 .map_err(|e| SilentPaymentError::CryptoError(e.to_string()))?;
75
76 Ok(b_m.serialize())
77 }
78
79 pub fn apply_to_privkey(&self, spend_privkey: &[u8; 32]) -> Result<[u8; 32]> {
83 let b_spend = SecretKey::from_slice(spend_privkey)
84 .map_err(|e| SilentPaymentError::InvalidPrivateKey(e.to_string()))?;
85
86 let label_sk = SecretKey::from_slice(&self.tweak)
87 .map_err(|e| SilentPaymentError::CryptoError(e.to_string()))?;
88
89 let b_m = b_spend
90 .add_tweak(&label_sk.into())
91 .map_err(|e| SilentPaymentError::CryptoError(e.to_string()))?;
92
93 Ok(b_m.secret_bytes())
94 }
95}
96
97#[derive(Debug, Clone)]
99pub struct LabelManager {
100 labels: Vec<Label>,
102}
103
104impl LabelManager {
105 pub fn new() -> Self {
107 Self { labels: Vec::new() }
108 }
109
110 pub fn add(&mut self, index: u32) -> &Label {
112 if let Some(pos) = self.labels.iter().position(|l| l.index == index) {
113 &self.labels[pos]
114 } else {
115 self.labels.push(Label::new(index));
116 self.labels.last().unwrap()
117 }
118 }
119
120 pub fn get(&self, index: u32) -> Option<&Label> {
122 self.labels.iter().find(|l| l.index == index)
123 }
124
125 pub fn labels(&self) -> &[Label] {
127 &self.labels
128 }
129
130 pub fn generate_range(&mut self, n: u32) {
132 for i in 0..n {
133 self.add(i);
134 }
135 }
136
137 pub fn find_matching_label(
139 &self,
140 spend_pubkey: &[u8; 33],
141 target_pubkey: &[u8; 33],
142 ) -> Option<&Label> {
143 for label in &self.labels {
144 if let Ok(labeled) = label.apply_to_pubkey(spend_pubkey) {
145 if &labeled == target_pubkey {
146 return Some(label);
147 }
148 }
149 }
150 None
151 }
152}
153
154impl Default for LabelManager {
155 fn default() -> Self {
156 Self::new()
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn test_label_creation() {
166 let label0 = Label::new(0);
167 let label1 = Label::new(1);
168
169 assert_eq!(label0.index(), 0);
170 assert_eq!(label1.index(), 1);
171 assert_ne!(label0.tweak(), label1.tweak());
172 }
173
174 #[test]
175 fn test_label_deterministic() {
176 let label1 = Label::new(42);
177 let label2 = Label::new(42);
178
179 assert_eq!(label1.tweak(), label2.tweak());
180 }
181
182 #[test]
183 fn test_label_apply_pubkey() {
184 use rustywallet_keys::private_key::PrivateKey;
185
186 let key = PrivateKey::random();
187 let pk: [u8; 33] = key.public_key().to_compressed().try_into().unwrap();
188
189 let label = Label::new(1);
190 let labeled = label.apply_to_pubkey(&pk).unwrap();
191
192 assert_ne!(labeled, pk);
194 }
195
196 #[test]
197 fn test_label_manager() {
198 let mut manager = LabelManager::new();
199
200 manager.add(0);
201 manager.add(1);
202 manager.add(0); assert_eq!(manager.labels().len(), 2);
205 assert!(manager.get(0).is_some());
206 assert!(manager.get(1).is_some());
207 assert!(manager.get(2).is_none());
208 }
209
210 #[test]
211 fn test_label_manager_range() {
212 let mut manager = LabelManager::new();
213 manager.generate_range(5);
214
215 assert_eq!(manager.labels().len(), 5);
216 for i in 0..5 {
217 assert!(manager.get(i).is_some());
218 }
219 }
220}