commonware_cryptography/bls12381/primitives/
poly.rs1use crate::bls12381::primitives::{
10 group::{self, Element, Scalar},
11 Error,
12};
13use bytes::BufMut;
14use commonware_utils::SizedSerialize;
15use rand::{rngs::OsRng, RngCore};
16use std::collections::BTreeMap;
17
18pub type Private = Poly<group::Private>;
20
21pub type Public = Poly<group::Public>;
23
24pub type Signature = Poly<group::Signature>;
27
28pub type PartialSignature = Eval<group::Signature>;
30
31pub const PARTIAL_SIGNATURE_LENGTH: usize = u32::SERIALIZED_LEN + group::SIGNATURE_LENGTH;
33
34#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
36pub struct Eval<C: Element> {
37 pub index: u32,
38 pub value: C,
39}
40
41impl<C: Element> Eval<C> {
42 pub fn serialize(&self) -> Vec<u8> {
44 let value_serialized = self.value.serialize();
45 let mut bytes = Vec::with_capacity(u32::SERIALIZED_LEN + value_serialized.len());
46 bytes.put_u32(self.index);
47 bytes.extend_from_slice(&value_serialized);
48 bytes
49 }
50
51 pub fn deserialize(bytes: &[u8]) -> Option<Self> {
53 let index = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
54 let value = C::deserialize(&bytes[u32::SERIALIZED_LEN..])?;
55 Some(Self { index, value })
56 }
57}
58
59#[derive(Debug, Clone, PartialEq, Eq)]
65pub struct Poly<C>(Vec<C>);
67
68pub fn new(degree: u32) -> Poly<Scalar> {
73 new_from(degree, &mut OsRng)
75}
76
77pub fn new_from<R: RngCore>(degree: u32, rng: &mut R) -> Poly<Scalar> {
82 let coeffs = (0..=degree).map(|_| Scalar::rand(rng)).collect::<Vec<_>>();
84 Poly::<Scalar>(coeffs)
85}
86
87impl<C> Poly<C> {
88 pub fn from(c: Vec<C>) -> Self {
90 Self(c)
91 }
92
93 pub fn constant(&self) -> &C {
95 &self.0[0]
96 }
97
98 pub fn degree(&self) -> u32 {
100 (self.0.len() - 1) as u32 }
102
103 pub fn required(&self) -> u32 {
107 self.0.len() as u32 }
109}
110
111impl<C: Element> Poly<C> {
112 pub fn commit(commits: Poly<Scalar>) -> Self {
118 let commits = commits
120 .0
121 .iter()
122 .map(|c| {
123 let mut commitment = C::one();
124 commitment.mul(c);
125 commitment
126 })
127 .collect::<Vec<C>>();
128
129 Poly::<C>::from(commits)
130 }
131
132 pub fn zero() -> Self {
134 Self::from(vec![C::zero()])
135 }
136
137 pub fn get(&self, i: u32) -> C {
141 self.0[i as usize].clone()
142 }
143
144 pub fn set(&mut self, index: u32, value: C) {
148 self.0[index as usize] = value;
149 }
150
151 pub fn add(&mut self, other: &Self) {
153 if self.0.len() < other.0.len() {
157 self.0.resize(other.0.len(), C::zero())
158 }
159
160 self.0.iter_mut().zip(&other.0).for_each(|(a, b)| a.add(b))
161 }
162
163 pub fn serialize(&self) -> Vec<u8> {
165 let mut bytes = Vec::new();
166 for c in &self.0 {
167 bytes.extend_from_slice(&c.serialize());
168 }
169 bytes
170 }
171
172 pub fn deserialize(bytes: &[u8], expected: u32) -> Option<Self> {
174 let expected = expected as usize;
175 let mut coeffs = Vec::with_capacity(expected);
176 for chunk in bytes.chunks_exact(C::size()) {
177 if coeffs.len() >= expected {
178 return None;
179 }
180 let c = C::deserialize(chunk)?;
181 coeffs.push(c);
182 }
183 if coeffs.len() != expected {
184 return None;
185 }
186 Some(Self(coeffs))
187 }
188
189 pub fn evaluate(&self, i: u32) -> Eval<C> {
191 let mut xi = Scalar::zero();
197 xi.set_int(i + 1);
198
199 let res = self.0.iter().rev().fold(C::zero(), |mut sum, coeff| {
201 sum.mul(&xi);
202 sum.add(coeff);
203 sum
204 });
205 Eval {
206 value: res,
207 index: i,
208 }
209 }
210
211 pub fn recover(t: u32, mut evals: Vec<Eval<C>>) -> Result<C, Error> {
213 let t = t as usize;
217 if evals.len() < t {
218 return Err(Error::InvalidRecovery);
219 }
220
221 let mut err = None;
223 evals.sort_by(|a, b| a.index.cmp(&b.index));
224 let xs = evals
225 .into_iter()
226 .take(t)
227 .fold(BTreeMap::new(), |mut m, sh| {
228 let mut xi = Scalar::zero();
229 xi.set_int(sh.index + 1);
230 if m.insert(sh.index, (xi, sh.value)).is_some() {
231 err = Some(Error::DuplicateEval);
232 }
233 m
234 });
235 if let Some(e) = err {
236 return Err(e);
237 }
238
239 let mut acc = C::zero();
242 for (i, xi) in &xs {
243 let mut yi = xi.1.clone();
244 let mut num = Scalar::one();
245 let mut den = Scalar::one();
246
247 for (j, xj) in &xs {
248 if i == j {
249 continue;
250 }
251
252 num.mul(&xj.0);
254
255 let mut tmp = xj.0;
257 tmp.sub(&xi.0);
258 den.mul(&tmp);
259 }
260
261 let inv = den.inverse().ok_or(Error::NoInverse)?;
262 num.mul(&inv);
263 yi.mul(&num);
264 acc.add(&yi);
265 }
266 Ok(acc)
267 }
268}
269
270pub fn public(public: &Public) -> group::Public {
272 *public.constant()
273}
274
275#[cfg(test)]
276pub mod tests {
277 use super::*;
279 use crate::bls12381::primitives::group::{Scalar, G2};
280
281 #[test]
282 fn poly_degree() {
283 let s = 5;
284 let p = new(s);
285 assert_eq!(p.degree(), s);
286 }
287
288 #[test]
289 fn add_zero() {
290 let p1 = new(3);
291 let p2 = Poly::<Scalar>::zero();
292 let mut res = p1.clone();
293 res.add(&p2);
294 assert_eq!(res, p1);
295
296 let p1 = Poly::<Scalar>::zero();
297 let p2 = new(3);
298 let mut res = p1;
299 res.add(&p2);
300 assert_eq!(res, p2);
301 }
302
303 #[test]
304 fn interpolation_insufficient_shares() {
305 let degree = 4;
306 let threshold = degree + 1;
307 let poly = new(degree);
308 let shares = (0..threshold - 1)
309 .map(|i| poly.evaluate(i))
310 .collect::<Vec<_>>();
311 Poly::recover(threshold, shares).unwrap_err();
312 }
313
314 #[test]
315 fn commit() {
316 let secret = new(5);
317 let coeffs = secret.0.clone();
318 let commitment = coeffs
319 .iter()
320 .map(|coeff| {
321 let mut p = G2::one();
322 p.mul(coeff);
323 p
324 })
325 .collect::<Vec<_>>();
326 let commitment = Poly::from(commitment);
327 assert_eq!(commitment, Poly::commit(secret));
328 }
329
330 fn pow(base: Scalar, pow: usize) -> Scalar {
331 let mut res = Scalar::one();
332 for _ in 0..pow {
333 res.mul(&base)
334 }
335 res
336 }
337
338 #[test]
339 fn addition() {
340 for deg1 in 0..100u32 {
341 for deg2 in 0..100u32 {
342 let p1 = new(deg1);
343 let p2 = new(deg2);
344 let mut res = p1.clone();
345 res.add(&p2);
346
347 let (larger, smaller) = if p1.degree() > p2.degree() {
348 (&p1, &p2)
349 } else {
350 (&p2, &p1)
351 };
352
353 for i in 0..larger.degree() + 1 {
354 let i = i as usize;
355 if i < (smaller.degree() + 1) as usize {
356 let mut coeff_sum = p1.0[i];
357 coeff_sum.add(&p2.0[i]);
358 assert_eq!(res.0[i], coeff_sum);
359 } else {
360 assert_eq!(res.0[i], larger.0[i]);
361 }
362 }
363 assert_eq!(
364 res.degree(),
365 larger.degree(),
366 "deg1={}, deg2={}",
367 deg1,
368 deg2
369 );
370 }
371 }
372 }
373
374 #[test]
375 fn interpolation() {
376 for degree in 0..100u32 {
377 for num_evals in 0..100u32 {
378 let poly = new(degree);
379 let expected = poly.0[0];
380
381 let shares = (0..num_evals).map(|i| poly.evaluate(i)).collect::<Vec<_>>();
382 let recovered_constant = Poly::recover(num_evals, shares).unwrap();
383
384 if num_evals > degree {
385 assert_eq!(
386 expected, recovered_constant,
387 "degree={}, num_evals={}",
388 degree, num_evals
389 );
390 } else {
391 assert_ne!(
392 expected, recovered_constant,
393 "degree={}, num_evals={}",
394 degree, num_evals
395 );
396 }
397 }
398 }
399 }
400
401 #[test]
402 fn evaluate() {
403 for d in 0..100u32 {
404 for idx in 0..100_u32 {
405 let mut x = Scalar::zero();
406 x.set_int(idx + 1);
407
408 let p1 = new(d);
409 let evaluation = p1.evaluate(idx).value;
410
411 let coeffs = p1.0;
412 let mut sum = coeffs[0];
413 for (i, coeff) in coeffs
414 .into_iter()
415 .enumerate()
416 .take((d + 1) as usize)
417 .skip(1)
418 {
419 let xi = pow(x, i);
420 let mut var = coeff;
421 var.mul(&xi);
422 sum.add(&var);
423 }
424
425 assert_eq!(sum, evaluation, "degree={}, idx={}", d, idx);
426 }
427 }
428 }
429}