瀏覽代碼

research/sss: Move shamir secret-sharing impl to own crate.

parazyd 3 年之前
父節點
當前提交
06d5c79212
共有 3 個文件被更改,包括 94 次插入0 次删除
  1. 2 0
      script/research/sss/.gitignore
  2. 12 0
      script/research/sss/Cargo.toml
  3. 80 0
      script/research/sss/src/main.rs

+ 2 - 0
script/research/sss/.gitignore

@@ -0,0 +1,2 @@
+Cargo.lock
+target/

+ 12 - 0
script/research/sss/Cargo.toml

@@ -0,0 +1,12 @@
+[package]
+name = "sss"
+version = "0.1.0"
+authors = ["Dyne.org foundation <foundation@dyne.org>"]
+license = "AGPL-3.0-only"
+edition = "2021"
+
+[workspace]
+
+[dependencies]
+pasta_curves = "0.5.0"
+rand = "0.8.5"

+ 80 - 0
script/research/sss/src/main.rs

@@ -0,0 +1,80 @@
+/* This file is part of DarkFi (https://dark.fi)
+ *
+ * Copyright (C) 2020-2023 Dyne.org foundation
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+//! A simple implementation of Shamir Secret Sharing using the pallas base field
+
+use pasta_curves::{group::ff::Field, pallas};
+use rand::{prelude::SliceRandom, rngs::OsRng};
+
+#[derive(Copy, Clone, Debug)]
+struct ShamirPoint {
+    pub x: pallas::Base,
+    pub y: pallas::Base,
+}
+
+fn sss_share(secret: pallas::Base, n_shares: usize, threshold: usize) -> Vec<ShamirPoint> {
+    assert!(threshold > 2 && n_shares > threshold);
+
+    let mut coeffs = vec![secret];
+    for _ in 0..threshold - 1 {
+        coeffs.push(pallas::Base::random(&mut OsRng));
+    }
+
+    let mut shares = Vec::with_capacity(n_shares);
+    for x in 1..n_shares + 1 {
+        let x = pallas::Base::from(x as u64);
+        let mut y = pallas::Base::zero();
+        for coeff in coeffs.iter().rev() {
+            y *= x;
+            y += coeff;
+        }
+
+        shares.push(ShamirPoint { x, y });
+    }
+
+    shares
+}
+
+fn sss_recover(shares: &[ShamirPoint]) -> pallas::Base {
+    assert!(shares.len() > 1);
+
+    let mut secret = pallas::Base::zero();
+
+    for (j, share_j) in shares.iter().enumerate() {
+        let mut prod = pallas::Base::one();
+
+        for (i, share_i) in shares.iter().enumerate() {
+            if i != j {
+                prod *= share_i.x * (share_i.x - share_j.x).invert().unwrap();
+            }
+        }
+
+        prod *= share_j.y;
+        secret += prod;
+    }
+
+    secret
+}
+
+fn main() {
+    let random_secret = pallas::Base::random(&mut OsRng);
+    let shares = sss_share(random_secret, 700, 300);
+    let sample: Vec<ShamirPoint> = shares.choose_multiple(&mut OsRng, 300).copied().collect();
+    let recovered_secret = sss_recover(&sample);
+    assert_eq!(random_secret, recovered_secret);
+}