<commit_before>extern crate rand;

use rand::{ Rng };

mod tests {
    use super::SecretData;
    #[test]
    fn it_works() {
    }

    #[test]
    fn it_generates_coefficients() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);
        assert_eq!(secret_data.coefficients.len(), 13);
    }

    #[test]
    #[should_panic]
    fn it_rejects_share_id_under_1() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);
        let _ = secret_data.get_share(0);
    }

    #[test]
    fn it_issues_shares() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);

        let s1 = secret_data.get_share(1);
        println!("Share: {:?}", s1);
        assert!(secret_data.is_valid_share(&s1));
    }

    #[test]
    fn it_repeatedly_issues_shares() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);

        let s1 = secret_data.get_share(1);
        println!("Share: {:?}", s1);
        assert!(secret_data.is_valid_share(&s1));

        let s2 = secret_data.get_share(1);
        assert_eq!(s1, s2);
    }

    #[test]
    fn it_can_recover_secret() {
        // let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);

        // let s1 = secret_data.get_share(1);
        // let s2 = secret_data.get_share(2);
        // let s3 = secret_data.get_share(3);

        let s1 = vec![1, 184, 190, 251, 87, 232, 39, 47, 17, 4, 36, 190, 245];
        let s2 = vec![2, 231, 107, 52, 138, 34, 221, 9, 221, 67, 79, 33, 16];
        let s3 = vec![3, 23, 176, 163, 177, 165, 218, 113, 163, 53, 7, 251, 196];

        let new_secret = SecretData::recover_secret(3, vec![s1, s2, s3]).unwrap();

        assert_eq!(&new_secret[..], "Hello, World!");
    }
}

pub struct SecretData {
    // threshold: u8,
    pub secret_data: Option<String>,
    pub coefficients: Vec<String>,
}

impl SecretData {
    pub fn with_secret(secret: &str, threshold: u8) -> SecretData {
        let mut coefficients: Vec<String> = vec![];
        let mut rng = rand::thread_rng();
        let mut rand_container = [0u8, threshold - 1];

        for c in secret.as_bytes() {
            rng.fill_bytes(&mut rand_container);
            coefficients.push(format!("{}{}", c,String::from_utf8_lossy(&rand_container)));
        }

        SecretData {
            secret_data: Some(secret.to_string()),
            // threshold: threshold,
            coefficients: coefficients,
        }
    }

    pub fn get_share(&self, id: u8) -> Vec<u8> {
        if id < 1 { // Don't need to check for id > 255 because u8 can't be
            panic!("share id must be between 1 and 255");
        }
        let mut share_bytes: Vec<u8> = vec![];
        let coefficients = self.coefficients.clone();
        for coefficient in coefficients {
            share_bytes.push(SecretData::accumulate_share_bytes(id, coefficient));
        }

        share_bytes.insert(0, id);
        share_bytes
    }

    pub fn is_valid_share( &self, share: &Vec<u8> ) -> bool {
        let id = share[0];
        // let share2 = share[1..];
        *share == self.get_share(id)
    }

    pub fn recover_secret(threshold: u8, shares: Vec<Vec<u8>>) -> Option<String> {
        if threshold as usize > shares.len() {
            // return None;
            panic!("Number of shares is below the threshold");
        }
        let mut xs: Vec<u8> = vec![];

        for share in shares.iter() {
            if xs.contains(&share[0]) {
                // return None;
                panic!("Multiple shares with the same first byte");
            }

            if share.len() != shares[0].len() {
                // return None;
                panic!("Shares have different lengths");
            }

            xs.push(share[0].clone());
        }
        // println!("xs is {:?}", xs);
        let mut mycoefficients: Vec<String> = vec![];
        // let mut mysecretdata = String::from("");
        let mut mysecretdata: Vec<u8> = vec![];
        let rounds = shares[0].len() - 1;

        let mut fxs: Vec<u8> = vec![];
        for byte_to_use in 0..rounds {
            fxs = vec![];
            for share in shares.clone() {
                fxs.push(share[1..][byte_to_use].clone());
            }
            // println!("fxs is {:?}", fxs);
            let resulting_poly: Vec<u8> = SecretData::full_lagrange(&xs, &fxs);
            // println!("resulting_poly = {:?}", resulting_poly);
            // let mut t = vec![&resulting_poly[0..(threshold - 1) as usize]];
            // let mut t = &resulting_poly[0..threshold - 1];
            // let mut t = slice[0..threshold - 1];
            // if slice[0..threshold - 1]
            // let right_side = shares.len() - threshold as usize;
            // let l = [0; shares.len() - (threshold as usize)];
            // t.append(&mut vec!(&l));
            // if resulting_poly[0..threshold-1 as usize].append([0; end as usize]) != resulting_poly {
                // raise "Share do not match. Cannot decode"
            // }
            mycoefficients.push(String::from_utf8_lossy(&resulting_poly[..]).to_string());
            mysecretdata.push(resulting_poly[0]);
        }
        return Some(String::from_utf8_lossy(&mysecretdata[..]).to_string());
        match String::from_utf8(mysecretdata) {
            Ok(s) => Some(s),
            Err(e) => {
                println!("{:?}", e);
                None
            },
        }
        // Some(mysecretdata)
    }

