Skip to main content

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}