1use crate::aes::{Iv, Key, Pad, IV_SIZE, KEY_SIZE, PAD_SIZE};
2use bytes::Bytes;
3use xor_name::XorName;
4
5pub(crate) fn xor(data: &Bytes, &Pad(pad): &Pad) -> Bytes {
7 let vec: Vec<_> = data
8 .iter()
9 .zip(pad.iter().cycle())
10 .map(|(&a, &b)| a ^ b)
11 .collect();
12 Bytes::from(vec)
13}
14
15pub fn extract_hashes(data_map: &crate::DataMap) -> Vec<XorName> {
16 data_map.infos().iter().map(|c| c.src_hash).collect()
17}
18
19pub(crate) fn get_pad_key_and_iv(chunk_index: usize, chunk_hashes: &[XorName]) -> (Pad, Key, Iv) {
20 let (n_1, n_2) = get_n_1_n_2(chunk_index, chunk_hashes.len());
21
22 let src_hash = &chunk_hashes[chunk_index];
23 let n_1_src_hash = &chunk_hashes[n_1];
24 let n_2_src_hash = &chunk_hashes[n_2];
25
26 get_pki(src_hash, n_1_src_hash, n_2_src_hash)
27}
28
29pub(crate) fn get_n_1_n_2(chunk_index: usize, total_num_chunks: usize) -> (usize, usize) {
30 match chunk_index {
31 0 => (total_num_chunks - 1, total_num_chunks - 2),
32 1 => (0, total_num_chunks - 1),
33 n => (n - 1, n - 2),
34 }
35}
36
37pub(crate) fn get_pki(
38 src_hash: &XorName,
39 n_1_src_hash: &XorName,
40 n_2_src_hash: &XorName,
41) -> (Pad, Key, Iv) {
42 let mut pad = [0u8; PAD_SIZE];
43 let mut key = [0u8; KEY_SIZE];
44 let mut iv = [0u8; IV_SIZE];
45
46 for (pad_iv_el, element) in pad
47 .iter_mut()
48 .zip(src_hash.iter().chain(n_2_src_hash.iter()))
49 {
50 *pad_iv_el = *element;
51 }
52
53 for (key_el, element) in key.iter_mut().chain(iv.iter_mut()).zip(n_1_src_hash.iter()) {
54 *key_el = *element;
55 }
56
57 (Pad(pad), Key(key), Iv(iv))
58}
59
60pub(crate) fn get_num_chunks(file_size: usize) -> usize {
62 get_num_chunks_with_variable_max(file_size, crate::MAX_CHUNK_SIZE)
63}
64
65pub(crate) fn get_num_chunks_with_variable_max(file_size: usize, max_chunk_size: usize) -> usize {
67 if file_size < (3 * crate::MIN_CHUNK_SIZE) {
68 return 0;
69 }
70 if file_size < (3 * max_chunk_size) {
71 return 3;
72 }
73 if file_size.is_multiple_of(max_chunk_size) {
74 file_size / max_chunk_size
75 } else {
76 (file_size / max_chunk_size) + 1
77 }
78}
79
80pub(crate) fn get_chunk_size(file_size: usize, chunk_index: usize) -> usize {
82 get_chunk_size_with_variable_max(file_size, chunk_index, crate::MAX_CHUNK_SIZE)
83}
84
85pub(crate) fn get_chunk_size_with_variable_max(
87 file_size: usize,
88 chunk_index: usize,
89 max_chunk_size: usize,
90) -> usize {
91 if file_size < 3 * crate::MIN_CHUNK_SIZE {
92 return 0;
93 }
94 if file_size < 3 * max_chunk_size {
95 if chunk_index < 2 {
96 return file_size / 3;
97 } else {
98 return file_size - (2 * (file_size / 3));
100 }
101 }
102 let total_chunks = get_num_chunks_with_variable_max(file_size, max_chunk_size);
103 if chunk_index < total_chunks - 2 {
104 return max_chunk_size;
105 }
106 let remainder = file_size % max_chunk_size;
107 let penultimate = (total_chunks - 2) == chunk_index;
108 if remainder == 0 {
109 return max_chunk_size;
110 }
111 if remainder < crate::MIN_CHUNK_SIZE {
112 if penultimate {
113 max_chunk_size - crate::MIN_CHUNK_SIZE
114 } else {
115 crate::MIN_CHUNK_SIZE + remainder
116 }
117 } else if penultimate {
118 max_chunk_size
119 } else {
120 remainder
121 }
122}
123
124pub(crate) fn get_start_end_positions(file_size: usize, chunk_index: usize) -> (usize, usize) {
126 if get_num_chunks(file_size) == 0 {
127 return (0, 0);
128 }
129 let start = get_start_position(file_size, chunk_index);
130 (start, start + get_chunk_size(file_size, chunk_index))
131}
132
133pub(crate) fn get_start_position(file_size: usize, chunk_index: usize) -> usize {
134 let total_chunks = get_num_chunks(file_size);
135 if total_chunks == 0 {
136 return 0;
137 }
138 let last = (total_chunks - 1) == chunk_index;
139 let first_chunk_size = get_chunk_size(file_size, 0);
140 if last {
141 first_chunk_size * (chunk_index - 1) + get_chunk_size(file_size, chunk_index - 1)
142 } else {
143 first_chunk_size * chunk_index
144 }
145}
146
147#[allow(dead_code)]
148pub(crate) fn get_chunk_index(file_size: usize, position: usize) -> usize {
149 let num_chunks = get_num_chunks(file_size);
150 if num_chunks == 0 {
151 return 0; }
153
154 let chunk_size = get_chunk_size(file_size, 0);
155 let remainder = file_size % chunk_size;
156
157 if remainder == 0
158 || remainder >= crate::MIN_CHUNK_SIZE
159 || position < file_size - remainder - crate::MIN_CHUNK_SIZE
160 {
161 usize::min(position / chunk_size, num_chunks - 1)
162 } else {
163 num_chunks - 1
164 }
165}