1use crate::host;
2use crate::host::error_codes::match_result_code_with_expected_bytes;
3use crate::host::{Error, Result};
4use crate::types::message::Message;
5use crate::types::public_key::{PUBLIC_KEY_BUFFER_SIZE, PublicKey};
6use crate::types::signature::Signature;
7
8pub fn sha512_half(data: &[u8]) -> Result<[u8; 32]> {
13 let mut out = [0u8; 32];
14 let rescode = unsafe { host::sha512_half(data.as_ptr(), data.len(), out.as_mut_ptr(), 32) };
15 match_result_code_with_expected_bytes(rescode, 32, || out)
16}
17
18pub fn check_sig(msg: Message, sig: Signature, key: &PublicKey) -> Result<bool> {
32 let rescode = unsafe {
33 host::check_sig(
34 msg.0.as_ptr(),
35 msg.0.len(),
36 sig.0.as_ptr(),
37 sig.0.len(),
38 key.0.as_ptr(),
39 PUBLIC_KEY_BUFFER_SIZE,
40 )
41 };
42 match rescode {
43 0 => Result::Ok(false),
44 1 => Result::Ok(true),
45 code if code < 0 => Result::Err(Error::from_code(code)),
46 code => panic!("internal invariant violated: host returned unexpected value {code}"),
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use crate::host::error_codes::{DATA_FIELD_TOO_LARGE, INVALID_PARAMS};
54 use crate::host::host_bindings_trait::MockHostBindings;
55 use crate::host::setup_mock;
56
57 fn write_digest(ptr: *mut u8, fill: u8) {
58 unsafe {
59 for i in 0..32 {
60 *ptr.add(i) = fill;
61 }
62 }
63 }
64
65 #[test]
68 fn test_sha512_half_success() {
69 let mut mock = MockHostBindings::new();
70 mock.expect_sha512_half()
71 .times(1)
72 .returning(|_data, _dlen, out_ptr, _olen| {
73 write_digest(out_ptr, 0xCD);
74 32
75 });
76 let _guard = setup_mock(mock);
77
78 let result = sha512_half(b"hello world");
79 assert!(result.is_ok());
80 assert_eq!(result.unwrap(), [0xCD; 32]);
81 }
82
83 #[test]
84 #[should_panic(expected = "internal invariant violated")]
85 fn test_sha512_half_wrong_byte_count() {
86 let mut mock = MockHostBindings::new();
87 mock.expect_sha512_half()
88 .times(1)
89 .returning(|_, _, _, _| 16); let _guard = setup_mock(mock);
91
92 let _ = sha512_half(b"hello");
93 }
94
95 #[test]
96 fn test_sha512_half_oversized() {
97 let mut mock = MockHostBindings::new();
98 mock.expect_sha512_half()
99 .times(1)
100 .returning(|_, _, _, _| DATA_FIELD_TOO_LARGE);
101 let _guard = setup_mock(mock);
102
103 let result = sha512_half(&[0u8; 1025]);
104 assert!(result.is_err());
105 assert_eq!(result.err().unwrap().code(), DATA_FIELD_TOO_LARGE);
106 }
107
108 const PUBKEY_BYTES: [u8; PUBLIC_KEY_BUFFER_SIZE] = [
111 0x02, 0xC7, 0x38, 0x7F, 0xFC, 0x25, 0xC1, 0x56, 0xCA, 0x7F, 0x8A, 0x6D, 0x76, 0x0C, 0x8D,
112 0x01, 0xEF, 0x64, 0x2C, 0xEE, 0x9C, 0xE4, 0x68, 0x0C, 0x33, 0xFF, 0xB3, 0xFF, 0x39, 0xAF,
113 0xEC, 0xFE, 0x70,
114 ];
115
116 #[test]
117 fn test_check_sig_valid() {
118 let mut mock = MockHostBindings::new();
119 mock.expect_check_sig()
120 .times(1)
121 .returning(|_, _, _, _, _, _| 1);
122 let _guard = setup_mock(mock);
123
124 let key = PublicKey::from(PUBKEY_BYTES);
125 let result = check_sig(Message(b"message"), Signature(b"signature"), &key);
126 assert!(result.unwrap());
127 }
128
129 #[test]
130 fn test_check_sig_invalid() {
131 let mut mock = MockHostBindings::new();
132 mock.expect_check_sig()
133 .times(1)
134 .returning(|_, _, _, _, _, _| 0);
135 let _guard = setup_mock(mock);
136
137 let key = PublicKey::from(PUBKEY_BYTES);
138 let result = check_sig(Message(b"message"), Signature(b"signature"), &key);
139 assert!(!result.unwrap());
140 }
141
142 #[test]
143 fn test_check_sig_bad_pubkey() {
144 let mut mock = MockHostBindings::new();
145 mock.expect_check_sig()
146 .times(1)
147 .returning(|_, _, _, _, _, _| INVALID_PARAMS);
148 let _guard = setup_mock(mock);
149
150 let key = PublicKey::from(PUBKEY_BYTES);
151 let result = check_sig(Message(b"message"), Signature(b"signature"), &key);
152 assert!(result.is_err());
153 assert_eq!(result.err().unwrap().code(), INVALID_PARAMS);
154 }
155
156 #[test]
157 fn test_check_sig_oversized() {
158 let mut mock = MockHostBindings::new();
159 mock.expect_check_sig()
160 .times(1)
161 .returning(|_, _, _, _, _, _| DATA_FIELD_TOO_LARGE);
162 let _guard = setup_mock(mock);
163
164 let key = PublicKey::from(PUBKEY_BYTES);
165 let result = check_sig(Message(&[0u8; 1025]), Signature(b"signature"), &key);
166 assert!(result.is_err());
167 assert_eq!(result.err().unwrap().code(), DATA_FIELD_TOO_LARGE);
168 }
169
170 #[test]
171 #[should_panic(expected = "internal invariant violated")]
172 fn test_check_sig_unexpected_positive() {
173 let mut mock = MockHostBindings::new();
174 mock.expect_check_sig()
175 .times(1)
176 .returning(|_, _, _, _, _, _| 2); let _guard = setup_mock(mock);
178
179 let key = PublicKey::from(PUBKEY_BYTES);
180 let _ = check_sig(Message(b"m"), Signature(b"s"), &key);
181 }
182}