Skip to main content

zip_plus/code/
raa_sign_flip.rs

1use super::raa::*;
2use crate::{code::LinearCode, pcs::structs::ZipTypes, utils::shuffle_seeded};
3use crypto_primitives::{
4    BaseFieldConfig, FixedConfig, ProjectPrimitiveIntegersWithConfig, Ring, RingConfig,
5};
6use std::fmt::Debug;
7use zinc_utils::from_ref::FromRef;
8
9/// Implementation of a repeat-accumulate-accumulate (RAA) codes.
10/// Flips signs of every second entry in the codeword, starting from the second
11/// one.
12#[derive(Clone)]
13pub struct RaaSignFlippingCode<Zt: ZipTypes, Config: RaaConfig, const REP: usize> {
14    raa: RaaCode<Zt, Config, REP>,
15}
16
17impl<Zt: ZipTypes, Config: RaaConfig, const REP: usize> RaaSignFlippingCode<Zt, Config, REP>
18where
19    Zt::Cw: Ring,
20{
21    pub fn new(row_len: usize) -> Self {
22        Self {
23            raa: RaaCode::new(row_len),
24        }
25    }
26
27    /// Do the actual encoding, as per RAA spec
28    fn encode_inner<In, C, Map>(&self, cfg: &C, row: &[In], map: Map) -> Vec<C::Element>
29    where
30        C: RingConfig,
31        Map: Fn(&In) -> C::Element + Clone,
32    {
33        debug_assert_eq!(
34            row.len(),
35            self.raa.row_len,
36            "Row length must match the code's row length"
37        );
38
39        let mut result: Vec<C::Element> = repeat(row, REP, map);
40        flip_even_signs(cfg, &mut result, Config::CHECK_FOR_OVERFLOWS);
41        if Config::PERMUTE_IN_PLACE {
42            shuffle_seeded(&mut result, self.raa.perm_1_seed);
43        } else {
44            result = clone_shuffled(&result, &self.raa.perm_1);
45        }
46        if Config::CHECK_FOR_OVERFLOWS {
47            accumulate(cfg, &mut result);
48        } else {
49            accumulate_unchecked(cfg, &mut result);
50        }
51        flip_even_signs(cfg, &mut result, Config::CHECK_FOR_OVERFLOWS);
52        if Config::PERMUTE_IN_PLACE {
53            shuffle_seeded(&mut result, self.raa.perm_2_seed);
54        } else {
55            result = clone_shuffled(&result, &self.raa.perm_2);
56        }
57        if Config::CHECK_FOR_OVERFLOWS {
58            accumulate(cfg, &mut result);
59        } else {
60            accumulate_unchecked(cfg, &mut result);
61        }
62        debug_assert_eq!(result.len(), self.codeword_len());
63        result
64    }
65}
66
67impl<Zt: ZipTypes, Config: RaaConfig, const REP: usize> LinearCode<Zt>
68    for RaaSignFlippingCode<Zt, Config, REP>
69where
70    Zt::Cw: Ring,
71{
72    const REPETITION_FACTOR: usize = REP;
73
74    fn row_len(&self) -> usize {
75        self.raa.row_len()
76    }
77
78    #[allow(clippy::arithmetic_side_effects)]
79    fn codeword_len(&self) -> usize {
80        self.raa.codeword_len()
81    }
82
83    fn params_string(&self) -> String {
84        self.raa.params_string()
85    }
86
87    fn encode(&self, row: &[Zt::Eval]) -> Vec<Zt::Cw> {
88        self.encode_inner(&FixedConfig::default(), row, Zt::Cw::from_ref)
89    }
90
91    fn encode_wide(&self, row: &[Zt::CombR]) -> Vec<Zt::CombR> {
92        self.encode_inner(&FixedConfig::default(), row, |v| v.clone())
93    }
94
95    fn encode_f<C>(&self, cfg: &C, row: &[C::Element]) -> Vec<C::Element>
96    where
97        C: BaseFieldConfig + ProjectPrimitiveIntegersWithConfig,
98    {
99        self.encode_inner(cfg, row, |v| v.clone())
100    }
101}
102
103impl<Zt: ZipTypes, Config: RaaConfig, const REP: usize> Debug
104    for RaaSignFlippingCode<Zt, Config, REP>
105{
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        f.debug_struct("SignFlipping")
108            .field("row_len", &self.raa.row_len)
109            .field("perm_1_seed", &self.raa.perm_1_seed)
110            .field("perm_2_seed", &self.raa.perm_2_seed)
111            .finish()
112    }
113}
114
115impl<Zt: ZipTypes, Config: RaaConfig, const REP: usize> PartialEq
116    for RaaSignFlippingCode<Zt, Config, REP>
117{
118    fn eq(&self, other: &Self) -> bool {
119        self.raa == other.raa
120    }
121}
122
123impl<Zt: ZipTypes, Config: RaaConfig, const REP: usize> Eq
124    for RaaSignFlippingCode<Zt, Config, REP>
125{
126}
127
128fn flip_even_signs<C: RingConfig>(cfg: &C, result: &mut [C::Element], check_for_overflows: bool) {
129    // Flip every other entry in the codeword
130    for i in (1..result.len()).step_by(2) {
131        if check_for_overflows {
132            result[i] = cfg.checked_neg(&result[i]).expect("Negation overflow");
133        } else {
134            cfg.neg_assign(&mut result[i]);
135        }
136    }
137}