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}