1#![no_std]
2#![deny(missing_docs)]
3
4mod error;
29mod pubkey;
30mod signature;
31
32#[cfg(not(any(target_arch = "bpf", target_os = "solana")))]
33mod privkey;
34
35#[cfg(not(any(target_arch = "bpf", target_os = "solana")))]
36mod keypair;
37
38pub use error::WinternitzError;
39pub use pubkey::{WinternitzPubkey, WinternitzRoot};
40pub use signature::WinternitzSignature;
41
42#[cfg(not(any(target_arch = "bpf", target_os = "solana")))]
43pub use privkey::WinternitzPrivkey;
44
45#[cfg(not(any(target_arch = "bpf", target_os = "solana")))]
46pub use keypair::WinternitzKeypair;
47
48pub(crate) const fn assert_n<const N: usize>() {
49 assert!(
50 N >= 16 && N <= 32 && N.is_multiple_of(2),
51 "N must be even and in 16..=32",
52 );
53}
54
55#[inline(always)]
56pub(crate) fn chain(seed: &[u8; 32], iters: u8) -> [u8; 32] {
57 let mut current = *seed;
58 for _ in 0..iters {
59 current = solana_sha256_hasher::hash(¤t).to_bytes();
60 }
61 current
62}
63
64#[inline(always)]
65pub(crate) fn hash<const N: usize>(message: &[&[u8]]) -> [u8; N] {
66 const { assert_n::<N>() };
67 let digest = solana_sha256_hasher::hashv(message).to_bytes();
68 let mut out = [0u8; N];
69 out.copy_from_slice(&digest[..N]);
70 out
71}