Skip to content

Commit

Permalink
feat: dfns/cggmp21 KeyRefresh RingPedersenParams on-chain verific…
Browse files Browse the repository at this point in the history
…ation (#469)

* ring pedersend params on chain verification

* fix clippy issues
  • Loading branch information
shekohex authored Feb 11, 2024
1 parent 60a471d commit 8b59cd0
Show file tree
Hide file tree
Showing 11 changed files with 606 additions and 47 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,8 @@ rpc-txpool = { path = "client/rpc/txpool" }
evm-tracer = { path = "runtime/testnet/evm_tracer", default-features = false }

# MPC
malachite = { version = "0.4", default-features = false }
malachite-base = { version = "0.4", default-features = false }
malachite-nz = { version = "0.4", default-features = false, features = ["32_bit_limbs"] }
postcard = { version = "1", default-features = false }
dfns-cggmp21 = { package = "cggmp21", version = "0.1.1", default-features = false }
udigest = { version = "0.1.0", default-features = false }
Expand All @@ -354,3 +355,5 @@ generic-ec = { git = "https://github.com/webb-tools/generic-ec", branch = "m" }
generic-ec-core = { git = "https://github.com/webb-tools/generic-ec", branch = "m" }
generic-ec-curves = { git = "https://github.com/webb-tools/generic-ec", branch = "m" }
generic-ec-zkp = { git = "https://github.com/webb-tools/generic-ec", branch = "m" }
malachite-base = { git = "https://github.com/shekohex/malachite", branch = "no-std" }
malachite-nz = { git = "https://github.com/shekohex/malachite", branch = "no-std" }
6 changes: 5 additions & 1 deletion pallets/dkg/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,20 @@ subtle = { workspace = true }
tangle-crypto-primitives = { workspace = true, default-features = false }
tangle-primitives = { workspace = true, default-features = false }
rand_core = { workspace = true, default-features = false }
rand_chacha = { workspace = true, default-features = false }

# dfns/CGGMP21 specific dependencies
malachite-base = { workspace = true, default-features = false }
malachite-nz = { workspace = true, default-features = false }
hex = { workspace = true, default-features = false, features = ["serde"] }
postcard = { workspace = true, default-features = false }
sha2 = { workspace = true, default-features = false }
digest = { workspace = true, default-features = false }
udigest = { workspace = true, features = ["derive"] }
generic-ec = { workspace = true, default-features = false, features = ["serde", "udigest", "curve-secp256k1"] }
generic-ec-zkp = { workspace = true, default-features = false, features = ["serde", "udigest", "alloc"] }

# FROST specific dependencies
frost-core = { workspace = true, default-features = false }
frost-ed25519 = { workspace = true, default-features = false }
elliptic-curve = { version = "0.13", features = ["hash2curve"], default-features = false }
Expand All @@ -52,7 +57,6 @@ pallet-balances = { workspace = true }
postcard = { workspace = true, default-features = false, features = ["alloc"] }
smallvec = { workspace = true }
sp-keystore = { workspace = true }
rand_chacha = { workspace = true }
dfns-cggmp21 = { workspace = true, default-features = false, features = ["curve-secp256k1"] }
round-based = { workspace = true, features = ["derive"] }
paillier-zk = { workspace = true, features = ["serde"] }
Expand Down
6 changes: 6 additions & 0 deletions pallets/dkg/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Tangle. If not, see <http://www.gnu.org/licenses/>.

#![allow(mixed_script_confusables, non_snake_case)]
#![cfg_attr(not(feature = "std"), no_std)]
//! # Pallet-DKG
//!
Expand Down Expand Up @@ -162,6 +163,11 @@ pub mod pallet {
/// Schnorr are valid. but the caller
/// claims it is invalid.
ValidSchnorrProof,
/// The submitted ring pedersen parameters are valid.
///
/// This error is returned when the ring pedersen parameters are valid
/// but the caller claims it is invalid.
ValidRingPedersenParameters,
}

#[pallet::call]
Expand Down
69 changes: 37 additions & 32 deletions pallets/dkg/src/misbehavior/dfns_cggmp21/aux_only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use tangle_primitives::misbehavior::{
MisbehaviorSubmission,
};

use super::{DefaultDigest, Integer, M, SECURITY_BYTES};
use super::{zk::ring_pedersen_parameters as π_prm, DefaultDigest, Integer, SECURITY_BYTES};

#[derive(udigest::Digestable)]
#[udigest(tag = "dfns.cggmp21.aux_gen.tag")]
Expand All @@ -39,36 +39,6 @@ pub enum Tag<'a> {
},
}

#[derive(Clone, RuntimeDebug, serde::Deserialize)]
pub struct Proof<const M: usize> {
#[serde(with = "serde_with::As::<[serde_with::Same; M]>")]
pub points: [ProofPoint; M],
}

