|
1 | 1 | use crate::galois_engine::degree4::GaloisRingIrisCodeShare;
|
| 2 | +use crate::IRIS_CODE_LENGTH; |
| 3 | +use crate::ROTATIONS; |
2 | 4 | use base64::{prelude::BASE64_STANDARD, Engine};
|
| 5 | +use bitvec::array::BitArray; |
| 6 | +use bitvec::slice::BitSlice; |
| 7 | +use bitvec::vec::BitVec; |
3 | 8 | use eyre::bail;
|
4 | 9 | use eyre::Result;
|
| 10 | +use itertools::izip; |
5 | 11 | use rand::{
|
6 | 12 | distributions::{Bernoulli, Distribution},
|
7 | 13 | Rng,
|
@@ -183,6 +189,121 @@ impl Default for IrisCode {
|
183 | 189 | }
|
184 | 190 | }
|
185 | 191 |
|
| 192 | +pub struct RotExtIrisCodeArray(pub [BitVec; 16]); |
| 193 | + |
| 194 | +impl From<IrisCodeArray> for RotExtIrisCodeArray { |
| 195 | + fn from(value: IrisCodeArray) -> Self { |
| 196 | + let code = value.bits().collect::<Vec<_>>(); |
| 197 | + Self( |
| 198 | + code.chunks_exact(IrisCode::CODE_COLS * 4) |
| 199 | + .map(|chunk| { |
| 200 | + let mut extended = [false; |
| 201 | + IrisCode::CODE_COLS * 4 + 2 * IrisCode::ROTATIONS_PER_DIRECTION * 4]; |
| 202 | + let left_len = IrisCode::ROTATIONS_PER_DIRECTION * 4; |
| 203 | + let chunk_len = IrisCode::CODE_COLS * 4; |
| 204 | + let right_len = IrisCode::ROTATIONS_PER_DIRECTION * 4; |
| 205 | + |
| 206 | + extended[..left_len].copy_from_slice(&chunk[chunk_len - left_len..chunk_len]); |
| 207 | + extended[left_len..left_len + chunk_len].copy_from_slice(chunk); |
| 208 | + extended[left_len + chunk_len..].copy_from_slice(&chunk[..right_len]); |
| 209 | + let extended: BitVec = extended.into_iter().collect(); |
| 210 | + extended |
| 211 | + }) |
| 212 | + .collect::<Vec<_>>() |
| 213 | + .try_into() |
| 214 | + .unwrap(), |
| 215 | + ) |
| 216 | + } |
| 217 | +} |
| 218 | + |
| 219 | +impl RotExtIrisCodeArray { |
| 220 | + pub const CENTER_START: usize = 4 * IrisCode::ROTATIONS_PER_DIRECTION; |
| 221 | + pub const ROW_LEN: usize = 800; |
| 222 | + |
| 223 | + fn get_rotation_slice(&self, by: isize) -> [&BitSlice; 16] { |
| 224 | + let start = (Self::CENTER_START as isize + 4 * by) |
| 225 | + .try_into() |
| 226 | + .expect("Invalid rotation delta"); |
| 227 | + let ret_vec = self |
| 228 | + .0 |
| 229 | + .iter() |
| 230 | + .map(|row| &row[start..start + Self::ROW_LEN]) |
| 231 | + .collect::<Vec<_>>(); |
| 232 | + ret_vec.try_into().unwrap() |
| 233 | + } |
| 234 | +} |
| 235 | + |
| 236 | +pub struct RotExtIrisCode { |
| 237 | + code: RotExtIrisCodeArray, |
| 238 | + mask: RotExtIrisCodeArray, |
| 239 | +} |
| 240 | + |
| 241 | +impl From<IrisCode> for RotExtIrisCode { |
| 242 | + fn from(value: IrisCode) -> Self { |
| 243 | + RotExtIrisCode { |
| 244 | + code: value.code.into(), |
| 245 | + mask: value.mask.into(), |
| 246 | + } |
| 247 | + } |
| 248 | +} |
| 249 | + |
| 250 | +struct RotExtIrisCodeRef<'a> { |
| 251 | + code: [&'a BitSlice; 16], |
| 252 | + mask: [&'a BitSlice; 16], |
| 253 | +} |
| 254 | + |
| 255 | +impl RotExtIrisCode { |
| 256 | + fn get_rotation<'a>(&'a self, by: isize) -> RotExtIrisCodeRef<'a> { |
| 257 | + RotExtIrisCodeRef { |
| 258 | + code: self.code.get_rotation_slice(by), |
| 259 | + mask: self.mask.get_rotation_slice(by), |
| 260 | + } |
| 261 | + } |
| 262 | +} |
| 263 | + |
| 264 | +impl RotExtIrisCodeRef<'_> { |
| 265 | + fn get_distance_fraction(&self, other: &RotExtIrisCodeRef) -> (u16, u16) { |
| 266 | + izip!(self.code, self.mask, other.code, other.mask).fold( |
| 267 | + (0, 0), |
| 268 | + |(num, denom), (lhs_code, lhs_mask, rhs_code, rhs_mask)| { |
| 269 | + let combined_mask = lhs_mask.to_owned() & rhs_mask; |
| 270 | + let combined_mask_len = combined_mask.count_ones(); |
| 271 | + |
| 272 | + let combined_code = (lhs_code.to_owned() ^ rhs_code) & combined_mask; |
| 273 | + let code_distance = combined_code.count_ones(); |
| 274 | + |
| 275 | + ( |
| 276 | + num + (code_distance as u16), |
| 277 | + denom + (combined_mask_len as u16), |
| 278 | + ) |
| 279 | + }, |
| 280 | + ) |
| 281 | + } |
| 282 | +} |
| 283 | + |
| 284 | +pub fn fraction_less_than(dist_1: &(u16, u16), dist_2: &(u16, u16)) -> bool { |
| 285 | + let (a, b) = *dist_1; // a/b |
| 286 | + let (c, d) = *dist_2; // c/d |
| 287 | + ((a as u32) * (d as u32)) < ((b as u32) * (c as u32)) |
| 288 | +} |
| 289 | + |
| 290 | +impl RotExtIrisCode { |
| 291 | + pub fn min_fhe(&self, other: &RotExtIrisCode) -> (u16, u16) { |
| 292 | + let other_center = other.get_rotation(0); |
| 293 | + |
| 294 | + let mut ret = (0, 1); |
| 295 | + for rot in -15..16 { |
| 296 | + let self_rotated = self.get_rotation(rot); |
| 297 | + let dist = self_rotated.get_distance_fraction(&other_center); |
| 298 | + if fraction_less_than(&dist, &ret) { |
| 299 | + ret = dist; |
| 300 | + } |
| 301 | + } |
| 302 | + |
| 303 | + ret |
| 304 | + } |
| 305 | +} |
| 306 | + |
186 | 307 | impl IrisCode {
|
187 | 308 | pub const IRIS_CODE_SIZE: usize = IrisCodeArray::IRIS_CODE_SIZE;
|
188 | 309 | pub const CODE_COLS: usize = 200;
|
|
0 commit comments