//! Additive secret sharing (n-of-n scheme).

/// Additive secret sharing over a prime field.
pub struct AdditiveSharing;

impl AdditiveSharing {
    /// Split a secret into n additive shares.
    /// All n shares are required to reconstruct.
    pub fn split(secret: u64, n: usize) -> Vec<u64> {
        assert!(n > 0, "Need at least 1 share");
        use crate::polynomial::PRIME;
        assert!(secret < PRIME, "Secret must be less than PRIME");

        let mut shares = Vec::with_capacity(n);
        let mut remaining = secret;

        for _ in 0..n - 1 {
            // Generate a random share
            let share = thread_rng_u64() % PRIME;
            remaining = if remaining >= share {
                remaining - share
            } else {
                PRIME - (share - remaining)
            };
            shares.push(share);
        }
        shares.push(remaining);
        shares
    }

    /// Reconstruct a secret from all additive shares.
    pub fn reconstruct(shares: &[u64]) -> u64 {
        use crate::polynomial::{mod_add, PRIME};
        shares.iter().fold(0u64, |acc, &s| mod_add(acc, s)) % PRIME
    }

    /// Verify that shares sum to the expected secret.
    pub fn verify(shares: &[u64], expected_secret: u64) -> bool {
        Self::reconstruct(shares) == expected_secret
    }
}

fn thread_rng_u64() -> u64 {
    use core::cell::Cell;
    thread_local! {
        static STATE: Cell<u64> = const { Cell::new(0x1234567890abcdef) };
    }
    STATE.with(|s| {
        let mut v = s.get();
        v ^= v << 13;
        v ^= v >> 7;
        v ^= v << 17;
        s.set(v);
        v
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_additive_split_reconstruct() {
        let secret = 42u64;
        let shares = AdditiveSharing::split(secret, 5);
        assert_eq!(shares.len(), 5);
        assert_eq!(AdditiveSharing::reconstruct(&shares), secret);
    }

    #[test]
    fn test_additive_verify() {
        let secret = 12345u64;
        let shares = AdditiveSharing::split(secret, 3);
        assert!(AdditiveSharing::verify(&shares, secret));
    }

    #[test]
    fn test_additive_2_shares() {
        let secret = 100u64;
        let shares = AdditiveSharing::split(secret, 2);
        assert_eq!(shares.len(), 2);
        assert_eq!(AdditiveSharing::reconstruct(&shares), secret);
    }

    #[test]
    fn test_additive_missing_share() {
        let secret = 999u64;
        let shares = AdditiveSharing::split(secret, 4);
        // Without all shares, we can't reconstruct
        let partial_sum = AdditiveSharing::reconstruct(&shares[..3]);
        assert_ne!(partial_sum, secret);
    }

    #[test]
    fn test_additive_secret_zero() {
        let shares = AdditiveSharing::split(0, 3);
        assert_eq!(AdditiveSharing::reconstruct(&shares), 0);
    }
}
