1use rhdl::prelude::*;
8
9pub const MESSAGE_BYTES: usize = 32;
11
12pub const MESSAGE_DIGITS: usize = 64;
14
15pub const CHECKSUM_DIGITS: usize = 3;
17
18pub const CHAIN_COUNT: usize = MESSAGE_DIGITS + CHECKSUM_DIGITS;
20
21pub type MessageBytes = [b8; MESSAGE_BYTES];
23
24pub type MessageDigitArray = [b4; CHAIN_COUNT];
26
27#[derive(Clone, Copy, Debug, Default, Digital, Eq, PartialEq)]
29pub struct SignatureCaptureInput {
30 pub message_digit: b4,
32 pub chain_position: b4,
34}
35
36#[kernel]
41pub fn message_digits_kernel(message: MessageBytes) -> MessageDigitArray {
42 let mut digits = [b4(0); CHAIN_COUNT];
43 let mut checksum = b10(0);
44 for byte_index in 0..MESSAGE_BYTES {
45 let high: b4 = (message[byte_index] >> 4).resize();
46 let low: b4 = message[byte_index].resize();
47 digits[byte_index * 2] = high;
48 digits[byte_index * 2 + 1] = low;
49 let high_wide: b10 = high.resize();
50 let low_wide: b10 = low.resize();
51 checksum = checksum + (b10(15) - high_wide) + (b10(15) - low_wide);
52 }
53 digits[64] = (checksum >> 8).resize();
54 digits[65] = (checksum >> 4).resize();
55 digits[66] = checksum.resize();
56 digits
57}
58
59#[kernel]
64pub fn signature_capture_kernel(input: SignatureCaptureInput) -> bool {
65 input.chain_position == input.message_digit
66}
67
68#[must_use]
70pub fn software_message_digits(message: &[u8; MESSAGE_BYTES]) -> [u8; CHAIN_COUNT] {
71 let mut digits = [0_u8; CHAIN_COUNT];
72 for (index, byte) in message.iter().copied().enumerate() {
73 digits[index * 2] = byte >> 4;
74 digits[index * 2 + 1] = byte & 0x0f;
75 }
76 let checksum = digits[..MESSAGE_DIGITS]
77 .iter()
78 .fold(0_u16, |sum, digit| sum + u16::from(15 - digit));
79 let checksum_bytes = checksum.to_be_bytes();
80 digits[64] = checksum_bytes[0] & 0x0f;
81 digits[65] = checksum_bytes[1] >> 4;
82 digits[66] = checksum_bytes[1] & 0x0f;
83 digits
84}
85
86const _: () = {
87 assert!(MESSAGE_DIGITS == MESSAGE_BYTES * 2);
88 assert!(CHAIN_COUNT == 67);
89 assert!(15 * MESSAGE_DIGITS < 1 << 10);
90};