1use byteorder::LittleEndian;
11use byteorder::WriteBytesExt;
12use digest::Digest;
13use serde::Deserialize;
14use serde::Serialize;
15use thiserror::Error;
16
17extern crate alloc;
18use alloc::vec;
19use core::fmt::{Debug, Display, Formatter};
20use std::collections::HashMap;
21
22use crate::encoding::BinaryMarshaler;
23
24use crate::encoding::MarshallingError;
25use crate::group::HashFactory;
26use crate::{cipher::Stream, Group, Point, Scalar};
27
28type ScalarMap<GROUP> = HashMap<usize, <<GROUP as Group>::POINT as Point>::SCALAR>;
30
31type PointMap<GROUP> = HashMap<usize, <GROUP as Group>::POINT>;
33
34#[derive(Copy, Clone, Eq, PartialEq, Default, Serialize, Deserialize)]
36pub struct PriShare<SCALAR> {
37 pub i: usize,
39 pub v: SCALAR,
41}
42
43impl<SCALAR: Scalar> Debug for PriShare<SCALAR> {
44 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
45 f.debug_struct("PriShare").field("i", &self.i).finish()
46 }
47}
48
49impl<SCALAR: Scalar> Display for PriShare<SCALAR> {
50 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
51 write!(f, "PriShare( index: {} )", self.i)
52 }
53}
54
55impl<SCALAR: Scalar> PriShare<SCALAR> {
56 pub fn hash<HASHFACTORY: HashFactory>(&self, s: HASHFACTORY) -> Result<Vec<u8>, PolyError> {
58 let mut h = s.hash();
59 self.v.marshal_to(&mut h)?;
60 h.write_u32::<LittleEndian>(self.i as u32)?;
61 Ok(h.finalize().to_vec())
62 }
63}
64
65#[derive(Clone, Default, Serialize, Deserialize, Eq, PartialEq)]
67pub struct PriPoly<GROUP: Group> {
68 pub g: GROUP,
70 pub(crate) coeffs: Vec<<GROUP::POINT as Point>::SCALAR>,
72}
73
74impl<GROUP: Group> Debug for PriPoly<GROUP> {
75 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
76 f.debug_struct("PriPoly").field("g", &self.g).finish()
77 }
78}
79
80impl<GROUP: Group> Display for PriPoly<GROUP> {
81 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
82 write!(f, "PriPoly( group: {} )", self.g)
83 }
84}
85
86pub fn new_pri_poly<GROUP: Group, STREAM>(
91 group: GROUP,
92 t: usize,
93 s: Option<<GROUP::POINT as Point>::SCALAR>,
94 mut rand: STREAM,
95) -> PriPoly<GROUP>
96where
97 STREAM: Stream,
98{
99 let mut coeffs: Vec<<GROUP::POINT as Point>::SCALAR> = vec![];
100 coeffs.push(match s {
101 Some(v) => v,
102 None => group.scalar().pick(&mut rand),
103 });
104 for _ in 1..t {
105 coeffs.push(group.scalar().pick(&mut rand));
106 }
107 PriPoly { g: group, coeffs }
108}
109
110pub fn coefficients_to_pri_poly<GROUP: Group>(
112 g: &GROUP,
113 coeffs: &[<GROUP::POINT as Point>::SCALAR],
114) -> PriPoly<GROUP> {
115 PriPoly {
116 g: g.clone(),
117 coeffs: coeffs.to_vec(),
118 }
119}
120
121impl<GROUP: Group> PriPoly<GROUP> {
122 pub fn threshold(&self) -> usize {
124 self.coeffs.len()
125 }
126
127 pub fn secret(&self) -> <GROUP::POINT as Point>::SCALAR {
129 self.coeffs[0].clone()
130 }
131
132 pub fn eval(&self, i: usize) -> PriShare<<GROUP::POINT as Point>::SCALAR> {
134 let xi = self.g.scalar().set_int64(1 + i as i64);
135 let mut v = self.g.scalar().zero();
136 for j in (0..self.threshold()).rev() {
137 v = v * xi.clone();
138 v = v + self.coeffs[j].clone();
139 }
140 PriShare { i, v }
141 }
142
143 pub fn shares(&self, n: usize) -> Vec<Option<PriShare<<GROUP::POINT as Point>::SCALAR>>> {
145 let mut shares = Vec::with_capacity(n);
146 for i in 0..n {
147 shares.push(Some(self.eval(i)));
148 }
149 shares
150 }
151
152 pub fn add(&self, q: &PriPoly<GROUP>) -> Result<PriPoly<GROUP>, PolyError> {
155 if self.g.to_string() != q.g.to_string() {
156 return Err(PolyError::NoGroupsMatch);
157 }
158 if self.threshold() != q.threshold() {
159 return Err(PolyError::WrongCoefficientsNumber);
160 }
161 let mut coeffs = Vec::with_capacity(self.threshold());
162 for i in 0..self.threshold() {
164 coeffs.push(self.coeffs[i].clone() + q.coeffs[i].clone());
165 }
166 Ok(PriPoly {
167 g: self.g.clone(),
168 coeffs,
169 })
170 }
171
172 pub fn equal(&self, q: &PriPoly<GROUP>) -> Result<bool, PolyError> {
177 if self.g.to_string() != q.g.to_string() {
178 return Ok(false);
179 }
180 if self.coeffs.len() != q.coeffs.len() {
181 return Ok(false);
182 }
183 let mut b = true;
184 for i in 0..self.threshold() {
185 let pb = self.coeffs[i].marshal_binary()?;
186 let qb = q.coeffs[i].marshal_binary()?;
187 b &= pb.eq(&qb);
188 }
190 Ok(b)
191 }
192
193 pub fn commit(&self, b: Option<&GROUP::POINT>) -> PubPoly<GROUP> {
196 let mut commits = vec![];
197 for i in 0..self.threshold() {
198 commits.push(self.g.point().mul(&self.coeffs[i], b));
199 }
200
201 PubPoly {
202 g: self.g.clone(),
203 b: b.cloned(),
204 commits,
205 }
206 }
207
208 pub fn mul(&self, q: &Self) -> Self {
214 let d1 = self.coeffs.len() - 1;
215 let d2 = q.coeffs.len() - 1;
216 let new_degree = d1 + d2;
217 let mut coeffs = Vec::with_capacity(new_degree + 1);
218 for _ in 0..new_degree + 1 {
219 coeffs.push(self.g.scalar().zero());
220 }
221 for (i, cp) in self.coeffs.iter().enumerate() {
222 for (j, cq) in q.coeffs.iter().enumerate() {
223 let mut tmp = cp.clone();
224 tmp = tmp * cq.clone();
225 coeffs[i + j] = coeffs[i + j].clone() + tmp;
226 }
227 }
228 PriPoly {
229 g: self.g.clone(),
230 coeffs,
231 }
232 }
233
234 pub fn coefficients(&self) -> Vec<<GROUP::POINT as Point>::SCALAR> {
238 self.coeffs.clone()
239 }
240}
241
242pub fn recover_secret<GROUP: Group>(
245 g: GROUP,
246 shares: &[Option<PriShare<<GROUP::POINT as Point>::SCALAR>>],
247 t: usize,
248 n: usize,
249) -> Result<<GROUP::POINT as Point>::SCALAR, PolyError> {
250 let (x, y) = xy_scalar(&g, shares, t, n);
251 if x.len() < t {
252 return Err(PolyError::NotEnoughSharesForSecret);
253 }
254
255 let mut acc = g.scalar().zero();
256 let mut num = g.scalar();
257 let mut den = g.scalar();
258 let mut tmp = g.scalar();
259
260 for (i, xi) in x.iter() {
261 let yi = &y[i];
262 num = num.set(yi);
263 den = den.one();
264 for (j, xj) in x.iter() {
265 if i == j {
266 continue;
267 }
268 num = num * xj.clone();
269 tmp = tmp.sub(xj, xi);
270 den = den * tmp.clone();
271 }
272 let num_clone = num.clone();
273 num = num.div(&num_clone, &den);
274 acc = acc + num.clone();
275 }
276
277 Ok(acc)
278}
279
280fn xy_scalar<GROUP: Group>(
284 g: &GROUP,
285 shares: &[Option<PriShare<<GROUP::POINT as Point>::SCALAR>>],
286 t: usize,
287 n: usize,
288) -> (ScalarMap<GROUP>, ScalarMap<GROUP>) {
289 let mut sorted = Vec::with_capacity(n);
293 shares.iter().for_each(|share| {
294 if let Some(share) = share {
295 sorted.push(share);
296 }
297 });
298 sorted.sort_by(|i, j| i.i.cmp(&j.i));
299
300 let mut x = HashMap::new();
301 let mut y = HashMap::new();
302 for s in sorted {
303 let idx = s.i;
304 x.insert(idx, g.scalar().set_int64((idx + 1) as i64));
305 y.insert(idx, s.v.clone());
306 if x.len() == t {
307 break;
308 }
309 }
310 (x, y)
311}
312
313fn minus_const<GROUP: Group>(g: &GROUP, c: <GROUP::POINT as Point>::SCALAR) -> PriPoly<GROUP> {
314 let neg = g.scalar().neg(&c);
315 PriPoly {
316 g: g.clone(),
317 coeffs: vec![neg, g.scalar().one()],
318 }
319}
320
321pub fn recover_pri_poly<GROUP: Group>(
327 g: &GROUP,
328 shares: &[Option<PriShare<<GROUP::POINT as Point>::SCALAR>>],
329 t: usize,
330 n: usize,
331) -> Result<PriPoly<GROUP>, PolyError> {
332 let (x, y) = xy_scalar(g, shares, t, n);
333 if x.len() != t {
334 return Err(PolyError::NotEnoughSharesForPublic);
335 }
336
337 let mut acc_poly = PriPoly {
338 g: g.clone(),
339 coeffs: vec![],
340 };
341 for j in x.keys() {
345 let mut basis = lagrange_basis(g, *j, x.clone());
346 for (i, _) in basis.coeffs.clone().iter().enumerate() {
347 basis.coeffs[i] = basis.coeffs[i].clone() * y[j].clone();
348 }
349
350 if acc_poly.coeffs.is_empty() {
351 acc_poly = basis;
352 continue;
353 }
354
355 acc_poly = acc_poly.add(&basis)?;
356 }
357
358 Ok(acc_poly)
359}
360
361impl<GROUP: Group> PriPoly<GROUP> {
362 pub fn string(&self) -> String {
363 let mut strs = Vec::with_capacity(self.coeffs.len());
364 for c in self.coeffs.clone() {
365 strs.push(format!("{c}"));
366 }
367 "[ ".to_string() + &strs.join(", ") + " ]"
368 }
369}
370
371#[derive(Clone, Copy, Default, Debug, Serialize, Deserialize, Eq, PartialEq)]
373pub struct PubShare<POINT: Point> {
374 pub i: usize,
376 #[serde(deserialize_with = "POINT::deserialize")]
378 pub v: POINT,
379}
380
381impl<POINT: Point> Display for PubShare<POINT> {
382 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
383 write!(f, "PubShare( index: {}, value: {} )", self.i, self.v)
384 }
385}
386
387impl<POINT: Point> PubShare<POINT> {
388 pub fn hash<HASHFACTORY: HashFactory>(&self, s: HASHFACTORY) -> Result<Vec<u8>, PolyError> {
390 let mut h = s.hash();
391 self.v.marshal_to(&mut h)?;
392 h.write_u32::<LittleEndian>(self.i as u32)?;
393 Ok(h.finalize().to_vec())
394 }
395}
396
397#[derive(Clone, Eq, PartialEq, Debug, Default, Serialize, Deserialize)]
399pub struct PubPoly<GROUP: Group> {
400 g: GROUP,
402 b: Option<GROUP::POINT>,
404 commits: Vec<GROUP::POINT>,
406}
407
408impl<GROUP: Group> Display for PubPoly<GROUP> {
409 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
410 write!(f, "PubPoly( group: {},", self.g,)?;
411
412 write!(f, " base_point:")?;
413 match self.b {
414 Some(ref base) => write!(f, " Some({}),", base),
415 None => write!(f, " None,"),
416 }?;
417
418 write!(f, " commits: [")?;
419 let commits = self
420 .commits
421 .iter()
422 .map(|c| c.to_string())
423 .collect::<Vec<_>>()
424 .join(", ");
425 write!(f, "{}] )", commits)
426 }
427}
428
429impl<GROUP: Group> PubPoly<GROUP> {
430 pub fn new(g: &GROUP, b: Option<GROUP::POINT>, commits: &[GROUP::POINT]) -> PubPoly<GROUP> {
432 PubPoly {
433 g: g.clone(),
434 b,
435 commits: commits.to_vec(),
436 }
437 }
438}
439
440impl<GROUP: Group> PubPoly<GROUP> {
441 pub fn info(&self) -> (Option<GROUP::POINT>, Vec<GROUP::POINT>) {
443 (self.b.clone(), self.commits.clone())
444 }
445
446 pub fn threshold(&self) -> usize {
448 self.commits.len()
449 }
450
451 pub fn commit(&self) -> GROUP::POINT {
453 self.commits[0].clone()
454 }
455
456 pub fn eval(&self, i: usize) -> PubShare<GROUP::POINT> {
458 let xi = self.g.scalar().set_int64(1 + (i as i64));
460 let mut v = self.g.point();
461 v = v.null();
462 for j in (0..=(self.threshold() - 1)).rev() {
463 let v_clone = v.clone();
464 v = v.mul(&xi, Some(&v_clone));
465 let v_clone = v.clone();
466 v = v.add(&v_clone, &self.commits[j]);
467 }
468 PubShare { i, v }
469 }
470
471 pub fn shares(&self, n: usize) -> Vec<Option<PubShare<GROUP::POINT>>> {
473 let mut shares = Vec::with_capacity(n);
474 for i in 0..n {
475 shares.push(Some(self.eval(i)));
476 }
477 shares
478 }
479
480 pub fn add(&self, q: &Self) -> Result<Self, PolyError> {
487 if self.g.to_string() != q.g.to_string() {
488 return Err(PolyError::NoGroupsMatch);
489 }
490
491 if self.threshold() != q.threshold() {
492 return Err(PolyError::WrongCoefficientsNumber);
493 }
494
495 let mut commits = vec![];
496 for i in 0..self.threshold() {
497 commits.push(self.g.point().add(&self.commits[i], &q.commits[i]));
498 }
499
500 Ok(PubPoly {
501 g: self.g.clone(),
502 b: self.b.clone(),
503 commits,
504 })
505 }
506
507 pub fn equal(&self, q: &PubPoly<GROUP>) -> Result<bool, PolyError> {
512 if self.g.to_string() != q.g.to_string() {
513 return Ok(false);
514 }
515 let mut b = true;
516 for i in 0..self.threshold() {
517 let pb = self.commits[i].marshal_binary()?;
518 let qb = q.commits[i].marshal_binary()?;
519 b &= pb.eq(&qb);
520 }
522 Ok(b)
523 }
524
525 pub fn check(&self, s: &PriShare<<GROUP::POINT as Point>::SCALAR>) -> bool {
527 let pv = self.eval(s.i);
528 let ps = self.g.point().mul(&s.v, self.b.as_ref());
529 pv.v.eq(&ps)
530 }
531}
532
533pub fn xy_commit<GROUP: Group>(
535 g: &GROUP,
536 shares: &[Option<PubShare<GROUP::POINT>>],
537 t: usize,
538 n: usize,
539) -> (ScalarMap<GROUP>, PointMap<GROUP>) {
540 let mut sorted = Vec::with_capacity(n);
544 shares.iter().for_each(|share| {
545 if let Some(share) = share {
546 sorted.push(share);
547 }
548 });
549 sorted.sort_by(|i, j| i.i.cmp(&j.i));
550
551 let mut x = HashMap::new();
552 let mut y = HashMap::new();
553 for s in sorted {
554 let idx = s.i;
555 x.insert(idx, g.scalar().set_int64((idx + 1) as i64));
556 y.insert(idx, s.v.clone());
557 if x.len() == t {
558 break;
559 }
560 }
561 (x, y)
562}
563
564pub fn recover_commit<GROUP: Group>(
567 g: GROUP,
568 shares: &[Option<PubShare<GROUP::POINT>>],
569 t: usize,
570 n: usize,
571) -> Result<GROUP::POINT, PolyError> {
572 let (x, y) = xy_commit(&g, shares, t, n);
573
574 if x.len() < t {
575 return Err(PolyError::NotEnoughtGoodPublics);
576 }
577
578 let mut num = g.scalar();
579 let mut den = g.scalar();
580 let mut tmp = g.scalar();
581 let mut acc = g.point().null();
582 let mut tmp_p = g.point();
583
584 for (i, xi) in x.iter() {
585 num = num.one();
586 den = den.one();
587 for (j, xj) in x.iter() {
588 if i == j {
589 continue;
590 }
591 num = num * xj.clone();
592 tmp = tmp.sub(xj, xi);
593 den = den * tmp.clone();
594 }
595 let num_clone = num.clone();
596 num = num.div(&num_clone, &den);
597 tmp_p = tmp_p.mul(&num, Some(&y[i]));
598 let acc_clone = acc.clone();
599 acc = acc.add(&acc_clone, &tmp_p);
600 }
601
602 Ok(acc)
603}
604
605pub fn recover_pub_poly<GROUP: Group>(
608 g: GROUP,
609 shares: &[Option<PubShare<GROUP::POINT>>],
610 t: usize,
611 n: usize,
612) -> Result<PubPoly<GROUP>, PolyError> {
613 let (x, y) = xy_commit(&g, shares, t, n);
614 if x.len() < t {
615 return Err(PolyError::NotEnoughtGoodPublics);
616 }
617
618 let mut acc_poly = PubPoly::new(&g, None, &[]);
619
620 for (j, _) in x.iter().enumerate() {
621 let basis = lagrange_basis(&g, j, x.clone());
622
623 let tmp = basis.commit(Some(&y[&j]));
625 if acc_poly.commits.is_empty() {
626 acc_poly = tmp;
627 continue;
628 }
629
630 acc_poly = acc_poly.add(&tmp)?;
632 }
633
634 Ok(acc_poly)
635}
636
637fn lagrange_basis<GROUP: Group>(
641 g: &GROUP,
642 i: usize,
643 xs: HashMap<usize, <GROUP::POINT as Point>::SCALAR>,
644) -> PriPoly<GROUP> {
645 let mut basis = PriPoly {
646 g: g.clone(),
647 coeffs: vec![g.clone().scalar().one()],
648 };
649 let mut den = g.scalar().one();
651 let mut acc = g.scalar().one();
652 for (m, xm) in xs.iter() {
653 if &i == m {
654 continue;
655 }
656 basis = basis.mul(&minus_const(g, xm.clone()));
657 den = den.sub(&xs[&i], xm); let den_clone = den.clone();
659 den = den.inv(&den_clone); acc = acc * den.clone(); }
662
663 for (i, _) in basis.coeffs.clone().iter().enumerate() {
665 basis.coeffs[i] = basis.coeffs[i].clone() * acc.clone();
666 }
667 basis
668}
669
670#[derive(Error, Debug)]
671pub enum PolyError {
672 #[error("marshalling error")]
673 MarshallingError(#[from] MarshallingError),
674 #[error("io error")]
675 IoError(#[from] std::io::Error),
676 #[error("not enough good public shares to reconstruct secret commitment")]
677 NotEnoughtGoodPublics,
678 #[error("non-matching groups")]
679 NoGroupsMatch,
680 #[error("different number of coefficients")]
681 WrongCoefficientsNumber,
682 #[error("not enough shares to recover private polynomial")]
683 NotEnoughSharesForPublic,
684 #[error("not enough shares to recover secret")]
685 NotEnoughSharesForSecret,
686}