ssi_data_integrity_core/
canonicalization.rs1use digest::Digest;
2use std::marker::PhantomData;
3
4use ssi_json_ld::{Expandable, JsonLdLoaderProvider, JsonLdNodeObject};
5use ssi_rdf::{AnyLdEnvironment, LdEnvironment};
6
7use crate::{
8 hashing::ConcatOutputSize,
9 suite::{
10 standard::{self, HashingAlgorithm, TransformationAlgorithm, TransformationError},
11 TransformationOptions,
12 },
13 CryptographicSuite, ProofConfigurationRef, SerializeCryptographicSuite,
14 StandardCryptographicSuite,
15};
16
17pub struct CanonicalClaimsAndConfiguration {
19 pub claims: Vec<String>,
20 pub configuration: Vec<String>,
21}
22
23pub struct CanonicalizeClaimsAndConfiguration;
25
26impl<S: CryptographicSuite> standard::TransformationAlgorithm<S>
27 for CanonicalizeClaimsAndConfiguration
28{
29 type Output = CanonicalClaimsAndConfiguration;
30}
31
32impl<S, T, C> standard::TypedTransformationAlgorithm<S, T, C> for CanonicalizeClaimsAndConfiguration
33where
34 S: SerializeCryptographicSuite,
35 T: JsonLdNodeObject + Expandable,
36 C: JsonLdLoaderProvider,
37{
38 async fn transform(
39 context: &C,
40 data: &T,
41 proof_configuration: ProofConfigurationRef<'_, S>,
42 _verification_method: &S::VerificationMethod,
43 _transformation_options: TransformationOptions<S>,
44 ) -> Result<Self::Output, TransformationError> {
45 let mut ld = LdEnvironment::default();
46
47 let expanded = data
48 .expand_with(&mut ld, context.loader())
49 .await
50 .map_err(|e| TransformationError::JsonLdExpansion(e.to_string()))?;
51
52 Ok(CanonicalClaimsAndConfiguration {
53 claims: ld
54 .canonical_form_of(&expanded)
55 .map_err(TransformationError::JsonLdDeserialization)?,
56 configuration: proof_configuration
57 .expand(context, data)
58 .await
59 .map_err(TransformationError::ProofConfigurationExpansion)?
60 .nquads_lines(),
61 })
62 }
63}
64
65pub struct HashCanonicalClaimsAndConfiguration<H>(PhantomData<H>);
66
67impl<H, S> HashingAlgorithm<S> for HashCanonicalClaimsAndConfiguration<H>
68where
69 H: Digest,
70 H::OutputSize: ConcatOutputSize,
71 S: StandardCryptographicSuite,
72 S::Transformation: TransformationAlgorithm<S, Output = CanonicalClaimsAndConfiguration>,
73{
74 type Output = <H::OutputSize as ConcatOutputSize>::ConcatOutput;
75
76 fn hash(
77 input: standard::TransformedData<S>,
78 _proof_configuration: ProofConfigurationRef<S>,
79 _verification_method: &S::VerificationMethod,
80 ) -> Result<Self::Output, standard::HashingError> {
81 let proof_configuration_hash = input
82 .configuration
83 .iter()
84 .fold(H::new(), |h, line| h.chain_update(line.as_bytes()))
85 .finalize();
86
87 let claims_hash = input
88 .claims
89 .iter()
90 .fold(H::new(), |h, line| h.chain_update(line.as_bytes()))
91 .finalize();
92
93 Ok(<H::OutputSize as ConcatOutputSize>::concat(
94 proof_configuration_hash,
95 claims_hash,
96 ))
97 }
98}
99
100pub struct ConcatCanonicalClaimsAndConfiguration;
101
102impl<S> HashingAlgorithm<S> for ConcatCanonicalClaimsAndConfiguration
103where
104 S: StandardCryptographicSuite,
105 S::Transformation: TransformationAlgorithm<S, Output = CanonicalClaimsAndConfiguration>,
106{
107 type Output = String;
108
109 fn hash(
110 input: standard::TransformedData<S>,
111 _proof_configuration: ProofConfigurationRef<S>,
112 _verification_method: &S::VerificationMethod,
113 ) -> Result<Self::Output, standard::HashingError> {
114 let mut result = String::new();
115
116 for line in &input.configuration {
117 result.push_str(line);
118 }
119
120 result.push('\n');
121
122 for line in &input.claims {
123 result.push_str(line);
124 }
125
126 Ok(result)
127 }
128}