tfhe/high_level_api/strings/ascii/
mod.rs1mod comp;
2mod contains;
3mod find;
4mod no_pattern;
5mod replace;
6mod strip;
7mod trim;
8
9pub use crate::high_level_api::backward_compatibility::strings::FheAsciiStringVersions;
10use crate::high_level_api::compressed_ciphertext_list::ToBeCompressed;
11use crate::high_level_api::details::MaybeCloned;
12use crate::high_level_api::errors::UninitializedServerKey;
13use crate::high_level_api::global_state;
14use crate::high_level_api::keys::InternalServerKey;
15use crate::high_level_api::re_randomization::ReRandomizationMetadata;
16use crate::integer::ciphertext::{Compressible, DataKind, Expandable};
17use crate::named::Named;
18use crate::prelude::{FheDecrypt, FheTryEncrypt, FheTryTrivialEncrypt, Tagged};
19use crate::shortint::ciphertext::NotTrivialCiphertextError;
20use crate::strings::ciphertext::FheString;
21use crate::{ClientKey, HlExpandable, Tag};
22pub use no_pattern::{FheStringIsEmpty, FheStringLen};
23use serde::{Deserialize, Deserializer, Serialize, Serializer};
24use tfhe_versionable::{Unversionize, UnversionizeError, Versionize, VersionizeOwned};
25
26pub enum EncryptableString<'a> {
27 NoPadding(&'a str),
28 WithPadding { str: &'a str, padding: u32 },
29}
30
31impl EncryptableString<'_> {
32 fn str_and_padding(&self) -> (&str, Option<u32>) {
33 match self {
34 EncryptableString::NoPadding(str) => (str, None),
35 EncryptableString::WithPadding { str, padding } => (str, Some(*padding)),
36 }
37 }
38}
39
40pub(crate) enum AsciiDevice {
41 Cpu(FheString),
42}
43
44impl From<FheString> for AsciiDevice {
45 fn from(value: FheString) -> Self {
46 Self::Cpu(value)
47 }
48}
49
50impl AsciiDevice {
51 pub fn on_cpu(&self) -> MaybeCloned<'_, FheString> {
52 match self {
53 Self::Cpu(cpu_string) => MaybeCloned::Borrowed(cpu_string),
54 }
55 }
56}
57
58impl Clone for AsciiDevice {
59 fn clone(&self) -> Self {
60 match self {
61 Self::Cpu(s) => Self::Cpu(s.clone()),
62 }
63 }
64}
65
66impl serde::Serialize for AsciiDevice {
67 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68 where
69 S: Serializer,
70 {
71 self.on_cpu().serialize(serializer)
72 }
73}
74
75impl<'de> serde::Deserialize<'de> for AsciiDevice {
76 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
77 where
78 D: Deserializer<'de>,
79 {
80 let deserialized = Self::Cpu(FheString::deserialize(deserializer)?);
81 Ok(deserialized)
82 }
83}
84
85#[derive(serde::Serialize, serde::Deserialize)]
87#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
88pub(crate) struct AsciiDeviceVersionOwned(<FheString as VersionizeOwned>::VersionedOwned);
89
90#[derive(Serialize, Deserialize)]
91#[cfg_attr(dylint_lib = "tfhe_lints", allow(serialize_without_versionize))]
92pub(crate) enum AsciiDeviceVersionedOwned {
93 V0(AsciiDeviceVersionOwned),
94}
95
96impl Versionize for AsciiDevice {
97 type Versioned<'vers> = AsciiDeviceVersionedOwned;
98
99 fn versionize(&self) -> Self::Versioned<'_> {
100 let data = self.on_cpu();
101 let versioned = data.into_owned().versionize_owned();
102 AsciiDeviceVersionedOwned::V0(AsciiDeviceVersionOwned(versioned))
103 }
104}
105
106impl VersionizeOwned for AsciiDevice {
107 type VersionedOwned = AsciiDeviceVersionedOwned;
108
109 fn versionize_owned(self) -> Self::VersionedOwned {
110 let cpu_data = self.on_cpu();
111 AsciiDeviceVersionedOwned::V0(AsciiDeviceVersionOwned(
112 cpu_data.into_owned().versionize_owned(),
113 ))
114 }
115}
116
117impl Unversionize for AsciiDevice {
118 fn unversionize(versioned: Self::VersionedOwned) -> Result<Self, UnversionizeError> {
119 match versioned {
120 AsciiDeviceVersionedOwned::V0(v0) => {
121 let unversioned = Self::Cpu(FheString::unversionize(v0.0)?);
122 Ok(unversioned)
123 }
124 }
125 }
126}
127
128#[derive(Serialize, Deserialize, Versionize, Clone)]
129#[versionize(FheAsciiStringVersions)]
130pub struct FheAsciiString {
131 pub(crate) inner: AsciiDevice,
132 pub(crate) tag: Tag,
133 pub(crate) re_randomization_metadata: ReRandomizationMetadata,
134}
135
136impl Named for FheAsciiString {
137 const NAME: &'static str = "high_level_api::FheAsciiString";
138}
139
140impl Tagged for FheAsciiString {
141 fn tag(&self) -> &Tag {
142 &self.tag
143 }
144
145 fn tag_mut(&mut self) -> &mut Tag {
146 &mut self.tag
147 }
148}
149
150impl FheAsciiString {
151 pub(crate) fn new(
152 inner: impl Into<AsciiDevice>,
153 tag: Tag,
154 re_randomization_metadata: ReRandomizationMetadata,
155 ) -> Self {
156 Self {
157 inner: inner.into(),
158 tag,
159 re_randomization_metadata,
160 }
161 }
162
163 pub fn try_encrypt_with_padding(
165 str: impl AsRef<str>,
166 padding: u32,
167 client_key: &ClientKey,
168 ) -> crate::Result<Self> {
169 Self::try_encrypt(
170 EncryptableString::WithPadding {
171 str: str.as_ref(),
172 padding,
173 },
174 client_key,
175 )
176 }
177
178 pub fn try_encrypt_with_fixed_sized(
227 str: impl AsRef<str>,
228 size: usize,
229 client_key: &ClientKey,
230 ) -> crate::Result<Self> {
231 let str = str.as_ref();
232 let (sliced, padding) = if str.len() >= size {
233 (&str[..size], 0)
234 } else {
235 (str, (size - str.len()) as u32)
236 };
237
238 Self::try_encrypt(
239 EncryptableString::WithPadding {
240 str: sliced,
241 padding,
242 },
243 client_key,
244 )
245 }
246
247 pub fn try_encrypt_trivial_with_padding(
263 str: impl AsRef<str>,
264 padding: u32,
265 ) -> crate::Result<Self> {
266 Self::try_encrypt_trivial(EncryptableString::WithPadding {
267 str: str.as_ref(),
268 padding,
269 })
270 }
271
272 pub fn try_encrypt_trivial_with_fixed_sized(
296 str: impl AsRef<str>,
297 size: usize,
298 ) -> crate::Result<Self> {
299 let str = str.as_ref();
300 let (sliced, padding) = if str.len() >= size {
301 (&str[..size], 0)
302 } else {
303 (str, (size - str.len()) as u32)
304 };
305
306 Self::try_encrypt_trivial(EncryptableString::WithPadding {
307 str: sliced,
308 padding,
309 })
310 }
311
312 pub fn try_decrypt_trivial(&self) -> Result<String, NotTrivialCiphertextError> {
313 self.inner.on_cpu().decrypt_trivial()
314 }
315
316 pub fn is_trivial(&self) -> bool {
317 self.inner.on_cpu().is_trivial()
318 }
319
320 pub fn re_randomization_metadata(&self) -> &ReRandomizationMetadata {
321 &self.re_randomization_metadata
322 }
323
324 pub fn re_randomization_metadata_mut(&mut self) -> &mut ReRandomizationMetadata {
325 &mut self.re_randomization_metadata
326 }
327}
328
329impl<'a> FheTryEncrypt<EncryptableString<'a>, ClientKey> for FheAsciiString {
330 type Error = crate::Error;
331
332 fn try_encrypt(value: EncryptableString<'a>, key: &ClientKey) -> Result<Self, Self::Error> {
333 let (str, padding) = value.str_and_padding();
334 if !str.is_ascii() || str.contains('\0') {
335 return Err(crate::Error::new(
336 "Input is not an ASCII string".to_string(),
337 ));
338 }
339
340 let inner = crate::strings::ClientKey::new(&key.key.key).encrypt_ascii(str, padding);
341 Ok(Self {
342 inner: inner.into(),
343 tag: key.tag.clone(),
344 re_randomization_metadata: ReRandomizationMetadata::default(),
345 })
346 }
347}
348
349impl FheTryEncrypt<&str, ClientKey> for FheAsciiString {
350 type Error = crate::Error;
351
352 fn try_encrypt(value: &str, key: &ClientKey) -> Result<Self, Self::Error> {
353 Self::try_encrypt(EncryptableString::NoPadding(value), key)
354 }
355}
356
357impl FheTryEncrypt<&String, ClientKey> for FheAsciiString {
358 type Error = crate::Error;
359
360 fn try_encrypt(value: &String, key: &ClientKey) -> Result<Self, Self::Error> {
361 Self::try_encrypt(EncryptableString::NoPadding(value), key)
362 }
363}
364
365impl<'a> FheTryTrivialEncrypt<EncryptableString<'a>> for FheAsciiString {
366 type Error = crate::Error;
367
368 fn try_encrypt_trivial(value: EncryptableString<'a>) -> Result<Self, Self::Error> {
369 let (str, padding) = value.str_and_padding();
370
371 if !str.is_ascii() || str.contains('\0') {
372 return Err(crate::Error::new(
373 "Input is not an ASCII string".to_string(),
374 ));
375 }
376
377 global_state::try_with_internal_keys(|keys| match keys {
378 Some(InternalServerKey::Cpu(cpu_key)) => {
379 let inner = cpu_key.string_key().trivial_encrypt_ascii(str, padding);
380 Ok(Self::new(
381 inner,
382 cpu_key.tag.clone(),
383 ReRandomizationMetadata::default(),
384 ))
385 }
386 #[cfg(feature = "gpu")]
387 Some(InternalServerKey::Cuda(_)) => Err(crate::error!("CUDA does not support string")),
388 #[cfg(feature = "hpu")]
389 Some(InternalServerKey::Hpu(_)) => Err(crate::error!("Hpu does not support string")),
390 None => Err(UninitializedServerKey.into()),
391 })
392 }
393}
394
395impl FheTryTrivialEncrypt<&str> for FheAsciiString {
396 type Error = crate::Error;
397
398 fn try_encrypt_trivial(value: &str) -> Result<Self, Self::Error> {
399 Self::try_encrypt_trivial(EncryptableString::NoPadding(value))
400 }
401}
402
403impl FheTryTrivialEncrypt<&String> for FheAsciiString {
404 type Error = crate::Error;
405
406 fn try_encrypt_trivial(value: &String) -> Result<Self, Self::Error> {
407 Self::try_encrypt_trivial(EncryptableString::NoPadding(value.as_str()))
408 }
409}
410
411impl FheDecrypt<String> for FheAsciiString {
412 fn decrypt(&self, key: &ClientKey) -> String {
413 crate::strings::ClientKey::new(&key.key.key).decrypt_ascii(&self.inner.on_cpu())
414 }
415}
416
417impl Expandable for FheAsciiString {
418 fn from_expanded_blocks(
419 blocks: Vec<crate::shortint::Ciphertext>,
420 kind: DataKind,
421 ) -> crate::Result<Self> {
422 FheString::from_expanded_blocks(blocks, kind).map(|cpu_string| {
423 Self::new(
424 cpu_string,
425 Tag::default(),
426 ReRandomizationMetadata::default(),
427 )
428 })
429 }
430}
431
432impl crate::HlCompactable for &crate::ClearString {}
433
434#[cfg(feature = "gpu")]
435impl crate::integer::gpu::ciphertext::compressed_ciphertext_list::CudaExpandable
436 for FheAsciiString
437{
438 fn from_expanded_blocks(
439 blocks: crate::integer::gpu::ciphertext::CudaRadixCiphertext,
440 kind: DataKind,
441 ) -> crate::Result<Self> {
442 let _ = (blocks, kind);
443 Err(crate::error!("GPU does not supports strings yet"))
444 }
445}
446
447impl crate::HlCompressible for FheAsciiString {
448 fn compress_into(self, messages: &mut Vec<(ToBeCompressed, DataKind)>) {
449 match self.inner {
450 AsciiDevice::Cpu(fhe_string) => {
451 let mut blocks = vec![];
452 let data_kind = fhe_string.compress_into(&mut blocks);
453 if let Some(data_kind) = data_kind {
454 messages.push((ToBeCompressed::Cpu(blocks), data_kind));
455 }
456 }
457 }
458 }
459
460 fn get_re_randomization_metadata(&self) -> ReRandomizationMetadata {
461 self.re_randomization_metadata.clone()
462 }
463}
464
465impl HlExpandable for FheAsciiString {
466 fn set_re_randomization_metadata(&mut self, meta: ReRandomizationMetadata) {
467 self.re_randomization_metadata = meta;
468 }
469}