├── .cargo └── config ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── blake2 ├── Cargo.toml └── src │ └── lib.rs ├── bls12pairing ├── Cargo.toml ├── README.md └── src │ └── lib.rs ├── chisel.yml ├── circle.yml ├── ecadd ├── Cargo.toml └── src │ └── lib.rs ├── ecmul ├── Cargo.toml └── src │ └── lib.rs ├── ecpairing ├── Cargo.toml └── src │ └── lib.rs ├── ecrecover ├── Cargo.toml └── src │ └── lib.rs ├── ed25519 ├── Cargo.toml ├── README.md └── src │ ├── lib.rs │ └── verify.rs ├── eip1962 ├── Cargo.toml └── src │ └── lib.rs ├── identity ├── Cargo.toml └── src │ └── lib.rs ├── keccak256 ├── Cargo.toml └── src │ └── lib.rs ├── modexp ├── Cargo.toml └── src │ └── lib.rs ├── ripemd160 ├── Cargo.toml └── src │ └── lib.rs ├── sha1 ├── Cargo.toml ├── README.md └── src │ └── lib.rs └── sha256 ├── Cargo.toml └── src └── lib.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | 3 | members = [ 4 | "blake2", 5 | "bls12pairing", 6 | "ecadd", 7 | "ecmul", 8 | "ecpairing", 9 | "ecrecover", 10 | "ed25519", 11 | "eip1962", 12 | "identity", 13 | "keccak256", 14 | "modexp", 15 | "ripemd160", 16 | "sha1", 17 | "sha256", 18 | ] 19 | 20 | [profile.release] 21 | lto = true 22 | opt-level = 'z' 23 | debug = false 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ewasm-precompiles 2 | 3 | Implementation of the Ethereum precompiled contracts in Rust. 4 | 5 | ## Build 6 | 7 | Each of them be compiled using in their appropriate directory: 8 | 9 | ```sh 10 | $ cargo build --release 11 | ``` 12 | 13 | The resulting files must be processed via [chisel](https://github.com/wasmx/wasm-chisel) to have the proper imports. 14 | 15 | This can be done via: 16 | 17 | ```sh 18 | $ chisel run 19 | ``` 20 | 21 | ## Author(s) 22 | 23 | Alex Beregszaszi 24 | 25 | ## License 26 | 27 | Apache 2.0 28 | -------------------------------------------------------------------------------- /blake2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-blake2" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum Blake2 precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | blake2 = "0.7" 13 | ewasm_api = "0.9" 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /blake2/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate blake2; 2 | extern crate ewasm_api; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | use blake2::{Blake2b, Digest}; 8 | 9 | let length = ewasm_api::calldata_size(); 10 | 11 | // charge a base fee plus a word fee for every 256-bit word 12 | let base_fee = 60; 13 | let word_fee = 12; 14 | let total_cost = base_fee + ((length + 31) / 32) * word_fee; 15 | 16 | ewasm_api::consume_gas(total_cost as u64); 17 | 18 | let data = ewasm_api::calldata_acquire(); 19 | 20 | let mut hasher = Blake2b::default(); 21 | hasher.input(&data); 22 | let hash = hasher.result(); 23 | 24 | ewasm_api::finish_data(&hash) 25 | } 26 | -------------------------------------------------------------------------------- /bls12pairing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-bls12pairing" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum BLS12-381 pairing precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | ethereum-bls12 = { git = "https://github.com/ewasm/ethereum-bls12.rs", tag = "0.1.2" } 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /bls12pairing/README.md: -------------------------------------------------------------------------------- 1 | # bls12pairing 2 | 3 | This is the precompile for enabling pairing on the BLS12-381 curve ([see this for a description](https://github.com/zcash/zips/blob/master/protocol/sapling.pdf)). 4 | 5 | It requires rustc >=1.27 to build. -------------------------------------------------------------------------------- /bls12pairing/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ethereum_bls12; 2 | extern crate ewasm_api; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | let length = ewasm_api::calldata_size(); 8 | 9 | // NOTE: this validation will also be done by bls12_pairing 10 | 11 | if length % 144 != 0 { 12 | ewasm_api::revert(); 13 | } 14 | 15 | // charge a base fee plus a word fee for every element 16 | let base_fee = 100000; 17 | let element_fee = 80000; 18 | let total_cost = base_fee + (length / 144) * element_fee; 19 | 20 | ewasm_api::consume_gas(total_cost as u64); 21 | 22 | let input = ewasm_api::calldata_acquire(); 23 | 24 | let mut output = [0u8; 32]; 25 | match ethereum_bls12::bls12_pairing(&input[..], &mut output) { 26 | Ok(_) => { 27 | ewasm_api::finish_data(&output); 28 | } 29 | Err(_) => { 30 | ewasm_api::revert(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /chisel.yml: -------------------------------------------------------------------------------- 1 | blake2: 2 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_blake2.wasm" 3 | remapimports: 4 | preset: "ewasm" 5 | trimexports: 6 | preset: "ewasm" 7 | verifyimports: 8 | preset: "ewasm" 9 | verifyexports: 10 | preset: "ewasm" 11 | snip: 12 | preset: "ewasm" 13 | repack: 14 | preset: "ewasm" 15 | 16 | bls12pairing: 17 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_bls12pairing.wasm" 18 | remapimports: 19 | preset: "ewasm" 20 | trimexports: 21 | preset: "ewasm" 22 | verifyimports: 23 | preset: "ewasm" 24 | verifyexports: 25 | preset: "ewasm" 26 | snip: 27 | preset: "ewasm" 28 | repack: 29 | preset: "ewasm" 30 | 31 | ecadd: 32 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_ecadd.wasm" 33 | remapimports: 34 | preset: "ewasm" 35 | trimexports: 36 | preset: "ewasm" 37 | verifyimports: 38 | preset: "ewasm" 39 | verifyexports: 40 | preset: "ewasm" 41 | snip: 42 | preset: "ewasm" 43 | repack: 44 | preset: "ewasm" 45 | 46 | ecmul: 47 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_ecmul.wasm" 48 | remapimports: 49 | preset: "ewasm" 50 | trimexports: 51 | preset: "ewasm" 52 | verifyimports: 53 | preset: "ewasm" 54 | verifyexports: 55 | preset: "ewasm" 56 | snip: 57 | preset: "ewasm" 58 | repack: 59 | preset: "ewasm" 60 | 61 | ecpairing: 62 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_ecpairing.wasm" 63 | remapimports: 64 | preset: "ewasm" 65 | trimexports: 66 | preset: "ewasm" 67 | verifyimports: 68 | preset: "ewasm" 69 | verifyexports: 70 | preset: "ewasm" 71 | snip: 72 | preset: "ewasm" 73 | repack: 74 | preset: "ewasm" 75 | 76 | ecrecover: 77 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_ecrecover.wasm" 78 | remapimports: 79 | preset: "ewasm" 80 | trimexports: 81 | preset: "ewasm" 82 | verifyimports: 83 | preset: "ewasm" 84 | verifyexports: 85 | preset: "ewasm" 86 | snip: 87 | preset: "ewasm" 88 | repack: 89 | preset: "ewasm" 90 | 91 | ed25519: 92 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_ed25519.wasm" 93 | remapimports: 94 | preset: "ewasm" 95 | trimexports: 96 | preset: "ewasm" 97 | verifyimports: 98 | preset: "ewasm" 99 | verifyexports: 100 | preset: "ewasm" 101 | snip: 102 | preset: "ewasm" 103 | repack: 104 | preset: "ewasm" 105 | 106 | eip1962: 107 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_eip1962.wasm" 108 | remapimports: 109 | preset: "ewasm" 110 | trimexports: 111 | preset: "ewasm" 112 | verifyimports: 113 | preset: "ewasm" 114 | verifyexports: 115 | preset: "ewasm" 116 | snip: 117 | preset: "ewasm" 118 | repack: 119 | preset: "ewasm" 120 | 121 | identity: 122 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_identity.wasm" 123 | remapimports: 124 | preset: "ewasm" 125 | trimexports: 126 | preset: "ewasm" 127 | verifyimports: 128 | preset: "ewasm" 129 | verifyexports: 130 | preset: "ewasm" 131 | snip: 132 | preset: "ewasm" 133 | repack: 134 | preset: "ewasm" 135 | 136 | modexp: 137 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_modexp.wasm" 138 | remapimports: 139 | preset: "ewasm" 140 | trimexports: 141 | preset: "ewasm" 142 | verifyimports: 143 | preset: "ewasm" 144 | verifyexports: 145 | preset: "ewasm" 146 | snip: 147 | preset: "ewasm" 148 | repack: 149 | preset: "ewasm" 150 | 151 | keccak256: 152 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_keccak256.wasm" 153 | remapimports: 154 | preset: "ewasm" 155 | trimexports: 156 | preset: "ewasm" 157 | verifyimports: 158 | preset: "ewasm" 159 | verifyexports: 160 | preset: "ewasm" 161 | snip: 162 | preset: "ewasm" 163 | repack: 164 | preset: "ewasm" 165 | 166 | ripemd160: 167 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_ripemd160.wasm" 168 | remapimports: 169 | preset: "ewasm" 170 | trimexports: 171 | preset: "ewasm" 172 | verifyimports: 173 | preset: "ewasm" 174 | verifyexports: 175 | preset: "ewasm" 176 | snip: 177 | preset: "ewasm" 178 | repack: 179 | preset: "ewasm" 180 | 181 | sha1: 182 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_sha1.wasm" 183 | remapimports: 184 | preset: "ewasm" 185 | trimexports: 186 | preset: "ewasm" 187 | verifyimports: 188 | preset: "ewasm" 189 | verifyexports: 190 | preset: "ewasm" 191 | snip: 192 | preset: "ewasm" 193 | repack: 194 | preset: "ewasm" 195 | 196 | sh256: 197 | file: "target/wasm32-unknown-unknown/release/ewasm_precompile_sha256.wasm" 198 | remapimports: 199 | preset: "ewasm" 200 | trimexports: 201 | preset: "ewasm" 202 | verifyimports: 203 | preset: "ewasm" 204 | verifyexports: 205 | preset: "ewasm" 206 | snip: 207 | preset: "ewasm" 208 | repack: 209 | preset: "ewasm" 210 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | jobs: 4 | build: 5 | docker: 6 | - image: rust:1 7 | steps: 8 | - checkout 9 | - run: 10 | name: Update rustc 11 | command: | 12 | rustup target add wasm32-unknown-unknown 13 | rustup component add rustfmt 14 | rustup update 15 | - run: 16 | name: Install chisel 17 | command: cargo install chisel 18 | - run: 19 | name: Check formatting 20 | command: | 21 | rustfmt --version 22 | cargo fmt --all -- --check 23 | - run: 24 | name: Build 25 | command: | 26 | cargo build --release 27 | chisel run 28 | - run: 29 | name: Tests 30 | command: cargo test --target=x86_64-unknown-linux-gnu 31 | -------------------------------------------------------------------------------- /ecadd/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-ecadd" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum ECADD precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | ethereum-bn128 = { git = "https://github.com/ewasm/ethereum-bn128.rs", tag = "0.1.1" } 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /ecadd/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ethereum_bn128; 2 | extern crate ewasm_api; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | // NOTE: no need to validate the input length as bn128_add will behave like EVM1.0 calldatacopy 8 | // add keep imaginary zeroes. 9 | 10 | ewasm_api::consume_gas(500); 11 | 12 | let input = ewasm_api::calldata_acquire(); 13 | 14 | let mut output = [0u8; 64]; 15 | match ethereum_bn128::bn128_add(&input[..], &mut output) { 16 | Ok(_) => ewasm_api::finish_data(&output), 17 | Err(_) => ewasm_api::abort(), 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ecmul/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-ecmul" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum ECMUL precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | ethereum-bn128 = { git = "https://github.com/ewasm/ethereum-bn128.rs", tag = "0.1.1" } 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /ecmul/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ethereum_bn128; 2 | extern crate ewasm_api; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | // NOTE: no need to validate the input length as bn128_mul will behave like EVM1.0 calldatacopy 8 | // add keep imaginary zeroes. 9 | 10 | ewasm_api::consume_gas(40000); 11 | 12 | let input = ewasm_api::calldata_acquire(); 13 | 14 | let mut output = [0u8; 64]; 15 | match ethereum_bn128::bn128_mul(&input[..], &mut output) { 16 | Ok(_) => ewasm_api::finish_data(&output), 17 | Err(_) => ewasm_api::abort(), 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ecpairing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-ecpairing" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum ECPAIRING precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | ethereum-bn128 = { git = "https://github.com/ewasm/ethereum-bn128.rs", tag = "0.1.1" } 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /ecpairing/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ethereum_bn128; 2 | extern crate ewasm_api; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | let length = ewasm_api::calldata_size(); 8 | 9 | // NOTE: this validation will also be done by bn128_pairing 10 | 11 | if length % 192 != 0 { 12 | ewasm_api::abort(); 13 | } 14 | 15 | // charge a base fee plus a word fee for every element 16 | let base_fee = 100000; 17 | let element_fee = 80000; 18 | let total_cost = base_fee + (length / 192) * element_fee; 19 | 20 | ewasm_api::consume_gas(total_cost as u64); 21 | 22 | let input = ewasm_api::calldata_acquire(); 23 | 24 | let mut output = [0u8; 32]; 25 | match ethereum_bn128::bn128_pairing(&input[..], &mut output) { 26 | Ok(_) => ewasm_api::finish_data(&output), 27 | Err(_) => ewasm_api::abort(), 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ecrecover/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-ecrecover" 3 | version = "0.2.0" 4 | authors = ["Guillaume Ballet "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum ecrecover precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | libsecp256k1 = "^0.2.1" 14 | tiny-keccak = "1.4" 15 | 16 | [dev-dependencies] 17 | rustc-hex = "1.0" 18 | 19 | [lib] 20 | crate-type = ["cdylib"] 21 | -------------------------------------------------------------------------------- /ecrecover/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ewasm_api; 2 | extern crate secp256k1; 3 | extern crate tiny_keccak; 4 | 5 | #[cfg(test)] 6 | use secp256k1::Error::InvalidSignature; 7 | use secp256k1::{recover, Message, RecoveryId, Signature}; 8 | use std::cmp::min; 9 | 10 | const HASH_OFFSET: usize = 0; 11 | const HASH_LENGTH: usize = 32; 12 | const REC_ID_OFFSET: usize = HASH_LENGTH; 13 | const REC_ID_LENGTH: usize = 32; 14 | const COORD_OFFSET: usize = REC_ID_OFFSET + REC_ID_LENGTH; 15 | const COORD_LENGTH: usize = 32; 16 | const SIG_OFFSET: usize = COORD_OFFSET + COORD_LENGTH; 17 | const SIG_LENGTH: usize = 32; 18 | 19 | fn keccak(input: &[u8]) -> [u8; 32] { 20 | let mut hash = [0u8; 32]; 21 | tiny_keccak::Keccak::keccak256(&input, &mut hash); 22 | hash 23 | } 24 | 25 | fn ecrecover(input: &[u8]) -> Result, secp256k1::Error> { 26 | let hash_start = min(HASH_OFFSET, input.len()); 27 | let hash_end = min(HASH_OFFSET + HASH_LENGTH, input.len()); 28 | let mut h = [0u8; HASH_LENGTH]; 29 | for (i, val) in (&input[hash_start..hash_end]).iter().enumerate() { 30 | h[i] = *val; 31 | } 32 | 33 | /* Recovery id is the last big-endian byte. */ 34 | let v = if input.len() > REC_ID_OFFSET + REC_ID_LENGTH - 1 { 35 | (input[REC_ID_OFFSET + REC_ID_LENGTH - 1] as i8 - 27) as u8 36 | } else { 37 | (256 - 27) as u8 /* Assume the padding would yield 0 */ 38 | }; 39 | if v != 0 && v != 1 { 40 | return Ok(vec![0u8; 0]); 41 | } 42 | 43 | let sig_start = min(COORD_OFFSET, input.len()); 44 | let sig_end = min(SIG_OFFSET + SIG_LENGTH, input.len()); 45 | let mut s = [0u8; 64]; 46 | for (i, val) in (&input[sig_start..sig_end]).iter().enumerate() { 47 | s[i] = *val; 48 | } 49 | 50 | let message = Message::parse(&h); 51 | let rec_id = RecoveryId::parse(v)?; 52 | let sig = Signature::parse(&s); 53 | 54 | let key = recover(&message, &sig, &rec_id)?; 55 | let ret = key.serialize(); 56 | let ret = keccak(&ret[1..65]); 57 | let mut output = vec![0u8; 12]; 58 | output.extend_from_slice(&ret[12..32]); 59 | Ok(output) 60 | } 61 | 62 | #[cfg(not(test))] 63 | #[no_mangle] 64 | pub extern "C" fn main() { 65 | use std::cmp; 66 | 67 | const G_EC_RECOVER_GAS: u64 = 3000; 68 | 69 | ewasm_api::consume_gas(G_EC_RECOVER_GAS); 70 | 71 | // Make sure that the input is 128 bytes 72 | let mut input = vec![0u8; HASH_LENGTH + REC_ID_LENGTH + COORD_LENGTH + SIG_LENGTH]; 73 | let common_length = cmp::min(input.len(), ewasm_api::calldata_size()); 74 | ewasm_api::unsafe_calldata_copy( 75 | HASH_OFFSET as usize, 76 | common_length, 77 | &mut input[..common_length], 78 | ); 79 | 80 | match ecrecover(&input) { 81 | Ok(ret) => ewasm_api::finish_data(&ret[..]), 82 | // NOTE: this should not result in an error, but return empty data. 83 | Err(_) => ewasm_api::finish(), 84 | } 85 | } 86 | 87 | #[cfg(test)] 88 | mod tests { 89 | extern crate rustc_hex; 90 | use super::*; 91 | use rustc_hex::FromHex; 92 | 93 | #[test] 94 | fn geth_test() { 95 | let input = FromHex::from_hex(&"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02"[..]) 96 | .unwrap(); 97 | let expected = FromHex::from_hex( 98 | &"000000000000000000000000ceaccac640adf55b2028469bd36ba501f28b699d"[..], 99 | ) 100 | .unwrap(); 101 | 102 | let output = ecrecover(&input).unwrap(); 103 | 104 | assert_eq!(expected, output); 105 | } 106 | 107 | #[test] 108 | fn empty_input() { 109 | // An empty input should yield a 0-filled 128-bit vector 110 | let input = vec![0u8; 128]; 111 | let expected = vec![0u8; 0]; 112 | 113 | let output = ecrecover(&input).unwrap(); 114 | 115 | assert_eq!(expected, output); 116 | } 117 | 118 | #[test] 119 | fn input_tooshort() { 120 | // Remove 3 bytes from the thing. Input should be padded. 121 | let input = FromHex::from_hex(&"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8"[..]) 122 | .unwrap(); 123 | let expected = vec![ 124 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 134, 29, 243, 69, 239, 34, 88, 56, 58, 179, 125 | 196, 62, 105, 206, 213, 175, 96, 118, 1, 126 | ]; 127 | 128 | let output = ecrecover(&input).unwrap(); 129 | 130 | assert_eq!(expected, output); 131 | } 132 | 133 | #[test] 134 | fn input_toolong() { 135 | // Add 3 bytes at the end of the input. The extra stuff is ignored. 136 | let input = FromHex::from_hex(&"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02ffffff"[..]) 137 | .unwrap(); 138 | let expected = FromHex::from_hex( 139 | &"000000000000000000000000ceaccac640adf55b2028469bd36ba501f28b699d"[..], 140 | ) 141 | .unwrap(); 142 | 143 | let output = ecrecover(&input).unwrap(); 144 | 145 | assert_eq!(expected, output); 146 | } 147 | 148 | #[test] 149 | fn invalid_recid() { 150 | // Same thing as the geth test, with an invalid '-1' recovery id 151 | let input = FromHex::from_hex(&"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e00000000000000000000000000000000000000000000000000000000000000ff38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02"[..]) 152 | .unwrap(); 153 | let expected = vec![0u8; 0]; 154 | 155 | let output = ecrecover(&input).unwrap(); 156 | 157 | assert_eq!(expected, output); 158 | 159 | // Same thing as the geth test, with an invalid 'infinite' recovery id 160 | let input = FromHex::from_hex(&"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001e38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02"[..]) 161 | .unwrap(); 162 | let expected = vec![0u8; 0]; 163 | 164 | let output = ecrecover(&input).unwrap(); 165 | 166 | assert_eq!(expected, output); 167 | } 168 | 169 | #[test] 170 | fn invalid_signature() { 171 | // Same thing as the geth test, with a corrupt signature 172 | let input = FromHex::from_hex(&"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffd4295423adf9ed98873e789d1dd423d25f0772d2748d60f7e4b81bb14d086eba8e8e8efb6dcff8a4ae02"[..]) 173 | .unwrap(); 174 | 175 | let output = ecrecover(&input); 176 | 177 | let error = output.expect_err("Expected an error because of an invalid signature"); 178 | assert_eq!(InvalidSignature, error); 179 | 180 | // Set s = 0 181 | let input = FromHex::from_hex(&"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e0000000000000000000000000000000000000000000000000000000000000000"[..]) 182 | .unwrap(); 183 | 184 | let output = ecrecover(&input); 185 | let error = output.expect_err("Expected an error because of an invalid signature"); 186 | assert_eq!(InvalidSignature, error); 187 | } 188 | 189 | #[test] 190 | fn large_signature() { 191 | // Same thing as the geth test, making sure that the s field is 192 | // greater than secp256k1n/2. 193 | let input = FromHex::from_hex(&"38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e000000000000000000000000000000000000000000000000000000000000001b38d18acb67d25c8bb9942764b62f18e17054f66a817bd4295423adf9ed98873e7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0"[..]) 194 | .unwrap(); 195 | 196 | let output = ecrecover(&input).unwrap(); 197 | 198 | // The yellow paper says that the signature is invalid if: 199 | // 200 | // (281) `0 < s < secp256k1n ÷ 2 + 1` 201 | // 202 | // but this isn't enforced for precompiles, only for external 203 | // transactions. Check that this contract doesn't enforce it. 204 | let expected = vec![ 205 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 88, 198, 174, 93, 17, 93, 119, 163, 216, 169, 239, 206 | 54, 214, 164, 45, 35, 105, 43, 170, 127, 207 | ]; 208 | 209 | assert_eq!(expected, output); 210 | } 211 | 212 | #[test] 213 | fn rinkeby_block_922696() { 214 | let input = vec![ 215 | 18, 29, 74, 146, 225, 18, 73, 146, 175, 38, 117, 160, 255, 236, 4, 34, 146, 162, 98, 216 | 186, 197, 121, 106, 188, 25, 142, 20, 96, 130, 129, 57, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 217 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 31, 103, 111, 23, 218 | 112, 203, 66, 38, 98, 36, 34, 85, 11, 110, 114, 222, 119, 5, 222, 193, 55, 172, 122, 0, 219 | 200, 103, 130, 10, 169, 226, 46, 168, 75, 46, 205, 130, 46, 74, 151, 64, 88, 183, 130, 220 | 253, 126, 146, 11, 157, 188, 140, 127, 44, 33, 28, 243, 111, 91, 147, 100, 29, 141, 81, 221 | 137, 25, 222 | ]; 223 | let output = ecrecover(&input); 224 | let expected = Err(InvalidSignature); 225 | assert_eq!(expected, output); 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /ed25519/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-ed25519" 3 | version = "0.2.0" 4 | authors = ["Jared Wasinger "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum Ed25519 precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | hex = "0.3.1" 14 | sha2 = "^0.8" 15 | 16 | [dependencies.rand] 17 | version = "0.6.0" 18 | 19 | [dependencies.ed25519-dalek] 20 | version = "0.9.1" 21 | 22 | [dependencies.clear_on_drop] 23 | features = ["no_cc"] 24 | version = "^0.2.3" 25 | 26 | [lib] 27 | crate-type = ["cdylib"] 28 | -------------------------------------------------------------------------------- /ed25519/README.md: -------------------------------------------------------------------------------- 1 | # ed25519 2 | 3 | This is the precompile for enabling Ed25519 signature verification according to [EIP-665](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-665.md) 4 | 5 | ## Notes on the EIP 6 | 7 | The EIP seems to avoid comprehensive specification. At least the following two questions are not specified: 8 | 1) What happens if the input is too short or too long? 9 | 2) What is the canonical return value in case of an error. The EIP says *any non-zero value indicates a signature verification failure*, which can lead to issues. 10 | -------------------------------------------------------------------------------- /ed25519/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ed25519_dalek; 2 | extern crate ewasm_api; 3 | extern crate sha2; 4 | 5 | mod verify; 6 | 7 | #[cfg(not(test))] 8 | #[no_mangle] 9 | pub extern "C" fn main() { 10 | ewasm_api::consume_gas(2000); 11 | 12 | // NOTE: EIP-665 doesn't clarify what should happen if the input is shorter or longer. 13 | // This seems to be the best approach, consider it an error. 14 | if ewasm_api::calldata_size() != 128 { 15 | ewasm_api::revert(); 16 | } 17 | 18 | let mut tmp = [0u8; 128]; 19 | ewasm_api::unsafe_calldata_copy(0, 128, &mut tmp); 20 | match verify::verify(&tmp) { 21 | Ok(true) => { 22 | ewasm_api::finish_data(&[0x00u8; 4]); 23 | } 24 | Ok(false) => { 25 | ewasm_api::finish_data(&[0xffu8; 4]); 26 | } 27 | Err(_) => { 28 | // FIXME: send the error message? 29 | ewasm_api::revert(); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ed25519/src/verify.rs: -------------------------------------------------------------------------------- 1 | use ed25519_dalek::{PublicKey, Signature}; 2 | use sha2::Sha512; 3 | 4 | #[derive(Debug)] 5 | pub struct Error(pub &'static str); 6 | 7 | impl From<&'static str> for self::Error { 8 | fn from(val: &'static str) -> Self { 9 | self::Error(val) 10 | } 11 | } 12 | 13 | pub fn verify(input: &[u8; 128]) -> Result { 14 | let message = &input[..32]; 15 | 16 | let public_key = 17 | PublicKey::from_bytes(&input[32..64]).expect("public key should be correctly formed"); 18 | let sig = Signature::from_bytes(&input[64..128]).expect("signature should be correctly formed"); 19 | 20 | Ok(public_key.verify::(&message, &sig).is_ok()) 21 | } 22 | 23 | #[cfg(test)] 24 | mod tests { 25 | extern crate hex; 26 | use super::*; 27 | 28 | // TODO : add test case for message 0x0000....000 29 | 30 | #[test] 31 | fn valid() { 32 | let inputs = [ 33 | "7557f01a255ac98a325a1bfaae484ba11b01368e299c3b8d9370180750823bead94430b019f29bc78bdd2a9cbe796c9b633ad5cbe4ac804ac118563790e4c657a978c89e1b83c4a2f337a77b10351d0e184089fecf0ea8870614570306edd4a9ece7cdbc3378978bf4a4f85c0252ebb51cf00b2a4fc23833c6a1f6875503ae08", 34 | "00cd4bfe82f3de702d6c7bdb03fb5e198b2c919d511da05340d9e9a8d19f23a36f584bdc06e318b65ebc19e9770f82688686c3301a46cda717a6f5d9799708fd66849b045d01b50976f25e092d82fd85c932ef28294e8270a3abdc98f4c8836aa3929002a0c7a33b4c8d9bb422cce5cd52954ade1228f1552694bb6f9f02fd0a", 35 | "6eab91e7e0497708974c04cd7a92ac5984c751ff314b8ffdedf9e6557891dd9ba8f3e79b5fd9518562af18fceab88dd334a2217a21a473d67f1c8f2ff0d6aa3fbf75a63eb07cb71af0dad5498cb85dee04ee09b52f08810e5438cf504d366e8d79ff7713a37b4aad2d71b5919e009f29dbed7000216d5c30a332d034bd6d5306", 36 | "09168da69e98a320abaf4d6800f818c3ac184a23dea24eea9bf9b562ab5cad1a62e2dd9d14b23ad80213b4ffd2bd11b9778464b95e5fb80edddecefe98ab01759916665e5211dae56d0c56cf55325785eb0415a2024a819a8503a1f272b4870df143f644ffb6709e68cd2a4899c638f24c7d5ab0a97a5a609b0013f8e1a8e80c", 37 | "328dc5e413547ab2a880cc31799d56fbbd74e3cd189b03c23b522f3ca6d0c4caa8348e1940ca6909ccd24c94ba3fdff06ce00be8bdf803c6b8e55894204260b0c3ca89cc9d010e455df065173ee9c2a46ac009da91bc47fd57f0b52fa83af58dab8d2159ddadc940b3f05f7f9cc3773336bda31b886130ef0b835b9a7e4df504", 38 | "3f86ab0c079174566336ecdc9dee65122cab4509f214023394cf20935a2f652e5a087ae6914888b6477a1abfc7a2a882c94c4be232cf74c7ea17a3536425cddad455185ec6f66f81437fe231018f7e2f45e053c44a6faebb7c66c12028e4bd1d24e8657bbc5c7472a0122eec7e5621cd60d6e8a4b546297fd98895df0bd11b0a", 39 | "35bf580db70fef11c8f207035a862c24e9190105f88c4337157d71dbd6ddcf6d3f8ef5ec4351210fb645adb3527ab354770fcc6ad1256ea383125c4f74fd254dd64d94983335d9aacae84b2803a44c28d92e2a119c31d62e8cab8fd453d712b50044be7e9c540330cd4a164729b49b50d1f80084568e4637afbd4a66e2090e00", 40 | "6506e556d2decaa0e79ecc7c4418942f5e53f0724479a5d2de7e8745e28f51b5e4485ef638bf72054adec057c18a7caa92739d83cb8b80a2486d65fe2573162a94400812e2840600f98ee6026ff492f3130f189c080073ec553599e1916084ef7257ad11c3685cfcc0c172b265947cac4c786877fc57ec7ebcc387a042b3200e", 41 | "815266a579c22b95366b9346f22b221d549e61b8480a2f6dbb093b3ab395758e09101ce0c831a172538acf0b3ade4f2e1468e31d71c7c959e8bb13acde91fddd9a17a8adbb390c51366b089efcfedb35b6a711ce890c86e25a99e59fd0590af82facfede4c321877004ee35c5069c1f54fea8561fdf159c6362d55eb8c0f3c0a", 42 | "1110f6e4c25cbc9453a02d8de442496f8fab9e9f5a989e648720ec715f43a14690708b09728172402cf857d3545ecf4882d3c0828d79ebf20360b7371da795af7a0df44510016c03ce137524349f422f399434e7365e5c6b904d466ddedd0639a5348413c758b8a5fa4a9c4adaf25e1c01f480fa9105c6820307df7336563a0b", 43 | "6b8567b18b4dfa882b92970c38d6568c104e0e69bba71cb45a1ab620bccf37bb9409cb3e4cf0983a40cd2ce8b98f4fe8f80b0a6bbbf9a711ff407aea383b29f5447fc9d754f8af11971771e2870431e956af319548618148bcfb918d4a030582ada2cfd9a051bac4d56c8c880333fdcf1071562abe05c5c33ed06ec2745d010c", 44 | ]; 45 | for i in 0..inputs.len() { 46 | let input = hex::decode(inputs[i]).unwrap(); 47 | let mut tmp = [0u8; 128]; 48 | tmp.copy_from_slice(&input[..128]); 49 | assert_eq!(verify(&tmp).unwrap(), true); 50 | } 51 | } 52 | 53 | #[test] 54 | fn invalid() { 55 | let inputs = [ 56 | "10cd4bfe82f3de702d6c7bdb03fb5e198b2c919d511da05340d9e9a8d19f23a36f584bdc06e318b65ebc19e9770f82688686c3301a46cda717a6f5d9799708fd66849b045d01b50976f25e092d82fd85c932ef28294e8270a3abdc98f4c8836aa3929002a0c7a33b4c8d9bb422cce5cd52954ade1228f1552694bb6f9f02fd0a", 57 | "6eab91e7e0497708974c04cd7a92ac5984c751ff314b8ffdedf9e6557891dd9ba8f3e79b5fd9518562af18fceab88dd334a2217a21a473d77f1c8f2ff0d6aa3fbf75a63eb07cb71af0dad5498cb85dee04ee09b52f08810e5438cf504d366e8d79ff7713a37b4aad2d71b5919e009f29dbed7000216d5c30a332d034bd6d5306", 58 | "09168da69e98a320abaf4d6800f818c3ac184a23dea24eea9bf9b562ab5cad1a62e2dd9d14b23ad80213b4ffd2bd11b9778464b95e5fb801dddecefe98ab01759916665e5211dae56d0c56cf55325785eb0415a2024a819a8503a1f272b4870df143f644ffb6709e68cd2a4899c638f24c7d5ab0a97a5a609b0013f8e1a8e80c", 59 | "328dc5e413547ab2a880cc31799d56fbbd74e3cd189b03c23b522f3ca6d0c4caa8348e1940ca6909ccd24c94ba3fdff06ce00be8bdf803c3b8e55894204260b0c3ca89cc9d010e455df065173ee9c2a46ac009da91bc47fd57f0b52fa83af58dab8d2159ddadc940b3f05f7f9cc3773336bda31b886130ef0b835b9a7e4df504", 60 | "3f86ab0c079174566336ecdc9dee65122cab4509f214023394cf20935a2f652e5a087ae6914888b6477a1abfc7a2a882c94c4be232cf71c7ea17a3536425cddad455185ec6f66f81437fe231018f7e2f45e053c44a6faebb7c66c12028e4bd1d24e8657bbc5c7472a0122eec7e5621cd60d6e8a4b546297fd98895df0bd11b0a", 61 | "35bf580db70fef11c8f207035a862c24e9190105f88c4337157d71dbd6ddcf6d3f8ef5ec4351210fb645adb3527ab354770fcc6ad1256ea283125c4f74fd254dd64d94983335d9aacae84b2803a44c28d92e2a119c31d62e8cab8fd453d712b50044be7e9c540330cd4a164729b49b50d1f80084568e4637afbd4a66e2090e00", 62 | "6506e556d2decaa0e79ecc7c4418942f5e53f0724479a5d2de7e8745e28f51b5e4485ef638bf72054adec057c18a7caa92739d83cb8b81a2486d65fe2573162a94400812e2840600f98ee6026ff492f3130f189c080073ec553599e1916084ef7257ad11c3685cfcc0c172b265947cac4c786877fc57ec7ebcc387a042b3200e", 63 | "815266a579c22b95366b9346f22b221d549e61b8480a2f6dbb093b3ab395758e09101ce0c831a172538acf0b3ade4f2e1468e31d71c7c159e8bb13acde91fddd9a17a8adbb390c51366b089efcfedb35b6a711ce890c86e25a99e59fd0590af82facfede4c321877004ee35c5069c1f54fea8561fdf159c6362d55eb8c0f3c0a", 64 | "1110f6e4c25cbc9453a02d8de442496f8fab9e9f5a989e648720ec715f43a14690708b09728172402cf857d3545ecf4882d3c0828d79e1f20360b7371da795af7a0df44510016c03ce137524349f422f399434e7365e5c6b904d466ddedd0639a5348413c758b8a5fa4a9c4adaf25e1c01f480fa9105c6820307df7336563a0b", 65 | "6b8567b18b4dfa882b92970c38d6568c104e0e69bba71cb45a1ab620bccf37bb9409cb3e4cf0983a40cd2ce8b98f4fe8f80b0a6bbbf9a111ff407aea383b29f5447fc9d754f8af11971771e2870431e956af319548618148bcfb918d4a030582ada2cfd9a051bac4d56c8c880333fdcf1071562abe05c5c33ed06ec2745d010c", 66 | ]; 67 | for i in 0..inputs.len() { 68 | let input = hex::decode(inputs[i]).unwrap(); 69 | let mut tmp = [0u8; 128]; 70 | tmp.copy_from_slice(&input[..128]); 71 | assert_eq!(verify(&tmp).unwrap(), false); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /eip1962/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-eip1962" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum EIP1962 precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | # 0.2.0 14 | eth_pairings = { git = "https://github.com/matter-labs/eip1962", rev = "6a06b44cd8d5dd9265480312a08b4a7c69fbbbe0" } 15 | 16 | [lib] 17 | crate-type = ["cdylib"] 18 | -------------------------------------------------------------------------------- /eip1962/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ewasm_api; 2 | 3 | #[cfg(not(test))] 4 | #[no_mangle] 5 | pub extern "C" fn main() { 6 | let input = ewasm_api::calldata_acquire(); 7 | 8 | let gas_cost = eth_pairings::gas_meter::GasMeter::meter(&input); 9 | let gas_cost = if gas_cost.is_err() { 10 | ewasm_api::abort(); 11 | } else { 12 | gas_cost.unwrap() 13 | }; 14 | 15 | ewasm_api::consume_gas(gas_cost); 16 | 17 | let result = eth_pairings::public_interface::API::run(&input); 18 | let result = if result.is_err() { 19 | ewasm_api::abort(); 20 | } else { 21 | result.unwrap() 22 | }; 23 | 24 | ewasm_api::finish_data(&result); 25 | } 26 | -------------------------------------------------------------------------------- /identity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-identity" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum identity precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | 14 | [lib] 15 | crate-type = ["cdylib"] 16 | -------------------------------------------------------------------------------- /identity/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ewasm_api; 2 | 3 | #[cfg(not(test))] 4 | #[no_mangle] 5 | pub extern "C" fn main() { 6 | let length = ewasm_api::calldata_size(); 7 | 8 | // charge a base fee plus a word fee for every 256-bit word 9 | let base_fee = 15; 10 | let word_fee = 3; 11 | let total_cost = base_fee + ((length + 31) / 32) * word_fee; 12 | 13 | ewasm_api::consume_gas(total_cost as u64); 14 | 15 | let data = ewasm_api::calldata_acquire(); 16 | 17 | ewasm_api::finish_data(&data) 18 | } 19 | -------------------------------------------------------------------------------- /keccak256/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-keccak256" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum Keccak-256 precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | tiny-keccak = "1.4" 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /keccak256/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ewasm_api; 2 | extern crate tiny_keccak; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | let length = ewasm_api::calldata_size(); 8 | 9 | // charge a base fee plus a word fee for every 256-bit word 10 | let base_fee = 60; 11 | let word_fee = 12; 12 | let total_cost = base_fee + ((length + 31) / 32) * word_fee; 13 | 14 | ewasm_api::consume_gas(total_cost as u64); 15 | 16 | let data = ewasm_api::calldata_acquire(); 17 | 18 | let mut hash = [0u8; 32]; 19 | tiny_keccak::Keccak::keccak256(&data[..], &mut hash); 20 | 21 | ewasm_api::finish_data(&hash[..]) 22 | } 23 | -------------------------------------------------------------------------------- /modexp/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-modexp" 3 | version = "0.2.0" 4 | authors = ["Guillaume Ballet "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum modexp precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | num = { version = "0.1.36", default-features = false } 14 | num-bigint = { version = "0.1.36", default-features = false } 15 | 16 | [lib] 17 | crate-type = ["cdylib"] 18 | -------------------------------------------------------------------------------- /modexp/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ewasm_api; 2 | extern crate num_bigint; 3 | 4 | use num::{One, Zero}; 5 | use num_bigint::{BigInt, Sign}; 6 | use std::cmp; 7 | #[cfg(not(test))] 8 | use std::io::{self, Read}; 9 | use std::ops::{Rem, Shl}; 10 | 11 | #[cfg(not(test))] 12 | const LENGTH_LENGTH: usize = 32; 13 | const G_QUAD_DIVISOR: u64 = 20; 14 | 15 | fn f(x: u64) -> u64 { 16 | match x { 17 | 0...64 => x * x, 18 | 65...1024 => (x * x / 4) + 96 * x - 3072, 19 | _ => (x * x / 16) + 480 * x - 199680, 20 | } 21 | } 22 | 23 | fn calculate_cost(lm: usize, lb: usize, exp: &BigInt) -> u64 { 24 | let le = exp.to_bytes_be().1.len(); 25 | let lep: u64 = match le { 26 | 0...32 => { 27 | if exp.is_zero() { 28 | 0u64 29 | } else { 30 | // Number of bits == ⌊log2()⌋ + 1 31 | exp.bits() as u64 - 1 32 | } 33 | } 34 | _ => { 35 | let nbits = exp.bits(); 36 | let (loglow32bytes, low32bytes) = if nbits > 256 { 37 | let x = exp.rem(&BigInt::one().shl(256)); 38 | (x.bits() - 1, x) 39 | } else { 40 | (nbits - 1, exp.clone()) 41 | }; 42 | 43 | if low32bytes > BigInt::zero() { 44 | 8 * (le as u64 - 32) + loglow32bytes as u64 45 | } else { 46 | 8 * (le as u64 - 32) 47 | } 48 | } 49 | }; 50 | 51 | (f(cmp::max(lm, lb) as u64) * cmp::max(lep, 1 as u64)) / G_QUAD_DIVISOR 52 | } 53 | 54 | fn modexp(base: &BigInt, exp: &BigInt, modulus: &BigInt) -> Vec { 55 | let x = if modulus.is_zero() { 56 | BigInt::zero() 57 | } else { 58 | base.modpow(exp, modulus) 59 | }; 60 | let (_, mut data) = x.to_bytes_be(); 61 | 62 | /* padded on 32 bytes */ 63 | let mut padded = vec![0u8; (32 - (data.len() % 32)) % 32]; 64 | padded.append(&mut data); 65 | padded 66 | } 67 | 68 | #[cfg(not(test))] 69 | #[no_mangle] 70 | pub extern "C" fn main() { 71 | use num::cast::ToPrimitive; 72 | 73 | let input_size = ewasm_api::calldata_size(); 74 | // Geth will consider the input size to be 0 if it's less than 75 | // 96 bytes. 76 | let input = if input_size >= 96 { 77 | ewasm_api::calldata_acquire() 78 | } else { 79 | vec![0u8; 0] 80 | }; 81 | 82 | let mut reader = input.chain(io::repeat(0)); 83 | 84 | let mut length_bytes = [0u8; LENGTH_LENGTH]; 85 | reader 86 | .read_exact(&mut length_bytes) 87 | .expect("Should be able to read 32 bytes from input"); 88 | let base_length = BigInt::from_bytes_be(Sign::Plus, &length_bytes[..]) 89 | .to_usize() // Get the `usize` version of base_length, as it won't 90 | .unwrap(); // be possible to read more anyway. 91 | 92 | reader 93 | .read_exact(&mut length_bytes) 94 | .expect("Should be able to read 32 bytes from input"); 95 | let exp_length = BigInt::from_bytes_be(Sign::Plus, &length_bytes[..]) 96 | .to_usize() // Same thing with exponent 97 | .unwrap(); 98 | 99 | reader 100 | .read_exact(&mut length_bytes) 101 | .expect("Should be able to read 32 bytes from input"); 102 | let mod_length = BigInt::from_bytes_be(Sign::Plus, &length_bytes[..]) 103 | .to_usize() 104 | .unwrap(); 105 | 106 | let mut base_bytes = vec![0u8; base_length]; 107 | reader 108 | .read_exact(&mut base_bytes[..]) 109 | .expect("Should be able to read base bytes from input"); 110 | let base = BigInt::from_bytes_be(Sign::Plus, &base_bytes[..]); 111 | let mut exp_bytes = vec![0u8; exp_length]; 112 | reader 113 | .read_exact(&mut exp_bytes[..]) 114 | .expect("Should be able to read exp bytes from input"); 115 | let exp = BigInt::from_bytes_be(Sign::Plus, &exp_bytes[..]); 116 | let mut mod_bytes = vec![0u8; mod_length]; 117 | reader 118 | .read_exact(&mut mod_bytes[..]) 119 | .expect("Should be able to read modulus bytes from input"); 120 | let modulus = BigInt::from_bytes_be(Sign::Plus, &mod_bytes[..]); 121 | 122 | ewasm_api::consume_gas(calculate_cost(mod_length, base_length, &exp)); 123 | 124 | // Geth's returns an empty array when base and mod both have 125 | // zero length. 126 | if base_length == 0 && mod_length == 0 { 127 | ewasm_api::finish(); 128 | } 129 | 130 | let output = modexp(&base, &exp, &modulus); 131 | ewasm_api::finish_data(&output[..]) 132 | } 133 | 134 | #[cfg(test)] 135 | mod tests { 136 | use super::*; 137 | use num::FromPrimitive; 138 | use std::ops::Shl; 139 | 140 | #[test] 141 | fn simple_modexp() { 142 | let output = modexp( 143 | &BigInt::from_i64(0xdeadbeef).unwrap(), 144 | &BigInt::one(), 145 | &BigInt::from_i32(10i32).unwrap(), 146 | ); 147 | assert_eq!( 148 | output, 149 | vec![ 150 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 151 | 0, 0, 0, 9 152 | ] 153 | ); 154 | } 155 | 156 | #[test] 157 | fn big_exponent_big_modulus_zero() { 158 | let output = modexp( 159 | &(BigInt::from_i8(2i8).unwrap()), 160 | &BigInt::from_u8(128u8).unwrap(), 161 | &BigInt::one().shl(64), 162 | ); 163 | assert_eq!(output, vec![0u8; 32]); 164 | } 165 | 166 | #[test] 167 | fn big_exponent_big_modulus() { 168 | let output = modexp( 169 | &(BigInt::from_i8(3i8).unwrap()), 170 | &BigInt::from_u8(128u8).unwrap(), 171 | &BigInt::one().shl(67), 172 | ); 173 | assert_eq!( 174 | output, 175 | vec![ 176 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 177 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 4u8, 128u8, 66u8, 20u8, 129u8, 138u8, 134u8, 178 | 122u8, 1u8 179 | ] 180 | ); 181 | } 182 | 183 | #[test] 184 | fn big_exponent_small_modulus() { 185 | let output = modexp( 186 | &BigInt::from_i8(2i8).unwrap(), 187 | &BigInt::from_u8(128u8).unwrap(), 188 | &BigInt::from_i8(10i8).unwrap(), 189 | ); 190 | assert_eq!( 191 | output, 192 | vec![ 193 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 194 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 6u8 195 | ] 196 | ); 197 | } 198 | 199 | #[test] 200 | fn check_mod_zero() { 201 | let output = modexp(&BigInt::one(), &BigInt::one(), &BigInt::zero()); 202 | assert_eq!(output, vec![0u8; 32]); 203 | } 204 | 205 | #[test] 206 | fn check_zero_exp_zero() { 207 | let output = modexp( 208 | &BigInt::zero(), 209 | &BigInt::zero(), 210 | &BigInt::from_i8(3).unwrap(), 211 | ); 212 | assert_eq!( 213 | output, 214 | vec![ 215 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 216 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8 217 | ] 218 | ); 219 | } 220 | 221 | #[test] 222 | fn check_rinkeby_972222() { 223 | /* Validate that values bigger than 32 bytes can be returned */ 224 | let output = modexp( 225 | &BigInt::from_bytes_be( 226 | Sign::Plus, 227 | &[ 228 | 105u8, 244u8, 148u8, 17u8, 230u8, 162u8, 38u8, 226u8, 21u8, 123u8, 99u8, 173u8, 229 | 92u8, 154u8, 225u8, 98u8, 221u8, 178u8, 13u8, 54u8, 142u8, 147u8, 227u8, 219u8, 230 | 150u8, 131u8, 6u8, 199u8, 20u8, 249u8, 189u8, 163u8, 10u8, 56u8, 142u8, 74u8, 231 | 160u8, 10u8, 23u8, 22u8, 133u8, 219u8, 196u8, 237u8, 209u8, 230u8, 181u8, 232 | 148u8, 170u8, 136u8, 152u8, 109u8, 145u8, 62u8, 113u8, 35u8, 177u8, 70u8, 90u8, 233 | 254u8, 242u8, 241u8, 37u8, 193u8, 137u8, 34u8, 80u8, 63u8, 201u8, 219u8, 98u8, 234 | 68u8, 242u8, 229u8, 107u8, 41u8, 194u8, 61u8, 241u8, 15u8, 186u8, 12u8, 61u8, 235 | 121u8, 166u8, 99u8, 226u8, 51u8, 245u8, 19u8, 98u8, 0u8, 231u8, 66u8, 220u8, 236 | 25u8, 113u8, 116u8, 46u8, 94u8, 215u8, 214u8, 68u8, 212u8, 24u8, 96u8, 201u8, 237 | 47u8, 67u8, 161u8, 233u8, 119u8, 20u8, 115u8, 28u8, 119u8, 60u8, 46u8, 206u8, 238 | 8u8, 59u8, 243u8, 245u8, 178u8, 177u8, 123u8, 131u8, 65u8, 239 | ], 240 | ), 241 | &BigInt::from_bytes_be( 242 | Sign::Plus, 243 | &[ 244 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 245 | 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 1u8, 246 | ], 247 | ), 248 | &BigInt::from_bytes_be( 249 | Sign::Plus, 250 | &[ 251 | 132u8, 63u8, 73u8, 203u8, 78u8, 27u8, 50u8, 102u8, 66u8, 138u8, 185u8, 34u8, 252 | 220u8, 161u8, 134u8, 52u8, 173u8, 16u8, 83u8, 166u8, 181u8, 82u8, 151u8, 245u8, 253 | 166u8, 158u8, 136u8, 110u8, 61u8, 191u8, 138u8, 213u8, 72u8, 170u8, 180u8, 254 | 26u8, 170u8, 159u8, 62u8, 89u8, 236u8, 155u8, 217u8, 242u8, 130u8, 160u8, 23u8, 255 | 193u8, 205u8, 210u8, 69u8, 52u8, 141u8, 166u8, 173u8, 203u8, 220u8, 93u8, 256 | 101u8, 86u8, 158u8, 107u8, 181u8, 184u8, 207u8, 171u8, 57u8, 103u8, 67u8, 257 | 243u8, 102u8, 12u8, 159u8, 44u8, 122u8, 105u8, 76u8, 152u8, 164u8, 7u8, 96u8, 258 | 175u8, 192u8, 144u8, 139u8, 76u8, 117u8, 90u8, 26u8, 188u8, 138u8, 149u8, 259 | 200u8, 175u8, 108u8, 201u8, 17u8, 211u8, 247u8, 177u8, 92u8, 214u8, 65u8, 260 | 243u8, 35u8, 10u8, 106u8, 79u8, 218u8, 176u8, 18u8, 106u8, 2u8, 71u8, 3u8, 261 | 174u8, 218u8, 178u8, 16u8, 244u8, 244u8, 89u8, 165u8, 195u8, 179u8, 247u8, 262 | 120u8, 47u8, 263 | ], 264 | ), 265 | ); 266 | assert_eq!( 267 | output, 268 | vec![ 269 | 0u8, 1u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 270 | 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 271 | 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 272 | 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 273 | 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 274 | 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 255u8, 275 | 255u8, 255u8, 255u8, 255u8, 0u8, 48u8, 49u8, 48u8, 13u8, 6u8, 9u8, 96u8, 134u8, 276 | 72u8, 1u8, 101u8, 3u8, 4u8, 2u8, 1u8, 5u8, 0u8, 4u8, 32u8, 152u8, 203u8, 93u8, 277 | 245u8, 45u8, 169u8, 18u8, 4u8, 171u8, 193u8, 131u8, 35u8, 108u8, 212u8, 190u8, 278 | 245u8, 181u8, 170u8, 134u8, 108u8, 120u8, 170u8, 237u8, 179u8, 241u8, 226u8, 128u8, 279 | 212u8, 149u8, 52u8, 51u8, 151u8 280 | ] 281 | ); 282 | } 283 | 284 | #[test] 285 | fn check_zero_exp_cost() { 286 | assert_eq!(calculate_cost(0 as usize, 0 as usize, &BigInt::zero()), 0); 287 | assert_eq!(calculate_cost(0 as usize, 0 as usize, &BigInt::zero()), 0); 288 | } 289 | 290 | #[test] 291 | fn check_exp_costs() { 292 | assert_eq!( 293 | calculate_cost(56 as usize, 25 as usize, &BigInt::from_i16(1024).unwrap()), 294 | ((56 * 56) * 10) / G_QUAD_DIVISOR 295 | ); 296 | 297 | assert_eq!( 298 | calculate_cost(65 as usize, 25 as usize, &BigInt::from_i16(1024).unwrap()), 299 | ((((65 * 65) / 4) + 96 * 65 - 3072) * 10) / G_QUAD_DIVISOR 300 | ); 301 | 302 | assert_eq!( 303 | calculate_cost(1025 as usize, 25 as usize, &BigInt::from_i16(1024).unwrap()), 304 | ((((1025 * 1025) / 16) + 480 * 1025 - 199680) * 10) / G_QUAD_DIVISOR 305 | ); 306 | 307 | assert_eq!( 308 | calculate_cost( 309 | 1 as usize, 310 | 20 as usize, 311 | &(BigInt::one().shl(257) + BigInt::one()) 312 | ), 313 | ((20 * 20) * 8) / G_QUAD_DIVISOR 314 | ); 315 | 316 | assert_eq!( 317 | calculate_cost( 318 | 1 as usize, 319 | 20 as usize, 320 | &(BigInt::one().shl(257) + BigInt::from_i8(10).unwrap()) 321 | ), 322 | ((20 * 20) * (8 + 3)) / G_QUAD_DIVISOR 323 | ); 324 | 325 | assert_eq!( 326 | calculate_cost(56 as usize, 25 as usize, &BigInt::zero()), 327 | ((56 * 56) * 1) / G_QUAD_DIVISOR 328 | ); 329 | } 330 | 331 | #[test] 332 | fn check_rinkeby_cost_972222() { 333 | assert_eq!( 334 | calculate_cost( 335 | 128 as usize, 336 | 128 as usize, 337 | &BigInt::from_u64(65537).unwrap() 338 | ), 339 | 10649 340 | ); 341 | } 342 | } 343 | -------------------------------------------------------------------------------- /ripemd160/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-ripemd160" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum RIPEMD160 precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | ripemd160 = "0.7" 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /ripemd160/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ewasm_api; 2 | extern crate ripemd160; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | use ripemd160::{Digest, Ripemd160}; 8 | 9 | let length = ewasm_api::calldata_size(); 10 | 11 | // charge a base fee plus a word fee for every 256-bit word 12 | let base_fee = 600; 13 | let word_fee = 120; 14 | let total_cost = base_fee + ((length + 31) / 32) * word_fee; 15 | 16 | ewasm_api::consume_gas(total_cost as u64); 17 | 18 | let data = ewasm_api::calldata_acquire(); 19 | 20 | let mut hasher = Ripemd160::default(); 21 | hasher.input(&data); 22 | let hash = hasher.result(); 23 | 24 | // As per YP the 20 byte hash should be left-padded to 32 bytes 25 | let mut padded_hash = vec![0; 12]; 26 | padded_hash.extend_from_slice(&hash); 27 | 28 | ewasm_api::finish_data(&padded_hash) 29 | } 30 | -------------------------------------------------------------------------------- /sha1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-sha1" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum SHA1 precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | sha1 = "0.6" 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /sha1/README.md: -------------------------------------------------------------------------------- 1 | # sha1 2 | 3 | This is the precompile for enabling SHA-1 hashing according to [EIP-180](https://github.com/ethereum/EIPs/issues/180) 4 | -------------------------------------------------------------------------------- /sha1/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ewasm_api; 2 | extern crate sha1; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | let length = ewasm_api::calldata_size(); 8 | 9 | // charge a base fee plus a word fee for every 256-bit word 10 | let base_fee = 62; 11 | let word_fee = 8; 12 | let total_cost = base_fee + ((length + 31) / 32) * word_fee; 13 | 14 | ewasm_api::consume_gas(total_cost as u64); 15 | 16 | let data = ewasm_api::calldata_acquire(); 17 | 18 | let hash = sha1::Sha1::from(data).digest().bytes(); 19 | 20 | ewasm_api::finish_data(&hash) 21 | } 22 | -------------------------------------------------------------------------------- /sha256/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ewasm-precompile-sha256" 3 | version = "0.2.0" 4 | authors = ["Alex Beregszaszi "] 5 | license = "Apache-2.0" 6 | repository = "https://github.com/ewasm/ewasm-precompiles" 7 | description = "Ethereum SHA256 precompile in Rust" 8 | publish = false 9 | edition = "2018" 10 | 11 | [dependencies] 12 | ewasm_api = "0.9" 13 | sha2 = "0.7" 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /sha256/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate ewasm_api; 2 | extern crate sha2; 3 | 4 | #[cfg(not(test))] 5 | #[no_mangle] 6 | pub extern "C" fn main() { 7 | use sha2::{Digest, Sha256}; 8 | 9 | let length = ewasm_api::calldata_size(); 10 | 11 | // charge a base fee plus a word fee for every 256-bit word 12 | let base_fee = 60; 13 | let word_fee = 12; 14 | let total_cost = base_fee + ((length + 31) / 32) * word_fee; 15 | 16 | ewasm_api::consume_gas(total_cost as u64); 17 | 18 | let data = ewasm_api::calldata_acquire(); 19 | 20 | let mut hasher = Sha256::default(); 21 | hasher.input(&data); 22 | let hash = hasher.result(); 23 | 24 | ewasm_api::finish_data(&hash) 25 | } 26 | --------------------------------------------------------------------------------