mithril_stm/bls_multi_signature/
verification_key.rs

1use std::{
2    cmp::Ordering,
3    fmt::{Display, Formatter},
4    hash::{Hash, Hasher},
5    iter::Sum,
6};
7
8use blst::{
9    BLST_ERROR,
10    min_sig::{AggregatePublicKey, PublicKey as BlstVk},
11};
12use serde::{Deserialize, Serialize};
13
14use crate::bls_multi_signature::{
15    BlsProofOfPossession, BlsSigningKey, POP, helper::unsafe_helpers::verify_pairing,
16};
17use crate::error::{MultiSignatureError, blst_err_to_mithril};
18
19/// MultiSig verification key, which is a wrapper over the BlstVk (element in G2)
20/// from the blst library.
21#[derive(Debug, Clone, Copy, Default)]
22pub struct BlsVerificationKey(pub BlstVk);
23
24impl BlsVerificationKey {
25    /// Convert an `VerificationKey` to its compressed byte representation.
26    pub fn to_bytes(self) -> [u8; 96] {
27        self.0.to_bytes()
28    }
29
30    /// Convert a compressed byte string into a `VerificationKey`.
31    ///
32    /// # Error
33    /// This function fails if the bytes do not represent a compressed point of the prime
34    /// order subgroup of the curve Bls12-381.
35    pub fn from_bytes(bytes: &[u8]) -> Result<Self, MultiSignatureError> {
36        let bytes = bytes.get(..96).ok_or(MultiSignatureError::SerializationError)?;
37        match BlstVk::key_validate(bytes) {
38            Ok(vk) => Ok(Self(vk)),
39            Err(e) => Err(blst_err_to_mithril(e, None, None)
40                .expect_err("If deserialization is not successful, blst returns and error different to SUCCESS."))
41        }
42    }
43
44    /// Compare two `VerificationKey`. Used for PartialOrd impl, used to order signatures. The comparison
45    /// function can be anything, as long as it is consistent.
46    fn compare_verification_keys(&self, other: &BlsVerificationKey) -> Ordering {
47        let self_bytes = self.to_bytes();
48        let other_bytes = other.to_bytes();
49        let mut result = Ordering::Equal;
50
51        for (i, j) in self_bytes.iter().zip(other_bytes.iter()) {
52            result = i.cmp(j);
53            if result != Ordering::Equal {
54                return result;
55            }
56        }
57
58        result
59    }
60
61    pub(crate) fn to_blst_verification_key(self) -> BlstVk {
62        self.0
63    }
64}
65
66impl Display for BlsVerificationKey {
67    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
68        write!(f, "{:?}", self.to_bytes())
69    }
70}
71
72impl Hash for BlsVerificationKey {
73    fn hash<H: Hasher>(&self, state: &mut H) {
74        Hash::hash_slice(&self.to_bytes(), state)
75    }
76}
77
78impl PartialEq for BlsVerificationKey {
79    fn eq(&self, other: &Self) -> bool {
80        self.0 == other.0
81    }
82}
83
84impl Eq for BlsVerificationKey {}
85
86impl PartialOrd for BlsVerificationKey {
87    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
88        Some(std::cmp::Ord::cmp(self, other))
89    }
90}
91
92impl Ord for BlsVerificationKey {
93    fn cmp(&self, other: &Self) -> Ordering {
94        self.compare_verification_keys(other)
95    }
96}
97
98impl<'a> Sum<&'a Self> for BlsVerificationKey {
99    fn sum<I>(iter: I) -> Self
100    where
101        I: Iterator<Item = &'a Self>,
102    {
103        let keys: Vec<&BlstVk> = iter.map(|x| &x.0).collect();
104
105        assert!(!keys.is_empty(), "One cannot add an empty vector");
106        let aggregate_key = AggregatePublicKey::aggregate(&keys, false)
107            .expect("An MspMvk is always a valid key. This function only fails if keys is empty or if the keys are invalid, none of which can happen.")
108            .to_public_key();
109
110        Self(aggregate_key)
111    }
112}
113
114impl From<&BlsSigningKey> for BlsVerificationKey {
115    /// Convert a secret key into an `MspMvk`. This is performed by computing
116    /// `MspMvk = g2 * sk`, where `g2` is the generator in G2. We can use the
117    /// blst built-in function `sk_to_pk`.
118    fn from(sk: &BlsSigningKey) -> Self {
119        BlsVerificationKey(sk.to_blst_secret_key().sk_to_pk())
120    }
121}
122
123/// MultiSig public key, contains the verification key and the proof of possession.
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
125pub struct BlsVerificationKeyProofOfPossession {
126    /// The verification key.
127    pub vk: BlsVerificationKey,
128    /// Proof of Possession.
129    pub pop: BlsProofOfPossession,
130}
131
132impl BlsVerificationKeyProofOfPossession {
133    /// if `e(k1,g2) = e(H_G1("PoP" || mvk),mvk)` and `e(g1,mvk) = e(k2,g2)`
134    /// are both true, return 1. The first part is a signature verification
135    /// of message "PoP", while the second we need to compute the pairing
136    /// manually.
137    // If we are really looking for performance improvements, we can combine the
138    // two final exponentiations (for verifying k1 and k2) into a single one.
139    pub(crate) fn verify_proof_of_possesion(&self) -> Result<(), MultiSignatureError> {
140        match self.vk.to_blst_verification_key().validate() {
141            Ok(_) => {
142                let result = verify_pairing(&self.vk, &self.pop);
143                if !(self.pop.get_k1().verify(
144                    false,
145                    POP,
146                    &[],
147                    &[],
148                    &self.vk.to_blst_verification_key(),
149                    false,
150                ) == BLST_ERROR::BLST_SUCCESS
151                    && result)
152                {
153                    return Err(MultiSignatureError::KeyInvalid(Box::new(*self)));
154                }
155                Ok(())
156            }
157            Err(e) => blst_err_to_mithril(e, None, Some(self.vk)),
158        }
159    }
160
161    /// if `e(k1,g2) = e(H_G1("PoP" || mvk),mvk)` and `e(g1,mvk) = e(k2,g2)`
162    /// are both true, return 1. The first part is a signature verification
163    /// of message "PoP", while the second we need to compute the pairing
164    /// manually.
165    // If we are really looking for performance improvements, we can combine the
166    // two final exponentiations (for verifying k1 and k2) into a single one.
167    #[deprecated(since = "0.4.9", note = "Use `verify_proof_of_possesion` instead")]
168    pub fn check(&self) -> Result<(), MultiSignatureError> {
169        Self::verify_proof_of_possesion(self)
170    }
171
172    /// Convert to a 144 byte string.
173    ///
174    /// # Layout
175    /// The layout of a `PublicKeyPoP` encoding is
176    /// * Public key
177    /// * Proof of Possession
178    pub fn to_bytes(self) -> [u8; 192] {
179        let mut vkpop_bytes = [0u8; 192];
180        vkpop_bytes[..96].copy_from_slice(&self.vk.to_bytes());
181        vkpop_bytes[96..].copy_from_slice(&self.pop.to_bytes());
182        vkpop_bytes
183    }
184
185    /// Deserialize a byte string to a `BlsVerificationKeyProofOfPossession`.
186    pub fn from_bytes(bytes: &[u8]) -> Result<Self, MultiSignatureError> {
187        let mvk = BlsVerificationKey::from_bytes(
188            bytes.get(..96).ok_or(MultiSignatureError::SerializationError)?,
189        )?;
190
191        let pop = BlsProofOfPossession::from_bytes(
192            bytes.get(96..).ok_or(MultiSignatureError::SerializationError)?,
193        )?;
194
195        Ok(Self { vk: mvk, pop })
196    }
197}
198
199impl From<&BlsSigningKey> for BlsVerificationKeyProofOfPossession {
200    /// Convert a secret key into a `BlsVerificationKeyProofOfPossession` by simply converting to a
201    /// `MspMvk` and `MspPoP`.
202    fn from(sk: &BlsSigningKey) -> Self {
203        Self {
204            vk: sk.into(),
205            pop: sk.into(),
206        }
207    }
208}