Skip to content

Commit

Permalink
Problem: tdbe types are not up to date with latest design (fixes cryp…
Browse files Browse the repository at this point in the history
…to-com#1967)

Solution: updated the data types according to the latest
doc https://github.com/crypto-com/chain-docs/pull/179/files

- chain-abci part was moved to extras module of mls for validation
(when crypto-org-chain/chain-docs#141 is done
implementation could go there)
- in order not to break tx format, confidential init is still takes as Vec<u8>
- as tdbe workflows aren't ready yet, a temporary wrapper was put in the client
  • Loading branch information
tomtau committed Jul 22, 2020
1 parent 5de7039 commit 169e9bb
Show file tree
Hide file tree
Showing 26 changed files with 256 additions and 72 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

8 changes: 4 additions & 4 deletions chain-abci/src/app/staking_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ impl fmt::Display for StakingCoinChange {
#[cfg(test)]
mod tests {
use super::*;
use chain_core::state::account::ConfidentialInit;
use chain_core::state::account::{ConfidentialInit, MLSInit};
use chain_core::state::tendermint::TendermintValidatorPubKey;
use chain_core::tx::fee::Fee;
use std::str::FromStr;
Expand Down Expand Up @@ -437,7 +437,7 @@ mod tests {

assert_eq!(
staking_diff.to_string(),
"{\"key\":\"CouncilNode\",\"value\":{\"name\":\"Council Node\",\"security_contact\":\"[email protected]\",\"confidential_init\":{\"keypackage\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"},\"consensus_pubkey\":{\"type\":\"tendermint/PubKeyEd25519\",\"value\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"}}}",
"{\"key\":\"CouncilNode\",\"value\":{\"name\":\"Council Node\",\"security_contact\":\"[email protected]\",\"confidential_init\":{\"init_payload\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"},\"consensus_pubkey\":{\"type\":\"tendermint/PubKeyEd25519\",\"value\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=\"}}}",
);
}

