1use std::cell::RefCell;
2
3use crate::stats::{sample_hgd, sample_uniform};
4use hmac::Hmac;
5use sha2::Sha256;
6
7pub type HmacSha256 = Hmac<Sha256>;
8
9pub const DEFAULT_IN_RANGE_START: i32 = 0;
10pub const DEFAULT_IN_RANGE_END: i32 = 2i32.pow(15) - 1;
11pub const DEFAULT_OUT_RANGE_START: i32 = 0;
12pub const DEFAULT_OUT_RANGE_END: i32 = 2i32.pow(15) - 1;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum OpeError {
16 InvalidRangeLimitsError,
17 InvalidCiphertextError,
18 OutOfRangeError,
19 InvalidCoinError,
20 NotEnoughCoinsError,
21}
22
23#[derive(Debug, Clone, PartialEq)]
24pub struct ValueRange {
25 pub start: i32,
26 pub end: i32,
27}
28
29impl ValueRange {
30 pub fn new(start: i32, end: i32) -> Result<Self, OpeError> {
31 if start > end {
32 return Err(OpeError::InvalidRangeLimitsError);
33 }
34 Ok(ValueRange { start, end })
35 }
36
37 pub fn size(&self) -> i32 {
38 self.end - self.start + 1
39 }
40
41 pub fn contains(&self, number: i32) -> bool {
42 self.start <= number && number <= self.end
43 }
44}
45
46pub struct Ope {
47 pub key: Vec<u8>,
48 pub in_range: ValueRange,
49 pub out_range: ValueRange,
50}
51
52impl Ope {
53 pub fn new(
54 key: &[u8],
55 in_range: Option<ValueRange>,
56 out_range: Option<ValueRange>,
57 ) -> Result<Self, OpeError> {
58 let in_range = in_range
59 .unwrap_or(ValueRange::new(DEFAULT_IN_RANGE_START, DEFAULT_IN_RANGE_END)?);
60 let out_range = out_range
61 .unwrap_or(ValueRange::new(DEFAULT_OUT_RANGE_START, DEFAULT_OUT_RANGE_END)?);
62
63 if in_range.size() > out_range.size() {
64 return Err(OpeError::OutOfRangeError);
65 }
66
67 Ok(Ope { key: key.to_vec(), in_range, out_range })
68 }
69
70 pub fn encrypt(&self, plaintext: i32) -> Result<i32, OpeError> {
71 if !self.in_range.contains(plaintext) {
72 return Err(OpeError::OutOfRangeError);
73 }
74 self.encrypt_recursive(plaintext, self.in_range.clone(), self.out_range.clone())
75 }
76
77 fn encrypt_recursive(
78 &self,
79 plaintext: i32,
80 mut in_range: ValueRange,
81 mut out_range: ValueRange,
82 ) -> Result<i32, OpeError> {
83 let in_size = in_range.size();
84 let out_size = out_range.size();
85 let in_edge = in_range.start.wrapping_sub(1);
86 let out_edge = out_range.start.wrapping_sub(1);
87 let mid = out_edge + ((out_size + 1) / 2);
88
89 if in_range.size() == 1 {
90 let coins = RefCell::new(self.tape_gen(plaintext));
91 let ciphertext = sample_uniform(out_range, Box::new(coins));
92 return Ok(ciphertext);
93 }
94
95 let coins = self.tape_gen(mid);
96 let x = sample_hgd(in_range, out_range, mid, Box::new(coins));
97
98 if plaintext <= x {
99 in_range = ValueRange::new(in_edge + 1, x)?;
100 out_range = ValueRange::new(out_edge + 1, mid)?;
101 } else {
102 in_range = ValueRange::new(x + 1, in_edge + in_size)?;
103 out_range = ValueRange::new(mid + 1, out_edge + out_size)?;
104 }
105 self.encrypt_recursive(plaintext, in_range, out_range)
106 }
107
108 pub fn decrypt(&self, ciphertext: i32) -> Result<i32, OpeError> {
109 if !self.out_range.contains(ciphertext) {
110 return Err(OpeError::OutOfRangeError);
111 }
112 self.decrypt_recursive(ciphertext, self.in_range.clone(), self.out_range.clone())
113 }
114
115 fn decrypt_recursive(
116 &self,
117 ciphertext: i32,
118 mut in_range: ValueRange,
119 mut out_range: ValueRange,
120 ) -> Result<i32, OpeError> {
121 let in_size = in_range.size();
122 let out_size = out_range.size();
123 let in_edge = in_range.start.wrapping_sub(1);
124 let out_edge = out_range.start.wrapping_sub(1);
125 let mid = out_edge + ((out_size + 1) / 2);
126
127 if out_range.size() == 1 {
128 let coins = RefCell::new(self.tape_gen(ciphertext));
129 let plaintext = sample_uniform(in_range, Box::new(coins)); return Ok(plaintext);
131 }
132
133 let coins = self.tape_gen(mid);
134 let x = sample_hgd(in_range, out_range, mid, Box::new(coins)); if ciphertext <= mid {
137 out_range = ValueRange::new(out_edge + 1, mid)?;
138 in_range = ValueRange::new(in_edge + 1, x)?;
139 } else {
140 out_range = ValueRange::new(mid + 1, out_edge + out_size)?;
141 in_range = ValueRange::new(x + 1, in_edge + in_size)?;
142 }
143 self.decrypt_recursive(ciphertext, in_range, out_range)
144 }
145
146 fn tape_gen(&self, data: i32) -> impl Iterator<Item = bool> {
147 let data_bytes = data.to_le_bytes();
148 let mut bits = Vec::new();
149
150 for &byte in data_bytes.iter() {
151 for i in 0..8 {
152 bits.push((byte >> i) & 1 == 1);
153 }
154 }
155
156 bits.into_iter()
157 }
158}