use crate::{simplex::elector, types::Round};
use commonware_codec::{types::lazy::Lazy, Encode};
use commonware_cryptography::{
certificate::{Attestation, Verification},
sha256::Sha256,
Hasher as _,
};
use commonware_parallel::Sequential;
use commonware_utils::{modulo, test_rng, Faults, Participant};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Behavior {
Honest,
CorruptSignature,
}
#[derive(Clone, Debug)]
pub struct Scheme<S> {
inner: S,
behavior: Behavior,
}
#[derive(Clone, Debug)]
pub struct Elector<E, S> {
inner: E,
_phantom: std::marker::PhantomData<S>,
}
#[derive(Clone, Debug, Default)]
pub struct Config<L>(pub L);
impl<S> Scheme<S> {
pub const fn new(inner: S, behavior: Behavior) -> Self {
Self { inner, behavior }
}
fn to_inner_attestation(attestation: &Attestation<Self>) -> Attestation<S>
where
S: commonware_cryptography::certificate::Scheme,
{
Attestation {
signer: attestation.signer,
signature: attestation.signature.clone(),
}
}
fn from_inner_attestation(attestation: Attestation<S>) -> Attestation<Self>
where
S: commonware_cryptography::certificate::Scheme,
{
Attestation {
signer: attestation.signer,
signature: attestation.signature,
}
}
fn corrupt_signature<D>(
inner: &S,
subject: <S as commonware_cryptography::certificate::Scheme>::Subject<'_, D>,
signer: Participant,
signature: &<S as commonware_cryptography::certificate::Scheme>::Signature,
) -> Lazy<<S as commonware_cryptography::certificate::Scheme>::Signature>
where
S: commonware_cryptography::certificate::Scheme,
D: commonware_cryptography::Digest,
{
let encoded = signature.encode().to_vec();
let bit_len = encoded.len() * 8;
let mut hasher = Sha256::default();
hasher.update(&signer.encode());
hasher.update(&encoded);
let digest = hasher.finalize();
let start = modulo(digest.as_ref(), bit_len as u64) as usize;
(0..bit_len)
.find_map(|offset| {
let flip = (start + offset) % bit_len;
let byte = flip / 8;
let bit = flip % 8;
let mut corrupted = encoded.clone();
corrupted[byte] ^= 1 << bit;
let lazy = Lazy::deferred(&mut corrupted.as_slice(), ());
let attestation = Attestation {
signer,
signature: lazy.clone(),
};
(lazy.get().is_some()
&& !inner.verify_attestation(
&mut test_rng(),
subject.clone(),
&attestation,
&Sequential,
))
.then_some(lazy)
})
.expect("expected at least one invalid but decodable signature mutation")
}
}
impl<S, L> elector::Config<Scheme<S>> for Config<L>
where
S: commonware_cryptography::certificate::Scheme,
L: elector::Config<S>,
{
type Elector = Elector<L::Elector, S>;
fn build(
self,
participants: &commonware_utils::ordered::Set<
<Scheme<S> as commonware_cryptography::certificate::Scheme>::PublicKey,
>,
) -> Self::Elector {
Elector {
inner: self.0.build(participants),
_phantom: std::marker::PhantomData,
}
}
}
impl<S, E> elector::Elector<Scheme<S>> for Elector<E, S>
where
S: commonware_cryptography::certificate::Scheme,
E: elector::Elector<S>,
{
fn elect(
&self,
round: Round,
certificate: Option<
&<Scheme<S> as commonware_cryptography::certificate::Scheme>::Certificate,
>,
) -> Participant {
self.inner.elect(round, certificate)
}
}
impl<S> commonware_cryptography::certificate::Scheme for Scheme<S>
where
S: commonware_cryptography::certificate::Scheme,
{
type Subject<'a, D: commonware_cryptography::Digest> = S::Subject<'a, D>;
type PublicKey = S::PublicKey;
type Signature = S::Signature;
type Certificate = S::Certificate;
fn me(&self) -> Option<Participant> {
self.inner.me()
}
fn participants(&self) -> &commonware_utils::ordered::Set<Self::PublicKey> {
self.inner.participants()
}
fn sign<D: commonware_cryptography::Digest>(
&self,
subject: Self::Subject<'_, D>,
) -> Option<Attestation<Self>> {
let attestation = self.inner.sign(subject.clone())?;
let signature = match self.behavior {
Behavior::Honest => attestation.signature,
Behavior::CorruptSignature => {
let signature = attestation
.signature
.get()
.expect("fresh signature should decode");
Self::corrupt_signature(&self.inner, subject, attestation.signer, signature)
}
};
Some(Attestation {
signer: attestation.signer,
signature,
})
}
fn verify_attestation<R, D>(
&self,
rng: &mut R,
subject: Self::Subject<'_, D>,
attestation: &Attestation<Self>,
strategy: &impl commonware_parallel::Strategy,
) -> bool
where
R: rand_core::CryptoRngCore,
D: commonware_cryptography::Digest,
{
self.inner.verify_attestation(
rng,
subject,
&Self::to_inner_attestation(attestation),
strategy,
)
}
fn verify_attestations<R, D, I>(
&self,
rng: &mut R,
subject: Self::Subject<'_, D>,
attestations: I,
strategy: &impl commonware_parallel::Strategy,
) -> Verification<Self>
where
R: rand_core::CryptoRngCore,
D: commonware_cryptography::Digest,
I: IntoIterator<Item = Attestation<Self>>,
I::IntoIter: Send,
{
let verification = self.inner.verify_attestations(
rng,
subject,
attestations.into_iter().map(|attestation| Attestation {
signer: attestation.signer,
signature: attestation.signature,
}),
strategy,
);
Verification::new(
verification
.verified
.into_iter()
.map(Self::from_inner_attestation)
.collect(),
verification.invalid,
)
}
fn assemble<I, M>(
&self,
attestations: I,
strategy: &impl commonware_parallel::Strategy,
) -> Option<Self::Certificate>
where
I: IntoIterator<Item = Attestation<Self>>,
I::IntoIter: Send,
M: Faults,
{
self.inner.assemble::<_, M>(
attestations.into_iter().map(|attestation| Attestation {
signer: attestation.signer,
signature: attestation.signature,
}),
strategy,
)
}
fn verify_certificate<R, D, M>(
&self,
rng: &mut R,
subject: Self::Subject<'_, D>,
certificate: &Self::Certificate,
strategy: &impl commonware_parallel::Strategy,
) -> bool
where
R: rand_core::CryptoRngCore,
D: commonware_cryptography::Digest,
M: Faults,
{
self.inner
.verify_certificate::<_, _, M>(rng, subject, certificate, strategy)
}
fn is_attributable() -> bool {
S::is_attributable()
}
fn is_batchable() -> bool {
S::is_batchable()
}
fn certificate_codec_config(&self) -> <Self::Certificate as commonware_codec::Read>::Cfg {
self.inner.certificate_codec_config()
}
fn certificate_codec_config_unbounded() -> <Self::Certificate as commonware_codec::Read>::Cfg {
S::certificate_codec_config_unbounded()
}
}