Remove generic E: Engine from crypto.
This commit is contained in:
parent
81cbe5a63b
commit
0c66e16010
235
mod.rs
235
mod.rs
|
@ -1,3 +1,7 @@
|
|||
// Clippy warns that it's dangerous to derive `PartialEq` and explicitly implement `Hash`, but the
|
||||
// `pairing::bls12_381` types don't implement `Hash`, so we can't derive it.
|
||||
#![cfg_attr(feature = "cargo-clippy", allow(derive_hash_xor_eq))]
|
||||
|
||||
pub mod error;
|
||||
pub mod poly;
|
||||
#[cfg(feature = "serialization-protobuf")]
|
||||
|
@ -10,6 +14,7 @@ use std::hash::{Hash, Hasher};
|
|||
use byteorder::{BigEndian, ByteOrder};
|
||||
use clear_on_drop::ClearOnDrop;
|
||||
use init_with::InitWith;
|
||||
use pairing::bls12_381::{Bls12, Fr, FrRepr, G1, G1Affine, G2, G2Affine};
|
||||
use pairing::{CurveAffine, CurveProjective, Engine, Field, PrimeField};
|
||||
use rand::{ChaChaRng, OsRng, Rng, SeedableRng};
|
||||
use ring::digest;
|
||||
|
@ -24,48 +29,42 @@ const CHACHA_RNG_SEED_SIZE: usize = 8;
|
|||
const ERR_OS_RNG: &str = "could not initialize the OS random number generator";
|
||||
|
||||
/// A public key, or a public key share.
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct PublicKey<E: Engine>(#[serde(with = "serde_impl::projective")] E::G1);
|
||||
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PublicKey(#[serde(with = "serde_impl::projective")] G1);
|
||||
|
||||
impl<E: Engine> PartialEq for PublicKey<E> {
|
||||
fn eq(&self, other: &PublicKey<E>) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Hash for PublicKey<E> {
|
||||
impl Hash for PublicKey {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.into_affine().into_compressed().as_ref().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> PublicKey<E> {
|
||||
/// Returns `true` if the signature matches the element of `E::G2`.
|
||||
pub fn verify_g2<H: Into<E::G2Affine>>(&self, sig: &Signature<E>, hash: H) -> bool {
|
||||
E::pairing(self.0, hash) == E::pairing(E::G1Affine::one(), sig.0)
|
||||
impl PublicKey {
|
||||
/// Returns `true` if the signature matches the element of `G2`.
|
||||
pub fn verify_g2<H: Into<G2Affine>>(&self, sig: &Signature, hash: H) -> bool {
|
||||
Bls12::pairing(self.0, hash) == Bls12::pairing(G1Affine::one(), sig.0)
|
||||
}
|
||||
|
||||
/// Returns `true` if the signature matches the message.
|
||||
pub fn verify<M: AsRef<[u8]>>(&self, sig: &Signature<E>, msg: M) -> bool {
|
||||
self.verify_g2(sig, hash_g2::<E, M>(msg))
|
||||
pub fn verify<M: AsRef<[u8]>>(&self, sig: &Signature, msg: M) -> bool {
|
||||
self.verify_g2(sig, hash_g2(msg))
|
||||
}
|
||||
|
||||
/// Returns `true` if the decryption share matches the ciphertext.
|
||||
pub fn verify_decryption_share(&self, share: &DecryptionShare<E>, ct: &Ciphertext<E>) -> bool {
|
||||
pub fn verify_decryption_share(&self, share: &DecryptionShare, ct: &Ciphertext) -> bool {
|
||||
let Ciphertext(ref u, ref v, ref w) = *ct;
|
||||
let hash = hash_g1_g2::<E, _>(*u, v);
|
||||
E::pairing(share.0, hash) == E::pairing(self.0, *w)
|
||||
let hash = hash_g1_g2(*u, v);
|
||||
Bls12::pairing(share.0, hash) == Bls12::pairing(self.0, *w)
|
||||
}
|
||||
|
||||
/// Encrypts the message.
|
||||
pub fn encrypt<M: AsRef<[u8]>>(&self, msg: M) -> Ciphertext<E> {
|
||||
let r: E::Fr = OsRng::new().expect(ERR_OS_RNG).gen();
|
||||
let u = E::G1Affine::one().mul(r);
|
||||
pub fn encrypt<M: AsRef<[u8]>>(&self, msg: M) -> Ciphertext {
|
||||
let r: Fr = OsRng::new().expect(ERR_OS_RNG).gen();
|
||||
let u = G1Affine::one().mul(r);
|
||||
let v: Vec<u8> = {
|
||||
let g = self.0.into_affine().mul(r);
|
||||
xor_vec(&hash_bytes::<E>(g, msg.as_ref().len()), msg.as_ref())
|
||||
xor_vec(&hash_bytes(g, msg.as_ref().len()), msg.as_ref())
|
||||
};
|
||||
let w = hash_g1_g2::<E, _>(u, &v).into_affine().mul(r);
|
||||
let w = hash_g1_g2(u, &v).into_affine().mul(r);
|
||||
Ciphertext(u, v, w)
|
||||
}
|
||||
|
||||
|
@ -76,10 +75,10 @@ impl<E: Engine> PublicKey<E> {
|
|||
}
|
||||
|
||||
/// A signature, or a signature share.
|
||||
#[derive(Deserialize, Serialize, Clone)]
|
||||
pub struct Signature<E: Engine>(#[serde(with = "serde_impl::projective")] E::G2);
|
||||
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
pub struct Signature(#[serde(with = "serde_impl::projective")] G2);
|
||||
|
||||
impl<E: Engine> fmt::Debug for Signature<E> {
|
||||
impl fmt::Debug for Signature {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let uncomp = self.0.into_affine().into_uncompressed();
|
||||
let bytes = uncomp.as_ref();
|
||||
|
@ -87,19 +86,13 @@ impl<E: Engine> fmt::Debug for Signature<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for Signature<E> {
|
||||
fn eq(&self, other: &Signature<E>) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Hash for Signature<E> {
|
||||
impl Hash for Signature {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.into_affine().into_compressed().as_ref().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Signature<E> {
|
||||
impl Signature {
|
||||
pub fn parity(&self) -> bool {
|
||||
let uncomp = self.0.into_affine().into_uncompressed();
|
||||
let bytes = uncomp.as_ref();
|
||||
|
@ -111,58 +104,52 @@ impl<E: Engine> Signature<E> {
|
|||
}
|
||||
|
||||
/// A secret key, or a secret key share.
|
||||
#[derive(Debug)]
|
||||
pub struct SecretKey<E: Engine>(E::Fr);
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct SecretKey(Fr);
|
||||
|
||||
impl<E: Engine> PartialEq for SecretKey<E> {
|
||||
fn eq(&self, other: &SecretKey<E>) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Default for SecretKey<E> {
|
||||
impl Default for SecretKey {
|
||||
fn default() -> Self {
|
||||
SecretKey(E::Fr::zero())
|
||||
SecretKey(Fr::zero())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> SecretKey<E> {
|
||||
impl SecretKey {
|
||||
/// Creates a new secret key.
|
||||
pub fn new<R: Rng>(rng: &mut R) -> Self {
|
||||
SecretKey(rng.gen())
|
||||
}
|
||||
|
||||
pub fn from_value(f: E::Fr) -> Self {
|
||||
pub fn from_value(f: Fr) -> Self {
|
||||
SecretKey(f)
|
||||
}
|
||||
|
||||
/// Returns the matching public key.
|
||||
pub fn public_key(&self) -> PublicKey<E> {
|
||||
PublicKey(E::G1Affine::one().mul(self.0))
|
||||
pub fn public_key(&self) -> PublicKey {
|
||||
PublicKey(G1Affine::one().mul(self.0))
|
||||
}
|
||||
|
||||
/// Signs the given element of `E::G2`.
|
||||
pub fn sign_g2<H: Into<E::G2Affine>>(&self, hash: H) -> Signature<E> {
|
||||
/// Signs the given element of `G2`.
|
||||
pub fn sign_g2<H: Into<G2Affine>>(&self, hash: H) -> Signature {
|
||||
Signature(hash.into().mul(self.0))
|
||||
}
|
||||
|
||||
/// Signs the given message.
|
||||
pub fn sign<M: AsRef<[u8]>>(&self, msg: M) -> Signature<E> {
|
||||
self.sign_g2(hash_g2::<E, M>(msg))
|
||||
pub fn sign<M: AsRef<[u8]>>(&self, msg: M) -> Signature {
|
||||
self.sign_g2(hash_g2(msg))
|
||||
}
|
||||
|
||||
/// Returns the decrypted text, or `None`, if the ciphertext isn't valid.
|
||||
pub fn decrypt(&self, ct: &Ciphertext<E>) -> Option<Vec<u8>> {
|
||||
pub fn decrypt(&self, ct: &Ciphertext) -> Option<Vec<u8>> {
|
||||
if !ct.verify() {
|
||||
return None;
|
||||
}
|
||||
let Ciphertext(ref u, ref v, _) = *ct;
|
||||
let g = u.into_affine().mul(self.0);
|
||||
Some(xor_vec(&hash_bytes::<E>(g, v.len()), v))
|
||||
Some(xor_vec(&hash_bytes(g, v.len()), v))
|
||||
}
|
||||
|
||||
/// Returns a decryption share, or `None`, if the ciphertext isn't valid.
|
||||
pub fn decrypt_share(&self, ct: &Ciphertext<E>) -> Option<DecryptionShare<E>> {
|
||||
pub fn decrypt_share(&self, ct: &Ciphertext) -> Option<DecryptionShare> {
|
||||
if !ct.verify() {
|
||||
return None;
|
||||
}
|
||||
|
@ -171,20 +158,14 @@ impl<E: Engine> SecretKey<E> {
|
|||
}
|
||||
|
||||
/// An encrypted message.
|
||||
#[derive(Deserialize, Serialize, Debug, Clone)]
|
||||
pub struct Ciphertext<E: Engine>(
|
||||
#[serde(with = "serde_impl::projective")] E::G1,
|
||||
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Ciphertext(
|
||||
#[serde(with = "serde_impl::projective")] G1,
|
||||
Vec<u8>,
|
||||
#[serde(with = "serde_impl::projective")] E::G2,
|
||||
#[serde(with = "serde_impl::projective")] G2,
|
||||
);
|
||||
|
||||
impl<E: Engine> PartialEq for Ciphertext<E> {
|
||||
fn eq(&self, other: &Ciphertext<E>) -> bool {
|
||||
self.0 == other.0 && self.1 == other.1 && self.2 == other.2
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Hash for Ciphertext<E> {
|
||||
impl Hash for Ciphertext {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Ciphertext(ref u, ref v, ref w) = *self;
|
||||
u.into_affine().into_compressed().as_ref().hash(state);
|
||||
|
@ -193,59 +174,47 @@ impl<E: Engine> Hash for Ciphertext<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Ciphertext<E> {
|
||||
impl Ciphertext {
|
||||
/// Returns `true` if this is a valid ciphertext. This check is necessary to prevent
|
||||
/// chosen-ciphertext attacks.
|
||||
pub fn verify(&self) -> bool {
|
||||
let Ciphertext(ref u, ref v, ref w) = *self;
|
||||
let hash = hash_g1_g2::<E, _>(*u, v);
|
||||
E::pairing(E::G1Affine::one(), *w) == E::pairing(*u, hash)
|
||||
let hash = hash_g1_g2(*u, v);
|
||||
Bls12::pairing(G1Affine::one(), *w) == Bls12::pairing(*u, hash)
|
||||
}
|
||||
}
|
||||
|
||||
/// A decryption share. A threshold of decryption shares can be used to decrypt a message.
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct DecryptionShare<E: Engine>(#[serde(with = "serde_impl::projective")] E::G1);
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
|
||||
pub struct DecryptionShare(#[serde(with = "serde_impl::projective")] G1);
|
||||
|
||||
impl<E: Engine> PartialEq for DecryptionShare<E> {
|
||||
fn eq(&self, other: &DecryptionShare<E>) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Hash for DecryptionShare<E> {
|
||||
impl Hash for DecryptionShare {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.0.into_affine().into_compressed().as_ref().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// A public key and an associated set of public key shares.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct PublicKeySet<E: Engine> {
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct PublicKeySet {
|
||||
/// The coefficients of a polynomial whose value at `0` is the "master key", and value at
|
||||
/// `i + 1` is key share number `i`.
|
||||
commit: Commitment<E>,
|
||||
commit: Commitment,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for PublicKeySet<E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.commit == other.commit
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Hash for PublicKeySet<E> {
|
||||
impl Hash for PublicKeySet {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.commit.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> From<Commitment<E>> for PublicKeySet<E> {
|
||||
fn from(commit: Commitment<E>) -> PublicKeySet<E> {
|
||||
impl From<Commitment> for PublicKeySet {
|
||||
fn from(commit: Commitment) -> PublicKeySet {
|
||||
PublicKeySet { commit }
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> PublicKeySet<E> {
|
||||
impl PublicKeySet {
|
||||
/// Returns the threshold `t`: any set of `t + 1` signature shares can be combined into a full
|
||||
/// signature.
|
||||
pub fn threshold(&self) -> usize {
|
||||
|
@ -253,51 +222,51 @@ impl<E: Engine> PublicKeySet<E> {
|
|||
}
|
||||
|
||||
/// Returns the public key.
|
||||
pub fn public_key(&self) -> PublicKey<E> {
|
||||
pub fn public_key(&self) -> PublicKey {
|
||||
PublicKey(self.commit.evaluate(0))
|
||||
}
|
||||
|
||||
/// Returns the `i`-th public key share.
|
||||
pub fn public_key_share<T: Into<<E::Fr as PrimeField>::Repr>>(&self, i: T) -> PublicKey<E> {
|
||||
PublicKey(self.commit.evaluate(from_repr_plus_1::<E::Fr>(i.into())))
|
||||
pub fn public_key_share<T: Into<FrRepr>>(&self, i: T) -> PublicKey {
|
||||
PublicKey(self.commit.evaluate(from_repr_plus_1::<Fr>(i.into())))
|
||||
}
|
||||
|
||||
/// Combines the shares into a signature that can be verified with the main public key.
|
||||
pub fn combine_signatures<'a, ITR, IND>(&self, shares: ITR) -> Result<Signature<E>>
|
||||
pub fn combine_signatures<'a, ITR, IND>(&self, shares: ITR) -> Result<Signature>
|
||||
where
|
||||
ITR: IntoIterator<Item = (&'a IND, &'a Signature<E>)>,
|
||||
IND: Into<<E::Fr as PrimeField>::Repr> + Clone + 'a,
|
||||
ITR: IntoIterator<Item = (&'a IND, &'a Signature)>,
|
||||
IND: Into<FrRepr> + Clone + 'a,
|
||||
{
|
||||
let samples = shares.into_iter().map(|(i, share)| (i, &share.0));
|
||||
Ok(Signature(interpolate(self.commit.degree() + 1, samples)?))
|
||||
}
|
||||
|
||||
/// Combines the shares to decrypt the ciphertext.
|
||||
pub fn decrypt<'a, ITR, IND>(&self, shares: ITR, ct: &Ciphertext<E>) -> Result<Vec<u8>>
|
||||
pub fn decrypt<'a, ITR, IND>(&self, shares: ITR, ct: &Ciphertext) -> Result<Vec<u8>>
|
||||
where
|
||||
ITR: IntoIterator<Item = (&'a IND, &'a DecryptionShare<E>)>,
|
||||
IND: Into<<E::Fr as PrimeField>::Repr> + Clone + 'a,
|
||||
ITR: IntoIterator<Item = (&'a IND, &'a DecryptionShare)>,
|
||||
IND: Into<FrRepr> + Clone + 'a,
|
||||
{
|
||||
let samples = shares.into_iter().map(|(i, share)| (i, &share.0));
|
||||
let g = interpolate(self.commit.degree() + 1, samples)?;
|
||||
Ok(xor_vec(&hash_bytes::<E>(g, ct.1.len()), &ct.1))
|
||||
Ok(xor_vec(&hash_bytes(g, ct.1.len()), &ct.1))
|
||||
}
|
||||
}
|
||||
|
||||
/// A secret key and an associated set of secret key shares.
|
||||
pub struct SecretKeySet<E: Engine> {
|
||||
pub struct SecretKeySet {
|
||||
/// The coefficients of a polynomial whose value at `0` is the "master key", and value at
|
||||
/// `i + 1` is key share number `i`.
|
||||
poly: Poly<E>,
|
||||
poly: Poly,
|
||||
}
|
||||
|
||||
impl<E: Engine> From<Poly<E>> for SecretKeySet<E> {
|
||||
fn from(poly: Poly<E>) -> SecretKeySet<E> {
|
||||
impl From<Poly> for SecretKeySet {
|
||||
fn from(poly: Poly) -> SecretKeySet {
|
||||
SecretKeySet { poly }
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> SecretKeySet<E> {
|
||||
impl SecretKeySet {
|
||||
/// Creates a set of secret key shares, where any `threshold + 1` of them can collaboratively
|
||||
/// sign and decrypt.
|
||||
pub fn random<R: Rng>(threshold: usize, rng: &mut R) -> Self {
|
||||
|
@ -313,17 +282,14 @@ impl<E: Engine> SecretKeySet<E> {
|
|||
}
|
||||
|
||||
/// Returns the `i`-th secret key share.
|
||||
pub fn secret_key_share<T>(&self, i: T) -> ClearOnDrop<Box<SecretKey<E>>>
|
||||
where
|
||||
T: Into<<E::Fr as PrimeField>::Repr>,
|
||||
{
|
||||
pub fn secret_key_share<T: Into<FrRepr>>(&self, i: T) -> ClearOnDrop<Box<SecretKey>> {
|
||||
ClearOnDrop::new(Box::new(SecretKey(
|
||||
self.poly.evaluate(from_repr_plus_1::<E::Fr>(i.into())),
|
||||
self.poly.evaluate(from_repr_plus_1::<Fr>(i.into())),
|
||||
)))
|
||||
}
|
||||
|
||||
/// Returns the corresponding public key set. That information can be shared publicly.
|
||||
pub fn public_keys(&self) -> PublicKeySet<E> {
|
||||
pub fn public_keys(&self) -> PublicKeySet {
|
||||
PublicKeySet {
|
||||
commit: self.poly.commitment(),
|
||||
}
|
||||
|
@ -331,13 +297,13 @@ impl<E: Engine> SecretKeySet<E> {
|
|||
|
||||
/// Returns the secret master key.
|
||||
#[cfg(test)]
|
||||
fn secret_key(&self) -> SecretKey<E> {
|
||||
fn secret_key(&self) -> SecretKey {
|
||||
SecretKey(self.poly.evaluate(0))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a hash of the given message in `G2`.
|
||||
fn hash_g2<E: Engine, M: AsRef<[u8]>>(msg: M) -> E::G2 {
|
||||
fn hash_g2<M: AsRef<[u8]>>(msg: M) -> G2 {
|
||||
let digest = digest::digest(&digest::SHA256, msg.as_ref());
|
||||
let seed = <[u32; CHACHA_RNG_SEED_SIZE]>::init_with_indices(|i| {
|
||||
BigEndian::read_u32(&digest.as_ref()[(4 * i)..(4 * i + 4)])
|
||||
|
@ -347,7 +313,7 @@ fn hash_g2<E: Engine, M: AsRef<[u8]>>(msg: M) -> E::G2 {
|
|||
}
|
||||
|
||||
/// Returns a hash of the group element and message, in the second group.
|
||||
fn hash_g1_g2<E: Engine, M: AsRef<[u8]>>(g1: E::G1, msg: M) -> E::G2 {
|
||||
fn hash_g1_g2<M: AsRef<[u8]>>(g1: G1, msg: M) -> G2 {
|
||||
// If the message is large, hash it, otherwise copy it.
|
||||
// TODO: Benchmark and optimize the threshold.
|
||||
let mut msg = if msg.as_ref().len() > 64 {
|
||||
|
@ -357,11 +323,11 @@ fn hash_g1_g2<E: Engine, M: AsRef<[u8]>>(g1: E::G1, msg: M) -> E::G2 {
|
|||
msg.as_ref().to_vec()
|
||||
};
|
||||
msg.extend(g1.into_affine().into_compressed().as_ref());
|
||||
hash_g2::<E, _>(&msg)
|
||||
hash_g2(&msg)
|
||||
}
|
||||
|
||||
/// Returns a hash of the group element with the specified length in bytes.
|
||||
fn hash_bytes<E: Engine>(g1: E::G1, len: usize) -> Vec<u8> {
|
||||
fn hash_bytes(g1: G1, len: usize) -> Vec<u8> {
|
||||
let digest = digest::digest(&digest::SHA256, g1.into_affine().into_compressed().as_ref());
|
||||
let seed = <[u32; CHACHA_RNG_SEED_SIZE]>::init_with_indices(|i| {
|
||||
BigEndian::read_u32(&digest.as_ref()[(4 * i)..(4 * i + 4)])
|
||||
|
@ -423,14 +389,13 @@ mod tests {
|
|||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use pairing::bls12_381::Bls12;
|
||||
use rand;
|
||||
|
||||
#[test]
|
||||
fn test_simple_sig() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let sk0 = SecretKey::<Bls12>::new(&mut rng);
|
||||
let sk1 = SecretKey::<Bls12>::new(&mut rng);
|
||||
let sk0 = SecretKey::new(&mut rng);
|
||||
let sk1 = SecretKey::new(&mut rng);
|
||||
let pk0 = sk0.public_key();
|
||||
let msg0 = b"Real news";
|
||||
let msg1 = b"Fake news";
|
||||
|
@ -442,7 +407,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_threshold_sig() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let sk_set = SecretKeySet::<Bls12>::random(3, &mut rng);
|
||||
let sk_set = SecretKeySet::random(3, &mut rng);
|
||||
let pk_set = sk_set.public_keys();
|
||||
|
||||
// Make sure the keys are different, and the first coefficient is the main key.
|
||||
|
@ -484,8 +449,8 @@ mod tests {
|
|||
#[test]
|
||||
fn test_simple_enc() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let sk_bob = SecretKey::<Bls12>::new(&mut rng);
|
||||
let sk_eve = SecretKey::<Bls12>::new(&mut rng);
|
||||
let sk_bob = SecretKey::new(&mut rng);
|
||||
let sk_eve = SecretKey::new(&mut rng);
|
||||
let pk_bob = sk_bob.public_key();
|
||||
let msg = b"Muffins in the canteen today! Don't tell Eve!";
|
||||
let ciphertext = pk_bob.encrypt(&msg[..]);
|
||||
|
@ -501,7 +466,7 @@ mod tests {
|
|||
|
||||
// Eve tries to trick Bob into decrypting `msg` xor `v`, but it doesn't validate.
|
||||
let Ciphertext(u, v, w) = ciphertext;
|
||||
let fake_ciphertext = Ciphertext::<Bls12>(u, vec![0; v.len()], w);
|
||||
let fake_ciphertext = Ciphertext(u, vec![0; v.len()], w);
|
||||
assert!(!fake_ciphertext.verify());
|
||||
assert_eq!(None, sk_bob.decrypt(&fake_ciphertext));
|
||||
}
|
||||
|
@ -509,7 +474,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_threshold_enc() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let sk_set = SecretKeySet::<Bls12>::random(3, &mut rng);
|
||||
let sk_set = SecretKeySet::random(3, &mut rng);
|
||||
let pk_set = sk_set.public_keys();
|
||||
let msg = b"Totally real news";
|
||||
let ciphertext = pk_set.public_key().encrypt(&msg[..]);
|
||||
|
@ -546,10 +511,9 @@ mod tests {
|
|||
let msg_end0: Vec<u8> = msg.iter().chain(b"end0").cloned().collect();
|
||||
let msg_end1: Vec<u8> = msg.iter().chain(b"end1").cloned().collect();
|
||||
|
||||
let hash = hash_g2::<Bls12, _>;
|
||||
assert_eq!(hash(&msg), hash(&msg));
|
||||
assert_ne!(hash(&msg), hash(&msg_end0));
|
||||
assert_ne!(hash(&msg_end0), hash(&msg_end1));
|
||||
assert_eq!(hash_g2(&msg), hash_g2(&msg));
|
||||
assert_ne!(hash_g2(&msg), hash_g2(&msg_end0));
|
||||
assert_ne!(hash_g2(&msg_end0), hash_g2(&msg_end1));
|
||||
}
|
||||
|
||||
/// Some basic sanity checks for the `hash_g1_g2` function.
|
||||
|
@ -562,11 +526,10 @@ mod tests {
|
|||
let g0 = rng.gen();
|
||||
let g1 = rng.gen();
|
||||
|
||||
let hash = hash_g1_g2::<Bls12, _>;
|
||||
assert_eq!(hash(g0, &msg), hash(g0, &msg));
|
||||
assert_ne!(hash(g0, &msg), hash(g0, &msg_end0));
|
||||
assert_ne!(hash(g0, &msg_end0), hash(g0, &msg_end1));
|
||||
assert_ne!(hash(g0, &msg), hash(g1, &msg));
|
||||
assert_eq!(hash_g1_g2(g0, &msg), hash_g1_g2(g0, &msg));
|
||||
assert_ne!(hash_g1_g2(g0, &msg), hash_g1_g2(g0, &msg_end0));
|
||||
assert_ne!(hash_g1_g2(g0, &msg_end0), hash_g1_g2(g0, &msg_end1));
|
||||
assert_ne!(hash_g1_g2(g0, &msg), hash_g1_g2(g1, &msg));
|
||||
}
|
||||
|
||||
/// Some basic sanity checks for the `hash_bytes` function.
|
||||
|
@ -575,7 +538,7 @@ mod tests {
|
|||
let mut rng = rand::thread_rng();
|
||||
let g0 = rng.gen();
|
||||
let g1 = rng.gen();
|
||||
let hash = hash_bytes::<Bls12>;
|
||||
let hash = hash_bytes;
|
||||
assert_eq!(hash(g0, 5), hash(g0, 5));
|
||||
assert_ne!(hash(g0, 5), hash(g1, 5));
|
||||
assert_eq!(5, hash(g0, 5).len());
|
||||
|
@ -588,7 +551,7 @@ mod tests {
|
|||
use bincode;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let sk = SecretKey::<Bls12>::new(&mut rng);
|
||||
let sk = SecretKey::new(&mut rng);
|
||||
let sig = sk.sign("Please sign here: ______");
|
||||
let pk = sk.public_key();
|
||||
let ser_pk = bincode::serialize(&pk).expect("serialize public key");
|
||||
|
|
183
poly.rs
183
poly.rs
|
@ -20,27 +20,22 @@ use std::borrow::Borrow;
|
|||
use std::hash::{Hash, Hasher};
|
||||
use std::{cmp, iter, ops};
|
||||
|
||||
use pairing::{CurveAffine, CurveProjective, Engine, Field, PrimeField};
|
||||
use pairing::bls12_381::{Fr, FrRepr, G1, G1Affine};
|
||||
use pairing::{CurveAffine, CurveProjective, Field, PrimeField};
|
||||
use rand::Rng;
|
||||
|
||||
/// A univariate polynomial in the prime field.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Poly<E: Engine> {
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Poly {
|
||||
/// The coefficients of a polynomial.
|
||||
#[serde(with = "super::serde_impl::field_vec")]
|
||||
coeff: Vec<E::Fr>,
|
||||
coeff: Vec<Fr>,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for Poly<E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.coeff == other.coeff
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Borrow<Poly<E>>, E: Engine> ops::AddAssign<B> for Poly<E> {
|
||||
impl<B: Borrow<Poly>> ops::AddAssign<B> for Poly {
|
||||
fn add_assign(&mut self, rhs: B) {
|
||||
let len = cmp::max(self.coeff.len(), rhs.borrow().coeff.len());
|
||||
self.coeff.resize(len, E::Fr::zero());
|
||||
self.coeff.resize(len, Fr::zero());
|
||||
for (self_c, rhs_c) in self.coeff.iter_mut().zip(&rhs.borrow().coeff) {
|
||||
self_c.add_assign(rhs_c);
|
||||
}
|
||||
|
@ -48,27 +43,27 @@ impl<B: Borrow<Poly<E>>, E: Engine> ops::AddAssign<B> for Poly<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, B: Borrow<Poly<E>>, E: Engine> ops::Add<B> for &'a Poly<E> {
|
||||
type Output = Poly<E>;
|
||||
impl<'a, B: Borrow<Poly>> ops::Add<B> for &'a Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn add(self, rhs: B) -> Poly<E> {
|
||||
fn add(self, rhs: B) -> Poly {
|
||||
(*self).clone() + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Borrow<Poly<E>>, E: Engine> ops::Add<B> for Poly<E> {
|
||||
type Output = Poly<E>;
|
||||
impl<B: Borrow<Poly>> ops::Add<B> for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn add(mut self, rhs: B) -> Poly<E> {
|
||||
fn add(mut self, rhs: B) -> Poly {
|
||||
self += rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Borrow<Poly<E>>, E: Engine> ops::SubAssign<B> for Poly<E> {
|
||||
impl<B: Borrow<Poly>> ops::SubAssign<B> for Poly {
|
||||
fn sub_assign(&mut self, rhs: B) {
|
||||
let len = cmp::max(self.coeff.len(), rhs.borrow().coeff.len());
|
||||
self.coeff.resize(len, E::Fr::zero());
|
||||
self.coeff.resize(len, Fr::zero());
|
||||
for (self_c, rhs_c) in self.coeff.iter_mut().zip(&rhs.borrow().coeff) {
|
||||
self_c.sub_assign(rhs_c);
|
||||
}
|
||||
|
@ -76,18 +71,18 @@ impl<B: Borrow<Poly<E>>, E: Engine> ops::SubAssign<B> for Poly<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, B: Borrow<Poly<E>>, E: Engine> ops::Sub<B> for &'a Poly<E> {
|
||||
type Output = Poly<E>;
|
||||
impl<'a, B: Borrow<Poly>> ops::Sub<B> for &'a Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn sub(self, rhs: B) -> Poly<E> {
|
||||
fn sub(self, rhs: B) -> Poly {
|
||||
(*self).clone() - rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Borrow<Poly<E>>, E: Engine> ops::Sub<B> for Poly<E> {
|
||||
type Output = Poly<E>;
|
||||
impl<B: Borrow<Poly>> ops::Sub<B> for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn sub(mut self, rhs: B) -> Poly<E> {
|
||||
fn sub(mut self, rhs: B) -> Poly {
|
||||
self -= rhs;
|
||||
self
|
||||
}
|
||||
|
@ -95,13 +90,13 @@ impl<B: Borrow<Poly<E>>, E: Engine> ops::Sub<B> for Poly<E> {
|
|||
|
||||
// Clippy thinks using any `+` and `-` in a `Mul` implementation is suspicious.
|
||||
#[cfg_attr(feature = "cargo-clippy", allow(suspicious_arithmetic_impl))]
|
||||
impl<'a, B: Borrow<Poly<E>>, E: Engine> ops::Mul<B> for &'a Poly<E> {
|
||||
type Output = Poly<E>;
|
||||
impl<'a, B: Borrow<Poly>> ops::Mul<B> for &'a Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn mul(self, rhs: B) -> Self::Output {
|
||||
let coeff = (0..(self.coeff.len() + rhs.borrow().coeff.len() - 1))
|
||||
.map(|i| {
|
||||
let mut c = E::Fr::zero();
|
||||
let mut c = Fr::zero();
|
||||
for j in i.saturating_sub(rhs.borrow().degree())..(1 + cmp::min(i, self.degree())) {
|
||||
let mut s = self.coeff[j];
|
||||
s.mul_assign(&rhs.borrow().coeff[i - j]);
|
||||
|
@ -114,21 +109,21 @@ impl<'a, B: Borrow<Poly<E>>, E: Engine> ops::Mul<B> for &'a Poly<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B: Borrow<Poly<E>>, E: Engine> ops::Mul<B> for Poly<E> {
|
||||
type Output = Poly<E>;
|
||||
impl<B: Borrow<Poly>> ops::Mul<B> for Poly {
|
||||
type Output = Poly;
|
||||
|
||||
fn mul(self, rhs: B) -> Self::Output {
|
||||
&self * rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Borrow<Self>, E: Engine> ops::MulAssign<B> for Poly<E> {
|
||||
impl<B: Borrow<Self>> ops::MulAssign<B> for Poly {
|
||||
fn mul_assign(&mut self, rhs: B) {
|
||||
*self = &*self * rhs;
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Poly<E> {
|
||||
impl Poly {
|
||||
/// Creates a random polynomial.
|
||||
pub fn random<R: Rng>(degree: usize, rng: &mut R) -> Self {
|
||||
Poly {
|
||||
|
@ -147,7 +142,7 @@ impl<E: Engine> Poly<E> {
|
|||
}
|
||||
|
||||
/// Returns the polynomial with constant value `c`.
|
||||
pub fn constant(c: E::Fr) -> Self {
|
||||
pub fn constant(c: Fr) -> Self {
|
||||
Poly { coeff: vec![c] }
|
||||
}
|
||||
|
||||
|
@ -159,9 +154,9 @@ impl<E: Engine> Poly<E> {
|
|||
/// Returns the (monic) monomial "`x.pow(degree)`".
|
||||
pub fn monomial(degree: usize) -> Self {
|
||||
Poly {
|
||||
coeff: iter::repeat(E::Fr::zero())
|
||||
coeff: iter::repeat(Fr::zero())
|
||||
.take(degree)
|
||||
.chain(iter::once(E::Fr::one()))
|
||||
.chain(iter::once(Fr::one()))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
@ -170,14 +165,14 @@ impl<E: Engine> Poly<E> {
|
|||
/// `(x, f(x))`.
|
||||
pub fn interpolate<'a, T, I>(samples_repr: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = (&'a T, &'a E::Fr)>,
|
||||
T: Into<<E::Fr as PrimeField>::Repr> + Clone + 'a,
|
||||
I: IntoIterator<Item = (&'a T, &'a Fr)>,
|
||||
T: Into<FrRepr> + Clone + 'a,
|
||||
{
|
||||
let convert = |(x_repr, y): (&T, &E::Fr)| {
|
||||
let x = E::Fr::from_repr(x_repr.clone().into()).expect("invalid index");
|
||||
let convert = |(x_repr, y): (&T, &Fr)| {
|
||||
let x = Fr::from_repr(x_repr.clone().into()).expect("invalid index");
|
||||
(x, *y)
|
||||
};
|
||||
let samples: Vec<(E::Fr, E::Fr)> = samples_repr.into_iter().map(convert).collect();
|
||||
let samples: Vec<(Fr, Fr)> = samples_repr.into_iter().map(convert).collect();
|
||||
Self::compute_interpolation(&samples)
|
||||
}
|
||||
|
||||
|
@ -187,12 +182,12 @@ impl<E: Engine> Poly<E> {
|
|||
}
|
||||
|
||||
/// Returns the value at the point `i`.
|
||||
pub fn evaluate<T: Into<<E::Fr as PrimeField>::Repr>>(&self, i: T) -> E::Fr {
|
||||
pub fn evaluate<T: Into<FrRepr>>(&self, i: T) -> Fr {
|
||||
let mut result = match self.coeff.last() {
|
||||
None => return E::Fr::zero(),
|
||||
None => return Fr::zero(),
|
||||
Some(c) => *c,
|
||||
};
|
||||
let x = E::Fr::from_repr(i.into()).expect("invalid index");
|
||||
let x = Fr::from_repr(i.into()).expect("invalid index");
|
||||
for c in self.coeff.iter().rev().skip(1) {
|
||||
result.mul_assign(&x);
|
||||
result.add_assign(c);
|
||||
|
@ -201,8 +196,8 @@ impl<E: Engine> Poly<E> {
|
|||
}
|
||||
|
||||
/// Returns the corresponding commitment.
|
||||
pub fn commitment(&self) -> Commitment<E> {
|
||||
let to_g1 = |c: &E::Fr| E::G1Affine::one().mul(*c);
|
||||
pub fn commitment(&self) -> Commitment {
|
||||
let to_g1 = |c: &Fr| G1Affine::one().mul(*c);
|
||||
Commitment {
|
||||
coeff: self.coeff.iter().map(to_g1).collect(),
|
||||
}
|
||||
|
@ -217,7 +212,7 @@ impl<E: Engine> Poly<E> {
|
|||
|
||||
/// Returns the unique polynomial `f` of degree `samples.len() - 1` with the given values
|
||||
/// `(x, f(x))`.
|
||||
fn compute_interpolation(samples: &[(E::Fr, E::Fr)]) -> Self {
|
||||
fn compute_interpolation(samples: &[(Fr, Fr)]) -> Self {
|
||||
if samples.is_empty() {
|
||||
return Poly::zero();
|
||||
} else if samples.len() == 1 {
|
||||
|
@ -234,7 +229,7 @@ impl<E: Engine> Poly<E> {
|
|||
}
|
||||
|
||||
/// Returns the Lagrange base polynomial that is `1` in `p` and `0` in every `samples[i].0`.
|
||||
fn lagrange(p: E::Fr, samples: &[(E::Fr, E::Fr)]) -> Self {
|
||||
fn lagrange(p: Fr, samples: &[(Fr, Fr)]) -> Self {
|
||||
let mut result = Self::one();
|
||||
for &(sx, _) in samples {
|
||||
let mut denom = p;
|
||||
|
@ -247,20 +242,14 @@ impl<E: Engine> Poly<E> {
|
|||
}
|
||||
|
||||
/// A commitment to a univariate polynomial.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Commitment<E: Engine> {
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Commitment {
|
||||
/// The coefficients of the polynomial.
|
||||
#[serde(with = "super::serde_impl::projective_vec")]
|
||||
coeff: Vec<E::G1>,
|
||||
coeff: Vec<G1>,
|
||||
}
|
||||
|
||||
impl<E: Engine> PartialEq for Commitment<E> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.coeff == other.coeff
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Hash for Commitment<E> {
|
||||
impl Hash for Commitment {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.coeff.len().hash(state);
|
||||
for c in &self.coeff {
|
||||
|
@ -269,10 +258,10 @@ impl<E: Engine> Hash for Commitment<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<B: Borrow<Commitment<E>>, E: Engine> ops::AddAssign<B> for Commitment<E> {
|
||||
impl<B: Borrow<Commitment>> ops::AddAssign<B> for Commitment {
|
||||
fn add_assign(&mut self, rhs: B) {
|
||||
let len = cmp::max(self.coeff.len(), rhs.borrow().coeff.len());
|
||||
self.coeff.resize(len, E::G1::zero());
|
||||
self.coeff.resize(len, G1::zero());
|
||||
for (self_c, rhs_c) in self.coeff.iter_mut().zip(&rhs.borrow().coeff) {
|
||||
self_c.add_assign(rhs_c);
|
||||
}
|
||||
|
@ -280,36 +269,36 @@ impl<B: Borrow<Commitment<E>>, E: Engine> ops::AddAssign<B> for Commitment<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, B: Borrow<Commitment<E>>, E: Engine> ops::Add<B> for &'a Commitment<E> {
|
||||
type Output = Commitment<E>;
|
||||
impl<'a, B: Borrow<Commitment>> ops::Add<B> for &'a Commitment {
|
||||
type Output = Commitment;
|
||||
|
||||
fn add(self, rhs: B) -> Commitment<E> {
|
||||
fn add(self, rhs: B) -> Commitment {
|
||||
(*self).clone() + rhs
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: Borrow<Commitment<E>>, E: Engine> ops::Add<B> for Commitment<E> {
|
||||
type Output = Commitment<E>;
|
||||
impl<B: Borrow<Commitment>> ops::Add<B> for Commitment {
|
||||
type Output = Commitment;
|
||||
|
||||
fn add(mut self, rhs: B) -> Commitment<E> {
|
||||
fn add(mut self, rhs: B) -> Commitment {
|
||||
self += rhs;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> Commitment<E> {
|
||||
impl Commitment {
|
||||
/// Returns the polynomial's degree.
|
||||
pub fn degree(&self) -> usize {
|
||||
self.coeff.len() - 1
|
||||
}
|
||||
|
||||
/// Returns the `i`-th public key share.
|
||||
pub fn evaluate<T: Into<<E::Fr as PrimeField>::Repr>>(&self, i: T) -> E::G1 {
|
||||
pub fn evaluate<T: Into<FrRepr>>(&self, i: T) -> G1 {
|
||||
let mut result = match self.coeff.last() {
|
||||
None => return E::G1::zero(),
|
||||
None => return G1::zero(),
|
||||
Some(c) => *c,
|
||||
};
|
||||
let x = E::Fr::from_repr(i.into()).expect("invalid index");
|
||||
let x = Fr::from_repr(i.into()).expect("invalid index");
|
||||
for c in self.coeff.iter().rev().skip(1) {
|
||||
result.mul_assign(x);
|
||||
result.add_assign(c);
|
||||
|
@ -330,15 +319,15 @@ impl<E: Engine> Commitment<E> {
|
|||
/// This can be used for Verifiable Secret Sharing and Distributed Key Generation. See the module
|
||||
/// documentation for details.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BivarPoly<E: Engine> {
|
||||
pub struct BivarPoly {
|
||||
/// The polynomial's degree in each of the two variables.
|
||||
degree: usize,
|
||||
/// The coefficients of the polynomial. Coefficient `(i, j)` for `i <= j` is in position
|
||||
/// `j * (j + 1) / 2 + i`.
|
||||
coeff: Vec<E::Fr>,
|
||||
coeff: Vec<Fr>,
|
||||
}
|
||||
|
||||
impl<E: Engine> BivarPoly<E> {
|
||||
impl BivarPoly {
|
||||
/// Creates a random polynomial.
|
||||
pub fn random<R: Rng>(degree: usize, rng: &mut R) -> Self {
|
||||
BivarPoly {
|
||||
|
@ -353,11 +342,11 @@ impl<E: Engine> BivarPoly<E> {
|
|||
}
|
||||
|
||||
/// Returns the polynomial's value at the point `(x, y)`.
|
||||
pub fn evaluate<T: Into<<E::Fr as PrimeField>::Repr>>(&self, x: T, y: T) -> E::Fr {
|
||||
pub fn evaluate<T: Into<FrRepr>>(&self, x: T, y: T) -> Fr {
|
||||
let x_pow = self.powers(x);
|
||||
let y_pow = self.powers(y);
|
||||
// TODO: Can we save a few multiplication steps here due to the symmetry?
|
||||
let mut result = E::Fr::zero();
|
||||
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)];
|
||||
|
@ -370,11 +359,11 @@ impl<E: Engine> BivarPoly<E> {
|
|||
}
|
||||
|
||||
/// Returns the `x`-th row, as a univariate polynomial.
|
||||
pub fn row<T: Into<<E::Fr as PrimeField>::Repr>>(&self, x: T) -> Poly<E> {
|
||||
pub fn row<T: Into<FrRepr>>(&self, x: T) -> Poly {
|
||||
let x_pow = self.powers(x);
|
||||
let coeff: Vec<E::Fr> = (0..=self.degree)
|
||||
let coeff: Vec<Fr> = (0..=self.degree)
|
||||
.map(|i| {
|
||||
let mut result = E::Fr::zero();
|
||||
let mut result = Fr::zero();
|
||||
for (j, x_pow_j) in x_pow.iter().enumerate() {
|
||||
let mut summand = self.coeff[coeff_pos(i, j)];
|
||||
summand.mul_assign(x_pow_j);
|
||||
|
@ -387,8 +376,8 @@ impl<E: Engine> BivarPoly<E> {
|
|||
}
|
||||
|
||||
/// Returns the corresponding commitment. That information can be shared publicly.
|
||||
pub fn commitment(&self) -> BivarCommitment<E> {
|
||||
let to_pub = |c: &E::Fr| E::G1Affine::one().mul(*c);
|
||||
pub fn commitment(&self) -> BivarCommitment {
|
||||
let to_pub = |c: &Fr| G1Affine::one().mul(*c);
|
||||
BivarCommitment {
|
||||
degree: self.degree,
|
||||
coeff: self.coeff.iter().map(to_pub).collect(),
|
||||
|
@ -396,22 +385,22 @@ impl<E: Engine> BivarPoly<E> {
|
|||
}
|
||||
|
||||
/// Returns the `0`-th to `degree`-th power of `x`.
|
||||
fn powers<T: Into<<E::Fr as PrimeField>::Repr>>(&self, x_repr: T) -> Vec<E::Fr> {
|
||||
fn powers<T: Into<FrRepr>>(&self, x_repr: T) -> Vec<Fr> {
|
||||
powers(x_repr, self.degree)
|
||||
}
|
||||
}
|
||||
|
||||
/// A commitment to a bivariate polynomial.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BivarCommitment<E: Engine> {
|
||||
pub struct BivarCommitment {
|
||||
/// The polynomial's degree in each of the two variables.
|
||||
degree: usize,
|
||||
/// The commitments to the coefficients.
|
||||
#[serde(with = "super::serde_impl::projective_vec")]
|
||||
coeff: Vec<E::G1>,
|
||||
coeff: Vec<G1>,
|
||||
}
|
||||
|
||||
impl<E: Engine> Hash for BivarCommitment<E> {
|
||||
impl Hash for BivarCommitment {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.degree.hash(state);
|
||||
for c in &self.coeff {
|
||||
|
@ -420,18 +409,18 @@ impl<E: Engine> Hash for BivarCommitment<E> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<E: Engine> BivarCommitment<E> {
|
||||
impl BivarCommitment {
|
||||
/// Returns the polynomial's degree: It is the same in both variables.
|
||||
pub fn degree(&self) -> usize {
|
||||
self.degree
|
||||
}
|
||||
|
||||
/// Returns the commitment's value at the point `(x, y)`.
|
||||
pub fn evaluate<T: Into<<E::Fr as PrimeField>::Repr>>(&self, x: T, y: T) -> E::G1 {
|
||||
pub fn evaluate<T: Into<FrRepr>>(&self, x: T, y: T) -> G1 {
|
||||
let x_pow = self.powers(x);
|
||||
let y_pow = self.powers(y);
|
||||
// TODO: Can we save a few multiplication steps here due to the symmetry?
|
||||
let mut result = E::G1::zero();
|
||||
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)];
|
||||
|
@ -444,11 +433,11 @@ impl<E: Engine> BivarCommitment<E> {
|
|||
}
|
||||
|
||||
/// Returns the `x`-th row, as a commitment to a univariate polynomial.
|
||||
pub fn row<T: Into<<E::Fr as PrimeField>::Repr>>(&self, x: T) -> Commitment<E> {
|
||||
pub fn row<T: Into<FrRepr>>(&self, x: T) -> Commitment {
|
||||
let x_pow = self.powers(x);
|
||||
let coeff: Vec<E::G1> = (0..=self.degree)
|
||||
let coeff: Vec<G1> = (0..=self.degree)
|
||||
.map(|i| {
|
||||
let mut result = E::G1::zero();
|
||||
let mut result = G1::zero();
|
||||
for (j, x_pow_j) in x_pow.iter().enumerate() {
|
||||
let mut summand = self.coeff[coeff_pos(i, j)];
|
||||
summand.mul_assign(*x_pow_j);
|
||||
|
@ -461,7 +450,7 @@ impl<E: Engine> BivarCommitment<E> {
|
|||
}
|
||||
|
||||
/// Returns the `0`-th to `degree`-th power of `x`.
|
||||
fn powers<T: Into<<E::Fr as PrimeField>::Repr>>(&self, x_repr: T) -> Vec<E::Fr> {
|
||||
fn powers<T: Into<FrRepr>>(&self, x_repr: T) -> Vec<Fr> {
|
||||
powers(x_repr, self.degree)
|
||||
}
|
||||
}
|
||||
|
@ -495,12 +484,10 @@ mod tests {
|
|||
|
||||
use super::{coeff_pos, BivarPoly, Poly};
|
||||
|
||||
use pairing::bls12_381::Bls12;
|
||||
use pairing::{CurveAffine, Engine, Field, PrimeField};
|
||||
use pairing::bls12_381::{Fr, G1Affine};
|
||||
use pairing::{CurveAffine, Field, PrimeField};
|
||||
use rand;
|
||||
|
||||
type Fr = <Bls12 as Engine>::Fr;
|
||||
|
||||
fn fr(x: i64) -> Fr {
|
||||
let mut result = Fr::from_repr((x.abs() as u64).into()).unwrap();
|
||||
if x < 0 {
|
||||
|
@ -527,7 +514,7 @@ mod tests {
|
|||
#[test]
|
||||
fn poly() {
|
||||
// The polynomial "`5 * x.pow(3) + x.pow(1) - 2`".
|
||||
let poly: Poly<Bls12> =
|
||||
let poly =
|
||||
Poly::monomial(3) * Poly::constant(fr(5)) + Poly::monomial(1) - Poly::constant(fr(2));
|
||||
let coeff = vec![fr(-2), fr(1), fr(0), fr(5)];
|
||||
assert_eq!(Poly { coeff }, poly);
|
||||
|
@ -554,7 +541,7 @@ mod tests {
|
|||
// For distributed key generation, a number of dealers, only one of who needs to be honest,
|
||||
// generates random bivariate polynomials and publicly commits to them. In partice, the
|
||||
// dealers can e.g. be any `faulty_num + 1` nodes.
|
||||
let bi_polys: Vec<BivarPoly<Bls12>> = (0..dealer_num)
|
||||
let bi_polys: Vec<BivarPoly> = (0..dealer_num)
|
||||
.map(|_| BivarPoly::random(faulty_num, &mut rng))
|
||||
.collect();
|
||||
let pub_bi_commits: Vec<_> = bi_polys.iter().map(BivarPoly::commitment).collect();
|
||||
|
@ -573,7 +560,7 @@ mod tests {
|
|||
// Node `s` receives the `s`-th value and verifies it.
|
||||
for s in 1..=node_num {
|
||||
let val = row_poly.evaluate(s as u64);
|
||||
let val_g1 = <Bls12 as Engine>::G1Affine::one().mul(val);
|
||||
let val_g1 = G1Affine::one().mul(val);
|
||||
assert_eq!(bi_commit.evaluate(m as u64, s as u64), val_g1);
|
||||
// The node can't verify this directly, but it should have the correct value:
|
||||
assert_eq!(bi_poly.evaluate(m as u64, s as u64), val);
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use super::Signature;
|
||||
use pairing::{CurveAffine, CurveProjective, EncodedPoint, Engine};
|
||||
use pairing::bls12_381::G2Compressed;
|
||||
use pairing::{CurveAffine, CurveProjective, EncodedPoint};
|
||||
|
||||
impl<E: Engine> Signature<E> {
|
||||
impl Signature {
|
||||
pub fn to_vec(&self) -> Vec<u8> {
|
||||
let comp = self.0.into_affine().into_compressed();
|
||||
comp.as_ref().to_vec()
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
|
||||
let mut comp = <E::G2Affine as CurveAffine>::Compressed::empty();
|
||||
let mut comp = G2Compressed::empty();
|
||||
comp.as_mut().copy_from_slice(bytes);
|
||||
if let Ok(affine) = comp.into_affine() {
|
||||
Some(Signature(affine.into_projective()))
|
||||
|
|
Loading…
Reference in New Issue