common_runtime/
signature.rs

1use common_primitives::{node, signatures::UnifiedSignature, utils::wrap_binary_data};
2use node::EIP712Encode;
3use sp_runtime::{traits::Verify, AccountId32, MultiSignature};
4extern crate alloc;
5use crate::constants::CHAIN_ID;
6use sp_core::Encode;
7
8pub fn check_signature<P>(signature: &MultiSignature, signer: AccountId32, payload: &P) -> bool
9where
10	P: Encode + EIP712Encode,
11{
12	let unified_signature: UnifiedSignature = signature.clone().into();
13	let scale_encoded = payload.encode();
14	let verify_signature = |payload: &[u8]| unified_signature.verify(payload, &signer.clone());
15
16	if verify_signature(&scale_encoded) {
17		return true;
18	}
19
20	match unified_signature {
21		// we don't need to check the wrapped bytes for ethereum signatures but we need to check EIP-712 ones
22		UnifiedSignature::Ecdsa(_) => verify_signature(&payload.encode_eip_712(CHAIN_ID)),
23		_ => {
24			let wrapped_payload = wrap_binary_data(scale_encoded);
25			verify_signature(&wrapped_payload)
26		},
27	}
28}
29
30#[cfg(test)]
31mod tests {
32	use super::*;
33	use common_primitives::signatures::UnifiedSigner;
34	use sp_core::{ecdsa, keccak_256, sr25519, Pair};
35	use sp_runtime::traits::IdentifyAccount;
36	/// A wrapped vec that allow different encodings for signature checks
37	#[derive(Clone, Debug, Encode)]
38	pub struct TestArrayWrapper(pub [u8; 12]);
39
40	impl EIP712Encode for TestArrayWrapper {
41		fn encode_eip_712(&self, _chain_id: u32) -> Box<[u8]> {
42			// not used in test but required to be implemented
43			Vec::new().into_boxed_slice()
44		}
45	}
46
47	#[test]
48	fn test_verify_signature_with_wrapped_bytes() {
49		let (key_pair_delegator, _) = sr25519::Pair::generate();
50
51		let payload = b"test_payload";
52		let encode_add_provider_data = wrap_binary_data(payload.to_vec());
53
54		let signature: MultiSignature = key_pair_delegator.sign(&encode_add_provider_data).into();
55
56		assert!(check_signature(
57			&signature,
58			key_pair_delegator.public().into(),
59			&TestArrayWrapper(payload.clone())
60		));
61	}
62
63	#[test]
64	fn test_verify_signature_without_wrapped_bytes() {
65		let (signer, _) = sr25519::Pair::generate();
66
67		let payload = b"test_payload";
68
69		let signature: MultiSignature = signer.sign(payload.as_slice()).into();
70
71		assert!(check_signature(
72			&signature,
73			signer.public().into(),
74			&TestArrayWrapper(payload.clone())
75		));
76	}
77
78	#[test]
79	fn test_check_signature_with_invalid_signature() {
80		let (signer, _) = sr25519::Pair::generate();
81
82		let payload = b"test_payload";
83
84		let signature: MultiSignature = signer.sign(payload.as_slice()).into();
85
86		let invalid_payload = b"fake_payload";
87
88		assert!(!check_signature(
89			&signature,
90			signer.public().into(),
91			&TestArrayWrapper(invalid_payload.clone())
92		));
93	}
94
95	#[test]
96	fn test_ethereum_verify_signature_without_wrapped_bytes_should_work() {
97		let (signer, _) = ecdsa::Pair::generate();
98
99		let payload = b"test_payload";
100
101		let signature: MultiSignature =
102			signer.sign_prehashed(&keccak_256(&payload.to_vec())).into();
103		let unified_signer = UnifiedSigner::from(signer.public());
104
105		assert!(check_signature(
106			&signature,
107			unified_signer.into_account(),
108			&TestArrayWrapper(payload.clone())
109		));
110	}
111
112	#[test]
113	fn test_ethereum_verify_signature_wrapped_bytes_should_fail() {
114		let (signer, _) = ecdsa::Pair::generate();
115
116		let payload = b"test_payload";
117		let encode_add_provider_data = wrap_binary_data(payload.to_vec());
118		let signature: MultiSignature =
119			signer.sign_prehashed(&keccak_256(&encode_add_provider_data)).into();
120		let unified_signer = UnifiedSigner::from(signer.public());
121
122		assert!(!check_signature(
123			&signature,
124			unified_signer.into_account(),
125			&TestArrayWrapper(payload.clone())
126		));
127	}
128}