ic_verify_bls_signature/
lib.rs

1#![no_std]
2#![forbid(unsafe_code)]
3#![forbid(missing_docs)]
4#![allow(clippy::result_unit_err)]
5
6//! Verify BLS signatures
7//!
8//! This verifies BLS signatures in a manner which is compatible with
9//! the Internet Computer.
10
11use core::fmt;
12
13use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve};
14use bls12_381::{G1Affine, G1Projective, G2Affine, Scalar};
15use pairing::group::Curve;
16
17#[cfg(feature = "alloc")]
18use core::ops::Neg;
19
20#[cfg(feature = "alloc")]
21lazy_static::lazy_static! {
22    static ref G2PREPARED_NEG_G : bls12_381::G2Prepared = G2Affine::generator().neg().into();
23}
24
25const BLS_SIGNATURE_DOMAIN_SEP: [u8; 43] = *b"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_";
26
27fn hash_to_g1(msg: &[u8]) -> G1Affine {
28    <G1Projective as HashToCurve<ExpandMsgXmd<sha2::Sha256>>>::hash_to_curve(
29        msg,
30        &BLS_SIGNATURE_DOMAIN_SEP,
31    )
32    .to_affine()
33}
34
35/// A BLS12-381 public key usable for signature verification
36#[derive(Clone, Eq, PartialEq)]
37#[cfg_attr(not(feature = "alloc"), derive(Debug))]
38pub struct PublicKey {
39    pk: G2Affine,
40}
41
42#[cfg(feature = "alloc")]
43impl fmt::Debug for PublicKey {
44    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45        write!(f, "PublicKey({})", hex::encode(self.serialize()))
46    }
47}
48
49/// An error indicating an encoded public key was not valid
50#[derive(Debug, Copy, Clone, Eq, PartialEq)]
51pub enum InvalidPublicKey {
52    /// The public key encoding was not the correct length
53    WrongLength,
54    /// The public key was not a valid BLS12-381 G2 point
55    InvalidPoint,
56}
57
58impl PublicKey {
59    /// The length of the binary encoding of this type
60    pub const BYTES: usize = 96;
61
62    fn new(pk: G2Affine) -> Self {
63        Self { pk }
64    }
65
66    /// Return the serialization of this BLS12-381 public key
67    pub fn serialize(&self) -> [u8; Self::BYTES] {
68        self.pk.to_compressed()
69    }
70
71    /// Deserialize a BLS12-381 public key
72    pub fn deserialize(bytes: &[u8]) -> Result<Self, InvalidPublicKey> {
73        let bytes: Result<[u8; Self::BYTES], _> = bytes.try_into();
74
75        match bytes {
76            Err(_) => Err(InvalidPublicKey::WrongLength),
77            Ok(b) => {
78                let pk = G2Affine::from_compressed(&b);
79                if bool::from(pk.is_some()) {
80                    Ok(Self::new(pk.unwrap()))
81                } else {
82                    Err(InvalidPublicKey::InvalidPoint)
83                }
84            }
85        }
86    }
87
88    /// Verify a BLS signature
89    pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), ()> {
90        let msg = hash_to_g1(message);
91
92        #[cfg(feature = "alloc")]
93        {
94            use bls12_381::{multi_miller_loop, G2Prepared};
95            use pairing::group::Group;
96
97            let g2_gen: &G2Prepared = &G2PREPARED_NEG_G;
98            let pk = G2Prepared::from(self.pk);
99
100            let sig_g2 = (&signature.sig, g2_gen);
101            let msg_pk = (&msg, &pk);
102
103            let x = multi_miller_loop(&[sig_g2, msg_pk]).final_exponentiation();
104
105            if bool::from(x.is_identity()) {
106                Ok(())
107            } else {
108                Err(())
109            }
110        }
111
112        #[cfg(not(feature = "alloc"))]
113        {
114            use bls12_381::pairing;
115
116            let g2 = G2Affine::generator();
117            let lhs = pairing(&signature.sig, &g2);
118            let rhs = pairing(&msg, &self.pk);
119
120            if lhs == rhs {
121                Ok(())
122            } else {
123                Err(())
124            }
125        }
126    }
127}
128
129/// An error indicating a signature could not be deserialized
130#[derive(Debug, Copy, Clone, Eq, PartialEq)]
131pub enum InvalidSignature {
132    /// The signature encoding is the wrong length
133    WrongLength,
134    /// The signature encoding is not a valid BLS12-381 G1 point
135    InvalidPoint,
136}
137
138/// A type expressing a BLS12-381 signature
139#[derive(Copy, Clone, Eq, PartialEq)]
140#[cfg_attr(not(feature = "alloc"), derive(Debug))]
141pub struct Signature {
142    sig: G1Affine,
143}
144
145#[cfg(feature = "alloc")]
146impl fmt::Debug for Signature {
147    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148        write!(f, "Signature({})", hex::encode(self.serialize()))
149    }
150}
151
152impl Signature {
153    /// The length of the binary encoding of this type
154    pub const BYTES: usize = 48;
155
156    fn new(sig: G1Affine) -> Self {
157        Self { sig }
158    }
159
160    /// Serialize the BLS signature
161    pub fn serialize(&self) -> [u8; Self::BYTES] {
162        self.sig.to_compressed()
163    }
164
165    /// Deserialize a BLS signature
166    pub fn deserialize(bytes: &[u8]) -> Result<Self, InvalidSignature> {
167        let bytes: Result<[u8; Self::BYTES], _> = bytes.try_into();
168
169        match bytes {
170            Err(_) => Err(InvalidSignature::WrongLength),
171            Ok(b) => {
172                let sig = G1Affine::from_compressed(&b);
173                if bool::from(sig.is_some()) {
174                    Ok(Self::new(sig.unwrap()))
175                } else {
176                    Err(InvalidSignature::InvalidPoint)
177                }
178            }
179        }
180    }
181}
182
183/// An error indicating a private key could not be deserialized
184#[derive(Debug, Copy, Clone, Eq, PartialEq)]
185pub enum InvalidPrivateKey {
186    /// The secret key encoding was the wrong length and not possibly valid
187    WrongLength,
188    /// The secret key was outside the valid range of BLS12-381 keys
189    OutOfRange,
190}
191
192/// A type expressing a BLS12-381 private key
193#[derive(Copy, Clone, Eq, PartialEq)]
194pub struct PrivateKey {
195    sk: Scalar,
196}
197
198impl fmt::Debug for PrivateKey {
199    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200        write!(f, "PrivateKey(REDACTED)")
201    }
202}
203
204impl PrivateKey {
205    /// The length of the serialized encoding of this type
206    pub const BYTES: usize = 32;
207
208    fn new(sk: Scalar) -> Self {
209        Self { sk }
210    }
211
212    /// Create a new random secret key using specified RNG
213    #[cfg(feature = "rand")]
214    pub fn random<R: rand::RngCore + rand::CryptoRng>(rng: &mut R) -> Self {
215        loop {
216            let mut buf = [0u8; 32];
217            rng.fill_bytes(&mut buf);
218            let s: Option<Scalar> = Scalar::from_bytes(&buf).into();
219
220            if let Some(s) = s {
221                return Self::new(s);
222            }
223        }
224    }
225
226    /// Serialize a private key to the binary big-ending encoding
227    pub fn serialize(&self) -> [u8; Self::BYTES] {
228        let mut bytes = self.sk.to_bytes();
229        bytes.reverse();
230        bytes
231    }
232
233    /// Deserialize a secret key
234    pub fn deserialize(bytes: &[u8]) -> Result<Self, InvalidPrivateKey> {
235        let bytes: Result<[u8; Self::BYTES], _> = bytes.try_into();
236
237        match bytes {
238            Err(_) => Err(InvalidPrivateKey::WrongLength),
239            Ok(mut b) => {
240                b.reverse();
241                let sk = Scalar::from_bytes(&b);
242                if bool::from(sk.is_some()) {
243                    Ok(Self::new(sk.unwrap()))
244                } else {
245                    Err(InvalidPrivateKey::OutOfRange)
246                }
247            }
248        }
249    }
250
251    /// Return the public key associated with this secret key
252    pub fn public_key(&self) -> PublicKey {
253        PublicKey::new(G2Affine::from(G2Affine::generator() * self.sk))
254    }
255
256    /// Sign a message using this private key
257    ///
258    /// The message can be of arbitrary length
259    pub fn sign(&self, message: &[u8]) -> Signature {
260        let sig = hash_to_g1(message) * self.sk;
261        Signature::new(sig.to_affine())
262    }
263}
264
265/// Verify a BLS signature
266///
267/// The signature must be exactly 48 bytes (compressed G1 element)
268/// The key must be exactly 96 bytes (compressed G2 element)
269pub fn verify_bls_signature(sig: &[u8], msg: &[u8], key: &[u8]) -> Result<(), ()> {
270    let sig = Signature::deserialize(sig).map_err(|_| ())?;
271    let pk = PublicKey::deserialize(key).map_err(|_| ())?;
272    pk.verify(msg, &sig)
273}