#secret-sharing #shamir #prime-field #mpc #secure-computation

阈值秘密共享

各种阈值秘密共享方案的纯Rust实现

5个版本

使用旧的Rust 2015

0.2.2 2017年1月23日
0.2.1 2016年12月30日
0.2.0 2016年12月15日
0.1.1 2016年10月4日
0.1.0 2016年8月16日

#1083密码学

50 每月下载次数

MIT/Apache

63KB
1K SLoC

阈值秘密共享

Build Status Latest version License: MIT/Apache2

高效纯Rust库,用于秘密共享,为传统的Shamir共享和包共享提供高效的份额生成和重建。目前,秘密和份额被固定为以i64值表示的素域元素。

安装

Cargo

[dependencies]
threshold-secret-sharing = "0.2"

GitHub

git clone https://github.com/snipsco/rust-threshold-secret-sharing
cd rust-threshold-secret-sharing
cargo build --release

示例

examples/目录中包含了几个示例。使用cargo运行每个示例,例如:

cargo run --example shamir

下面的Shamir示例。

Shamir共享

使用Shamir方案相对简单。

在选择参数时,必须选择thresholdshare_count以满足安全性要求,并且prime必须足够大,以便正确编码要共享的值(并且满足prime >= share_count + 1)。

在重建秘密时,必须显式提供索引以标识份额;这些索引对应于由share()返回的向量中的份额索引。

extern crate threshold_secret_sharing as tss;

fn main() {
  // create instance of the Shamir scheme
  let ref tss = tss::shamir::ShamirSecretSharing {
    threshold: 8,           // privacy threshold
    share_count: 20,        // total number of shares to generate
    prime: 41               // prime field to use
  };

  let secret = 5;

  // generate shares for secret
  let all_shares = tss.share(secret);

  // artificially remove some of the shares
  let number_of_recovered_shared = 10;
  assert!(number_of_recovered_shared >= tss.reconstruct_limit());
  let recovered_indices: Vec<usize> = (0..number_of_recovered_shared).collect();
  let recovered_shares: &[i64] = &all_shares[0..number_of_recovered_shared];

  // reconstruct using remaining subset of shares
  let reconstructed_secret = tss.reconstruct(&recovered_indices, recovered_shares);
  assert_eq!(reconstructed_secret, secret);
}

打包共享

如果许多秘密都需要进行秘密共享,则可能有益于使用打包方案,其中多个秘密打包到每个份额中。虽然仍然非常计算高效,但一个缺点是参数有一些限制。

具体来说,参数分为方案参数实现参数

  • 前者,如Shamir共享,确定方案的具体属性,但现在还有一个secret_count指定每个份额中要打包多少个秘密;重建限制隐式定义为secret_count + threshold + 1
  • 后者与实现(目前基于快速傅里叶变换)相关,需要指定字段的prime,还需要该字段中的两个单位根,分别必须是2的幂和3的幂

由于这种复杂性增加,正在提供辅助函数以查找合适的参数。目前,以下示例中包含在 packed 模块中的几个固定字段:

  • PSS_4_8_3PSS_4_26_3PSS_155_728_100PSS_155_19682_100

PSS_T_N_D 格式,将 D 秘密分成 N 份,阈值为 T

extern crate threshold_secret_sharing as tss;

fn main() {
  // use predefined parameters
  let ref tss = tss::packed::PSS_4_26_3;

  // generate shares for a vector of secrets
  let secrets = [1, 2, 3];
  let all_shares = tss.share(&secrets);

  // artificially remove some of the shares; keep only the first 8
  let indices: Vec<usize> = (0..8).collect();
  let shares = &all_shares[0..8];

  // reconstruct using remaining subset of shares
  let recovered_secrets = tss.reconstruct(&indices, shares);
  assert_eq!(recovered_secrets, vec![1, 2, 3]);
}

同态性质

Shamir 和打包方案都享有某些同态性质:共享秘密可以通过操作份额进行转换。加法和乘法都起作用,但请注意,在乘法的情况下,重建限制随着每次应用翻倍。

extern crate threshold_secret_sharing as tss;

fn main() {
  // use predefined parameters
  let ref tss = tss::PSS_4_26_3;

  // generate shares for first vector of secrets
  let secrets_1 = [1, 2, 3];
  let shares_1 = tss.share(&secrets_1);

  // generate shares for second vector of secrets
  let secrets_2 = [4, 5, 6];
  let shares_2 = tss.share(&secrets_2);

  // combine shares pointwise to get shares of the sum of the secrets
  let shares_sum: Vec<i64> = shares_1.iter().zip(&shares_2)
    .map(|(a, b)| (a + b) % tss.prime).collect();

  // artificially remove some of the shares; keep only the first 8
  let indices: Vec<usize> = (0..8).collect();
  let shares = &shares_sum[0..8];

  // reconstruct using remaining subset of shares
  let recovered_secrets = tss.reconstruct(&indices, shares);
  assert_eq!(recovered_secrets, vec![5, 7, 9]);
}

参数生成

虽然实例化 Shamir 方案很简单,如上所述,打包方案更复杂,因此提供了一些辅助方法。由于某些应用程序只需要固定参数的选择,这些辅助方法是可选的,并且仅在编译时激活 paramgen 功能时才包含在内

cargo build --features paramgen

这也增加了几个额外的依赖项。

性能

迄今为止,大多数性能工作都集中在打包方案的份额生成上,在此过程中对重建进行了一些明显的改进。例如,使用打包方案将 100 个秘密分成约 20,000 份需要在大约 31ms 内完成,在 Raspberry Pi 3 上需要大约 590ms。

这些数字是通过运行

cargo bench

使用夜间工具链获得的。

许可证

根据您的选择,许可协议为以下之一:

贡献

除非您明确表示,否则根据 Apache-2.0 许可证定义,您提交的任何有意包含在作品中的贡献都应双重许可,如上所述,不附加任何额外条款或条件。

依赖关系

~315–690KB