    fn accumulate_share_bytes(id: u8, coefficient_bytes: String) -> u8 {
        if id < 1 { // Don't need to check for id > 255 because u8 can't be
            panic!("share id must be between 1 and 255");
        }
        let mut accumulator: u8 = 0;

        let mut x_i: u8 = 1;

        for c in coefficient_bytes.as_bytes() {
            accumulator = SecretData::gf256_add(&accumulator, &SecretData::gf256_mul(c, &x_i));
            x_i = SecretData::gf256_mul(&x_i, &id);
        }

        accumulator
    }

    fn full_lagrange(xs: &Vec<u8>, fxs: &Vec<u8>) -> Vec<u8> {
        let mut returned_coefficients: Vec<u8> = vec![];
        let len = fxs.len();
        for i in 0..len {
            let mut this_polynomial: Vec<u8> = vec![1];

            for j in 0..len {
                if i == j {
                    continue;
                }

                let denominator = SecretData::gf256_sub(&xs[i], &xs[j]);
                let this_term = vec![SecretData::gf256_div(&xs[j], &denominator), SecretData::gf256_div(&1, &denominator)];

                this_polynomial = SecretData::multiply_polynomials(&this_polynomial, &this_term);<commit_msg>can encode / decode shamir secrets :)<commit_after>extern crate rand;

use rand::{ Rng };

mod tests {
    use super::SecretData;
    #[test]
    fn it_works() {
    }

    #[test]
    fn it_generates_coefficients() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);
        assert_eq!(secret_data.coefficients.len(), 13);
    }

    #[test]
    #[should_panic]
    fn it_rejects_share_id_under_1() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);
        let _ = secret_data.get_share(0);
    }

    #[test]
    fn it_issues_shares() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);

        let s1 = secret_data.get_share(1);
        println!("Share: {:?}", s1);
        assert!(secret_data.is_valid_share(&s1));
    }

    #[test]
    fn it_repeatedly_issues_shares() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);

        let s1 = secret_data.get_share(1);
        println!("Share: {:?}", s1);
        assert!(secret_data.is_valid_share(&s1));

        let s2 = secret_data.get_share(1);
        assert_eq!(s1, s2);
    }

    #[test]
    fn it_can_recover_secret() {
        // let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);

        // let s1 = secret_data.get_share(1);
        // let s2 = secret_data.get_share(2);
        // let s3 = secret_data.get_share(3);

        let s1 = vec![1, 184, 190, 251, 87, 232, 39, 47, 17, 4, 36, 190, 245];
        let s2 = vec![2, 231, 107, 52, 138, 34, 221, 9, 221, 67, 79, 33, 16];
        let s3 = vec![3, 23, 176, 163, 177, 165, 218, 113, 163, 53, 7, 251, 196];

        let new_secret = SecretData::recover_secret(3, vec![s1, s2, s3]).unwrap();

        assert_eq!(&new_secret[..], "Hello World!");
    }

    #[test]
    fn it_can_recover_a_generated_secret() {
        let secret_data = SecretData::with_secret(&"Hello, world!"[..], 3);

        let s1 = secret_data.get_share(1);
        println!("s1: {:?}", s1);
        let s2 = secret_data.get_share(2);
        println!("s2: {:?}", s2);
        let s3 = secret_data.get_share(3);
        println!("s3: {:?}", s3);

        let new_secret = SecretData::recover_secret(3, vec![s1, s2, s3]).unwrap();

        assert_eq!(&new_secret[..], "Hello, world!");
    }
}

pub struct SecretData {
    // threshold: u8,
    pub secret_data: Option<String>,
    pub coefficients: Vec<Vec<u8>>,
}

