Skip to content

Commit e66763b

Browse files
authored
Merge pull request #719 from input-output-hk/reorganize-multisig
Reorganize mithril-stm multi_sig.rs
2 parents 30f6152 + edd88eb commit e66763b

File tree

1 file changed

+96
-104
lines changed

1 file changed

+96
-104
lines changed

mithril-stm/src/multi_sig.rs

Lines changed: 96 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Base multisignature scheme, used as a primitive for STM.
1+
//! Base multi-signature scheme, used as a primitive for STM.
22
//! See Section 2.4 of [the paper](https://eprint.iacr.org/2021/916).
33
//! This module uses the `blst` library as a backend for pairings.
44
@@ -30,15 +30,40 @@ use std::{
3030
/// String used to generate the proofs of possession.
3131
const POP: &[u8] = b"PoP";
3232

33-
// ---------------------------------------------------------------------
34-
// Multi signature keys
35-
// ---------------------------------------------------------------------
36-
3733
/// MultiSig secret key, which is a wrapper over the BlstSk type from the blst
3834
/// library.
3935
#[derive(Debug, Clone)]
4036
pub struct SigningKey(BlstSk);
4137

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+
4267
impl SigningKey {
4368
/// Generate a secret key
4469
pub fn gen(rng: &mut (impl RngCore + CryptoRng)) -> Self {
@@ -68,36 +93,11 @@ impl SigningKey {
6893
match BlstSk::from_bytes(&bytes[..32]) {
6994
Ok(sk) => Ok(Self(sk)),
7095
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."))
7297
}
7398
}
7499
}
75100

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-
101101
impl VerificationKey {
102102
/// Convert an `VerificationKey` to its compressed byte representation.
103103
pub fn to_bytes(self) -> [u8; 96] {
@@ -113,7 +113,7 @@ impl VerificationKey {
113113
match BlstVk::key_validate(&bytes[..96]) {
114114
Ok(vk) => Ok(Self(vk)),
115115
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."))
117117
}
118118
}
119119

@@ -135,6 +135,26 @@ impl VerificationKey {
135135
}
136136
}
137137

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+
138158
impl PartialOrd for VerificationKey {
139159
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
140160
Some(self.cmp_msp_mvk(other))
@@ -163,26 +183,6 @@ impl<'a> Sum<&'a Self> for VerificationKey {
163183
}
164184
}
165185

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-
186186
impl From<&SigningKey> for VerificationKey {
187187
/// Convert a secret key into an `MspMvk`. This is performed by computing
188188
/// `MspMvk = g2 * sk`, where `g2` is the generator in G2. We can use the
@@ -192,43 +192,13 @@ impl From<&SigningKey> for VerificationKey {
192192
}
193193
}
194194

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-
225195
impl VerificationKeyPoP {
226196
/// if `e(k1,g2) = e(H_G1("PoP" || mvk),mvk)` and `e(g1,mvk) = e(k2,g2)`
227197
/// are both true, return 1. The first part is a signature verification
228198
/// of message "PoP", while the second we need to compute the pairing
229199
/// manually.
230200
// 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.
232202
pub fn check(&self) -> Result<(), MultiSignatureError> {
233203
use blst::{
234204
blst_fp12, blst_fp12_finalverify, blst_p1_affine_generator, blst_p2_affine_generator,
@@ -268,7 +238,7 @@ impl VerificationKeyPoP {
268238
vkpop_bytes
269239
}
270240

271-
/// Deserialise a byte string to a `PublicKeyPoP`.
241+
/// Deserialize a byte string to a `PublicKeyPoP`.
272242
pub fn from_bytes(bytes: &[u8]) -> Result<Self, MultiSignatureError> {
273243
let mvk = VerificationKey::from_bytes(&bytes[..96])?;
274244

@@ -278,6 +248,17 @@ impl VerificationKeyPoP {
278248
}
279249
}
280250

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+
281262
impl ProofOfPossession {
282263
/// Convert to a 96 byte string.
283264
///
@@ -297,7 +278,7 @@ impl ProofOfPossession {
297278
pop_bytes
298279
}
299280

300-
/// Deserialise a byte string to a `PublicKeyPoP`.
281+
/// Deserialize a byte string to a `PublicKeyPoP`.
301282
pub fn from_bytes(bytes: &[u8]) -> Result<Self, MultiSignatureError> {
302283
let k1 = match BlstSig::from_bytes(&bytes[..48]) {
303284
Ok(key) => key,
@@ -319,26 +300,22 @@ impl ProofOfPossession {
319300
}
320301
}
321302

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

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+
};
340317

341-
Self(aggregate)
318+
Self { k1, k2 }
342319
}
343320
}
344321

@@ -382,7 +359,7 @@ impl Signature {
382359
match BlstSig::sig_validate(&bytes[..48], true) {
383360
Ok(sig) => Ok(Self(sig)),
384361
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."))
386363
}
387364
}
388365

@@ -517,6 +494,21 @@ impl Signature {
517494
}
518495
}
519496

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+
520512
impl PartialOrd for Signature {
521513
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
522514
Some(self.cmp_msp_sig(other))

0 commit comments

Comments
 (0)