aptos_crypto_link/bls12381/
bls12381_keys.rs1use crate::{
24 bls12381, bls12381::DST_BLS_SIG_IN_G2_WITH_POP, hash::CryptoHash, signing_message, traits,
25 CryptoMaterialError, Genesis, Length, Uniform, ValidCryptoMaterial,
26 ValidCryptoMaterialStringExt, VerifyingKey,
27};
28use anyhow::{anyhow, Result};
29use aptos_crypto_derive::{DeserializeKey, SerializeKey, SilentDebug, SilentDisplay};
30use serde::Serialize;
31use std::{convert::TryFrom, fmt};
32
33#[derive(Clone, Eq, SerializeKey, DeserializeKey)]
34pub struct PublicKey {
36 pub(crate) pubkey: blst::min_pk::PublicKey,
37 }
40
41#[derive(SerializeKey, DeserializeKey, SilentDebug, SilentDisplay)]
42pub struct PrivateKey {
44 pub(crate) privkey: blst::min_pk::SecretKey,
45}
46
47impl PublicKey {
52 pub const LENGTH: usize = 48;
55
56 pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
58 self.pubkey.to_bytes()
59 }
60
61 pub fn subgroup_check(&self) -> Result<()> {
68 self.pubkey.validate().map_err(|e| anyhow!("{:?}", e))
69 }
70
71 pub fn aggregate(pubkeys: Vec<&Self>) -> Result<PublicKey> {
77 let blst_pubkeys: Vec<_> = pubkeys.iter().map(|pk| &pk.pubkey).collect();
78
79 let aggpk = blst::min_pk::AggregatePublicKey::aggregate(&blst_pubkeys[..], false)
81 .map_err(|e| anyhow!("{:?}", e))?;
82
83 Ok(PublicKey {
84 pubkey: aggpk.to_public_key(),
85 })
86 }
87}
88
89impl PrivateKey {
90 pub const LENGTH: usize = 32;
93
94 pub fn to_bytes(&self) -> [u8; Self::LENGTH] {
96 self.privkey.to_bytes()
97 }
98}
99
100impl traits::PrivateKey for PrivateKey {
105 type PublicKeyMaterial = PublicKey;
106}
107
108impl traits::SigningKey for PrivateKey {
109 type VerifyingKeyMaterial = PublicKey;
110 type SignatureMaterial = bls12381::Signature;
111
112 fn sign<T: CryptoHash + Serialize>(
113 &self,
114 message: &T,
115 ) -> Result<bls12381::Signature, CryptoMaterialError> {
116 Ok(bls12381::Signature {
117 sig: self
118 .privkey
119 .sign(&signing_message(message)?, DST_BLS_SIG_IN_G2_WITH_POP, &[]),
120 })
121 }
122
123 #[cfg(any(test, feature = "fuzzing"))]
124 fn sign_arbitrary_message(&self, message: &[u8]) -> bls12381::Signature {
125 bls12381::Signature {
126 sig: self.privkey.sign(message, DST_BLS_SIG_IN_G2_WITH_POP, &[]),
127 }
128 }
129}
130
131impl traits::ValidCryptoMaterial for PrivateKey {
132 fn to_bytes(&self) -> Vec<u8> {
133 self.to_bytes().to_vec()
134 }
135}
136
137impl Length for PrivateKey {
138 fn length(&self) -> usize {
139 Self::LENGTH
140 }
141}
142
143impl TryFrom<&[u8]> for PrivateKey {
144 type Error = CryptoMaterialError;
145
146 fn try_from(bytes: &[u8]) -> std::result::Result<Self, CryptoMaterialError> {
148 Ok(Self {
149 privkey: blst::min_pk::SecretKey::from_bytes(bytes)
150 .map_err(|_| CryptoMaterialError::DeserializationError)?,
151 })
152 }
153}
154
155impl Uniform for PrivateKey {
156 fn generate<R>(rng: &mut R) -> Self
157 where
158 R: ::rand::RngCore + ::rand::CryptoRng,
159 {
160 let mut ikm = [0u8; 32];
164 rng.fill_bytes(&mut ikm);
165 let privkey =
166 blst::min_pk::SecretKey::key_gen(&ikm, &[]).expect("ikm length should be higher");
167 Self { privkey }
168 }
169}
170
171impl Genesis for PrivateKey {
172 fn genesis() -> Self {
173 let mut buf = [0u8; Self::LENGTH];
174 buf[Self::LENGTH - 1] = 1;
175 Self::try_from(buf.as_ref()).unwrap()
176 }
177}
178
179#[cfg(feature = "assert-private-keys-not-cloneable")]
180static_assertions::assert_not_impl_any!(PrivateKey: Clone);
181
182#[cfg(any(test, feature = "cloneable-private-keys"))]
183impl Clone for PrivateKey {
184 fn clone(&self) -> Self {
185 let serialized: &[u8] = &(self.to_bytes());
186 PrivateKey::try_from(serialized).unwrap()
187 }
188}
189
190impl From<&PrivateKey> for PublicKey {
195 fn from(private_key: &PrivateKey) -> Self {
196 Self {
197 pubkey: private_key.privkey.sk_to_pk(),
198 }
199 }
200}
201
202impl traits::PublicKey for PublicKey {
203 type PrivateKeyMaterial = PrivateKey;
204}
205
206impl VerifyingKey for PublicKey {
207 type SigningKeyMaterial = PrivateKey;
208 type SignatureMaterial = bls12381::Signature;
209}
210
211impl ValidCryptoMaterial for PublicKey {
212 fn to_bytes(&self) -> Vec<u8> {
213 self.to_bytes().to_vec()
214 }
215}
216
217impl Length for PublicKey {
218 fn length(&self) -> usize {
219 Self::LENGTH
220 }
221}
222
223impl TryFrom<&[u8]> for PublicKey {
224 type Error = CryptoMaterialError;
225
226 fn try_from(bytes: &[u8]) -> std::result::Result<Self, CryptoMaterialError> {
239 Ok(Self {
240 pubkey: blst::min_pk::PublicKey::from_bytes(bytes)
241 .map_err(|_| CryptoMaterialError::DeserializationError)?,
242 })
243 }
244}
245
246impl std::hash::Hash for PublicKey {
247 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
248 let encoded_pubkey = self.to_bytes();
249 state.write(&encoded_pubkey);
250 }
251}
252
253impl PartialEq for PublicKey {
255 fn eq(&self, other: &Self) -> bool {
256 self.to_bytes()[..] == other.to_bytes()[..]
257 }
258}
259
260impl fmt::Debug for PublicKey {
261 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262 write!(f, "{}", hex::encode(&self.to_bytes()))
263 }
264}
265
266impl fmt::Display for PublicKey {
267 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268 write!(f, "{}", hex::encode(&self.to_bytes()))
269 }
270}
271
272#[cfg(any(test, feature = "fuzzing"))]
273use crate::test_utils::KeyPair;
274#[cfg(any(test, feature = "fuzzing"))]
275use proptest::prelude::*;
276
277#[cfg(any(test, feature = "fuzzing"))]
279pub fn keypair_strategy() -> impl Strategy<Value = KeyPair<PrivateKey, PublicKey>> {
280 crate::test_utils::uniform_keypair_strategy::<PrivateKey, PublicKey>()
281}
282
283#[cfg(any(test, feature = "fuzzing"))]
284impl proptest::arbitrary::Arbitrary for PublicKey {
285 type Parameters = ();
286 type Strategy = BoxedStrategy<Self>;
287
288 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
289 crate::test_utils::uniform_keypair_strategy::<PrivateKey, PublicKey>()
290 .prop_map(|v| v.public_key)
291 .boxed()
292 }
293}