use crate::error::{Error, Result};
use crate::primitives::BigNumber;
fn half_order() -> BigNumber {
BigNumber::from_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0")
.expect("valid constant")
}
#[derive(Clone, PartialEq, Eq)]
pub struct Signature {
r: [u8; 32],
s: [u8; 32],
}
impl Signature {
pub fn new(r: [u8; 32], s: [u8; 32]) -> Self {
Self { r, s }
}
pub fn from_der(der: &[u8]) -> Result<Self> {
if der.len() < 8 {
return Err(Error::InvalidSignature("DER too short".to_string()));
}
if der[0] != 0x30 {
return Err(Error::InvalidSignature(
"Expected sequence tag 0x30".to_string(),
));
}
let total_len = der[1] as usize;
if der.len() < total_len + 2 {
return Err(Error::InvalidSignature("DER length mismatch".to_string()));
}
let mut pos = 2;
if der[pos] != 0x02 {
return Err(Error::InvalidSignature(
"Expected integer tag 0x02 for R".to_string(),
));
}
pos += 1;
let r_len = der[pos] as usize;
pos += 1;
if pos + r_len > der.len() {
return Err(Error::InvalidSignature("R length overflow".to_string()));
}
let r_bytes = &der[pos..pos + r_len];
pos += r_len;
if pos >= der.len() || der[pos] != 0x02 {
return Err(Error::InvalidSignature(
"Expected integer tag 0x02 for S".to_string(),
));
}
pos += 1;
if pos >= der.len() {
return Err(Error::InvalidSignature("S length missing".to_string()));
}
let s_len = der[pos] as usize;
pos += 1;
if pos + s_len > der.len() {
return Err(Error::InvalidSignature("S length overflow".to_string()));
}
let s_bytes = &der[pos..pos + s_len];
let r = Self::der_int_to_fixed(r_bytes)?;
let s = Self::der_int_to_fixed(s_bytes)?;
Ok(Self { r, s })
}
pub fn from_compact(data: &[u8; 64]) -> Result<Self> {
let mut r = [0u8; 32];
let mut s = [0u8; 32];
r.copy_from_slice(&data[..32]);
s.copy_from_slice(&data[32..]);
Ok(Self { r, s })
}
pub fn from_compact_slice(data: &[u8]) -> Result<Self> {
if data.len() != 64 {
return Err(Error::InvalidSignature(format!(
"Compact signature must be 64 bytes, got {}",
data.len()
)));
}
let mut arr = [0u8; 64];
arr.copy_from_slice(data);
Self::from_compact(&arr)
}
pub fn r(&self) -> &[u8; 32] {
&self.r
}
pub fn s(&self) -> &[u8; 32] {
&self.s
}
pub fn to_der(&self) -> Vec<u8> {
let sig = self.to_low_s();
let r_bytes = Self::fixed_to_der_int(&sig.r);
let s_bytes = Self::fixed_to_der_int(&sig.s);
let content_len = 2 + r_bytes.len() + 2 + s_bytes.len();
let mut der = Vec::with_capacity(2 + content_len);
der.push(0x30); der.push(content_len as u8);
der.push(0x02); der.push(r_bytes.len() as u8);
der.extend_from_slice(&r_bytes);
der.push(0x02); der.push(s_bytes.len() as u8);
der.extend_from_slice(&s_bytes);
der
}
pub fn to_compact(&self) -> [u8; 64] {
let mut result = [0u8; 64];
result[..32].copy_from_slice(&self.r);
result[32..].copy_from_slice(&self.s);
result
}
pub fn is_low_s(&self) -> bool {
let s = BigNumber::from_bytes_be(&self.s);
let half = half_order();
s <= half
}
pub fn to_low_s(&self) -> Signature {
if self.is_low_s() {
return self.clone();
}
let s = BigNumber::from_bytes_be(&self.s);
let n = BigNumber::secp256k1_order();
let new_s = n.sub(&s);
let s_bytes = new_s.to_bytes_be(32);
let mut new_s_arr = [0u8; 32];
new_s_arr.copy_from_slice(&s_bytes);
Signature {
r: self.r,
s: new_s_arr,
}
}
pub fn verify(&self, msg_hash: &[u8; 32], public_key: &super::PublicKey) -> bool {
super::verify(msg_hash, self, public_key)
}
fn der_int_to_fixed(bytes: &[u8]) -> Result<[u8; 32]> {
let bytes = if !bytes.is_empty() && bytes[0] == 0x00 {
&bytes[1..]
} else {
bytes
};
if bytes.len() > 32 {
return Err(Error::InvalidSignature(
"Integer component too large".to_string(),
));
}
let mut result = [0u8; 32];
let start = 32 - bytes.len();
result[start..].copy_from_slice(bytes);
Ok(result)
}
fn fixed_to_der_int(bytes: &[u8; 32]) -> Vec<u8> {
let start = bytes.iter().position(|&b| b != 0).unwrap_or(31);
let trimmed = &bytes[start..];
if trimmed.is_empty() {
vec![0x00]
} else if trimmed[0] & 0x80 != 0 {
let mut result = vec![0x00];
result.extend_from_slice(trimmed);
result
} else {
trimmed.to_vec()
}
}
}
impl std::fmt::Debug for Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Signature")
.field("r", &hex::encode(self.r))
.field("s", &hex::encode(self.s))
.finish()
}
}
impl std::fmt::Display for Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", hex::encode(self.to_der()))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_signature_new() {
let r = [1u8; 32];
let s = [2u8; 32];
let sig = Signature::new(r, s);
assert_eq!(sig.r(), &r);
assert_eq!(sig.s(), &s);
}
#[test]
fn test_signature_compact_roundtrip() {
let mut r = [0u8; 32];
let mut s = [0u8; 32];
r[31] = 0x42;
s[31] = 0x43;
let sig = Signature::new(r, s);
let compact = sig.to_compact();
let recovered = Signature::from_compact(&compact).unwrap();
assert_eq!(sig.r(), recovered.r());
assert_eq!(sig.s(), recovered.s());
}
#[test]
fn test_signature_der_roundtrip() {
let r = hex::decode("b4d19cdc7e93c36f3b5d6f7e8a2a6c9e3c8f9a1b2c3d4e5f6a7b8c9d0e1f2a3b")
.unwrap();
let s = hex::decode("0f8e9d0c1b2a3948576a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e")
.unwrap();
let mut r_arr = [0u8; 32];
let mut s_arr = [0u8; 32];
r_arr.copy_from_slice(&r);
s_arr.copy_from_slice(&s);
let sig = Signature::new(r_arr, s_arr);
let der = sig.to_der();
let recovered = Signature::from_der(&der).unwrap();
assert_eq!(sig.r(), recovered.r());
assert!(sig.s() == recovered.s() || sig.to_low_s().s() == recovered.s());
}
#[test]
fn test_der_parsing() {
let der = hex::decode(
"3045022100b4d19cdc7e93c36f3b5d6f7e8a2a6c9e3c8f9a1b2c3d4e5f6a7b8c9d0e1f2a3b02200f8e9d0c1b2a3948576a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e",
)
.unwrap();
let sig = Signature::from_der(&der).unwrap();
assert_eq!(
hex::encode(sig.r()),
"b4d19cdc7e93c36f3b5d6f7e8a2a6c9e3c8f9a1b2c3d4e5f6a7b8c9d0e1f2a3b"
);
assert_eq!(
hex::encode(sig.s()),
"0f8e9d0c1b2a3948576a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e"
);
}
#[test]
fn test_is_low_s() {
let r = [0u8; 32];
let mut s_low = [0u8; 32];
s_low[31] = 0x01;
let sig_low = Signature::new(r, s_low);
assert!(sig_low.is_low_s());
let s_high =
hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140")
.unwrap();
let mut s_high_arr = [0u8; 32];
s_high_arr.copy_from_slice(&s_high);
let sig_high = Signature::new(r, s_high_arr);
assert!(!sig_high.is_low_s());
}
#[test]
fn test_to_low_s() {
let r = [0u8; 32];
let s_high =
hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140")
.unwrap();
let mut s_high_arr = [0u8; 32];
s_high_arr.copy_from_slice(&s_high);
let sig_high = Signature::new(r, s_high_arr);
assert!(!sig_high.is_low_s());
let sig_low = sig_high.to_low_s();
assert!(sig_low.is_low_s());
let mut s_already_low = [0u8; 32];
s_already_low[31] = 0x01;
let sig = Signature::new(r, s_already_low);
let sig_converted = sig.to_low_s();
assert_eq!(sig.s(), sig_converted.s());
}
#[test]
fn test_der_int_to_fixed_with_leading_zero() {
let bytes = vec![0x00, 0x80, 0x00, 0x00];
let fixed = Signature::der_int_to_fixed(&bytes).unwrap();
assert_eq!(&fixed[29..], &[0x80, 0x00, 0x00]);
}
#[test]
fn test_fixed_to_der_int_adds_leading_zero() {
let mut bytes = [0u8; 32];
bytes[0] = 0x80;
let der = Signature::fixed_to_der_int(&bytes);
assert_eq!(der[0], 0x00);
assert_eq!(der[1], 0x80);
}
#[test]
fn test_signature_from_compact_slice() {
let data = [0x42u8; 64];
let sig = Signature::from_compact_slice(&data).unwrap();
assert_eq!(sig.r()[0], 0x42);
assert_eq!(sig.s()[0], 0x42);
assert!(Signature::from_compact_slice(&[0u8; 63]).is_err());
assert!(Signature::from_compact_slice(&[0u8; 65]).is_err());
}
#[test]
fn test_all_zero_signature_fails_verification() {
let sig = Signature::from_compact_slice(&[0u8; 64]).unwrap();
assert_eq!(sig.r(), &[0u8; 32]);
assert_eq!(sig.s(), &[0u8; 32]);
use crate::primitives::hash::sha256;
use crate::primitives::PrivateKey;
let pubkey = PrivateKey::random().public_key();
let msg_hash = sha256(b"test");
assert!(!pubkey.verify(&msg_hash, &sig));
}
#[test]
fn test_signature_r_at_curve_order() {
let r = hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
.unwrap();
let mut r_arr = [0u8; 32];
r_arr.copy_from_slice(&r);
let mut s_arr = [0u8; 32];
s_arr[31] = 1;
let sig = Signature::new(r_arr, s_arr);
use crate::primitives::hash::sha256;
use crate::primitives::PrivateKey;
let pubkey = PrivateKey::random().public_key();
let msg_hash = sha256(b"test");
assert!(!pubkey.verify(&msg_hash, &sig));
}
#[test]
fn test_signature_s_at_curve_order() {
let s = hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")
.unwrap();
let mut r_arr = [0u8; 32];
r_arr[31] = 1;
let mut s_arr = [0u8; 32];
s_arr.copy_from_slice(&s);
let sig = Signature::new(r_arr, s_arr);
use crate::primitives::hash::sha256;
use crate::primitives::PrivateKey;
let pubkey = PrivateKey::random().public_key();
let msg_hash = sha256(b"test");
assert!(!pubkey.verify(&msg_hash, &sig));
}
}