radix_common/crypto/bls12381/
public_key.rs

1use crate::internal_prelude::*;
2
3use blst::{
4    min_pk::{AggregatePublicKey, PublicKey},
5    BLST_ERROR,
6};
7
8/// Represents a BLS12-381 G1 public key.
9#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
10#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
11#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Sbor)]
12#[sbor(transparent)]
13pub struct Bls12381G1PublicKey(
14    #[cfg_attr(feature = "serde", serde(with = "hex::serde"))] pub [u8; Self::LENGTH],
15);
16
17impl Bls12381G1PublicKey {
18    pub const LENGTH: usize = 48;
19
20    pub fn to_vec(&self) -> Vec<u8> {
21        self.0.to_vec()
22    }
23
24    fn to_native_public_key(self) -> Result<PublicKey, ParseBlsPublicKeyError> {
25        PublicKey::from_bytes(&self.0).map_err(|err| err.into())
26    }
27
28    /// Aggregate multiple public keys into a single one.
29    /// This method validates provided input keys if `should_validate` flag is set.
30    pub fn aggregate(
31        public_keys: &[Self],
32        should_validate: bool,
33    ) -> Result<Self, ParseBlsPublicKeyError> {
34        if public_keys.is_empty() {
35            return Err(ParseBlsPublicKeyError::NoPublicKeysGiven);
36        }
37        let serialized_pks = public_keys.iter().map(|pk| pk.as_ref()).collect::<Vec<_>>();
38
39        let pk = AggregatePublicKey::aggregate_serialized(&serialized_pks, should_validate)?
40            .to_public_key();
41
42        Ok(Self(pk.to_bytes()))
43    }
44
45    /// Aggregate multiple public keys into a single one.
46    /// This method does not validate provided input keys, it is left here
47    /// for backward compatibility.
48    /// It is recommended to use `aggregate()` method instead.
49    pub fn aggregate_anemone(public_keys: &[Self]) -> Result<Self, ParseBlsPublicKeyError> {
50        if !public_keys.is_empty() {
51            let pk_first = public_keys[0].to_native_public_key()?;
52
53            let mut agg_pk = AggregatePublicKey::from_public_key(&pk_first);
54
55            for pk in public_keys.iter().skip(1) {
56                agg_pk.add_public_key(&pk.to_native_public_key()?, true)?;
57            }
58            Ok(Self(agg_pk.to_public_key().to_bytes()))
59        } else {
60            Err(ParseBlsPublicKeyError::NoPublicKeysGiven)
61        }
62    }
63}
64
65impl TryFrom<&[u8]> for Bls12381G1PublicKey {
66    type Error = ParseBlsPublicKeyError;
67
68    fn try_from(slice: &[u8]) -> Result<Self, Self::Error> {
69        if slice.len() != Self::LENGTH {
70            return Err(ParseBlsPublicKeyError::InvalidLength(slice.len()));
71        }
72
73        Ok(Self(copy_u8_array(slice)))
74    }
75}
76
77impl AsRef<Self> for Bls12381G1PublicKey {
78    fn as_ref(&self) -> &Self {
79        self
80    }
81}
82
83impl AsRef<[u8]> for Bls12381G1PublicKey {
84    fn as_ref(&self) -> &[u8] {
85        &self.0
86    }
87}
88
89//======
90// error
91//======
92
93impl From<BLST_ERROR> for ParseBlsPublicKeyError {
94    fn from(error: BLST_ERROR) -> Self {
95        let err_msg = format!("{:?}", error);
96        Self::BlsError(err_msg)
97    }
98}
99
100/// Represents an error when retrieving BLS public key from hex or when aggregating.
101#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
102pub enum ParseBlsPublicKeyError {
103    InvalidHex(String),
104    InvalidLength(usize),
105    NoPublicKeysGiven,
106    // Error returned by underlying BLS library
107    BlsError(String),
108}
109
110#[cfg(not(feature = "alloc"))]
111impl std::error::Error for ParseBlsPublicKeyError {}
112
113#[cfg(not(feature = "alloc"))]
114impl fmt::Display for ParseBlsPublicKeyError {
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116        write!(f, "{:?}", self)
117    }
118}
119
120//======
121// text
122//======
123
124impl FromStr for Bls12381G1PublicKey {
125    type Err = ParseBlsPublicKeyError;
126
127    fn from_str(s: &str) -> Result<Self, Self::Err> {
128        let bytes = hex::decode(s).map_err(|_| ParseBlsPublicKeyError::InvalidHex(s.to_owned()))?;
129        Self::try_from(bytes.as_slice())
130    }
131}
132
133impl fmt::Display for Bls12381G1PublicKey {
134    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
135        write!(f, "{}", hex::encode(self.to_vec()))
136    }
137}
138
139impl fmt::Debug for Bls12381G1PublicKey {
140    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
141        write!(f, "{}", self)
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148    use sbor::rust::str::FromStr;
149
150    macro_rules! public_key_validate {
151        ($pk: expr) => {
152            blst::min_pk::PublicKey::from_bytes(&$pk.0)
153                .unwrap()
154                .validate()
155        };
156    }
157
158    #[test]
159    fn public_keys_not_in_group() {
160        let public_key_valid = "93b1aa7542a5423e21d8e84b4472c31664412cc604a666e9fdf03baf3c758e728c7a11576ebb01110ac39a0df95636e2";
161        let public_key_valid = Bls12381G1PublicKey::from_str(public_key_valid).unwrap();
162        let public_key_not_in_group = "8bb1aa7542a5423e21d8e84b4472c31664412cc604a666e9fdf03baf3c758e728c7a11576ebb01110ac39a0df95636e2";
163        let public_key_not_in_group =
164            Bls12381G1PublicKey::from_str(public_key_not_in_group).unwrap();
165
166        assert_eq!(
167            public_key_validate!(public_key_not_in_group),
168            Err(blst::BLST_ERROR::BLST_POINT_NOT_IN_GROUP)
169        );
170
171        let public_keys = vec![public_key_not_in_group, public_key_valid];
172
173        let agg_pk = Bls12381G1PublicKey::aggregate(&public_keys, true);
174
175        assert_eq!(
176            agg_pk,
177            Err(ParseBlsPublicKeyError::BlsError(
178                "BLST_POINT_NOT_IN_GROUP".to_string()
179            ))
180        );
181
182        let public_keys = vec![public_key_valid, public_key_not_in_group];
183
184        let agg_pk = Bls12381G1PublicKey::aggregate(&public_keys, true);
185
186        assert_eq!(
187            agg_pk,
188            Err(ParseBlsPublicKeyError::BlsError(
189                "BLST_POINT_NOT_IN_GROUP".to_string()
190            ))
191        );
192    }
193
194    #[test]
195    fn public_key_is_infinity() {
196        let public_key_valid = "93b1aa7542a5423e21d8e84b4472c31664412cc604a666e9fdf03baf3c758e728c7a11576ebb01110ac39a0df95636e2";
197        let public_key_valid = Bls12381G1PublicKey::from_str(public_key_valid).unwrap();
198        let public_key_is_infinity =  "c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
199        let public_key_is_infinity = Bls12381G1PublicKey::from_str(public_key_is_infinity).unwrap();
200
201        assert_eq!(
202            public_key_validate!(public_key_is_infinity),
203            Err(blst::BLST_ERROR::BLST_PK_IS_INFINITY)
204        );
205
206        let public_keys = vec![public_key_is_infinity, public_key_valid];
207
208        let agg_pk = Bls12381G1PublicKey::aggregate(&public_keys, true);
209
210        assert_eq!(
211            agg_pk,
212            Err(ParseBlsPublicKeyError::BlsError(
213                "BLST_PK_IS_INFINITY".to_string()
214            ))
215        );
216
217        let public_keys = vec![public_key_is_infinity, public_key_valid];
218
219        let agg_pk = Bls12381G1PublicKey::aggregate(&public_keys, true);
220
221        assert_eq!(
222            agg_pk,
223            Err(ParseBlsPublicKeyError::BlsError(
224                "BLST_PK_IS_INFINITY".to_string()
225            ))
226        );
227    }
228}