use rand::Rng;
use std::mem::size_of;
use crate::{ err::MixError, MAX_U16, MAX_U32, MAX_U56, encoder::traits::EncoderDecoder };
#[derive(Default, Debug)]
struct RandType {
slat: u64,
rand: u8,
padding: u8,
key_check: u8,
rand_check: u8,
}
fn normalization(user_key: u64, src_id: u64, is_decode: bool) -> (u64, RandType, u64) {
let key: u64;
let mut id = src_id;
let mut rand_obj = RandType::default();
if is_decode {
rand_obj = RandType {
slat: 0,
rand: ((src_id & 0xff) as u8) >> 3,
padding: ((src_id & 0b100) as u8) >> 2,
key_check: ((src_id & 0b10) as u8) >> 1,
rand_check: (src_id & 0b1) as u8,
};
id = src_id >> 8;
} else {
let mut rng = rand::thread_rng();
rand_obj.rand = rng.gen_range(0..32);
}
if DEBUG && is_decode {
println!("原始ID[{}],去掉管理字节后的ID[{}]", src_id, id);
}
if id <= MAX_U16 {
key = user_key & MAX_U16;
rand_obj.slat = ((rand_obj.rand as u64) << 8) ^ key;
} else if id <= MAX_U32 {
key = user_key & MAX_U32;
rand_obj.slat = ((rand_obj.rand as u64) << 16) ^ key;
if rand_obj.padding == 1 && is_decode {
id = id & 0xffff;
}
} else {
key = user_key & MAX_U56;
rand_obj.slat = ((rand_obj.rand as u64) << 32) ^ key;
if rand_obj.padding == 1 && is_decode {
id = id & 0xffff_ffff;
}
}
(key, rand_obj, id)
}
const DEBUG: bool = false;
pub fn mix(key: u64, id: u64) -> Result<u64, MixError> {
if id > MAX_U56 {
return Err(MixError {
msg: String::from(format!("数字[{}]已超出最大可混淆数字[{}]", id, MAX_U56)),
});
}
let (k, rand_obj, id) = normalization(key, id, false);
if DEBUG {
println!(
"编码源信息:用户Key[{}],规整Key[{}],随机数[{}],原始ID[{}]",
key,
k,
rand_obj.rand,
id
);
}
let mut new_id = k ^ id;
let key_sign = parity_check(new_id);
if DEBUG {
println!("加密码混淆:[{} => {:064b}],校验位[{}]", new_id, new_id, key_sign);
}
new_id = new_id ^ rand_obj.slat;
let rand_sign = parity_check(new_id);
if DEBUG {
println!(
"随机盐混淆:[{} => {:064b}],盐[{}],校验位[{}]",
new_id,
new_id,
rand_obj.slat,
rand_sign
);
}
let mut padding_sign = 0u8;
if id > MAX_U16 && id <= MAX_U32 && new_id <= 0xffff {
new_id |= 0x1_0000;
padding_sign = 1;
} else if id > MAX_U32 && new_id <= 0xffff_ffff {
new_id |= 0x1_0000_0000;
padding_sign = 1;
}
let manager_bit = (rand_obj.rand << 3) | (padding_sign << 2) | (key_sign << 1) | rand_sign;
if DEBUG {
println!(
"管理字节位:[{} => {:08b}],随机数[{}],高位补码位[{}],加密码校验位[{}],随机盐校验位[{}]",
manager_bit,
manager_bit,
rand_obj.rand,
padding_sign,
key_sign,
rand_sign
);
}
new_id = (new_id << 8) + (manager_bit as u64);
if DEBUG {
println!("最终生成数:[{} => {:064b}]", new_id, new_id);
}
Ok(new_id)
}
pub fn unmix(key: u64, id: u64) -> Result<u64, MixError> {
let (k, rand_obj, id) = normalization(key, id, true);
if DEBUG {
println!(
"解码源信息:用户Key[{}],规整Key[{}],随机数[{}],原始ID[{}]",
key,
k,
rand_obj.rand,
id
);
println!(
"管理字信息:随机数[{}],高位补码位[{:08b}],加密码校验位[{}],随机盐校验位[{}]",
rand_obj.rand,
rand_obj.padding,
rand_obj.key_check,
rand_obj.rand_check
);
println!(
"随机盐校验:[{} => {:064b}],盐[{}],校验位[{}]",
id,
id,
rand_obj.slat,
rand_obj.rand_check
);
}
if rand_obj.rand_check != parity_check(id) {
return Err(MixError { msg: String::from("校验失败[randsalt]") });
}
let new_id = id ^ rand_obj.slat;
if DEBUG {
println!("加密码校验:[{} => {:064b}],校验位[{}]", new_id, new_id, rand_obj.key_check);
}
if rand_obj.key_check != parity_check(new_id) {
return Err(MixError { msg: String::from("校验失败[key]") });
}
return Ok(k ^ new_id);
}
pub fn encode(key: u64, id: u64, encode: &dyn EncoderDecoder) -> Result<String, MixError> {
if DEBUG {
println!("编码:id:{} ", id);
}
let new_id = mix(key, id)?;
if DEBUG {
println!("编码:id:{} mixid:{} ", id, new_id);
}
let rs = encode.encode(new_id)?;
if DEBUG {
println!("编码:id:{} mixid:{} str:{}", id, new_id, rs);
}
Ok(rs)
}
pub fn decode(key: u64, str: &str, encode: &dyn EncoderDecoder) -> Result<u64, MixError> {
if DEBUG {
println!("解码:str:{} ", str);
}
let new_id = encode.decode(str.to_string())?;
if DEBUG {
println!("解码:str:{} mixid:{} ", str, new_id);
}
let id = unmix(key, new_id)?;
if DEBUG {
println!("解码:str:{} mixid:{} id:{}", str, new_id, id);
}
Ok(id)
}
pub fn parity_check<T: Into<u64>>(id: T) -> u8 {
let mut result = 0_u8;
let bits = size_of::<T>() * 8;
let val = id.into();
for i in 0..bits {
if val & (1 << i) > 0 {
result ^= 1;
}
}
if DEBUG {
println!("整数{}的奇偶校验结果为{}", val, result);
}
result
}