use crate::Error;
use crate::Result;
pub fn parse_sig_r_s(signature: &[u8]) -> Result<(&[u8], &[u8])> {
let mut ints = parse_sequence_of_unsigned(&signature)?;
let r = ints.next().ok_or_else(not_set)??;
let s = ints.next().ok_or_else(not_set)??;
if ints.next().is_some() {
return Err(unexpected_data());
}
Ok((r, s))
}
fn decode_length(der: &[u8]) -> Result<(usize, usize)> {
let len = *der.get(0).ok_or_else(unexpected_data)? as usize;
if len < 128 {
return Ok((1, len));
}
let octets = len ^ 0x80;
if octets > 4 {
return Err(unexpected_data());
}
let len_len = 1 + octets;
if der.len() < len_len {
return Err(unexpected_data());
}
let mut value_len = 0;
for b in &der[1..len_len] {
value_len <<= 8;
value_len |= *b as usize;
}
Ok((len_len, value_len))
}
fn parse_sequence_of_unsigned<'der>(
der: &'der [u8]
)
-> Result<impl Iterator<Item=Result<&'der [u8]>> + 'der>
{
if false {
let mut hd = crate::fmt::hex::Dumper::new(std::io::stderr(), "");
hd.write(&der, "SEQUENCE")?;
}
let typ = *der.get(0).ok_or_else(unexpected_data)?;
let der = &der[1..];
if typ != TAG_SEQUENCE {
return Err(unexpected_data());
}
let (len_len, value_len) = decode_length(der)?;
let mut der = &der[len_len..];
if der.len() != value_len {
return Err(unexpected_data());
}
Ok(std::iter::from_fn(move || -> Option<Result<&'der [u8]>> {
if der.is_empty() {
return None;
}
let for_debugging = der;
let typ = if let Some(t) = der.get(0) {
*t
} else {
return Some(Err(unexpected_data()));
};
der = &der[1..];
if typ != TAG_INTEGER {
return Some(Err(unexpected_data()));
}
let len = if let Ok((len_len, value_len)) = decode_length(der) {
der = &der[len_len..];
value_len
} else {
return Some(Err(unexpected_data()));
};
if der.len() < len {
return Some(Err(unexpected_data()));
}
let mut v = &der[..len];
der = &der[len..];
if v.get(0) == Some(&0) {
v = &v[1..];
}
if false {
let mut hd = crate::fmt::hex::Dumper::new(std::io::stderr(), " ");
let l = for_debugging.len() - der.len();
hd.write(&for_debugging[..l], "INTEGER").unwrap();
}
Some(Ok(v))
}))
}
pub fn encode_sig_r_s(w: &mut Vec<u8>, r: &[u8], s: &[u8]) -> Result<()> {
let body_len = encoded_len_unsigned(r) + encoded_len_unsigned(s);
w.reserve(1 + encoded_len_len(body_len) + body_len);
w.push(TAG_SEQUENCE);
encode_len(w, body_len)?;
encode_unsigned(w, r)?;
encode_unsigned(w, s)?;
Ok(())
}
fn encode_len(w: &mut Vec<u8>, mut len: usize) -> Result<()> {
if len < 128 {
w.push(len as u8);
} else {
let mut bytes = Vec::new();
while len > 0 {
bytes.push((len & 0xff) as u8);
len >>= 8;
}
bytes.reverse();
w.push(0x80 | bytes.len() as u8);
w.extend_from_slice(&bytes);
}
Ok(())
}
fn encode_unsigned(w: &mut Vec<u8>, v: &[u8]) -> Result<()> {
w.push(TAG_INTEGER);
if leftmost_bit_set(v) {
encode_len(w, 1 + v.len())?;
w.push(0); } else {
encode_len(w, v.len())?;
}
w.extend_from_slice(v);
Ok(())
}
fn encoded_len_len(len: usize) -> usize {
if len < 128 {
1
} else {
1 + ((usize::BITS - len.leading_zeros() + 7) / 8) as usize
}
}
fn encoded_len_unsigned(v: &[u8]) -> usize {
let payload_len =
if leftmost_bit_set(v) { 1 } else { 0 } + v.len();
1 + encoded_len_len(payload_len) + payload_len
}
fn leftmost_bit_set(v: &[u8]) -> bool {
v.get(0).map(|l| l & 0x80 == 0x80).unwrap_or(false)
}
fn not_set() -> anyhow::Error {
Error::InvalidOperation("a required value was not set".into())
.into()
}
fn unexpected_data() -> anyhow::Error {
Error::InvalidOperation("data returned has an unexpected shape".into())
.into()
}
const TAG_INTEGER: u8 = 0x02;
const TAG_SEQUENCE: u8 = 0x30;
#[cfg(test)]
mod tests {
use super::*;
quickcheck! {
fn signature_roundtrip(r: Vec<u8>, s: Vec<u8>) -> bool {
let mut r = &r[..];
while r.get(0) == Some(&0) {
r = &r[1..];
}
let mut s = &s[..];
while s.get(0) == Some(&0) {
s = &s[1..];
}
let mut buf = Vec::new();
encode_sig_r_s(&mut buf, r, s).unwrap();
let (r_, s_) = parse_sig_r_s(&buf).unwrap();
assert_eq!(r, r_);
assert_eq!(s, s_);
true
}
}
}