use crate::macros::pattern;
use ed25519::Signature;
use ed25519_dalek::SignatureError;
use ed25519_dalek::Verifier;
use ed25519_dalek::VerifyingKey;
use itertools::Itertools;
use crate::blob::Blob;
use crate::find;
use crate::id::Id;
use crate::inline::Inline;
use crate::prelude::blobencodings::SimpleArchive;
use crate::trible::TribleSet;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum BranchEntityError {
Missing,
Ambiguous,
}
pub fn branch_entity(meta: &TribleSet, branch_id: Id) -> Result<Id, BranchEntityError> {
let mut entities = find!(
entity: Id,
pattern!(meta, [{ ?entity @ super::branch: branch_id }])
);
let Some(entity) = entities.next() else {
return Err(BranchEntityError::Missing);
};
if entities.next().is_some() {
return Err(BranchEntityError::Ambiguous);
}
Ok(entity)
}
pub enum ValidationError {
InvalidBranchMetadata,
AmbiguousSignature,
MissingSignature,
FailedValidation,
}
impl From<SignatureError> for ValidationError {
fn from(_: SignatureError) -> Self {
ValidationError::FailedValidation
}
}
pub fn verify(
branch_id: Id,
commit_head: Blob<SimpleArchive>,
metadata: TribleSet,
) -> Result<(), ValidationError> {
let handle = commit_head.get_handle();
let branch_entity =
branch_entity(&metadata, branch_id).map_err(|_| ValidationError::InvalidBranchMetadata)?;
let (pubkey, r, s) = match find!(
(pubkey: Inline<_>, r, s),
pattern!(&metadata, [
{
branch_entity @ super::head: handle,
crate::attestation::signed_by: ?pubkey,
crate::attestation::signature_r: ?r,
crate::attestation::signature_s: ?s,
}]))
.at_most_one()
{
Ok(Some(result)) => result,
Ok(None) => return Err(ValidationError::MissingSignature),
Err(_) => return Err(ValidationError::AmbiguousSignature),
};
let Ok(pubkey): Result<VerifyingKey, _> = pubkey.try_from_inline() else {
return Err(ValidationError::FailedValidation);
};
let signature = Signature::from_components(r, s);
pubkey.verify(&commit_head.bytes, &signature)?;
Ok(())
}