1use serde::{Deserialize, Serialize};
16
17use crate::{
18 encoding::{
19 base64url_decode, base64url_encode, base64url_encode_serializable, SerializationType,
20 },
21 errors::CustomError,
22 jpa::{algs::ProofAlgorithm, bbs_plus::BBSplusAlgorithm},
23 jpt::{
24 claims::{Claims, JptClaims},
25 payloads::{PayloadType, Payloads},
26 },
27 jwk::key::Jwk,
28};
29
30use super::header::IssuerProtectedHeader;
31
32macro_rules! expect_three {
35 ($iter:expr) => {{
36 let mut i = $iter;
37 match (i.next(), i.next(), i.next()) {
38 (Some(first), Some(second), Some(third)) => (first, second, third),
39 _ => return Err(CustomError::InvalidIssuedJwp),
40 }
41 }};
42}
43
44#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
46pub struct JwpIssuedBuilder {
47 issuer_protected_header: Option<IssuerProtectedHeader>,
48 payloads: Option<Payloads>,
49}
50
51impl JwpIssuedBuilder {
52 pub fn new(issuer_protected_header: IssuerProtectedHeader, jpt_claims: JptClaims) -> Self {
53 let (claims, payloads) = jpt_claims.get_claims_and_payloads();
54 let mut issuer_protected_header = issuer_protected_header;
56 issuer_protected_header.set_claims(Some(claims));
57
58 Self {
59 issuer_protected_header: Some(issuer_protected_header),
60 payloads: Some(payloads),
61 }
62 }
63
64 pub fn get_issuer_protected_header(&self) -> Option<&IssuerProtectedHeader> {
65 self.issuer_protected_header.as_ref()
66 }
67
68 pub fn get_payloads(&self) -> Option<&Payloads> {
69 self.payloads.as_ref()
70 }
71
72 pub fn build_with_proof(&self, proof: Vec<u8>) -> Result<JwpIssued, CustomError> {
73 if let Some(issuer_protected_header) = self.issuer_protected_header.clone() {
74 if let Some(payloads) = self.payloads.clone() {
75 Ok(JwpIssued {
76 issuer_protected_header,
77 payloads,
78 proof,
79 })
80 } else {
81 Err(CustomError::IncompleteJwpBuild(
82 crate::errors::IncompleteJwpBuild::NoClaimsAndPayloads,
83 ))
84 }
85 } else {
86 Err(CustomError::IncompleteJwpBuild(
87 crate::errors::IncompleteJwpBuild::NoIssuerHeader,
88 ))
89 }
90 }
91
92 pub fn build(&self, jwk: &Jwk) -> Result<JwpIssued, CustomError> {
93 if let Some(issuer_protected_header) = self.issuer_protected_header.clone() {
94 if let Some(payloads) = self.payloads.clone() {
95 let issuer_header_oct = serde_json::to_vec(&self.issuer_protected_header).unwrap();
96 let proof = Self::generate_proof(
97 issuer_protected_header.alg(),
98 &jwk,
99 &issuer_header_oct,
100 &payloads,
101 )?;
102
103 Ok(JwpIssued {
104 issuer_protected_header,
105 payloads,
106 proof,
107 })
108 } else {
109 Err(CustomError::IncompleteJwpBuild(
110 crate::errors::IncompleteJwpBuild::NoClaimsAndPayloads,
111 ))
112 }
113 } else {
114 Err(CustomError::IncompleteJwpBuild(
115 crate::errors::IncompleteJwpBuild::NoIssuerHeader,
116 ))
117 }
118 }
119
120 fn generate_proof(
121 alg: ProofAlgorithm,
122 key: &Jwk,
123 issuer_header_oct: &[u8],
124 payloads: &Payloads,
125 ) -> Result<Vec<u8>, CustomError> {
126 let proof = match alg {
127 ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256 => {
128 BBSplusAlgorithm::generate_issuer_proof(alg, payloads, key, issuer_header_oct)?
129 }
130 ProofAlgorithm::SU_ES256 => todo!(),
131 ProofAlgorithm::MAC_H256 => todo!(),
132 ProofAlgorithm::MAC_H384 => todo!(),
133 ProofAlgorithm::MAC_H512 => todo!(),
134 ProofAlgorithm::MAC_K25519 => todo!(),
135 ProofAlgorithm::MAC_K448 => todo!(),
136 ProofAlgorithm::MAC_H256K => todo!(),
137 };
138
139 Ok(proof)
140 }
141}
142
143#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
145pub struct JwpIssuedDecoder {
146 issuer_protected_header: IssuerProtectedHeader,
147 payloads: Payloads,
148 proof: Vec<u8>,
149}
150
151impl JwpIssuedDecoder {
152 pub fn decode(jpt: &str, serialization: SerializationType) -> Result<Self, CustomError> {
154 match serialization {
155 SerializationType::COMPACT => {
156 let (encoded_issuer_protected_header, encoded_payloads, encoded_proof) =
157 expect_three!(jpt.splitn(3, '.'));
158 let issuer_protected_header: IssuerProtectedHeader =
159 serde_json::from_slice(&base64url_decode(encoded_issuer_protected_header))
160 .map_err(|_| CustomError::SerializationError)?;
161 let payloads = Payloads(
163 encoded_payloads
164 .splitn(issuer_protected_header.claims().unwrap().0.len(), "~")
165 .map(|v| {
166 if v == "" {
167 (serde_json::Value::Null, PayloadType::Undisclosed)
168 } else {
169 (
170 serde_json::from_slice(&base64url_decode(v)).unwrap(),
171 PayloadType::Disclosed,
172 )
173 }
174 })
175 .collect(),
176 );
177
178 if !match issuer_protected_header.claims() {
179 Some(claims) => claims.0.len() == payloads.0.len(),
180 None => payloads.0.len() == 0,
181 } {
182 return Err(CustomError::InvalidIssuedJwp);
183 }
184
185 let proof = base64url_decode(encoded_proof);
186 Ok(Self {
187 issuer_protected_header,
188 payloads,
189 proof: proof,
190 })
191 }
192 SerializationType::JSON => todo!(),
193 }
194 }
195
196 pub fn verify(&self, key: &Jwk) -> Result<JwpIssued, CustomError> {
198 let issuer_header_oct = serde_json::to_vec(&self.issuer_protected_header).unwrap();
199
200 Self::verify_proof(
201 self.issuer_protected_header.alg(),
202 key,
203 &self.proof,
204 &issuer_header_oct,
205 &self.payloads,
206 )?;
207
208 Ok(JwpIssued {
209 issuer_protected_header: self.issuer_protected_header.clone(),
210 payloads: self.payloads.clone(),
211 proof: self.proof.clone(),
212 })
213 }
214
215 pub fn get_header(&self) -> &IssuerProtectedHeader {
216 &self.issuer_protected_header
217 }
218
219 pub fn get_payloads(&self) -> &Payloads {
220 &self.payloads
221 }
222
223 fn verify_proof(
224 alg: ProofAlgorithm,
225 key: &Jwk,
226 proof: &[u8],
227 issuer_header_oct: &[u8],
228 payloads: &Payloads,
229 ) -> Result<(), CustomError> {
230 let check = match alg {
231 ProofAlgorithm::BLS12381_SHA256 | ProofAlgorithm::BLS12381_SHAKE256 => {
232 BBSplusAlgorithm::verify_issuer_proof(alg, &key, proof, issuer_header_oct, payloads)
233 }
234 ProofAlgorithm::SU_ES256 => todo!(),
235 ProofAlgorithm::MAC_H256 => todo!(),
236 ProofAlgorithm::MAC_H384 => todo!(),
237 ProofAlgorithm::MAC_H512 => todo!(),
238 ProofAlgorithm::MAC_K25519 => todo!(),
239 ProofAlgorithm::MAC_K448 => todo!(),
240 ProofAlgorithm::MAC_H256K => todo!(),
241 };
242
243 check
244 }
245}
246
247#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
249pub struct JwpIssued {
250 issuer_protected_header: IssuerProtectedHeader,
251 payloads: Payloads,
252 proof: Vec<u8>,
253}
254
255impl JwpIssued {
256 pub fn encode(&self, serialization: SerializationType) -> Result<String, CustomError> {
257 let issuer_header_oct = serde_json::to_vec(&self.issuer_protected_header)
260 .map_err(|_| CustomError::SerializationError)?;
261
262 let jwp = Self::serialize(
263 serialization,
264 &issuer_header_oct,
265 &self.payloads,
266 &self.proof,
267 );
268
269 Ok(jwp)
270 }
271
272 pub fn get_issuer_protected_header(&self) -> &IssuerProtectedHeader {
273 &self.issuer_protected_header
274 }
275
276 pub fn get_claims(&self) -> Option<&Claims> {
277 self.issuer_protected_header.claims()
278 }
279
280 pub fn set_claims(&mut self, claims: Claims) {
281 self.issuer_protected_header.set_claims(Some(claims));
282 }
283
284 pub fn get_payloads(&self) -> &Payloads {
285 &self.payloads
286 }
287
288 pub fn set_payloads(&mut self, payloads: Payloads) {
289 self.payloads = payloads;
290 }
291
292 pub fn get_proof(&self) -> &[u8] {
293 self.proof.as_ref()
294 }
295
296 pub fn set_proof(&mut self, proof: &[u8]) {
297 self.proof = proof.to_vec();
298 }
299
300 fn serialize(
301 serialization: SerializationType,
302 issuer_header_oct: &[u8],
303 payloads: &Payloads,
304 proof: &[u8],
305 ) -> String {
306 let encoded_issuer_header = base64url_encode(issuer_header_oct);
307 let encoded_proof = base64url_encode(proof);
308 let jwp = match serialization {
309 SerializationType::COMPACT => {
310 let encoded_payloads = payloads
311 .0
312 .iter()
313 .map(|p| {
314 if p.1 == PayloadType::Undisclosed {
315 "".to_string()
316 } else {
317 base64url_encode_serializable(&p.0)
318 }
319 })
320 .collect::<Vec<String>>()
321 .join("~");
322
323 format!(
324 "{}.{}.{}",
325 encoded_issuer_header, encoded_payloads, encoded_proof
326 )
327 }
328 SerializationType::JSON => todo!(),
329 };
330
331 jwp
332 }
333}