1use rhdl::prelude::*;
33use rhdl_fpga::core::{
34 dff::DFF,
35 ram::synchronous::{In as SyncBramIn, SyncBRAM, Write as SyncBramWrite},
36};
37use rhdl_primitives::NoResetDff;
38use sha256_rhdl::lane::{CompressionInput, CompressionOutput};
39
40use crate::{
41 blocks::{
42 ChainBlockInput, EndpointPairInput, HashBytes, HashWords, PrfBlockInput,
43 chain_block_kernel, endpoint_final_block_kernel, endpoint_pair_block_kernel,
44 hash_words_to_bytes_kernel, initial_state_words_kernel, prf_block_kernel,
45 },
46 digits::message_digits_kernel,
47 engine::{
48 ENGINE_SEGMENTS, MASK_ADDRESS_BITS, MASK_STORAGE_BITS, SEGMENT_GROUPS,
49 STATE_BANK_ADDRESS_BITS, STATE_STORAGE_BITS, SegmentGroups, SegmentStages,
50 exclude_segment_groups_kernel, public_key_endpoints_ready_kernel, segment_bit_kernel,
51 segment_required_mask_kernel, select_public_key_focus_segment_kernel,
52 select_ready_segment_kernel, set_segment_bit_kernel, state_pair_exclusion_kernel,
53 union_segment_groups_kernel, wake_segments_for_mask_kernel,
54 },
55 tag::{TagFields, decode_tag_kernel, encode_tag_kernel},
56 verify::{
57 framing::{VerifyStreamBeat, verify_beat_halves_kernel, verify_hash_equal_kernel},
58 tasks::{
59 verification_chain_fields_kernel, verification_sha_task_count_kernel,
60 verification_tag_is_well_formed_kernel,
61 },
62 },
63};
64
65pub const VERIFY_ERROR_NONE: u128 = 0;
67pub const VERIFY_ERROR_FRAME: u128 = 1;
69pub const VERIFY_ERROR_TRANSPORT: u128 = 2;
71pub const VERIFY_ERROR_AUDIT: u128 = 3;
73
74const VERIFY_FULL_KEEP_BITS: u128 = u64::MAX as u128;
75const VERIFY_DUE_INSERT_BITS: u128 = 1_u128 << 63;
76const VERIFY_REMOVED_MESSAGE_DIGIT_STATE_BITS: usize = ENGINE_SEGMENTS * 4;
77
78pub const VERIFY_CONTEXT_LOGICAL_RAM_BITS: usize = STATE_STORAGE_BITS + MASK_STORAGE_BITS;
80pub const VERIFY_LANE_LATENCY: usize = 64;
82
83const _: () = {
84 assert!(ENGINE_SEGMENTS == 67);
85 assert!(VERIFY_CONTEXT_LOGICAL_RAM_BITS == 36_864);
86 assert!(VERIFY_LANE_LATENCY == 64);
87 assert!(VERIFY_REMOVED_MESSAGE_DIGIT_STATE_BITS == 268);
88};
89
90#[allow(clippy::struct_excessive_bools)]
92#[derive(Clone, Copy, Debug, Digital, Eq, PartialEq)]
93pub struct VerifyContextControl {
94 pub loading: bool,
96 pub active: bool,
98 pub result_valid: bool,
100 pub fault: bool,
102 pub frame_fault: bool,
104 pub result_verified: bool,
106 pub result_error: b3,
108 pub load_beat: b6,
110 pub mask_ready: b16,
112 pub mask_inflight: b16,
114 pub mask_done: b16,
116 pub segment_ready: SegmentGroups,
118 pub segment_inflight: SegmentGroups,
120 pub segment_stage: SegmentStages,
122 pub endpoint_done: SegmentGroups,
124 pub segment_group_cursor: b4,
126 pub public_key_block: b6,
128 pub public_key_inflight: bool,
130 pub public_key_state_ready: bool,
132 pub total_issued: b11,
134 pub total_retired: b11,
136 pub response_due: b64,
138 pub expected_tasks: b11,
140 pub prefetch_pending: bool,
142 pub prefetch_tag: b32,
144 pub request_valid: bool,
146 pub context: b4,
148 pub generation: b8,
150}
151
152impl Default for VerifyContextControl {
153 fn default() -> Self {
154 Self {
155 loading: false,
156 active: false,
157 result_valid: false,
158 fault: false,
159 frame_fault: false,
160 result_verified: false,
161 result_error: b3(0),
162 load_beat: b6(0),
163 mask_ready: b16(0),
164 mask_inflight: b16(0),
165 mask_done: b16(0),
166 segment_ready: [b8(0); SEGMENT_GROUPS],
167 segment_inflight: [b8(0); SEGMENT_GROUPS],
168 segment_stage: [b5(18); ENGINE_SEGMENTS],
169 endpoint_done: [b8(0); SEGMENT_GROUPS],
170 segment_group_cursor: b4(0),
171 public_key_block: b6(0),
172 public_key_inflight: false,
173 public_key_state_ready: false,
174 total_issued: b11(0),
175 total_retired: b11(0),
176 response_due: b64(0),
177 expected_tasks: b11(0),
178 prefetch_pending: false,
179 prefetch_tag: b32(0),
180 request_valid: false,
181 context: b4(0),
182 generation: b8(0),
183 }
184 }
185}
186
187#[allow(clippy::struct_excessive_bools)]
189#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
190pub struct VerifyContextInput {
191 pub stream_valid: bool,
193 pub stream: VerifyStreamBeat,
195 pub context: b4,
197 pub context_enabled: bool,
199 pub generation: b8,
201 pub request_ready: bool,
203 pub response: CompressionOutput,
205 pub result_ready: bool,
207 pub transport_abort: bool,
213}
214
215#[allow(clippy::struct_excessive_bools)]
217#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
218pub struct VerifyContextOutput {
219 pub stream_ready: bool,
221 pub loading: bool,
223 pub active: bool,
225 pub request: CompressionInput,
227 pub transport_request: CompressionInput,
234 pub response_ready: bool,
236 pub response_rejected: bool,
238 pub fault: bool,
240 pub fault_latched: bool,
242 pub done: bool,
244 pub result_valid: bool,
246 pub result_transfer: bool,
248 pub result_job_id: b32,
250 pub verified: bool,
252 pub error: b3,
254 pub expected_tasks: b11,
256 pub total_issued: b11,
258 pub total_retired: b11,
260}
261
262#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
264pub struct VerifyPrepareRequestInput {
265 pub fields: TagFields,
267 pub public_seed: HashBytes,
269 pub public_key_state: HashWords,
271 pub state_even: HashWords,
273 pub state_odd: HashWords,
275 pub mask: HashWords,
277}
278
279#[kernel]
281pub fn prepare_verify_request_kernel(input: VerifyPrepareRequestInput) -> CompressionInput {
282 let initial = initial_state_words_kernel(b1(0));
283 let state_words = if input.fields.segment & b7(1) == b7(0) {
284 input.state_even
285 } else {
286 input.state_odd
287 };
288 let mut chaining = initial;
289 let mut block = prf_block_kernel(PrfBlockInput {
290 seed: input.public_seed,
291 index: input.fields.segment.resize(),
292 });
293 let mut valid = input.fields.kind == b3(2);
294
295 if input.fields.kind == b3(6) {
296 valid = true;
297 block = chain_block_kernel(ChainBlockInput {
298 state: hash_words_to_bytes_kernel(state_words),
299 mask: hash_words_to_bytes_kernel(input.mask),
300 });
301 } else if input.fields.kind == b3(7) {
302 valid = true;
303 if input.fields.block_index != b6(0) {
304 chaining = input.public_key_state;
305 }
306 if input.fields.block_index == b6(33) {
307 block = endpoint_final_block_kernel(hash_words_to_bytes_kernel(input.state_even));
308 } else {
309 block = endpoint_pair_block_kernel(EndpointPairInput {
310 first: hash_words_to_bytes_kernel(input.state_even),
311 second: hash_words_to_bytes_kernel(input.state_odd),
312 });
313 }
314 }
315
316 CompressionInput {
317 chaining,
318 block,
319 tag: encode_tag_kernel(input.fields),
320 valid,
321 }
322}
323
324#[derive(Clone, Debug, Synchronous, SynchronousDQ)]
326#[rhdl(dq_no_prefix)]
327pub struct VerifySingleContextSha {
328 control: DFF<VerifyContextControl>,
329 request: NoResetDff<CompressionInput>,
330 public_seed: NoResetDff<HashBytes>,
331 expected_hash: NoResetDff<HashBytes>,
332 public_key_state: NoResetDff<HashWords>,
333 job_id: NoResetDff<b32>,
334 state_even: SyncBRAM<HashWords, STATE_BANK_ADDRESS_BITS>,
335 state_odd: SyncBRAM<HashWords, STATE_BANK_ADDRESS_BITS>,
336 masks: SyncBRAM<HashWords, MASK_ADDRESS_BITS>,
337}
338
339impl Default for VerifySingleContextSha {
340 fn default() -> Self {
341 Self {
342 control: DFF::new(VerifyContextControl::default()),
343 request: NoResetDff::new(),
344 public_seed: NoResetDff::new(),
345 expected_hash: NoResetDff::new(),
346 public_key_state: NoResetDff::new(),
347 job_id: NoResetDff::new(),
348 state_even: SyncBRAM::default(),
349 state_odd: SyncBRAM::default(),
350 masks: SyncBRAM::default(),
351 }
352 }
353}
354
355impl SynchronousIO for VerifySingleContextSha {
356 type I = VerifyContextInput;
357 type O = VerifyContextOutput;
358 type Kernel = verify_single_context_sha_kernel;
359}
360
361#[allow(
363 clippy::assign_op_pattern,
364 clippy::comparison_chain,
365 clippy::match_same_arms,
366 clippy::needless_range_loop
367)]
368#[kernel]
369pub fn verify_single_context_sha_kernel(
370 clock_reset: ClockReset,
371 input: VerifyContextInput,
372 q: Q,
373) -> (VerifyContextOutput, D) {
374 let resetting = clock_reset.reset.any();
375 let zero_words = [b32(0); 8];
376 let halves = verify_beat_halves_kernel(input.stream.data);
377 let mut first_words = [b32(0); 8];
378 let mut second_words = [b32(0); 8];
379 for word in 0..8 {
380 let first_byte = word * 4;
381 let a: b32 = halves.first[first_byte].resize();
382 let b: b32 = halves.first[first_byte + 1].resize();
383 let c: b32 = halves.first[first_byte + 2].resize();
384 let d: b32 = halves.first[first_byte + 3].resize();
385 first_words[word] = (a << 24) | (b << 16) | (c << 8) | d;
386 let e: b32 = halves.second[first_byte].resize();
387 let f: b32 = halves.second[first_byte + 1].resize();
388 let g: b32 = halves.second[first_byte + 2].resize();
389 let h: b32 = halves.second[first_byte + 3].resize();
390 second_words[word] = (e << 24) | (f << 16) | (g << 8) | h;
391 }
392
393 let mut control = q.control;
394 let mut next_request = q.request;
395 let mut next_public_seed = q.public_seed;
396 let mut next_expected_hash = q.expected_hash;
397 let mut next_public_key_state = q.public_key_state;
398 let mut next_job_id = q.job_id;
399 let mut state_read_addr = b6(0);
400 let mut mask_read_addr = b4(0);
401 let mut state_even_write = SyncBramWrite::<HashWords, STATE_BANK_ADDRESS_BITS> {
402 addr: b6(0),
403 value: zero_words,
404 enable: false,
405 };
406 let mut state_odd_write = SyncBramWrite::<HashWords, STATE_BANK_ADDRESS_BITS> {
407 addr: b6(0),
408 value: zero_words,
409 enable: false,
410 };
411 let mut mask_write = SyncBramWrite::<HashWords, MASK_ADDRESS_BITS> {
412 addr: b4(0),
413 value: zero_words,
414 enable: false,
415 };
416 let mut done = false;
417
418 let idle =
419 !q.control.loading && !q.control.active && !q.control.result_valid && !q.control.fault;
420 let transport_abort_live = !resetting
421 && input.transport_abort
422 && (q.control.loading
423 || q.control.active
424 || (q.control.result_valid
425 && !q.control.fault
426 && q.control.result_error == b3(VERIFY_ERROR_NONE)));
427 let stream_ready = !resetting
428 && !input.transport_abort
429 && (q.control.loading || (idle && input.context_enabled));
430 let stream_accepted = input.stream_valid && stream_ready;
431 let frame_start = stream_accepted && !q.control.loading;
432 let beat_index = if q.control.loading {
433 q.control.load_beat
434 } else {
435 b6(0)
436 };
437
438 let result_transfer_requested =
439 !resetting && !transport_abort_live && q.control.result_valid && input.result_ready;
440 if result_transfer_requested {
441 control.result_valid = false;
442 control.result_verified = false;
443 control.result_error = b3(VERIFY_ERROR_NONE);
444 control.frame_fault = false;
445 }
446
447 if frame_start {
448 control.loading = true;
449 control.active = false;
450 control.result_valid = false;
451 control.fault = false;
452 control.frame_fault = false;
453 control.result_verified = false;
454 control.result_error = b3(VERIFY_ERROR_NONE);
455 control.load_beat = b6(0);
456 control.mask_ready = b16(0);
457 control.mask_inflight = b16(0);
458 control.mask_done = b16(0);
459 control.segment_ready = [b8(0); SEGMENT_GROUPS];
460 control.segment_inflight = [b8(0); SEGMENT_GROUPS];
461 control.segment_stage = [b5(18); ENGINE_SEGMENTS];
462 control.endpoint_done = [b8(0); SEGMENT_GROUPS];
463 control.segment_group_cursor = b4(0);
464 control.public_key_block = b6(0);
465 control.public_key_inflight = false;
466 control.public_key_state_ready = false;
467 control.total_issued = b11(0);
468 control.total_retired = b11(0);
469 control.response_due = b64(0);
470 control.expected_tasks = b11(0);
471 control.prefetch_pending = false;
472 control.request_valid = false;
473 control.context = input.context;
474 control.generation = input.generation;
475 next_job_id = input.stream.job_id;
476 next_public_key_state = zero_words;
477 }
478
479 if stream_accepted {
480 let expected_last = beat_index == b6(34);
481 let identity_matches = frame_start
482 || (input.stream.job_id == q.job_id
483 && input.context == q.control.context
484 && input.generation == q.control.generation);
485 let beat_fault = input.stream.keep != b64(VERIFY_FULL_KEEP_BITS)
486 || input.stream.last != expected_last
487 || !identity_matches;
488 control.frame_fault = control.frame_fault || beat_fault;
489
490 if beat_index < b6(33) {
491 state_even_write = SyncBramWrite::<HashWords, STATE_BANK_ADDRESS_BITS> {
492 addr: beat_index,
493 value: first_words,
494 enable: true,
495 };
496 state_odd_write = SyncBramWrite::<HashWords, STATE_BANK_ADDRESS_BITS> {
497 addr: beat_index,
498 value: second_words,
499 enable: true,
500 };
501 } else if beat_index == b6(33) {
502 state_even_write = SyncBramWrite::<HashWords, STATE_BANK_ADDRESS_BITS> {
503 addr: b6(33),
504 value: first_words,
505 enable: true,
506 };
507 next_public_seed = halves.second;
508 } else {
509 next_expected_hash = halves.first;
510 let digits = message_digits_kernel(halves.second);
511 control.loading = false;
512 if control.frame_fault {
513 control.result_valid = true;
514 control.result_verified = false;
515 control.result_error = b3(VERIFY_ERROR_FRAME);
516 done = true;
517 } else {
518 control.active = true;
519 control.mask_ready = b16(0xffff);
520 control.public_key_state_ready = true;
521 control.expected_tasks = verification_sha_task_count_kernel(digits);
522 for segment in 0..ENGINE_SEGMENTS {
523 let segment_index = b7(segment as u128);
524 let digit = digits[segment];
525 if digit == b4(15) {
526 control.endpoint_done =
527 set_segment_bit_kernel(control.endpoint_done, segment_index, true);
528 control.segment_stage[segment] = b5(18);
529 } else {
530 let digit_wide: b5 = digit.resize();
531 control.segment_stage[segment] = digit_wide + b5(3);
532 }
533 }
534 }
535 }
536 if beat_index < b6(34) {
537 control.load_beat = beat_index + b6(1);
538 }
539 }
540
541 let response_fields = decode_tag_kernel(input.response.tag);
542 let response_common = !resetting
543 && !transport_abort_live
544 && q.control.active
545 && input.response.valid
546 && verification_tag_is_well_formed_kernel(input.response.tag)
547 && response_fields.context == q.control.context
548 && response_fields.generation == q.control.generation;
549 let bounded_segment = if response_fields.segment < b7(67) {
550 response_fields.segment
551 } else {
552 b7(0)
553 };
554 let bounded_mask = if response_fields.segment < b7(16) {
555 response_fields.segment
556 } else {
557 b7(0)
558 };
559 let mask_bit = b16(1) << bounded_mask;
560 let mask_response = response_common
561 && response_fields.kind == b3(2)
562 && q.control.mask_inflight & mask_bit != b16(0);
563 let expected_chain = verification_chain_fields_kernel(
564 q.control.segment_stage[bounded_segment],
565 bounded_segment,
566 q.control.context,
567 q.control.generation,
568 );
569 let chain_response = response_common
570 && response_fields.kind == b3(6)
571 && segment_bit_kernel(q.control.segment_inflight, bounded_segment)
572 && input.response.tag == encode_tag_kernel(expected_chain);
573 let public_key_response = response_common
574 && response_fields.kind == b3(7)
575 && q.control.public_key_inflight
576 && response_fields.block_index == q.control.public_key_block;
577 let response_due_now = q.control.response_due & b64(1) != b64(0);
578 let operation_live = q.control.loading
579 || q.control.active
580 || frame_start
581 || (q.control.result_valid && !q.control.fault);
582 let response_payload_accepted = mask_response || chain_response || public_key_response;
583 let response_accepted = response_due_now && response_payload_accepted;
584 let response_timing_matches = (q.control.active && response_due_now) == input.response.valid;
585 let local_terminal_transport = !resetting
586 && !transport_abort_live
587 && operation_live
588 && (!response_timing_matches || (input.response.valid && !response_accepted));
589 let terminal_transport = transport_abort_live || local_terminal_transport;
590 let response_rejected = local_terminal_transport && input.response.valid;
591 let mut response_cycle_excluded = [b8(0); SEGMENT_GROUPS];
592 let mut public_key_response_guard = false;
593
594 if q.control.active {
595 control.response_due = q.control.response_due >> 1;
596 }
597
598 let request_accepted = !terminal_transport
599 && !resetting
600 && q.control.active
601 && q.control.request_valid
602 && input.request_ready;
603 if request_accepted {
604 let issued_fields = decode_tag_kernel(q.request.tag);
605 control.request_valid = false;
606 control.total_issued = q.control.total_issued + b11(1);
607 control.response_due = control.response_due | b64(VERIFY_DUE_INSERT_BITS);
608 if issued_fields.kind == b3(2) {
609 let bit = b16(1) << issued_fields.segment;
610 control.mask_ready = q.control.mask_ready & !bit;
611 control.mask_inflight = q.control.mask_inflight | bit;
612 } else if issued_fields.kind == b3(6) {
613 control.segment_ready =
614 set_segment_bit_kernel(q.control.segment_ready, issued_fields.segment, false);
615 control.segment_inflight =
616 set_segment_bit_kernel(q.control.segment_inflight, issued_fields.segment, true);
617 } else if issued_fields.kind == b3(7) {
618 control.public_key_inflight = true;
619 control.public_key_state_ready = false;
620 } else {
621 control.fault = true;
622 }
623 }
624 if response_accepted {
625 control.total_retired = q.control.total_retired + b11(1);
626 }
627
628 if mask_response {
629 control.mask_inflight = control.mask_inflight & !mask_bit;
630 control.mask_done = control.mask_done | mask_bit;
631 mask_write = SyncBramWrite::<HashWords, MASK_ADDRESS_BITS> {
632 addr: response_fields.segment.resize(),
633 value: input.response.digest,
634 enable: true,
635 };
636 let ready_before = control.segment_ready;
637 control.segment_ready = wake_segments_for_mask_kernel(
638 control.segment_stage,
639 control.segment_ready,
640 control.segment_inflight,
641 response_fields.segment.resize(),
642 );
643 response_cycle_excluded = union_segment_groups_kernel(
644 response_cycle_excluded,
645 exclude_segment_groups_kernel(control.segment_ready, ready_before),
646 );
647 }
648
649 if chain_response {
650 let segment = response_fields.segment;
651 let pair_addr: b6 = (segment >> 1).resize();
652 control.segment_inflight = set_segment_bit_kernel(control.segment_inflight, segment, false);
653 response_cycle_excluded = union_segment_groups_kernel(
654 response_cycle_excluded,
655 state_pair_exclusion_kernel(segment),
656 );
657 if segment & b7(1) == b7(0) {
658 state_even_write = SyncBramWrite::<HashWords, STATE_BANK_ADDRESS_BITS> {
659 addr: pair_addr,
660 value: input.response.digest,
661 enable: true,
662 };
663 } else {
664 state_odd_write = SyncBramWrite::<HashWords, STATE_BANK_ADDRESS_BITS> {
665 addr: pair_addr,
666 value: input.response.digest,
667 enable: true,
668 };
669 }
670
671 let current_stage = q.control.segment_stage[segment];
672 if current_stage < b5(17) {
673 let next_stage = current_stage + b5(1);
674 control.segment_stage[segment] = next_stage;
675 let required = segment_required_mask_kernel(next_stage);
676 if control.mask_done & (b16(1) << required) != b16(0) {
677 control.segment_ready =
678 set_segment_bit_kernel(control.segment_ready, segment, true);
679 response_cycle_excluded =
680 set_segment_bit_kernel(response_cycle_excluded, segment, true);
681 }
682 } else {
683 control.segment_stage[segment] = b5(18);
684 control.endpoint_done = set_segment_bit_kernel(control.endpoint_done, segment, true);
685 public_key_response_guard = true;
686 }
687 }
688
689 if public_key_response {
690 next_public_key_state = input.response.digest;
691 control.public_key_inflight = false;
692 control.public_key_state_ready = true;
693 if q.control.public_key_block == b6(33) {
694 let endpoints_complete = q.control.endpoint_done[0] == b8(0xff)
695 && q.control.endpoint_done[1] == b8(0xff)
696 && q.control.endpoint_done[2] == b8(0xff)
697 && q.control.endpoint_done[3] == b8(0xff)
698 && q.control.endpoint_done[4] == b8(0xff)
699 && q.control.endpoint_done[5] == b8(0xff)
700 && q.control.endpoint_done[6] == b8(0xff)
701 && q.control.endpoint_done[7] == b8(0xff)
702 && q.control.endpoint_done[8] == b8(0x07);
703 let exact_final = q.control.total_issued == q.control.expected_tasks
704 && q.control.total_retired + b11(1) == q.control.expected_tasks
705 && q.control.mask_done == b16(0xffff)
706 && endpoints_complete;
707 control.active = false;
708 control.result_valid = true;
709 control.prefetch_pending = false;
710 control.request_valid = false;
711 control.result_verified = false;
712 if !exact_final {
713 control.result_error = b3(VERIFY_ERROR_AUDIT);
714 control.fault = true;
715 } else if control.fault {
716 control.result_error = b3(VERIFY_ERROR_TRANSPORT);
717 } else {
718 control.result_error = b3(VERIFY_ERROR_NONE);
719 control.result_verified = verify_hash_equal_kernel(
720 hash_words_to_bytes_kernel(input.response.digest),
721 q.expected_hash,
722 );
723 }
724 done = true;
725 } else {
726 control.public_key_block = q.control.public_key_block + b6(1);
727 }
728 }
729
730 if !resetting && control.active && q.control.prefetch_pending && !q.control.request_valid {
731 next_request = prepare_verify_request_kernel(VerifyPrepareRequestInput {
732 fields: decode_tag_kernel(q.control.prefetch_tag),
733 public_seed: q.public_seed,
734 public_key_state: q.public_key_state,
735 state_even: q.state_even,
736 state_odd: q.state_odd,
737 mask: q.masks,
738 });
739 control.prefetch_pending = false;
740 control.request_valid = true;
741 }
742
743 let request_slot_free = !control.request_valid && !control.prefetch_pending;
744 let visible_ready =
745 exclude_segment_groups_kernel(control.segment_ready, response_cycle_excluded);
746 let segment_selection =
747 select_ready_segment_kernel(visible_ready, control.segment_group_cursor);
748 let focus_selection = select_public_key_focus_segment_kernel(
749 visible_ready,
750 control.public_key_block,
751 control.public_key_inflight,
752 );
753 let public_key_ready = !public_key_response_guard
754 && !control.public_key_inflight
755 && control.public_key_state_ready
756 && public_key_endpoints_ready_kernel(control.endpoint_done, control.public_key_block);
757 let mut selected_valid = false;
758 let mut selected_fields = TagFields {
759 context: control.context,
760 generation: control.generation,
761 ..TagFields::default()
762 };
763
764 if control.active && request_slot_free {
765 if public_key_ready {
766 selected_valid = true;
767 selected_fields.kind = b3(7);
768 selected_fields.block_index = control.public_key_block;
769 } else if control.mask_ready != b16(0) {
770 selected_valid = true;
771 selected_fields.kind = b3(2);
772 if control.mask_ready & b16(0x0001) != b16(0) {
773 selected_fields.segment = b7(0);
774 } else if control.mask_ready & b16(0x0002) != b16(0) {
775 selected_fields.segment = b7(1);
776 } else if control.mask_ready & b16(0x0004) != b16(0) {
777 selected_fields.segment = b7(2);
778 } else if control.mask_ready & b16(0x0008) != b16(0) {
779 selected_fields.segment = b7(3);
780 } else if control.mask_ready & b16(0x0010) != b16(0) {
781 selected_fields.segment = b7(4);
782 } else if control.mask_ready & b16(0x0020) != b16(0) {
783 selected_fields.segment = b7(5);
784 } else if control.mask_ready & b16(0x0040) != b16(0) {
785 selected_fields.segment = b7(6);
786 } else if control.mask_ready & b16(0x0080) != b16(0) {
787 selected_fields.segment = b7(7);
788 } else if control.mask_ready & b16(0x0100) != b16(0) {
789 selected_fields.segment = b7(8);
790 } else if control.mask_ready & b16(0x0200) != b16(0) {
791 selected_fields.segment = b7(9);
792 } else if control.mask_ready & b16(0x0400) != b16(0) {
793 selected_fields.segment = b7(10);
794 } else if control.mask_ready & b16(0x0800) != b16(0) {
795 selected_fields.segment = b7(11);
796 } else if control.mask_ready & b16(0x1000) != b16(0) {
797 selected_fields.segment = b7(12);
798 } else if control.mask_ready & b16(0x2000) != b16(0) {
799 selected_fields.segment = b7(13);
800 } else if control.mask_ready & b16(0x4000) != b16(0) {
801 selected_fields.segment = b7(14);
802 } else {
803 selected_fields.segment = b7(15);
804 }
805 } else if focus_selection.valid {
806 selected_valid = true;
807 selected_fields = verification_chain_fields_kernel(
808 control.segment_stage[focus_selection.segment],
809 focus_selection.segment,
810 control.context,
811 control.generation,
812 );
813 } else if segment_selection.valid {
814 selected_valid = true;
815 selected_fields = verification_chain_fields_kernel(
816 control.segment_stage[segment_selection.segment],
817 segment_selection.segment,
818 control.context,
819 control.generation,
820 );
821 control.segment_group_cursor = segment_selection.next_group;
822 }
823 }
824
825 if selected_valid {
826 control.prefetch_pending = true;
827 control.prefetch_tag = encode_tag_kernel(selected_fields);
828 if selected_fields.kind == b3(6) {
829 state_read_addr = (selected_fields.segment >> 1).resize();
830 mask_read_addr = selected_fields.chain_step;
831 } else if selected_fields.kind == b3(7) {
832 state_read_addr = selected_fields.block_index;
833 }
834 }
835
836 if terminal_transport {
837 control.loading = false;
838 control.active = false;
839 control.result_valid = true;
840 control.fault = true;
841 control.result_verified = false;
842 control.result_error = b3(VERIFY_ERROR_TRANSPORT);
843 control.prefetch_pending = false;
844 control.request_valid = false;
845 control.response_due = b64(0);
846 next_request.valid = false;
847 state_even_write.enable = false;
848 state_odd_write.enable = false;
849 mask_write.enable = false;
850 done = true;
851 }
852
853 if resetting {
854 state_even_write.enable = false;
855 state_odd_write.enable = false;
856 mask_write.enable = false;
857 }
858
859 let mut transport_request = q.request;
860 transport_request.valid = !resetting && q.control.request_valid;
861 let mut request = transport_request;
862 request.valid = transport_request.valid && !terminal_transport;
863 let result_transfer = result_transfer_requested && !terminal_transport;
864 let output = VerifyContextOutput {
865 stream_ready,
866 loading: !resetting && q.control.loading,
867 active: !resetting && q.control.active,
868 request,
869 transport_request,
870 response_ready: response_accepted,
871 response_rejected,
872 fault: !resetting && (q.control.fault || terminal_transport),
873 fault_latched: !resetting && q.control.fault,
874 done,
875 result_valid: !resetting && q.control.result_valid,
876 result_transfer,
877 result_job_id: q.job_id,
878 verified: !terminal_transport
879 && !resetting
880 && q.control.result_valid
881 && q.control.result_error == b3(VERIFY_ERROR_NONE)
882 && q.control.result_verified,
883 error: if terminal_transport {
884 b3(VERIFY_ERROR_TRANSPORT)
885 } else {
886 q.control.result_error
887 },
888 expected_tasks: q.control.expected_tasks,
889 total_issued: q.control.total_issued,
890 total_retired: q.control.total_retired,
891 };
892
893 let d = D {
894 control,
895 request: next_request,
896 public_seed: next_public_seed,
897 expected_hash: next_expected_hash,
898 public_key_state: next_public_key_state,
899 job_id: next_job_id,
900 state_even: SyncBramIn::<HashWords, STATE_BANK_ADDRESS_BITS> {
901 read_addr: state_read_addr,
902 write: state_even_write,
903 },
904 state_odd: SyncBramIn::<HashWords, STATE_BANK_ADDRESS_BITS> {
905 read_addr: state_read_addr,
906 write: state_odd_write,
907 },
908 masks: SyncBramIn::<HashWords, MASK_ADDRESS_BITS> {
909 read_addr: mask_read_addr,
910 write: mask_write,
911 },
912 };
913 (output, d)
914}