Skip to content

Commit 6de2fd6

Browse files
committed
Merge branch 'main' into feat/signed-doc-macro
2 parents 323c4ce + fdce7e9 commit 6de2fd6

File tree

15 files changed

+542
-502
lines changed

15 files changed

+542
-502
lines changed

.config/dictionaries/project.dic

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ MPMC
192192
msvc
193193
Multiaddr
194194
multiera
195+
mutlisig
195196
mypy
196197
nanos
197198
netkey

rust/signed_doc/src/providers.rs

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ use ed25519_dalek::VerifyingKey;
88
use crate::{CatalystSignedDocument, DocumentRef};
99

1010
/// `VerifyingKey` Provider trait
11-
pub trait VerifyingKeyProvider {
11+
pub trait VerifyingKeyProvider: Send + Sync {
1212
/// Try to get `VerifyingKey`
1313
fn try_get_key(
1414
&self,
1515
kid: &CatalystId,
16-
) -> impl Future<Output = anyhow::Result<Option<VerifyingKey>>>;
16+
) -> impl Future<Output = anyhow::Result<Option<VerifyingKey>>> + Send;
1717
}
1818

1919
/// `CatalystSignedDocument` Provider trait
@@ -53,11 +53,16 @@ pub mod tests {
5353
};
5454
use crate::{DocLocator, DocumentRef};
5555

56-
/// Simple testing implementation of `CatalystSignedDocumentProvider`
56+
/// Simple testing implementation of `CatalystSignedDocumentProvider`,
5757
#[derive(Default, Debug)]
58-
pub struct TestCatalystSignedDocumentProvider(HashMap<DocumentRef, CatalystSignedDocument>);
58+
pub struct TestCatalystProvider {
59+
/// For `CatalystSignedDocumentProvider`.
60+
signed_doc: HashMap<DocumentRef, CatalystSignedDocument>,
61+
/// For `VerifyingKeyProvider`.
62+
verifying_key: HashMap<CatalystId, VerifyingKey>,
63+
}
5964

