1use super::functions::*;
5
6#[derive(Debug, Clone)]
14pub struct SchnorrParams {
15 pub p: u64,
17 pub q: u64,
19 pub g: u64,
21}
22impl SchnorrParams {
23 pub fn commit(&self, r: u64) -> u64 {
28 mod_exp(self.g, r % self.q, self.p)
29 }
30 pub fn respond(&self, r: u64, challenge: u64, secret_x: u64) -> u64 {
32 let r = r % self.q;
33 let e_x = (challenge as u128 * secret_x as u128 % self.q as u128) as u64;
34 (r + e_x) % self.q
35 }
36 pub fn verify(&self, transcript: &SchnorrTranscript, public_y: u64) -> bool {
38 let lhs = mod_exp(self.g, transcript.response, self.p);
39 let ye = mod_exp(public_y, transcript.challenge, self.p);
40 let rhs = (transcript.commitment as u128 * ye as u128 % self.p as u128) as u64;
41 lhs == rhs
42 }
43 pub fn prove(&self, secret_x: u64, r: u64, challenge: u64) -> SchnorrTranscript {
45 let commitment = self.commit(r);
46 let response = self.respond(r, challenge, secret_x);
47 SchnorrTranscript {
48 commitment,
49 challenge,
50 response,
51 }
52 }
53}
54#[allow(dead_code)]
55#[derive(Debug, Clone, PartialEq)]
56pub enum MPCSecurityModel {
57 SemiHonest,
58 Malicious,
59 Covert,
60}
61#[derive(Debug, Clone)]
66pub struct ShamirSS {
67 pub p: u64,
69 pub t: usize,
71 pub n: usize,
73}
74impl ShamirSS {
75 pub fn split(&self, secret: u64, coeffs: &[u64]) -> Vec<(u64, u64)> {
82 assert_eq!(
83 coeffs.len(),
84 self.t - 1,
85 "Need exactly t-1 random coefficients"
86 );
87 (1..=(self.n as u64))
88 .map(|i| {
89 let mut val: u128 = secret as u128;
90 let mut ipow: u128 = i as u128;
91 for &c in coeffs {
92 val = (val + c as u128 * ipow) % self.p as u128;
93 ipow = ipow * i as u128 % self.p as u128;
94 }
95 (i, val as u64)
96 })
97 .collect()
98 }
99 pub fn reconstruct(&self, shares: &[(u64, u64)]) -> u64 {
103 assert!(shares.len() >= self.t, "Need at least t shares");
104 let shares = &shares[..self.t];
105 let p = self.p;
106 let mut secret: i128 = 0;
107 for (j, &(xj, yj)) in shares.iter().enumerate() {
108 let mut num: i128 = 1;
109 let mut den: i128 = 1;
110 for (k, &(xk, _)) in shares.iter().enumerate() {
111 if k == j {
112 continue;
113 }
114 num = num * (-(xk as i128)) % p as i128;
115 den = den * (xj as i128 - xk as i128) % p as i128;
116 }
117 let den_inv =
118 mod_inv(((den % p as i128 + p as i128) % p as i128) as u64, p).unwrap_or(0) as i128;
119 let lagrange = num * den_inv % p as i128;
120 secret = (secret + yj as i128 * lagrange) % p as i128;
121 }
122 ((secret % p as i128 + p as i128) % p as i128) as u64
123 }
124}
125#[derive(Debug, Clone)]
133pub struct ToyOT {
134 pub p: u64,
136 pub g: u64,
138}
139impl ToyOT {
140 pub fn sender_setup(&self, a: u64) -> u64 {
142 mod_exp(self.g, a, self.p)
143 }
144 pub fn receiver_choose(&self, c: u64, b: u8, k: u64) -> (u64, u64) {
147 let gk = mod_exp(self.g, k, self.p);
148 let gk_inv = mod_inv(gk, self.p).unwrap_or(1);
149 let other = (c as u128 * gk_inv as u128 % self.p as u128) as u64;
150 if b == 0 {
151 (gk, other)
152 } else {
153 (other, gk)
154 }
155 }
156 pub fn receiver_key(&self, c: u64, b: u8, k: u64) -> u64 {
158 let _ = b;
159 mod_exp(c, k, self.p)
160 }
161}
162#[allow(dead_code)]
164#[derive(Debug, Clone)]
165pub struct ObliviousTransfer {
166 pub variant: OTVariant,
167 pub security_parameter: usize,
168}
169#[allow(dead_code)]
170impl ObliviousTransfer {
171 pub fn new(variant: OTVariant, sec: usize) -> Self {
172 ObliviousTransfer {
173 variant,
174 security_parameter: sec,
175 }
176 }
177 pub fn is_fundamental(&self) -> bool {
178 matches!(self.variant, OTVariant::OneOutOfTwo)
179 }
180 pub fn n_messages(&self) -> usize {
181 match &self.variant {
182 OTVariant::OneOutOfTwo => 2,
183 OTVariant::OneOutOfN(n) => *n,
184 OTVariant::RandomOT => 2,
185 }
186 }
187}
188#[derive(Debug, Clone)]
195pub struct PedersenCommitment {
196 pub p: u64,
198 pub q: u64,
200 pub g: u64,
202 pub h: u64,
204}
205impl PedersenCommitment {
206 pub fn commit(&self, m: u64, r: u64) -> u64 {
208 let gm = mod_exp(self.g, m % self.q, self.p);
209 let hr = mod_exp(self.h, r % self.q, self.p);
210 (gm as u128 * hr as u128 % self.p as u128) as u64
211 }
212 pub fn verify(&self, c: u64, m: u64, r: u64) -> bool {
214 self.commit(m, r) == c
215 }
216 pub fn add(&self, c1: u64, c2: u64) -> u64 {
218 (c1 as u128 * c2 as u128 % self.p as u128) as u64
219 }
220 pub fn batch_commit(&self, pairs: &[(u64, u64)]) -> Vec<u64> {
223 pairs.iter().map(|&(m, r)| self.commit(m, r)).collect()
224 }
225}
226#[allow(dead_code)]
228#[derive(Debug, Clone)]
229pub struct ZKProofSystem {
230 pub name: String,
231 pub is_interactive: bool,
232 pub soundness_error: f64,
233 pub completeness_error: f64,
234 pub proof_size_bytes: Option<usize>,
235}
236#[allow(dead_code)]
237impl ZKProofSystem {
238 pub fn new(name: &str, interactive: bool) -> Self {
239 ZKProofSystem {
240 name: name.to_string(),
241 is_interactive: interactive,
242 soundness_error: 0.5,
243 completeness_error: 0.0,
244 proof_size_bytes: None,
245 }
246 }
247 pub fn schnorr() -> Self {
248 let mut s = ZKProofSystem::new("Schnorr", true);
249 s.soundness_error = 1.0 / 2.0_f64.powi(128);
250 s.proof_size_bytes = Some(64);
251 s
252 }
253 pub fn groth16() -> Self {
254 let mut s = ZKProofSystem::new("Groth16", false);
255 s.soundness_error = 1.0 / 2.0_f64.powi(128);
256 s.proof_size_bytes = Some(128);
257 s
258 }
259 pub fn plonk() -> Self {
260 let mut s = ZKProofSystem::new("PLONK", false);
261 s.soundness_error = 1.0 / 2.0_f64.powi(128);
262 s.proof_size_bytes = Some(640);
263 s
264 }
265 pub fn is_non_interactive(&self) -> bool {
266 !self.is_interactive
267 }
268 pub fn is_succinct(&self) -> bool {
269 matches!(self.proof_size_bytes, Some(n) if n < 1000)
270 }
271}
272#[derive(Debug, Clone)]
277pub struct ShamirSecretSharingExtended {
278 pub p: u64,
280 pub t: usize,
282 pub n: usize,
284}
285impl ShamirSecretSharingExtended {
286 pub fn share(&self, secret: u64, coeffs: &[u64]) -> Vec<(u64, u64)> {
289 assert_eq!(coeffs.len(), self.t - 1, "Need t-1 coefficients");
290 (1..=self.n as u64)
291 .map(|i| {
292 let mut val: u128 = secret as u128 % self.p as u128;
293 let mut ipow: u128 = i as u128;
294 for &c in coeffs {
295 val = (val + c as u128 % self.p as u128 * ipow) % self.p as u128;
296 ipow = ipow * i as u128 % self.p as u128;
297 }
298 (i, val as u64)
299 })
300 .collect()
301 }
302 pub fn reconstruct(&self, shares: &[(u64, u64)]) -> u64 {
304 assert!(shares.len() >= self.t);
305 let shares = &shares[..self.t];
306 let p = self.p;
307 let mut acc: i128 = 0;
308 for (j, &(xj, yj)) in shares.iter().enumerate() {
309 let mut num: i128 = 1;
310 let mut den: i128 = 1;
311 for (k, &(xk, _)) in shares.iter().enumerate() {
312 if k == j {
313 continue;
314 }
315 num = num * (p as i128 - xk as i128) % p as i128;
316 den = den * ((xj as i128 - xk as i128).rem_euclid(p as i128)) % p as i128;
317 }
318 let den_pos = den.rem_euclid(p as i128) as u64;
319 let inv = mod_inv(den_pos, p).unwrap_or(0) as i128;
320 let lagrange = num % p as i128 * inv % p as i128;
321 acc = (acc + yj as i128 * lagrange % p as i128).rem_euclid(p as i128);
322 }
323 acc as u64
324 }
325}
326#[derive(Debug, Clone)]
334pub struct GarbledGate {
335 pub table: [[u64; 2]; 2],
337 pub labels_a: [u64; 2],
339 pub labels_b: [u64; 2],
341 pub labels_out: [u64; 2],
343}
344impl GarbledGate {
345 pub fn garble_and(labels_a: [u64; 2], labels_b: [u64; 2], labels_out: [u64; 2]) -> Self {
348 let mut table = [[0u64; 2]; 2];
349 for a in 0usize..2 {
350 for b in 0usize..2 {
351 let out_bit = a & b;
352 table[a][b] = toy_encrypt(labels_a[a], labels_b[b], labels_out[out_bit]);
353 }
354 }
355 GarbledGate {
356 table,
357 labels_a,
358 labels_b,
359 labels_out,
360 }
361 }
362 pub fn garble_or(labels_a: [u64; 2], labels_b: [u64; 2], labels_out: [u64; 2]) -> Self {
364 let mut table = [[0u64; 2]; 2];
365 for a in 0usize..2 {
366 for b in 0usize..2 {
367 let out_bit = a | b;
368 table[a][b] = toy_encrypt(labels_a[a], labels_b[b], labels_out[out_bit]);
369 }
370 }
371 GarbledGate {
372 table,
373 labels_a,
374 labels_b,
375 labels_out,
376 }
377 }
378 pub fn evaluate(&self, label_a: u64, label_b: u64) -> Option<u64> {
380 for a in 0usize..2 {
381 for b in 0usize..2 {
382 if self.labels_a[a] == label_a && self.labels_b[b] == label_b {
383 let out = toy_encrypt(label_a, label_b, self.table[a][b]);
384 return Some(out);
385 }
386 }
387 }
388 None
389 }
390 pub fn is_output_one(&self, output_label: u64) -> bool {
392 output_label == self.labels_out[1]
393 }
394}
395#[derive(Debug, Clone)]
404pub struct PedersenParams {
405 pub p: u64,
407 pub q: u64,
409 pub g: u64,
411 pub h: u64,
413}
414impl PedersenParams {
415 pub fn commit(&self, m: u64, r: u64) -> u64 {
417 let gm = mod_exp(self.g, m % self.q, self.p);
418 let hr = mod_exp(self.h, r % self.q, self.p);
419 (gm as u128 * hr as u128 % self.p as u128) as u64
420 }
421 pub fn verify(&self, c: u64, m: u64, r: u64) -> bool {
423 self.commit(m, r) == c
424 }
425 pub fn add_commitments(&self, c1: u64, c2: u64) -> u64 {
427 (c1 as u128 * c2 as u128 % self.p as u128) as u64
428 }
429}
430#[derive(Debug, Clone)]
438pub struct MpcShare {
439 pub party: u8,
441 pub share: bool,
443}
444impl MpcShare {
445 pub fn xor_gate(a: &MpcShare, b: &MpcShare) -> MpcShare {
447 assert_eq!(a.party, b.party);
448 MpcShare {
449 party: a.party,
450 share: a.share ^ b.share,
451 }
452 }
453 pub fn reconstruct(s0: &MpcShare, s1: &MpcShare) -> bool {
455 s0.share ^ s1.share
456 }
457}
458#[allow(dead_code)]
459#[derive(Debug, Clone, PartialEq)]
460pub enum OTVariant {
461 OneOutOfTwo,
462 OneOutOfN(usize),
463 RandomOT,
464}
465#[allow(dead_code)]
467#[derive(Debug, Clone)]
468pub struct CommitmentScheme {
469 pub name: String,
470 pub is_perfectly_hiding: bool,
471 pub is_computationally_binding: bool,
472 pub is_homomorphic: bool,
473}
474#[allow(dead_code)]
475impl CommitmentScheme {
476 pub fn new(name: &str) -> Self {
477 CommitmentScheme {
478 name: name.to_string(),
479 is_perfectly_hiding: false,
480 is_computationally_binding: false,
481 is_homomorphic: false,
482 }
483 }
484 pub fn pedersen() -> Self {
485 CommitmentScheme {
486 name: "Pedersen".to_string(),
487 is_perfectly_hiding: true,
488 is_computationally_binding: true,
489 is_homomorphic: true,
490 }
491 }
492 pub fn sha256_hash() -> Self {
493 CommitmentScheme {
494 name: "SHA256-hash".to_string(),
495 is_perfectly_hiding: false,
496 is_computationally_binding: true,
497 is_homomorphic: false,
498 }
499 }
500 pub fn satisfies_binding_hiding_tradeoff(&self) -> bool {
501 !self.is_perfectly_hiding || !self.is_computationally_binding
502 }
503}
504#[allow(dead_code)]
506#[derive(Debug, Clone)]
507pub struct MPCProtocol {
508 pub name: String,
509 pub n_parties: usize,
510 pub threshold_corruption: usize,
511 pub security_model: MPCSecurityModel,
512}
513#[allow(dead_code)]
514impl MPCProtocol {
515 pub fn new(name: &str, n: usize, t: usize, model: MPCSecurityModel) -> Self {
516 MPCProtocol {
517 name: name.to_string(),
518 n_parties: n,
519 threshold_corruption: t,
520 security_model: model,
521 }
522 }
523 pub fn bgw(n: usize, t: usize) -> Self {
524 MPCProtocol::new("BGW", n, t, MPCSecurityModel::Malicious)
525 }
526 pub fn is_secure_against_majority_corruption(&self) -> bool {
527 self.threshold_corruption * 2 < self.n_parties
528 }
529 pub fn is_optimal_corruption_threshold(&self) -> bool {
530 match self.security_model {
531 MPCSecurityModel::Malicious => self.threshold_corruption * 3 < self.n_parties,
532 MPCSecurityModel::SemiHonest => self.threshold_corruption * 2 < self.n_parties,
533 MPCSecurityModel::Covert => self.threshold_corruption * 2 < self.n_parties,
534 }
535 }
536}
537#[allow(dead_code)]
539#[derive(Debug, Clone)]
540pub struct SecretSharing {
541 pub threshold: usize,
542 pub n_shares: usize,
543 pub field_size_bits: usize,
544}
545#[allow(dead_code)]
546impl SecretSharing {
547 pub fn new(t: usize, n: usize, field_bits: usize) -> Self {
548 assert!(t <= n);
549 SecretSharing {
550 threshold: t,
551 n_shares: n,
552 field_size_bits: field_bits,
553 }
554 }
555 pub fn shamir_2_of_3() -> Self {
556 SecretSharing::new(2, 3, 256)
557 }
558 pub fn is_perfect(&self) -> bool {
559 true
560 }
561 pub fn min_shares_needed(&self) -> usize {
562 self.threshold
563 }
564 pub fn share_size_bits(&self) -> usize {
565 self.field_size_bits
566 }
567}
568#[derive(Debug, Clone, PartialEq, Eq)]
570pub struct SchnorrTranscript {
571 pub commitment: u64,
573 pub challenge: u64,
575 pub response: u64,
577}
578#[derive(Debug, Clone)]
585pub struct PaillierHomomorphic {
586 pub n: u64,
588 pub n_sq: u128,
590 pub g: u64,
592 pub lambda: u64,
594 pub mu: u64,
596}
597impl PaillierHomomorphic {
598 pub fn encrypt(&self, m: u64, r: u64) -> u128 {
601 let n_sq = self.n_sq;
602 let gm = {
603 let base = (self.g as u128).pow(1) % n_sq;
604 let mut result: u128 = 1;
605 let mut exp = m;
606 let mut b = self.g as u128 % n_sq;
607 while exp > 0 {
608 if exp & 1 == 1 {
609 result = result * b % n_sq;
610 }
611 exp >>= 1;
612 b = b * b % n_sq;
613 }
614 let _ = base;
615 result
616 };
617 let rn = {
618 let mut result: u128 = 1;
619 let mut exp = self.n;
620 let mut b = r as u128 % n_sq;
621 while exp > 0 {
622 if exp & 1 == 1 {
623 result = result * b % n_sq;
624 }
625 exp >>= 1;
626 b = b * b % n_sq;
627 }
628 result
629 };
630 gm * rn % n_sq
631 }
632 pub fn add_ciphertexts(&self, c1: u128, c2: u128) -> u128 {
634 c1 * c2 % self.n_sq
635 }
636 fn l_func(&self, x: u128) -> u64 {
638 ((x - 1) / self.n as u128) as u64
639 }
640 pub fn decrypt(&self, c: u128) -> u64 {
642 let n_sq = self.n_sq;
643 let mut result: u128 = 1;
644 let mut exp = self.lambda;
645 let mut b = c % n_sq;
646 while exp > 0 {
647 if exp & 1 == 1 {
648 result = result * b % n_sq;
649 }
650 exp >>= 1;
651 b = b * b % n_sq;
652 }
653 let lval = self.l_func(result);
654 (lval as u128 * self.mu as u128 % self.n as u128) as u64
655 }
656}
657#[derive(Debug, Clone)]
669pub struct BlindSignatureScheme {
670 pub n: u64,
672 pub e: u64,
674 pub d: u64,
676}
677impl BlindSignatureScheme {
678 pub fn blind(&self, m: u64, r: u64) -> u64 {
680 let re = mod_exp(r, self.e, self.n);
681 (re as u128 * m as u128 % self.n as u128) as u64
682 }
683 pub fn sign_blinded(&self, blinded: u64) -> u64 {
685 mod_exp(blinded, self.d, self.n)
686 }
687 pub fn unblind(&self, s_prime: u64, r: u64) -> u64 {
689 let r_inv = mod_inv(r, self.n).unwrap_or(1);
690 (s_prime as u128 * r_inv as u128 % self.n as u128) as u64
691 }
692 pub fn verify(&self, m: u64, s: u64) -> bool {
694 mod_exp(s, self.e, self.n) == m % self.n
695 }
696}