tfhe_hpu_backend/interface/rtl/
params.rs

1//!
2//! Extract architecture properties from RTL registers
3//! Read Rtl parameters from registers.
4//! NB: Some registers contains encoded value that must be converted to concrete one (i.e.
5//! apps/ntt_moduls)
6use parameters::HpuNttPrime;
7
8use super::*;
9use crate::entities::*;
10
11// Set of constant defined in RTL and associated rust definition
12// -> Cf. fpga/hw/common_lib/common_package/rtl/common_definition_pkg.sv
13pub const NTT_CORE_ARCH_OFS: u32 = 5 << 8;
14pub const MOD_NTT_NAME_OFS: u32 = 6 << 8;
15pub const APPLICATION_NAME_OFS: u32 = 7 << 8;
16pub const SIMULATION_CODE: u32 = 1;
17
18impl FromRtl for HpuParameters {
19    fn from_rtl(ffi_hw: &mut ffi::HpuHw, regmap: &FlatRegmap) -> Self {
20        let pbs_params = HpuPBSParameters::from_rtl(ffi_hw, regmap);
21        let ntt_params = HpuNttParameters::from_rtl(ffi_hw, regmap);
22        let ks_params = HpuKeyswitchParameters::from_rtl(ffi_hw, regmap);
23        let pc_params = HpuPcParameters::from_rtl(ffi_hw, regmap);
24        let regf_params = HpuRegfileParameters::from_rtl(ffi_hw, regmap);
25        let isc_params = HpuIscParameters::from_rtl(ffi_hw, regmap);
26        Self {
27            pbs_params,
28            ntt_params,
29            ks_params,
30            pc_params,
31            regf_params,
32            isc_params,
33        }
34    }
35}
36
37impl FromRtl for HpuKeyswitchParameters {
38    fn from_rtl(ffi_hw: &mut ffi::HpuHw, regmap: &FlatRegmap) -> Self {
39        let ks_shape = regmap
40            .register()
41            .get("info::ks_structure")
42            .expect("Unknown register, check regmap definition");
43        let shape_val = ffi_hw.read_reg(*ks_shape.offset() as u64);
44        let shape_fields = ks_shape.as_field(shape_val);
45
46        let ks_info = regmap
47            .register()
48            .get("info::ks_crypto_param")
49            .expect("Unknown register, check regmap definition");
50        let info_val = ffi_hw.read_reg(*ks_info.offset() as u64);
51        let info_fields = ks_info.as_field(info_val);
52
53        Self {
54            width: *info_fields.get("mod_ksk_w").expect("Unknown field") as usize,
55            lbx: *shape_fields.get("x").expect("Unknown field") as usize,
56            lby: *shape_fields.get("y").expect("Unknown field") as usize,
57            lbz: *shape_fields.get("z").expect("Unknown field") as usize,
58        }
59    }
60}
61impl FromRtl for HpuNttParameters {
62    fn from_rtl(ffi_hw: &mut ffi::HpuHw, regmap: &FlatRegmap) -> Self {
63        let core_arch = HpuNttCoreArch::from_rtl(ffi_hw, regmap);
64
65        // Values extracted from NttInternal register
66        let ntt_internal = regmap
67            .register()
68            .get("info::ntt_structure")
69            .expect("Unknown register, check regmap definition");
70        let internal_val = ffi_hw.read_reg(*ntt_internal.offset() as u64);
71        let internal_fields = ntt_internal.as_field(internal_val);
72
73        let radix = *internal_fields.get("radix").expect("Unknown field") as usize;
74        let psi = *internal_fields.get("psi").expect("Unknown field") as usize;
75        let delta = *internal_fields.get("delta").expect("Unknown field") as usize;
76
77        // Values extracted from NttInternal register
78        let ntt_pbs_nb = regmap
79            .register()
80            .get("info::ntt_pbs")
81            .expect("Unknown register, check regmap definition");
82        let pbs_nb_val = ffi_hw.read_reg(*ntt_pbs_nb.offset() as u64);
83        let pbs_nb_fields = ntt_pbs_nb.as_field(pbs_nb_val);
84
85        let batch_pbs_nb = *pbs_nb_fields.get("batch_pbs_nb").expect("Unknown field") as usize;
86        let total_pbs_nb = *pbs_nb_fields.get("total_pbs_nb").expect("Unknown field") as usize;
87
88        // Values extracted from NttModulo register
89        // Modulus isn't directly expressed, instead used custom encoding
90        let ntt_modulo = regmap
91            .register()
92            .get("info::ntt_modulo")
93            .expect("Unknown register, check regmap definition");
94        let ntt_modulo_val = ffi_hw.read_reg(*ntt_modulo.offset() as u64);
95
96        let prime_modulus = {
97            // Check register encoding
98            let field_code = ntt_modulo_val & (!0xFF_u32);
99            assert_eq!(
100                field_code, MOD_NTT_NAME_OFS,
101                "Invalid register encoding. Check register map definition"
102            );
103            match (ntt_modulo_val & 0xFF) as u8 {
104                enum_id if enum_id == HpuNttPrime::GF64 as u8 => HpuNttPrime::GF64,
105                enum_id if enum_id == HpuNttPrime::Solinas3_32_17_13 as u8 => {
106                    HpuNttPrime::Solinas3_32_17_13
107                }
108                enum_id if enum_id == HpuNttPrime::Solinas2_44_14 as u8 => {
109                    HpuNttPrime::Solinas2_44_14
110                }
111                _ => panic!("Unknown NttModName encoding"),
112            }
113        };
114
115        // Values extracted from Application
116        // Not the cleanest way but some required ntt information are only available in the
117        // parameters set Thus parse extract HpuPBSParameters inside HpuNttParameters
118        let pbs_params = HpuPBSParameters::from_rtl(ffi_hw, regmap);
119        let stg_nb = pbs_params.polynomial_size.ilog(radix) as usize;
120
121        Self {
122            core_arch,
123            min_pbs_nb: None, // TODO: Get this from a register
124            batch_pbs_nb,
125            total_pbs_nb,
126            ct_width: pbs_params.ciphertext_width as u32,
127            radix,
128            stg_nb,
129            prime_modulus,
130            psi,
131            delta,
132        }
133    }
134}
135
136impl FromRtl for HpuNttCoreArch {
137    fn from_rtl(ffi_hw: &mut ffi::HpuHw, regmap: &FlatRegmap) -> Self {
138        // Values extracted from NttModulo register
139        // Modulus isn't directly expressed, instead used custom encoding
140        let ntt_core_arch = regmap
141            .register()
142            .get("info::ntt_architecture")
143            .expect("Unknown register, check regmap definition");
144        let ntt_core_arch_val = ffi_hw.read_reg(*ntt_core_arch.offset() as u64);
145
146        // Check register encoding
147        let field_code = ntt_core_arch_val & (!0xFF_u32);
148        assert_eq!(
149            field_code, NTT_CORE_ARCH_OFS,
150            "Invalid register encoding. Check register map definition"
151        );
152
153        match ntt_core_arch_val & 0xFF {
154            // NB: Previous arch aren't supported anymore
155            3 => Self::WmmCompactPcg,
156            4 => Self::WmmUnfoldPcg,
157            5 => {
158                // Extract associated radix split
159
160                let radix_cut = regmap
161                    .register()
162                    .get("info::ntt_rdx_cut")
163                    .expect("Unknown register, check regmap definition");
164                let radix_cut_val = ffi_hw.read_reg(*radix_cut.offset() as u64);
165                let cut_l = (0..(u32::BITS / 4))
166                    .map(|ofst| ((radix_cut_val >> (ofst * 4)) & 0xf) as u8)
167                    .filter(|x| *x != 0)
168                    .collect::<Vec<u8>>();
169                Self::GF64(cut_l)
170            }
171            _ => panic!("Unknown NttCoreArch encoding"),
172        }
173    }
174}
175
176impl FromRtl for HpuPcParameters {
177    fn from_rtl(ffi_hw: &mut ffi::HpuHw, regmap: &FlatRegmap) -> Self {
178        // Extract number of Pc for each channel
179        let hbm_pc = regmap
180            .register()
181            .get("info::hbm_axi4_nb")
182            .expect("Unknown register, check regmap definition");
183        let hbm_pc_val = ffi_hw.read_reg(*hbm_pc.offset() as u64);
184        let hbm_pc_fields = hbm_pc.as_field(hbm_pc_val);
185
186        let ksk_pc = *hbm_pc_fields.get("ksk_pc").expect("Unknown field") as usize;
187        let bsk_pc = *hbm_pc_fields.get("bsk_pc").expect("Unknown field") as usize;
188        let pem_pc = *hbm_pc_fields.get("pem_pc").expect("Unknown field") as usize;
189
190        // Extract bus width for each channel
191        let ksk_bytes_w = {
192            let ksk_axi4_data_w = regmap
193                .register()
194                .get("info::hbm_axi4_dataw_ksk")
195                .expect("Unknown register, check regmap definition");
196            let ksk_axi4_data_w_val = ffi_hw.read_reg(*ksk_axi4_data_w.offset() as u64);
197            // Value is in bit in rtl and SW expect bytes
198            ksk_axi4_data_w_val.div_ceil(u8::BITS) as usize
199        };
200        let bsk_bytes_w = {
201            let bsk_axi4_data_w = regmap
202                .register()
203                .get("info::hbm_axi4_dataw_bsk")
204                .expect("Unknown register, check regmap definition");
205            let bsk_axi4_data_w_val = ffi_hw.read_reg(*bsk_axi4_data_w.offset() as u64);
206            // Value is in bit in rtl and SW expect bytes
207            bsk_axi4_data_w_val.div_ceil(u8::BITS) as usize
208        };
209        let pem_bytes_w = {
210            let pem_axi4_data_w = regmap
211                .register()
212                .get("info::hbm_axi4_dataw_pem")
213                .expect("Unknown register, check regmap definition");
214            let pem_axi4_data_w_val = ffi_hw.read_reg(*pem_axi4_data_w.offset() as u64);
215            // Value is in bit in rtl and SW expect bytes
216            pem_axi4_data_w_val.div_ceil(u8::BITS) as usize
217        };
218        let glwe_bytes_w = {
219            let glwe_axi4_data_w = regmap
220                .register()
221                .get("info::hbm_axi4_dataw_glwe")
222                .expect("Unknown register, check regmap definition");
223            let glwe_axi4_data_w_val = ffi_hw.read_reg(*glwe_axi4_data_w.offset() as u64);
224            // Value is in bit in rtl and SW expect bytes
225            glwe_axi4_data_w_val.div_ceil(u8::BITS) as usize
226        };
227
228        Self {
229            ksk_pc,
230            bsk_pc,
231            pem_pc,
232            ksk_bytes_w,
233            bsk_bytes_w,
234            pem_bytes_w,
235            glwe_bytes_w,
236        }
237    }
238}
239
240impl FromRtl for HpuRegfileParameters {
241    fn from_rtl(ffi_hw: &mut ffi::HpuHw, regmap: &FlatRegmap) -> Self {
242        let regf = regmap
243            .register()
244            .get("info::regf_structure")
245            .expect("Unknown register, check regmap definition");
246        let regf_val = ffi_hw.read_reg(*regf.offset() as u64);
247        let regf_fields = regf.as_field(regf_val);
248
249        Self {
250            reg_nb: *regf_fields.get("reg_nb").expect("Unknown field") as usize,
251            coef_nb: *regf_fields.get("coef_nb").expect("Unknown field") as usize,
252        }
253    }
254}
255
256impl FromRtl for HpuIscParameters {
257    fn from_rtl(ffi_hw: &mut ffi::HpuHw, regmap: &FlatRegmap) -> Self {
258        let isc = regmap
259            .register()
260            .get("info::isc_structure")
261            .expect("Unknown register, check regmap definition");
262        let isc_val = ffi_hw.read_reg(*isc.offset() as u64);
263        let isc_fields = isc.as_field(isc_val);
264
265        Self {
266            min_iop_size: *isc_fields.get("min_iop_size").expect("Unknown field") as usize,
267            depth: *isc_fields.get("depth").expect("Unknown field") as usize,
268        }
269    }
270}
271
272// Define parameters set as constants
273// Used to easily derived IoMeasure version without duplication
274pub const CONCRETE_BOOLEAN: HpuPBSParameters = HpuPBSParameters {
275    lwe_dimension: 586,
276    glwe_dimension: 2,
277    polynomial_size: 512,
278    lwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(0.00000000007069849454709433),
279    glwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(
280        0.0000000000000000000029403601535432533,
281    ),
282    pbs_base_log: 8,
283    pbs_level: 2,
284    ks_base_log: 5,
285    ks_level: 4,
286    message_width: 1,
287    carry_width: 0,
288    ciphertext_width: 32,
289    log2_p_fail: -64.0,
290    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
291};
292
293pub const MSG2_CARRY2: HpuPBSParameters = HpuPBSParameters {
294    lwe_dimension: 742,
295    glwe_dimension: 1,
296    polynomial_size: 2048,
297    lwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(9.039_924_320_497_611e-6_f64),
298    glwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(3.1529314934984704e-16_f64),
299    pbs_base_log: 19,
300    pbs_level: 1,
301    ks_base_log: 3,
302    ks_level: 5,
303    message_width: 2,
304    carry_width: 2,
305    ciphertext_width: u64::BITS as usize,
306    log2_p_fail: -64.0,
307    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
308};
309
310pub const MSG2_CARRY2_64B: HpuPBSParameters = HpuPBSParameters {
311    lwe_dimension: 710,
312    glwe_dimension: 2,
313    polynomial_size: 1024,
314    lwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(1.630_783_646_854_603e-5_f64),
315    glwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(3.1529314934984704e-16_f64),
316    pbs_base_log: 25,
317    pbs_level: 1,
318    ks_base_log: 2,
319    ks_level: 7,
320    message_width: 2,
321    carry_width: 2,
322    ciphertext_width: u64::BITS as usize,
323    log2_p_fail: -64.0,
324    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
325};
326
327pub const MSG2_CARRY2_44B: HpuPBSParameters = HpuPBSParameters {
328    lwe_dimension: 724,
329    glwe_dimension: 2,
330    polynomial_size: 1024,
331    lwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(
332        1.259_780_968_897_627_7e-5_f64,
333    ),
334    glwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(2.2737367544323206e-13_f64),
335    pbs_base_log: 20,
336    pbs_level: 1,
337    ks_base_log: 2,
338    ks_level: 7,
339    message_width: 2,
340    carry_width: 2,
341    ciphertext_width: 44,
342    log2_p_fail: -64.0,
343    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
344};
345
346pub const MSG2_CARRY2_64B_FAKE: HpuPBSParameters = HpuPBSParameters {
347    lwe_dimension: 724,
348    glwe_dimension: 2,
349    polynomial_size: 1024,
350    lwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(
351        1.259_780_968_897_627_7e-5_f64,
352    ),
353    glwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(2.2737367544323206e-13_f64),
354    pbs_base_log: 20,
355    pbs_level: 1,
356    ks_base_log: 2,
357    ks_level: 7,
358    message_width: 2,
359    carry_width: 2,
360    ciphertext_width: 64,
361    log2_p_fail: -64.0,
362    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
363};
364
365pub const MSG2_CARRY2_GAUSSIAN: HpuPBSParameters = HpuPBSParameters {
366    lwe_dimension: 834,
367    glwe_dimension: 1,
368    polynomial_size: 2048,
369    lwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(
370        3.553_990_235_944_282_5e-6_f64,
371    ),
372    glwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(2.845267479601915e-15_f64),
373    pbs_base_log: 23,
374    pbs_level: 1,
375    ks_base_log: 3,
376    ks_level: 5,
377    message_width: 2,
378    carry_width: 2,
379    ciphertext_width: 64,
380    log2_p_fail: -64.0,
381    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
382};
383
384pub const MSG2_CARRY2_TUNIFORM: HpuPBSParameters = HpuPBSParameters {
385    lwe_dimension: 887,
386    glwe_dimension: 1,
387    polynomial_size: 2048,
388    lwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(
389        3.553_990_235_944_282_5e-6_f64,
390    ),
391    glwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(2.845267479601915e-15_f64),
392    pbs_base_log: 22,
393    pbs_level: 1,
394    ks_base_log: 3,
395    ks_level: 5,
396    message_width: 2,
397    carry_width: 2,
398    ciphertext_width: 64,
399    log2_p_fail: -64.0,
400    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
401};
402
403pub const MSG2_CARRY2_PFAIL64_132B_GAUSSIAN_1F72DBA: HpuPBSParameters = HpuPBSParameters {
404    lwe_dimension: 804,
405    glwe_dimension: 1,
406    polynomial_size: 2048,
407    lwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(5.963_599_673_924_788e-6_f64),
408    glwe_noise_distribution: HpuNoiseDistributionInput::GaussianStdDev(2.8452674713391114e-15_f64),
409    pbs_base_log: 23,
410    pbs_level: 1,
411    ks_base_log: 2,
412    ks_level: 8,
413    message_width: 2,
414    carry_width: 2,
415    ciphertext_width: 64,
416    log2_p_fail: -64.0,
417    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
418};
419
420pub const MSG2_CARRY2_PFAIL64_132B_TUNIFORM_7E47D8C: HpuPBSParameters = HpuPBSParameters {
421    lwe_dimension: 839,
422    glwe_dimension: 1,
423    polynomial_size: 2048,
424    lwe_noise_distribution: HpuNoiseDistributionInput::TUniformBound(4),
425    glwe_noise_distribution: HpuNoiseDistributionInput::TUniformBound(17),
426    pbs_base_log: 23,
427    pbs_level: 1,
428    ks_base_log: 2,
429    ks_level: 7,
430    message_width: 2,
431    carry_width: 2,
432    ciphertext_width: 64,
433    log2_p_fail: -64.0,
434    modulus_switch_type: parameters::HpuModulusSwitchType::Standard,
435};
436
437pub const MSG2_CARRY2_PFAIL128_132B_TUNIFORM_144A47: HpuPBSParameters = HpuPBSParameters {
438    lwe_dimension: 879,
439    glwe_dimension: 1,
440    polynomial_size: 2048,
441    lwe_noise_distribution: HpuNoiseDistributionInput::TUniformBound(3),
442    glwe_noise_distribution: HpuNoiseDistributionInput::TUniformBound(17),
443    pbs_base_log: 23,
444    pbs_level: 1,
445    ks_base_log: 2,
446    ks_level: 8,
447    message_width: 2,
448    carry_width: 2,
449    ciphertext_width: 64,
450    log2_p_fail: -128.0,
451    modulus_switch_type: parameters::HpuModulusSwitchType::CenteredMeanNoiseReduction,
452};
453
454impl FromRtl for HpuPBSParameters {
455    fn from_rtl(ffi_hw: &mut ffi::HpuHw, regmap: &FlatRegmap) -> Self {
456        let pbs_app = regmap
457            .register()
458            .get("info::application")
459            .expect("Unknown register, check regmap definition");
460        let pbs_app_val = ffi_hw.read_reg(*pbs_app.offset() as u64);
461
462        // Check register encoding
463        let field_code = pbs_app_val & (!0xFF_u32);
464        #[cfg(not(any(feature = "hw-xrt", feature = "hw-v80")))]
465        {
466            if (field_code == 0) && (pbs_app_val == SIMULATION_CODE) {
467                tracing::warn!("Run an simulation backend with custom SIMU parameters set");
468                return ffi_hw.get_pbs_parameters();
469            }
470        }
471        #[cfg(any(feature = "hw-xrt", feature = "hw-v80"))]
472        {
473            assert_eq!(
474                field_code, APPLICATION_NAME_OFS,
475                "Invalid register encoding. Check register map definition"
476            );
477        }
478
479        match pbs_app_val & 0xFF {
480            0 => CONCRETE_BOOLEAN,
481            1 => MSG2_CARRY2,
482            2 => {
483                let mut params = MSG2_CARRY2;
484                params.lwe_dimension = 2;
485                params
486            }
487            3 => MSG2_CARRY2_64B,
488            4 => MSG2_CARRY2_44B,
489            9 => MSG2_CARRY2_64B_FAKE,
490            10 => MSG2_CARRY2_GAUSSIAN,
491            11 => MSG2_CARRY2_TUNIFORM,
492            12 => MSG2_CARRY2_PFAIL64_132B_GAUSSIAN_1F72DBA,
493            13 => MSG2_CARRY2_PFAIL64_132B_TUNIFORM_7E47D8C,
494            14 => MSG2_CARRY2_PFAIL128_132B_TUNIFORM_144A47,
495            _ => panic!("Unknown TfheAppName encoding"),
496        }
497    }
498}