Validate polynomial degrees: fix panics.
This commit is contained in:
parent
0bb41bd990
commit
84e8b69a24
|
@ -9,6 +9,8 @@ pub enum Error {
|
|||
NotEnoughShares,
|
||||
#[fail(display = "Signature shares contain a duplicated index")]
|
||||
DuplicateEntry,
|
||||
#[fail(display = "The degree is too high for the coefficients to be indexed by usize.")]
|
||||
DegreeTooHigh,
|
||||
#[fail(
|
||||
display = "Failed to `mlock` {} bytes starting at address: {}",
|
||||
n_bytes,
|
||||
|
|
|
@ -863,6 +863,14 @@ mod tests {
|
|||
assert_eq!(None, sk_bob.decrypt(&fake_ciphertext));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_random_extreme_thresholds() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let sks = SecretKeySet::random(0, &mut rng);
|
||||
assert_eq!(0, sks.threshold());
|
||||
assert!(SecretKeySet::try_random(usize::max_value(), &mut rng).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_threshold_enc() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
|
48
src/poly.rs
48
src/poly.rs
|
@ -26,7 +26,7 @@ use pairing::bls12_381::{Fr, G1Affine, G1};
|
|||
use pairing::{CurveAffine, CurveProjective, Field};
|
||||
use rand::Rng;
|
||||
|
||||
use error::Result;
|
||||
use error::{Error, Result};
|
||||
use into_fr::IntoFr;
|
||||
use secret::{clear_fr, ContainsSecret, MemRange, Safe};
|
||||
|
||||
|
@ -357,8 +357,12 @@ impl Poly {
|
|||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an `Error::MlockFailed` if we have reached the systems's locked memory limit.
|
||||
/// Returns an `Error::MlockFailed` if we have reached the systems's locked memory limit or if
|
||||
/// the degree is `usize::max_value()`.
|
||||
pub fn try_random<R: Rng>(degree: usize, rng: &mut R) -> Result<Self> {
|
||||
if degree == usize::max_value() {
|
||||
return Err(Error::DegreeTooHigh);
|
||||
}
|
||||
let coeff: Vec<Fr> = (0..=degree).map(|_| rng.gen()).collect();
|
||||
Poly::try_from(coeff)
|
||||
}
|
||||
|
@ -744,9 +748,12 @@ impl BivarPoly {
|
|||
///
|
||||
/// Returns an `Error::MlockFailed` if we have reached the systems's locked memory limit.
|
||||
pub fn try_random<R: Rng>(degree: usize, rng: &mut R) -> Result<Self> {
|
||||
let len = coeff_pos(degree, degree)
|
||||
.and_then(|l| l.checked_add(1))
|
||||
.ok_or(Error::DegreeTooHigh)?;
|
||||
let poly = BivarPoly {
|
||||
degree,
|
||||
coeff: (0..coeff_pos(degree + 1, 0)).map(|_| rng.gen()).collect(),
|
||||
coeff: (0..len).map(|_| rng.gen()).collect(),
|
||||
};
|
||||
poly.mlock_secret()?;
|
||||
Ok(poly)
|
||||
|
@ -765,7 +772,8 @@ impl BivarPoly {
|
|||
let mut result = Fr::zero();
|
||||
for (i, x_pow_i) in x_pow.into_iter().enumerate() {
|
||||
for (j, y_pow_j) in y_pow.iter().enumerate() {
|
||||
let mut summand = self.coeff[coeff_pos(i, j)];
|
||||
let index = coeff_pos(i, j).expect("polynomial degree too high");
|
||||
let mut summand = self.coeff[index];
|
||||
summand.mul_assign(&x_pow_i);
|
||||
summand.mul_assign(y_pow_j);
|
||||
result.add_assign(&summand);
|
||||
|
@ -797,7 +805,8 @@ impl BivarPoly {
|
|||
// TODO: clear these secrets from the stack.
|
||||
let mut result = Fr::zero();
|
||||
for (j, x_pow_j) in x_pow.iter().enumerate() {
|
||||
let mut summand = self.coeff[coeff_pos(i, j)];
|
||||
let index = coeff_pos(i, j).expect("polynomial degree too high");
|
||||
let mut summand = self.coeff[index];
|
||||
summand.mul_assign(x_pow_j);
|
||||
result.add_assign(&summand);
|
||||
}
|
||||
|
@ -832,13 +841,12 @@ impl BivarPoly {
|
|||
}
|
||||
|
||||
/// A commitment to a symmetric bivariate polynomial.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct BivarCommitment {
|
||||
/// The polynomial's degree in each of the two variables.
|
||||
degree: usize,
|
||||
pub(crate) degree: usize,
|
||||
/// The commitments to the coefficients.
|
||||
#[serde(with = "super::serde_impl::projective_vec")]
|
||||
coeff: Vec<G1>,
|
||||
pub(crate) coeff: Vec<G1>,
|
||||
}
|
||||
|
||||
impl Hash for BivarCommitment {
|
||||
|
@ -864,7 +872,8 @@ impl BivarCommitment {
|
|||
let mut result = G1::zero();
|
||||
for (i, x_pow_i) in x_pow.into_iter().enumerate() {
|
||||
for (j, y_pow_j) in y_pow.iter().enumerate() {
|
||||
let mut summand = self.coeff[coeff_pos(i, j)];
|
||||
let index = coeff_pos(i, j).expect("polynomial degree too high");
|
||||
let mut summand = self.coeff[index];
|
||||
summand.mul_assign(x_pow_i);
|
||||
summand.mul_assign(*y_pow_j);
|
||||
result.add_assign(&summand);
|
||||
|
@ -880,7 +889,8 @@ impl BivarCommitment {
|
|||
.map(|i| {
|
||||
let mut result = G1::zero();
|
||||
for (j, x_pow_j) in x_pow.iter().enumerate() {
|
||||
let mut summand = self.coeff[coeff_pos(i, j)];
|
||||
let index = coeff_pos(i, j).expect("polynomial degree too high");
|
||||
let mut summand = self.coeff[index];
|
||||
summand.mul_assign(*x_pow_j);
|
||||
result.add_assign(&summand);
|
||||
}
|
||||
|
@ -907,14 +917,12 @@ fn powers<T: IntoFr>(into_x: T, degree: usize) -> Vec<Fr> {
|
|||
}
|
||||
|
||||
/// Returns the position of coefficient `(i, j)` in the vector describing a symmetric bivariate
|
||||
/// polynomial.
|
||||
fn coeff_pos(i: usize, j: usize) -> usize {
|
||||
/// polynomial. If `i` or `j` are too large to represent the position as a `usize`, `None` is
|
||||
/// returned.
|
||||
pub(crate) fn coeff_pos(i: usize, j: usize) -> Option<usize> {
|
||||
// Since the polynomial is symmetric, we can order such that `j >= i`.
|
||||
if j >= i {
|
||||
j * (j + 1) / 2 + i
|
||||
} else {
|
||||
i * (i + 1) / 2 + j
|
||||
}
|
||||
let (j, i) = if j >= i { (j, i) } else { (i, j) };
|
||||
i.checked_add(j.checked_mul(j.checked_add(1)?)? / 2)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -932,7 +940,7 @@ mod tests {
|
|||
let mut i = 0;
|
||||
let mut j = 0;
|
||||
for n in 0..100 {
|
||||
assert_eq!(n, coeff_pos(i, j));
|
||||
assert_eq!(Some(n), coeff_pos(i, j));
|
||||
if i >= j {
|
||||
j += 1;
|
||||
i = 0;
|
||||
|
@ -940,6 +948,8 @@ mod tests {
|
|||
i += 1;
|
||||
}
|
||||
}
|
||||
let too_large = 1 << (0usize.count_zeros() / 2);
|
||||
assert_eq!(None, coeff_pos(0, too_large));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,3 +1,45 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use pairing::bls12_381::G1;
|
||||
use serde::de::Error as DeserializeError;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use poly::{coeff_pos, BivarCommitment};
|
||||
|
||||
const ERR_DEG: &str = "commitment degree does not match coefficients";
|
||||
|
||||
/// A type with the same content as `BivarCommitment`, but that has not been validated yet.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct WireBivarCommitment<'a> {
|
||||
/// The polynomial's degree in each of the two variables.
|
||||
degree: usize,
|
||||
/// The commitments to the coefficients.
|
||||
#[serde(with = "projective_vec")]
|
||||
coeff: Cow<'a, [G1]>,
|
||||
}
|
||||
|
||||
impl Serialize for BivarCommitment {
|
||||
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
WireBivarCommitment {
|
||||
degree: self.degree,
|
||||
coeff: Cow::Borrowed(&self.coeff),
|
||||
}.serialize(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for BivarCommitment {
|
||||
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||
let WireBivarCommitment { degree, coeff } = Deserialize::deserialize(d)?;
|
||||
if coeff_pos(degree, degree).and_then(|l| l.checked_add(1)) != Some(coeff.len()) {
|
||||
return Err(D::Error::custom(ERR_DEG));
|
||||
}
|
||||
Ok(BivarCommitment {
|
||||
degree,
|
||||
coeff: coeff.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialization and deserialization of a group element's compressed representation.
|
||||
pub mod projective {
|
||||
use pairing::{CurveAffine, CurveProjective, EncodedPoint};
|
||||
|
@ -34,6 +76,7 @@ pub mod projective {
|
|||
/// Serialization and deserialization of vectors of projective curve elements.
|
||||
pub mod projective_vec {
|
||||
use std::borrow::Borrow;
|
||||
use std::iter::FromIterator;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use pairing::CurveProjective;
|
||||
|
@ -62,19 +105,21 @@ pub mod projective_vec {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn serialize<S, C>(vec: &[C], s: S) -> Result<S::Ok, S::Error>
|
||||
pub fn serialize<S, C, T>(vec: T, s: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
C: CurveProjective,
|
||||
T: AsRef<[C]>,
|
||||
{
|
||||
let wrap_vec: Vec<CurveWrap<C, &C>> = vec.iter().map(CurveWrap::new).collect();
|
||||
let wrap_vec: Vec<CurveWrap<C, &C>> = vec.as_ref().iter().map(CurveWrap::new).collect();
|
||||
wrap_vec.serialize(s)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, D, C>(d: D) -> Result<Vec<C>, D::Error>
|
||||
pub fn deserialize<'de, D, C, T>(d: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
C: CurveProjective,
|
||||
T: FromIterator<C>,
|
||||
{
|
||||
let wrap_vec = <Vec<CurveWrap<C, C>>>::deserialize(d)?;
|
||||
Ok(wrap_vec.into_iter().map(|CurveWrap(c, _)| c).collect())
|
||||
|
@ -156,6 +201,8 @@ mod tests {
|
|||
use pairing::Engine;
|
||||
use rand::{self, Rng};
|
||||
|
||||
use poly::BivarPoly;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Vecs<E: Engine> {
|
||||
#[serde(with = "super::projective_vec")]
|
||||
|
@ -181,4 +228,16 @@ mod tests {
|
|||
let de_vecs = bincode::deserialize(&ser_vecs).expect("deserialize vecs");
|
||||
assert_eq!(vecs, de_vecs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bivar_commitment() {
|
||||
let mut rng = rand::thread_rng();
|
||||
for deg in 1..8 {
|
||||
let poly = BivarPoly::random(deg, &mut rng);
|
||||
let comm = poly.commitment();
|
||||
let ser_comm = bincode::serialize(&comm).expect("serialize commitment");
|
||||
let de_comm = bincode::deserialize(&ser_comm).expect("deserialize commitment");
|
||||
assert_eq!(comm, de_comm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue