credx/knox/bbs/
pok_signature_proof.rs1use crate::error::Error;
2use crate::knox::bbs::PublicKey;
3use crate::knox::short_group_sig_core::short_group_traits::ProofOfSignatureKnowledge;
4use crate::CredxResult;
5use blsful::inner_types::{
6 multi_miller_loop, G1Affine, G2Affine, G2Prepared, MillerLoopResult, PrimeCurveAffine, Scalar,
7};
8use bulletproofs::inner_types::G1Projective;
9use elliptic_curve::group::Curve;
10use elliptic_curve::{Group, PrimeField};
11use merlin::Transcript;
12use serde::{Deserialize, Serialize};
13use std::collections::{BTreeMap, BTreeSet};
14
15#[derive(Debug, Clone, Deserialize, Serialize)]
17pub struct PokSignatureProof {
18 pub(crate) a_bar: G1Projective,
19 pub(crate) b_bar: G1Projective,
20 pub(crate) t: G1Projective,
21 pub(crate) proof: Vec<Scalar>,
22}
23
24impl ProofOfSignatureKnowledge for PokSignatureProof {
25 type PublicKey = PublicKey;
26
27 fn add_proof_contribution(
28 &self,
29 _public_key: &Self::PublicKey,
30 _revealed_messages: &[(usize, Scalar)],
31 _challenge: Scalar,
32 transcript: &mut Transcript,
33 ) {
34 transcript.append_message(b"a_bar", self.a_bar.to_compressed().as_ref());
35 transcript.append_message(b"b_bar", self.b_bar.to_compressed().as_ref());
36 transcript.append_message(b"commitment", self.t.to_compressed().as_ref());
37 }
38
39 fn verify(
40 &self,
41 public_key: &Self::PublicKey,
42 revealed_messages: &[(usize, Scalar)],
43 challenge: Scalar,
44 ) -> CredxResult<()> {
45 if (self.a_bar.is_identity() | self.b_bar.is_identity() | self.t.is_identity()).into() {
46 return Err(Error::General("Invalid proof - identity"));
47 }
48 if public_key.is_invalid().into() {
49 return Err(Error::General("Invalid public key"));
50 }
51 let mut points = Vec::with_capacity(public_key.y.len() + 3);
52 let mut msgs = Vec::with_capacity(revealed_messages.len());
53 let mut known = BTreeSet::new();
54 for (idx, msg) in revealed_messages {
55 if *idx >= public_key.y.len() {
56 continue;
57 }
58 known.insert(*idx);
59 points.push(public_key.y[*idx]);
60 msgs.push(*msg);
61 }
62 let lhs = -G1Projective::sum_of_products(&points, &msgs) - G1Projective::GENERATOR;
63 points.clear();
64 msgs.clear();
65
66 for (idx, y) in public_key.y.iter().enumerate() {
67 if known.contains(&idx) {
68 continue;
69 }
70 points.push(*y);
71 }
72
73 points.push(self.a_bar);
74 points.push(self.b_bar);
75 points.push(lhs);
76 let mut scalars = self.proof.clone();
77 scalars.push(-challenge);
78 let commitment = G1Projective::sum_of_products(&points, &scalars);
79 if self.t != commitment {
80 return Err(Error::General("Invalid proof - invalid messages"));
81 }
82
83 let res = multi_miller_loop(&[
84 (
85 &self.a_bar.to_affine(),
86 &G2Prepared::from(public_key.w.to_affine()),
87 ),
88 (
89 &self.b_bar.to_affine(),
90 &G2Prepared::from(-G2Affine::generator()),
91 ),
92 ])
93 .final_exponentiation()
94 .is_identity()
95 .unwrap_u8()
96 == 1;
97
98 if res {
99 Ok(())
100 } else {
101 Err(Error::General("Invalid proof - signature proof"))
102 }
103 }
104
105 fn get_hidden_message_proofs(
106 &self,
107 public_key: &Self::PublicKey,
108 rvl_msgs: &[(usize, Scalar)],
109 ) -> CredxResult<BTreeMap<usize, Scalar>> {
110 if public_key.y.len() < rvl_msgs.len() {
111 return Err(Error::General("Proof error"));
112 }
113 if public_key.is_invalid().unwrap_u8() == 1u8 {
114 return Err(Error::General("Proof error"));
115 }
116
117 let mut hidden = BTreeMap::new();
118 let mut j = 0;
119 for i in 0..public_key.y.len() {
120 if j < rvl_msgs.len() && rvl_msgs[j].0 == i {
121 j += 1;
122 continue;
123 }
124 let message = self
125 .proof
126 .get(i - j)
127 .ok_or(Error::General("invalid proof"))?;
128 hidden.insert(i, *message);
129 }
130
131 Ok(hidden)
132 }
133}
134
135impl PokSignatureProof {
136 pub fn to_bytes(&self) -> Vec<u8> {
138 let mut buffer = Vec::with_capacity(48 * 3 + 32 * self.proof.len());
139
140 buffer.extend_from_slice(&self.a_bar.to_compressed());
141 buffer.extend_from_slice(&self.b_bar.to_compressed());
142 buffer.extend_from_slice(&self.t.to_compressed());
143 for scalar in &self.proof {
144 buffer.extend_from_slice(scalar.to_repr().as_ref());
145 }
146 buffer
147 }
148
149 pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Option<Self> {
151 const SIZE: usize = 32 * 3 + 48 * 3;
152 let buffer = bytes.as_ref();
153 if buffer.len() < SIZE {
154 return None;
155 }
156 if buffer.len() % 32 != 0 {
157 return None;
158 }
159
160 let hid_msg_cnt = (buffer.len() - 48 * 3) / 32;
161 let mut offset = 48;
162 let mut end = 96;
163 let a_bar = G1Affine::from_compressed(&<[u8; 48]>::try_from(&buffer[..offset]).unwrap())
164 .map(G1Projective::from);
165 let b_bar = G1Affine::from_compressed(&<[u8; 48]>::try_from(&buffer[offset..end]).unwrap())
166 .map(G1Projective::from);
167 offset = end;
168 end += 48;
169 let commitment =
170 G1Affine::from_compressed(&<[u8; 48]>::try_from(&buffer[offset..end]).unwrap())
171 .map(G1Projective::from);
172
173 if (a_bar.is_none() | b_bar.is_none() | commitment.is_none()).into() {
174 return None;
175 }
176
177 offset = end;
178 end += 32;
179
180 let mut proof = Vec::new();
181 for _ in 0..hid_msg_cnt {
182 let c = Scalar::from_be_bytes(&<[u8; 32]>::try_from(&buffer[offset..end]).unwrap());
183 offset = end;
184 end = offset + 32;
185 if c.is_none().unwrap_u8() == 1 {
186 return None;
187 }
188
189 proof.push(c.unwrap());
190 }
191 Some(Self {
192 a_bar: a_bar.unwrap(),
193 b_bar: b_bar.unwrap(),
194 t: commitment.unwrap(),
195 proof,
196 })
197 }
198}