1#[cfg(feature = "std")]
6use std::{fmt, str};
7
8use crate::ffi::CPtr;
9#[cfg(feature = "std")]
10use crate::from_hex;
11use crate::{ffi, Error, PublicKey, Secp256k1, SecretKey, Signing, Verification};
12
13#[derive(Clone, PartialEq, Eq, Hash)]
15#[repr(transparent)]
16pub struct WhitelistSignature(ffi::WhitelistSignature);
17
18impl WhitelistSignature {
19 pub fn n_keys(&self) -> usize {
21 self.0.n_keys
22 }
23
24 #[cfg(feature = "std")]
26 pub fn serialize(&self) -> Vec<u8> {
27 let mut buf = vec![0; 33 + 32 * self.n_keys()];
28
29 let mut out_len = buf.len();
30 let ret = unsafe {
31 ffi::secp256k1_whitelist_signature_serialize(
32 ffi::secp256k1_context_no_precomp,
33 buf.as_mut_ptr(),
34 &mut out_len,
35 &self.0,
36 )
37 };
38 assert_eq!(ret, 1, "failed to serialize whitelist signature");
39 assert_eq!(
40 out_len,
41 buf.len(),
42 "whitelist serialized to unexpected length"
43 );
44
45 buf
46 }
47
48 pub fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
50 let mut sig = ffi::WhitelistSignature::default();
51
52 let ret = unsafe {
53 ffi::secp256k1_whitelist_signature_parse(
54 ffi::secp256k1_context_no_precomp,
55 &mut sig,
56 bytes.as_ptr(),
57 bytes.len(),
58 )
59 };
60 if ret != 1 {
61 return Err(Error::InvalidWhitelistSignature);
62 }
63
64 Ok(WhitelistSignature(sig))
65 }
66
67 pub fn new<C: Signing>(
69 secp: &Secp256k1<C>,
70 online_keys: &[PublicKey],
71 offline_keys: &[PublicKey],
72 whitelist_key: &PublicKey,
73 online_secret_key: &SecretKey,
74 summed_secret_key: &SecretKey,
75 key_index: usize,
76 ) -> Result<WhitelistSignature, Error> {
77 if online_keys.len() != offline_keys.len() {
78 return Err(Error::InvalidPakList);
79 }
80 let n_keys = online_keys.len();
81
82 let mut sig = ffi::WhitelistSignature::default();
83 let ret = unsafe {
84 ffi::secp256k1_whitelist_sign(
85 secp.ctx().as_ptr(),
86 &mut sig,
87 online_keys.as_c_ptr() as *const ffi::PublicKey,
89 offline_keys.as_c_ptr() as *const ffi::PublicKey,
90 n_keys,
91 whitelist_key.as_c_ptr(),
92 online_secret_key.as_c_ptr(),
93 summed_secret_key.as_c_ptr(),
94 key_index,
95 )
96 };
97 if ret != 1 {
98 return Err(Error::CannotCreateWhitelistSignature);
99 }
100
101 Ok(WhitelistSignature(sig))
102 }
103
104 pub fn verify<C: Verification>(
106 &self,
107 secp: &Secp256k1<C>,
108 online_keys: &[PublicKey],
109 offline_keys: &[PublicKey],
110 whitelist_key: &PublicKey,
111 ) -> Result<(), Error> {
112 if online_keys.len() != offline_keys.len() {
113 return Err(Error::InvalidPakList);
114 }
115 let n_keys = online_keys.len();
116
117 let ret = unsafe {
118 ffi::secp256k1_whitelist_verify(
119 secp.ctx().as_ptr(),
120 &self.0,
121 online_keys.as_c_ptr() as *const ffi::PublicKey,
123 offline_keys.as_c_ptr() as *const ffi::PublicKey,
124 n_keys,
125 whitelist_key.as_c_ptr(),
126 )
127 };
128 if ret != 1 {
129 return Err(Error::InvalidWhitelistProof);
130 }
131
132 Ok(())
133 }
134
135 #[inline]
137 pub fn as_ptr(&self) -> *const ffi::WhitelistSignature {
138 &self.0
139 }
140
141 #[inline]
143 pub fn as_mut_ptr(&mut self) -> *mut ffi::WhitelistSignature {
144 &mut self.0
145 }
146}
147
148#[cfg(feature = "std")]
149impl fmt::LowerHex for WhitelistSignature {
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 for ch in self.serialize().iter() {
152 write!(f, "{:02x}", ch)?;
153 }
154 Ok(())
155 }
156}
157
158#[cfg(feature = "std")]
159impl fmt::Display for WhitelistSignature {
160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161 fmt::LowerHex::fmt(self, f)
162 }
163}
164
165#[cfg(feature = "std")]
166impl fmt::Debug for WhitelistSignature {
167 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168 fmt::Display::fmt(self, f)
169 }
170}
171
172#[cfg(feature = "std")]
173impl str::FromStr for WhitelistSignature {
174 type Err = Error;
175 fn from_str(s: &str) -> Result<WhitelistSignature, Error> {
176 let mut buf = vec![0; s.len() / 2];
177 from_hex(s, &mut buf).map_err(|_| Error::InvalidWhitelistSignature)?;
178 WhitelistSignature::from_slice(&buf)
179 }
180}
181
182#[cfg(all(feature = "serde", feature = "std"))]
183impl ::serde::Serialize for WhitelistSignature {
184 fn serialize<S: ::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
185 if s.is_human_readable() {
186 s.collect_str(self)
187 } else {
188 s.serialize_bytes(&self.serialize())
189 }
190 }
191}
192
193#[cfg(all(feature = "serde", feature = "std"))]
194impl<'de> ::serde::Deserialize<'de> for WhitelistSignature {
195 fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
196 use crate::serde_util;
197
198 if d.is_human_readable() {
199 d.deserialize_str(serde_util::FromStrVisitor::new("an ASCII hex string"))
200 } else {
201 d.deserialize_bytes(serde_util::BytesVisitor::new(
202 "a bytestring",
203 WhitelistSignature::from_slice,
204 ))
205 }
206 }
207}
208
209impl CPtr for WhitelistSignature {
210 type Target = ffi::WhitelistSignature;
211 fn as_c_ptr(&self) -> *const Self::Target {
212 self.as_ptr()
213 }
214
215 fn as_mut_c_ptr(&mut self) -> *mut Self::Target {
216 self.as_mut_ptr()
217 }
218}
219
220#[cfg(all(test, feature = "global-context"))]
221mod tests {
222 use super::*;
223 use crate::SECP256K1;
224 use rand::thread_rng;
225
226 fn test_whitelist_proof_roundtrip(n_keys: usize) {
227 let mut rng = thread_rng();
228 let (keys_online, pak_online) = (0..n_keys)
229 .map(|_| SECP256K1.generate_keypair(&mut rng))
230 .unzip::<_, _, Vec<_>, Vec<_>>();
231 let (keys_offline, pak_offline) = (0..n_keys)
232 .map(|_| SECP256K1.generate_keypair(&mut rng))
233 .unzip::<_, _, Vec<_>, Vec<_>>();
234
235 let (whitelist_sk, whitelist_pk) = SECP256K1.generate_keypair(&mut rng);
236
237 for our_idx in vec![0, n_keys / 2, n_keys - 1].into_iter() {
238 let summed_key = keys_offline[our_idx]
241 .add_tweak(&whitelist_sk.into())
242 .unwrap();
243
244 let signature = WhitelistSignature::new(
245 SECP256K1,
246 &pak_online,
247 &pak_offline,
248 &whitelist_pk,
249 &keys_online[our_idx],
250 &summed_key,
251 our_idx,
252 )
253 .unwrap();
254 assert_eq!(n_keys, signature.n_keys());
255
256 signature
259 .verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk)
260 .unwrap();
261
262 let encoded = signature.serialize();
265 let decoded = WhitelistSignature::from_slice(&encoded).unwrap();
266 assert_eq!(n_keys, decoded.n_keys());
267 assert_eq!(signature, decoded);
268 decoded
269 .verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk)
270 .unwrap();
271 }
272 }
273
274 #[test]
275 fn test_whitelist_proof_roundtrip_n1() {
276 test_whitelist_proof_roundtrip(1);
277 }
278
279 #[test]
280 fn test_whitelist_proof_roundtrip_n50() {
281 test_whitelist_proof_roundtrip(50);
282 }
283
284 #[test]
285 fn test_whitelist_proof_roundtrip_n255() {
286 test_whitelist_proof_roundtrip(255);
287 }
288
289 #[test]
290 fn test_whitelist_proof_invalid() {
291 let n_keys = 255;
292
293 let mut rng = thread_rng();
294 let (keys_online, pak_online) = (0..n_keys)
295 .map(|_| SECP256K1.generate_keypair(&mut rng))
296 .unzip::<_, _, Vec<_>, Vec<_>>();
297 let (keys_offline, pak_offline) = (0..n_keys)
298 .map(|_| SECP256K1.generate_keypair(&mut rng))
299 .unzip::<_, _, Vec<_>, Vec<_>>();
300
301 let (whitelist_sk, whitelist_pk) = SECP256K1.generate_keypair(&mut rng);
302
303 let our_idx = 100;
304 let summed_key = keys_offline[our_idx]
305 .add_tweak(&whitelist_sk.into())
306 .unwrap();
307
308 {
309 let offline = pak_offline[1..].to_vec();
311 assert_eq!(
312 Err(Error::InvalidPakList),
313 WhitelistSignature::new(
314 SECP256K1,
315 &pak_online,
316 &offline, &whitelist_pk,
318 &keys_online[our_idx],
319 &summed_key,
320 our_idx,
321 )
322 );
323 }
324
325 let correct_signature = WhitelistSignature::new(
326 SECP256K1,
327 &pak_online,
328 &pak_offline,
329 &whitelist_pk,
330 &keys_online[our_idx],
331 &summed_key,
332 our_idx,
333 )
334 .unwrap();
335
336 {
337 let sig = unsafe {
339 let sig = correct_signature.clone();
340 let ptr = sig.as_c_ptr() as *mut ffi::WhitelistSignature;
341 (*ptr).n_keys -= 1;
342 sig
343 };
344 assert_eq!(
345 Err(Error::InvalidWhitelistProof),
346 sig.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,)
347 );
348 }
349
350 {
351 let offline = pak_offline[1..].to_vec();
353 assert_eq!(
354 Err(Error::InvalidPakList),
355 correct_signature.verify(SECP256K1, &pak_online, &offline, &whitelist_pk,)
356 );
357 }
358
359 {
360 assert_eq!(
362 Err(Error::InvalidWhitelistProof),
363 correct_signature.verify(
364 SECP256K1,
365 &pak_online,
366 &pak_offline,
367 &pak_online[our_idx],
368 )
369 );
370 }
371
372 {
373 assert_eq!(
375 Err(Error::InvalidWhitelistProof),
376 correct_signature.verify(
377 SECP256K1,
378 &pak_online,
379 &pak_offline,
380 &pak_offline[our_idx],
381 )
382 );
383 }
384
385 {
386 let mut encoded = correct_signature.serialize();
388 encoded.push(42);
389 assert_eq!(
390 Err(Error::InvalidWhitelistSignature),
391 WhitelistSignature::from_slice(&encoded),
392 );
393 }
394
395 {
396 let mut encoded = correct_signature.serialize();
398 let len = encoded.len();
399 encoded[len - 1] ^= 0x01;
400 let decoded = WhitelistSignature::from_slice(&encoded).unwrap();
401 assert_eq!(
402 Err(Error::InvalidWhitelistProof),
403 decoded.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,)
404 );
405 }
406
407 {
408 let sig = WhitelistSignature::new(
410 SECP256K1,
411 &pak_online,
412 &pak_offline,
413 &whitelist_pk,
414 &keys_online[our_idx],
415 &keys_offline[our_idx], our_idx,
417 )
418 .unwrap();
419
420 assert_eq!(
421 Err(Error::InvalidWhitelistProof),
422 sig.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,)
423 );
424 assert_eq!(
425 Err(Error::InvalidWhitelistProof),
426 sig.verify(SECP256K1, &pak_online, &pak_offline, &pak_offline[our_idx],)
427 );
428 }
429
430 {
431 let sig = WhitelistSignature::new(
433 SECP256K1,
434 &pak_online,
435 &pak_offline,
436 &whitelist_pk,
437 &keys_online[our_idx],
438 &whitelist_sk, our_idx,
440 )
441 .unwrap();
442
443 assert_eq!(
444 Err(Error::InvalidWhitelistProof),
445 sig.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,)
446 );
447 }
448
449 assert_eq!(
450 Ok(()),
451 correct_signature.verify(SECP256K1, &pak_online, &pak_offline, &whitelist_pk,)
452 );
453 }
454}