pallet_evm_precompile_sha3fips/
lib.rs1#![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
33pub trait WeightInfo {
35 fn sha3_fips_256(preimage_len: u32) -> Weight;
36 fn sha3_fips_512(preimage_len: u32) -> Weight;
37}
38
39impl WeightInfo for () {
41 fn sha3_fips_256(n: u32) -> Weight {
43 Weight::from_parts(516_915, 0)
48 .saturating_add(Weight::from_parts(0, 0))
49 .saturating_add(Weight::from_parts(2_019, 0).saturating_mul(n.into()))
51 }
52 fn sha3_fips_512(n: u32) -> Weight {
54 Weight::from_parts(441_854, 0)
59 .saturating_add(Weight::from_parts(0, 0))
60 .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}