rust_bls_bn254/
lib.rs

1#![warn(unused_crate_dependencies)]
2#![cfg_attr(not(feature = "std"), no_std)]
3extern crate alloc;
4
5#[cfg(test)]
6use hex_literal as _;
7
8#[cfg(test)]
9use json as _;
10
11#[cfg(test)]
12use proptest as _;
13
14#[cfg(test)]
15use rand_core as _;
16
17#[cfg(test)]
18use assert_matches as _;
19
20use ark_bn254::{Bn254, Fq, Fr, G1Affine, G1Projective, G2Affine, G2Projective};
21use ark_ec::{
22    pairing::{Pairing, PairingOutput},
23    AffineRepr, CurveGroup,
24};
25use ark_ff::{BigInteger256, Field, PrimeField, Zero};
26use ark_serialize::CanonicalSerialize;
27use ark_std::One;
28use consts::{BLS_SIG_KEYGEN_SALT, BN254_CURVE_ORDER};
29use errors::BLSError;
30use hkdf::Hkdf;
31use num_bigint::BigUint;
32use sha2::{Digest, Sha256};
33
34pub mod consts;
35pub mod errors;
36pub mod keystores;
37pub mod mnemonics;
38pub mod utils;
39
40pub const CHINESE_SIMPLIFIED_WORD_LIST: &str = include_str!("word_lists/chinese_simplified.txt");
41pub const CHINESE_TRADITIONAL_WORD_LIST: &str = include_str!("word_lists/chinese_traditional.txt");
42pub const CZECH_WORD_LIST: &str = include_str!("word_lists/czech.txt");
43pub const ENGLISH_WORD_LIST: &str = include_str!("word_lists/english.txt");
44pub const ITALIAN_WORD_LIST: &str = include_str!("word_lists/italian.txt");
45pub const KOREAN_WORD_LIST: &str = include_str!("word_lists/korean.txt");
46pub const PORTUGUESE_WORD_LIST: &str = include_str!("word_lists/portuguese.txt");
47pub const SPANISH_WORD_LIST: &str = include_str!("word_lists/spanish.txt");
48
49pub fn pairing(u: G2Affine, v: G1Affine) -> PairingOutput<Bn254> {
50    Bn254::pairing(v, u)
51}
52
53fn xmd_hash_function(input: &[u8]) -> Vec<u8> {
54    let mut hasher = Sha256::new();
55    hasher.update(input);
56    hasher.finalize().to_vec()
57}
58
59fn i2osp(x: usize, x_len: usize) -> Vec<u8> {
60    let mut result = vec![0u8; x_len];
61    let mut x = x;
62    for i in (0..x_len).rev() {
63        result[i] = (x & 0xff) as u8;
64        x >>= 8;
65    }
66    result
67}
68
69fn os2ip(bytes: &[u8]) -> BigUint {
70    BigUint::from_bytes_be(bytes)
71}
72
73pub fn key_gen(ikm: &[u8], key_info: &[u8]) -> BigUint {
74    let curve_order = BigUint::parse_bytes(BN254_CURVE_ORDER.as_bytes(), 10).unwrap();
75    let mut salt = BLS_SIG_KEYGEN_SALT.to_vec();
76    let mut sk = BigUint::zero();
77
78    while sk.is_zero() {
79        salt = xmd_hash_function(&salt);
80        let mut temp_idk = ikm.to_vec();
81        temp_idk.extend_from_slice(&[0u8]);
82        let hkdf = Hkdf::<Sha256>::new(Some(&salt), &temp_idk);
83        let mut okm = vec![0u8; (1.5 * ((curve_order.bits() as f64) / 8.0)).ceil() as usize];
84        let mut temp_key_info = key_info.to_vec();
85        temp_key_info.extend_from_slice(&i2osp(okm.len(), 2));
86        hkdf.expand(&temp_key_info, &mut okm).unwrap();
87        sk = os2ip(&okm) % &curve_order;
88    }
89    sk
90}
91
92pub fn sk_to_pk_g2(sk: &[u8]) -> Vec<u8> {
93    let _sk = Fr::from_be_bytes_mod_order(sk);
94    let mut compressed_bytes = Vec::new();
95    let pk = G2Projective::from(G2Affine::generator()) * _sk;
96    pk.serialize_uncompressed(&mut compressed_bytes).unwrap();
97    compressed_bytes
98}
99
100pub fn sk_to_pk_g1(sk: &[u8]) -> Vec<u8> {
101    let _sk = Fr::from_be_bytes_mod_order(sk);
102    let mut compressed_bytes = Vec::new();
103    let pk = G1Projective::from(G1Affine::generator()) * _sk;
104    pk.serialize_uncompressed(&mut compressed_bytes).unwrap();
105    compressed_bytes
106}
107
108fn hash_to_curve(digest: &[u8]) -> G1Affine {
109    let one = Fq::one();
110    let three = Fq::from(3u64);
111
112    let mut hasher = Sha256::new();
113    hasher.update(digest);
114    let hashed_result = hasher.finalize();
115
116    // Convert digest to a big integer and then to a field element
117    let mut x = {
118        let big_int = BigUint::from_bytes_be(&hashed_result);
119        let mut bytes = [0u8; 32];
120        big_int
121            .to_bytes_be()
122            .iter()
123            .rev()
124            .enumerate()
125            .for_each(|(i, &b)| bytes[i] = b);
126        Fq::from_le_bytes_mod_order(&bytes)
127    };
128
129    loop {
130        // y = x^3 + 3
131        let mut y = x;
132        y.square_in_place();
133        y *= x;
134        y += three;
135
136        // Check if y is a quadratic residue (i.e., has a square root in the field)
137        if let Some(y) = y.sqrt() {
138            return G1Projective::new(x, y, Fq::one()).into_affine();
139        } else {
140            // x = x + 1
141            x += one;
142        }
143    }
144}
145
146pub fn sign(sk: Fr, message: &[u8]) -> Result<G1Affine, BLSError> {
147    let q = hash_to_curve(message);
148
149    let sk_int: BigInteger256 = sk.into();
150    let r = q.mul_bigint(sk_int);
151
152    if !r.into_affine().is_on_curve() || !r.into_affine().is_in_correct_subgroup_assuming_on_curve()
153    {
154        return Err(BLSError::SignatureNotInSubgroup);
155    }
156
157    Ok(r.into_affine())
158}
159
160pub fn verify(public_key: G2Affine, message: &[u8], signature: G1Affine) -> bool {
161    if !signature.is_in_correct_subgroup_assuming_on_curve() || !signature.is_on_curve() {
162        return false;
163    }
164
165    let q = hash_to_curve(message);
166    let c1 = pairing(public_key, q);
167    let c2 = pairing(G2Affine::generator(), signature);
168    c1 == c2
169}
170
171pub fn aggregate_signatures(signatures: &[G1Affine]) -> Result<G1Affine, BLSError> {
172    if signatures.is_empty() {
173        return Err(BLSError::SignatureListEmpty);
174    }
175
176    let signatures_in_projective: Vec<G1Projective> = signatures
177        .iter()
178        .map(|sig| {
179            let proj = G1Projective::from(*sig);
180            if !sig.is_on_curve() || !sig.is_in_correct_subgroup_assuming_on_curve() {
181                return Err(BLSError::SignatureNotInSubgroup);
182            }
183            Ok(proj)
184        })
185        .collect::<Result<Vec<_>, _>>()?;
186
187    let mut aggregated = signatures_in_projective[0];
188    for sig in &signatures[1..] {
189        aggregated += sig;
190    }
191    Ok(aggregated.into_affine())
192}
193
194pub fn aggregate_public_keys(public_keys: &[G2Affine]) -> Result<G2Affine, BLSError> {
195    if public_keys.is_empty() {
196        return Err(BLSError::PublicKeyListEmpty);
197    }
198
199    let public_keys_in_projective: Vec<G2Projective> = public_keys
200        .iter()
201        .map(|pk| {
202            let proj = G2Projective::from(*pk);
203            if !pk.is_on_curve() || !pk.is_in_correct_subgroup_assuming_on_curve() {
204                return Err(BLSError::PublicKeyNotInSubgroup);
205            }
206            Ok(proj)
207        })
208        .collect::<Result<Vec<_>, _>>()?;
209
210    let mut aggregated = public_keys_in_projective[0];
211    for pk in &public_keys_in_projective[1..] {
212        aggregated += *pk;
213    }
214
215    Ok(aggregated.into_affine())
216}
217
218#[cfg(test)]
219mod test {
220    use super::*;
221use ark_ec::AdditiveGroup;
222    use ark_bn254::G2Projective;
223    use ark_ff::UniformRand;
224    use ark_std::{ops::Mul, test_rng};
225
226    #[test]
227    fn test_aggregate_and_verify() {
228        let mut rng = test_rng();
229
230        // Generate private keys and corresponding public keys
231        let private_keys: Vec<Fr> = (0..500).map(|_| Fr::rand(&mut rng)).collect();
232        let public_keys: Vec<G2Affine> = private_keys
233            .iter()
234            .map(|sk| (G2Affine::generator() * sk).into_affine())
235            .collect();
236
237        let message = b"Test message";
238
239        // Sign the message with each private key
240        let signatures: Vec<G1Affine> = private_keys
241            .iter()
242            .map(|sk| sign(*sk, message).unwrap())
243            .collect();
244
245        // Aggregate the signatures and public keys
246        let aggregated_signature = aggregate_signatures(&signatures).unwrap();
247        let aggregated_public_key = aggregate_public_keys(&public_keys).unwrap();
248
249        // Verify the aggregated signature with the aggregated public key
250        let is_valid = verify(aggregated_public_key, message, aggregated_signature);
251        assert!(is_valid, "Aggregated signature verification failed");
252    }
253
254    #[test]
255    fn test_generic() {
256        let mut rng = ark_std::test_rng();
257        let sk = Fr::rand(&mut rng);
258        let pubkey = G2Projective::from(G2Affine::generator())
259            .mul(sk)
260            .into_affine();
261
262        let message = "random".as_bytes();
263        let message2 = "random2".as_bytes();
264
265        let sig = sign(sk, &message.to_vec()).unwrap();
266
267        let res = verify(pubkey, &message2.to_vec(), sig);
268        print!("{}", res);
269    }
270
271    #[test]
272    fn test_aggregate_signatures() {
273        let mut rng = test_rng();
274
275        // Generate valid signatures
276        let signatures: Vec<G1Affine> = (0..5).map(|_| G1Affine::rand(&mut rng)).collect();
277
278        // Aggregate the signatures
279        let result = aggregate_signatures(&signatures);
280        assert!(result.is_ok());
281
282        // Test with an empty list
283        let empty_signatures: Vec<G1Affine> = vec![];
284        let result = aggregate_signatures(&empty_signatures);
285        assert!(result.is_err());
286        assert_eq!(
287            result.unwrap_err().to_string(),
288            BLSError::SignatureListEmpty.to_string()
289        );
290
291        // Test with an invalid signature
292        let mut invalid_signature = G1Affine::rand(&mut rng);
293        invalid_signature.y = invalid_signature.y.double(); // This makes it invalid
294        let mut invalid_signatures = signatures.clone();
295        invalid_signatures.push(invalid_signature);
296        let result = aggregate_signatures(&invalid_signatures);
297        assert!(result.is_err());
298        assert_eq!(
299            result.unwrap_err().to_string(),
300            BLSError::SignatureNotInSubgroup.to_string()
301        );
302    }
303
304    #[test]
305    fn test_aggregate_public_keys() {
306        let mut rng = test_rng();
307
308        // Generate valid public keys
309        let public_keys: Vec<G2Affine> = (0..5).map(|_| G2Affine::rand(&mut rng)).collect();
310
311        // Aggregate the public keys
312        let result = aggregate_public_keys(&public_keys);
313        assert!(result.is_ok());
314
315        // Test with an empty list
316        let empty_public_keys: Vec<G2Affine> = vec![];
317        let result = aggregate_public_keys(&empty_public_keys);
318        assert!(result.is_err());
319        assert_eq!(
320            result.unwrap_err().to_string(),
321            BLSError::PublicKeyListEmpty.to_string()
322        );
323
324        // Test with an invalid public key
325        let mut invalid_public_key = G2Affine::rand(&mut rng);
326        invalid_public_key.y = invalid_public_key.y.double(); // This makes it invalid
327        let mut invalid_public_keys = public_keys.clone();
328        invalid_public_keys.push(invalid_public_key);
329        let result = aggregate_public_keys(&invalid_public_keys);
330        assert!(result.is_err());
331        assert_eq!(
332            result.unwrap_err().to_string(),
333            BLSError::PublicKeyNotInSubgroup.to_string()
334        );
335    }
336}