Expand All @@ -446,7 +446,7 @@ mod tests {
let any_security_contact = Some(String::from("[email protected]"));
let any_pub_key = TendermintValidatorPubKey::Ed25519([0u8; 32]);
let any_cert = ConfidentialInit {
keypackage: [0u8; 32].to_vec(),
init_payload: MLSInit::Genesis([0u8; 32].to_vec()),
};

CouncilNodeMeta::new_with_details(
Expand Down Expand Up @@ -546,7 +546,7 @@ mod tests {
let any_security_contact = Some(String::from("[email protected]"));
let any_pub_key = TendermintValidatorPubKey::Ed25519([0u8; 32]);
let any_cert = ConfidentialInit {
keypackage: [0u8; 32].to_vec(),
init_payload: MLSInit::Genesis([0u8; 32].to_vec()),
};

CouncilNodeMeta::new_with_details(
Expand Down
15 changes: 8 additions & 7 deletions chain-abci/src/staking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ mod tests {
use chain_core::tx::fee::Fee;
use chain_storage::buffer::{Get, GetStaking, MemStore, StoreStaking};
use test_common::chain_env::{
get_init_network_params, mock_council_node, mock_council_node_meta, DEFAULT_GENESIS_TIME,
get_init_network_params, mock_council_node_join, mock_council_node_meta,
DEFAULT_GENESIS_TIME,
};

use super::*;
Expand Down Expand Up @@ -118,7 +119,7 @@ mod tests {
nonce,
address: addr4,
attributes: Default::default(),
node_meta: mock_council_node(val_pk4.clone()),
node_meta: mock_council_node_join(val_pk4.clone()),
};
table
.node_join(&mut store, DEFAULT_GENESIS_TIME + 10, 0, 0, &node_join)
Expand Down Expand Up @@ -271,7 +272,7 @@ mod tests {
nonce,
address: addr1,
attributes: Default::default(),
node_meta: mock_council_node(val_pk_new),
node_meta: mock_council_node_join(val_pk_new),
};
assert!(matches!(
table.node_join(&mut store, DEFAULT_GENESIS_TIME + 3, 0, 0, &node_join),
Expand Down Expand Up @@ -337,7 +338,7 @@ mod tests {
nonce: staking.nonce + 1,
address: addr,
attributes: Default::default(),
node_meta: mock_council_node(val_pk_new.clone()),
node_meta: mock_council_node_join(val_pk_new.clone()),
};
// change to new validator key
let result = table.node_join(store, DEFAULT_GENESIS_TIME + 1, 1, 0, &node_join);
Expand Down Expand Up @@ -392,7 +393,7 @@ mod tests {
nonce: 0,
address: addr_new,
attributes: Default::default(),
node_meta: mock_council_node(val_pk1),
node_meta: mock_council_node_join(val_pk1),
};
// can't join with used key
assert!(matches!(
Expand Down Expand Up @@ -469,7 +470,7 @@ mod tests {
nonce,
address: addr1,
attributes: Default::default(),
node_meta: mock_council_node(val_pk1.clone()),
node_meta: mock_council_node_join(val_pk1.clone()),
};

let mut init_params = get_init_network_params(Coin::zero());
Expand Down Expand Up @@ -795,7 +796,7 @@ mod tests {
nonce: 1,
address: addr2,
attributes: Default::default(),
node_meta: mock_council_node(val_pk_new.clone()),
node_meta: mock_council_node_join(val_pk_new.clone()),
};
table
.node_join(&mut store, DEFAULT_GENESIS_TIME + 2, 0, 0, &tx)
Expand Down
16 changes: 8 additions & 8 deletions chain-abci/src/staking/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ use chain_core::state::tendermint::{BlockHeight, TendermintValidatorAddress};
use chain_core::state::validator::NodeJoinRequestTx;
use chain_core::tx::fee::Fee;
use chain_storage::buffer::StoreStaking;
use mls::{Codec, KeyPackage};
use ra_client::ENCLAVE_CERT_VERIFIER;
use mls::extras::check_nodejoin;

use super::table::{set_staking, StakingTable};
use crate::tx_error::{
Expand Down Expand Up @@ -40,13 +39,14 @@ impl StakingTable {
let isv_svn = if cfg!(feature = "mock-enclave") {
0
} else {
let keypackage = KeyPackage::read_bytes(&tx.get_keypackage_payload())
.ok_or(NodeJoinError::KeyPackageDecodeError)?;
let info = keypackage
.verify(&*ENCLAVE_CERT_VERIFIER, block_time)
.map_err(NodeJoinError::KeyPackageVerifyError)?;
// FIXME: more tdbe-related checks that may be observable by abci -- e.g. key not in the mls tree already
info.quote.report_body.isv_svn
let (add, commit) = tx
.node_meta
.get_node_join_mls_init()
.ok_or(NodeJoinError::InvalidMLSInitData)?;
let r = check_nodejoin(add, commit, block_time)
.map_err(NodeJoinError::MLSInitVerifyError)?;
r.info.quote.report_body.isv_svn
};

let new_isv_svn = if isv_svn > recent_isv_svn {
Expand Down
10 changes: 5 additions & 5 deletions chain-abci/src/tx_error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use chain_core::init::coin::{Coin, CoinError};
use mls::keypackage;
use mls::extras::{self};

#[derive(thiserror::Error, Debug)]
pub enum TxError {
Expand Down Expand Up @@ -53,10 +53,10 @@ pub enum NodeJoinError {
IsJailed,
#[error("the used_validator_addresses queue is full")]
UsedValidatorAddrFull,
#[error("key package decode failed")]
KeyPackageDecodeError,
#[error("invalid key package: {0}")]
KeyPackageVerifyError(#[from] keypackage::Error),
#[error("failed to decode Add proposal and Commit message")]
InvalidMLSInitData,
#[error("invalid mls init data: {0}")]
MLSInitVerifyError(#[from] extras::NodeJoinError),
#[error("FIXME: WIP -- community node not yet supported")]
WIPNotValidator,
}
Expand Down
4 changes: 2 additions & 2 deletions chain-abci/tests/abci_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use std::convert::TryInto;
use std::str::FromStr;
use std::sync::Arc;
use test_common::chain_env::{
mock_confidential_init, mock_council_node, ChainEnv, DEFAULT_GENESIS_TIME,
mock_confidential_init, mock_council_node_join, ChainEnv, DEFAULT_GENESIS_TIME,
};

const TEST_CHAIN_ID: &str = "test-00";
Expand Down Expand Up @@ -1064,7 +1064,7 @@ fn all_valid_tx_types_should_commit() {
1,
addr.into(),
StakedStateOpAttributes::new(0),
mock_council_node(TendermintValidatorPubKey::Ed25519([2u8; 32])),
mock_council_node_join(TendermintValidatorPubKey::Ed25519([2u8; 32])),
);
let secp = Secp256k1::new();
let witness = StakedStateOpWitness::new(get_ecdsa_witness(&secp, &tx.id(), &secret_key));
Expand Down
4 changes: 2 additions & 2 deletions chain-abci/tests/tx_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use std::fmt::Debug;
use std::mem;
use std::sync::Arc;
use test_common::chain_env::{
mock_confidential_init, mock_council_node_meta, DEFAULT_GENESIS_TIME,
mock_confidential_init_node_join, mock_council_node_meta, DEFAULT_GENESIS_TIME,
};

fn verify_enclave_tx<T: EnclaveProxy>(
Expand Down Expand Up @@ -1347,7 +1347,7 @@ fn prepare_nodejoin_transaction(
"test".to_string(),
None,
TendermintValidatorPubKey::Ed25519([1u8; 32]),
mock_confidential_init(),
mock_confidential_init_node_join(),
),
};
let witness = get_account_op_witness(secp, &tx.id(), &secret_key);
Expand Down
7 changes: 5 additions & 2 deletions chain-core/src/init/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::init::address::RedeemAddress;
use crate::init::coin::{sum_coins, Coin, CoinError};
pub use crate::init::params::*;
use crate::state::account::{
ConfidentialInit, CouncilNodeMeta, NodeName, NodeSecurityContact, StakedState,
ConfidentialInit, CouncilNodeMeta, MLSInit, NodeName, NodeSecurityContact, StakedState,
StakedStateAddress, StakedStateDestination,
};
use crate::state::tendermint::TendermintValidatorPubKey;
Expand Down Expand Up @@ -200,7 +200,10 @@ impl InitConfig {

let isv_svn = validators
.iter()
.map(|v| verify_keypackage(genesis_time, &v.1.node_info.confidential_init.keypackage))
.map(|v| match &v.1.node_info.confidential_init.init_payload {
MLSInit::Genesis(ref kp) => verify_keypackage(genesis_time, &kp),
_ => Err(DistributionError::KeyPackageDecodeError),
})
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.max()
Expand Down
71 changes: 58 additions & 13 deletions chain-core/src/state/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ pub type NodeName = String;
/// optional security@... email
pub type NodeSecurityContact = Option<String>;

/// FIXME: Encode, Decode implementations when MLS payloads are stabilized
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode)]
pub enum MLSInit {
/// KeyPackage
Genesis(Vec<u8>),
/// payloads retrieved from other node's TDBE
NodeJoin {
/// MLSPlaintext -- Add
add: Vec<u8>,
/// MLSPlaintext -- Commit
commit: Vec<u8>,
},
}

/// the initial data a node submits to join a MLS group
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[cfg_attr(not(feature = "mesalock_sgx"), derive(Serialize, Deserialize))]
Expand All @@ -45,24 +59,29 @@ pub struct ConfidentialInit {
deserialize_with = "deserialize_base64"
)
)]
pub keypackage: Vec<u8>,
pub init_payload: MLSInit,
}

#[cfg(not(feature = "mesalock_sgx"))]
fn serialize_base64<S>(keypackage: &[u8], serializer: S) -> Result<S::Ok, S::Error>
fn serialize_base64<S>(init_payload: &MLSInit, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
base64::encode(keypackage).serialize(serializer)
match init_payload {
MLSInit::Genesis(kp) => base64::encode(kp).serialize(serializer),
_ => "FIXME".serialize(serializer),
}
}

#[cfg(not(feature = "mesalock_sgx"))]
fn deserialize_base64<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
fn deserialize_base64<'de, D>(deserializer: D) -> Result<MLSInit, D::Error>
where
D: Deserializer<'de>,
{
base64::decode(String::deserialize(deserializer)?.as_bytes())
.map_err(|e| D::Error::custom(format!("{}", e)))
let kp = base64::decode(String::deserialize(deserializer)?.as_bytes())
.map_err(|e| D::Error::custom(format!("{}", e)))?;
// FIXME: non-genesis
Ok(MLSInit::Genesis(kp))
}

/// Information common to different node types
Expand Down Expand Up @@ -96,7 +115,10 @@ impl Encode for NodeCommonInfo {
c.encode_to(dest);
}
};
self.confidential_init.keypackage.encode_to(dest);
// 0.5 test vectors specified it as Vec<u8> blob
// FIXME: ok to break when stabilized in 0.6? will it break HW wallet parser?
let temp: Vec<u8> = self.confidential_init.init_payload.encode();
temp.encode_to(dest);
}
}

Expand Down Expand Up @@ -126,11 +148,14 @@ const MAX_STRING_LEN: usize = 255;
impl Decode for NodeCommonInfo {
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
let (name, security_contact) = decode_name_security_contact(input)?;
let keypackage: Vec<u8> = Vec::decode(input)?;
// 0.5 test vectors specified it as Vec<u8> blob
// FIXME: ok to break when stabilized in 0.6? will it break HW wallet parser?
let temp: Vec<u8> = Vec::decode(input)?;
let init_payload = MLSInit::decode(&mut temp.as_ref())?;
Ok(NodeCommonInfo {
name,
security_contact,
confidential_init: ConfidentialInit { keypackage },
confidential_init: ConfidentialInit { init_payload },
})
}
}
Expand Down Expand Up @@ -160,7 +185,10 @@ impl Encode for CouncilNodeMeta {
}
};
self.consensus_pubkey.encode_to(dest);
self.node_info.confidential_init.keypackage.encode_to(dest);
// 0.5 test vectors specified it as Vec<u8> blob
// FIXME: ok to break when stabilized in 0.6? will it break HW wallet parser?
let temp: Vec<u8> = self.node_info.confidential_init.init_payload.encode();
temp.encode_to(dest);
}
}

Expand All @@ -171,12 +199,15 @@ impl Decode for CouncilNodeMeta {
// where it was like this
let (name, security_contact) = decode_name_security_contact(input)?;
let consensus_pubkey = TendermintValidatorPubKey::decode(input)?;
let keypackage: Vec<u8> = Vec::decode(input)?;
// 0.5 test vectors specified it as Vec<u8> blob
// FIXME: ok to break when stabilized in 0.6? will it break HW wallet parser?
let temp: Vec<u8> = Vec::decode(input)?;
let init_payload = MLSInit::decode(&mut temp.as_ref())?;
Ok(CouncilNodeMeta::new_with_details(
name,
security_contact,
consensus_pubkey,
ConfidentialInit { keypackage },
ConfidentialInit { init_payload },
))
}
}
Expand Down Expand Up @@ -235,6 +266,18 @@ impl Decode for NodeMetadata {
}

impl NodeMetadata {
/// retrieves the add and commit proposals (if any)
pub fn get_node_join_mls_init(&self) -> Option<(&[u8], &[u8])> {
let init_payload = match self {
NodeMetadata::CouncilNode(cm) => &cm.node_info.confidential_init.init_payload,
NodeMetadata::CommunityNode(info) => &info.confidential_init.init_payload,
};
match init_payload {
MLSInit::NodeJoin { add, commit } => Some((add, commit)),
_ => None,
}
}

/// create an empty council node (in testing etc.)
pub fn new_council_node(
consensus_pubkey: TendermintValidatorPubKey,
Expand Down Expand Up @@ -622,7 +665,9 @@ mod test {
name,
security_contact,
TendermintValidatorPubKey::Ed25519(raw_pubkey),
ConfidentialInit { keypackage },
ConfidentialInit {
init_payload: MLSInit::Genesis(keypackage),
},
)
}
}
Expand Down
8 changes: 0 additions & 8 deletions chain-core/src/state/validator/nodejoin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,6 @@ impl Encode for NodeJoinRequestTx {
impl TransactionId for NodeJoinRequestTx {}

impl NodeJoinRequestTx {
/// returns the keypackage
pub fn get_keypackage_payload(&self) -> &[u8] {
match &self.node_meta {
NodeMetadata::CouncilNode(cm) => &cm.node_info.confidential_init.keypackage,
NodeMetadata::CommunityNode(cm) => &cm.confidential_init.keypackage,
}
}

/// constructs a new node join request transaction from the provided components
#[inline]
pub fn new(
Expand Down
8 changes: 8 additions & 0 deletions chain-tx-enclave-next/mls/src/extras/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
///! This module contains additional parts that are a part of the MLS draft spec,
///! but are required for resolving relevant open issues in the draft spec
///! or for extra conventions / operations: https://github.com/crypto-com/chain-docs/blob/master/docs/modules/tdbe.md.
/// module for external validation
mod validation;

pub use validation::{check_nodejoin, NodeJoinError, NodeJoinResult};
Loading

0 comments on commit 169e9bb

Please sign in to comment.