1
- //! Base multisignature scheme, used as a primitive for STM.
1
+ //! Base multi-signature scheme, used as a primitive for STM.
2
2
//! See Section 2.4 of [the paper](https://eprint.iacr.org/2021/916).
3
3
//! This module uses the `blst` library as a backend for pairings.
4
4
@@ -30,15 +30,40 @@ use std::{
30
30
/// String used to generate the proofs of possession.
31
31
const POP : & [ u8 ] = b"PoP" ;
32
32
33
- // ---------------------------------------------------------------------
34
- // Multi signature keys
35
- // ---------------------------------------------------------------------
36
-
37
33
/// MultiSig secret key, which is a wrapper over the BlstSk type from the blst
38
34
/// library.
39
35
#[ derive( Debug , Clone ) ]
40
36
pub struct SigningKey ( BlstSk ) ;
41
37
38
+ /// MultiSig verification key, which is a wrapper over the BlstVk (element in G2)
39
+ /// from the blst library.
40
+ #[ derive( Debug , Clone , Copy , Default ) ]
41
+ pub struct VerificationKey ( BlstVk ) ;
42
+
43
+ /// MultiSig proof of possession, which contains two elements from G1. However,
44
+ /// the two elements have different types: `k1` is represented as a BlstSig
45
+ /// as it has the same structure, and this facilitates its verification. On
46
+ /// the other hand, `k2` is a G1 point, as it does not share structure with
47
+ /// the BLS signature, and we need to have an ad-hoc verification mechanism.
48
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
49
+ pub struct ProofOfPossession {
50
+ k1 : BlstSig ,
51
+ k2 : blst_p1 ,
52
+ }
53
+
54
+ /// MultiSig public key, contains the verification key and the proof of possession.
55
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Serialize , Deserialize ) ]
56
+ pub struct VerificationKeyPoP {
57
+ /// The verification key.
58
+ pub vk : VerificationKey ,
59
+ /// Proof of Possession.
60
+ pub pop : ProofOfPossession ,
61
+ }
62
+
63
+ /// MultiSig signature, which is a wrapper over the `BlstSig` type.
64
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
65
+ pub struct Signature ( BlstSig ) ;
66
+
42
67
impl SigningKey {
43
68
/// Generate a secret key
44
69
pub fn gen ( rng : & mut ( impl RngCore + CryptoRng ) ) -> Self {
@@ -68,36 +93,11 @@ impl SigningKey {
68
93
match BlstSk :: from_bytes ( & bytes[ ..32 ] ) {
69
94
Ok ( sk) => Ok ( Self ( sk) ) ,
70
95
Err ( e) => Err ( blst_err_to_mithril ( e, None )
71
- . expect_err ( "If deserialisation is not successful, blst returns and error different to SUCCESS." ) )
96
+ . expect_err ( "If deserialization is not successful, blst returns and error different to SUCCESS." ) )
72
97
}
73
98
}
74
99
}
75
100
76
- /// MultiSig verification key, which is a wrapper over the BlstVk (element in G2)
77
- /// from the blst library.
78
- #[ derive( Debug , Clone , Copy , Default ) ]
79
- pub struct VerificationKey ( BlstVk ) ;
80
-
81
- impl Display for VerificationKey {
82
- fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
83
- write ! ( f, "{:?}" , self . to_bytes( ) )
84
- }
85
- }
86
-
87
- impl Hash for VerificationKey {
88
- fn hash < H : Hasher > ( & self , state : & mut H ) {
89
- Hash :: hash_slice ( & self . to_bytes ( ) , state)
90
- }
91
- }
92
-
93
- impl PartialEq for VerificationKey {
94
- fn eq ( & self , other : & Self ) -> bool {
95
- self . 0 == other. 0
96
- }
97
- }
98
-
99
- impl Eq for VerificationKey { }
100
-
101
101
impl VerificationKey {
102
102
/// Convert an `VerificationKey` to its compressed byte representation.
103
103
pub fn to_bytes ( self ) -> [ u8 ; 96 ] {
@@ -113,7 +113,7 @@ impl VerificationKey {
113
113
match BlstVk :: key_validate ( & bytes[ ..96 ] ) {
114
114
Ok ( vk) => Ok ( Self ( vk) ) ,
115
115
Err ( e) => Err ( blst_err_to_mithril ( e, None )
116
- . expect_err ( "If deserialisation is not successful, blst returns and error different to SUCCESS." ) )
116
+ . expect_err ( "If deserialization is not successful, blst returns and error different to SUCCESS." ) )
117
117
}
118
118
}
119
119
@@ -135,6 +135,26 @@ impl VerificationKey {
135
135
}
136
136
}
137
137
138
+ impl Display for VerificationKey {
139
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
140
+ write ! ( f, "{:?}" , self . to_bytes( ) )
141
+ }
142
+ }
143
+
144
+ impl Hash for VerificationKey {
145
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
146
+ Hash :: hash_slice ( & self . to_bytes ( ) , state)
147
+ }
148
+ }
149
+
150
+ impl PartialEq for VerificationKey {
151
+ fn eq ( & self , other : & Self ) -> bool {
152
+ self . 0 == other. 0
153
+ }
154
+ }
155
+
156
+ impl Eq for VerificationKey { }
157
+
138
158
impl PartialOrd for VerificationKey {
139
159
fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
140
160
Some ( self . cmp_msp_mvk ( other) )
@@ -163,26 +183,6 @@ impl<'a> Sum<&'a Self> for VerificationKey {
163
183
}
164
184
}
165
185
166
- /// MultiSig proof of possession, which contains two elements from G1. However,
167
- /// the two elements have different types: `k1` is represented as a BlstSig
168
- /// as it has the same structure, and this facilitates its verification. On
169
- /// the other hand, `k2` is a G1 point, as it does not share structure with
170
- /// the BLS signature, and we need to have an ad-hoc verification mechanism.
171
- #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
172
- pub struct ProofOfPossession {
173
- k1 : BlstSig ,
174
- k2 : blst_p1 ,
175
- }
176
-
177
- /// MultiSig public key, contains the verification key and the proof of possession.
178
- #[ derive( Debug , Clone , Copy , PartialEq , Eq , Serialize , Deserialize ) ]
179
- pub struct VerificationKeyPoP {
180
- /// The verification key.
181
- pub vk : VerificationKey ,
182
- /// Proof of Possession.
183
- pub pop : ProofOfPossession ,
184
- }
185
-
186
186
impl From < & SigningKey > for VerificationKey {
187
187
/// Convert a secret key into an `MspMvk`. This is performed by computing
188
188
/// `MspMvk = g2 * sk`, where `g2` is the generator in G2. We can use the
@@ -192,43 +192,13 @@ impl From<&SigningKey> for VerificationKey {
192
192
}
193
193
}
194
194
195
- impl From < & SigningKey > for ProofOfPossession {
196
- /// Convert a secret key into an `MspPoP`. This is performed by computing
197
- /// `k1 = H_G1(b"PoP" || mvk)` and `k2 = g1 * sk` where `H_G1` hashes into
198
- /// `G1` and `g1` is the generator in `G1`.
199
- fn from ( sk : & SigningKey ) -> Self {
200
- use blst:: blst_sk_to_pk_in_g1;
201
- let k1 = sk. 0 . sign ( POP , & [ ] , & [ ] ) ;
202
- let k2 = unsafe {
203
- let sk_scalar = std:: mem:: transmute :: < & BlstSk , & blst_scalar > ( & sk. 0 ) ;
204
-
205
- let mut out = blst_p1:: default ( ) ;
206
- blst_sk_to_pk_in_g1 ( & mut out, sk_scalar) ;
207
- out
208
- } ;
209
-
210
- Self { k1, k2 }
211
- }
212
- }
213
-
214
- impl From < & SigningKey > for VerificationKeyPoP {
215
- /// Convert a secret key into a `VerificationKeyPoP` by simply converting to a
216
- /// `MspMvk` and `MspPoP`.
217
- fn from ( sk : & SigningKey ) -> Self {
218
- Self {
219
- vk : sk. into ( ) ,
220
- pop : sk. into ( ) ,
221
- }
222
- }
223
- }
224
-
225
195
impl VerificationKeyPoP {
226
196
/// if `e(k1,g2) = e(H_G1("PoP" || mvk),mvk)` and `e(g1,mvk) = e(k2,g2)`
227
197
/// are both true, return 1. The first part is a signature verification
228
198
/// of message "PoP", while the second we need to compute the pairing
229
199
/// manually.
230
200
// If we are really looking for performance improvements, we can combine the
231
- // two final exponantiations (for verifying k1 and k2) into a single one.
201
+ // two final exponentiations (for verifying k1 and k2) into a single one.
232
202
pub fn check ( & self ) -> Result < ( ) , MultiSignatureError > {
233
203
use blst:: {
234
204
blst_fp12, blst_fp12_finalverify, blst_p1_affine_generator, blst_p2_affine_generator,
@@ -268,7 +238,7 @@ impl VerificationKeyPoP {
268
238
vkpop_bytes
269
239
}
270
240
271
- /// Deserialise a byte string to a `PublicKeyPoP`.
241
+ /// Deserialize a byte string to a `PublicKeyPoP`.
272
242
pub fn from_bytes ( bytes : & [ u8 ] ) -> Result < Self , MultiSignatureError > {
273
243
let mvk = VerificationKey :: from_bytes ( & bytes[ ..96 ] ) ?;
274
244
@@ -278,6 +248,17 @@ impl VerificationKeyPoP {
278
248
}
279
249
}
280
250
251
+ impl From < & SigningKey > for VerificationKeyPoP {
252
+ /// Convert a secret key into a `VerificationKeyPoP` by simply converting to a
253
+ /// `MspMvk` and `MspPoP`.
254
+ fn from ( sk : & SigningKey ) -> Self {
255
+ Self {
256
+ vk : sk. into ( ) ,
257
+ pop : sk. into ( ) ,
258
+ }
259
+ }
260
+ }
261
+
281
262
impl ProofOfPossession {
282
263
/// Convert to a 96 byte string.
283
264
///
@@ -297,7 +278,7 @@ impl ProofOfPossession {
297
278
pop_bytes
298
279
}
299
280
300
- /// Deserialise a byte string to a `PublicKeyPoP`.
281
+ /// Deserialize a byte string to a `PublicKeyPoP`.
301
282
pub fn from_bytes ( bytes : & [ u8 ] ) -> Result < Self , MultiSignatureError > {
302
283
let k1 = match BlstSig :: from_bytes ( & bytes[ ..48 ] ) {
303
284
Ok ( key) => key,
@@ -319,26 +300,22 @@ impl ProofOfPossession {
319
300
}
320
301
}
321
302
322
- // ---------------------------------------------------------------------
323
- // Multi signature
324
- // ---------------------------------------------------------------------
325
-
326
- /// MultiSig signature, which is a wrapper over the `BlstSig` type.
327
- #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
328
- pub struct Signature ( BlstSig ) ;
303
+ impl From < & SigningKey > for ProofOfPossession {
304
+ /// Convert a secret key into an `MspPoP`. This is performed by computing
305
+ /// `k1 = H_G1(b"PoP" || mvk)` and `k2 = g1 * sk` where `H_G1` hashes into
306
+ /// `G1` and `g1` is the generator in `G1`.
307
+ fn from ( sk : & SigningKey ) -> Self {
308
+ use blst:: blst_sk_to_pk_in_g1;
309
+ let k1 = sk. 0 . sign ( POP , & [ ] , & [ ] ) ;
310
+ let k2 = unsafe {
311
+ let sk_scalar = std:: mem:: transmute :: < & BlstSk , & blst_scalar > ( & sk. 0 ) ;
329
312
330
- impl < ' a > Sum < & ' a Self > for Signature {
331
- fn sum < I > ( iter : I ) -> Self
332
- where
333
- I : Iterator < Item = & ' a Self > ,
334
- {
335
- let signatures: Vec < & BlstSig > = iter. map ( |x| & x. 0 ) . collect ( ) ;
336
- assert ! ( !signatures. is_empty( ) , "One cannot add an empty vector" ) ;
337
- let aggregate = AggregateSignature :: aggregate ( & signatures, false )
338
- . expect ( "An MspSig is always a valid signature. This function only fails if signatures is empty or if the signatures are invalid, none of which can happen." )
339
- . to_signature ( ) ;
313
+ let mut out = blst_p1:: default ( ) ;
314
+ blst_sk_to_pk_in_g1 ( & mut out, sk_scalar) ;
315
+ out
316
+ } ;
340
317
341
- Self ( aggregate )
318
+ Self { k1 , k2 }
342
319
}
343
320
}
344
321
@@ -382,7 +359,7 @@ impl Signature {
382
359
match BlstSig :: sig_validate ( & bytes[ ..48 ] , true ) {
383
360
Ok ( sig) => Ok ( Self ( sig) ) ,
384
361
Err ( e) => Err ( blst_err_to_mithril ( e, None )
385
- . expect_err ( "If deserialisation is not successful, blst returns and error different to SUCCESS." ) )
362
+ . expect_err ( "If deserialization is not successful, blst returns and error different to SUCCESS." ) )
386
363
}
387
364
}
388
365
@@ -517,6 +494,21 @@ impl Signature {
517
494
}
518
495
}
519
496
497
+ impl < ' a > Sum < & ' a Self > for Signature {
498
+ fn sum < I > ( iter : I ) -> Self
499
+ where
500
+ I : Iterator < Item = & ' a Self > ,
501
+ {
502
+ let signatures: Vec < & BlstSig > = iter. map ( |x| & x. 0 ) . collect ( ) ;
503
+ assert ! ( !signatures. is_empty( ) , "One cannot add an empty vector" ) ;
504
+ let aggregate = AggregateSignature :: aggregate ( & signatures, false )
505
+ . expect ( "An MspSig is always a valid signature. This function only fails if signatures is empty or if the signatures are invalid, none of which can happen." )
506
+ . to_signature ( ) ;
507
+
508
+ Self ( aggregate)
509
+ }
510
+ }
511
+
520
512
impl PartialOrd for Signature {
521
513
fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
522
514
Some ( self . cmp_msp_sig ( other) )
0 commit comments