common_runtime/
signature.rs

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use common_primitives::{node, signatures::UnifiedSignature, utils::wrap_binary_data};
use node::EIP712Encode;
use sp_runtime::{traits::Verify, AccountId32, MultiSignature};
extern crate alloc;
use sp_core::Encode;

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

	if verify_signature(&scale_encoded) {
		return true;
	}

	match unified_signature {
		// we don't need to check the wrapped bytes for ethereum signatures but we need to check EIP-712 ones
		UnifiedSignature::Ecdsa(_) => verify_signature(&payload.encode_eip_712()),
		_ => {
			let wrapped_payload = wrap_binary_data(scale_encoded);
			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;
	/// A wrapped vec that allow different encodings for signature checks
	#[derive(Clone, Debug, Encode)]
	pub struct TestArrayWrapper(pub [u8; 12]);

	impl EIP712Encode for TestArrayWrapper {
		fn encode_eip_712(&self) -> Box<[u8]> {
			// not used in test but required to be implemented
			Vec::new().into_boxed_slice()
		}
	}

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

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

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

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

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

		let payload = b"test_payload";

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

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

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

		let payload = b"test_payload";

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

		let invalid_payload = b"fake_payload";

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

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

		let payload = b"test_payload";

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

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

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

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

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