1#![allow(missing_docs)]
5
6use uor_foundation::enforcement::{GroundedShape, ShapeViolation};
7use uor_foundation::pipeline::{ConstrainedTypeShape, ConstraintRef, IntoBindingValue};
8use uor_foundation_sdk::axis;
9
10axis! {
11 pub trait FheAxis: AxisExtension {
19 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/FheAxis";
20 const MAX_OUTPUT_BYTES: usize = 32;
22 fn add_ciphertexts(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation>;
29 }
30}
31
32pub const MAX_FHE_BLOCK_BYTES: usize = 256;
36
37fn shape_violation(constraint: &'static str) -> ShapeViolation {
38 ShapeViolation {
39 shape_iri: "https://uor.foundation/axis/FheAxis",
40 constraint_iri: constraint,
41 property_iri: "https://uor.foundation/axis/inputBytes",
42 expected_range: "https://uor.foundation/axis/FheBlockShape",
43 min_count: 0,
44 max_count: 0,
45 kind: uor_foundation::ViolationKind::ValueCheck,
46 }
47}
48
49#[derive(Debug, Clone, Copy)]
58pub struct OneTimePadFhe<const BLOCK_BYTES: usize>;
59
60impl<const BLOCK_BYTES: usize> Default for OneTimePadFhe<BLOCK_BYTES> {
61 fn default() -> Self {
62 Self
63 }
64}
65
66impl<const BLOCK_BYTES: usize> FheAxis for OneTimePadFhe<BLOCK_BYTES> {
67 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/FheAxis/OneTimePadReference";
68 const MAX_OUTPUT_BYTES: usize = BLOCK_BYTES;
69
70 fn add_ciphertexts(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation> {
71 if BLOCK_BYTES == 0 || BLOCK_BYTES > MAX_FHE_BLOCK_BYTES {
72 return Err(shape_violation(
73 "https://uor.foundation/axis/FheAxis/blockBytesInRange",
74 ));
75 }
76 if input.len() != 2 * BLOCK_BYTES {
77 return Err(shape_violation(
78 "https://uor.foundation/axis/FheAxis/inputBlockPair",
79 ));
80 }
81 if out.len() < BLOCK_BYTES {
82 return Err(shape_violation(
83 "https://uor.foundation/axis/FheAxis/outputBlock",
84 ));
85 }
86 for i in 0..BLOCK_BYTES {
87 out[i] = input[i] ^ input[BLOCK_BYTES + i];
88 }
89 Ok(BLOCK_BYTES)
90 }
91}
92
93axis_extension_impl_for_fhe_axis!(@generic OneTimePadFhe<BLOCK_BYTES>, [const BLOCK_BYTES: usize]);
95
96pub type OneTimePadFheAxis = OneTimePadFhe<32>;
98pub type OneTimePadFhe16 = OneTimePadFhe<16>;
100pub type OneTimePadFhe64 = OneTimePadFhe<64>;
102pub type OneTimePadFhe128 = OneTimePadFhe<128>;
104
105#[derive(Debug, Clone, Copy)]
116pub struct CiphertextShape<const BYTES: usize>;
117
118impl<const BYTES: usize> Default for CiphertextShape<BYTES> {
119 fn default() -> Self {
120 Self
121 }
122}
123
124impl<const BYTES: usize> ConstrainedTypeShape for CiphertextShape<BYTES> {
125 const IRI: &'static str = "https://uor.foundation/type/ConstrainedType";
126 const SITE_COUNT: usize = BYTES;
127 const CONSTRAINTS: &'static [ConstraintRef] = &[];
128 #[allow(clippy::cast_possible_truncation)]
129 const CYCLE_SIZE: u64 = 256u64.saturating_pow(BYTES as u32);
130}
131
132impl<const BYTES: usize> uor_foundation::pipeline::__sdk_seal::Sealed for CiphertextShape<BYTES> {}
133impl<const BYTES: usize> GroundedShape for CiphertextShape<BYTES> {}
134impl<const BYTES: usize> IntoBindingValue for CiphertextShape<BYTES> {
135 const MAX_BYTES: usize = BYTES;
136
137 fn into_binding_bytes(&self, _out: &mut [u8]) -> Result<usize, ShapeViolation> {
138 Ok(0)
139 }
140}