),
}
/// Trait allowing access to the document through it's proper protocol version.
///
/// This trait is generic over `P` providing all supported protocol version variants.
///
/// A lifetime is specified to allow enum variants to hold references to the document.
pub trait IntoSpecializedDocument {
/// Get a protocol-specific document wrapped in an enum variant.
fn into_specialized(self) -> P;
}
/// Trait helper for building new documents.
pub trait DocumentBuilder {
/// Type of the builded document.
type Document: Document;
/// Type of the private keys signing the documents.
type PrivateKey: PrivateKey<
Signature = <::PublicKey as PublicKey>::Signature,
>;
/// Build a document with provided signatures.
fn build_with_signature(
&self,
signatures: Vec<<::PublicKey as PublicKey>::Signature>,
) -> Self::Document;
/// Build a document and sign it with the private key.
fn build_and_sign(&self, private_keys: Vec) -> Self::Document;
}
/// Trait for a document parser from a `S` source
/// format to a `D` document. Will return the
/// parsed document or an `E` error.
pub trait DocumentParser {
/// Parse a source and return a document or an error.
fn parse(source: S) -> Result;
}
#[cfg(test)]
mod tests {
use super::*;
use duniter_crypto::keys::{Signature, ed25519};
// simple text document for signature testing
#[derive(Debug, Clone)]
struct PlainTextDocument {
pub text: &'static str,
pub issuers: Vec,
pub signatures: Vec,
}
impl Document for PlainTextDocument {
type PublicKey = ed25519::PublicKey;
type CurrencyType = str;
fn version(&self) -> u16 {
unimplemented!()
}
fn currency(&self) -> &str {
unimplemented!()
}
fn issuers(&self) -> &Vec {
&self.issuers
}
fn signatures(&self) -> &Vec {
&self.signatures
}
fn as_bytes(&self) -> &[u8] {
self.text.as_bytes()
}
}
#[test]
fn verify_signatures() {
let text = "Version: 10
Type: Identity
Currency: duniter_unit_test_currency
Issuer: DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV
UniqueID: tic
Timestamp: 0-E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
";
// good pair
let issuer1 = ed25519::PublicKey::from_base58(
"DNann1Lh55eZMEDXeYt59bzHbA3NJR46DeQYCS2qQdLV",
).unwrap();
let sig1 = ed25519::Signature::from_base64(
"1eubHHbuNfilHMM0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
).unwrap();
// incorrect pair
let issuer2 = ed25519::PublicKey::from_base58(
"DNann1Lh55eZMEDXeYt32bzHbA3NJR46DeQYCS2qQdLV",
).unwrap();
let sig2 = ed25519::Signature::from_base64(
"1eubHHbuNfilHHH0G2bI30iZzebQ2cQ1PC7uPAw08FGMM\
mQCRerlF/3pc4sAcsnexsxBseA/3lY03KlONqJBAg==",
).unwrap();
{
let doc = PlainTextDocument {
text,
issuers: vec![issuer1],
signatures: vec![sig1],
};
assert_eq!(doc.verify_signatures(), VerificationResult::Valid());
}
{
let doc = PlainTextDocument {
text,
issuers: vec![issuer1],
signatures: vec![sig2],
};
assert_eq!(
doc.verify_signatures(),
VerificationResult::Invalid(vec![0])
);
}
{
let doc = PlainTextDocument {
text,
issuers: vec![issuer1, issuer2],
signatures: vec![sig1],
};
assert_eq!(
doc.verify_signatures(),
VerificationResult::IncompletePairs(2, 1)
);
}
{
let doc = PlainTextDocument {
text,
issuers: vec![issuer1],
signatures: vec![sig1, sig2],
};
assert_eq!(
doc.verify_signatures(),
VerificationResult::IncompletePairs(1, 2)
);
}
}
}