1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
use common_primitives::{signatures::UnifiedSignature, utils::wrap_binary_data};
use sp_runtime::{traits::Verify, AccountId32, MultiSignature};
use sp_std::vec::Vec;

pub fn check_signature(signature: &MultiSignature, signer: AccountId32, payload: Vec<u8>) -> bool {
	let unified_signature: UnifiedSignature = signature.clone().into();
	let verify_signature =
		|payload: &[u8]| unified_signature.verify(payload, &signer.clone().into());

	if verify_signature(&payload) {
		return true;
	}

	match unified_signature {
		// we don't need to check the wrapped bytes for ethereum signatures
		UnifiedSignature::Ecdsa(_) => false,
		_ => {
			let wrapped_payload = wrap_binary_data(payload);
			verify_signature(&wrapped_payload)
		},
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use common_primitives::signatures::UnifiedSigner;
	use sp_core::{ecdsa, keccak_256, sr25519, Pair};
	use sp_runtime::traits::IdentifyAccount;

	#[test]
	fn test_verify_signature_with_wrapped_bytes() {
		let (key_pair_delegator, _) = sr25519::Pair::generate();

		let payload = b"test_payload".to_vec();
		let encode_add_provider_data = wrap_binary_data(payload.clone());

		let signature: MultiSignature = key_pair_delegator.sign(&encode_add_provider_data).into();

		assert!(check_signature(&signature, key_pair_delegator.public().into(), payload.clone()));
	}

	#[test]
	fn test_verify_signature_without_wrapped_bytes() {
		let (signer, _) = sr25519::Pair::generate();

		let payload = b"test_payload".to_vec();

		let signature: MultiSignature = signer.sign(&payload).into();

		assert!(check_signature(&signature, signer.public().into(), payload));
	}

	#[test]
	fn test_check_signature_with_invalid_signature() {
		let (signer, _) = sr25519::Pair::generate();

		let payload = b"test_payload".to_vec();

		let signature: MultiSignature = signer.sign(&payload).into();

		let invalid_payload = b"invalid_payload".to_vec();

		assert!(!check_signature(&signature, signer.public().into(), invalid_payload));
	}

	#[test]
	fn test_ethereum_verify_signature_without_wrapped_bytes_should_work() {
		let (signer, _) = ecdsa::Pair::generate();

		let payload = b"test_payload".to_vec();

		let signature: MultiSignature = signer.sign_prehashed(&keccak_256(&payload)).into();
		let unified_signer = UnifiedSigner::from(signer.public());

		assert!(check_signature(&signature, unified_signer.into_account(), payload));
	}

	#[test]
	fn test_ethereum_verify_signature_wrapped_bytes_should_fail() {
		let (signer, _) = ecdsa::Pair::generate();

		let payload = b"test_payload".to_vec();
		let encode_add_provider_data = wrap_binary_data(payload.clone());
		let signature: MultiSignature =
			signer.sign_prehashed(&keccak_256(&encode_add_provider_data)).into();
		let unified_signer = UnifiedSigner::from(signer.public());

		assert_eq!(check_signature(&signature, unified_signer.into_account(), payload), false);
	}
}