1use super::*;
4
5#[derive(Clone, Copy, Debug, PartialEq, Digital)]
7pub struct UbftIn {
8 pub axi: AxiLiteIn,
10 pub sign: Axis512,
12 pub sig_ready: bool,
14 pub verify: Axis512,
16 pub verdict_ready: bool,
18}
19
20#[derive(Clone, Copy, Debug, PartialEq, Digital)]
22pub struct UbftOut {
23 pub axi: AxiLiteOut,
25 pub sign_ready: bool,
27 pub sig: Axis512,
29 pub verify_ready: bool,
31 pub verdict: Axis64,
33}
34
35#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
37#[doc(hidden)]
38pub struct SigDone {
39 idx: b4,
41 signature: [b64; 8],
43}
44
45#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
47#[doc(hidden)]
48pub struct VerdictDone {
49 idx: b4,
51 error: b8,
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Digital)]
57#[doc(hidden)]
58pub struct UbftArgs {
59 sign_count: b32,
60 verify_count: b32,
61 seed: [b32; 8],
62 key_mask: b16,
63 keys: [[b32; 8]; KEY_SLOTS],
64}
65
66#[derive(Clone, Copy, Debug, PartialEq, Digital)]
68#[doc(hidden)]
69pub struct UbftControl {
70 args: UbftArgs,
71 running: bool,
72 done: bool,
73 done_unread: bool,
74 gie: bool,
75 ier: bool,
76 isr: bool,
77 ticks: b64,
78 start_tick: b64,
79 done_tick: b64,
80 key_tick: b64,
81 ticks_hi: b32,
82 seed_sent: bool,
84 kl_slot: b5,
86 kl_wait: bool,
88 kl_pulse: bool,
90 keys_settled: bool,
92 keys_ticked: bool,
94 key_bad: bool,
96 aw_addr: b12,
97 aw_have: bool,
98 w_data: b32,
99 w_have: bool,
100 b_valid: bool,
101 r_valid: bool,
102 r_data: b32,
103 sign_free: b16,
105 sign_tag: [b64; 16],
106 sign_in_flight: b5,
108 sig_beat: bool,
110 verify_free: b16,
112 verify_tag: [b32; 16],
113 verify_slot: [b4; 16],
114 verify_in_flight: b5,
116 vin_beat: b2,
118 vin_full: bool,
120 vin_slot: b4,
121 vin_tag: b32,
122 vin_message: [b64; 8],
123 vin_signature: [b64; 8],
124 framing_fault: bool,
126 signed: b32,
127 sign_taken: b32,
128 verified: b32,
129 valid: b32,
130 sign_latency: Latency,
131 verify_latency: Latency,
132}
133
134impl Default for UbftControl {
135 fn default() -> Self {
137 Self {
138 args: UbftArgs {
139 sign_count: b32(0),
140 verify_count: b32(0),
141 seed: [b32(0); 8],
142 key_mask: b16(0),
143 keys: [[b32(0); 8]; KEY_SLOTS],
144 },
145 running: false,
146 done: false,
147 done_unread: false,
148 gie: false,
149 ier: false,
150 isr: false,
151 ticks: b64(0),
152 start_tick: b64(0),
153 done_tick: b64(0),
154 key_tick: b64(0),
155 ticks_hi: b32(0),
156 seed_sent: false,
157 kl_slot: b5(0),
158 kl_wait: false,
159 kl_pulse: false,
160 keys_settled: false,
161 keys_ticked: false,
162 key_bad: false,
163 aw_addr: b12(0),
164 aw_have: false,
165 w_data: b32(0),
166 w_have: false,
167 b_valid: false,
168 r_valid: false,
169 r_data: b32(0),
170 sign_free: b16(0xffff),
171 sign_tag: [b64(0); 16],
172 sign_in_flight: b5(0),
173 sig_beat: false,
174 verify_free: b16(0xffff),
175 verify_tag: [b32(0); 16],
176 verify_slot: [b4(0); 16],
177 verify_in_flight: b5(0),
178 vin_beat: b2(0),
179 vin_full: false,
180 vin_slot: b4(0),
181 vin_tag: b32(0),
182 vin_message: [b64(0); 8],
183 vin_signature: [b64(0); 8],
184 framing_fault: false,
185 signed: b32(0),
186 sign_taken: b32(0),
187 verified: b32(0),
188 valid: b32(0),
189 sign_latency: Latency::default(),
190 verify_latency: Latency::default(),
191 }
192 }
193}
194
195#[derive(Clone, Debug, Synchronous, SynchronousDQ)]
200pub struct UbftEd25519<const NFB: usize, const NV: usize> {
201 control: DFF<UbftControl>,
203 signer: Ed25519SignCore<NFB, 1, 1, 0>,
205 verifier: KnownKeyVerifyCore<NV, 1, 1, 0>,
207 sig_fifo: SyncFIFO<SigDone, 5>,
210 verdict_fifo: SyncFIFO<VerdictDone, 5>,
212}
213
214impl<const NFB: usize, const NV: usize> Default for UbftEd25519<NFB, NV> {
215 fn default() -> Self {
217 Self {
218 control: DFF::new(UbftControl::default()),
219 signer: Ed25519SignCore::default(),
220 verifier: KnownKeyVerifyCore::default(),
221 sig_fifo: SyncFIFO::default(),
222 verdict_fifo: SyncFIFO::default(),
223 }
224 }
225}
226
227impl<const NFB: usize, const NV: usize> SynchronousIO for UbftEd25519<NFB, NV> {
228 type I = UbftIn;
229 type O = UbftOut;
230 type Kernel = ubft_ed25519_kernel<NFB, NV>;
231}
232
233#[allow(clippy::needless_range_loop, clippy::too_many_lines)]
235#[kernel]
236pub fn ubft_ed25519_kernel<const NFB: usize, const NV: usize>(
237 clock_reset: ClockReset,
238 input: UbftIn,
239 q: UbftEd25519Q<NFB, NV>,
240) -> (UbftOut, UbftEd25519D<NFB, NV>) {
241 let resetting = clock_reset.reset.any();
242 let r = q.control;
243 let args = q.control.args;
244 let mut c = q.control;
245 c.ticks = r.ticks + b64(1);
246 c.kl_pulse = false;
247 let sig = q.signer;
248 let ver = q.verifier;
249
250 let fault_bits: b32 = (if sig.internal_error { b32(1) } else { b32(0) })
252 | (if ver.internal_error { b32(4) } else { b32(0) })
253 | (if r.key_bad { b32(8) } else { b32(0) })
254 | (if r.framing_fault { b32(16) } else { b32(0) });
255 let settled_start = r.ticks - r.start_tick > b64(16);
256 if r.running && settled_start && r.keys_ticked && r.signed == args.sign_count && r.verified == args.verify_count {
257 c.running = false;
258 c.done = true;
259 c.done_unread = true;
260 c.isr = true;
261 c.done_tick = r.ticks;
262 }
263
264 let mut seed_words = [b64(0); 4];
266 for w in 0..4 {
267 seed_words[w] = args.seed[2 * w].resize::<64>() | (args.seed[2 * w + 1].resize::<64>() << 32);
268 }
269 let seed_offer = r.running && !r.seed_sent && sig.load_key_ready && !resetting;
270 if seed_offer {
271 c.seed_sent = true;
272 }
273
274 let mut kl_key = [b64(0); 4];
278 let mut kl_masked = false;
279 let mut kl_state = b2(0);
280 for s in 0..16 {
281 if r.kl_slot == b5(s as u128) {
282 kl_masked = (args.key_mask & (b16(1) << b16(s as u128))) != b16(0);
283 kl_state = ver.key_state[s];
284 for w in 0..4 {
285 kl_key[w] = args.keys[s][2 * w].resize::<64>() | (args.keys[s][2 * w + 1].resize::<64>() << 32);
286 }
287 }
288 }
289 if r.running && !r.keys_settled && !resetting {
290 if r.kl_slot == b5(16) {
291 c.keys_settled = true;
292 } else if !kl_masked {
293 c.kl_slot = r.kl_slot + b5(1);
294 } else if !r.kl_wait {
295 if ver.load_key_ready && !r.kl_pulse {
296 c.kl_pulse = true;
297 c.kl_wait = true;
298 }
299 } else if !r.kl_pulse && (kl_state == b2(2) || kl_state == b2(3)) {
300 c.kl_wait = false;
301 c.kl_slot = r.kl_slot + b5(1);
302 if kl_state == b2(3) {
303 c.key_bad = true;
304 }
305 }
306 }
307 if r.running && r.keys_settled && sig.key_loaded && !r.keys_ticked {
308 c.keys_ticked = true;
309 c.key_tick = r.ticks;
310 }
311
312 let sign_open = r.running && r.keys_ticked && !resetting;
314 let sign_ready = sign_open && sig.ready && r.sign_free != b16(0);
315 let sign_take = sign_ready && input.sign.valid;
316 let sign_req = sign_take && input.sign.last;
319 if sign_take && !input.sign.last {
320 c.framing_fault = true;
321 }
322 let sign_idx = lowest_free(r.sign_free);
323 let words_in = beat_words(input.sign.data);
326 let message = sign_message(words_in);
327 if sign_req {
328 c.sign_free = c.sign_free & !(b16(1) << sign_idx.resize::<16>());
329 c.sign_tag[sign_idx] = words_in[0];
330 c.sign_taken = r.sign_taken + b32(1);
331 }
332
333 let sig_head = q.sig_fifo.data;
335 let mut sig_out = Axis512 { valid: false, data: [b8(0); 64], last: false };
336 let mut sig_pop = false;
337 let mut sig_done = SigDone { idx: b4(0), signature: [b64(0); 8] };
338 match sig_head {
339 Some(h) => {
340 sig_done = h;
341 sig_out.valid = true;
342 if r.sig_beat {
343 let mut tag_words = [b64(0); 8];
344 tag_words[0] = r.sign_tag[h.idx];
345 sig_out.data = words_beat(tag_words);
346 sig_out.last = true;
347 } else {
348 sig_out.data = words_beat(h.signature);
349 }
350 }
351 None => {}
352 }
353 if sig_out.valid && input.sig_ready {
354 if r.sig_beat {
355 sig_pop = true;
356 c.sig_beat = false;
357 c.signed = r.signed + b32(1);
358 } else {
359 c.sig_beat = true;
360 }
361 }
362 if sig_pop {
363 c.sign_free = c.sign_free | (b16(1) << sig_done.idx.resize::<16>());
364 }
365 let sign_in_flight = r.sign_in_flight + (if sign_req { b5(1) } else { b5(0) }) - (if sig_pop { b5(1) } else { b5(0) });
366 c.sign_in_flight = sign_in_flight;
367 c.sign_latency = latency_kernel(
368 r.sign_latency,
369 r.ticks,
370 sign_req && r.sign_in_flight == b5(0),
371 sig_pop && r.sign_in_flight == b5(1),
372 sign_req && r.sign_in_flight != b5(0),
373 );
374
375 let verify_open = r.running && r.keys_ticked && !resetting;
377 let verify_ready = verify_open && !r.vin_full;
378 let beat = input.verify;
379 let vtake = verify_ready && beat.valid;
380 let beat_w = beat_words(beat.data);
381 let mut verify_first = false;
382 if vtake {
383 if r.vin_beat == b2(0) {
384 c.vin_slot = beat.data[0].resize();
385 c.vin_tag = (beat_w[0] >> 32).resize();
386 c.vin_beat = b2(1);
387 verify_first = true;
388 } else if r.vin_beat == b2(1) {
389 c.vin_message = beat_w;
390 c.vin_beat = b2(2);
391 } else {
392 c.vin_signature = beat_w;
393 c.vin_beat = b2(0);
394 c.vin_full = true;
395 }
396 if beat.last != (r.vin_beat == b2(2)) {
397 c.framing_fault = true;
398 }
399 }
400
401 let mut slot_key = [b64(0); 4];
405 for s in 0..16 {
406 if r.vin_slot == b4(s as u128) {
407 for w in 0..4 {
408 slot_key[w] = args.keys[s][2 * w].resize::<64>() | (args.keys[s][2 * w + 1].resize::<64>() << 32);
409 }
410 }
411 }
412 let verify_idx = lowest_free(r.verify_free);
413 let verify_issue = r.vin_full && ver.ready && r.verify_free != b16(0) && !r.kl_pulse && !resetting;
414 if verify_issue {
415 c.vin_full = false;
416 c.verify_free = c.verify_free & !(b16(1) << verify_idx.resize::<16>());
417 c.verify_tag[verify_idx] = r.vin_tag;
418 c.verify_slot[verify_idx] = r.vin_slot;
419 }
420
421 let verdict_head = q.verdict_fifo.data;
423 let mut verdict_out = Axis64 { valid: false, data: b64(0) };
424 let mut verdict_pop = false;
425 let mut vd = VerdictDone { idx: b4(0), error: b8(0) };
426 match verdict_head {
427 Some(h) => {
428 vd = h;
429 verdict_out.valid = true;
430 verdict_out.data = (b64(0x80) | h.error.resize::<64>())
431 | (r.verify_slot[h.idx].resize::<64>() << b64(8))
432 | (r.verify_tag[h.idx].resize::<64>() << b64(32));
433 }
434 None => {}
435 }
436 if verdict_out.valid && input.verdict_ready {
437 verdict_pop = true;
438 c.verify_free = c.verify_free | (b16(1) << vd.idx.resize::<16>());
439 c.verified = r.verified + b32(1);
440 if vd.error == b8(0) {
441 c.valid = r.valid + b32(1);
442 }
443 }
444 let verify_in_flight =
445 r.verify_in_flight + (if verify_first { b5(1) } else { b5(0) }) - (if verdict_pop { b5(1) } else { b5(0) });
446 c.verify_in_flight = verify_in_flight;
447 c.verify_latency = latency_kernel(
448 r.verify_latency,
449 r.ticks,
450 verify_first && r.verify_in_flight == b5(0),
451 verdict_pop && r.verify_in_flight == b5(1),
452 verify_first && r.verify_in_flight != b5(0),
453 );
454
455 let axi = input.axi;
457 if axi.aw_valid && !r.aw_have {
458 c.aw_addr = axi.aw_addr;
459 c.aw_have = true;
460 }
461 if axi.w_valid && !r.w_have {
462 c.w_data = axi.w_data;
463 c.w_have = true;
464 }
465 if r.b_valid && axi.b_ready {
466 c.b_valid = false;
467 }
468 if r.aw_have && r.w_have && !r.b_valid {
469 let a = r.aw_addr;
470 let v = r.w_data;
471 c.aw_have = false;
472 c.w_have = false;
473 c.b_valid = true;
474 if a == b12(0x000) && (v & b32(1)) == b32(1) && !r.running && !r.done {
475 c.running = true;
476 c.start_tick = r.ticks;
477 }
478 if a == b12(0x004) {
479 c.gie = (v & b32(1)) == b32(1);
480 }
481 if a == b12(0x008) {
482 c.ier = (v & b32(1)) == b32(1);
483 }
484 if a == b12(0x00c) && (v & b32(1)) == b32(1) {
485 c.isr = !r.isr;
486 }
487 if !r.running && !r.done {
488 if a == b12(ARG_SIGN_COUNT as u128) {
489 c.args.sign_count = v;
490 }
491 if a == b12(ARG_VERIFY_COUNT as u128) {
492 c.args.verify_count = v;
493 }
494 for w in 0..8 {
495 if a == b12((ARG_SEED + 4 * w) as u128) {
496 c.args.seed[w] = v;
497 }
498 }
499 if a == b12(ARG_KEY_MASK as u128) {
500 c.args.key_mask = v.resize();
501 }
502 for s in 0..16 {
503 for w in 0..8 {
504 if a == b12((ARG_KEYS + 0x20 * s + 4 * w) as u128) {
505 c.args.keys[s][w] = v;
506 }
507 }
508 }
509 }
510 }
511
512 if r.r_valid && axi.r_ready {
514 c.r_valid = false;
515 }
516 let ar_ready = !r.r_valid;
517 if axi.ar_valid && ar_ready {
518 let a = axi.ar_addr;
519 let mut value = b32(0);
520 if a == b12(0x000) {
521 value = (if r.running { b32(1) } else { b32(0) })
522 | (if r.done_unread { b32(2) } else { b32(0) })
523 | (if !r.running { b32(4) } else { b32(0) })
524 | (if r.done_unread { b32(8) } else { b32(0) });
525 c.done_unread = false;
526 }
527 if a == b12(0x004) {
528 value = if r.gie { b32(1) } else { b32(0) };
529 }
530 if a == b12(0x008) {
531 value = if r.ier { b32(1) } else { b32(0) };
532 }
533 if a == b12(0x00c) {
534 value = if r.isr { b32(1) } else { b32(0) };
535 }
536 if a == b12(REG_MAGIC as u128) {
537 value = MAGIC;
538 }
539 if a == b12(REG_ABI as u128) {
540 value = ABI_VERSION;
541 }
542 if a == b12(REG_SHAPE as u128) {
543 value = b32((NFB | (NV << 8) | (16 << 24)) as u128);
544 }
545 if a == b12(REG_FAULT as u128) {
546 value = fault_bits;
547 }
548 if a == b12(REG_TICKS as u128) {
549 value = r.ticks.resize();
550 c.ticks_hi = (r.ticks >> 32).resize();
551 }
552 if a == b12((REG_TICKS + 4) as u128) {
553 value = r.ticks_hi;
554 }
555 if a == b12(REG_START_TICK as u128) {
556 value = r.start_tick.resize();
557 }
558 if a == b12((REG_START_TICK + 4) as u128) {
559 value = (r.start_tick >> 32).resize();
560 }
561 if a == b12(REG_DONE_TICK as u128) {
562 value = r.done_tick.resize();
563 }
564 if a == b12((REG_DONE_TICK + 4) as u128) {
565 value = (r.done_tick >> 32).resize();
566 }
567 if a == b12(REG_KEY_TICK as u128) {
568 value = r.key_tick.resize();
569 }
570 if a == b12((REG_KEY_TICK + 4) as u128) {
571 value = (r.key_tick >> 32).resize();
572 }
573 if a == b12(REG_SIGNED as u128) {
574 value = r.signed;
575 }
576 if a == b12(REG_SIGN_TAKEN as u128) {
577 value = r.sign_taken;
578 }
579 if a == b12(REG_VERIFIED as u128) {
580 value = r.verified;
581 }
582 if a == b12(REG_VALID as u128) {
583 value = r.valid;
584 }
585 for i in 0..6 {
586 if a == b12((REG_SIGN_LATENCY + 4 * i) as u128) {
587 value = latency_word(r.sign_latency, b3(i as u128));
588 }
589 if a == b12((REG_VERIFY_LATENCY + 4 * i) as u128) {
590 value = latency_word(r.verify_latency, b3(i as u128));
591 }
592 }
593 for w in 0..4 {
594 if a == b12((REG_PUBLIC_KEY + 8 * w) as u128) {
595 value = sig.public_key.words[w].resize();
596 }
597 if a == b12((REG_PUBLIC_KEY + 8 * w + 4) as u128) {
598 value = (sig.public_key.words[w] >> 32).resize();
599 }
600 }
601 c.r_valid = true;
602 c.r_data = value;
603 }
604
605 let mut d = UbftEd25519D::<NFB, NV>::dont_care();
607 d.control = c;
608 d.signer = CachedSignIn {
609 load_key_valid: seed_offer,
610 key_seed: ScalarWords { words: seed_words },
611 clear_key: false,
612 valid: sign_req,
613 request: SignRequest { message: Words512 { words: message }, tag: sign_idx.resize() },
614 };
615 d.verifier = VerifyIn {
616 valid: verify_issue,
617 request: VerifyRequest {
618 message: Words512 { words: r.vin_message },
619 public_key: ScalarWords { words: slot_key },
620 signature: Words512 { words: r.vin_signature },
621 tag: verify_idx.resize(),
622 },
623 load_key_valid: r.kl_pulse,
624 load_key: ScalarWords { words: kl_key },
625 load_slot: r.kl_slot.resize(),
626 sha_ext: ShaRingOut { ready: false, done: ShaDone { valid: false, tag: b16(0), state: [b64(0); 8] } },
627 };
628 d.sig_fifo = FifoIn::<SigDone> {
629 data: if sig.valid { Some(SigDone { idx: sig.tag.resize(), signature: sig.signature.words }) } else { None },
630 next: sig_pop,
631 };
632 d.verdict_fifo = FifoIn::<VerdictDone> {
633 data: if ver.valid { Some(VerdictDone { idx: ver.tag.resize(), error: ver.error }) } else { None },
634 next: verdict_pop,
635 };
636 let out = UbftOut {
637 axi: AxiLiteOut {
638 aw_ready: !r.aw_have,
639 w_ready: !r.w_have,
640 b_valid: r.b_valid,
641 b_resp: b2(0),
642 ar_ready,
643 r_valid: r.r_valid,
644 r_data: r.r_data,
645 r_resp: b2(0),
646 interrupt: r.gie && r.ier && r.isr,
647 },
648 sign_ready,
649 sig: sig_out,
650 verify_ready,
651 verdict: verdict_out,
652 };
653 (out, d)
654}