2017-03-13 12:54:56 +01:00
// 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/>.
2017-11-16 17:34:23 +01:00
use std ::collections ::BTreeSet ;
2017-03-13 12:54:56 +01:00
use std ::sync ::Arc ;
2017-04-03 11:13:51 +02:00
use parking_lot ::{ Mutex , Condvar } ;
2018-01-10 13:35:18 +01:00
use ethereum_types ::H256 ;
2017-07-06 14:02:10 +02:00
use ethkey ::{ Secret , Signature } ;
use key_server_cluster ::{ Error , AclStorage , DocumentKeyShare , NodeId , SessionId , EncryptedDocumentKeyShadow , SessionMeta } ;
2017-03-13 12:54:56 +01:00
use key_server_cluster ::cluster ::Cluster ;
2017-11-02 15:33:11 +01:00
use key_server_cluster ::cluster_sessions ::{ SessionIdWithSubSession , ClusterSession } ;
2017-07-06 14:02:10 +02:00
use key_server_cluster ::message ::{ Message , DecryptionMessage , DecryptionConsensusMessage , RequestPartialDecryption ,
PartialDecryption , DecryptionSessionError , DecryptionSessionCompleted , ConsensusMessage , InitializeConsensusSession ,
2017-11-02 15:33:11 +01:00
ConfirmConsensusInitialization , DecryptionSessionDelegation , DecryptionSessionDelegationCompleted } ;
2018-02-12 18:05:33 +01:00
use key_server_cluster ::jobs ::job_session ::{ JobSession , JobTransport } ;
2017-10-02 15:27:31 +02:00
use key_server_cluster ::jobs ::key_access_job ::KeyAccessJob ;
2017-07-06 14:02:10 +02:00
use key_server_cluster ::jobs ::decryption_job ::{ PartialDecryptionRequest , PartialDecryptionResponse , DecryptionJob } ;
use key_server_cluster ::jobs ::consensus_session ::{ ConsensusSessionParams , ConsensusSessionState , ConsensusSession } ;
2017-04-03 11:13:51 +02:00
2017-03-13 12:54:56 +01:00
/// Distributed decryption session.
/// Based on "ECDKG: A Distributed Key Generation Protocol Based on Elliptic Curve Discrete Logarithm" paper:
/// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.124.4128&rep=rep1&type=pdf
/// Brief overview:
/// 1) initialization: master node (which has received request for decrypting the secret) requests all other nodes to decrypt the secret
/// 2) ACL check: all nodes which have received the request are querying ACL-contract to check if requestor has access to the document
/// 3) partial decryption: every node which has succussfully checked access for the requestor do a partial decryption
/// 4) decryption: master node receives all partial decryptions of the secret and restores the secret
2017-04-03 11:13:51 +02:00
pub struct SessionImpl {
2017-07-06 14:02:10 +02:00
/// Session core.
core : SessionCore ,
/// Session data.
data : Mutex < SessionData > ,
}
/// Immutable session data.
struct SessionCore {
/// Session metadata.
pub meta : SessionMeta ,
2017-03-13 12:54:56 +01:00
/// Decryption session access key.
2017-07-06 14:02:10 +02:00
pub access_key : Secret ,
/// Key share.
2017-11-02 15:33:11 +01:00
pub key_share : Option < DocumentKeyShare > ,
2017-03-13 12:54:56 +01:00
/// Cluster which allows this node to send messages to other nodes in the cluster.
2017-07-06 14:02:10 +02:00
pub cluster : Arc < Cluster > ,
2017-09-14 19:29:01 +02:00
/// Session-level nonce.
pub nonce : u64 ,
2017-04-03 11:13:51 +02:00
/// SessionImpl completion condvar.
2017-07-06 14:02:10 +02:00
pub completed : Condvar ,
}
/// Decryption consensus session type.
2017-10-02 15:27:31 +02:00
type DecryptionConsensusSession = ConsensusSession < KeyAccessJob , DecryptionConsensusTransport , DecryptionJob , DecryptionJobTransport > ;
2018-02-12 18:05:33 +01:00
/// Broadcast decryption job session type.
type BroadcastDecryptionJobSession = JobSession < DecryptionJob , DecryptionJobTransport > ;
2017-07-06 14:02:10 +02:00
/// Mutable session data.
struct SessionData {
2017-11-02 15:33:11 +01:00
/// Key version to use for decryption.
pub version : Option < H256 > ,
2017-07-06 14:02:10 +02:00
/// Consensus-based decryption session.
pub consensus_session : DecryptionConsensusSession ,
2018-02-12 18:05:33 +01:00
/// Broadcast decryption job.
pub broadcast_job_session : Option < BroadcastDecryptionJobSession > ,
2017-07-06 14:02:10 +02:00
/// Is shadow decryption requested?
pub is_shadow_decryption : Option < bool > ,
2018-02-12 18:05:33 +01:00
/// Decryption result must be reconstructed on all participating nodes. This is useful
/// for service contract API so that all nodes from consensus group can confirm decryption.
pub is_broadcast_session : Option < bool > ,
2017-11-02 15:33:11 +01:00
/// Delegation status.
pub delegation_status : Option < DelegationStatus > ,
2017-07-06 14:02:10 +02:00
/// Decryption result.
pub result : Option < Result < EncryptedDocumentKeyShadow , Error > > ,
2017-03-13 12:54:56 +01:00
}
2017-04-03 11:13:51 +02:00
/// SessionImpl creation parameters
2017-03-13 12:54:56 +01:00
pub struct SessionParams {
2017-07-06 14:02:10 +02:00
/// Session metadata.
pub meta : SessionMeta ,
/// Session access key.
2017-03-13 12:54:56 +01:00
pub access_key : Secret ,
2017-07-06 14:02:10 +02:00
/// Key share.
2017-11-02 15:33:11 +01:00
pub key_share : Option < DocumentKeyShare > ,
2017-03-13 12:54:56 +01:00
/// ACL storage.
pub acl_storage : Arc < AclStorage > ,
2017-09-14 19:29:01 +02:00
/// Cluster.
2017-03-13 12:54:56 +01:00
pub cluster : Arc < Cluster > ,
2017-09-14 19:29:01 +02:00
/// Session nonce.
pub nonce : u64 ,
2017-03-13 12:54:56 +01:00
}
2017-07-06 14:02:10 +02:00
/// Decryption consensus transport.
struct DecryptionConsensusTransport {
/// Session id.
id : SessionId ,
/// Session access key.
access_key : Secret ,
2017-09-14 19:29:01 +02:00
/// Session-level nonce.
nonce : u64 ,
2017-11-02 15:33:11 +01:00
/// Selected key version (on master node).
version : Option < H256 > ,
2017-07-06 14:02:10 +02:00
/// Cluster.
cluster : Arc < Cluster > ,
2017-03-13 12:54:56 +01:00
}
2017-07-06 14:02:10 +02:00
/// Decryption job transport
struct DecryptionJobTransport {
/// Session id.
id : SessionId ,
//// Session access key.
access_key : Secret ,
2017-09-14 19:29:01 +02:00
/// Session-level nonce.
nonce : u64 ,
2018-02-12 18:05:33 +01:00
/// Is this a broadcast transport? If true, requests are not send and responses are sent only to non-master nodes.
is_broadcast_transport : bool ,
/// Master node id.
master_node_id : NodeId ,
2017-07-06 14:02:10 +02:00
/// Cluster.
cluster : Arc < Cluster > ,
2017-03-13 12:54:56 +01:00
}
2017-11-02 15:33:11 +01:00
/// Session delegation status.
enum DelegationStatus {
/// Delegated to other node.
DelegatedTo ( NodeId ) ,
/// Delegated from other node.
DelegatedFrom ( NodeId , u64 ) ,
}
2017-04-03 11:13:51 +02:00
impl SessionImpl {
2017-03-13 12:54:56 +01:00
/// Create new decryption session.
2017-07-06 14:02:10 +02:00
pub fn new ( params : SessionParams , requester_signature : Option < Signature > ) -> Result < Self , Error > {
2017-11-02 15:33:11 +01:00
debug_assert_eq! ( params . meta . threshold , params . key_share . as_ref ( ) . map ( | ks | ks . threshold ) . unwrap_or_default ( ) ) ;
2017-07-06 14:02:10 +02:00
// check that common_point and encrypted_point are already set
2017-11-02 15:33:11 +01:00
if let Some ( key_share ) = params . key_share . as_ref ( ) {
// encrypted data must be set
if key_share . common_point . is_none ( ) | | key_share . encrypted_point . is_none ( ) {
return Err ( Error ::NotStartedSessionId ) ;
}
2017-07-06 14:02:10 +02:00
}
let consensus_transport = DecryptionConsensusTransport {
id : params . meta . id . clone ( ) ,
access_key : params . access_key . clone ( ) ,
2017-09-14 19:29:01 +02:00
nonce : params . nonce ,
2017-11-02 15:33:11 +01:00
version : None ,
2017-07-06 14:02:10 +02:00
cluster : params . cluster . clone ( ) ,
} ;
2017-10-02 15:27:31 +02:00
let consensus_session = ConsensusSession ::new ( ConsensusSessionParams {
meta : params . meta . clone ( ) ,
consensus_executor : match requester_signature {
Some ( requester_signature ) = > KeyAccessJob ::new_on_master ( params . meta . id . clone ( ) , params . acl_storage . clone ( ) , requester_signature ) ,
None = > KeyAccessJob ::new_on_slave ( params . meta . id . clone ( ) , params . acl_storage . clone ( ) ) ,
} ,
consensus_transport : consensus_transport ,
} ) ? ;
2017-03-13 12:54:56 +01:00
2017-04-03 11:13:51 +02:00
Ok ( SessionImpl {
2017-07-06 14:02:10 +02:00
core : SessionCore {
2017-10-02 15:27:31 +02:00
meta : params . meta ,
2017-07-06 14:02:10 +02:00
access_key : params . access_key ,
key_share : params . key_share ,
cluster : params . cluster ,
2017-09-14 19:29:01 +02:00
nonce : params . nonce ,
2017-07-06 14:02:10 +02:00
completed : Condvar ::new ( ) ,
} ,
2017-03-13 12:54:56 +01:00
data : Mutex ::new ( SessionData {
2017-11-02 15:33:11 +01:00
version : None ,
2017-10-02 15:27:31 +02:00
consensus_session : consensus_session ,
2018-02-12 18:05:33 +01:00
broadcast_job_session : None ,
2017-04-08 11:26:16 +02:00
is_shadow_decryption : None ,
2018-02-12 18:05:33 +01:00
is_broadcast_session : None ,
2017-11-02 15:33:11 +01:00
delegation_status : None ,
2017-07-06 14:02:10 +02:00
result : None ,
} ) ,
2017-03-13 12:54:56 +01:00
} )
}
2017-07-06 14:02:10 +02:00
/// Get this node id.
2017-09-06 11:09:22 +02:00
#[ cfg(test) ]
2017-03-13 12:54:56 +01:00
pub fn node ( & self ) -> & NodeId {
2017-07-06 14:02:10 +02:00
& self . core . meta . self_node_id
2017-04-25 21:34:03 +02:00
}
2017-03-13 12:54:56 +01:00
/// Get this session access key.
2017-09-06 11:09:22 +02:00
#[ cfg(test) ]
2017-03-13 12:54:56 +01:00
pub fn access_key ( & self ) -> & Secret {
2017-07-06 14:02:10 +02:00
& self . core . access_key
}
/// Get session state.
2017-09-06 11:09:22 +02:00
#[ cfg(test) ]
2017-07-06 14:02:10 +02:00
pub fn state ( & self ) -> ConsensusSessionState {
self . data . lock ( ) . consensus_session . state ( )
2017-03-13 12:54:56 +01:00
}
/// Get decrypted secret
2017-09-06 11:09:22 +02:00
#[ cfg(test) ]
2017-07-06 14:02:10 +02:00
pub fn decrypted_secret ( & self ) -> Option < Result < EncryptedDocumentKeyShadow , Error > > {
self . data . lock ( ) . result . clone ( )
2017-03-13 12:54:56 +01:00
}
2017-11-22 08:21:14 +01:00
/// Wait for session completion.
pub fn wait ( & self ) -> Result < EncryptedDocumentKeyShadow , Error > {
2017-12-20 17:11:37 +01:00
Self ::wait_session ( & self . core . completed , & self . data , None , | data | data . result . clone ( ) )
2017-11-22 08:21:14 +01:00
}
2017-11-02 15:33:11 +01:00
/// Delegate session to other node.
2018-02-12 18:05:33 +01:00
pub fn delegate ( & self , master : NodeId , version : H256 , is_shadow_decryption : bool , is_broadcast_session : bool ) -> Result < ( ) , Error > {
2017-11-02 15:33:11 +01:00
if self . core . meta . master_node_id ! = self . core . meta . self_node_id {
return Err ( Error ::InvalidStateForRequest ) ;
}
let mut data = self . data . lock ( ) ;
if data . consensus_session . state ( ) ! = ConsensusSessionState ::WaitingForInitialization | | data . delegation_status . is_some ( ) {
return Err ( Error ::InvalidStateForRequest ) ;
}
data . consensus_session . consensus_job_mut ( ) . executor_mut ( ) . set_has_key_share ( false ) ;
self . core . cluster . send ( & master , Message ::Decryption ( DecryptionMessage ::DecryptionSessionDelegation ( DecryptionSessionDelegation {
session : self . core . meta . id . clone ( ) . into ( ) ,
sub_session : self . core . access_key . clone ( ) . into ( ) ,
session_nonce : self . core . nonce ,
requestor_signature : data . consensus_session . consensus_job ( ) . executor ( ) . requester_signature ( )
. expect ( " signature is passed to master node on creation; session can be delegated from master node only; qed " )
. clone ( ) . into ( ) ,
version : version . into ( ) ,
is_shadow_decryption : is_shadow_decryption ,
2018-02-12 18:05:33 +01:00
is_broadcast_session : is_broadcast_session ,
2017-11-02 15:33:11 +01:00
} ) ) ) ? ;
data . delegation_status = Some ( DelegationStatus ::DelegatedTo ( master ) ) ;
Ok ( ( ) )
}
2017-07-06 14:02:10 +02:00
/// Initialize decryption session on master node.
2018-02-12 18:05:33 +01:00
pub fn initialize ( & self , version : H256 , is_shadow_decryption : bool , is_broadcast_session : bool ) -> Result < ( ) , Error > {
2017-11-02 15:33:11 +01:00
debug_assert_eq! ( self . core . meta . self_node_id , self . core . meta . master_node_id ) ;
// check if version exists
let key_version = match self . core . key_share . as_ref ( ) {
None = > return Err ( Error ::InvalidMessage ) ,
Some ( key_share ) = > key_share . version ( & version ) . map_err ( | e | Error ::KeyStorage ( e . into ( ) ) ) ? ,
} ;
2017-03-13 12:54:56 +01:00
let mut data = self . data . lock ( ) ;
2017-11-02 15:33:11 +01:00
let non_isolated_nodes = self . core . cluster . nodes ( ) ;
2017-11-16 17:34:23 +01:00
let mut consensus_nodes : BTreeSet < _ > = key_version . id_numbers . keys ( )
2017-11-02 15:33:11 +01:00
. filter ( | n | non_isolated_nodes . contains ( * n ) )
. cloned ( )
. chain ( ::std ::iter ::once ( self . core . meta . self_node_id . clone ( ) ) )
2017-11-16 17:34:23 +01:00
. collect ( ) ;
if let Some ( & DelegationStatus ::DelegatedFrom ( delegation_master , _ ) ) = data . delegation_status . as_ref ( ) {
consensus_nodes . remove ( & delegation_master ) ;
}
data . consensus_session . consensus_job_mut ( ) . transport_mut ( ) . version = Some ( version . clone ( ) ) ;
data . version = Some ( version . clone ( ) ) ;
data . is_shadow_decryption = Some ( is_shadow_decryption ) ;
2018-02-12 18:05:33 +01:00
data . is_broadcast_session = Some ( is_broadcast_session ) ;
2017-11-16 17:34:23 +01:00
data . consensus_session . initialize ( consensus_nodes ) ? ;
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
if data . consensus_session . state ( ) = = ConsensusSessionState ::ConsensusEstablished {
2018-02-12 18:05:33 +01:00
Self ::disseminate_jobs ( & self . core , & mut * data , & version , is_shadow_decryption , is_broadcast_session ) ? ;
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
debug_assert! ( data . consensus_session . state ( ) = = ConsensusSessionState ::Finished ) ;
2017-11-02 15:33:11 +01:00
let result = data . consensus_session . result ( ) ? ;
Self ::set_decryption_result ( & self . core , & mut * data , Ok ( result ) ) ;
2017-03-13 12:54:56 +01:00
}
Ok ( ( ) )
}
2017-07-06 14:02:10 +02:00
/// Process decryption message.
pub fn process_message ( & self , sender : & NodeId , message : & DecryptionMessage ) -> Result < ( ) , Error > {
2017-09-14 19:29:01 +02:00
if self . core . nonce ! = message . session_nonce ( ) {
return Err ( Error ::ReplayProtection ) ;
}
2017-07-06 14:02:10 +02:00
match message {
& DecryptionMessage ::DecryptionConsensusMessage ( ref message ) = >
self . on_consensus_message ( sender , message ) ,
& DecryptionMessage ::RequestPartialDecryption ( ref message ) = >
self . on_partial_decryption_requested ( sender , message ) ,
& DecryptionMessage ::PartialDecryption ( ref message ) = >
self . on_partial_decryption ( sender , message ) ,
& DecryptionMessage ::DecryptionSessionError ( ref message ) = >
2017-11-02 15:33:11 +01:00
self . process_node_error ( Some ( & sender ) , Error ::Io ( message . error . clone ( ) ) ) ,
2017-07-06 14:02:10 +02:00
& DecryptionMessage ::DecryptionSessionCompleted ( ref message ) = >
self . on_session_completed ( sender , message ) ,
2017-11-02 15:33:11 +01:00
& DecryptionMessage ::DecryptionSessionDelegation ( ref message ) = >
self . on_session_delegated ( sender , message ) ,
& DecryptionMessage ::DecryptionSessionDelegationCompleted ( 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 : & DecryptionSessionDelegation ) -> Result < ( ) , Error > {
debug_assert! ( self . core . meta . id = = * message . session ) ;
debug_assert! ( self . core . access_key = = * message . sub_session ) ;
{
let mut data = self . data . lock ( ) ;
if data . consensus_session . state ( ) ! = ConsensusSessionState ::WaitingForInitialization | | data . delegation_status . is_some ( ) {
return Err ( Error ::InvalidStateForRequest ) ;
}
data . consensus_session . consensus_job_mut ( ) . executor_mut ( ) . set_requester_signature ( message . requestor_signature . clone ( ) . into ( ) ) ;
data . delegation_status = Some ( DelegationStatus ::DelegatedFrom ( sender . clone ( ) , message . session_nonce ) ) ;
}
2018-02-12 18:05:33 +01:00
self . initialize ( message . version . clone ( ) . into ( ) , message . is_shadow_decryption , message . is_broadcast_session )
2017-11-02 15:33:11 +01:00
}
/// When delegated session is completed on other node.
pub fn on_session_delegation_completed ( & self , sender : & NodeId , message : & DecryptionSessionDelegationCompleted ) -> Result < ( ) , Error > {
debug_assert! ( self . core . meta . id = = * message . session ) ;
debug_assert! ( self . core . access_key = = * message . sub_session ) ;
if self . core . meta . master_node_id ! = self . core . meta . self_node_id {
return Err ( Error ::InvalidStateForRequest ) ;
}
let mut data = self . data . lock ( ) ;
match data . delegation_status . as_ref ( ) {
Some ( & DelegationStatus ::DelegatedTo ( ref node ) ) if node = = sender = > ( ) ,
_ = > return Err ( Error ::InvalidMessage ) ,
2017-03-13 12:54:56 +01:00
}
2017-11-02 15:33:11 +01:00
Self ::set_decryption_result ( & self . core , & mut * data , Ok ( EncryptedDocumentKeyShadow {
decrypted_secret : message . decrypted_secret . clone ( ) . into ( ) ,
common_point : message . common_point . clone ( ) . map ( Into ::into ) ,
decrypt_shadows : message . decrypt_shadows . clone ( ) . map ( Into ::into ) ,
} ) ) ;
Ok ( ( ) )
2017-03-13 12:54:56 +01:00
}
2017-07-06 14:02:10 +02:00
/// When consensus-related message is received.
pub fn on_consensus_message ( & self , sender : & NodeId , message : & DecryptionConsensusMessage ) -> Result < ( ) , Error > {
debug_assert! ( self . core . meta . id = = * message . session ) ;
debug_assert! ( self . core . access_key = = * message . sub_session ) ;
2017-03-13 12:54:56 +01:00
let mut data = self . data . lock ( ) ;
2017-07-06 14:02:10 +02:00
let is_establishing_consensus = data . consensus_session . state ( ) = = ConsensusSessionState ::EstablishingConsensus ;
2017-11-02 15:33:11 +01:00
if let & ConsensusMessage ::InitializeConsensusSession ( ref msg ) = & message . message {
let version = msg . version . clone ( ) . into ( ) ;
let has_key_share = self . core . key_share . as_ref ( )
. map ( | ks | ks . version ( & version ) . is_ok ( ) )
. unwrap_or ( false ) ;
data . consensus_session . consensus_job_mut ( ) . executor_mut ( ) . set_has_key_share ( has_key_share ) ;
data . version = Some ( version ) ;
}
2017-07-06 14:02:10 +02:00
data . consensus_session . on_consensus_message ( & sender , & message . message ) ? ;
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
let is_consensus_established = data . consensus_session . state ( ) = = ConsensusSessionState ::ConsensusEstablished ;
if self . core . meta . self_node_id ! = self . core . meta . master_node_id | | ! is_establishing_consensus | | ! is_consensus_established {
2017-03-13 12:54:56 +01:00
return Ok ( ( ) ) ;
}
2017-11-02 15:33:11 +01:00
let version = data . version . as_ref ( ) . ok_or ( Error ::InvalidMessage ) ? . clone ( ) ;
2017-07-06 14:02:10 +02:00
let is_shadow_decryption = data . is_shadow_decryption
. expect ( " we are on master node; on master node is_shadow_decryption is filled in initialize(); on_consensus_message follows initialize (state check in consensus_session); qed " ) ;
2018-02-12 18:05:33 +01:00
let is_broadcast_session = data . is_broadcast_session
. expect ( " we are on master node; on master node is_broadcast_session is filled in initialize(); on_consensus_message follows initialize (state check in consensus_session); qed " ) ;
Self ::disseminate_jobs ( & self . core , & mut * data , & version , is_shadow_decryption , is_broadcast_session )
2017-03-13 12:54:56 +01:00
}
/// When partial decryption is requested.
2017-07-06 14:02:10 +02:00
pub fn on_partial_decryption_requested ( & self , sender : & NodeId , message : & RequestPartialDecryption ) -> 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 ) ;
2017-03-13 12:54:56 +01:00
2017-11-02 15:33:11 +01:00
let key_share = match self . core . key_share . as_ref ( ) {
None = > return Err ( Error ::InvalidMessage ) ,
Some ( key_share ) = > key_share ,
} ;
2017-07-06 14:02:10 +02:00
let mut data = self . data . lock ( ) ;
2017-11-02 15:33:11 +01:00
let key_version = key_share . version ( data . version . as_ref ( ) . ok_or ( Error ::InvalidMessage ) ? )
. map_err ( | e | Error ::KeyStorage ( e . into ( ) ) ) ? . hash . clone ( ) ;
2017-10-02 15:27:31 +02:00
let requester = data . consensus_session . consensus_job ( ) . executor ( ) . requester ( ) ? . ok_or ( Error ::InvalidStateForRequest ) ? . clone ( ) ;
2017-11-02 15:33:11 +01:00
let decryption_job = DecryptionJob ::new_on_slave ( self . core . meta . self_node_id . clone ( ) , self . core . access_key . clone ( ) , requester , key_share . clone ( ) , key_version ) ? ;
2018-02-12 18:05:33 +01:00
let decryption_transport = self . core . decryption_transport ( false ) ;
2017-03-13 12:54:56 +01:00
2018-02-12 18:05:33 +01:00
// respond to request
data . consensus_session . on_job_request ( sender , PartialDecryptionRequest {
2017-07-06 14:02:10 +02:00
id : message . request_id . clone ( ) . into ( ) ,
is_shadow_decryption : message . is_shadow_decryption ,
2018-02-12 18:05:33 +01:00
is_broadcast_session : message . is_broadcast_session ,
2017-07-06 14:02:10 +02:00
other_nodes_ids : message . nodes . iter ( ) . cloned ( ) . map ( Into ::into ) . collect ( ) ,
2018-02-12 18:05:33 +01:00
} , decryption_job , decryption_transport ) ? ;
// ...and prepare decryption job session if we need to broadcast result
if message . is_broadcast_session {
let consensus_group : BTreeSet < _ > = message . nodes . iter ( ) . cloned ( ) . map ( Into ::into ) . collect ( ) ;
let broadcast_decryption_job = DecryptionJob ::new_on_master ( self . core . meta . self_node_id . clone ( ) ,
self . core . access_key . clone ( ) , requester , key_share . clone ( ) , key_version ,
message . is_shadow_decryption , message . is_broadcast_session ) ? ;
Self ::create_broadcast_decryption_job ( & self . core , & mut * data , consensus_group , broadcast_decryption_job ,
message . request_id . clone ( ) . into ( ) ) ? ;
}
Ok ( ( ) )
2017-03-13 12:54:56 +01:00
}
/// When partial decryption is received.
2017-07-06 14:02:10 +02:00
pub fn on_partial_decryption ( & self , sender : & NodeId , message : & PartialDecryption ) -> 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 ) ;
2017-03-13 12:54:56 +01:00
let mut data = self . data . lock ( ) ;
2018-02-12 18:05:33 +01:00
if self . core . meta . self_node_id = = self . core . meta . master_node_id {
data . consensus_session . on_job_response ( sender , PartialDecryptionResponse {
request_id : message . request_id . clone ( ) . into ( ) ,
shadow_point : message . shadow_point . clone ( ) . into ( ) ,
decrypt_shadow : message . decrypt_shadow . clone ( ) ,
} ) ? ;
} else {
match data . broadcast_job_session . as_mut ( ) {
Some ( broadcast_job_session ) = > broadcast_job_session . on_partial_response ( sender , PartialDecryptionResponse {
request_id : message . request_id . clone ( ) . into ( ) ,
shadow_point : message . shadow_point . clone ( ) . into ( ) ,
decrypt_shadow : message . decrypt_shadow . clone ( ) ,
} ) ? ,
None = > return Err ( Error ::TooEarlyForRequest ) ,
}
}
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
if data . consensus_session . state ( ) ! = ConsensusSessionState ::Finished {
2017-03-13 12:54:56 +01:00
return Ok ( ( ) ) ;
}
2017-08-29 14:35:39 +02:00
// 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 ::Decryption ( DecryptionMessage ::DecryptionSessionCompleted ( DecryptionSessionCompleted {
session : self . core . meta . id . clone ( ) . into ( ) ,
sub_session : self . core . access_key . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : self . core . nonce ,
2017-08-29 14:35:39 +02:00
} ) ) ) ? ;
}
2017-04-25 21:34:03 +02:00
2017-11-02 15:33:11 +01:00
let result = data . consensus_session . result ( ) ? ;
Self ::set_decryption_result ( & self . core , & mut * data , Ok ( result ) ) ;
2017-04-03 11:13:51 +02:00
Ok ( ( ) )
}
2017-04-25 21:34:03 +02:00
/// When session is completed.
2017-07-06 14:02:10 +02:00
pub fn on_session_completed ( & self , sender : & NodeId , message : & DecryptionSessionCompleted ) -> 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 ) ;
2017-04-25 21:34:03 +02:00
2018-02-12 18:05:33 +01:00
let mut data = self . data . lock ( ) ;
// if it is a broadcast session, wait for all answers before completing the session
let decryption_result = match data . broadcast_job_session . as_ref ( ) {
Some ( broadcast_job_session ) = > {
if ! broadcast_job_session . is_result_ready ( ) {
return Err ( Error ::TooEarlyForRequest ) ;
}
Some ( broadcast_job_session . result ( ) )
} ,
None = > None ,
} ;
if let Some ( decryption_result ) = decryption_result {
Self ::set_decryption_result ( & self . core , & mut * data , decryption_result ) ;
}
data . consensus_session . on_session_completed ( sender )
2017-04-25 21:34:03 +02:00
}
2017-07-06 14:02:10 +02:00
/// Process error from the other node.
2017-11-02 15:33:11 +01:00
fn process_node_error ( & self , node : Option < & NodeId > , error : Error ) -> Result < ( ) , Error > {
2017-04-25 21:34:03 +02:00
let mut data = self . data . lock ( ) ;
2017-11-02 15:33:11 +01:00
let is_self_node_error = node . map ( | n | n = = & self . core . meta . self_node_id ) . unwrap_or ( false ) ;
// error is always fatal if coming from this node
if is_self_node_error {
Self ::set_decryption_result ( & self . core , & mut * data , Err ( error . clone ( ) ) ) ;
return Err ( error ) ;
}
2017-07-06 14:02:10 +02:00
match {
match node {
Some ( node ) = > data . consensus_session . on_node_error ( node ) ,
None = > data . consensus_session . on_session_timeout ( ) ,
}
} {
Ok ( false ) = > Ok ( ( ) ) ,
Ok ( true ) = > {
2017-11-02 15:33:11 +01:00
let version = data . version . as_ref ( ) . ok_or ( Error ::InvalidMessage ) ? . clone ( ) ;
2018-02-12 18:05:33 +01:00
let proof = " on_node_error returned true; this means that jobs must be REsent; this means that jobs already have been sent; jobs are sent when is_shadow_decryption.is_some(); qed " ;
let is_shadow_decryption = data . is_shadow_decryption . expect ( proof ) ;
let is_broadcast_session = data . is_broadcast_session . expect ( proof ) ;
let disseminate_result = Self ::disseminate_jobs ( & self . core , & mut * data , & version , is_shadow_decryption , is_broadcast_session ) ;
2017-07-06 14:02:10 +02:00
match disseminate_result {
Ok ( ( ) ) = > Ok ( ( ) ) ,
Err ( err ) = > {
warn! ( " {}: decryption session failed with error: {:?} from {:?} " , & self . core . meta . self_node_id , error , node ) ;
2017-11-02 15:33:11 +01:00
Self ::set_decryption_result ( & self . core , & mut * data , Err ( err . clone ( ) ) ) ;
2017-07-06 14:02:10 +02:00
Err ( err )
2017-04-25 21:34:03 +02:00
}
}
2017-07-06 14:02:10 +02:00
} ,
Err ( err ) = > {
warn! ( " {}: decryption session failed with error: {:?} from {:?} " , & self . core . meta . self_node_id , error , node ) ;
2017-04-25 21:34:03 +02:00
2017-11-02 15:33:11 +01:00
Self ::set_decryption_result ( & self . core , & mut * data , Err ( err . clone ( ) ) ) ;
2017-07-06 14:02:10 +02:00
Err ( err )
} ,
}
}
2017-11-02 15:33:11 +01:00
2018-02-12 18:05:33 +01:00
/// Disseminate jobs on session master.
fn disseminate_jobs ( core : & SessionCore , data : & mut SessionData , version : & H256 , is_shadow_decryption : bool , is_broadcast_session : bool ) -> Result < ( ) , Error > {
let key_share = match core . key_share . as_ref ( ) {
None = > return Err ( Error ::InvalidMessage ) ,
Some ( key_share ) = > key_share ,
} ;
let key_version = key_share . version ( version ) . map_err ( | e | Error ::KeyStorage ( e . into ( ) ) ) ? . hash . clone ( ) ;
let requester = data . consensus_session . consensus_job ( ) . executor ( ) . requester ( ) ? . ok_or ( Error ::InvalidStateForRequest ) ? . clone ( ) ;
let consensus_group = data . consensus_session . select_consensus_group ( ) ? . clone ( ) ;
let decryption_job = DecryptionJob ::new_on_master ( core . meta . self_node_id . clone ( ) ,
core . access_key . clone ( ) , requester , key_share . clone ( ) , key_version ,
is_shadow_decryption , is_broadcast_session ) ? ;
let decryption_request_id = decryption_job . request_id ( ) . clone ( ) . expect ( " TODO " ) ;
let decryption_transport = core . decryption_transport ( false ) ;
data . consensus_session . disseminate_jobs ( decryption_job , decryption_transport , data . is_broadcast_session . expect ( " TODO " ) ) ? ;
// ...and prepare decryption job session if we need to broadcast result
if data . is_broadcast_session . expect ( " TODO " ) {
let broadcast_decryption_job = DecryptionJob ::new_on_master ( core . meta . self_node_id . clone ( ) ,
core . access_key . clone ( ) , requester , key_share . clone ( ) , key_version , is_shadow_decryption , is_broadcast_session ) ? ;
Self ::create_broadcast_decryption_job ( & core , data , consensus_group , broadcast_decryption_job ,
decryption_request_id ) ? ;
}
Ok ( ( ) )
}
/// Create broadcast decryption job.
fn create_broadcast_decryption_job ( core : & SessionCore , data : & mut SessionData , mut consensus_group : BTreeSet < NodeId > , mut job : DecryptionJob , request_id : Secret ) -> Result < ( ) , Error > {
consensus_group . insert ( core . meta . self_node_id . clone ( ) ) ;
job . set_request_id ( request_id . clone ( ) . into ( ) ) ;
let transport = core . decryption_transport ( true ) ;
let mut job_session = JobSession ::new ( SessionMeta {
id : core . meta . id . clone ( ) ,
master_node_id : core . meta . self_node_id . clone ( ) ,
self_node_id : core . meta . self_node_id . clone ( ) ,
threshold : core . meta . threshold ,
} , job , transport ) ;
job_session . initialize ( consensus_group , core . meta . self_node_id ! = core . meta . master_node_id ) ? ;
data . broadcast_job_session = Some ( job_session ) ;
Ok ( ( ) )
}
2017-11-02 15:33:11 +01:00
/// Set decryption result.
fn set_decryption_result ( core : & SessionCore , data : & mut SessionData , result : Result < EncryptedDocumentKeyShadow , Error > ) {
if let Some ( DelegationStatus ::DelegatedFrom ( master , nonce ) ) = data . delegation_status . take ( ) {
// error means can't communicate => ignore it
let _ = match result . as_ref ( ) {
Ok ( document_key ) = > core . cluster . send ( & master , Message ::Decryption ( DecryptionMessage ::DecryptionSessionDelegationCompleted ( DecryptionSessionDelegationCompleted {
session : core . meta . id . clone ( ) . into ( ) ,
sub_session : core . access_key . clone ( ) . into ( ) ,
session_nonce : nonce ,
decrypted_secret : document_key . decrypted_secret . clone ( ) . into ( ) ,
common_point : document_key . common_point . clone ( ) . map ( Into ::into ) ,
decrypt_shadows : document_key . decrypt_shadows . clone ( ) ,
} ) ) ) ,
Err ( error ) = > core . cluster . send ( & master , Message ::Decryption ( DecryptionMessage ::DecryptionSessionError ( DecryptionSessionError {
session : core . meta . id . clone ( ) . into ( ) ,
sub_session : core . access_key . clone ( ) . into ( ) ,
session_nonce : nonce ,
error : error . clone ( ) . into ( ) ,
} ) ) ) ,
} ;
}
data . result = Some ( result ) ;
core . completed . notify_all ( ) ;
}
2017-07-06 14:02:10 +02:00
}
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
impl ClusterSession for SessionImpl {
2017-11-02 15:33:11 +01:00
type Id = SessionIdWithSubSession ;
fn type_name ( ) -> & 'static str {
" decryption "
}
fn id ( & self ) -> SessionIdWithSubSession {
SessionIdWithSubSession ::new ( self . core . meta . id . clone ( ) , self . core . access_key . clone ( ) )
}
2017-07-06 14:02:10 +02:00
fn is_finished ( & self ) -> bool {
2017-11-16 17:34:23 +01:00
let data = self . data . lock ( ) ;
data . consensus_session . state ( ) = = ConsensusSessionState ::Failed
| | data . consensus_session . state ( ) = = ConsensusSessionState ::Finished
| | data . result . is_some ( )
2017-04-03 11:13:51 +02:00
}
2017-07-06 14:02:10 +02:00
fn on_node_timeout ( & self , node : & NodeId ) {
// ignore error, only state matters
2017-11-02 15:33:11 +01:00
let _ = self . process_node_error ( Some ( node ) , Error ::NodeDisconnected ) ;
2017-07-06 14:02:10 +02:00
}
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
fn on_session_timeout ( & self ) {
// ignore error, only state matters
2017-11-02 15:33:11 +01:00
let _ = self . process_node_error ( None , Error ::NodeDisconnected ) ;
}
fn on_session_error ( & self , node : & NodeId , error : Error ) {
let is_fatal = self . process_node_error ( Some ( node ) , error . clone ( ) ) . is_err ( ) ;
let is_this_node_error = * node = = self . core . meta . self_node_id ;
if is_fatal | | is_this_node_error {
// error in signing session is non-fatal, if occurs on slave node
// => either respond with error
// => or broadcast error
let message = Message ::Decryption ( DecryptionMessage ::DecryptionSessionError ( DecryptionSessionError {
session : self . core . meta . id . clone ( ) . into ( ) ,
sub_session : self . core . access_key . clone ( ) . into ( ) ,
session_nonce : self . core . nonce ,
error : error . clone ( ) . into ( ) ,
} ) ) ;
// do not bother processing send error, as we already processing error
let _ = if self . core . meta . master_node_id = = self . core . meta . self_node_id {
self . core . cluster . broadcast ( message )
} else {
self . core . cluster . send ( & self . core . meta . master_node_id , message )
} ;
}
}
fn on_message ( & self , sender : & NodeId , message : & Message ) -> Result < ( ) , Error > {
match * message {
Message ::Decryption ( ref message ) = > self . process_message ( sender , message ) ,
_ = > unreachable! ( " cluster checks message to be correct before passing; qed " ) ,
}
2017-07-06 14:02:10 +02:00
}
}
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
impl SessionCore {
2018-02-12 18:05:33 +01:00
pub fn decryption_transport ( & self , is_broadcast_transport : bool ) -> DecryptionJobTransport {
2017-07-06 14:02:10 +02:00
DecryptionJobTransport {
id : self . meta . id . clone ( ) ,
access_key : self . access_key . clone ( ) ,
2017-09-14 19:29:01 +02:00
nonce : self . nonce ,
2018-02-12 18:05:33 +01:00
is_broadcast_transport : is_broadcast_transport ,
master_node_id : self . meta . master_node_id . clone ( ) ,
cluster : self . cluster . clone ( ) ,
2017-04-08 11:26:16 +02:00
}
2017-07-06 14:02:10 +02:00
}
}
2017-04-03 11:13:51 +02:00
2017-07-06 14:02:10 +02:00
impl JobTransport for DecryptionConsensusTransport {
type PartialJobRequest = Signature ;
type PartialJobResponse = bool ;
2017-04-03 11:13:51 +02:00
2017-07-06 14:02:10 +02:00
fn send_partial_request ( & self , node : & NodeId , request : Signature ) -> Result < ( ) , Error > {
2017-11-02 15:33:11 +01:00
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 " ) ;
2017-07-06 14:02:10 +02:00
self . cluster . send ( node , Message ::Decryption ( DecryptionMessage ::DecryptionConsensusMessage ( DecryptionConsensusMessage {
session : self . id . clone ( ) . into ( ) ,
sub_session : self . access_key . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : self . nonce ,
2017-07-06 14:02:10 +02:00
message : ConsensusMessage ::InitializeConsensusSession ( InitializeConsensusSession {
requestor_signature : request . into ( ) ,
2017-11-02 15:33:11 +01:00
version : version . clone ( ) . into ( ) ,
2017-07-06 14:02:10 +02:00
} )
} ) ) )
}
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
fn send_partial_response ( & self , node : & NodeId , response : bool ) -> Result < ( ) , Error > {
self . cluster . send ( node , Message ::Decryption ( DecryptionMessage ::DecryptionConsensusMessage ( DecryptionConsensusMessage {
session : self . id . clone ( ) . into ( ) ,
sub_session : self . access_key . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : self . nonce ,
2017-07-06 14:02:10 +02:00
message : ConsensusMessage ::ConfirmConsensusInitialization ( ConfirmConsensusInitialization {
is_confirmed : response ,
} )
} ) ) )
2017-03-13 12:54:56 +01:00
}
}
2017-07-06 14:02:10 +02:00
impl JobTransport for DecryptionJobTransport {
type PartialJobRequest = PartialDecryptionRequest ;
type PartialJobResponse = PartialDecryptionResponse ;
2017-04-03 11:13:51 +02:00
2017-07-06 14:02:10 +02:00
fn send_partial_request ( & self , node : & NodeId , request : PartialDecryptionRequest ) -> Result < ( ) , Error > {
2018-02-12 18:05:33 +01:00
if ! self . is_broadcast_transport {
self . cluster . send ( node , Message ::Decryption ( DecryptionMessage ::RequestPartialDecryption ( RequestPartialDecryption {
session : self . id . clone ( ) . into ( ) ,
sub_session : self . access_key . clone ( ) . into ( ) ,
session_nonce : self . nonce ,
request_id : request . id . into ( ) ,
is_shadow_decryption : request . is_shadow_decryption ,
is_broadcast_session : request . is_broadcast_session ,
nodes : request . other_nodes_ids . into_iter ( ) . map ( Into ::into ) . collect ( ) ,
} ) ) ) ? ;
}
Ok ( ( ) )
2017-07-06 14:02:10 +02:00
}
fn send_partial_response ( & self , node : & NodeId , response : PartialDecryptionResponse ) -> Result < ( ) , Error > {
2018-02-12 18:05:33 +01:00
if ! self . is_broadcast_transport | | * node ! = self . master_node_id {
self . cluster . send ( node , Message ::Decryption ( DecryptionMessage ::PartialDecryption ( PartialDecryption {
session : self . id . clone ( ) . into ( ) ,
sub_session : self . access_key . clone ( ) . into ( ) ,
session_nonce : self . nonce ,
request_id : response . request_id . into ( ) ,
shadow_point : response . shadow_point . into ( ) ,
decrypt_shadow : response . decrypt_shadow ,
} ) ) ) ? ;
}
Ok ( ( ) )
2017-04-03 11:13:51 +02:00
}
}
2017-03-13 12:54:56 +01:00
#[ cfg(test) ]
mod tests {
use std ::sync ::Arc ;
2018-02-12 18:05:33 +01:00
use std ::collections ::{ BTreeMap , VecDeque } ;
2017-08-09 17:17:28 +02:00
use acl_storage ::DummyAclStorage ;
2017-07-06 14:02:10 +02:00
use ethkey ::{ self , KeyPair , Random , Generator , Public , Secret } ;
2017-11-02 15:33:11 +01:00
use key_server_cluster ::{ NodeId , DocumentKeyShare , DocumentKeyShareVersion , SessionId , Error , EncryptedDocumentKeyShadow , SessionMeta } ;
2017-03-13 12:54:56 +01:00
use key_server_cluster ::cluster ::tests ::DummyCluster ;
2017-07-06 14:02:10 +02:00
use key_server_cluster ::cluster_sessions ::ClusterSession ;
use key_server_cluster ::decryption_session ::{ SessionImpl , SessionParams } ;
2017-04-03 11:13:51 +02:00
use key_server_cluster ::message ::{ self , Message , DecryptionMessage } ;
2017-04-08 11:26:16 +02:00
use key_server_cluster ::math ;
2017-07-06 14:02:10 +02:00
use key_server_cluster ::jobs ::consensus_session ::ConsensusSessionState ;
2017-03-13 12:54:56 +01:00
const SECRET_PLAIN : & 'static str = " d2b57ae7619e070af0af6bc8c703c0cd27814c54d5d6a999cacac0da34ede279ca0d9216e85991029e54e2f0c92ee0bd30237725fa765cbdbfc4529489864c5f " ;
2017-07-06 14:02:10 +02:00
fn prepare_decryption_sessions ( ) -> ( KeyPair , Vec < Arc < DummyCluster > > , Vec < Arc < DummyAclStorage > > , Vec < SessionImpl > ) {
2017-03-13 12:54:56 +01:00
// prepare encrypted data + cluster configuration for scheme 4-of-5
let session_id = SessionId ::default ( ) ;
let access_key = Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) ;
2017-04-03 11:13:51 +02:00
let secret_shares : Vec < Secret > = vec! [
" 834cb736f02d9c968dfaf0c37658a1d86ff140554fc8b59c9fdad5a8cf810eec " . parse ( ) . unwrap ( ) ,
" 5a3c1d90fafafa66bb808bcc464354a98b05e6b2c95b5f609d4511cdd1b17a0b " . parse ( ) . unwrap ( ) ,
" 71bf61e7848e08e3a8486c308ce521bdacfebcf9116a0151447eb301f3a2d0e9 " . parse ( ) . unwrap ( ) ,
" 80c0e5e2bea66fa9b2e07f7ce09630a9563e8242446d5ee63221feb09c4338f4 " . parse ( ) . unwrap ( ) ,
" c06546b5669877ba579ca437a5602e89425c53808c708d44ccd6afcaa4610fad " . parse ( ) . unwrap ( ) ,
2017-03-13 12:54:56 +01:00
] ;
let id_numbers : Vec < ( NodeId , Secret ) > = vec! [
( " b486d3840218837b035c66196ecb15e6b067ca20101e11bd5e626288ab6806ecc70b8307012626bd512bad1559112d11d21025cef48cc7a1d2f3976da08f36c8 " . into ( ) ,
2017-04-03 11:13:51 +02:00
" 281b6bf43cb86d0dc7b98e1b7def4a80f3ce16d28d2308f934f116767306f06c " . parse ( ) . unwrap ( ) ) ,
2017-03-13 12:54:56 +01:00
( " 1395568277679f7f583ab7c0992da35f26cde57149ee70e524e49bdae62db3e18eb96122501e7cbb798b784395d7bb5a499edead0706638ad056d886e56cf8fb " . into ( ) ,
2017-04-03 11:13:51 +02:00
" 00125d85a05e5e63e214cb60fe63f132eec8a103aa29266b7e6e6c5b7597230b " . parse ( ) . unwrap ( ) ) ,
2017-03-13 12:54:56 +01:00
( " 99e82b163b062d55a64085bacfd407bb55f194ba5fb7a1af9c34b84435455520f1372e0e650a4f91aed0058cb823f62146ccb5599c8d13372c300dea866b69fc " . into ( ) ,
2017-04-03 11:13:51 +02:00
" f43ac0fba42a5b6ed95707d2244659e89ba877b1c9b82c0d0a9dcf834e80fc62 " . parse ( ) . unwrap ( ) ) ,
2017-03-13 12:54:56 +01:00
( " 7e05df9dd077ec21ed4bc45c9fe9e0a43d65fa4be540630de615ced5e95cf5c3003035eb713317237d7667feeeb64335525158f5f7411f67aca9645169ea554c " . into ( ) ,
2017-04-03 11:13:51 +02:00
" 5a324938dfb2516800487d25ab7289ba8ec38811f77c3df602e4e65e3c9acd9f " . parse ( ) . unwrap ( ) ) ,
2017-03-13 12:54:56 +01:00
( " 321977760d1d8e15b047a309e4c7fe6f355c10bb5a06c68472b676926427f69f229024fa2692c10da167d14cdc77eb95d0fce68af0a0f704f0d3db36baa83bb2 " . into ( ) ,
2017-04-03 11:13:51 +02:00
" 12cf422d50002d04e52bd4906fd7f5f235f051ca36abfe37e061f8da248008d8 " . parse ( ) . unwrap ( ) ) ,
2017-03-13 12:54:56 +01:00
] ;
let common_point : Public = " 6962be696e1bcbba8e64cc7fddf140f854835354b5804f3bb95ae5a2799130371b589a131bd39699ac7174ccb35fc4342dab05331202209582fc8f3a40916ab0 " . into ( ) ;
let encrypted_point : Public = " b07031982bde9890e12eff154765f03c56c3ab646ad47431db5dd2d742a9297679c4c65b998557f8008469afd0c43d40b6c5f6c6a1c7354875da4115237ed87a " . into ( ) ;
2017-04-03 11:13:51 +02:00
let encrypted_datas : Vec < _ > = ( 0 .. 5 ) . map ( | i | DocumentKeyShare {
2017-07-06 14:02:10 +02:00
author : Public ::default ( ) ,
2017-03-13 12:54:56 +01:00
threshold : 3 ,
2017-11-22 09:09:48 +01:00
public : Default ::default ( ) ,
2017-07-06 14:02:10 +02:00
common_point : Some ( common_point . clone ( ) ) ,
encrypted_point : Some ( encrypted_point . clone ( ) ) ,
2017-11-02 15:33:11 +01:00
versions : vec ! [ DocumentKeyShareVersion {
hash : Default ::default ( ) ,
id_numbers : id_numbers . clone ( ) . into_iter ( ) . collect ( ) ,
secret_share : secret_shares [ i ] . clone ( ) ,
} ] ,
2017-03-13 12:54:56 +01:00
} ) . collect ( ) ;
let acl_storages : Vec < _ > = ( 0 .. 5 ) . map ( | _ | Arc ::new ( DummyAclStorage ::default ( ) ) ) . collect ( ) ;
2017-04-25 21:34:03 +02:00
let clusters : Vec < _ > = ( 0 .. 5 ) . map ( | i | {
let cluster = Arc ::new ( DummyCluster ::new ( id_numbers . iter ( ) . nth ( i ) . clone ( ) . unwrap ( ) . 0 ) ) ;
for id_number in & id_numbers {
cluster . add_node ( id_number . 0. clone ( ) ) ;
}
cluster
} ) . collect ( ) ;
2017-07-06 14:02:10 +02:00
let requester = Random . generate ( ) . unwrap ( ) ;
let signature = Some ( ethkey ::sign ( requester . secret ( ) , & SessionId ::default ( ) ) . unwrap ( ) ) ;
2017-04-03 11:13:51 +02:00
let sessions : Vec < _ > = ( 0 .. 5 ) . map ( | i | SessionImpl ::new ( SessionParams {
2017-07-06 14:02:10 +02:00
meta : SessionMeta {
id : session_id . clone ( ) ,
self_node_id : id_numbers . iter ( ) . nth ( i ) . clone ( ) . unwrap ( ) . 0 ,
master_node_id : id_numbers . iter ( ) . nth ( 0 ) . clone ( ) . unwrap ( ) . 0 ,
threshold : encrypted_datas [ i ] . threshold ,
} ,
2017-03-13 12:54:56 +01:00
access_key : access_key . clone ( ) ,
2017-11-02 15:33:11 +01:00
key_share : Some ( encrypted_datas [ i ] . clone ( ) ) ,
2017-03-13 12:54:56 +01:00
acl_storage : acl_storages [ i ] . clone ( ) ,
2017-09-14 19:29:01 +02:00
cluster : clusters [ i ] . clone ( ) ,
nonce : 0 ,
2017-07-06 14:02:10 +02:00
} , if i = = 0 { signature . clone ( ) } else { None } ) . unwrap ( ) ) . collect ( ) ;
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
( requester , clusters , acl_storages , sessions )
2017-03-13 12:54:56 +01:00
}
2017-07-06 14:02:10 +02:00
fn do_messages_exchange ( clusters : & [ Arc < DummyCluster > ] , sessions : & [ SessionImpl ] ) -> Result < ( ) , Error > {
do_messages_exchange_until ( clusters , sessions , | _ , _ , _ | false )
2017-03-13 12:54:56 +01:00
}
2017-07-06 14:02:10 +02:00
fn do_messages_exchange_until < F > ( clusters : & [ Arc < DummyCluster > ] , sessions : & [ SessionImpl ] , mut cond : F ) -> Result < ( ) , Error > where F : FnMut ( & NodeId , & NodeId , & Message ) -> bool {
2018-02-12 18:05:33 +01:00
let mut queue : VecDeque < ( NodeId , NodeId , Message ) > = VecDeque ::new ( ) ;
while let Some ( ( mut from , mut to , mut message ) ) = clusters . iter ( ) . filter_map ( | c | c . take_message ( ) . map ( | ( to , msg ) | ( c . node ( ) , to , msg ) ) ) . next ( ) {
2017-03-13 12:54:56 +01:00
if cond ( & from , & to , & message ) {
break ;
}
2018-02-12 18:05:33 +01:00
let mut is_queued_message = false ;
loop {
let session = & sessions [ sessions . iter ( ) . position ( | s | s . node ( ) = = & to ) . unwrap ( ) ] ;
match session . on_message ( & from , & message ) {
Ok ( _ ) = > {
if let Some ( qmessage ) = queue . pop_front ( ) {
from = qmessage . 0 ;
to = qmessage . 1 ;
message = qmessage . 2 ;
is_queued_message = true ;
continue ;
}
break ;
} ,
Err ( Error ::TooEarlyForRequest ) = > {
if is_queued_message {
queue . push_front ( ( from , to , message ) ) ;
} else {
queue . push_back ( ( from , to , message ) ) ;
}
break ;
} ,
Err ( err ) = > return Err ( err ) ,
}
2017-03-13 12:54:56 +01:00
}
}
2017-07-06 14:02:10 +02:00
Ok ( ( ) )
2017-03-13 12:54:56 +01:00
}
#[ test ]
2017-04-25 21:34:03 +02:00
fn constructs_in_cluster_of_single_node ( ) {
2017-03-13 12:54:56 +01:00
let mut nodes = BTreeMap ::new ( ) ;
let self_node_id = Random . generate ( ) . unwrap ( ) . public ( ) . clone ( ) ;
nodes . insert ( self_node_id , Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) ) ;
2017-04-03 11:13:51 +02:00
match SessionImpl ::new ( SessionParams {
2017-07-06 14:02:10 +02:00
meta : SessionMeta {
id : SessionId ::default ( ) ,
self_node_id : self_node_id . clone ( ) ,
master_node_id : self_node_id . clone ( ) ,
threshold : 0 ,
} ,
2017-03-13 12:54:56 +01:00
access_key : Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) ,
2017-11-02 15:33:11 +01:00
key_share : Some ( DocumentKeyShare {
2017-07-06 14:02:10 +02:00
author : Public ::default ( ) ,
2017-03-13 12:54:56 +01:00
threshold : 0 ,
2017-11-22 09:09:48 +01:00
public : Default ::default ( ) ,
2017-07-06 14:02:10 +02:00
common_point : Some ( Random . generate ( ) . unwrap ( ) . public ( ) . clone ( ) ) ,
encrypted_point : Some ( Random . generate ( ) . unwrap ( ) . public ( ) . clone ( ) ) ,
2017-11-02 15:33:11 +01:00
versions : vec ! [ DocumentKeyShareVersion {
hash : Default ::default ( ) ,
id_numbers : nodes ,
secret_share : Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) ,
} ] ,
} ) ,
2017-03-13 12:54:56 +01:00
acl_storage : Arc ::new ( DummyAclStorage ::default ( ) ) ,
cluster : Arc ::new ( DummyCluster ::new ( self_node_id . clone ( ) ) ) ,
2017-09-14 19:29:01 +02:00
nonce : 0 ,
2017-07-06 14:02:10 +02:00
} , Some ( ethkey ::sign ( Random . generate ( ) . unwrap ( ) . secret ( ) , & SessionId ::default ( ) ) . unwrap ( ) ) ) {
2017-04-25 21:34:03 +02:00
Ok ( _ ) = > ( ) ,
2017-03-13 12:54:56 +01:00
_ = > panic! ( " unexpected " ) ,
}
}
#[ test ]
2017-11-02 15:33:11 +01:00
fn fails_to_initialize_if_does_not_have_a_share ( ) {
2017-03-13 12:54:56 +01:00
let self_node_id = Random . generate ( ) . unwrap ( ) . public ( ) . clone ( ) ;
2017-11-02 15:33:11 +01:00
let session = SessionImpl ::new ( SessionParams {
2017-07-06 14:02:10 +02:00
meta : SessionMeta {
id : SessionId ::default ( ) ,
self_node_id : self_node_id . clone ( ) ,
master_node_id : self_node_id . clone ( ) ,
threshold : 0 ,
} ,
2017-03-13 12:54:56 +01:00
access_key : Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) ,
2017-11-02 15:33:11 +01:00
key_share : None ,
2017-03-13 12:54:56 +01:00
acl_storage : Arc ::new ( DummyAclStorage ::default ( ) ) ,
cluster : Arc ::new ( DummyCluster ::new ( self_node_id . clone ( ) ) ) ,
2017-09-14 19:29:01 +02:00
nonce : 0 ,
2017-11-02 15:33:11 +01:00
} , Some ( ethkey ::sign ( Random . generate ( ) . unwrap ( ) . secret ( ) , & SessionId ::default ( ) ) . unwrap ( ) ) ) . unwrap ( ) ;
2018-02-12 18:05:33 +01:00
assert_eq! ( session . initialize ( Default ::default ( ) , false , false ) , Err ( Error ::InvalidMessage ) ) ;
2017-03-13 12:54:56 +01:00
}
#[ test ]
2017-11-02 15:33:11 +01:00
fn fails_to_initialize_if_threshold_is_wrong ( ) {
2017-03-13 12:54:56 +01:00
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 ( ) ) ;
nodes . insert ( Random . generate ( ) . unwrap ( ) . public ( ) . clone ( ) , Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) ) ;
2017-11-02 15:33:11 +01:00
let session = SessionImpl ::new ( SessionParams {
2017-07-06 14:02:10 +02:00
meta : SessionMeta {
id : SessionId ::default ( ) ,
self_node_id : self_node_id . clone ( ) ,
master_node_id : self_node_id . clone ( ) ,
threshold : 2 ,
} ,
2017-03-13 12:54:56 +01:00
access_key : Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) ,
2017-11-02 15:33:11 +01:00
key_share : Some ( DocumentKeyShare {
2017-07-06 14:02:10 +02:00
author : Public ::default ( ) ,
2017-03-13 12:54:56 +01:00
threshold : 2 ,
2017-11-22 09:09:48 +01:00
public : Default ::default ( ) ,
2017-07-06 14:02:10 +02:00
common_point : Some ( Random . generate ( ) . unwrap ( ) . public ( ) . clone ( ) ) ,
encrypted_point : Some ( Random . generate ( ) . unwrap ( ) . public ( ) . clone ( ) ) ,
2017-11-02 15:33:11 +01:00
versions : vec ! [ DocumentKeyShareVersion {
hash : Default ::default ( ) ,
id_numbers : nodes ,
secret_share : Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) ,
} ] ,
} ) ,
2017-03-13 12:54:56 +01:00
acl_storage : Arc ::new ( DummyAclStorage ::default ( ) ) ,
cluster : Arc ::new ( DummyCluster ::new ( self_node_id . clone ( ) ) ) ,
2017-09-14 19:29:01 +02:00
nonce : 0 ,
2017-11-02 15:33:11 +01:00
} , Some ( ethkey ::sign ( Random . generate ( ) . unwrap ( ) . secret ( ) , & SessionId ::default ( ) ) . unwrap ( ) ) ) . unwrap ( ) ;
2018-02-12 18:05:33 +01:00
assert_eq! ( session . initialize ( Default ::default ( ) , false , false ) , Err ( Error ::ConsensusUnreachable ) ) ;
2017-03-13 12:54:56 +01:00
}
#[ test ]
fn fails_to_initialize_when_already_initialized ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , _ , _ , sessions ) = prepare_decryption_sessions ( ) ;
2018-02-12 18:05:33 +01:00
assert_eq! ( sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) , ( ) ) ;
assert_eq! ( sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap_err ( ) , Error ::InvalidStateForRequest ) ;
2017-03-13 12:54:56 +01:00
}
#[ test ]
fn fails_to_accept_initialization_when_already_initialized ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , _ , _ , sessions ) = prepare_decryption_sessions ( ) ;
2018-02-12 18:05:33 +01:00
assert_eq! ( sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) , ( ) ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 0 ] . on_consensus_message ( sessions [ 1 ] . node ( ) , & message ::DecryptionConsensusMessage {
session : SessionId ::default ( ) . into ( ) ,
sub_session : sessions [ 0 ] . access_key ( ) . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : 0 ,
2017-07-06 14:02:10 +02:00
message : message ::ConsensusMessage ::InitializeConsensusSession ( message ::InitializeConsensusSession {
requestor_signature : ethkey ::sign ( Random . generate ( ) . unwrap ( ) . secret ( ) , & SessionId ::default ( ) ) . unwrap ( ) . into ( ) ,
2017-11-02 15:33:11 +01:00
version : Default ::default ( ) ,
2017-07-06 14:02:10 +02:00
} ) ,
} ) . unwrap_err ( ) , Error ::InvalidMessage ) ;
2017-03-13 12:54:56 +01:00
}
#[ test ]
fn fails_to_partial_decrypt_if_requested_by_slave ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , _ , _ , sessions ) = prepare_decryption_sessions ( ) ;
assert_eq! ( sessions [ 1 ] . on_consensus_message ( sessions [ 0 ] . node ( ) , & message ::DecryptionConsensusMessage {
session : SessionId ::default ( ) . into ( ) ,
sub_session : sessions [ 0 ] . access_key ( ) . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : 0 ,
2017-07-06 14:02:10 +02:00
message : message ::ConsensusMessage ::InitializeConsensusSession ( message ::InitializeConsensusSession {
requestor_signature : ethkey ::sign ( Random . generate ( ) . unwrap ( ) . secret ( ) , & SessionId ::default ( ) ) . unwrap ( ) . into ( ) ,
2017-11-02 15:33:11 +01:00
version : Default ::default ( ) ,
2017-07-06 14:02:10 +02:00
} ) ,
2017-03-13 12:54:56 +01:00
} ) . unwrap ( ) , ( ) ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 1 ] . on_partial_decryption_requested ( sessions [ 2 ] . node ( ) , & message ::RequestPartialDecryption {
2017-04-03 11:13:51 +02:00
session : SessionId ::default ( ) . into ( ) ,
sub_session : sessions [ 0 ] . access_key ( ) . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : 0 ,
2017-07-06 14:02:10 +02:00
request_id : Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) . into ( ) ,
is_shadow_decryption : false ,
2018-02-12 18:05:33 +01:00
is_broadcast_session : false ,
2017-04-03 11:13:51 +02:00
nodes : sessions . iter ( ) . map ( | s | s . node ( ) . clone ( ) . into ( ) ) . take ( 4 ) . collect ( ) ,
2017-03-13 12:54:56 +01:00
} ) . unwrap_err ( ) , Error ::InvalidMessage ) ;
}
#[ test ]
fn fails_to_partial_decrypt_if_wrong_number_of_nodes_participating ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , _ , _ , sessions ) = prepare_decryption_sessions ( ) ;
assert_eq! ( sessions [ 1 ] . on_consensus_message ( sessions [ 0 ] . node ( ) , & message ::DecryptionConsensusMessage {
session : SessionId ::default ( ) . into ( ) ,
sub_session : sessions [ 0 ] . access_key ( ) . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : 0 ,
2017-07-06 14:02:10 +02:00
message : message ::ConsensusMessage ::InitializeConsensusSession ( message ::InitializeConsensusSession {
requestor_signature : ethkey ::sign ( Random . generate ( ) . unwrap ( ) . secret ( ) , & SessionId ::default ( ) ) . unwrap ( ) . into ( ) ,
2017-11-02 15:33:11 +01:00
version : Default ::default ( ) ,
2017-07-06 14:02:10 +02:00
} ) ,
2017-03-13 12:54:56 +01:00
} ) . unwrap ( ) , ( ) ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 1 ] . on_partial_decryption_requested ( sessions [ 0 ] . node ( ) , & message ::RequestPartialDecryption {
2017-04-03 11:13:51 +02:00
session : SessionId ::default ( ) . into ( ) ,
sub_session : sessions [ 0 ] . access_key ( ) . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : 0 ,
2017-07-06 14:02:10 +02:00
request_id : Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) . into ( ) ,
is_shadow_decryption : false ,
2018-02-12 18:05:33 +01:00
is_broadcast_session : false ,
2017-04-03 11:13:51 +02:00
nodes : sessions . iter ( ) . map ( | s | s . node ( ) . clone ( ) . into ( ) ) . take ( 2 ) . collect ( ) ,
2017-03-13 12:54:56 +01:00
} ) . unwrap_err ( ) , Error ::InvalidMessage ) ;
}
#[ test ]
fn fails_to_accept_partial_decrypt_if_not_waiting ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , _ , _ , sessions ) = prepare_decryption_sessions ( ) ;
assert_eq! ( sessions [ 0 ] . on_partial_decryption ( sessions [ 1 ] . node ( ) , & message ::PartialDecryption {
2017-04-03 11:13:51 +02:00
session : SessionId ::default ( ) . into ( ) ,
sub_session : sessions [ 0 ] . access_key ( ) . clone ( ) . into ( ) ,
2017-09-14 19:29:01 +02:00
session_nonce : 0 ,
2017-07-06 14:02:10 +02:00
request_id : Random . generate ( ) . unwrap ( ) . secret ( ) . clone ( ) . into ( ) ,
2017-04-03 11:13:51 +02:00
shadow_point : Random . generate ( ) . unwrap ( ) . public ( ) . clone ( ) . into ( ) ,
2017-04-08 11:26:16 +02:00
decrypt_shadow : None ,
2017-03-13 12:54:56 +01:00
} ) . unwrap_err ( ) , Error ::InvalidStateForRequest ) ;
}
#[ test ]
fn fails_to_accept_partial_decrypt_twice ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-03-13 12:54:56 +01:00
let mut pd_from = None ;
let mut pd_msg = None ;
do_messages_exchange_until ( & clusters , & sessions , | from , _ , msg | match msg {
2017-04-03 11:13:51 +02:00
& Message ::Decryption ( DecryptionMessage ::PartialDecryption ( ref msg ) ) = > {
2017-03-13 12:54:56 +01:00
pd_from = Some ( from . clone ( ) ) ;
pd_msg = Some ( msg . clone ( ) ) ;
true
} ,
_ = > false ,
2017-07-06 14:02:10 +02:00
} ) . unwrap ( ) ;
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 0 ] . on_partial_decryption ( pd_from . as_ref ( ) . unwrap ( ) , & pd_msg . clone ( ) . unwrap ( ) ) . unwrap ( ) , ( ) ) ;
assert_eq! ( sessions [ 0 ] . on_partial_decryption ( pd_from . as_ref ( ) . unwrap ( ) , & pd_msg . unwrap ( ) ) . unwrap_err ( ) , Error ::InvalidNodeForRequest ) ;
2017-03-13 12:54:56 +01:00
}
2017-04-25 21:34:03 +02:00
#[ test ]
fn decryption_fails_on_session_timeout ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , _ , _ , sessions ) = prepare_decryption_sessions ( ) ;
2017-04-25 21:34:03 +02:00
assert! ( sessions [ 0 ] . decrypted_secret ( ) . is_none ( ) ) ;
sessions [ 0 ] . on_session_timeout ( ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 0 ] . decrypted_secret ( ) . unwrap ( ) . unwrap_err ( ) , Error ::ConsensusUnreachable ) ;
2017-04-25 21:34:03 +02:00
}
#[ test ]
fn node_is_marked_rejected_when_timed_out_during_initialization_confirmation ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , _ , _ , sessions ) = prepare_decryption_sessions ( ) ;
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
// 1 node disconnects => we still can recover secret
sessions [ 0 ] . on_node_timeout ( sessions [ 1 ] . node ( ) ) ;
2017-07-06 14:02:10 +02:00
assert! ( sessions [ 0 ] . data . lock ( ) . consensus_session . consensus_job ( ) . rejects ( ) . contains ( sessions [ 1 ] . node ( ) ) ) ;
assert! ( sessions [ 0 ] . state ( ) = = ConsensusSessionState ::EstablishingConsensus ) ;
2017-04-25 21:34:03 +02:00
// 2 node are disconnected => we can not recover secret
sessions [ 0 ] . on_node_timeout ( sessions [ 2 ] . node ( ) ) ;
2017-07-06 14:02:10 +02:00
assert! ( sessions [ 0 ] . state ( ) = = ConsensusSessionState ::Failed ) ;
2017-04-25 21:34:03 +02:00
}
#[ test ]
fn session_does_not_fail_if_rejected_node_disconnects ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , clusters , acl_storages , sessions ) = prepare_decryption_sessions ( ) ;
2017-04-25 21:34:03 +02:00
let key_pair = Random . generate ( ) . unwrap ( ) ;
acl_storages [ 1 ] . prohibit ( key_pair . public ( ) . clone ( ) , SessionId ::default ( ) ) ;
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
do_messages_exchange_until ( & clusters , & sessions , | _ , _ , _ | sessions [ 0 ] . state ( ) = = ConsensusSessionState ::WaitingForPartialResults ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
// 1st node disconnects => ignore this
sessions [ 0 ] . on_node_timeout ( sessions [ 1 ] . node ( ) ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 0 ] . state ( ) , ConsensusSessionState ::EstablishingConsensus ) ;
2017-04-25 21:34:03 +02:00
}
#[ test ]
fn session_does_not_fail_if_requested_node_disconnects ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
do_messages_exchange_until ( & clusters , & sessions , | _ , _ , _ | sessions [ 0 ] . state ( ) = = ConsensusSessionState ::WaitingForPartialResults ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
// 1 node disconnects => we still can recover secret
sessions [ 0 ] . on_node_timeout ( sessions [ 1 ] . node ( ) ) ;
2017-07-06 14:02:10 +02:00
assert! ( sessions [ 0 ] . state ( ) = = ConsensusSessionState ::EstablishingConsensus ) ;
2017-04-25 21:34:03 +02:00
// 2 node are disconnected => we can not recover secret
sessions [ 0 ] . on_node_timeout ( sessions [ 2 ] . node ( ) ) ;
2017-07-06 14:02:10 +02:00
assert! ( sessions [ 0 ] . state ( ) = = ConsensusSessionState ::Failed ) ;
2017-04-25 21:34:03 +02:00
}
#[ test ]
fn session_does_not_fail_if_node_with_shadow_point_disconnects ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
do_messages_exchange_until ( & clusters , & sessions , | _ , _ , _ | sessions [ 0 ] . state ( ) = = ConsensusSessionState ::WaitingForPartialResults
& & sessions [ 0 ] . data . lock ( ) . consensus_session . computation_job ( ) . responses ( ) . len ( ) = = 2 ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
// disconnects from the node which has already sent us its own shadow point
let disconnected = sessions [ 0 ] . data . lock ( ) .
2017-07-06 14:02:10 +02:00
consensus_session . computation_job ( ) . responses ( ) . keys ( )
2017-04-25 21:34:03 +02:00
. filter ( | n | * n ! = sessions [ 0 ] . node ( ) )
. cloned ( ) . nth ( 0 ) . unwrap ( ) ;
sessions [ 0 ] . on_node_timeout ( & disconnected ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 0 ] . state ( ) , ConsensusSessionState ::EstablishingConsensus ) ;
2017-04-25 21:34:03 +02:00
}
#[ test ]
fn session_restarts_if_confirmed_node_disconnects ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
do_messages_exchange_until ( & clusters , & sessions , | _ , _ , _ | sessions [ 0 ] . state ( ) = = ConsensusSessionState ::WaitingForPartialResults ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
// disconnects from the node which has already confirmed its participation
2017-07-06 14:02:10 +02:00
let disconnected = sessions [ 0 ] . data . lock ( ) . consensus_session . computation_job ( ) . requests ( ) . iter ( ) . cloned ( ) . nth ( 0 ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
sessions [ 0 ] . on_node_timeout ( & disconnected ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 0 ] . state ( ) , ConsensusSessionState ::EstablishingConsensus ) ;
assert! ( sessions [ 0 ] . data . lock ( ) . consensus_session . computation_job ( ) . rejects ( ) . contains ( & disconnected ) ) ;
assert! ( ! sessions [ 0 ] . data . lock ( ) . consensus_session . computation_job ( ) . requests ( ) . contains ( & disconnected ) ) ;
2017-04-25 21:34:03 +02:00
}
#[ test ]
fn session_does_not_fail_if_non_master_node_disconnects_from_non_master_node ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
do_messages_exchange_until ( & clusters , & sessions , | _ , _ , _ | sessions [ 0 ] . state ( ) = = ConsensusSessionState ::WaitingForPartialResults ) . unwrap ( ) ;
2017-04-25 21:34:03 +02:00
// disconnects from the node which has already confirmed its participation
sessions [ 1 ] . on_node_timeout ( sessions [ 2 ] . node ( ) ) ;
2017-07-06 14:02:10 +02:00
assert! ( sessions [ 0 ] . state ( ) = = ConsensusSessionState ::WaitingForPartialResults ) ;
assert! ( sessions [ 1 ] . state ( ) = = ConsensusSessionState ::ConsensusEstablished ) ;
2017-04-25 21:34:03 +02:00
}
2017-03-13 12:54:56 +01:00
#[ test ]
fn complete_dec_session ( ) {
2017-07-06 14:02:10 +02:00
let ( _ , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
2017-03-13 12:54:56 +01:00
// now let's try to do a decryption
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-04-08 11:26:16 +02:00
2017-07-06 14:02:10 +02:00
do_messages_exchange ( & clusters , & sessions ) . unwrap ( ) ;
2017-04-08 11:26:16 +02:00
// now check that:
2017-04-25 21:34:03 +02:00
// 1) 5 of 5 sessions are in Finished state
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions . iter ( ) . filter ( | s | s . state ( ) = = ConsensusSessionState ::Finished ) . count ( ) , 5 ) ;
2017-04-25 21:34:03 +02:00
// 2) 1 session has decrypted key value
2017-04-08 11:26:16 +02:00
assert! ( sessions . iter ( ) . skip ( 1 ) . all ( | s | s . decrypted_secret ( ) . is_none ( ) ) ) ;
2017-04-25 21:34:03 +02:00
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 0 ] . decrypted_secret ( ) . unwrap ( ) . unwrap ( ) , EncryptedDocumentKeyShadow {
2017-04-08 11:26:16 +02:00
decrypted_secret : SECRET_PLAIN . into ( ) ,
common_point : None ,
decrypt_shadows : None ,
2017-04-25 21:34:03 +02:00
} ) ;
2017-04-08 11:26:16 +02:00
}
#[ test ]
fn complete_shadow_dec_session ( ) {
2017-07-06 14:02:10 +02:00
let ( key_pair , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
2017-04-08 11:26:16 +02:00
// now let's try to do a decryption
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , true , false ) . unwrap ( ) ;
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
do_messages_exchange ( & clusters , & sessions ) . unwrap ( ) ;
2017-03-13 12:54:56 +01:00
// now check that:
2017-04-25 21:34:03 +02:00
// 1) 5 of 5 sessions are in Finished state
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions . iter ( ) . filter ( | s | s . state ( ) = = ConsensusSessionState ::Finished ) . count ( ) , 5 ) ;
2017-04-25 21:34:03 +02:00
// 2) 1 session has decrypted key value
2017-03-13 12:54:56 +01:00
assert! ( sessions . iter ( ) . skip ( 1 ) . all ( | s | s . decrypted_secret ( ) . is_none ( ) ) ) ;
2017-04-08 11:26:16 +02:00
2017-04-25 21:34:03 +02:00
let decrypted_secret = sessions [ 0 ] . decrypted_secret ( ) . unwrap ( ) . unwrap ( ) ;
2017-04-08 11:26:16 +02:00
// check that decrypted_secret != SECRET_PLAIN
assert! ( decrypted_secret . decrypted_secret ! = SECRET_PLAIN . into ( ) ) ;
// check that common point && shadow coefficients are returned
assert! ( decrypted_secret . common_point . is_some ( ) ) ;
assert! ( decrypted_secret . decrypt_shadows . is_some ( ) ) ;
// check that KS client is able to restore original secret
2017-05-05 15:57:29 +02:00
use ethcrypto ::DEFAULT_MAC ;
use ethcrypto ::ecies ::decrypt ;
2017-04-08 11:26:16 +02:00
let decrypt_shadows : Vec < _ > = decrypted_secret . decrypt_shadows . unwrap ( ) . into_iter ( )
2017-05-19 17:06:36 +02:00
. map ( | c | Secret ::from_slice ( & decrypt ( key_pair . secret ( ) , & DEFAULT_MAC , & c ) . unwrap ( ) ) )
2017-04-08 11:26:16 +02:00
. collect ( ) ;
let decrypted_secret = math ::decrypt_with_shadow_coefficients ( decrypted_secret . decrypted_secret , decrypted_secret . common_point . unwrap ( ) , decrypt_shadows ) . unwrap ( ) ;
assert_eq! ( decrypted_secret , SECRET_PLAIN . into ( ) ) ;
2017-03-13 12:54:56 +01:00
}
#[ test ]
fn failed_dec_session ( ) {
2017-07-06 14:02:10 +02:00
let ( key_pair , clusters , acl_storages , sessions ) = prepare_decryption_sessions ( ) ;
2017-03-13 12:54:56 +01:00
// now let's try to do a decryption
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-03-13 12:54:56 +01:00
// we need 4 out of 5 nodes to agree to do a decryption
// let's say that 2 of these nodes are disagree
acl_storages [ 1 ] . prohibit ( key_pair . public ( ) . clone ( ) , SessionId ::default ( ) ) ;
acl_storages [ 2 ] . prohibit ( key_pair . public ( ) . clone ( ) , SessionId ::default ( ) ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( do_messages_exchange ( & clusters , & sessions ) . unwrap_err ( ) , Error ::ConsensusUnreachable ) ;
2017-03-13 12:54:56 +01:00
2017-07-06 14:02:10 +02:00
// check that 3 nodes have failed state
assert_eq! ( sessions [ 0 ] . state ( ) , ConsensusSessionState ::Failed ) ;
assert_eq! ( sessions . iter ( ) . filter ( | s | s . state ( ) = = ConsensusSessionState ::Failed ) . count ( ) , 3 ) ;
2017-03-13 12:54:56 +01:00
}
2017-04-03 11:13:51 +02:00
2017-04-08 11:26:16 +02:00
#[ test ]
fn complete_dec_session_with_acl_check_failed_on_master ( ) {
2017-07-06 14:02:10 +02:00
let ( key_pair , clusters , acl_storages , sessions ) = prepare_decryption_sessions ( ) ;
2017-04-08 11:26:16 +02:00
// we need 4 out of 5 nodes to agree to do a decryption
// let's say that 1 of these nodes (master) is disagree
acl_storages [ 0 ] . prohibit ( key_pair . public ( ) . clone ( ) , SessionId ::default ( ) ) ;
// now let's try to do a decryption
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-04-08 11:26:16 +02:00
2017-07-06 14:02:10 +02:00
do_messages_exchange ( & clusters , & sessions ) . unwrap ( ) ;
2017-04-08 11:26:16 +02:00
// now check that:
// 1) 4 of 5 sessions are in Finished state
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions . iter ( ) . filter ( | s | s . state ( ) = = ConsensusSessionState ::Finished ) . count ( ) , 5 ) ;
2017-04-08 11:26:16 +02:00
// 2) 1 session has decrypted key value
assert! ( sessions . iter ( ) . skip ( 1 ) . all ( | s | s . decrypted_secret ( ) . is_none ( ) ) ) ;
2017-07-06 14:02:10 +02:00
assert_eq! ( sessions [ 0 ] . decrypted_secret ( ) . unwrap ( ) . unwrap ( ) , EncryptedDocumentKeyShadow {
2017-04-08 11:26:16 +02:00
decrypted_secret : SECRET_PLAIN . into ( ) ,
common_point : None ,
decrypt_shadows : None ,
2017-04-25 21:34:03 +02:00
} ) ;
2017-04-08 11:26:16 +02:00
}
2017-04-03 11:13:51 +02:00
#[ test ]
2017-09-14 19:29:01 +02:00
fn decryption_message_fails_when_nonce_is_wrong ( ) {
let ( _ , _ , _ , sessions ) = prepare_decryption_sessions ( ) ;
assert_eq! ( sessions [ 1 ] . process_message ( sessions [ 0 ] . node ( ) , & message ::DecryptionMessage ::DecryptionSessionCompleted (
message ::DecryptionSessionCompleted {
session : SessionId ::default ( ) . into ( ) ,
sub_session : sessions [ 0 ] . access_key ( ) . clone ( ) . into ( ) ,
session_nonce : 10 ,
}
) ) , Err ( Error ::ReplayProtection ) ) ;
2017-04-03 11:13:51 +02:00
}
2017-11-02 15:33:11 +01:00
#[ test ]
fn decryption_works_when_delegated_to_other_node ( ) {
let ( _ , clusters , _ , mut sessions ) = prepare_decryption_sessions ( ) ;
// let's say node1 doesn't have a share && delegates decryption request to node0
// initially session is created on node1 => node1 is master for itself, but for other nodes node0 is still master
sessions [ 1 ] . core . meta . master_node_id = sessions [ 1 ] . core . meta . self_node_id . clone ( ) ;
sessions [ 1 ] . data . lock ( ) . consensus_session . consensus_job_mut ( ) . executor_mut ( ) . set_requester_signature (
sessions [ 0 ] . data . lock ( ) . consensus_session . consensus_job ( ) . executor ( ) . requester_signature ( ) . unwrap ( ) . clone ( )
) ;
// now let's try to do a decryption
2018-02-12 18:05:33 +01:00
sessions [ 1 ] . delegate ( sessions [ 0 ] . core . meta . self_node_id . clone ( ) , Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-11-02 15:33:11 +01:00
do_messages_exchange ( & clusters , & sessions ) . unwrap ( ) ;
// now check that:
// 1) 4 of 5 sessions are in Finished state
2017-11-16 17:34:23 +01:00
assert_eq! ( sessions . iter ( ) . filter ( | s | s . state ( ) = = ConsensusSessionState ::Finished ) . count ( ) , 4 ) ;
2017-11-02 15:33:11 +01:00
// 2) 1 session has decrypted key value
assert_eq! ( sessions [ 1 ] . decrypted_secret ( ) . unwrap ( ) . unwrap ( ) , EncryptedDocumentKeyShadow {
decrypted_secret : SECRET_PLAIN . into ( ) ,
common_point : None ,
decrypt_shadows : None ,
} ) ;
}
#[ test ]
fn decryption_works_when_share_owners_are_isolated ( ) {
let ( _ , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
// we need 4 out of 5 nodes to agree to do a decryption
// let's say that 1 of these nodes (master) is isolated
let isolated_node_id = sessions [ 4 ] . core . meta . self_node_id . clone ( ) ;
for cluster in & clusters {
cluster . remove_node ( & isolated_node_id ) ;
}
// now let's try to do a decryption
2018-02-12 18:05:33 +01:00
sessions [ 0 ] . initialize ( Default ::default ( ) , false , false ) . unwrap ( ) ;
2017-11-02 15:33:11 +01:00
do_messages_exchange ( & clusters , & sessions ) . unwrap ( ) ;
assert_eq! ( sessions [ 0 ] . decrypted_secret ( ) . unwrap ( ) . unwrap ( ) , EncryptedDocumentKeyShadow {
decrypted_secret : SECRET_PLAIN . into ( ) ,
common_point : None ,
decrypt_shadows : None ,
} ) ;
}
2018-02-12 18:05:33 +01:00
#[ test ]
fn decryption_result_restored_on_all_nodes_if_broadcast_session_is_completed ( ) {
let ( _ , clusters , _ , sessions ) = prepare_decryption_sessions ( ) ;
sessions [ 0 ] . initialize ( Default ::default ( ) , false , true ) . unwrap ( ) ;
do_messages_exchange ( & clusters , & sessions ) . unwrap ( ) ;
// decryption result must be the same and available on 4 nodes
let result = sessions [ 0 ] . decrypted_secret ( ) ;
assert! ( result . clone ( ) . unwrap ( ) . is_ok ( ) ) ;
assert_eq! ( 3 , sessions . iter ( ) . skip ( 1 ) . filter ( | s | s . decrypted_secret ( ) = = result ) . count ( ) ) ;
assert_eq! ( 1 , sessions . iter ( ) . skip ( 1 ) . filter ( | s | s . decrypted_secret ( ) . is_none ( ) ) . count ( ) ) ;
}
2017-03-13 12:54:56 +01:00
}