1use crate::{
2 crypto::{
3 ecdsa::{ECDSASigner, ECDSAVerifier},
4 KeyType, PrivateKey, PublicKey, Signature,
5 },
6 error::{ChaincraftError, Result},
7 shared::{MessageType, SharedMessage, SharedObjectId},
8 shared_object::ApplicationObject,
9};
10use async_trait::async_trait;
11use chrono::{DateTime, Utc};
12use serde::{Deserialize, Serialize};
13use sha2::{Digest, Sha256};
14use std::collections::{HashMap, HashSet};
15
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
18pub enum BeaconMessageType {
19 VrfProof {
21 round: u64,
22 input: String,
23 proof: String,
24 output: String,
25 validator: String,
26 signature: String,
27 timestamp: DateTime<Utc>,
28 },
29 PartialSignature {
31 round: u64,
32 validator: String,
33 partial_sig: String,
34 signature: String,
35 timestamp: DateTime<Utc>,
36 },
37 FinalizedBeacon {
39 round: u64,
40 randomness: String,
41 vrf_proofs: Vec<String>,
42 threshold_sig: String,
43 participants: Vec<String>,
44 timestamp: DateTime<Utc>,
45 },
46 ValidatorRegistration {
48 validator: String,
49 public_key: String,
50 vrf_key: String,
51 stake: u64,
52 signature: String,
53 },
54 BiasChallenge {
56 round: u64,
57 challenger: String,
58 target_validator: String,
59 challenge_data: String,
60 signature: String,
61 },
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
66pub struct VrfProof {
67 pub validator: String,
68 pub input: String,
69 pub proof: String,
70 pub output: String,
71 pub signature: String,
72 pub timestamp: DateTime<Utc>,
73}
74
75#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct BeaconValidator {
78 pub address: String,
79 pub public_key: String,
80 pub vrf_key: String,
81 pub stake: u64,
82 pub active: bool,
83 pub last_participation: Option<u64>,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
88pub struct BeaconRound {
89 pub round: u64,
90 pub randomness: String,
91 pub participants: Vec<String>,
92 pub vrf_proofs: Vec<VrfProof>,
93 pub threshold_signature: String,
94 pub finalized_at: DateTime<Utc>,
95 pub bias_challenges: Vec<String>,
96}
97
98#[derive(Debug)]
100pub struct RandomnessBeaconObject {
101 pub id: SharedObjectId,
102 pub validators: HashMap<String, BeaconValidator>,
103 pub rounds: HashMap<u64, BeaconRound>,
104 pub current_round: u64,
105 pub round_duration_secs: u64,
106 pub last_round_time: DateTime<Utc>,
107 pub pending_vrf_proofs: HashMap<u64, Vec<VrfProof>>,
108 pub pending_partial_sigs: HashMap<u64, HashMap<String, String>>,
109 pub threshold: u64, pub my_validator_address: String,
111 pub signer: ECDSASigner,
112 pub verifier: ECDSAVerifier,
113 pub messages: Vec<BeaconMessageType>,
114 pub bias_resistance_enabled: bool,
115 pub challenges: HashMap<u64, Vec<BeaconMessageType>>,
116}
117
118impl RandomnessBeaconObject {
119 pub fn new(round_duration_secs: u64, threshold: u64) -> Result<Self> {
120 let signer = ECDSASigner::new()?;
121 let my_validator_address = signer.get_public_key_pem()?;
122
123 Ok(Self {
124 id: SharedObjectId::new(),
125 validators: HashMap::new(),
126 rounds: HashMap::new(),
127 current_round: 1,
128 round_duration_secs,
129 last_round_time: Utc::now(),
130 pending_vrf_proofs: HashMap::new(),
131 pending_partial_sigs: HashMap::new(),
132 threshold,
133 my_validator_address,
134 signer,
135 verifier: ECDSAVerifier::new(),
136 messages: Vec::new(),
137 bias_resistance_enabled: true,
138 challenges: HashMap::new(),
139 })
140 }
141
142 pub fn register_validator(&mut self, validator: BeaconValidator) -> Result<()> {
144 self.validators.insert(validator.address.clone(), validator);
146 Ok(())
147 }
148
149 pub fn should_advance_round(&self) -> bool {
151 let elapsed = Utc::now().signed_duration_since(self.last_round_time);
152 elapsed.num_seconds() >= self.round_duration_secs as i64
153 }
154
155 pub fn generate_vrf_proof(&self, input: &str) -> Result<VrfProof> {
157 let vrf_input = format!("round_{}_{}", self.current_round, input);
159 let mut hasher = Sha256::new();
160 hasher.update(vrf_input.as_bytes());
161 hasher.update(self.my_validator_address.as_bytes());
162 let hash = hasher.finalize();
163
164 let proof = hex::encode(&hash[0..16]); let output = hex::encode(&hash[16..32]); let signature_data = format!("vrf:{}:{}:{}:{}", self.current_round, input, proof, output);
168 let signature = self.signer.sign(signature_data.as_bytes())?;
169
170 Ok(VrfProof {
171 validator: self.my_validator_address.clone(),
172 input: input.to_string(),
173 proof,
174 output,
175 signature: hex::encode(signature.to_bytes()),
176 timestamp: Utc::now(),
177 })
178 }
179
180 pub fn process_vrf_proof(&mut self, msg: BeaconMessageType) -> Result<bool> {
182 if let BeaconMessageType::VrfProof {
183 round,
184 input,
185 proof,
186 output,
187 validator,
188 signature,
189 timestamp,
190 } = msg
191 {
192 if round != self.current_round {
193 return Ok(false);
194 }
195
196 if !self.validators.contains_key(&validator) {
198 return Ok(false);
199 }
200
201 let vrf_proof = VrfProof {
202 validator: validator.clone(),
203 input,
204 proof,
205 output,
206 signature,
207 timestamp,
208 };
209
210 self.pending_vrf_proofs
211 .entry(round)
212 .or_default()
213 .push(vrf_proof.clone());
214
215 self.messages.push(BeaconMessageType::VrfProof {
216 round,
217 input: vrf_proof.input,
218 proof: vrf_proof.proof,
219 output: vrf_proof.output,
220 validator,
221 signature: vrf_proof.signature,
222 timestamp,
223 });
224
225 return Ok(true);
226 }
227 Ok(false)
228 }
229
230 pub fn process_partial_signature(&mut self, msg: BeaconMessageType) -> Result<bool> {
232 if let BeaconMessageType::PartialSignature {
233 round,
234 validator,
235 partial_sig,
236 signature,
237 timestamp,
238 } = msg
239 {
240 if round != self.current_round {
241 return Ok(false);
242 }
243
244 if !self.validators.contains_key(&validator) {
245 return Ok(false);
246 }
247
248 self.pending_partial_sigs
249 .entry(round)
250 .or_default()
251 .insert(validator.clone(), partial_sig.clone());
252
253 self.messages.push(BeaconMessageType::PartialSignature {
254 round,
255 validator,
256 partial_sig,
257 signature,
258 timestamp,
259 });
260
261 return Ok(true);
262 }
263 Ok(false)
264 }
265
266 pub fn can_finalize_round(&self) -> bool {
268 let vrf_count = self
269 .pending_vrf_proofs
270 .get(&self.current_round)
271 .map(|proofs| proofs.len())
272 .unwrap_or(0);
273
274 let partial_sig_count = self
275 .pending_partial_sigs
276 .get(&self.current_round)
277 .map(|sigs| sigs.len())
278 .unwrap_or(0);
279
280 vrf_count >= self.threshold as usize && partial_sig_count >= self.threshold as usize
281 }
282
283 pub fn finalize_round(&mut self) -> Result<String> {
285 if !self.can_finalize_round() {
286 return Err(ChaincraftError::validation(
287 "Insufficient proofs/signatures for finalization",
288 ));
289 }
290
291 let vrf_proofs = self
292 .pending_vrf_proofs
293 .get(&self.current_round)
294 .cloned()
295 .unwrap_or_default();
296
297 let partial_sigs = self
298 .pending_partial_sigs
299 .get(&self.current_round)
300 .cloned()
301 .unwrap_or_default();
302
303 let mut combined_randomness = String::new();
305 for proof in &vrf_proofs {
306 combined_randomness.push_str(&proof.output);
307 }
308
309 let mut hasher = Sha256::new();
310 hasher.update(combined_randomness.as_bytes());
311 hasher.update(self.current_round.to_string().as_bytes());
312 let final_randomness = hex::encode(hasher.finalize());
313
314 let mut threshold_sig = String::new();
316 for (validator, sig) in &partial_sigs {
317 threshold_sig.push_str(&format!("{}:{};", validator, sig));
318 }
319
320 let participants: Vec<String> = vrf_proofs.iter().map(|p| p.validator.clone()).collect();
321
322 let beacon_round = BeaconRound {
323 round: self.current_round,
324 randomness: final_randomness.clone(),
325 participants: participants.clone(),
326 vrf_proofs,
327 threshold_signature: threshold_sig,
328 finalized_at: Utc::now(),
329 bias_challenges: self
330 .challenges
331 .get(&self.current_round)
332 .map(|challenges| challenges.iter().map(|c| format!("{:?}", c)).collect())
333 .unwrap_or_default(),
334 };
335
336 self.rounds.insert(self.current_round, beacon_round);
337
338 self.pending_vrf_proofs.remove(&self.current_round);
340 self.pending_partial_sigs.remove(&self.current_round);
341 self.challenges.remove(&self.current_round);
342
343 self.current_round += 1;
344 self.last_round_time = Utc::now();
345
346 Ok(final_randomness)
347 }
348
349 pub fn process_bias_challenge(&mut self, msg: BeaconMessageType) -> Result<bool> {
351 if !self.bias_resistance_enabled {
352 return Ok(false);
353 }
354
355 if let BeaconMessageType::BiasChallenge { round, .. } = &msg {
356 self.challenges.entry(*round).or_default().push(msg.clone());
357
358 self.messages.push(msg);
359 return Ok(true);
360 }
361 Ok(false)
362 }
363
364 pub fn get_beacon_stats(&self) -> serde_json::Value {
366 let current_vrf_count = self
367 .pending_vrf_proofs
368 .get(&self.current_round)
369 .map(|proofs| proofs.len())
370 .unwrap_or(0);
371
372 let current_partial_sigs = self
373 .pending_partial_sigs
374 .get(&self.current_round)
375 .map(|sigs| sigs.len())
376 .unwrap_or(0);
377
378 serde_json::json!({
379 "current_round": self.current_round,
380 "total_rounds": self.rounds.len(),
381 "active_validators": self.validators.values().filter(|v| v.active).count(),
382 "threshold": self.threshold,
383 "current_vrf_proofs": current_vrf_count,
384 "current_partial_signatures": current_partial_sigs,
385 "can_finalize": self.can_finalize_round(),
386 "should_advance": self.should_advance_round(),
387 "bias_resistance": self.bias_resistance_enabled,
388 "total_challenges": self.challenges.values().map(|c| c.len()).sum::<usize>()
389 })
390 }
391
392 pub fn get_latest_randomness(&self) -> Option<String> {
394 if self.current_round > 1 {
395 self.rounds
396 .get(&(self.current_round - 1))
397 .map(|round| round.randomness.clone())
398 } else {
399 None
400 }
401 }
402
403 pub fn get_randomness_history(&self, count: usize) -> Vec<(u64, String)> {
405 let mut history: Vec<_> = self
406 .rounds
407 .iter()
408 .map(|(round, data)| (*round, data.randomness.clone()))
409 .collect();
410 history.sort_by_key(|(round, _)| *round);
411 history.into_iter().rev().take(count).collect()
412 }
413}
414
415#[async_trait]
416impl ApplicationObject for RandomnessBeaconObject {
417 fn id(&self) -> &SharedObjectId {
418 &self.id
419 }
420
421 fn type_name(&self) -> &'static str {
422 "RandomnessBeacon"
423 }
424
425 async fn is_valid(&self, message: &SharedMessage) -> Result<bool> {
426 let msg_result: std::result::Result<BeaconMessageType, _> =
427 serde_json::from_value(message.data.clone());
428 Ok(msg_result.is_ok())
429 }
430
431 async fn add_message(&mut self, message: SharedMessage) -> Result<()> {
432 let beacon_msg: BeaconMessageType =
433 serde_json::from_value(message.data.clone()).map_err(|e| {
434 ChaincraftError::Serialization(crate::error::SerializationError::Json(e))
435 })?;
436
437 let processed = match &beacon_msg {
438 BeaconMessageType::VrfProof { .. } => self.process_vrf_proof(beacon_msg.clone())?,
439 BeaconMessageType::PartialSignature { .. } => {
440 self.process_partial_signature(beacon_msg.clone())?
441 },
442 BeaconMessageType::ValidatorRegistration {
443 validator,
444 public_key,
445 vrf_key,
446 stake,
447 ..
448 } => {
449 let beacon_validator = BeaconValidator {
450 address: validator.clone(),
451 public_key: public_key.clone(),
452 vrf_key: vrf_key.clone(),
453 stake: *stake,
454 active: true,
455 last_participation: None,
456 };
457 self.register_validator(beacon_validator)?;
458 true
459 },
460 BeaconMessageType::BiasChallenge { .. } => {
461 self.process_bias_challenge(beacon_msg.clone())?
462 },
463 BeaconMessageType::FinalizedBeacon { .. } => {
464 self.messages.push(beacon_msg.clone());
466 true
467 },
468 };
469
470 if processed {
471 tracing::debug!("Successfully processed beacon message: {:?}", beacon_msg);
472
473 if self.can_finalize_round() {
475 if let Ok(randomness) = self.finalize_round() {
476 tracing::info!(
477 "Finalized beacon round {} with randomness: {}",
478 self.current_round - 1,
479 randomness
480 );
481 }
482 }
483 }
484
485 Ok(())
486 }
487
488 fn is_merkleized(&self) -> bool {
489 false
490 }
491
492 async fn get_latest_digest(&self) -> Result<String> {
493 Ok(format!("beacon_round:{}", self.current_round))
494 }
495
496 async fn has_digest(&self, digest: &str) -> Result<bool> {
497 let current_digest = format!("beacon_round:{}", self.current_round);
498 Ok(digest == current_digest)
499 }
500
501 async fn is_valid_digest(&self, _digest: &str) -> Result<bool> {
502 Ok(true)
503 }
504
505 async fn add_digest(&mut self, _digest: String) -> Result<bool> {
506 Ok(true)
507 }
508
509 async fn gossip_messages(&self, _digest: Option<&str>) -> Result<Vec<SharedMessage>> {
510 Ok(Vec::new())
511 }
512
513 async fn get_messages_since_digest(&self, _digest: &str) -> Result<Vec<SharedMessage>> {
514 Ok(Vec::new())
515 }
516
517 async fn get_state(&self) -> Result<serde_json::Value> {
518 Ok(serde_json::json!({
519 "type": "RandomnessBeacon",
520 "current_round": self.current_round,
521 "validators": self.validators.len(),
522 "finalized_rounds": self.rounds.len(),
523 "messages": self.messages.len(),
524 "latest_randomness": self.get_latest_randomness(),
525 "beacon_stats": self.get_beacon_stats(),
526 "randomness_history": self.get_randomness_history(10)
527 }))
528 }
529
530 async fn reset(&mut self) -> Result<()> {
531 self.rounds.clear();
532 self.current_round = 1;
533 self.last_round_time = Utc::now();
534 self.pending_vrf_proofs.clear();
535 self.pending_partial_sigs.clear();
536 self.challenges.clear();
537 self.messages.clear();
538 Ok(())
539 }
540
541 fn clone_box(&self) -> Box<dyn ApplicationObject> {
542 let new_obj = RandomnessBeaconObject::new(self.round_duration_secs, self.threshold)
544 .unwrap_or_else(|_| {
545 let signer = ECDSASigner::new().unwrap();
547 let my_validator_address = signer.get_public_key_pem().unwrap();
548 RandomnessBeaconObject {
549 id: SharedObjectId::new(),
550 validators: HashMap::new(),
551 rounds: HashMap::new(),
552 current_round: 1,
553 round_duration_secs: 60,
554 last_round_time: Utc::now(),
555 pending_vrf_proofs: HashMap::new(),
556 pending_partial_sigs: HashMap::new(),
557 threshold: 3,
558 my_validator_address,
559 signer,
560 verifier: ECDSAVerifier::new(),
561 messages: Vec::new(),
562 bias_resistance_enabled: true,
563 challenges: HashMap::new(),
564 }
565 });
566 Box::new(new_obj)
567 }
568
569 fn as_any(&self) -> &dyn std::any::Any {
570 self
571 }
572
573 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
574 self
575 }
576}
577
578pub mod helpers {
580 use super::*;
581
582 pub fn create_validator_registration(
583 validator: String,
584 public_key: String,
585 vrf_key: String,
586 stake: u64,
587 signer: &ECDSASigner,
588 ) -> Result<serde_json::Value> {
589 let signature_data = format!("register:{}:{}:{}:{}", validator, public_key, vrf_key, stake);
590 let signature = signer.sign(signature_data.as_bytes())?;
591
592 let registration = BeaconMessageType::ValidatorRegistration {
593 validator,
594 public_key,
595 vrf_key,
596 stake,
597 signature: hex::encode(signature.to_bytes()),
598 };
599
600 serde_json::to_value(registration)
601 .map_err(|e| ChaincraftError::Serialization(crate::error::SerializationError::Json(e)))
602 }
603
604 pub fn create_vrf_proof_message(
605 round: u64,
606 input: String,
607 proof: String,
608 output: String,
609 validator: String,
610 signer: &ECDSASigner,
611 ) -> Result<serde_json::Value> {
612 let signature_data = format!("vrf:{}:{}:{}:{}", round, input, proof, output);
613 let signature = signer.sign(signature_data.as_bytes())?;
614
615 let vrf_msg = BeaconMessageType::VrfProof {
616 round,
617 input,
618 proof,
619 output,
620 validator,
621 signature: hex::encode(signature.to_bytes()),
622 timestamp: Utc::now(),
623 };
624
625 serde_json::to_value(vrf_msg)
626 .map_err(|e| ChaincraftError::Serialization(crate::error::SerializationError::Json(e)))
627 }
628
629 pub fn create_partial_signature_message(
630 round: u64,
631 validator: String,
632 partial_sig: String,
633 signer: &ECDSASigner,
634 ) -> Result<serde_json::Value> {
635 let signature_data = format!("partial_sig:{}:{}:{}", round, validator, partial_sig);
636 let signature = signer.sign(signature_data.as_bytes())?;
637
638 let partial_sig_msg = BeaconMessageType::PartialSignature {
639 round,
640 validator,
641 partial_sig,
642 signature: hex::encode(signature.to_bytes()),
643 timestamp: Utc::now(),
644 };
645
646 serde_json::to_value(partial_sig_msg)
647 .map_err(|e| ChaincraftError::Serialization(crate::error::SerializationError::Json(e)))
648 }
649
650 pub fn create_bias_challenge(
651 round: u64,
652 challenger: String,
653 target_validator: String,
654 challenge_data: String,
655 signer: &ECDSASigner,
656 ) -> Result<serde_json::Value> {
657 let signature_data =
658 format!("challenge:{}:{}:{}:{}", round, challenger, target_validator, challenge_data);
659 let signature = signer.sign(signature_data.as_bytes())?;
660
661 let challenge = BeaconMessageType::BiasChallenge {
662 round,
663 challenger,
664 target_validator,
665 challenge_data,
666 signature: hex::encode(signature.to_bytes()),
667 };
668
669 serde_json::to_value(challenge)
670 .map_err(|e| ChaincraftError::Serialization(crate::error::SerializationError::Json(e)))
671 }
672}