labrador/core/env_params.rs
1use crate::ring::zq::Zq;
2
3// Example Environment parameters used for LaBRADOR, can be expanded as required by testing.
4#[derive(Clone)]
5pub struct EnvironmentParameters {
6 /// Relation R Parameters
7 pub n: usize, // rank (size of each witness s_i)
8 pub r: usize, // multiplicity (number of witness elements)
9
10 /// Decomposition Parameters
11 pub b: Zq, // z decomposition base
12 pub b_1: Zq, // t_i decomposition base
13 pub t_1: usize, // t_i number of parts
14 pub b_2: Zq, // g_ij decomposition base
15 pub t_2: usize, // g_ij number of parts
16
17 /// Norm Bounds
18 pub beta: Zq, // Bound for witness s_i
19 pub gamma: Zq, // Bound for z
20 pub gamma_1: Zq, // Bound for t
21 pub gamma_2: Zq, // Bound for g and h
22
23 /// Commitment Matrices Sizes
24 pub kappa: usize, // Number of rows in A
25 pub kappa_1: usize, // Number of rows in B
26 pub kappa_2: usize, // Number of rows in C
27
28 /// Security Parameter
29 pub lambda: usize, // security parameter
30
31 /// Function Families Sizes
32 pub constraint_k: usize, // Number of constraints of the form f
33 pub constraint_l: usize, // Number of constraints of the form f'
34
35 /// Other Parameters
36 pub log_q: usize, // Size of log(q) in bits, where q is the modulo
37}
38
39#[allow(clippy::too_many_arguments)]
40impl EnvironmentParameters {
41 pub fn new(
42 n: usize,
43 r: usize,
44 b: Zq,
45 b_1: Zq,
46 t_1: usize,
47 b_2: Zq,
48 t_2: usize,
49 beta: Zq,
50 gamma: Zq,
51 gamma_1: Zq,
52 gamma_2: Zq,
53 kappa: usize,
54 kappa_1: usize,
55 kappa_2: usize,
56 lambda: usize,
57 constraint_k: usize,
58 constraint_l: usize,
59 log_q: usize,
60 ) -> Self {
61 Self {
62 n,
63 r,
64 b,
65 b_1,
66 t_1,
67 b_2,
68 t_2,
69 beta,
70 gamma,
71 gamma_1,
72 gamma_2,
73 kappa,
74 kappa_1,
75 kappa_2,
76 lambda,
77 constraint_k,
78 constraint_l,
79 log_q,
80 }
81 }
82}
83
84impl Default for EnvironmentParameters {
85 fn default() -> Self {
86 Self {
87 n: 5,
88 r: 3,
89 b: Zq::new(2),
90 b_1: Zq::new(16),
91 t_1: 4,
92 b_2: Zq::new(16),
93 t_2: 4,
94 beta: Zq::new(65535),
95 gamma: Zq::new(16),
96 gamma_1: Zq::new(16),
97 gamma_2: Zq::new(16),
98 kappa: 4,
99 kappa_1: 5,
100 kappa_2: 5,
101 lambda: 128,
102 constraint_k: 5,
103 constraint_l: 5,
104 log_q: 32,
105 }
106 }
107}
108
109// Todo: Revise and complete the following functionality
110// /// Calculate optimal decomposition parameters based on Section 5.4 of the paper
111// #[allow(clippy::as_conversions)]
112// pub fn calculate_optimal_parameters(
113// n: usize, // Dimension of the witness vector
114// s: f64, // Standard deviation of witness coefficients
115// beta: f64, // Ajtai commitment parameter
116// ) -> GarbageParameters {
117// // Calculate estimated standard deviations based on Section 5.4
118// // For g_{ij}, std dev is approximately s_g = sqrt(n*d) * s^2
119// // For h_{ij}, std dev is approximately s_h = beta * sqrt(n*d) * s
120// let n_d_sqrt = (n * d) as f64;
121// let s_g = n_d_sqrt * s * s;
122// let s_h = beta * n_d_sqrt * s;
123
124// // Calculate optimal bases using formula from Section 5.4
125// // B_i ≈ sqrt(12 * s_i)
126// let b2 = ((12.0 * s_g).sqrt() as u32).max(2);
127// let b1 = ((12.0 * s_h).sqrt() as u32).max(2);
128
129// // Calculate optimal number of parts
130// // t_i ≈ log_B_i(q)
131// let t2 = ((32.0 / (b2 as f64).log2()).ceil() as usize).max(2);
132// let t1 = ((32.0 / (b1 as f64).log2()).ceil() as usize).max(2);
133
134// GarbageParameters {
135// g_base: Zq::new(b2),
136// g_parts: t2,
137// h_base: Zq::new(b1),
138// h_parts: t1,
139// }
140// }
141
142// #[test]
143// #[allow(clippy::as_conversions)]
144// fn test_optimal_parameters_accuracy() {
145// // Choose small, simple values for manual calculation
146// let n = 4; // Small dimension
147// let d = 4; // Small degree
148// let s = 2.0; // Simple standard deviation
149// let beta = 1.0; // Simple beta value
150
151// // Manually calculate the expected values according to the paper's formulas
152// let n_d_sqrt = (n * d) as f64; // = 4.0
153
154// // s_g = sqrt(n*d) * s^2 = 4.0 * 4.0 = 16.0
155// let s_g = n_d_sqrt * s * s;
156
157// // s_h = beta * sqrt(n*d) * s = 1.0 * 4.0 * 2.0 = 8.0
158// let s_h = beta * n_d_sqrt * s;
159
160// // b2 ≈ sqrt(12 * s_g) = sqrt(12 * 16.0) = sqrt(192) ≈ 13.856... => 13
161// let expected_b2 = (12.0 * s_g).sqrt() as u32;
162
163// // b1 ≈ sqrt(12 * s_h) = sqrt(12 * 8.0) = sqrt(96) ≈ 9.798... => 9
164// let expected_b1 = (12.0 * s_h).sqrt() as u32;
165
166// // For q = 2^32:
167// // t2 ≈ log_b2(q) = log_13(2^32) = 32/log_2(13) ≈ 32/3.7 ≈ 8.65 => 9
168// let expected_t2 = ((32.0 / (expected_b2 as f64).log2()).ceil() as usize).max(2);
169
170// // t1 ≈ log_b1(q) = log_9(2^32) = 32/log_2(9) ≈ 32/3.17 ≈ 10.09 => 11
171// let expected_t1 = ((32.0 / (expected_b1 as f64).log2()).ceil() as usize).max(2);
172
173// // Call the function under test
174// let params =
175// GarbagePolynomialCommitment::<TEST_M, TEST_N, TEST_D>::calculate_optimal_parameters(
176// n, d, s, beta,
177// );
178
179// // Check results
180// assert!(
181// params.g_base.to_u128() >= expected_b2 as u128 - 1
182// && params.g_base.to_u128() <= expected_b2 as u128 + 1,
183// "g_base {}, expected {}",
184// params.g_base.to_u128(),
185// expected_b2
186// );
187
188// assert!(
189// params.h_base.to_u128() >= expected_b1 as u128 - 1
190// && params.h_base.to_u128() <= expected_b1 as u128 + 1,
191// "h_base {}, expected {}",
192// params.h_base.to_u128(),
193// expected_b1
194// );
195
196// // For part counts, use approximate comparison due to potential floating point differences
197// assert!(
198// params.g_parts >= expected_t2 - 1 && params.g_parts <= expected_t2 + 1,
199// "g_parts {}, expected {}",
200// params.g_parts,
201// expected_t2
202// );
203
204// assert!(
205// params.h_parts >= expected_t1 - 1 && params.h_parts <= expected_t1 + 1,
206// "h_parts {}, expected {}",
207// params.h_parts,
208// expected_t1
209// );
210// }