triblespace_core/repo/
commit.rs1use crate::macros::entity;
2use crate::macros::pattern;
3use crate::inline::TryToInline;
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::encodings::longstring::LongString;
14use crate::blob::encodings::simplearchive::SimpleArchive;
15use crate::blob::Blob;
16use crate::prelude::inlineencodings::Handle;
17use crate::query::find;
18use crate::trible::TribleSet;
19use crate::inline::Inline;
20
21
22pub enum ValidationError {
24 AmbiguousSignature,
26 MissingSignature,
28 FailedValidation,
30}
31
32impl From<SignatureError> for ValidationError {
33 fn from(_: SignatureError) -> Self {
35 ValidationError::FailedValidation
36 }
37}
38
39pub fn commit_metadata(
55 signing_key: &SigningKey,
56 parents: impl IntoIterator<Item = Inline<Handle<SimpleArchive>>>,
57 msg: Option<Inline<Handle<LongString>>>,
58 content: Option<Blob<SimpleArchive>>,
59 metadata: Option<Inline<Handle<SimpleArchive>>>,
60) -> TribleSet {
61 let (content_handle, signed_by, signature, created_at) = match content.as_ref() {
64 Some(blob) => {
65 let now = crate::clock::epoch_now();
69 let timestamp: Inline<_> =
70 (now, now).try_to_inline().expect("point interval");
71 (
72 Some(blob.get_handle()),
73 Some(signing_key.verifying_key()),
74 Some(signing_key.sign(&blob.bytes)),
75 Some(timestamp),
76 )
77 }
78 None => (None, None, None, None),
79 };
80 let parents: Vec<_> = parents.into_iter().collect();
81
82 let fragment = entity! {
87 crate::metadata::created_at?: created_at,
88 super::content?: content_handle,
89 super::signed_by?: signed_by,
90 super::signature_r?: signature,
91 super::signature_s?: signature,
92 super::message?: msg,
93 super::metadata?: metadata,
94 super::parent*: parents,
95 };
96
97 fragment.into()
98}
99
100pub fn verify(content: Blob<SimpleArchive>, metadata: TribleSet) -> Result<(), ValidationError> {
106 let handle = content.get_handle();
107 let (pubkey, r, s) = match find!(
108 (pubkey: Inline<_>, r, s),
109 pattern!(&metadata, [
110 {
111 super::content: handle,
112 super::signed_by: ?pubkey,
113 super::signature_r: ?r,
114 super::signature_s: ?s
115 }]))
116 .at_most_one()
117 {
118 Ok(Some(result)) => result,
119 Ok(None) => return Err(ValidationError::MissingSignature),
120 Err(_) => return Err(ValidationError::AmbiguousSignature),
121 };
122
123 let pubkey: VerifyingKey = pubkey.try_from_inline()?;
124 let signature = Signature::from_components(r, s);
125 pubkey.verify(&content.bytes, &signature)?;
126 Ok(())
127}