radix_common/crypto/bls12381/
public_key.rs1use crate::internal_prelude::*;
2
3use blst::{
4 min_pk::{AggregatePublicKey, PublicKey},
5 BLST_ERROR,
6};
7
8#[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 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 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
89impl 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#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor)]
102pub enum ParseBlsPublicKeyError {
103 InvalidHex(String),
104 InvalidLength(usize),
105 NoPublicKeysGiven,
106 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
120impl 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}