1use num_bigint::{BigInt, BigUint, ToBigInt};
12use num_integer::Integer;
13use num_traits::identities::{One, Zero};
14use sha2::{Digest, Sha256};
15use std::collections::{BTreeMap, HashMap};
16use std::sync::Arc;
17
18use crate::dleq::DLEQ;
19use crate::group::Group;
20use crate::groups::ModpGroup;
21use crate::polynomial::Polynomial;
22use crate::sharebox::{DistributionSharesBox, ShareBox};
23
24use crate::groups::Secp256k1Group;
27
28use k256::elliptic_curve::FieldBytes;
29
30use k256::elliptic_curve::ff::PrimeField;
31
32use k256::{AffinePoint, Scalar};
33
34use crate::groups::Ristretto255Group;
36
37use curve25519_dalek::ristretto::RistrettoPoint;
38
39use curve25519_dalek::scalar::Scalar as RistrettoScalar;
40
41#[derive(Debug)]
64pub struct Participant<G: Group> {
65 group: Arc<G>,
66 pub privatekey: G::Scalar,
67 pub publickey: G::Element,
68}
69
70impl<G: Group> Clone for Participant<G>
73where
74 G::Scalar: Clone,
75 G::Element: Clone,
76{
77 fn clone(&self) -> Self {
78 Participant {
79 group: Arc::clone(&self.group),
80 privatekey: self.privatekey.clone(),
81 publickey: self.publickey.clone(),
82 }
83 }
84}
85
86impl<G: Group> Participant<G> {
87 pub fn with_arc(group: Arc<G>) -> Self
99 where
100 G::Scalar: Default,
101 G::Element: Default,
102 {
103 Participant {
104 group,
105 privatekey: Default::default(),
106 publickey: Default::default(),
107 }
108 }
109
110 pub fn new(group: G) -> Self
127 where
128 G::Scalar: Default,
129 G::Element: Default,
130 {
131 Participant {
132 group: Arc::new(group),
133 privatekey: Default::default(),
134 publickey: Default::default(),
135 }
136 }
137
138 pub fn initialize(&mut self)
140 where
141 G::Scalar: Default,
142 G::Element: Default,
143 {
144 self.privatekey = self.group.generate_private_key();
145 self.publickey = self.group.generate_public_key(&self.privatekey);
146 }
147}
148
149impl Participant<ModpGroup> {
159 pub fn distribute_secret(
161 &mut self,
162 secret: &BigInt,
163 publickeys: &[BigInt],
164 threshold: u32,
165 ) -> DistributionSharesBox<ModpGroup> {
166 assert!(threshold <= publickeys.len() as u32);
167
168 let subgroup_gen = self.group.subgroup_generator();
170 let main_gen = self.group.generator();
171 let group_order = self.group.order();
172
173 let mut polynomial = Polynomial::new();
175 polynomial.init((threshold - 1) as i32, group_order);
176
177 let w = self.group.generate_private_key();
179
180 let mut commitments: Vec<BigInt> = Vec::new();
182 let mut positions: HashMap<Vec<u8>, i64> = HashMap::new();
183 let mut x: HashMap<Vec<u8>, BigInt> = HashMap::new();
184 let mut shares: HashMap<Vec<u8>, BigInt> = HashMap::new();
185 let mut challenge_hasher = Sha256::new();
186
187 let mut sampling_points: HashMap<Vec<u8>, BigInt> = HashMap::new();
188 let mut dleq_w: HashMap<Vec<u8>, BigInt> = HashMap::new();
189 let mut position: i64 = 1;
190
191 for j in 0..threshold {
193 let coeff = &polynomial.coefficients[j as usize];
194 let commitment = self.group.exp(&subgroup_gen, coeff);
195 commitments.push(commitment);
196 }
197
198 for pubkey in publickeys {
200 let pubkey_bytes = self.group.element_to_bytes(pubkey);
201 positions.insert(pubkey_bytes.clone(), position);
202
203 let pos_scalar = &BigInt::from(position);
205 let secret_share = polynomial.get_value(pos_scalar) % group_order;
206 sampling_points.insert(pubkey_bytes.clone(), secret_share.clone());
207
208 let mut x_val = self.group.identity();
211 let mut exponent = BigInt::one();
212 for j in 0..threshold {
213 let c_j_pow =
214 self.group.exp(&commitments[j as usize], &exponent);
215 x_val = self.group.mul(&x_val, &c_j_pow);
216 exponent =
217 self.group.scalar_mul(&exponent, pos_scalar) % group_order;
218 }
219 x.insert(pubkey_bytes.clone(), x_val.clone());
220
221 let encrypted_secret_share = self.group.exp(pubkey, &secret_share);
223 shares.insert(pubkey_bytes.clone(), encrypted_secret_share.clone());
224
225 let mut dleq = DLEQ::new(self.group.clone());
227 dleq.init(
228 subgroup_gen.clone(),
229 x_val.clone(),
230 pubkey.clone(),
231 encrypted_secret_share.clone(),
232 secret_share.clone(),
233 w.clone(),
234 );
235 dleq_w.insert(pubkey_bytes.clone(), w.clone());
236
237 let a1 = dleq.get_a1();
239 let a2 = dleq.get_a2();
240 challenge_hasher.update(
241 x_val.to_biguint().unwrap().to_str_radix(10).as_bytes(),
242 );
243 challenge_hasher.update(
244 encrypted_secret_share
245 .to_biguint()
246 .unwrap()
247 .to_str_radix(10)
248 .as_bytes(),
249 );
250 challenge_hasher
251 .update(a1.to_biguint().unwrap().to_str_radix(10).as_bytes());
252 challenge_hasher
253 .update(a2.to_biguint().unwrap().to_str_radix(10).as_bytes());
254
255 position += 1;
256 }
257
258 let challenge_hash = challenge_hasher.finalize();
260 let challenge = self.group.hash_to_scalar(&challenge_hash);
261
262 let mut responses: HashMap<Vec<u8>, BigInt> = HashMap::new();
264 for pubkey in publickeys {
265 let pubkey_bytes = self.group.element_to_bytes(pubkey);
266 let alpha = sampling_points.get(&pubkey_bytes).unwrap();
267 let w_i = dleq_w.get(&pubkey_bytes).unwrap();
268 let alpha_c =
269 self.group.scalar_mul(alpha, &challenge) % group_order;
270 let response = self.group.scalar_sub(w_i, &alpha_c) % group_order;
271 responses.insert(pubkey_bytes, response);
272 }
273
274 let s = polynomial.get_value(&BigInt::zero()) % group_order;
276 let g_s = self.group.exp(&main_gen, &s);
277 let sha256_hash = Sha256::digest(
278 g_s.to_biguint().unwrap().to_str_radix(10).as_bytes(),
279 );
280 let hash_biguint = BigUint::from_bytes_be(&sha256_hash[..])
281 .mod_floor(&self.group.modulus().to_biguint().unwrap());
282 let u = secret.to_biguint().unwrap() ^ hash_biguint;
283
284 let mut shares_box = DistributionSharesBox::new();
286 shares_box.init(
287 &commitments,
288 positions,
289 shares,
290 publickeys,
291 &challenge,
292 responses,
293 &u.to_bigint().unwrap(),
294 );
295 shares_box
296 }
297
298 pub fn extract_secret_share(
305 &self,
306 shares_box: &DistributionSharesBox<ModpGroup>,
307 private_key: &BigInt,
308 w: &BigInt,
309 ) -> Option<ShareBox<ModpGroup>> {
310 use crate::util::Util;
311
312 let main_gen = self.group.generator();
313 let group_order = self.group.order();
314
315 let public_key = self.group.generate_public_key(private_key);
317
318 let pubkey_bytes = self.group.element_to_bytes(&public_key);
320 let encrypted_secret_share = shares_box.shares.get(&pubkey_bytes)?;
321
322 let privkey_inverse = Util::mod_inverse(private_key, group_order)?;
325 let decrypted_share =
326 self.group.exp(encrypted_secret_share, &privkey_inverse);
327
328 let mut dleq = DLEQ::new(self.group.clone());
330 dleq.init(
331 main_gen.clone(),
332 public_key.clone(),
333 decrypted_share.clone(),
334 encrypted_secret_share.clone(),
335 private_key.clone(),
336 w.clone(),
337 );
338
339 let mut challenge_hasher = Sha256::new();
341 challenge_hasher.update(
342 public_key.to_biguint().unwrap().to_str_radix(10).as_bytes(),
343 );
344 challenge_hasher.update(
345 encrypted_secret_share
346 .to_biguint()
347 .unwrap()
348 .to_str_radix(10)
349 .as_bytes(),
350 );
351
352 let a1 = dleq.get_a1();
353 let a2 = dleq.get_a2();
354 challenge_hasher
355 .update(a1.to_biguint().unwrap().to_str_radix(10).as_bytes());
356 challenge_hasher
357 .update(a2.to_biguint().unwrap().to_str_radix(10).as_bytes());
358
359 let challenge_hash = challenge_hasher.finalize();
360 let challenge = self.group.hash_to_scalar(&challenge_hash);
361 dleq.c = Some(challenge.clone());
362
363 let response = dleq.get_r()?;
365
366 let mut share_box = ShareBox::new();
368 share_box.init(public_key, decrypted_share, challenge, response);
369 Some(share_box)
370 }
371
372 pub fn verify_share(
379 &self,
380 sharebox: &ShareBox<ModpGroup>,
381 distribution_sharebox: &DistributionSharesBox<ModpGroup>,
382 publickey: &BigInt,
383 ) -> bool {
384 let main_gen = self.group.generator();
385
386 let pubkey_bytes = self.group.element_to_bytes(publickey);
388 let encrypted_share =
389 match distribution_sharebox.shares.get(&pubkey_bytes) {
390 Some(s) => s,
391 None => return false,
392 };
393
394 let g1_r = self.group.exp(&main_gen, &sharebox.response);
397 let h1_c = self.group.exp(publickey, &sharebox.challenge);
398 let a1_verify = self.group.mul(&g1_r, &h1_c);
399
400 let g2_r = self.group.exp(&sharebox.share, &sharebox.response);
401 let h2_c = self.group.exp(encrypted_share, &sharebox.challenge);
402 let a2_verify = self.group.mul(&g2_r, &h2_c);
403
404 let mut challenge_hasher = Sha256::new();
406 challenge_hasher.update(
407 publickey.to_biguint().unwrap().to_str_radix(10).as_bytes(),
408 );
409 challenge_hasher.update(
410 encrypted_share
411 .to_biguint()
412 .unwrap()
413 .to_str_radix(10)
414 .as_bytes(),
415 );
416 challenge_hasher.update(
417 a1_verify.to_biguint().unwrap().to_str_radix(10).as_bytes(),
418 );
419 challenge_hasher.update(
420 a2_verify.to_biguint().unwrap().to_str_radix(10).as_bytes(),
421 );
422
423 let challenge_hash = challenge_hasher.finalize();
424 let challenge_computed = self.group.hash_to_scalar(&challenge_hash);
425
426 challenge_computed == sharebox.challenge
427 }
428
429 pub fn verify_distribution_shares(
441 &self,
442 distribute_sharesbox: &DistributionSharesBox<ModpGroup>,
443 ) -> bool {
444 let subgroup_gen = self.group.subgroup_generator();
445 let group_order = self.group.order();
446 let mut challenge_hasher = Sha256::new();
447
448 for publickey in &distribute_sharesbox.publickeys {
450 let pubkey_bytes = self.group.element_to_bytes(publickey);
451 let position = distribute_sharesbox.positions.get(&pubkey_bytes);
452 let response = distribute_sharesbox.responses.get(&pubkey_bytes);
453 let encrypted_share =
454 distribute_sharesbox.shares.get(&pubkey_bytes);
455
456 if position.is_none()
457 || response.is_none()
458 || encrypted_share.is_none()
459 {
460 return false;
461 }
462
463 let mut x_val = self.group.identity();
465 let mut exponent = BigInt::one();
466 for j in 0..distribute_sharesbox.commitments.len() {
467 let c_j_pow = self
468 .group
469 .exp(&distribute_sharesbox.commitments[j], &exponent);
470 x_val = self.group.mul(&x_val, &c_j_pow);
471 exponent = self
472 .group
473 .scalar_mul(&exponent, &BigInt::from(*position.unwrap()))
474 % group_order;
475 }
476
477 let g_r = self.group.exp(&subgroup_gen, response.unwrap());
481 let x_c = self.group.exp(&x_val, &distribute_sharesbox.challenge);
482 let a1 = self.group.mul(&g_r, &x_c);
483
484 let y_r = self.group.exp(publickey, response.unwrap());
485 let y_c = self
486 .group
487 .exp(encrypted_share.unwrap(), &distribute_sharesbox.challenge);
488 let a2 = self.group.mul(&y_r, &y_c);
489
490 challenge_hasher.update(
492 x_val.to_biguint().unwrap().to_str_radix(10).as_bytes(),
493 );
494 challenge_hasher.update(
495 encrypted_share
496 .unwrap()
497 .to_biguint()
498 .unwrap()
499 .to_str_radix(10)
500 .as_bytes(),
501 );
502 challenge_hasher
503 .update(a1.to_biguint().unwrap().to_str_radix(10).as_bytes());
504 challenge_hasher
505 .update(a2.to_biguint().unwrap().to_str_radix(10).as_bytes());
506 }
507
508 let challenge_hash = challenge_hasher.finalize();
510 let computed_challenge = self.group.hash_to_scalar(&challenge_hash);
511
512 computed_challenge == distribute_sharesbox.challenge
513 }
514
515 pub fn reconstruct(
521 &self,
522 share_boxes: &[ShareBox<ModpGroup>],
523 distribute_share_box: &DistributionSharesBox<ModpGroup>,
524 ) -> Option<BigInt> {
525 use rayon::prelude::*;
526
527 if share_boxes.len() < distribute_share_box.commitments.len() {
528 return None;
529 }
530
531 let group_modulus = self.group.modulus();
532
533 let mut shares: BTreeMap<i64, BigInt> = BTreeMap::new();
535 for share_box in share_boxes.iter() {
536 let pubkey_bytes =
537 self.group.element_to_bytes(&share_box.publickey);
538 let position = distribute_share_box.positions.get(&pubkey_bytes)?;
539 shares.insert(*position, share_box.share.clone());
540 }
541
542 let mut secret = self.group.identity();
544 let values: Vec<i64> = shares.keys().copied().collect();
545 let shares_vec: Vec<(i64, BigInt)> = shares.into_iter().collect();
546 let shares_slice = shares_vec.as_slice();
547
548 let factors: Vec<BigInt> = shares_slice
549 .par_iter()
550 .map(|(position, share)| {
551 self.compute_lagrange_factor(
552 *position,
553 share,
554 &values,
555 group_modulus,
556 )
557 })
558 .collect();
559
560 secret = factors
562 .into_iter()
563 .fold(secret, |acc, factor| self.group.mul(&acc, &factor));
564
565 let secret_hash = Sha256::digest(
567 secret.to_biguint().unwrap().to_str_radix(10).as_bytes(),
568 );
569 let hash_biguint = BigUint::from_bytes_be(&secret_hash[..])
570 .mod_floor(&self.group.modulus().to_biguint().unwrap());
571 let decrypted_secret =
572 hash_biguint ^ distribute_share_box.U.to_biguint().unwrap();
573
574 Some(decrypted_secret.to_bigint().unwrap())
575 }
576
577 fn compute_lagrange_factor(
583 &self,
584 position: i64,
585 share: &BigInt,
586 values: &[i64],
587 group_modulus: &BigInt,
588 ) -> BigInt {
589 use crate::util::Util;
590
591 let lagrange_coefficient =
592 Util::lagrange_coefficient(&position, values);
593
594 let exponent = if lagrange_coefficient.1 == BigInt::from(1) {
596 lagrange_coefficient.0.clone() / Util::abs(&lagrange_coefficient.1)
598 } else {
599 let mut numerator = lagrange_coefficient.0.to_biguint().unwrap();
601 let mut denominator =
602 Util::abs(&lagrange_coefficient.1).to_biguint().unwrap();
603 let gcd = numerator.gcd(&denominator);
604 numerator /= &gcd;
605 denominator /= &gcd;
606
607 let group_order_minus_1 = group_modulus - BigInt::one();
608 let inverse_denominator = Util::mod_inverse(
609 &denominator.to_bigint().unwrap(),
610 &group_order_minus_1,
611 );
612
613 match inverse_denominator {
614 Some(inv) => {
615 (numerator.to_bigint().unwrap() * inv) % group_order_minus_1
616 }
617 None => {
618 BigInt::one()
621 }
622 }
623 };
624
625 let mut factor = self.group.exp(share, &exponent);
627
628 if lagrange_coefficient.0.clone() * lagrange_coefficient.1
630 < BigInt::zero()
631 && let Some(inverse_factor) = self.group.element_inverse(&factor)
632 {
633 factor = inverse_factor;
634 }
635
636 factor
637 }
638}
639
640pub type ModpParticipant = Participant<ModpGroup>;
643
644#[cfg(test)]
645mod tests {
646 use super::*;
647 use crate::groups::ModpGroup;
648 use crate::participant::Participant;
649 use num_bigint::RandBigInt;
650
651 #[test]
652 fn test_generic_modp_participant_new() {
653 let group = ModpGroup::new();
654 let participant = Participant::with_arc(group);
655 assert_eq!(participant.publickey, Default::default());
656 }
657
658 #[test]
659 fn test_generic_modp_participant_initialize() {
660 let group = ModpGroup::new();
661 let mut participant = Participant::with_arc(group);
662 participant.initialize();
663 let _ = &participant.privatekey;
664 let _ = &participant.publickey;
665 }
666
667 #[test]
669 fn test_end_to_end_modp() {
670 use num_bigint::{BigUint, ToBigInt};
671
672 let group = ModpGroup::new();
674 let mut dealer = Participant::with_arc(group.clone());
675 dealer.initialize();
676
677 let mut p1 = Participant::with_arc(group.clone());
678 let mut p2 = Participant::with_arc(group.clone());
679 let mut p3 = Participant::with_arc(group.clone());
680 p1.initialize();
681 p2.initialize();
682 p3.initialize();
683
684 let secret_message = String::from("Hello MPVSS End-to-End Test!");
685 let secret = BigUint::from_bytes_be(secret_message.as_bytes());
686
687 let publickeys = vec![
688 p1.publickey.clone(),
689 p2.publickey.clone(),
690 p3.publickey.clone(),
691 ];
692 let threshold = 3;
693
694 let dist_box = dealer.distribute_secret(
696 &secret.to_bigint().unwrap(),
697 &publickeys,
698 threshold,
699 );
700
701 let verified_by_p1 = dealer.verify_distribution_shares(&dist_box);
704 let verified_by_p2 = dealer.verify_distribution_shares(&dist_box);
705 let verified_by_p3 = dealer.verify_distribution_shares(&dist_box);
706 assert!(verified_by_p1, "P1 should verify distribution as valid");
707 assert!(verified_by_p2, "P2 should verify distribution as valid");
708 assert!(verified_by_p3, "P3 should verify distribution as valid");
709
710 assert_eq!(dist_box.publickeys.len(), 3, "Should have 3 public keys");
712 assert_eq!(dist_box.commitments.len(), 3, "Should have 3 commitments");
713 assert_eq!(dist_box.shares.len(), 3, "Should have 3 shares");
714 assert_ne!(dist_box.U, BigInt::zero(), "U should not be zero");
715
716 let mut rng = rand::thread_rng();
718 let w: BigInt = rng
719 .gen_biguint_below(&group.modulus().to_biguint().unwrap())
720 .to_bigint()
721 .unwrap();
722
723 let s1 = p1
725 .extract_secret_share(&dist_box, &p1.privatekey, &w)
726 .unwrap();
727 let s2 = p2
728 .extract_secret_share(&dist_box, &p2.privatekey, &w)
729 .unwrap();
730 let s3 = p3
731 .extract_secret_share(&dist_box, &p3.privatekey, &w)
732 .unwrap();
733
734 assert_eq!(s1.publickey, p1.publickey, "P1 publickey should match");
736 assert_ne!(s1.share, BigInt::zero(), "P1 share should not be zero");
737
738 assert_eq!(s2.publickey, p2.publickey, "P2 publickey should match");
739 assert_ne!(s2.share, BigInt::zero(), "P2 share should not be zero");
740
741 assert_eq!(s3.publickey, p3.publickey, "P3 publickey should match");
742 assert_ne!(s3.share, BigInt::zero(), "P3 share should not be zero");
743
744 let p1_verifies_s2 = dealer.verify_share(&s2, &dist_box, &p2.publickey);
747 let p1_verifies_s3 = dealer.verify_share(&s3, &dist_box, &p3.publickey);
748 assert!(p1_verifies_s2, "P1 should verify P2's share as valid");
749 assert!(p1_verifies_s3, "P1 should verify P3's share as valid");
750
751 let p2_verifies_s1 = dealer.verify_share(&s1, &dist_box, &p1.publickey);
752 let p2_verifies_s3 = dealer.verify_share(&s3, &dist_box, &p3.publickey);
753 assert!(p2_verifies_s1, "P2 should verify P1's share as valid");
754 assert!(p2_verifies_s3, "P2 should verify P3's share as valid");
755
756 let p3_verifies_s1 = dealer.verify_share(&s1, &dist_box, &p1.publickey);
757 let p3_verifies_s2 = dealer.verify_share(&s2, &dist_box, &p2.publickey);
758 assert!(p3_verifies_s1, "P3 should verify P1's share as valid");
759 assert!(p3_verifies_s2, "P3 should verify P2's share as valid");
760
761 let shares = vec![s1, s2, s3];
763 let reconstructed = dealer.reconstruct(&shares, &dist_box).unwrap();
764
765 let reconstructed_message = String::from_utf8(
767 reconstructed.to_biguint().unwrap().to_bytes_be(),
768 )
769 .unwrap();
770 assert_eq!(
771 reconstructed_message, secret_message,
772 "Reconstructed message should match original"
773 );
774 }
775
776 #[test]
783 fn test_end_to_end_secp256k1() {
784 use num_bigint::{BigUint, ToBigInt};
785
786 let group = Secp256k1Group::new();
788 let mut dealer = Participant::with_arc(group.clone());
789 dealer.initialize();
790
791 let mut p1 = Participant::with_arc(group.clone());
792 let mut p2 = Participant::with_arc(group.clone());
793 let mut p3 = Participant::with_arc(group.clone());
794 p1.initialize();
795 p2.initialize();
796 p3.initialize();
797
798 let secret_message = String::from("Hello secp256k1 PVSS!");
799 let secret = BigUint::from_bytes_be(secret_message.as_bytes());
800
801 let publickeys: Vec<k256::AffinePoint> = vec![
802 p1.publickey.clone(),
803 p2.publickey.clone(),
804 p3.publickey.clone(),
805 ];
806 let threshold = 3;
807
808 let dist_box = dealer.distribute_secret(
810 &secret.to_bigint().unwrap(),
811 &publickeys,
812 threshold,
813 );
814
815 assert!(
817 dealer.verify_distribution_shares(&dist_box),
818 "Distribution should be valid"
819 );
820
821 let w = group.generate_private_key();
823
824 let s1 = p1
826 .extract_secret_share(&dist_box, &p1.privatekey, &w)
827 .unwrap();
828 let s2 = p2
829 .extract_secret_share(&dist_box, &p2.privatekey, &w)
830 .unwrap();
831 let s3 = p3
832 .extract_secret_share(&dist_box, &p3.privatekey, &w)
833 .unwrap();
834
835 assert!(
837 dealer.verify_share(&s1, &dist_box, &p1.publickey),
838 "P1's share should be valid"
839 );
840 assert!(
841 dealer.verify_share(&s3, &dist_box, &p3.publickey),
842 "P3's share should be valid"
843 );
844
845 let shares = vec![s1, s2, s3];
847 let reconstructed = dealer.reconstruct(&shares, &dist_box).unwrap();
848
849 let reconstructed_message = String::from_utf8(
851 reconstructed.to_biguint().unwrap().to_bytes_be(),
852 )
853 .unwrap();
854 assert_eq!(
855 reconstructed_message, secret_message,
856 "Reconstructed message should match original"
857 );
858 }
859
860 #[test]
863 fn test_threshold_secp256k1() {
864 use num_bigint::{BigUint, ToBigInt};
865
866 let group = Secp256k1Group::new();
868 let mut dealer = Participant::with_arc(group.clone());
869 dealer.initialize();
870
871 let mut p1 = Participant::with_arc(group.clone());
872 let mut p2 = Participant::with_arc(group.clone());
873 let mut p3 = Participant::with_arc(group.clone());
874 let mut p4 = Participant::with_arc(group.clone());
875 let mut p5 = Participant::with_arc(group.clone());
876 p1.initialize();
877 p2.initialize();
878 p3.initialize();
879 p4.initialize();
880 p5.initialize();
881
882 let secret_message = String::from("Threshold test secp256k1!");
883 let secret = BigUint::from_bytes_be(secret_message.as_bytes());
884
885 let publickeys: Vec<k256::AffinePoint> = vec![
886 p1.publickey.clone(),
887 p2.publickey.clone(),
888 p3.publickey.clone(),
889 p4.publickey.clone(),
890 p5.publickey.clone(),
891 ];
892 let threshold = 3;
893
894 let dist_box = dealer.distribute_secret(
896 &secret.to_bigint().unwrap(),
897 &publickeys,
898 threshold,
899 );
900
901 assert!(
903 dealer.verify_distribution_shares(&dist_box),
904 "Distribution should be valid"
905 );
906
907 let w = group.generate_private_key();
909
910 let s1 = p1
912 .extract_secret_share(&dist_box, &p1.privatekey, &w)
913 .unwrap();
914 let s3 = p3
915 .extract_secret_share(&dist_box, &p3.privatekey, &w)
916 .unwrap();
917 let s5 = p5
918 .extract_secret_share(&dist_box, &p5.privatekey, &w)
919 .unwrap();
920
921 let shares = vec![s1, s3, s5];
923 let reconstructed = dealer.reconstruct(&shares, &dist_box).unwrap();
924
925 let reconstructed_message = String::from_utf8(
927 reconstructed.to_biguint().unwrap().to_bytes_be(),
928 )
929 .unwrap();
930 assert_eq!(
931 reconstructed_message, secret_message,
932 "Reconstructed message should match original"
933 );
934 }
935
936 #[test]
939 fn test_scalar_arithmetic_secp256k1() {
940 use num_bigint::BigInt;
941
942 let group = Secp256k1Group::new();
943
944 let a_bigint = BigInt::from(5u32);
946 let b_bigint = BigInt::from(7u32);
947 let s_bigint = &a_bigint + &b_bigint; let a = Scalar::from_repr({
951 let mut fb = FieldBytes::<k256::Secp256k1>::default();
952 let b = a_bigint.to_bytes_be().1;
953 if b.len() < 32 {
954 fb[32 - b.len()..].copy_from_slice(&b);
955 } else {
956 fb.copy_from_slice(&b[..32]);
957 }
958 fb.into()
959 })
960 .unwrap();
961
962 let b = Scalar::from_repr({
963 let mut fb = FieldBytes::<k256::Secp256k1>::default();
964 let b = b_bigint.to_bytes_be().1;
965 if b.len() < 32 {
966 fb[32 - b.len()..].copy_from_slice(&b);
967 } else {
968 fb.copy_from_slice(&b[..32]);
969 }
970 fb.into()
971 })
972 .unwrap();
973
974 let s = Scalar::from_repr({
975 let mut fb = FieldBytes::<k256::Secp256k1>::default();
976 let b = s_bigint.to_bytes_be().1;
977 if b.len() < 32 {
978 fb[32 - b.len()..].copy_from_slice(&b);
979 } else {
980 fb.copy_from_slice(&b[..32]);
981 }
982 fb.into()
983 })
984 .unwrap();
985
986 let g = group.generator();
988
989 let a_times_g = group.exp(&g, &a);
990 let b_times_g = group.exp(&g, &b);
991 let s_times_g = group.exp(&g, &s);
992
993 let sum_ab_g = group.mul(&a_times_g, &b_times_g);
994
995 assert_eq!(
996 sum_ab_g, s_times_g,
997 "Scalar arithmetic: (a+b)*g should equal a*g + b*g"
998 );
999 }
1000
1001 #[test]
1004 fn test_dleq_basic_secp256k1() {
1005 let group = Secp256k1Group::new();
1006 let mut dealer = Participant::with_arc(group.clone());
1007 dealer.initialize();
1008
1009 let alpha = group.generate_private_key();
1011 let w = group.generate_private_key();
1012
1013 let g1 = group.generator();
1015 let h1 = group.exp(&g1, &alpha);
1016
1017 let mut p2 = Participant::with_arc(group.clone());
1019 p2.initialize();
1020 let g2 = p2.publickey;
1021 let h2 = group.exp(&g2, &alpha);
1022
1023 let mut dleq = DLEQ::new(group.clone());
1025 dleq.init(g1, h1, g2, h2, alpha, w);
1026
1027 let a1 = dleq.get_a1();
1029 let a2 = dleq.get_a2();
1030
1031 use sha2::{Digest, Sha256};
1033 let mut hasher = Sha256::new();
1034 hasher.update(group.element_to_bytes(&h1));
1035 hasher.update(group.element_to_bytes(&h2));
1036 hasher.update(group.element_to_bytes(&a1));
1037 hasher.update(group.element_to_bytes(&a2));
1038 let hash = hasher.finalize();
1039 let challenge = group.hash_to_scalar(&hash);
1040
1041 dleq.c = Some(challenge.clone());
1042 let response = dleq.get_r().unwrap();
1043 dleq.r = Some(response);
1044
1045 assert!(dleq.verify(), "Basic DLEQ proof should verify");
1047 }
1048
1049 #[test]
1052 fn test_dleq_proofs_secp256k1() {
1053 use num_bigint::{BigUint, ToBigInt};
1054
1055 let group = Secp256k1Group::new();
1056 let mut dealer = Participant::with_arc(group.clone());
1057 dealer.initialize();
1058
1059 let mut p1 = Participant::with_arc(group.clone());
1060 let mut p2 = Participant::with_arc(group.clone());
1061 p1.initialize();
1062 p2.initialize();
1063
1064 let secret = BigUint::from_bytes_be(b"DLEQ test secp256k1");
1065
1066 let publickeys: Vec<k256::AffinePoint> =
1067 vec![p1.publickey.clone(), p2.publickey.clone()];
1068 let threshold = 2;
1069
1070 let dist_box = dealer.distribute_secret(
1072 &secret.to_bigint().unwrap(),
1073 &publickeys,
1074 threshold,
1075 );
1076
1077 assert!(
1079 dealer.verify_distribution_shares(&dist_box),
1080 "Distribution DLEQ proofs should be valid"
1081 );
1082
1083 let w = group.generate_private_key();
1085
1086 let s1 = p1
1088 .extract_secret_share(&dist_box, &p1.privatekey, &w)
1089 .unwrap();
1090 let s2 = p2
1091 .extract_secret_share(&dist_box, &p2.privatekey, &w)
1092 .unwrap();
1093
1094 assert!(
1096 dealer.verify_share(&s1, &dist_box, &p1.publickey),
1097 "P1's DLEQ proof should be valid"
1098 );
1099 assert!(
1100 dealer.verify_share(&s2, &dist_box, &p2.publickey),
1101 "P2's DLEQ proof should be valid"
1102 );
1103 }
1104}
1105
1106impl Participant<Secp256k1Group> {
1124 pub fn distribute_secret(
1133 &mut self,
1134 secret: &BigInt,
1135 publickeys: &[AffinePoint],
1136 threshold: u32,
1137 ) -> DistributionSharesBox<Secp256k1Group> {
1138 assert!(threshold <= publickeys.len() as u32);
1139
1140 let subgroup_gen = self.group.subgroup_generator();
1142 let main_gen = self.group.generator();
1143 let _group_order = self.group.order(); let mut polynomial = Polynomial::new();
1147 let group_order_bigint = self.group.order_as_bigint().clone();
1151 polynomial.init((threshold - 1) as i32, &group_order_bigint);
1152
1153 let w = self.group.generate_private_key();
1155
1156 let mut commitments: Vec<AffinePoint> = Vec::new();
1158 let mut positions: std::collections::HashMap<Vec<u8>, i64> =
1159 std::collections::HashMap::new();
1160 let mut shares: std::collections::HashMap<Vec<u8>, AffinePoint> =
1161 std::collections::HashMap::new();
1162 let mut challenge_hasher = Sha256::new();
1163
1164 let mut sampling_points: std::collections::HashMap<Vec<u8>, Scalar> =
1165 std::collections::HashMap::new();
1166 let mut dleq_w: std::collections::HashMap<Vec<u8>, Scalar> =
1167 std::collections::HashMap::new();
1168 let mut position: i64 = 1;
1169
1170 for j in 0..threshold {
1172 let coeff_bigint = &polynomial.coefficients[j as usize];
1173 let coeff_bytes = coeff_bigint.to_bytes_be().1;
1176 let mut field_bytes = FieldBytes::<k256::Secp256k1>::default();
1177 if coeff_bytes.len() < 32 {
1178 field_bytes[32 - coeff_bytes.len()..]
1180 .copy_from_slice(&coeff_bytes);
1181 } else {
1182 field_bytes.copy_from_slice(&coeff_bytes[..32]);
1183 }
1184 let coeff = Scalar::from_repr(field_bytes).unwrap();
1185 let commitment = self.group.exp(&subgroup_gen, &coeff);
1186 commitments.push(commitment);
1187 }
1188
1189 for pubkey in publickeys.iter() {
1191 let pubkey_bytes = self.group.element_to_bytes(pubkey);
1192 positions.insert(pubkey_bytes.clone(), position);
1193
1194 let pos_scalar = BigInt::from(position);
1196 let secret_share_bigint = polynomial.get_value(&pos_scalar);
1197 let secret_share_mod = &secret_share_bigint % &group_order_bigint;
1199 let secret_share_bytes = secret_share_mod.to_bytes_be().1;
1201 let mut field_bytes = FieldBytes::<k256::Secp256k1>::default();
1202 if secret_share_bytes.len() < 32 {
1203 field_bytes[32 - secret_share_bytes.len()..]
1205 .copy_from_slice(&secret_share_bytes);
1206 } else {
1207 field_bytes.copy_from_slice(&secret_share_bytes[..32]);
1208 }
1209 let secret_share = Scalar::from_repr(field_bytes).unwrap();
1210 sampling_points.insert(pubkey_bytes.clone(), secret_share);
1211 dleq_w.insert(pubkey_bytes.clone(), w);
1212
1213 let mut x_val = self.group.identity();
1215 let mut exponent = Scalar::ONE;
1216 for j in 0..threshold {
1217 let c_j_pow =
1219 self.group.exp(&commitments[j as usize], &exponent);
1220 x_val = self.group.mul(&x_val, &c_j_pow);
1221 let pos_scalar = Scalar::from(position as u64);
1223 exponent = self.group.scalar_mul(&exponent, &pos_scalar);
1224 }
1225
1226 let encrypted_secret_share = self.group.exp(pubkey, &secret_share);
1228 shares.insert(pubkey_bytes.clone(), encrypted_secret_share);
1229
1230 let mut dleq = DLEQ::new(self.group.clone());
1232 dleq.init(
1233 subgroup_gen,
1234 x_val,
1235 *pubkey,
1236 encrypted_secret_share,
1237 secret_share,
1238 w,
1239 );
1240
1241 let a1 = dleq.get_a1();
1243 let a2 = dleq.get_a2();
1244
1245 challenge_hasher.update(self.group.element_to_bytes(&x_val));
1246 challenge_hasher
1247 .update(self.group.element_to_bytes(&encrypted_secret_share));
1248 challenge_hasher.update(self.group.element_to_bytes(&a1));
1249 challenge_hasher.update(self.group.element_to_bytes(&a2));
1250
1251 position += 1;
1252 }
1253
1254 let challenge_hash = challenge_hasher.finalize();
1256 let challenge = self.group.hash_to_scalar(&challenge_hash);
1257
1258 let mut responses: std::collections::HashMap<Vec<u8>, Scalar> =
1260 std::collections::HashMap::new();
1261 for pubkey in publickeys {
1262 let pubkey_bytes = self.group.element_to_bytes(pubkey);
1263 let alpha = sampling_points.get(&pubkey_bytes).unwrap();
1264 let alpha_c = self.group.scalar_mul(alpha, &challenge);
1265 let w_i = dleq_w.get(&pubkey_bytes).unwrap();
1266 let response = self.group.scalar_sub(w_i, &alpha_c);
1267
1268 responses.insert(pubkey_bytes, response);
1269 }
1270
1271 let s_bigint = polynomial.get_value(&BigInt::zero());
1273 let s_bytes = s_bigint.to_bytes_be().1;
1274 let mut field_bytes = FieldBytes::<k256::Secp256k1>::default();
1275 if s_bytes.len() < 32 {
1276 field_bytes[32 - s_bytes.len()..].copy_from_slice(&s_bytes);
1277 } else {
1278 field_bytes.copy_from_slice(&s_bytes[s_bytes.len() - 32..]);
1279 }
1280 let s = Scalar::from_repr(field_bytes).unwrap();
1281 let g_s = self.group.exp(&main_gen, &s);
1282
1283 let sha256_hash = Sha256::digest(self.group.element_to_bytes(&g_s));
1285 let mut field_bytes2 = FieldBytes::<k256::Secp256k1>::default();
1287 let hash_len = sha256_hash.len().min(field_bytes2.len());
1288 field_bytes2[32 - hash_len..].copy_from_slice(&sha256_hash[..hash_len]);
1289 let hash_scalar = Scalar::from_repr(field_bytes2).unwrap();
1290 let hash_bytes = hash_scalar.to_bytes();
1291 let hash_biguint = BigUint::from_bytes_be(&hash_bytes);
1292 let curve_order_bigint = BigUint::from_bytes_be(
1295 &self.group.order_as_bigint().to_bytes_be().1,
1296 );
1297 let hash_reduced = hash_biguint % curve_order_bigint;
1298 let u = secret.to_biguint().unwrap() ^ hash_reduced;
1299
1300 let mut shares_box = DistributionSharesBox::new();
1302 shares_box.init(
1303 &commitments,
1304 positions,
1305 shares,
1306 publickeys,
1307 &challenge,
1308 responses,
1309 &u.to_bigint().unwrap(),
1310 );
1311 shares_box
1312 }
1313
1314 pub fn extract_secret_share(
1321 &self,
1322 shares_box: &DistributionSharesBox<Secp256k1Group>,
1323 private_key: &Scalar,
1324 w: &Scalar,
1325 ) -> Option<ShareBox<Secp256k1Group>> {
1326 let main_gen = self.group.generator();
1327
1328 let public_key = self.group.generate_public_key(private_key);
1330
1331 let public_key_bytes = self.group.element_to_bytes(&public_key);
1333 let encrypted_secret_share =
1334 shares_box.shares.get(&public_key_bytes)?;
1335
1336 let privkey_inverse = self.group.scalar_inverse(private_key)?;
1338 let decrypted_share =
1339 self.group.exp(encrypted_secret_share, &privkey_inverse);
1340
1341 let mut dleq = DLEQ::new(self.group.clone());
1343 dleq.init(
1344 main_gen,
1345 public_key,
1346 decrypted_share,
1347 *encrypted_secret_share,
1348 *private_key,
1349 *w,
1350 );
1351
1352 let mut challenge_hasher = Sha256::new();
1354 challenge_hasher.update(self.group.element_to_bytes(&public_key));
1355 challenge_hasher
1356 .update(self.group.element_to_bytes(encrypted_secret_share));
1357
1358 let a1 = dleq.get_a1();
1359 let a2 = dleq.get_a2();
1360 challenge_hasher.update(self.group.element_to_bytes(&a1));
1361 challenge_hasher.update(self.group.element_to_bytes(&a2));
1362
1363 let challenge_hash = challenge_hasher.finalize();
1364 let challenge = self.group.hash_to_scalar(&challenge_hash);
1365 dleq.c = Some(challenge);
1366
1367 let response = dleq.get_r()?;
1369
1370 let mut share_box = ShareBox::new();
1372 share_box.init(public_key, decrypted_share, challenge, response);
1373 Some(share_box)
1374 }
1375
1376 pub fn verify_share(
1383 &self,
1384 sharebox: &ShareBox<Secp256k1Group>,
1385 distribution_sharebox: &DistributionSharesBox<Secp256k1Group>,
1386 publickey: &AffinePoint,
1387 ) -> bool {
1388 let main_gen = self.group.generator();
1389
1390 let publickey_bytes = self.group.element_to_bytes(publickey);
1392 let encrypted_share =
1393 match distribution_sharebox.shares.get(&publickey_bytes) {
1394 Some(s) => s,
1395 None => return false,
1396 };
1397
1398 let g1_r = self.group.exp(&main_gen, &sharebox.response);
1401 let h1_c = self.group.exp(publickey, &sharebox.challenge);
1402 let a1_verify = self.group.mul(&g1_r, &h1_c);
1403
1404 let g2_r = self.group.exp(&sharebox.share, &sharebox.response);
1406 let h2_c = self.group.exp(encrypted_share, &sharebox.challenge);
1407 let a2_verify = self.group.mul(&g2_r, &h2_c);
1408
1409 let mut challenge_hasher = Sha256::new();
1411 challenge_hasher.update(self.group.element_to_bytes(publickey));
1412 challenge_hasher.update(self.group.element_to_bytes(encrypted_share));
1413 challenge_hasher.update(self.group.element_to_bytes(&a1_verify));
1414 challenge_hasher.update(self.group.element_to_bytes(&a2_verify));
1415
1416 let challenge_hash = challenge_hasher.finalize();
1417 let challenge_computed = self.group.hash_to_scalar(&challenge_hash);
1418
1419 challenge_computed == sharebox.challenge
1420 }
1421
1422 pub fn verify_distribution_shares(
1434 &self,
1435 distribute_sharesbox: &DistributionSharesBox<Secp256k1Group>,
1436 ) -> bool {
1437 let subgroup_gen = self.group.subgroup_generator();
1438 let mut challenge_hasher = Sha256::new();
1439
1440 for publickey in distribute_sharesbox.publickeys.iter() {
1442 let publickey_bytes = self.group.element_to_bytes(publickey);
1443 let position = distribute_sharesbox.positions.get(&publickey_bytes);
1444 let response = distribute_sharesbox.responses.get(&publickey_bytes);
1445 let encrypted_share =
1446 distribute_sharesbox.shares.get(&publickey_bytes);
1447
1448 if position.is_none()
1449 || response.is_none()
1450 || encrypted_share.is_none()
1451 {
1452 return false;
1453 }
1454
1455 let position = *position.unwrap();
1456 let response = response.unwrap();
1457 let encrypted_share = encrypted_share.unwrap();
1458
1459 let mut x_val = self.group.identity();
1461 let mut exponent = Scalar::ONE;
1462 for j in 0..distribute_sharesbox.commitments.len() {
1463 let c_j_pow = self
1465 .group
1466 .exp(&distribute_sharesbox.commitments[j], &exponent);
1467 x_val = self.group.mul(&x_val, &c_j_pow);
1468 let pos_scalar = Scalar::from(position as u64);
1469 exponent = self.group.scalar_mul(&exponent, &pos_scalar);
1470 }
1471
1472 let g_r = self.group.exp(&subgroup_gen, response);
1476 let x_c = self.group.exp(&x_val, &distribute_sharesbox.challenge);
1477 let a1 = self.group.mul(&g_r, &x_c);
1478
1479 let y_r = self.group.exp(publickey, response);
1480 let y_c = self
1481 .group
1482 .exp(encrypted_share, &distribute_sharesbox.challenge);
1483 let a2 = self.group.mul(&y_r, &y_c);
1484
1485 challenge_hasher.update(self.group.element_to_bytes(&x_val));
1487 challenge_hasher
1488 .update(self.group.element_to_bytes(encrypted_share));
1489 challenge_hasher.update(self.group.element_to_bytes(&a1));
1490 challenge_hasher.update(self.group.element_to_bytes(&a2));
1491 }
1492
1493 let challenge_hash = challenge_hasher.finalize();
1495 let computed_challenge = self.group.hash_to_scalar(&challenge_hash);
1496
1497 computed_challenge == distribute_sharesbox.challenge
1498 }
1499
1500 pub fn reconstruct(
1509 &self,
1510 share_boxes: &[ShareBox<Secp256k1Group>],
1511 distribute_share_box: &DistributionSharesBox<Secp256k1Group>,
1512 ) -> Option<BigInt> {
1513 use rayon::prelude::*;
1514
1515 if share_boxes.len() < distribute_share_box.commitments.len() {
1516 return None;
1517 }
1518
1519 let mut shares: std::collections::HashMap<i64, AffinePoint> =
1521 std::collections::HashMap::new();
1522 for share_box in share_boxes.iter() {
1523 let publickey_bytes =
1524 self.group.element_to_bytes(&share_box.publickey);
1525 let position =
1526 distribute_share_box.positions.get(&publickey_bytes)?;
1527 shares.insert(*position, share_box.share);
1528 }
1529
1530 let secret = self.group.identity();
1532 let values: Vec<i64> = shares.keys().copied().collect();
1533 let shares_vec: Vec<(i64, AffinePoint)> = shares.into_iter().collect();
1534 let shares_slice = shares_vec.as_slice();
1535
1536 let factors: Vec<AffinePoint> = shares_slice
1537 .par_iter()
1538 .map(|(position, share)| {
1539 self.compute_lagrange_factor_secp256k1(
1540 *position, share, &values,
1541 )
1542 })
1543 .collect();
1544
1545 let final_secret = factors
1547 .into_iter()
1548 .fold(secret, |acc, factor| self.group.mul(&acc, &factor));
1549
1550 let secret_hash =
1552 Sha256::digest(self.group.element_to_bytes(&final_secret));
1553 let mut field_bytes = FieldBytes::<k256::Secp256k1>::default();
1555 let hash_len = secret_hash.len().min(field_bytes.len());
1556 field_bytes[32 - hash_len..].copy_from_slice(&secret_hash[..hash_len]);
1557 let hash_scalar = Scalar::from_repr(field_bytes).unwrap();
1558 let hash_bytes = hash_scalar.to_bytes();
1559 let hash_biguint = BigUint::from_bytes_be(&hash_bytes);
1560 let scalar_bytes = self.group.order_as_bigint().to_bytes_be().1;
1563 let curve_order_bigint = BigUint::from_bytes_be(&scalar_bytes);
1564 let hash_reduced = hash_biguint % curve_order_bigint;
1565 let decrypted_secret =
1566 hash_reduced ^ distribute_share_box.U.to_biguint().unwrap();
1567
1568 Some(decrypted_secret.to_bigint().unwrap())
1569 }
1570
1571 fn compute_lagrange_factor_secp256k1(
1575 &self,
1576 position: i64,
1577 share: &AffinePoint,
1578 values: &[i64],
1579 ) -> AffinePoint {
1580 let mut lambda_num = Scalar::ONE;
1582 let mut lambda_den = Scalar::ONE;
1583 let mut sign = 1i64;
1584
1585 for &j in values {
1586 if j == position {
1587 continue;
1588 }
1589 lambda_num *= Scalar::from(j as u64);
1590 let diff = j - position;
1591 if diff < 0 {
1592 sign *= -1;
1593 lambda_den *= Scalar::from((-diff) as u64);
1594 } else {
1595 lambda_den *= Scalar::from(diff as u64);
1596 }
1597 }
1598
1599 let lambda = lambda_num * lambda_den.invert().unwrap();
1601
1602 let mut factor = self.group.exp(share, &lambda);
1604
1605 if sign < 0
1607 && let Some(negated) = self.group.element_inverse(&factor)
1608 {
1609 factor = negated;
1610 }
1611
1612 factor
1613 }
1614}
1615
1616impl Participant<Ristretto255Group> {
1621 pub fn distribute_secret(
1630 &mut self,
1631 secret: &BigInt,
1632 publickeys: &[RistrettoPoint],
1633 threshold: u32,
1634 ) -> DistributionSharesBox<Ristretto255Group> {
1635 assert!(threshold <= publickeys.len() as u32);
1636
1637 let subgroup_gen = self.group.subgroup_generator();
1639 let main_gen = self.group.generator();
1640 let _group_order = self.group.order(); let mut polynomial = Polynomial::new();
1644 let group_order_bigint = self.group.order_as_bigint().clone();
1645 polynomial.init((threshold - 1) as i32, &group_order_bigint);
1646
1647 let w = self.group.generate_private_key();
1649
1650 let mut commitments: Vec<RistrettoPoint> = Vec::new();
1652 let mut positions: HashMap<Vec<u8>, i64> = HashMap::new();
1653 let mut shares: HashMap<Vec<u8>, RistrettoPoint> = HashMap::new();
1654 let mut challenge_hasher = Sha256::new();
1655
1656 let mut sampling_points: HashMap<Vec<u8>, RistrettoScalar> =
1657 HashMap::new();
1658 let mut dleq_w: HashMap<Vec<u8>, RistrettoScalar> = HashMap::new();
1659 let mut position: i64 = 1;
1660
1661 for j in 0..threshold {
1663 let coeff_bigint = &polynomial.coefficients[j as usize];
1664 let coeff = Ristretto255Group::bigint_to_scalar(coeff_bigint);
1667 let commitment = self.group.exp(&subgroup_gen, &coeff);
1668 commitments.push(commitment);
1669 }
1670
1671 for pubkey in publickeys {
1673 let pubkey_bytes = self.group.element_to_bytes(pubkey);
1674 positions.insert(pubkey_bytes.clone(), position);
1675
1676 let pos_scalar = BigInt::from(position);
1678 let secret_share_bigint = polynomial.get_value(&pos_scalar);
1679 let secret_share_mod = &secret_share_bigint % &group_order_bigint;
1681 let secret_share =
1683 Ristretto255Group::bigint_to_scalar(&secret_share_mod);
1684 sampling_points.insert(pubkey_bytes.clone(), secret_share);
1685 dleq_w.insert(pubkey_bytes.clone(), w);
1686
1687 let mut x_val = self.group.identity();
1689 let mut exponent = RistrettoScalar::ONE;
1690
1691 for j in 0..threshold {
1692 let c_j_pow =
1694 self.group.exp(&commitments[j as usize], &exponent);
1695 x_val = self.group.mul(&x_val, &c_j_pow);
1696
1697 let pos_scalar = RistrettoScalar::from(position as u64);
1699 exponent = self.group.scalar_mul(&exponent, &pos_scalar);
1700 }
1701
1702 let encrypted_secret_share = self.group.exp(pubkey, &secret_share);
1704 shares.insert(pubkey_bytes.clone(), encrypted_secret_share);
1705
1706 let mut dleq = DLEQ::new(self.group.clone());
1708 dleq.init(
1709 subgroup_gen,
1710 x_val,
1711 *pubkey,
1712 encrypted_secret_share,
1713 secret_share,
1714 w,
1715 );
1716
1717 let a1 = dleq.get_a1();
1719 let a2 = dleq.get_a2();
1720
1721 challenge_hasher.update(self.group.element_to_bytes(&x_val));
1722 challenge_hasher
1723 .update(self.group.element_to_bytes(&encrypted_secret_share));
1724 challenge_hasher.update(self.group.element_to_bytes(&a1));
1725 challenge_hasher.update(self.group.element_to_bytes(&a2));
1726
1727 position += 1;
1728 }
1729
1730 let challenge_hash = challenge_hasher.finalize();
1732 let challenge = self.group.hash_to_scalar(&challenge_hash);
1733
1734 let mut responses: HashMap<Vec<u8>, RistrettoScalar> = HashMap::new();
1736 for pubkey in publickeys {
1737 let pubkey_bytes = self.group.element_to_bytes(pubkey);
1738 let alpha = sampling_points.get(&pubkey_bytes).unwrap();
1739 let alpha_c = self.group.scalar_mul(alpha, &challenge);
1740 let w_i = dleq_w.get(&pubkey_bytes).unwrap();
1741 let response = self.group.scalar_sub(w_i, &alpha_c);
1742
1743 responses.insert(pubkey_bytes, response);
1744 }
1745
1746 let s_bigint = polynomial.get_value(&BigInt::zero());
1748 let s = Ristretto255Group::bigint_to_scalar(&s_bigint);
1749 let g_s = self.group.exp(&main_gen, &s);
1750
1751 let sha256_hash = Sha256::digest(self.group.element_to_bytes(&g_s));
1753 let hash_biguint = BigUint::from_bytes_be(&sha256_hash[..]);
1755 let curve_order_bigint = BigUint::from_bytes_be(
1756 &self.group.order_as_bigint().to_bytes_be().1,
1757 );
1758 let hash_reduced = hash_biguint % curve_order_bigint;
1759 let u = secret.to_biguint().unwrap() ^ hash_reduced;
1760
1761 let mut shares_box = DistributionSharesBox::new();
1763 shares_box.init(
1764 &commitments,
1765 positions,
1766 shares,
1767 publickeys,
1768 &challenge,
1769 responses,
1770 &u.to_bigint().unwrap(),
1771 );
1772 shares_box
1773 }
1774
1775 pub fn extract_secret_share(
1782 &self,
1783 shares_box: &DistributionSharesBox<Ristretto255Group>,
1784 private_key: &RistrettoScalar,
1785 w: &RistrettoScalar,
1786 ) -> Option<ShareBox<Ristretto255Group>> {
1787 let main_gen = self.group.generator();
1788
1789 let public_key = self.group.generate_public_key(private_key);
1791
1792 let public_key_bytes = self.group.element_to_bytes(&public_key);
1794 let encrypted_secret_share =
1795 shares_box.shares.get(&public_key_bytes)?;
1796
1797 let privkey_inverse = self.group.scalar_inverse(private_key)?;
1799 let decrypted_share =
1800 self.group.exp(encrypted_secret_share, &privkey_inverse);
1801
1802 let mut dleq = DLEQ::new(self.group.clone());
1804 dleq.init(
1805 main_gen,
1806 public_key,
1807 decrypted_share,
1808 *encrypted_secret_share,
1809 *private_key,
1810 *w,
1811 );
1812
1813 let mut challenge_hasher = Sha256::new();
1815 challenge_hasher.update(self.group.element_to_bytes(&public_key));
1816 challenge_hasher
1817 .update(self.group.element_to_bytes(encrypted_secret_share));
1818
1819 let a1 = dleq.get_a1();
1820 let a2 = dleq.get_a2();
1821 challenge_hasher.update(self.group.element_to_bytes(&a1));
1822 challenge_hasher.update(self.group.element_to_bytes(&a2));
1823
1824 let challenge_hash = challenge_hasher.finalize();
1825 let challenge = self.group.hash_to_scalar(&challenge_hash);
1826 dleq.c = Some(challenge);
1827
1828 let response = dleq.get_r()?;
1830
1831 let mut share_box = ShareBox::new();
1833 share_box.init(public_key, decrypted_share, challenge, response);
1834 Some(share_box)
1835 }
1836
1837 pub fn verify_share(
1844 &self,
1845 sharebox: &ShareBox<Ristretto255Group>,
1846 distribution_sharebox: &DistributionSharesBox<Ristretto255Group>,
1847 publickey: &RistrettoPoint,
1848 ) -> bool {
1849 let main_gen = self.group.generator();
1850
1851 let publickey_bytes = self.group.element_to_bytes(publickey);
1853 let encrypted_share =
1854 match distribution_sharebox.shares.get(&publickey_bytes) {
1855 Some(s) => s,
1856 None => return false,
1857 };
1858
1859 let g1_r = self.group.exp(&main_gen, &sharebox.response);
1862 let h1_c = self.group.exp(publickey, &sharebox.challenge);
1863 let a1_verify = self.group.mul(&g1_r, &h1_c);
1864
1865 let g2_r = self.group.exp(&sharebox.share, &sharebox.response);
1867 let h2_c = self.group.exp(encrypted_share, &sharebox.challenge);
1868 let a2_verify = self.group.mul(&g2_r, &h2_c);
1869
1870 let mut challenge_hasher = Sha256::new();
1872 challenge_hasher.update(self.group.element_to_bytes(publickey));
1873 challenge_hasher.update(self.group.element_to_bytes(encrypted_share));
1874 challenge_hasher.update(self.group.element_to_bytes(&a1_verify));
1875 challenge_hasher.update(self.group.element_to_bytes(&a2_verify));
1876
1877 let challenge_hash = challenge_hasher.finalize();
1878 let challenge_computed = self.group.hash_to_scalar(&challenge_hash);
1879
1880 challenge_computed == sharebox.challenge
1881 }
1882
1883 pub fn verify_distribution_shares(
1895 &self,
1896 distribute_sharesbox: &DistributionSharesBox<Ristretto255Group>,
1897 ) -> bool {
1898 let subgroup_gen = self.group.subgroup_generator();
1899 let mut challenge_hasher = Sha256::new();
1900
1901 for publickey in &distribute_sharesbox.publickeys {
1903 let publickey_bytes = self.group.element_to_bytes(publickey);
1904 let position = distribute_sharesbox.positions.get(&publickey_bytes);
1905 let response = distribute_sharesbox.responses.get(&publickey_bytes);
1906 let encrypted_share =
1907 distribute_sharesbox.shares.get(&publickey_bytes);
1908
1909 if position.is_none()
1910 || response.is_none()
1911 || encrypted_share.is_none()
1912 {
1913 return false;
1914 }
1915
1916 let position = *position.unwrap();
1917 let response = response.unwrap();
1918 let encrypted_share = encrypted_share.unwrap();
1919
1920 let mut x_val = self.group.identity();
1922 let mut exponent = RistrettoScalar::ONE;
1923 for j in 0..distribute_sharesbox.commitments.len() {
1924 let c_j_pow = self
1926 .group
1927 .exp(&distribute_sharesbox.commitments[j], &exponent);
1928 x_val = self.group.mul(&x_val, &c_j_pow);
1929 let pos_scalar = RistrettoScalar::from(position as u64);
1930 exponent = self.group.scalar_mul(&exponent, &pos_scalar);
1931 }
1932
1933 let g_r = self.group.exp(&subgroup_gen, response);
1937 let x_c = self.group.exp(&x_val, &distribute_sharesbox.challenge);
1938 let a1 = self.group.mul(&g_r, &x_c);
1939
1940 let y_r = self.group.exp(publickey, response);
1941 let y_c = self
1942 .group
1943 .exp(encrypted_share, &distribute_sharesbox.challenge);
1944 let a2 = self.group.mul(&y_r, &y_c);
1945
1946 challenge_hasher.update(self.group.element_to_bytes(&x_val));
1948 challenge_hasher
1949 .update(self.group.element_to_bytes(encrypted_share));
1950 challenge_hasher.update(self.group.element_to_bytes(&a1));
1951 challenge_hasher.update(self.group.element_to_bytes(&a2));
1952 }
1953
1954 let challenge_hash = challenge_hasher.finalize();
1956 let computed_challenge = self.group.hash_to_scalar(&challenge_hash);
1957
1958 computed_challenge == distribute_sharesbox.challenge
1959 }
1960
1961 pub fn reconstruct(
1970 &self,
1971 share_boxes: &[ShareBox<Ristretto255Group>],
1972 distribute_share_box: &DistributionSharesBox<Ristretto255Group>,
1973 ) -> Option<BigInt> {
1974 use rayon::prelude::*;
1975
1976 if share_boxes.len() < distribute_share_box.commitments.len() {
1977 return None;
1978 }
1979
1980 let mut shares: HashMap<i64, RistrettoPoint> = HashMap::new();
1982 for share_box in share_boxes.iter() {
1983 let publickey_bytes =
1984 self.group.element_to_bytes(&share_box.publickey);
1985 let position =
1986 distribute_share_box.positions.get(&publickey_bytes)?;
1987 shares.insert(*position, share_box.share);
1988 }
1989
1990 let secret = self.group.identity();
1992 let values: Vec<i64> = shares.keys().copied().collect();
1993 let shares_vec: Vec<(i64, RistrettoPoint)> =
1994 shares.into_iter().collect();
1995 let shares_slice = shares_vec.as_slice();
1996
1997 let factors: Vec<RistrettoPoint> = shares_slice
1998 .par_iter()
1999 .map(|(position, share)| {
2000 self.compute_lagrange_factor_ristretto(
2001 *position, share, &values,
2002 )
2003 })
2004 .collect();
2005
2006 let final_secret = factors
2008 .into_iter()
2009 .fold(secret, |acc, factor| self.group.mul(&acc, &factor));
2010
2011 let secret_hash =
2013 Sha256::digest(self.group.element_to_bytes(&final_secret));
2014 let hash_biguint = BigUint::from_bytes_be(&secret_hash[..]);
2016 let curve_order_bigint = BigUint::from_bytes_be(
2017 &self.group.order_as_bigint().to_bytes_be().1,
2018 );
2019 let hash_reduced = hash_biguint % curve_order_bigint;
2020 let decrypted_secret =
2021 hash_reduced ^ distribute_share_box.U.to_biguint().unwrap();
2022
2023 Some(decrypted_secret.to_bigint().unwrap())
2024 }
2025
2026 fn compute_lagrange_factor_ristretto(
2030 &self,
2031 position: i64,
2032 share: &RistrettoPoint,
2033 values: &[i64],
2034 ) -> RistrettoPoint {
2035 let mut lambda_num = RistrettoScalar::ONE;
2037 let mut lambda_den = RistrettoScalar::ONE;
2038 let mut sign = 1i64;
2039
2040 for &j in values {
2041 if j == position {
2042 continue;
2043 }
2044 lambda_num *= RistrettoScalar::from(j as u64);
2045 let diff = j - position;
2046 if diff < 0 {
2047 sign *= -1;
2048 lambda_den *= RistrettoScalar::from((-diff) as u64);
2049 } else {
2050 lambda_den *= RistrettoScalar::from(diff as u64);
2051 }
2052 }
2053
2054 let lambda_den_inv = Option::from(lambda_den.invert());
2057 let lambda = match lambda_den_inv {
2058 Some(inv) => lambda_num * inv,
2059 None => {
2060 RistrettoScalar::ZERO
2062 }
2063 };
2064
2065 let mut factor = self.group.exp(share, &lambda);
2067
2068 if sign < 0
2070 && let Some(negated) = self.group.element_inverse(&factor)
2071 {
2072 factor = negated;
2073 }
2074
2075 factor
2076 }
2077}