feistel_permutation_rs/
feistel.rs1use std::hash::{BuildHasher, Hasher};
3
4
5pub struct Feistel<B>
11where
12 B: BuildHasher,
13{
14 bob: B,
15 bits: usize,
16 keys: Vec<u64>,
17}
18
19impl<B> Feistel<B>
20where
21 B: BuildHasher,
22{
23 pub fn new(bob: B, bits: usize, keys: &[u64]) -> Feistel<B> {
25 assert_eq!(bits & 1, 0);
27 Feistel {
28 bob,
29 bits,
30 keys: Vec::from(keys),
31 }
32 }
33
34 pub fn encrypt(&self, x: u64) -> u64 {
36 let (mut l, mut r) = self.split(x);
37 for k in self.keys.iter() {
38 l ^= self.hash(*k, r);
39 let t = l;
40 l = r;
41 r = t;
42 }
43 self.combine(r, l)
44 }
45
46 pub fn decrypt(&self, x: u64) -> u64 {
48 let (mut l, mut r) = self.split(x);
49 for k in self.keys.iter().rev() {
50 l ^= self.hash(*k, r);
51 let t = l;
52 l = r;
53 r = t;
54 }
55 self.combine(r, l)
56 }
57
58 fn split(&self, x: u64) -> (u64, u64) {
59 let n = self.bits >> 1;
60 let m = (1u64 << n) - 1;
61 let hi = x >> n;
62 let lo = x & m;
63 (hi, lo)
64 }
65
66 fn combine(&self, hi: u64, lo: u64) -> u64 {
67 let n = self.bits >> 1;
68 (hi << n) | lo
69 }
70
71 fn hash(&self, k: u64, x: u64) -> u64 {
72 let mut h: <B as BuildHasher>::Hasher = self.bob.build_hasher();
73 h.write_u64(k);
74 h.write_u64(x);
75 let res = h.finish();
76 let n = self.bits >> 1;
77 let m = (1u64 << n) - 1;
78 res & m
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use crate::DefaultBuildHasher;
85
86 use super::*;
87
88 #[test]
89 fn test_1a() {
90 let bob = DefaultBuildHasher::new();
91 let bits = 32;
92 let keys = [0x1c10u64, 0x8fd6u64, 0x2d5au64, 0x7363u64, 0x5f70u64];
93 let f = Feistel::new(bob, bits, &keys);
94 let x = 17;
95 let y = f.encrypt(x);
96 let z = f.decrypt(y);
97 println!("x=0x{x:0x}, y=0x{y:0x}, z=0x{z:0x}");
98 assert_eq!(x, z);
99 }
100
101 #[test]
102 fn test_1b() {
103 let bob = DefaultBuildHasher::new();
104 let bits = 32;
105 let keys = [0x1c10u64, 0x8fd6u64, 0x2d5au64, 0x7363u64, 0x5f70u64];
106 let f = Feistel::new(bob, bits, &keys);
107 let x = 234;
108 let y = f.encrypt(x);
109 let z = f.decrypt(y);
110 assert_eq!(x, z);
111 }
112
113 #[test]
114 fn test_2() {
115 let bob = DefaultBuildHasher::new();
116 let bits = 56;
117 let keys = [0x1c10u64, 0x8fd6u64, 0x2d5au64, 0x7363u64, 0x5f70u64];
118 let f = Feistel::new(bob, bits, &keys);
119 let x = 17;
120 let y = f.encrypt(x);
121 let z = f.decrypt(y);
122 assert_eq!(x, z);
123 }
124}