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