1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
//! WOTS keypairs.
use crate::{public::PublicKey, secret::SecretKey, signature::Signature};
use rand::{CryptoRng, RngCore};
use sha256_rs::*;
const EMPTY: [[u8; 32]; 32] = [[0u8; 32]; 32];
/// An WOTS keypair.
pub struct Keypair {
/// The secret half of this keypair.
pub secret: SecretKey,
/// The public half of this keypair.
pub public: PublicKey,
}
impl Keypair {
/// Generate an WOTS keypair.
///
/// # Example
///
/// ```
/// use rand::rngs::OsRng;
/// use wots_rs::Keypair;
///
/// let mut csprng = OsRng{};
/// let keypair: Keypair = Keypair::generate(&mut csprng);
///
/// ```
///
/// # Input
///
/// A CSPRNG with a `fill_bytes()` method, e.g. `rand_os::OsRng`.
pub fn generate<R>(csprng: &mut R) -> Self
where
R: CryptoRng + RngCore,
{
let mut secret_key = EMPTY;
let mut public_key = EMPTY;
for key in secret_key.iter_mut() {
let mut temp = [0u8; 32];
csprng.fill_bytes(&mut temp);
*key = temp;
}
for (i, key) in public_key.iter_mut().enumerate() {
let mut skey = secret_key[i];
for _ in 0..256 {
skey = sha256(&skey);
}
*key = skey;
}
Keypair {
secret: SecretKey::from(secret_key),
public: PublicKey::from(public_key),
}
}
/// Sign a `message` with this `Keypair` using the
/// WOTS algorithm.
///
/// # Inputs
///
/// * `message` in bytes representation.
///
/// # Returns
///
/// An WOTS [`Signature`] on the `message`.
///
/// # Example
///
/// ```
/// use rand::rngs::OsRng;
/// use wots_rs::Keypair;
///
/// let mut csprng = OsRng{};
/// let keypair: Keypair = Keypair::generate(&mut csprng);
///
/// let message = b"hello";
/// let signature = keypair.sign(message);
///
/// ```
pub fn sign(&self, message: &[u8]) -> Signature {
let secret_key = self.secret.to_bytes();
let mut signature = EMPTY;
let hash = sha256(message);
for (i, s) in signature.iter_mut().enumerate() {
let mut skey = secret_key[i];
let n = hash[i];
for _ in 0..256 - n as usize {
skey = sha256(&skey);
}
*s = skey;
}
Signature::from(signature)
}
/// Verify a `signature` on a `message` using the WOTS algorithm.
///
/// # Inputs
///
/// * `message` in bytes representation.
/// * `signature` is a purported WOTS [`Signature`] on the `message`.
///
/// # Returns
///
/// Returns `true` if the `signature` was a valid signature created by this
/// `Keypair` on the `message`.
///
/// # Example
///
/// ```
/// use rand::rngs::OsRng;
/// use wots_rs::Keypair;
///
/// let mut csprng = OsRng{};
/// let keypair: Keypair = Keypair::generate(&mut csprng);
///
/// let message = b"hello";
/// let signature = keypair.sign(message);
///
/// assert!(keypair.verify(message, signature));
///
/// ```
pub fn verify(&self, message: &[u8], signature: Signature) -> bool {
let signature = signature.to_bytes();
let mut pkey = EMPTY;
let hash = sha256(message);
for (i, key) in pkey.iter_mut().enumerate() {
let mut s = signature[i];
let n = hash[i];
for _ in 0..n as usize {
s = sha256(&s);
}
*key = s;
}
self.public == PublicKey::from(pkey)
}
}