1use std::borrow::Borrow;
20use std::cmp::Ordering;
21use std::fmt::{self, Debug, Formatter};
22use std::hash::{Hash, Hasher};
23use std::{cmp, iter, ops};
24
25use core::ops::{AddAssign, Mul, MulAssign, SubAssign};
26use ff::Field;
27use rand::RngCore;
28#[cfg(feature = "serde")]
29use serde::{Deserialize, Serialize};
30use zeroize::{Zeroize, Zeroizing};
31
32use crate::cmp_pairing::cmp_projective;
33use crate::error::{Error, Result};
34use crate::into_fr::IntoScalar;
35use crate::{G1Affine, G1Projective, Scalar};
36
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[derive(PartialEq, Eq, Clone)]
66pub struct Poly {
67 #[cfg_attr(feature = "serde", serde(with = "super::serde_impl::field_vec"))]
69 pub(super) coeff: Vec<Scalar>,
70}
71
72impl Zeroize for Poly {
73 fn zeroize(&mut self) {
74 for s in self.coeff.iter_mut() {
75 s.zeroize();
76 }
77 }
78}
79
80impl Drop for Poly {
81 fn drop(&mut self) {
82 self.zeroize();
83 }
84}
85
86impl Debug for Poly {
88 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
89 f.debug_struct("Poly").field("coeff", &"...").finish()
90 }
91}
92
93#[allow(clippy::suspicious_op_assign_impl)]
94impl<B: Borrow<Poly>> ops::AddAssign<B> for Poly {
95 fn add_assign(&mut self, rhs: B) {
96 let len = self.coeff.len();
97 let rhs_len = rhs.borrow().coeff.len();
98 if rhs_len > len {
99 self.coeff.resize(rhs_len, Scalar::zero());
100 }
101 for (self_c, rhs_c) in self.coeff.iter_mut().zip(&rhs.borrow().coeff) {
102 self_c.add_assign(rhs_c);
103 }
104 self.remove_zeros();
105 }
106}
107
108impl<B: Borrow<Poly>> ops::Add<B> for &Poly {
109 type Output = Poly;
110
111 fn add(self, rhs: B) -> Poly {
112 (*self).clone() + rhs
113 }
114}
115
116impl<B: Borrow<Poly>> ops::Add<B> for Poly {
117 type Output = Poly;
118
119 fn add(mut self, rhs: B) -> Poly {
120 self += rhs;
121 self
122 }
123}
124
125impl ops::Add<Scalar> for Poly {
126 type Output = Poly;
127
128 fn add(mut self, rhs: Scalar) -> Self::Output {
129 if self.coeff.is_empty() {
130 if !bool::from(rhs.is_zero()) {
131 self.coeff.push(rhs);
132 }
133 } else {
134 self.coeff[0].add_assign(&rhs);
135 self.remove_zeros();
136 }
137 self
138 }
139}
140
141impl ops::Add<u64> for Poly {
142 type Output = Poly;
143
144 fn add(self, rhs: u64) -> Self::Output {
145 self + rhs.into_scalar()
146 }
147}
148
149impl<B: Borrow<Poly>> ops::SubAssign<B> for Poly {
150 fn sub_assign(&mut self, rhs: B) {
151 let len = self.coeff.len();
152 let rhs_len = rhs.borrow().coeff.len();
153 if rhs_len > len {
154 self.coeff.resize(rhs_len, Scalar::zero());
155 }
156 for (self_c, rhs_c) in self.coeff.iter_mut().zip(&rhs.borrow().coeff) {
157 self_c.sub_assign(rhs_c);
158 }
159 self.remove_zeros();
160 }
161}
162
163impl<B: Borrow<Poly>> ops::Sub<B> for &Poly {
164 type Output = Poly;
165
166 fn sub(self, rhs: B) -> Poly {
167 (*self).clone() - rhs
168 }
169}
170
171impl<B: Borrow<Poly>> ops::Sub<B> for Poly {
172 type Output = Poly;
173
174 fn sub(mut self, rhs: B) -> Poly {
175 self -= rhs;
176 self
177 }
178}
179
180#[allow(clippy::suspicious_arithmetic_impl)]
182impl ops::Sub<Scalar> for Poly {
183 type Output = Poly;
184
185 fn sub(self, rhs: Scalar) -> Self::Output {
186 self + rhs.neg()
187 }
188}
189
190impl ops::Sub<u64> for Poly {
191 type Output = Poly;
192
193 fn sub(self, rhs: u64) -> Self::Output {
194 self - rhs.into_scalar()
195 }
196}
197
198#[allow(clippy::suspicious_arithmetic_impl)]
200impl<B: Borrow<Poly>> ops::Mul<B> for &Poly {
201 type Output = Poly;
202
203 fn mul(self, rhs: B) -> Self::Output {
204 let rhs = rhs.borrow();
205 if rhs.is_zero() || self.is_zero() {
206 return Poly::zero();
207 }
208 let n_coeffs = self.coeff.len() + rhs.coeff.len() - 1;
209 let mut coeffs = vec![Scalar::zero(); n_coeffs];
210 let mut tmp = Zeroizing::new(Scalar::zero());
211 for (i, ca) in self.coeff.iter().enumerate() {
212 for (j, cb) in rhs.coeff.iter().enumerate() {
213 *tmp = *ca;
214 tmp.mul_assign(cb);
215 coeffs[i + j].add_assign(&*tmp);
216 }
217 }
218 Poly::from(coeffs)
219 }
220}
221
222impl<B: Borrow<Poly>> ops::Mul<B> for Poly {
223 type Output = Poly;
224
225 fn mul(self, rhs: B) -> Self::Output {
226 &self * rhs
227 }
228}
229
230impl<B: Borrow<Self>> ops::MulAssign<B> for Poly {
231 fn mul_assign(&mut self, rhs: B) {
232 *self = &*self * rhs;
233 }
234}
235
236impl ops::MulAssign<Scalar> for Poly {
237 fn mul_assign(&mut self, rhs: Scalar) {
238 if bool::from(rhs.is_zero()) {
239 self.zeroize();
240 self.coeff.clear();
241 } else {
242 for c in &mut self.coeff {
243 c.mul_assign(rhs);
244 }
245 }
246 }
247}
248
249impl ops::Mul<&Scalar> for Poly {
250 type Output = Poly;
251
252 fn mul(mut self, rhs: &Scalar) -> Self::Output {
253 if bool::from(rhs.is_zero()) {
254 self.zeroize();
255 self.coeff.clear();
256 } else {
257 self.coeff.iter_mut().for_each(|c| c.mul_assign(rhs));
258 }
259 self
260 }
261}
262
263impl ops::Mul<Scalar> for Poly {
264 type Output = Poly;
265
266 fn mul(self, rhs: Scalar) -> Self::Output {
267 let rhs = &rhs;
268 self * rhs
269 }
270}
271
272impl<'a> ops::Mul<&'a Scalar> for &'a Poly {
273 type Output = Poly;
274
275 fn mul(self, rhs: &Scalar) -> Self::Output {
276 (*self).clone() * rhs
277 }
278}
279
280impl ops::Mul<Scalar> for &Poly {
281 type Output = Poly;
282
283 fn mul(self, rhs: Scalar) -> Self::Output {
284 (*self).clone() * rhs
285 }
286}
287
288impl ops::Mul<u64> for Poly {
289 type Output = Poly;
290
291 fn mul(self, rhs: u64) -> Self::Output {
292 self * rhs.into_scalar()
293 }
294}
295
296impl From<Vec<Scalar>> for Poly {
299 fn from(coeff: Vec<Scalar>) -> Self {
300 Poly { coeff }
301 }
302}
303
304impl Poly {
305 pub fn random<R: RngCore>(degree: usize, rng: &mut R) -> Self {
311 Poly::try_random(degree, rng)
312 .unwrap_or_else(|e| panic!("Failed to create random `Poly`: {}", e))
313 }
314
315 pub fn try_random<R: RngCore>(degree: usize, rng: &mut R) -> Result<Self> {
319 if degree == usize::MAX {
320 return Err(Error::DegreeTooHigh);
321 }
322 let mut coeff = Vec::with_capacity(degree + 1);
323 for _ in 0..=degree {
324 coeff.push(Scalar::random(&mut *rng));
325 }
326 Ok(Poly::from(coeff))
327 }
328
329 pub fn zero() -> Self {
331 Poly { coeff: vec![] }
332 }
333
334 pub fn is_zero(&self) -> bool {
336 self.coeff.iter().all(|coeff| bool::from(coeff.is_zero()))
337 }
338
339 pub fn one() -> Self {
341 Poly::constant(Scalar::one())
342 }
343
344 pub fn constant(c: Scalar) -> Self {
346 Poly::from(vec![c])
348 }
349
350 pub fn identity() -> Self {
352 Poly::monomial(1)
353 }
354
355 pub fn monomial(degree: usize) -> Self {
357 let coeff: Vec<Scalar> = iter::repeat_n(Scalar::zero(), degree)
358 .chain(iter::once(Scalar::one()))
359 .collect();
360 Poly::from(coeff)
361 }
362
363 pub fn interpolate<T, U, I>(samples_repr: I) -> Self
366 where
367 I: IntoIterator<Item = (T, U)>,
368 T: IntoScalar,
369 U: IntoScalar,
370 {
371 let convert = |(x, y): (T, U)| (x.into_scalar(), y.into_scalar());
372 let samples: Vec<(Scalar, Scalar)> = samples_repr.into_iter().map(convert).collect();
373 Poly::compute_interpolation(&samples)
374 }
375
376 pub fn degree(&self) -> usize {
378 self.coeff.len().saturating_sub(1)
379 }
380
381 pub fn evaluate<T: IntoScalar>(&self, i: T) -> Scalar {
383 let mut result = Zeroizing::new(match self.coeff.last() {
384 None => return Scalar::zero(),
385 Some(c) => *c,
386 });
387 let x = Zeroizing::new(i.into_scalar());
388 for c in self.coeff.iter().rev().skip(1) {
389 result.mul_assign(&*x);
390 result.add_assign(c);
391 }
392 *result
393 }
394
395 pub fn commitment(&self) -> Commitment {
397 let to_g1 = |c: &Scalar| G1Affine::generator().mul(*c);
398 Commitment {
399 coeff: self.coeff.iter().map(to_g1).collect(),
400 }
401 }
402
403 fn remove_zeros(&mut self) {
405 let zeros = self
406 .coeff
407 .iter()
408 .rev()
409 .take_while(|c| bool::from(c.is_zero()))
410 .count();
411 let len = self.coeff.len() - zeros;
412 self.coeff.truncate(len);
413 }
414
415 fn compute_interpolation(samples: &[(Scalar, Scalar)]) -> Self {
418 if samples.is_empty() {
419 return Poly::zero();
420 }
421 let mut poly = Poly::constant(samples[0].1);
423 let minus_s0 = samples[0].0.neg();
424 let mut base = Poly::from(vec![minus_s0, Scalar::one()]);
426
427 for (ref x, ref y) in &samples[1..] {
430 let mut diff = *y;
433 diff.sub_assign(&poly.evaluate(x));
434 let base_val = base.evaluate(x);
435 diff.mul_assign(&base_val.invert().expect("sample points must be distinct"));
436 base *= diff;
437 poly += &base;
438
439 let minus_x = (*x).neg();
441 base *= Poly::from(vec![minus_x, Scalar::one()]);
442 }
443 poly
444 }
445
446 #[cfg(feature = "expose-secret")]
459 pub fn reveal(&self) -> String {
460 format!("Poly {{ coeff: {:?} }}", self.coeff)
461 }
462}
463
464#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
488#[derive(Debug, Clone, PartialEq, Eq)]
489pub struct Commitment {
490 #[cfg_attr(feature = "serde", serde(with = "super::serde_impl::projective_vec"))]
492 pub(super) coeff: Vec<G1Projective>,
493}
494
495impl PartialOrd for Commitment {
496 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
497 Some(self.cmp(other))
498 }
499}
500
501impl Ord for Commitment {
502 fn cmp(&self, other: &Self) -> Ordering {
503 self.coeff.len().cmp(&other.coeff.len()).then_with(|| {
504 self.coeff
505 .iter()
506 .zip(&other.coeff)
507 .find(|(x, y)| x != y)
508 .map_or(Ordering::Equal, |(x, y)| cmp_projective(x, y))
509 })
510 }
511}
512
513impl Hash for Commitment {
514 fn hash<H: Hasher>(&self, state: &mut H) {
515 self.coeff.len().hash(state);
516 for c in &self.coeff {
517 G1Affine::from(c).to_compressed().as_ref().hash(state);
518 }
519 }
520}
521
522impl<B: Borrow<Commitment>> ops::AddAssign<B> for Commitment {
523 fn add_assign(&mut self, rhs: B) {
524 let len = cmp::max(self.coeff.len(), rhs.borrow().coeff.len());
525 self.coeff.resize(len, G1Projective::identity());
526 for (self_c, rhs_c) in self.coeff.iter_mut().zip(&rhs.borrow().coeff) {
527 self_c.add_assign(rhs_c);
528 }
529 self.remove_zeros();
530 }
531}
532
533impl<B: Borrow<Commitment>> ops::Add<B> for &Commitment {
534 type Output = Commitment;
535
536 fn add(self, rhs: B) -> Commitment {
537 (*self).clone() + rhs
538 }
539}
540
541impl<B: Borrow<Commitment>> ops::Add<B> for Commitment {
542 type Output = Commitment;
543
544 fn add(mut self, rhs: B) -> Commitment {
545 self += rhs;
546 self
547 }
548}
549
550impl Commitment {
551 pub fn degree(&self) -> usize {
555 self.coeff.len().saturating_sub(1)
556 }
557
558 pub fn evaluate<T: IntoScalar>(&self, i: T) -> G1Projective {
560 let mut result = match self.coeff.last() {
561 None => return G1Projective::identity(),
562 Some(c) => *c,
563 };
564 let x = i.into_scalar();
565 for c in self.coeff.iter().rev().skip(1) {
566 result.mul_assign(x);
567 result.add_assign(c);
568 }
569 result
570 }
571
572 fn remove_zeros(&mut self) {
574 let zeros = self
575 .coeff
576 .iter()
577 .rev()
578 .take_while(|c| bool::from(c.is_identity()))
579 .count();
580 let len = self.coeff.len() - zeros;
581 self.coeff.truncate(len)
582 }
583}
584
585#[derive(Clone)]
618pub struct BivarPoly {
619 degree: usize,
621 coeff: Vec<Scalar>,
624}
625
626impl Zeroize for BivarPoly {
627 fn zeroize(&mut self) {
628 for s in self.coeff.iter_mut() {
629 s.zeroize();
630 }
631 self.degree.zeroize();
632 }
633}
634
635impl Drop for BivarPoly {
636 fn drop(&mut self) {
637 self.zeroize();
638 }
639}
640
641impl Debug for BivarPoly {
643 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
644 f.debug_struct("BivarPoly")
645 .field("degree", &self.degree)
646 .field("coeff", &"...")
647 .finish()
648 }
649}
650
651impl BivarPoly {
652 pub fn random<R: RngCore>(degree: usize, rng: &mut R) -> Self {
658 BivarPoly::try_random(degree, rng).unwrap_or_else(|e| {
659 panic!(
660 "Failed to create random `BivarPoly` of degree {}: {}",
661 degree, e
662 )
663 })
664 }
665
666 pub fn try_random<R: RngCore>(degree: usize, rng: &mut R) -> Result<Self> {
668 let len = coeff_pos(degree, degree)
669 .and_then(|l| l.checked_add(1))
670 .ok_or(Error::DegreeTooHigh)?;
671 let mut coeff = Vec::with_capacity(len);
672 for _ in 0..=len - 1 {
673 coeff.push(Scalar::random(&mut *rng));
674 }
675 let poly = BivarPoly { degree, coeff };
676 Ok(poly)
677 }
678
679 pub fn degree(&self) -> usize {
681 self.degree
682 }
683
684 pub fn evaluate<T: IntoScalar>(&self, x: T, y: T) -> Scalar {
686 let x_pow = self.powers(x);
687 let y_pow = self.powers(y);
688 let mut result = Zeroizing::new(Scalar::zero());
689 for (i, x_pow_i) in x_pow.into_iter().enumerate() {
690 for (j, y_pow_j) in y_pow.iter().enumerate() {
691 let index = coeff_pos(i, j).expect("polynomial degree too high");
692 let mut summand = Zeroizing::new(self.coeff[index]);
693 summand.mul_assign(&x_pow_i);
694 summand.mul_assign(y_pow_j);
695 result.add_assign(&*summand);
696 }
697 }
698 *result
699 }
700
701 pub fn row<T: IntoScalar>(&self, x: T) -> Poly {
703 let x_pow = self.powers(x);
704 let coeff: Vec<Scalar> = (0..=self.degree)
705 .map(|i| {
706 let mut result = Zeroizing::new(Scalar::zero());
707 for (j, x_pow_j) in x_pow.iter().enumerate() {
708 let index = coeff_pos(i, j).expect("polynomial degree too high");
709 let mut summand = Zeroizing::new(self.coeff[index]);
710 summand.mul_assign(x_pow_j);
711 result.add_assign(&*summand);
712 }
713 *result
714 })
715 .collect();
716 Poly::from(coeff)
717 }
718
719 pub fn commitment(&self) -> BivarCommitment {
721 let to_pub = |c: &Scalar| G1Affine::generator().mul(*c);
722 BivarCommitment {
723 degree: self.degree,
724 coeff: self.coeff.iter().map(to_pub).collect(),
725 }
726 }
727
728 fn powers<T: IntoScalar>(&self, x: T) -> Vec<Scalar> {
730 powers(x, self.degree)
731 }
732
733 #[cfg(feature = "expose-secret")]
746 pub fn reveal(&self) -> String {
747 format!(
748 "BivarPoly {{ degree: {}, coeff: {:?} }}",
749 self.degree, self.coeff
750 )
751 }
752}
753
754#[derive(Debug, Clone, Eq, PartialEq)]
776pub struct BivarCommitment {
777 pub(crate) degree: usize,
779 pub(crate) coeff: Vec<G1Projective>,
781}
782
783impl Hash for BivarCommitment {
784 fn hash<H: Hasher>(&self, state: &mut H) {
785 self.degree.hash(state);
786 for c in &self.coeff {
787 G1Affine::from(c).to_compressed().as_ref().hash(state);
788 }
789 }
790}
791
792impl PartialOrd for BivarCommitment {
793 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
794 Some(self.cmp(other))
795 }
796}
797
798impl Ord for BivarCommitment {
799 fn cmp(&self, other: &Self) -> Ordering {
800 self.degree.cmp(&other.degree).then_with(|| {
801 self.coeff
802 .iter()
803 .zip(&other.coeff)
804 .find(|(x, y)| x != y)
805 .map_or(Ordering::Equal, |(x, y)| cmp_projective(x, y))
806 })
807 }
808}
809
810impl BivarCommitment {
811 pub fn degree(&self) -> usize {
813 self.degree
814 }
815
816 pub fn evaluate<T: IntoScalar>(&self, x: T, y: T) -> G1Projective {
818 let x_pow = self.powers(x);
819 let y_pow = self.powers(y);
820 let mut result = G1Projective::identity();
821 for (i, x_pow_i) in x_pow.into_iter().enumerate() {
822 for (j, y_pow_j) in y_pow.iter().enumerate() {
823 let index = coeff_pos(i, j).expect("polynomial degree too high");
824 let mut summand = self.coeff[index];
825 summand.mul_assign(x_pow_i);
826 summand.mul_assign(*y_pow_j);
827 result.add_assign(&summand);
828 }
829 }
830 result
831 }
832
833 pub fn row<T: IntoScalar>(&self, x: T) -> Commitment {
835 let x_pow = self.powers(x);
836 let coeff: Vec<G1Projective> = (0..=self.degree)
837 .map(|i| {
838 let mut result = G1Projective::identity();
839 for (j, x_pow_j) in x_pow.iter().enumerate() {
840 let index = coeff_pos(i, j).expect("polynomial degree too high");
841 let mut summand = self.coeff[index];
842 summand.mul_assign(*x_pow_j);
843 result.add_assign(&summand);
844 }
845 result
846 })
847 .collect();
848 Commitment { coeff }
849 }
850
851 fn powers<T: IntoScalar>(&self, x: T) -> Vec<Scalar> {
853 powers(x, self.degree)
854 }
855}
856
857fn powers<T: IntoScalar>(into_x: T, degree: usize) -> Vec<Scalar> {
859 let x = Zeroizing::new(into_x.into_scalar());
860 let mut x_pow_i = Zeroizing::new(Scalar::one());
861 iter::once(*x_pow_i)
862 .chain((0..degree).map(|_| {
863 x_pow_i.mul_assign(&*x);
864 *x_pow_i
865 }))
866 .collect()
867}
868
869pub(crate) fn coeff_pos(i: usize, j: usize) -> Option<usize> {
873 let (j, i) = if j >= i { (j, i) } else { (i, j) };
875 i.checked_add(j.checked_mul(j.checked_add(1)?)? / 2)
876}
877
878#[cfg(test)]
879mod tests {
880 use core::ops::{AddAssign, Mul};
881 use std::collections::BTreeMap;
882
883 use super::{coeff_pos, BivarPoly, IntoScalar, Poly};
884 use super::{G1Affine, G1Projective, Scalar};
885 use ff::Field;
886 use zeroize::Zeroize;
887
888 #[test]
889 fn test_coeff_pos() {
890 let mut i = 0;
891 let mut j = 0;
892 for n in 0..100 {
893 assert_eq!(Some(n), coeff_pos(i, j));
894 if i >= j {
895 j += 1;
896 i = 0;
897 } else {
898 i += 1;
899 }
900 }
901 let too_large = 1 << (0usize.count_zeros() / 2);
902 assert_eq!(None, coeff_pos(0, too_large));
903 }
904
905 #[test]
906 fn test_commitment_degree_empty_does_not_panic() {
907 use super::Commitment;
908 let empty_commitment = Commitment { coeff: vec![] };
910 assert_eq!(empty_commitment.degree(), 0);
912 }
913
914 #[test]
915 fn test_poly_degree_empty() {
916 let zero_poly = Poly::zero();
918 assert_eq!(zero_poly.degree(), 0);
919 let commitment = zero_poly.commitment();
921 assert_eq!(commitment.degree(), 0);
922 }
923
924 #[test]
925 fn poly() {
926 let x_pow_3 = Poly::monomial(3);
928 let x_pow_1 = Poly::monomial(1);
929 let poly = x_pow_3 * 5 + x_pow_1 - 2;
930
931 let coeff: Vec<_> = [-2, 1, 0, 5].iter().map(IntoScalar::into_scalar).collect();
932 assert_eq!(Poly { coeff }, poly);
933 let samples = vec![(-1, -8), (2, 40), (3, 136), (5, 628)];
934 for &(x, y) in &samples {
935 assert_eq!(y.into_scalar(), poly.evaluate(x));
936 }
937 let interp = Poly::interpolate(samples);
938 assert_eq!(interp, poly);
939 }
940
941 #[test]
942 fn test_zeroize() {
943 let mut poly = Poly::monomial(3) + Poly::monomial(2) - 1;
944 poly.zeroize();
945 assert!(poly.is_zero());
946
947 let mut bi_poly = BivarPoly::random(3, &mut rand::thread_rng());
948 let random_commitment = bi_poly.commitment();
949
950 bi_poly.zeroize();
951
952 let zero_commitment = bi_poly.commitment();
953 assert_ne!(random_commitment, zero_commitment);
954
955 let mut rng = rand::thread_rng();
956 let (x, y): (Scalar, Scalar) = (Scalar::random(&mut rng), Scalar::random(&mut rng));
957 assert_eq!(zero_commitment.evaluate(x, y), G1Projective::identity());
958 }
959
960 #[test]
961 fn distributed_key_generation() {
962 let mut rng = rand::thread_rng();
963 let dealer_num = 3;
964 let node_num = 5;
965 let faulty_num = 2;
966
967 let bi_polys: Vec<BivarPoly> = (0..dealer_num)
971 .map(|_| BivarPoly::random(faulty_num, &mut rng))
972 .collect();
973 let pub_bi_commits: Vec<_> = bi_polys.iter().map(BivarPoly::commitment).collect();
974
975 let mut sec_keys = vec![Scalar::zero(); node_num];
976
977 for (bi_poly, bi_commit) in bi_polys.iter().zip(&pub_bi_commits) {
981 for m in 1..=node_num {
982 let row_poly = bi_poly.row(m);
984 let row_commit = bi_commit.row(m);
985 assert_eq!(row_poly.commitment(), row_commit);
986 for s in 1..=node_num {
988 let val = row_poly.evaluate(s);
989 let val_g1 = G1Affine::generator().mul(val);
990 assert_eq!(bi_commit.evaluate(m, s), val_g1);
991 assert_eq!(bi_poly.evaluate(m, s), val);
993 }
994
995 let x_pow_2 = Poly::monomial(2);
997 let five = Poly::constant(5.into_scalar());
998 let wrong_poly = row_poly.clone() + x_pow_2 * five;
999 assert_ne!(wrong_poly.commitment(), row_commit);
1000
1001 let received: BTreeMap<_, _> = [1, 2, 4]
1009 .iter()
1010 .map(|&i| (i, bi_poly.evaluate(m, i)))
1011 .collect();
1012 let my_row = Poly::interpolate(received);
1013 assert_eq!(bi_poly.evaluate(m, 0), my_row.evaluate(0));
1014 assert_eq!(row_poly, my_row);
1015
1016 sec_keys[m - 1].add_assign(&my_row.evaluate(Scalar::zero()));
1019 }
1020 }
1021
1022 let mut sec_key_set = Poly::zero();
1028 for bi_poly in &bi_polys {
1029 sec_key_set += bi_poly.row(0);
1030 }
1031 for m in 1..=node_num {
1032 assert_eq!(sec_key_set.evaluate(m), sec_keys[m - 1]);
1033 }
1034
1035 let mut sum_commit = Poly::zero().commitment();
1038 for bi_commit in &pub_bi_commits {
1039 sum_commit += bi_commit.row(0);
1040 }
1041 assert_eq!(sum_commit, sec_key_set.commitment());
1042 }
1043}