cesr/core/primitives/
siger.rs1use alloc::borrow::Cow;
2#[cfg(feature = "alloc")]
3#[allow(
4 unused_imports,
5 reason = "alloc prelude items; subset used per cfg/feature combination"
6)]
7use alloc::{string::String, vec, vec::Vec};
8use core::fmt;
9
10use crate::core::indexer::Indexer;
11use crate::core::indexer::code::IndexedSigCode;
12
13use super::Verfer;
14
15pub struct Siger<'a> {
25 indexer: Indexer<'a>,
26 verfer: Option<Verfer<'a>>,
27}
28
29impl fmt::Debug for Siger<'_> {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.debug_struct("Siger")
34 .field("code", &self.indexer.code())
35 .field("index", &self.indexer.index())
36 .field("ondex", &self.indexer.ondex())
37 .field("raw_len", &self.indexer.raw().len())
38 .field("has_verfer", &self.verfer.is_some())
39 .finish()
40 }
41}
42
43impl Clone for Siger<'_> {
44 fn clone(&self) -> Self {
45 let cloned_verfer = self.verfer.as_ref().map(|v| {
46 crate::core::matter::matter::Matter::new(
47 *v.code(),
48 Cow::Owned(v.raw().to_vec()),
49 Cow::Owned(String::from(v.soft())),
50 )
51 });
52 Self {
53 indexer: self.indexer.clone(),
54 verfer: cloned_verfer,
55 }
56 }
57}
58
59impl PartialEq for Siger<'_> {
60 fn eq(&self, other: &Self) -> bool {
61 if self.indexer != other.indexer {
62 return false;
63 }
64 match (&self.verfer, &other.verfer) {
65 (None, None) => true,
66 (Some(a), Some(b)) => a.code() == b.code() && a.raw() == b.raw(),
67 _ => false,
68 }
69 }
70}
71
72impl Eq for Siger<'_> {}
73
74impl<'a> Siger<'a> {
75 #[must_use]
77 pub const fn new(indexer: Indexer<'a>) -> Self {
78 Self {
79 indexer,
80 verfer: None,
81 }
82 }
83
84 #[must_use]
86 pub fn with_verfer(mut self, verfer: Verfer<'a>) -> Self {
87 self.verfer = Some(verfer);
88 self
89 }
90
91 #[must_use]
93 pub const fn code(&self) -> IndexedSigCode {
94 self.indexer.code()
95 }
96
97 #[must_use]
99 pub const fn index(&self) -> u32 {
100 self.indexer.index()
101 }
102
103 #[must_use]
105 pub const fn ondex(&self) -> Option<u32> {
106 self.indexer.ondex()
107 }
108
109 #[must_use]
111 pub fn raw(&self) -> &[u8] {
112 self.indexer.raw()
113 }
114
115 #[must_use]
117 pub const fn verfer(&self) -> Option<&Verfer<'a>> {
118 self.verfer.as_ref()
119 }
120
121 #[must_use]
123 pub fn full_size(&self) -> usize {
124 self.indexer.full_size()
125 }
126
127 #[must_use]
130 pub fn to_qb64(&self) -> String {
131 self.indexer.to_qb64()
132 }
133
134 #[must_use]
137 pub fn to_qb2(&self) -> Vec<u8> {
138 self.indexer.to_qb2()
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145 use crate::core::indexer::IndexerBuilder;
146 use crate::core::indexer::code::IndexedSigCode;
147 use crate::core::matter::builder::MatterBuilder;
148 use crate::core::matter::code::VerKeyCode;
149
150 fn ed25519_indexer(index: u32, raw: &[u8]) -> Indexer<'_> {
152 IndexerBuilder::new()
153 .with_code(IndexedSigCode::Ed25519)
154 .with_index(index)
155 .unwrap()
156 .with_raw(raw)
157 .unwrap()
158 }
159
160 fn ed25519_verfer(key_bytes: &[u8; 32]) -> Verfer<'_> {
162 MatterBuilder::new()
163 .with_code(VerKeyCode::Ed25519)
164 .with_raw(Cow::Borrowed(key_bytes.as_slice()))
165 .unwrap()
166 .build()
167 .unwrap()
168 }
169
170 #[test]
171 fn siger_delegates_to_indexer() {
172 let raw = [0xAB_u8; 64];
173 let indexer = ed25519_indexer(3, &raw);
174 let siger = Siger::new(indexer);
175
176 assert_eq!(siger.code(), IndexedSigCode::Ed25519);
177 assert_eq!(siger.index(), 3);
178 assert_eq!(siger.ondex(), Some(3));
179 assert_eq!(siger.raw(), &raw);
180 }
181
182 #[test]
183 fn siger_with_verfer_attached() {
184 let sig_bytes = [0u8; 64];
185 let key_bytes = [0u8; 32];
186
187 let indexer = ed25519_indexer(0, &sig_bytes);
188 let verfer = ed25519_verfer(&key_bytes);
189
190 let siger = Siger::new(indexer).with_verfer(verfer);
191
192 assert!(siger.verfer().is_some());
193 let v = siger.verfer().unwrap();
194 assert_eq!(*v.code(), VerKeyCode::Ed25519);
195 assert_eq!(v.raw(), &key_bytes);
196 }
197
198 #[test]
199 fn verfer_returns_none_when_absent() {
200 let indexer = ed25519_indexer(0, &[0u8; 64]);
201 let siger = Siger::new(indexer);
202 assert!(siger.verfer().is_none());
203 }
204
205 #[test]
206 fn to_qb64_delegation_returns_correct_size() {
207 let indexer = ed25519_indexer(0, &[0u8; 64]);
208 let siger = Siger::new(indexer);
209 let qb64 = siger.to_qb64();
210 assert_eq!(qb64.len(), 88);
212 }
213
214 #[test]
215 fn full_size_delegation() {
216 let indexer = ed25519_indexer(0, &[0u8; 64]);
217 let siger = Siger::new(indexer);
218 assert_eq!(siger.full_size(), 88);
219 }
220
221 #[test]
222 fn owned_siger_is_static() {
223 let sig_bytes = vec![0xCDu8; 64];
224 let key_bytes = [0xEFu8; 32];
225
226 let indexer: Indexer<'static> = IndexerBuilder::new()
228 .with_code(IndexedSigCode::Ed25519)
229 .with_index(5)
230 .unwrap()
231 .with_raw(sig_bytes)
232 .unwrap();
233
234 let verfer: Verfer<'static> = MatterBuilder::new()
235 .with_code(VerKeyCode::Ed25519)
236 .with_raw(key_bytes.to_vec())
237 .unwrap()
238 .build()
239 .unwrap();
240
241 let siger: Siger<'static> = Siger::new(indexer).with_verfer(verfer);
242
243 assert_eq!(siger.code(), IndexedSigCode::Ed25519);
244 assert_eq!(siger.index(), 5);
245 assert_eq!(siger.raw(), &[0xCD; 64]);
246 assert!(siger.verfer().is_some());
247 assert_eq!(siger.verfer().unwrap().raw(), &[0xEF; 32]);
248 }
249
250 #[test]
251 fn to_qb2_delegation() {
252 let indexer = ed25519_indexer(0, &[0u8; 64]);
253 let siger = Siger::new(indexer);
254 let qb2 = siger.to_qb2();
255 assert_eq!(qb2.len(), 66);
257 }
258
259 #[test]
260 fn clone_preserves_all_fields() {
261 let indexer = ed25519_indexer(2, &[0u8; 64]);
262 let verfer = ed25519_verfer(&[0u8; 32]);
263 let siger = Siger::new(indexer).with_verfer(verfer);
264 let cloned = siger.clone();
265 assert_eq!(siger, cloned);
266 }
267}