snarkvm_algorithms/polycommit/sonic_pc/
polynomial.rs1use super::PolynomialLabel;
17use crate::fft::{DensePolynomial, EvaluationDomain, Evaluations as EvaluationsOnDomain, Polynomial, SparsePolynomial};
18use snarkvm_fields::{Field, PrimeField};
19use snarkvm_utilities::{CanonicalDeserialize, CanonicalSerialize, cfg_iter, cfg_iter_mut};
20
21use anyhow::Result;
22use std::borrow::Cow;
23
24#[cfg(feature = "serial")]
25use itertools::Itertools;
26#[cfg(not(feature = "serial"))]
27use rayon::prelude::*;
28
29#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize, Eq, PartialEq)]
30pub struct PolynomialInfo {
31 label: PolynomialLabel,
32 degree_bound: Option<usize>,
33 hiding_bound: Option<usize>,
34}
35
36impl PolynomialInfo {
37 pub fn new(label: PolynomialLabel, degree_bound: Option<usize>, hiding_bound: Option<usize>) -> Self {
39 Self { label, degree_bound, hiding_bound }
40 }
41
42 pub fn label(&self) -> &str {
44 &self.label
45 }
46
47 pub fn degree_bound(&self) -> Option<usize> {
49 self.degree_bound
50 }
51
52 pub fn is_hiding(&self) -> bool {
54 self.hiding_bound.is_some()
55 }
56
57 pub fn hiding_bound(&self) -> Option<usize> {
59 self.hiding_bound
60 }
61}
62
63#[derive(Debug, Clone, CanonicalSerialize, CanonicalDeserialize, PartialEq, Eq)]
68pub struct LabeledPolynomial<F: Field> {
69 pub info: PolynomialInfo,
70 pub polynomial: Polynomial<'static, F>,
71}
72
73impl<F: Field> core::ops::Deref for LabeledPolynomial<F> {
74 type Target = Polynomial<'static, F>;
75
76 fn deref(&self) -> &Self::Target {
77 &self.polynomial
78 }
79}
80
81impl<F: Field> LabeledPolynomial<F> {
82 pub fn new(
84 label: impl Into<PolynomialLabel>,
85 polynomial: impl Into<Polynomial<'static, F>>,
86 degree_bound: impl Into<Option<usize>>,
87 hiding_bound: impl Into<Option<usize>>,
88 ) -> Self {
89 let info = PolynomialInfo::new(label.into(), degree_bound.into(), hiding_bound.into());
90 Self { info, polynomial: polynomial.into() }
91 }
92
93 pub fn info(&self) -> &PolynomialInfo {
94 &self.info
95 }
96
97 pub fn label(&self) -> &str {
99 &self.info.label
100 }
101
102 pub fn to_label(&self) -> String {
104 self.info.label.clone()
105 }
106
107 pub fn polynomial(&self) -> &Polynomial<F> {
109 &self.polynomial
110 }
111
112 pub fn polynomial_mut(&mut self) -> &mut Polynomial<'static, F> {
114 &mut self.polynomial
115 }
116
117 pub fn evaluate(&self, point: F) -> F {
119 self.polynomial.evaluate(point)
120 }
121
122 pub fn degree_bound(&self) -> Option<usize> {
124 self.info.degree_bound
125 }
126
127 pub fn is_hiding(&self) -> bool {
129 self.info.hiding_bound.is_some()
130 }
131
132 pub fn hiding_bound(&self) -> Option<usize> {
134 self.info.hiding_bound
135 }
136}
137
138#[derive(Debug, Clone)]
141pub struct LabeledPolynomialWithBasis<'a, F: PrimeField> {
142 pub info: PolynomialInfo,
143 pub polynomial: PolynomialWithBasis<'a, F>,
144}
145
146impl<'a, F: PrimeField> LabeledPolynomialWithBasis<'a, F> {
147 pub fn new_monomial_basis(
149 label: PolynomialLabel,
150 polynomial: &'a Polynomial<F>,
151 degree_bound: Option<usize>,
152 hiding_bound: Option<usize>,
153 ) -> Self {
154 let polynomial = PolynomialWithBasis::new_monomial_basis_ref(polynomial, degree_bound);
155 let info = PolynomialInfo::new(label, degree_bound, hiding_bound);
156 Self { info, polynomial }
157 }
158
159 pub fn new_lagrange_basis(
160 label: PolynomialLabel,
161 polynomial: EvaluationsOnDomain<F>,
162 hiding_bound: Option<usize>,
163 ) -> Self {
164 let polynomial = PolynomialWithBasis::new_lagrange_basis(polynomial);
165 let info = PolynomialInfo::new(label, None, hiding_bound);
166 Self { info, polynomial }
167 }
168
169 pub fn new_lagrange_basis_ref(
170 label: PolynomialLabel,
171 polynomial: &'a EvaluationsOnDomain<F>,
172 hiding_bound: Option<usize>,
173 ) -> Self {
174 let polynomial = PolynomialWithBasis::new_lagrange_basis_ref(polynomial);
175 let info = PolynomialInfo::new(label, None, hiding_bound);
176 Self { info, polynomial }
177 }
178
179 pub fn label(&self) -> &str {
181 &self.info.label
182 }
183
184 pub fn info(&self) -> &PolynomialInfo {
187 &self.info
188 }
189
190 pub fn degree(&self) -> usize {
191 match &self.polynomial {
192 PolynomialWithBasis::Lagrange { evaluations } => evaluations.domain().size() - 1,
193 PolynomialWithBasis::Monomial { polynomial, .. } => polynomial.degree(),
194 }
195 }
196
197 pub fn evaluate(&self, point: F) -> F {
199 self.polynomial.evaluate(point)
200 }
201
202 pub fn degree_bound(&self) -> Option<usize> {
204 match self.polynomial {
205 PolynomialWithBasis::Monomial { degree_bound, .. } => degree_bound,
206 _ => None,
207 }
208 }
209
210 pub fn is_hiding(&self) -> bool {
212 self.info.hiding_bound.is_some()
213 }
214
215 pub fn hiding_bound(&self) -> Option<usize> {
217 self.info.hiding_bound
218 }
219}
220
221impl<'a, F: PrimeField> From<&'a LabeledPolynomial<F>> for LabeledPolynomialWithBasis<'a, F> {
222 fn from(other: &'a LabeledPolynomial<F>) -> Self {
223 let polynomial = PolynomialWithBasis::Monomial {
224 polynomial: Cow::Borrowed(other.polynomial()),
225 degree_bound: other.degree_bound(),
226 };
227 Self { info: other.info.clone(), polynomial }
228 }
229}
230
231impl<F: PrimeField> From<LabeledPolynomial<F>> for LabeledPolynomialWithBasis<'_, F> {
232 fn from(other: LabeledPolynomial<F>) -> Self {
233 let polynomial = PolynomialWithBasis::Monomial {
234 polynomial: Cow::Owned(other.polynomial),
235 degree_bound: other.info.degree_bound,
236 };
237 Self { info: other.info.clone(), polynomial }
238 }
239}
240
241#[derive(Debug, Clone)]
242pub enum PolynomialWithBasis<'a, F: PrimeField> {
243 Monomial { polynomial: Cow<'a, Polynomial<'a, F>>, degree_bound: Option<usize> },
246
247 Lagrange { evaluations: Cow<'a, EvaluationsOnDomain<F>> },
250}
251
252impl<'a, F: PrimeField> PolynomialWithBasis<'a, F> {
253 pub fn new_monomial_basis_ref(polynomial: &'a Polynomial<F>, degree_bound: Option<usize>) -> Self {
254 Self::Monomial { polynomial: Cow::Borrowed(polynomial), degree_bound }
255 }
256
257 pub fn new_monomial_basis(polynomial: Polynomial<'a, F>, degree_bound: Option<usize>) -> Self {
258 Self::Monomial { polynomial: Cow::Owned(polynomial), degree_bound }
259 }
260
261 pub fn new_dense_monomial_basis_ref(polynomial: &'a DensePolynomial<F>, degree_bound: Option<usize>) -> Self {
262 let polynomial = Polynomial::Dense(Cow::Borrowed(polynomial));
263 Self::Monomial { polynomial: Cow::Owned(polynomial), degree_bound }
264 }
265
266 pub fn new_dense_monomial_basis(polynomial: DensePolynomial<F>, degree_bound: Option<usize>) -> Self {
267 let polynomial = Polynomial::from(polynomial);
268 Self::Monomial { polynomial: Cow::Owned(polynomial), degree_bound }
269 }
270
271 pub fn new_sparse_monomial_basis_ref(polynomial: &'a SparsePolynomial<F>, degree_bound: Option<usize>) -> Self {
272 let polynomial = Polynomial::Sparse(Cow::Borrowed(polynomial));
273 Self::Monomial { polynomial: Cow::Owned(polynomial), degree_bound }
274 }
275
276 pub fn new_sparse_monomial_basis(polynomial: SparsePolynomial<F>, degree_bound: Option<usize>) -> Self {
277 let polynomial = Polynomial::from(polynomial);
278 Self::Monomial { polynomial: Cow::Owned(polynomial), degree_bound }
279 }
280
281 pub fn new_lagrange_basis(evaluations: EvaluationsOnDomain<F>) -> Self {
282 Self::Lagrange { evaluations: Cow::Owned(evaluations) }
283 }
284
285 pub fn new_lagrange_basis_ref(evaluations: &'a EvaluationsOnDomain<F>) -> Self {
286 Self::Lagrange { evaluations: Cow::Borrowed(evaluations) }
287 }
288
289 pub fn is_in_monomial_basis(&self) -> bool {
290 matches!(self, Self::Monomial { .. })
291 }
292
293 pub fn degree_bound(&self) -> Option<usize> {
295 match self {
296 Self::Monomial { degree_bound, .. } => *degree_bound,
297 _ => None,
298 }
299 }
300
301 pub fn is_sparse(&self) -> bool {
303 match self {
304 Self::Monomial { polynomial, .. } => matches!(polynomial.as_ref(), Polynomial::Sparse(_)),
305 _ => false,
306 }
307 }
308
309 pub fn is_in_lagrange_basis(&self) -> bool {
310 matches!(self, Self::Lagrange { .. })
311 }
312
313 pub fn domain(&self) -> Option<EvaluationDomain<F>> {
314 match self {
315 Self::Lagrange { evaluations } => Some(evaluations.domain()),
316 _ => None,
317 }
318 }
319
320 pub fn evaluate(&self, point: F) -> F {
321 match self {
322 Self::Monomial { polynomial, .. } => polynomial.evaluate(point),
323 Self::Lagrange { evaluations } => {
324 let domain = evaluations.domain();
325 let degree = domain.size() as u64;
326 let multiplier = (point.pow([degree]) - F::one()) / F::from(degree);
327 let powers: Vec<_> = domain.elements().collect();
328 let mut denominators = cfg_iter!(powers).map(|pow| point - pow).collect::<Vec<_>>();
329 snarkvm_fields::batch_inversion(&mut denominators);
330 cfg_iter_mut!(denominators)
331 .zip_eq(powers)
332 .zip_eq(&evaluations.evaluations)
333 .map(|((denom, power), coeff)| *denom * power * coeff)
334 .sum::<F>()
335 * multiplier
336 }
337 }
338 }
339}