Skip to main content

oxilean_std/cryptography/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4use super::functions::*;
5
6/// Toy Diffie-Hellman key exchange simulation.
7///
8/// Encapsulates a full simulated key exchange between Alice and Bob.
9///
10/// # WARNING
11/// Uses tiny parameters with no real security.
12pub struct DiffieHellmanSim {
13    /// Shared prime p
14    pub p: u64,
15    /// Generator g
16    pub g: u64,
17    /// Alice's private key
18    pub alice_priv: u64,
19    /// Bob's private key
20    pub bob_priv: u64,
21}
22impl DiffieHellmanSim {
23    /// Create a simulation with given parameters.
24    pub fn new(p: u64, g: u64, alice_priv: u64, bob_priv: u64) -> Self {
25        DiffieHellmanSim {
26            p,
27            g,
28            alice_priv,
29            bob_priv,
30        }
31    }
32    /// Alice's public key: g^a mod p.
33    pub fn alice_public(&self) -> u64 {
34        mod_exp(self.g, self.alice_priv, self.p)
35    }
36    /// Bob's public key: g^b mod p.
37    pub fn bob_public(&self) -> u64 {
38        mod_exp(self.g, self.bob_priv, self.p)
39    }
40    /// Shared secret computed by Alice: (g^b)^a mod p.
41    pub fn alice_shared_secret(&self) -> u64 {
42        mod_exp(self.bob_public(), self.alice_priv, self.p)
43    }
44    /// Shared secret computed by Bob: (g^a)^b mod p.
45    pub fn bob_shared_secret(&self) -> u64 {
46        mod_exp(self.alice_public(), self.bob_priv, self.p)
47    }
48    /// Verify that Alice and Bob derive the same shared secret.
49    pub fn secrets_match(&self) -> bool {
50        self.alice_shared_secret() == self.bob_shared_secret()
51    }
52}
53/// Modular arithmetic helpers with support for common field operations.
54///
55/// # WARNING
56/// Educational implementation only.
57pub struct ModularArithmetic {
58    /// The modulus
59    pub modulus: u64,
60}
61impl ModularArithmetic {
62    /// Create a new modular arithmetic context with the given modulus.
63    pub fn new(modulus: u64) -> Self {
64        ModularArithmetic { modulus }
65    }
66    /// Add two values mod p.
67    pub fn add(&self, a: u64, b: u64) -> u64 {
68        (a + b) % self.modulus
69    }
70    /// Subtract two values mod p.
71    pub fn sub(&self, a: u64, b: u64) -> u64 {
72        (a + self.modulus - b % self.modulus) % self.modulus
73    }
74    /// Multiply two values mod p.
75    pub fn mul(&self, a: u64, b: u64) -> u64 {
76        ((a as u128 * b as u128) % self.modulus as u128) as u64
77    }
78    /// Fast exponentiation a^e mod p using repeated squaring.
79    pub fn pow(&self, a: u64, e: u64) -> u64 {
80        mod_exp(a, e, self.modulus)
81    }
82    /// Modular inverse a^{-1} mod p (requires gcd(a, p) = 1).
83    pub fn inv(&self, a: u64) -> Option<u64> {
84        mod_inverse(a, self.modulus)
85    }
86    /// Legendre symbol (a | p): 1 if a is a quadratic residue mod prime p,
87    /// -1 if not, 0 if p | a. Uses Euler's criterion: a^{(p-1)/2} mod p.
88    ///
89    /// # WARNING
90    /// Assumes modulus is an odd prime; undefined otherwise.
91    pub fn legendre(&self, a: u64) -> i64 {
92        if a % self.modulus == 0 {
93            return 0;
94        }
95        let exp = (self.modulus - 1) / 2;
96        let result = self.pow(a % self.modulus, exp);
97        if result == 1 {
98            1
99        } else {
100            -1
101        }
102    }
103}
104/// A simple hash chain using a polynomial rolling hash as a stand-in for
105/// a cryptographic hash function.
106///
107/// h_0 = initial_value, h_{i+1} = hash(h_i || data_i)
108///
109/// # WARNING
110/// The polynomial hash used here is NOT a cryptographic hash function and
111/// provides no real security. This is a structural illustration only.
112#[derive(Debug, Clone)]
113pub struct HashChain {
114    /// The chain of hash values: chain[0] is genesis, chain[i+1] = hash(chain[i], data[i])
115    pub chain: Vec<u64>,
116}
117impl HashChain {
118    /// Create a new hash chain with a genesis value.
119    pub fn new(genesis: u64) -> Self {
120        HashChain {
121            chain: vec![genesis],
122        }
123    }
124    /// Internal link hash: combines previous hash with new data.
125    fn link_hash(prev: u64, data: u64) -> u64 {
126        let mut buf = [0u8; 16];
127        buf[..8].copy_from_slice(&prev.to_le_bytes());
128        buf[8..].copy_from_slice(&data.to_le_bytes());
129        simple_hash(&buf)
130    }
131    /// Append a new block with the given data, extending the chain.
132    pub fn append(&mut self, data: u64) {
133        let prev = *self
134            .chain
135            .last()
136            .expect("chain is non-empty: initialized with genesis value");
137        self.chain.push(Self::link_hash(prev, data));
138    }
139    /// Return the current tip (latest hash).
140    pub fn tip(&self) -> u64 {
141        *self
142            .chain
143            .last()
144            .expect("chain is non-empty: initialized with genesis value")
145    }
146    /// Verify the chain is internally consistent.
147    /// Returns `true` if all links are valid, assuming the provided data sequence.
148    pub fn verify(&self, data: &[u64]) -> bool {
149        if data.len() + 1 != self.chain.len() {
150            return false;
151        }
152        for (i, &d) in data.iter().enumerate() {
153            let expected = Self::link_hash(self.chain[i], d);
154            if self.chain[i + 1] != expected {
155                return false;
156            }
157        }
158        true
159    }
160}
161/// Toy Diffie-Hellman parameters (prime p, generator g).
162///
163/// # WARNING
164/// Educational only. Real DH requires carefully chosen safe primes and
165/// generators. This implementation is NOT secure.
166pub struct ToyDiffieHellman {
167    /// A prime modulus p
168    pub p: u64,
169    /// A generator g of the multiplicative group mod p
170    pub g: u64,
171}
172impl ToyDiffieHellman {
173    /// Compute the public key `g^private mod p`.
174    ///
175    /// # WARNING
176    /// Educational only.
177    pub fn public_key(&self, private: u64) -> u64 {
178        mod_exp(self.g, private, self.p)
179    }
180    /// Compute the shared secret `their_public^my_private mod p`.
181    ///
182    /// Both parties derive the same value: (g^a)^b = (g^b)^a mod p.
183    ///
184    /// # WARNING
185    /// Educational only. Does not defend against MITM attacks without
186    /// authentication.
187    pub fn shared_secret(&self, their_public: u64, my_private: u64) -> u64 {
188        mod_exp(their_public, my_private, self.p)
189    }
190}
191/// Toy Schnorr signature scheme over a finite cyclic group Z_p^*.
192///
193/// # WARNING
194/// Educational only. Parameters are not secure.
195#[allow(dead_code)]
196pub struct ToySchnorr {
197    /// Prime modulus p
198    pub p: u64,
199    /// Group order q (should be a prime divisor of p-1)
200    pub q: u64,
201    /// Generator g of the subgroup of order q
202    pub g: u64,
203}
204#[allow(dead_code)]
205impl ToySchnorr {
206    /// Create a Schnorr context.
207    pub fn new(p: u64, q: u64, g: u64) -> Self {
208        ToySchnorr { p, q, g }
209    }
210    /// Compute the public key: g^x mod p.
211    pub fn public_key(&self, x: u64) -> u64 {
212        mod_exp(self.g, x, self.p)
213    }
214    /// Sign a message hash `h` with private key `x` and nonce `k`.
215    ///
216    /// Returns (r, s) where r = g^k mod p mod q, s = (k - x*r) mod q.
217    ///
218    /// # WARNING
219    /// Never reuse the nonce k. In practice, k must be uniformly random.
220    pub fn sign(&self, x: u64, k: u64, h: u64) -> (u64, u64) {
221        let r = mod_exp(self.g, k, self.p) % self.q;
222        let s = (k.wrapping_add(x.wrapping_mul(r).wrapping_add(h))) % self.q;
223        (r, s)
224    }
225    /// Verify a Schnorr signature (r, s) on hash h with public key pk.
226    ///
227    /// Checks: g^s * pk^h ≡ R and R mod q == r.
228    pub fn verify(&self, pk: u64, h: u64, r: u64, s: u64) -> bool {
229        let gs = mod_exp(self.g, s, self.p);
230        let pkh = mod_exp(pk, h, self.p);
231        let lhs = ((gs as u128 * pkh as u128) % self.p as u128) as u64;
232        lhs % self.q == r
233    }
234}
235/// Toy RSA key pair (n, e, d).
236///
237/// # WARNING
238/// This is a **toy implementation for education only**. It uses tiny parameters
239/// and is completely insecure. NEVER use for real data.
240pub struct ToyRsa {
241    /// RSA modulus n = p * q
242    pub n: u64,
243    /// Public exponent e (typically 65537 in real RSA)
244    pub e: u64,
245    /// Private exponent d (e^{-1} mod λ(n))
246    pub d: u64,
247}
248impl ToyRsa {
249    /// Generate a toy RSA key pair from two small primes `p` and `q`.
250    ///
251    /// Computes n = p*q, λ(n) = lcm(p-1, q-1), chooses e=65537 (or 3 as fallback),
252    /// and derives d = e^{-1} mod λ(n).
253    ///
254    /// Returns `None` if the primes are unsuitable (e.g., gcd(e, λ(n)) ≠ 1).
255    ///
256    /// # WARNING
257    /// Educational only. Real RSA requires 2048-bit+ primes.
258    pub fn generate(p: u64, q: u64) -> Option<Self> {
259        let n = p.checked_mul(q)?;
260        let pm1 = p - 1;
261        let qm1 = q - 1;
262        let g = {
263            let (gcd, _, _) = extended_gcd(pm1 as i64, qm1 as i64);
264            gcd.unsigned_abs()
265        };
266        let lambda_n = pm1 / g * qm1;
267        let candidates = [65537u64, 17, 3];
268        for &e in &candidates {
269            if e >= lambda_n {
270                continue;
271            }
272            if let Some(d) = mod_inverse(e, lambda_n) {
273                return Some(ToyRsa { n, e, d });
274            }
275        }
276        None
277    }
278    /// Encrypt plaintext `m` as `m^e mod n`.
279    ///
280    /// # WARNING
281    /// Toy implementation. Does not pad, not semantically secure.
282    pub fn encrypt(&self, m: u64) -> u64 {
283        mod_exp(m, self.e, self.n)
284    }
285    /// Decrypt ciphertext `c` as `c^d mod n`.
286    ///
287    /// # WARNING
288    /// Toy implementation only.
289    pub fn decrypt(&self, c: u64) -> u64 {
290        mod_exp(c, self.d, self.n)
291    }
292}
293/// Polynomial commitment scheme toy (Kate-style, educational model).
294///
295/// In real KZG commitments, the commitment is an elliptic curve point.
296/// Here we use a simplified polynomial evaluation model.
297///
298/// # WARNING
299/// This is a structural illustration only. It provides NO cryptographic security.
300#[allow(dead_code)]
301pub struct ToyPolyCommit {
302    /// Evaluation point (the "trusted setup" scalar Ï„)
303    pub tau: u64,
304    /// Field modulus
305    pub q: u64,
306}
307#[allow(dead_code)]
308impl ToyPolyCommit {
309    /// Create a toy polynomial commitment context.
310    pub fn new(tau: u64, q: u64) -> Self {
311        ToyPolyCommit { tau, q }
312    }
313    /// Commit to a polynomial given as coefficient vector (lowest degree first).
314    ///
315    /// Commitment = p(Ï„) mod q (educational stand-in for g^{p(Ï„)} on an EC).
316    pub fn commit(&self, coeffs: &[u64]) -> u64 {
317        let q = self.q as u128;
318        let tau = self.tau as u128;
319        let mut power = 1u128;
320        let mut result = 0u128;
321        for &c in coeffs {
322            result = (result + c as u128 * power) % q;
323            power = power * tau % q;
324        }
325        result as u64
326    }
327    /// Evaluate the polynomial at a given point z.
328    pub fn evaluate(&self, coeffs: &[u64], z: u64) -> u64 {
329        let q = self.q as u128;
330        let z = z as u128;
331        let mut power = 1u128;
332        let mut result = 0u128;
333        for &c in coeffs {
334            result = (result + c as u128 * power) % q;
335            power = power * z % q;
336        }
337        result as u64
338    }
339    /// Verify an opening: checks that the committed value matches
340    /// the claimed evaluation p(z) = v by comparing with stored commitment.
341    ///
342    /// In real KZG this requires a pairing check.
343    pub fn verify_opening(&self, commitment: u64, z: u64, v: u64, coeffs: &[u64]) -> bool {
344        let actual = self.evaluate(coeffs, z);
345        let claimed_commit = self.commit(coeffs);
346        actual == v && claimed_commit == commitment
347    }
348}
349/// Lattice-based encryption toy model.
350///
351/// Implements a toy version of LWE encryption for educational illustration.
352/// Uses very small parameters (NOT secure).
353///
354/// # WARNING
355/// This is an educational toy. Parameters are not cryptographically secure.
356#[allow(dead_code)]
357pub struct ToyLwe {
358    /// Dimension n (key length)
359    pub n: usize,
360    /// Modulus q
361    pub q: u64,
362    /// Error bound (max absolute value of noise)
363    pub error_bound: u64,
364}
365#[allow(dead_code)]
366impl ToyLwe {
367    /// Create a new LWE context with given parameters.
368    pub fn new(n: usize, q: u64, error_bound: u64) -> Self {
369        ToyLwe { n, q, error_bound }
370    }
371    /// Compute (a · s) mod q, the inner product of a and s.
372    pub fn inner_product(&self, a: &[u64], s: &[u64]) -> u64 {
373        assert_eq!(a.len(), s.len());
374        let q = self.q as u128;
375        a.iter()
376            .zip(s.iter())
377            .fold(0u128, |acc, (&ai, &si)| (acc + ai as u128 * si as u128) % q) as u64
378    }
379    /// Encrypt a bit (0 or 1) using the LWE public key (A, b = As + e).
380    ///
381    /// Returns (u, v) where u = A^T r, v = b^T r + bit * floor(q/2).
382    /// For simplicity in this toy version, just uses the scalar version.
383    pub fn encrypt_bit(&self, secret: &[u64], bit: u8, noise: u64, a: &[u64]) -> (Vec<u64>, u64) {
384        let b = (self.inner_product(a, secret) + noise % self.q) % self.q;
385        let v = (b + (bit as u64) * (self.q / 2)) % self.q;
386        (a.to_vec(), v)
387    }
388    /// Decrypt: compute v - a · s mod q, return 0 or 1.
389    pub fn decrypt_bit(&self, secret: &[u64], a: &[u64], v: u64) -> u8 {
390        let dot = self.inner_product(a, secret);
391        let diff = (v + self.q - dot) % self.q;
392        if diff < self.q / 4 || diff > 3 * self.q / 4 {
393            0
394        } else {
395            1
396        }
397    }
398}
399/// Shamir's Secret Sharing over a finite field Z_p.
400///
401/// Splits a secret s into n shares such that any k shares can reconstruct s
402/// via Lagrange interpolation, but any k-1 shares reveal nothing about s.
403///
404/// # WARNING
405/// Educational implementation. The polynomial coefficients are NOT generated
406/// with cryptographically secure randomness. Do NOT use for real secrets.
407pub struct ShamirSecretShare {
408    /// Prime modulus p (field F_p)
409    pub p: u64,
410    /// Threshold k: minimum shares needed for reconstruction
411    pub k: usize,
412    /// Total shares n
413    pub n: usize,
414}
415impl ShamirSecretShare {
416    /// Create a new Shamir secret sharing instance.
417    pub fn new(p: u64, k: usize, n: usize) -> Self {
418        ShamirSecretShare { p, k, n }
419    }
420    /// Evaluate the polynomial f(x) = coeffs[0] + coeffs[1]*x + ... + coeffs[k-1]*x^{k-1} mod p.
421    fn eval_poly(&self, coeffs: &[u64], x: u64) -> u64 {
422        let mut result = 0u64;
423        for &c in coeffs.iter().rev() {
424            result = (((result as u128 * x as u128) % self.p as u128 + c as u128) % self.p as u128)
425                as u64;
426        }
427        result
428    }
429    /// Split a secret `s` into n shares using a deterministic polynomial
430    /// with coefficients derived from `seed` (for reproducibility in tests).
431    ///
432    /// Returns a vector of (x, y) pairs where x = 1..=n and y = f(x).
433    ///
434    /// # WARNING
435    /// The seed-based coefficient generation is NOT secure. Real Shamir's scheme
436    /// requires cryptographically random coefficients.
437    pub fn share(&self, secret: u64, seed: u64) -> Vec<(u64, u64)> {
438        let mut coeffs = vec![secret % self.p];
439        for i in 1..self.k {
440            let c = (seed
441                .wrapping_mul(0x9e3779b97f4a7c15)
442                .wrapping_add(i as u64 * 0x6c62272e07bb0142))
443                % self.p;
444            coeffs.push(c);
445        }
446        (1..=self.n as u64)
447            .map(|x| (x, self.eval_poly(&coeffs, x)))
448            .collect()
449    }
450    /// Reconstruct the secret from any k shares using Lagrange interpolation over F_p.
451    ///
452    /// Each share is an (x, y) pair. Computes f(0) = Σ y_i * L_i(0) mod p.
453    pub fn reconstruct(&self, shares: &[(u64, u64)]) -> Option<u64> {
454        if shares.len() < self.k {
455            return None;
456        }
457        let shares = &shares[..self.k];
458        let p = self.p;
459        let mut secret = 0u64;
460        for (i, &(xi, yi)) in shares.iter().enumerate() {
461            let mut num: u128 = 1;
462            let mut den: u128 = 1;
463            for (j, &(xj, _)) in shares.iter().enumerate() {
464                if i != j {
465                    num = num * ((p - xj % p) as u128) % p as u128;
466                    let diff = ((xi as i128 - xj as i128).rem_euclid(p as i128)) as u64;
467                    den = den * diff as u128 % p as u128;
468                }
469            }
470            let den_inv = mod_inverse(den as u64, p)?;
471            let li = (num as u64 * den_inv % p * yi % p) % p;
472            secret = (secret + li) % p;
473        }
474        Some(secret)
475    }
476}
477/// Toy RSA key generation from scratch: finds two random-ish primes near
478/// the given starting point using Miller-Rabin, then builds the key pair.
479///
480/// # WARNING
481/// This is purely educational. Key sizes are dangerously small.
482pub struct RsaKeyGen;
483impl RsaKeyGen {
484    /// Find the next (probably) prime after `start` using Miller-Rabin.
485    pub fn next_prime(start: u64) -> u64 {
486        let witnesses = [2u64, 3, 5, 7, 11, 13];
487        let mut candidate = if start % 2 == 0 { start + 1 } else { start };
488        loop {
489            if miller_rabin(candidate, &witnesses) {
490                return candidate;
491            }
492            candidate += 2;
493        }
494    }
495    /// Generate a toy RSA key pair by finding two primes near `seed`.
496    ///
497    /// Returns `(ToyRsa, p, q)` for inspection.
498    ///
499    /// # WARNING
500    /// For illustration only. Do not use for any security purpose.
501    pub fn generate_from_seed(seed: u64) -> Option<(ToyRsa, u64, u64)> {
502        let p = Self::next_prime(seed);
503        let q = Self::next_prime(p + 2);
504        let rsa = ToyRsa::generate(p, q)?;
505        Some((rsa, p, q))
506    }
507}
508/// Polynomial-ring arithmetic over Z_q[x]/(x^n + 1).
509///
510/// Supports the ring operations needed for Ring-LWE and NTRU-based schemes.
511///
512/// # WARNING
513/// Educational implementation. Not optimized or secure.
514#[allow(dead_code)]
515pub struct RingZq {
516    /// Ring dimension n (must be a power of 2 for NTT)
517    pub n: usize,
518    /// Modulus q
519    pub q: u64,
520}
521#[allow(dead_code)]
522impl RingZq {
523    /// Create a new ring Z_q[x]/(x^n + 1).
524    pub fn new(n: usize, q: u64) -> Self {
525        RingZq { n, q }
526    }
527    /// Reduce polynomial coefficients modulo q.
528    pub fn reduce(&self, poly: &[u64]) -> Vec<u64> {
529        poly.iter().map(|&c| c % self.q).collect()
530    }
531    /// Add two polynomials in the ring.
532    pub fn add(&self, a: &[u64], b: &[u64]) -> Vec<u64> {
533        assert_eq!(a.len(), self.n);
534        assert_eq!(b.len(), self.n);
535        a.iter()
536            .zip(b.iter())
537            .map(|(&ai, &bi)| (ai + bi) % self.q)
538            .collect()
539    }
540    /// Subtract two polynomials in the ring.
541    pub fn sub(&self, a: &[u64], b: &[u64]) -> Vec<u64> {
542        assert_eq!(a.len(), self.n);
543        assert_eq!(b.len(), self.n);
544        a.iter()
545            .zip(b.iter())
546            .map(|(&ai, &bi)| (ai + self.q - bi % self.q) % self.q)
547            .collect()
548    }
549    /// Multiply two polynomials in Z_q[x]/(x^n + 1) using schoolbook multiplication.
550    ///
551    /// O(n^2) — for educational purposes. Real implementations use NTT.
552    pub fn mul(&self, a: &[u64], b: &[u64]) -> Vec<u64> {
553        assert_eq!(a.len(), self.n);
554        assert_eq!(b.len(), self.n);
555        let mut result = vec![0i128; self.n];
556        let q = self.q as i128;
557        for i in 0..self.n {
558            for j in 0..self.n {
559                let idx = i + j;
560                let coeff = a[i] as i128 * b[j] as i128 % q;
561                if idx < self.n {
562                    result[idx] = (result[idx] + coeff) % q;
563                } else {
564                    result[idx - self.n] = (result[idx - self.n] - coeff + q) % q;
565                }
566            }
567        }
568        result.iter().map(|&c| c as u64).collect()
569    }
570    /// L-infinity norm: max absolute deviation from 0 or q (viewing coefficients
571    /// as centered in (-q/2, q/2]).
572    pub fn linf_norm(&self, poly: &[u64]) -> u64 {
573        let half_q = self.q / 2;
574        poly.iter()
575            .map(|&c| {
576                let c = c % self.q;
577                if c <= half_q {
578                    c
579                } else {
580                    self.q - c
581                }
582            })
583            .max()
584            .unwrap_or(0)
585    }
586}