Validate polynomial degrees: fix panics.
This commit is contained in:
parent
0bb41bd990
commit
84e8b69a24
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
|
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 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]
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue