1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![cfg_attr(not(test), no_std)]
3#![doc = include_str!("../README.md")]
4
5#[cfg(feature = "hashstrings")]
6mod hashstrings;
7#[cfg(feature = "hashstrings")]
8pub use hashstrings::*;
9
10#[cfg(not(test))]
11extern crate core;
12
13extern crate alloc;
14
15use alloc::ffi::CString;
16use alloc::string::String;
17use alloc::vec::Vec;
18use core::any::TypeId;
19use core::ops::{Deref, DerefMut};
20use core::slice;
21
22use rand::rngs::Xoshiro256PlusPlus;
23use rand::seq::SliceRandom;
24use rand::{Rng, SeedableRng};
25use zeroize::Zeroize;
26
27#[doc(hidden)]
30pub mod __private {
31 pub use alloc::ffi::CString;
32 pub use alloc::string::String;
33 pub use alloc::vec;
34}
35
36pub struct Encrusted<T>
41where
42 T: Encrust,
43 T::Storage: Zeroize,
44{
45 data: T::Storage,
46 seed: u64,
47}
48
49impl<T> Encrusted<T>
50where
51 T: Encrust,
52 T::Storage: Zeroize,
53{
54 pub fn new(data: T, seed: u64) -> Self {
56 let mut data = data.to_storage();
57
58 let mut encrust_rng = Xoshiro256PlusPlus::seed_from_u64(seed);
59
60 <T as Encrust>::toggle_encrust(&mut data, &mut encrust_rng);
61
62 Self { data, seed }
63 }
64
65 #[doc(hidden)]
78 #[cfg(feature = "macros")]
79 pub const unsafe fn from_encrusted_data(data: T::Storage, seed: u64) -> Self {
80 Self { data, seed }
81 }
82
83 pub fn reseed(&mut self, new_seed: u64) {
85 {
86 let mut decruster = Xoshiro256PlusPlus::seed_from_u64(self.seed);
87
88 <T as Encrust>::toggle_encrust(&mut self.data, &mut decruster);
89 }
90
91 self.seed = new_seed;
92
93 let mut encrust_rng = Xoshiro256PlusPlus::seed_from_u64(self.seed);
94
95 <T as Encrust>::toggle_encrust(&mut self.data, &mut encrust_rng);
96 }
97
98 #[doc(alias("expose", "unlock"))]
100 pub fn decrust(&mut self) -> DecrustGuard<'_, T> {
101 DecrustGuard::new(self)
102 }
103}
104
105impl<T> Drop for Encrusted<T>
106where
107 T: Encrust,
108 T::Storage: Zeroize,
109{
110 fn drop(&mut self) {
115 self.data.zeroize();
116 self.seed.zeroize();
117 }
118}
119
120pub struct DecrustGuard<'decrusted, T>
124where
125 T: Encrust,
126 T::Storage: Zeroize,
127{
128 encrusted_data: &'decrusted mut Encrusted<T>,
129}
130
131impl<'decrusted, T> DecrustGuard<'decrusted, T>
132where
133 T: Encrust,
134 T::Storage: Zeroize,
135{
136 fn new(encrusted_data: &'decrusted mut Encrusted<T>) -> Self {
137 let mut decruster = Xoshiro256PlusPlus::seed_from_u64(encrusted_data.seed);
138
139 <T as Encrust>::toggle_encrust(&mut encrusted_data.data, &mut decruster);
140
141 Self { encrusted_data }
142 }
143}
144
145impl<T> Drop for DecrustGuard<'_, T>
146where
147 T: Encrust,
148 T::Storage: Zeroize,
149{
150 fn drop(&mut self) {
151 let mut encrust_rng = Xoshiro256PlusPlus::seed_from_u64(self.encrusted_data.seed);
152
153 <T as Encrust>::toggle_encrust(&mut self.encrusted_data.data, &mut encrust_rng);
154 }
155}
156
157impl<T> Deref for DecrustGuard<'_, T>
158where
159 T: Encrust,
160 T::Storage: Zeroize,
161{
162 type Target = T::Ref;
163
164 fn deref(&self) -> &Self::Target {
165 unsafe { <T as Encrust>::as_ref(&self.encrusted_data.data) }
168 }
169}
170
171impl<T> DerefMut for DecrustGuard<'_, T>
172where
173 T: Encrust,
174 T::Storage: Zeroize,
175{
176 fn deref_mut(&mut self) -> &mut Self::Target {
177 unsafe { <T as Encrust>::as_mut_ref(&mut self.encrusted_data.data) }
180 }
181}
182
183pub trait Encrust {
189 type Storage;
196
197 type Ref: ?Sized;
204
205 fn to_storage(self) -> Self::Storage;
207
208 unsafe fn as_ref(storage: &Self::Storage) -> &Self::Ref;
215
216 unsafe fn as_mut_ref(storage: &mut Self::Storage) -> &mut Self::Ref;
223
224 fn toggle_encrust(storage: &mut Self::Storage, encrust_rng: &mut impl Rng);
233}
234
235pub trait InPlaceEncrust {
244 fn toggle_encrust(&mut self, encrust_rng: &mut impl Rng);
253}
254
255impl<T> Encrust for T
256where
257 T: InPlaceEncrust,
258{
259 type Storage = Self;
260 type Ref = Self;
261
262 fn to_storage(self) -> Self::Storage {
263 self
264 }
265
266 unsafe fn as_ref(storage: &Self::Storage) -> &Self::Ref {
267 storage
268 }
269
270 unsafe fn as_mut_ref(storage: &mut Self::Storage) -> &mut Self::Ref {
271 storage
272 }
273
274 fn toggle_encrust(storage: &mut Self::Storage, encrust_rng: &mut impl Rng) {
275 <T as InPlaceEncrust>::toggle_encrust(storage, encrust_rng);
276 }
277}
278
279macro_rules! encrust_int {
280 ( $( $t:ty ),* ) => {
281 $(
282 impl InPlaceEncrust for $t {
283 fn toggle_encrust(&mut self, encrust_rng: &mut impl Rng) {
284 let mut bytes = self.to_le_bytes();
285
286 for chunk in bytes.chunks_mut(8) {
289 let key = encrust_rng.next_u64().to_le_bytes();
290 for (byte, byte_key) in chunk.iter_mut().zip(key.iter()) {
291 *byte ^= byte_key;
292 }
293 }
294
295 *self = Self::from_le_bytes(bytes);
296 }
297 }
298 )*
299 };
300}
301
302encrust_int!(
303 u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize
304);
305
306impl<T, const N: usize> InPlaceEncrust for [T; N]
307where
308 T: InPlaceEncrust + 'static,
309{
310 fn toggle_encrust(&mut self, encrust_rng: &mut impl Rng) {
311 slice_toggle_encrust::<T>(self, encrust_rng);
312 }
313}
314
315impl Encrust for String {
316 type Storage = Vec<u8>;
317
318 type Ref = str;
319
320 fn to_storage(self) -> Self::Storage {
321 self.into_bytes()
322 }
323
324 unsafe fn as_ref(storage: &Self::Storage) -> &Self::Ref {
325 unsafe { str::from_utf8_unchecked(storage) }
328 }
329
330 unsafe fn as_mut_ref(storage: &mut Self::Storage) -> &mut Self::Ref {
331 unsafe { str::from_utf8_unchecked_mut(storage) }
334 }
335
336 fn toggle_encrust(storage: &mut Self::Storage, encrust_rng: &mut impl Rng) {
337 slice_toggle_encrust::<u8>(storage, encrust_rng);
338 }
339}
340
341impl Encrust for CString {
342 type Storage = Vec<u8>;
343 type Ref = [u8];
345
346 fn to_storage(self) -> Self::Storage {
347 self.into_bytes_with_nul()
348 }
349
350 unsafe fn as_ref(storage: &Self::Storage) -> &Self::Ref {
351 storage.as_ref()
352 }
353
354 unsafe fn as_mut_ref(storage: &mut Self::Storage) -> &mut Self::Ref {
355 storage.as_mut()
356 }
357
358 fn toggle_encrust(storage: &mut Self::Storage, encrust_rng: &mut impl Rng) {
359 slice_toggle_encrust::<u8>(storage, encrust_rng);
360 }
361}
362
363impl<T> Encrust for Vec<T>
364where
365 T: InPlaceEncrust + 'static,
366{
367 type Storage = Self;
368 type Ref = [T];
369
370 fn to_storage(self) -> Self::Storage {
371 self
372 }
373
374 unsafe fn as_ref(storage: &Self::Storage) -> &Self::Ref {
375 storage.as_ref()
376 }
377
378 unsafe fn as_mut_ref(storage: &mut Self::Storage) -> &mut Self::Ref {
379 storage.as_mut()
380 }
381
382 fn toggle_encrust(storage: &mut Self::Storage, encrust_rng: &mut impl Rng) {
383 slice_toggle_encrust::<T>(storage, encrust_rng);
384 }
385}
386
387macro_rules! toggle_encrust_for_integer {
394 ($ty:ty, $type_id:ident, $slice:ident, $rng:ident) => {{
395 const ARRAY_SIZE: usize = core::mem::size_of::<u64>() / core::mem::size_of::<$ty>();
396
397 assert!($type_id == TypeId::of::<$ty>());
401 assert!(core::mem::size_of::<u64>() >= core::mem::size_of::<[$ty; ARRAY_SIZE]>());
402
403 let slice = slice::from_raw_parts_mut($slice.as_mut_ptr().cast::<$ty>(), $slice.len());
404
405 for chunk in slice.chunks_mut(ARRAY_SIZE) {
406 let key = $rng.next_u64().to_le_bytes();
407 let key: [$ty; ARRAY_SIZE] = core::array::from_fn(|i| {
408 let start = i * core::mem::size_of::<$ty>();
409 <$ty>::from_le_bytes(
410 key[start..start + core::mem::size_of::<$ty>()]
411 .try_into()
412 .unwrap(),
413 )
414 });
415
416 for (num, key) in chunk.iter_mut().zip(key.iter()) {
417 *num ^= key;
418 }
419 }
420 }};
421}
422
423fn slice_toggle_encrust<T>(encrust_slice: &mut [T::Storage], encrust_rng: &mut impl Rng)
425where
426 T: Encrust,
427 T::Storage: 'static,
428{
429 let type_id: TypeId = TypeId::of::<T::Storage>();
430
431 if type_id == TypeId::of::<u8>() {
432 let encrust_slice = unsafe {
438 slice::from_raw_parts_mut(encrust_slice.as_mut_ptr().cast::<u8>(), encrust_slice.len())
439 };
440
441 u8_slice_toggle_encrust(encrust_slice, encrust_rng);
442 } else if type_id == TypeId::of::<i8>() {
443 unsafe {
445 toggle_encrust_for_integer!(i8, type_id, encrust_slice, encrust_rng);
446 }
447 } else if type_id == TypeId::of::<i16>() {
448 unsafe {
450 toggle_encrust_for_integer!(i16, type_id, encrust_slice, encrust_rng);
451 }
452 } else if type_id == TypeId::of::<i32>() {
453 unsafe {
455 toggle_encrust_for_integer!(i32, type_id, encrust_slice, encrust_rng);
456 }
457 } else if type_id == TypeId::of::<i64>() {
458 unsafe {
460 toggle_encrust_for_integer!(i64, type_id, encrust_slice, encrust_rng);
461 }
462 } else if type_id == TypeId::of::<isize>() {
463 unsafe {
465 toggle_encrust_for_integer!(isize, type_id, encrust_slice, encrust_rng);
466 }
467 } else if type_id == TypeId::of::<i128>() {
468 let encrust_slice = unsafe {
474 slice::from_raw_parts_mut(
475 encrust_slice.as_mut_ptr().cast::<i128>(),
476 encrust_slice.len(),
477 )
478 };
479
480 let mut key = [0u8; 16];
481
482 for num in encrust_slice {
483 encrust_rng.fill_bytes(&mut key);
484 *num ^= i128::from_le_bytes(key);
485 }
486 } else if type_id == TypeId::of::<u16>() {
487 unsafe {
489 toggle_encrust_for_integer!(u16, type_id, encrust_slice, encrust_rng);
490 }
491 } else if type_id == TypeId::of::<u32>() {
492 unsafe {
494 toggle_encrust_for_integer!(u32, type_id, encrust_slice, encrust_rng);
495 }
496 } else if type_id == TypeId::of::<u64>() {
497 unsafe {
499 toggle_encrust_for_integer!(u64, type_id, encrust_slice, encrust_rng);
500 }
501 } else if type_id == TypeId::of::<usize>() {
502 unsafe {
504 toggle_encrust_for_integer!(usize, type_id, encrust_slice, encrust_rng);
505 }
506 } else if type_id == TypeId::of::<u128>() {
507 let encrust_slice = unsafe {
513 slice::from_raw_parts_mut(
514 encrust_slice.as_mut_ptr().cast::<u128>(),
515 encrust_slice.len(),
516 )
517 };
518
519 let mut key = [0u8; 16];
520
521 for num in encrust_slice {
522 encrust_rng.fill_bytes(&mut key);
523 *num ^= u128::from_le_bytes(key);
524 }
525 } else {
526 for element in encrust_slice {
528 <T as Encrust>::toggle_encrust(element, encrust_rng);
529 }
530 }
531}
532
533fn u8_slice_toggle_encrust(encrust_slice: &mut [u8], encrust_rng: &mut impl Rng) {
538 let mut shuffle_indices: [u8; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
539
540 for chunk in encrust_slice.chunks_mut(16) {
541 let mut key = encrust_rng.next_u64().to_le_bytes();
542
543 for byte in &mut key {
545 *byte &= 0b00_01_10_01;
546 }
547
548 let (n_shuffle_indices, is_odd) = if chunk.len() < 16 {
550 let (shuffle_count, is_odd) = if (chunk.len() % 2) == 0 {
555 (chunk.len(), false)
556 } else {
557 (chunk.len() - 1, true)
558 };
559
560 for (i, elem) in shuffle_indices.iter_mut().enumerate().take(shuffle_count) {
561 *elem = u8::try_from(i).unwrap();
562 }
563
564 shuffle_indices[0..shuffle_count].shuffle(encrust_rng);
565
566 (shuffle_count, is_odd)
567 } else {
568 shuffle_indices.shuffle(encrust_rng);
569
570 (chunk.len(), false)
571 };
572
573 for (pair, key) in shuffle_indices[..n_shuffle_indices].chunks(2).zip(key) {
576 let i = usize::from(pair[0]);
577 let j = usize::from(pair[1]);
578
579 chunk[i] = chunk[i].wrapping_add(key);
580 chunk[j] = chunk[j].wrapping_sub(key);
581 chunk.swap(i, j);
582 }
583
584 if is_odd {
585 *chunk.last_mut().unwrap() ^= key.last().unwrap();
586 }
587 }
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593
594 const TEST_STRING: &str = "The quick brown fox jumps over the lazy dog😊";
595
596 const SEED: u64 = 0x2357_bd11_1317_1d1f;
597
598 macro_rules! test_ints {
599 ( $( $t:ty => [$($value:expr),+ $(,)?] ),* $(,)? ) => {
600 $(
601 $(
602 {
603 let mut encrusted = Encrusted::<$t>::new($value, SEED);
604
605 {
606 let decrusted = encrusted.decrust();
607 assert_eq!(*decrusted, $value);
608 }
609
610 {
611 let decrusted = encrusted.decrust();
612 assert_eq!(*decrusted, $value);
613 }
614 }
615 )+
616
617 #[cfg(feature = "macros")]
618 {
619 $(
620 let mut encrust_rng = Xoshiro256PlusPlus::seed_from_u64(SEED);
621 let mut encrusted_data: $t = $value;
622 encrusted_data.toggle_encrust(&mut encrust_rng);
623
624 let mut encrusted = unsafe {
627 Encrusted::<$t>::from_encrusted_data(encrusted_data, SEED)
628 };
629
630 assert_ne!(encrusted.data, $value);
631
632 {
633 let decrusted = encrusted.decrust();
634 assert_eq!(*decrusted, $value);
635 }
636
637 assert_ne!(encrusted.data, $value);
638 )+
639 }
640 )*
641 };
642 }
643
644 macro_rules! test_int_arrays {
645 ( $( $t:ty ),* ) => {
646 $(
647 let zero_array: [$t; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0];
648 {
649 let mut encrusted = Encrusted::<[$t; 9]>::new(zero_array, SEED);
650 assert_ne!(encrusted.data, zero_array);
651
652 {
653 let decrusted = encrusted.decrust();
654 assert_eq!(*decrusted, zero_array);
655 }
656
657 assert_ne!(encrusted.data, zero_array);
658 }
659
660 #[cfg(feature = "macros")]
661 {
662 let mut encrust_rng = Xoshiro256PlusPlus::seed_from_u64(SEED);
663 let mut encrusted_data: [$t; 9] = zero_array;
664 encrusted_data.toggle_encrust(&mut encrust_rng);
665
666 let mut encrusted = unsafe {
669 Encrusted::<[$t; 9]>::from_encrusted_data(encrusted_data, SEED)
670 };
671
672 assert_ne!(encrusted.data, zero_array);
673
674 {
675 let decrusted = encrusted.decrust();
676 assert_eq!(*decrusted, zero_array);
677 }
678
679 assert_ne!(encrusted.data, zero_array);
680 }
681 )*
682 };
683 }
684
685 #[test]
686 fn test_ints() {
687 test_ints!(
688 u8 => [0u8, 1u8, u8::MAX],
689 i8 => [0i8, 1i8, -1i8, i8::MIN, i8::MAX],
690 u16 => [0u16, 1u16, u16::MAX],
691 i16 => [0i16, 1i16, -1i16, i16::MIN, i16::MAX],
692 u32 => [0u32, 1u32, u32::MAX],
693 i32 => [0i32, 1i32, -1i32, i32::MIN, i32::MAX],
694 u64 => [0u64, 1u64, u64::MAX],
695 i64 => [0i64, 1i64, -1i64, i64::MIN, i64::MAX],
696 u128 => [0u128, 1u128, u128::MAX],
697 i128 => [0i128, 1i128, -1i128, i128::MIN, i128::MAX],
698 usize => [0usize, 1usize, usize::MAX],
699 isize => [0isize, 1isize, -1isize, isize::MIN, isize::MAX],
700 );
701 }
702
703 #[test]
704 fn test_int_arrays() {
705 test_int_arrays!(
706 u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize
707 );
708 }
709
710 #[test]
711 fn test_strings() {
712 let mut encrusted = Encrusted::new(TEST_STRING.to_owned(), SEED);
713 assert_ne!(encrusted.data, TEST_STRING.as_bytes());
714
715 {
716 let decrusted = encrusted.decrust();
717 assert_eq!(&*decrusted, TEST_STRING);
718 }
719
720 assert_ne!(encrusted.data, TEST_STRING.as_bytes());
721 }
722
723 #[test]
724 fn test_string_lengths_around_u8_chunk_boundaries() {
725 for len in [0, 1, 2, 7, 8, 9, 15, 16, 17, 45] {
726 let string = "a".repeat(len);
727 let mut encrusted = Encrusted::new(string.clone(), SEED);
728
729 {
730 let decrusted = encrusted.decrust();
731 assert_eq!(&*decrusted, string);
732 }
733
734 {
735 let decrusted = encrusted.decrust();
736 assert_eq!(&*decrusted, string);
737 }
738 }
739 }
740
741 #[cfg(feature = "macros")]
742 #[test]
743 fn test_strings_from_encrusted() {
744 let mut encrust_rng = Xoshiro256PlusPlus::seed_from_u64(SEED);
745
746 let mut encrusted_string = TEST_STRING.to_owned().into_bytes();
747
748 let mut encrusted = unsafe {
751 <String as Encrust>::toggle_encrust(&mut encrusted_string, &mut encrust_rng);
752 Encrusted::<String>::from_encrusted_data(encrusted_string, SEED)
753 };
754
755 assert_ne!(encrusted.data, TEST_STRING.as_bytes());
756
757 {
758 let decrusted = encrusted.decrust();
759 assert_eq!(&*decrusted, TEST_STRING);
760 }
761
762 assert_ne!(encrusted.data, TEST_STRING.as_bytes());
763 }
764
765 #[test]
766 fn test_arrays() {
767 let orig_array: [u8; 45] = [
768 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
769 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
770 ];
771
772 let mut encrusted = Encrusted::new(orig_array, SEED);
773 assert_ne!(encrusted.data, orig_array);
774
775 {
776 let decrusted = encrusted.decrust();
777 assert_eq!(*decrusted, orig_array);
778 }
779
780 assert_ne!(encrusted.data, orig_array);
781 }
782
783 #[test]
784 fn test_arrays_from_encrusted() {
785 let mut encrust_rng = Xoshiro256PlusPlus::seed_from_u64(SEED);
786 let orig_array: [u8; 45] = [
787 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
788 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
789 ];
790
791 let mut encrusted_array = orig_array;
792
793 let mut encrusted = unsafe {
796 <[u8; 45] as Encrust>::toggle_encrust(&mut encrusted_array, &mut encrust_rng);
797 Encrusted::<[u8; 45]>::from_encrusted_data(encrusted_array, SEED)
798 };
799
800 assert_ne!(encrusted.data, orig_array);
801
802 {
803 let decrusted = encrusted.decrust();
804 assert_eq!(*decrusted, orig_array);
805 }
806
807 assert_ne!(encrusted.data, orig_array);
808 }
809
810 #[test]
811 fn test_vecs() {
812 let orig_vec = TEST_STRING.as_bytes().to_vec();
813
814 let mut encrusted = Encrusted::new(orig_vec.clone(), SEED);
815 assert_ne!(encrusted.data, orig_vec);
816
817 {
818 let decrusted = encrusted.decrust();
819 assert_eq!(*decrusted, orig_vec);
820 }
821
822 assert_ne!(encrusted.data, orig_vec);
823 }
824
825 #[cfg(feature = "macros")]
826 #[test]
827 fn test_vecs_from_encrusted() {
828 let mut encrust_rng = Xoshiro256PlusPlus::seed_from_u64(SEED);
829 let orig_vec = TEST_STRING.as_bytes().to_vec();
830
831 let mut encrusted_vec = orig_vec.clone();
832
833 let mut encrusted = unsafe {
836 <Vec<u8> as Encrust>::toggle_encrust(&mut encrusted_vec, &mut encrust_rng);
837 Encrusted::<Vec<u8>>::from_encrusted_data(encrusted_vec, SEED)
838 };
839
840 assert_ne!(encrusted.data, orig_vec);
841
842 {
843 let decrusted = encrusted.decrust();
844 assert_eq!(*decrusted, orig_vec);
845 }
846
847 assert_ne!(encrusted.data, orig_vec);
848 }
849
850 #[test]
851 fn test_reseed() {
852 let num = 828_627_825_u64;
853 let mut encrusted = Encrusted::new(num, SEED);
854 let new_seed = SEED ^ 0xffff_ffff_ffff_ffff;
855
856 encrusted.reseed(new_seed);
857
858 {
859 let decrusted = encrusted.decrust();
860 assert_eq!(*decrusted, num);
861 }
862 }
863
864 #[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
865 struct CustomInPlaceEncrust(u32);
866
867 impl InPlaceEncrust for CustomInPlaceEncrust {
868 fn toggle_encrust(&mut self, encrust_rng: &mut impl Rng) {
869 self.0 ^= encrust_rng.next_u32();
870 }
871 }
872
873 #[test]
874 fn vec_of_custom_type_uses_fallback_slice_path() {
875 let values = vec![
876 CustomInPlaceEncrust(0),
877 CustomInPlaceEncrust(1),
878 CustomInPlaceEncrust(u32::MAX),
879 CustomInPlaceEncrust(0xfeed_beef),
880 ];
881
882 let values_clone = values.clone();
883
884 let mut encrusted = Encrusted::new(values, SEED);
885
886 assert_ne!(encrusted.data, values_clone);
887
888 let decrusted = encrusted.decrust();
889 assert_eq!(&*decrusted, &values_clone);
890 }
891
892 #[cfg(feature = "macros")]
895 #[test]
896 fn ensure_encrust_has_not_changed() {
897 let mut test_string = unsafe {
900 Encrusted::<String>::from_encrusted_data(
901 vec![
902 114u8, 87u8, 102u8, 107u8, 117u8, 113u8, 32u8, 110u8, 32u8, 97u8, 33u8, 84u8,
903 128u8, 118u8, 99u8, 105u8, 112u8, 92u8, 110u8, 106u8, 32u8, 120u8, 128u8,
904 109u8, 142u8, 87u8, 56u8, 91u8, 124u8, 16u8, 130u8, 93u8, 119u8, 84u8, 24u8,
905 125u8, 91u8, 121u8, 122u8, 40u8, 106u8, 96u8, 161u8, 175u8, 224u8, 94u8, 146u8,
906 ],
907 #[allow(
908 clippy::unreadable_literal,
909 reason = "Arbitrary number chosen at random with no further meaning."
910 )]
911 5233902475398815152u64,
912 )
913 };
914
915 let decrusted_test_string = test_string.decrust();
916 assert_eq!(decrusted_test_string.as_bytes(), TEST_STRING.as_bytes());
917 }
918}