60-
impl TestCatalystSignedDocumentProvider {
65+
impl TestCatalystProvider {
6166
/// Inserts document into the `TestCatalystSignedDocumentProvider` where
6267
/// if document reference is provided use that value.
6368
/// if not use the id and version of the provided doc.
@@ -71,29 +76,38 @@ pub mod tests {
7176
doc: &CatalystSignedDocument,
7277
) -> anyhow::Result<()> {
7378
if let Some(dr) = doc_ref {
74-
self.0.insert(dr, doc.clone());
79+
self.signed_doc.insert(dr, doc.clone());
7580
} else {
7681
let dr = DocumentRef::new(doc.doc_id()?, doc.doc_ver()?, DocLocator::default());
77-
self.0.insert(dr, doc.clone());
82+
self.signed_doc.insert(dr, doc.clone());
7883
}
7984
Ok(())
8085
}
86+
87+
/// Inserts public key into the `TestVerifyingKeyProvider`
88+
pub fn add_pk(
89+
&mut self,
90+
kid: CatalystId,
91+
pk: VerifyingKey,
92+
) {
93+
self.verifying_key.insert(kid, pk);
94+
}
8195
}
8296

83-
impl CatalystSignedDocumentProvider for TestCatalystSignedDocumentProvider {
97+
impl CatalystSignedDocumentProvider for TestCatalystProvider {
8498
async fn try_get_doc(
8599
&self,
86100
doc_ref: &DocumentRef,
87101
) -> anyhow::Result<Option<CatalystSignedDocument>> {
88-
Ok(self.0.get(doc_ref).cloned())
102+
Ok(self.signed_doc.get(doc_ref).cloned())
89103
}
90104

91105
async fn try_get_last_doc(
92106
&self,
93107
id: catalyst_types::uuid::UuidV7,
94108
) -> anyhow::Result<Option<CatalystSignedDocument>> {
95109
Ok(self
96-
.0
110+
.signed_doc
97111
.iter()
98112
.filter(|(doc_ref, _)| doc_ref.id() == &id)
99113
.max_by_key(|(doc_ref, _)| doc_ref.ver().uuid())
@@ -109,27 +123,12 @@ pub mod tests {
109123
}
110124
}
111125

112-
/// Simple testing implementation of `VerifyingKeyProvider`
113-
#[derive(Default)]
114-
pub struct TestVerifyingKeyProvider(HashMap<CatalystId, VerifyingKey>);
115-
116-
impl TestVerifyingKeyProvider {
117-
/// Inserts public key into the `TestVerifyingKeyProvider`
118-
pub fn add_pk(
119-
&mut self,
120-
kid: CatalystId,
121-
pk: VerifyingKey,
122-
) {
123-
self.0.insert(kid, pk);
124-
}
125-
}
126-
127-
impl VerifyingKeyProvider for TestVerifyingKeyProvider {
126+
impl VerifyingKeyProvider for TestCatalystProvider {
128127
async fn try_get_key(
129128
&self,
130129
kid: &CatalystId,
131130
) -> anyhow::Result<Option<VerifyingKey>> {
132-
Ok(self.0.get(kid).copied())
131+
Ok(self.verifying_key.get(kid).copied())
133132
}
134133
}
135134
}

rust/signed_doc/src/validator/mod.rs

Lines changed: 6 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ pub(crate) mod rules;
55

66
use std::{collections::HashMap, sync::LazyLock};
77

8-
use anyhow::Context;
98
use catalyst_signed_doc_macro;
10-
use catalyst_types::{catalyst_id::role_index::RoleId, problem_report::ProblemReport};
9+
use catalyst_types::catalyst_id::role_index::RoleId;
1110
use rules::{
1211
ContentEncodingRule, ContentRule, ContentSchema, ContentTypeRule, IdRule, ParametersRule,
1312
RefRule, ReplyRule, Rules, SectionRule, SignatureKidRule, VerRule,
@@ -20,7 +19,7 @@ use crate::{
2019
},
2120
metadata::DocType,
2221
providers::{CatalystSignedDocumentProvider, VerifyingKeyProvider},
23-
signature::{tbs_data, Signature},
22+
validator::rules::SignatureRule,
2423
CatalystSignedDocument, ContentEncoding, ContentType,
2524
};
2625

@@ -62,6 +61,7 @@ fn proposal_rule() -> Rules {
6261
kid: SignatureKidRule {
6362
exp: &[RoleId::Proposer],
6463
},
64+
signature: SignatureRule { mutlisig: false },
6565
}
6666
}
6767

@@ -104,6 +104,7 @@ fn proposal_comment_rule() -> Rules {
104104
kid: SignatureKidRule {
105105
exp: &[RoleId::Role0],
106106
},
107+
signature: SignatureRule { mutlisig: false },
107108
}
108109
}
109110

@@ -152,6 +153,7 @@ fn proposal_submission_action_rule() -> Rules {
152153
kid: SignatureKidRule {
153154
exp: &[RoleId::Proposer],
154155
},
156+
signature: SignatureRule { mutlisig: false },
155157
}
156158
}
157159

@@ -185,7 +187,7 @@ pub async fn validate<Provider>(
185187
provider: &Provider,
186188
) -> anyhow::Result<bool>
187189
where
188-
Provider: CatalystSignedDocumentProvider,
190+
Provider: CatalystSignedDocumentProvider + VerifyingKeyProvider,
189191
{
190192
let Ok(doc_type) = doc.doc_type() else {
191193
doc.report().missing_field(
@@ -207,82 +209,6 @@ where
207209
rules.check(doc, provider).await
208210
}
209211

210-
/// Verify document signatures.
211-
/// Return true if all signatures are valid, otherwise return false.
212-
///
213-
/// # Errors
214-
/// If `provider` returns error, fails fast throwing that error.
215-
pub async fn validate_signatures(
216-
doc: &CatalystSignedDocument,
217-
provider: &impl VerifyingKeyProvider,
218-
) -> anyhow::Result<bool> {
219-
if doc.signatures().is_empty() {
220-
doc.report().other(
221-
"Catalyst Signed Document is unsigned",
222-
"During Catalyst Signed Document signature validation",
223-
);
224-
return Ok(false);
225-
}
226-
227-
let sign_rules = doc
228-
.signatures()
229-
.iter()
230-
.map(|sign| validate_signature(doc, sign, provider, doc.report()));
231-
232-
let res = futures::future::join_all(sign_rules)
233-
.await
234-
.into_iter()
235-
.collect::<anyhow::Result<Vec<_>>>()?
236-
.iter()
237-
.all(|res| *res);
238-
239-
Ok(res)
240-
}
241-
242-
/// A single signature validation function
243-
async fn validate_signature<Provider>(
244-
doc: &CatalystSignedDocument,
245-
sign: &Signature,
246-
provider: &Provider,
247-
report: &ProblemReport,
248-
) -> anyhow::Result<bool>
249-
where
250-
Provider: VerifyingKeyProvider,
251-
{
252-
let kid = sign.kid();
253-
254-
let Some(pk) = provider.try_get_key(kid).await? else {
255-
report.other(
256-
&format!("Missing public key for {kid}."),
257-
"During public key extraction",
258-
);
259-
return Ok(false);
260-
};
261-
262-
let tbs_data = tbs_data(kid, doc.doc_meta(), doc.content()).context("Probably a bug, cannot build CBOR COSE bytes for signature verification from the structurally valid COSE object.")?;
263-
264-
let Ok(signature_bytes) = sign.signature().try_into() else {
265-
report.invalid_value(
266-
"cose signature",
267-
&format!("{}", sign.signature().len()),
268-
&format!("must be {}", ed25519_dalek::Signature::BYTE_SIZE),
269-
"During encoding cose signature to bytes",
270-
);
271-
return Ok(false);
272-
};
273-
274-
let signature = ed25519_dalek::Signature::from_bytes(signature_bytes);
275-
if pk.verify_strict(&tbs_data, &signature).is_err() {
276-
report.functional_validation(
277-
&format!("Verification failed for signature with Key ID {kid}"),
278-
"During signature validation with verifying key",
279-
);
280-
return Ok(false);
281-
}
282-
283-
Ok(true)
284-
}
285-
286212
#[cfg(test)]
287213
mod tests {
288214
use crate::validator::document_rules_init;

rust/signed_doc/src/validator/rules/content.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,14 +211,14 @@ mod tests {
211211

212212
use super::*;
213213
use crate::{
214-
builder::tests::Builder, metadata::SupportedField,
215-
providers::tests::TestCatalystSignedDocumentProvider, DocLocator, DocumentRef,
214+
builder::tests::Builder, metadata::SupportedField, providers::tests::TestCatalystProvider,
215+
DocLocator, DocumentRef,
216216
};
217217

218218
#[allow(clippy::too_many_lines)]
219219
#[tokio::test]
220220
async fn content_rule_templated_test() {
221-
let mut provider = TestCatalystSignedDocumentProvider::default();
221+
let mut provider = TestCatalystProvider::default();
222222

223223
let exp_template_type = UuidV4::new();
224224
let content_type = ContentType::Json;
@@ -437,7 +437,7 @@ mod tests {
437437
#[allow(clippy::too_many_lines)]
438438
#[tokio::test]
439439
async fn content_rule_static_test() {
440-
let provider = TestCatalystSignedDocumentProvider::default();
440+
let provider = TestCatalystProvider::default();
441441
let schema = json_schema::JsonSchema::try_from(&serde_json::json!({})).unwrap();
442442
let content_schema = ContentSchema::Json(schema);
443443
let json_content = serde_json::to_vec(&serde_json::json!({})).unwrap();
@@ -470,7 +470,7 @@ mod tests {
470470
#[tokio::test]
471471
async fn template_rule_not_specified_test() {
472472
let rule = ContentRule::NotSpecified;
473-
let provider = TestCatalystSignedDocumentProvider::default();
473+
let provider = TestCatalystProvider::default();
474474

475475
let doc = Builder::new().build();
476476
assert!(rule.check(&doc, &provider).await.unwrap());

rust/signed_doc/src/validator/rules/doc_ref.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ mod tests {
188188

189189
use super::*;
190190
use crate::{
191-
builder::tests::Builder, metadata::SupportedField,
192-
providers::tests::TestCatalystSignedDocumentProvider, DocLocator, DocumentRef,
191+
builder::tests::Builder, metadata::SupportedField, providers::tests::TestCatalystProvider,
192+
DocLocator, DocumentRef,
193193
};
194194

195195
#[test_case(
@@ -397,12 +397,9 @@ mod tests {
397397
)]
398398
#[tokio::test]
399399
async fn ref_specified_test(
400-
doc_gen: impl FnOnce(
401-
&[DocType; 2],
402-
&mut TestCatalystSignedDocumentProvider,
403-
) -> CatalystSignedDocument
400+
doc_gen: impl FnOnce(&[DocType; 2], &mut TestCatalystProvider) -> CatalystSignedDocument
404401
) -> bool {
405-
let mut provider = TestCatalystSignedDocumentProvider::default();
402+
let mut provider = TestCatalystProvider::default();
406403

407404
let exp_types: [DocType; 2] = [UuidV4::new().into(), UuidV4::new().into()];
408405

@@ -430,7 +427,7 @@ mod tests {
430427

431428
#[tokio::test]
432429
async fn ref_specified_optional_test() {
433-
let provider = TestCatalystSignedDocumentProvider::default();
430+
let provider = TestCatalystProvider::default();
434431
let rule = RefRule::Specified {
435432
exp_ref_types: vec![UuidV4::new().into()],
436433
optional: true,
@@ -439,7 +436,7 @@ mod tests {
439436
let doc = Builder::new().build();
440437
assert!(rule.check(&doc, &provider).await.unwrap());
441438

442-
let provider = TestCatalystSignedDocumentProvider::default();
439+
let provider = TestCatalystProvider::default();
443440
let rule = RefRule::Specified {
444441
exp_ref_types: vec![UuidV4::new().into()],
445442
optional: false,
@@ -452,7 +449,7 @@ mod tests {
452449
#[tokio::test]
453450
async fn ref_rule_not_specified_test() {
454451
let rule = RefRule::NotSpecified;
455-
let provider = TestCatalystSignedDocumentProvider::default();
452+
let provider = TestCatalystProvider::default();
456453

457454
let doc = Builder::new().build();
458455
assert!(rule.check(&doc, &provider).await.unwrap());

rust/signed_doc/src/validator/rules/id.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ mod tests {
102102

103103
use super::*;
104104
use crate::{
105-
builder::tests::Builder, metadata::SupportedField,
106-
providers::tests::TestCatalystSignedDocumentProvider, UuidV7,
105+
builder::tests::Builder, metadata::SupportedField, providers::tests::TestCatalystProvider,
106+
UuidV7,
107107
};
108108

109109
#[test_case(
@@ -171,9 +171,9 @@ mod tests {
171171
)]
172172
#[tokio::test]
173173
async fn id_test(
174-
doc_gen: impl FnOnce(&TestCatalystSignedDocumentProvider) -> CatalystSignedDocument
174+
doc_gen: impl FnOnce(&TestCatalystProvider) -> CatalystSignedDocument
175175
) -> bool {
176-
let provider = TestCatalystSignedDocumentProvider::default();
176+
let provider = TestCatalystProvider::default();
177177
let doc = doc_gen(&provider);
178178

179179
IdRule.check(&doc, &provider).await.unwrap()

0 commit comments

Comments
 (0)