Contains all the relevant tools for polynomials. Supports:
lambdaworks's polynomials work over Finite Fields.
Univariate polynomials are expressions of the form
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Polynomial<FE> {
pub coefficients: Vec<FE>,
}
it contains the coefficients in increasing order (we start with the independent term,
let my_poly = Polynomial::new(&[FE::new(1), FE::new(2), FE::new(3)])
This creates the polynomial new
method will remove those unnecessary zeros. For example,
let my_poly = Polynomial::new(&[FE::new(1), FE::new(2), FE::new(3), FE::ZERO])
generates the same polynomial as before. We can also create a monomial, such as
let my_monomial = Polynomial::new_monomial(FE::new(27),6)
generates the monomial
Univariate polynomials have a ring structure: we can add, subtract, multiply and divide as we did with integers. For example, to add two polynomials,
let p_1 = Polynomial::new(&[FE::new(3), FE::new(4), FE::new(5)])
let p_2 = Polynomial::new(&[FE::new(4), FE::new(6), FE::new(8)])
let p_a = p_1 + p_2
Polynomial multiplication,
let p1 = Polynomial::new(&[FE::new(3), FE::new(3), FE::new(2)]);
let p2 = Polynomial::new(&[FE::new(4), FE::new(1)]);
assert_eq!(
p2 * p1,
Polynomial::new(&[FE::new(12), FE::new(15), FE::new(11), FE::new(2)])
);
Division,
let p1 = Polynomial::new(&[FE::new(1), FE::new(3)]);
let p2 = Polynomial::new(&[FE::new(1), FE::new(3)]);
let p3 = p1.mul_with_ref(&p2);
assert_eq!(p3 / p2, p1);
Note that, in the case of polynomial division, it may have a remainder. If you want to divide a polynomial ruffini_division
or ruffini_division_inplace
.
Polynomials can also be evaluated at a point evaluate
. This provides the evaluation
let p = Polynomial::new(&[FE::new(3), -FE::new(2), FE::new(4)]);
assert_eq!(p.evaluate(&FE::new(2)), FE::new(15));
evaluates the polynomial evaluate_slice
.
Alternatively, polynomials of degree interpolate
, which takes to vectors, of equal length: the first contains the
let p = Polynomial::interpolate(&[FE::new(0), FE::new(1)], &[FE::new(2), FE::new(1)]).unwrap();
Many polynomial operations can go faster by using the Fast Fourier Transform.
Multilinear polynomials are useful to define multilinear extensions of functions, which then play an important role in proof systems involving the sumcheck protocol. There are two ways to define multilinear polynomials:
- Dense
- Sparse
Sparse is more convenient whenever the number of non-zero coefficients in the polynomial is small (compared to the length of the polynomial), avoiding the storage of unnecessary zeros. For dense multilinear polynomials we have the following structure, working over some field
pub struct DenseMultilinearPolynomial<F: IsField>
where
<F as IsField>::BaseType: Send + Sync,
{
evals: Vec<FieldElement<F>>,
n_vars: usize,
len: usize,
}
The polynomial is assumed to be given in evaluation form over the binary strings of length
An advantage of Lagrange basis polynomials is that we can evaluate all
To create a new polynomial, provide a list of evaluations of
pub fn new(mut evals: Vec<FieldElement<F>>) -> Self {
while !evals.len().is_power_of_two() {
evals.push(FieldElement::zero());
}
let len = evals.len();
DenseMultilinearPolynomial {
n_vars: log_2(len),
evals,
len,
}
}
Dense multilinear polynomials allow you to access the fields n_vars
, len
and evals
with the methods pub fn num_vars(&self) -> usize
, pub fn len(&self) -> usize
and pub fn evals(&self) -> &Vec<FieldElement<F>>
.
If you want to evaluate outside pub fn evaluate(&self, r: Vec<FieldElement<F>>)
and pub fn evaluate_with(evals: &[FieldElement<F>], r: &[FieldElement<F>])
, providing the point
// Example: Z = [1, 2, 1, 4]
let z = vec![FE::one(), FE::from(2u64), FE::one(), FE::from(4u64)];
// r = [4, 3]
let r = vec![FE::from(4u64), FE::from(3u64)];
let eval_with_lr = evaluate_with_lr(&z, &r);
let poly = DenseMultilinearPolynomial::new(z);
let eval = poly.evaluate(r).unwrap();
assert_eq!(eval, FE::from(28u64));
An important functionality is pub fn to_univariate(&self) -> Polynomial<FieldElement<F>>
, which converts a multilinear polynomial into a univariate polynomial, by summing over all variables over
let univar0 = prover.poly.to_univariate();
is used in the sumcheck protocol.
Multilinear polynomials can be added and multiplied by scalars.