High-level functionality for working with compact Winternitz signatures. Compact signatures contain the signature of each digit, but not the digit itself. ## See [`Wots`]
| 217 | /// |
| 218 | /// [`Wots`] |
| 219 | pub trait CompactWots: Wots { |
| 220 | type CompactSignature: AsRef<[[u8; 20]]> + TryFrom<Vec<[u8; 20]>, Error: std::fmt::Debug>; |
| 221 | const COMPACT_ALGORITHM: Winternitz<BruteforceVerifier, Self::Converter> = Winternitz::new(); |
| 222 | |
| 223 | /// Generates a compact signature for the given `secret_key` and `message`, |
| 224 | /// in form of a Bitcoin witness. |
| 225 | fn compact_sign_to_raw_witness( |
| 226 | secret_key: &WinternitzSecret, |
| 227 | message: &Self::Message, |
| 228 | ) -> bitcoin::Witness { |
| 229 | let witness = Self::COMPACT_ALGORITHM.sign(&Self::PARAMETERS, secret_key, message.as_ref()); |
| 230 | debug_assert_eq!(witness.len(), Self::TOTAL_DIGIT_LEN as usize); |
| 231 | witness |
| 232 | } |
| 233 | |
| 234 | /// Generates a compact signature for the given `secret_key` and `message`. |
| 235 | fn compact_sign( |
| 236 | secret_key: &WinternitzSecret, |
| 237 | message: &Self::Message, |
| 238 | ) -> Self::CompactSignature { |
| 239 | let witness = Self::compact_sign_to_raw_witness(secret_key, message); |
| 240 | Self::compact_raw_witness_to_signature(&witness) |
| 241 | } |
| 242 | |
| 243 | /// Parses the given bitcoin `witness` as a Winternitz signature. |
| 244 | /// |
| 245 | /// The `witness` must be in the format that is returned by [`CompactWots::compact_sign`]. |
| 246 | /// |
| 247 | /// ## Panics |
| 248 | /// |
| 249 | /// This method panics if the `witness` is ill-formatted. |
| 250 | fn compact_raw_witness_to_signature(witness: &bitcoin::Witness) -> Self::CompactSignature { |
| 251 | assert_eq!(witness.len(), Self::TOTAL_DIGIT_LEN as usize); |
| 252 | let mut digit_signatures: Vec<[u8; 20]> = |
| 253 | Vec::with_capacity(Self::TOTAL_DIGIT_LEN as usize); |
| 254 | |
| 255 | for i in 0..witness.len() { |
| 256 | assert_eq!( |
| 257 | witness[i].len(), |
| 258 | 20, |
| 259 | "the digit signature should be constant 20 bytes" |
| 260 | ); |
| 261 | |
| 262 | let digit_signature: [u8; 20] = witness[i].try_into().unwrap(); |
| 263 | digit_signatures.push(digit_signature); |
| 264 | } |
| 265 | |
| 266 | debug_assert_eq!(digit_signatures.len(), Self::TOTAL_DIGIT_LEN as usize); |
| 267 | match Self::CompactSignature::try_from(digit_signatures) { |
| 268 | Ok(signature) => signature, |
| 269 | _ => unreachable!(), |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | /// Encodes the given Winternitz `signature` as a bitcoin witness. |
| 274 | fn compact_signature_to_raw_witness(signature: &Self::CompactSignature) -> bitcoin::Witness { |
| 275 | let mut witness = bitcoin::Witness::new(); |
| 276 |
nothing calls this directly
no outgoing calls
no test coverage detected