arnaucube
arnaucube/shamirsecretsharingPublic Self-hosted repository
shamirsecretsharing/shamirsecretsharing-rs/src/lib.rs
shamirsecretsharing-rs/src/lib.rsRaw
  1extern crate rand;
  2extern crate num;
  3extern crate num_bigint;
  4extern crate num_traits;
  5
  6use std::str::FromStr;
  7
  8use num_bigint::RandBigInt;
  9use num::pow::pow;
 10use num::Integer;
 11
 12
 13use num_bigint::{BigInt, ToBigInt};
 14use num_traits::{Zero, One};
 15
 16fn modulus(a: &BigInt, m: &BigInt) -> BigInt {
 17    ((a%m) + m) % m
 18}
 19
 20pub fn create(t: u32, n: u32,p: &BigInt, k: &BigInt) -> Vec<[BigInt;2]> {
 21    // t: number of secrets needed
 22    // n: number of shares
 23    // p: random point
 24    // k: secret to share
 25    if k>p {
 26        println!("\nERROR: need k<p\n");
 27    }
 28
 29    // generate base_polynomial
 30    let mut base_polynomial: Vec<BigInt> = Vec::new();
 31    base_polynomial.push(k.clone());
 32    for _ in 0..t as usize-1 {
 33        let mut rng = rand::thread_rng();
 34        let a = rng.gen_bigint(1024);
 35        base_polynomial.push(a);
 36    }
 37
 38    // calculate shares, based on the base_polynomial
 39    let mut shares: Vec<BigInt> = Vec::new();
 40    for i in 1..n+1 {
 41        let mut p_res: BigInt = Zero::zero();
 42        let mut x = 0;
 43        for pol_elem in &base_polynomial {
 44            if x==0 {
 45                p_res = p_res + pol_elem;
 46            } else {
 47                let i_pow = pow(i, x);
 48                let curr_elem = i_pow * pol_elem;
 49                p_res = p_res + curr_elem;
 50                p_res = modulus(&p_res, p);
 51            }
 52            x = x+1;
 53        }
 54        shares.push(p_res);
 55    }
 56    pack_shares(shares)
 57}
 58
 59fn pack_shares(shares: Vec<BigInt>) -> Vec<[BigInt;2]> {
 60    let mut r: Vec<[BigInt;2]> = Vec::new();
 61    for i in 0..shares.len() {
 62        let curr: [BigInt;2] = [shares[i].clone(), (i+1).to_bigint().unwrap()];
 63        r.push(curr);
 64    }
 65    r
 66}
 67
 68fn unpack_shares(s: Vec<[BigInt;2]>) -> (Vec<BigInt>, Vec<BigInt>) {
 69    let mut shares: Vec<BigInt> = Vec::new();
 70    let mut is: Vec<BigInt> = Vec::new();
 71    for i in 0..s.len() {
 72        shares.push(s[i][0].clone());
 73        is.push(s[i][1].clone());
 74    }
 75    (shares, is)
 76}
 77
 78fn mod_inverse(a: BigInt, module: BigInt) -> BigInt {
 79    // TODO search biguint impl of mod_inv
 80    let mut mn = (module.clone(), a);
 81    let mut xy: (BigInt, BigInt) = (Zero::zero(), One::one());
 82
 83    let big_zero: BigInt = Zero::zero();
 84    while mn.1 != big_zero {
 85        xy = (xy.1.clone(), xy.0 - (mn.0.clone() / mn.1.clone()) * xy.1);
 86        mn = (mn.1.clone(), modulus(&mn.0, &mn.1));
 87    }
 88
 89    while xy.0 < Zero::zero() {
 90        xy.0 += module.clone();
 91    }
 92    xy.0
 93}
 94
 95/// Compute `a^-1 (mod l)` using the the Kalinski implementation
 96/// of the Montgomery Modular Inverse algorithm.
 97/// B. S. Kaliski Jr. - The  Montgomery  inverse  and  its  applica-tions.
 98/// IEEE Transactions on Computers, 44(8):1064–1065, August-1995
 99pub fn kalinski_inv(a: &BigInt, modulo: &BigInt) -> BigInt {
100    // This Phase I indeed is the Binary GCD algorithm , a version o Stein's algorithm
101    // which tries to remove the expensive division operation away from the Classical
102    // Euclidean GDC algorithm replacing it for Bit-shifting, subtraction and comparaison.
103    // 
104    // Output = `a^(-1) * 2^k (mod l)` where `k = log2(modulo) == Number of bits`.
105    // 
106    // Stein, J.: Computational problems associated with Racah algebra.J. Comput. Phys.1, 397–405 (1967).
107    let phase1 = |a: &BigInt| -> (BigInt, u64) {
108        assert!(a != &BigInt::zero());
109        let p = modulo;
110        let mut u = modulo.clone();
111        let mut v = a.clone();
112        let mut r = BigInt::zero();
113        let mut s = BigInt::one();
114        let mut k = 0u64;
115
116        while v > BigInt::zero() {
117            match(u.is_even(), v.is_even(), u > v, v >= u) {
118                // u is even
119                (true, _, _, _) => {
120
121                    u = u >> 1;
122                    s = s << 1;
123                },
124                // u isn't even but v is even
125                (false, true, _, _) => {
126
127                    v = v >> 1;
128                    r = &r << 1;
129                },
130                // u and v aren't even and u > v
131                (false, false, true, _) => {
132
133                    u = &u - &v;
134                    u = u >> 1;
135                    r = &r + &s;
136                    s = &s << 1;
137                },
138                // u and v aren't even and v > u
139                (false, false, false, true) => {
140
141                    v = &v - &u;
142                    v = v >> 1;
143                    s = &r + &s;
144                    r = &r << 1;
145                },
146                (false, false, false, false) => panic!("Unexpected error has ocurred."),
147            }
148            k += 1;
149        }
150        if &r > p {
151            r = &r - p;
152        }
153        ((p - &r), k)
154    };
155
156    // Phase II performs some adjustments to obtain
157    // the Montgomery inverse.
158    // 
159    // We implement it as a clousure to be able to grap the 
160    // kalinski_inv scope to get `modulo` variable.
161    let phase2 = |r: &BigInt, k: &u64| -> BigInt {
162        let mut rr = r.clone();
163        let _p = modulo;
164
165        for _i in 0..(k - modulo.bits() as u64) {
166            match rr.is_even() {
167                true => {
168                    rr = rr >> 1;
169                },
170                false => {
171                    rr = (rr + modulo) >> 1;
172                }
173            }
174        }
175        rr 
176    };
177
178    let (r, z) = phase1(&a.clone());
179
180    phase2(&r, &z)
181}
182
183pub fn lagrange_interpolation(p: &BigInt, shares_packed: Vec<[BigInt;2]>) -> BigInt {
184    let mut res_n: BigInt = Zero::zero();
185    let mut res_d: BigInt = Zero::zero();
186    let (shares, sh_i) = unpack_shares(shares_packed);
187
188    for i in 0..shares.len() {
189        let mut lagrange_numerator: BigInt = One::one();
190        let mut lagrange_denominator: BigInt = One::one();
191        for j in 0..shares.len() {
192            if shares[i] != shares[j] {
193                let curr_l_numerator = &sh_i[j];
194                let curr_l_denominator = &sh_i[j] - &sh_i[i];
195                lagrange_numerator = lagrange_numerator * curr_l_numerator;
196                lagrange_denominator = lagrange_denominator * curr_l_denominator;
197            }
198        }
199        let numerator: BigInt = &shares[i] * &lagrange_numerator;
200
201        let quo: BigInt = (&numerator / &lagrange_denominator) + (&lagrange_denominator ) % &lagrange_denominator;
202        if quo != Zero::zero() {
203            res_n = res_n + quo;
204        } else {
205            let res_n_mul_lagrange_den = res_n * &lagrange_denominator;
206            res_n = res_n_mul_lagrange_den + numerator;
207            res_d = res_d + lagrange_denominator;
208        }
209    }
210    let modinv_mul: BigInt;
211    if res_d != Zero::zero() {
212        let modinv = kalinski_inv(&res_d, &p);
213        modinv_mul = res_n * modinv;
214    } else {
215        modinv_mul = res_n;
216    }
217    let r = modulus(&modinv_mul, &p);
218    r
219}
220
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225    use std::str::FromStr;
226
227    #[test]
228    fn test_create_and_lagrange_interpolation() {
229        let mut rng = rand::thread_rng();
230        let p = rng.gen_biguint(1024).to_bigint().unwrap();
231        println!("p: {:?}", p);
232        let k = BigInt::parse_bytes(b"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", 10).unwrap();
233
234        let s = create(3, 6, &p, &k);
235        // println!("s: {:?}", s);
236
237        let mut shares_to_use: Vec<[BigInt;2]> = Vec::new();
238        shares_to_use.push(s[2].clone());
239        shares_to_use.push(s[1].clone());
240        shares_to_use.push(s[0].clone());
241        let r = lagrange_interpolation(&p, shares_to_use);
242        println!("recovered secret: {:?}", r.to_string());
243        println!("original secret: {:?}", k.to_string());
244        assert_eq!(k, r);
245    }
246
247    #[test]
248    fn kalinski_modular_inverse() {
249        let modul1 = BigInt::from(127u64);
250
251        let a = BigInt::from(79u64);
252        let res1 = kalinski_inv(&a, &modul1);
253        let expected1 = BigInt::from(82u64);
254        assert_eq!(res1, expected1);
255
256        let b = BigInt::from(50u64);
257        let res2 = kalinski_inv(&b, &modul1);
258        let expected2 = BigInt::from(94u64);
259        assert_eq!(res2, expected2);
260
261        // Big numbers testing.
262        // C = 19.
263        // modul2 = 2^255 - 19.
264        let modul2 = BigInt::from_str("57896044618658097711785492504343953926634992332820282019728792003956564819949").unwrap();
265        let c = BigInt::from_str("19").unwrap();
266        let res3 = kalinski_inv(&c, &modul2);
267        let expected3 = BigInt::from_str("1").unwrap();
268        assert_eq!(res3, expected3);
269
270        // D = 182687704666362864775460604089535377456991567872.
271        // modul3 = 2^252 + 27742317777372353535851937790883648493.
272        let modul3 = BigInt::from_str("7237005577332262213973186563042994240857116359379907606001950938285454250989").unwrap();
273        let d = BigInt::from_str("182687704666362864775460604089535377456991567872").unwrap();
274        let res4 = kalinski_inv(&d, &modul3); 
275        println!("RES ON IMPL: {}", res4);
276        let expected4 = BigInt::from_str("7155219595916845557842258654134856828180378438239419449390401977965479867845").unwrap();
277        assert_eq!(expected4, res4);
278    }
279}