triblespace_core/value/schemas/
ed25519.rs1use ed25519::ComponentBytes;
2use ed25519::Signature;
3use ed25519_dalek::SignatureError;
4pub use ed25519_dalek::VerifyingKey;
5
6use crate::id::ExclusiveId;
7use crate::id::Id;
8use crate::id_hex;
9use crate::macros::entity;
10use crate::metadata;
11use crate::metadata::{ConstDescribe, ConstId};
12use crate::repo::BlobStore;
13use crate::trible::Fragment;
14use crate::value::schemas::hash::Blake3;
15use crate::value::ToValue;
16use crate::value::TryFromValue;
17use crate::value::Value;
18use crate::value::ValueSchema;
19use std::convert::Infallible;
20
21pub struct ED25519RComponent;
23
24impl ConstId for ED25519RComponent {
25 const ID: Id = id_hex!("995A86FFC83DB95ECEAA17E226208897");
26}
27
28pub struct ED25519SComponent;
30
31impl ConstId for ED25519SComponent {
32 const ID: Id = id_hex!("10D35B0B628E9E409C549D8EC1FB3598");
33}
34
35pub struct ED25519PublicKey;
37
38impl ConstId for ED25519PublicKey {
39 const ID: Id = id_hex!("69A872254E01B4C1ED36E08E40445E93");
40}
41
42impl ConstDescribe for ED25519RComponent {
43 fn describe<B>(blobs: &mut B) -> Result<Fragment, B::PutError>
44 where
45 B: BlobStore<Blake3>,
46 {
47 let id = Self::ID;
48 let description = blobs.put(
49 "Ed25519 signature R component stored as a 32-byte field. This is one half of the standard 64-byte Ed25519 signature.\n\nUse when you store signatures as structured values or need to index the components separately. Pair with the S component to reconstruct or verify the full signature.\n\nIf you prefer storing the signature as a single binary blob, use a blob schema (for example LongString with base64 or a custom blob schema).",
50 )?;
51 let tribles = entity! {
52 ExclusiveId::force_ref(&id) @
53 metadata::name: blobs.put("ed25519:r")?,
54 metadata::description: description,
55 metadata::tag: metadata::KIND_VALUE_SCHEMA,
56 };
57
58 #[cfg(feature = "wasm")]
59 let tribles = {
60 let mut tribles = tribles;
61 tribles += entity! { ExclusiveId::force_ref(&id) @
62 metadata::value_formatter: blobs.put(wasm_formatter::ED25519_R_WASM)?,
63 };
64 tribles
65 };
66 Ok(tribles)
67 }
68}
69impl ValueSchema for ED25519RComponent {
70 type ValidationError = Infallible;
71}
72impl ConstDescribe for ED25519SComponent {
73 fn describe<B>(blobs: &mut B) -> Result<Fragment, B::PutError>
74 where
75 B: BlobStore<Blake3>,
76 {
77 let id = Self::ID;
78 let description = blobs.put(
79 "Ed25519 signature S component stored as a 32-byte field. This is the second half of the standard Ed25519 signature.\n\nUse when storing or querying signatures in a structured form. Pair with the R component to reconstruct or verify the full signature.\n\nAs with the R component, treat this as public data; private signing keys should be stored separately and securely.",
80 )?;
81 let tribles = entity! {
82 ExclusiveId::force_ref(&id) @
83 metadata::name: blobs.put("ed25519:s")?,
84 metadata::description: description,
85 metadata::tag: metadata::KIND_VALUE_SCHEMA,
86 };
87
88 #[cfg(feature = "wasm")]
89 let tribles = {
90 let mut tribles = tribles;
91 tribles += entity! { ExclusiveId::force_ref(&id) @
92 metadata::value_formatter: blobs.put(wasm_formatter::ED25519_S_WASM)?,
93 };
94 tribles
95 };
96 Ok(tribles)
97 }
98}
99impl ValueSchema for ED25519SComponent {
100 type ValidationError = Infallible;
101}
102impl ConstDescribe for ED25519PublicKey {
103 fn describe<B>(blobs: &mut B) -> Result<Fragment, B::PutError>
104 where
105 B: BlobStore<Blake3>,
106 {
107 let id = Self::ID;
108 let description = blobs.put(
109 "Ed25519 public key stored as a 32-byte field. Public keys verify signatures and identify signing identities.\n\nUse for signer registries, verification records, or key references associated with signatures. Private keys are not represented by a built-in schema and should be handled separately.\n\nEd25519 is widely supported and deterministic; if you need another scheme, define a custom schema with its own metadata.",
110 )?;
111 let tribles = entity! {
112 ExclusiveId::force_ref(&id) @
113 metadata::name: blobs.put("ed25519:pubkey")?,
114 metadata::description: description,
115 metadata::tag: metadata::KIND_VALUE_SCHEMA,
116 };
117
118 #[cfg(feature = "wasm")]
119 let tribles = {
120 let mut tribles = tribles;
121 tribles += entity! { ExclusiveId::force_ref(&id) @
122 metadata::value_formatter: blobs.put(wasm_formatter::ED25519_PUBKEY_WASM)?,
123 };
124 tribles
125 };
126 Ok(tribles)
127 }
128}
129impl ValueSchema for ED25519PublicKey {
130 type ValidationError = Infallible;
131}
132
133#[cfg(feature = "wasm")]
134mod wasm_formatter {
135 use core::fmt::Write;
136
137 use triblespace_core_macros::value_formatter;
138
139 #[value_formatter(const_wasm = ED25519_R_WASM)]
140 pub(crate) fn ed25519_r(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
141 out.write_str("ed25519:r:").map_err(|_| 1u32)?;
142 const TABLE: &[u8; 16] = b"0123456789ABCDEF";
143 for &byte in raw {
144 let hi = (byte >> 4) as usize;
145 let lo = (byte & 0x0F) as usize;
146 out.write_char(TABLE[hi] as char).map_err(|_| 1u32)?;
147 out.write_char(TABLE[lo] as char).map_err(|_| 1u32)?;
148 }
149 Ok(())
150 }
151
152 #[value_formatter(const_wasm = ED25519_S_WASM)]
153 pub(crate) fn ed25519_s(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
154 out.write_str("ed25519:s:").map_err(|_| 1u32)?;
155 const TABLE: &[u8; 16] = b"0123456789ABCDEF";
156 for &byte in raw {
157 let hi = (byte >> 4) as usize;
158 let lo = (byte & 0x0F) as usize;
159 out.write_char(TABLE[hi] as char).map_err(|_| 1u32)?;
160 out.write_char(TABLE[lo] as char).map_err(|_| 1u32)?;
161 }
162 Ok(())
163 }
164
165 #[value_formatter(const_wasm = ED25519_PUBKEY_WASM)]
166 pub(crate) fn ed25519_pubkey(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
167 out.write_str("ed25519:pubkey:").map_err(|_| 1u32)?;
168 const TABLE: &[u8; 16] = b"0123456789ABCDEF";
169 for &byte in raw {
170 let hi = (byte >> 4) as usize;
171 let lo = (byte & 0x0F) as usize;
172 out.write_char(TABLE[hi] as char).map_err(|_| 1u32)?;
173 out.write_char(TABLE[lo] as char).map_err(|_| 1u32)?;
174 }
175 Ok(())
176 }
177}
178
179impl ED25519RComponent {
180 pub fn from_signature(s: Signature) -> Value<ED25519RComponent> {
181 Value::new(*s.r_bytes())
182 }
183}
184
185impl ED25519SComponent {
186 pub fn from_signature(s: Signature) -> Value<ED25519SComponent> {
187 Value::new(*s.s_bytes())
188 }
189}
190
191impl ToValue<ED25519RComponent> for Signature {
192 fn to_value(self) -> Value<ED25519RComponent> {
193 ED25519RComponent::from_signature(self)
194 }
195}
196
197impl ToValue<ED25519SComponent> for Signature {
198 fn to_value(self) -> Value<ED25519SComponent> {
199 ED25519SComponent::from_signature(self)
200 }
201}
202
203impl ToValue<ED25519RComponent> for ComponentBytes {
204 fn to_value(self) -> Value<ED25519RComponent> {
205 Value::new(self)
206 }
207}
208
209impl TryFromValue<'_, ED25519RComponent> for ComponentBytes {
210 type Error = Infallible;
211 fn try_from_value(v: &Value<ED25519RComponent>) -> Result<Self, Infallible> {
212 Ok(v.raw)
213 }
214}
215
216impl ToValue<ED25519SComponent> for ComponentBytes {
217 fn to_value(self) -> Value<ED25519SComponent> {
218 Value::new(self)
219 }
220}
221
222impl TryFromValue<'_, ED25519SComponent> for ComponentBytes {
223 type Error = Infallible;
224 fn try_from_value(v: &Value<ED25519SComponent>) -> Result<Self, Infallible> {
225 Ok(v.raw)
226 }
227}
228
229impl ToValue<ED25519PublicKey> for VerifyingKey {
230 fn to_value(self) -> Value<ED25519PublicKey> {
231 Value::new(self.to_bytes())
232 }
233}
234
235impl TryFromValue<'_, ED25519PublicKey> for VerifyingKey {
236 type Error = SignatureError;
237
238 fn try_from_value(v: &Value<ED25519PublicKey>) -> Result<Self, Self::Error> {
239 VerifyingKey::from_bytes(&v.raw)
240 }
241}