#![allow(dead_code)]
use crate::error_sanitize::sanitize_error;
pub fn raw_ecdsa_to_der(raw: &[u8]) -> crate::Result<Vec<u8>> {
if raw.len() != 64 {
return Err(crate::Error::Io(std::io::Error::other(sanitize_error(
&format!("Invalid raw signature length: {}, expected 64", raw.len()),
"Failed to sign",
))));
}
let r = &raw[0..32];
let s = &raw[32..64];
let r_der = encode_integer(r);
let s_der = encode_integer(s);
let seq_len = r_der.len() + s_der.len();
let mut der = vec![0x30];
if seq_len < 128 {
der.push(seq_len as u8);
} else {
der.push(0x81);
der.push(seq_len as u8);
}
der.extend_from_slice(&r_der);
der.extend_from_slice(&s_der);
Ok(der)
}
fn encode_integer(value: &[u8]) -> Vec<u8> {
let mut start = 0;
while start < value.len() - 1 && value[start] == 0 {
start += 1;
}
let trimmed = &value[start..];
let needs_padding = trimmed[0] & 0x80 != 0;
let len = trimmed.len() + if needs_padding { 1 } else { 0 };
let mut result = vec![0x02, len as u8]; if needs_padding {
result.push(0x00);
}
result.extend_from_slice(trimmed);
result
}
#[cfg(test)]
mod tests {
use super::*;
fn make_raw_sig(r: &[u8], s: &[u8]) -> Vec<u8> {
let mut raw = vec![0u8; 64];
let r_start = 32 - r.len();
raw[r_start..32].copy_from_slice(r);
let s_start = 64 - s.len();
raw[s_start..64].copy_from_slice(s);
raw
}
fn verify_der_structure(der: &[u8]) -> bool {
if der.is_empty() || der[0] != 0x30 {
return false; }
let (seq_len, header_len) = if der[1] < 128 {
(der[1] as usize, 2)
} else if der[1] == 0x81 {
(der[2] as usize, 3)
} else {
return false; };
if der.len() != header_len + seq_len {
return false; }
let mut pos = header_len;
if der[pos] != 0x02 {
return false; }
let r_len = der[pos + 1] as usize;
pos += 2 + r_len;
if pos >= der.len() || der[pos] != 0x02 {
return false;
}
let s_len = der[pos + 1] as usize;
pos += 2 + s_len;
pos == der.len() }
#[test]
fn test_der_encoding_minimal_values() {
let raw = make_raw_sig(&[1], &[1]);
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
assert_eq!(der, vec![0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01]);
}
#[test]
fn test_der_encoding_all_zeros() {
let raw = vec![0u8; 64];
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
assert_eq!(der, vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]);
}
#[test]
fn test_der_encoding_high_bit_set() {
let raw = make_raw_sig(&[0x80], &[0xFF]);
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
assert_eq!(
der,
vec![0x30, 0x08, 0x02, 0x02, 0x00, 0x80, 0x02, 0x02, 0x00, 0xFF]
);
}
#[test]
fn test_der_encoding_no_padding_needed() {
let raw = make_raw_sig(&[0x7F], &[0x01]);
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
assert_eq!(der, vec![0x30, 0x06, 0x02, 0x01, 0x7F, 0x02, 0x01, 0x01]);
}
#[test]
fn test_der_encoding_full_32_bytes_with_high_bit() {
let r = vec![0xFF; 32];
let s = vec![0x01];
let raw = make_raw_sig(&r, &s);
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
assert_eq!(der[0], 0x30); assert_eq!(der[1], 38); assert_eq!(der[2], 0x02); assert_eq!(der[3], 33); assert_eq!(der[4], 0x00); assert_eq!(der[5], 0xFF); }
#[test]
fn test_der_encoding_full_32_bytes_no_padding() {
let r = vec![0x7F; 32];
let s = vec![0x01];
let raw = make_raw_sig(&r, &s);
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
assert_eq!(der[0], 0x30); assert_eq!(der[1], 37); assert_eq!(der[2], 0x02); assert_eq!(der[3], 32); assert_eq!(der[4], 0x7F); }
#[test]
fn test_der_encoding_typical_signature() {
let r: Vec<u8> = (0..32).map(|i| ((i * 7) % 256) as u8).collect();
let s: Vec<u8> = (0..32).map(|i| ((i * 13 + 5) % 256) as u8).collect();
let mut raw = vec![0u8; 64];
raw[..32].copy_from_slice(&r);
raw[32..].copy_from_slice(&s);
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
}
#[test]
fn test_der_encoding_max_values() {
let raw = vec![0xFF; 64];
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
assert_eq!(der[0], 0x30); assert_eq!(der[1], 70); }
#[test]
fn test_der_encoding_invalid_length() {
let raw = vec![0u8; 63]; let result = raw_ecdsa_to_der(&raw);
assert!(result.is_err());
let raw = vec![0u8; 65]; let result = raw_ecdsa_to_der(&raw);
assert!(result.is_err());
}
#[test]
fn test_der_encoding_leading_zeros_stripped() {
let raw = make_raw_sig(&[0x42], &[0x01]);
let der = raw_ecdsa_to_der(&raw).unwrap();
assert!(verify_der_structure(&der));
assert_eq!(der, vec![0x30, 0x06, 0x02, 0x01, 0x42, 0x02, 0x01, 0x01]);
}
}