Skip to main content

ferveo_nucypher/
validator.rs

1use std::{collections::HashSet, fmt::Display, str::FromStr};
2
3use ark_ec::pairing::Pairing;
4use ferveo_common::PublicKey as ValidatorPublicKey;
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7
8use crate::Error;
9
10const ETHEREUM_ADDRESS_LEN: usize = 42;
11
12#[derive(
13    Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash,
14)]
15pub struct EthereumAddress(String);
16
17#[derive(Debug, Error, Clone, PartialEq, Eq)]
18pub enum EthereumAddressParseError {
19    #[error("Invalid Ethereum address length.")]
20    InvalidLength,
21
22    #[error("Invalid hex value in Ethereum address.")]
23    InvalidHex,
24}
25
26impl FromStr for EthereumAddress {
27    type Err = EthereumAddressParseError;
28
29    fn from_str(s: &str) -> Result<EthereumAddress, EthereumAddressParseError> {
30        if s.len() != ETHEREUM_ADDRESS_LEN {
31            return Err(EthereumAddressParseError::InvalidLength);
32        }
33        let prefix_len = "0x".len();
34        hex::decode(&s[prefix_len..])
35            .map_err(|_| EthereumAddressParseError::InvalidHex)?;
36        Ok(EthereumAddress(s.to_string()))
37    }
38}
39
40impl Display for EthereumAddress {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        write!(f, "{}", self.0)
43    }
44}
45
46#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
47/// Represents an external validator
48pub struct Validator<E: Pairing> {
49    /// The established address of the validator
50    pub address: EthereumAddress,
51    /// The Public key
52    pub public_key: ValidatorPublicKey<E>,
53    /// The index of the validator in the given ritual
54    pub share_index: u32,
55}
56
57impl<E: Pairing> Validator<E> {
58    pub fn new(
59        address: String,
60        public_key: ValidatorPublicKey<E>,
61        share_index: u32,
62    ) -> Result<Self, EthereumAddressParseError> {
63        Ok(Self {
64            address: EthereumAddress::from_str(&address)?,
65            public_key,
66            share_index,
67        })
68    }
69}
70
71pub fn assert_no_share_duplicates<E: Pairing>(
72    validators: &[Validator<E>],
73) -> Result<(), Error> {
74    let mut set = HashSet::new();
75    for validator in validators {
76        if set.contains(&validator.share_index) {
77            return Err(Error::DuplicatedShareIndex(validator.share_index));
78        } else {
79            set.insert(validator.share_index);
80        }
81    }
82    Ok(())
83}