main.rs 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! A simple implementation of Shamir Secret Sharing using the pallas base field
  19. use pasta_curves::{group::ff::Field, pallas};
  20. use rand::{prelude::SliceRandom, rngs::OsRng};
  21. #[derive(Copy, Clone, Debug)]
  22. struct ShamirPoint {
  23. pub x: pallas::Base,
  24. pub y: pallas::Base,
  25. }
  26. fn sss_share(secret: pallas::Base, n_shares: usize, threshold: usize) -> Vec<ShamirPoint> {
  27. assert!(threshold > 2 && n_shares > threshold);
  28. let mut coeffs = vec![secret];
  29. for _ in 0..threshold - 1 {
  30. coeffs.push(pallas::Base::random(&mut OsRng));
  31. }
  32. let mut shares = Vec::with_capacity(n_shares);
  33. for x in 1..n_shares + 1 {
  34. let x = pallas::Base::from(x as u64);
  35. let mut y = pallas::Base::zero();
  36. for coeff in coeffs.iter().rev() {
  37. y *= x;
  38. y += coeff;
  39. }
  40. shares.push(ShamirPoint { x, y });
  41. }
  42. shares
  43. }
  44. fn sss_recover(shares: &[ShamirPoint]) -> pallas::Base {
  45. assert!(shares.len() > 1);
  46. let mut secret = pallas::Base::zero();
  47. for (j, share_j) in shares.iter().enumerate() {
  48. let mut prod = pallas::Base::one();
  49. for (i, share_i) in shares.iter().enumerate() {
  50. if i != j {
  51. prod *= share_i.x * (share_i.x - share_j.x).invert().unwrap();
  52. }
  53. }
  54. prod *= share_j.y;
  55. secret += prod;
  56. }
  57. secret
  58. }
  59. fn main() {
  60. let random_secret = pallas::Base::random(&mut OsRng);
  61. let shares = sss_share(random_secret, 700, 300);
  62. let sample: Vec<ShamirPoint> = shares.choose_multiple(&mut OsRng, 300).copied().collect();
  63. let recovered_secret = sss_recover(&sample);
  64. assert_eq!(random_secret, recovered_secret);
  65. }