zf_zebrachain/lib.rs
1#![deny(missing_docs)]
2
3//! # 🦓 🔗 ZebraChain: A futuristic cryptographic identity system.
4//!
5//! ZebraChain is a logged, quantum safe signing protocol designed to replace the long lived
6//! asymmetric key pairs used to sign software releases (and to sign other super important stuff).
7//!
8//! In short, ZebraChain:
9//!
10//! * Logs each signature in a block chain
11//!
12//! * Changes the keypairs at every signature by including the public key used to sign the current
13//! block and the hash of the public key that will be used to sign the next block
14//!
15//! * Is quantum secure because it uses ML-DSA + ed25519 in a hybrid signing construction (as
16//! recommended by the ML-DSA authors)
17//!
18//! This is a pre-release crate. The API is still being finalized. The 0.0.x releases make no
19//! API commitments, nor any commits to the protocol.
20//!
21//! However, the dust is settling quickly and it's a perfect time to jump in and start building
22//! experimental applications on top of ZebraChain!
23//!
24//! ## ⚠️ Security Warning
25//!
26//! ZebraChain is not yet suitable for production use.
27//!
28//! This is a nascent implementation of a yet to be finalized protocol. It's also built on a quite new
29//! Rust implementation of [ML-DSA] that has its own security warning.
30//!
31//! ## 🚀 Quickstart
32//!
33//! ```
34//! use tempfile;
35//! use zf_zebrachain::{ChainStore, Cursor, Hash, OwnedChainStore, Payload};
36//!
37//! // To create a chain and make signatures, you need a directory for your public chain files
38//! // and another directory for your secret chain files:
39//! let chain_dir = tempfile::TempDir::new().unwrap();
40//! let secret_chain_dir = tempfile::TempDir::new().unwrap();
41//!
42//! // Use both directories in your OwnedChainStore:
43//! let owned_store = OwnedChainStore::new(chain_dir.path(), secret_chain_dir.path());
44//!
45//! // OwnedChainStore.list_chains() will return zero chains (as we haven't created any yet):
46//! assert_eq!(owned_store.list_chains().unwrap(), []);
47//!
48//! // A Payload is what you to sign. Currently it's a 64-bit timestamp and a 320-bit hash. To
49//! // create a new chain, you need the first payload that you want to sign:
50//! let payload1 = Payload::new_time_stamped(Hash::compute(b"Message number 1"));
51//!
52//! // Lastly, you need a password (or a key from a hardware security module or similar) that will
53//! // be used to encrypt this secret chain:
54//! let password = b"SUPER BAD PASSWORD";
55//! let mut owned_chain = owned_store.generate_chain(&payload1, password).unwrap();
56//! assert_eq!(owned_chain.head().payload, payload1);
57//! assert_eq!(owned_chain.tail().payload, payload1);
58//!
59//! // Make another signature like this:
60//! let payload2 = Payload::new_time_stamped(Hash::compute(b"Message number 2"));
61//! owned_chain.sign(&payload2).unwrap();
62//! assert_eq!(owned_chain.head().payload, payload1);
63//! assert_eq!(owned_chain.tail().payload, payload2);
64//!
65//! // A chain is identified by its `chain_hash`, which is the hash of the 1st block in the chain:
66//! let chain_hash = *owned_chain.chain_hash();
67//! assert_eq!(chain_hash, owned_chain.head().block_hash);
68//!
69//! // OwnedChainStore.list_chains() now shows our expected chain:
70//! assert_eq!(owned_store.list_chains().unwrap(), [chain_hash]);
71//!
72//! // Reopen the owned chain and create additional signatures like this:
73//! let mut owned_chain = owned_store.open_chain(&chain_hash, password).unwrap();
74//! let payload3 = Payload::new_time_stamped(Hash::compute(b"Message number 3"));
75//! owned_chain.sign(&payload3).unwrap();
76//! assert_eq!(owned_chain.head().payload, payload1);
77//! assert_eq!(owned_chain.tail().payload, payload3);
78//!
79//! // A ChainStore is used for consuming the public side of the chain:
80//! let store = ChainStore::new(chain_dir.path());
81//!
82//! // ChainStore.list_chains() likewise shows our expected chain:
83//! assert_eq!(store.list_chains().unwrap(), [chain_hash]);
84//!
85//! // Open and fully verify the public chain by the `chain_hash` like this:
86//! let mut chain = store.open_chain(&chain_hash).unwrap();
87//! assert_eq!(chain.head().payload, payload1);
88//! assert_eq!(chain.tail().payload, payload3);
89//!
90//! // A Cursor allows you step step forward and backward through a chain:
91//! let mut cursor = Cursor::from_tail(&mut chain);
92//! assert_eq!(cursor.block_state().payload, payload3);
93//! cursor.previous_block().unwrap();
94//! assert_eq!(cursor.block_state().payload, payload2);
95//! cursor.previous_block().unwrap();
96//! assert_eq!(cursor.block_state().payload, payload1);
97//! ```
98//!
99//! [ML-DSA]: https://github.com/RustCrypto/signatures/tree/master/ml-dsa
100
101mod always;
102mod block;
103mod chain;
104mod errors;
105mod fsutil;
106mod hashing;
107mod ownedblock;
108mod ownedchain;
109mod payload;
110mod pksign;
111mod secretblock;
112mod secretchain;
113mod secretseed;
114
115#[cfg(test)]
116pub mod testhelpers;
117
118pub use always::{
119 BLOCK, CONTEXT, DIGEST, HEXDIGEST, PAYLOAD, SECRET, SECRET_BLOCK, SECRET_BLOCK_AEAD,
120 SECRET_CHAIN_HEADER, Z32DIGEST,
121};
122pub use block::{Block, BlockState, CheckPoint, MutBlock, sign_block};
123pub use chain::{Chain, ChainIter, ChainStore, Cursor};
124pub use errors::{BlockError, EntropyError, SecretBlockError};
125pub use hashing::{Hash, HexError, Secret, SubSecret, SubSecret192, SubSecret256, Zbase32Error};
126pub use ownedblock::{MutOwnedBlock, OwnedBlockState};
127pub use ownedchain::{OwnedChain, OwnedChainStore};
128pub use payload::Payload;
129pub use secretblock::{MutSecretBlock, SecretBlock, SecretBlockState};
130pub use secretchain::{SecretChain, SecretChainHeader, SecretChainIter, SecretChainStore};
131pub use secretseed::Seed;