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