hash_based_signatures/signature/
basic_lamport.rs1use rand::prelude::*;
2use rand_chacha::ChaCha20Rng;
3use serde::{Deserialize, Serialize};
4use serde_big_array::BigArray;
5
6use crate::signature::{HashType, SignatureScheme};
7use crate::utils::hash;
8
9pub type BasicLamportKey = [[[u8; 32]; 2]; 256];
10
11#[derive(PartialEq, Serialize, Deserialize)]
13pub struct BasicLamportSignature {
14 #[serde(with = "BigArray")]
15 preimages: [[u8; 32]; 256],
16}
17
18#[derive(Clone)]
43pub struct BasicLamportSignatureScheme {
44 sk: BasicLamportKey,
45 pk: BasicLamportKey,
46 message: Option<HashType>,
47}
48
49impl BasicLamportSignatureScheme {
50 pub fn new(seed: [u8; 32]) -> Self {
52 let mut rng = ChaCha20Rng::from_seed(seed);
53 let mut sk = [[[0; 32]; 2]; 256];
54
55 for bit_to_sign in 0..256 {
57 for bit in 0..2 {
58 rng.fill_bytes(&mut sk[bit_to_sign][bit]);
59 }
60 }
61
62 let mut pk = [[[0; 32]; 2]; 256];
64 for bit_to_sign in 0..256 {
65 for bit in 0..2 {
66 pk[bit_to_sign][bit] = hash(&sk[bit_to_sign][bit]);
67 }
68 }
69 Self {
70 pk,
71 sk,
72 message: None,
73 }
74 }
75}
76
77impl SignatureScheme<BasicLamportKey, HashType, BasicLamportSignature>
78 for BasicLamportSignatureScheme
79{
80 fn public_key(&self) -> BasicLamportKey {
81 self.pk
82 }
83
84 fn sign(&mut self, message: HashType) -> BasicLamportSignature {
92 if let Some(existing_message) = self.message {
93 if existing_message != message {
94 panic!("One-time signature has been used to sign more than one message!")
95 }
96 }
97 self.message = Some(message);
98
99 let mut signature: [[u8; 32]; 256] = [[0; 32]; 256];
100 for byte_index in 0..32 {
101 let byte = message[byte_index];
102 for local_bit_index in 0..8 {
103 let bit_index = byte_index * 8 + local_bit_index;
104 if byte & (1 << local_bit_index) != 0 {
105 signature[bit_index] = self.sk[bit_index][1];
106 } else {
107 signature[bit_index] = self.sk[bit_index][0];
108 }
109 }
110 }
111 BasicLamportSignature {
112 preimages: signature,
113 }
114 }
115
116 fn verify(pk: BasicLamportKey, message: HashType, signature: &BasicLamportSignature) -> bool {
117 let mut is_correct = true;
118 for byte_index in 0..32 {
119 let byte = message[byte_index];
120 for local_bit_index in 0..8 {
121 let bit_index = byte_index * 8 + local_bit_index;
122 let hash = hash(&signature.preimages[bit_index]);
123 let pk_index_to_expect = (byte & (1 << local_bit_index) != 0) as usize;
124 is_correct &= hash == pk[bit_index][pk_index_to_expect];
125 }
126 }
127 is_correct
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use crate::signature::basic_lamport::{BasicLamportSignature, BasicLamportSignatureScheme};
134 use crate::signature::SignatureScheme;
135
136 fn get_signature_scheme() -> BasicLamportSignatureScheme {
137 let seed = [0u8; 32];
138 BasicLamportSignatureScheme::new(seed)
139 }
140
141 #[test]
142 fn test_correct_signature() {
143 let mut signature_scheme = get_signature_scheme();
144 let signature = signature_scheme.sign([1u8; 32]);
145 assert!(BasicLamportSignatureScheme::verify(
146 signature_scheme.public_key(),
147 [1u8; 32],
148 &signature
149 ))
150 }
151
152 #[test]
153 fn test_incorrect_signature() {
154 let signature_scheme = get_signature_scheme();
155 let incorrect_signature = BasicLamportSignature {
156 preimages: [[0u8; 32]; 256],
157 };
158 assert!(!BasicLamportSignatureScheme::verify(
159 signature_scheme.public_key(),
160 [1u8; 32],
161 &incorrect_signature
162 ))
163 }
164
165 #[test]
166 fn test_can_sign_same_message() {
167 let mut signature_scheme = get_signature_scheme();
168 signature_scheme.sign([1u8; 32]);
169 signature_scheme.sign([1u8; 32]);
170 }
171
172 #[test]
173 #[should_panic]
174 fn test_cant_sign_different_messages() {
175 let mut signature_scheme = get_signature_scheme();
176 signature_scheme.sign([1u8; 32]);
177 signature_scheme.sign([2u8; 32]);
178 }
179}