78 lines
1.8 KiB
Rust
78 lines
1.8 KiB
Rust
/// ECDSA signatures:
|
|
/// conversion from/to byte vectors.
|
|
/// from/to v, r, s components.
|
|
|
|
use ethereum_types::H256;
|
|
use ethabi;
|
|
|
|
use error::Error;
|
|
|
|
pub const SIGNATURE_LENGTH: usize = 65;
|
|
|
|
/// an ECDSA signature consisting of `v`, `r` and `s`
|
|
#[derive(PartialEq, Debug)]
|
|
pub struct Signature {
|
|
pub v: u8,
|
|
pub r: H256,
|
|
pub s: H256,
|
|
}
|
|
|
|
impl Signature {
|
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
|
|
if bytes.len() != SIGNATURE_LENGTH {
|
|
bail!("`bytes`.len() must be {}", SIGNATURE_LENGTH);
|
|
}
|
|
|
|
Ok(Self {
|
|
v: bytes[64],
|
|
r: bytes[0..32].into(),
|
|
s: bytes[32..64].into(),
|
|
})
|
|
}
|
|
|
|
pub fn to_bytes(&self) -> Vec<u8> {
|
|
let mut result = vec![0u8; SIGNATURE_LENGTH];
|
|
result[0..32].copy_from_slice(&self.r.0[..]);
|
|
result[32..64].copy_from_slice(&self.s.0[..]);
|
|
result[64] = self.v;
|
|
return result;
|
|
}
|
|
|
|
pub fn to_payload(&self) -> Vec<u8> {
|
|
ethabi::encode(&[ethabi::Token::Bytes(self.to_bytes())])
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use quickcheck::TestResult;
|
|
use super::*;
|
|
|
|
quickcheck! {
|
|
fn quickcheck_signature_roundtrips(v: u8, r_raw: Vec<u8>, s_raw: Vec<u8>) -> TestResult {
|
|
if r_raw.len() != 32 || s_raw.len() != 32 {
|
|
return TestResult::discard();
|
|
}
|
|
|
|
let r: H256 = r_raw.as_slice().into();
|
|
let s: H256 = s_raw.as_slice().into();
|
|
let signature = Signature { v, r, s };
|
|
assert_eq!(v, signature.v);
|
|
assert_eq!(r, signature.r);
|
|
assert_eq!(s, signature.s);
|
|
|
|
let bytes = signature.to_bytes();
|
|
|
|
assert_eq!(signature, Signature::from_bytes(bytes.as_slice()).unwrap());
|
|
|
|
let payload = signature.to_payload();
|
|
let mut tokens = ethabi::decode(&[ethabi::ParamType::Bytes], payload.as_slice())
|
|
.unwrap();
|
|
let decoded = tokens.pop().unwrap().to_bytes().unwrap();
|
|
assert_eq!(signature, Signature::from_bytes(decoded.as_slice()).unwrap());
|
|
|
|
TestResult::passed()
|
|
}
|
|
}
|
|
}
|