1use serde::{Deserialize, Serialize};
16use zkryptium::{
17 bbsplus::{
18 keys::{BBSplusPublicKey, BBSplusSecretKey},
19 proof::BBSplusPoKSignature,
20 signature::BBSplusSignature,
21 },
22 schemes::{
23 algorithms::{BbsBls12381Sha256, BbsBls12381Shake256},
24 generics::{PoKSignature, Signature},
25 },
26};
27
28use crate::{
29 encoding::base64url_decode,
30 errors::CustomError,
31 jpt::payloads::Payloads,
32 jwk::{
33 alg_parameters::{Algorithm, JwkAlgorithmParameters},
34 key::Jwk,
35 utils::{check_alg_curve_compatibility, check_presentation_alg_curve_compatibility},
36 },
37};
38
39use super::algs::{PresentationProofAlgorithm, ProofAlgorithm};
40
41#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
42pub struct BBSplusAlgorithm {}
43
44impl BBSplusAlgorithm {
45 pub fn generate_issuer_proof(
46 alg: ProofAlgorithm,
47 payloads: &Payloads,
48 key: &Jwk,
49 issuer_header: &[u8],
50 ) -> Result<Vec<u8>, CustomError> {
51 let key_params = match &key.key_params {
52 JwkAlgorithmParameters::EllipticCurve(params) => {
53 if params.is_private() == false {
54 return Err(CustomError::ProofGenerationError(
55 "key is not compatible".to_string(),
56 ));
57 }
58 params
59 }
60 _ => {
61 return Err(CustomError::ProofGenerationError(
62 "key is not compatible".to_string(),
63 ))
64 }
65 };
66
67 if check_alg_curve_compatibility(Algorithm::Proof(alg.clone()), key_params.crv.clone())
68 == false
69 {
70 Err(CustomError::ProofGenerationError(
71 "key is not compatible".to_string(),
72 ))
73 } else {
74 let x: [u8; 96] = base64url_decode(&key_params.x)
75 .try_into()
76 .map_err(|_| CustomError::InvalidJwk)?;
77 let y: [u8; 96] = base64url_decode(&key_params.y)
78 .try_into()
79 .map_err(|_| CustomError::InvalidJwk)?;
80
81 let pk =
82 BBSplusPublicKey::from_coordinates(&x, &y).map_err(|_| CustomError::InvalidJwk)?;
83
84 let sk = BBSplusSecretKey::from_bytes(&base64url_decode(
85 key_params.d.as_ref().ok_or(CustomError::InvalidJwk)?,
86 ))
87 .map_err(|_| CustomError::SerializationError)?;
88
89 let proof = match alg {
90 ProofAlgorithm::BBS => Signature::<BbsBls12381Sha256>::sign(
91 Some(&payloads.to_bytes()?),
92 &sk,
93 &pk,
94 Some(issuer_header),
95 )
96 .map_err(|e| CustomError::ProofGenerationError(e.to_string()))?
97 .to_bytes(),
98 ProofAlgorithm::BBS_SHAKE256 => Signature::<BbsBls12381Shake256>::sign(
99 Some(&payloads.to_bytes()?),
100 &sk,
101 &pk,
102 Some(issuer_header),
103 )
104 .map_err(|e| CustomError::ProofGenerationError(e.to_string()))?
105 .to_bytes(),
106 _ => unreachable!(),
107 };
108
109 Ok(proof.to_vec())
110 }
111 }
112
113 pub fn verify_issuer_proof(
114 alg: ProofAlgorithm,
115 key: &Jwk,
116 proof: &[u8],
117 issuer_header: &[u8],
118 payloads: &Payloads,
119 ) -> Result<(), CustomError> {
120 let key_params = match &key.key_params {
121 JwkAlgorithmParameters::EllipticCurve(params) => {
122 if params.is_public() == false {
123 return Err(CustomError::ProofGenerationError(
124 "key is not compatible".to_string(),
125 ));
126 }
127 params
128 }
129 _ => {
130 return Err(CustomError::ProofGenerationError(
131 "key is not compatible".to_string(),
132 ))
133 }
134 };
135
136 if check_alg_curve_compatibility(Algorithm::Proof(alg.clone()), key_params.crv.clone())
137 == false
138 {
139 Err(CustomError::ProofGenerationError(
140 "key is not compatible".to_string(),
141 ))
142 } else {
143 let x: [u8; 96] = base64url_decode(&key_params.x)
144 .try_into()
145 .map_err(|_| CustomError::InvalidJwk)?;
146 let y: [u8; 96] = base64url_decode(&key_params.y)
147 .try_into()
148 .map_err(|_| CustomError::InvalidJwk)?;
149
150 let pk =
151 BBSplusPublicKey::from_coordinates(&x, &y).map_err(|_| CustomError::InvalidJwk)?;
152 let proof = BBSplusSignature::from_bytes(proof.try_into().map_err(|_| {
153 CustomError::ProofVerificationError("Proof is not valid".to_owned())
154 })?)
155 .map_err(|_| CustomError::SerializationError)?;
156 let check = match alg {
157 ProofAlgorithm::BBS => {
158 let proof = Signature::<BbsBls12381Sha256>::BBSplus(proof);
159 proof.verify(&pk, Some(&payloads.to_bytes()?), Some(issuer_header))
160 }
161 ProofAlgorithm::BBS_SHAKE256 => {
162 let proof = Signature::<BbsBls12381Shake256>::BBSplus(proof);
163 proof.verify(&pk, Some(&payloads.to_bytes()?), Some(issuer_header))
164 }
165 _ => unreachable!(),
166 };
167
168 check.map_err(|e| CustomError::ProofVerificationError(e.to_string()))
169 }
170 }
171
172 pub fn generate_presentation_proof(
173 alg: PresentationProofAlgorithm,
174 signature: &[u8],
175 payloads: &Payloads,
176 key: &Jwk,
177 issuer_header: &[u8],
178 presentation_header: &[u8],
179 ) -> Result<Vec<u8>, CustomError> {
180 let key_params = match &key.key_params {
181 JwkAlgorithmParameters::EllipticCurve(params) => {
182 if params.is_public() == false {
183 return Err(CustomError::ProofGenerationError(
184 "key is not compatible".to_string(),
185 ));
186 }
187 params
188 }
189 _ => {
190 return Err(CustomError::ProofGenerationError(
191 "key is not compatible".to_string(),
192 ))
193 }
194 };
195
196 if check_presentation_alg_curve_compatibility(alg, key_params.crv.clone()) == false {
197 Err(CustomError::ProofGenerationError(
198 "key is not compatible".to_string(),
199 ))
200 } else {
201 let x: [u8; 96] = base64url_decode(&key_params.x)
202 .try_into()
203 .map_err(|_| CustomError::InvalidJwk)?;
204 let y: [u8; 96] = base64url_decode(&key_params.y)
205 .try_into()
206 .map_err(|_| CustomError::InvalidJwk)?;
207
208 let pk =
209 BBSplusPublicKey::from_coordinates(&x, &y).map_err(|_| CustomError::InvalidJwk)?;
210 let revealed_message_indexes = payloads.get_disclosed_indexes();
211 let proof = match alg {
212 PresentationProofAlgorithm::BBS => {
213 PoKSignature::<BbsBls12381Sha256>::proof_gen(
214 &pk,
215 &signature,
216 Some(issuer_header),
217 Some(presentation_header),
218 Some(&payloads.to_bytes()?),
219 Some(&revealed_message_indexes),
220 )
221 .map_err(|e| CustomError::ProofGenerationError(e.to_string()))?
222 .to_bytes()
223 }
224 PresentationProofAlgorithm::BBS_SHAKE256 => {
225 PoKSignature::<BbsBls12381Shake256>::proof_gen(
226 &pk,
227 &signature,
228 Some(issuer_header),
229 Some(presentation_header),
230 Some(&payloads.to_bytes()?),
231 Some(&revealed_message_indexes),
232 )
233 .map_err(|e| CustomError::ProofGenerationError(e.to_string()))?
234 .to_bytes()
235 }
236 _ => unreachable!(),
237 };
238
239 Ok(proof.to_vec())
240 }
241 }
242
243 pub fn verify_presentation_proof(
244 alg: PresentationProofAlgorithm,
245 key: &Jwk,
246 proof: &[u8],
247 presentation_header: &[u8],
248 issuer_header: &[u8],
249 payloads: &Payloads,
250 ) -> Result<(), CustomError> {
251 let key_params = match &key.key_params {
252 JwkAlgorithmParameters::EllipticCurve(params) => {
253 if params.is_public() == false {
254 return Err(CustomError::ProofGenerationError(
255 "key is not compatible".to_string(),
256 ));
257 }
258 params
259 }
260 _ => {
261 return Err(CustomError::ProofGenerationError(
262 "key is not compatible".to_string(),
263 ))
264 }
265 };
266
267 if check_presentation_alg_curve_compatibility(alg, key_params.crv.clone()) == false {
268 Err(CustomError::ProofGenerationError(
269 "key is not compatible".to_string(),
270 ))
271 } else {
272 let x: [u8; 96] = base64url_decode(&key_params.x)
273 .try_into()
274 .map_err(|_| CustomError::InvalidJwk)?;
275 let y: [u8; 96] = base64url_decode(&key_params.y)
276 .try_into()
277 .map_err(|_| CustomError::InvalidJwk)?;
278
279 let pk =
280 BBSplusPublicKey::from_coordinates(&x, &y).map_err(|_| CustomError::InvalidJwk)?;
281 let disclosed_indexes = payloads.get_disclosed_indexes();
282 let proof = BBSplusPoKSignature::from_bytes(proof.try_into().map_err(|_| {
283 CustomError::ProofVerificationError("Proof is not valid".to_owned())
284 })?)
285 .map_err(|_| CustomError::InvalidJwk)?;
286 let check = match alg {
287 PresentationProofAlgorithm::BBS => {
288 let proof = PoKSignature::<BbsBls12381Sha256>::BBSplus(proof);
289 proof.proof_verify(
290 &pk,
291 Some(&payloads.get_disclosed_payloads().to_bytes()?),
292 Some(&disclosed_indexes),
293 Some(issuer_header),
294 Some(presentation_header),
295 )
296 }
297 PresentationProofAlgorithm::BBS_SHAKE256 => {
298 let proof = PoKSignature::<BbsBls12381Shake256>::BBSplus(proof);
299 proof.proof_verify(
300 &pk,
301 Some(&payloads.get_disclosed_payloads().to_bytes()?),
302 Some(&disclosed_indexes),
303 Some(issuer_header),
304 Some(presentation_header),
305 )
306 }
307 _ => unreachable!(),
308 };
309
310 check.map_err(|e| CustomError::ProofVerificationError(e.to_string()))
311 }
312 }
313}