wots_rhdl/verify/
tasks.rs1use rhdl::prelude::*;
10
11use crate::{
12 digits::{CHAIN_COUNT, MessageBytes, MessageDigitArray, message_digits_kernel},
13 tag::{DecodedTaskTag, TagFields, TaskKind, encode_tag_kernel, tag_is_well_formed_kernel},
14};
15
16pub const VERIFY_MASK_TASKS: usize = 16;
18pub const VERIFY_PUBLIC_KEY_TASKS: usize = 34;
20pub const VERIFY_MIN_CHAIN_TASKS: usize = 45;
22pub const VERIFY_MAX_CHAIN_TASKS: usize = 990;
24pub const VERIFY_MIN_SHA_TASKS: usize = 95;
26pub const VERIFY_MAX_SHA_TASKS: usize = 1_040;
28
29const _: () = {
30 assert!(VERIFY_MIN_SHA_TASKS == VERIFY_MASK_TASKS + VERIFY_MIN_CHAIN_TASKS + 34);
31 assert!(VERIFY_MAX_SHA_TASKS == VERIFY_MASK_TASKS + VERIFY_MAX_CHAIN_TASKS + 34);
32};
33
34#[allow(clippy::assign_op_pattern, clippy::needless_range_loop)]
36#[kernel]
37pub fn verification_chain_count_kernel(digits: MessageDigitArray) -> b10 {
38 let mut count = b10(0);
39 for segment in 0..CHAIN_COUNT {
40 let digit: b10 = digits[segment].resize();
41 count = count + (b10(15) - digit);
42 }
43 count
44}
45
46#[kernel]
48pub fn verification_sha_task_count_kernel(digits: MessageDigitArray) -> b11 {
49 let chain: b11 = verification_chain_count_kernel(digits).resize();
50 chain + b11((VERIFY_MASK_TASKS + VERIFY_PUBLIC_KEY_TASKS) as u128)
51}
52
53#[kernel]
55pub fn verification_message_task_count_kernel(message: MessageBytes) -> b11 {
56 verification_sha_task_count_kernel(message_digits_kernel(message))
57}
58
59#[kernel]
61pub fn verification_tag_is_well_formed_kernel(tag: b32) -> bool {
62 if tag_is_well_formed_kernel(tag) {
63 let kind: b3 = (tag >> 4).resize();
64 kind == b3(2) || kind == b3(6) || kind == b3(7)
65 } else {
66 false
67 }
68}
69
70#[kernel]
75pub fn verification_chain_fields_kernel(
76 stage: b5,
77 segment: b7,
78 context: b4,
79 generation: b8,
80) -> TagFields {
81 TagFields {
82 context,
83 kind: b3(6),
84 segment,
85 chain_step: (stage - b5(2)).resize(),
86 block_index: b6(0),
87 generation,
88 }
89}
90
91#[kernel]
93pub fn verification_fields_are_canonical_kernel(fields: TagFields) -> bool {
94 verification_tag_is_well_formed_kernel(encode_tag_kernel(fields))
95}
96
97pub fn verification_chain_count(digits: &[u8; CHAIN_COUNT]) -> Result<usize, (usize, u8)> {
103 digits
104 .iter()
105 .copied()
106 .enumerate()
107 .try_fold(0_usize, |count, (segment, digit)| {
108 if digit > 15 {
109 Err((segment, digit))
110 } else {
111 Ok(count + usize::from(15 - digit))
112 }
113 })
114}
115
116pub fn verification_sha_task_count(digits: &[u8; CHAIN_COUNT]) -> Result<usize, (usize, u8)> {
122 verification_chain_count(digits)
123 .map(|chain| VERIFY_MASK_TASKS + chain + VERIFY_PUBLIC_KEY_TASKS)
124}
125
126#[must_use]
136pub fn canonical_verification_tasks(
137 context: u8,
138 generation: u8,
139 digits: &[u8; CHAIN_COUNT],
140) -> Vec<DecodedTaskTag> {
141 assert!(context < 16, "verification context must fit four bits");
142 let expected = verification_sha_task_count(digits).expect("message digits are base 16");
143 let mut tasks = Vec::with_capacity(expected);
144 for mask in 0_u8..16 {
145 tasks.push(
146 DecodedTaskTag::new(context, TaskKind::Mask, mask, 0, 0, generation)
147 .expect("mask tag is canonical"),
148 );
149 }
150 for (segment, digit) in digits.iter().copied().enumerate() {
151 for step in digit + 1..=15 {
152 tasks.push(
153 DecodedTaskTag::new(
154 context,
155 TaskKind::Chain,
156 u8::try_from(segment).expect("67 segments fit u8"),
157 step,
158 0,
159 generation,
160 )
161 .expect("chain tag is canonical"),
162 );
163 }
164 }
165 for block in 0_u8..34 {
166 tasks.push(
167 DecodedTaskTag::new(context, TaskKind::PublicKey, 0, 0, block, generation)
168 .expect("public-key tag is canonical"),
169 );
170 }
171 assert_eq!(tasks.len(), expected);
172 tasks
173}