Cryptographic Foundations
Deep dive into the cryptographic primitives underlying Zeris: hash functions, timestamp proofs, Merkle trees, and deterministic sequencing.
Hash Functions
Zeris relies on SHA256 as its primary cryptographic hash function. SHA256 provides:
- Pre-image resistance - Computationally infeasible to find input given output
- Second pre-image resistance - Cannot find different input with same hash
- Collision resistance - Extremely difficult to find two inputs with identical hash
SHA256 Properties
- Output size: 256 bits (32 bytes)
- Block size: 512 bits
- Security level: 2^128 operations for collision
- Typical performance: ~300 MB/s on modern CPUs
use sha2::{Sha256, Digest};
fn compute_hash(data: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(data);
hasher.finalize().into()
}
// Sequential hashing for PoH
fn poh_chain(genesis: [u8; 32], ticks: u64) -> [u8; 32] {
let mut current = genesis;
for _ in 0..ticks {
current = compute_hash(¤t);
}
current
}Timestamp Proofs
Zeris constructs cryptographic timestamp proofs using sequential hashing. The key insight is that computing n sequential hashes requires at minimum n × t_hash time.
Verifiable Delay Function (VDF)
A VDF is a function that requires a specified number of sequential steps to compute but can be efficiently verified:
struct TimestampProof {
input: [u8; 32],
output: [u8; 32],
num_iterations: u64,
checkpoints: Vec<[u8; 32]>,
}
fn generate_timestamp_proof(
input: [u8; 32],
num_iterations: u64
) -> TimestampProof {
let checkpoint_interval = num_iterations / 8;
let mut checkpoints = Vec::new();
let mut current = input;
for i in 0..num_iterations {
current = compute_hash(¤t);
if i % checkpoint_interval == 0 {
checkpoints.push(current);
}
}
TimestampProof {
input,
output: current,
num_iterations,
checkpoints,
}
}
fn verify_timestamp_proof(proof: &TimestampProof) -> bool {
let checkpoint_interval = proof.num_iterations / 8;
let mut current = proof.input;
for (i, checkpoint) in proof.checkpoints.iter().enumerate() {
// Compute hashes until checkpoint
for _ in 0..checkpoint_interval {
current = compute_hash(¤t);
}
// Verify checkpoint matches
if current != *checkpoint {
return false;
}
}
current == proof.output
}Merkle Branching
Merkle trees enable efficient proof of inclusion for transactions. A Merkle tree is a binary tree where each leaf is a transaction hash and each internal node is the hash of its children.
Merkle Tree Construction
class MerkleTree {
private leaves: Buffer[];
private layers: Buffer[][];
constructor(leaves: Buffer[]) {
this.leaves = leaves;
this.layers = this.buildLayers(leaves);
}
private buildLayers(leaves: Buffer[]): Buffer[][] {
const layers = [leaves];
while (layers[layers.length - 1].length > 1) {
const currentLayer = layers[layers.length - 1];
const nextLayer: Buffer[] = [];
for (let i = 0; i < currentLayer.length; i += 2) {
const left = currentLayer[i];
const right = i + 1 < currentLayer.length
? currentLayer[i + 1]
: left; // Duplicate if odd number
const combined = Buffer.concat([left, right]);
nextLayer.push(sha256(combined));
}
layers.push(nextLayer);
}
return layers;
}
getRoot(): Buffer {
return this.layers[this.layers.length - 1][0];
}
getProof(index: number): Buffer[] {
const proof: Buffer[] = [];
for (let i = 0; i < this.layers.length - 1; i++) {
const layer = this.layers[i];
const isRightNode = index % 2 === 1;
const siblingIndex = isRightNode ? index - 1 : index + 1;
if (siblingIndex < layer.length) {
proof.push(layer[siblingIndex]);
}
index = Math.floor(index / 2);
}
return proof;
}
}Merkle Proof Verification
function verifyMerkleProof(
leaf: Buffer,
proof: Buffer[],
root: Buffer,
index: number
): boolean {
let computedHash = leaf;
for (const proofElement of proof) {
const isRightNode = index % 2 === 1;
if (isRightNode) {
computedHash = sha256(
Buffer.concat([proofElement, computedHash])
);
} else {
computedHash = sha256(
Buffer.concat([computedHash, proofElement])
);
}
index = Math.floor(index / 2);
}
return computedHash.equals(root);
}Merkle proofs require O(log n) space and verification time, making them highly efficient for large transaction sets.
Deterministic Sequencing
Zeris ensures deterministic ordering through a combination of PoH timestamps and content-addressed hashing.
Transaction Ordering Algorithm
#[derive(Debug, Clone)]
struct OrderedTransaction {
tx_hash: [u8; 32],
poh_tick: u64,
pow_nonce: u64,
timestamp: i64,
}
impl PartialOrd for OrderedTransaction {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for OrderedTransaction {
fn cmp(&self, other: &Self) -> Ordering {
// Primary: PoH tick (deterministic time)
match self.poh_tick.cmp(&other.poh_tick) {
Ordering::Equal => {
// Secondary: Transaction hash (deterministic tiebreaker)
self.tx_hash.cmp(&other.tx_hash)
}
other => other,
}
}
}
fn order_transactions(txs: &mut [OrderedTransaction]) {
txs.sort(); // Uses Ord implementation above
// Verify ordering is deterministic
assert!(is_strictly_ordered(txs));
}
fn is_strictly_ordered(txs: &[OrderedTransaction]) -> bool {
txs.windows(2).all(|w| w[0] < w[1])
}Sybil Cost Model
The PoW layer imposes quantifiable costs on creating multiple identities:
Economic Attack Analysis
Given:
C= Cost per identity (PoW computation)N= Number of sybil identitiesB= Benefit from attack
An attack is profitable only if:
By tuning PoW difficulty, Zeris ensures N × C exceeds any realistic attack benefit.
Cryptographic Security Parameters
| Parameter | Value | Security Level |
|---|---|---|
| Hash Function | SHA256 | 128-bit collision resistance |
| Min PoW Difficulty | 16 bits | ~65k average attempts |
| Max PoW Difficulty | 32 bits | ~4B average attempts |
| PoH Tick Rate | 1000/sec | 1ms timestamp resolution |
| PoS Threshold | 67% | Byzantine fault tolerant |
