winterwallet_core/
signature.rs1use core::mem::MaybeUninit;
2
3use crate::{WinternitzError, WinternitzPubkey, WinternitzRoot};
4
5#[repr(C)]
12pub struct WinternitzSignature<const N: usize> {
13 scalars: [[u8; 32]; N],
14 checksum: [[u8; 32]; 2],
15}
16
17impl<const N: usize> WinternitzSignature<N> {
18 pub fn new(scalars: [[u8; 32]; N], checksum: [[u8; 32]; 2]) -> Self {
20 const { crate::assert_n::<N>() };
21 Self { scalars, checksum }
22 }
23
24 pub fn as_bytes(&self) -> &[u8] {
27 unsafe {
29 core::slice::from_raw_parts(
30 self as *const Self as *const u8,
31 core::mem::size_of::<Self>(),
32 )
33 }
34 }
35
36 pub fn verify(&self, message: &[&[u8]], root: &WinternitzRoot) -> bool {
42 self.recover_pubkey(message).merklize() == *root
43 }
44
45 #[inline(always)]
48 pub fn verify_prehashed(&self, hash: &[u8; N], root: &WinternitzRoot) -> bool {
49 self.recover_pubkey_prehashed(hash).merklize() == *root
50 }
51
52 #[inline(always)]
61 pub fn recover_pubkey(&self, message: &[&[u8]]) -> WinternitzPubkey<N> {
62 const { crate::assert_n::<N>() };
63 let h = crate::hash::<N>(message);
64 self.recover_pubkey_prehashed(&h)
65 }
66
67 #[inline(always)]
70 pub fn recover_pubkey_prehashed(&self, hash: &[u8; N]) -> WinternitzPubkey<N> {
71 const { crate::assert_n::<N>() };
72 let mut pk_scalars: [MaybeUninit<[u8; 32]>; N] = [const { MaybeUninit::uninit() }; N];
73 let mut checksum_sum: u16 = 0;
74 for i in 0..N {
75 let b = hash[i];
76 pk_scalars[i].write(crate::chain(&self.scalars[i], 255 - b));
77 checksum_sum += 255u16 - b as u16;
78 }
79 let pk_checksum = [
80 crate::chain(&self.checksum[0], 255 - (checksum_sum >> 8) as u8),
81 crate::chain(&self.checksum[1], 255 - checksum_sum as u8),
82 ];
83 let pk_scalars: [[u8; 32]; N] =
86 unsafe { core::ptr::read(pk_scalars.as_ptr() as *const [[u8; 32]; N]) };
87 WinternitzPubkey::new(pk_scalars, pk_checksum)
88 }
89
90 #[inline(always)]
94 pub fn hash(message: &[&[u8]]) -> [u8; N] {
95 crate::hash::<N>(message)
96 }
97}
98
99impl<const N: usize> core::fmt::Display for WinternitzSignature<N> {
100 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
101 write!(f, "0x")?;
102 for s in self.scalars.iter().chain(self.checksum.iter()) {
103 for b in s {
104 write!(f, "{:02x}", b)?;
105 }
106 }
107 Ok(())
108 }
109}
110
111impl<const N: usize> core::fmt::Debug for WinternitzSignature<N> {
112 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
113 writeln!(f, "WinternitzSignature {{")?;
114 for (i, s) in self.scalars.iter().enumerate() {
115 write!(f, " scalars[{}] = 0x", i)?;
116 for b in s {
117 write!(f, "{:02x}", b)?;
118 }
119 writeln!(f)?;
120 }
121 for (i, s) in self.checksum.iter().enumerate() {
122 write!(f, " checksum[{}] = 0x", i)?;
123 for b in s {
124 write!(f, "{:02x}", b)?;
125 }
126 writeln!(f)?;
127 }
128 write!(f, "}}")
129 }
130}
131
132impl<'a, const N: usize> TryFrom<&'a [u8]> for &'a WinternitzSignature<N> {
133 type Error = WinternitzError;
134
135 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
136 const { crate::assert_n::<N>() };
137 if value.len() != (N + 2) * 32 {
138 return Err(WinternitzError::InvalidLength);
139 }
140 Ok(unsafe { &*value.as_ptr().cast::<WinternitzSignature<N>>() })
142 }
143}