What changed, and why it matters
This commit simply moves a function called rust_salt_hash_data from one Rust source file to another. The function itself is unchanged; only its location and the associated test code are reorganized. There is no indication this fixes or introduces a security problem.
No security action required. Treat as a normal refactor commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch relocates the unsafe extern “C” fn rust_salt_hash_data from src/rust/bitbox02-rust/src/salt.rs to src/rust/bitbox02-rust-c/src/firmware_c_api.rs. The function body, signature, and safety contract remain identical. The salt module loses its C-FFI wrapper and its C-specific tests, while the firmware_c_api module gains the wrapper. This is a code-organization refactor with no functional change to the hashing logic or the C/Rust boundary behavior.
Changed components
src/rust/bitbox02-rust-c/src/firmware_c_api.rssrc/rust/bitbox02-rust/src/salt.rsInspect captured patch +26 / −64
diff --git a/src/rust/bitbox02-rust-c/src/firmware_c_api.rs b/src/rust/bitbox02-rust-c/src/firmware_c_api.rs
index 988e8a5..c5da0bf 100644
--- a/src/rust/bitbox02-rust-c/src/firmware_c_api.rs
+++ b/src/rust/bitbox02-rust-c/src/firmware_c_api.rs
@@ -1,7 +1,32 @@
// SPDX-License-Identifier: Apache-2.0
+use core::ffi::c_char;
+use util::bytes::{Bytes, BytesMut};
+
#[cfg(not(any(feature = "c-unit-testing", feature = "simulator-graphical")))]
#[unsafe(no_mangle)]
pub extern "C" fn rust_main_loop() -> ! {
bitbox02_rust::main_loop::main_loop(&mut crate::HalImpl::new())
}
+
+/// # Safety
+///
+/// `purpose` must be a valid, null-terminated UTF-8 string pointer.
+#[unsafe(no_mangle)]
+pub unsafe extern "C" fn rust_salt_hash_data(
+ data: Bytes,
+ purpose: *const c_char,
+ mut hash_out: BytesMut,
+) -> bool {
+ let purpose_str = match unsafe { util::strings::str_from_null_terminated_ptr(purpose) } {
+ Ok(purpose) => purpose,
+ Err(()) => return false,
+ };
+ match bitbox02_rust::salt::hash_data(&mut crate::HalImpl::new(), data.as_ref(), purpose_str) {
+ Ok(hash) => {
+ hash_out.as_mut()[..32].copy_from_slice(&hash);
+ true
+ }
+ Err(()) => false,
+ }
+}
diff --git a/src/rust/bitbox02-rust/src/salt.rs b/src/rust/bitbox02-rust/src/salt.rs
index 95b70f5..1442637 100644
--- a/src/rust/bitbox02-rust/src/salt.rs
+++ b/src/rust/bitbox02-rust/src/salt.rs
@@ -1,11 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
use alloc::vec::Vec;
-use core::ffi::c_char;
use crate::hal::Memory;
use sha2::Digest;
-use util::bytes::{Bytes, BytesMut};
use zeroize::Zeroizing;
/// Creates `SHA256(salt_root || purpose || data)`, where `salt_root` is a persisted value that
@@ -28,36 +26,12 @@ pub fn hash_data(
Ok(Zeroizing::new(hasher.finalize().to_vec()))
}
-/// # Safety
-///
-/// `purpose` must be a valid, null-terminated UTF-8 string pointer.
-#[unsafe(no_mangle)]
-pub unsafe extern "C" fn rust_salt_hash_data(
- data: Bytes,
- purpose: *const c_char,
- mut hash_out: BytesMut,
-) -> bool {
- let purpose_str = match unsafe { util::strings::str_from_null_terminated_ptr(purpose) } {
- Ok(purpose) => purpose,
- Err(()) => return false,
- };
- let mut hal = crate::hal::BitBox02Hal::new();
- match hash_data(&mut hal, data.as_ref(), purpose_str) {
- Ok(hash) => {
- hash_out.as_mut()[..32].copy_from_slice(&hash);
- true
- }
- Err(()) => false,
- }
-}
-
#[cfg(test)]
mod tests {
use super::*;
use crate::hal::testing::TestingHal;
- use bitbox02::{memory, testing::mock_memory};
+ use bitbox02::testing::mock_memory;
use core::convert::TryInto;
- use core::ptr;
use hex_lit::hex;
const MOCK_SALT_ROOT: [u8; 32] =
@@ -87,41 +61,4 @@ mod tests {
let hash = hash_data(&mut mock_hal, &[], "").unwrap();
assert_eq!(hash.as_slice(), &expected);
}
-
- #[test]
- fn test_rust_salt_hash_data() {
- mock_memory();
- memory::set_salt_root(&MOCK_SALT_ROOT).unwrap();
-
- let data = hex!("001122334455667788");
- let expected = hex!("62db8dcd47ddf8e81809c377ed96643855d3052bb73237100ca81f0f5a7611e6");
-
- let mut hash_out = [0u8; 32];
- let purpose = c"test purpose";
- assert!(unsafe {
- rust_salt_hash_data(
- util::bytes::rust_util_bytes(data.as_ptr(), data.len()),
- purpose.as_ptr(),
- util::bytes::rust_util_bytes_mut(hash_out.as_mut_ptr(), hash_out.len()),
- )
- });
- assert_eq!(hash_out, expected);
- }
-
- #[test]
- fn test_rust_salt_hash_data_empty_inputs() {
- mock_memory();
- memory::set_salt_root(&MOCK_SALT_ROOT).unwrap();
-
- let expected = hex!("2dbb05dd73d94edba6946611aaca367f76c809e96f20499ad674e596050f9833");
- let mut hash_out = [0u8; 32];
- assert!(unsafe {
- rust_salt_hash_data(
- util::bytes::rust_util_bytes(ptr::null(), 0),
- c"".as_ptr(),
- util::bytes::rust_util_bytes_mut(hash_out.as_mut_ptr(), hash_out.len()),
- )
- });
- assert_eq!(hash_out, expected);
- }
}
Why this scored 11/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.