Validate polynomial degrees: fix panics.

This commit is contained in:
Andreas Fackler 2018-10-04 18:03:42 +02:00 committed by Andreas Fackler
parent 0bb41bd990
commit 84e8b69a24
4 changed files with 101 additions and 22 deletions

View File

@ -9,6 +9,8 @@ pub enum Error {
NotEnoughShares, NotEnoughShares,
#[fail(display = "Signature shares contain a duplicated index")] #[fail(display = "Signature shares contain a duplicated index")]
DuplicateEntry, DuplicateEntry,
#[fail(display = "The degree is too high for the coefficients to be indexed by usize.")]
DegreeTooHigh,
#[fail( #[fail(
display = "Failed to `mlock` {} bytes starting at address: {}", display = "Failed to `mlock` {} bytes starting at address: {}",
n_bytes, n_bytes,

View File

@ -863,6 +863,14 @@ mod tests {
assert_eq!(None, sk_bob.decrypt(&fake_ciphertext)); 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] #[test]
fn test_threshold_enc() { fn test_threshold_enc() {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();

View File

@ -26,7 +26,7 @@ use pairing::bls12_381::{Fr, G1Affine, G1};
use pairing::{CurveAffine, CurveProjective, Field}; use pairing::{CurveAffine, CurveProjective, Field};
use rand::Rng; use rand::Rng;
use error::Result; use error::{Error, Result};
use into_fr::IntoFr; use into_fr::IntoFr;
use secret::{clear_fr, ContainsSecret, MemRange, Safe}; use secret::{clear_fr, ContainsSecret, MemRange, Safe};
@ -357,8 +357,12 @@ impl Poly {
/// ///
/// # Errors /// # 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> { 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(); let coeff: Vec<Fr> = (0..=degree).map(|_| rng.gen()).collect();
Poly::try_from(coeff) Poly::try_from(coeff)
} }
@ -744,9 +748,12 @@ impl BivarPoly {
/// ///
/// 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.
pub fn try_random<R: Rng>(degree: usize, rng: &mut R) -> Result<Self> { 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 { let poly = BivarPoly {
degree, degree,
coeff: (0..coeff_pos(degree + 1, 0)).map(|_| rng.gen()).collect(), coeff: (0..len).map(|_| rng.gen()).collect(),
}; };
poly.mlock_secret()?; poly.mlock_secret()?;
Ok(poly) Ok(poly)
@ -765,7 +772,8 @@ impl BivarPoly {
let mut result = Fr::zero(); let mut result = Fr::zero();
for (i, x_pow_i) in x_pow.into_iter().enumerate() { for (i, x_pow_i) in x_pow.into_iter().enumerate() {
for (j, y_pow_j) in y_pow.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(&x_pow_i);
summand.mul_assign(y_pow_j); summand.mul_assign(y_pow_j);
result.add_assign(&summand); result.add_assign(&summand);
@ -797,7 +805,8 @@ impl BivarPoly {
// TODO: clear these secrets from the stack. // TODO: clear these secrets from the stack.
let mut result = Fr::zero(); let mut result = Fr::zero();
for (j, x_pow_j) in x_pow.iter().enumerate() { 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); summand.mul_assign(x_pow_j);
result.add_assign(&summand); result.add_assign(&summand);
} }
@ -832,13 +841,12 @@ impl BivarPoly {
} }
/// A commitment to a symmetric bivariate polynomial. /// A commitment to a symmetric bivariate polynomial.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub struct BivarCommitment { pub struct BivarCommitment {
/// The polynomial's degree in each of the two variables. /// The polynomial's degree in each of the two variables.
degree: usize, pub(crate) degree: usize,
/// The commitments to the coefficients. /// The commitments to the coefficients.
#[serde(with = "super::serde_impl::projective_vec")] pub(crate) coeff: Vec<G1>,
coeff: Vec<G1>,
} }
impl Hash for BivarCommitment { impl Hash for BivarCommitment {
@ -864,7 +872,8 @@ impl BivarCommitment {
let mut result = G1::zero(); let mut result = G1::zero();
for (i, x_pow_i) in x_pow.into_iter().enumerate() { for (i, x_pow_i) in x_pow.into_iter().enumerate() {
for (j, y_pow_j) in y_pow.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(x_pow_i);
summand.mul_assign(*y_pow_j); summand.mul_assign(*y_pow_j);
result.add_assign(&summand); result.add_assign(&summand);
@ -880,7 +889,8 @@ impl BivarCommitment {
.map(|i| { .map(|i| {
let mut result = G1::zero(); let mut result = G1::zero();
for (j, x_pow_j) in x_pow.iter().enumerate() { 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); summand.mul_assign(*x_pow_j);
result.add_assign(&summand); 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 /// Returns the position of coefficient `(i, j)` in the vector describing a symmetric bivariate
/// polynomial. /// polynomial. If `i` or `j` are too large to represent the position as a `usize`, `None` is
fn coeff_pos(i: usize, j: usize) -> usize { /// returned.
pub(crate) fn coeff_pos(i: usize, j: usize) -> Option<usize> {
// Since the polynomial is symmetric, we can order such that `j >= i`. // Since the polynomial is symmetric, we can order such that `j >= i`.
if j >= i { let (j, i) = if j >= i { (j, i) } else { (i, j) };
j * (j + 1) / 2 + i i.checked_add(j.checked_mul(j.checked_add(1)?)? / 2)
} else {
i * (i + 1) / 2 + j
}
} }
#[cfg(test)] #[cfg(test)]
@ -932,7 +940,7 @@ mod tests {
let mut i = 0; let mut i = 0;
let mut j = 0; let mut j = 0;
for n in 0..100 { for n in 0..100 {
assert_eq!(n, coeff_pos(i, j)); assert_eq!(Some(n), coeff_pos(i, j));
if i >= j { if i >= j {
j += 1; j += 1;
i = 0; i = 0;
@ -940,6 +948,8 @@ mod tests {
i += 1; i += 1;
} }
} }
let too_large = 1 << (0usize.count_zeros() / 2);
assert_eq!(None, coeff_pos(0, too_large));
} }
#[test] #[test]

View File

@ -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. /// Serialization and deserialization of a group element's compressed representation.
pub mod projective { pub mod projective {
use pairing::{CurveAffine, CurveProjective, EncodedPoint}; use pairing::{CurveAffine, CurveProjective, EncodedPoint};
@ -34,6 +76,7 @@ pub mod projective {
/// Serialization and deserialization of vectors of projective curve elements. /// Serialization and deserialization of vectors of projective curve elements.
pub mod projective_vec { pub mod projective_vec {
use std::borrow::Borrow; use std::borrow::Borrow;
use std::iter::FromIterator;
use std::marker::PhantomData; use std::marker::PhantomData;
use pairing::CurveProjective; 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 where
S: Serializer, S: Serializer,
C: CurveProjective, 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) 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 where
D: Deserializer<'de>, D: Deserializer<'de>,
C: CurveProjective, C: CurveProjective,
T: FromIterator<C>,
{ {
let wrap_vec = <Vec<CurveWrap<C, C>>>::deserialize(d)?; let wrap_vec = <Vec<CurveWrap<C, C>>>::deserialize(d)?;
Ok(wrap_vec.into_iter().map(|CurveWrap(c, _)| c).collect()) Ok(wrap_vec.into_iter().map(|CurveWrap(c, _)| c).collect())
@ -156,6 +201,8 @@ mod tests {
use pairing::Engine; use pairing::Engine;
use rand::{self, Rng}; use rand::{self, Rng};
use poly::BivarPoly;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Vecs<E: Engine> { pub struct Vecs<E: Engine> {
#[serde(with = "super::projective_vec")] #[serde(with = "super::projective_vec")]
@ -181,4 +228,16 @@ mod tests {
let de_vecs = bincode::deserialize(&ser_vecs).expect("deserialize vecs"); let de_vecs = bincode::deserialize(&ser_vecs).expect("deserialize vecs");
assert_eq!(vecs, de_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);
}
}
} }