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