1use alloc::vec::Vec;
7use core::cmp::Ordering;
8use crypto_bigint::{BoxedUint, ConcatenatingMul, Gcd, Integer, NonZero, RandomMod};
9use k256::ProjectivePoint;
10use rand_core::CryptoRng;
11use sha2::{Digest, Sha256};
12use zeroize::{ZeroizeOnDrop, Zeroizing};
13
14use crate::{
15 arith::{
16 fixed_base::FixedBase,
17 monty::Modulus,
18 sbig::{SBig, resized},
19 },
20 curve::{decode_point, derive_h_f, encode_point, is_identity},
21 df::DfParams,
22 error::{Error, Result},
23 paillier::{PaillierPk, PaillierSk},
24 params::Params,
25 rsa::tough::{sample_df, sample_rsa},
26 transcript::{Transcript, uint_from_be, uint_to_be},
27 zk::{
28 df::{DfProof, DfStatement, DfWitness},
29 fac::{FacParams, FacProof, FacWitness},
30 modulus::{ModProof, ModWitness},
31 },
32};
33
34pub const FORMAT_VERSION: u8 = 0x01;
36pub const MAX_SERVER_ID_LEN: usize = 256;
38pub const RHO_TABLE_WINDOW: u32 = 4;
40pub const DF_TABLE_WINDOW: u32 = 3;
42
43#[derive(Clone, Debug)]
45pub struct SetupData {
46 pub params: Params,
47 pub fac: FacParams,
48 pub setup_id: [u8; 32],
49 pub server_id: Vec<u8>,
50 pub n: BoxedUint,
51 pub n_hat: BoxedUint,
52 pub rho0: BoxedUint,
53 pub rho: BoxedUint,
54 pub t: BoxedUint,
55 pub s1: BoxedUint,
56 pub s2: BoxedUint,
57 pub h: ProjectivePoint,
58 pub f: ProjectivePoint,
59 pub pi_mod: ModProof,
60 pub pi_fac: FacProof,
61 pub pi_df: DfProof,
62}
63
64#[derive(ZeroizeOnDrop)]
66pub struct ServerSetupSecret {
67 #[zeroize(skip)]
68 sk: PaillierSk,
69}
70
71impl core::fmt::Debug for ServerSetupSecret {
72 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
73 f.write_str("ServerSetupSecret(***)")
74 }
75}
76
77const SECRET_VERSION: u8 = 0x01;
79
80impl ServerSetupSecret {
81 pub fn paillier_sk(&self) -> &PaillierSk {
82 &self.sk
83 }
84
85 pub fn export_secret(&self, params: &Params) -> Result<Zeroizing<Vec<u8>>> {
87 let len = nb(params) / 2;
88 let (p, q) = self.sk.factors();
89 let mut out = Zeroizing::new(Vec::with_capacity(1 + 2 * len));
90 out.push(SECRET_VERSION);
91 out.extend_from_slice(&Zeroizing::new(uint_to_be(p, len)?));
92 out.extend_from_slice(&Zeroizing::new(uint_to_be(q, len)?));
93 Ok(out)
94 }
95
96 pub fn import_secret(bytes: &[u8], data: &SetupData) -> Result<Self> {
99 let len = nb(&data.params) / 2;
100 if bytes.len() != 1 + 2 * len || bytes[0] != SECRET_VERSION {
101 return Err(Error::InvalidEncoding);
102 }
103 let bits = len as u32 * 8;
104 let p = uint_from_be(&bytes[1..1 + len], bits)?;
105 let q = uint_from_be(&bytes[1 + len..], bits)?;
106 let sk = PaillierSk::new(p, q)?;
107 let (p, q) = sk.factors();
108 let n = p.concatenating_mul(q);
109 let bits = n.bits_precision().max(data.n.bits_precision());
110 if resized(&n, bits).cmp_vartime(resized(&data.n, bits)) != Ordering::Equal {
111 return Err(Error::InvalidEncoding);
112 }
113 Ok(Self { sk })
114 }
115}
116
117fn nb(params: &Params) -> usize {
118 (params.n_rsa as usize).div_ceil(8)
119}
120
121fn lt(a: &BoxedUint, b: &BoxedUint) -> bool {
122 let bits = a.bits_precision().max(b.bits_precision());
123 resized(a, bits).cmp_vartime(resized(b, bits)) == Ordering::Less
124}
125
126fn is_unit(a: &BoxedUint, n: &BoxedUint) -> bool {
127 let bits = a.bits_precision().max(n.bits_precision());
128 bool::from(resized(a, bits).gcd_vartime(&resized(n, bits)).is_one())
129}
130
131fn aux(setup_id: &[u8; 32], server_id: &[u8]) -> Vec<u8> {
132 let mut a = Vec::with_capacity(36 + server_id.len());
133 a.extend_from_slice(setup_id);
134 a.extend_from_slice(&(server_id.len() as u32).to_be_bytes());
135 a.extend_from_slice(server_id);
136 a
137}
138
139fn base_tx(params: &Params, setup_id: &[u8; 32], server_id: &[u8]) -> Transcript {
141 let mut tx = Transcript::new("setup");
142 tx.append("params_id", &[params.id as u8]);
143 tx.append("setup_id", setup_id);
144 tx.append("server_id", server_id);
145 tx
146}
147
148fn rho_of(n: &BoxedUint, rho0: &BoxedUint) -> Result<BoxedUint> {
150 let n2 = Modulus::new(n.concatenating_mul_self())?;
151 let exp = resized(n, n.bits_precision() + 64);
152 let exp = exp.wrapping_add(&exp);
153 let r = n2.pow_vartime(&n2.residue(rho0), &SBig::from_uint(exp))?;
154 Ok(r.retrieve())
155}
156
157trait SquareExt {
158 fn concatenating_mul_self(&self) -> BoxedUint;
159}
160impl SquareExt for BoxedUint {
161 fn concatenating_mul_self(&self) -> BoxedUint {
162 crypto_bigint::ConcatenatingMul::concatenating_mul(self, self)
163 }
164}
165
166pub fn server_setup<R: CryptoRng + ?Sized>(
168 rng: &mut R,
169 params: &Params,
170 setup_id: [u8; 32],
171 server_id: &[u8],
172) -> Result<(SetupData, ServerSetupSecret)> {
173 server_setup_with(rng, params, &FacParams::standard()?, setup_id, server_id)
174}
175
176pub fn server_setup_with<R: CryptoRng + ?Sized>(
178 rng: &mut R,
179 params: &Params,
180 fac: &FacParams,
181 setup_id: [u8; 32],
182 server_id: &[u8],
183) -> Result<(SetupData, ServerSetupSecret)> {
184 if server_id.len() > MAX_SERVER_ID_LEN {
185 return Err(Error::OutOfRange);
186 }
187 let tx = base_tx(params, &setup_id, server_id);
188 let rsa = sample_rsa(rng, params).map_err(|_| Error::InvalidModulus)?;
190 let n = rsa.n.clone();
191 let (p1, p2) = (rsa.secret.p1.p(), rsa.secret.p2.p());
192 let pi_mod = ModProof::prove(rng, &tx, params, &n, &ModWitness { p1, p2 })?;
193 let pi_fac = FacProof::prove(rng, &tx, params, fac, &n, &FacWitness { p: p1, q: p2 })?;
194 let sk = PaillierSk::new(p1.clone(), p2.clone())?;
195 let nz = Option::<NonZero<BoxedUint>>::from(n.to_nz()).ok_or(Error::InvalidModulus)?;
197 let rho0 = loop {
198 let r = BoxedUint::random_mod_vartime(rng, &nz);
199 if is_unit(&r, &n) {
200 break r;
201 }
202 };
203 let rho = rho_of(&n, &rho0)?;
204 let df = sample_df(rng, params).map_err(|_| Error::InvalidModulus)?;
206 let st = DfStatement::from_uints(&df.n_hat, &df.t, &df.s1, &df.s2)?;
207 let pi_df = DfProof::prove(rng, &tx, params, &st, &DfWitness::from_secret(&df.secret))?;
208 let (h, f) = derive_h_f(&aux(&setup_id, server_id))?;
210 let data = SetupData {
211 params: *params,
212 fac: fac.clone(),
213 setup_id,
214 server_id: server_id.to_vec(),
215 n,
216 n_hat: df.n_hat.clone(),
217 rho0,
218 rho,
219 t: df.t.clone(),
220 s1: df.s1.clone(),
221 s2: df.s2.clone(),
222 h,
223 f,
224 pi_mod,
225 pi_fac,
226 pi_df,
227 };
228 Ok((data, ServerSetupSecret { sk }))
229}
230
231struct Reader<'a> {
232 b: &'a [u8],
233 pos: usize,
234}
235
236impl<'a> Reader<'a> {
237 fn take(&mut self, len: usize) -> Result<&'a [u8]> {
238 let end = self.pos.checked_add(len).ok_or(Error::InvalidEncoding)?;
239 let s = self.b.get(self.pos..end).ok_or(Error::InvalidEncoding)?;
240 self.pos = end;
241 Ok(s)
242 }
243}
244
245impl SetupData {
246 pub fn aux(&self) -> Vec<u8> {
248 aux(&self.setup_id, &self.server_id)
249 }
250
251 pub fn paillier_pk(&self) -> Result<PaillierPk> {
253 PaillierPk::new(self.n.clone(), &self.rho)
254 }
255
256 pub fn to_bytes(&self) -> Result<Vec<u8>> {
258 let p = &self.params;
259 let len = nb(p);
260 if self.server_id.len() > MAX_SERVER_ID_LEN {
261 return Err(Error::OutOfRange);
262 }
263 let mut out = Vec::new();
264 out.push(FORMAT_VERSION);
265 out.extend_from_slice(&self.setup_id);
266 out.extend_from_slice(&(self.server_id.len() as u16).to_be_bytes());
267 out.extend_from_slice(&self.server_id);
268 for v in [&self.n, &self.n_hat, &self.rho0] {
269 out.extend_from_slice(&uint_to_be(v, len)?);
270 }
271 out.extend_from_slice(&uint_to_be(&self.rho, 2 * len)?);
272 for v in [&self.t, &self.s1, &self.s2] {
273 out.extend_from_slice(&uint_to_be(v, len)?);
274 }
275 for pt in [&self.h, &self.f] {
276 if is_identity(pt) {
277 return Err(Error::InvalidEncoding);
278 }
279 out.extend_from_slice(&encode_point(pt));
280 }
281 out.extend_from_slice(&self.pi_mod.encode(p.n_rsa)?);
282 out.extend_from_slice(&self.pi_fac.encode(p, &self.fac, p.n_rsa)?);
283 out.extend_from_slice(&self.pi_df.encode(p)?);
284 Ok(out)
285 }
286
287 pub fn hash(&self) -> Result<[u8; 32]> {
289 Ok(Sha256::digest(self.to_bytes()?).into())
290 }
291
292 pub fn from_bytes(bytes: &[u8], params: &Params) -> Result<Self> {
294 Self::from_bytes_with(bytes, params, &FacParams::standard()?)
295 }
296
297 pub fn from_bytes_with(bytes: &[u8], params: &Params, fac: &FacParams) -> Result<Self> {
298 let bad = Error::InvalidEncoding;
299 let len = nb(params);
300 let mut r = Reader { b: bytes, pos: 0 };
301 if r.take(1)?[0] != FORMAT_VERSION {
302 return Err(bad);
303 }
304 let setup_id: [u8; 32] = r.take(32)?.try_into().map_err(|_| bad)?;
305 let sl = u16::from_be_bytes(r.take(2)?.try_into().map_err(|_| bad)?) as usize;
306 if sl > MAX_SERVER_ID_LEN {
307 return Err(bad);
308 }
309 let server_id = r.take(sl)?.to_vec();
310 let fixed = 8 * len + 66;
311 let (ml, fl, dl) = (
312 ModProof::encoded_len(params, params.n_rsa),
313 FacProof::encoded_len(params, fac, params.n_rsa),
314 DfProof::encoded_len(params),
315 );
316 if bytes.len() != r.pos + fixed + ml + fl + dl {
317 return Err(bad);
318 }
319 let mut uint = |l: usize| uint_from_be(r.take(l)?, params.n_rsa);
320 let n = uint(len)?;
321 let n_hat = uint(len)?;
322 let rho0 = uint(len)?;
323 let rho = uint(2 * len)?;
324 let t = uint(len)?;
325 let s1 = uint(len)?;
326 let s2 = uint(len)?;
327 let h = decode_point(r.take(33)?)?;
328 let f = decode_point(r.take(33)?)?;
329 let pi_mod = ModProof::decode(r.take(ml)?, params, params.n_rsa)?;
330 let pi_fac = FacProof::decode(r.take(fl)?, params, fac, params.n_rsa)?;
331 let pi_df = DfProof::decode(r.take(dl)?, params)?;
332 let data = Self {
333 params: *params,
334 fac: fac.clone(),
335 setup_id,
336 server_id,
337 n,
338 n_hat,
339 rho0,
340 rho,
341 t,
342 s1,
343 s2,
344 h,
345 f,
346 pi_mod,
347 pi_fac,
348 pi_df,
349 };
350 data.check_basic()?;
351 Ok(data)
352 }
353
354 fn check_basic(&self) -> Result<()> {
356 let fail = Error::VerificationFailed;
357 let p = &self.params;
358 if self.server_id.len() > MAX_SERVER_ID_LEN {
359 return Err(fail);
360 }
361 for m in [&self.n, &self.n_hat] {
362 if m.bits() != p.n_rsa || !bool::from(m.is_odd()) {
363 return Err(fail);
364 }
365 }
366 if !lt(&self.rho0, &self.n) || !is_unit(&self.rho0, &self.n) {
367 return Err(fail);
368 }
369 let n2 = self.n.concatenating_mul_self();
370 if !lt(&self.rho, &n2) || !is_unit(&self.rho, &self.n) {
371 return Err(fail);
372 }
373 for v in [&self.t, &self.s1, &self.s2] {
374 if !lt(v, &self.n_hat) || !is_unit(v, &self.n_hat) {
375 return Err(fail);
376 }
377 }
378 Ok(())
379 }
380
381 pub fn verify(&self, params: &Params) -> Result<VerifiedSetup> {
383 self.verify_with(params, &FacParams::standard()?)
384 }
385
386 pub fn verify_with(&self, params: &Params, fac: &FacParams) -> Result<VerifiedSetup> {
387 let fail = Error::VerificationFailed;
388 if self.params != *params {
389 return Err(fail);
390 }
391 self.check_basic()?;
392 let (h, f) = derive_h_f(&self.aux()).map_err(|_| fail)?;
393 if is_identity(&self.h) || is_identity(&self.f) || self.h != h || self.f != f || h == f {
394 return Err(fail);
395 }
396 let want = rho_of(&self.n, &self.rho0)?;
397 let bits = want.bits_precision().max(self.rho.bits_precision());
398 if resized(&want, bits) != resized(&self.rho, bits) {
399 return Err(fail);
400 }
401 let tx = base_tx(params, &self.setup_id, &self.server_id);
402 self.pi_fac.verify(&tx, params, fac, &self.n)?;
403 let st = DfStatement::from_uints(&self.n_hat, &self.t, &self.s1, &self.s2)?;
404 self.pi_df.verify(&tx, params, &st)?;
405 self.pi_mod.verify(&tx, params, &self.n, params.n_rsa)?;
406 let hash = self.hash()?;
407 let pk = self.paillier_pk()?;
408 let df = DfParams::new(st.n_hat, st.t, st.s1, st.s2);
409 Ok(VerifiedSetup {
410 pk,
411 df,
412 h,
413 f,
414 hash,
415 server_id: self.server_id.clone(),
416 params: *params,
417 rho_table: None,
418 })
419 }
420}
421
422impl SetupData {
423 pub fn assume_verified(&self, params: &Params) -> Result<VerifiedSetup> {
426 if self.params != *params {
427 return Err(Error::VerificationFailed);
428 }
429 self.check_basic()?;
430 let st = DfStatement::from_uints(&self.n_hat, &self.t, &self.s1, &self.s2)?;
431 Ok(VerifiedSetup {
432 pk: self.paillier_pk()?,
433 df: DfParams::new(st.n_hat, st.t, st.s1, st.s2),
434 h: self.h,
435 f: self.f,
436 hash: self.hash()?,
437 server_id: self.server_id.clone(),
438 params: *params,
439 rho_table: None,
440 })
441 }
442}
443
444pub struct VerifiedSetup {
446 pk: PaillierPk,
447 df: DfParams,
448 h: ProjectivePoint,
449 f: ProjectivePoint,
450 hash: [u8; 32],
451 server_id: Vec<u8>,
452 params: Params,
453 rho_table: Option<FixedBase>,
454}
455
456impl VerifiedSetup {
457 pub fn server_id(&self) -> &[u8] {
459 &self.server_id
460 }
461
462 pub fn paillier_pk(&self) -> &PaillierPk {
463 &self.pk
464 }
465 pub fn df(&self) -> &DfParams {
466 &self.df
467 }
468 pub fn h(&self) -> &ProjectivePoint {
469 &self.h
470 }
471 pub fn f(&self) -> &ProjectivePoint {
472 &self.f
473 }
474 pub fn hash(&self) -> [u8; 32] {
476 self.hash
477 }
478 pub fn params(&self) -> &Params {
479 &self.params
480 }
481 pub fn rho_table(&self) -> Option<&FixedBase> {
482 self.rho_table.as_ref()
483 }
484
485 pub fn with_tables_custom(mut self, rho_window: u32, df_bits: u32, df_window: u32) -> Self {
488 let rho = self.pk.rho().clone();
489 self.rho_table = Some(FixedBase::new(
490 self.pk.mod_n2(),
491 &rho,
492 self.params.n_lambda0(),
493 rho_window,
494 ));
495 self.df = self.df.with_tables(df_bits, df_window);
496 self
497 }
498
499 pub fn with_tables(mut self) -> Self {
502 let p = self.params;
503 let eps = p.eps();
504 self.rho_table = Some(FixedBase::new(
505 self.pk.mod_n2(),
506 self.pk.rho(),
507 p.n_lambda0() + eps,
508 RHO_TABLE_WINDOW,
509 ));
510 self.df = self.df.with_tables_sized(
511 [p.n_t_rho + eps, p.n_a() + eps, p.n_b() + eps],
512 DF_TABLE_WINDOW,
513 );
514 self
515 }
516
517 pub fn tables_size_bytes(&self) -> usize {
519 self.rho_table.as_ref().map_or(0, FixedBase::size_bytes) + self.df.tables_size_bytes()
520 }
521}
522
523#[cfg(test)]
524mod tests {
525 extern crate std;
526 use super::*;
527 use crate::{
528 params::{PARAMS_128, ParamsId},
529 rsa::tough::{ToughSpec, sample_tough_prime},
530 zk::{fac::FacParams, modulus::ModRep},
531 };
532 use rand_chacha::ChaCha8Rng;
533 use rand_core::SeedableRng;
534 use std::{sync::OnceLock, time::Instant};
535
536 fn small_params() -> Params {
537 Params {
538 id: ParamsId::P128,
539 ell: 16,
540 nu: 16,
541 n_rsa: 512,
542 r_mod: 8,
543 r_df: 16,
544 r_df_star: 4,
545 tough_count: 4,
546 tough_bits: 64,
547 ..PARAMS_128
548 }
549 }
550
551 struct Fx {
552 fac: FacParams,
553 data: SetupData,
554 other: SetupData,
555 sk: ServerSetupSecret,
556 }
557
558 fn fx() -> &'static Fx {
559 static F: OnceLock<Fx> = OnceLock::new();
560 F.get_or_init(|| {
561 let p = small_params();
562 let mut rng = ChaCha8Rng::seed_from_u64(1);
563 let d_bits = p.n_rsa + 2 * p.ell + 2 * p.nu + 4;
564 let d = sample_tough_prime(&mut rng, d_bits, 7, ToughSpec::SAFE).unwrap();
565 let fac = FacParams::new(d.p().clone()).unwrap();
566 let (data, sk) = server_setup_with(&mut rng, &p, &fac, [7u8; 32], b"server-A").unwrap();
567 let (other, _) = server_setup_with(&mut rng, &p, &fac, [9u8; 32], b"server-B").unwrap();
568 Fx {
569 fac,
570 data,
571 other,
572 sk,
573 }
574 })
575 }
576
577 fn ok(d: &SetupData) -> bool {
578 d.verify_with(&small_params(), &fx().fac).is_ok()
579 }
580
581 #[test]
582 fn server_secret_export_roundtrip_and_binding() {
583 let f = fx();
584 let p = small_params();
585 let bytes = f.sk.export_secret(&p).unwrap();
586 let back = ServerSetupSecret::import_secret(&bytes, &f.data).unwrap();
587 let pk = f.data.paillier_pk().unwrap();
588 let c = pk.g_pow(&SBig::from_i64(777));
589 let m = back.paillier_sk().dec(&c).unwrap();
590 assert_eq!(resized(&m, 64), BoxedUint::from(777u64));
591 assert!(ServerSetupSecret::import_secret(&bytes, &f.other).is_err());
593 assert!(ServerSetupSecret::import_secret(&bytes[1..], &f.data).is_err());
595 let mut bad = bytes.to_vec();
596 bad[0] ^= 1;
597 assert!(ServerSetupSecret::import_secret(&bad, &f.data).is_err());
598 let mut bad = bytes.to_vec();
599 *bad.last_mut().unwrap() ^= 2;
600 assert!(ServerSetupSecret::import_secret(&bad, &f.data).is_err());
601 }
602
603 #[test]
604 fn honest_setup_verifies() {
605 let f = fx();
606 let v = f.data.verify_with(&small_params(), &f.fac).unwrap();
607 assert_eq!(v.hash(), f.data.hash().unwrap());
608 assert_eq!(v.paillier_pk().n(), &f.data.n);
609 assert_eq!(
610 f.data.verify_with(&small_params(), &f.fac).unwrap().hash(),
611 v.hash()
612 );
613 assert_eq!(std::format!("{:?}", f.sk), "ServerSetupSecret(***)");
614 let pk = f.data.paillier_pk().unwrap();
616 let c = pk.g_pow(&SBig::from_i64(12345));
617 let m = f.sk.paillier_sk().dec(&c).unwrap();
618 assert_eq!(resized(&m, 64), BoxedUint::from(12345u64));
619 let v = v.with_tables();
620 assert!(v.rho_table().is_some() && v.tables_size_bytes() > 0);
621 let mut p2 = small_params();
623 p2.r_mod = 9;
624 assert!(f.data.verify_with(&p2, &f.fac).is_err());
625 }
626
627 #[test]
628 fn roundtrip_and_strict_length() {
629 let f = fx();
630 let p = small_params();
631 let bytes = f.data.to_bytes().unwrap();
632 let back = SetupData::from_bytes_with(&bytes, &p, &f.fac).unwrap();
633 assert_eq!(back.to_bytes().unwrap(), bytes);
634 assert!(ok(&back));
635 assert!(SetupData::from_bytes_with(&bytes[1..], &p, &f.fac).is_err());
636 assert!(SetupData::from_bytes_with(&bytes[..bytes.len() - 1], &p, &f.fac).is_err());
637 let mut long = bytes.clone();
638 long.push(0);
639 assert!(SetupData::from_bytes_with(&long, &p, &f.fac).is_err());
640 assert!(SetupData::from_bytes_with(&[], &p, &f.fac).is_err());
641 }
642
643 #[test]
644 fn byte_flip_in_every_field_rejected() {
645 let f = fx();
646 let p = small_params();
647 let bytes = f.data.to_bytes().unwrap();
648 let len = nb(&p);
649 let sl = f.data.server_id.len();
650 let mut regions: Vec<(usize, usize)> = std::vec![(0, 1), (1, 32), (33, 2), (35, sl)];
651 let mut pos = 35 + sl;
652 for l in [len, len, len, 2 * len, len, len, len, 33, 33] {
653 regions.push((pos, l));
654 pos += l;
655 }
656 for l in [
657 ModProof::encoded_len(&p, p.n_rsa),
658 FacProof::encoded_len(&p, &f.fac, p.n_rsa),
659 DfProof::encoded_len(&p),
660 ] {
661 regions.push((pos, l));
662 pos += l;
663 }
664 assert_eq!(pos, bytes.len());
665 let orig = f.data.hash().unwrap();
666 for (start, l) in regions {
667 for off in [0, l / 2, l - 1] {
668 for bit in [0x01u8, 0x80] {
669 let mut b = bytes.clone();
670 b[start + off] ^= bit;
671 match SetupData::from_bytes_with(&b, &p, &f.fac) {
672 Err(_) => {}
673 Ok(d) => {
674 assert!(!ok(&d), "flip at {} accepted", start + off);
675 assert_ne!(d.hash().unwrap(), orig);
676 }
677 }
678 }
679 }
680 }
681 }
682
683 #[test]
684 fn field_tampering_rejected() {
685 let f = fx();
686 let one = |b: &BoxedUint| {
687 let bits = b.bits_precision();
688 b.wrapping_add(BoxedUint::one_with_precision(bits))
689 };
690 let orig = f.data.hash().unwrap();
691 let mut cases: Vec<SetupData> = Vec::new();
692 let mut d = f.data.clone();
693 core::mem::swap(&mut d.h, &mut d.f);
694 cases.push(d);
695 let mut d = f.data.clone();
696 d.h += d.f;
697 cases.push(d);
698 let mut d = f.data.clone();
699 d.rho = one(&d.rho);
700 cases.push(d);
701 let mut d = f.data.clone();
702 d.rho0 = one(&d.rho0);
703 cases.push(d);
704 let mut d = f.data.clone();
705 d.t = one(&d.t);
706 cases.push(d);
707 let mut d = f.data.clone();
708 d.s1 = d.s2.clone();
709 cases.push(d);
710 let mut d = f.data.clone();
711 d.s2 = BoxedUint::zero_with_precision(512);
712 cases.push(d);
713 let mut d = f.data.clone();
715 d.n_hat = d.n_hat.shr_vartime(1).unwrap();
716 cases.push(d);
717 let mut d = f.data.clone();
718 d.n = d.n_hat.clone();
719 cases.push(d);
720 let mut d = f.data.clone();
721 d.n = f.other.n.clone();
722 cases.push(d);
723 let mut d = f.data.clone();
725 d.pi_mod = f.other.pi_mod.clone();
726 cases.push(d);
727 let mut d = f.data.clone();
728 d.pi_fac = f.other.pi_fac.clone();
729 cases.push(d);
730 let mut d = f.data.clone();
731 d.pi_df = f.other.pi_df.clone();
732 cases.push(d);
733 let mut d = f.data.clone();
734 d.server_id = f.other.server_id.clone();
735 cases.push(d);
736 let mut d = f.data.clone();
737 d.setup_id = f.other.setup_id;
738 cases.push(d);
739 let mut d = f.data.clone();
740 d.server_id = std::vec![0u8; 257];
741 cases.push(d);
742 let mut d = f.data.clone();
744 d.pi_mod.reps[0] = ModRep {
745 a: !d.pi_mod.reps[0].a,
746 ..d.pi_mod.reps[0].clone()
747 };
748 cases.push(d);
749 let mut d = f.data.clone();
750 d.pi_df.e[0] ^= 1;
751 cases.push(d);
752 let mut d = f.data.clone();
753 d.pi_fac.w = one(&d.pi_fac.w);
754 cases.push(d);
755 for (i, d) in cases.iter().enumerate() {
756 assert!(!ok(d), "case {i} accepted");
757 if let Ok(h) = d.hash() {
758 assert_ne!(h, orig, "case {i}");
759 }
760 }
761 assert!(ok(&f.data));
762 }
763
764 #[test]
765 fn server_id_limit() {
766 let p = small_params();
767 let mut rng = ChaCha8Rng::seed_from_u64(5);
768 let r = server_setup_with(&mut rng, &p, &fx().fac, [0; 32], &[0u8; 257]);
769 assert!(r.is_err());
770 }
771
772 #[test]
773 #[ignore]
774 fn full_size_setup() {
775 let mut rng = ChaCha8Rng::seed_from_u64(99);
776 let t0 = Instant::now();
777 let (data, _sk) = server_setup(&mut rng, &PARAMS_128, [1u8; 32], b"example.org").unwrap();
778 std::println!("server setup: {:?}", t0.elapsed());
779 let bytes = data.to_bytes().unwrap();
780 std::println!("setup size: {} bytes", bytes.len());
781 let data = SetupData::from_bytes(&bytes, &PARAMS_128).unwrap();
782 let fac = FacParams::standard().unwrap();
783 let t0 = Instant::now();
784 data.check_basic().unwrap();
785 std::println!("check_basic: {:?}", t0.elapsed());
786 let t0 = Instant::now();
787 let want = rho_of(&data.n, &data.rho0).unwrap();
788 std::println!("rho check: {:?} {}", t0.elapsed(), want.bits());
789 let tx = base_tx(&PARAMS_128, &data.setup_id, &data.server_id);
790 let t0 = Instant::now();
791 data.pi_fac.verify(&tx, &PARAMS_128, &fac, &data.n).unwrap();
792 std::println!("fac verify: {:?}", t0.elapsed());
793 let st = DfStatement::from_uints(&data.n_hat, &data.t, &data.s1, &data.s2).unwrap();
794 let t0 = Instant::now();
795 data.pi_df.verify(&tx, &PARAMS_128, &st).unwrap();
796 std::println!("df verify: {:?}", t0.elapsed());
797 let t0 = Instant::now();
798 data.pi_mod
799 .verify(&tx, &PARAMS_128, &data.n, PARAMS_128.n_rsa)
800 .unwrap();
801 std::println!("mod verify: {:?}", t0.elapsed());
802 let t0 = Instant::now();
803 let v = data.verify(&PARAMS_128).unwrap();
804 std::println!("client verify total: {:?}", t0.elapsed());
805 let t0 = Instant::now();
806 let v = v.with_tables();
807 std::println!(
808 "tables: {:?}, {} bytes (rho {}, df {})",
809 t0.elapsed(),
810 v.tables_size_bytes(),
811 v.rho_table().map_or(0, FixedBase::size_bytes),
812 v.df().tables_size_bytes()
813 );
814 assert_eq!(v.hash(), data.hash().unwrap());
815 }
816}