mithril_stm/bls_multi_signature/
signature.rs

1use std::{cmp::Ordering, iter::Sum};
2
3use blake2::{Blake2b, Blake2b512, Digest};
4use blst::{
5    blst_p1, blst_p2,
6    min_sig::{AggregateSignature, PublicKey as BlstVk, Signature as BlstSig},
7    p1_affines, p2_affines,
8};
9use digest::consts::U16;
10
11use crate::bls_multi_signature::{
12    BlsVerificationKey,
13    helper::unsafe_helpers::{p1_affine_to_sig, p2_affine_to_vk, sig_to_p1, vk_from_p2_affine},
14};
15use crate::{
16    Index,
17    error::{MultiSignatureError, blst_err_to_mithril},
18};
19
20/// MultiSig signature, which is a wrapper over the `BlstSig` type.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub struct BlsSignature(pub BlstSig);
23
24impl BlsSignature {
25    /// Verify a signature against a verification key.
26    pub fn verify(&self, msg: &[u8], mvk: &BlsVerificationKey) -> Result<(), MultiSignatureError> {
27        blst_err_to_mithril(
28            self.0.validate(true).map_or_else(
29                |e| e,
30                |_| {
31                    self.0
32                        .verify(false, msg, &[], &[], &mvk.to_blst_verification_key(), false)
33                },
34            ),
35            Some(*self),
36            None,
37        )
38    }
39
40    /// Dense mapping function indexed by the index to be evaluated.
41    /// We hash the signature to produce a 64 bytes integer.
42    /// The return value of this function refers to
43    /// `ev = H("map" || msg || index || σ) <- MSP.Eval(msg,index,σ)` given in paper.
44    pub(crate) fn evaluate_dense_mapping(&self, msg: &[u8], index: Index) -> [u8; 64] {
45        let hasher = Blake2b512::new()
46            .chain_update(b"map")
47            .chain_update(msg)
48            .chain_update(index.to_le_bytes())
49            .chain_update(self.to_bytes())
50            .finalize();
51
52        let mut output = [0u8; 64];
53        output.copy_from_slice(hasher.as_slice());
54
55        output
56    }
57
58    /// Convert an `Signature` to its compressed byte representation.
59    pub fn to_bytes(self) -> [u8; 48] {
60        self.0.to_bytes()
61    }
62
63    /// Convert a string of bytes into a `MspSig`.
64    ///
65    /// # Error
66    /// Returns an error if the byte string does not represent a point in the curve.
67    pub fn from_bytes(bytes: &[u8]) -> Result<Self, MultiSignatureError> {
68        let bytes = bytes.get(..48).ok_or(MultiSignatureError::SerializationError)?;
69        match BlstSig::sig_validate(bytes, true) {
70            Ok(sig) => Ok(Self(sig)),
71            Err(e) => Err(blst_err_to_mithril(e, None, None)
72                .expect_err("If deserialization is not successful, blst returns and error different to SUCCESS."))
73        }
74    }
75
76    /// Compare two signatures. Used for PartialOrd impl, used to rank signatures. The comparison
77    /// function can be anything, as long as it is consistent across different nodes.
78    fn compare_signatures(&self, other: &Self) -> Ordering {
79        let self_bytes = self.to_bytes();
80        let other_bytes = other.to_bytes();
81        let mut result = Ordering::Equal;
82
83        for (i, j) in self_bytes.iter().zip(other_bytes.iter()) {
84            result = i.cmp(j);
85            if result != Ordering::Equal {
86                return result;
87            }
88        }
89        result
90    }
91
92    /// Aggregate a slice of verification keys and Signatures by first hashing the
93    /// signatures into random scalars, and multiplying the signature and verification
94    /// key with the resulting value. This follows the steps defined in Figure 6,
95    /// `Aggregate` step.
96    pub fn aggregate(
97        vks: &[BlsVerificationKey],
98        sigs: &[BlsSignature],
99    ) -> Result<(BlsVerificationKey, BlsSignature), MultiSignatureError> {
100        if vks.len() != sigs.len() || vks.is_empty() {
101            return Err(MultiSignatureError::AggregateSignatureInvalid);
102        }
103
104        if vks.len() < 2 {
105            return Ok((vks[0], sigs[0]));
106        }
107
108        let mut hashed_sigs = Blake2b::<U16>::new();
109        for sig in sigs {
110            hashed_sigs.update(sig.to_bytes());
111        }
112
113        // First we generate the scalars
114        let mut scalars = Vec::with_capacity(vks.len() * 128);
115        let mut signatures = Vec::with_capacity(vks.len());
116        for (index, sig) in sigs.iter().enumerate() {
117            let mut hasher = hashed_sigs.clone();
118            hasher.update(index.to_be_bytes());
119            signatures.push(sig.0);
120            scalars.extend_from_slice(hasher.finalize().as_slice());
121        }
122
123        let transmuted_vks: Vec<blst_p2> = vks.iter().map(vk_from_p2_affine).collect();
124        let transmuted_sigs: Vec<blst_p1> = signatures.iter().map(sig_to_p1).collect();
125
126        let grouped_vks = p2_affines::from(transmuted_vks.as_slice());
127        let grouped_sigs = p1_affines::from(transmuted_sigs.as_slice());
128
129        let aggr_vk: BlstVk = p2_affine_to_vk(&grouped_vks.mult(&scalars, 128));
130        let aggr_sig: BlstSig = p1_affine_to_sig(&grouped_sigs.mult(&scalars, 128));
131
132        Ok((BlsVerificationKey(aggr_vk), BlsSignature(aggr_sig)))
133    }
134
135    /// Verify a set of signatures with their corresponding verification keys using the
136    /// aggregation mechanism of Figure 6.
137    pub fn verify_aggregate(
138        msg: &[u8],
139        vks: &[BlsVerificationKey],
140        sigs: &[BlsSignature],
141    ) -> Result<(), MultiSignatureError> {
142        let (aggr_vk, aggr_sig) = Self::aggregate(vks, sigs)?;
143
144        blst_err_to_mithril(
145            aggr_sig.0.verify(
146                false,
147                msg,
148                &[],
149                &[],
150                &aggr_vk.to_blst_verification_key(),
151                false,
152            ),
153            Some(aggr_sig),
154            None,
155        )
156    }
157
158    /// Batch verify several sets of signatures with their corresponding verification keys.
159    pub fn batch_verify_aggregates(
160        msgs: &[Vec<u8>],
161        vks: &[BlsVerificationKey],
162        sigs: &[BlsSignature],
163    ) -> Result<(), MultiSignatureError> {
164        let batched_sig: BlstSig = match AggregateSignature::aggregate(
165            &(sigs.iter().map(|sig| &sig.0).collect::<Vec<&BlstSig>>()),
166            false,
167        ) {
168            Ok(sig) => BlstSig::from_aggregate(&sig),
169            Err(e) => return blst_err_to_mithril(e, None, None),
170        };
171
172        let p2_vks: Vec<BlstVk> = vks.iter().map(|vk| vk.to_blst_verification_key()).collect();
173        let p2_vks_ref: Vec<&BlstVk> = p2_vks.iter().collect();
174        let slice_msgs = msgs.iter().map(|msg| msg.as_slice()).collect::<Vec<&[u8]>>();
175
176        blst_err_to_mithril(
177            batched_sig.aggregate_verify(false, &slice_msgs, &[], &p2_vks_ref, false),
178            None,
179            None,
180        )
181        .map_err(|_| MultiSignatureError::BatchInvalid)
182    }
183}
184
185impl<'a> Sum<&'a Self> for BlsSignature {
186    fn sum<I>(iter: I) -> Self
187    where
188        I: Iterator<Item = &'a Self>,
189    {
190        let signatures: Vec<&BlstSig> = iter.map(|x| &x.0).collect();
191        assert!(!signatures.is_empty(), "One cannot add an empty vector");
192        let aggregate = AggregateSignature::aggregate(&signatures, false)
193            .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.")
194            .to_signature();
195
196        Self(aggregate)
197    }
198}
199
200impl PartialOrd for BlsSignature {
201    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
202        Some(std::cmp::Ord::cmp(self, other))
203    }
204}
205
206impl Ord for BlsSignature {
207    fn cmp(&self, other: &Self) -> Ordering {
208        self.compare_signatures(other)
209    }
210}