Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
113
vendor/ruvector/crates/rvf/rvf-crypto/src/footer.rs
vendored
Normal file
113
vendor/ruvector/crates/rvf/rvf-crypto/src/footer.rs
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
//! Signature footer codec for RVF segments.
|
||||
//!
|
||||
//! Encodes/decodes `rvf_types::SignatureFooter` to/from wire-format bytes.
|
||||
//! Wire layout:
|
||||
//! [0..2] sig_algo (u16 LE)
|
||||
//! [2..4] sig_length (u16 LE)
|
||||
//! [4..4+sig_length] signature bytes
|
||||
//! [4+sig_length..4+sig_length+4] footer_length (u32 LE)
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use rvf_types::{ErrorCode, RvfError, SignatureFooter};
|
||||
|
||||
/// Minimum footer wire size: 2 (algo) + 2 (sig_len) + 4 (footer_len) = 8 bytes.
|
||||
const FOOTER_MIN_SIZE: usize = 8;
|
||||
|
||||
/// Encode a `SignatureFooter` into wire-format bytes.
|
||||
pub fn encode_signature_footer(footer: &SignatureFooter) -> Vec<u8> {
|
||||
let sig_len = footer.sig_length as usize;
|
||||
let total = 2 + 2 + sig_len + 4;
|
||||
let mut buf = Vec::with_capacity(total);
|
||||
buf.extend_from_slice(&footer.sig_algo.to_le_bytes());
|
||||
buf.extend_from_slice(&footer.sig_length.to_le_bytes());
|
||||
buf.extend_from_slice(&footer.signature[..sig_len]);
|
||||
buf.extend_from_slice(&footer.footer_length.to_le_bytes());
|
||||
buf
|
||||
}
|
||||
|
||||
/// Decode a `SignatureFooter` from wire-format bytes.
|
||||
pub fn decode_signature_footer(data: &[u8]) -> Result<SignatureFooter, RvfError> {
|
||||
if data.len() < FOOTER_MIN_SIZE {
|
||||
return Err(RvfError::Code(ErrorCode::TruncatedSegment));
|
||||
}
|
||||
let sig_algo = u16::from_le_bytes([data[0], data[1]]);
|
||||
let sig_length = u16::from_le_bytes([data[2], data[3]]);
|
||||
let sig_len = sig_length as usize;
|
||||
|
||||
if sig_len > SignatureFooter::MAX_SIG_LEN {
|
||||
return Err(RvfError::Code(ErrorCode::InvalidSignature));
|
||||
}
|
||||
if data.len() < 4 + sig_len + 4 {
|
||||
return Err(RvfError::Code(ErrorCode::TruncatedSegment));
|
||||
}
|
||||
|
||||
let mut signature = [0u8; SignatureFooter::MAX_SIG_LEN];
|
||||
signature[..sig_len].copy_from_slice(&data[4..4 + sig_len]);
|
||||
|
||||
let fl_offset = 4 + sig_len;
|
||||
let footer_length = u32::from_le_bytes([
|
||||
data[fl_offset],
|
||||
data[fl_offset + 1],
|
||||
data[fl_offset + 2],
|
||||
data[fl_offset + 3],
|
||||
]);
|
||||
|
||||
Ok(SignatureFooter {
|
||||
sig_algo,
|
||||
sig_length,
|
||||
signature,
|
||||
footer_length,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn make_footer(algo: u16, sig_len: u16, fill: u8) -> SignatureFooter {
|
||||
let mut signature = [0u8; SignatureFooter::MAX_SIG_LEN];
|
||||
signature[..sig_len as usize].fill(fill);
|
||||
SignatureFooter {
|
||||
sig_algo: algo,
|
||||
sig_length: sig_len,
|
||||
signature,
|
||||
footer_length: SignatureFooter::compute_footer_length(sig_len),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip_ed25519() {
|
||||
let footer = make_footer(0, 64, 0xAB);
|
||||
let encoded = encode_signature_footer(&footer);
|
||||
assert_eq!(encoded.len(), 2 + 2 + 64 + 4);
|
||||
let decoded = decode_signature_footer(&encoded).unwrap();
|
||||
assert_eq!(decoded.sig_algo, footer.sig_algo);
|
||||
assert_eq!(decoded.sig_length, footer.sig_length);
|
||||
assert_eq!(&decoded.signature[..64], &footer.signature[..64]);
|
||||
assert_eq!(decoded.footer_length, footer.footer_length);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_truncated_header() {
|
||||
let result = decode_signature_footer(&[0u8; 5]);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_truncated_signature() {
|
||||
let footer = make_footer(0, 64, 0xCC);
|
||||
let encoded = encode_signature_footer(&footer);
|
||||
let result = decode_signature_footer(&encoded[..10]);
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_signature() {
|
||||
let footer = make_footer(1, 0, 0);
|
||||
let encoded = encode_signature_footer(&footer);
|
||||
assert_eq!(encoded.len(), FOOTER_MIN_SIZE);
|
||||
let decoded = decode_signature_footer(&encoded).unwrap();
|
||||
assert_eq!(decoded.sig_algo, 1);
|
||||
assert_eq!(decoded.sig_length, 0);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user