Skip to main content

rustfs_erasure_codec/core/
verify.rs

1extern crate alloc;
2
3use alloc::vec;
4use alloc::vec::Vec;
5
6use smallvec::SmallVec;
7
8use crate::Field;
9use crate::errors::Error;
10
11use super::{ReedSolomon, VERIFY_INLINE_SCRATCH_ELEMS, VerifyWorkspace};
12
13impl<F: Field> ReedSolomon<F> {
14    fn check_some_slices_with_buffer<T, U>(
15        &self,
16        matrix_rows: &[&[F::Elem]],
17        inputs: &[T],
18        to_check: &[T],
19        buffer: &mut [U],
20    ) -> bool
21    where
22        T: AsRef<[F::Elem]>,
23        U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
24    {
25        self.code_some_slices(matrix_rows, inputs, buffer);
26
27        for (expected_parity_shard, actual_parity_shard) in buffer.iter().zip(to_check.iter()) {
28            if expected_parity_shard.as_ref() != actual_parity_shard.as_ref() {
29                return false;
30            }
31        }
32        true
33    }
34
35    fn check_some_slices_with_buffer_raw<T: AsRef<[F::Elem]>>(
36        &self,
37        matrix_rows: &[&[F::Elem]],
38        inputs: &[T],
39        to_check: &[T],
40        buffer: &mut [&mut [F::Elem]],
41    ) -> bool {
42        self.code_some_slices(matrix_rows, inputs, buffer);
43
44        for (expected_parity_shard, actual_parity_shard) in buffer.iter().zip(to_check.iter()) {
45            if *expected_parity_shard != actual_parity_shard.as_ref() {
46                return false;
47            }
48        }
49        true
50    }
51
52    fn verify_leopard_with_buffer<T, U>(
53        &self,
54        slices: &[T],
55        parity: &mut [U],
56    ) -> Result<bool, Error>
57    where
58        T: AsRef<[F::Elem]>,
59        U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
60    {
61        let data = &slices[0..self.data_shard_count];
62        let to_check = &slices[self.data_shard_count..];
63        if self.is_leopard_gf8_family() {
64            self.encode_leopard_gf8_sep(data, parity)?;
65        } else {
66            self.encode_leopard_gf16_sep(data, parity)?;
67        }
68
69        for (expected, actual) in parity.iter().zip(to_check.iter()) {
70            if expected.as_ref() != actual.as_ref() {
71                return Ok(false);
72            }
73        }
74        Ok(true)
75    }
76
77    /// Verify Leopard parity shards by re-encoding and comparing.
78    fn verify_leopard<T: AsRef<[F::Elem]>>(&self, slices: &[T]) -> Result<bool, Error> {
79        let slice_len = slices[0].as_ref().len();
80        let mut parity_bufs: Vec<Vec<F::Elem>> = (0..self.parity_shard_count)
81            .map(|_| vec![F::zero(); slice_len])
82            .collect();
83        self.verify_leopard_with_buffer(slices, &mut parity_bufs)
84    }
85
86    /// Verify that parity shards are consistent with data shards.
87    ///
88    /// Returns `true` if valid, `false` if corrupted.
89    pub fn verify<T: AsRef<[F::Elem]>>(&self, slices: &[T]) -> Result<bool, Error> {
90        self.ensure_classic_family_execution()?;
91        check_piece_count!(all => self, slices);
92        check_slices!(multi => slices);
93
94        if self.is_leopard_gf8_family() || self.is_leopard_gf16_family() {
95            return self.verify_leopard(slices);
96        }
97
98        let slice_len = slices[0].as_ref().len();
99        let data = &slices[0..self.data_shard_count];
100        let to_check = &slices[self.data_shard_count..];
101
102        if self.fast_one_parity_enabled() {
103            let mut buffer = vec![F::zero(); slice_len];
104            self.encode_fast_one_parity(data, core::slice::from_mut(&mut buffer));
105            return Ok(buffer.as_slice() == to_check[0].as_ref());
106        }
107
108        let parity_rows = self.get_parity_rows();
109        let scratch_len = self.parity_shard_count * slice_len;
110        let mut scratch: SmallVec<[F::Elem; VERIFY_INLINE_SCRATCH_ELEMS]> =
111            SmallVec::with_capacity(scratch_len);
112        scratch.resize(scratch_len, F::zero());
113        let mut buffer_views: SmallVec<[&mut [F::Elem]; 32]> =
114            scratch.chunks_mut(slice_len).collect();
115
116        Ok(self.check_some_slices_with_buffer_raw(&parity_rows, data, to_check, &mut buffer_views))
117    }
118
119    /// Verify using a pre-allocated [`VerifyWorkspace`] to avoid repeated allocation.
120    pub fn verify_with_workspace<T>(
121        &self,
122        slices: &[T],
123        workspace: &mut VerifyWorkspace<F>,
124    ) -> Result<bool, Error>
125    where
126        T: AsRef<[F::Elem]>,
127    {
128        self.ensure_classic_family_execution()?;
129        check_piece_count!(all => self, slices);
130        check_slices!(multi => slices);
131
132        let slice_len = slices[0].as_ref().len();
133        if self.is_leopard_gf8_family() || self.is_leopard_gf16_family() {
134            workspace.prepare(self, slice_len);
135            return self.verify_leopard_with_buffer(slices, workspace.as_mut_shards());
136        }
137
138        workspace.prepare(self, slice_len);
139        self.verify_with_buffer(slices, workspace.as_mut_shards())
140    }
141
142    /// Verify using a caller-provided scratch buffer.
143    pub fn verify_with_buffer<T, U>(&self, slices: &[T], buffer: &mut [U]) -> Result<bool, Error>
144    where
145        T: AsRef<[F::Elem]>,
146        U: AsRef<[F::Elem]> + AsMut<[F::Elem]>,
147    {
148        self.ensure_classic_family_execution()?;
149        check_piece_count!(all => self, slices);
150        check_piece_count!(parity_buf => self, buffer);
151        check_slices!(multi => slices, multi => buffer);
152
153        if self.is_leopard_gf8_family() || self.is_leopard_gf16_family() {
154            return self.verify_leopard_with_buffer(slices, buffer);
155        }
156
157        let data = &slices[0..self.data_shard_count];
158        let to_check = &slices[self.data_shard_count..];
159
160        if self.fast_one_parity_enabled() {
161            self.encode_fast_one_parity(data, buffer);
162            return Ok(buffer[0].as_ref() == to_check[0].as_ref());
163        }
164
165        let parity_rows = self.get_parity_rows();
166        Ok(self.check_some_slices_with_buffer(&parity_rows, data, to_check, buffer))
167    }
168
169    /// Parallel version of [`verify_with_buffer`](Self::verify_with_buffer).
170    #[cfg(feature = "std")]
171    pub fn verify_with_buffer_par<T, U>(
172        &self,
173        slices: &[T],
174        buffer: &mut [U],
175    ) -> Result<bool, Error>
176    where
177        F::Elem: Send + Sync,
178        T: AsRef<[F::Elem]> + Sync,
179        U: AsRef<[F::Elem]> + AsMut<[F::Elem]> + Send,
180    {
181        self.ensure_classic_family_execution()?;
182        check_piece_count!(all => self, slices);
183        check_piece_count!(parity_buf => self, buffer);
184        check_slices!(multi => slices, multi => buffer);
185
186        if self.is_leopard_gf8_family() || self.is_leopard_gf16_family() {
187            return self.verify_leopard_with_buffer(slices, buffer);
188        }
189
190        let data = &slices[0..self.data_shard_count];
191        let to_check = &slices[self.data_shard_count..];
192
193        if self.fast_one_parity_enabled() {
194            self.encode_fast_one_parity(data, buffer);
195            return Ok(buffer[0].as_ref() == to_check[0].as_ref());
196        }
197
198        self.encode_sep_par(data, buffer)?;
199
200        Ok(buffer
201            .iter()
202            .zip(to_check.iter())
203            .all(|(expected, actual)| expected.as_ref() == actual.as_ref()))
204    }
205
206    /// Parallel version of [`verify`](Self::verify).
207    #[cfg(feature = "std")]
208    pub fn verify_par<T>(&self, slices: &[T]) -> Result<bool, Error>
209    where
210        F::Elem: Send + Sync,
211        T: AsRef<[F::Elem]> + Sync,
212    {
213        self.ensure_classic_family_execution()?;
214        check_piece_count!(all => self, slices);
215        check_slices!(multi => slices);
216
217        if self.is_leopard_gf8_family() || self.is_leopard_gf16_family() {
218            return self.verify_leopard(slices);
219        }
220
221        let slice_len = slices[0].as_ref().len();
222        let scratch_len = self.parity_shard_count * slice_len;
223        let mut scratch: SmallVec<[F::Elem; VERIFY_INLINE_SCRATCH_ELEMS]> =
224            SmallVec::with_capacity(scratch_len);
225        scratch.resize(scratch_len, F::zero());
226        let mut buffer_views: SmallVec<[&mut [F::Elem]; 32]> =
227            scratch.chunks_mut(slice_len).collect();
228
229        self.verify_with_buffer_par(slices, &mut buffer_views)
230    }
231}