raiden-primitives 0.1.0

Raiden Network implementation in Rust
Documentation
use once_cell::sync::Lazy;
use secp256k1::{
	ecdsa::{
		RecoverableSignature,
		RecoveryId,
	},
	All,
	Message,
	Secp256k1,
};
use web3::{
	ethabi::Address,
	signing::RecoveryError,
	types::Bytes,
};

/// Secp256k1 instance for recovering public key
static CONTEXT: Lazy<Secp256k1<All>> = Lazy::new(Secp256k1::new);

/// Hash data in ethereum-compatible format.
pub fn hash_data(data: &[u8]) -> [u8; 32] {
	let prefix_msg = "\x19Ethereum Signed Message:\n";
	let len_str = data.len().to_string();
	let mut res: Vec<u8> = Vec::new();
	res.append(&mut prefix_msg.as_bytes().to_vec());
	res.append(&mut len_str.as_bytes().to_vec());
	res.append(&mut data.to_vec());

	web3::signing::keccak256(&res)
}

/// Recover address from data and signature.
pub fn recover(data: &[u8], signature: &[u8]) -> Result<Address, RecoveryError> {
	let data_hash = hash_data(data);
	let recovery_id = signature[64] as i32 - 27;
	web3::signing::recover(&data_hash, &signature[..64], recovery_id)
}

/// Recover public key from data and signature.
pub fn recover_pub_key(data: &[u8], signature: &[u8]) -> Result<Bytes, RecoveryError> {
	let data_hash = hash_data(data);
	let recovery_id = signature[64] as i32 - 27;
	let message = Message::from_slice(&data_hash).map_err(|_| RecoveryError::InvalidMessage)?;
	let recovery_id =
		RecoveryId::from_i32(recovery_id).map_err(|_| RecoveryError::InvalidSignature)?;
	let signature = RecoverableSignature::from_compact(&signature[..64], recovery_id)
		.map_err(|_| RecoveryError::InvalidSignature)?;
	let public_key = CONTEXT
		.recover_ecdsa(&message, &signature)
		.map_err(|_| RecoveryError::InvalidSignature)?;

	let public_key: [u8; 65] = public_key.serialize_uncompressed();
	Ok(Bytes(public_key[1..].to_vec()))
}