1#![allow(missing_docs)]
12
13use uor_foundation::enforcement::{GroundedShape, ShapeViolation};
14use uor_foundation::pipeline::{
15 AxisExtension, ConstrainedTypeShape, ConstraintRef, IntoBindingValue,
16};
17use uor_foundation_sdk::axis;
18
19use crate::{check_output, split_pair};
20
21axis! {
22 pub trait RingAxis: AxisExtension {
28 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/RingAxis";
30 const MAX_OUTPUT_BYTES: usize = 32;
32 fn add(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation>;
38 fn mul(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation>;
44 }
45}
46
47pub const MAX_GF2_BYTES: usize = 128;
52
53fn width_violation() -> ShapeViolation {
54 ShapeViolation {
55 shape_iri: "https://uor.foundation/axis/RingAxis",
56 constraint_iri: "https://uor.foundation/axis/RingAxis/widthInRange",
57 property_iri: "https://uor.foundation/axis/operandByteWidth",
58 expected_range: "https://uor.foundation/axis/RingAxis/MaxGf2Bytes",
59 min_count: 1,
60 #[allow(clippy::cast_possible_truncation)]
61 max_count: MAX_GF2_BYTES as u32,
62 kind: uor_foundation::ViolationKind::ValueCheck,
63 }
64}
65
66#[derive(Debug, Clone, Copy)]
72pub struct Gf2NumericAxisN<const BYTES: usize>;
73
74impl<const BYTES: usize> Default for Gf2NumericAxisN<BYTES> {
75 fn default() -> Self {
76 Self
77 }
78}
79
80impl<const BYTES: usize> RingAxis for Gf2NumericAxisN<BYTES> {
81 const AXIS_ADDRESS: &'static str = "https://uor.foundation/axis/RingAxis/Gf2";
82 const MAX_OUTPUT_BYTES: usize = BYTES;
83
84 fn add(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation> {
85 if BYTES == 0 || BYTES > MAX_GF2_BYTES {
86 return Err(width_violation());
87 }
88 let (a, b) = split_pair(input, BYTES)?;
89 check_output(out, BYTES)?;
90 for i in 0..BYTES {
91 out[i] = a[i] ^ b[i];
92 }
93 Ok(BYTES)
94 }
95
96 fn mul(input: &[u8], out: &mut [u8]) -> Result<usize, ShapeViolation> {
97 if BYTES == 0 || BYTES > MAX_GF2_BYTES {
98 return Err(width_violation());
99 }
100 let (a, b) = split_pair(input, BYTES)?;
101 check_output(out, BYTES)?;
102 for i in 0..BYTES {
103 out[i] = a[i] & b[i];
104 }
105 Ok(BYTES)
106 }
107}
108
109axis_extension_impl_for_ring_axis!(@generic Gf2NumericAxisN<BYTES>, [const BYTES: usize]);
111
112pub type Gf2NumericAxis = Gf2NumericAxisN<32>;
114pub type Gf2NumericAxis128 = Gf2NumericAxisN<16>;
116pub type Gf2NumericAxis512 = Gf2NumericAxisN<64>;
118
119#[derive(Debug, Clone, Copy)]
123pub struct Gf2RingShape<const BYTES: usize>;
124
125impl<const BYTES: usize> Default for Gf2RingShape<BYTES> {
126 fn default() -> Self {
127 Self
128 }
129}
130
131impl<const BYTES: usize> ConstrainedTypeShape for Gf2RingShape<BYTES> {
132 const IRI: &'static str = "https://uor.foundation/type/ConstrainedType";
133 const SITE_COUNT: usize = BYTES;
134 const CONSTRAINTS: &'static [ConstraintRef] = &[];
135 #[allow(clippy::cast_possible_truncation)]
136 const CYCLE_SIZE: u64 = 256u64.saturating_pow(BYTES as u32);
137}
138
139impl<const BYTES: usize> uor_foundation::pipeline::__sdk_seal::Sealed for Gf2RingShape<BYTES> {}
140impl<const BYTES: usize> GroundedShape for Gf2RingShape<BYTES> {}
141impl<const BYTES: usize> IntoBindingValue for Gf2RingShape<BYTES> {
142 const MAX_BYTES: usize = BYTES;
143
144 fn into_binding_bytes(&self, _out: &mut [u8]) -> Result<usize, ShapeViolation> {
145 Ok(0)
146 }
147}