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