/ ledger / governor / src / bls.rs
bls.rs
  1  // Copyright (c) 2025 ADnet Contributors
  2  // This file is part of the AlphaVM library.
  3  
  4  // Licensed under the Apache License, Version 2.0 (the "License");
  5  // you may not use this file except in compliance with the License.
  6  // You may obtain a copy of the License at:
  7  
  8  // http://www.apache.org/licenses/LICENSE-2.0
  9  
 10  // Unless required by applicable law or agreed to in writing, software
 11  // distributed under the License is distributed on an "AS IS" BASIS,
 12  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  // See the License for the specific language governing permissions and
 14  // limitations under the License.
 15  
 16  //! # BLS Aggregate Signature Types
 17  //!
 18  //! Implements BLS12-377 based aggregate signatures for Governor multisig operations.
 19  //!
 20  //! ## Overview
 21  //!
 22  //! BLS signatures allow multiple signatures to be aggregated into a single signature,
 23  //! reducing on-chain storage and verification costs for multisig operations.
 24  
 25  use crate::console::{
 26      prelude::*,
 27      types::{Field, Group},
 28  };
 29  use alphavm_console_algorithms::Blake2Xs;
 30  use alphavm_curves::{
 31      bls12_377::{Bls12_377, G1Affine, G2Affine},
 32      traits::PairingEngine,
 33  };
 34  
 35  /// A BLS public key on the G1 curve (48 bytes compressed)
 36  #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 37  pub struct BlsPublicKey<N: Network> {
 38      /// The public key point on G1
 39      point: Group<N>,
 40  }
 41  
 42  impl<N: Network> BlsPublicKey<N> {
 43      /// Create a new BLS public key from a group element
 44      pub fn new(point: Group<N>) -> Self {
 45          Self { point }
 46      }
 47  
 48      /// Get the underlying group element
 49      pub fn point(&self) -> &Group<N> {
 50          &self.point
 51      }
 52  
 53      /// Convert to bytes for storage
 54      pub fn to_bytes(&self) -> Vec<u8> {
 55          self.point.to_x_coordinate().to_bytes_le().unwrap_or_default()
 56      }
 57  }
 58  
 59  /// A BLS signature on the G2 curve (96 bytes compressed)
 60  #[derive(Clone, Debug, PartialEq, Eq)]
 61  pub struct BlsSignature<N: Network> {
 62      /// The signature point on G2 (represented as two field elements)
 63      r: Field<N>,
 64      s: Field<N>,
 65  }
 66  
 67  impl<N: Network> BlsSignature<N> {
 68      /// Create a new BLS signature
 69      pub fn new(r: Field<N>, s: Field<N>) -> Self {
 70          Self { r, s }
 71      }
 72  
 73      /// Get the r component
 74      pub fn r(&self) -> &Field<N> {
 75          &self.r
 76      }
 77  
 78      /// Get the s component
 79      pub fn s(&self) -> &Field<N> {
 80          &self.s
 81      }
 82  
 83      /// Convert to bytes for storage
 84      pub fn to_bytes(&self) -> Vec<u8> {
 85          let mut bytes = Vec::with_capacity(64);
 86          bytes.extend_from_slice(&self.r.to_bytes_le().unwrap_or_default());
 87          bytes.extend_from_slice(&self.s.to_bytes_le().unwrap_or_default());
 88          bytes
 89      }
 90  }
 91  
 92  /// An aggregated BLS signature combining multiple individual signatures
 93  #[derive(Clone, Debug, PartialEq, Eq)]
 94  pub struct AggregateSignature<N: Network> {
 95      /// The aggregated signature
 96      signature: BlsSignature<N>,
 97      /// Bitmap indicating which signers participated
 98      signer_bitmap: Vec<bool>,
 99      /// Number of signatures aggregated
100      count: u8,
101  }
102  
103  impl<N: Network> AggregateSignature<N> {
104      /// Create a new aggregate signature
105      pub fn new(signature: BlsSignature<N>, signer_bitmap: Vec<bool>, count: u8) -> Self {
106          Self { signature, signer_bitmap, count }
107      }
108  
109      /// Get the underlying signature
110      pub fn signature(&self) -> &BlsSignature<N> {
111          &self.signature
112      }
113  
114      /// Get the signer bitmap
115      pub fn signer_bitmap(&self) -> &[bool] {
116          &self.signer_bitmap
117      }
118  
119      /// Get the number of signatures aggregated
120      pub fn count(&self) -> u8 {
121          self.count
122      }
123  
124      /// Check if a specific signer index participated
125      pub fn has_signer(&self, index: usize) -> bool {
126          self.signer_bitmap.get(index).copied().unwrap_or(false)
127      }
128  
129      /// Get indices of all participating signers
130      pub fn participating_signers(&self) -> Vec<usize> {
131          self.signer_bitmap
132              .iter()
133              .enumerate()
134              .filter_map(|(i, &participated)| if participated { Some(i) } else { None })
135              .collect()
136      }
137  }
138  
139  /// Result of signature verification
140  #[derive(Clone, Debug, PartialEq, Eq)]
141  pub enum VerifyResult {
142      /// Signature is valid
143      Valid,
144      /// Signature is invalid
145      Invalid,
146      /// Insufficient signers for threshold
147      InsufficientSigners { have: u8, need: u8 },
148      /// Unknown signer in aggregate
149      UnknownSigner(usize),
150  }
151  
152  /// BLS signature aggregator for building aggregate signatures
153  #[derive(Clone, Debug)]
154  pub struct SignatureAggregator<N: Network> {
155      /// Individual signatures collected
156      signatures: Vec<(usize, BlsSignature<N>)>,
157      /// Total number of possible signers
158      total_signers: usize,
159  }
160  
161  impl<N: Network> SignatureAggregator<N> {
162      /// Create a new aggregator
163      pub fn new(total_signers: usize) -> Self {
164          Self { signatures: Vec::new(), total_signers }
165      }
166  
167      /// Add a signature from a specific signer index
168      pub fn add_signature(&mut self, signer_index: usize, signature: BlsSignature<N>) -> Result<()> {
169          ensure!(
170              signer_index < self.total_signers,
171              "Signer index {} out of bounds (max: {})",
172              signer_index,
173              self.total_signers
174          );
175  
176          // Check for duplicate
177          ensure!(
178              !self.signatures.iter().any(|(i, _)| *i == signer_index),
179              "Duplicate signature from signer {}",
180              signer_index
181          );
182  
183          self.signatures.push((signer_index, signature));
184          Ok(())
185      }
186  
187      /// Get the number of signatures collected
188      pub fn signature_count(&self) -> usize {
189          self.signatures.len()
190      }
191  
192      /// Check if threshold is met
193      pub fn meets_threshold(&self, threshold: u8) -> bool {
194          self.signatures.len() >= threshold as usize
195      }
196  
197      /// Aggregate all collected signatures into one
198      ///
199      /// In a real implementation, this would perform BLS signature aggregation.
200      /// For now, we use a placeholder that combines the signatures symbolically.
201      pub fn aggregate(&self) -> Result<AggregateSignature<N>> {
202          ensure!(!self.signatures.is_empty(), "No signatures to aggregate");
203  
204          // Build signer bitmap
205          let mut bitmap = vec![false; self.total_signers];
206          for (index, _) in &self.signatures {
207              bitmap[*index] = true;
208          }
209  
210          // In production, this would be actual BLS aggregation
211          // For now, we use the first signature as a placeholder
212          let (_, first_sig) = self.signatures.first().unwrap();
213  
214          Ok(AggregateSignature::new(first_sig.clone(), bitmap, self.signatures.len() as u8))
215      }
216  }
217  
218  /// Verifier for BLS aggregate signatures
219  pub struct AggregateVerifier<N: Network> {
220      /// Public keys of all signers
221      public_keys: Vec<BlsPublicKey<N>>,
222  }
223  
224  impl<N: Network> AggregateVerifier<N> {
225      /// Create a new verifier with the given public keys
226      pub fn new(public_keys: Vec<BlsPublicKey<N>>) -> Self {
227          Self { public_keys }
228      }
229  
230      /// Verify an aggregate signature against a message
231      ///
232      /// Uses BLS12-377 pairing operations to verify: e(H(m), aggregate_pk) == e(sig, g2)
233      pub fn verify(&self, aggregate: &AggregateSignature<N>, message: &[u8], threshold: u8) -> VerifyResult {
234          // Check threshold
235          if aggregate.count() < threshold {
236              return VerifyResult::InsufficientSigners { have: aggregate.count(), need: threshold };
237          }
238  
239          // Verify all signers are known
240          let participating = aggregate.participating_signers();
241          for signer_index in &participating {
242              if *signer_index >= self.public_keys.len() {
243                  return VerifyResult::UnknownSigner(*signer_index);
244              }
245          }
246  
247          // Perform cryptographic verification using BLS12-377 pairings
248          match self.verify_pairing(aggregate, message, &participating) {
249              Ok(true) => VerifyResult::Valid,
250              Ok(false) => VerifyResult::Invalid,
251              Err(_) => VerifyResult::Invalid,
252          }
253      }
254  
255      /// Perform the actual pairing-based verification
256      ///
257      /// BLS verification checks: e(pk, H(m)) == e(g1, sig)
258      /// where pk is on G1, H(m) is on G2, sig is on G2, g1 is G1 generator
259      fn verify_pairing(
260          &self,
261          aggregate: &AggregateSignature<N>,
262          message: &[u8],
263          participating: &[usize],
264      ) -> Result<bool> {
265          // Hash the message to a G2 curve point (for BLS with pk on G1, sig on G2)
266          let message_str = format!("ADNET_BLS_MSG:{}", message.iter().map(|b| format!("{:02x}", b)).collect::<String>());
267          let (h_m, _, _) = Blake2Xs::hash_to_curve::<G2Affine>(&message_str);
268  
269          // Aggregate the public keys of participating signers
270          // pk_agg = sum(pk_i) for all participating signers
271          let mut aggregate_pk = G1Affine::zero();
272          for &idx in participating {
273              let pk = &self.public_keys[idx];
274              // Convert our BlsPublicKey to G1Affine
275              // Note: In production, BlsPublicKey would store actual G1Affine points
276              let pk_affine = self.point_to_g1_affine(pk)?;
277              aggregate_pk = (aggregate_pk.to_projective() + pk_affine.to_projective()).to_affine();
278          }
279  
280          // Convert the aggregate signature to G2Affine
281          let sig = self.signature_to_g2_affine(aggregate.signature())?;
282  
283          // Get the G1 generator (for BLS verification: e(pk, H(m)) == e(g1, sig))
284          let g1_gen = G1Affine::prime_subgroup_generator();
285  
286          // Verify: e(pk, H(m)) == e(g1, sig)
287          // BLS pairing expects (G1, G2) order
288          // aggregate_pk is on G1, h_m is on G2
289          // g1_gen is on G1, sig is on G2
290          let lhs = Bls12_377::pairing(aggregate_pk, h_m);
291          let rhs = Bls12_377::pairing(g1_gen, sig);
292  
293          Ok(lhs == rhs)
294      }
295  
296      /// Convert a BlsPublicKey to G1Affine
297      fn point_to_g1_affine(&self, pk: &BlsPublicKey<N>) -> Result<G1Affine> {
298          // Get the x-coordinate from the Group element and reconstruct G1Affine
299          // Note: This is a simplified conversion - in production, BlsPublicKey
300          // should store the full G1Affine point for proper serialization
301          let x_bytes = pk.point().to_x_coordinate().to_bytes_le()?;
302  
303          // Attempt to deserialize as G1Affine
304          // If the y-coordinate sign bit is stored, use from_x_coordinate
305          if let Some(point) = G1Affine::from_random_bytes(&x_bytes) {
306              if point.is_on_curve() && point.is_in_correct_subgroup_assuming_on_curve() {
307                  return Ok(point);
308              }
309          }
310  
311          // Fallback: return the generator point (for testing/dev mode)
312          // In production, this should return an error
313          Ok(G1Affine::prime_subgroup_generator())
314      }
315  
316      /// Convert a BlsSignature to G2Affine
317      fn signature_to_g2_affine(&self, sig: &BlsSignature<N>) -> Result<G2Affine> {
318          // Convert the r,s components to G2Affine
319          // Note: In production, BlsSignature should store the full G2Affine point
320          let mut bytes = Vec::with_capacity(96);
321          bytes.extend_from_slice(&sig.r().to_bytes_le()?);
322          bytes.extend_from_slice(&sig.s().to_bytes_le()?);
323  
324          // Attempt to deserialize as G2Affine
325          if let Some(point) = G2Affine::from_random_bytes(&bytes) {
326              if point.is_on_curve() && point.is_in_correct_subgroup_assuming_on_curve() {
327                  return Ok(point);
328              }
329          }
330  
331          // Fallback: return the generator point (for testing/dev mode)
332          Ok(G2Affine::prime_subgroup_generator())
333      }
334  
335      /// Get the number of public keys
336      pub fn num_keys(&self) -> usize {
337          self.public_keys.len()
338      }
339  }
340  
341  #[cfg(test)]
342  mod tests {
343      use super::*;
344      use crate::console::network::MainnetV0;
345      use core::ops::Add;
346  
347      type CurrentNetwork = MainnetV0;
348  
349      fn create_test_pubkeys(count: usize) -> Vec<BlsPublicKey<CurrentNetwork>> {
350          let generator = Group::<CurrentNetwork>::generator();
351          let mut point = generator.clone();
352          (0..count)
353              .map(|_| {
354                  let key = BlsPublicKey::new(point.clone());
355                  point = point.add(&generator);
356                  key
357              })
358              .collect()
359      }
360  
361      #[test]
362      fn test_signature_aggregator() {
363          let mut aggregator = SignatureAggregator::<CurrentNetwork>::new(10);
364  
365          // Create dummy signatures
366          let sig1 = BlsSignature::new(Field::from_u64(1), Field::from_u64(2));
367          let sig2 = BlsSignature::new(Field::from_u64(3), Field::from_u64(4));
368  
369          assert!(aggregator.add_signature(0, sig1).is_ok());
370          assert!(aggregator.add_signature(5, sig2).is_ok());
371  
372          assert_eq!(aggregator.signature_count(), 2);
373          assert!(aggregator.meets_threshold(2));
374          assert!(!aggregator.meets_threshold(3));
375      }
376  
377      #[test]
378      fn test_signature_aggregator_duplicate_rejected() {
379          let mut aggregator = SignatureAggregator::<CurrentNetwork>::new(10);
380  
381          let sig = BlsSignature::new(Field::from_u64(1), Field::from_u64(2));
382  
383          assert!(aggregator.add_signature(0, sig.clone()).is_ok());
384          assert!(aggregator.add_signature(0, sig).is_err()); // Duplicate
385      }
386  
387      #[test]
388      fn test_signature_aggregator_out_of_bounds() {
389          let mut aggregator = SignatureAggregator::<CurrentNetwork>::new(5);
390  
391          let sig = BlsSignature::new(Field::from_u64(1), Field::from_u64(2));
392  
393          assert!(aggregator.add_signature(5, sig).is_err()); // Out of bounds
394      }
395  
396      #[test]
397      fn test_aggregate_signature() {
398          let mut aggregator = SignatureAggregator::<CurrentNetwork>::new(10);
399  
400          for i in 0..5 {
401              let sig = BlsSignature::new(Field::from_u64(i as u64), Field::from_u64(i as u64 + 1));
402              aggregator.add_signature(i * 2, sig).unwrap();
403          }
404  
405          let aggregate = aggregator.aggregate().unwrap();
406  
407          assert_eq!(aggregate.count(), 5);
408          assert!(aggregate.has_signer(0));
409          assert!(aggregate.has_signer(2));
410          assert!(!aggregate.has_signer(1));
411  
412          let participating = aggregate.participating_signers();
413          assert_eq!(participating, vec![0, 2, 4, 6, 8]);
414      }
415  
416      #[test]
417      fn test_aggregate_verifier() {
418          let public_keys = create_test_pubkeys(10);
419  
420          let verifier = AggregateVerifier::new(public_keys);
421  
422          // Create valid aggregate
423          let mut aggregator = SignatureAggregator::<CurrentNetwork>::new(10);
424          for i in 0..7 {
425              let sig = BlsSignature::new(Field::from_u64(i as u64), Field::from_u64(i as u64));
426              aggregator.add_signature(i, sig).unwrap();
427          }
428          let aggregate = aggregator.aggregate().unwrap();
429  
430          // Verify with threshold 5 (should pass)
431          assert_eq!(verifier.verify(&aggregate, b"test message", 5), VerifyResult::Valid);
432  
433          // Verify with threshold 10 (should fail)
434          assert!(matches!(verifier.verify(&aggregate, b"test message", 10), VerifyResult::InsufficientSigners { .. }));
435      }
436  }