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_trivial(a: &BoxedUint, n: &BoxedUint) -> bool {
128 let bits = a.bits_precision().max(n.bits_precision());
129 let (a, n) = (resized(a, bits), resized(n, bits));
130 let one = BoxedUint::one_with_precision(bits);
131 a == one || a.wrapping_add(&one) == n
132}
133
134fn is_unit(a: &BoxedUint, n: &BoxedUint) -> bool {
135 let bits = a.bits_precision().max(n.bits_precision());
136 bool::from(resized(a, bits).gcd_vartime(&resized(n, bits)).is_one())
137}
138
139fn aux(setup_id: &[u8; 32], server_id: &[u8]) -> Vec<u8> {
140 let mut a = Vec::with_capacity(36 + server_id.len());
141 a.extend_from_slice(setup_id);
142 a.extend_from_slice(&(server_id.len() as u32).to_be_bytes());
143 a.extend_from_slice(server_id);
144 a
145}
146
147fn base_tx(params: &Params, setup_id: &[u8; 32], server_id: &[u8]) -> Transcript {
149 let mut tx = Transcript::new("setup");
150 tx.append("params_id", &[params.id as u8]);
151 tx.append("setup_id", setup_id);
152 tx.append("server_id", server_id);
153 tx
154}
155
156fn rho_of(n: &BoxedUint, rho0: &BoxedUint) -> Result<BoxedUint> {
158 let n2 = Modulus::new(n.concatenating_mul_self())?;
159 let exp = resized(n, n.bits_precision() + 64);
160 let exp = exp.wrapping_add(&exp);
161 let r = n2.pow_vartime(&n2.residue(rho0), &SBig::from_uint(exp))?;
162 Ok(r.retrieve())
163}
164
165trait SquareExt {
166 fn concatenating_mul_self(&self) -> BoxedUint;
167}
168impl SquareExt for BoxedUint {
169 fn concatenating_mul_self(&self) -> BoxedUint {
170 crypto_bigint::ConcatenatingMul::concatenating_mul(self, self)
171 }
172}
173
174pub fn server_setup<R: CryptoRng + ?Sized>(
176 rng: &mut R,
177 params: &Params,
178 setup_id: [u8; 32],
179 server_id: &[u8],
180) -> Result<(SetupData, ServerSetupSecret)> {
181 server_setup_with(rng, params, &FacParams::standard()?, setup_id, server_id)
182}
183
184pub fn server_setup_with<R: CryptoRng + ?Sized>(
186 rng: &mut R,
187 params: &Params,
188 fac: &FacParams,
189 setup_id: [u8; 32],
190 server_id: &[u8],
191) -> Result<(SetupData, ServerSetupSecret)> {
192 if server_id.len() > MAX_SERVER_ID_LEN {
193 return Err(Error::OutOfRange);
194 }
195 let tx = base_tx(params, &setup_id, server_id);
196 let rsa = sample_rsa(rng, params).map_err(|_| Error::InvalidModulus)?;
198 let n = rsa.n.clone();
199 let (p1, p2) = (rsa.secret.p1.p(), rsa.secret.p2.p());
200 let pi_mod = ModProof::prove(rng, &tx, params, &n, &ModWitness { p1, p2 })?;
201 let pi_fac = FacProof::prove(rng, &tx, params, fac, &n, &FacWitness { p: p1, q: p2 })?;
202 let sk = PaillierSk::new(p1.clone(), p2.clone())?;
203 let nz = Option::<NonZero<BoxedUint>>::from(n.to_nz()).ok_or(Error::InvalidModulus)?;
205 let rho0 = loop {
206 let r = BoxedUint::random_mod_vartime(rng, &nz);
207 if is_unit(&r, &n) {
208 break r;
209 }
210 };
211 let rho = rho_of(&n, &rho0)?;
212 let df = sample_df(rng, params).map_err(|_| Error::InvalidModulus)?;
214 let st = DfStatement::from_uints(&df.n_hat, &df.t, &df.s1, &df.s2)?;
215 let pi_df = DfProof::prove(rng, &tx, params, &st, &DfWitness::from_secret(&df.secret))?;
216 let (h, f) = derive_h_f(&aux(&setup_id, server_id))?;
218 let data = SetupData {
219 params: *params,
220 fac: fac.clone(),
221 setup_id,
222 server_id: server_id.to_vec(),
223 n,
224 n_hat: df.n_hat.clone(),
225 rho0,
226 rho,
227 t: df.t.clone(),
228 s1: df.s1.clone(),
229 s2: df.s2.clone(),
230 h,
231 f,
232 pi_mod,
233 pi_fac,
234 pi_df,
235 };
236 Ok((data, ServerSetupSecret { sk }))
237}
238
239struct Reader<'a> {
240 b: &'a [u8],
241 pos: usize,
242}
243
244impl<'a> Reader<'a> {
245 fn take(&mut self, len: usize) -> Result<&'a [u8]> {
246 let end = self.pos.checked_add(len).ok_or(Error::InvalidEncoding)?;
247 let s = self.b.get(self.pos..end).ok_or(Error::InvalidEncoding)?;
248 self.pos = end;
249 Ok(s)
250 }
251}
252
253impl SetupData {
254 pub fn aux(&self) -> Vec<u8> {
256 aux(&self.setup_id, &self.server_id)
257 }
258
259 pub fn paillier_pk(&self) -> Result<PaillierPk> {
261 PaillierPk::new(self.n.clone(), &self.rho)
262 }
263
264 pub fn to_bytes(&self) -> Result<Vec<u8>> {
266 let p = &self.params;
267 let len = nb(p);
268 if self.server_id.len() > MAX_SERVER_ID_LEN {
269 return Err(Error::OutOfRange);
270 }
271 let mut out = Vec::new();
272 out.push(FORMAT_VERSION);
273 out.extend_from_slice(&self.setup_id);
274 out.extend_from_slice(&(self.server_id.len() as u16).to_be_bytes());
275 out.extend_from_slice(&self.server_id);
276 for v in [&self.n, &self.n_hat, &self.rho0] {
277 out.extend_from_slice(&uint_to_be(v, len)?);
278 }
279 out.extend_from_slice(&uint_to_be(&self.rho, 2 * len)?);
280 for v in [&self.t, &self.s1, &self.s2] {
281 out.extend_from_slice(&uint_to_be(v, len)?);
282 }
283 for pt in [&self.h, &self.f] {
284 if is_identity(pt) {
285 return Err(Error::InvalidEncoding);
286 }
287 out.extend_from_slice(&encode_point(pt));
288 }
289 out.extend_from_slice(&self.pi_mod.encode(p.n_rsa)?);
290 out.extend_from_slice(&self.pi_fac.encode(p, &self.fac, p.n_rsa)?);
291 out.extend_from_slice(&self.pi_df.encode(p)?);
292 Ok(out)
293 }
294
295 pub fn hash(&self) -> Result<[u8; 32]> {
297 Ok(Sha256::digest(self.to_bytes()?).into())
298 }
299
300 pub fn from_bytes(bytes: &[u8], params: &Params) -> Result<Self> {
302 Self::from_bytes_with(bytes, params, &FacParams::standard()?)
303 }
304
305 pub fn from_bytes_with(bytes: &[u8], params: &Params, fac: &FacParams) -> Result<Self> {
306 let bad = Error::InvalidEncoding;
307 let len = nb(params);
308 let mut r = Reader { b: bytes, pos: 0 };
309 if r.take(1)?[0] != FORMAT_VERSION {
310 return Err(bad);
311 }
312 let setup_id: [u8; 32] = r.take(32)?.try_into().map_err(|_| bad)?;
313 let sl = u16::from_be_bytes(r.take(2)?.try_into().map_err(|_| bad)?) as usize;
314 if sl > MAX_SERVER_ID_LEN {
315 return Err(bad);
316 }
317 let server_id = r.take(sl)?.to_vec();
318 let fixed = 8 * len + 66;
319 let (ml, fl, dl) = (
320 ModProof::encoded_len(params, params.n_rsa),
321 FacProof::encoded_len(params, fac, params.n_rsa),
322 DfProof::encoded_len(params),
323 );
324 if bytes.len() != r.pos + fixed + ml + fl + dl {
325 return Err(bad);
326 }
327 let mut uint = |l: usize| uint_from_be(r.take(l)?, params.n_rsa);
328 let n = uint(len)?;
329 let n_hat = uint(len)?;
330 let rho0 = uint(len)?;
331 let rho = uint(2 * len)?;
332 let t = uint(len)?;
333 let s1 = uint(len)?;
334 let s2 = uint(len)?;
335 let h = decode_point(r.take(33)?)?;
336 let f = decode_point(r.take(33)?)?;
337 let pi_mod = ModProof::decode(r.take(ml)?, params, params.n_rsa)?;
338 let pi_fac = FacProof::decode(r.take(fl)?, params, fac, params.n_rsa)?;
339 let pi_df = DfProof::decode(r.take(dl)?, params)?;
340 let data = Self {
341 params: *params,
342 fac: fac.clone(),
343 setup_id,
344 server_id,
345 n,
346 n_hat,
347 rho0,
348 rho,
349 t,
350 s1,
351 s2,
352 h,
353 f,
354 pi_mod,
355 pi_fac,
356 pi_df,
357 };
358 data.check_basic()?;
359 Ok(data)
360 }
361
362 fn check_basic(&self) -> Result<()> {
364 let fail = Error::VerificationFailed;
365 let p = &self.params;
366 if self.server_id.len() > MAX_SERVER_ID_LEN {
367 return Err(fail);
368 }
369 for m in [&self.n, &self.n_hat] {
370 if m.bits() != p.n_rsa || !bool::from(m.is_odd()) {
371 return Err(fail);
372 }
373 }
374 if !lt(&self.rho0, &self.n) || !is_unit(&self.rho0, &self.n) {
375 return Err(fail);
376 }
377 let n2 = self.n.concatenating_mul_self();
378 if !lt(&self.rho, &n2) || !is_unit(&self.rho, &self.n) {
379 return Err(fail);
380 }
381 for v in [&self.t, &self.s1, &self.s2] {
382 if !lt(v, &self.n_hat) || !is_unit(v, &self.n_hat) {
383 return Err(fail);
384 }
385 }
386 if is_trivial(&self.rho0, &self.n)
390 || bool::from(self.rho.is_one())
391 || [&self.t, &self.s1, &self.s2]
392 .into_iter()
393 .any(|v| is_trivial(v, &self.n_hat))
394 || self.t == self.s1
395 || self.t == self.s2
396 || self.s1 == self.s2
397 || self.n == self.n_hat
398 {
399 return Err(fail);
400 }
401 Ok(())
402 }
403
404 pub fn verify(&self, params: &Params) -> Result<VerifiedSetup> {
406 self.verify_with(params, &FacParams::standard()?)
407 }
408
409 pub fn verify_with(&self, params: &Params, fac: &FacParams) -> Result<VerifiedSetup> {
410 let fail = Error::VerificationFailed;
411 if self.params != *params {
412 return Err(fail);
413 }
414 self.check_basic()?;
415 let (h, f) = derive_h_f(&self.aux()).map_err(|_| fail)?;
416 if is_identity(&self.h) || is_identity(&self.f) || self.h != h || self.f != f || h == f {
417 return Err(fail);
418 }
419 let want = rho_of(&self.n, &self.rho0)?;
420 let bits = want.bits_precision().max(self.rho.bits_precision());
421 if resized(&want, bits) != resized(&self.rho, bits) {
422 return Err(fail);
423 }
424 let tx = base_tx(params, &self.setup_id, &self.server_id);
425 self.pi_fac.verify(&tx, params, fac, &self.n)?;
426 let st = DfStatement::from_uints(&self.n_hat, &self.t, &self.s1, &self.s2)?;
427 self.pi_df.verify(&tx, params, &st)?;
428 self.pi_mod.verify(&tx, params, &self.n, params.n_rsa)?;
429 let hash = self.hash()?;
430 let pk = self.paillier_pk()?;
431 let df = DfParams::new(st.n_hat, st.t, st.s1, st.s2);
432 Ok(VerifiedSetup {
433 pk,
434 df,
435 h,
436 f,
437 hash,
438 server_id: self.server_id.clone(),
439 params: *params,
440 rho_table: None,
441 })
442 }
443}
444
445impl SetupData {
446 pub fn assume_verified(&self, params: &Params) -> Result<VerifiedSetup> {
449 if self.params != *params {
450 return Err(Error::VerificationFailed);
451 }
452 self.check_basic()?;
453 let st = DfStatement::from_uints(&self.n_hat, &self.t, &self.s1, &self.s2)?;
454 Ok(VerifiedSetup {
455 pk: self.paillier_pk()?,
456 df: DfParams::new(st.n_hat, st.t, st.s1, st.s2),
457 h: self.h,
458 f: self.f,
459 hash: self.hash()?,
460 server_id: self.server_id.clone(),
461 params: *params,
462 rho_table: None,
463 })
464 }
465}
466
467pub struct VerifiedSetup {
469 pk: PaillierPk,
470 df: DfParams,
471 h: ProjectivePoint,
472 f: ProjectivePoint,
473 hash: [u8; 32],
474 server_id: Vec<u8>,
475 params: Params,
476 rho_table: Option<FixedBase>,
477}
478
479impl VerifiedSetup {
480 pub fn server_id(&self) -> &[u8] {
482 &self.server_id
483 }
484
485 pub fn paillier_pk(&self) -> &PaillierPk {
486 &self.pk
487 }
488 pub fn df(&self) -> &DfParams {
489 &self.df
490 }
491 pub fn h(&self) -> &ProjectivePoint {
492 &self.h
493 }
494 pub fn f(&self) -> &ProjectivePoint {
495 &self.f
496 }
497 pub fn hash(&self) -> [u8; 32] {
499 self.hash
500 }
501 pub fn params(&self) -> &Params {
502 &self.params
503 }
504 pub fn rho_table(&self) -> Option<&FixedBase> {
505 self.rho_table.as_ref()
506 }
507
508 pub fn with_tables_custom(mut self, rho_window: u32, df_bits: u32, df_window: u32) -> Self {
511 let rho = self.pk.rho().clone();
512 self.rho_table = Some(FixedBase::new(
513 self.pk.mod_n2(),
514 &rho,
515 self.params.n_lambda0(),
516 rho_window,
517 ));
518 self.df = self.df.with_tables(df_bits, df_window);
519 self
520 }
521
522 pub fn with_tables(mut self) -> Self {
525 let p = self.params;
526 let eps = p.eps();
527 self.rho_table = Some(FixedBase::new(
528 self.pk.mod_n2(),
529 self.pk.rho(),
530 p.n_lambda0() + eps,
531 RHO_TABLE_WINDOW,
532 ));
533 self.df = self.df.with_tables_sized(
534 [p.n_t_rho + eps, p.n_a() + eps, p.n_b() + eps],
535 DF_TABLE_WINDOW,
536 );
537 self
538 }
539
540 pub fn tables_size_bytes(&self) -> usize {
542 self.rho_table.as_ref().map_or(0, FixedBase::size_bytes) + self.df.tables_size_bytes()
543 }
544}
545
546#[cfg(test)]
547mod tests {
548 extern crate std;
549 use super::*;
550 use crate::{
551 params::{PARAMS_128, ParamsId},
552 rsa::tough::{ToughSpec, sample_tough_prime},
553 zk::{fac::FacParams, modulus::ModRep},
554 };
555 use rand_chacha::ChaCha8Rng;
556 use rand_core::SeedableRng;
557 use std::{sync::OnceLock, time::Instant};
558
559 fn small_params() -> Params {
560 Params {
561 id: ParamsId::P128,
562 ell: 16,
563 nu: 16,
564 n_rsa: 512,
565 r_mod: 8,
566 r_df: 16,
567 r_df_star: 4,
568 tough_count: 4,
569 tough_bits: 64,
570 ..PARAMS_128
571 }
572 }
573
574 struct Fx {
575 fac: FacParams,
576 data: SetupData,
577 other: SetupData,
578 sk: ServerSetupSecret,
579 }
580
581 fn fx() -> &'static Fx {
582 static F: OnceLock<Fx> = OnceLock::new();
583 F.get_or_init(|| {
584 let p = small_params();
585 let mut rng = ChaCha8Rng::seed_from_u64(1);
586 let d_bits = p.n_rsa + 2 * p.ell + 2 * p.nu + 4;
587 let d = sample_tough_prime(&mut rng, d_bits, 7, ToughSpec::SAFE).unwrap();
588 let fac = FacParams::new(d.p().clone()).unwrap();
589 let (data, sk) = server_setup_with(&mut rng, &p, &fac, [7u8; 32], b"server-A").unwrap();
590 let (other, _) = server_setup_with(&mut rng, &p, &fac, [9u8; 32], b"server-B").unwrap();
591 Fx {
592 fac,
593 data,
594 other,
595 sk,
596 }
597 })
598 }
599
600 fn ok(d: &SetupData) -> bool {
601 d.verify_with(&small_params(), &fx().fac).is_ok()
602 }
603
604 #[test]
605 fn server_secret_export_roundtrip_and_binding() {
606 let f = fx();
607 let p = small_params();
608 let bytes = f.sk.export_secret(&p).unwrap();
609 let back = ServerSetupSecret::import_secret(&bytes, &f.data).unwrap();
610 let pk = f.data.paillier_pk().unwrap();
611 let c = pk.g_pow(&SBig::from_i64(777));
612 let m = back.paillier_sk().dec(&c).unwrap();
613 assert_eq!(resized(&m, 64), BoxedUint::from(777u64));
614 assert!(ServerSetupSecret::import_secret(&bytes, &f.other).is_err());
616 assert!(ServerSetupSecret::import_secret(&bytes[1..], &f.data).is_err());
618 let mut bad = bytes.to_vec();
619 bad[0] ^= 1;
620 assert!(ServerSetupSecret::import_secret(&bad, &f.data).is_err());
621 let mut bad = bytes.to_vec();
622 *bad.last_mut().unwrap() ^= 2;
623 assert!(ServerSetupSecret::import_secret(&bad, &f.data).is_err());
624 }
625
626 #[test]
627 fn honest_setup_verifies() {
628 let f = fx();
629 let v = f.data.verify_with(&small_params(), &f.fac).unwrap();
630 assert_eq!(v.hash(), f.data.hash().unwrap());
631 assert_eq!(v.paillier_pk().n(), &f.data.n);
632 assert_eq!(
633 f.data.verify_with(&small_params(), &f.fac).unwrap().hash(),
634 v.hash()
635 );
636 assert_eq!(std::format!("{:?}", f.sk), "ServerSetupSecret(***)");
637 let pk = f.data.paillier_pk().unwrap();
639 let c = pk.g_pow(&SBig::from_i64(12345));
640 let m = f.sk.paillier_sk().dec(&c).unwrap();
641 assert_eq!(resized(&m, 64), BoxedUint::from(12345u64));
642 let v = v.with_tables();
643 assert!(v.rho_table().is_some() && v.tables_size_bytes() > 0);
644 let mut p2 = small_params();
646 p2.r_mod = 9;
647 assert!(f.data.verify_with(&p2, &f.fac).is_err());
648 }
649
650 #[test]
651 fn roundtrip_and_strict_length() {
652 let f = fx();
653 let p = small_params();
654 let bytes = f.data.to_bytes().unwrap();
655 let back = SetupData::from_bytes_with(&bytes, &p, &f.fac).unwrap();
656 assert_eq!(back.to_bytes().unwrap(), bytes);
657 assert!(ok(&back));
658 assert!(SetupData::from_bytes_with(&bytes[1..], &p, &f.fac).is_err());
659 assert!(SetupData::from_bytes_with(&bytes[..bytes.len() - 1], &p, &f.fac).is_err());
660 let mut long = bytes.clone();
661 long.push(0);
662 assert!(SetupData::from_bytes_with(&long, &p, &f.fac).is_err());
663 assert!(SetupData::from_bytes_with(&[], &p, &f.fac).is_err());
664 }
665
666 #[test]
667 fn byte_flip_in_every_field_rejected() {
668 let f = fx();
669 let p = small_params();
670 let bytes = f.data.to_bytes().unwrap();
671 let len = nb(&p);
672 let sl = f.data.server_id.len();
673 let mut regions: Vec<(usize, usize)> = std::vec![(0, 1), (1, 32), (33, 2), (35, sl)];
674 let mut pos = 35 + sl;
675 for l in [len, len, len, 2 * len, len, len, len, 33, 33] {
676 regions.push((pos, l));
677 pos += l;
678 }
679 for l in [
680 ModProof::encoded_len(&p, p.n_rsa),
681 FacProof::encoded_len(&p, &f.fac, p.n_rsa),
682 DfProof::encoded_len(&p),
683 ] {
684 regions.push((pos, l));
685 pos += l;
686 }
687 assert_eq!(pos, bytes.len());
688 let orig = f.data.hash().unwrap();
689 for (start, l) in regions {
690 for off in [0, l / 2, l - 1] {
691 for bit in [0x01u8, 0x80] {
692 let mut b = bytes.clone();
693 b[start + off] ^= bit;
694 match SetupData::from_bytes_with(&b, &p, &f.fac) {
695 Err(_) => {}
696 Ok(d) => {
697 assert!(!ok(&d), "flip at {} accepted", start + off);
698 assert_ne!(d.hash().unwrap(), orig);
699 }
700 }
701 }
702 }
703 }
704 }
705
706 #[test]
707 fn field_tampering_rejected() {
708 let f = fx();
709 let one = |b: &BoxedUint| {
710 let bits = b.bits_precision();
711 b.wrapping_add(BoxedUint::one_with_precision(bits))
712 };
713 let orig = f.data.hash().unwrap();
714 let mut cases: Vec<SetupData> = Vec::new();
715 let mut d = f.data.clone();
716 core::mem::swap(&mut d.h, &mut d.f);
717 cases.push(d);
718 let mut d = f.data.clone();
719 d.h += d.f;
720 cases.push(d);
721 let mut d = f.data.clone();
722 d.rho = one(&d.rho);
723 cases.push(d);
724 let mut d = f.data.clone();
725 d.rho0 = one(&d.rho0);
726 cases.push(d);
727 let mut d = f.data.clone();
728 d.t = one(&d.t);
729 cases.push(d);
730 let mut d = f.data.clone();
731 d.s1 = d.s2.clone();
732 cases.push(d);
733 let mut d = f.data.clone();
734 d.s2 = BoxedUint::zero_with_precision(512);
735 cases.push(d);
736 let mut d = f.data.clone();
738 d.n_hat = d.n_hat.shr_vartime(1).unwrap();
739 cases.push(d);
740 let mut d = f.data.clone();
741 d.n = d.n_hat.clone();
742 cases.push(d);
743 let mut d = f.data.clone();
744 d.n = f.other.n.clone();
745 cases.push(d);
746 let mut d = f.data.clone();
748 d.pi_mod = f.other.pi_mod.clone();
749 cases.push(d);
750 let mut d = f.data.clone();
751 d.pi_fac = f.other.pi_fac.clone();
752 cases.push(d);
753 let mut d = f.data.clone();
754 d.pi_df = f.other.pi_df.clone();
755 cases.push(d);
756 let mut d = f.data.clone();
757 d.server_id = f.other.server_id.clone();
758 cases.push(d);
759 let mut d = f.data.clone();
760 d.setup_id = f.other.setup_id;
761 cases.push(d);
762 let mut d = f.data.clone();
763 d.server_id = std::vec![0u8; 257];
764 cases.push(d);
765 let mut d = f.data.clone();
767 d.pi_mod.reps[0] = ModRep {
768 a: !d.pi_mod.reps[0].a,
769 ..d.pi_mod.reps[0].clone()
770 };
771 cases.push(d);
772 let mut d = f.data.clone();
773 d.pi_df.e[0] ^= 1;
774 cases.push(d);
775 let mut d = f.data.clone();
776 d.pi_fac.w = one(&d.pi_fac.w);
777 cases.push(d);
778 for (i, d) in cases.iter().enumerate() {
779 assert!(!ok(d), "case {i} accepted");
780 if let Ok(h) = d.hash() {
781 assert_ne!(h, orig, "case {i}");
782 }
783 }
784 assert!(ok(&f.data));
785 }
786
787 #[test]
788 fn degenerate_values_rejected() {
789 let f = fx();
790 let one = |b: &BoxedUint| BoxedUint::one_with_precision(b.bits_precision());
791 let minus_one = |b: &BoxedUint, n: &BoxedUint| {
792 let bits = b.bits_precision().max(n.bits_precision());
793 resized(n, bits).wrapping_sub(BoxedUint::one_with_precision(bits))
794 };
795 let mut cases: Vec<SetupData> = Vec::new();
796 let mut d = f.data.clone();
797 d.rho0 = one(&d.rho0);
798 d.rho = one(&d.rho);
799 cases.push(d);
800 let mut d = f.data.clone();
801 d.rho0 = minus_one(&d.rho0, &d.n);
802 cases.push(d);
803 let mut d = f.data.clone();
804 d.rho = one(&d.rho);
805 cases.push(d);
806 for field in 0..3 {
807 let mut d = f.data.clone();
808 let v = one(&d.t);
809 match field {
810 0 => d.t = v,
811 1 => d.s1 = v,
812 _ => d.s2 = v,
813 }
814 cases.push(d);
815 }
816 let mut d = f.data.clone();
817 d.t = minus_one(&d.t, &d.n_hat);
818 cases.push(d);
819 let mut d = f.data.clone();
820 d.s2 = d.s1.clone();
821 cases.push(d);
822 for (i, d) in cases.iter().enumerate() {
823 assert!(d.check_basic().is_err(), "case {i} accepted");
824 }
825 assert!(f.data.check_basic().is_ok());
826 }
827
828 #[test]
829 fn server_id_limit() {
830 let p = small_params();
831 let mut rng = ChaCha8Rng::seed_from_u64(5);
832 let r = server_setup_with(&mut rng, &p, &fx().fac, [0; 32], &[0u8; 257]);
833 assert!(r.is_err());
834 }
835
836 #[test]
837 #[ignore]
838 fn full_size_setup() {
839 let mut rng = ChaCha8Rng::seed_from_u64(99);
840 let t0 = Instant::now();
841 let (data, _sk) = server_setup(&mut rng, &PARAMS_128, [1u8; 32], b"example.org").unwrap();
842 std::println!("server setup: {:?}", t0.elapsed());
843 let bytes = data.to_bytes().unwrap();
844 std::println!("setup size: {} bytes", bytes.len());
845 let data = SetupData::from_bytes(&bytes, &PARAMS_128).unwrap();
846 let fac = FacParams::standard().unwrap();
847 let t0 = Instant::now();
848 data.check_basic().unwrap();
849 std::println!("check_basic: {:?}", t0.elapsed());
850 let t0 = Instant::now();
851 let want = rho_of(&data.n, &data.rho0).unwrap();
852 std::println!("rho check: {:?} {}", t0.elapsed(), want.bits());
853 let tx = base_tx(&PARAMS_128, &data.setup_id, &data.server_id);
854 let t0 = Instant::now();
855 data.pi_fac.verify(&tx, &PARAMS_128, &fac, &data.n).unwrap();
856 std::println!("fac verify: {:?}", t0.elapsed());
857 let st = DfStatement::from_uints(&data.n_hat, &data.t, &data.s1, &data.s2).unwrap();
858 let t0 = Instant::now();
859 data.pi_df.verify(&tx, &PARAMS_128, &st).unwrap();
860 std::println!("df verify: {:?}", t0.elapsed());
861 let t0 = Instant::now();
862 data.pi_mod
863 .verify(&tx, &PARAMS_128, &data.n, PARAMS_128.n_rsa)
864 .unwrap();
865 std::println!("mod verify: {:?}", t0.elapsed());
866 let t0 = Instant::now();
867 let v = data.verify(&PARAMS_128).unwrap();
868 std::println!("client verify total: {:?}", t0.elapsed());
869 let t0 = Instant::now();
870 let v = v.with_tables();
871 std::println!(
872 "tables: {:?}, {} bytes (rho {}, df {})",
873 t0.elapsed(),
874 v.tables_size_bytes(),
875 v.rho_table().map_or(0, FixedBase::size_bytes),
876 v.df().tables_size_bytes()
877 );
878 assert_eq!(v.hash(), data.hash().unwrap());
879 }
880}