triblespace_core/repo/
commit.rs1use crate::macros::entity;
2use crate::value::TryToValue;
3use crate::macros::pattern;
4use ed25519::Signature;
5use ed25519_dalek::SignatureError;
6use ed25519_dalek::SigningKey;
7use ed25519_dalek::Verifier;
8use ed25519_dalek::VerifyingKey;
9use itertools::Itertools;
10
11use ed25519::signature::Signer;
12
13use crate::blob::schemas::longstring::LongString;
14use crate::blob::schemas::simplearchive::SimpleArchive;
15use crate::blob::Blob;
16use crate::prelude::valueschemas::Handle;
17use crate::query::find;
18use crate::trible::TribleSet;
19use crate::value::Value;
20
21use crate::value::schemas::hash::Blake3;
22use hifitime::Epoch;
23
24pub enum ValidationError {
26 AmbiguousSignature,
28 MissingSignature,
30 FailedValidation,
32}
33
34impl From<SignatureError> for ValidationError {
35 fn from(_: SignatureError) -> Self {
37 ValidationError::FailedValidation
38 }
39}
40
41pub fn commit_metadata(
48 signing_key: &SigningKey,
49 parents: impl IntoIterator<Item = Value<Handle<Blake3, SimpleArchive>>>,
50 msg: Option<Value<Handle<Blake3, LongString>>>,
51 content: Option<Blob<SimpleArchive>>,
52 metadata: Option<Value<Handle<Blake3, SimpleArchive>>>,
53) -> TribleSet {
54 let mut commit = TribleSet::new();
55 let commit_entity = crate::id::rngid();
56 let now = Epoch::now().expect("system time");
57
58 commit += entity! { &commit_entity @ super::timestamp: (now, now).try_to_value().expect("point interval") };
59
60 if let Some(content) = content {
61 let handle = content.get_handle();
62 let signature = signing_key.sign(&content.bytes);
63
64 commit += entity! { &commit_entity @
65 super::content: handle,
66 super::signed_by: signing_key.verifying_key(),
67 super::signature_r: signature,
68 super::signature_s: signature,
69 };
70 }
71
72 if let Some(h) = msg {
73 commit += entity! { &commit_entity @
74 super::message: h,
75 };
76 }
77
78 if let Some(handle) = metadata {
79 commit += entity! { &commit_entity @
80 super::metadata: handle,
81 };
82 }
83
84 for parent in parents {
85 commit += entity! { &commit_entity @
86 super::parent: parent,
87 };
88 }
89
90 commit
91}
92
93pub fn verify(content: Blob<SimpleArchive>, metadata: TribleSet) -> Result<(), ValidationError> {
99 let handle = content.get_handle();
100 let (pubkey, r, s) = match find!(
101 (pubkey: Value<_>, r, s),
102 pattern!(&metadata, [
103 {
104 super::content: handle,
105 super::signed_by: ?pubkey,
106 super::signature_r: ?r,
107 super::signature_s: ?s
108 }]))
109 .at_most_one()
110 {
111 Ok(Some(result)) => result,
112 Ok(None) => return Err(ValidationError::MissingSignature),
113 Err(_) => return Err(ValidationError::AmbiguousSignature),
114 };
115
116 let pubkey: VerifyingKey = pubkey.try_from_value()?;
117 let signature = Signature::from_components(r, s);
118 pubkey.verify(&content.bytes, &signature)?;
119 Ok(())
120}