ovr_evm_precompile_ed25519/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2// This file is part of Frontier.
3//
4// Copyright (c) 2020 Parity Technologies (UK) Ltd.
5//
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18extern crate alloc;
19
20use alloc::vec::Vec;
21use core::convert::TryFrom;
22use ed25519_dalek::{PublicKey, Signature, Verifier};
23use fp_evm::{ExitError, ExitSucceed, LinearCostPrecompile, PrecompileFailure};
24
25pub struct Ed25519Verify;
26
27impl LinearCostPrecompile for Ed25519Verify {
28	const BASE: u64 = 15;
29	const WORD: u64 = 3;
30
31	fn execute(input: &[u8], _: u64) -> Result<(ExitSucceed, Vec<u8>), PrecompileFailure> {
32		if input.len() < 128 {
33			return Err(PrecompileFailure::Error {
34				exit_status: ExitError::Other("input must contain 128 bytes".into()),
35			});
36		};
37
38		let mut i = [0u8; 128];
39		i[..128].copy_from_slice(&input[..128]);
40
41		let mut buf = [0u8; 4];
42
43		let msg = &i[0..32];
44		let pk = PublicKey::from_bytes(&i[32..64]).map_err(|_| PrecompileFailure::Error {
45			exit_status: ExitError::Other("Public key recover failed".into()),
46		})?;
47		let sig = Signature::try_from(&i[64..128]).map_err(|_| PrecompileFailure::Error {
48			exit_status: ExitError::Other("Signature recover failed".into()),
49		})?;
50
51		// https://docs.rs/rust-crypto/0.2.36/crypto/ed25519/fn.verify.html
52		if pk.verify(msg, &sig).is_ok() {
53			buf[3] = 0u8;
54		} else {
55			buf[3] = 1u8;
56		};
57
58		Ok((ExitSucceed::Returned, buf.to_vec()))
59	}
60}
61
62#[cfg(test)]
63mod tests {
64	use super::*;
65	use ed25519_dalek::{Keypair, SecretKey, Signer};
66
67	#[test]
68	fn test_empty_input() -> Result<(), PrecompileFailure> {
69		let input: [u8; 0] = [];
70		let cost: u64 = 1;
71
72		match Ed25519Verify::execute(&input, cost) {
73			Ok((_, _)) => {
74				panic!("Test not expected to pass");
75			}
76			Err(e) => {
77				assert_eq!(
78					e,
79					PrecompileFailure::Error {
80						exit_status: ExitError::Other("input must contain 128 bytes".into())
81					}
82				);
83				Ok(())
84			}
85		}
86	}
87
88	#[test]
89	fn test_verify() -> Result<(), PrecompileFailure> {
90		let secret_key_bytes: [u8; ed25519_dalek::SECRET_KEY_LENGTH] = [
91			157, 097, 177, 157, 239, 253, 090, 096, 186, 132, 074, 244, 146, 236, 044, 196, 068,
92			073, 197, 105, 123, 050, 105, 025, 112, 059, 172, 003, 028, 174, 127, 096,
93		];
94
95		let secret_key =
96			SecretKey::from_bytes(&secret_key_bytes).expect("Failed to generate secretkey");
97		let public_key = (&secret_key).into();
98
99		let keypair = Keypair {
100			secret: secret_key,
101			public: public_key,
102		};
103
104		let msg: &[u8] = b"abcdefghijklmnopqrstuvwxyz123456";
105		assert_eq!(msg.len(), 32);
106		let signature = keypair.sign(msg);
107
108		// input is:
109		// 1) message (32 bytes)
110		// 2) pubkey (32 bytes)
111		// 3) signature (64 bytes)
112		let mut input: Vec<u8> = Vec::with_capacity(128);
113		input.extend_from_slice(msg);
114		input.extend_from_slice(&public_key.to_bytes());
115		input.extend_from_slice(&signature.to_bytes());
116		assert_eq!(input.len(), 128);
117
118		let cost: u64 = 1;
119
120		match Ed25519Verify::execute(&input, cost) {
121			Ok((_, output)) => {
122				assert_eq!(output.len(), 4);
123				assert_eq!(output[0], 0u8);
124				assert_eq!(output[1], 0u8);
125				assert_eq!(output[2], 0u8);
126				assert_eq!(output[3], 0u8);
127			}
128			Err(e) => {
129				return Err(e);
130			}
131		};
132
133		// try again with a different message
134		let msg: &[u8] = b"BAD_MESSAGE_mnopqrstuvwxyz123456";
135
136		let mut input: Vec<u8> = Vec::with_capacity(128);
137		input.extend_from_slice(msg);
138		input.extend_from_slice(&public_key.to_bytes());
139		input.extend_from_slice(&signature.to_bytes());
140		assert_eq!(input.len(), 128);
141
142		match Ed25519Verify::execute(&input, cost) {
143			Ok((_, output)) => {
144				assert_eq!(output.len(), 4);
145				assert_eq!(output[0], 0u8);
146				assert_eq!(output[1], 0u8);
147				assert_eq!(output[2], 0u8);
148				assert_eq!(output[3], 1u8); // non-zero indicates error (in our case, 1)
149			}
150			Err(e) => {
151				return Err(e);
152			}
153		};
154
155		Ok(())
156	}
157}