zinc_protocol/
shared_challenge.rs1use crypto_primitives::BaseFieldConfig;
18use zinc_transcript::traits::{ConstTranscribable, Transcript};
19
20#[inline]
29pub fn compute_q_star_idx<C>(prime_cfgs: &[C]) -> usize
30where
31 C: BaseFieldConfig,
32{
33 prime_cfgs
34 .iter()
35 .enumerate()
36 .min_by_key(|(_, cfg)| cfg.modulus())
37 .map(|(i, _)| i)
38 .expect("prime_cfgs must be non-empty")
39}
40
41#[inline]
54pub fn sample_shared_field_challenge<C>(
55 transcript: &mut impl Transcript,
56 q_star_cfg: &C,
57 prime_cfgs: &[C],
58) -> Vec<C::Element>
59where
60 C: BaseFieldConfig,
61 C::Integer: ConstTranscribable,
62{
63 let v = transcript.get_field_challenge(q_star_cfg);
64 let v_int = q_star_cfg.lift(&v);
65 prime_cfgs.iter().map(|cfg| cfg.project(&v_int)).collect()
66}
67
68#[inline]
73pub fn sample_shared_field_challenges<C>(
74 transcript: &mut impl Transcript,
75 n: usize,
76 q_star_cfg: &C,
77 prime_cfgs: &[C],
78) -> Vec<Vec<C::Element>>
79where
80 C: BaseFieldConfig,
81 C::Integer: ConstTranscribable,
82{
83 let shared: Vec<C::Integer> = (0..n)
87 .map(|_| {
88 let v = transcript.get_field_challenge(q_star_cfg);
89 q_star_cfg.lift(&v)
90 })
91 .collect();
92
93 prime_cfgs
94 .iter()
95 .map(|cfg| shared.iter().map(|v| cfg.project(v)).collect())
96 .collect()
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crypto_primitives::{
103 LiftElementWithConfig,
104 crypto_bigint_monty::MontyField,
105 crypto_bigint_uint::{U64, Uint},
106 };
107 use zinc_transcript::Blake3Transcript;
108
109 const FIELD_LIMBS: usize = U64::LIMBS * 3;
110 type Cfg = MontyField<FIELD_LIMBS>;
111 type FMod = Uint<FIELD_LIMBS>;
112
113 fn cfg_from_u64(prime: u64) -> Cfg {
114 Cfg::new(&FMod::from(prime)).expect("prime")
115 }
116
117 #[test]
118 fn compute_q_star_picks_minimum() {
119 let cfgs = vec![
121 cfg_from_u64(0xFFFF_FFFF_FFFF_FFC5),
122 cfg_from_u64(0xFFFF_FFFF_FFFF_FFAD),
123 cfg_from_u64(0xFFFF_FFFF_FFFF_F9C5),
124 ];
125 let idx = compute_q_star_idx(&cfgs);
126 assert_eq!(idx, 2);
127 let q_star = cfgs[idx].modulus();
128 let expected = FMod::from(0xFFFF_FFFF_FFFF_F9C5_u64);
129 assert_eq!(q_star, expected);
130 }
131
132 #[test]
133 fn shared_challenge_lifts_same_integer_to_each_family() {
134 let cfgs = vec![
135 cfg_from_u64(0xFFFF_FFFF_FFFF_FFC5),
136 cfg_from_u64(0xFFFF_FFFF_FFFF_FFAD),
137 ];
138 let q_star = &cfgs[compute_q_star_idx(&cfgs)];
139 let mut transcript = Blake3Transcript::new();
140
141 let per_family = sample_shared_field_challenge(&mut transcript, q_star, &cfgs);
142 assert_eq!(per_family.len(), cfgs.len());
143
144 let int_0: FMod = cfgs[0].lift(&per_family[0]);
150 for (i, fe) in per_family.iter().enumerate().skip(1) {
151 let int_i: FMod = cfgs[i].lift(fe);
152 assert_eq!(
153 int_i, int_0,
154 "family {i}: shared challenge differs from family 0",
155 );
156 }
157
158 assert!(
160 int_0 < q_star.modulus(),
161 "shared challenge must be < q_star"
162 );
163 }
164
165 #[test]
166 fn shared_challenges_batched_matches_repeated_singles() {
167 let cfgs = vec![
168 cfg_from_u64(0xFFFF_FFFF_FFFF_FFC5),
169 cfg_from_u64(0xFFFF_FFFF_FFFF_FFAD),
170 ];
171 let q_star = &cfgs[compute_q_star_idx(&cfgs)];
172 let n = 5;
173
174 let mut t_batch = Blake3Transcript::new();
176 let batched = sample_shared_field_challenges(&mut t_batch, n, q_star, &cfgs);
177 assert_eq!(batched.len(), cfgs.len());
178 for family in &batched {
179 assert_eq!(family.len(), n);
180 }
181
182 let mut t_single = Blake3Transcript::new();
184 let mut singles_per_family: Vec<Vec<_>> =
185 cfgs.iter().map(|_| Vec::with_capacity(n)).collect();
186 for _ in 0..n {
187 let per_family = sample_shared_field_challenge(&mut t_single, q_star, &cfgs);
188 for (i, fe) in per_family.into_iter().enumerate() {
189 singles_per_family[i].push(fe);
190 }
191 }
192
193 for (i, (b, s)) in batched.iter().zip(&singles_per_family).enumerate() {
196 for (k, (bk, sk)) in b.iter().zip(s).enumerate() {
197 let bk_int: FMod = cfgs[i].lift(bk);
198 let sk_int: FMod = cfgs[i].lift(sk);
199 assert_eq!(
200 bk_int, sk_int,
201 "family {i}, idx {k}: batched != repeated singles",
202 );
203 }
204 }
205 }
206}