SecretStore: ECDSA session for cases when 2*t < N (#7739)
* SecretStore: ECDSA PoC * SecretStore: fixed ECDSA serialization + cleanup * removed unused param * removed unused method * removed debug unwrap * SecretStore: 'limited' ECDSA session * fix after merge
This commit is contained in:
parent
cdb3afee42
commit
0da6c7eb45
@ -132,13 +132,13 @@ impl DocumentKeyServer for KeyServerImpl {
|
||||
}
|
||||
|
||||
impl MessageSigner for KeyServerImpl {
|
||||
fn sign_message(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
fn sign_message_schnorr(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
// recover requestor' public key from signature
|
||||
let public = ethkey::recover(signature, key_id)
|
||||
.map_err(|_| Error::BadSignature)?;
|
||||
|
||||
// sign message
|
||||
let signing_session = self.data.lock().cluster.new_signing_session(key_id.clone(), signature.clone(), None, message)?;
|
||||
let signing_session = self.data.lock().cluster.new_schnorr_signing_session(key_id.clone(), signature.clone(), None, message)?;
|
||||
let message_signature = signing_session.wait()?;
|
||||
|
||||
// compose two message signature components into single one
|
||||
@ -151,6 +151,21 @@ impl MessageSigner for KeyServerImpl {
|
||||
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
|
||||
Ok(message_signature)
|
||||
}
|
||||
|
||||
fn sign_message_ecdsa(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
// recover requestor' public key from signature
|
||||
let public = ethkey::recover(signature, key_id)
|
||||
.map_err(|_| Error::BadSignature)?;
|
||||
|
||||
// sign message
|
||||
let signing_session = self.data.lock().cluster.new_ecdsa_signing_session(key_id.clone(), signature.clone(), None, message)?;
|
||||
let message_signature = signing_session.wait()?;
|
||||
|
||||
// encrypt combined signature with requestor public key
|
||||
let message_signature = ethcrypto::ecies::encrypt(&public, ðcrypto::DEFAULT_MAC, &*message_signature)
|
||||
.map_err(|err| Error::Internal(format!("Error encrypting message signature: {}", err)))?;
|
||||
Ok(message_signature)
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyServerCore {
|
||||
@ -209,13 +224,13 @@ pub mod tests {
|
||||
use std::net::SocketAddr;
|
||||
use std::collections::BTreeMap;
|
||||
use ethcrypto;
|
||||
use ethkey::{self, Secret, Random, Generator};
|
||||
use ethkey::{self, Secret, Random, Generator, verify_public};
|
||||
use acl_storage::DummyAclStorage;
|
||||
use key_storage::tests::DummyKeyStorage;
|
||||
use node_key_pair::PlainNodeKeyPair;
|
||||
use key_server_set::tests::MapKeyServerSet;
|
||||
use key_server_cluster::math;
|
||||
use ethereum_types::H256;
|
||||
use ethereum_types::{H256, H520};
|
||||
use types::all::{Error, Public, ClusterConfiguration, NodeAddress, RequestSignature, ServerKeyId,
|
||||
EncryptedDocumentKey, EncryptedDocumentKeyShadow, MessageHash, EncryptedMessageSignature, NodeId};
|
||||
use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
|
||||
@ -260,7 +275,11 @@ pub mod tests {
|
||||
}
|
||||
|
||||
impl MessageSigner for DummyKeyServer {
|
||||
fn sign_message(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
fn sign_message_schnorr(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
unimplemented!("test-only")
|
||||
}
|
||||
|
||||
fn sign_message_ecdsa(&self, _key_id: &ServerKeyId, _signature: &RequestSignature, _message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
unimplemented!("test-only")
|
||||
}
|
||||
}
|
||||
@ -411,13 +430,13 @@ pub mod tests {
|
||||
|
||||
// sign message
|
||||
let message_hash = H256::from(42);
|
||||
let combined_signature = key_servers[0].sign_message(&server_key_id, &signature, message_hash.clone()).unwrap();
|
||||
let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature, message_hash.clone()).unwrap();
|
||||
let combined_signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &combined_signature).unwrap();
|
||||
let signature_c = Secret::from_slice(&combined_signature[..32]);
|
||||
let signature_s = Secret::from_slice(&combined_signature[32..]);
|
||||
|
||||
// check signature
|
||||
assert_eq!(math::verify_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
|
||||
assert_eq!(math::verify_schnorr_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
|
||||
}
|
||||
}
|
||||
|
||||
@ -444,7 +463,7 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signing_session_is_delegated_when_node_does_not_have_key_share() {
|
||||
fn schnorr_signing_session_is_delegated_when_node_does_not_have_key_share() {
|
||||
//::logger::init_log();
|
||||
let key_servers = make_key_servers(6114, 3);
|
||||
let threshold = 1;
|
||||
@ -460,13 +479,38 @@ pub mod tests {
|
||||
|
||||
// sign message
|
||||
let message_hash = H256::from(42);
|
||||
let combined_signature = key_servers[0].sign_message(&server_key_id, &signature, message_hash.clone()).unwrap();
|
||||
let combined_signature = key_servers[0].sign_message_schnorr(&server_key_id, &signature, message_hash.clone()).unwrap();
|
||||
let combined_signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &combined_signature).unwrap();
|
||||
let signature_c = Secret::from_slice(&combined_signature[..32]);
|
||||
let signature_s = Secret::from_slice(&combined_signature[32..]);
|
||||
|
||||
// check signature
|
||||
assert_eq!(math::verify_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
|
||||
assert_eq!(math::verify_schnorr_signature(&server_public, &(signature_c, signature_s), &message_hash), Ok(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ecdsa_signing_session_is_delegated_when_node_does_not_have_key_share() {
|
||||
//::logger::init_log();
|
||||
let key_servers = make_key_servers(6117, 4);
|
||||
let threshold = 1;
|
||||
|
||||
// generate server key
|
||||
let server_key_id = Random.generate().unwrap().secret().clone();
|
||||
let requestor_secret = Random.generate().unwrap().secret().clone();
|
||||
let signature = ethkey::sign(&requestor_secret, &server_key_id).unwrap();
|
||||
let server_public = key_servers[0].generate_key(&server_key_id, &signature, threshold).unwrap();
|
||||
|
||||
// remove key from node0
|
||||
key_servers[0].cluster().key_storage().remove(&server_key_id).unwrap();
|
||||
|
||||
// sign message
|
||||
let message_hash = H256::random();
|
||||
let signature = key_servers[0].sign_message_ecdsa(&server_key_id, &signature, message_hash.clone()).unwrap();
|
||||
let signature = ethcrypto::ecies::decrypt(&requestor_secret, ðcrypto::DEFAULT_MAC, &signature).unwrap();
|
||||
let signature: H520 = signature[0..65].into();
|
||||
|
||||
// check signature
|
||||
assert!(verify_public(&server_public, &signature.into(), &message_hash).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -23,7 +23,8 @@ use key_server_cluster::{Error, SessionId, NodeId, DocumentKeyShare};
|
||||
use key_server_cluster::cluster::Cluster;
|
||||
use key_server_cluster::cluster_sessions::{SessionIdWithSubSession, ClusterSession};
|
||||
use key_server_cluster::decryption_session::SessionImpl as DecryptionSession;
|
||||
use key_server_cluster::signing_session::SessionImpl as SigningSession;
|
||||
use key_server_cluster::signing_session_ecdsa::SessionImpl as EcdsaSigningSession;
|
||||
use key_server_cluster::signing_session_schnorr::SessionImpl as SchnorrSigningSession;
|
||||
use key_server_cluster::message::{Message, KeyVersionNegotiationMessage, RequestKeyVersions, KeyVersions};
|
||||
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
||||
|
||||
@ -56,8 +57,10 @@ pub struct SessionImpl<T: SessionTransport> {
|
||||
pub enum ContinueAction {
|
||||
/// Decryption session + is_shadow_decryption.
|
||||
Decrypt(Arc<DecryptionSession>, bool),
|
||||
/// Signing session + message hash.
|
||||
Sign(Arc<SigningSession>, H256),
|
||||
/// Schnorr signing session + message hash.
|
||||
SchnorrSign(Arc<SchnorrSigningSession>, H256),
|
||||
/// ECDSA signing session + message hash.
|
||||
EcdsaSign(Arc<EcdsaSigningSession>, H256),
|
||||
}
|
||||
|
||||
/// Immutable session data.
|
||||
|
@ -1166,7 +1166,7 @@ pub mod tests {
|
||||
|
||||
pub fn generate_key(threshold: usize, nodes_ids: BTreeSet<NodeId>) -> GenerationMessageLoop {
|
||||
let mut gml = GenerationMessageLoop::with_nodes_ids(nodes_ids);
|
||||
gml.master().initialize(Public::default(), threshold, gml.nodes.keys().cloned().collect()).unwrap();
|
||||
gml.master().initialize(Public::default(), false, threshold, gml.nodes.keys().cloned().collect::<BTreeSet<_>>().into()).unwrap();
|
||||
while let Some((from, to, message)) = gml.take_message() {
|
||||
gml.process_message((from, to, message)).unwrap();
|
||||
}
|
||||
|
@ -81,6 +81,8 @@ struct SessionData {
|
||||
author: Option<Public>,
|
||||
|
||||
// === Values, filled when session initialization is completed ===
|
||||
/// Is zero secret generation session?
|
||||
is_zero: Option<bool>,
|
||||
/// Threshold value for this DKG. Only `threshold + 1` will be able to collectively recreate joint secret,
|
||||
/// and thus - decrypt message, encrypted with joint public.
|
||||
threshold: Option<usize>,
|
||||
@ -103,7 +105,7 @@ struct SessionData {
|
||||
/// Key share.
|
||||
key_share: Option<Result<DocumentKeyShare, Error>>,
|
||||
/// Jointly generated public key, which can be used to encrypt secret. Public.
|
||||
joint_public_and_secret: Option<Result<(Public, Secret), Error>>,
|
||||
joint_public_and_secret: Option<Result<(Public, Secret, Secret), Error>>,
|
||||
}
|
||||
|
||||
/// Mutable node-specific data.
|
||||
@ -171,6 +173,32 @@ pub enum SessionState {
|
||||
Failed,
|
||||
}
|
||||
|
||||
pub enum InitializationNodes {
|
||||
RandomNumbers(BTreeSet<NodeId>),
|
||||
SpecificNumbers(BTreeMap<NodeId, Secret>)
|
||||
}
|
||||
|
||||
impl InitializationNodes {
|
||||
pub fn set(&self) -> BTreeSet<NodeId> {
|
||||
match *self {
|
||||
InitializationNodes::RandomNumbers(ref nodes) => nodes.clone(),
|
||||
InitializationNodes::SpecificNumbers(ref nodes) => nodes.keys().cloned().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BTreeSet<NodeId>> for InitializationNodes {
|
||||
fn from(nodes: BTreeSet<NodeId>) -> Self {
|
||||
InitializationNodes::RandomNumbers(nodes)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BTreeMap<NodeId, Secret>> for InitializationNodes {
|
||||
fn from(nodes: BTreeMap<NodeId, Secret>) -> Self {
|
||||
InitializationNodes::SpecificNumbers(nodes)
|
||||
}
|
||||
}
|
||||
|
||||
impl SessionImpl {
|
||||
/// Create new generation session.
|
||||
pub fn new(params: SessionParams) -> Self {
|
||||
@ -188,6 +216,7 @@ impl SessionImpl {
|
||||
simulate_faulty_behaviour: false,
|
||||
master: None,
|
||||
author: None,
|
||||
is_zero: None,
|
||||
threshold: None,
|
||||
derived_point: None,
|
||||
nodes: BTreeMap::new(),
|
||||
@ -228,14 +257,14 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
/// Get generated public and secret (if any).
|
||||
pub fn joint_public_and_secret(&self) -> Option<Result<(Public, Secret), Error>> {
|
||||
pub fn joint_public_and_secret(&self) -> Option<Result<(Public, Secret, Secret), Error>> {
|
||||
self.data.lock().joint_public_and_secret.clone()
|
||||
}
|
||||
|
||||
/// Start new session initialization. This must be called on master node.
|
||||
pub fn initialize(&self, author: Public, threshold: usize, nodes: BTreeSet<NodeId>) -> Result<(), Error> {
|
||||
check_cluster_nodes(self.node(), &nodes)?;
|
||||
check_threshold(threshold, &nodes)?;
|
||||
pub fn initialize(&self, author: Public, is_zero: bool, threshold: usize, nodes: InitializationNodes) -> Result<(), Error> {
|
||||
check_cluster_nodes(self.node(), &nodes.set())?;
|
||||
check_threshold(threshold, &nodes.set())?;
|
||||
|
||||
let mut data = self.data.lock();
|
||||
|
||||
@ -247,11 +276,21 @@ impl SessionImpl {
|
||||
// update state
|
||||
data.master = Some(self.node().clone());
|
||||
data.author = Some(author.clone());
|
||||
data.is_zero = Some(is_zero);
|
||||
data.threshold = Some(threshold);
|
||||
for node_id in &nodes {
|
||||
// generate node identification parameter
|
||||
let node_id_number = math::generate_random_scalar()?;
|
||||
data.nodes.insert(node_id.clone(), NodeData::with_id_number(node_id_number));
|
||||
match nodes {
|
||||
InitializationNodes::RandomNumbers(nodes) => {
|
||||
for node_id in nodes {
|
||||
// generate node identification parameter
|
||||
let node_id_number = math::generate_random_scalar()?;
|
||||
data.nodes.insert(node_id, NodeData::with_id_number(node_id_number));
|
||||
}
|
||||
},
|
||||
InitializationNodes::SpecificNumbers(nodes) => {
|
||||
for (node_id, node_id_number) in nodes {
|
||||
data.nodes.insert(node_id, NodeData::with_id_number(node_id_number));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
let mut visit_policy = EveryOtherNodeVisitor::new(self.node(), data.nodes.keys().cloned());
|
||||
@ -266,6 +305,7 @@ impl SessionImpl {
|
||||
session_nonce: self.nonce,
|
||||
author: author.into(),
|
||||
nodes: data.nodes.iter().map(|(k, v)| (k.clone().into(), v.id_number.clone().into())).collect(),
|
||||
is_zero: data.is_zero.expect("is_zero is filled in initialization phase; KD phase follows initialization phase; qed"),
|
||||
threshold: data.threshold.expect("threshold is filled in initialization phase; KD phase follows initialization phase; qed"),
|
||||
derived_point: derived_point.into(),
|
||||
})))
|
||||
@ -339,6 +379,7 @@ impl SessionImpl {
|
||||
data.author = Some(message.author.clone().into());
|
||||
data.state = SessionState::WaitingForInitializationComplete;
|
||||
data.nodes = message.nodes.iter().map(|(id, number)| (id.clone().into(), NodeData::with_id_number(number.clone().into()))).collect();
|
||||
data.is_zero = Some(message.is_zero);
|
||||
data.threshold = Some(message.threshold);
|
||||
|
||||
Ok(())
|
||||
@ -371,6 +412,7 @@ impl SessionImpl {
|
||||
session_nonce: self.nonce,
|
||||
author: data.author.as_ref().expect("author is filled on initialization step; confrm initialization follows initialization; qed").clone().into(),
|
||||
nodes: data.nodes.iter().map(|(k, v)| (k.clone().into(), v.id_number.clone().into())).collect(),
|
||||
is_zero: data.is_zero.expect("is_zero is filled in initialization phase; KD phase follows initialization phase; qed"),
|
||||
threshold: data.threshold.expect("threshold is filled in initialization phase; KD phase follows initialization phase; qed"),
|
||||
derived_point: message.derived_point.clone().into(),
|
||||
})));
|
||||
@ -427,8 +469,9 @@ impl SessionImpl {
|
||||
debug_assert!(data.nodes.contains_key(&sender));
|
||||
|
||||
// check message
|
||||
let is_zero = data.is_zero.expect("is_zero is filled in initialization phase; KD phase follows initialization phase; qed");
|
||||
let threshold = data.threshold.expect("threshold is filled in initialization phase; KD phase follows initialization phase; qed");
|
||||
if message.publics.len() != threshold + 1 {
|
||||
if !is_zero && message.publics.len() != threshold + 1 {
|
||||
return Err(Error::InvalidMessage);
|
||||
}
|
||||
|
||||
@ -509,9 +552,12 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
// calculate joint public key
|
||||
let joint_public = {
|
||||
let is_zero = data.is_zero.expect("is_zero is filled in initialization phase; KG phase follows initialization phase; qed");
|
||||
let joint_public = if !is_zero {
|
||||
let public_shares = data.nodes.values().map(|n| n.public_share.as_ref().expect("keys received on KD phase; KG phase follows KD phase; qed"));
|
||||
math::compute_joint_public(public_shares)?
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
// save encrypted data to key storage
|
||||
@ -585,16 +631,23 @@ impl SessionImpl {
|
||||
|
||||
// pick 2t + 2 random numbers as polynomial coefficients for 2 polynoms
|
||||
let threshold = data.threshold.expect("threshold is filled on initialization phase; KD phase follows initialization phase; qed");
|
||||
let polynom1 = math::generate_random_polynom(threshold)?;
|
||||
let is_zero = data.is_zero.expect("is_zero is filled on initialization phase; KD phase follows initialization phase; qed");
|
||||
let mut polynom1 = math::generate_random_polynom(threshold)?;
|
||||
if is_zero {
|
||||
polynom1[0] = math::zero_scalar();
|
||||
}
|
||||
let polynom2 = math::generate_random_polynom(threshold)?;
|
||||
data.polynom1 = Some(polynom1.clone());
|
||||
data.secret_coeff = Some(polynom1[0].clone());
|
||||
|
||||
// compute t+1 public values
|
||||
let publics = math::public_values_generation(threshold,
|
||||
data.derived_point.as_ref().expect("keys dissemination occurs after derived point is agreed; qed"),
|
||||
&polynom1,
|
||||
&polynom2)?;
|
||||
let publics = match is_zero {
|
||||
false => math::public_values_generation(threshold,
|
||||
data.derived_point.as_ref().expect("keys dissemination occurs after derived point is agreed; qed"),
|
||||
&polynom1,
|
||||
&polynom2)?,
|
||||
true => Default::default(),
|
||||
};
|
||||
|
||||
// compute secret values for every other node
|
||||
for (node, node_data) in data.nodes.iter_mut() {
|
||||
@ -629,25 +682,35 @@ impl SessionImpl {
|
||||
|
||||
// key verification (KV) phase: check that other nodes have passed correct secrets
|
||||
let threshold = data.threshold.expect("threshold is filled in initialization phase; KV phase follows initialization phase; qed");
|
||||
let derived_point = data.derived_point.clone().expect("derived point generated on initialization phase; KV phase follows initialization phase; qed");
|
||||
let number_id = data.nodes[self.node()].id_number.clone();
|
||||
for (_ , node_data) in data.nodes.iter_mut().filter(|&(node_id, _)| node_id != self.node()) {
|
||||
let secret1 = node_data.secret1.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed");
|
||||
let secret2 = node_data.secret2.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed");
|
||||
let publics = node_data.publics.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed");
|
||||
let is_key_verification_ok = math::keys_verification(threshold, &derived_point, &number_id,
|
||||
secret1, secret2, publics)?;
|
||||
|
||||
if !is_key_verification_ok {
|
||||
// node has sent us incorrect values. In original ECDKG protocol we should have sent complaint here.
|
||||
return Err(Error::InvalidMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate public share
|
||||
let is_zero = data.is_zero.expect("is_zero is filled in initialization phase; KV phase follows initialization phase; qed");
|
||||
let self_public_share = {
|
||||
let self_secret_coeff = data.secret_coeff.as_ref().expect("secret_coeff is generated on KD phase; KG phase follows KD phase; qed");
|
||||
math::compute_public_share(self_secret_coeff)?
|
||||
if !is_zero {
|
||||
let derived_point = data.derived_point.clone().expect("derived point generated on initialization phase; KV phase follows initialization phase; qed");
|
||||
let number_id = data.nodes[self.node()].id_number.clone();
|
||||
for (_ , node_data) in data.nodes.iter_mut().filter(|&(node_id, _)| node_id != self.node()) {
|
||||
let secret1 = node_data.secret1.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed");
|
||||
let secret2 = node_data.secret2.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed");
|
||||
let publics = node_data.publics.as_ref().expect("keys received on KD phase; KV phase follows KD phase; qed");
|
||||
let is_key_verification_ok = math::keys_verification(threshold, &derived_point, &number_id,
|
||||
secret1, secret2, publics)?;
|
||||
|
||||
if !is_key_verification_ok {
|
||||
// node has sent us incorrect values. In original ECDKG protocol we should have sent complaint here.
|
||||
return Err(Error::InvalidMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate public share
|
||||
let self_public_share = {
|
||||
let self_secret_coeff = data.secret_coeff.as_ref().expect("secret_coeff is generated on KD phase; KG phase follows KD phase; qed");
|
||||
math::compute_public_share(self_secret_coeff)?
|
||||
};
|
||||
|
||||
self_public_share
|
||||
} else {
|
||||
// TODO [Trust]: add verification when available
|
||||
Default::default()
|
||||
}
|
||||
};
|
||||
|
||||
// calculate self secret + public shares
|
||||
@ -676,12 +739,16 @@ impl SessionImpl {
|
||||
let mut data = self.data.lock();
|
||||
|
||||
// calculate joint public key
|
||||
let joint_public = {
|
||||
let is_zero = data.is_zero.expect("is_zero is filled in initialization phase; KG phase follows initialization phase; qed");
|
||||
let joint_public = if !is_zero {
|
||||
let public_shares = data.nodes.values().map(|n| n.public_share.as_ref().expect("keys received on KD phase; KG phase follows KD phase; qed"));
|
||||
math::compute_joint_public(public_shares)?
|
||||
} else {
|
||||
Default::default()
|
||||
};
|
||||
|
||||
// prepare key data
|
||||
let secret_share = data.secret_share.as_ref().expect("secret_share is filled in KG phase; we are at the end of KG phase; qed").clone();
|
||||
let encrypted_data = DocumentKeyShare {
|
||||
author: data.author.as_ref().expect("author is filled in initialization phase; KG phase follows initialization phase; qed").clone(),
|
||||
threshold: data.threshold.expect("threshold is filled in initialization phase; KG phase follows initialization phase; qed"),
|
||||
@ -690,7 +757,7 @@ impl SessionImpl {
|
||||
encrypted_point: None,
|
||||
versions: vec![DocumentKeyShareVersion::new(
|
||||
data.nodes.iter().map(|(node_id, node_data)| (node_id.clone(), node_data.id_number.clone())).collect(),
|
||||
data.secret_share.as_ref().expect("secret_share is filled in KG phase; we are at the end of KG phase; qed").clone(),
|
||||
secret_share.clone(),
|
||||
)],
|
||||
};
|
||||
|
||||
@ -698,7 +765,7 @@ impl SessionImpl {
|
||||
let secret_coeff = data.secret_coeff.as_ref().expect("secret coeff is selected on initialization phase; current phase follows initialization; qed").clone();
|
||||
if data.master.as_ref() != Some(self.node()) {
|
||||
data.key_share = Some(Ok(encrypted_data));
|
||||
data.joint_public_and_secret = Some(Ok((joint_public, secret_coeff)));
|
||||
data.joint_public_and_secret = Some(Ok((joint_public, secret_coeff, secret_share)));
|
||||
data.state = SessionState::WaitingForGenerationConfirmation;
|
||||
return Ok(());
|
||||
}
|
||||
@ -721,7 +788,7 @@ impl SessionImpl {
|
||||
self_node.completion_confirmed = true;
|
||||
}
|
||||
data.key_share = Some(Ok(encrypted_data));
|
||||
data.joint_public_and_secret = Some(Ok((joint_public, secret_coeff)));
|
||||
data.joint_public_and_secret = Some(Ok((joint_public, secret_coeff, secret_share)));
|
||||
data.state = SessionState::WaitingForGenerationConfirmation;
|
||||
|
||||
Ok(())
|
||||
@ -996,7 +1063,7 @@ pub mod tests {
|
||||
|
||||
fn make_simple_cluster(threshold: usize, num_nodes: usize) -> Result<(SessionId, NodeId, NodeId, MessageLoop), Error> {
|
||||
let l = MessageLoop::new(num_nodes);
|
||||
l.master().initialize(Public::default(), threshold, l.nodes.keys().cloned().collect())?;
|
||||
l.master().initialize(Public::default(), false, threshold, l.nodes.keys().cloned().collect::<BTreeSet<_>>().into())?;
|
||||
|
||||
let session_id = l.session_id.clone();
|
||||
let master_id = l.master().node().clone();
|
||||
@ -1007,7 +1074,7 @@ pub mod tests {
|
||||
#[test]
|
||||
fn initializes_in_cluster_of_single_node() {
|
||||
let l = MessageLoop::new(1);
|
||||
assert!(l.master().initialize(Public::default(), 0, l.nodes.keys().cloned().collect()).is_ok());
|
||||
assert!(l.master().initialize(Public::default(), false, 0, l.nodes.keys().cloned().collect::<BTreeSet<_>>().into()).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1022,7 +1089,7 @@ pub mod tests {
|
||||
nonce: Some(0),
|
||||
});
|
||||
let cluster_nodes: BTreeSet<_> = (0..2).map(|_| math::generate_random_point().unwrap()).collect();
|
||||
assert_eq!(session.initialize(Public::default(), 0, cluster_nodes).unwrap_err(), Error::InvalidNodesConfiguration);
|
||||
assert_eq!(session.initialize(Public::default(), false, 0, cluster_nodes.into()).unwrap_err(), Error::InvalidNodesConfiguration);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1036,7 +1103,8 @@ pub mod tests {
|
||||
#[test]
|
||||
fn fails_to_initialize_when_already_initialized() {
|
||||
let (_, _, _, l) = make_simple_cluster(0, 2).unwrap();
|
||||
assert_eq!(l.master().initialize(Public::default(), 0, l.nodes.keys().cloned().collect()).unwrap_err(), Error::InvalidStateForRequest);
|
||||
assert_eq!(l.master().initialize(Public::default(), false, 0, l.nodes.keys().cloned().collect::<BTreeSet<_>>().into()).unwrap_err(),
|
||||
Error::InvalidStateForRequest);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1117,6 +1185,7 @@ pub mod tests {
|
||||
session_nonce: 0,
|
||||
author: Public::default().into(),
|
||||
nodes: nodes.into_iter().map(|(k, v)| (k.into(), v.into())).collect(),
|
||||
is_zero: false,
|
||||
threshold: 0,
|
||||
derived_point: math::generate_random_point().unwrap().into(),
|
||||
}).unwrap_err(), Error::InvalidNodesConfiguration);
|
||||
@ -1133,6 +1202,7 @@ pub mod tests {
|
||||
session_nonce: 0,
|
||||
author: Public::default().into(),
|
||||
nodes: nodes.into_iter().map(|(k, v)| (k.into(), v.into())).collect(),
|
||||
is_zero: false,
|
||||
threshold: 2,
|
||||
derived_point: math::generate_random_point().unwrap().into(),
|
||||
}).unwrap_err(), Error::InvalidThreshold);
|
||||
@ -1273,7 +1343,7 @@ pub mod tests {
|
||||
let test_cases = [(0, 5), (2, 5), (3, 5)];
|
||||
for &(threshold, num_nodes) in &test_cases {
|
||||
let mut l = MessageLoop::new(num_nodes);
|
||||
l.master().initialize(Public::default(), threshold, l.nodes.keys().cloned().collect()).unwrap();
|
||||
l.master().initialize(Public::default(), false, threshold, l.nodes.keys().cloned().collect::<BTreeSet<_>>().into()).unwrap();
|
||||
assert_eq!(l.nodes.len(), num_nodes);
|
||||
|
||||
// let nodes do initialization + keys dissemination
|
||||
|
@ -17,4 +17,5 @@
|
||||
pub mod decryption_session;
|
||||
pub mod encryption_session;
|
||||
pub mod generation_session;
|
||||
pub mod signing_session;
|
||||
pub mod signing_session_ecdsa;
|
||||
pub mod signing_session_schnorr;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -24,15 +24,16 @@ use key_server_cluster::cluster::{Cluster};
|
||||
use key_server_cluster::cluster_sessions::{SessionIdWithSubSession, ClusterSession};
|
||||
use key_server_cluster::generation_session::{SessionImpl as GenerationSession, SessionParams as GenerationSessionParams,
|
||||
SessionState as GenerationSessionState};
|
||||
use key_server_cluster::message::{Message, SigningMessage, SigningConsensusMessage, SigningGenerationMessage,
|
||||
RequestPartialSignature, PartialSignature, SigningSessionCompleted, GenerationMessage, ConsensusMessage, SigningSessionError,
|
||||
InitializeConsensusSession, ConfirmConsensusInitialization, SigningSessionDelegation, SigningSessionDelegationCompleted};
|
||||
use key_server_cluster::message::{Message, SchnorrSigningMessage, SchnorrSigningConsensusMessage, SchnorrSigningGenerationMessage,
|
||||
SchnorrRequestPartialSignature, SchnorrPartialSignature, SchnorrSigningSessionCompleted, GenerationMessage,
|
||||
ConsensusMessage, SchnorrSigningSessionError, InitializeConsensusSession, ConfirmConsensusInitialization,
|
||||
SchnorrSigningSessionDelegation, SchnorrSigningSessionDelegationCompleted};
|
||||
use key_server_cluster::jobs::job_session::JobTransport;
|
||||
use key_server_cluster::jobs::key_access_job::KeyAccessJob;
|
||||
use key_server_cluster::jobs::signing_job::{PartialSigningRequest, PartialSigningResponse, SigningJob};
|
||||
use key_server_cluster::jobs::signing_job_schnorr::{SchnorrPartialSigningRequest, SchnorrPartialSigningResponse, SchnorrSigningJob};
|
||||
use key_server_cluster::jobs::consensus_session::{ConsensusSessionParams, ConsensusSessionState, ConsensusSession};
|
||||
|
||||
/// Distributed signing session.
|
||||
/// Distributed Schnorr-signing session.
|
||||
/// Based on "Efficient Multi-Party Digital Signature using Adaptive Secret Sharing for Low-Power Devices in Wireless Network" paper.
|
||||
/// Brief overview:
|
||||
/// 1) initialization: master node (which has received request for signing the message) requests all other nodes to sign the message
|
||||
@ -63,7 +64,7 @@ struct SessionCore {
|
||||
}
|
||||
|
||||
/// Signing consensus session type.
|
||||
type SigningConsensusSession = ConsensusSession<KeyAccessJob, SigningConsensusTransport, SigningJob, SigningJobTransport>;
|
||||
type SigningConsensusSession = ConsensusSession<KeyAccessJob, SigningConsensusTransport, SchnorrSigningJob, SigningJobTransport>;
|
||||
|
||||
/// Mutable session data.
|
||||
struct SessionData {
|
||||
@ -222,7 +223,7 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
data.consensus_session.consensus_job_mut().executor_mut().set_has_key_share(false);
|
||||
self.core.cluster.send(&master, Message::Signing(SigningMessage::SigningSessionDelegation(SigningSessionDelegation {
|
||||
self.core.cluster.send(&master, Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionDelegation(SchnorrSigningSessionDelegation {
|
||||
session: self.core.meta.id.clone().into(),
|
||||
sub_session: self.core.access_key.clone().into(),
|
||||
session_nonce: self.core.nonce,
|
||||
@ -276,7 +277,7 @@ impl SessionImpl {
|
||||
}),
|
||||
nonce: None,
|
||||
});
|
||||
generation_session.initialize(Public::default(), 0, vec![self.core.meta.self_node_id.clone()].into_iter().collect())?;
|
||||
generation_session.initialize(Public::default(), false, 0, vec![self.core.meta.self_node_id.clone()].into_iter().collect::<BTreeSet<_>>().into())?;
|
||||
|
||||
debug_assert_eq!(generation_session.state(), GenerationSessionState::WaitingForGenerationConfirmation);
|
||||
let joint_public_and_secret = generation_session
|
||||
@ -296,33 +297,33 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
/// Process signing message.
|
||||
pub fn process_message(&self, sender: &NodeId, message: &SigningMessage) -> Result<(), Error> {
|
||||
pub fn process_message(&self, sender: &NodeId, message: &SchnorrSigningMessage) -> Result<(), Error> {
|
||||
if self.core.nonce != message.session_nonce() {
|
||||
return Err(Error::ReplayProtection);
|
||||
}
|
||||
|
||||
match message {
|
||||
&SigningMessage::SigningConsensusMessage(ref message) =>
|
||||
&SchnorrSigningMessage::SchnorrSigningConsensusMessage(ref message) =>
|
||||
self.on_consensus_message(sender, message),
|
||||
&SigningMessage::SigningGenerationMessage(ref message) =>
|
||||
&SchnorrSigningMessage::SchnorrSigningGenerationMessage(ref message) =>
|
||||
self.on_generation_message(sender, message),
|
||||
&SigningMessage::RequestPartialSignature(ref message) =>
|
||||
&SchnorrSigningMessage::SchnorrRequestPartialSignature(ref message) =>
|
||||
self.on_partial_signature_requested(sender, message),
|
||||
&SigningMessage::PartialSignature(ref message) =>
|
||||
&SchnorrSigningMessage::SchnorrPartialSignature(ref message) =>
|
||||
self.on_partial_signature(sender, message),
|
||||
&SigningMessage::SigningSessionError(ref message) =>
|
||||
&SchnorrSigningMessage::SchnorrSigningSessionError(ref message) =>
|
||||
self.process_node_error(Some(&sender), Error::Io(message.error.clone())),
|
||||
&SigningMessage::SigningSessionCompleted(ref message) =>
|
||||
&SchnorrSigningMessage::SchnorrSigningSessionCompleted(ref message) =>
|
||||
self.on_session_completed(sender, message),
|
||||
&SigningMessage::SigningSessionDelegation(ref message) =>
|
||||
&SchnorrSigningMessage::SchnorrSigningSessionDelegation(ref message) =>
|
||||
self.on_session_delegated(sender, message),
|
||||
&SigningMessage::SigningSessionDelegationCompleted(ref message) =>
|
||||
&SchnorrSigningMessage::SchnorrSigningSessionDelegationCompleted(ref message) =>
|
||||
self.on_session_delegation_completed(sender, message),
|
||||
}
|
||||
}
|
||||
|
||||
/// When session is delegated to this node.
|
||||
pub fn on_session_delegated(&self, sender: &NodeId, message: &SigningSessionDelegation) -> Result<(), Error> {
|
||||
pub fn on_session_delegated(&self, sender: &NodeId, message: &SchnorrSigningSessionDelegation) -> Result<(), Error> {
|
||||
debug_assert!(self.core.meta.id == *message.session);
|
||||
debug_assert!(self.core.access_key == *message.sub_session);
|
||||
|
||||
@ -340,7 +341,7 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
/// When delegated session is completed on other node.
|
||||
pub fn on_session_delegation_completed(&self, sender: &NodeId, message: &SigningSessionDelegationCompleted) -> Result<(), Error> {
|
||||
pub fn on_session_delegation_completed(&self, sender: &NodeId, message: &SchnorrSigningSessionDelegationCompleted) -> Result<(), Error> {
|
||||
debug_assert!(self.core.meta.id == *message.session);
|
||||
debug_assert!(self.core.access_key == *message.sub_session);
|
||||
|
||||
@ -360,7 +361,7 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
/// When consensus-related message is received.
|
||||
pub fn on_consensus_message(&self, sender: &NodeId, message: &SigningConsensusMessage) -> Result<(), Error> {
|
||||
pub fn on_consensus_message(&self, sender: &NodeId, message: &SchnorrSigningConsensusMessage) -> Result<(), Error> {
|
||||
debug_assert!(self.core.meta.id == *message.session);
|
||||
debug_assert!(self.core.access_key == *message.sub_session);
|
||||
debug_assert!(sender != &self.core.meta.self_node_id);
|
||||
@ -404,7 +405,7 @@ impl SessionImpl {
|
||||
}),
|
||||
nonce: None,
|
||||
});
|
||||
generation_session.initialize(Public::default(), key_share.threshold, consensus_group)?;
|
||||
generation_session.initialize(Public::default(), false, key_share.threshold, consensus_group.into())?;
|
||||
data.generation_session = Some(generation_session);
|
||||
data.state = SessionState::SessionKeyGeneration;
|
||||
|
||||
@ -412,7 +413,7 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
/// When session key related message is received.
|
||||
pub fn on_generation_message(&self, sender: &NodeId, message: &SigningGenerationMessage) -> Result<(), Error> {
|
||||
pub fn on_generation_message(&self, sender: &NodeId, message: &SchnorrSigningGenerationMessage) -> Result<(), Error> {
|
||||
debug_assert!(self.core.meta.id == *message.session);
|
||||
debug_assert!(self.core.access_key == *message.sub_session);
|
||||
debug_assert!(sender != &self.core.meta.self_node_id);
|
||||
@ -474,7 +475,7 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
/// When partial signature is requested.
|
||||
pub fn on_partial_signature_requested(&self, sender: &NodeId, message: &RequestPartialSignature) -> Result<(), Error> {
|
||||
pub fn on_partial_signature_requested(&self, sender: &NodeId, message: &SchnorrRequestPartialSignature) -> Result<(), Error> {
|
||||
debug_assert!(self.core.meta.id == *message.session);
|
||||
debug_assert!(self.core.access_key == *message.sub_session);
|
||||
debug_assert!(sender != &self.core.meta.self_node_id);
|
||||
@ -499,10 +500,10 @@ impl SessionImpl {
|
||||
.expect("session key is generated before signature is computed; we are in SignatureComputing state; qed")?;
|
||||
let key_version = key_share.version(data.version.as_ref().ok_or(Error::InvalidMessage)?)
|
||||
.map_err(|e| Error::KeyStorage(e.into()))?.hash.clone();
|
||||
let signing_job = SigningJob::new_on_slave(self.core.meta.self_node_id.clone(), key_share.clone(), key_version, joint_public_and_secret.0, joint_public_and_secret.1)?;
|
||||
let signing_job = SchnorrSigningJob::new_on_slave(self.core.meta.self_node_id.clone(), key_share.clone(), key_version, joint_public_and_secret.0, joint_public_and_secret.1)?;
|
||||
let signing_transport = self.core.signing_transport();
|
||||
|
||||
data.consensus_session.on_job_request(sender, PartialSigningRequest {
|
||||
data.consensus_session.on_job_request(sender, SchnorrPartialSigningRequest {
|
||||
id: message.request_id.clone().into(),
|
||||
message_hash: message.message_hash.clone().into(),
|
||||
other_nodes_ids: message.nodes.iter().cloned().map(Into::into).collect(),
|
||||
@ -510,13 +511,13 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
/// When partial signature is received.
|
||||
pub fn on_partial_signature(&self, sender: &NodeId, message: &PartialSignature) -> Result<(), Error> {
|
||||
pub fn on_partial_signature(&self, sender: &NodeId, message: &SchnorrPartialSignature) -> Result<(), Error> {
|
||||
debug_assert!(self.core.meta.id == *message.session);
|
||||
debug_assert!(self.core.access_key == *message.sub_session);
|
||||
debug_assert!(sender != &self.core.meta.self_node_id);
|
||||
|
||||
let mut data = self.data.lock();
|
||||
data.consensus_session.on_job_response(sender, PartialSigningResponse {
|
||||
data.consensus_session.on_job_response(sender, SchnorrPartialSigningResponse {
|
||||
request_id: message.request_id.clone().into(),
|
||||
partial_signature: message.partial_signature.clone().into(),
|
||||
})?;
|
||||
@ -527,7 +528,7 @@ impl SessionImpl {
|
||||
|
||||
// send compeltion signal to all nodes, except for rejected nodes
|
||||
for node in data.consensus_session.consensus_non_rejected_nodes() {
|
||||
self.core.cluster.send(&node, Message::Signing(SigningMessage::SigningSessionCompleted(SigningSessionCompleted {
|
||||
self.core.cluster.send(&node, Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionCompleted(SchnorrSigningSessionCompleted {
|
||||
session: self.core.meta.id.clone().into(),
|
||||
sub_session: self.core.access_key.clone().into(),
|
||||
session_nonce: self.core.nonce,
|
||||
@ -541,7 +542,7 @@ impl SessionImpl {
|
||||
}
|
||||
|
||||
/// When session is completed.
|
||||
pub fn on_session_completed(&self, sender: &NodeId, message: &SigningSessionCompleted) -> Result<(), Error> {
|
||||
pub fn on_session_completed(&self, sender: &NodeId, message: &SchnorrSigningSessionCompleted) -> Result<(), Error> {
|
||||
debug_assert!(self.core.meta.id == *message.session);
|
||||
debug_assert!(self.core.access_key == *message.sub_session);
|
||||
debug_assert!(sender != &self.core.meta.self_node_id);
|
||||
@ -599,14 +600,14 @@ impl SessionImpl {
|
||||
if let Some(DelegationStatus::DelegatedFrom(master, nonce)) = data.delegation_status.take() {
|
||||
// error means can't communicate => ignore it
|
||||
let _ = match result.as_ref() {
|
||||
Ok(signature) => core.cluster.send(&master, Message::Signing(SigningMessage::SigningSessionDelegationCompleted(SigningSessionDelegationCompleted {
|
||||
Ok(signature) => core.cluster.send(&master, Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionDelegationCompleted(SchnorrSigningSessionDelegationCompleted {
|
||||
session: core.meta.id.clone().into(),
|
||||
sub_session: core.access_key.clone().into(),
|
||||
session_nonce: nonce,
|
||||
signature_c: signature.0.clone().into(),
|
||||
signature_s: signature.1.clone().into(),
|
||||
}))),
|
||||
Err(error) => core.cluster.send(&master, Message::Signing(SigningMessage::SigningSessionError(SigningSessionError {
|
||||
Err(error) => core.cluster.send(&master, Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionError(SchnorrSigningSessionError {
|
||||
session: core.meta.id.clone().into(),
|
||||
sub_session: core.access_key.clone().into(),
|
||||
session_nonce: nonce,
|
||||
@ -655,7 +656,7 @@ impl ClusterSession for SessionImpl {
|
||||
// error in signing session is non-fatal, if occurs on slave node
|
||||
// => either respond with error
|
||||
// => or broadcast error
|
||||
let message = Message::Signing(SigningMessage::SigningSessionError(SigningSessionError {
|
||||
let message = Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionError(SchnorrSigningSessionError {
|
||||
session: self.core.meta.id.clone().into(),
|
||||
sub_session: self.core.access_key.clone().into(),
|
||||
session_nonce: self.core.nonce,
|
||||
@ -673,7 +674,7 @@ impl ClusterSession for SessionImpl {
|
||||
|
||||
fn on_message(&self, sender: &NodeId, message: &Message) -> Result<(), Error> {
|
||||
match *message {
|
||||
Message::Signing(ref message) => self.process_message(sender, message),
|
||||
Message::SchnorrSigning(ref message) => self.process_message(sender, message),
|
||||
_ => unreachable!("cluster checks message to be correct before passing; qed"),
|
||||
}
|
||||
}
|
||||
@ -682,7 +683,7 @@ impl ClusterSession for SessionImpl {
|
||||
impl SessionKeyGenerationTransport {
|
||||
fn map_message(&self, message: Message) -> Result<Message, Error> {
|
||||
match message {
|
||||
Message::Generation(message) => Ok(Message::Signing(SigningMessage::SigningGenerationMessage(SigningGenerationMessage {
|
||||
Message::Generation(message) => Ok(Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningGenerationMessage(SchnorrSigningGenerationMessage {
|
||||
session: message.session_id().clone().into(),
|
||||
sub_session: self.access_key.clone().into(),
|
||||
session_nonce: self.nonce,
|
||||
@ -733,7 +734,7 @@ impl SessionCore {
|
||||
};
|
||||
|
||||
let key_version = key_share.version(version).map_err(|e| Error::KeyStorage(e.into()))?.hash.clone();
|
||||
let signing_job = SigningJob::new_on_master(self.meta.self_node_id.clone(), key_share.clone(), key_version, session_public, session_secret_share, message_hash)?;
|
||||
let signing_job = SchnorrSigningJob::new_on_master(self.meta.self_node_id.clone(), key_share.clone(), key_version, session_public, session_secret_share, message_hash)?;
|
||||
consensus_session.disseminate_jobs(signing_job, self.signing_transport(), false)
|
||||
}
|
||||
}
|
||||
@ -745,7 +746,7 @@ impl JobTransport for SigningConsensusTransport {
|
||||
fn send_partial_request(&self, node: &NodeId, request: Signature) -> Result<(), Error> {
|
||||
let version = self.version.as_ref()
|
||||
.expect("send_partial_request is called on initialized master node only; version is filled in before initialization starts on master node; qed");
|
||||
self.cluster.send(node, Message::Signing(SigningMessage::SigningConsensusMessage(SigningConsensusMessage {
|
||||
self.cluster.send(node, Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningConsensusMessage(SchnorrSigningConsensusMessage {
|
||||
session: self.id.clone().into(),
|
||||
sub_session: self.access_key.clone().into(),
|
||||
session_nonce: self.nonce,
|
||||
@ -757,7 +758,7 @@ impl JobTransport for SigningConsensusTransport {
|
||||
}
|
||||
|
||||
fn send_partial_response(&self, node: &NodeId, response: bool) -> Result<(), Error> {
|
||||
self.cluster.send(node, Message::Signing(SigningMessage::SigningConsensusMessage(SigningConsensusMessage {
|
||||
self.cluster.send(node, Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningConsensusMessage(SchnorrSigningConsensusMessage {
|
||||
session: self.id.clone().into(),
|
||||
sub_session: self.access_key.clone().into(),
|
||||
session_nonce: self.nonce,
|
||||
@ -769,11 +770,11 @@ impl JobTransport for SigningConsensusTransport {
|
||||
}
|
||||
|
||||
impl JobTransport for SigningJobTransport {
|
||||
type PartialJobRequest=PartialSigningRequest;
|
||||
type PartialJobResponse=PartialSigningResponse;
|
||||
type PartialJobRequest=SchnorrPartialSigningRequest;
|
||||
type PartialJobResponse=SchnorrPartialSigningResponse;
|
||||
|
||||
fn send_partial_request(&self, node: &NodeId, request: PartialSigningRequest) -> Result<(), Error> {
|
||||
self.cluster.send(node, Message::Signing(SigningMessage::RequestPartialSignature(RequestPartialSignature {
|
||||
fn send_partial_request(&self, node: &NodeId, request: SchnorrPartialSigningRequest) -> Result<(), Error> {
|
||||
self.cluster.send(node, Message::SchnorrSigning(SchnorrSigningMessage::SchnorrRequestPartialSignature(SchnorrRequestPartialSignature {
|
||||
session: self.id.clone().into(),
|
||||
sub_session: self.access_key.clone().into(),
|
||||
session_nonce: self.nonce,
|
||||
@ -783,8 +784,8 @@ impl JobTransport for SigningJobTransport {
|
||||
})))
|
||||
}
|
||||
|
||||
fn send_partial_response(&self, node: &NodeId, response: PartialSigningResponse) -> Result<(), Error> {
|
||||
self.cluster.send(node, Message::Signing(SigningMessage::PartialSignature(PartialSignature {
|
||||
fn send_partial_response(&self, node: &NodeId, response: SchnorrPartialSigningResponse) -> Result<(), Error> {
|
||||
self.cluster.send(node, Message::SchnorrSigning(SchnorrSigningMessage::SchnorrPartialSignature(SchnorrPartialSignature {
|
||||
session: self.id.clone().into(),
|
||||
sub_session: self.access_key.clone().into(),
|
||||
session_nonce: self.nonce,
|
||||
@ -798,7 +799,7 @@ impl JobTransport for SigningJobTransport {
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use std::str::FromStr;
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::collections::{BTreeSet, BTreeMap, VecDeque};
|
||||
use ethereum_types::H256;
|
||||
use ethkey::{self, Random, Generator, Public, Secret, KeyPair};
|
||||
use acl_storage::DummyAclStorage;
|
||||
@ -807,9 +808,9 @@ mod tests {
|
||||
use key_server_cluster::cluster::tests::DummyCluster;
|
||||
use key_server_cluster::generation_session::tests::MessageLoop as KeyGenerationMessageLoop;
|
||||
use key_server_cluster::math;
|
||||
use key_server_cluster::message::{Message, SigningMessage, SigningConsensusMessage, ConsensusMessage, ConfirmConsensusInitialization,
|
||||
SigningGenerationMessage, GenerationMessage, ConfirmInitialization, InitializeSession, RequestPartialSignature};
|
||||
use key_server_cluster::signing_session::{SessionImpl, SessionState, SessionParams};
|
||||
use key_server_cluster::message::{Message, SchnorrSigningMessage, SchnorrSigningConsensusMessage, ConsensusMessage, ConfirmConsensusInitialization,
|
||||
SchnorrSigningGenerationMessage, GenerationMessage, ConfirmInitialization, InitializeSession, SchnorrRequestPartialSignature};
|
||||
use key_server_cluster::signing_session_schnorr::{SessionImpl, SessionState, SessionParams};
|
||||
|
||||
struct Node {
|
||||
pub node_id: NodeId,
|
||||
@ -925,7 +926,7 @@ mod tests {
|
||||
fn prepare_signing_sessions(threshold: usize, num_nodes: usize) -> (KeyGenerationMessageLoop, MessageLoop) {
|
||||
// run key generation sessions
|
||||
let mut gl = KeyGenerationMessageLoop::new(num_nodes);
|
||||
gl.master().initialize(Public::default(), threshold, gl.nodes.keys().cloned().collect()).unwrap();
|
||||
gl.master().initialize(Public::default(), false, threshold, gl.nodes.keys().cloned().collect::<BTreeSet<_>>().into()).unwrap();
|
||||
while let Some((from, to, message)) = gl.take_message() {
|
||||
gl.process_message((from, to, message)).unwrap();
|
||||
}
|
||||
@ -936,7 +937,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_gen_sign_session() {
|
||||
fn schnorr_complete_gen_sign_session() {
|
||||
let test_cases = [(0, 1), (0, 5), (2, 5), (3, 5)];
|
||||
for &(threshold, num_nodes) in &test_cases {
|
||||
let (gl, mut sl) = prepare_signing_sessions(threshold, num_nodes);
|
||||
@ -951,12 +952,12 @@ mod tests {
|
||||
// verify signature
|
||||
let public = gl.master().joint_public_and_secret().unwrap().unwrap().0;
|
||||
let signature = sl.master().wait().unwrap();
|
||||
assert!(math::verify_signature(&public, &signature, &message_hash).unwrap());
|
||||
assert!(math::verify_schnorr_signature(&public, &signature, &message_hash).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn constructs_in_cluster_of_single_node() {
|
||||
fn schnorr_constructs_in_cluster_of_single_node() {
|
||||
let mut nodes = BTreeMap::new();
|
||||
let self_node_id = Random.generate().unwrap().public().clone();
|
||||
nodes.insert(self_node_id, Random.generate().unwrap().secret().clone());
|
||||
@ -990,7 +991,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_to_initialize_if_does_not_have_a_share() {
|
||||
fn schnorr_fails_to_initialize_if_does_not_have_a_share() {
|
||||
let self_node_id = Random.generate().unwrap().public().clone();
|
||||
let session = SessionImpl::new(SessionParams {
|
||||
meta: SessionMeta {
|
||||
@ -1009,7 +1010,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_to_initialize_if_threshold_is_wrong() {
|
||||
fn schnorr_fails_to_initialize_if_threshold_is_wrong() {
|
||||
let mut nodes = BTreeMap::new();
|
||||
let self_node_id = Random.generate().unwrap().public().clone();
|
||||
nodes.insert(self_node_id.clone(), Random.generate().unwrap().secret().clone());
|
||||
@ -1042,14 +1043,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_to_initialize_when_already_initialized() {
|
||||
fn schnorr_fails_to_initialize_when_already_initialized() {
|
||||
let (_, sl) = prepare_signing_sessions(1, 3);
|
||||
assert_eq!(sl.master().initialize(sl.version.clone(), 777.into()), Ok(()));
|
||||
assert_eq!(sl.master().initialize(sl.version.clone(), 777.into()), Err(Error::InvalidStateForRequest));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn does_not_fail_when_consensus_message_received_after_consensus_established() {
|
||||
fn schnorr_does_not_fail_when_consensus_message_received_after_consensus_established() {
|
||||
let (_, mut sl) = prepare_signing_sessions(1, 3);
|
||||
sl.master().initialize(sl.version.clone(), 777.into()).unwrap();
|
||||
// consensus is established
|
||||
@ -1068,9 +1069,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_when_consensus_message_is_received_when_not_initialized() {
|
||||
fn schnorr_fails_when_consensus_message_is_received_when_not_initialized() {
|
||||
let (_, sl) = prepare_signing_sessions(1, 3);
|
||||
assert_eq!(sl.master().on_consensus_message(sl.nodes.keys().nth(1).unwrap(), &SigningConsensusMessage {
|
||||
assert_eq!(sl.master().on_consensus_message(sl.nodes.keys().nth(1).unwrap(), &SchnorrSigningConsensusMessage {
|
||||
session: SessionId::default().into(),
|
||||
sub_session: sl.master().core.access_key.clone().into(),
|
||||
session_nonce: 0,
|
||||
@ -1081,9 +1082,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_when_generation_message_is_received_when_not_initialized() {
|
||||
fn schnorr_fails_when_generation_message_is_received_when_not_initialized() {
|
||||
let (_, sl) = prepare_signing_sessions(1, 3);
|
||||
assert_eq!(sl.master().on_generation_message(sl.nodes.keys().nth(1).unwrap(), &SigningGenerationMessage {
|
||||
assert_eq!(sl.master().on_generation_message(sl.nodes.keys().nth(1).unwrap(), &SchnorrSigningGenerationMessage {
|
||||
session: SessionId::default().into(),
|
||||
sub_session: sl.master().core.access_key.clone().into(),
|
||||
session_nonce: 0,
|
||||
@ -1096,7 +1097,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_when_generation_sesson_is_initialized_by_slave_node() {
|
||||
fn schnorr_fails_when_generation_sesson_is_initialized_by_slave_node() {
|
||||
let (_, mut sl) = prepare_signing_sessions(1, 3);
|
||||
sl.master().initialize(sl.version.clone(), 777.into()).unwrap();
|
||||
sl.run_until(|sl| sl.master().state() == SessionState::SessionKeyGeneration).unwrap();
|
||||
@ -1104,7 +1105,7 @@ mod tests {
|
||||
let slave2_id = sl.nodes.keys().nth(2).unwrap().clone();
|
||||
let slave1 = &sl.nodes.values().nth(1).unwrap().session;
|
||||
|
||||
assert_eq!(slave1.on_generation_message(&slave2_id, &SigningGenerationMessage {
|
||||
assert_eq!(slave1.on_generation_message(&slave2_id, &SchnorrSigningGenerationMessage {
|
||||
session: SessionId::default().into(),
|
||||
sub_session: sl.master().core.access_key.clone().into(),
|
||||
session_nonce: 0,
|
||||
@ -1113,6 +1114,7 @@ mod tests {
|
||||
session_nonce: 0,
|
||||
author: Public::default().into(),
|
||||
nodes: BTreeMap::new(),
|
||||
is_zero: false,
|
||||
threshold: 1,
|
||||
derived_point: Public::default().into(),
|
||||
})
|
||||
@ -1120,10 +1122,10 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_when_signature_requested_when_not_initialized() {
|
||||
fn schnorr_fails_when_signature_requested_when_not_initialized() {
|
||||
let (_, sl) = prepare_signing_sessions(1, 3);
|
||||
let slave1 = &sl.nodes.values().nth(1).unwrap().session;
|
||||
assert_eq!(slave1.on_partial_signature_requested(sl.nodes.keys().nth(0).unwrap(), &RequestPartialSignature {
|
||||
assert_eq!(slave1.on_partial_signature_requested(sl.nodes.keys().nth(0).unwrap(), &SchnorrRequestPartialSignature {
|
||||
session: SessionId::default().into(),
|
||||
sub_session: sl.master().core.access_key.clone().into(),
|
||||
session_nonce: 0,
|
||||
@ -1134,9 +1136,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_when_signature_requested_by_slave_node() {
|
||||
fn schnorr_fails_when_signature_requested_by_slave_node() {
|
||||
let (_, sl) = prepare_signing_sessions(1, 3);
|
||||
assert_eq!(sl.master().on_partial_signature_requested(sl.nodes.keys().nth(1).unwrap(), &RequestPartialSignature {
|
||||
assert_eq!(sl.master().on_partial_signature_requested(sl.nodes.keys().nth(1).unwrap(), &SchnorrRequestPartialSignature {
|
||||
session: SessionId::default().into(),
|
||||
sub_session: sl.master().core.access_key.clone().into(),
|
||||
session_nonce: 0,
|
||||
@ -1147,7 +1149,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn failed_signing_session() {
|
||||
fn schnorr_failed_signing_session() {
|
||||
let (_, mut sl) = prepare_signing_sessions(1, 3);
|
||||
sl.master().initialize(sl.version.clone(), 777.into()).unwrap();
|
||||
|
||||
@ -1161,7 +1163,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_signing_session_with_single_node_failing() {
|
||||
fn schnorr_complete_signing_session_with_single_node_failing() {
|
||||
let (_, mut sl) = prepare_signing_sessions(1, 3);
|
||||
sl.master().initialize(sl.version.clone(), 777.into()).unwrap();
|
||||
|
||||
@ -1182,7 +1184,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn complete_signing_session_with_acl_check_failed_on_master() {
|
||||
fn schnorr_complete_signing_session_with_acl_check_failed_on_master() {
|
||||
let (_, mut sl) = prepare_signing_sessions(1, 3);
|
||||
sl.master().initialize(sl.version.clone(), 777.into()).unwrap();
|
||||
|
||||
@ -1203,9 +1205,9 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signing_message_fails_when_nonce_is_wrong() {
|
||||
fn schnorr_signing_message_fails_when_nonce_is_wrong() {
|
||||
let (_, sl) = prepare_signing_sessions(1, 3);
|
||||
assert_eq!(sl.master().process_message(sl.nodes.keys().nth(1).unwrap(), &SigningMessage::SigningGenerationMessage(SigningGenerationMessage {
|
||||
assert_eq!(sl.master().process_message(sl.nodes.keys().nth(1).unwrap(), &SchnorrSigningMessage::SchnorrSigningGenerationMessage(SchnorrSigningGenerationMessage {
|
||||
session: SessionId::default().into(),
|
||||
sub_session: sl.master().core.access_key.clone().into(),
|
||||
session_nonce: 10,
|
||||
@ -1218,7 +1220,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signing_works_when_delegated_to_other_node() {
|
||||
fn schnorr_signing_works_when_delegated_to_other_node() {
|
||||
let (_, mut sl) = prepare_signing_sessions(1, 3);
|
||||
|
||||
// let's say node1 doesn't have a share && delegates decryption request to node0
|
||||
@ -1243,7 +1245,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signing_works_when_share_owners_are_isolated() {
|
||||
fn schnorr_signing_works_when_share_owners_are_isolated() {
|
||||
let (_, mut sl) = prepare_signing_sessions(1, 3);
|
||||
|
||||
// we need 2 out of 3 nodes to agree to do a decryption
|
@ -36,7 +36,8 @@ use key_server_cluster::message::{self, Message, ClusterMessage};
|
||||
use key_server_cluster::generation_session::{SessionImpl as GenerationSession};
|
||||
use key_server_cluster::decryption_session::{SessionImpl as DecryptionSession};
|
||||
use key_server_cluster::encryption_session::{SessionImpl as EncryptionSession};
|
||||
use key_server_cluster::signing_session::{SessionImpl as SigningSession};
|
||||
use key_server_cluster::signing_session_ecdsa::{SessionImpl as EcdsaSigningSession};
|
||||
use key_server_cluster::signing_session_schnorr::{SessionImpl as SchnorrSigningSession};
|
||||
use key_server_cluster::key_version_negotiation_session::{SessionImpl as KeyVersionNegotiationSession,
|
||||
IsolatedSessionTransport as KeyVersionNegotiationSessionTransport, ContinueAction};
|
||||
use key_server_cluster::io::{DeadlineStatus, ReadMessage, SharedTcpStream, read_encrypted_message, WriteMessage, write_encrypted_message};
|
||||
@ -71,7 +72,9 @@ pub trait ClusterClient: Send + Sync {
|
||||
/// Start new decryption session.
|
||||
fn new_decryption_session(&self, session_id: SessionId, requestor_signature: Signature, version: Option<H256>, is_shadow_decryption: bool) -> Result<Arc<DecryptionSession>, Error>;
|
||||
/// Start new signing session.
|
||||
fn new_signing_session(&self, session_id: SessionId, requestor_signature: Signature, version: Option<H256>, message_hash: H256) -> Result<Arc<SigningSession>, Error>;
|
||||
fn new_schnorr_signing_session(&self, session_id: SessionId, requestor_signature: Signature, version: Option<H256>, message_hash: H256) -> Result<Arc<SchnorrSigningSession>, Error>;
|
||||
/// Start new ECDSA session.
|
||||
fn new_ecdsa_signing_session(&self, session_id: SessionId, requestor_signature: Signature, version: Option<H256>, message_hash: H256) -> Result<Arc<EcdsaSigningSession>, Error>;
|
||||
/// Start new key version negotiation session.
|
||||
fn new_key_version_negotiation_session(&self, session_id: SessionId) -> Result<Arc<KeyVersionNegotiationSession<KeyVersionNegotiationSessionTransport>>, Error>;
|
||||
/// Start new servers set change session.
|
||||
@ -441,7 +444,9 @@ impl ClusterCore {
|
||||
.map(|_| ()).unwrap_or_default(),
|
||||
Message::Decryption(message) => Self::process_message(&data, &data.sessions.decryption_sessions, connection, Message::Decryption(message))
|
||||
.map(|_| ()).unwrap_or_default(),
|
||||
Message::Signing(message) => Self::process_message(&data, &data.sessions.signing_sessions, connection, Message::Signing(message))
|
||||
Message::SchnorrSigning(message) => Self::process_message(&data, &data.sessions.schnorr_signing_sessions, connection, Message::SchnorrSigning(message))
|
||||
.map(|_| ()).unwrap_or_default(),
|
||||
Message::EcdsaSigning(message) => Self::process_message(&data, &data.sessions.ecdsa_signing_sessions, connection, Message::EcdsaSigning(message))
|
||||
.map(|_| ()).unwrap_or_default(),
|
||||
Message::ServersSetChange(message) => {
|
||||
let message = Message::ServersSetChange(message);
|
||||
@ -484,7 +489,7 @@ impl ClusterCore {
|
||||
data.sessions.decryption_sessions.remove(&session.id());
|
||||
}
|
||||
},
|
||||
Some(ContinueAction::Sign(session, message_hash)) => {
|
||||
Some(ContinueAction::SchnorrSign(session, message_hash)) => {
|
||||
let initialization_error = if data.self_key_pair.public() == &master {
|
||||
session.initialize(version, message_hash)
|
||||
} else {
|
||||
@ -493,7 +498,19 @@ impl ClusterCore {
|
||||
|
||||
if let Err(error) = initialization_error {
|
||||
session.on_session_error(&meta.self_node_id, error);
|
||||
data.sessions.signing_sessions.remove(&session.id());
|
||||
data.sessions.schnorr_signing_sessions.remove(&session.id());
|
||||
}
|
||||
},
|
||||
Some(ContinueAction::EcdsaSign(session, message_hash)) => {
|
||||
let initialization_error = if data.self_key_pair.public() == &master {
|
||||
session.initialize(version, message_hash)
|
||||
} else {
|
||||
session.delegate(master, version, message_hash)
|
||||
};
|
||||
|
||||
if let Err(error) = initialization_error {
|
||||
session.on_session_error(&meta.self_node_id, error);
|
||||
data.sessions.ecdsa_signing_sessions.remove(&session.id());
|
||||
}
|
||||
},
|
||||
None => (),
|
||||
@ -503,8 +520,12 @@ impl ClusterCore {
|
||||
data.sessions.decryption_sessions.remove(&session.id());
|
||||
session.on_session_error(&meta.self_node_id, error);
|
||||
},
|
||||
Some(ContinueAction::Sign(session, _)) => {
|
||||
data.sessions.signing_sessions.remove(&session.id());
|
||||
Some(ContinueAction::SchnorrSign(session, _)) => {
|
||||
data.sessions.schnorr_signing_sessions.remove(&session.id());
|
||||
session.on_session_error(&meta.self_node_id, error);
|
||||
},
|
||||
Some(ContinueAction::EcdsaSign(session, _)) => {
|
||||
data.sessions.ecdsa_signing_sessions.remove(&session.id());
|
||||
session.on_session_error(&meta.self_node_id, error);
|
||||
},
|
||||
None => (),
|
||||
@ -886,7 +907,7 @@ impl ClusterClient for ClusterClientImpl {
|
||||
|
||||
let cluster = create_cluster_view(&self.data, true)?;
|
||||
let session = self.data.sessions.generation_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id, None, false, None)?;
|
||||
match session.initialize(author, threshold, connected_nodes) {
|
||||
match session.initialize(author, false, threshold, connected_nodes.into()) {
|
||||
Ok(()) => Ok(session),
|
||||
Err(error) => {
|
||||
self.data.sessions.generation_sessions.remove(&session.id());
|
||||
@ -939,21 +960,21 @@ impl ClusterClient for ClusterClientImpl {
|
||||
}
|
||||
}
|
||||
|
||||
fn new_signing_session(&self, session_id: SessionId, requestor_signature: Signature, version: Option<H256>, message_hash: H256) -> Result<Arc<SigningSession>, Error> {
|
||||
fn new_schnorr_signing_session(&self, session_id: SessionId, requestor_signature: Signature, version: Option<H256>, message_hash: H256) -> Result<Arc<SchnorrSigningSession>, Error> {
|
||||
let mut connected_nodes = self.data.connections.connected_nodes();
|
||||
connected_nodes.insert(self.data.self_key_pair.public().clone());
|
||||
|
||||
let access_key = Random.generate()?.secret().clone();
|
||||
let session_id = SessionIdWithSubSession::new(session_id, access_key);
|
||||
let cluster = create_cluster_view(&self.data, false)?;
|
||||
let session = self.data.sessions.signing_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id.clone(), None, false, Some(requestor_signature))?;
|
||||
let session = self.data.sessions.schnorr_signing_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id.clone(), None, false, Some(requestor_signature))?;
|
||||
|
||||
let initialization_result = match version {
|
||||
Some(version) => session.initialize(version, message_hash),
|
||||
None => {
|
||||
self.create_key_version_negotiation_session(session_id.id.clone())
|
||||
.map(|version_session| {
|
||||
version_session.set_continue_action(ContinueAction::Sign(session.clone(), message_hash));
|
||||
version_session.set_continue_action(ContinueAction::SchnorrSign(session.clone(), message_hash));
|
||||
ClusterCore::try_continue_session(&self.data, Some(version_session));
|
||||
})
|
||||
},
|
||||
@ -962,7 +983,36 @@ impl ClusterClient for ClusterClientImpl {
|
||||
match initialization_result {
|
||||
Ok(()) => Ok(session),
|
||||
Err(error) => {
|
||||
self.data.sessions.signing_sessions.remove(&session.id());
|
||||
self.data.sessions.schnorr_signing_sessions.remove(&session.id());
|
||||
Err(error)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn new_ecdsa_signing_session(&self, session_id: SessionId, requestor_signature: Signature, version: Option<H256>, message_hash: H256) -> Result<Arc<EcdsaSigningSession>, Error> {
|
||||
let mut connected_nodes = self.data.connections.connected_nodes();
|
||||
connected_nodes.insert(self.data.self_key_pair.public().clone());
|
||||
|
||||
let access_key = Random.generate()?.secret().clone();
|
||||
let session_id = SessionIdWithSubSession::new(session_id, access_key);
|
||||
let cluster = create_cluster_view(&self.data, false)?;
|
||||
let session = self.data.sessions.ecdsa_signing_sessions.insert(cluster, self.data.self_key_pair.public().clone(), session_id.clone(), None, false, Some(requestor_signature))?;
|
||||
|
||||
let initialization_result = match version {
|
||||
Some(version) => session.initialize(version, message_hash),
|
||||
None => {
|
||||
self.create_key_version_negotiation_session(session_id.id.clone())
|
||||
.map(|version_session| {
|
||||
version_session.set_continue_action(ContinueAction::EcdsaSign(session.clone(), message_hash));
|
||||
ClusterCore::try_continue_session(&self.data, Some(version_session));
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
match initialization_result {
|
||||
Ok(()) => Ok(session),
|
||||
Err(error) => {
|
||||
self.data.sessions.ecdsa_signing_sessions.remove(&session.id());
|
||||
Err(error)
|
||||
},
|
||||
}
|
||||
@ -1047,7 +1097,8 @@ pub mod tests {
|
||||
use key_server_cluster::generation_session::{SessionImpl as GenerationSession, SessionState as GenerationSessionState};
|
||||
use key_server_cluster::decryption_session::{SessionImpl as DecryptionSession};
|
||||
use key_server_cluster::encryption_session::{SessionImpl as EncryptionSession};
|
||||
use key_server_cluster::signing_session::{SessionImpl as SigningSession};
|
||||
use key_server_cluster::signing_session_ecdsa::{SessionImpl as EcdsaSigningSession};
|
||||
use key_server_cluster::signing_session_schnorr::{SessionImpl as SchnorrSigningSession};
|
||||
use key_server_cluster::key_version_negotiation_session::{SessionImpl as KeyVersionNegotiationSession,
|
||||
IsolatedSessionTransport as KeyVersionNegotiationSessionTransport};
|
||||
|
||||
@ -1071,7 +1122,8 @@ pub mod tests {
|
||||
fn new_generation_session(&self, _session_id: SessionId, _author: Public, _threshold: usize) -> Result<Arc<GenerationSession>, Error> { unimplemented!("test-only") }
|
||||
fn new_encryption_session(&self, _session_id: SessionId, _requestor_signature: Signature, _common_point: Public, _encrypted_point: Public) -> Result<Arc<EncryptionSession>, Error> { unimplemented!("test-only") }
|
||||
fn new_decryption_session(&self, _session_id: SessionId, _requestor_signature: Signature, _version: Option<H256>, _is_shadow_decryption: bool) -> Result<Arc<DecryptionSession>, Error> { unimplemented!("test-only") }
|
||||
fn new_signing_session(&self, _session_id: SessionId, _requestor_signature: Signature, _version: Option<H256>, _message_hash: H256) -> Result<Arc<SigningSession>, Error> { unimplemented!("test-only") }
|
||||
fn new_schnorr_signing_session(&self, _session_id: SessionId, _requestor_signature: Signature, _version: Option<H256>, _message_hash: H256) -> Result<Arc<SchnorrSigningSession>, Error> { unimplemented!("test-only") }
|
||||
fn new_ecdsa_signing_session(&self, _session_id: SessionId, _requestor_signature: Signature, _version: Option<H256>, _message_hash: H256) -> Result<Arc<EcdsaSigningSession>, Error> { unimplemented!("test-only") }
|
||||
fn new_key_version_negotiation_session(&self, _session_id: SessionId) -> Result<Arc<KeyVersionNegotiationSession<KeyVersionNegotiationSessionTransport>>, Error> { unimplemented!("test-only") }
|
||||
fn new_servers_set_change_session(&self, _session_id: Option<SessionId>, _migration_id: Option<H256>, _new_nodes_set: BTreeSet<NodeId>, _old_set_signature: Signature, _new_set_signature: Signature) -> Result<Arc<AdminSession>, Error> { unimplemented!("test-only") }
|
||||
|
||||
@ -1329,7 +1381,7 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signing_session_completes_if_node_does_not_have_a_share() {
|
||||
fn schnorr_signing_session_completes_if_node_does_not_have_a_share() {
|
||||
//::logger::init_log();
|
||||
let mut core = Core::new().unwrap();
|
||||
let clusters = make_clusters(&core, 6028, 3);
|
||||
@ -1349,19 +1401,19 @@ pub mod tests {
|
||||
|
||||
// and try to sign message with generated key
|
||||
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
||||
let session0 = clusters[0].client().new_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
||||
let session = clusters[0].data.sessions.signing_sessions.first().unwrap();
|
||||
let session0 = clusters[0].client().new_schnorr_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
||||
let session = clusters[0].data.sessions.schnorr_signing_sessions.first().unwrap();
|
||||
|
||||
loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished() && (0..3).all(|i|
|
||||
clusters[i].data.sessions.signing_sessions.is_empty()));
|
||||
clusters[i].data.sessions.schnorr_signing_sessions.is_empty()));
|
||||
session0.wait().unwrap();
|
||||
|
||||
// and try to sign message with generated key using node that has no key share
|
||||
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
||||
let session2 = clusters[2].client().new_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
||||
let session = clusters[2].data.sessions.signing_sessions.first().unwrap();
|
||||
let session2 = clusters[2].client().new_schnorr_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
||||
let session = clusters[2].data.sessions.schnorr_signing_sessions.first().unwrap();
|
||||
loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished() && (0..3).all(|i|
|
||||
clusters[i].data.sessions.signing_sessions.is_empty()));
|
||||
clusters[i].data.sessions.schnorr_signing_sessions.is_empty()));
|
||||
session2.wait().unwrap();
|
||||
|
||||
// now remove share from node1
|
||||
@ -1369,9 +1421,56 @@ pub mod tests {
|
||||
|
||||
// and try to sign message with generated key
|
||||
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
||||
let session1 = clusters[0].client().new_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
||||
let session = clusters[0].data.sessions.signing_sessions.first().unwrap();
|
||||
let session1 = clusters[0].client().new_schnorr_signing_session(Default::default(), signature, None, Default::default()).unwrap();
|
||||
let session = clusters[0].data.sessions.schnorr_signing_sessions.first().unwrap();
|
||||
loop_until(&mut core, time::Duration::from_millis(300), || session.is_finished());
|
||||
session1.wait().unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ecdsa_signing_session_completes_if_node_does_not_have_a_share() {
|
||||
//::logger::init_log();
|
||||
let mut core = Core::new().unwrap();
|
||||
let clusters = make_clusters(&core, 6041, 4);
|
||||
run_clusters(&clusters);
|
||||
loop_until(&mut core, time::Duration::from_millis(300), || clusters.iter().all(all_connections_established));
|
||||
|
||||
// start && wait for generation session to complete
|
||||
let session = clusters[0].client().new_generation_session(SessionId::default(), Public::default(), 1).unwrap();
|
||||
loop_until(&mut core, time::Duration::from_millis(300), || (session.state() == GenerationSessionState::Finished
|
||||
|| session.state() == GenerationSessionState::Failed)
|
||||
&& clusters[0].client().generation_session(&SessionId::default()).is_none());
|
||||
assert!(session.joint_public_and_secret().unwrap().is_ok());
|
||||
|
||||
// now remove share from node2
|
||||
assert!((0..3).all(|i| clusters[i].data.sessions.generation_sessions.is_empty()));
|
||||
clusters[2].data.config.key_storage.remove(&Default::default()).unwrap();
|
||||
|
||||
// and try to sign message with generated key
|
||||
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
||||
let session0 = clusters[0].client().new_ecdsa_signing_session(Default::default(), signature, None, H256::random()).unwrap();
|
||||
let session = clusters[0].data.sessions.ecdsa_signing_sessions.first().unwrap();
|
||||
|
||||
loop_until(&mut core, time::Duration::from_millis(1000), || session.is_finished() && (0..3).all(|i|
|
||||
clusters[i].data.sessions.ecdsa_signing_sessions.is_empty()));
|
||||
session0.wait().unwrap();
|
||||
|
||||
// and try to sign message with generated key using node that has no key share
|
||||
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
||||
let session2 = clusters[2].client().new_ecdsa_signing_session(Default::default(), signature, None, H256::random()).unwrap();
|
||||
let session = clusters[2].data.sessions.ecdsa_signing_sessions.first().unwrap();
|
||||
loop_until(&mut core, time::Duration::from_millis(1000), || session.is_finished() && (0..3).all(|i|
|
||||
clusters[i].data.sessions.ecdsa_signing_sessions.is_empty()));
|
||||
session2.wait().unwrap();
|
||||
|
||||
// now remove share from node1
|
||||
clusters[1].data.config.key_storage.remove(&Default::default()).unwrap();
|
||||
|
||||
// and try to sign message with generated key
|
||||
let signature = sign(Random.generate().unwrap().secret(), &Default::default()).unwrap();
|
||||
let session1 = clusters[0].client().new_ecdsa_signing_session(Default::default(), signature, None, H256::random()).unwrap();
|
||||
let session = clusters[0].data.sessions.ecdsa_signing_sessions.first().unwrap();
|
||||
loop_until(&mut core, time::Duration::from_millis(1000), || session.is_finished());
|
||||
session1.wait().unwrap_err();
|
||||
}
|
||||
}
|
||||
|
@ -28,14 +28,16 @@ use key_server_cluster::message::{self, Message};
|
||||
use key_server_cluster::generation_session::{SessionImpl as GenerationSessionImpl};
|
||||
use key_server_cluster::decryption_session::{SessionImpl as DecryptionSessionImpl};
|
||||
use key_server_cluster::encryption_session::{SessionImpl as EncryptionSessionImpl};
|
||||
use key_server_cluster::signing_session::{SessionImpl as SigningSessionImpl};
|
||||
use key_server_cluster::signing_session_ecdsa::{SessionImpl as EcdsaSigningSessionImpl};
|
||||
use key_server_cluster::signing_session_schnorr::{SessionImpl as SchnorrSigningSessionImpl};
|
||||
use key_server_cluster::share_add_session::{SessionImpl as ShareAddSessionImpl, IsolatedSessionTransport as ShareAddTransport};
|
||||
use key_server_cluster::servers_set_change_session::{SessionImpl as ServersSetChangeSessionImpl};
|
||||
use key_server_cluster::key_version_negotiation_session::{SessionImpl as KeyVersionNegotiationSessionImpl,
|
||||
IsolatedSessionTransport as VersionNegotiationTransport};
|
||||
|
||||
use key_server_cluster::cluster_sessions_creator::{GenerationSessionCreator, EncryptionSessionCreator, DecryptionSessionCreator, SigningSessionCreator,
|
||||
KeyVersionNegotiationSessionCreator, AdminSessionCreator, SessionCreatorCore, ClusterSessionCreator};
|
||||
use key_server_cluster::cluster_sessions_creator::{GenerationSessionCreator, EncryptionSessionCreator, DecryptionSessionCreator,
|
||||
SchnorrSigningSessionCreator, KeyVersionNegotiationSessionCreator, AdminSessionCreator, SessionCreatorCore,
|
||||
EcdsaSigningSessionCreator, ClusterSessionCreator};
|
||||
|
||||
/// When there are no session-related messages for SESSION_TIMEOUT_INTERVAL seconds,
|
||||
/// we must treat this session as stalled && finish it with an error.
|
||||
@ -125,8 +127,10 @@ pub struct ClusterSessions {
|
||||
pub encryption_sessions: ClusterSessionsContainer<EncryptionSessionImpl, EncryptionSessionCreator, ()>,
|
||||
/// Decryption sessions.
|
||||
pub decryption_sessions: ClusterSessionsContainer<DecryptionSessionImpl, DecryptionSessionCreator, Signature>,
|
||||
/// Signing sessions.
|
||||
pub signing_sessions: ClusterSessionsContainer<SigningSessionImpl, SigningSessionCreator, Signature>,
|
||||
/// Schnorr signing sessions.
|
||||
pub schnorr_signing_sessions: ClusterSessionsContainer<SchnorrSigningSessionImpl, SchnorrSigningSessionCreator, Signature>,
|
||||
/// ECDSA signing sessions.
|
||||
pub ecdsa_signing_sessions: ClusterSessionsContainer<EcdsaSigningSessionImpl, EcdsaSigningSessionCreator, Signature>,
|
||||
/// Key version negotiation sessions.
|
||||
pub negotiation_sessions: ClusterSessionsContainer<KeyVersionNegotiationSessionImpl<VersionNegotiationTransport>, KeyVersionNegotiationSessionCreator, ()>,
|
||||
/// Administrative sessions.
|
||||
@ -203,7 +207,10 @@ impl ClusterSessions {
|
||||
decryption_sessions: ClusterSessionsContainer::new(DecryptionSessionCreator {
|
||||
core: creator_core.clone(),
|
||||
}, container_state.clone()),
|
||||
signing_sessions: ClusterSessionsContainer::new(SigningSessionCreator {
|
||||
schnorr_signing_sessions: ClusterSessionsContainer::new(SchnorrSigningSessionCreator {
|
||||
core: creator_core.clone(),
|
||||
}, container_state.clone()),
|
||||
ecdsa_signing_sessions: ClusterSessionsContainer::new(EcdsaSigningSessionCreator {
|
||||
core: creator_core.clone(),
|
||||
}, container_state.clone()),
|
||||
negotiation_sessions: ClusterSessionsContainer::new(KeyVersionNegotiationSessionCreator {
|
||||
@ -240,7 +247,8 @@ impl ClusterSessions {
|
||||
self.generation_sessions.stop_stalled_sessions();
|
||||
self.encryption_sessions.stop_stalled_sessions();
|
||||
self.decryption_sessions.stop_stalled_sessions();
|
||||
self.signing_sessions.stop_stalled_sessions();
|
||||
self.schnorr_signing_sessions.stop_stalled_sessions();
|
||||
self.ecdsa_signing_sessions.stop_stalled_sessions();
|
||||
self.negotiation_sessions.stop_stalled_sessions();
|
||||
self.admin_sessions.stop_stalled_sessions();
|
||||
}
|
||||
@ -250,7 +258,8 @@ impl ClusterSessions {
|
||||
self.generation_sessions.on_connection_timeout(node_id);
|
||||
self.encryption_sessions.on_connection_timeout(node_id);
|
||||
self.decryption_sessions.on_connection_timeout(node_id);
|
||||
self.signing_sessions.on_connection_timeout(node_id);
|
||||
self.schnorr_signing_sessions.on_connection_timeout(node_id);
|
||||
self.ecdsa_signing_sessions.on_connection_timeout(node_id);
|
||||
self.negotiation_sessions.on_connection_timeout(node_id);
|
||||
self.admin_sessions.on_connection_timeout(node_id);
|
||||
self.creator_core.on_connection_timeout(node_id);
|
||||
|
@ -23,14 +23,16 @@ use key_server_cluster::{Error, NodeId, SessionId, AclStorage, KeyStorage, Docum
|
||||
use key_server_cluster::cluster::{Cluster, ClusterConfiguration};
|
||||
use key_server_cluster::connection_trigger::ServersSetChangeSessionCreatorConnector;
|
||||
use key_server_cluster::cluster_sessions::{ClusterSession, SessionIdWithSubSession, AdminSession, AdminSessionCreationData};
|
||||
use key_server_cluster::message::{self, Message, DecryptionMessage, SigningMessage, ConsensusMessageOfShareAdd,
|
||||
ShareAddMessage, ServersSetChangeMessage, ConsensusMessage, ConsensusMessageWithServersSet};
|
||||
use key_server_cluster::message::{self, Message, DecryptionMessage, SchnorrSigningMessage, ConsensusMessageOfShareAdd,
|
||||
ShareAddMessage, ServersSetChangeMessage, ConsensusMessage, ConsensusMessageWithServersSet, EcdsaSigningMessage};
|
||||
use key_server_cluster::generation_session::{SessionImpl as GenerationSessionImpl, SessionParams as GenerationSessionParams};
|
||||
use key_server_cluster::decryption_session::{SessionImpl as DecryptionSessionImpl,
|
||||
SessionParams as DecryptionSessionParams};
|
||||
use key_server_cluster::encryption_session::{SessionImpl as EncryptionSessionImpl, SessionParams as EncryptionSessionParams};
|
||||
use key_server_cluster::signing_session::{SessionImpl as SigningSessionImpl,
|
||||
SessionParams as SigningSessionParams};
|
||||
use key_server_cluster::signing_session_ecdsa::{SessionImpl as EcdsaSigningSessionImpl,
|
||||
SessionParams as EcdsaSigningSessionParams};
|
||||
use key_server_cluster::signing_session_schnorr::{SessionImpl as SchnorrSigningSessionImpl,
|
||||
SessionParams as SchnorrSigningSessionParams};
|
||||
use key_server_cluster::share_add_session::{SessionImpl as ShareAddSessionImpl,
|
||||
SessionParams as ShareAddSessionParams, IsolatedSessionTransport as ShareAddTransport};
|
||||
use key_server_cluster::servers_set_change_session::{SessionImpl as ServersSetChangeSessionImpl,
|
||||
@ -240,26 +242,26 @@ impl ClusterSessionCreator<DecryptionSessionImpl, Signature> for DecryptionSessi
|
||||
}
|
||||
}
|
||||
|
||||
/// Signing session creator.
|
||||
pub struct SigningSessionCreator {
|
||||
/// Schnorr signing session creator.
|
||||
pub struct SchnorrSigningSessionCreator {
|
||||
/// Creator core.
|
||||
pub core: Arc<SessionCreatorCore>,
|
||||
}
|
||||
|
||||
impl ClusterSessionCreator<SigningSessionImpl, Signature> for SigningSessionCreator {
|
||||
impl ClusterSessionCreator<SchnorrSigningSessionImpl, Signature> for SchnorrSigningSessionCreator {
|
||||
fn creation_data_from_message(message: &Message) -> Result<Option<Signature>, Error> {
|
||||
match *message {
|
||||
Message::Signing(SigningMessage::SigningConsensusMessage(ref message)) => match &message.message {
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningConsensusMessage(ref message)) => match &message.message {
|
||||
&ConsensusMessage::InitializeConsensusSession(ref message) => Ok(Some(message.requestor_signature.clone().into())),
|
||||
_ => Err(Error::InvalidMessage),
|
||||
},
|
||||
Message::Signing(SigningMessage::SigningSessionDelegation(ref message)) => Ok(Some(message.requestor_signature.clone().into())),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionDelegation(ref message)) => Ok(Some(message.requestor_signature.clone().into())),
|
||||
_ => Err(Error::InvalidMessage),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_error_message(sid: SessionIdWithSubSession, nonce: u64, err: Error) -> Message {
|
||||
message::Message::Signing(message::SigningMessage::SigningSessionError(message::SigningSessionError {
|
||||
message::Message::SchnorrSigning(message::SchnorrSigningMessage::SchnorrSigningSessionError(message::SchnorrSigningSessionError {
|
||||
session: sid.id.into(),
|
||||
sub_session: sid.access_key.into(),
|
||||
session_nonce: nonce,
|
||||
@ -267,10 +269,56 @@ impl ClusterSessionCreator<SigningSessionImpl, Signature> for SigningSessionCrea
|
||||
}))
|
||||
}
|
||||
|
||||
fn create(&self, cluster: Arc<Cluster>, master: NodeId, nonce: Option<u64>, id: SessionIdWithSubSession, requester_signature: Option<Signature>) -> Result<Arc<SigningSessionImpl>, Error> {
|
||||
fn create(&self, cluster: Arc<Cluster>, master: NodeId, nonce: Option<u64>, id: SessionIdWithSubSession, requester_signature: Option<Signature>) -> Result<Arc<SchnorrSigningSessionImpl>, Error> {
|
||||
let encrypted_data = self.core.read_key_share(&id.id)?;
|
||||
let nonce = self.core.check_session_nonce(&master, nonce)?;
|
||||
Ok(Arc::new(SigningSessionImpl::new(SigningSessionParams {
|
||||
Ok(Arc::new(SchnorrSigningSessionImpl::new(SchnorrSigningSessionParams {
|
||||
meta: SessionMeta {
|
||||
id: id.id,
|
||||
self_node_id: self.core.self_node_id.clone(),
|
||||
master_node_id: master,
|
||||
threshold: encrypted_data.as_ref().map(|ks| ks.threshold).unwrap_or_default(),
|
||||
},
|
||||
access_key: id.access_key,
|
||||
key_share: encrypted_data,
|
||||
acl_storage: self.core.acl_storage.clone(),
|
||||
cluster: cluster,
|
||||
nonce: nonce,
|
||||
}, requester_signature)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// ECDSA signing session creator.
|
||||
pub struct EcdsaSigningSessionCreator {
|
||||
/// Creator core.
|
||||
pub core: Arc<SessionCreatorCore>,
|
||||
}
|
||||
|
||||
impl ClusterSessionCreator<EcdsaSigningSessionImpl, Signature> for EcdsaSigningSessionCreator {
|
||||
fn creation_data_from_message(message: &Message) -> Result<Option<Signature>, Error> {
|
||||
match *message {
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningConsensusMessage(ref message)) => match &message.message {
|
||||
&ConsensusMessage::InitializeConsensusSession(ref message) => Ok(Some(message.requestor_signature.clone().into())),
|
||||
_ => Err(Error::InvalidMessage),
|
||||
},
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionDelegation(ref message)) => Ok(Some(message.requestor_signature.clone().into())),
|
||||
_ => Err(Error::InvalidMessage),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_error_message(sid: SessionIdWithSubSession, nonce: u64, err: Error) -> Message {
|
||||
message::Message::EcdsaSigning(message::EcdsaSigningMessage::EcdsaSigningSessionError(message::EcdsaSigningSessionError {
|
||||
session: sid.id.into(),
|
||||
sub_session: sid.access_key.into(),
|
||||
session_nonce: nonce,
|
||||
error: err.into(),
|
||||
}))
|
||||
}
|
||||
|
||||
fn create(&self, cluster: Arc<Cluster>, master: NodeId, nonce: Option<u64>, id: SessionIdWithSubSession, requester_signature: Option<Signature>) -> Result<Arc<EcdsaSigningSessionImpl>, Error> {
|
||||
let encrypted_data = self.core.read_key_share(&id.id)?;
|
||||
let nonce = self.core.check_session_nonce(&master, nonce)?;
|
||||
Ok(Arc::new(EcdsaSigningSessionImpl::new(EcdsaSigningSessionParams {
|
||||
meta: SessionMeta {
|
||||
id: id.id,
|
||||
self_node_id: self.core.self_node_id.clone(),
|
||||
@ -407,7 +455,8 @@ impl IntoSessionId<SessionId> for Message {
|
||||
Message::Generation(ref message) => Ok(message.session_id().clone()),
|
||||
Message::Encryption(ref message) => Ok(message.session_id().clone()),
|
||||
Message::Decryption(_) => Err(Error::InvalidMessage),
|
||||
Message::Signing(_) => Err(Error::InvalidMessage),
|
||||
Message::SchnorrSigning(_) => Err(Error::InvalidMessage),
|
||||
Message::EcdsaSigning(_) => Err(Error::InvalidMessage),
|
||||
Message::ServersSetChange(ref message) => Ok(message.session_id().clone()),
|
||||
Message::ShareAdd(ref message) => Ok(message.session_id().clone()),
|
||||
Message::KeyVersionNegotiation(_) => Err(Error::InvalidMessage),
|
||||
@ -422,7 +471,8 @@ impl IntoSessionId<SessionIdWithSubSession> for Message {
|
||||
Message::Generation(_) => Err(Error::InvalidMessage),
|
||||
Message::Encryption(_) => Err(Error::InvalidMessage),
|
||||
Message::Decryption(ref message) => Ok(SessionIdWithSubSession::new(message.session_id().clone(), message.sub_session_id().clone())),
|
||||
Message::Signing(ref message) => Ok(SessionIdWithSubSession::new(message.session_id().clone(), message.sub_session_id().clone())),
|
||||
Message::SchnorrSigning(ref message) => Ok(SessionIdWithSubSession::new(message.session_id().clone(), message.sub_session_id().clone())),
|
||||
Message::EcdsaSigning(ref message) => Ok(SessionIdWithSubSession::new(message.session_id().clone(), message.sub_session_id().clone())),
|
||||
Message::ServersSetChange(_) => Err(Error::InvalidMessage),
|
||||
Message::ShareAdd(_) => Err(Error::InvalidMessage),
|
||||
Message::KeyVersionNegotiation(ref message) => Ok(SessionIdWithSubSession::new(message.session_id().clone(), message.sub_session_id().clone())),
|
||||
|
@ -24,8 +24,8 @@ use ethkey::{Secret, KeyPair};
|
||||
use ethkey::math::curve_order;
|
||||
use ethereum_types::{H256, U256};
|
||||
use key_server_cluster::Error;
|
||||
use key_server_cluster::message::{Message, ClusterMessage, GenerationMessage, EncryptionMessage,
|
||||
DecryptionMessage, SigningMessage, ServersSetChangeMessage, ShareAddMessage, KeyVersionNegotiationMessage};
|
||||
use key_server_cluster::message::{Message, ClusterMessage, GenerationMessage, EncryptionMessage, DecryptionMessage,
|
||||
SchnorrSigningMessage, EcdsaSigningMessage, ServersSetChangeMessage, ShareAddMessage, KeyVersionNegotiationMessage};
|
||||
|
||||
/// Size of serialized header.
|
||||
pub const MESSAGE_HEADER_SIZE: usize = 18;
|
||||
@ -90,14 +90,20 @@ pub fn serialize_message(message: Message) -> Result<SerializedMessage, Error> {
|
||||
Message::Decryption(DecryptionMessage::DecryptionSessionDelegationCompleted(payload))
|
||||
=> (156, serde_json::to_vec(&payload)),
|
||||
|
||||
Message::Signing(SigningMessage::SigningConsensusMessage(payload)) => (200, serde_json::to_vec(&payload)),
|
||||
Message::Signing(SigningMessage::SigningGenerationMessage(payload)) => (201, serde_json::to_vec(&payload)),
|
||||
Message::Signing(SigningMessage::RequestPartialSignature(payload)) => (202, serde_json::to_vec(&payload)),
|
||||
Message::Signing(SigningMessage::PartialSignature(payload)) => (203, serde_json::to_vec(&payload)),
|
||||
Message::Signing(SigningMessage::SigningSessionError(payload)) => (204, serde_json::to_vec(&payload)),
|
||||
Message::Signing(SigningMessage::SigningSessionCompleted(payload)) => (205, serde_json::to_vec(&payload)),
|
||||
Message::Signing(SigningMessage::SigningSessionDelegation(payload)) => (206, serde_json::to_vec(&payload)),
|
||||
Message::Signing(SigningMessage::SigningSessionDelegationCompleted(payload)) => (207, serde_json::to_vec(&payload)),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningConsensusMessage(payload))
|
||||
=> (200, serde_json::to_vec(&payload)),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningGenerationMessage(payload))
|
||||
=> (201, serde_json::to_vec(&payload)),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrRequestPartialSignature(payload))
|
||||
=> (202, serde_json::to_vec(&payload)),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrPartialSignature(payload)) => (203, serde_json::to_vec(&payload)),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionError(payload)) => (204, serde_json::to_vec(&payload)),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionCompleted(payload))
|
||||
=> (205, serde_json::to_vec(&payload)),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionDelegation(payload))
|
||||
=> (206, serde_json::to_vec(&payload)),
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionDelegationCompleted(payload))
|
||||
=> (207, serde_json::to_vec(&payload)),
|
||||
|
||||
Message::ServersSetChange(ServersSetChangeMessage::ServersSetChangeConsensusMessage(payload))
|
||||
=> (250, serde_json::to_vec(&payload)),
|
||||
@ -130,6 +136,23 @@ pub fn serialize_message(message: Message) -> Result<SerializedMessage, Error> {
|
||||
=> (451, serde_json::to_vec(&payload)),
|
||||
Message::KeyVersionNegotiation(KeyVersionNegotiationMessage::KeyVersionsError(payload))
|
||||
=> (452, serde_json::to_vec(&payload)),
|
||||
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningConsensusMessage(payload)) => (500, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSignatureNonceGenerationMessage(payload))
|
||||
=> (501, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaInversionNonceGenerationMessage(payload))
|
||||
=> (502, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaInversionZeroGenerationMessage(payload))
|
||||
=> (503, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningInversedNonceCoeffShare(payload))
|
||||
=> (504, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaRequestPartialSignature(payload)) => (505, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaPartialSignature(payload)) => (506, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionError(payload)) => (507, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionCompleted(payload)) => (508, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionDelegation(payload)) => (509, serde_json::to_vec(&payload)),
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionDelegationCompleted(payload))
|
||||
=> (510, serde_json::to_vec(&payload)),
|
||||
};
|
||||
|
||||
let payload = payload.map_err(|err| Error::Serde(err.to_string()))?;
|
||||
@ -168,14 +191,14 @@ pub fn deserialize_message(header: &MessageHeader, payload: Vec<u8>) -> Result<M
|
||||
155 => Message::Decryption(DecryptionMessage::DecryptionSessionDelegation(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
156 => Message::Decryption(DecryptionMessage::DecryptionSessionDelegationCompleted(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
|
||||
200 => Message::Signing(SigningMessage::SigningConsensusMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
201 => Message::Signing(SigningMessage::SigningGenerationMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
202 => Message::Signing(SigningMessage::RequestPartialSignature(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
203 => Message::Signing(SigningMessage::PartialSignature(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
204 => Message::Signing(SigningMessage::SigningSessionError(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
205 => Message::Signing(SigningMessage::SigningSessionCompleted(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
206 => Message::Signing(SigningMessage::SigningSessionDelegation(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
207 => Message::Signing(SigningMessage::SigningSessionDelegationCompleted(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
200 => Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningConsensusMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
201 => Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningGenerationMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
202 => Message::SchnorrSigning(SchnorrSigningMessage::SchnorrRequestPartialSignature(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
203 => Message::SchnorrSigning(SchnorrSigningMessage::SchnorrPartialSignature(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
204 => Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionError(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
205 => Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionCompleted(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
206 => Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionDelegation(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
207 => Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionDelegationCompleted(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
|
||||
250 => Message::ServersSetChange(ServersSetChangeMessage::ServersSetChangeConsensusMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
251 => Message::ServersSetChange(ServersSetChangeMessage::UnknownSessionsRequest(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
@ -198,6 +221,18 @@ pub fn deserialize_message(header: &MessageHeader, payload: Vec<u8>) -> Result<M
|
||||
451 => Message::KeyVersionNegotiation(KeyVersionNegotiationMessage::KeyVersions(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
452 => Message::KeyVersionNegotiation(KeyVersionNegotiationMessage::KeyVersionsError(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
|
||||
500 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningConsensusMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
501 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSignatureNonceGenerationMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
502 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaInversionNonceGenerationMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
503 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaInversionZeroGenerationMessage(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
504 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningInversedNonceCoeffShare(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
505 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaRequestPartialSignature(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
506 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaPartialSignature(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
507 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionError(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
508 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionCompleted(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
509 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionDelegation(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
510 => Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionDelegationCompleted(serde_json::from_slice(&payload).map_err(|err| Error::Serde(err.to_string()))?)),
|
||||
|
||||
_ => return Err(Error::Serde(format!("unknown message type {}", header.kind))),
|
||||
})
|
||||
}
|
||||
|
@ -20,5 +20,6 @@ pub mod dummy_job;
|
||||
pub mod job_session;
|
||||
pub mod key_access_job;
|
||||
pub mod servers_set_change_access_job;
|
||||
pub mod signing_job;
|
||||
pub mod signing_job_ecdsa;
|
||||
pub mod signing_job_schnorr;
|
||||
pub mod unknown_sessions_job;
|
||||
|
151
secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs
Normal file
151
secret_store/src/key_server_cluster/jobs/signing_job_ecdsa.rs
Normal file
@ -0,0 +1,151 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::collections::{BTreeSet, BTreeMap};
|
||||
use ethkey::{Public, Secret, Signature};
|
||||
use ethereum_types::H256;
|
||||
use key_server_cluster::{Error, NodeId, DocumentKeyShare};
|
||||
use key_server_cluster::math;
|
||||
use key_server_cluster::jobs::job_session::{JobPartialRequestAction, JobPartialResponseAction, JobExecutor};
|
||||
|
||||
/// Signing job.
|
||||
pub struct EcdsaSigningJob {
|
||||
/// Key share.
|
||||
key_share: DocumentKeyShare,
|
||||
/// Key version.
|
||||
key_version: H256,
|
||||
/// Share of inv(nonce).
|
||||
inv_nonce_share: Secret,
|
||||
/// Nonce public.
|
||||
nonce_public: Public,
|
||||
/// Request id.
|
||||
request_id: Option<Secret>,
|
||||
///
|
||||
inversed_nonce_coeff: Option<Secret>,
|
||||
/// Message hash.
|
||||
message_hash: Option<H256>,
|
||||
}
|
||||
|
||||
/// Signing job partial request.
|
||||
pub struct EcdsaPartialSigningRequest {
|
||||
/// Request id.
|
||||
pub id: Secret,
|
||||
///
|
||||
pub inversed_nonce_coeff: Secret,
|
||||
/// Message hash to sign.
|
||||
pub message_hash: H256,
|
||||
}
|
||||
|
||||
/// Signing job partial response.
|
||||
#[derive(Clone)]
|
||||
pub struct EcdsaPartialSigningResponse {
|
||||
/// Request id.
|
||||
pub request_id: Secret,
|
||||
/// Partial signature' s share.
|
||||
pub partial_signature_s: Secret,
|
||||
}
|
||||
|
||||
impl EcdsaSigningJob {
|
||||
pub fn new_on_slave(key_share: DocumentKeyShare, key_version: H256, nonce_public: Public, inv_nonce_share: Secret) -> Result<Self, Error> {
|
||||
Ok(EcdsaSigningJob {
|
||||
key_share: key_share,
|
||||
key_version: key_version,
|
||||
nonce_public: nonce_public,
|
||||
inv_nonce_share: inv_nonce_share,
|
||||
request_id: None,
|
||||
inversed_nonce_coeff: None,
|
||||
message_hash: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_on_master(key_share: DocumentKeyShare, key_version: H256, nonce_public: Public, inv_nonce_share: Secret, inversed_nonce_coeff: Secret, message_hash: H256) -> Result<Self, Error> {
|
||||
Ok(EcdsaSigningJob {
|
||||
key_share: key_share,
|
||||
key_version: key_version,
|
||||
nonce_public: nonce_public,
|
||||
inv_nonce_share: inv_nonce_share,
|
||||
request_id: Some(math::generate_random_scalar()?),
|
||||
inversed_nonce_coeff: Some(inversed_nonce_coeff),
|
||||
message_hash: Some(message_hash),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl JobExecutor for EcdsaSigningJob {
|
||||
type PartialJobRequest = EcdsaPartialSigningRequest;
|
||||
type PartialJobResponse = EcdsaPartialSigningResponse;
|
||||
type JobResponse = Signature;
|
||||
|
||||
fn prepare_partial_request(&self, _node: &NodeId, nodes: &BTreeSet<NodeId>) -> Result<EcdsaPartialSigningRequest, Error> {
|
||||
debug_assert!(nodes.len() == self.key_share.threshold * 2 + 1);
|
||||
|
||||
let request_id = self.request_id.as_ref()
|
||||
.expect("prepare_partial_request is only called on master nodes; request_id is filed in constructor on master nodes; qed");
|
||||
let inversed_nonce_coeff = self.inversed_nonce_coeff.as_ref()
|
||||
.expect("prepare_partial_request is only called on master nodes; inversed_nonce_coeff is filed in constructor on master nodes; qed");
|
||||
let message_hash = self.message_hash.as_ref()
|
||||
.expect("compute_response is only called on master nodes; message_hash is filed in constructor on master nodes; qed");
|
||||
|
||||
Ok(EcdsaPartialSigningRequest {
|
||||
id: request_id.clone(),
|
||||
inversed_nonce_coeff: inversed_nonce_coeff.clone(),
|
||||
message_hash: message_hash.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
fn process_partial_request(&mut self, partial_request: EcdsaPartialSigningRequest) -> Result<JobPartialRequestAction<EcdsaPartialSigningResponse>, Error> {
|
||||
let inversed_nonce_coeff_mul_nonce = math::compute_secret_mul(&partial_request.inversed_nonce_coeff, &self.inv_nonce_share)?;
|
||||
let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?;
|
||||
let signature_r = math::compute_ecdsa_r(&self.nonce_public)?;
|
||||
let inv_nonce_mul_secret = math::compute_secret_mul(&inversed_nonce_coeff_mul_nonce, &key_version.secret_share)?;
|
||||
let partial_signature_s = math::compute_ecdsa_s_share(
|
||||
&inversed_nonce_coeff_mul_nonce,
|
||||
&inv_nonce_mul_secret,
|
||||
&signature_r,
|
||||
&math::to_scalar(partial_request.message_hash)?,
|
||||
)?;
|
||||
|
||||
Ok(JobPartialRequestAction::Respond(EcdsaPartialSigningResponse {
|
||||
request_id: partial_request.id,
|
||||
partial_signature_s: partial_signature_s,
|
||||
}))
|
||||
}
|
||||
|
||||
fn check_partial_response(&mut self, _sender: &NodeId, partial_response: &EcdsaPartialSigningResponse) -> Result<JobPartialResponseAction, Error> {
|
||||
if Some(&partial_response.request_id) != self.request_id.as_ref() {
|
||||
return Ok(JobPartialResponseAction::Ignore);
|
||||
}
|
||||
// TODO [Trust]: check_ecdsa_signature_share()
|
||||
|
||||
Ok(JobPartialResponseAction::Accept)
|
||||
}
|
||||
|
||||
fn compute_response(&self, partial_responses: &BTreeMap<NodeId, EcdsaPartialSigningResponse>) -> Result<Signature, Error> {
|
||||
let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?;
|
||||
if partial_responses.keys().any(|n| !key_version.id_numbers.contains_key(n)) {
|
||||
return Err(Error::InvalidMessage);
|
||||
}
|
||||
|
||||
let id_numbers: Vec<_> = partial_responses.keys().map(|n| key_version.id_numbers[n].clone()).collect();
|
||||
let signature_s_shares: Vec<_> = partial_responses.values().map(|r| r.partial_signature_s.clone()).collect();
|
||||
let signature_s = math::compute_ecdsa_s(self.key_share.threshold, &signature_s_shares, &id_numbers)?;
|
||||
let signature_r = math::compute_ecdsa_r(&self.nonce_public)?;
|
||||
|
||||
let signature = math::serialize_ecdsa_signature(&self.nonce_public, signature_r, signature_s);
|
||||
|
||||
Ok(signature)
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ use key_server_cluster::math;
|
||||
use key_server_cluster::jobs::job_session::{JobPartialRequestAction, JobPartialResponseAction, JobExecutor};
|
||||
|
||||
/// Signing job.
|
||||
pub struct SigningJob {
|
||||
pub struct SchnorrSigningJob {
|
||||
/// This node id.
|
||||
self_node_id: NodeId,
|
||||
/// Key share.
|
||||
@ -40,7 +40,7 @@ pub struct SigningJob {
|
||||
}
|
||||
|
||||
/// Signing job partial request.
|
||||
pub struct PartialSigningRequest {
|
||||
pub struct SchnorrPartialSigningRequest {
|
||||
/// Request id.
|
||||
pub id: Secret,
|
||||
/// Message hash.
|
||||
@ -51,16 +51,16 @@ pub struct PartialSigningRequest {
|
||||
|
||||
/// Signing job partial response.
|
||||
#[derive(Clone)]
|
||||
pub struct PartialSigningResponse {
|
||||
pub struct SchnorrPartialSigningResponse {
|
||||
/// Request id.
|
||||
pub request_id: Secret,
|
||||
/// Partial signature.
|
||||
pub partial_signature: Secret,
|
||||
}
|
||||
|
||||
impl SigningJob {
|
||||
impl SchnorrSigningJob {
|
||||
pub fn new_on_slave(self_node_id: NodeId, key_share: DocumentKeyShare, key_version: H256, session_public: Public, session_secret_coeff: Secret) -> Result<Self, Error> {
|
||||
Ok(SigningJob {
|
||||
Ok(SchnorrSigningJob {
|
||||
self_node_id: self_node_id,
|
||||
key_share: key_share,
|
||||
key_version: key_version,
|
||||
@ -72,7 +72,7 @@ impl SigningJob {
|
||||
}
|
||||
|
||||
pub fn new_on_master(self_node_id: NodeId, key_share: DocumentKeyShare, key_version: H256, session_public: Public, session_secret_coeff: Secret, message_hash: H256) -> Result<Self, Error> {
|
||||
Ok(SigningJob {
|
||||
Ok(SchnorrSigningJob {
|
||||
self_node_id: self_node_id,
|
||||
key_share: key_share,
|
||||
key_version: key_version,
|
||||
@ -84,12 +84,12 @@ impl SigningJob {
|
||||
}
|
||||
}
|
||||
|
||||
impl JobExecutor for SigningJob {
|
||||
type PartialJobRequest = PartialSigningRequest;
|
||||
type PartialJobResponse = PartialSigningResponse;
|
||||
impl JobExecutor for SchnorrSigningJob {
|
||||
type PartialJobRequest = SchnorrPartialSigningRequest;
|
||||
type PartialJobResponse = SchnorrPartialSigningResponse;
|
||||
type JobResponse = (Secret, Secret);
|
||||
|
||||
fn prepare_partial_request(&self, node: &NodeId, nodes: &BTreeSet<NodeId>) -> Result<PartialSigningRequest, Error> {
|
||||
fn prepare_partial_request(&self, node: &NodeId, nodes: &BTreeSet<NodeId>) -> Result<SchnorrPartialSigningRequest, Error> {
|
||||
debug_assert!(nodes.len() == self.key_share.threshold + 1);
|
||||
|
||||
let request_id = self.request_id.as_ref()
|
||||
@ -99,14 +99,14 @@ impl JobExecutor for SigningJob {
|
||||
let mut other_nodes_ids = nodes.clone();
|
||||
other_nodes_ids.remove(node);
|
||||
|
||||
Ok(PartialSigningRequest {
|
||||
Ok(SchnorrPartialSigningRequest {
|
||||
id: request_id.clone(),
|
||||
message_hash: message_hash.clone(),
|
||||
other_nodes_ids: other_nodes_ids,
|
||||
})
|
||||
}
|
||||
|
||||
fn process_partial_request(&mut self, partial_request: PartialSigningRequest) -> Result<JobPartialRequestAction<PartialSigningResponse>, Error> {
|
||||
fn process_partial_request(&mut self, partial_request: SchnorrPartialSigningRequest) -> Result<JobPartialRequestAction<SchnorrPartialSigningResponse>, Error> {
|
||||
let key_version = self.key_share.version(&self.key_version).map_err(|e| Error::KeyStorage(e.into()))?;
|
||||
if partial_request.other_nodes_ids.len() != self.key_share.threshold
|
||||
|| partial_request.other_nodes_ids.contains(&self.self_node_id)
|
||||
@ -117,9 +117,9 @@ impl JobExecutor for SigningJob {
|
||||
let self_id_number = &key_version.id_numbers[&self.self_node_id];
|
||||
let other_id_numbers = partial_request.other_nodes_ids.iter().map(|n| &key_version.id_numbers[n]);
|
||||
let combined_hash = math::combine_message_hash_with_public(&partial_request.message_hash, &self.session_public)?;
|
||||
Ok(JobPartialRequestAction::Respond(PartialSigningResponse {
|
||||
Ok(JobPartialRequestAction::Respond(SchnorrPartialSigningResponse {
|
||||
request_id: partial_request.id,
|
||||
partial_signature: math::compute_signature_share(
|
||||
partial_signature: math::compute_schnorr_signature_share(
|
||||
self.key_share.threshold,
|
||||
&combined_hash,
|
||||
&self.session_secret_coeff,
|
||||
@ -130,21 +130,21 @@ impl JobExecutor for SigningJob {
|
||||
}))
|
||||
}
|
||||
|
||||
fn check_partial_response(&mut self, _sender: &NodeId, partial_response: &PartialSigningResponse) -> Result<JobPartialResponseAction, Error> {
|
||||
fn check_partial_response(&mut self, _sender: &NodeId, partial_response: &SchnorrPartialSigningResponse) -> Result<JobPartialResponseAction, Error> {
|
||||
if Some(&partial_response.request_id) != self.request_id.as_ref() {
|
||||
return Ok(JobPartialResponseAction::Ignore);
|
||||
}
|
||||
// TODO [Trust]: check_signature_share()
|
||||
// TODO [Trust]: check_schnorr_signature_share()
|
||||
|
||||
Ok(JobPartialResponseAction::Accept)
|
||||
}
|
||||
|
||||
fn compute_response(&self, partial_responses: &BTreeMap<NodeId, PartialSigningResponse>) -> Result<(Secret, Secret), Error> {
|
||||
fn compute_response(&self, partial_responses: &BTreeMap<NodeId, SchnorrPartialSigningResponse>) -> Result<(Secret, Secret), Error> {
|
||||
let message_hash = self.message_hash.as_ref()
|
||||
.expect("compute_response is only called on master nodes; message_hash is filed in constructor on master nodes; qed");
|
||||
|
||||
let signature_c = math::combine_message_hash_with_public(message_hash, &self.session_public)?;
|
||||
let signature_s = math::compute_signature(partial_responses.values().map(|r| &r.partial_signature))?;
|
||||
let signature_s = math::compute_schnorr_signature(partial_responses.values().map(|r| &r.partial_signature))?;
|
||||
|
||||
Ok((signature_c, signature_s))
|
||||
}
|
@ -14,11 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethkey::{Public, Secret, Random, Generator, math};
|
||||
use ethkey::{Public, Secret, Signature, Random, Generator, math};
|
||||
use ethereum_types::{H256, U256};
|
||||
use hash::keccak;
|
||||
use key_server_cluster::Error;
|
||||
#[cfg(test)] use ethkey::Signature;
|
||||
|
||||
/// Encryption result.
|
||||
#[derive(Debug)]
|
||||
@ -30,7 +29,6 @@ pub struct EncryptedSecret {
|
||||
}
|
||||
|
||||
/// Create zero scalar.
|
||||
#[cfg(test)]
|
||||
pub fn zero_scalar() -> Secret {
|
||||
Secret::zero()
|
||||
}
|
||||
@ -55,13 +53,11 @@ pub fn generate_random_point() -> Result<Public, Error> {
|
||||
}
|
||||
|
||||
/// Get X coordinate of point.
|
||||
#[cfg(test)]
|
||||
fn public_x(public: &Public) -> H256 {
|
||||
public[0..32].into()
|
||||
}
|
||||
|
||||
/// Get Y coordinate of point.
|
||||
#[cfg(test)]
|
||||
fn public_y(public: &Public) -> H256 {
|
||||
public[32..64].into()
|
||||
}
|
||||
@ -84,6 +80,13 @@ pub fn compute_secret_sum<'a, I>(mut secrets: I) -> Result<Secret, Error> where
|
||||
Ok(sum)
|
||||
}
|
||||
|
||||
/// Compute secrets multiplication.
|
||||
pub fn compute_secret_mul(secret1: &Secret, secret2: &Secret) -> Result<Secret, Error> {
|
||||
let mut secret_mul = secret1.clone();
|
||||
secret_mul.mul(secret2)?;
|
||||
Ok(secret_mul)
|
||||
}
|
||||
|
||||
/// Compute secrets 'shadow' multiplication: coeff * multiplication(s[j] / (s[i] - s[j])) for every i != j
|
||||
pub fn compute_shadow_mul<'a, I>(coeff: &Secret, self_secret: &Secret, mut other_secrets: I) -> Result<Secret, Error> where I: Iterator<Item=&'a Secret> {
|
||||
// when there are no other secrets, only coeff is left
|
||||
@ -227,7 +230,6 @@ pub fn compute_joint_secret<'a, I>(secret_coeffs: I) -> Result<Secret, Error> wh
|
||||
}
|
||||
|
||||
/// Compute joint secret key from t+1 secret shares.
|
||||
#[cfg(test)]
|
||||
pub fn compute_joint_secret_from_shares<'a>(t: usize, secret_shares: &[&'a Secret], id_numbers: &[&'a Secret]) -> Result<Secret, Error> {
|
||||
let secret_share_0 = secret_shares[0];
|
||||
let id_number_0 = id_numbers[0];
|
||||
@ -374,7 +376,7 @@ pub fn combine_message_hash_with_public(message_hash: &H256, public: &Public) ->
|
||||
}
|
||||
|
||||
/// Compute Schnorr signature share.
|
||||
pub fn compute_signature_share<'a, I>(threshold: usize, combined_hash: &Secret, one_time_secret_coeff: &Secret, node_secret_share: &Secret, node_number: &Secret, other_nodes_numbers: I)
|
||||
pub fn compute_schnorr_signature_share<'a, I>(threshold: usize, combined_hash: &Secret, one_time_secret_coeff: &Secret, node_secret_share: &Secret, node_number: &Secret, other_nodes_numbers: I)
|
||||
-> Result<Secret, Error> where I: Iterator<Item=&'a Secret> {
|
||||
let mut sum = one_time_secret_coeff.clone();
|
||||
let mut subtrahend = compute_shadow_mul(combined_hash, node_number, other_nodes_numbers)?;
|
||||
@ -388,7 +390,7 @@ pub fn compute_signature_share<'a, I>(threshold: usize, combined_hash: &Secret,
|
||||
}
|
||||
|
||||
/// Check Schnorr signature share.
|
||||
pub fn _check_signature_share<'a, I>(_combined_hash: &Secret, _signature_share: &Secret, _public_share: &Public, _one_time_public_share: &Public, _node_numbers: I)
|
||||
pub fn _check_schnorr_signature_share<'a, I>(_combined_hash: &Secret, _signature_share: &Secret, _public_share: &Public, _one_time_public_share: &Public, _node_numbers: I)
|
||||
-> Result<bool, Error> where I: Iterator<Item=&'a Secret> {
|
||||
// TODO [Trust]: in paper partial signature is checked using comparison:
|
||||
// sig[i] * T = r[i] - c * lagrange_coeff(i) * y[i]
|
||||
@ -408,13 +410,13 @@ pub fn _check_signature_share<'a, I>(_combined_hash: &Secret, _signature_share:
|
||||
}
|
||||
|
||||
/// Compute Schnorr signature.
|
||||
pub fn compute_signature<'a, I>(signature_shares: I) -> Result<Secret, Error> where I: Iterator<Item=&'a Secret> {
|
||||
pub fn compute_schnorr_signature<'a, I>(signature_shares: I) -> Result<Secret, Error> where I: Iterator<Item=&'a Secret> {
|
||||
compute_secret_sum(signature_shares)
|
||||
}
|
||||
|
||||
/// Locally compute Schnorr signature as described in https://en.wikipedia.org/wiki/Schnorr_signature#Signing.
|
||||
#[cfg(test)]
|
||||
pub fn local_compute_signature(nonce: &Secret, secret: &Secret, message_hash: &Secret) -> Result<(Secret, Secret), Error> {
|
||||
pub fn local_compute_schnorr_signature(nonce: &Secret, secret: &Secret, message_hash: &Secret) -> Result<(Secret, Secret), Error> {
|
||||
let mut nonce_public = math::generation_point();
|
||||
math::public_mul_secret(&mut nonce_public, &nonce).unwrap();
|
||||
|
||||
@ -430,7 +432,7 @@ pub fn local_compute_signature(nonce: &Secret, secret: &Secret, message_hash: &S
|
||||
|
||||
/// Verify Schnorr signature as described in https://en.wikipedia.org/wiki/Schnorr_signature#Verifying.
|
||||
#[cfg(test)]
|
||||
pub fn verify_signature(public: &Public, signature: &(Secret, Secret), message_hash: &H256) -> Result<bool, Error> {
|
||||
pub fn verify_schnorr_signature(public: &Public, signature: &(Secret, Secret), message_hash: &H256) -> Result<bool, Error> {
|
||||
let mut addendum = math::generation_point();
|
||||
math::public_mul_secret(&mut addendum, &signature.1)?;
|
||||
let mut nonce_public = public.clone();
|
||||
@ -442,13 +444,11 @@ pub fn verify_signature(public: &Public, signature: &(Secret, Secret), message_h
|
||||
}
|
||||
|
||||
/// Compute R part of ECDSA signature.
|
||||
#[cfg(test)]
|
||||
pub fn compute_ecdsa_r(nonce_public: &Public) -> Result<Secret, Error> {
|
||||
to_scalar(public_x(nonce_public))
|
||||
}
|
||||
|
||||
/// Compute share of S part of ECDSA signature.
|
||||
#[cfg(test)]
|
||||
pub fn compute_ecdsa_s_share(inv_nonce_share: &Secret, inv_nonce_mul_secret: &Secret, signature_r: &Secret, message_hash: &Secret) -> Result<Secret, Error> {
|
||||
let mut nonce_inv_share_mul_message_hash = inv_nonce_share.clone();
|
||||
nonce_inv_share_mul_message_hash.mul(&message_hash.clone().into())?;
|
||||
@ -463,7 +463,6 @@ pub fn compute_ecdsa_s_share(inv_nonce_share: &Secret, inv_nonce_mul_secret: &Se
|
||||
}
|
||||
|
||||
/// Compute S part of ECDSA signature from shares.
|
||||
#[cfg(test)]
|
||||
pub fn compute_ecdsa_s(t: usize, signature_s_shares: &[Secret], id_numbers: &[Secret]) -> Result<Secret, Error> {
|
||||
let double_t = t * 2;
|
||||
debug_assert!(id_numbers.len() >= double_t + 1);
|
||||
@ -475,9 +474,8 @@ pub fn compute_ecdsa_s(t: usize, signature_s_shares: &[Secret], id_numbers: &[Se
|
||||
}
|
||||
|
||||
/// Serialize ECDSA signature to [r][s]v form.
|
||||
#[cfg(test)]
|
||||
pub fn serialize_ecdsa_signature(nonce_public: &Public, signature_r: Secret, mut signature_s: Secret) -> Signature {
|
||||
// compute recvery param
|
||||
// compute recovery param
|
||||
let mut signature_v = {
|
||||
let nonce_public_x = public_x(nonce_public);
|
||||
let nonce_public_y: U256 = public_y(nonce_public).into();
|
||||
@ -507,7 +505,6 @@ pub fn serialize_ecdsa_signature(nonce_public: &Public, signature_r: Secret, mut
|
||||
}
|
||||
|
||||
/// Compute share of ECDSA reversed-nonce coefficient. Result of this_coeff * secret_share gives us a share of inv(nonce).
|
||||
#[cfg(test)]
|
||||
pub fn compute_ecdsa_inversed_secret_coeff_share(secret_share: &Secret, nonce_share: &Secret, zero_share: &Secret) -> Result<Secret, Error> {
|
||||
let mut coeff = secret_share.clone();
|
||||
coeff.mul(nonce_share).unwrap();
|
||||
@ -516,7 +513,6 @@ pub fn compute_ecdsa_inversed_secret_coeff_share(secret_share: &Secret, nonce_sh
|
||||
}
|
||||
|
||||
/// Compute ECDSA reversed-nonce coefficient from its shares. Result of this_coeff * secret_share gives us a share of inv(nonce).
|
||||
#[cfg(test)]
|
||||
pub fn compute_ecdsa_inversed_secret_coeff_from_shares(t: usize, id_numbers: &[Secret], shares: &[Secret]) -> Result<Secret, Error> {
|
||||
debug_assert_eq!(shares.len(), 2 * t + 1);
|
||||
debug_assert_eq!(shares.len(), id_numbers.len());
|
||||
@ -805,8 +801,8 @@ pub mod tests {
|
||||
let key_pair = Random.generate().unwrap();
|
||||
let message_hash = "0000000000000000000000000000000000000000000000000000000000000042".parse().unwrap();
|
||||
let nonce = generate_random_scalar().unwrap();
|
||||
let signature = local_compute_signature(&nonce, key_pair.secret(), &message_hash).unwrap();
|
||||
assert_eq!(verify_signature(key_pair.public(), &signature, &message_hash), Ok(true));
|
||||
let signature = local_compute_schnorr_signature(&nonce, key_pair.secret(), &message_hash).unwrap();
|
||||
assert_eq!(verify_schnorr_signature(key_pair.public(), &signature, &message_hash), Ok(true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -837,7 +833,7 @@ pub mod tests {
|
||||
|
||||
// step 3: compute signature shares
|
||||
let partial_signatures: Vec<_> = (0..n)
|
||||
.map(|i| compute_signature_share(
|
||||
.map(|i| compute_schnorr_signature_share(
|
||||
t,
|
||||
&combined_hash,
|
||||
&one_time_artifacts.polynoms1[i][0],
|
||||
@ -857,7 +853,7 @@ pub mod tests {
|
||||
.filter(|j| i != *j)
|
||||
.map(|j| {
|
||||
let signature_share = partial_signatures[j].clone();
|
||||
assert!(_check_signature_share(&combined_hash,
|
||||
assert!(_check_schnorr_signature_share(&combined_hash,
|
||||
&signature_share,
|
||||
&artifacts.public_shares[j],
|
||||
&one_time_artifacts.public_shares[j],
|
||||
@ -869,16 +865,16 @@ pub mod tests {
|
||||
|
||||
// step 5: compute signature
|
||||
let signatures: Vec<_> = (0..n)
|
||||
.map(|i| (combined_hash.clone(), compute_signature(received_signatures[i].iter().chain(once(&partial_signatures[i]))).unwrap()))
|
||||
.map(|i| (combined_hash.clone(), compute_schnorr_signature(received_signatures[i].iter().chain(once(&partial_signatures[i]))).unwrap()))
|
||||
.collect();
|
||||
|
||||
// === verify signature ===
|
||||
let master_secret = compute_joint_secret(artifacts.polynoms1.iter().map(|p| &p[0])).unwrap();
|
||||
let nonce = compute_joint_secret(one_time_artifacts.polynoms1.iter().map(|p| &p[0])).unwrap();
|
||||
let local_signature = local_compute_signature(&nonce, &master_secret, &message_hash).unwrap();
|
||||
let local_signature = local_compute_schnorr_signature(&nonce, &master_secret, &message_hash).unwrap();
|
||||
for signature in &signatures {
|
||||
assert_eq!(signature, &local_signature);
|
||||
assert_eq!(verify_signature(&artifacts.joint_public, signature, &message_hash), Ok(true));
|
||||
assert_eq!(verify_schnorr_signature(&artifacts.joint_public, signature, &message_hash), Ok(true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,10 @@ pub enum Message {
|
||||
Encryption(EncryptionMessage),
|
||||
/// Decryption message.
|
||||
Decryption(DecryptionMessage),
|
||||
/// Signing message.
|
||||
Signing(SigningMessage),
|
||||
/// Schnorr signing message.
|
||||
SchnorrSigning(SchnorrSigningMessage),
|
||||
/// ECDSA signing message.
|
||||
EcdsaSigning(EcdsaSigningMessage),
|
||||
/// Key version negotiation message.
|
||||
KeyVersionNegotiation(KeyVersionNegotiationMessage),
|
||||
/// Share add message.
|
||||
@ -133,25 +135,52 @@ pub enum DecryptionMessage {
|
||||
DecryptionSessionDelegationCompleted(DecryptionSessionDelegationCompleted),
|
||||
}
|
||||
|
||||
/// All possible messages that can be sent during signing session.
|
||||
/// All possible messages that can be sent during Schnorr signing session.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum SigningMessage {
|
||||
pub enum SchnorrSigningMessage {
|
||||
/// Consensus establishing message.
|
||||
SigningConsensusMessage(SigningConsensusMessage),
|
||||
SchnorrSigningConsensusMessage(SchnorrSigningConsensusMessage),
|
||||
/// Session key generation message.
|
||||
SigningGenerationMessage(SigningGenerationMessage),
|
||||
SchnorrSigningGenerationMessage(SchnorrSigningGenerationMessage),
|
||||
/// Request partial signature from node.
|
||||
RequestPartialSignature(RequestPartialSignature),
|
||||
SchnorrRequestPartialSignature(SchnorrRequestPartialSignature),
|
||||
/// Partial signature is generated.
|
||||
PartialSignature(PartialSignature),
|
||||
SchnorrPartialSignature(SchnorrPartialSignature),
|
||||
/// Signing error occured.
|
||||
SigningSessionError(SigningSessionError),
|
||||
SchnorrSigningSessionError(SchnorrSigningSessionError),
|
||||
/// Signing session completed.
|
||||
SigningSessionCompleted(SigningSessionCompleted),
|
||||
SchnorrSigningSessionCompleted(SchnorrSigningSessionCompleted),
|
||||
/// When signing session is delegated to another node.
|
||||
SigningSessionDelegation(SigningSessionDelegation),
|
||||
SchnorrSigningSessionDelegation(SchnorrSigningSessionDelegation),
|
||||
/// When delegated signing session is completed.
|
||||
SigningSessionDelegationCompleted(SigningSessionDelegationCompleted),
|
||||
SchnorrSigningSessionDelegationCompleted(SchnorrSigningSessionDelegationCompleted),
|
||||
}
|
||||
|
||||
/// All possible messages that can be sent during ECDSA signing session.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum EcdsaSigningMessage {
|
||||
/// Consensus establishing message.
|
||||
EcdsaSigningConsensusMessage(EcdsaSigningConsensusMessage),
|
||||
/// Signature nonce generation message.
|
||||
EcdsaSignatureNonceGenerationMessage(EcdsaSignatureNonceGenerationMessage),
|
||||
/// Inversion nonce generation message.
|
||||
EcdsaInversionNonceGenerationMessage(EcdsaInversionNonceGenerationMessage),
|
||||
/// Inversion zero generation message.
|
||||
EcdsaInversionZeroGenerationMessage(EcdsaInversionZeroGenerationMessage),
|
||||
/// Inversed nonce coefficient share.
|
||||
EcdsaSigningInversedNonceCoeffShare(EcdsaSigningInversedNonceCoeffShare),
|
||||
/// Request partial signature from node.
|
||||
EcdsaRequestPartialSignature(EcdsaRequestPartialSignature),
|
||||
/// Partial signature is generated.
|
||||
EcdsaPartialSignature(EcdsaPartialSignature),
|
||||
/// Signing error occured.
|
||||
EcdsaSigningSessionError(EcdsaSigningSessionError),
|
||||
/// Signing session completed.
|
||||
EcdsaSigningSessionCompleted(EcdsaSigningSessionCompleted),
|
||||
/// When signing session is delegated to another node.
|
||||
EcdsaSigningSessionDelegation(EcdsaSigningSessionDelegation),
|
||||
/// When delegated signing session is completed.
|
||||
EcdsaSigningSessionDelegationCompleted(EcdsaSigningSessionDelegationCompleted),
|
||||
}
|
||||
|
||||
/// All possible messages that can be sent during servers set change session.
|
||||
@ -246,6 +275,8 @@ pub struct InitializeSession {
|
||||
pub author: SerializablePublic,
|
||||
/// All session participants along with their identification numbers.
|
||||
pub nodes: BTreeMap<MessageNodeId, SerializableSecret>,
|
||||
/// Is zero secret generation session?
|
||||
pub is_zero: bool,
|
||||
/// Decryption threshold. During decryption threshold-of-route.len() nodes must came to
|
||||
/// consensus to successfully decrypt message.
|
||||
pub threshold: usize,
|
||||
@ -407,9 +438,9 @@ pub struct InitializeConsensusSessionOfShareAdd {
|
||||
pub new_set_signature: SerializableSignature,
|
||||
}
|
||||
|
||||
/// Consensus-related signing message.
|
||||
/// Consensus-related Schnorr signing message.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SigningConsensusMessage {
|
||||
pub struct SchnorrSigningConsensusMessage {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
@ -422,7 +453,7 @@ pub struct SigningConsensusMessage {
|
||||
|
||||
/// Session key generation message.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SigningGenerationMessage {
|
||||
pub struct SchnorrSigningGenerationMessage {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
@ -433,9 +464,9 @@ pub struct SigningGenerationMessage {
|
||||
pub message: GenerationMessage,
|
||||
}
|
||||
|
||||
/// Request partial signature.
|
||||
/// Request partial Schnorr signature.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct RequestPartialSignature {
|
||||
pub struct SchnorrRequestPartialSignature {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
@ -450,9 +481,9 @@ pub struct RequestPartialSignature {
|
||||
pub nodes: BTreeSet<MessageNodeId>,
|
||||
}
|
||||
|
||||
/// Partial signature.
|
||||
/// Partial Schnorr signature.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct PartialSignature {
|
||||
pub struct SchnorrPartialSignature {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
@ -465,9 +496,9 @@ pub struct PartialSignature {
|
||||
pub partial_signature: SerializableSecret,
|
||||
}
|
||||
|
||||
/// When signing session error has occured.
|
||||
/// When Schnorr signing session error has occured.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SigningSessionError {
|
||||
pub struct SchnorrSigningSessionError {
|
||||
/// Encryption session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
@ -478,9 +509,9 @@ pub struct SigningSessionError {
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
/// Signing session completed.
|
||||
/// Schnorr signing session completed.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SigningSessionCompleted {
|
||||
pub struct SchnorrSigningSessionCompleted {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
@ -489,9 +520,9 @@ pub struct SigningSessionCompleted {
|
||||
pub session_nonce: u64,
|
||||
}
|
||||
|
||||
/// When signing session is delegated to another node.
|
||||
/// When Schnorr signing session is delegated to another node.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SigningSessionDelegation {
|
||||
pub struct SchnorrSigningSessionDelegation {
|
||||
/// Encryption session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Decryption session Id.
|
||||
@ -506,9 +537,9 @@ pub struct SigningSessionDelegation {
|
||||
pub message_hash: SerializableH256,
|
||||
}
|
||||
|
||||
/// When delegated signing session is completed.
|
||||
/// When delegated Schnorr signing session is completed.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct SigningSessionDelegationCompleted {
|
||||
pub struct SchnorrSigningSessionDelegationCompleted {
|
||||
/// Encryption session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Decryption session Id.
|
||||
@ -521,6 +552,157 @@ pub struct SigningSessionDelegationCompleted {
|
||||
pub signature_c: SerializableSecret,
|
||||
}
|
||||
|
||||
/// Consensus-related ECDSA signing message.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaSigningConsensusMessage {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Consensus message.
|
||||
pub message: ConsensusMessage,
|
||||
}
|
||||
|
||||
/// ECDSA signature nonce generation message.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaSignatureNonceGenerationMessage {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Generation message.
|
||||
pub message: GenerationMessage,
|
||||
}
|
||||
|
||||
/// ECDSA inversion nonce generation message.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaInversionNonceGenerationMessage {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Generation message.
|
||||
pub message: GenerationMessage,
|
||||
}
|
||||
|
||||
/// ECDSA inversed nonce share message.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaSigningInversedNonceCoeffShare {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Inversed nonce coefficient share.
|
||||
pub inversed_nonce_coeff_share: SerializableSecret,
|
||||
}
|
||||
|
||||
/// ECDSA inversion zero generation message.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaInversionZeroGenerationMessage {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Generation message.
|
||||
pub message: GenerationMessage,
|
||||
}
|
||||
|
||||
/// Request partial ECDSA signature.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaRequestPartialSignature {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Request id.
|
||||
pub request_id: SerializableSecret,
|
||||
///
|
||||
pub inversed_nonce_coeff: SerializableSecret,
|
||||
/// Message hash.
|
||||
pub message_hash: SerializableMessageHash,
|
||||
}
|
||||
|
||||
/// Partial ECDSA signature.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaPartialSignature {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Request id.
|
||||
pub request_id: SerializableSecret,
|
||||
/// Partial S part of signature.
|
||||
pub partial_signature_s: SerializableSecret,
|
||||
}
|
||||
|
||||
/// When ECDSA signing session error has occured.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaSigningSessionError {
|
||||
/// Encryption session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Error message.
|
||||
pub error: String,
|
||||
}
|
||||
|
||||
/// ECDSA signing session completed.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaSigningSessionCompleted {
|
||||
/// Generation session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Signing session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
}
|
||||
|
||||
/// When ECDSA signing session is delegated to another node.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaSigningSessionDelegation {
|
||||
/// Encryption session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Decryption session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Requestor signature.
|
||||
pub requestor_signature: SerializableSignature,
|
||||
/// Key version.
|
||||
pub version: SerializableH256,
|
||||
/// Message hash.
|
||||
pub message_hash: SerializableH256,
|
||||
}
|
||||
|
||||
/// When delegated ECDSA signing session is completed.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct EcdsaSigningSessionDelegationCompleted {
|
||||
/// Encryption session Id.
|
||||
pub session: MessageSessionId,
|
||||
/// Decryption session Id.
|
||||
pub sub_session: SerializableSecret,
|
||||
/// Session-level nonce.
|
||||
pub session_nonce: u64,
|
||||
/// Signature.
|
||||
pub signature: SerializableSignature,
|
||||
}
|
||||
|
||||
/// Consensus-related decryption message.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct DecryptionConsensusMessage {
|
||||
@ -861,7 +1043,11 @@ impl Message {
|
||||
ConsensusMessage::InitializeConsensusSession(_) => true,
|
||||
_ => false
|
||||
},
|
||||
Message::Signing(SigningMessage::SigningConsensusMessage(ref msg)) => match msg.message {
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningConsensusMessage(ref msg)) => match msg.message {
|
||||
ConsensusMessage::InitializeConsensusSession(_) => true,
|
||||
_ => false
|
||||
},
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningConsensusMessage(ref msg)) => match msg.message {
|
||||
ConsensusMessage::InitializeConsensusSession(_) => true,
|
||||
_ => false
|
||||
},
|
||||
@ -881,7 +1067,8 @@ impl Message {
|
||||
pub fn is_delegation_message(&self) -> bool {
|
||||
match *self {
|
||||
Message::Decryption(DecryptionMessage::DecryptionSessionDelegation(_)) => true,
|
||||
Message::Signing(SigningMessage::SigningSessionDelegation(_)) => true,
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionDelegation(_)) => true,
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionDelegation(_)) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -891,7 +1078,8 @@ impl Message {
|
||||
Message::Generation(GenerationMessage::SessionError(_)) => true,
|
||||
Message::Encryption(EncryptionMessage::EncryptionSessionError(_)) => true,
|
||||
Message::Decryption(DecryptionMessage::DecryptionSessionError(_)) => true,
|
||||
Message::Signing(SigningMessage::SigningConsensusMessage(_)) => true,
|
||||
Message::SchnorrSigning(SchnorrSigningMessage::SchnorrSigningSessionError(_)) => true,
|
||||
Message::EcdsaSigning(EcdsaSigningMessage::EcdsaSigningSessionError(_)) => true,
|
||||
Message::KeyVersionNegotiation(KeyVersionNegotiationMessage::KeyVersionsError(_)) => true,
|
||||
Message::ShareAdd(ShareAddMessage::ShareAddError(_)) => true,
|
||||
Message::ServersSetChange(ServersSetChangeMessage::ServersSetChangeError(_)) => true,
|
||||
@ -912,7 +1100,8 @@ impl Message {
|
||||
Message::Generation(ref message) => Some(message.session_nonce()),
|
||||
Message::Encryption(ref message) => Some(message.session_nonce()),
|
||||
Message::Decryption(ref message) => Some(message.session_nonce()),
|
||||
Message::Signing(ref message) => Some(message.session_nonce()),
|
||||
Message::SchnorrSigning(ref message) => Some(message.session_nonce()),
|
||||
Message::EcdsaSigning(ref message) => Some(message.session_nonce()),
|
||||
Message::ShareAdd(ref message) => Some(message.session_nonce()),
|
||||
Message::ServersSetChange(ref message) => Some(message.session_nonce()),
|
||||
Message::KeyVersionNegotiation(ref message) => Some(message.session_nonce()),
|
||||
@ -1002,43 +1191,93 @@ impl DecryptionMessage {
|
||||
}
|
||||
}
|
||||
|
||||
impl SigningMessage {
|
||||
impl SchnorrSigningMessage {
|
||||
pub fn session_id(&self) -> &SessionId {
|
||||
match *self {
|
||||
SigningMessage::SigningConsensusMessage(ref msg) => &msg.session,
|
||||
SigningMessage::SigningGenerationMessage(ref msg) => &msg.session,
|
||||
SigningMessage::RequestPartialSignature(ref msg) => &msg.session,
|
||||
SigningMessage::PartialSignature(ref msg) => &msg.session,
|
||||
SigningMessage::SigningSessionError(ref msg) => &msg.session,
|
||||
SigningMessage::SigningSessionCompleted(ref msg) => &msg.session,
|
||||
SigningMessage::SigningSessionDelegation(ref msg) => &msg.session,
|
||||
SigningMessage::SigningSessionDelegationCompleted(ref msg) => &msg.session,
|
||||
SchnorrSigningMessage::SchnorrSigningConsensusMessage(ref msg) => &msg.session,
|
||||
SchnorrSigningMessage::SchnorrSigningGenerationMessage(ref msg) => &msg.session,
|
||||
SchnorrSigningMessage::SchnorrRequestPartialSignature(ref msg) => &msg.session,
|
||||
SchnorrSigningMessage::SchnorrPartialSignature(ref msg) => &msg.session,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionError(ref msg) => &msg.session,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionCompleted(ref msg) => &msg.session,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionDelegation(ref msg) => &msg.session,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionDelegationCompleted(ref msg) => &msg.session,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub_session_id(&self) -> &Secret {
|
||||
match *self {
|
||||
SigningMessage::SigningConsensusMessage(ref msg) => &msg.sub_session,
|
||||
SigningMessage::SigningGenerationMessage(ref msg) => &msg.sub_session,
|
||||
SigningMessage::RequestPartialSignature(ref msg) => &msg.sub_session,
|
||||
SigningMessage::PartialSignature(ref msg) => &msg.sub_session,
|
||||
SigningMessage::SigningSessionError(ref msg) => &msg.sub_session,
|
||||
SigningMessage::SigningSessionCompleted(ref msg) => &msg.sub_session,
|
||||
SigningMessage::SigningSessionDelegation(ref msg) => &msg.sub_session,
|
||||
SigningMessage::SigningSessionDelegationCompleted(ref msg) => &msg.sub_session,
|
||||
SchnorrSigningMessage::SchnorrSigningConsensusMessage(ref msg) => &msg.sub_session,
|
||||
SchnorrSigningMessage::SchnorrSigningGenerationMessage(ref msg) => &msg.sub_session,
|
||||
SchnorrSigningMessage::SchnorrRequestPartialSignature(ref msg) => &msg.sub_session,
|
||||
SchnorrSigningMessage::SchnorrPartialSignature(ref msg) => &msg.sub_session,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionError(ref msg) => &msg.sub_session,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionCompleted(ref msg) => &msg.sub_session,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionDelegation(ref msg) => &msg.sub_session,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionDelegationCompleted(ref msg) => &msg.sub_session,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_nonce(&self) -> u64 {
|
||||
match *self {
|
||||
SigningMessage::SigningConsensusMessage(ref msg) => msg.session_nonce,
|
||||
SigningMessage::SigningGenerationMessage(ref msg) => msg.session_nonce,
|
||||
SigningMessage::RequestPartialSignature(ref msg) => msg.session_nonce,
|
||||
SigningMessage::PartialSignature(ref msg) => msg.session_nonce,
|
||||
SigningMessage::SigningSessionError(ref msg) => msg.session_nonce,
|
||||
SigningMessage::SigningSessionCompleted(ref msg) => msg.session_nonce,
|
||||
SigningMessage::SigningSessionDelegation(ref msg) => msg.session_nonce,
|
||||
SigningMessage::SigningSessionDelegationCompleted(ref msg) => msg.session_nonce,
|
||||
SchnorrSigningMessage::SchnorrSigningConsensusMessage(ref msg) => msg.session_nonce,
|
||||
SchnorrSigningMessage::SchnorrSigningGenerationMessage(ref msg) => msg.session_nonce,
|
||||
SchnorrSigningMessage::SchnorrRequestPartialSignature(ref msg) => msg.session_nonce,
|
||||
SchnorrSigningMessage::SchnorrPartialSignature(ref msg) => msg.session_nonce,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionError(ref msg) => msg.session_nonce,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionCompleted(ref msg) => msg.session_nonce,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionDelegation(ref msg) => msg.session_nonce,
|
||||
SchnorrSigningMessage::SchnorrSigningSessionDelegationCompleted(ref msg) => msg.session_nonce,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EcdsaSigningMessage {
|
||||
pub fn session_id(&self) -> &SessionId {
|
||||
match *self {
|
||||
EcdsaSigningMessage::EcdsaSigningConsensusMessage(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaSignatureNonceGenerationMessage(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaInversionNonceGenerationMessage(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaInversionZeroGenerationMessage(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaSigningInversedNonceCoeffShare(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaRequestPartialSignature(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaPartialSignature(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionError(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionCompleted(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionDelegation(ref msg) => &msg.session,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionDelegationCompleted(ref msg) => &msg.session,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sub_session_id(&self) -> &Secret {
|
||||
match *self {
|
||||
EcdsaSigningMessage::EcdsaSigningConsensusMessage(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaSignatureNonceGenerationMessage(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaInversionNonceGenerationMessage(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaInversionZeroGenerationMessage(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaSigningInversedNonceCoeffShare(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaRequestPartialSignature(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaPartialSignature(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionError(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionCompleted(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionDelegation(ref msg) => &msg.sub_session,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionDelegationCompleted(ref msg) => &msg.sub_session,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_nonce(&self) -> u64 {
|
||||
match *self {
|
||||
EcdsaSigningMessage::EcdsaSigningConsensusMessage(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaSignatureNonceGenerationMessage(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaInversionNonceGenerationMessage(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaInversionZeroGenerationMessage(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaSigningInversedNonceCoeffShare(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaRequestPartialSignature(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaPartialSignature(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionError(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionCompleted(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionDelegation(ref msg) => msg.session_nonce,
|
||||
EcdsaSigningMessage::EcdsaSigningSessionDelegationCompleted(ref msg) => msg.session_nonce,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1130,7 +1369,8 @@ impl fmt::Display for Message {
|
||||
Message::Generation(ref message) => write!(f, "Generation.{}", message),
|
||||
Message::Encryption(ref message) => write!(f, "Encryption.{}", message),
|
||||
Message::Decryption(ref message) => write!(f, "Decryption.{}", message),
|
||||
Message::Signing(ref message) => write!(f, "Signing.{}", message),
|
||||
Message::SchnorrSigning(ref message) => write!(f, "SchnorrSigning.{}", message),
|
||||
Message::EcdsaSigning(ref message) => write!(f, "EcdsaSigning.{}", message),
|
||||
Message::ServersSetChange(ref message) => write!(f, "ServersSetChange.{}", message),
|
||||
Message::ShareAdd(ref message) => write!(f, "ShareAdd.{}", message),
|
||||
Message::KeyVersionNegotiation(ref message) => write!(f, "KeyVersionNegotiation.{}", message),
|
||||
@ -1214,17 +1454,35 @@ impl fmt::Display for DecryptionMessage {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SigningMessage {
|
||||
impl fmt::Display for SchnorrSigningMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
SigningMessage::SigningConsensusMessage(ref m) => write!(f, "SigningConsensusMessage.{}", m.message),
|
||||
SigningMessage::SigningGenerationMessage(ref m) => write!(f, "SigningGenerationMessage.{}", m.message),
|
||||
SigningMessage::RequestPartialSignature(_) => write!(f, "RequestPartialSignature"),
|
||||
SigningMessage::PartialSignature(_) => write!(f, "PartialSignature"),
|
||||
SigningMessage::SigningSessionError(_) => write!(f, "SigningSessionError"),
|
||||
SigningMessage::SigningSessionCompleted(_) => write!(f, "SigningSessionCompleted"),
|
||||
SigningMessage::SigningSessionDelegation(_) => write!(f, "SigningSessionDelegation"),
|
||||
SigningMessage::SigningSessionDelegationCompleted(_) => write!(f, "SigningSessionDelegationCompleted"),
|
||||
SchnorrSigningMessage::SchnorrSigningConsensusMessage(ref m) => write!(f, "SchnorrSigningConsensusMessage.{}", m.message),
|
||||
SchnorrSigningMessage::SchnorrSigningGenerationMessage(ref m) => write!(f, "SchnorrSigningGenerationMessage.{}", m.message),
|
||||
SchnorrSigningMessage::SchnorrRequestPartialSignature(_) => write!(f, "SchnorrRequestPartialSignature"),
|
||||
SchnorrSigningMessage::SchnorrPartialSignature(_) => write!(f, "SchnorrPartialSignature"),
|
||||
SchnorrSigningMessage::SchnorrSigningSessionError(_) => write!(f, "SchnorrSigningSessionError"),
|
||||
SchnorrSigningMessage::SchnorrSigningSessionCompleted(_) => write!(f, "SchnorrSigningSessionCompleted"),
|
||||
SchnorrSigningMessage::SchnorrSigningSessionDelegation(_) => write!(f, "SchnorrSigningSessionDelegation"),
|
||||
SchnorrSigningMessage::SchnorrSigningSessionDelegationCompleted(_) => write!(f, "SchnorrSigningSessionDelegationCompleted"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EcdsaSigningMessage {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
EcdsaSigningMessage::EcdsaSigningConsensusMessage(ref m) => write!(f, "EcdsaSigningConsensusMessage.{}", m.message),
|
||||
EcdsaSigningMessage::EcdsaSignatureNonceGenerationMessage(ref m) => write!(f, "EcdsaSignatureNonceGenerationMessage.{}", m.message),
|
||||
EcdsaSigningMessage::EcdsaInversionNonceGenerationMessage(ref m) => write!(f, "EcdsaInversionNonceGenerationMessage.{}", m.message),
|
||||
EcdsaSigningMessage::EcdsaInversionZeroGenerationMessage(ref m) => write!(f, "EcdsaInversionZeroGenerationMessage.{}", m.message),
|
||||
EcdsaSigningMessage::EcdsaSigningInversedNonceCoeffShare(_) => write!(f, "EcdsaSigningInversedNonceCoeffShare"),
|
||||
EcdsaSigningMessage::EcdsaRequestPartialSignature(_) => write!(f, "EcdsaRequestPartialSignature"),
|
||||
EcdsaSigningMessage::EcdsaPartialSignature(_) => write!(f, "EcdsaPartialSignature"),
|
||||
EcdsaSigningMessage::EcdsaSigningSessionError(_) => write!(f, "EcdsaSigningSessionError"),
|
||||
EcdsaSigningMessage::EcdsaSigningSessionCompleted(_) => write!(f, "EcdsaSigningSessionCompleted"),
|
||||
EcdsaSigningMessage::EcdsaSigningSessionDelegation(_) => write!(f, "EcdsaSigningSessionDelegation"),
|
||||
EcdsaSigningMessage::EcdsaSigningSessionDelegationCompleted(_) => write!(f, "EcdsaSigningSessionDelegationCompleted"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,8 @@ pub use self::admin_sessions::share_change_session;
|
||||
pub use self::client_sessions::decryption_session;
|
||||
pub use self::client_sessions::encryption_session;
|
||||
pub use self::client_sessions::generation_session;
|
||||
pub use self::client_sessions::signing_session;
|
||||
pub use self::client_sessions::signing_session_ecdsa;
|
||||
pub use self::client_sessions::signing_session_schnorr;
|
||||
|
||||
mod cluster;
|
||||
mod cluster_sessions;
|
||||
|
@ -38,7 +38,8 @@ use types::all::{Error, Public, MessageHash, NodeAddress, RequestSignature, Serv
|
||||
/// To generate server && document key: POST /{server_key_id}/{signature}/{threshold}
|
||||
/// To get document key: GET /{server_key_id}/{signature}
|
||||
/// To get document key shadow: GET /shadow/{server_key_id}/{signature}
|
||||
/// To sign message with server key: GET /{server_key_id}/{signature}/{message_hash}
|
||||
/// To generate Schnorr signature with server key: GET /schnorr/{server_key_id}/{signature}/{message_hash}
|
||||
/// To generate ECDSA signature with server key: GET /ecdsa/{server_key_id}/{signature}/{message_hash}
|
||||
/// To change servers set: POST /admin/servers_set_change/{old_signature}/{new_signature} + BODY: json array of hex-encoded nodes ids
|
||||
|
||||
pub struct KeyServerHttpListener {
|
||||
@ -61,8 +62,10 @@ enum Request {
|
||||
GetDocumentKey(ServerKeyId, RequestSignature),
|
||||
/// Request shadow of encryption key of given document for given requestor.
|
||||
GetDocumentKeyShadow(ServerKeyId, RequestSignature),
|
||||
/// Sign message.
|
||||
SignMessage(ServerKeyId, RequestSignature, MessageHash),
|
||||
/// Generate Schnorr signature for the message.
|
||||
SchnorrSignMessage(ServerKeyId, RequestSignature, MessageHash),
|
||||
/// Generate ECDSA signature for the message.
|
||||
EcdsaSignMessage(ServerKeyId, RequestSignature, MessageHash),
|
||||
/// Change servers set.
|
||||
ChangeServersSet(RequestSignature, RequestSignature, BTreeSet<NodeId>),
|
||||
}
|
||||
@ -159,10 +162,17 @@ impl HttpHandler for KeyServerHttpHandler {
|
||||
err
|
||||
}));
|
||||
},
|
||||
Request::SignMessage(document, signature, message_hash) => {
|
||||
return_message_signature(req, res, self.handler.key_server.sign_message(&document, &signature, message_hash)
|
||||
Request::SchnorrSignMessage(document, signature, message_hash) => {
|
||||
return_message_signature(req, res, self.handler.key_server.sign_message_schnorr(&document, &signature, message_hash)
|
||||
.map_err(|err| {
|
||||
warn!(target: "secretstore", "SignMessage request {} has failed with: {}", req_uri, err);
|
||||
warn!(target: "secretstore", "SchnorrSignMessage request {} has failed with: {}", req_uri, err);
|
||||
err
|
||||
}));
|
||||
},
|
||||
Request::EcdsaSignMessage(document, signature, message_hash) => {
|
||||
return_message_signature(req, res, self.handler.key_server.sign_message_ecdsa(&document, &signature, message_hash)
|
||||
.map_err(|err| {
|
||||
warn!(target: "secretstore", "EcdsaSignMessage request {} has failed with: {}", req_uri, err);
|
||||
err
|
||||
}));
|
||||
},
|
||||
@ -263,7 +273,8 @@ fn parse_request(method: &HttpMethod, uri_path: &str, body: &str) -> Request {
|
||||
return parse_admin_request(method, path, body);
|
||||
}
|
||||
|
||||
let (is_shadow_request, args_offset) = if &path[0] == "shadow" { (true, 1) } else { (false, 0) };
|
||||
let (prefix, args_offset) = if &path[0] == "shadow" || &path[0] == "schnorr" || &path[0] == "ecdsa"
|
||||
{ (&*path[0], 1) } else { ("", 0) };
|
||||
let args_count = path.len() - args_offset;
|
||||
if args_count < 2 || path[args_offset].is_empty() || path[args_offset + 1].is_empty() {
|
||||
return Request::Invalid;
|
||||
@ -282,19 +293,21 @@ fn parse_request(method: &HttpMethod, uri_path: &str, body: &str) -> Request {
|
||||
let message_hash = path.get(args_offset + 2).map(|v| v.parse());
|
||||
let common_point = path.get(args_offset + 2).map(|v| v.parse());
|
||||
let encrypted_key = path.get(args_offset + 3).map(|v| v.parse());
|
||||
match (is_shadow_request, args_count, method, threshold, message_hash, common_point, encrypted_key) {
|
||||
(true, 3, &HttpMethod::Post, Some(Ok(threshold)), _, _, _) =>
|
||||
match (prefix, args_count, method, threshold, message_hash, common_point, encrypted_key) {
|
||||
("shadow", 3, &HttpMethod::Post, Some(Ok(threshold)), _, _, _) =>
|
||||
Request::GenerateServerKey(document, signature, threshold),
|
||||
(true, 4, &HttpMethod::Post, _, _, Some(Ok(common_point)), Some(Ok(encrypted_key))) =>
|
||||
("shadow", 4, &HttpMethod::Post, _, _, Some(Ok(common_point)), Some(Ok(encrypted_key))) =>
|
||||
Request::StoreDocumentKey(document, signature, common_point, encrypted_key),
|
||||
(false, 3, &HttpMethod::Post, Some(Ok(threshold)), _, _, _) =>
|
||||
("", 3, &HttpMethod::Post, Some(Ok(threshold)), _, _, _) =>
|
||||
Request::GenerateDocumentKey(document, signature, threshold),
|
||||
(false, 2, &HttpMethod::Get, _, _, _, _) =>
|
||||
("", 2, &HttpMethod::Get, _, _, _, _) =>
|
||||
Request::GetDocumentKey(document, signature),
|
||||
(true, 2, &HttpMethod::Get, _, _, _, _) =>
|
||||
("shadow", 2, &HttpMethod::Get, _, _, _, _) =>
|
||||
Request::GetDocumentKeyShadow(document, signature),
|
||||
(false, 3, &HttpMethod::Get, _, Some(Ok(message_hash)), _, _) =>
|
||||
Request::SignMessage(document, signature, message_hash),
|
||||
("schnorr", 3, &HttpMethod::Get, _, Some(Ok(message_hash)), _, _) =>
|
||||
Request::SchnorrSignMessage(document, signature, message_hash),
|
||||
("ecdsa", 3, &HttpMethod::Get, _, Some(Ok(message_hash)), _, _) =>
|
||||
Request::EcdsaSignMessage(document, signature, message_hash),
|
||||
_ => Request::Invalid,
|
||||
}
|
||||
}
|
||||
@ -370,9 +383,14 @@ mod tests {
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/shadow/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01", Default::default()),
|
||||
Request::GetDocumentKeyShadow("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap()));
|
||||
// GET /{server_key_id}/{signature}/{message_hash} => sign message with server key
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c", Default::default()),
|
||||
Request::SignMessage("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||
// GET /schnorr/{server_key_id}/{signature}/{message_hash} => schnorr-sign message with server key
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/schnorr/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c", Default::default()),
|
||||
Request::SchnorrSignMessage("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||
"281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c".parse().unwrap()));
|
||||
// GET /ecdsa/{server_key_id}/{signature}/{message_hash} => ecdsa-sign message with server key
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/ecdsa/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c", Default::default()),
|
||||
Request::EcdsaSignMessage("0000000000000000000000000000000000000000000000000000000000000001".into(),
|
||||
"a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01".parse().unwrap(),
|
||||
"281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c".parse().unwrap()));
|
||||
// POST /admin/servers_set_change/{old_set_signature}/{new_set_signature} + body
|
||||
@ -398,7 +416,8 @@ mod tests {
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001", Default::default()), Request::Invalid);
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/", Default::default()), Request::Invalid);
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/a/b", Default::default()), Request::Invalid);
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/0000000000000000000000000000000000000000000000000000000000000002/0000000000000000000000000000000000000000000000000000000000000002", Default::default()), Request::Invalid);
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/schnorr/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/0000000000000000000000000000000000000000000000000000000000000002/0000000000000000000000000000000000000000000000000000000000000002", Default::default()), Request::Invalid);
|
||||
assert_eq!(parse_request(&HttpMethod::Get, "/ecdsa/0000000000000000000000000000000000000000000000000000000000000001/a199fb39e11eefb61c78a4074a53c0d4424600a3e74aad4fb9d93a26c30d067e1d4d29936de0c73f19827394a1dd049480a0d581aee7ae7546968da7d3d1c2fd01/0000000000000000000000000000000000000000000000000000000000000002/0000000000000000000000000000000000000000000000000000000000000002", Default::default()), Request::Invalid);
|
||||
assert_eq!(parse_request(&HttpMethod::Post, "/admin/servers_set_change/xxx/yyy",
|
||||
&r#"["0x843645726384530ffb0c52f175278143b5a93959af7864460f5a4fec9afd1450cfb8aef63dec90657f43f55b13e0a73c7524d4e9a13c051b4e5f1e53f39ecd91",
|
||||
"0x07230e34ebfe41337d3ed53b186b3861751f2401ee74b988bba55694e2a6f60c757677e194be2e53c3523cc8548694e636e6acb35c4e8fdc5e29d28679b9b2f3"]"#),
|
||||
|
@ -68,8 +68,12 @@ impl DocumentKeyServer for Listener {
|
||||
}
|
||||
|
||||
impl MessageSigner for Listener {
|
||||
fn sign_message(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
self.key_server.sign_message(key_id, signature, message)
|
||||
fn sign_message_schnorr(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
self.key_server.sign_message_schnorr(key_id, signature, message)
|
||||
}
|
||||
|
||||
fn sign_message_ecdsa(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error> {
|
||||
self.key_server.sign_message_ecdsa(key_id, signature, message)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,12 +76,19 @@ pub trait DocumentKeyServer: ServerKeyGenerator {
|
||||
|
||||
/// Message signer.
|
||||
pub trait MessageSigner: ServerKeyGenerator {
|
||||
/// Sign message with previously generated SK.
|
||||
/// Generate Schnorr signature for message with previously generated SK.
|
||||
/// `key_id` is the caller-provided identifier of generated SK.
|
||||
/// `signature` is `key_id`, signed with caller public key.
|
||||
/// `message` is the message to be signed.
|
||||
/// Result is a signed message, encrypted with caller public key.
|
||||
fn sign_message(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error>;
|
||||
fn sign_message_schnorr(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error>;
|
||||
/// Generate ECDSA signature for message with previously generated SK.
|
||||
/// WARNING: only possible when SK was generated using t <= 2 * N.
|
||||
/// `key_id` is the caller-provided identifier of generated SK.
|
||||
/// `signature` is `key_id`, signed with caller public key.
|
||||
/// `message` is the message to be signed.
|
||||
/// Result is a signed message, encrypted with caller public key.
|
||||
fn sign_message_ecdsa(&self, key_id: &ServerKeyId, signature: &RequestSignature, message: MessageHash) -> Result<EncryptedMessageSignature, Error>;
|
||||
}
|
||||
|
||||
/// Administrative sessions server.
|
||||
|
Loading…
Reference in New Issue
Block a user