triblespace_core/value/schemas/
ed25519.rs1use ed25519::ComponentBytes;
2use ed25519::Signature;
3use ed25519_dalek::SignatureError;
4pub use ed25519_dalek::VerifyingKey;
6
7use crate::id::ExclusiveId;
8use crate::id::Id;
9use crate::id_hex;
10use crate::macros::entity;
11use crate::metadata;
12use crate::metadata::{ConstDescribe, ConstId};
13use crate::repo::BlobStore;
14use crate::trible::Fragment;
15use crate::value::schemas::hash::Blake3;
16use crate::value::ToValue;
17use crate::value::TryFromValue;
18use crate::value::Value;
19use crate::value::ValueSchema;
20use std::convert::Infallible;
21
22pub struct ED25519RComponent;
24
25impl ConstId for ED25519RComponent {
26 const ID: Id = id_hex!("995A86FFC83DB95ECEAA17E226208897");
27}
28
29pub struct ED25519SComponent;
31
32impl ConstId for ED25519SComponent {
33 const ID: Id = id_hex!("10D35B0B628E9E409C549D8EC1FB3598");
34}
35
36pub struct ED25519PublicKey;
38
39impl ConstId for ED25519PublicKey {
40 const ID: Id = id_hex!("69A872254E01B4C1ED36E08E40445E93");
41}
42
43impl ConstDescribe for ED25519RComponent {
44 fn describe<B>(blobs: &mut B) -> Result<Fragment, B::PutError>
45 where
46 B: BlobStore<Blake3>,
47 {
48 let id = Self::ID;
49 let description = blobs.put(
50 "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).",
51 )?;
52 let tribles = entity! {
53 ExclusiveId::force_ref(&id) @
54 metadata::name: blobs.put("ed25519:r")?,
55 metadata::description: description,
56 metadata::tag: metadata::KIND_VALUE_SCHEMA,
57 };
58
59 #[cfg(feature = "wasm")]
60 let tribles = {
61 let mut tribles = tribles;
62 tribles += entity! { ExclusiveId::force_ref(&id) @
63 metadata::value_formatter: blobs.put(wasm_formatter::ED25519_R_WASM)?,
64 };
65 tribles
66 };
67 Ok(tribles)
68 }
69}
70impl ValueSchema for ED25519RComponent {
71 type ValidationError = Infallible;
72}
73impl ConstDescribe for ED25519SComponent {
74 fn describe<B>(blobs: &mut B) -> Result<Fragment, B::PutError>
75 where
76 B: BlobStore<Blake3>,
77 {
78 let id = Self::ID;
79 let description = blobs.put(
80 "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.",
81 )?;
82 let tribles = entity! {
83 ExclusiveId::force_ref(&id) @
84 metadata::name: blobs.put("ed25519:s")?,
85 metadata::description: description,
86 metadata::tag: metadata::KIND_VALUE_SCHEMA,
87 };
88
89 #[cfg(feature = "wasm")]
90 let tribles = {
91 let mut tribles = tribles;
92 tribles += entity! { ExclusiveId::force_ref(&id) @
93 metadata::value_formatter: blobs.put(wasm_formatter::ED25519_S_WASM)?,
94 };
95 tribles
96 };
97 Ok(tribles)
98 }
99}
100impl ValueSchema for ED25519SComponent {
101 type ValidationError = Infallible;
102}
103impl ConstDescribe for ED25519PublicKey {
104 fn describe<B>(blobs: &mut B) -> Result<Fragment, B::PutError>
105 where
106 B: BlobStore<Blake3>,
107 {
108 let id = Self::ID;
109 let description = blobs.put(
110 "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.",
111 )?;
112 let tribles = entity! {
113 ExclusiveId::force_ref(&id) @
114 metadata::name: blobs.put("ed25519:pubkey")?,
115 metadata::description: description,
116 metadata::tag: metadata::KIND_VALUE_SCHEMA,
117 };
118
119 #[cfg(feature = "wasm")]
120 let tribles = {
121 let mut tribles = tribles;
122 tribles += entity! { ExclusiveId::force_ref(&id) @
123 metadata::value_formatter: blobs.put(wasm_formatter::ED25519_PUBKEY_WASM)?,
124 };
125 tribles
126 };
127 Ok(tribles)
128 }
129}
130impl ValueSchema for ED25519PublicKey {
131 type ValidationError = Infallible;
132}
133
134#[cfg(feature = "wasm")]
135mod wasm_formatter {
136 use core::fmt::Write;
137
138 use triblespace_core_macros::value_formatter;
139
140 #[value_formatter(const_wasm = ED25519_R_WASM)]
141 pub(crate) fn ed25519_r(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
142 out.write_str("ed25519:r:").map_err(|_| 1u32)?;
143 const TABLE: &[u8; 16] = b"0123456789ABCDEF";
144 for &byte in raw {
145 let hi = (byte >> 4) as usize;
146 let lo = (byte & 0x0F) as usize;
147 out.write_char(TABLE[hi] as char).map_err(|_| 1u32)?;
148 out.write_char(TABLE[lo] as char).map_err(|_| 1u32)?;
149 }
150 Ok(())
151 }
152
153 #[value_formatter(const_wasm = ED25519_S_WASM)]
154 pub(crate) fn ed25519_s(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
155 out.write_str("ed25519:s:").map_err(|_| 1u32)?;
156 const TABLE: &[u8; 16] = b"0123456789ABCDEF";
157 for &byte in raw {
158 let hi = (byte >> 4) as usize;
159 let lo = (byte & 0x0F) as usize;
160 out.write_char(TABLE[hi] as char).map_err(|_| 1u32)?;
161 out.write_char(TABLE[lo] as char).map_err(|_| 1u32)?;
162 }
163 Ok(())
164 }
165
166 #[value_formatter(const_wasm = ED25519_PUBKEY_WASM)]
167 pub(crate) fn ed25519_pubkey(raw: &[u8; 32], out: &mut impl Write) -> Result<(), u32> {
168 out.write_str("ed25519:pubkey:").map_err(|_| 1u32)?;
169 const TABLE: &[u8; 16] = b"0123456789ABCDEF";
170 for &byte in raw {
171 let hi = (byte >> 4) as usize;
172 let lo = (byte & 0x0F) as usize;
173 out.write_char(TABLE[hi] as char).map_err(|_| 1u32)?;
174 out.write_char(TABLE[lo] as char).map_err(|_| 1u32)?;
175 }
176 Ok(())
177 }
178}
179
180impl ED25519RComponent {
181 pub fn from_signature(s: Signature) -> Value<ED25519RComponent> {
183 Value::new(*s.r_bytes())
184 }
185}
186
187impl ED25519SComponent {
188 pub fn from_signature(s: Signature) -> Value<ED25519SComponent> {
190 Value::new(*s.s_bytes())
191 }
192}
193
194impl ToValue<ED25519RComponent> for Signature {
195 fn to_value(self) -> Value<ED25519RComponent> {
196 ED25519RComponent::from_signature(self)
197 }
198}
199
200impl ToValue<ED25519SComponent> for Signature {
201 fn to_value(self) -> Value<ED25519SComponent> {
202 ED25519SComponent::from_signature(self)
203 }
204}
205
206impl ToValue<ED25519RComponent> for ComponentBytes {
207 fn to_value(self) -> Value<ED25519RComponent> {
208 Value::new(self)
209 }
210}
211
212impl TryFromValue<'_, ED25519RComponent> for ComponentBytes {
213 type Error = Infallible;
214 fn try_from_value(v: &Value<ED25519RComponent>) -> Result<Self, Infallible> {
215 Ok(v.raw)
216 }
217}
218
219impl ToValue<ED25519SComponent> for ComponentBytes {
220 fn to_value(self) -> Value<ED25519SComponent> {
221 Value::new(self)
222 }
223}
224
225impl TryFromValue<'_, ED25519SComponent> for ComponentBytes {
226 type Error = Infallible;
227 fn try_from_value(v: &Value<ED25519SComponent>) -> Result<Self, Infallible> {
228 Ok(v.raw)
229 }
230}
231
232impl ToValue<ED25519PublicKey> for VerifyingKey {
233 fn to_value(self) -> Value<ED25519PublicKey> {
234 Value::new(self.to_bytes())
235 }
236}
237
238impl TryFromValue<'_, ED25519PublicKey> for VerifyingKey {
239 type Error = SignatureError;
240
241 fn try_from_value(v: &Value<ED25519PublicKey>) -> Result<Self, Self::Error> {
242 VerifyingKey::from_bytes(&v.raw)
243 }
244}