/// The ZK proof. Computed by [`prove`].
///
/// Parameter `M` is security level. The probability of an adversary generating
/// a correct proof for incorrect data is $2^{-M}$. You can use M defined here
/// as [`SECURITY`]
#[serde_with::serde_as]
#[derive(Clone, RuntimeDebug, serde::Deserialize, udigest::Digestable)]
pub struct ParamProof<const M: usize> {
#[serde_as(as = "[_; M]")]
#[udigest(with = super::integer::encoding::integers_list)]
pub commitment: [Integer; M],
#[serde_as(as = "[_; M]")]
#[udigest(with = super::integer::encoding::integers_list)]
pub zs: [Integer; M],
}

#[derive(Clone, RuntimeDebug, serde::Deserialize)]
pub struct ProofPoint {
pub x: Integer,
pub a: bool,
pub b: bool,
pub z: Integer,
}

/// Message from round 1
#[derive(Clone, RuntimeDebug, serde::Deserialize, udigest::Digestable)]
#[udigest(tag = "dfns.cggmp21.aux_gen.round1")]
Expand All @@ -88,15 +58,18 @@ pub struct MsgRound1<D: Digest> {
pub struct MsgRound2 {
/// $N_i$
#[udigest(with = super::integer::encoding::integer)]
#[serde(with = "super::integer::serde")]
pub N: Integer,
/// $s_i$
#[udigest(with = super::integer::encoding::integer)]
#[serde(with = "super::integer::serde")]
pub s: Integer,
/// $t_i$
#[udigest(with = super::integer::encoding::integer)]
#[serde(with = "super::integer::serde")]
pub t: Integer,
/// $\hat \psi_i$
pub params_proof: ParamProof<M>,
pub params_proof: super::zk::ring_pedersen_parameters::Proof,
/// $\rho_i$
#[serde(with = "hex")]
#[udigest(as_bytes)]
Expand Down Expand Up @@ -138,3 +111,35 @@ pub fn invalid_decommitment<T: Config>(
// TODO: add slashing logic
Ok(())
}

/// Given a KeyRefresh Round2 message, verify the misbehavior and return the result.
pub fn invalid_ring_pedersen_parameters<T: Config>(
data: &MisbehaviorSubmission,
round2: &SignedRoundMessage,
) -> DispatchResult {
Pallet::<T>::ensure_signed_by_offender(round2, data.offender)?;
let i = round2.sender;
let job_id_bytes = data.job_id.to_be_bytes();
let mix = keccak_256(AUX_GEN_EID);
let eid_bytes = [&job_id_bytes[..], &mix[..]].concat();
let parties_shared_state = DefaultDigest::new_with_prefix(DefaultDigest::digest(eid_bytes));
let round2_msg = postcard::from_bytes::<MsgRound2>(&round2.message)
.map_err(|_| Error::<T>::MalformedRoundMessage)?;
if !super::validate_public_paillier_key_size(&round2_msg.N) {
// Slash the offender!
// TODO: add slashing logic
}

let data = π_prm::Data { N: &round2_msg.N, s: &round2_msg.s, t: &round2_msg.t };
let proof = π_prm::verify(
parties_shared_state.clone().chain_update(i.to_be_bytes()),
data,
&round2_msg.params_proof,
);

ensure!(proof.is_err(), Error::<T>::ValidRingPedersenParameters);

// Slash the offender!
// TODO: add slashing logic
Ok(())
}
148 changes: 138 additions & 10 deletions pallets/dkg/src/misbehavior/dfns_cggmp21/integer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,24 @@
// You should have received a copy of the GNU General Public License
// along with Tangle. If not, see <http://www.gnu.org/licenses/>.

use malachite_base::num::conversion::traits::FromStringBase;
use parity_scale_codec::{Decode, Encode};
use scale_info::TypeInfo;
use sp_core::RuntimeDebug;
use sp_std::prelude::*;

#[derive(Clone, RuntimeDebug, serde::Serialize, serde::Deserialize)]
pub struct Integer {
pub radix: i32,
#[derive(Clone, RuntimeDebug, ::serde::Deserialize, ::serde::Serialize)]
pub struct RugInteger {
radix: i32,
#[cfg(not(feature = "std"))]
pub value: ::alloc::string::String,
value: ::alloc::string::String,
#[cfg(feature = "std")]
pub value: ::std::string::String,
value: ::std::string::String,
}

impl Integer {
impl RugInteger {
pub fn to_vec(&self) -> Vec<u8> {
if self.value == "0" {
if self.value == "0" || self.value.is_empty() {
return Vec::new()
}
let mut x = self.value.clone();
Expand All @@ -43,17 +46,56 @@ impl Integer {
}
}

impl<'a> From<&'a malachite_nz::integer::Integer> for RugInteger {
fn from(x: &'a malachite_nz::integer::Integer) -> Self {
use malachite_base::num::{
conversion::traits::ToStringBase, logic::traits::SignificantBits,
};
let radix = if x.significant_bits() <= 32 { 10 } else { 16 };
let value = x.to_string_base(radix as _);
Self { radix, value }
}
}

impl From<malachite_nz::integer::Integer> for RugInteger {
fn from(x: malachite_nz::integer::Integer) -> Self {
Self::from(&x)
}
}

#[derive(RuntimeDebug, Default, Encode, Decode, TypeInfo)]
pub struct MalachiteIntegerError;

impl core::fmt::Display for MalachiteIntegerError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(f, "Could not convert from RugInteger to MalachiteInteger")
}
}

impl TryFrom<RugInteger> for malachite_nz::integer::Integer {
type Error = MalachiteIntegerError;
fn try_from(x: RugInteger) -> Result<Self, Self::Error> {
if x.radix < 2 || x.radix > 36 {
return Err(MalachiteIntegerError)
}
let radix = x.radix as _;
let value = x.value;
malachite_nz::integer::Integer::from_string_base(radix, &value).ok_or(MalachiteIntegerError)
}
}

/// Unambiguous encoding for different types for which it was not defined
pub mod encoding {
pub fn integer<B: udigest::Buffer>(
x: &super::Integer,
x: &malachite_nz::integer::Integer,
encoder: udigest::encoding::EncodeValue<B>,
) {
encoder.encode_leaf().chain(x.to_vec());
let v = super::RugInteger::from(x);
encoder.encode_leaf().chain(v.to_vec());
}

pub fn integers_list<B: udigest::Buffer>(
list: &[super::Integer],
list: &[malachite_nz::integer::Integer],
encoder: udigest::encoding::EncodeValue<B>,
) {
let mut encoder = encoder.encode_list();
Expand All @@ -62,3 +104,89 @@ pub mod encoding {
}
}
}

#[allow(unused)]
pub mod serde {
use ::serde::{Deserialize, Deserializer, Serialize, Serializer};

pub fn serialize<S: Serializer>(
x: &malachite_nz::integer::Integer,
serializer: S,
) -> Result<S::Ok, S::Error> {
let v = super::RugInteger::from(x);
v.serialize(serializer)
}

pub fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<malachite_nz::integer::Integer, D::Error> {
let v = super::RugInteger::deserialize(deserializer)?;
v.try_into().map_err(serde::de::Error::custom)
}
}

#[allow(unused)]
pub mod serde_list {
use crate::misbehavior::dfns_cggmp21::M;
#[cfg(not(feature = "std"))]
use ::alloc::vec::Vec;
use ::serde::{Deserialize, Deserializer, Serialize, Serializer};
use sp_runtime::DeserializeOwned;

#[serde_with::serde_as]
#[derive(Serialize, Deserialize)]
struct FixedLengthArray<T, const N: usize>(#[serde_as(as = "[_; N]")] [T; N])
where
T: Serialize + DeserializeOwned;

pub fn serialize<S: Serializer>(
list: &[malachite_nz::integer::Integer],
serializer: S,
) -> Result<S::Ok, S::Error> {
let out: [super::RugInteger; M] = list
.iter()
.map(super::RugInteger::from)
.collect::<Vec<_>>()
.try_into()
.map_err(|_| serde::ser::Error::custom("Invalid integer list length"))?;
out.serialize(serializer)
}

pub fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<[malachite_nz::integer::Integer; M], D::Error> {
FixedLengthArray::<super::RugInteger, M>::deserialize(deserializer)?
.0
.into_iter()
.map(|x| x.try_into().map_err(serde::de::Error::custom))
.collect::<Result<Vec<_>, _>>()?
.try_into()
.map_err(|_| serde::de::Error::custom("Invalid integer list length"))
}
}

#[allow(unused)]
pub mod serde_vec {
#[cfg(not(feature = "std"))]
use ::alloc::vec::Vec;
use ::serde::{Deserialize, Deserializer, Serialize, Serializer};

pub fn serialize<S: Serializer>(
list: &[malachite_nz::integer::Integer],
serializer: S,
) -> Result<S::Ok, S::Error> {
list.iter()
.map(super::RugInteger::from)
.collect::<Vec<_>>()
.serialize(serializer)
}

pub fn deserialize<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<malachite_nz::integer::Integer>, D::Error> {
Vec::<super::RugInteger>::deserialize(deserializer)?
.into_iter()
.map(|x| x.try_into().map_err(serde::de::Error::custom))
.collect()
}
}
Loading

0 comments on commit 8b59cd0

Please sign in to comment.