ckks_engine/
polynomial.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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
#[derive(Debug, Clone)]
pub struct Polynomial {
    pub coeffs: Vec<i64>,  // Coefficients for the polynomial
}

impl Polynomial {
    // Constructor to create a new Polynomial with given coefficients
    pub fn new(coeffs: Vec<i64>) -> Self {
        Polynomial { coeffs }
    }

    //wrote this only for homomorphic truncate - we haven't used this anywhere apart from it
    pub fn decode(&self) -> Vec<i64> {
        self.coeffs.iter().map(|&c| {
            let real = (c as f64) / 10_000_000.0;
            real.round() as i64 // Round to the nearest integer
        }).collect()
    }

    // Polynomial addition
    pub fn add(&self, other: &Polynomial) -> Polynomial {
        // Determine the maximum length of the two polynomials
        let len = self.coeffs.len().max(other.coeffs.len());
        let mut result = vec![0; len];  // Initialize result vector with zeros

        // Add coefficients of both polynomials
        for i in 0..len {
            let a = if i < self.coeffs.len() { self.coeffs[i] } else { 0 };  // Get coefficient from self or 0 if out of bounds
            let b = if i < other.coeffs.len() { other.coeffs[i] } else { 0 }; // Get coefficient from other or 0 if out of bounds
            result[i] = a + b;  // Add coefficients
        }

        Polynomial::new(result)  // Return new polynomial as the result
    }

    // Polynomial subtraction
    pub fn subtract(&self, other: &Polynomial) -> Polynomial {
        // Determine the maximum length of the two polynomials
        let len = self.coeffs.len().max(other.coeffs.len());
        let mut result = vec![0; len];  // Initialize result vector with zeros

        // Subtract coefficients of the second polynomial from the first
        for i in 0..len {
            let a = if i < self.coeffs.len() { self.coeffs[i] } else { 0 };  // Get coefficient from self or 0 if out of bounds
            let b = if i < other.coeffs.len() { other.coeffs[i] } else { 0 }; // Get coefficient from other or 0 if out of bounds
            result[i] = a - b;  // Subtract coefficients
        }

        Polynomial::new(result)  // Return new polynomial as the result
    }

    // Polynomial multiplication
    pub fn multiply(&self, other: &Polynomial) -> Polynomial {
        // Determine size for the resulting polynomial
        let result_size = self.coeffs.len().max(other.coeffs.len());
        let mut result_coeffs = vec![0.0; result_size]; // Initialize result coefficients with f64 for scaling

        // Multiply matching coefficients of both polynomials
        let min_len = self.coeffs.len().min(other.coeffs.len());
        for i in 0..min_len {
            result_coeffs[i] = (self.coeffs[i] as f64 * other.coeffs[i] as f64) / 1e7; // Scale and store the product
        }
        // Create a new polynomial with rounded coefficients
        Polynomial::new(result_coeffs.iter().map(|&x| x.round() as i64).collect())
    }

    // Polynomial negation
    pub fn negation(&self) -> Polynomial {
        // Negate each coefficient of the polynomial
        let negated_coeffs: Vec<f64> = self.coeffs.iter().map(|&c| -(c as f64)).collect();
        // Create a new polynomial with rounded negated coefficients
        Polynomial::new(negated_coeffs.iter().map(|&x| x.round() as i64).collect())
    }

    pub fn divide(&self, divisor: &Polynomial, scaling_factor: f64) -> Polynomial {
        let mut result_coeffs = Vec::with_capacity(self.coeffs.len());
 
        for (a, b) in self.coeffs.iter().zip(divisor.coeffs.iter()) {
            // Check for zero in the divisor to avoid division by zero
            if *b == 0 {
                panic!("Division by zero encountered in polynomial division");
            }
 
            // Perform the division and scaling
            let scaled_result = (*a as f64 / *b as f64) * scaling_factor;
           
            // Convert the scaled result to an integer and push it into the result coefficients
            result_coeffs.push(scaled_result.round() as i64);
        }
 
        // Return a new polynomial with the resulting coefficients after division
        Polynomial::new(result_coeffs)
    }
}