11// @todo: remove this
22#![ allow( dead_code) ]
3- use mithril_aggregator:: entities;
43
54use ark_bls12_377:: Bls12_377 ;
5+ use hex:: { FromHex , ToHex } ;
6+ use std:: io:: Cursor ;
7+ use thiserror:: Error ;
8+
69use mithril:: key_reg:: KeyReg ;
710use mithril:: merkle_tree:: MTHashLeaf ;
811use mithril:: mithril_proof:: concat_proofs:: { ConcatProof , TrivialEnv } ;
@@ -11,7 +14,7 @@ use mithril::stm::{
1114 Index , MTValue , PartyId , Stake , StmClerk , StmInitializer , StmMultiSig , StmParameters , StmSig ,
1215 StmSigner ,
1316} ;
14- use thiserror :: Error ;
17+ use mithril_aggregator :: entities ;
1518
1619pub type Bytes = Vec < u8 > ;
1720
@@ -36,6 +39,9 @@ pub type ProtocolSignerSecretKey = MspSk<Bls12_377>;
3639use mithril_aggregator:: entities:: { SignerWithStake , SingleSignature } ;
3740#[ cfg( test) ]
3841use mockall:: automock;
42+ use rand_chacha:: ChaCha20Rng ;
43+ use rand_core:: SeedableRng ;
44+ use slog_scope:: { trace, warn} ;
3945
4046#[ cfg_attr( test, automock) ]
4147pub trait SingleSigner {
@@ -49,38 +55,161 @@ pub trait SingleSigner {
4955
5056#[ derive( Error , Debug , PartialEq ) ]
5157pub enum SingleSignerError {
52- #[ error( "the signer is not registered in the stake distribution" ) ]
58+ #[ error( "the signer verification key is not registered in the stake distribution" ) ]
5359 UnregisteredVerificationKey ( ) ,
60+
61+ #[ error( "the signer party id is not registered in the stake distribution" ) ]
62+ UnregisteredPartyId ( ) ,
63+
64+ #[ error( "the protocol signer creation failed: `{0}`" ) ]
65+ ProtocolSignerCreationFailure ( String ) ,
5466}
5567
56- pub struct MithrilSingleSigner { }
68+ pub struct MithrilSingleSigner {
69+ party_id : u64 ,
70+ secret_key : ProtocolSignerSecretKey ,
71+ }
5772
5873impl MithrilSingleSigner {
59- pub fn new ( ) -> Self {
60- Self { }
74+ pub fn new ( party_id : u64 , secret_key : ProtocolSignerSecretKey ) -> Self {
75+ Self {
76+ party_id,
77+ secret_key,
78+ }
79+ }
80+
81+ pub fn create_protocol_signer (
82+ & self ,
83+ current_player_stake : ProtocolStake ,
84+ stake_distribution : & [ SignerWithStake ] , // @todo : use a hmap to prevent party id duplication
85+ protocol_parameters : & entities:: ProtocolParameters ,
86+ ) -> Result < ProtocolSigner , String > {
87+ let players = stake_distribution
88+ . iter ( )
89+ . map ( |s| ( s. party_id as ProtocolPartyId , s. stake as ProtocolStake ) )
90+ . collect :: < Vec < _ > > ( ) ;
91+ let protocol_parameters = ProtocolParameters {
92+ k : protocol_parameters. k ,
93+ m : protocol_parameters. m ,
94+ phi_f : protocol_parameters. phi_f as f64 ,
95+ } ;
96+
97+ let mut key_reg = KeyReg :: new ( & players) ;
98+ for s in stake_distribution {
99+ let decoded_key = key_decode_hex ( & s. verification_key ) ?;
100+ key_reg
101+ . register ( s. party_id as ProtocolPartyId , decoded_key)
102+ . unwrap ( ) ;
103+ }
104+ let closed_reg = key_reg. close ( ) ;
105+
106+ let seed = [ 0u8 ; 32 ] ;
107+ let mut rng = ChaCha20Rng :: from_seed ( seed) ;
108+ let mut initializer = StmInitializer :: setup (
109+ protocol_parameters,
110+ self . party_id as ProtocolPartyId ,
111+ current_player_stake,
112+ & mut rng,
113+ ) ;
114+ initializer. set_key ( & self . secret_key ) ;
115+
116+ Ok ( initializer. new_signer ( closed_reg) )
61117 }
62118}
63119
64120impl SingleSigner for MithrilSingleSigner {
65121 fn compute_single_signatures (
66122 & self ,
67- _message : Bytes ,
68- _stake_distribution : Vec < SignerWithStake > ,
69- _protocol_parameters : & entities:: ProtocolParameters ,
123+ message : Bytes ,
124+ stake_distribution : Vec < SignerWithStake > , // @todo : use a hmap to prevent party id duplication
125+ protocol_parameters : & entities:: ProtocolParameters ,
70126 ) -> Result < Vec < SingleSignature > , SingleSignerError > {
71- Err ( SingleSignerError :: UnregisteredVerificationKey ( ) )
127+ let current_signer_with_stake = stake_distribution
128+ . iter ( )
129+ . find ( |s| s. party_id == self . party_id )
130+ . ok_or ( SingleSignerError :: UnregisteredPartyId ( ) ) ?;
131+
132+ if current_signer_with_stake. verification_key . is_empty ( ) {
133+ return Err ( SingleSignerError :: UnregisteredVerificationKey ( ) ) ;
134+ }
135+
136+ let protocol_signer = self
137+ . create_protocol_signer (
138+ current_signer_with_stake. stake ,
139+ & stake_distribution,
140+ protocol_parameters,
141+ )
142+ . map_err ( SingleSignerError :: ProtocolSignerCreationFailure ) ?;
143+
144+ trace ! (
145+ "Party #{}: sign message {}" ,
146+ self . party_id,
147+ message. encode_hex:: <String >( )
148+ ) ;
149+
150+ let mut signatures = Vec :: new ( ) ;
151+ for i in 1 ..=protocol_parameters. m {
152+ if let Some ( signature) = protocol_signer. sign ( & message, i) {
153+ trace ! ( "Party #{}: lottery #{} won" , self . party_id, i, ) ;
154+ let encoded_signature = key_encode_hex ( signature) ;
155+
156+ if encoded_signature. is_err ( ) {
157+ warn ! ( "couldn't compute signature: `{:?}`" , encoded_signature) ; // @todo: structured log
158+ continue ;
159+ }
160+
161+ signatures. push ( SingleSignature :: new (
162+ self . party_id ,
163+ i,
164+ encoded_signature. unwrap ( ) ,
165+ ) ) ;
166+ }
167+ }
168+ Ok ( signatures)
72169 }
73170}
74171
172+ /// Encode key to hex helper
173+ pub fn key_encode_hex < T : ark_ff:: ToBytes > ( from : T ) -> Result < String , String > {
174+ Ok ( ark_ff:: to_bytes!( from)
175+ . map_err ( |e| format ! ( "can't convert to hex: {}" , e) ) ?
176+ . encode_hex :: < String > ( ) )
177+ }
178+
179+ /// Decode key from hex helper
180+ pub fn key_decode_hex < T : ark_ff:: FromBytes > ( from : & str ) -> Result < T , String > {
181+ ark_ff:: FromBytes :: read ( Cursor :: new (
182+ Vec :: from_hex ( from) . map_err ( |e| format ! ( "can't parse from hex: {}" , e) ) ?,
183+ ) )
184+ . map_err ( |e| format ! ( "can't convert to bytes: {}" , e) )
185+ }
186+
75187#[ cfg( test) ]
76188mod tests {
77189 use super :: * ;
78190 use mithril_aggregator:: fake_data;
79191
80192 #[ test]
81193 fn cant_compute_if_signer_verification_key_is_not_registered ( ) {
82- let single_signer = MithrilSingleSigner :: new ( ) ;
83- let stake_distribution = fake_data:: signers_with_stakes ( 5 ) ;
194+ let signer_with_keys = fake_data:: signer_keys ( 0 ) . unwrap ( ) ;
195+ let single_signer = MithrilSingleSigner :: new (
196+ signer_with_keys. party_id ,
197+ key_decode_hex ( & signer_with_keys. secret_key ) . unwrap ( ) ,
198+ ) ;
199+ let stake_distribution = fake_data:: signers_with_stakes ( 5 )
200+ . into_iter ( )
201+ . map ( |s| {
202+ if s. party_id == signer_with_keys. party_id {
203+ SignerWithStake {
204+ party_id : s. party_id ,
205+ verification_key : "" . to_string ( ) ,
206+ stake : s. stake ,
207+ }
208+ } else {
209+ s
210+ }
211+ } )
212+ . collect ( ) ;
84213 let protocol_parameters = fake_data:: protocol_parameters ( ) ;
85214
86215 let sign_result = single_signer. compute_single_signatures (
@@ -94,4 +223,40 @@ mod tests {
94223 sign_result. unwrap_err( )
95224 )
96225 }
226+
227+ #[ test]
228+ fn should_produce_a_single_signature ( ) {
229+ let signer_with_keys = fake_data:: signer_keys ( 0 ) . unwrap ( ) ;
230+ let single_signer = MithrilSingleSigner :: new (
231+ signer_with_keys. party_id ,
232+ key_decode_hex ( & signer_with_keys. secret_key ) . unwrap ( ) ,
233+ ) ;
234+ let stake_distribution = fake_data:: signers_with_stakes ( 5 ) ;
235+ let protocol_parameters = fake_data:: protocol_parameters ( ) ;
236+ let protocol_signer: ProtocolSigner = single_signer
237+ . create_protocol_signer (
238+ signer_with_keys. stake ,
239+ & stake_distribution,
240+ & protocol_parameters,
241+ )
242+ . unwrap ( ) ;
243+ let clerk = StmClerk :: from_signer ( & protocol_signer, TrivialEnv ) ;
244+
245+ let message = "message" . as_bytes ( ) ;
246+ let sign_result = single_signer. compute_single_signatures (
247+ message. to_vec ( ) ,
248+ stake_distribution,
249+ & protocol_parameters,
250+ ) ;
251+
252+ assert ! ( !sign_result. as_ref( ) . unwrap( ) . is_empty( ) ) ;
253+ for sig in sign_result. unwrap ( ) {
254+ let decoded_sig = key_decode_hex ( & sig. signature ) . unwrap ( ) ;
255+ assert ! ( clerk. verify_sig( & decoded_sig, sig. index, message) . is_ok( ) ) ;
256+ assert_eq ! (
257+ decoded_sig. pk,
258+ key_decode_hex( & signer_with_keys. verification_key) . unwrap( )
259+ ) ;
260+ }
261+ }
97262}
0 commit comments