1use alloc::string::{String, ToString};
2
3use sha2::digest::Digest;
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use crate::curve::CurvePoint;
9use crate::hashing::BackendDigestOutput;
10use crate::hashing_ds::{hash_to_cfrag_verification, kfrag_signature_message};
11use crate::keys::digest_for_signing;
12use crate::params::Parameters;
13use crate::{Capsule, PublicKey, VerifiedCapsuleFrag};
14
15#[cfg(docsrs)]
17use crate::CapsuleFrag;
18
19#[cfg(feature = "default-serialization")]
20use crate::{DefaultDeserialize, DefaultSerialize};
21
22#[derive(Clone, Debug)]
49#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50pub struct ReencryptionEvidence {
51 pub e: CurvePoint,
53 pub ez: CurvePoint,
56 pub e1: CurvePoint,
58 pub e1h: CurvePoint,
60 pub e2: CurvePoint,
62 pub v: CurvePoint,
64 pub vz: CurvePoint,
67 pub v1: CurvePoint,
69 pub v1h: CurvePoint,
71 pub v2: CurvePoint,
73 pub uz: CurvePoint,
76 pub u1: CurvePoint,
78 pub u1h: CurvePoint,
80 pub u2: CurvePoint,
82 #[cfg_attr(feature = "serde", serde(with = "crate::serde_bytes::as_hex"))]
85 pub kfrag_validity_message_hash: BackendDigestOutput,
86 pub kfrag_signature_v: bool,
89}
90
91impl ReencryptionEvidence {
92 pub fn new(
94 capsule: &Capsule,
95 vcfrag: &VerifiedCapsuleFrag,
96 verifying_pk: &PublicKey,
97 delegating_pk: &PublicKey,
98 receiving_pk: &PublicKey,
99 ) -> Result<Self, String> {
100 let params = Parameters::new();
101
102 let cfrag = vcfrag.clone().unverify();
103
104 let u = params.u;
105 let u1 = cfrag.proof.kfrag_commitment;
106 let u2 = cfrag.proof.kfrag_pok;
107
108 let h = hash_to_cfrag_verification(
109 &capsule.point_e,
110 &cfrag.point_e1,
111 &cfrag.proof.point_e2,
112 &capsule.point_v,
113 &cfrag.point_v1,
114 &cfrag.proof.point_v2,
115 ¶ms.u,
116 &cfrag.proof.kfrag_commitment,
117 &cfrag.proof.kfrag_pok,
118 );
119
120 let e1h = &cfrag.point_e1 * &h;
121 let v1h = &cfrag.point_v1 * &h;
122 let u1h = &u1 * &h;
123
124 let z = cfrag.proof.signature;
125 let ez = &capsule.point_e * &z;
126 let vz = &capsule.point_v * &z;
127 let uz = &u * &z;
128
129 let kfrag_message = kfrag_signature_message(
130 &cfrag.kfrag_id,
131 &u1,
132 &cfrag.precursor,
133 Some(delegating_pk),
134 Some(receiving_pk),
135 );
136
137 let kfrag_message_hash = digest_for_signing(&kfrag_message).finalize();
138
139 let recovery_id = cfrag
140 .proof
141 .kfrag_signature
142 .get_recovery_id(verifying_pk, &kfrag_message)
143 .ok_or_else(|| {
144 "Could not find the recovery ID for the kfrag signature: mismatched verifying key?"
145 .to_string()
146 })?;
147
148 let kfrag_signature_v = recovery_id.is_y_odd();
150
151 Ok(Self {
155 e: capsule.point_e,
156 ez,
157 e1: cfrag.point_e1,
158 e1h,
159 e2: cfrag.proof.point_e2,
160 v: capsule.point_v,
161 vz,
162 v1: cfrag.point_v1,
163 v1h,
164 v2: cfrag.proof.point_v2,
165 uz,
166 u1,
167 u1h,
168 u2,
169 kfrag_validity_message_hash: kfrag_message_hash,
170 kfrag_signature_v,
171 })
172 }
173}
174
175#[cfg(feature = "default-serialization")]
176impl DefaultSerialize for ReencryptionEvidence {}
177
178#[cfg(feature = "default-serialization")]
179impl<'de> DefaultDeserialize<'de> for ReencryptionEvidence {}
180
181#[cfg(test)]
182mod tests {
183 use super::ReencryptionEvidence;
184 use crate::{
185 curve::CurveScalar, encrypt, generate_kfrags, hash_to_cfrag_verification, reencrypt,
186 Parameters, PublicKey, RecoverableSignature, SecretKey, Signature, Signer,
187 };
188
189 fn assert_eq_byte_refs(x: &(impl AsRef<[u8]> + ?Sized), y: &(impl AsRef<[u8]> + ?Sized)) {
190 assert_eq!(x.as_ref(), y.as_ref());
191 }
192
193 #[test]
194 fn contract() {
195 let threshold: usize = 2;
196 let num_frags: usize = threshold + 1;
197
198 let delegating_sk = SecretKey::random();
199 let delegating_pk = delegating_sk.public_key();
200
201 let signer = Signer::new(SecretKey::random());
202 let verifying_pk = signer.verifying_key();
203
204 let receiving_sk = SecretKey::random();
205 let receiving_pk = receiving_sk.public_key();
206
207 let plaintext = b"peace at dawn";
208 let (capsule, _ciphertext) = encrypt(&delegating_pk, plaintext).unwrap();
209
210 let vkfrags = generate_kfrags(
211 &delegating_sk,
212 &receiving_pk,
213 &signer,
214 threshold,
215 num_frags,
216 true,
217 true,
218 );
219
220 let vcfrag = reencrypt(&capsule, vkfrags[0].clone());
221
222 let evidence = ReencryptionEvidence::new(
223 &capsule,
224 &vcfrag,
225 &verifying_pk,
226 &delegating_pk,
227 &receiving_pk,
228 )
229 .unwrap();
230
231 let capsule_bytes = capsule.to_bytes_simple();
232 let cfrag_bytes = vcfrag.to_bytes_simple();
233
234 assert_eq_byte_refs(&capsule_bytes[0..33], &evidence.e.to_compressed_array());
236 assert_eq_byte_refs(&capsule_bytes[33..66], &evidence.v.to_compressed_array());
237
238 assert_eq_byte_refs(&cfrag_bytes[0..33], &evidence.e1.to_compressed_array());
239 assert_eq_byte_refs(&cfrag_bytes[33..66], &evidence.v1.to_compressed_array());
240 assert_eq_byte_refs(&cfrag_bytes[131..164], &evidence.e2.to_compressed_array());
241 assert_eq_byte_refs(&cfrag_bytes[164..197], &evidence.v2.to_compressed_array());
242 assert_eq_byte_refs(&cfrag_bytes[197..230], &evidence.u1.to_compressed_array());
243 assert_eq_byte_refs(&cfrag_bytes[230..263], &evidence.u2.to_compressed_array());
244
245 let z = CurveScalar::try_from_bytes(&cfrag_bytes[263..(263 + 32)]).unwrap();
246
247 let sig = Signature::try_from_be_bytes(&cfrag_bytes[295..(295 + 64)]).unwrap();
248 let rsig = RecoverableSignature::from_normalized(sig, evidence.kfrag_signature_v);
249
250 let vkey =
252 PublicKey::recover_from_prehash(&evidence.kfrag_validity_message_hash, &rsig).unwrap();
253 assert_eq!(vkey, verifying_pk);
254
255 let params = Parameters::new();
258
259 let h = hash_to_cfrag_verification(
260 &evidence.e,
261 &evidence.e1,
262 &evidence.e2,
263 &evidence.v,
264 &evidence.v1,
265 &evidence.v2,
266 ¶ms.u,
267 &evidence.u1,
268 &evidence.u2,
269 );
270
271 assert_eq!(&evidence.e * &z, &(&evidence.e1 * &h) + &evidence.e2);
272 assert_eq!(&evidence.v * &z, &(&evidence.v1 * &h) + &evidence.v2);
273 assert_eq!(¶ms.u * &z, &(&evidence.u1 * &h) + &evidence.u2);
274 }
275}