baseid_bbs/
proof.rs

1use crate::error::BbsError;
2use zkryptium::bbsplus::keys::BBSplusPublicKey;
3use zkryptium::schemes::algorithms::BbsBls12381Sha256;
4use zkryptium::schemes::generics::PoKSignature;
5
6/// Derive a zero-knowledge proof revealing only specified message indices.
7pub fn bbs_proof_gen(
8    public_key: &[u8],
9    signature: &[u8],
10    messages: &[Vec<u8>],
11    disclosed_indices: &[usize],
12    header: Option<&[u8]>,
13    nonce: Option<&[u8]>,
14) -> Result<Vec<u8>, BbsError> {
15    let pk = BBSplusPublicKey::from_bytes(public_key)
16        .map_err(|e| BbsError::ProofGenerationFailed(format!("invalid public key: {:?}", e)))?;
17
18    let msg_refs: Option<&[Vec<u8>]> = if messages.is_empty() {
19        None
20    } else {
21        Some(messages)
22    };
23
24    let idx_refs: Option<&[usize]> = if disclosed_indices.is_empty() {
25        None
26    } else {
27        Some(disclosed_indices)
28    };
29
30    let proof = PoKSignature::<BbsBls12381Sha256>::proof_gen(
31        &pk, signature, header, nonce, msg_refs, idx_refs,
32    )
33    .map_err(|e| BbsError::ProofGenerationFailed(format!("{:?}", e)))?;
34
35    Ok(proof.to_bytes())
36}
37
38/// Verify a BBS+ zero-knowledge proof.
39pub fn bbs_proof_verify(
40    public_key: &[u8],
41    proof: &[u8],
42    disclosed_messages: &[(usize, Vec<u8>)],
43    header: Option<&[u8]>,
44    nonce: Option<&[u8]>,
45) -> Result<bool, BbsError> {
46    let pk = BBSplusPublicKey::from_bytes(public_key)
47        .map_err(|e| BbsError::ProofVerificationFailed(format!("invalid public key: {:?}", e)))?;
48
49    let pok = PoKSignature::<BbsBls12381Sha256>::from_bytes(proof)
50        .map_err(|e| BbsError::ProofVerificationFailed(format!("invalid proof: {:?}", e)))?;
51
52    // Separate indices and messages
53    let indices: Vec<usize> = disclosed_messages.iter().map(|(i, _)| *i).collect();
54    let msg_vecs: Vec<Vec<u8>> = disclosed_messages.iter().map(|(_, m)| m.clone()).collect();
55
56    let disclosed_refs: Option<&[Vec<u8>]> = if msg_vecs.is_empty() {
57        None
58    } else {
59        Some(&msg_vecs)
60    };
61    let indices_refs: Option<&[usize]> = if indices.is_empty() {
62        None
63    } else {
64        Some(&indices)
65    };
66
67    match pok.proof_verify(&pk, disclosed_refs, indices_refs, header, nonce) {
68        Ok(()) => Ok(true),
69        Err(_) => Ok(false),
70    }
71}