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