├── .gitignore ├── Cargo.toml ├── README.md ├── paper ├── feldmanVSS.pdf ├── feldmanVSS_review_cn.md ├── stadlerPVSS.pdf └── stadlerPVSS_review_cn.md └── src ├── feldman_vss.rs ├── lib.rs ├── secp256k1_helper.rs └── simple_sss.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "verifiable_secret_sharing" 3 | version = "0.1.1" 4 | authors = ["hupeng "] 5 | edition = "2018" 6 | repository = "https://github.com/bitrocks/shamir-secret-sharing" 7 | readme = "README.md" 8 | description = "A rust implementation of Shamir Secret Sharing over Finite Field." 9 | license = "MIT" 10 | documentation = "https://docs.rs/shamir_secret_sharing" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | [dependencies] 14 | rand = "0.6" 15 | num-bigint-dig = "0.4" 16 | num-bigint = {version = "0.2.6", features = ["rand"]} 17 | num-traits = "0.2.11" 18 | num-integer = {version = "0.1.42", features = ["std", "i128"]} 19 | secp256k1 = {version = "0.17.2", features = ["rand-std", "serde"]} 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Verifiable Secret Sharing(Rust) 2 | 3 | ## Intro 4 | 5 | A rust implementation of Verifiable Secret Sharing over Finite Field. 6 | 7 | * [x] impl naive shamir's secret sharing; 8 | * [x] impl feldman's verifiable secret sharing; 9 | * [ ] improve the mod_inv impl, replace extended_euclid_algorithm with stein_algorithm 10 | * [ ] impl publicly verifiable secret sharing 11 | * [ ] client-server mode 12 | 13 | It's not optimized for production purpose yet. 14 | 15 | ## Simple Shamir Secret Sharing 16 | 17 | The lib support large field charactirics `prime` by taking advantage of `num_bigint` . 18 | 19 | ### Example 20 | 21 | ``` rust 22 | use verifiable_secret_sharing::ShamirSecretSharing as SSS; 23 | use num_bigint::{BigInt, BigUint}; 24 | fn main() { 25 | let sss = SSS { 26 | threshold: 3, 27 | share_amount: 5, 28 | prime: BigInt::parse_bytes(b"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",16).unwrap() 29 | }; 30 | 31 | let secret = BigInt::parse_bytes(b"ffffffffffffffffffffffffffffffffffffff", 16).unwrap(); 32 | 33 | let shares = sss.split(secret.clone()); 34 | 35 | println!("shares: {:?}", shares); 36 | assert_eq!(secret, sss.recover(&shares[0..sss.threshold as usize])); 37 | } 38 | 39 | ``` 40 | 41 | ## Verifiable Secret Sharing(VSS) 42 | 43 | [A practical scheme for non-interactive verifiable secret sharing](./paper/feldmanVSS.pdf) 44 | 45 | ### How it works? 46 | check [feldmanVSS review note](./paper/feldmanVSS_review_cn.md). 47 | 48 | ### Example 49 | ``` rust 50 | 51 | use verifiable_secret_sharing::VerifiableSecretSharing; 52 | use verifiable_secret_sharing::Secp256k1Scalar; 53 | fn main(){ 54 | let secret: Secp256k1Scalar = Secp256k1Scalar::from_hex(b"7613c39ea009afd24ccf8c25f13591377091297b20a48ecaad0e92618d36dcc6"); 55 | let vss = VerifiableSecretSharing { 56 | threshold: 3, 57 | share_amount: 5, 58 | }; 59 | let (shares, commitments) = vss.split(&secret); 60 | let sub_shares = &shares[0..3]; 61 | let recovered = vss.recover(&sub_shares); 62 | assert_eq!(secret, recovered); 63 | for share in shares { 64 | assert!(VerifiableSecretSharing::verify(share, &commitments)) 65 | } 66 | } 67 | ``` 68 | 69 | ## Publicly Verifiable Secret Sharing(PVSS) 70 | [Publicly Verifiable Secret Sharing](./paper/stadlerPVSS.pdf) 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /paper/feldmanVSS.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitrocks/verifiable-secret-sharing/569c9a8a03c71a0bf121f316ac571fcd4869830f/paper/feldmanVSS.pdf -------------------------------------------------------------------------------- /paper/feldmanVSS_review_cn.md: -------------------------------------------------------------------------------- 1 | # FeldmanVSS note 2 | 3 | ## 历史 4 | 5 | 1. SSS 由Shamir提出密钥共享及一个基于多项式插值的方案 6 | 2. VSS 由Chor, Goldwasser, Micali, Awerbuch提出可验证密钥共享,并提出一个基于大数分解难题的常数轮交互方案 7 | 3. 基于Goldreich, Micali和Wigderson的零知识证明系统,可以构造常数轮交互方案 8 | 4. Benaloh基于可靠公共信标,构造出常数轮交互方案 9 | 10 | 5.feldman在本文提出了第一个非交互的方案,仅需要两轮通信。 11 | 12 | ## 实用性指标 13 | 14 | 1. 通信的轮数 15 | 2. 通信的数据大小 16 | 3. dealer需要执行的计算量 17 | 18 | ## FeldmanVSS 协议 19 | 20 | 30 | 31 | ### 步骤 32 | 33 | 1. 初始化 34 | 1. 椭圆曲线(如Secp256k1); 35 | 2. 随机数生成器; 36 | 37 | 2. 密钥分享(dealer) 38 | 1. 输入{secret, k, n},secret在内部转换为`Secp256k1Scalar`; 39 | 2. 生成多项式函数的系数coefs = {a0,a1,a2,...,ak-1},表示一个k-1次多项式, 40 | 41 | ,a0 = secret,需要k个点的数据才能恢复; 42 | 3. 在多项式上取n个点,生成n个子密钥,{<1, a(1)>, <2,a(2)>, ..., },计算过程x值全部转化成`Secp256k1Scalar`; 43 | 4. 生成k个系数的commitments, 44 | ,其中g是椭圆曲线上的的generator 45 | 46 | 3. 密钥恢复(dealer) 47 | 1. 任意k个点,使用Lagrange插值恢复出secret; 48 | 2. 验证 c0 == g^secret 49 | 50 | 4. 子密钥验证(players) 51 | 1. 任何子密钥持有者执行以下校验,{, {c0,c1,c2,..ck-1}} 52 | 53 | 通过验证表明dealer分配的子密钥是正确的。 54 | 55 | ## 应用 56 | 57 | ### 模拟一个同步广播网络 58 | 59 | ### 快速拜占庭一致性 60 | 61 | ### 密码学协议的组件 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /paper/stadlerPVSS.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bitrocks/verifiable-secret-sharing/569c9a8a03c71a0bf121f316ac571fcd4869830f/paper/stadlerPVSS.pdf -------------------------------------------------------------------------------- /paper/stadlerPVSS_review_cn.md: -------------------------------------------------------------------------------- 1 | # Publicly Verifiable Secret Sharing review 2 | 3 | ## 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/feldman_vss.rs: -------------------------------------------------------------------------------- 1 | use crate::secp256k1_helper::{Secp256k1Point, Secp256k1Scalar}; 2 | use num_bigint_dig::BigInt; 3 | /// The `VerifiableSecretSharing` stores. 4 | pub struct VerifiableSecretSharing { 5 | /// the threshold of shares to recover the secret. 6 | pub threshold: usize, 7 | /// the total number of shares to generate from the secret. 8 | pub share_amount: usize, 9 | } 10 | 11 | impl VerifiableSecretSharing { 12 | /// Split the secret to shares and commitments. 13 | /// 14 | /// Shares are represented as Secp256k1Scalar, which is 32 bytes slice. 15 | /// Commitment are represented as Secp256k1Point 16 | pub fn split( 17 | &self, 18 | secret: &Secp256k1Scalar, 19 | ) -> (Vec<(usize, Secp256k1Scalar)>, Vec) { 20 | assert!(self.threshold <= self.share_amount); 21 | let polynomial = self.sample_polynomial(secret); 22 | let shares = self.evaluate_polynomial(&polynomial); 23 | println!("polynomial: {:?}", polynomial); 24 | let commitments = Self::generate_commitments(&polynomial); 25 | (shares, commitments) 26 | } 27 | 28 | /// Recover the secret by threshold+1 shares. 29 | pub fn recover(&self, shares: &[(usize, Secp256k1Scalar)]) -> Secp256k1Scalar { 30 | assert!(shares.len() == self.threshold); 31 | let (xs, ys): (Vec, Vec) = shares.iter().cloned().unzip(); 32 | self.lagrange_interpolation(Secp256k1Scalar::zero(), &xs, &ys) 33 | } 34 | 35 | /// Verify a specific share distributed by the dealer is valid. 36 | pub fn verify(share: (usize, Secp256k1Scalar), commitments: &[Secp256k1Point]) -> bool { 37 | let generator = Secp256k1Point::generator(); 38 | let (share_index, share_value) = share; 39 | let share_value_commitment = generator * share_value; 40 | let share_index_scalar = Secp256k1Scalar::from_bigint(&BigInt::from(share_index)); 41 | let mut commitments_iter_rev = commitments.iter().rev(); 42 | let commitments_head = commitments_iter_rev.next().unwrap(); 43 | // println!( 44 | // "share_index_scalar:{:?}, share_value:{:?}, commitments: {:?}", 45 | // share_index_scalar, share_value, commitments 46 | // ); 47 | let share_index_commitment = commitments_iter_rev.fold(*commitments_head, |sum, item| { 48 | // println!( 49 | // "sum * share_index_scalar + *item: {:?} * {:?} + {:?}", 50 | // sum, share_index_scalar, *item 51 | // ); 52 | sum * share_index_scalar + *item 53 | }); 54 | // println!( 55 | // "share_value_commitment: {:?} \n 56 | // share_index_commitment:{:?} \n 57 | // manual_value_commitment: {:?} \n 58 | // manual_a0_commitment: {:?}, \n 59 | // manual_a1_commitment: {:?}, \n 60 | // manual_index_commitment: {:?}", 61 | // share_value_commitment, 62 | // share_index_commitment, 63 | // generator * Secp256k1Scalar::from_bigint(&BigInt::from(11)), 64 | // generator * Secp256k1Scalar::from_bigint(&BigInt::from(5)), 65 | // generator * Secp256k1Scalar::from_bigint(&BigInt::from(3)), 66 | // generator 67 | // * Secp256k1Scalar::from_bigint(&BigInt::from(3)) 68 | // * Secp256k1Scalar::from_bigint(&BigInt::from(2)) 69 | // + generator * Secp256k1Scalar::from_bigint(&BigInt::from(5)), 70 | // ); 71 | share_value_commitment == share_index_commitment 72 | } 73 | 74 | fn generate_commitments(polynomial: &[Secp256k1Scalar]) -> Vec { 75 | let generator: Secp256k1Point = Secp256k1Point::generator(); 76 | let len = polynomial.len(); 77 | (0..len).map(|i| generator * polynomial[i]).collect() 78 | } 79 | 80 | fn sample_polynomial(&self, secret: &Secp256k1Scalar) -> Vec { 81 | let mut coefficients = vec![*secret]; 82 | let random_coefficients: Vec = (0..(self.threshold - 1)) 83 | .map(|_| Secp256k1Scalar::new_random()) 84 | .collect(); 85 | coefficients.extend(random_coefficients); 86 | coefficients 87 | } 88 | 89 | fn evaluate_polynomial(&self, polynomial: &[Secp256k1Scalar]) -> Vec<(usize, Secp256k1Scalar)> { 90 | (1..=self.share_amount) 91 | .map(|x| (x, self.mod_evaluate_at(polynomial, x))) 92 | .collect() 93 | } 94 | 95 | fn mod_evaluate_at(&self, polynomial: &[Secp256k1Scalar], x: usize) -> Secp256k1Scalar { 96 | let scalar_x: Secp256k1Scalar = Secp256k1Scalar::from_bigint(&BigInt::from(x)); 97 | polynomial 98 | .iter() 99 | .rev() 100 | .fold(Secp256k1Scalar::zero(), |sum, item| { 101 | // println!( 102 | // "scalar_x * sum + item: {:?} * {:?} + {:?}", 103 | // scalar_x, sum, *item 104 | // ); 105 | (scalar_x * sum + *item).mod_scalar() 106 | }) 107 | } 108 | 109 | fn lagrange_interpolation( 110 | &self, 111 | x: Secp256k1Scalar, 112 | xs: &[usize], 113 | ys: &[Secp256k1Scalar], 114 | ) -> Secp256k1Scalar { 115 | let scalar_xs: Vec = xs 116 | .iter() 117 | .map(|x| Secp256k1Scalar::from_bigint(&BigInt::from(*x))) 118 | .collect(); 119 | (0..self.threshold).fold(Secp256k1Scalar::zero(), |sum, item| { 120 | let numerator: Secp256k1Scalar = 121 | (0..self.threshold).fold(Secp256k1Scalar::one(), |product, i| { 122 | if i == item { 123 | product 124 | } else { 125 | (product * (x - scalar_xs[i])).mod_scalar() 126 | } 127 | }); 128 | let denominator: Secp256k1Scalar = 129 | (0..self.threshold).fold(Secp256k1Scalar::one(), |product, i| { 130 | if i == item { 131 | product 132 | } else { 133 | product * (scalar_xs[item] - scalar_xs[i]).mod_scalar() 134 | } 135 | }); 136 | // println!( 137 | // "sum + num/den * ys[{:?}]: {:?} + {:?} / {:?} * {:?} ", 138 | // item, sum, numerator, denominator, ys[item] 139 | // ); 140 | (sum + numerator * denominator.inv() * ys[item]).mod_scalar() 141 | }) 142 | } 143 | } 144 | 145 | #[cfg(test)] 146 | mod tests { 147 | use super::*; 148 | #[test] 149 | fn test_vss_3_of_5_works() { 150 | let secret: Secp256k1Scalar = Secp256k1Scalar::new_random(); 151 | let vss = VerifiableSecretSharing { 152 | threshold: 3, 153 | share_amount: 5, 154 | }; 155 | let (shares, commitments) = vss.split(&secret); 156 | let sub_shares = &shares[0..3]; 157 | let recovered = vss.recover(&sub_shares); 158 | assert_eq!(secret, recovered); 159 | for share in shares { 160 | assert!(VerifiableSecretSharing::verify(share, &commitments)) 161 | } 162 | } 163 | 164 | #[test] 165 | fn test_vss_2_of_2_works() { 166 | let secret: Secp256k1Scalar = Secp256k1Scalar::new_random(); 167 | let vss = VerifiableSecretSharing { 168 | threshold: 2, 169 | share_amount: 2, 170 | }; 171 | let (shares, commitments) = vss.split(&secret); 172 | println!("shares: {:?}", shares); 173 | let sub_shares = &shares[0..2]; 174 | let recovered = vss.recover(&sub_shares); 175 | assert_eq!(secret, recovered); 176 | for share in shares { 177 | assert!(VerifiableSecretSharing::verify(share, &commitments)) 178 | } 179 | } 180 | 181 | // y = 5 + 3x, point1(1,8), point2(2,11) 182 | #[test] 183 | fn test_vss_simple_2_of_2_works() { 184 | let secret: Secp256k1Scalar = Secp256k1Scalar::from_hex( 185 | b"0000000000000000000000000000000000000000000000000000000000000005", 186 | ); 187 | let cof = Secp256k1Scalar::from_hex( 188 | b"0000000000000000000000000000000000000000000000000000000000000003", 189 | ); 190 | let polynomial = vec![secret, cof]; 191 | let vss = VerifiableSecretSharing { 192 | threshold: 2, 193 | share_amount: 2, 194 | }; 195 | let shares = vss.evaluate_polynomial(&polynomial); 196 | println!("shares: {:?}", shares); 197 | 198 | let recovered = vss.recover(&shares); 199 | assert_eq!(secret, recovered); 200 | let commitments = VerifiableSecretSharing::generate_commitments(&polynomial); 201 | for share in shares { 202 | assert!(VerifiableSecretSharing::verify(share, &commitments)) 203 | } 204 | } 205 | 206 | #[test] 207 | fn test_vss_67_of_100_works() { 208 | let secret: Secp256k1Scalar = Secp256k1Scalar::new_random(); 209 | let vss = VerifiableSecretSharing { 210 | threshold: 67, 211 | share_amount: 100, 212 | }; 213 | let (shares, commitments) = vss.split(&secret); 214 | let sub_shares = &shares[0..67]; 215 | let recovered = vss.recover(&sub_shares); 216 | assert_eq!(secret, recovered); 217 | for share in shares { 218 | assert!(VerifiableSecretSharing::verify(share, &commitments)) 219 | } 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | //! A lib impl Secret Sharing Scheme 3 | 4 | //! A rust implementation of Shamir Secret Sharing over Finite Field. 5 | //! 6 | //! 7 | //! ## Example 8 | //! ### shamir's secret sharing 9 | //! 10 | //! ```rust 11 | //! use verifiable_secret_sharing::ShamirSecretSharing as SSS; 12 | //! use num_bigint::{BigInt, BigUint}; 13 | //! # fn main() { 14 | //! let sss = SSS { 15 | //! threshold: 3, 16 | //! share_amount: 5, 17 | //! prime: BigInt::parse_bytes(b"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",16).unwrap() 18 | //! }; 19 | //! 20 | //! let secret = BigInt::parse_bytes(b"ffffffffffffffffffffffffffffffffffffff", 16).unwrap(); 21 | //! 22 | //! let shares = sss.split(secret.clone()); 23 | //! 24 | //! println!("shares: {:?}", shares); 25 | //! assert_eq!(secret, sss.recover(&shares[0..sss.threshold as usize])); 26 | //! # } 27 | //! 28 | //! ``` 29 | //! 30 | //! ### feldman's verifiable secret sharing 31 | //! 32 | //! ```rust 33 | //! use verifiable_secret_sharing::VerifiableSecretSharing; 34 | //! use verifiable_secret_sharing::Secp256k1Scalar; 35 | //! # fn main(){ 36 | //! let secret: Secp256k1Scalar = Secp256k1Scalar::from_hex(b"7613c39ea009afd24ccf8c25f13591377091297b20a48ecaad0e92618d36dcc6"); 37 | //! let vss = VerifiableSecretSharing { 38 | //! threshold: 3, 39 | //! share_amount: 5, 40 | //! }; 41 | //! let (shares, commitments) = vss.split(&secret); 42 | //! let sub_shares = &shares[0..3]; 43 | //! let recovered = vss.recover(&sub_shares); 44 | //! assert_eq!(secret, recovered); 45 | //! for share in shares { 46 | //! assert!(VerifiableSecretSharing::verify(share, &commitments)) 47 | //! } 48 | //! # } 49 | //! ``` 50 | pub use feldman_vss::VerifiableSecretSharing; 51 | pub use secp256k1_helper::{Secp256k1Point, Secp256k1Scalar}; 52 | pub use simple_sss::ShamirSecretSharing; 53 | 54 | mod feldman_vss; 55 | mod secp256k1_helper; 56 | mod simple_sss; 57 | -------------------------------------------------------------------------------- /src/secp256k1_helper.rs: -------------------------------------------------------------------------------- 1 | use num_bigint_dig::traits::ModInverse; 2 | use num_bigint_dig::BigInt; 3 | use num_bigint_dig::Sign::Plus; 4 | use num_integer::Integer; 5 | use rand::{thread_rng, Rng}; 6 | use secp256k1::constants::{CURVE_ORDER, GENERATOR_X, GENERATOR_Y, SECRET_KEY_SIZE}; 7 | use secp256k1::{PublicKey, Secp256k1, SecretKey, VerifyOnly}; 8 | use std::ops::{Add, Mul, Sub}; 9 | use std::sync::Once; 10 | /// The `Secp256k1Scalar` is a scalar, wrapping the `SecretKey` 11 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 12 | pub struct Secp256k1Scalar(SecretKey); 13 | 14 | /// The `Secp256k1Point` is a point in elliptic curve, wrapping the `PublicKey` 15 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 16 | pub struct Secp256k1Point(PublicKey); 17 | 18 | impl Secp256k1Point { 19 | /// 20 | pub fn generator() -> Secp256k1Point { 21 | let mut v = vec![4 as u8]; 22 | v.extend(GENERATOR_X.as_ref()); 23 | v.extend(GENERATOR_Y.as_ref()); 24 | Secp256k1Point(PublicKey::from_slice(&v).unwrap()) 25 | } 26 | 27 | // fn random_point() -> Secp256k1Point { 28 | // let random_scalar: Secp256k1Scalar = Secp256k1Scalar::new_random(); 29 | // let base_point = Self::generator(); 30 | // base_point.scalar_mul(&random_scalar) 31 | // } 32 | 33 | fn add_point(&self, other: &PublicKey) -> Secp256k1Point { 34 | Secp256k1Point(self.0.combine(other).unwrap()) 35 | } 36 | 37 | fn scalar_mul(&self, other: &Secp256k1Scalar) -> Secp256k1Point { 38 | let mut new_point = *self; 39 | new_point 40 | .0 41 | .mul_assign(get_context(), &other.0[..]) 42 | .expect("Assignment expected"); 43 | new_point 44 | } 45 | } 46 | 47 | impl Secp256k1Scalar { 48 | /// 49 | pub fn new_random() -> Secp256k1Scalar { 50 | // let rand_bytes = thread_rng().gen::<[u8; 32]>(); 51 | let mut rand_bytes = [0u8; 32]; 52 | thread_rng().fill(&mut rand_bytes[..]); 53 | Secp256k1Scalar(SecretKey::from_slice(&rand_bytes[..]).unwrap()) 54 | } 55 | 56 | /// 57 | pub fn zero() -> Secp256k1Scalar { 58 | let zero_arr = [0u8; 32]; 59 | let zero = unsafe { std::mem::transmute::<[u8; 32], SecretKey>(zero_arr) }; 60 | Secp256k1Scalar(zero) 61 | } 62 | 63 | /// 64 | pub fn one() -> Secp256k1Scalar { 65 | Secp256k1Scalar::from_bigint(&BigInt::from(1)) 66 | } 67 | fn to_bigint(&self) -> BigInt { 68 | // Scalar is big endian in bitcoin secp256k1 impl 69 | BigInt::from_bytes_be(Plus, &self.0[..]) 70 | } 71 | 72 | /// 73 | pub fn curve_order() -> BigInt { 74 | BigInt::from_bytes_be(Plus, &CURVE_ORDER) 75 | } 76 | 77 | fn add_scalar(&self, other: &Secp256k1Scalar) -> Secp256k1Scalar { 78 | let result_bigint = self.to_bigint() + other.to_bigint(); 79 | let result_bigint_mod = result_bigint.mod_floor(&Secp256k1Scalar::curve_order()); 80 | Secp256k1Scalar::from_bigint(&result_bigint_mod) 81 | } 82 | 83 | fn sub_scalar(&self, other: &Secp256k1Scalar) -> Secp256k1Scalar { 84 | let result_bigint = self.to_bigint() - other.to_bigint(); 85 | let result_bigint_mod = result_bigint.mod_floor(&Secp256k1Scalar::curve_order()); 86 | Secp256k1Scalar::from_bigint(&result_bigint_mod) 87 | } 88 | 89 | fn mul_scalar(&self, other: &Secp256k1Scalar) -> Secp256k1Scalar { 90 | let result_bigint = self.to_bigint() * other.to_bigint(); 91 | let result_bigint_mod = result_bigint.mod_floor(&Secp256k1Scalar::curve_order()); 92 | Secp256k1Scalar::from_bigint(&result_bigint_mod) 93 | } 94 | 95 | /// 96 | pub fn inv(&self) -> Secp256k1Scalar { 97 | let element = self.to_bigint(); 98 | let modulus = Secp256k1Scalar::curve_order(); 99 | Secp256k1Scalar::from_bigint(&element.mod_inverse(&modulus).unwrap()) 100 | } 101 | 102 | /// Calculate the inverse of Scalar, using the Euclid Extend Algorithm 103 | pub fn inverse(&self) -> Secp256k1Scalar { 104 | let num = self.to_bigint(); 105 | let order = Secp256k1Scalar::curve_order(); 106 | let (mut r, mut next_r, mut s, mut next_s, mut t, mut next_t) = ( 107 | order.clone(), 108 | num.clone(), 109 | BigInt::from(1), 110 | BigInt::from(0), 111 | BigInt::from(0), 112 | BigInt::from(1), 113 | ); 114 | let mut quotient; 115 | let mut tmp; 116 | while next_r > BigInt::from(0) { 117 | quotient = r.clone() / next_r.clone(); 118 | tmp = next_r.clone(); 119 | next_r = r.clone() - next_r.clone() * quotient.clone(); 120 | r = tmp.clone(); 121 | tmp = next_s.clone(); 122 | next_s = s - next_s.clone() * quotient.clone(); 123 | s = tmp; 124 | tmp = next_t.clone(); 125 | next_t = t - next_t * quotient; 126 | t = tmp; 127 | } 128 | Secp256k1Scalar::from_bigint(&t) 129 | } 130 | 131 | /// 132 | pub fn mod_scalar(&self) -> Secp256k1Scalar { 133 | let bigint_self = self.to_bigint(); 134 | let mod_bigint_self = bigint_self.mod_floor(&Secp256k1Scalar::curve_order()); 135 | // println!( 136 | // "bigint_self: {:?}, curve_order: {:?}, mod_bigint_self: {:?}", 137 | // bigint_self, 138 | // Secp256k1Scalar::curve_order(), 139 | // mod_bigint_self 140 | // ); 141 | Secp256k1Scalar::from_bigint(&mod_bigint_self) 142 | } 143 | 144 | /// 145 | pub fn from_bigint(n: &BigInt) -> Secp256k1Scalar { 146 | if *n == BigInt::from(0) { 147 | Secp256k1Scalar::zero() 148 | } else { 149 | let (_sign, mut result_bytes) = n.to_bytes_be(); 150 | if result_bytes.len() < SECRET_KEY_SIZE { 151 | let mut padding = vec![0; SECRET_KEY_SIZE - result_bytes.len()]; 152 | padding.extend(result_bytes.iter()); 153 | result_bytes = padding 154 | } 155 | // println!("secret_key: {:?}", result_bytes); 156 | Secp256k1Scalar(SecretKey::from_slice(&result_bytes).unwrap()) 157 | } 158 | } 159 | /// 160 | pub fn from_hex(hex: &[u8]) -> Secp256k1Scalar { 161 | Secp256k1Scalar::from_bigint(&BigInt::parse_bytes(hex, 16).unwrap()) 162 | } 163 | } 164 | impl Add for Secp256k1Scalar { 165 | type Output = Secp256k1Scalar; 166 | fn add(self, other: Secp256k1Scalar) -> Self::Output { 167 | self.add_scalar(&other) 168 | } 169 | } 170 | impl Sub for Secp256k1Scalar { 171 | type Output = Secp256k1Scalar; 172 | fn sub(self, other: Secp256k1Scalar) -> Self::Output { 173 | self.sub_scalar(&other) 174 | } 175 | } 176 | impl Mul for Secp256k1Scalar { 177 | type Output = Secp256k1Scalar; 178 | fn mul(self, other: Secp256k1Scalar) -> Self::Output { 179 | self.mul_scalar(&other) 180 | } 181 | } 182 | impl Add for Secp256k1Point { 183 | type Output = Secp256k1Point; 184 | fn add(self, other: Secp256k1Point) -> Self::Output { 185 | self.add_point(&other.0) 186 | } 187 | } 188 | 189 | impl Mul for Secp256k1Point { 190 | type Output = Secp256k1Point; 191 | fn mul(self, other: Secp256k1Scalar) -> Self::Output { 192 | self.scalar_mul(&other) 193 | } 194 | } 195 | 196 | static mut CONTEXT: Option> = None; 197 | /// 198 | pub fn get_context() -> &'static Secp256k1 { 199 | static INIT_CONTEXT: Once = Once::new(); 200 | INIT_CONTEXT.call_once(|| unsafe { 201 | CONTEXT = Some(Secp256k1::verification_only()); 202 | }); 203 | unsafe { CONTEXT.as_ref().unwrap() } 204 | } 205 | 206 | #[cfg(test)] 207 | mod tests { 208 | use super::*; 209 | 210 | #[test] 211 | fn test_bigint_to_scalar() { 212 | let random_scalar = Secp256k1Scalar::new_random(); 213 | let bigint = random_scalar.to_bigint(); 214 | let scalar2 = Secp256k1Scalar::from_bigint(&bigint); 215 | assert_eq!(random_scalar, scalar2); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /src/simple_sss.rs: -------------------------------------------------------------------------------- 1 | pub use num_bigint; 2 | use num_bigint::{BigInt, RandBigInt}; 3 | use num_traits::{One, Zero}; 4 | use rand; 5 | /// The `ShamirSecretSharing` stores threshold, share_amount and the prime of finite field. 6 | #[derive(Clone, Debug)] 7 | pub struct ShamirSecretSharing { 8 | /// the threshold of shares to recover the secret. 9 | pub threshold: usize, 10 | /// the total number of shares to generate from the secret. 11 | pub share_amount: usize, 12 | /// the characteristic of finite field. 13 | pub prime: BigInt, 14 | } 15 | 16 | impl ShamirSecretSharing { 17 | /// Split a secret according to the config. 18 | pub fn split(&self, secret: BigInt) -> Vec<(usize, BigInt)> { 19 | assert!(self.threshold < self.share_amount); 20 | let polynomial = self.sample_polynomial(secret); 21 | // println!("polynomial: {:?}", polynomial); 22 | self.evaluate_polynomial(polynomial) 23 | } 24 | 25 | fn sample_polynomial(&self, secret: BigInt) -> Vec { 26 | let mut coefficients: Vec = vec![secret]; 27 | let mut rng = rand::thread_rng(); 28 | let low = BigInt::from(0); 29 | let high = &self.prime - BigInt::from(1); 30 | let random_coefficients: Vec = (0..(self.threshold - 1)) 31 | .map(|_| rng.gen_bigint_range(&low, &high)) 32 | .collect(); 33 | coefficients.extend(random_coefficients); 34 | coefficients 35 | } 36 | 37 | fn evaluate_polynomial(&self, polynomial: Vec) -> Vec<(usize, BigInt)> { 38 | (1..=self.share_amount) 39 | .map(|x| (x, self.mod_evaluate_at(&polynomial, x))) 40 | .collect() 41 | } 42 | 43 | fn mod_evaluate_at(&self, polynomial: &[BigInt], x: usize) -> BigInt { 44 | let x_bigint = BigInt::from(x); 45 | polynomial.iter().rev().fold(Zero::zero(), |sum, item| { 46 | (&x_bigint * sum + item) % &self.prime 47 | }) 48 | } 49 | 50 | /// Recover the secret by the shares. 51 | pub fn recover(&self, shares: &[(usize, BigInt)]) -> BigInt { 52 | assert!(shares.len() == self.threshold, "wrong shares number"); 53 | let (xs, ys): (Vec, Vec) = shares.iter().cloned().unzip(); 54 | let result = self.lagrange_interpolation(Zero::zero(), xs, ys); 55 | if result < Zero::zero() { 56 | result + &self.prime 57 | } else { 58 | result 59 | } 60 | } 61 | 62 | fn lagrange_interpolation(&self, x: BigInt, xs: Vec, ys: Vec) -> BigInt { 63 | let len = xs.len(); 64 | // println!("x: {}, xs: {:?}, ys: {:?}", x, xs, ys); 65 | let xs_bigint: Vec = xs.iter().map(|x| BigInt::from(*x as i64)).collect(); 66 | // println!("sx_bigint: {:?}", xs_bigint); 67 | (0..len).fold(Zero::zero(), |sum, item| { 68 | let numerator = (0..len).fold(One::one(), |product: BigInt, i| { 69 | if i == item { 70 | product 71 | } else { 72 | product * (&x - &xs_bigint[i]) % &self.prime 73 | } 74 | }); 75 | let denominator = (0..len).fold(One::one(), |product: BigInt, i| { 76 | if i == item { 77 | product 78 | } else { 79 | product * (&xs_bigint[item] - &xs_bigint[i]) % &self.prime 80 | } 81 | }); 82 | // println!( 83 | // "numerator: {}, donominator: {}, y: {}", 84 | // numerator, denominator, &ys[item] 85 | // ); 86 | (sum + numerator * self.mod_reverse(denominator) * &ys[item]) % &self.prime 87 | }) 88 | } 89 | 90 | fn mod_reverse(&self, num: BigInt) -> BigInt { 91 | let num1 = if num < Zero::zero() { 92 | num + &self.prime 93 | } else { 94 | num 95 | }; 96 | let (_gcd, _, inv) = self.extend_euclid_algo(num1); 97 | // println!("inv:{}", inv); 98 | inv 99 | } 100 | 101 | /** 102 | * https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm 103 | * 104 | * a*s + b*t = gcd(a,b) a > b 105 | * r_0 = a*s_0 + b*t_0 s_0 = 1 t_0 = 0 106 | * r_1 = a*s_1 + b*t_1 s_1 = 0 t_1 = 1 107 | * r_2 = r_0 - r_1*q_1 108 | * = a(s_0 - s_1*q_1) + b(t_0 - t_1*q_1) s_2 = s_0 - s_1*q_1 t_2 = t_0 - t_1*q_1 109 | * ... 110 | * stop when r_k = 0 111 | */ 112 | fn extend_euclid_algo(&self, num: BigInt) -> (BigInt, BigInt, BigInt) { 113 | let (mut r, mut next_r, mut s, mut next_s, mut t, mut next_t) = ( 114 | self.prime.clone(), 115 | num.clone(), 116 | BigInt::from(1), 117 | BigInt::from(0), 118 | BigInt::from(0), 119 | BigInt::from(1), 120 | ); 121 | let mut quotient; 122 | let mut tmp; 123 | while next_r > Zero::zero() { 124 | quotient = r.clone() / next_r.clone(); 125 | tmp = next_r.clone(); 126 | next_r = r.clone() - next_r.clone() * quotient.clone(); 127 | r = tmp.clone(); 128 | tmp = next_s.clone(); 129 | next_s = s - next_s.clone() * quotient.clone(); 130 | s = tmp; 131 | tmp = next_t.clone(); 132 | next_t = t - next_t * quotient; 133 | t = tmp; 134 | } 135 | // println!( 136 | // "{} * {} + {} * {} = {} mod {}", 137 | // num, t, &self.prime, s, r, &self.prime 138 | // ); 139 | (r, s, t) 140 | } 141 | } 142 | 143 | #[cfg(test)] 144 | mod tests { 145 | use super::*; 146 | #[test] 147 | fn test_wikipedia_example() { 148 | let sss = ShamirSecretSharing { 149 | threshold: 3, 150 | share_amount: 6, 151 | prime: BigInt::from(1613), 152 | }; 153 | let shares = sss.evaluate_polynomial(vec![ 154 | BigInt::from(1234), 155 | BigInt::from(166), 156 | BigInt::from(94), 157 | ]); 158 | assert_eq!( 159 | shares, 160 | [ 161 | (1, BigInt::from(1494)), 162 | (2, BigInt::from(329)), 163 | (3, BigInt::from(965)), 164 | (4, BigInt::from(176)), 165 | (5, BigInt::from(1188)), 166 | (6, BigInt::from(775)) 167 | ] 168 | ); 169 | assert_eq!( 170 | sss.recover(&[ 171 | (1, BigInt::from(1494)), 172 | (2, BigInt::from(329)), 173 | (3, BigInt::from(965)) 174 | ]), 175 | BigInt::from(1234) 176 | ); 177 | } 178 | #[test] 179 | fn test_large_prime() { 180 | let sss = ShamirSecretSharing { 181 | threshold: 3, 182 | share_amount: 5, 183 | // prime: BigInt::from(6999213259363483493573619703 as i128), 184 | prime: BigInt::parse_bytes( 185 | b"fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", 186 | 16, 187 | ) 188 | .unwrap(), 189 | }; 190 | let secret = BigInt::parse_bytes(b"ffffffffffffffffffffffffffffffffffffff", 16).unwrap(); 191 | let shares = sss.split(secret.clone()); 192 | assert_eq!(secret, sss.recover(&shares[0..sss.threshold as usize])); 193 | } 194 | 195 | #[test] 196 | fn test_secp256k1() { 197 | use secp256k1::{Message, Secp256k1}; 198 | let secp = Secp256k1::new(); 199 | let mut rng = rand::thread_rng(); 200 | let (secret, public) = secp.generate_keypair(&mut rng); 201 | let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); 202 | let sig = secp.sign(&message, &secret); 203 | assert!(secp.verify(&message, &sig, &public).is_ok()); 204 | } 205 | } 206 | --------------------------------------------------------------------------------