pallet_evm_precompile_sha3fips/
lib.rs

1// This file is part of Frontier.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
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
18#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(unused_crate_dependencies)]
20
21extern crate alloc;
22
23use alloc::vec::Vec;
24use core::marker::PhantomData;
25
26use fp_evm::{
27	ExitSucceed, Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput,
28	PrecompileResult,
29};
30use frame_support::weights::Weight;
31use pallet_evm::GasWeightMapping;
32
33// Weight provider trait for these precompiles. Implementations should return Substrate Weights.
34pub trait WeightInfo {
35	fn sha3_fips_256(preimage_len: u32) -> Weight;
36	fn sha3_fips_512(preimage_len: u32) -> Weight;
37}
38
39// Default weights from benchmarks run on a laptop, do not use them in production !
40impl WeightInfo for () {
41	/// The range of component `n` is `[1, 4096]`.
42	fn sha3_fips_256(n: u32) -> Weight {
43		// Proof Size summary in bytes:
44		//  Measured:  `0`
45		//  Estimated: `0`
46		// Minimum execution time: 0_000 picoseconds.
47		Weight::from_parts(516_915, 0)
48			.saturating_add(Weight::from_parts(0, 0))
49			// Standard Error: 13
50			.saturating_add(Weight::from_parts(2_019, 0).saturating_mul(n.into()))
51	}
52	/// The range of component `n` is `[1, 4096]`.
53	fn sha3_fips_512(n: u32) -> Weight {
54		// Proof Size summary in bytes:
55		//  Measured:  `0`
56		//  Estimated: `0`
57		// Minimum execution time: 0_000 picoseconds.
58		Weight::from_parts(441_854, 0)
59			.saturating_add(Weight::from_parts(0, 0))
60			// Standard Error: 14
61			.saturating_add(Weight::from_parts(3_678, 0).saturating_mul(n.into()))
62	}
63}
64
65pub struct Sha3FIPS256<R, WI>(PhantomData<(R, WI)>);
66
67impl<R, WI> Precompile for Sha3FIPS256<R, WI>
68where
69	R: pallet_evm::Config,
70	WI: WeightInfo,
71{
72	fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
73		let input_len = handle.input().len() as u32;
74		let weight = WI::sha3_fips_256(input_len);
75		let gas = R::GasWeightMapping::weight_to_gas(weight);
76		handle.record_cost(gas)?;
77
78		let (exit_status, output) = Self::execute_inner(handle.input(), gas)?;
79		Ok(PrecompileOutput {
80			exit_status,
81			output,
82		})
83	}
84}
85
86impl<R, WI> Sha3FIPS256<R, WI>
87where
88	WI: WeightInfo,
89{
90	pub fn execute_inner(
91		input: &[u8],
92		_: u64,
93	) -> Result<(ExitSucceed, Vec<u8>), PrecompileFailure> {
94		use tiny_keccak::Hasher;
95		let mut output = [0; 32];
96		let mut sha3 = tiny_keccak::Sha3::v256();
97		sha3.update(input);
98		sha3.finalize(&mut output);
99		Ok((ExitSucceed::Returned, output.to_vec()))
100	}
101}
102
103pub struct Sha3FIPS512<R, WI>(PhantomData<(R, WI)>);
104
105impl<R, WI> Precompile for Sha3FIPS512<R, WI>
106where
107	R: pallet_evm::Config,
108	WI: WeightInfo,
109{
110	fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult {
111		let input_len = handle.input().len() as u32;
112		let weight = WI::sha3_fips_512(input_len);
113		let gas = R::GasWeightMapping::weight_to_gas(weight);
114		handle.record_cost(gas)?;
115
116		let (exit_status, output) = Self::execute_inner(handle.input(), gas)?;
117		Ok(PrecompileOutput {
118			exit_status,
119			output,
120		})
121	}
122}
123
124impl<R, WI> Sha3FIPS512<R, WI>
125where
126	WI: WeightInfo,
127{
128	pub fn execute_inner(
129		input: &[u8],
130		_: u64,
131	) -> Result<(ExitSucceed, Vec<u8>), PrecompileFailure> {
132		use tiny_keccak::Hasher;
133		let mut output = [0; 64];
134		let mut sha3 = tiny_keccak::Sha3::v512();
135		sha3.update(input);
136		sha3.finalize(&mut output);
137		Ok((ExitSucceed::Returned, output.to_vec()))
138	}
139}
140
141#[cfg(test)]
142mod tests {
143	use super::*;
144
145	#[test]
146	fn test_empty_input() -> Result<(), PrecompileFailure> {
147		let input: [u8; 0] = [];
148		let expected = b"\
149			\xa7\xff\xc6\xf8\xbf\x1e\xd7\x66\x51\xc1\x47\x56\xa0\x61\xd6\x62\
150			\xf5\x80\xff\x4d\xe4\x3b\x49\xfa\x82\xd8\x0a\x4b\x80\xf8\x43\x4a\
151		";
152
153		let cost: u64 = 1;
154
155		match Sha3FIPS256::<(), ()>::execute_inner(&input, cost) {
156			Ok((_, out)) => {
157				assert_eq!(out, expected);
158				Ok(())
159			}
160			Err(e) => {
161				panic!("Test not expected to fail: {e:?}");
162			}
163		}
164	}
165
166	#[test]
167	fn hello_sha3_256() -> Result<(), PrecompileFailure> {
168		let input = b"hello";
169		let expected = b"\
170			\x33\x38\xbe\x69\x4f\x50\xc5\xf3\x38\x81\x49\x86\xcd\xf0\x68\x64\
171			\x53\xa8\x88\xb8\x4f\x42\x4d\x79\x2a\xf4\xb9\x20\x23\x98\xf3\x92\
172		";
173
174		let cost: u64 = 1;
175
176		match Sha3FIPS256::<(), ()>::execute_inner(input, cost) {
177			Ok((_, out)) => {
178				assert_eq!(out, expected);
179				Ok(())
180			}
181			Err(e) => {
182				panic!("Test not expected to fail: {e:?}");
183			}
184		}
185	}
186
187	#[test]
188	fn long_string_sha3_256() -> Result<(), PrecompileFailure> {
189		let input = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
190		let expected = b"\
191			\xbd\xe3\xf2\x69\x17\x5e\x1d\xcd\xa1\x38\x48\x27\x8a\xa6\x04\x6b\
192			\xd6\x43\xce\xa8\x5b\x84\xc8\xb8\xbb\x80\x95\x2e\x70\xb6\xea\xe0\
193		";
194
195		let cost: u64 = 1;
196
197		match Sha3FIPS256::<(), ()>::execute_inner(input, cost) {
198			Ok((_, out)) => {
199				assert_eq!(out, expected);
200				Ok(())
201			}
202			Err(e) => {
203				panic!("Test not expected to fail: {e:?}");
204			}
205		}
206	}
207
208	#[test]
209	fn long_string_sha3_512() -> Result<(), PrecompileFailure> {
210		let input = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
211		let expected = b"\
212			\xf3\x2a\x94\x23\x55\x13\x51\xdf\x0a\x07\xc0\xb8\xc2\x0e\xb9\x72\
213			\x36\x7c\x39\x8d\x61\x06\x60\x38\xe1\x69\x86\x44\x8e\xbf\xbc\x3d\
214			\x15\xed\xe0\xed\x36\x93\xe3\x90\x5e\x9a\x8c\x60\x1d\x9d\x00\x2a\
215			\x06\x85\x3b\x97\x97\xef\x9a\xb1\x0c\xbd\xe1\x00\x9c\x7d\x0f\x09\
216		";
217
218		let cost: u64 = 1;
219
220		match Sha3FIPS512::<(), ()>::execute_inner(input, cost) {
221			Ok((_, out)) => {
222				assert_eq!(out, expected);
223				Ok(())
224			}
225			Err(e) => {
226				panic!("Test not expected to fail: {e:?}");
227			}
228		}
229	}
230}