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:
Svyatoslav Nikolsky 2018-03-01 11:59:21 +03:00 committed by Marek Kotewicz
parent cdb3afee42
commit 0da6c7eb45
20 changed files with 2381 additions and 329 deletions

View File

@ -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, &ethcrypto::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, &ethcrypto::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, &ethcrypto::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, &ethcrypto::DEFAULT_MAC, &signature).unwrap();
let signature: H520 = signature[0..65].into();
// check signature
assert!(verify_public(&server_public, &signature.into(), &message_hash).unwrap());
}
#[test]

View File

@ -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.

View File

@ -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();
}

View File

@ -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 {
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.clone(), NodeData::with_id_number(node_id_number));
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,
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)?;
&polynom2)?,
true => Default::default(),
};
// compute secret values for every other node
for (node, node_data) in data.nodes.iter_mut() {
@ -629,6 +682,9 @@ 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 is_zero = data.is_zero.expect("is_zero is filled in initialization phase; KV phase follows initialization phase; qed");
let self_public_share = {
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()) {
@ -650,6 +706,13 @@ impl SessionImpl {
math::compute_public_share(self_secret_coeff)?
};
self_public_share
} else {
// TODO [Trust]: add verification when available
Default::default()
}
};
// calculate self secret + public shares
let self_secret_share = {
let secret_values_iter = data.nodes.values()
@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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())),

View File

@ -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))),
})
}

View File

@ -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;

View 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)
}
}

View File

@ -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))
}

View File

@ -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));
}
}
}

View File

@ -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"),
}
}
}

View File

@ -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;

View File

@ -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"]"#),

View File

@ -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)
}
}

View File

@ -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.