curv/cryptographic_primitives/secret_sharing/
polynomial.rs

1use std::cmp::Ordering;
2use std::convert::TryFrom;
3use std::{iter, ops};
4
5use serde::{Deserialize, Serialize};
6
7use crate::elliptic::curves::{Curve, Scalar};
8
9/// Degree of a [polynomial](Polynomial).
10///
11/// For a polynomial of the form: $f(x) = a_0 + a_1 x^1 + \dots{} + a_{n-1} x^{n-1} + a_n x^n$
12///
13/// The degree of $f(x)$ is defined as the biggest $i$ such that $a_i \neq 0$.
14/// If $f(x) = 0$ it's degree is defined as $\infty$.
15#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
16pub enum PolynomialDegree {
17    Infinity,
18    Finite(u16),
19}
20
21impl From<u16> for PolynomialDegree {
22    fn from(deg: u16) -> Self {
23        PolynomialDegree::Finite(deg)
24    }
25}
26
27impl PartialOrd for PolynomialDegree {
28    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
29        Some(self.cmp(other))
30    }
31}
32
33impl Ord for PolynomialDegree {
34    fn cmp(&self, other: &Self) -> Ordering {
35        match (self, other) {
36            (Self::Infinity, Self::Infinity) => Ordering::Equal,
37            (Self::Infinity, Self::Finite(_)) => Ordering::Greater,
38            (Self::Finite(_), Self::Infinity) => Ordering::Less,
39            (Self::Finite(a), Self::Finite(b)) => a.cmp(b),
40        }
41    }
42}
43
44/// Polynomial of some degree $n$
45///
46/// Polynomial has a form: $f(x) = a_0 + a_1 x^1 + \dots{} + a_{n-1} x^{n-1} + a_n x^n$
47///
48/// Coefficients $a_i$ and indeterminate $x$ are in $\Zq$, ie. they are [`Scalar<E>`](Scalar).
49#[derive(Clone, Debug, Serialize, Deserialize)]
50#[serde(bound = "")]
51pub struct Polynomial<E: Curve> {
52    coefficients: Vec<Scalar<E>>,
53}
54
55impl<E: Curve> Polynomial<E> {
56    /// Constructs polynomial $f(x)$ from list of coefficients $a_0, \dots, a_n$ in $\Zq$
57    ///
58    /// ## Order
59    ///
60    /// $a_i$ should corresponds to polynomial $i^{\text{th}}$ coefficient $f(x) = \dots{} + a_i x^i + \dots$
61    ///
62    /// ## Polynomial degree
63    ///
64    /// Note that it's not guaranteed that constructed polynomial degree equals to `coefficients.len()-1`
65    /// as it's allowed to end with zero coefficients. Actual polynomial degree equals to index of last
66    /// non-zero coefficient or zero if all the coefficients are zero.
67    ///
68    /// ## Example
69    ///
70    /// ```rust
71    /// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
72    /// use curv::elliptic::curves::{Scalar, Point, Secp256k1};
73    ///
74    /// let coefs = vec![Scalar::random(), Scalar::random()];
75    /// let poly = Polynomial::<Secp256k1>::from_coefficients(coefs.clone());
76    ///
77    /// assert_eq!(coefs, poly.coefficients());
78    /// ```
79    pub fn from_coefficients(coefficients: Vec<Scalar<E>>) -> Self {
80        Self { coefficients }
81    }
82
83    /// Sample a random polynomial of given degree
84    ///
85    /// ## Example
86    /// ```rust
87    /// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
88    /// use curv::elliptic::curves::Secp256k1;
89    /// use curv::cryptographic_primitives::secret_sharing::PolynomialDegree;
90    ///
91    /// let polynomial = Polynomial::<Secp256k1>::sample_exact(3);
92    /// assert_eq!(polynomial.degree(), 3.into());
93    ///
94    /// let zero_polynomial = Polynomial::<Secp256k1>::sample_exact(PolynomialDegree::Infinity);
95    /// assert_eq!(zero_polynomial.degree(), PolynomialDegree::Infinity);
96    /// ```
97    pub fn sample_exact(degree: impl Into<PolynomialDegree>) -> Self {
98        match degree.into() {
99            PolynomialDegree::Finite(degree) => Self::from_coefficients(
100                iter::repeat_with(Scalar::random)
101                    .take(usize::from(degree) + 1)
102                    .collect(),
103            ),
104            PolynomialDegree::Infinity => Self::from_coefficients(vec![]),
105        }
106    }
107
108    /// Samples random polynomial of degree $n$ with fixed constant term (ie. $a_0 = \text{constant\\_term}$)
109    ///
110    /// ## Example
111    /// ```rust
112    /// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
113    /// use curv::elliptic::curves::{Secp256k1, Scalar};
114    ///
115    /// let const_term = Scalar::<Secp256k1>::random();
116    /// let polynomial = Polynomial::<Secp256k1>::sample_exact_with_fixed_const_term(3, const_term.clone());
117    /// assert_eq!(polynomial.degree(), 3.into());
118    /// assert_eq!(polynomial.evaluate(&Scalar::zero()), const_term);
119    /// ```
120    pub fn sample_exact_with_fixed_const_term(n: u16, const_term: Scalar<E>) -> Self {
121        if n == 0 {
122            Self::from_coefficients(vec![const_term])
123        } else {
124            let random_coefficients = iter::repeat_with(Scalar::random).take(usize::from(n));
125            Self::from_coefficients(iter::once(const_term).chain(random_coefficients).collect())
126        }
127    }
128
129    /// Returns degree $d$ of polynomial $f(x)$: $d = \deg f$
130    ///
131    /// ```rust
132    /// # use curv::cryptographic_primitives::secret_sharing::{Polynomial, PolynomialDegree};
133    /// use curv::elliptic::curves::{Secp256k1, Scalar};
134    ///
135    /// let polynomial = Polynomial::<Secp256k1>::from_coefficients(vec![
136    ///     Scalar::from(1), Scalar::from(2),
137    /// ]);
138    /// assert_eq!(polynomial.degree(), 1.into());
139    ///
140    /// let polynomial = Polynomial::<Secp256k1>::from_coefficients(vec![
141    ///     Scalar::zero()
142    /// ]);
143    /// assert_eq!(polynomial.degree(), PolynomialDegree::Infinity);
144    /// ```
145    pub fn degree(&self) -> PolynomialDegree {
146        self.coefficients()
147            .iter()
148            .enumerate()
149            .rev()
150            .find(|(_, a)| !a.is_zero())
151            .map(|(i, _)| {
152                PolynomialDegree::Finite(
153                    u16::try_from(i).expect("polynomial degree guaranteed to fit into u16"),
154                )
155            })
156            .unwrap_or(PolynomialDegree::Infinity)
157    }
158
159    /// Takes scalar $x$ and evaluates $f(x)$
160    ///
161    /// ## Example
162    /// ```rust
163    /// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
164    /// use curv::elliptic::curves::{Secp256k1, Scalar};
165    ///
166    /// let polynomial = Polynomial::<Secp256k1>::sample_exact(2);
167    ///
168    /// let x = Scalar::from(10);
169    /// let y = polynomial.evaluate(&x);
170    ///
171    /// let a = polynomial.coefficients();
172    /// assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x);
173    /// ```
174    pub fn evaluate(&self, point_x: &Scalar<E>) -> Scalar<E> {
175        let mut reversed_coefficients = self.coefficients.iter().rev();
176        let head = reversed_coefficients
177            .next()
178            .expect("at least one coefficient is guaranteed to be present");
179        let tail = reversed_coefficients;
180        tail.fold(head.clone(), |partial, coef| {
181            let partial_times_point_x = partial * point_x;
182            partial_times_point_x + coef
183        })
184    }
185
186    /// Takes point $x$ that's convertable to BigInt, and evaluates $f(x)$
187    ///
188    /// ## Example
189    /// ```rust
190    /// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
191    /// use curv::elliptic::curves::{Secp256k1, Scalar};
192    ///
193    /// let polynomial = Polynomial::<Secp256k1>::sample_exact(2);
194    ///
195    /// let x: u16 = 10;
196    /// let y: Scalar<Secp256k1> = polynomial.evaluate_bigint(x);
197    ///
198    /// let a = polynomial.coefficients();
199    /// let x = Scalar::from(x);
200    /// assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x);
201    /// ```
202    pub fn evaluate_bigint<B>(&self, point_x: B) -> Scalar<E>
203    where
204        Scalar<E>: From<B>,
205    {
206        self.evaluate(&Scalar::from(point_x))
207    }
208
209    /// Takes list of points $x$ and returns iterator over $f(x_i)$
210    ///
211    /// ## Example
212    /// ```rust
213    /// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
214    /// use curv::elliptic::curves::{Secp256k1, Scalar};
215    ///
216    /// let polynomial = Polynomial::<Secp256k1>::sample_exact(2);
217    ///
218    /// let xs = &[Scalar::from(10), Scalar::from(11)];
219    /// let ys = polynomial.evaluate_many(xs);
220    ///
221    /// let a = polynomial.coefficients();
222    /// for (y, x) in ys.zip(xs) {
223    ///     assert_eq!(y, &a[0] + &a[1] * x + &a[2] * x*x);
224    /// }
225    /// ```
226    pub fn evaluate_many<'i, I>(&'i self, points_x: I) -> impl Iterator<Item = Scalar<E>> + 'i
227    where
228        I: IntoIterator<Item = &'i Scalar<E>> + 'i,
229    {
230        points_x.into_iter().map(move |x| self.evaluate(x))
231    }
232
233    /// Takes a list of points $x$ that are convertable to BigInt, and returns iterator over
234    /// $f(x_i)$.
235    ///
236    /// ## Example
237    /// ```rust
238    /// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
239    /// use curv::elliptic::curves::{Secp256k1, Scalar};
240    ///
241    /// let polynomial = Polynomial::<Secp256k1>::sample_exact(2);
242    ///
243    /// let xs: &[u16] = &[10, 11];
244    /// let ys = polynomial.evaluate_many_bigint(xs.iter().copied());
245    ///
246    /// let a = polynomial.coefficients();
247    /// for (y, x) in ys.zip(xs) {
248    ///     let x = Scalar::from(*x);
249    ///     assert_eq!(y, &a[0] + &a[1] * &x + &a[2] * &x*&x);
250    /// }
251    /// ```
252    pub fn evaluate_many_bigint<'i, B, I>(
253        &'i self,
254        points_x: I,
255    ) -> impl Iterator<Item = Scalar<E>> + 'i
256    where
257        I: IntoIterator<Item = B> + 'i,
258        Scalar<E>: From<B>,
259    {
260        points_x.into_iter().map(move |x| self.evaluate_bigint(x))
261    }
262
263    /// Returns list of polynomial coefficients $a$: $a_i$ corresponds to $i^{\text{th}}$ coefficient of
264    /// polynomial $f(x) = \dots{} + a_i x^i + \dots{}$
265    ///
266    /// ## Example
267    ///
268    /// ```rust
269    /// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
270    /// use curv::elliptic::curves::{Secp256k1, Scalar};
271    ///
272    /// let polynomial = Polynomial::<Secp256k1>::sample_exact(3);
273    /// let a = polynomial.coefficients();
274    /// let x = Scalar::<Secp256k1>::random();
275    /// assert_eq!(polynomial.evaluate(&x), &a[0] + &a[1] * &x + &a[2] * &x*&x + &a[3] * &x*&x*&x);
276    /// ```
277    pub fn coefficients(&self) -> &[Scalar<E>] {
278        &self.coefficients
279    }
280
281    /// Evaluates lagrange basis polynomial
282    ///
283    /// $$l_{X,j}(x) = \prod_{\substack{0 \leq m \leq t,\\\\m \ne j}} \frac{x - X_m}{X_j - X_m}$$
284    ///
285    /// Lagrange basis polynomials are mainly used for Lagrange interpolation, ie. calculating $L(x)$
286    /// where polynomial $L$ is defined as set of $t+1$ distinct points $(x_i, y_i)$ ($t = \deg f$).
287    /// Example section shows how Lagrange interpolation can be implemented using this function.
288    ///
289    /// ## Panics
290    /// This function will panic if elements in `xs` are not pairwise distinct, or `j ≥ xs.len()`
291    ///
292    /// ## Example
293    /// If you have polynomial $f$ defined as $t+1$ points $(x_0, y_0), \dots, (x_t, y_t)$ (and polynomial
294    /// degree is $t$), then you can, for instance, calculate $f(15)$ using Lagrange interpolation:
295    ///
296    /// ```rust
297    /// use curv::cryptographic_primitives::secret_sharing::Polynomial;
298    /// # use curv::elliptic::curves::*;
299    ///
300    /// # let t = 3;
301    /// # let f = Polynomial::<Secp256r1>::sample_exact(t);
302    /// # let (x_0, x_1, x_2, x_3) = (Scalar::from(1), Scalar::from(2), Scalar::from(3), Scalar::from(4));
303    /// # let (y_0, y_1, y_2, y_3) = (f.evaluate(&x_0), f.evaluate(&x_1), f.evaluate(&x_2), f.evaluate(&x_3));
304    /// let xs = &[x_0, x_1, x_2, x_3];
305    /// let ys = &[y_0, y_1, y_2, y_3];
306    ///
307    /// let f_15: Scalar<_> = (0..).zip(ys)
308    ///     .map(|(j, y_j)| y_j * Polynomial::lagrange_basis(&Scalar::from(15), j, xs))
309    ///     .sum();
310    /// assert_eq!(f_15, f.evaluate(&Scalar::from(15)));
311    /// ```
312    ///
313    /// Generally, formula of Lagrange interpolation is:
314    ///
315    /// $$ L_{X,Y}(x) = \sum^t_{j=0} Y\_j \cdot l_{X,j}(x) $$
316    pub fn lagrange_basis(x: &Scalar<E>, j: u16, xs: &[Scalar<E>]) -> Scalar<E> {
317        let x_j = &xs[usize::from(j)];
318        let num: Scalar<E> = (0u16..)
319            .zip(xs)
320            .filter(|(m, _)| *m != j)
321            .map(|(_, x_m)| x - x_m)
322            .product();
323        let denum: Scalar<E> = (0u16..)
324            .zip(xs)
325            .filter(|(m, _)| *m != j)
326            .map(|(_, x_m)| x_j - x_m)
327            .product();
328        let denum = denum
329            .invert()
330            .expect("elements in xs are not pairwise distinct");
331        num * denum
332    }
333}
334
335/// Multiplies polynomial `f(x)` at scalar `s`, returning resulting polynomial `g(x) = s * f(x)`
336///
337/// ## Example
338///
339/// ```rust
340/// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
341/// use curv::elliptic::curves::{Secp256k1, Scalar};
342///
343/// let f = Polynomial::<Secp256k1>::sample_exact(3);
344///
345/// let s = Scalar::<Secp256k1>::random();
346/// let g = &f * &s;
347///
348/// for (f_coef, g_coef) in f.coefficients().iter().zip(g.coefficients()) {
349///     assert_eq!(&(f_coef * &s), g_coef);
350/// }
351/// ```
352impl<E: Curve> ops::Mul<&Scalar<E>> for &Polynomial<E> {
353    type Output = Polynomial<E>;
354    fn mul(self, scalar: &Scalar<E>) -> Self::Output {
355        let coefficients = self.coefficients.iter().map(|c| c * scalar).collect();
356        Polynomial::from_coefficients(coefficients)
357    }
358}
359
360/// Adds two polynomial `f(x)` and `g(x)` returning resulting polynomial `h(x) = f(x) + g(x)`
361///
362/// ## Example
363///
364/// ```rust
365/// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
366/// use curv::elliptic::curves::{Secp256k1, Scalar};
367///
368/// let f = Polynomial::<Secp256k1>::sample_exact(2);
369/// let g = Polynomial::<Secp256k1>::sample_exact(3);
370/// let h = &f + &g;
371///
372/// let x = Scalar::<Secp256k1>::from(10);
373/// assert_eq!(h.evaluate(&x), f.evaluate(&x) + g.evaluate(&x));
374/// ```
375impl<E: Curve> ops::Add for &Polynomial<E> {
376    type Output = Polynomial<E>;
377    fn add(self, g: Self) -> Self::Output {
378        let len1 = self.coefficients.len();
379        let len2 = g.coefficients.len();
380
381        let overlapped = self
382            .coefficients()
383            .iter()
384            .zip(g.coefficients())
385            .map(|(f_coef, g_coef)| f_coef + g_coef);
386        let tail = if len1 < len2 {
387            &g.coefficients()[len1..]
388        } else {
389            &self.coefficients()[len2..]
390        };
391
392        Polynomial::from_coefficients(overlapped.chain(tail.iter().cloned()).collect())
393    }
394}
395
396/// Subtracts two polynomial `g(x)` from `f(x)` returning resulting polynomial `h(x) = f(x) - g(x)`
397///
398/// ## Example
399///
400/// ```rust
401/// # use curv::cryptographic_primitives::secret_sharing::Polynomial;
402/// use curv::elliptic::curves::{Secp256k1, Scalar};
403///
404/// let f = Polynomial::<Secp256k1>::sample_exact(2);
405/// let g = Polynomial::<Secp256k1>::sample_exact(3);
406/// let h = &f - &g;
407///
408/// let x = Scalar::<Secp256k1>::from(10);
409/// assert_eq!(h.evaluate(&x), f.evaluate(&x) - &g.evaluate(&x));
410/// ```
411impl<E: Curve> ops::Sub for &Polynomial<E> {
412    type Output = Polynomial<E>;
413    fn sub(self, g: Self) -> Self::Output {
414        let len1 = self.coefficients.len();
415        let len2 = g.coefficients.len();
416
417        let overlapped = self
418            .coefficients()
419            .iter()
420            .zip(g.coefficients())
421            .map(|(f_coef, g_coef)| f_coef - g_coef);
422        let tail = if len1 < len2 {
423            g.coefficients()[len1..].iter().map(|x| -x).collect()
424        } else {
425            self.coefficients()[len2..].to_vec()
426        };
427
428        Polynomial::from_coefficients(overlapped.chain(tail.into_iter()).collect())
429    }
430}