impl SecretData {
    pub fn with_secret(secret: &str, threshold: u8) -> SecretData {
        let mut coefficients: Vec<Vec<u8>> = vec![];
        let mut rng = rand::thread_rng();
        let mut rand_container = [0u8, threshold - 1];
        for c in secret.as_bytes() {
            rng.fill_bytes(&mut rand_container);
            let mut coef: Vec<u8> = vec![*c];
            for r in rand_container.iter() {
                coef.push(*r);
            }
            coefficients.push(coef);
        }

        SecretData {
            secret_data: Some(secret.to_string()),
            // threshold: threshold,
            coefficients: coefficients,
        }
    }

    pub fn get_share(&self, id: u8) -> Vec<u8> {
        if id < 1 { // Don't need to check for id > 255 because u8 can't be
            panic!("share id must be between 1 and 255");
        }
        let mut share_bytes: Vec<u8> = vec![];
        let coefficients = self.coefficients.clone();
        for coefficient in coefficients {
            share_bytes.push(SecretData::accumulate_share_bytes(id, coefficient));
        }

        share_bytes.insert(0, id);
        share_bytes
    }

    pub fn is_valid_share( &self, share: &Vec<u8> ) -> bool {
        let id = share[0];
        // let share2 = share[1..];
        *share == self.get_share(id)
    }

    pub fn recover_secret(threshold: u8, shares: Vec<Vec<u8>>) -> Option<String> {
        if threshold as usize > shares.len() {
            println!("Number of shares is below the threshold");
            return None;
        }
        let mut xs: Vec<u8> = vec![];

        for share in shares.iter() {
            if xs.contains(&share[0]) {
                println!("Multiple shares with the same first byte");
                return None;
            }

            if share.len() != shares[0].len() {
                println!("Shares have different lengths");
                return None;
            }

            xs.push(share[0].clone());
        }
        // println!("xs is {:?}", xs);
        let mut mycoefficients: Vec<String> = vec![];
        // let mut mysecretdata = String::from("");
        let mut mysecretdata: Vec<u8> = vec![];
        let rounds = shares[0].len() - 1;

        for byte_to_use in 0..rounds {
            let mut fxs: Vec<u8> = vec![];
            for share in shares.clone() {
                fxs.push(share[1..][byte_to_use].clone());
            }
            // println!("fxs is {:?}", fxs);
            let resulting_poly: Vec<u8> = SecretData::full_lagrange(&xs, &fxs);
            // println!("resulting_poly = {:?}", resulting_poly);
            // let mut t = vec![&resulting_poly[0..(threshold - 1) as usize]];
            // let mut t = &resulting_poly[0..threshold - 1];
            // let mut t = slice[0..threshold - 1];
            // if slice[0..threshold - 1]
            // let right_side = shares.len() - threshold as usize;
            // let l = [0; shares.len() - (threshold as usize)];
            // t.append(&mut vec!(&l));
            // if resulting_poly[0..threshold-1 as usize].append([0; end as usize]) != resulting_poly {
                // raise "Share do not match. Cannot decode"
            // }
            mycoefficients.push(String::from_utf8_lossy(&resulting_poly[..]).to_string());
            mysecretdata.push(resulting_poly[0]);
        }

        match String::from_utf8(mysecretdata) {
            Ok(s) => Some(s),
            Err(e) => {
                println!("{:?}", e);
                None
            },
        }
        // Some(mysecretdata)
    }

    fn accumulate_share_bytes(id: u8, coefficient_bytes: Vec<u8>) -> u8 {
        if id < 1 { // Don't need to check for id > 255 because u8 can't be
            panic!("share id must be between 1 and 255");
        }
        let mut accumulator: u8 = 0;

        let mut x_i: u8 = 1;

        for c in coefficient_bytes {
            accumulator = SecretData::gf256_add(&accumulator, &SecretData::gf256_mul(&c, &x_i));
            x_i = SecretData::gf256_mul(&x_i, &id);
        }

        accumulator
    }

    fn full_lagrange(xs: &Vec<u8>, fxs: &Vec<u8>) -> Vec<u8> {
        let mut returned_coefficients: Vec<u8> = vec![];
        let len = fxs.len();
        for i in 0..len {
            let mut this_polynomial: Vec<u8> = vec![1];

            for j in 0..len {
                if i == j {
                    continue;
                }

                let denominator = SecretData::gf256_sub(&xs[i], &xs[j]);
                let this_term = vec![SecretData::gf256_div(&xs[j], &denominator), SecretData::gf256_div(&1, &denominator)];

                this_polynomial = SecretData::multiply_polynomials(&this_polynomial, &this_term);
{'fraction_non_alphanumeric': 0.15424760800231951, 'fraction_numerical': 0.03327051319222963, 'mean_word_length': 1.9760569456427954, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6286621', 'n_tokens_mistral': 4813, 'n_tokens_neox': 4426, 'n_words': 1049}