From f9069a34a1d9046bc15505b8a8ba4db147d8580e Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 8 Jun 2022 10:44:35 +0100 Subject: [PATCH 1/7] compilation flag with zcash's implementation --- Cargo.lock | 89 +++++ mithril-core/Cargo.toml | 8 +- mithril-core/src/error.rs | 34 +- mithril-core/src/key_reg.rs | 11 +- mithril-core/src/lib.rs | 3 + mithril-core/src/merkle_tree.rs | 3 + mithril-core/src/multi_sig_zcash.rs | 580 ++++++++++++++++++++++++++++ mithril-core/src/stm.rs | 3 + 8 files changed, 712 insertions(+), 19 deletions(-) create mode 100644 mithril-core/src/multi_sig_zcash.rs diff --git a/Cargo.lock b/Cargo.lock index 476bbc029b..f8a5761983 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,6 +310,18 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitvec" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1489fcb93a5bb47da0462ca93ad252ad6af2145cce58d10d46a83931ba9f016b" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "blake2" version = "0.9.2" @@ -374,6 +386,20 @@ dependencies = [ "once_cell", ] +[[package]] +name = "bls12_381" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62250ece575fa9b22068b3a8d59586f01d426dd7785522efd97632959e71c986" +dependencies = [ + "digest 0.9.0", + "ff", + "group", + "pairing", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "blst" version = "0.3.7" @@ -1031,6 +1057,17 @@ dependencies = [ "instant", ] +[[package]] +name = "ff" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df689201f395c6b90dfe87127685f8dbfc083a5e779e613575d8bd7314300c3e" +dependencies = [ + "bitvec", + "rand_core 0.6.3", + "subtle", +] + [[package]] name = "filetime" version = "0.2.16" @@ -1127,6 +1164,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9d758e60b45e8d749c89c1b389ad8aee550f86aa12e2b9298b546dda7a82ab1" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.21" @@ -1300,6 +1343,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "group" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7391856def869c1c81063a03457c676fbcd419709c3dfb33d8d319de484b154d" +dependencies = [ + "byteorder", + "ff", + "rand 0.8.5", + "rand_core 0.6.3", + "rand_xorshift", + "subtle", +] + [[package]] name = "gzip-header" version = "0.3.0" @@ -1851,12 +1908,14 @@ version = "0.1.0" dependencies = [ "bincode", "blake2", + "bls12_381", "blst", "bytes", "cbindgen", "criterion", "digest 0.9.0", "generic-array 0.14.5", + "group", "libc", "num-bigint 0.4.3", "num-integer", @@ -2321,6 +2380,15 @@ version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" +[[package]] +name = "pairing" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" +dependencies = [ + "group", +] + [[package]] name = "parking" version = "2.0.0" @@ -2636,6 +2704,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.7.3" @@ -3403,6 +3477,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tar" version = "0.4.38" @@ -4169,6 +4249,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "wyz" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e" +dependencies = [ + "tap", +] + [[package]] name = "xattr" version = "0.2.3" diff --git a/mithril-core/Cargo.toml b/mithril-core/Cargo.toml index 1864ac20fe..d8fc0f5e1c 100644 --- a/mithril-core/Cargo.toml +++ b/mithril-core/Cargo.toml @@ -9,7 +9,9 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] blake2 = "0.9.2" -blst = "0.3.7" +blst = { version = "0.3.7", optional = true } +bls12_381 = { version = "0.7.0", features = ["experimental"], optional = true } +group = { version = "0.12.0", features = ["tests"], optional = true } bytes = "1" digest = { version = "0.9.0", features = ["alloc"] } generic-array = "0.14" @@ -52,6 +54,8 @@ name = "size_benches" harness = false [features] -default = ["rug"] +default = ["rug", "zcash"] rug-backend = ["rug/default"] num-integer-backend = ["num-integer/default"] +zcash = ["bls12_381", "group"] +blast = ["blst"] diff --git a/mithril-core/src/error.rs b/mithril-core/src/error.rs index f517fbdb24..9c733faf98 100644 --- a/mithril-core/src/error.rs +++ b/mithril-core/src/error.rs @@ -1,9 +1,14 @@ //! Crate specific errors use crate::merkle_tree::Path; -use crate::multi_sig::{Signature, VerificationKey, VerificationKeyPoP}; +#[cfg(not(feature = "zcash"))] +use { + crate::multi_sig::{Signature, VerificationKey, VerificationKeyPoP}, + blst::BLST_ERROR, +}; +#[cfg(feature = "zcash")] +use crate::multi_sig_zcash::{Signature, VerificationKey, VerificationKeyPoP}; use crate::stm::PartyId; -use blst::BLST_ERROR; use digest::{Digest, FixedOutput}; // todo: better organise these errors. @@ -11,18 +16,18 @@ use digest::{Digest, FixedOutput}; #[derive(Debug, thiserror::Error, Eq, PartialEq)] /// Error types for multi signatures pub enum MultiSignatureError { - /// Invalid Multi signature - #[error("Invalid multi signature")] - InvalidSignature, - /// This error occurs when the underlying function is passed infinity or an element outsize of the group - #[error("Unexpected point")] - UnexpectedBlstTypes, - /// This error occurs when the the serialization of the raw bytes failed - #[error("Invalid bytes")] - SerializationError, - /// Incorrect proof of possession - #[error("Key with invalid PoP")] - InvalidKey(Box), +/// Invalid Multi signature +#[error("Invalid multi signature")] +InvalidSignature, +/// This error occurs when the underlying function is passed infinity or an element outsize of the group +#[error("Unexpected point")] +UnexpectedBlstTypes, +/// This error occurs when the the serialization of the raw bytes failed +#[error("Invalid bytes")] +SerializationError, +/// Incorrect proof of possession +#[error("Key with invalid PoP")] +InvalidKey(Box), } /// Errors which can be output by Mithril verification. @@ -168,6 +173,7 @@ impl From> for MithrilWi } } +#[cfg(not(feature = "zcash"))] pub(crate) fn blst_err_to_atms(e: BLST_ERROR) -> Result<(), MultiSignatureError> { match e { BLST_ERROR::BLST_SUCCESS => Ok(()), diff --git a/mithril-core/src/key_reg.rs b/mithril-core/src/key_reg.rs index 1d2b2c7e85..da608e43af 100644 --- a/mithril-core/src/key_reg.rs +++ b/mithril-core/src/key_reg.rs @@ -5,11 +5,13 @@ use digest::{Digest, FixedOutput}; use std::collections::{HashMap, HashSet}; use std::sync::Arc; -use super::multi_sig::VerificationKeyPoP; -use super::stm::{PartyId, Stake}; +#[cfg(not(feature = "zcash"))] +use crate::multi_sig::{VerificationKeyPoP, VerificationKey}; +#[cfg(feature = "zcash")] +use crate::multi_sig_zcash::{VerificationKey, VerificationKeyPoP}; +use super::stm::{PartyId, Stake}; use crate::merkle_tree::{MTLeaf, MerkleTree}; -use crate::multi_sig::VerificationKey; /// Struct that collects public keys and stakes of parties. Each participant (both the /// signers and the clerks) need to run their own instance of the key registration. @@ -126,7 +128,10 @@ impl Default for KeyReg { #[cfg(test)] mod tests { use super::*; + #[cfg(not(feature = "zcash"))] use crate::multi_sig::SigningKey; + #[cfg(feature = "zcash")] + use crate::multi_sig_zcash::SigningKey; use blake2::Blake2b; use proptest::collection::vec; use proptest::prelude::*; diff --git a/mithril-core/src/lib.rs b/mithril-core/src/lib.rs index 2515b1c985..fc3e074e8c 100644 --- a/mithril-core/src/lib.rs +++ b/mithril-core/src/lib.rs @@ -7,5 +7,8 @@ mod dense_mapping; pub mod error; pub mod key_reg; pub mod merkle_tree; +#[cfg(not(feature = "zcash"))] mod multi_sig; +#[cfg(feature = "zcash")] +mod multi_sig_zcash; pub mod stm; diff --git a/mithril-core/src/merkle_tree.rs b/mithril-core/src/merkle_tree.rs index b27627aa5b..4ee62060fd 100644 --- a/mithril-core/src/merkle_tree.rs +++ b/mithril-core/src/merkle_tree.rs @@ -1,6 +1,9 @@ //! Creation and verification of Merkle Trees use crate::error::MerkleTreeError; +#[cfg(not(feature = "zcash"))] use crate::multi_sig::VerificationKey; +#[cfg(feature = "zcash")] +use crate::multi_sig_zcash::VerificationKey; use crate::stm::Stake; use digest::{Digest, FixedOutput}; use serde::{Deserialize, Serialize}; diff --git a/mithril-core/src/multi_sig_zcash.rs b/mithril-core/src/multi_sig_zcash.rs new file mode 100644 index 0000000000..ee0ab19c45 --- /dev/null +++ b/mithril-core/src/multi_sig_zcash.rs @@ -0,0 +1,580 @@ +//! Base multisignature scheme, used as a primitive for STM. +//! See Section 2.4 of [the paper](https://eprint.iacr.org/2021/916). +//! + +use super::stm::Index; + +use crate::error::MultiSignatureError; +use blake2::{Blake2b, Digest}; + +use bls12_381::*; +use group::ff::Field; +use group::prime::PrimeCurveAffine; +use group::{Curve, GroupEncoding}; +use group::Group; + +use rand_core::{CryptoRng, RngCore}; +use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; +use std::convert::TryInto; +use std::{ + cmp::Ordering, + hash::{Hash, Hasher}, + iter::Sum, + ops::Sub, +}; +use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, MapToCurve}; + +/// String used to generate the proofs of possession. +const POP: &[u8] = b"PoP"; + +// --------------------------------------------------------------------- +// Multi signature using blst +// --------------------------------------------------------------------- + +/// MultiSig secret key, which is a wrapper over the BlstSk type from the blst +/// library. +#[derive(Debug, Clone)] +pub struct SigningKey(Scalar); + +impl SigningKey { + /// Generate a secret key + pub fn gen(rng: &mut (impl RngCore + CryptoRng)) -> Self { + SigningKey(Scalar::random(rng)) + } + + /// Sign a message with the given secret key + pub fn sign(&self, msg: &[u8]) -> Signature { + let point = >>::encode_to_curve(msg, &[]); + Signature(point * self.0) + } + + /// Convert the secret key into byte string. + pub fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } + + /// Convert a string of bytes into a `SigningKey`. + /// # Error + /// Fails if the byte string represents a scalar larger than the group order. + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() < 32 { + return Err(MultiSignatureError::SerializationError); + } + let mut array_bytes = [0u8; 32]; + array_bytes.copy_from_slice(&bytes[..32]); + Ok(Self(Scalar::from_bytes(&array_bytes).unwrap())) + } +} + +/// MultiSig verification key, which iss a wrapper over the BlstPk (element in G2) +/// from the blst library. +#[derive(Debug, Clone, Copy)] +pub struct VerificationKey(G2Projective); + +impl Default for VerificationKey { + fn default() -> Self { + VerificationKey(G2Projective::identity()) + } +} + +impl Hash for VerificationKey { + fn hash(&self, state: &mut H) { + Hash::hash_slice(&self.to_bytes(), state) + } +} + +// We need to implement PartialEq instead of deriving it because we are implementing Hash. +impl PartialEq for VerificationKey { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for VerificationKey {} + +impl VerificationKey { + /// Convert an `VerificationKey` to its compressed byte representation. + pub fn to_bytes(self) -> [u8; 96] { + self.0.to_affine().to_compressed() + } + + /// Convert a compressed byte string into a `VerificationKey`. + /// + /// # Error + /// This function fails if the bytes do not represent a compressed point of the curve. + // todo: check that whether this checks that the point is in the prime order group. + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.len() < 96 { + return Err(MultiSignatureError::SerializationError); + } + let mut array_bytes = [0u8; 96]; + array_bytes.copy_from_slice(&bytes[..96]); + let key = if G2Affine::from_compressed(&array_bytes) + .is_some() + .unwrap_u8() + == 1u8 + { + G2Affine::from_compressed(&array_bytes).unwrap() + } else { + return Err(MultiSignatureError::SerializationError); + }; + + Ok(Self(G2Projective::from(key))) + } + + /// Compare two `VerificationKey`. Used for PartialOrd impl, used to order signatures. The comparison + /// function can be anything, as long as it is consistent. + fn cmp_msp_mvk(&self, other: &VerificationKey) -> Ordering { + let self_bytes = self.to_bytes(); + let other_bytes = other.to_bytes(); + let mut result = Ordering::Equal; + + for (i, j) in self_bytes.iter().zip(other_bytes.iter()) { + result = i.cmp(j); + if result != Ordering::Equal { + return result; + } + } + + result + } +} + +impl PartialOrd for VerificationKey { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp_msp_mvk(other)) + } +} + +impl Ord for VerificationKey { + fn cmp(&self, other: &Self) -> Ordering { + self.cmp_msp_mvk(other) + } +} + +impl<'a> Sum<&'a Self> for VerificationKey { + fn sum(iter: I) -> Self + where + I: Iterator, + { + let mut start = G2Projective::identity(); + iter.map(|x| start += x.0); + + Self(start) + } +} + +impl<'a> Sum<&'a Self> for Signature { + fn sum(iter: I) -> Self + where + I: Iterator, + { + let mut start = G1Projective::identity(); + iter.map(|x| start += x.0); + + Self(start) + } +} + +/// MultiSig proof of possession, which contains two elements from G1. However, +/// the two elements have different types: `k1` is represented as a BlstSig +/// as it has the same structure, and this facilitates its verification. On +/// the other hand, `k2` is a G1 point, as it does not share structure with +/// the BLS signature, and we need to have an ad-hoc verification mechanism. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct ProofOfPossession { + k1: G1Projective, + k2: G1Projective, +} + +/// MultiSig public key, contains the verification key and the proof of possession. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub struct VerificationKeyPoP { + /// The verification key. + pub vk: VerificationKey, + /// Proof of Possession. + pub pop: ProofOfPossession, +} + +impl From<&SigningKey> for VerificationKey { + /// Convert a secret key into an `MspMvk`. This is performed by computing + /// `MspMvk = g2 * sk`, where `g2` is the generator in G2. We can use the + /// blst built-in function `sk_to_pk`. + fn from(sk: &SigningKey) -> Self { + VerificationKey(G2Affine::generator() * sk.0) + } +} + +// Again, unsafe code to access the algebraic operations. +// todo: particular care reviewing this (specially transmute) +impl From<&SigningKey> for ProofOfPossession { + /// Convert a secret key into an `MspPoP`. This is performed by computing + /// `k1 = H_G1(b"PoP" || mvk) * sk` and `k2 = g1 * sk` where `H_G1` hashes into + /// `G1` and `g1` is the generator in `G1`. + fn from(sk: &SigningKey) -> Self { + let k1 = >>::encode_to_curve(POP, &[]) * sk.0; + let k2 = G1Affine::generator() * sk.0; + + Self { k1, k2 } + } +} + +impl From<&SigningKey> for VerificationKeyPoP { + /// Convert a secret key into an `MspPk` by simply converting to a + /// `MspMvk` and `MspPoP`. + fn from(sk: &SigningKey) -> Self { + Self { + vk: sk.into(), + pop: sk.into(), + } + } +} + +impl VerificationKeyPoP { + /// if `e(k1,g2) = e(H_G1("PoP" || mvk),mvk)` and `e(g1,mvk) = e(k2,g2)` + /// are both true, return 1. The first part is a signature verification + /// of message "PoP", while the second we need to compute the pairing + /// manually. + // If we are really looking for performance improvements, we can combine the + // two final exponantiations (for verifying k1 and k2) into a single one. + pub fn check(&self) -> Result<(), MultiSignatureError> { + let lhs_1 = pairing(&self.pop.k1.to_affine(), &G2Affine::generator()); + let rhs_1 = pairing( + &>>::encode_to_curve(POP, &[]).to_affine(), + &self.vk.0.to_affine(), + ); + + let lhs_2 = pairing(&G1Affine::generator(), &self.vk.0.to_affine()); + let rhs_2 = pairing(&self.pop.k2.to_affine(), &G2Affine::generator()); + + if !(lhs_1 == rhs_1 && lhs_2 == rhs_2) { + return Err(MultiSignatureError::InvalidKey(Box::new(*self))); + } + Ok(()) + } + /// Convert to a 144 byte string. + /// + /// # Layout + /// The layout of a `PublicKeyPoP` encoding is + /// * Public key + /// * Proof of Possession + pub fn to_bytes(self) -> [u8; 192] { + let mut pkpop_bytes = [0u8; 192]; + pkpop_bytes[..96].copy_from_slice(&self.vk.to_bytes()); + pkpop_bytes[96..].copy_from_slice(&self.pop.to_bytes()); + pkpop_bytes + } + + /// Deserialise a byte string to a `PublicKeyPoP`. + pub fn from_bytes(bytes: &[u8]) -> Result { + let mvk = VerificationKey::from_bytes(&bytes[..96])?; + + let pop = ProofOfPossession::from_bytes(&bytes[96..])?; + + Ok(Self { vk: mvk, pop }) + } +} + +impl ProofOfPossession { + /// Convert to a 96 byte string. + /// + /// # Layout + /// The layout of a `MspPoP` encoding is + /// * K1 (G1 point) + /// * K2 (G1 point) + pub fn to_bytes(self) -> [u8; 96] { + let mut pop_bytes = [0u8; 96]; + pop_bytes[..48].copy_from_slice(&self.k1.to_affine().to_compressed()); + pop_bytes[48..].copy_from_slice(&self.k2.to_affine().to_compressed()); + pop_bytes + } + + /// Deserialise a byte string to a `PublicKeyPoP`. + pub fn from_bytes(bytes: &[u8]) -> Result { + let mut array_byte = [0u8; 48]; + array_byte.copy_from_slice(&bytes[..48]); + let k1 = G1Projective::from(G1Affine::from_compressed(&array_byte).unwrap()); + + array_byte.copy_from_slice(&bytes[48..]); + let k2 = G1Projective::from(G1Affine::from_compressed(&array_byte).unwrap()); + + Ok(Self { k1, k2 }) + } +} + +// --------------------------------------------------------------------- +// Multi signature +// --------------------------------------------------------------------- + +/// MultiSig signature, which is a wrapper over the `BlstSig` type. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Signature(G1Projective); + +impl Signature { + /// Verify a signature against a verification key. + pub fn verify(&self, msg: &[u8], mvk: &VerificationKey) -> Result<(), MultiSignatureError> { + let lhs = pairing(&self.0.to_affine(), &G2Affine::generator()); + let rhs = pairing( + &>>::encode_to_curve(msg, &[]).to_affine(), + &mvk.0.to_affine(), + ); + if lhs == rhs { + return Ok(()); + } + + Err(MultiSignatureError::InvalidSignature) + } + + /// Check if the signature is valid for the given index. We hash the signature to produce a + /// 64 bytes integer. We follow the same mechanism as Shelley + /// for the lottery (i.e., we follow the VRF lottery mechanism as described in Section 16 of + /// ). + // todo: if we are generic over the hash function, shouldn't we use the instance here? + pub fn eval(&self, msg: &[u8], index: Index) -> [u8; 64] { + let hasher = Blake2b::new() + .chain(b"map") + .chain(msg) + .chain(&index.to_le_bytes()) + .chain(&self.to_bytes()) + .finalize(); + + let mut output = [0u8; 64]; + output.copy_from_slice(hasher.as_slice()); + + output + } + + /// Convert an `Signature` to its compressed byte representation. + pub fn to_bytes(self) -> [u8; 48] { + self.0.to_affine().to_compressed() + } + + /// Convert a string of bytes into a `MspSig`. + /// # Error + /// Returns an error if the byte string does not represent a point in the curve. + // todo: check that whether this checks that the point is in the prime order group. + pub fn from_bytes(bytes: &[u8]) -> Result { + let mut array_byte = [0u8; 48]; + array_byte.copy_from_slice(&bytes[..48]); + Ok(Self(G1Projective::from(G1Affine::from_compressed(&array_byte).unwrap()))) + } + + /// Compare two signatures. Used for PartialOrd impl, used to rank signatures. The comparison + /// function can be anything, as long as it is consistent across different nodes. + fn cmp_msp_sig(&self, other: &Self) -> Ordering { + let self_bytes = self.to_bytes(); + let other_bytes = other.to_bytes(); + let mut result = Ordering::Equal; + + for (i, j) in self_bytes.iter().zip(other_bytes.iter()) { + result = i.cmp(j); + if result != Ordering::Equal { + return result; + } + } + result + } +} + +impl PartialOrd for Signature { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp_msp_sig(other)) + } +} + +impl Ord for Signature { + fn cmp(&self, other: &Self) -> Ordering { + self.cmp_msp_sig(other) + } +} + +// --------------------------------------------------------------------- +// Serde implementation +// --------------------------------------------------------------------- + +macro_rules! impl_serde { + ($st:ty,$visitor:ident,$size:expr) => { + impl Serialize for $st { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + use serde::ser::SerializeTuple; + let mut seq = serializer.serialize_tuple($size)?; + for e in self.to_bytes().iter() { + seq.serialize_element(e)?; + } + seq.end() + } + } + + impl<'de> Deserialize<'de> for $st { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct $visitor; + + impl<'de> Visitor<'de> for $visitor { + type Value = $st; + + fn expecting( + &self, + formatter: &mut ::core::fmt::Formatter, + ) -> ::core::fmt::Result { + formatter + .write_str(format!("a multi signature {}", stringify!($st)).as_str()) + } + + fn visit_seq(self, mut seq: A) -> Result<$st, A::Error> + where + A: serde::de::SeqAccess<'de>, + { + let mut bytes = [0u8; $size]; + for i in 0..$size { + bytes[i] = + seq.next_element()?.ok_or(serde::de::Error::invalid_length( + i, + &format!("expected bytes{}", $size.to_string()).as_str(), + ))?; + } + <$st>::from_bytes(&bytes).map_err(|_| { + serde::de::Error::custom( + &format!("deserialization failed [{}]", stringify!($st)).as_str(), + ) + }) + } + } + + deserializer.deserialize_tuple($size, $visitor) + } + } + }; +} +impl_serde!(SigningKey, SigningKeyVisitor, 32); +impl_serde!(VerificationKey, VerificationKeyVisitor, 96); +impl_serde!(ProofOfPossession, ProofOfPossessionVisitor, 96); +impl_serde!(Signature, SignatureVisitor, 48); + +#[cfg(test)] +mod tests { + use super::*; + use proptest::prelude::*; + use rand_chacha::ChaCha20Rng; + use rand_core::{OsRng, SeedableRng}; + + impl PartialEq for SigningKey { + fn eq(&self, other: &Self) -> bool { + self.0.to_bytes() == other.0.to_bytes() + } + } + + impl Eq for SigningKey {} + + proptest! { + #![proptest_config(ProptestConfig::with_cases(1000))] + + #[test] + fn test_sig( + msg in prop::collection::vec(any::(), 1..128), + seed in any::<[u8;32]>(), + ) { + let sk = SigningKey::gen(&mut ChaCha20Rng::from_seed(seed)); + let pk = VerificationKey::from(&sk); + let sig = sk.sign(&msg); + assert!(sig.verify(&msg, &pk).is_ok()); + } + + #[test] + fn test_invalid_sig(msg in prop::collection::vec(any::(), 1..128), + seed in any::<[u8;32]>(), + ) { + let mut rng = ChaCha20Rng::from_seed(seed); + let sk1 = SigningKey::gen(&mut rng); + let pk1 = VerificationKey::from(&sk1); + let sk2 = SigningKey::gen(&mut rng); + let fake_sig = sk2.sign(&msg); + assert!(fake_sig.verify(&msg, &pk1).is_err()); + } + + #[test] + fn test_aggregate_sig(msg in prop::collection::vec(any::(), 1..128), + num_sigs in 1..16, + seed in any::<[u8;32]>(), + ) { + let mut rng = ChaCha20Rng::from_seed(seed); + let mut mvks = Vec::new(); + let mut sigs = Vec::new(); + for _ in 0..num_sigs { + let sk = SigningKey::gen(&mut rng); + let pk = VerificationKey::from(&sk); + let sig = sk.sign(&msg); + assert!(sig.verify(&msg, &pk).is_ok()); + sigs.push(sig); + mvks.push(pk); + } + let ivk = mvks.iter().sum(); + let mu: Signature = sigs.iter().sum(); + assert!(mu.verify(&msg, &ivk).is_ok()); + } + + #[test] + fn test_eval_sanity_check(msg in prop::collection::vec(any::(), 1..128), + idx in any::(), + seed in any::<[u8;32]>()) { + let sk = SigningKey::gen(&mut ChaCha20Rng::from_seed(seed)); + let sig = sk.sign(&msg); + sig.eval(&msg, idx); + } + + #[test] + fn serialize_deserialize_pk(seed in any::()) { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + let sk = SigningKey::gen(&mut rng); + let vk = VerificationKey::from(&sk); + let vk_bytes = vk.to_bytes(); + let vk2 = VerificationKey::from_bytes(&vk_bytes).unwrap(); + assert_eq!(vk, vk2); + let pk = VerificationKeyPoP::from(&sk); + let pk_bytes = pk.to_bytes(); + let pk2: VerificationKeyPoP = VerificationKeyPoP::from_bytes(&pk_bytes).unwrap(); + assert_eq!(pk, pk2); + + // Now we test serde + let encoded = bincode::serialize(&vk).unwrap(); + assert_eq!(encoded, vk_bytes); + let decoded: VerificationKey = bincode::deserialize(&encoded).unwrap(); + assert_eq!(vk, decoded); + let encoded = bincode::serialize(&pk).unwrap(); + let decoded: VerificationKeyPoP = bincode::deserialize(&encoded).unwrap(); + assert_eq!(pk, decoded); + } + + #[test] + fn serialize_deserialize_sk(seed in any::()) { + let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(seed); + let sk = SigningKey::gen(&mut rng); + let sk_bytes: [u8; 32] = sk.to_bytes(); + let sk2 = SigningKey::from_bytes(&sk_bytes).unwrap(); + assert_eq!(sk, sk2); + + // Now we test serde + let encoded = bincode::serialize(&sk).unwrap(); + let decoded: SigningKey = bincode::deserialize(&encoded).unwrap(); + assert_eq!(sk, decoded); + + // See that it is consistent with raw serialisation + let decoded_bytes: SigningKey = bincode::deserialize(&sk_bytes).unwrap(); + assert_eq!(sk, decoded_bytes); + } + } + + #[test] + fn test_gen() { + for _ in 0..128 { + let sk = SigningKey::gen(&mut OsRng); + let pk = VerificationKeyPoP::from(&sk); + assert!(pk.check().is_ok()); + } + } +} diff --git a/mithril-core/src/stm.rs b/mithril-core/src/stm.rs index 2a6ba82f83..176632000f 100644 --- a/mithril-core/src/stm.rs +++ b/mithril-core/src/stm.rs @@ -128,7 +128,10 @@ use crate::error::{ }; use crate::key_reg::ClosedKeyReg; use crate::merkle_tree::{MTLeaf, MerkleTreeCommitment, Path}; +#[cfg(not(feature = "zcash"))] use crate::multi_sig::{Signature, SigningKey, VerificationKey, VerificationKeyPoP}; +#[cfg(feature = "zcash")] +use crate::multi_sig_zcash::{Signature, SigningKey, VerificationKey, VerificationKeyPoP}; use digest::{Digest, FixedOutput}; use rand_core::{CryptoRng, RngCore}; use serde::{Deserialize, Serialize}; From e37c9748a2541597950f09e1939974c60c48458d Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 8 Jun 2022 11:14:26 +0100 Subject: [PATCH 2/7] Remove panics from_bytes functions --- mithril-core/src/error.rs | 3 +++ mithril-core/src/key_reg.rs | 10 +++++++--- mithril-core/src/merkle_tree.rs | 4 ++-- mithril-core/src/stm.rs | 10 ++++++---- mithril-core/tests/integration.rs | 3 +++ 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/mithril-core/src/error.rs b/mithril-core/src/error.rs index 9c733faf98..9ec5369c4c 100644 --- a/mithril-core/src/error.rs +++ b/mithril-core/src/error.rs @@ -86,6 +86,9 @@ pub enum AggregationFailure { /// Not enough signatures were collected, got this many instead. #[error("Not enough signatures. Got only {0} out of {1}.")] NotEnoughSignatures(u64, u64), + /// This error happens when we try to convert a u64 to a usize and it does not fit + #[error("Invalid usize conversion")] + InvalidUsizeConversion } /// Error types for single signature verification diff --git a/mithril-core/src/key_reg.rs b/mithril-core/src/key_reg.rs index da608e43af..b4091dead7 100644 --- a/mithril-core/src/key_reg.rs +++ b/mithril-core/src/key_reg.rs @@ -97,13 +97,17 @@ impl KeyReg { where D: Digest + FixedOutput, { - let mut total_stake = 0; + let mut total_stake: Stake = 0; let mut reg_parties = self .parties .iter() .filter_map(|(_, party)| { if let Some(vk) = party.vk { - total_stake += party.stake; + let (res, overflow) = total_stake.overflowing_add(party.stake); + if overflow { + panic!("Total stake overflow"); + } + total_stake = res; return Some(MTLeaf(vk, party.stake)); } None @@ -139,7 +143,7 @@ mod tests { use rand_core::SeedableRng; fn arb_participants(min: usize, max: usize) -> impl Strategy> { - vec(any::(), min..=max).prop_map(|v| { + vec(1..1u64<<60, min..=max).prop_map(|v| { // 1<<60 to avoid overflows v.into_iter() .enumerate() .map(|(index, value)| (index as u64, value)) diff --git a/mithril-core/src/merkle_tree.rs b/mithril-core/src/merkle_tree.rs index 4ee62060fd..25eacb8d83 100644 --- a/mithril-core/src/merkle_tree.rs +++ b/mithril-core/src/merkle_tree.rs @@ -245,7 +245,7 @@ where let mut result = Vec::with_capacity(8 + self.nodes.len() * D::output_size()); result.extend_from_slice( &u64::try_from(self.n) - .expect("Length must fit in u32") + .unwrap() .to_be_bytes(), ); for node in self.nodes.iter() { @@ -258,7 +258,7 @@ where pub fn from_bytes(bytes: &[u8]) -> Result { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(&bytes[..8]); - let n = usize::try_from(u64::from_be_bytes(u64_bytes)).unwrap(); // todo: handle the conversion + let n = usize::try_from(u64::from_be_bytes(u64_bytes)).map_err(|_| MerkleTreeError::SerializationError)?; let num_nodes = n + n.next_power_of_two() - 1; let mut nodes = Vec::with_capacity(num_nodes); for i in 0..num_nodes { diff --git a/mithril-core/src/stm.rs b/mithril-core/src/stm.rs index 176632000f..85d47f29c7 100644 --- a/mithril-core/src/stm.rs +++ b/mithril-core/src/stm.rs @@ -475,9 +475,9 @@ impl StmAggrSig { pub fn from_bytes(bytes: &[u8]) -> Result, MultiSignatureError> { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(&bytes[..8]); - let size = usize::try_from(u64::from_be_bytes(u64_bytes)).unwrap(); + let size = usize::try_from(u64::from_be_bytes(u64_bytes)).map_err(|_| MultiSignatureError::SerializationError)?; u64_bytes.copy_from_slice(&bytes[8..16]); - let sig_size = usize::try_from(u64::from_be_bytes(u64_bytes)).unwrap(); + let sig_size = usize::try_from(u64::from_be_bytes(u64_bytes)).map_err(|_| MultiSignatureError::SerializationError)?; let mut signatures = Vec::with_capacity(size); for i in 0..size { signatures.push(StmSig::from_bytes( @@ -657,7 +657,7 @@ where let path = self .closed_reg .merkle_tree - .get_path(self.mt_index.try_into().unwrap()); + .get_path(self.mt_index.try_into().ok()?); Some(StmSig { sigma, pk: self.vk, @@ -839,7 +839,7 @@ where ) -> Result, AggregationFailure> { // todo: how come the dedup does not take the concatenated message // let msgp = concat_avk_with_msg(&self.avk.to_commitment(), msg); - let mut unique_sigs = Vec::with_capacity(self.params.k.try_into().unwrap()); + let mut unique_sigs = Vec::with_capacity(self.params.k.try_into().map_err(|_| AggregationFailure::InvalidUsizeConversion)?); for (_, sigs) in self.dedup_sigs_for_indices(msg, sigs)? { unique_sigs.push(sigs.clone()) } @@ -1096,6 +1096,8 @@ mod tests { } Err(AggregationFailure::NotEnoughSignatures(n, k)) => assert!(n < params.k || k == params.k), + Err(AggregationFailure::InvalidUsizeConversion) => + unreachable!() } } } diff --git a/mithril-core/tests/integration.rs b/mithril-core/tests/integration.rs index d9d4355a8c..5fe8aab702 100644 --- a/mithril-core/tests/integration.rs +++ b/mithril-core/tests/integration.rs @@ -94,5 +94,8 @@ fn test_full_protocol() { println!("Not enough signatures"); assert!(n < params.k && k == params.k) } + Err(AggregationFailure::InvalidUsizeConversion) => { + println!("Invalid usize conversion"); + } } } From f7d1e95f36332058187a032d6f2bfc553843f38c Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 8 Jun 2022 11:20:27 +0100 Subject: [PATCH 3/7] Resolved error in initialiser's serialisation --- mithril-core/src/stm.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mithril-core/src/stm.rs b/mithril-core/src/stm.rs index 85d47f29c7..b3495f9d2a 100644 --- a/mithril-core/src/stm.rs +++ b/mithril-core/src/stm.rs @@ -620,7 +620,7 @@ impl StmInitializer { let party_id = u64::from_be_bytes(u64_bytes); u64_bytes.copy_from_slice(&bytes[8..16]); let stake = u64::from_be_bytes(u64_bytes); - let params = StmParameters::from_bytes(&bytes[16..])?; + let params = StmParameters::from_bytes(&bytes[16..40])?; let sk = SigningKey::from_bytes(&bytes[40..])?; let pk = StmVerificationKeyPoP::from_bytes(&bytes[72..])?; @@ -1104,6 +1104,14 @@ mod tests { proptest! { #![proptest_config(ProptestConfig::with_cases(10))] + #[test] + fn test_parameters_serialize_deserialize(m in any::(), k in any::(), phi_f in any::()) { + let params = StmParameters { m, k, phi_f }; + + let bytes = params.to_bytes(); + let deserialised = StmParameters::from_bytes(&bytes); + assert!(deserialised.is_ok()) + } #[test] fn test_initializer_serialize_deserialize(seed in any::<[u8;32]>()) { @@ -1113,6 +1121,9 @@ mod tests { let stake = rng.next_u64(); let initializer = StmInitializer::setup(params, pid, stake, &mut rng); + let bytes = initializer.to_bytes(); + assert!(StmInitializer::from_bytes(&bytes).is_ok()); + let bytes = bincode::serialize(&initializer).unwrap(); assert!(bincode::deserialize::(&bytes).is_ok()) } From dacee4f25b22fc93bf0c5e11882f4ffda69ff254 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 8 Jun 2022 11:28:03 +0100 Subject: [PATCH 4/7] Use as_ptr() and as_mut_ptr() --- mithril-core/src/multi_sig.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mithril-core/src/multi_sig.rs b/mithril-core/src/multi_sig.rs index 4571e46dfe..01ccb73a36 100644 --- a/mithril-core/src/multi_sig.rs +++ b/mithril-core/src/multi_sig.rs @@ -163,13 +163,14 @@ impl Sub for VerificationKey { use blst::{blst_bendian_from_fp, blst_fp, blst_fp_cneg, blst_fp_from_bendian}; let mut rhs_bytes = rhs.0.serialize(); unsafe { - let y_bytes: Vec = rhs_bytes[48..].to_vec(); + let mut y_bytes: Vec = rhs_bytes[48..].to_vec(); let mut y: blst_fp = blst_fp::default(); let mut neg_y: blst_fp = blst_fp::default(); - blst_fp_from_bendian(&mut y, &y_bytes[0]); + blst_fp_from_bendian(&mut y, y_bytes.as_ptr()); blst_fp_cneg(&mut neg_y, &y, true); - blst_bendian_from_fp(&mut rhs_bytes[48], &neg_y); + blst_bendian_from_fp(y_bytes.as_mut_ptr(), &neg_y); + rhs_bytes[48..].copy_from_slice(&y_bytes); } let neg_rhs = BlstPk::deserialize(&rhs_bytes) .expect("The negative of a valid point is also a valid point."); @@ -311,7 +312,7 @@ impl ProofOfPossession { pop_bytes[..48].copy_from_slice(&self.k1.to_bytes()); let k2_bytes = unsafe { let mut bytes = [0u8; 48]; - blst_p1_compress(&mut bytes[0], &self.k2); + blst_p1_compress(bytes.as_mut_ptr(), &self.k2); bytes }; pop_bytes[48..].copy_from_slice(&k2_bytes); @@ -331,7 +332,7 @@ impl ProofOfPossession { let k2 = unsafe { let mut point = blst_p1_affine::default(); let mut out = blst_p1::default(); - blst_p1_uncompress(&mut point, &bytes[48]); + blst_p1_uncompress(&mut point, bytes[48..].as_ptr()); blst_p1_from_affine(&mut out, &point); out }; From 1a68789b0fa7f51b33175960a5ee6bb26331201e Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 8 Jun 2022 11:45:47 +0100 Subject: [PATCH 5/7] Remove sub implementation --- mithril-core/src/multi_sig.rs | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/mithril-core/src/multi_sig.rs b/mithril-core/src/multi_sig.rs index 01ccb73a36..38ab27237a 100644 --- a/mithril-core/src/multi_sig.rs +++ b/mithril-core/src/multi_sig.rs @@ -22,7 +22,6 @@ use std::{ cmp::Ordering, hash::{Hash, Hasher}, iter::Sum, - ops::Sub, }; /// String used to generate the proofs of possession. @@ -155,33 +154,6 @@ impl<'a> Sum<&'a Self> for VerificationKey { } } -// We need some unsafe code here due to what is being exposed in the rust FFI. -// todo: Take particular care reviewing this -impl Sub for VerificationKey { - type Output = Self; - fn sub(self, rhs: Self) -> VerificationKey { - use blst::{blst_bendian_from_fp, blst_fp, blst_fp_cneg, blst_fp_from_bendian}; - let mut rhs_bytes = rhs.0.serialize(); - unsafe { - let mut y_bytes: Vec = rhs_bytes[48..].to_vec(); - let mut y: blst_fp = blst_fp::default(); - let mut neg_y: blst_fp = blst_fp::default(); - blst_fp_from_bendian(&mut y, y_bytes.as_ptr()); - blst_fp_cneg(&mut neg_y, &y, true); - - blst_bendian_from_fp(y_bytes.as_mut_ptr(), &neg_y); - rhs_bytes[48..].copy_from_slice(&y_bytes); - } - let neg_rhs = BlstPk::deserialize(&rhs_bytes) - .expect("The negative of a valid point is also a valid point."); - VerificationKey( - AggregatePublicKey::aggregate(&[&neg_rhs, &self.0], false) - .expect("Points are valid") - .to_public_key(), - ) - } -} - /// MultiSig proof of possession, which contains two elements from G1. However, /// the two elements have different types: `k1` is represented as a BlstSig /// as it has the same structure, and this facilitates its verification. On From 4266b06e5c52e9018e0dced748f6e2df5212cc6f Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 8 Jun 2022 11:53:41 +0100 Subject: [PATCH 6/7] lints --- mithril-core/src/error.rs | 36 ++++++++++++++-------------- mithril-core/src/key_reg.rs | 9 +++---- mithril-core/src/merkle_tree.rs | 9 +++---- mithril-core/src/multi_sig_zcash.rs | 37 ++++++++++++++++------------- mithril-core/src/stm.rs | 13 +++++++--- 5 files changed, 57 insertions(+), 47 deletions(-) diff --git a/mithril-core/src/error.rs b/mithril-core/src/error.rs index 9ec5369c4c..0a11507dce 100644 --- a/mithril-core/src/error.rs +++ b/mithril-core/src/error.rs @@ -1,33 +1,33 @@ //! Crate specific errors use crate::merkle_tree::Path; +#[cfg(feature = "zcash")] +use crate::multi_sig_zcash::{Signature, VerificationKey, VerificationKeyPoP}; +use crate::stm::PartyId; +use digest::{Digest, FixedOutput}; #[cfg(not(feature = "zcash"))] use { crate::multi_sig::{Signature, VerificationKey, VerificationKeyPoP}, blst::BLST_ERROR, }; -#[cfg(feature = "zcash")] -use crate::multi_sig_zcash::{Signature, VerificationKey, VerificationKeyPoP}; -use crate::stm::PartyId; -use digest::{Digest, FixedOutput}; // todo: better organise these errors. #[derive(Debug, thiserror::Error, Eq, PartialEq)] /// Error types for multi signatures pub enum MultiSignatureError { -/// Invalid Multi signature -#[error("Invalid multi signature")] -InvalidSignature, -/// This error occurs when the underlying function is passed infinity or an element outsize of the group -#[error("Unexpected point")] -UnexpectedBlstTypes, -/// This error occurs when the the serialization of the raw bytes failed -#[error("Invalid bytes")] -SerializationError, -/// Incorrect proof of possession -#[error("Key with invalid PoP")] -InvalidKey(Box), + /// Invalid Multi signature + #[error("Invalid multi signature")] + InvalidSignature, + /// This error occurs when the underlying function is passed infinity or an element outsize of the group + #[error("Unexpected point")] + UnexpectedBlstTypes, + /// This error occurs when the the serialization of the raw bytes failed + #[error("Invalid bytes")] + SerializationError, + /// Incorrect proof of possession + #[error("Key with invalid PoP")] + InvalidKey(Box), } /// Errors which can be output by Mithril verification. @@ -88,7 +88,7 @@ pub enum AggregationFailure { NotEnoughSignatures(u64, u64), /// This error happens when we try to convert a u64 to a usize and it does not fit #[error("Invalid usize conversion")] - InvalidUsizeConversion + InvalidUsizeConversion, } /// Error types for single signature verification @@ -124,7 +124,7 @@ pub enum MerkleTreeError { pub enum RegisterError { /// This key has already been registered by a participant #[error("This key has already been registered.")] - KeyRegistered(VerificationKey), + KeyRegistered(Box), /// This participant has already been registered #[error("Participant {0} has already been registered.")] PartyRegistered(PartyId), diff --git a/mithril-core/src/key_reg.rs b/mithril-core/src/key_reg.rs index b4091dead7..760d50a358 100644 --- a/mithril-core/src/key_reg.rs +++ b/mithril-core/src/key_reg.rs @@ -6,7 +6,7 @@ use std::collections::{HashMap, HashSet}; use std::sync::Arc; #[cfg(not(feature = "zcash"))] -use crate::multi_sig::{VerificationKeyPoP, VerificationKey}; +use crate::multi_sig::{VerificationKey, VerificationKeyPoP}; #[cfg(feature = "zcash")] use crate::multi_sig_zcash::{VerificationKey, VerificationKeyPoP}; @@ -75,7 +75,7 @@ impl KeyReg { pk: VerificationKeyPoP, ) -> Result<(), RegisterError> { if self.keys.contains(&pk.vk) { - return Err(RegisterError::KeyRegistered(pk.vk)); + return Err(RegisterError::KeyRegistered(Box::new(pk.vk))); } if let Some(mut party) = self.parties.get_mut(&party_id) { @@ -143,7 +143,8 @@ mod tests { use rand_core::SeedableRng; fn arb_participants(min: usize, max: usize) -> impl Strategy> { - vec(1..1u64<<60, min..=max).prop_map(|v| { // 1<<60 to avoid overflows + vec(1..1u64 << 60, min..=max).prop_map(|v| { + // 1<<60 to avoid overflows v.into_iter() .enumerate() .map(|(index, value)| (index as u64, value)) @@ -193,7 +194,7 @@ mod tests { assert!(parties.insert(p.0)); }, Err(RegisterError::KeyRegistered(pk1)) => { - assert!(pk1 == pk.vk); + assert!(pk1.as_ref() == &pk.vk); assert!(keys.contains(&pk.vk)); } Err(RegisterError::PartyRegistered(party)) => { diff --git a/mithril-core/src/merkle_tree.rs b/mithril-core/src/merkle_tree.rs index 25eacb8d83..76cb4d6d0e 100644 --- a/mithril-core/src/merkle_tree.rs +++ b/mithril-core/src/merkle_tree.rs @@ -243,11 +243,7 @@ where /// * All nodes of the merkle tree (starting with the root) pub fn to_bytes(&self) -> Vec { let mut result = Vec::with_capacity(8 + self.nodes.len() * D::output_size()); - result.extend_from_slice( - &u64::try_from(self.n) - .unwrap() - .to_be_bytes(), - ); + result.extend_from_slice(&u64::try_from(self.n).unwrap().to_be_bytes()); for node in self.nodes.iter() { result.extend_from_slice(node); } @@ -258,7 +254,8 @@ where pub fn from_bytes(bytes: &[u8]) -> Result { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(&bytes[..8]); - let n = usize::try_from(u64::from_be_bytes(u64_bytes)).map_err(|_| MerkleTreeError::SerializationError)?; + let n = usize::try_from(u64::from_be_bytes(u64_bytes)) + .map_err(|_| MerkleTreeError::SerializationError)?; let num_nodes = n + n.next_power_of_two() - 1; let mut nodes = Vec::with_capacity(num_nodes); for i in 0..num_nodes { diff --git a/mithril-core/src/multi_sig_zcash.rs b/mithril-core/src/multi_sig_zcash.rs index ee0ab19c45..912335adf4 100644 --- a/mithril-core/src/multi_sig_zcash.rs +++ b/mithril-core/src/multi_sig_zcash.rs @@ -7,22 +7,18 @@ use super::stm::Index; use crate::error::MultiSignatureError; use blake2::{Blake2b, Digest}; +use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve}; use bls12_381::*; use group::ff::Field; -use group::prime::PrimeCurveAffine; -use group::{Curve, GroupEncoding}; -use group::Group; +use group::Curve; use rand_core::{CryptoRng, RngCore}; use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer}; -use std::convert::TryInto; use std::{ cmp::Ordering, hash::{Hash, Hasher}, iter::Sum, - ops::Sub, }; -use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, MapToCurve}; /// String used to generate the proofs of possession. const POP: &[u8] = b"PoP"; @@ -154,11 +150,13 @@ impl Ord for VerificationKey { impl<'a> Sum<&'a Self> for VerificationKey { fn sum(iter: I) -> Self - where - I: Iterator, + where + I: Iterator, { let mut start = G2Projective::identity(); - iter.map(|x| start += x.0); + for val in iter { + start += val.0; + } Self(start) } @@ -166,11 +164,13 @@ impl<'a> Sum<&'a Self> for VerificationKey { impl<'a> Sum<&'a Self> for Signature { fn sum(iter: I) -> Self - where - I: Iterator, + where + I: Iterator, { let mut start = G1Projective::identity(); - iter.map(|x| start += x.0); + for val in iter { + start += val.0; + } Self(start) } @@ -212,7 +212,8 @@ impl From<&SigningKey> for ProofOfPossession { /// `k1 = H_G1(b"PoP" || mvk) * sk` and `k2 = g1 * sk` where `H_G1` hashes into /// `G1` and `g1` is the generator in `G1`. fn from(sk: &SigningKey) -> Self { - let k1 = >>::encode_to_curve(POP, &[]) * sk.0; + let k1 = + >>::encode_to_curve(POP, &[]) * sk.0; let k2 = G1Affine::generator() * sk.0; Self { k1, k2 } @@ -240,7 +241,8 @@ impl VerificationKeyPoP { pub fn check(&self) -> Result<(), MultiSignatureError> { let lhs_1 = pairing(&self.pop.k1.to_affine(), &G2Affine::generator()); let rhs_1 = pairing( - &>>::encode_to_curve(POP, &[]).to_affine(), + &>>::encode_to_curve(POP, &[]) + .to_affine(), &self.vk.0.to_affine(), ); @@ -315,7 +317,8 @@ impl Signature { pub fn verify(&self, msg: &[u8], mvk: &VerificationKey) -> Result<(), MultiSignatureError> { let lhs = pairing(&self.0.to_affine(), &G2Affine::generator()); let rhs = pairing( - &>>::encode_to_curve(msg, &[]).to_affine(), + &>>::encode_to_curve(msg, &[]) + .to_affine(), &mvk.0.to_affine(), ); if lhs == rhs { @@ -356,7 +359,9 @@ impl Signature { pub fn from_bytes(bytes: &[u8]) -> Result { let mut array_byte = [0u8; 48]; array_byte.copy_from_slice(&bytes[..48]); - Ok(Self(G1Projective::from(G1Affine::from_compressed(&array_byte).unwrap()))) + Ok(Self(G1Projective::from( + G1Affine::from_compressed(&array_byte).unwrap(), + ))) } /// Compare two signatures. Used for PartialOrd impl, used to rank signatures. The comparison diff --git a/mithril-core/src/stm.rs b/mithril-core/src/stm.rs index b3495f9d2a..1d9e3b95de 100644 --- a/mithril-core/src/stm.rs +++ b/mithril-core/src/stm.rs @@ -475,9 +475,11 @@ impl StmAggrSig { pub fn from_bytes(bytes: &[u8]) -> Result, MultiSignatureError> { let mut u64_bytes = [0u8; 8]; u64_bytes.copy_from_slice(&bytes[..8]); - let size = usize::try_from(u64::from_be_bytes(u64_bytes)).map_err(|_| MultiSignatureError::SerializationError)?; + let size = usize::try_from(u64::from_be_bytes(u64_bytes)) + .map_err(|_| MultiSignatureError::SerializationError)?; u64_bytes.copy_from_slice(&bytes[8..16]); - let sig_size = usize::try_from(u64::from_be_bytes(u64_bytes)).map_err(|_| MultiSignatureError::SerializationError)?; + let sig_size = usize::try_from(u64::from_be_bytes(u64_bytes)) + .map_err(|_| MultiSignatureError::SerializationError)?; let mut signatures = Vec::with_capacity(size); for i in 0..size { signatures.push(StmSig::from_bytes( @@ -839,7 +841,12 @@ where ) -> Result, AggregationFailure> { // todo: how come the dedup does not take the concatenated message // let msgp = concat_avk_with_msg(&self.avk.to_commitment(), msg); - let mut unique_sigs = Vec::with_capacity(self.params.k.try_into().map_err(|_| AggregationFailure::InvalidUsizeConversion)?); + let mut unique_sigs = Vec::with_capacity( + self.params + .k + .try_into() + .map_err(|_| AggregationFailure::InvalidUsizeConversion)?, + ); for (_, sigs) in self.dedup_sigs_for_indices(msg, sigs)? { unique_sigs.push(sigs.clone()) } From cf5d3ff59e112f26062649693a8af949e5c52554 Mon Sep 17 00:00:00 2001 From: iquerejeta Date: Wed, 8 Jun 2022 12:14:22 +0100 Subject: [PATCH 7/7] sort --- mithril-core/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mithril-core/Cargo.toml b/mithril-core/Cargo.toml index d8fc0f5e1c..5cf9e75d72 100644 --- a/mithril-core/Cargo.toml +++ b/mithril-core/Cargo.toml @@ -9,12 +9,12 @@ crate-type = ["lib", "cdylib", "staticlib"] [dependencies] blake2 = "0.9.2" -blst = { version = "0.3.7", optional = true } bls12_381 = { version = "0.7.0", features = ["experimental"], optional = true } -group = { version = "0.12.0", features = ["tests"], optional = true } +blst = { version = "0.3.7", optional = true } bytes = "1" digest = { version = "0.9.0", features = ["alloc"] } generic-array = "0.14" +group = { version = "0.12.0", features = ["tests"], optional = true } libc = "0.2.40" num-bigint = "0.4.0" num-integer = { version = "0.1.44", optional = true }