use std::collections::HashMap;
use ark_ed_on_bn254::EdwardsConfig as Config;
use ark_ff::PrimeField;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use jf_signature::schnorr;
use primitive_types::U256;
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;
use serde::{Deserialize, Serialize};
use tagged_base64::tagged;
pub type CircuitField = ark_ed_on_bn254::Fq;
pub type LightClientState = GenericLightClientState<CircuitField>;
pub type StakeTableState = GenericStakeTableState<CircuitField>;
pub type StateSignatureScheme =
jf_signature::schnorr::SchnorrSignatureScheme<ark_ed_on_bn254::EdwardsConfig>;
pub type StateSignature = schnorr::Signature<Config>;
pub type StateVerKey = schnorr::VerKey<Config>;
pub type StateSignKey = schnorr::SignKey<ark_ed_on_bn254::Fr>;
pub type PublicInput = GenericPublicInput<CircuitField>;
#[derive(Debug, Default, Clone)]
pub struct StateKeyPair(pub schnorr::KeyPair<Config>);
#[derive(Clone, Debug, CanonicalSerialize, CanonicalDeserialize, Serialize, Deserialize)]
pub struct StateSignatureRequestBody {
pub key: StateVerKey,
pub state: LightClientState,
pub signature: StateSignature,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct StateSignaturesBundle {
pub state: LightClientState,
pub signatures: HashMap<StateVerKey, StateSignature>,
pub accumulated_weight: U256,
}
#[tagged("LIGHT_CLIENT_STATE")]
#[derive(
Clone,
Debug,
CanonicalSerialize,
CanonicalDeserialize,
Default,
Eq,
PartialEq,
PartialOrd,
Ord,
Hash,
)]
pub struct GenericLightClientState<F: PrimeField> {
pub view_number: usize,
pub block_height: usize,
pub block_comm_root: F,
}
impl<F: PrimeField> From<GenericLightClientState<F>> for [F; 3] {
fn from(state: GenericLightClientState<F>) -> Self {
[
F::from(state.view_number as u64),
F::from(state.block_height as u64),
state.block_comm_root,
]
}
}
impl<F: PrimeField> From<&GenericLightClientState<F>> for [F; 3] {
fn from(state: &GenericLightClientState<F>) -> Self {
[
F::from(state.view_number as u64),
F::from(state.block_height as u64),
state.block_comm_root,
]
}
}
#[tagged("STAKE_TABLE_STATE")]
#[derive(
Clone,
Debug,
CanonicalSerialize,
CanonicalDeserialize,
Default,
Eq,
PartialEq,
PartialOrd,
Ord,
Hash,
Copy,
)]
pub struct GenericStakeTableState<F: PrimeField> {
pub bls_key_comm: F,
pub schnorr_key_comm: F,
pub amount_comm: F,
pub threshold: F,
}
impl std::ops::Deref for StateKeyPair {
type Target = schnorr::KeyPair<Config>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl StateKeyPair {
#[must_use]
pub fn from_sign_key(sk: StateSignKey) -> Self {
Self(schnorr::KeyPair::<Config>::from(sk))
}
#[must_use]
pub fn generate() -> StateKeyPair {
schnorr::KeyPair::generate(&mut rand::thread_rng()).into()
}
#[must_use]
pub fn generate_from_seed(seed: [u8; 32]) -> StateKeyPair {
schnorr::KeyPair::generate(&mut ChaCha20Rng::from_seed(seed)).into()
}
#[must_use]
pub fn generate_from_seed_indexed(seed: [u8; 32], index: u64) -> StateKeyPair {
let mut hasher = blake3::Hasher::new();
hasher.update(&seed);
hasher.update(&index.to_le_bytes());
let new_seed = *hasher.finalize().as_bytes();
Self::generate_from_seed(new_seed)
}
}
impl From<schnorr::KeyPair<Config>> for StateKeyPair {
fn from(value: schnorr::KeyPair<Config>) -> Self {
StateKeyPair(value)
}
}
#[derive(Clone, Debug)]
pub struct GenericPublicInput<F: PrimeField>(Vec<F>);
impl<F: PrimeField> GenericPublicInput<F> {
pub fn new(lc_state: GenericLightClientState<F>, st_state: GenericStakeTableState<F>) -> Self {
let lc_state_f: [F; 3] = lc_state.into();
Self(vec![
lc_state_f[0],
lc_state_f[1],
lc_state_f[2],
st_state.bls_key_comm,
st_state.schnorr_key_comm,
st_state.amount_comm,
st_state.threshold,
])
}
}
impl<F: PrimeField> AsRef<[F]> for GenericPublicInput<F> {
fn as_ref(&self) -> &[F] {
&self.0
}
}
impl<F: PrimeField> From<Vec<F>> for GenericPublicInput<F> {
fn from(v: Vec<F>) -> Self {
Self(v)
}
}
impl<F: PrimeField> GenericPublicInput<F> {
#[must_use]
pub fn view_number(&self) -> F {
self.0[0]
}
#[must_use]
pub fn block_height(&self) -> F {
self.0[1]
}
#[must_use]
pub fn block_comm_root(&self) -> F {
self.0[2]
}
#[must_use]
pub fn stake_table_comm(&self) -> (F, F, F) {
(self.0[3], self.0[4], self.0[5])
}
#[must_use]
pub fn qc_key_comm(&self) -> F {
self.0[3]
}
#[must_use]
pub fn state_key_comm(&self) -> F {
self.0[4]
}
#[must_use]
pub fn stake_amount_comm(&self) -> F {
self.0[5]
}
#[must_use]
pub fn threshold(&self) -> F {
self.0[6]
}
}