Implement ToString and FromStr traits for SignatureData

This commit is contained in:
silverpill 2022-04-20 09:04:56 +00:00
parent bffe3bbe7d
commit fc60bb78f2

View file

@ -1,3 +1,4 @@
use std::convert::TryInto;
use std::str::FromStr; use std::str::FromStr;
use secp256k1::{Error as KeyError, SecretKey, rand::rngs::OsRng}; use secp256k1::{Error as KeyError, SecretKey, rand::rngs::OsRng};
@ -46,11 +47,40 @@ pub enum SignatureError {
RecoveryError(#[from] RecoveryError), RecoveryError(#[from] RecoveryError),
} }
impl ToString for SignatureData {
fn to_string(&self) -> String {
let mut bytes = Vec::with_capacity(65);
bytes.extend_from_slice(&self.r);
bytes.extend_from_slice(&self.s);
let v: u8 = self.v.try_into()
.expect("signature recovery in electrum notation always fits in a u8");
bytes.push(v);
hex::encode(bytes)
}
}
impl FromStr for SignatureData {
type Err = SignatureError;
fn from_str(value: &str) -> Result<Self, Self::Err> {
let mut bytes = [0u8; 65];
hex::decode_to_slice(value, &mut bytes)
.map_err(|_| Self::Err::InvalidSignature)?;
let v = bytes[64].into();
let r = bytes[0..32].try_into()
.map_err(|_| Self::Err::InvalidSignature)?;
let s = bytes[32..64].try_into()
.map_err(|_| Self::Err::InvalidSignature)?;
let signature_data = Self { v, r, s };
Ok(signature_data)
}
}
fn prepare_message(message: &[u8]) -> [u8; 32] { fn prepare_message(message: &[u8]) -> [u8; 32] {
let eip_191_message = [ let eip_191_message = [
"\x19Ethereum Signed Message:\n".as_bytes(), "\x19Ethereum Signed Message:\n".as_bytes(),
message.len().to_string().as_bytes(), message.len().to_string().as_bytes(),
&message, message,
].concat(); ].concat();
let eip_191_message_hash = keccak256(&eip_191_message); let eip_191_message_hash = keccak256(&eip_191_message);
eip_191_message_hash eip_191_message_hash
@ -128,6 +158,33 @@ pub fn sign_contract_call(
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn test_signature_string_conversion() {
let v = 28;
let r: [u8; 32] = hex::decode("b91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd")
.unwrap().try_into().unwrap();
let s: [u8; 32] = hex::decode("6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a029")
.unwrap().try_into().unwrap();
let expected_signature =
"b91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a0291c";
let signature_data = SignatureData { v, r, s };
let signature_str = signature_data.to_string();
assert_eq!(signature_str, expected_signature);
let parsed = signature_str.parse::<SignatureData>().unwrap();
assert_eq!(parsed.v, v);
assert_eq!(parsed.r, r);
assert_eq!(parsed.s, s);
}
#[test]
fn test_signature_from_string_with_0x_prefix() {
let signature_str = "0xb91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a0291c";
let result = signature_str.parse::<SignatureData>();
assert_eq!(result.is_err(), true);
}
#[test] #[test]
fn test_sign_message() { fn test_sign_message() {
let signing_key = generate_ecdsa_key(); let signing_key = generate_ecdsa_key();