poh_yugen/lib.rs
1
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module provides the data structures and functions for the Proof of History (PoH) algorithm.
5//! The PoH algorithm is a cryptographic primitive that allows for the generation
6//! of a verifiable and tamper-proof history of events. It is used in various
7//! blockchain systems to provide a secure and efficient way to order transactions
8//! and events in a distributed network.
9//!
10
11// Digestis used for hashing and cryptographic operations.
12// The `digest` crate provides a variety of hashing algorithms and utilities
13use digest::{Digest,Output,OutputSizeUser};
14use sha2::Sha256;
15
16
17pub mod extensions;
18
19pub trait Seedable {
20 /// Generates a new seed for the Proof of History (PoH) algorithm.
21 /// This function should be implemented to provide a cryptographically
22 /// secure random seed that can be used to initialize the PoH process.
23 fn generate_seed() -> [u8; 64];
24 fn get_seed(&self) -> [u8; 64];
25 fn set_seed(&mut self, seed: [u8; 64]);
26}
27
28pub trait EventData {
29 /// Generates a hash for the given event data.
30 /// This function should be implemented to provide a secure hash
31 /// of the event data, which can be used to verify the integrity
32 /// of the PoH entries.
33 fn hash_event_data(data: &[u8]) -> [u8; 32];
34}
35
36
37/// Initial seed for the Proof of History (PoH) algorithm.
38/// This seed is used to initialize the PoH process and is typically derived
39/// from a known source of entropy, such as the system's random number generator.
40/// The seed is a 64-byte array, which provides sufficient entropy for the PoH algorithm.
41/// The seed is used to generate the initial state of the PoH, which is then
42/// updated with each tick of the PoH clock.
43/// The seed is crucial for ensuring the security and unpredictability of the PoH process.
44/// It is important to keep the seed secret and secure, as it directly affects
45/// the integrity of the PoH output.
46/// The seed should be generated using a cryptographically secure random number generator
47/// to ensure that it is unpredictable and resistant to attacks.
48#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
49pub struct InitialSeed(pub [u8; 64]);
50
51/// Appended Data for the Proof of History (PoH) algorithm.
52/// This structure is used to store additional data that is appended to the PoH entries.
53/// The appended data can be used to include metadata or other information
54/// that is relevant to the PoH process.
55#[derive(Debug, Clone, PartialEq, Eq, Hash)]
56pub struct AppendedData {
57 data: Vec<u8>,
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub struct EventHash {
62 pub hash: [u8; 32],
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
66pub struct PoHConfig<D: Digest + Clone> {
67 /// The hasher used for the Proof of History (PoH) algorithm.
68 /// This hasher is responsible for generating the cryptographic hashes
69 /// for the PoH entries and for verifying the integrity of the PoH process.
70 /// The hasher should be a cryptographic hash function that is suitable
71 /// for use in the PoH algorithm, such as SHA-256 or SHA-512.
72 /// The hasher should be chosen based on the desired security level
73 /// and performance requirements of the PoH process.
74 /// The hasher should be implemented using the `digest` crate,
75 /// which provides a variety of hashing algorithms and utilities.
76 /// The hasher should be initialized with a secure random seed
77 /// to ensure that the PoH process is unpredictable and resistant to attacks.
78 /// The hasher should be able to produce a fixed-size output, typically 32 or 64 bytes,
79 /// depending on the chosen hashing algorithm.
80 /// The hasher should be able to process input data of arbitrary length
81 /// and produce a hash output that is unique to the input data.
82 /// The hasher should be able to handle collisions and produce a unique
83 /// hash output for different input data.
84 /// The hasher should be able to produce a hash output that is resistant
85 /// to pre-image and second pre-image attacks, ensuring the integrity
86 /// and security of the PoH process.
87 /// The hasher should be able to produce a hash output that is collision-resistant,
88 /// ensuring that it is computationally infeasible to find two different
89 /// input data that produce the same hash output.
90 /// The hasher should be able to produce a hash output that is secure
91 /// against length extension attacks, ensuring that it is computationally
92 /// infeasible to find a valid hash output for a modified input data
93 /// without knowing the original input data.
94 /// The hasher should be able to produce a hash output that is secure
95 /// against chosen-prefix attacks, ensuring that it is computationally
96 /// infeasible to find two different input data that produce the same
97 /// hash output when the prefix of the input data is known.
98 /// The hasher should be able to produce a hash output that is secure
99 /// against birthday attacks, ensuring that it is computationally infeasible
100 /// to find two different input data that produce the same hash output
101 /// when the length of the input data is known.
102 /// The hasher should be able to produce a hash output that is secure
103 /// against length extension attacks, ensuring that it is computationally
104 /// infeasible to find a valid hash output for a modified input data
105 /// without knowing the original input data.
106 pub hasher: D,
107 /// The size of the output produced by the PoH algorithm.
108 /// This value determines the length of the hash output generated by
109 /// the PoH process. The output size is typically measured in bytes
110 /// and should be chosen based on the desired security level and
111 /// performance requirements of the PoH process.
112 /// A common value for the output size is 32 bytes (256 bits) for SHA-256
113 /// or 64 bytes (512 bits) for SHA-512. The output size should be
114 /// set to a positive value to ensure that the PoH process can generate
115 /// a valid hash output. A value of 0 indicates that the PoH process
116 /// should not produce any output and the PoH state should remain empty
117 /// until the next entry is added. The output size should be chosen
118 /// based on the specific requirements of the application and the
119 /// capabilities of the underlying hardware.
120 pub output_size: usize,
121 /// The interval in ticks for the PoH algorithm.
122 /// This value determines how often the PoH clock ticks and updates the state.
123 /// A smaller value results in more frequent updates, while a larger value
124 /// results in less frequent updates. The ticks interval should be chosen
125 /// based on the desired granularity of the PoH process and the performance
126 /// requirements of the system.
127 /// The ticks interval is typically measured in milliseconds or microseconds,
128 /// depending on the desired resolution of the PoH clock.
129 /// A common value for the ticks interval is 1000 microseconds (1 millisecond),
130 /// which provides a good balance between performance and granularity.
131 /// The ticks interval should be chosen based on the specific requirements
132 /// of the application and the capabilities of the underlying hardware.
133 /// A value of 0 indicates that the PoH clock should not tick, and the PoH
134 /// process should be paused until the next tick is triggered.
135 /// The ticks interval should be set to a positive value to ensure that
136 /// the PoH process continues to run and update the state.
137 /// A value of 1 indicates that the PoH clock should tick once per microsecond,
138 pub tick_interval: u64,
139 /// The maximum number of entries allowed in the PoH.
140 /// This value determines the maximum size of the PoH state and the
141 /// maximum number of entries that can be generated by the PoH algorithm.
142 /// A smaller value results in a smaller PoH state and fewer entries,
143 /// while a larger value results in a larger PoH state and more entries.
144 /// The maximum entries value should be chosen based on the desired
145 /// capacity of the PoH process and the performance requirements of the system.
146 /// The maximum entries value is typically measured in bytes or kilobytes,
147 /// depending on the desired size of the PoH state and the number of entries.
148 /// A common value for the maximum entries is 1000, which provides a good
149 /// balance between capacity and performance.
150 /// The maximum entries value should be set to a positive value to ensure
151 /// that the PoH process can generate entries and update the state.
152 /// A value of None indicates that there is no limit on the number of entries
153 /// and the PoH process can continue to generate entries until it is stopped.
154 /// A value of 0 indicates that the PoH process should not generate any entries
155 /// and the PoH state should remain empty until the next entry is added.
156 pub max_entries: Option<usize>,
157 /// Flags to control the behavior of the PoH algorithm.
158 /// These flags determine whether data entries and empty entries are allowed
159 /// in the PoH process. The allow_data_entries flag indicates whether
160 /// data entries can be added to the PoH, while the allow_empty_entries
161 /// flag indicates whether empty entries can be added to the PoH.
162 /// The allow_data_entries flag should be set to true if the PoH process
163 /// should allow data entries to be added, and false if only empty entries
164 /// should be allowed.
165 pub allow_data_entries: bool,
166 pub allow_empty_entries: bool,
167
168 /// The type of entry to be used in the PoH process.
169 /// This value determines the type of data that can be appended to the PoH entries.
170 /// The tic_entry_type value should be set to one of the following types:
171 /// - Data: Indicates that the PoH process should allow data entries to be added.
172 /// - Empty: Indicates that the PoH process should allow empty entries to be added.
173 /// - UTF8String: Indicates that the PoH process should allow UTF-8 string entries to be added.
174 /// - Hash(usize): Indicates that the PoH process should allow hash entries of a specified size to be added.
175 /// The tic_entry_type value should be set to a valid TicEntryType value
176 /// to ensure that the PoH process can generate entries and update the state.
177 pub tick_entry_type: TickEntryType,
178
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
182pub enum TickEntryType {
183 Data,
184 Empty,
185 ByteString,
186 UTF8String,
187 Hash(usize),
188 /// Event hash types for different sizes
189 EventHash28,
190 EventHash32,
191 EventHash48,
192 EventHash64,
193}
194
195impl<D: Digest + Clone> PoHConfig<D> {
196 pub fn new(digest: D, output_size: usize, tick_interval: u64, max_entries: Option<usize>, allow_data_entries: bool, allow_empty_entries: bool, tick_entry_type: TickEntryType) -> Self {
197 Self {
198 // Hasher used for the PoH algorithm with variable output size
199 hasher: digest,
200 output_size: output_size,
201
202 tick_interval,
203 max_entries,
204
205 allow_data_entries,
206 allow_empty_entries,
207 tick_entry_type,
208 }
209 }
210}
211
212/*
213impl<D: Digest + Clone> Clone for PoHConfig<D> {
214 fn clone(&self) -> Self {
215 Self {
216 hasher: self.hasher.clone(),
217 output_size: self.output_size,
218 tick_interval: self.tick_interval,
219 max_entries: self.max_entries,
220 allow_data_entries: self.allow_data_entries,
221 allow_empty_entries: self.allow_empty_entries,
222 tick_entry_type: self.tick_entry_type,
223 }
224 }
225}
226*/
227
228/// Proof of History (PoH) usage structure.
229/// This structure encapsulates the configuration and functionality
230/// of the Proof of History (PoH) algorithm.
231/// It provides methods for generating and verifying PoH entries,
232/// as well as for managing the PoH state.
233#[derive(Debug, Clone, PartialEq, Eq, Hash)]
234pub struct PoHUsage<D: Digest + Clone> {
235 id: u64,
236 config: PoHConfig<D>,
237 state: Vec<PoHEntry>, // Holds the PoH entries
238 extensions: Vec<extensions::Extensions>, // Holds any extensions for the PoH process
239}
240
241#[derive(Debug, Clone, PartialEq, Eq, Hash)]
242pub struct PoHEntry {
243 pub hash: Vec<u8>, // The hash of the PoH entry
244 pub appended_data: Option<AppendedData>,
245}
246
247impl<D: Digest + Clone> PoHUsage<D> {
248 pub fn new(config: PoHConfig<D>, seed: InitialSeed, init_data: Option<Vec<u8>>, extensions: Vec<extensions::Extensions>) -> Self {
249 // Appended Data is initialized to None, as it will be created if init_data is provided
250 let mut appended_data = None;
251
252 // Initialize the PoH with the provided seed
253 let mut hasher = config.hasher.clone();
254 hasher.update(seed.0);
255
256 // If there is initial data, hash it and create an AppendedData instance
257 if init_data.is_some() {
258 hasher.update(init_data.clone().unwrap());
259 appended_data = Some(AppendedData::new(init_data.unwrap().to_vec()));
260 }
261 let output = hasher.finalize();
262
263 Self {
264 id: 0,
265 config: config,
266 state: vec![PoHEntry { hash: output.to_vec(), appended_data: appended_data }],
267 extensions,
268 }
269 }
270 pub fn get_id(&self) -> u64 {
271 self.id
272 }
273 pub fn get_config(&self) -> &PoHConfig<D> {
274 &self.config
275 }
276 pub fn init(&mut self) {
277 let initial_state = self.state[0].hash.clone();
278 let interval = self.config.tick_interval;
279 let max_entries = self.config.max_entries.unwrap_or(1000); // Default to 1000 if None
280
281
282 let mut output_of_previous_tick: Vec<u8> = initial_state;
283 for _ in 0..max_entries {
284 for _ in 0..interval {
285 let mut hasher = self.config.hasher.clone();
286 hasher.update(output_of_previous_tick);
287 let output = hasher.finalize();
288 output_of_previous_tick = output.to_vec();
289 }
290 // Create a new PoH entry with the output of the previous tick
291 let new_entry = PoHEntry {
292 hash: output_of_previous_tick.clone(),
293 appended_data: None, // No appended data for now
294 };
295 self.state.push(new_entry);
296 // Print the output of the previous tick
297 println!("Output after {} ticks: {:?}", interval, hex::encode(output_of_previous_tick.clone()));
298 }
299 }
300 pub fn get_state(&self) -> &Vec<PoHEntry> {
301 &self.state
302 }
303
304}
305
306
307impl PoHEntry {
308 pub fn to_hex_string(&self) -> String {
309 hex::encode(&self.hash)
310 }
311}
312
313// Appended Data implementation
314
315impl AppendedData {
316 pub fn new(data: Vec<u8>) -> Self {
317 Self { data }
318 }
319
320 pub fn get_data(&self) -> &[u8] {
321 &self.data
322 }
323}
324
325#[test]
326fn run() {
327 let config = PoHConfig::new(Sha256::new(), 32, 1000, Some(1000), true, true, TickEntryType::Data);
328 let seed = InitialSeed([0; 64]);
329 let mut poh = PoHUsage::new(config, seed, Some(vec![1, 2, 3]), vec![]);
330 println!("{:?}", poh.state);
331 println!("Initializing PoH...");
332 // Initialize the PoH process
333 poh.init();
334
335}