├── .dockerignore ├── .gitignore ├── .gitmodules ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── examples ├── 0001.c ├── 0002-fib.c ├── 0003-bf.c ├── 0004-lisp.c ├── 0005-prime.c ├── 0006-editdis.c ├── 0007-perceptron.c ├── 0008-rpn.c ├── 0009-gameoflife.c ├── 0010-struct.c ├── fib.c └── mitou.s ├── kvsp └── main.go ├── share ├── cahp-pearl.toml └── cahp-ruby.toml ├── test.sh └── toolbox.sh /.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tfheutil/tfheutil 2 | kvsp/kvsp 3 | build 4 | _* 5 | .clangd 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cahp-sim"] 2 | path = cahp-sim 3 | url = https://github.com/virtualsecureplatform/cahp-sim.git 4 | [submodule "llvm-cahp"] 5 | path = llvm-cahp 6 | url = https://github.com/virtualsecureplatform/llvm-cahp.git 7 | [submodule "cahp-rt"] 8 | path = cahp-rt 9 | url = https://github.com/virtualsecureplatform/cahp-rt.git 10 | [submodule "Iyokan-L1"] 11 | path = Iyokan-L1 12 | url = https://github.com/virtualsecureplatform/Iyokan-L1.git 13 | [submodule "Iyokan"] 14 | path = Iyokan 15 | url = https://github.com/virtualsecureplatform/Iyokan.git 16 | [submodule "yosys"] 17 | path = yosys 18 | url = https://github.com/YosysHQ/yosys.git 19 | [submodule "cahp-ruby"] 20 | path = cahp-ruby 21 | url = https://github.com/virtualsecureplatform/cahp-ruby.git 22 | [submodule "cahp-pearl"] 23 | path = cahp-pearl 24 | url = https://github.com/virtualsecureplatform/cahp-pearl.git 25 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvidia/cuda:11.1.1-devel-ubuntu20.04 2 | #FROM nvidia/cuda:11.2.2-devel-ubuntu20.04 3 | 4 | ENV DEBIAN_FRONTEND=noninteractive 5 | 6 | RUN apt-get update && apt-get install -y \ 7 | build-essential git curl software-properties-common openjdk-11-jre \ 8 | cmake clang clang-9 bison flex libreadline-dev \ 9 | gawk tcl-dev libffi-dev graphviz xdot pkg-config python3 libboost-system-dev \ 10 | libboost-python-dev libboost-filesystem-dev zlib1g-dev \ 11 | && rm -rf /var/lib/apt/lists/* 12 | 13 | # Install .NET Core SDK 14 | RUN curl -sL https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -o packages-microsoft-prod.deb 15 | RUN dpkg -i packages-microsoft-prod.deb 16 | RUN apt-get update && apt-get install -y dotnet-sdk-3.1 17 | 18 | # Install sbt 19 | RUN echo "deb https://dl.bintray.com/sbt/debian /" | tee -a /etc/apt/sources.list.d/sbt.list 20 | RUN curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | apt-key add 21 | RUN apt-get update && apt-get install -y sbt 22 | 23 | # Install Go 24 | RUN add-apt-repository ppa:longsleep/golang-backports 25 | RUN apt-get update && apt-get install -y golang-go 26 | RUN go get github.com/BurntSushi/toml 27 | 28 | # Run the build when executing `docker run` 29 | CMD ["bash", "-c", "make -j$(nproc) ENABLE_CUDA=1 CUDACXX=\"/usr/local/cuda/bin/nvcc\" CUDAHOSTCXX=\"/usr/bin/clang-9\""] 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | KVSP consists of many different components, which are distributed under 2 | different licenses. 3 | 4 | 1. The following directories are our works and have their own LICENSE/COPYING files. 5 | 6 | - Iyokan-L1/ 7 | - Iyokan/ 8 | - cahp-pearl/ 9 | - cahp-ruby/ 10 | - cahp-rt/ 11 | - cahp-sim/ 12 | 13 | 14 | 2. The following directories were authored in other projects (not our works). 15 | 16 | - llvm-cahp/ 17 | See llvm-cahp/*/LICENSE*. 18 | - yosys/ 19 | See yosys/COPYING. 20 | 21 | 22 | 3. The following files and directories are our works and licensed under the Apache License, Version 2.0. 23 | 24 | - files in the root directory. 25 | - kvsp/ 26 | 27 | Apache License 28 | Version 2.0, January 2004 29 | http://www.apache.org/licenses/ 30 | 31 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 32 | 33 | 1. Definitions. 34 | 35 | "License" shall mean the terms and conditions for use, reproduction, 36 | and distribution as defined by Sections 1 through 9 of this document. 37 | 38 | "Licensor" shall mean the copyright owner or entity authorized by 39 | the copyright owner that is granting the License. 40 | 41 | "Legal Entity" shall mean the union of the acting entity and all 42 | other entities that control, are controlled by, or are under common 43 | control with that entity. For the purposes of this definition, 44 | "control" means (i) the power, direct or indirect, to cause the 45 | direction or management of such entity, whether by contract or 46 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 47 | outstanding shares, or (iii) beneficial ownership of such entity. 48 | 49 | "You" (or "Your") shall mean an individual or Legal Entity 50 | exercising permissions granted by this License. 51 | 52 | "Source" form shall mean the preferred form for making modifications, 53 | including but not limited to software source code, documentation 54 | source, and configuration files. 55 | 56 | "Object" form shall mean any form resulting from mechanical 57 | transformation or translation of a Source form, including but 58 | not limited to compiled object code, generated documentation, 59 | and conversions to other media types. 60 | 61 | "Work" shall mean the work of authorship, whether in Source or 62 | Object form, made available under the License, as indicated by a 63 | copyright notice that is included in or attached to the work 64 | (an example is provided in the Appendix below). 65 | 66 | "Derivative Works" shall mean any work, whether in Source or Object 67 | form, that is based on (or derived from) the Work and for which the 68 | editorial revisions, annotations, elaborations, or other modifications 69 | represent, as a whole, an original work of authorship. For the purposes 70 | of this License, Derivative Works shall not include works that remain 71 | separable from, or merely link (or bind by name) to the interfaces of, 72 | the Work and Derivative Works thereof. 73 | 74 | "Contribution" shall mean any work of authorship, including 75 | the original version of the Work and any modifications or additions 76 | to that Work or Derivative Works thereof, that is intentionally 77 | submitted to Licensor for inclusion in the Work by the copyright owner 78 | or by an individual or Legal Entity authorized to submit on behalf of 79 | the copyright owner. For the purposes of this definition, "submitted" 80 | means any form of electronic, verbal, or written communication sent 81 | to the Licensor or its representatives, including but not limited to 82 | communication on electronic mailing lists, source code control systems, 83 | and issue tracking systems that are managed by, or on behalf of, the 84 | Licensor for the purpose of discussing and improving the Work, but 85 | excluding communication that is conspicuously marked or otherwise 86 | designated in writing by the copyright owner as "Not a Contribution." 87 | 88 | "Contributor" shall mean Licensor and any individual or Legal Entity 89 | on behalf of whom a Contribution has been received by Licensor and 90 | subsequently incorporated within the Work. 91 | 92 | 2. Grant of Copyright License. Subject to the terms and conditions of 93 | this License, each Contributor hereby grants to You a perpetual, 94 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 95 | copyright license to reproduce, prepare Derivative Works of, 96 | publicly display, publicly perform, sublicense, and distribute the 97 | Work and such Derivative Works in Source or Object form. 98 | 99 | 3. Grant of Patent License. Subject to the terms and conditions of 100 | this License, each Contributor hereby grants to You a perpetual, 101 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 102 | (except as stated in this section) patent license to make, have made, 103 | use, offer to sell, sell, import, and otherwise transfer the Work, 104 | where such license applies only to those patent claims licensable 105 | by such Contributor that are necessarily infringed by their 106 | Contribution(s) alone or by combination of their Contribution(s) 107 | with the Work to which such Contribution(s) was submitted. If You 108 | institute patent litigation against any entity (including a 109 | cross-claim or counterclaim in a lawsuit) alleging that the Work 110 | or a Contribution incorporated within the Work constitutes direct 111 | or contributory patent infringement, then any patent licenses 112 | granted to You under this License for that Work shall terminate 113 | as of the date such litigation is filed. 114 | 115 | 4. Redistribution. You may reproduce and distribute copies of the 116 | Work or Derivative Works thereof in any medium, with or without 117 | modifications, and in Source or Object form, provided that You 118 | meet the following conditions: 119 | 120 | (a) You must give any other recipients of the Work or 121 | Derivative Works a copy of this License; and 122 | 123 | (b) You must cause any modified files to carry prominent notices 124 | stating that You changed the files; and 125 | 126 | (c) You must retain, in the Source form of any Derivative Works 127 | that You distribute, all copyright, patent, trademark, and 128 | attribution notices from the Source form of the Work, 129 | excluding those notices that do not pertain to any part of 130 | the Derivative Works; and 131 | 132 | (d) If the Work includes a "NOTICE" text file as part of its 133 | distribution, then any Derivative Works that You distribute must 134 | include a readable copy of the attribution notices contained 135 | within such NOTICE file, excluding those notices that do not 136 | pertain to any part of the Derivative Works, in at least one 137 | of the following places: within a NOTICE text file distributed 138 | as part of the Derivative Works; within the Source form or 139 | documentation, if provided along with the Derivative Works; or, 140 | within a display generated by the Derivative Works, if and 141 | wherever such third-party notices normally appear. The contents 142 | of the NOTICE file are for informational purposes only and 143 | do not modify the License. You may add Your own attribution 144 | notices within Derivative Works that You distribute, alongside 145 | or as an addendum to the NOTICE text from the Work, provided 146 | that such additional attribution notices cannot be construed 147 | as modifying the License. 148 | 149 | You may add Your own copyright statement to Your modifications and 150 | may provide additional or different license terms and conditions 151 | for use, reproduction, or distribution of Your modifications, or 152 | for any such Derivative Works as a whole, provided Your use, 153 | reproduction, and distribution of the Work otherwise complies with 154 | the conditions stated in this License. 155 | 156 | 5. Submission of Contributions. Unless You explicitly state otherwise, 157 | any Contribution intentionally submitted for inclusion in the Work 158 | by You to the Licensor shall be under the terms and conditions of 159 | this License, without any additional terms or conditions. 160 | Notwithstanding the above, nothing herein shall supersede or modify 161 | the terms of any separate license agreement you may have executed 162 | with Licensor regarding such Contributions. 163 | 164 | 6. Trademarks. This License does not grant permission to use the trade 165 | names, trademarks, service marks, or product names of the Licensor, 166 | except as required for reasonable and customary use in describing the 167 | origin of the Work and reproducing the content of the NOTICE file. 168 | 169 | 7. Disclaimer of Warranty. Unless required by applicable law or 170 | agreed to in writing, Licensor provides the Work (and each 171 | Contributor provides its Contributions) on an "AS IS" BASIS, 172 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 173 | implied, including, without limitation, any warranties or conditions 174 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 175 | PARTICULAR PURPOSE. You are solely responsible for determining the 176 | appropriateness of using or redistributing the Work and assume any 177 | risks associated with Your exercise of permissions under this License. 178 | 179 | 8. Limitation of Liability. In no event and under no legal theory, 180 | whether in tort (including negligence), contract, or otherwise, 181 | unless required by applicable law (such as deliberate and grossly 182 | negligent acts) or agreed to in writing, shall any Contributor be 183 | liable to You for damages, including any direct, indirect, special, 184 | incidental, or consequential damages of any character arising as a 185 | result of this License or out of the use or inability to use the 186 | Work (including but not limited to damages for loss of goodwill, 187 | work stoppage, computer failure or malfunction, or any and all 188 | other commercial damages or losses), even if such Contributor 189 | has been advised of the possibility of such damages. 190 | 191 | 9. Accepting Warranty or Additional Liability. While redistributing 192 | the Work or Derivative Works thereof, You may choose to offer, 193 | and charge a fee for, acceptance of support, warranty, indemnity, 194 | or other liability obligations and/or rights consistent with this 195 | License. However, in accepting such obligations, You may act only 196 | on Your own behalf and on Your sole responsibility, not on behalf 197 | of any other Contributor, and only if You agree to indemnify, 198 | defend, and hold each Contributor harmless for any liability 199 | incurred by, or claims asserted against, such Contributor by reason 200 | of your accepting any such warranty or additional liability. 201 | 202 | END OF TERMS AND CONDITIONS 203 | 204 | APPENDIX: How to apply the Apache License to your work. 205 | 206 | To apply the Apache License to your work, attach the following 207 | boilerplate notice, with the fields enclosed by brackets "[]" 208 | replaced with your own identifying information. (Don't include 209 | the brackets!) The text should be enclosed in the appropriate 210 | comment syntax for the file format. We also recommend that a 211 | file or class name and description of purpose be included on the 212 | same "printed page" as the copyright notice for easier 213 | identification within third-party archives. 214 | 215 | Copyright 2019 Kotaro Matsuoka, Ryotaro Banno, Naoki Matsumoto 216 | 217 | Licensed under the Apache License, Version 2.0 (the "License"); 218 | you may not use this file except in compliance with the License. 219 | You may obtain a copy of the License at 220 | 221 | http://www.apache.org/licenses/LICENSE-2.0 222 | 223 | Unless required by applicable law or agreed to in writing, software 224 | distributed under the License is distributed on an "AS IS" BASIS, 225 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 226 | See the License for the specific language governing permissions and 227 | limitations under the License. 228 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL=/bin/bash 2 | 3 | ### Config parameters. 4 | ENABLE_CUDA=0 5 | 6 | all: step10_cahp-rt 7 | ### ============================== 8 | ### Build successfully completed! 9 | ### ============================== 10 | 11 | step1_prepare: 12 | ### ============================== 13 | ### Preparing for build 14 | ### ============================== 15 | mkdir -p build/bin 16 | mkdir -p build/share/kvsp 17 | cp -a share/* build/share/kvsp/ 18 | 19 | step2_kvsp: step1_prepare 20 | ### ============================== 21 | ### Building kvsp 22 | ### ============================== 23 | mkdir -p build/kvsp 24 | cd kvsp && \ 25 | go build -o ../build/kvsp/kvsp -ldflags "\ 26 | -X main.kvspVersion=$$(git describe --tags --abbrev=0 || echo "unk") \ 27 | -X main.kvspRevision=$$(git rev-parse --short HEAD || echo "unk") \ 28 | -X main.iyokanRevision=$$(git -C ../Iyokan rev-parse --short HEAD || echo "unk") \ 29 | -X main.iyokanL1Revision=$$(git -C ../Iyokan-L1 rev-parse --short HEAD || echo "unk") \ 30 | -X main.cahpRubyRevision=$$(git -C ../cahp-ruby rev-parse --short HEAD || echo "unk") \ 31 | -X main.cahpPearlRevision=$$(git -C ../cahp-pearl rev-parse --short HEAD || echo "unk") \ 32 | -X main.cahpRtRevision=$$(git -C ../cahp-rt rev-parse --short HEAD || echo "unk") \ 33 | -X main.cahpSimRevision=$$(git -C ../cahp-sim rev-parse --short HEAD || echo "unk") \ 34 | -X main.llvmCahpRevision=$$(git -C ../llvm-cahp rev-parse --short HEAD || echo "unk") \ 35 | -X main.yosysRevision=$$(git -C ../yosys rev-parse --short HEAD || echo "unk")" 36 | cp -a build/kvsp/kvsp build/bin/ 37 | 38 | step3_iyokan: step2_kvsp 39 | ### ============================== 40 | ### Building Iyokan 41 | ### ============================== 42 | mkdir -p build/Iyokan 43 | cd build/Iyokan && \ 44 | cmake \ 45 | -DCMAKE_BUILD_TYPE="Release" \ 46 | -DIYOKAN_ENABLE_CUDA=$(ENABLE_CUDA) \ 47 | -DCMAKE_C_COMPILER=clang \ 48 | -DCMAKE_CXX_COMPILER=clang++ \ 49 | ../../Iyokan && \ 50 | $(MAKE) iyokan iyokan-packet 51 | cp -a build/Iyokan/bin/iyokan build/bin/ 52 | cp -a build/Iyokan/bin/iyokan-packet build/bin/ 53 | 54 | step4_cahp-sim: step3_iyokan 55 | ### ============================== 56 | ### Building cahp-sim 57 | ### ============================== 58 | mkdir -p build/cahp-sim 59 | cd build/cahp-sim && \ 60 | cmake \ 61 | -DCMAKE_BUILD_TYPE="Release" \ 62 | ../../cahp-sim && \ 63 | $(MAKE) cahp-sim 64 | cp -a build/cahp-sim/src/cahp-sim build/bin/ 65 | 66 | step5_yosys: step4_cahp-sim 67 | ### ============================== 68 | ### Building Yosys 69 | ### ============================== 70 | cp -a yosys build/ 71 | cd build/yosys && $(MAKE) 72 | 73 | step6_iyokan-l1: step5_yosys 74 | ### ============================== 75 | ### Building Iyokan-L1 76 | ### ============================== 77 | cp -a Iyokan-L1 build/ 78 | cd build/Iyokan-L1 && dotnet build 79 | 80 | step7_cahp-ruby: step6_iyokan-l1 81 | ### ============================== 82 | ### Building cahp-ruby 83 | ### ============================== 84 | cp -a cahp-ruby build/ 85 | cd build/cahp-ruby && sbt run 86 | cd build/cahp-ruby && \ 87 | ../yosys/yosys build.ys 88 | dotnet run -p build/Iyokan-L1/ -c Release build/cahp-ruby/vsp-core-ruby.json build/share/kvsp/ruby-core.json 89 | 90 | step8_cahp-pearl: step7_cahp-ruby 91 | ### ============================== 92 | ### Building cahp-pearl 93 | ### ============================== 94 | cp -a cahp-pearl build/ 95 | cd build/cahp-pearl && sbt run 96 | cd build/cahp-pearl && \ 97 | ../yosys/yosys build.ys 98 | dotnet run -p build/Iyokan-L1/ -c Release build/cahp-pearl/vsp-core-pearl.json build/share/kvsp/pearl-core.json 99 | 100 | step9_llvm-cahp: step8_cahp-pearl 101 | ### ============================== 102 | ### Building llvm-cahp 103 | ### ============================== 104 | mkdir -p build/llvm-cahp 105 | cd build/llvm-cahp && \ 106 | cmake \ 107 | -DCMAKE_BUILD_TYPE="Release" \ 108 | -DLLVM_ENABLE_PROJECTS="lld;clang" \ 109 | -DLLVM_TARGETS_TO_BUILD="" \ 110 | -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD="CAHP" \ 111 | ../../llvm-cahp/llvm && \ 112 | $(MAKE) 113 | cp -a build/llvm-cahp/bin/* build/bin/ 114 | 115 | step10_cahp-rt: step9_llvm-cahp 116 | ### ============================== 117 | ### Building cahp-rt 118 | ### ============================== 119 | cp -a cahp-rt build/ 120 | cd build/cahp-rt && CC=../llvm-cahp/bin/clang $(MAKE) 121 | mkdir -p build/share/kvsp/cahp-rt 122 | cd build/cahp-rt && \ 123 | cp -a crt0.o libc.a cahp.lds ../share/kvsp/cahp-rt/ 124 | 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KVSP; Kyoto Virtual Secure Platform 2 | 3 | [[Official website](https://virtualsecureplatform.github.io/)] 4 | [[Paper on arXiv](https://arxiv.org/abs/2010.09410)] 5 | [[Brief Japanese description on KVSP](https://anqou.net/poc/2019/10/18/post-3106/)] 6 | 7 | Virtual Secure Platform (VSP) provides a toolchain to run encrypted C programs without decryption. 8 | 9 | VSP is the first comprehensive platform that implements 10 | a multi-opcode general-purpose sequential processor 11 | over Fully Homomorphic Encryption (FHE) for Secure Multi-Party Computation (SMPC). 12 | VSP protects both the data and functions on which the data are evaluated 13 | from the adversary in a secure computation offloading situation like cloud computing. 14 | 15 | KVSP (Kyoto Virtual Secure Platform) is the first implementation 16 | of VSP. KVSP consists of many other sub-projects. 17 | The `kvsp` command, which this repository serves, is a 18 | simple interface to use them easily. 19 | 20 | ## Paper 21 | 22 | We published a [paper](https://www.usenix.org/conference/usenixsecurity21/presentation/matsuoka) on VSP, which is accepted by USENIX Security Symposium 2021. 23 | We uploaded its full version onto [arXiv](https://arxiv.org/abs/2010.09410). 24 | 25 | ## Quick Start 26 | 27 | Demo is on [YouTube](https://www.youtube.com/watch?v=1YsUaZMITR8). 28 | 29 | [![Demo for Kyoto Virtual Secure Platform](http://img.youtube.com/vi/1YsUaZMITR8/0.jpg)](http://www.youtube.com/watch?v=1YsUaZMITR8 "Demo for Kyoto Virtual Secure Platform") 30 | 31 | Download a KVSP release from [here](https://github.com/virtualsecureplatform/kvsp/releases/latest) and unzip it. 32 | (It has been compiled on Ubuntu 20.04 LTS and CUDA 11.1.1. 33 | If it doesn't work in the following steps, 34 | please read __Build__ section and try to build KVSP on your own. 35 | It may be time-consuming, but not so hard.) 36 | 37 | ``` 38 | $ wget 'https://github.com/virtualsecureplatform/kvsp/releases/latest/download/kvsp.tar.gz' 39 | $ tar xf kvsp.tar.gz 40 | $ cd kvsp_v29/bin # The directory's name depends on the file you download. 41 | ``` 42 | 43 | Write some C code... 44 | 45 | ``` 46 | $ vim fib.c 47 | 48 | $ cat fib.c 49 | static int fib(int n) { 50 | int a = 0, b = 1; 51 | for (int i = 0; i < n; i++) { 52 | int tmp = a + b; 53 | a = b; 54 | b = tmp; 55 | } 56 | return a; 57 | } 58 | 59 | int main(int argc, char **argv) { 60 | // Calculate n-th Fibonacci number. 61 | // n is a 1-digit number and given as command-line argument. 62 | return fib(argv[1][0] - '0'); 63 | } 64 | ``` 65 | 66 | ...like so. This program (`fib.c`) returns the n-th term of Fibonacci sequence, 67 | as its comment says. 68 | 69 | Compile `fib.c` to an executable file `fib`. 70 | 71 | ``` 72 | $ ./kvsp cc fib.c -o fib 73 | ``` 74 | 75 | Let's encrypt it. First, we'll generate a secret key (`secret.key`): 76 | 77 | ``` 78 | $ ./kvsp genkey -o secret.key 79 | ``` 80 | 81 | Then encrypt `fib` with `secret.key` to get an **encrypted** executable `fib.enc`. 82 | We have to pass its command-line arguments here. I chose 5, so the result 83 | of this program will be fib(5)=5. 84 | 85 | ``` 86 | $ ./kvsp enc -k secret.key -i fib -o fib.enc 5 87 | ``` 88 | 89 | Okay. Now we will run `fib.enc` without `secret.key`. 90 | To do this, first we have to make a _bootstrapping key_, which doesn't reveal 91 | the secret key at all but only enables the computation: 92 | 93 | ``` 94 | $ ./kvsp genbkey -i secret.key -o bootstrapping.key 95 | ``` 96 | 97 | Then we will execute the program, but here is a problem: 98 | once it starts running we can't know if it is still running or has already halted, 99 | because **everything about the code is totally encrypted**! 100 | 101 | So, we have to decide how many clock cycles to run `fib.enc` at our choice. 102 | It is, say, 30. 103 | 104 | ``` 105 | # If you have GPUs use '-g NUM-OF-GPUS' option. 106 | $ ./kvsp run -bkey bootstrapping.key -i fib.enc -o result.enc -c 30 107 | ``` 108 | 109 | Let's check the result. We'll decrypt `result.enc`: 110 | 111 | ``` 112 | $ ./kvsp dec -k secret.key -i result.enc 113 | ... 114 | f0 false 115 | ... 116 | ``` 117 | 118 | `f0` is 'finish flag', which is true iff the program ends. 119 | So, 30 cycles were not enough. Let's try another 30; 120 | We can resume from the point where we stopped using 'snapshot' file 121 | (its filename depends on your environment): 122 | 123 | ``` 124 | $ ./kvsp resume -c 30 -i kvsp_20200517002413.snapshot -o result.enc -bkey bootstrapping.key 125 | ``` 126 | 127 | Check the result again: 128 | 129 | ``` 130 | $ ./kvsp dec -k secret.key -i result.enc 131 | ... 132 | f0 true 133 | ... 134 | x8 5 135 | ... 136 | ``` 137 | 138 | Finished! x8 register has the returned value from `main()` and it is the correct answer 5. 139 | We could get the correct answer using secure computation! 140 | 141 | ## More examples? 142 | 143 | See the directory `examples/`. 144 | 145 | ## System Requirements 146 | 147 | We ensure that KVSP works on the following cloud services: 148 | 149 | - [さくらインターネット 高火力コンピューティング Tesla V100(32GB)モデル](https://www.sakura.ad.jp/koukaryoku/) 150 | - [GCP n1-standard-96 with 8 x NVIDIA Tesla V100](https://cloud.google.com/compute/docs/machine-types?hl=ja#n1_standard_machine_types) 151 | - [AWS EC2 p3.16xlarge](https://aws.amazon.com/jp/ec2/instance-types/p3/) 152 | - [AWS EC2 p3.8xlarge](https://aws.amazon.com/jp/ec2/instance-types/p3/) 153 | - [AWS EC2 p3.2xlarge](https://aws.amazon.com/jp/ec2/instance-types/p3/) 154 | - [AWS EC2 m5.metal](https://aws.amazon.com/ec2/instance-types/c5/) 155 | 156 | If you run KVSP locally, prepare a machine with the following devices: 157 | 158 | - Intel CPU with AVX2 support (e.g. Intel Core i7-8700) 159 | - 16GB RAM 160 | - NVIDIA GPU (not required but highly recommended) 161 | - Only NVIDIA V100 and A100 are supported. 162 | - Other GPUs _may_ work but are not supported. 163 | 164 | ## Dependencies 165 | 166 | We are using Ubuntu 20.04 LTS in the development of v30 and later. 167 | Following commands setup the AWS instances. 168 | If you use AWS p3 instances, we highly recommend to increase EBS (Storage) size to 12 GB because intermediate files will be some GBs orders. 169 | 170 | p3 instances (This includes reboot at last to enable a GPU driver.) 171 | ``` 172 | sudo apt update&&sudo apt upgrade -y&&sudo apt install -y libgoogle-perftools-dev libomp-dev nvidia-driver-460&&sudo reboot 173 | ``` 174 | 175 | c5.metal 176 | ``` 177 | sudo apt update&&sudo apt upgrade -y&&sudo apt install -y libgoogle-perftools-dev libomp-dev 178 | ``` 179 | 180 | ## Build 181 | 182 | Clone this repository: 183 | 184 | ``` 185 | $ git clone https://github.com/virtualsecureplatform/kvsp.git 186 | ``` 187 | 188 | Clone submodules recursively: 189 | 190 | ``` 191 | $ git submodule update --init --recursive 192 | ``` 193 | 194 | Build KVSP: 195 | 196 | ``` 197 | $ make -j$(nproc) # It may take a while. 198 | ``` 199 | 200 | Use option `ENABLE_CUDA` if you build KVSP with GPU support: 201 | 202 | ``` 203 | $ make -j$(nproc) ENABLE_CUDA=1 CUDACXX="/usr/local/cuda/bin/nvcc" CUDAHOSTCXX="/usr/bin/clang-8" 204 | ``` 205 | 206 | ## Build KVSP Using Docker 207 | 208 | Based on Ubuntu 20.04 LTS with NVIDIA CUDA 11.1.1. 209 | Note that NVIDIA GPU is NOT necessary to build KVSP. 210 | 211 | ``` 212 | $ docker build -t kvsp-build . 213 | $ docker run -it -v $PWD:/build -w /build kvsp-build:latest 214 | ``` 215 | 216 | ## Code Owners 217 | 218 | - [kvsp](https://github.com/virtualsecureplatform/kvsp/tree/master/kvsp) 219 | - @ushitora-anqou 220 | - [llvm-cahp](https://github.com/virtualsecureplatform/llvm-cahp) 221 | - @ushitora-anqou 222 | - This is forked from [llvm/llvm-project](https://github.com/llvm/llvm-project) 223 | - [cahp-rt](https://github.com/virtualsecureplatform/cahp-rt) 224 | - @ushitora-anqou 225 | - [cahp-sim](https://github.com/virtualsecureplatform/cahp-sim) 226 | - @ushitora-anqou 227 | - [Iyokan-L1](https://github.com/virtualsecureplatform/Iyokan-L1) 228 | - @naoki9911 229 | - [cahp-pearl](https://github.com/virtualsecureplatform/cahp-pearl) 230 | - @naoki9911 231 | - [cahp-ruby](https://github.com/virtualsecureplatform/cahp-ruby) 232 | - @naoki9911 233 | - [Iyokan](https://github.com/virtualsecureplatform/Iyokan) 234 | - @ushitora-anqou and @naoki9911 235 | - [TFHEpp](https://github.com/virtualsecureplatform/TFHEpp) 236 | - @nindanaoto 237 | - [cuFHE](https://github.com/virtualsecureplatform/cuFHE) 238 | - @nindanaoto and @naoki9911 239 | - This is forked from [vernamlab/cuFHE](https://github.com/vernamlab/cuFHE) 240 | -------------------------------------------------------------------------------- /examples/0001.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | return 42; 4 | } 5 | -------------------------------------------------------------------------------- /examples/0002-fib.c: -------------------------------------------------------------------------------- 1 | int fib(int n) 2 | { 3 | if (n <= 1) return n; 4 | return fib(n - 1) + fib(n - 2); 5 | } 6 | 7 | int main() 8 | { 9 | return fib(5); 10 | } 11 | -------------------------------------------------------------------------------- /examples/0003-bf.c: -------------------------------------------------------------------------------- 1 | static void jumpFront(const char *str, int *index) 2 | { 3 | if (str[*index] != '[') return; 4 | for (int count = 0; str[*index] != '\0'; (*index)++) { 5 | if (str[*index] == '[') 6 | count++; 7 | else if (str[*index] == ']') 8 | count--; 9 | if (count == 0) break; 10 | } 11 | } 12 | 13 | static void jumpBack(const char *str, int *index) 14 | { 15 | if (str[*index] != ']') return; 16 | for (int count = 0; *index >= 0; (*index)--) { 17 | if (str[*index] == '[') 18 | count--; 19 | else if (str[*index] == ']') 20 | count++; 21 | if (count == 0) break; 22 | } 23 | } 24 | 25 | static int brainfuck(const char *str) 26 | { 27 | static int data[100]; 28 | 29 | int pointer = sizeof(data) / sizeof(int) / 2; 30 | for (int index = 0; str[index] != '\0'; index++) { 31 | switch (str[index]) { 32 | case '+': 33 | data[pointer]++; 34 | break; 35 | case '-': 36 | data[pointer]--; 37 | break; 38 | case '>': 39 | pointer++; 40 | break; 41 | case '<': 42 | pointer--; 43 | break; 44 | case '.': 45 | break; 46 | case ',': 47 | break; 48 | case '[': 49 | if (data[pointer] == 0) jumpFront(str, &index); 50 | break; 51 | case ']': 52 | if (data[pointer] != 0) jumpBack(str, &index); 53 | break; 54 | } 55 | } 56 | return data[pointer]; 57 | } 58 | 59 | int main() 60 | { 61 | return brainfuck("++++[>++++++++++<-]>++"); 62 | } 63 | -------------------------------------------------------------------------------- /examples/0004-lisp.c: -------------------------------------------------------------------------------- 1 | static int pc = 0; 2 | static const char *text; 3 | 4 | static int var[128]; 5 | 6 | #define NEXT (text[pc++]) 7 | #define PEEK (text[pc]) 8 | 9 | int next(void) 10 | { 11 | while (text[pc] == ' ') pc++; 12 | return text[pc++]; 13 | } 14 | 15 | int peek(void) 16 | { 17 | while (text[pc] == ' ') pc++; 18 | return text[pc]; 19 | } 20 | 21 | int interpret(void) 22 | { 23 | char ch = next(); 24 | 25 | if (ch == '(') { 26 | ch = next(); 27 | 28 | switch (ch) { 29 | default: 30 | return -1; // error 31 | 32 | case '+': { 33 | int val = interpret(); 34 | val += interpret(); 35 | next(); // Eat ')'. 36 | return val; 37 | } 38 | 39 | case '-': { 40 | int val = interpret(); 41 | val -= interpret(); 42 | next(); // Eat ')'. 43 | return val; 44 | } 45 | 46 | case 'l': { 47 | next(); // Eat 'e'. 48 | next(); // Eat 't'. 49 | next(); // Eat '('. 50 | next(); // Eat '('. 51 | char id = next(); 52 | int val = interpret(); 53 | var[(int)id] = val; 54 | next(); // Eat ')'. 55 | next(); // Eat ')'. 56 | return interpret(); 57 | } 58 | } 59 | } 60 | 61 | if ('0' <= ch && ch <= '9') return ch - '0'; 62 | 63 | return var[(int)ch]; 64 | } 65 | 66 | int lisp(const char *str) 67 | { 68 | pc = 0; 69 | text = str; 70 | 71 | int val = interpret(); 72 | return val; 73 | } 74 | 75 | int main() 76 | { 77 | return lisp( 78 | "(let ((a (+ (+ (+ 9 9) (+ 9 9)) 9)))" 79 | " (- a 3))"); 80 | } 81 | -------------------------------------------------------------------------------- /examples/0005-prime.c: -------------------------------------------------------------------------------- 1 | int prime(int index) 2 | { 3 | if (index <= 0) return 2; 4 | 5 | static int primes[100]; 6 | int nprimes = 0; 7 | 8 | primes[nprimes++] = 2; 9 | for (int i = 3;; i++) { 10 | int j = 0; 11 | while (j < nprimes && i % primes[j] != 0) j++; 12 | if (j != nprimes) continue; 13 | 14 | // i is a prime. 15 | if (nprimes == index) return i; 16 | primes[nprimes++] = i; 17 | } 18 | } 19 | 20 | int main() 21 | { 22 | return prime(99); 23 | } 24 | -------------------------------------------------------------------------------- /examples/0006-editdis.c: -------------------------------------------------------------------------------- 1 | static int min3(int a, int b, int c) 2 | { 3 | if (a < b) { 4 | if (b < c) return a; 5 | if (c < a) return c; 6 | // a < b && a <= c 7 | return a; 8 | } 9 | 10 | // b <= a 11 | if (b < c) return b; 12 | // b <= a && c <= b 13 | return c; 14 | } 15 | 16 | static int strlen(const char *s) 17 | { 18 | int i = 0; 19 | while (s[i] != '\0') i++; 20 | return i; 21 | } 22 | 23 | static void swap_intp(int **lhs, int **rhs) 24 | { 25 | int *tmp = *lhs; 26 | *lhs = *rhs; 27 | *rhs = tmp; 28 | } 29 | 30 | static int calc_edit_distance(const char *str0, const char *str1) 31 | { 32 | static int dp[2][7 + 1]; 33 | 34 | int *dp0 = dp[0], *dp1 = dp[1]; 35 | int n = strlen(str0), m = strlen(str1); 36 | 37 | // Initialization of array `dp`. 38 | for (int i = 0; i <= n; i++) dp0[i] = i; 39 | dp1[0] = 0; 40 | 41 | // Let's DP. 42 | for (int i = 1; i <= n; i++) { 43 | for (int j = 1; j <= m; j++) { 44 | dp1[j] = min3(dp0[j] + 1, dp1[j - 1] + 1, 45 | dp0[j - 1] + (str0[i] == str1[i] ? 0 : 1)); 46 | } 47 | swap_intp(&dp0, &dp1); 48 | } 49 | 50 | return dp0[m]; 51 | } 52 | 53 | int main() 54 | { 55 | return calc_edit_distance("kitten", "sitting"); 56 | } 57 | -------------------------------------------------------------------------------- /examples/0007-perceptron.c: -------------------------------------------------------------------------------- 1 | static int weight[3]; 2 | 3 | static int predict(int x, int y) 4 | { 5 | return weight[0] * x + weight[1] * y + weight[2] > 0 ? 1 : 0; 6 | } 7 | 8 | static void train(int x, int y, int z) 9 | { 10 | int val = predict(x, y); 11 | if (val < z) { 12 | weight[0] += x; 13 | weight[1] += y; 14 | weight[2] += z; 15 | } 16 | else if (z < val) { 17 | weight[0] -= x; 18 | weight[1] -= y; 19 | weight[2] -= z; 20 | } 21 | } 22 | 23 | int main() 24 | { 25 | for (int i = 0; i < 10; i++) { 26 | train(0, 0, 1); 27 | train(0, 1, 1); 28 | train(1, 0, 1); 29 | train(1, 1, 0); 30 | } 31 | 32 | return predict(0, 0) | (predict(0, 1) << 1) | (predict(1, 0) << 2) | 33 | (predict(1, 1) << 3); 34 | } 35 | -------------------------------------------------------------------------------- /examples/0008-rpn.c: -------------------------------------------------------------------------------- 1 | static int calc_rpn(const char *src) 2 | { 3 | int stack[10]; 4 | int sp = -1; 5 | 6 | for (int i = 0; src[i] != '\0'; i++) { 7 | if ('0' <= src[i] && src[i] <= '9') { // digit 8 | stack[++sp] = src[i] - '0'; 9 | continue; 10 | } 11 | 12 | switch (src[i]) { 13 | case '+': 14 | stack[sp - 1] = stack[sp - 1] + stack[sp]; 15 | sp--; 16 | break; 17 | 18 | case '-': 19 | stack[sp - 1] = stack[sp - 1] - stack[sp]; 20 | sp--; 21 | break; 22 | 23 | case '*': 24 | stack[sp - 1] = stack[sp - 1] * stack[sp]; 25 | sp--; 26 | break; 27 | } 28 | } 29 | 30 | return stack[sp]; 31 | } 32 | 33 | int main() 34 | { 35 | return calc_rpn("3 4 + 2 1 - *"); 36 | } 37 | -------------------------------------------------------------------------------- /examples/0009-gameoflife.c: -------------------------------------------------------------------------------- 1 | // Thanks to: http://nyanp.hatenablog.com/entry/20110728/p1 2 | #define $ ((((((((0 3 | #define X <<1|1) 4 | #define _ <<1)//)))))) 5 | 6 | typedef unsigned char uint8_t; 7 | 8 | enum { 9 | SIZE = 8, 10 | }; 11 | 12 | static uint8_t at(uint8_t map[], int x, int y) 13 | { 14 | return (map[y] >> (7 - x)) & 1; 15 | } 16 | 17 | /* 18 | static uint8_t safe_at(uint8_t map[], int x, int y) 19 | { 20 | if (x < 0) x += 8; 21 | if (x >= 8) x -= 8; 22 | if (y < 0) y += SIZE; 23 | if (y >= SIZE) y -= SIZE; 24 | 25 | return at(map, x, y); 26 | } 27 | */ 28 | 29 | static void step(uint8_t map[]) 30 | { 31 | uint8_t src[SIZE]; 32 | for (int i = 0; i < SIZE; i++) src[i] = map[i]; 33 | 34 | for (int y = 1; y < SIZE - 1; y++) { 35 | int res = 0; 36 | 37 | for (int x = 1; x < 8 - 1; x++) { 38 | uint8_t p = at(src, x, y); 39 | 40 | int cnt = 0; 41 | 42 | if (at(src, x - 1, y - 1)) cnt++; 43 | if (at(src, x, y - 1)) cnt++; 44 | if (at(src, x + 1, y - 1)) cnt++; 45 | 46 | if (at(src, x - 1, y)) cnt++; 47 | if (at(src, x + 1, y)) cnt++; 48 | 49 | if (at(src, x - 1, y + 1)) cnt++; 50 | if (at(src, x, y + 1)) cnt++; 51 | if (at(src, x + 1, y + 1)) cnt++; 52 | 53 | if (!p && cnt == 3) res |= (1 << (7 - x)); 54 | if (p && (cnt == 2 || cnt == 3)) res |= (1 << (7 - x)); 55 | } 56 | 57 | map[y] = res; 58 | } 59 | } 60 | 61 | int main() 62 | { 63 | static uint8_t map[SIZE] = { 64 | $ _ _ _ _ _ _ _ _, // 65 | $ _ _ X _ _ _ _ _, // 66 | $ _ _ _ X _ _ _ _, // 67 | $ _ X X X _ _ _ _, // 68 | $ _ _ _ _ _ _ _ _, // 69 | $ _ _ _ _ _ _ _ _, // 70 | $ _ _ _ _ _ _ _ _, // 71 | $ _ _ _ _ _ _ _ _, // 72 | }; 73 | 74 | step(map); 75 | step(map); 76 | step(map); 77 | step(map); 78 | 79 | return ((map[1] >> 3) << 12) | ((map[2] >> 3) << 8) | ((map[3] >> 3) << 4) | 80 | (map[4] >> 3); 81 | } 82 | -------------------------------------------------------------------------------- /examples/0010-struct.c: -------------------------------------------------------------------------------- 1 | struct hoge { 2 | long long int x, y; 3 | }; 4 | 5 | struct hoge piyo(struct hoge h) 6 | { 7 | if (h.x < 0) return h; 8 | 9 | h.x -= 1; 10 | h.y -= 1; 11 | struct hoge ret = piyo(h); 12 | return ret; 13 | } 14 | 15 | int main() 16 | { 17 | struct hoge h = {1, 3}; 18 | return piyo(h).y; 19 | } 20 | -------------------------------------------------------------------------------- /examples/fib.c: -------------------------------------------------------------------------------- 1 | static int fib(int n) { 2 | int a = 0, b = 1; 3 | for (int i = 0; i < n; i++) { 4 | int tmp = a + b; 5 | a = b; 6 | b = tmp; 7 | } 8 | return a; 9 | } 10 | 11 | int main() { 12 | // The result will be set in the register x8. 13 | return fib(5); 14 | } 15 | -------------------------------------------------------------------------------- /examples/mitou.s: -------------------------------------------------------------------------------- 1 | .global main 2 | main: 3 | lsi a1, 2 4 | li a2, 2+377 5 | lsi a3, -1 6 | loop: 7 | lw a0, 0(a1) 8 | xor2 a0, a3 # not a0 9 | sw a0, 0(a1) 10 | addi2 a1, 2 11 | blt a1, a2, loop 12 | hlt 13 | .rodata 14 | .byte 0b00000000 15 | .byte 0b00000000 16 | .byte 0b00000000 17 | .byte 0b00000000 18 | .byte 0b00000000 19 | .byte 0b00000000 20 | .byte 0b00000000 21 | .byte 0b00000000 22 | .byte 0b00000000 23 | .byte 0b00000000 24 | .byte 0b00000000 25 | .byte 0b11000000 26 | .byte 0b00000000 27 | .byte 0b00000000 28 | .byte 0b00000000 29 | .byte 0b00000000 30 | .byte 0b00000000 31 | .byte 0b00000000 32 | .byte 0b00111000 33 | .byte 0b00000000 34 | .byte 0b00000000 35 | .byte 0b00000000 36 | .byte 0b00000000 37 | .byte 0b00000000 38 | .byte 0b00000000 39 | .byte 0b00000111 40 | .byte 0b10000000 41 | .byte 0b00000000 42 | .byte 0b00000000 43 | .byte 0b00000000 44 | .byte 0b00000000 45 | .byte 0b00000000 46 | .byte 0b00000001 47 | .byte 0b11111000 48 | .byte 0b00000000 49 | .byte 0b00000000 50 | .byte 0b00000000 51 | .byte 0b00000000 52 | .byte 0b00000000 53 | .byte 0b00000000 54 | .byte 0b00111111 55 | .byte 0b00000000 56 | .byte 0b00000000 57 | .byte 0b00000000 58 | .byte 0b00000000 59 | .byte 0b00000000 60 | .byte 0b00000000 61 | .byte 0b00001111 62 | .byte 0b11110000 63 | .byte 0b00000000 64 | .byte 0b00000000 65 | .byte 0b00000000 66 | .byte 0b00000000 67 | .byte 0b00000000 68 | .byte 0b00000001 69 | .byte 0b11001110 70 | .byte 0b00000000 71 | .byte 0b00000000 72 | .byte 0b00000000 73 | .byte 0b00000000 74 | .byte 0b00000000 75 | .byte 0b00000000 76 | .byte 0b01111001 77 | .byte 0b11100000 78 | .byte 0b00000000 79 | .byte 0b00000000 80 | .byte 0b00000000 81 | .byte 0b00000000 82 | .byte 0b00000000 83 | .byte 0b00011110 84 | .byte 0b00011100 85 | .byte 0b00000000 86 | .byte 0b00000000 87 | .byte 0b00000000 88 | .byte 0b00000000 89 | .byte 0b00000000 90 | .byte 0b00000011 91 | .byte 0b11000011 92 | .byte 0b11000000 93 | .byte 0b00000000 94 | .byte 0b00000000 95 | .byte 0b00000000 96 | .byte 0b00000000 97 | .byte 0b00000000 98 | .byte 0b11110000 99 | .byte 0b00111100 100 | .byte 0b00000000 101 | .byte 0b00000000 102 | .byte 0b00000000 103 | .byte 0b00000000 104 | .byte 0b00000000 105 | .byte 0b00011100 106 | .byte 0b00000111 107 | .byte 0b10000000 108 | .byte 0b00000000 109 | .byte 0b00000000 110 | .byte 0b00000000 111 | .byte 0b00000000 112 | .byte 0b00000111 113 | .byte 0b10000000 114 | .byte 0b01111000 115 | .byte 0b00000000 116 | .byte 0b00000000 117 | .byte 0b00000000 118 | .byte 0b00000000 119 | .byte 0b00000000 120 | .byte 0b11100000 121 | .byte 0b00000111 122 | .byte 0b00000000 123 | .byte 0b00000000 124 | .byte 0b00000000 125 | .byte 0b00000000 126 | .byte 0b00000000 127 | .byte 0b00111100 128 | .byte 0b00000000 129 | .byte 0b11110000 130 | .byte 0b00000000 131 | .byte 0b00000000 132 | .byte 0b00000000 133 | .byte 0b00000000 134 | .byte 0b00001111 135 | .byte 0b00000000 136 | .byte 0b00001111 137 | .byte 0b00000000 138 | .byte 0b00000000 139 | .byte 0b00000000 140 | .byte 0b00000000 141 | .byte 0b00000001 142 | .byte 0b11000000 143 | .byte 0b00000001 144 | .byte 0b11100000 145 | .byte 0b00000000 146 | .byte 0b00000000 147 | .byte 0b00000000 148 | .byte 0b00000000 149 | .byte 0b01111000 150 | .byte 0b00000000 151 | .byte 0b00011110 152 | .byte 0b00000000 153 | .byte 0b00000000 154 | .byte 0b00000000 155 | .byte 0b00000000 156 | .byte 0b00001111 157 | .byte 0b00000000 158 | .byte 0b00000011 159 | .byte 0b11000000 160 | .byte 0b00000000 161 | .byte 0b00000000 162 | .byte 0b00000000 163 | .byte 0b00000011 164 | .byte 0b11110000 165 | .byte 0b00000000 166 | .byte 0b11111100 167 | .byte 0b00000000 168 | .byte 0b00000000 169 | .byte 0b00000000 170 | .byte 0b00000000 171 | .byte 0b11111110 172 | .byte 0b00000000 173 | .byte 0b00111111 174 | .byte 0b10000000 175 | .byte 0b00000000 176 | .byte 0b00000000 177 | .byte 0b00000000 178 | .byte 0b00011111 179 | .byte 0b11100000 180 | .byte 0b00000111 181 | .byte 0b11111000 182 | .byte 0b00000000 183 | .byte 0b00000000 184 | .byte 0b00000000 185 | .byte 0b00000111 186 | .byte 0b10011110 187 | .byte 0b00000001 188 | .byte 0b11100111 189 | .byte 0b10000000 190 | .byte 0b00000000 191 | .byte 0b00000000 192 | .byte 0b00000000 193 | .byte 0b11100011 194 | .byte 0b11000000 195 | .byte 0b00111000 196 | .byte 0b11110000 197 | .byte 0b00000000 198 | .byte 0b00000000 199 | .byte 0b00000000 200 | .byte 0b00111100 201 | .byte 0b00111100 202 | .byte 0b00001111 203 | .byte 0b00001111 204 | .byte 0b00000000 205 | .byte 0b00000000 206 | .byte 0b00000000 207 | .byte 0b00000111 208 | .byte 0b00000011 209 | .byte 0b10000001 210 | .byte 0b11000000 211 | .byte 0b11100000 212 | .byte 0b00000000 213 | .byte 0b00000000 214 | .byte 0b00000001 215 | .byte 0b11100000 216 | .byte 0b01111000 217 | .byte 0b01111000 218 | .byte 0b00011110 219 | .byte 0b00000000 220 | .byte 0b00000000 221 | .byte 0b00000000 222 | .byte 0b01111000 223 | .byte 0b00000111 224 | .byte 0b00011110 225 | .byte 0b00000001 226 | .byte 0b11000000 227 | .byte 0b00000000 228 | .byte 0b00000000 229 | .byte 0b00001111 230 | .byte 0b00000000 231 | .byte 0b11110011 232 | .byte 0b11000000 233 | .byte 0b00111100 234 | .byte 0b00000000 235 | .byte 0b00000000 236 | .byte 0b00000011 237 | .byte 0b11000000 238 | .byte 0b00001111 239 | .byte 0b11110000 240 | .byte 0b00000011 241 | .byte 0b11000000 242 | .byte 0b00000000 243 | .byte 0b00000000 244 | .byte 0b01110000 245 | .byte 0b00000001 246 | .byte 0b11111100 247 | .byte 0b00000000 248 | .byte 0b01111000 249 | .byte 0b00000000 250 | .byte 0b00000000 251 | .byte 0b00011110 252 | .byte 0b00000000 253 | .byte 0b00011111 254 | .byte 0b10000000 255 | .byte 0b00000111 256 | .byte 0b10000000 257 | .byte 0b00000000 258 | .byte 0b00000011 259 | .byte 0b10000000 260 | .byte 0b00000001 261 | .byte 0b11100000 262 | .byte 0b00000000 263 | .byte 0b01110000 264 | .byte 0b00000000 265 | .byte 0b00000000 266 | .byte 0b11110000 267 | .byte 0b00000000 268 | .byte 0b00111100 269 | .byte 0b00000000 270 | .byte 0b00001111 271 | .byte 0b00000000 272 | .byte 0b00000000 273 | .byte 0b00111100 274 | .byte 0b00000000 275 | .byte 0b00001111 276 | .byte 0b10000000 277 | .byte 0b00000000 278 | .byte 0b11100000 279 | .byte 0b00000000 280 | .byte 0b00000111 281 | .byte 0b10000000 282 | .byte 0b00000001 283 | .byte 0b11111000 284 | .byte 0b00000000 285 | .byte 0b00011110 286 | .byte 0b00000000 287 | .byte 0b00000001 288 | .byte 0b11100000 289 | .byte 0b00000000 290 | .byte 0b01111111 291 | .byte 0b10000000 292 | .byte 0b00000001 293 | .byte 0b11100000 294 | .byte 0b00000000 295 | .byte 0b00111000 296 | .byte 0b00000000 297 | .byte 0b00001110 298 | .byte 0b11110000 299 | .byte 0b00000000 300 | .byte 0b00011100 301 | .byte 0b00000000 302 | .byte 0b00001111 303 | .byte 0b00000000 304 | .byte 0b00000011 305 | .byte 0b11001111 306 | .byte 0b00000000 307 | .byte 0b00000011 308 | .byte 0b11000000 309 | .byte 0b00000001 310 | .byte 0b11000000 311 | .byte 0b00000000 312 | .byte 0b01110000 313 | .byte 0b11100000 314 | .byte 0b00000000 315 | .byte 0b00111000 316 | .byte 0b00000000 317 | .byte 0b01111000 318 | .byte 0b00000000 319 | .byte 0b00011110 320 | .byte 0b00011110 321 | .byte 0b00000000 322 | .byte 0b00000111 323 | .byte 0b10000000 324 | .byte 0b00011110 325 | .byte 0b00000000 326 | .byte 0b00000111 327 | .byte 0b10000001 328 | .byte 0b11000000 329 | .byte 0b00000000 330 | .byte 0b01111000 331 | .byte 0b00000011 332 | .byte 0b10000000 333 | .byte 0b00000000 334 | .byte 0b11100000 335 | .byte 0b00111100 336 | .byte 0b00000000 337 | .byte 0b00001111 338 | .byte 0b00000000 339 | .byte 0b11110000 340 | .byte 0b00000000 341 | .byte 0b00111100 342 | .byte 0b00000011 343 | .byte 0b11000000 344 | .byte 0b00000000 345 | .byte 0b11110000 346 | .byte 0b00011100 347 | .byte 0b00000000 348 | .byte 0b00000111 349 | .byte 0b00000000 350 | .byte 0b00111000 351 | .byte 0b00000000 352 | .byte 0b00001110 353 | .byte 0b00000111 354 | .byte 0b10000000 355 | .byte 0b00000001 356 | .byte 0b11100000 357 | .byte 0b00000111 358 | .byte 0b10000000 359 | .byte 0b00000001 360 | .byte 0b11100001 361 | .byte 0b11100000 362 | .byte 0b00000000 363 | .byte 0b01111000 364 | .byte 0b00000000 365 | .byte 0b01110000 366 | .byte 0b00000000 367 | .byte 0b00011100 368 | .byte 0b00111111 369 | .byte 0b11111111 370 | .byte 0b11111111 371 | .byte 0b00000000 372 | .byte 0b00001111 373 | .byte 0b11111111 374 | .byte 0b11111111 375 | .byte 0b11001111 376 | .byte 0b11111111 377 | .byte 0b11111111 378 | .byte 0b11000000 379 | .byte 0b00000000 380 | .byte 0b11111111 381 | .byte 0b11111111 382 | .byte 0b11111101 383 | .byte 0b11111111 384 | .byte 0b11111111 385 | .byte 0b11110000 386 | .byte 0b00000000 387 | .byte 0b00011111 388 | .byte 0b11111111 389 | .byte 0b11111111 390 | .byte 0b11111111 391 | -------------------------------------------------------------------------------- /kvsp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "debug/elf" 5 | "errors" 6 | "flag" 7 | "fmt" 8 | "io" 9 | "io/ioutil" 10 | "log" 11 | "os" 12 | "os/exec" 13 | "path/filepath" 14 | "strings" 15 | "time" 16 | 17 | "github.com/BurntSushi/toml" 18 | ) 19 | 20 | var flagVerbose bool 21 | 22 | const defaultCAHPProc = "ruby" 23 | const defaultROMSize = 512 24 | const defaultRAMSize = 512 25 | 26 | // Flag for a list of values 27 | // Thanks to: https://stackoverflow.com/a/28323276 28 | type arrayFlags []string 29 | 30 | func (i *arrayFlags) String() string { 31 | return "my string representation" 32 | } 33 | 34 | func (i *arrayFlags) Set(value string) error { 35 | *i = append(*i, value) 36 | return nil 37 | } 38 | 39 | func write16le(out []byte, val int) { 40 | out[0] = byte(val & 0xff) 41 | out[1] = byte((val >> 8) & 0xff) 42 | } 43 | 44 | func fileExists(path string) bool { 45 | _, err := os.Stat(path) 46 | return err == nil 47 | } 48 | 49 | func getExecDir() (string, error) { 50 | execPath, err := os.Executable() 51 | if err != nil { 52 | return "", err 53 | } 54 | return filepath.Dir(execPath), nil 55 | } 56 | 57 | func prefixExecDir(path string) (string, error) { 58 | execPath, err := getExecDir() 59 | if err != nil { 60 | return "", err 61 | } 62 | return filepath.Join(execPath, path), nil 63 | } 64 | 65 | func getPathOf(name string) (string, error) { 66 | path := "" 67 | relative := true 68 | 69 | // Check if environment variable is set in KVSP_XXX. 70 | if path = os.Getenv("KVSP_" + strings.Replace(name, "-", "_", -1) + "_PATH"); path != "" { 71 | relative = false 72 | } else { 73 | /* 74 | Do heuristic approach, which assumes binaries are in the current 75 | (this executable's) directory, and others are in ../share/kvsp. 76 | */ 77 | switch name { 78 | case "CAHP_RT": 79 | path = "../share/kvsp/cahp-rt" 80 | case "CAHP_SIM": 81 | path = "cahp-sim" 82 | case "CLANG": 83 | path = "clang" 84 | case "IYOKAN": 85 | path = "iyokan" 86 | case "IYOKAN-BLUEPRINT-RUBY": 87 | path = "../share/kvsp/cahp-ruby.toml" 88 | case "IYOKAN-BLUEPRINT-PEARL": 89 | path = "../share/kvsp/cahp-pearl.toml" 90 | case "IYOKAN-PACKET": 91 | path = "iyokan-packet" 92 | default: 93 | return "", errors.New("Invalid name") 94 | } 95 | } 96 | 97 | if relative { 98 | newPath, err := prefixExecDir(path) 99 | if err != nil { 100 | return "", err 101 | } 102 | path = newPath 103 | } 104 | 105 | if !fileExists(path) { 106 | return "", fmt.Errorf("%s not found at %s", name, path) 107 | } 108 | 109 | return path, nil 110 | } 111 | 112 | // Parse the input as ELF and get ROM and RAM images. 113 | func parseELF(fileName string, romSize, ramSize uint64) ([]byte, []byte, error) { 114 | input, err := elf.Open(fileName) 115 | if err != nil { 116 | return nil, nil, err 117 | } 118 | 119 | rom := make([]byte, romSize) 120 | ram := make([]byte, ramSize) 121 | 122 | for _, prog := range input.Progs { 123 | addr := prog.ProgHeader.Vaddr 124 | size := prog.ProgHeader.Filesz 125 | if size == 0 { 126 | continue 127 | } 128 | 129 | var mem []byte 130 | if addr < 0x10000 { // ROM 131 | if addr+size >= romSize { 132 | return nil, nil, errors.New("Invalid ROM size: too small") 133 | } 134 | mem = rom[addr : addr+size] 135 | } else { // RAM 136 | if addr-0x10000+size >= ramSize { 137 | return nil, nil, errors.New("Invalid RAM size: too small") 138 | } 139 | mem = ram[addr-0x10000 : addr-0x10000+size] 140 | } 141 | 142 | reader := prog.Open() 143 | _, err := reader.Read(mem) 144 | if err != nil { 145 | return nil, nil, err 146 | } 147 | } 148 | 149 | return rom, ram, nil 150 | } 151 | 152 | func attachCommandLineOptions(ram []byte, cmdOptsSrc []string) error { 153 | // N1548 5.1.2.2.1 2 154 | // the string pointed to by argv[0] 155 | // represents the program name; argv[0][0] shall be the null character if the 156 | // program name is not available from the host environment. 157 | cmdOpts := []string{""} 158 | cmdOpts = append(cmdOpts, cmdOptsSrc...) 159 | argc := len(cmdOpts) 160 | 161 | // Slice for *argv. 162 | sargv := []int{ 163 | // N1548 5.1.2.2.1 2 164 | // argv[argc] shall be a null pointer. 165 | 0, 166 | } 167 | 168 | ramSize := len(ram) 169 | index := ramSize - 2 170 | 171 | // Set **argv to RAM 172 | for i := len(cmdOpts) - 1; i >= 0; i-- { 173 | opt := append([]byte(cmdOpts[i]), 0) 174 | for j := len(opt) - 1; j >= 0; j-- { 175 | index-- 176 | ram[index] = opt[j] 177 | } 178 | sargv = append(sargv, index) 179 | } 180 | // Align index 181 | if index%2 == 1 { 182 | index-- 183 | } 184 | // Set *argv to RAM 185 | for _, val := range sargv { 186 | index -= 2 187 | write16le(ram[index:index+2], val) 188 | } 189 | // Save argc in RAM 190 | index -= 2 191 | write16le(ram[index:index+2], argc) 192 | // Save initial stack pointer in RAM 193 | initSP := index 194 | write16le(ram[ramSize-2:ramSize], initSP) 195 | 196 | return nil 197 | } 198 | 199 | func execCmdImpl(name string, args []string) *exec.Cmd { 200 | if flagVerbose { 201 | fmtArgs := make([]string, len(args)) 202 | for i, arg := range args { 203 | fmtArgs[i] = fmt.Sprintf("'%s'", arg) 204 | } 205 | fmt.Fprintf(os.Stderr, "exec: '%s' %s\n", name, strings.Join(fmtArgs, " ")) 206 | } 207 | 208 | cmd := exec.Command(name, args...) 209 | cmd.Stderr = os.Stderr 210 | return cmd 211 | } 212 | 213 | func execCmd(name string, args []string) error { 214 | cmd := execCmdImpl(name, args) 215 | cmd.Stdin = os.Stdin 216 | cmd.Stdout = os.Stdout 217 | return cmd.Run() 218 | } 219 | 220 | func outCmd(name string, args []string) (string, error) { 221 | out, err := execCmdImpl(name, args).Output() 222 | return string(out), err 223 | } 224 | 225 | func runIyokanPacket(args ...string) (string, error) { 226 | // Get the path of iyokan-packet 227 | path, err := getPathOf("IYOKAN-PACKET") 228 | if err != nil { 229 | return "", err 230 | } 231 | 232 | // Run 233 | return outCmd(path, args) 234 | } 235 | 236 | func runIyokan(args0 []string, args1 []string) error { 237 | iyokanPath, err := getPathOf("IYOKAN") 238 | if err != nil { 239 | return err 240 | } 241 | 242 | // Run iyokan 243 | args := append(args0, args1...) 244 | return execCmd(iyokanPath, args) 245 | } 246 | 247 | func packELF( 248 | inputFileName, outputFileName string, 249 | cmdOpts []string, 250 | romSize, ramSize uint64, 251 | ) error { 252 | if !fileExists(inputFileName) { 253 | return errors.New("File not found") 254 | } 255 | rom, ram, err := parseELF(inputFileName, romSize, ramSize) 256 | if err != nil { 257 | return err 258 | } 259 | if err = attachCommandLineOptions(ram, cmdOpts); err != nil { 260 | return err 261 | } 262 | 263 | args := []string{ 264 | "pack", 265 | "--out", outputFileName, 266 | } 267 | 268 | // Write ROM data 269 | romTmpFile, err := ioutil.TempFile("", "") 270 | if err != nil { 271 | return err 272 | } 273 | defer os.Remove(romTmpFile.Name()) 274 | if _, err = romTmpFile.Write(rom); err != nil { 275 | return err 276 | } 277 | args = append(args, "--rom", "rom:"+romTmpFile.Name()) 278 | 279 | // Write RAM data 280 | ramTmpFile, err := ioutil.TempFile("", "") 281 | if err != nil { 282 | return err 283 | } 284 | defer os.Remove(ramTmpFile.Name()) 285 | if _, err = ramTmpFile.Write(ram); err != nil { 286 | return err 287 | } 288 | args = append(args, "--ram", "ram:"+ramTmpFile.Name()) 289 | 290 | // Pack 291 | if _, err = runIyokanPacket(args...); err != nil { 292 | return err 293 | } 294 | 295 | return nil 296 | } 297 | 298 | type plainPacketTOML struct { 299 | NumCycles int `toml:"cycles"` 300 | Ram []plainPacketEntryTOML `toml:"ram"` 301 | Bits []plainPacketEntryTOML `toml:"bits"` 302 | } 303 | type plainPacketEntryTOML struct { 304 | Name string `toml:"name"` 305 | Size int `toml:"size"` 306 | Bytes []int `toml:"bytes"` 307 | } 308 | type plainPacket struct { 309 | NumCycles int 310 | Flags map[string]bool 311 | Regs map[string]int 312 | Ram []int 313 | } 314 | 315 | func (pkt *plainPacket) loadTOML(src string) error { 316 | var pktTOML plainPacketTOML 317 | if _, err := toml.Decode(src, &pktTOML); err != nil { 318 | return err 319 | } 320 | 321 | pkt.NumCycles = pktTOML.NumCycles 322 | 323 | // Load flags and registers 324 | pkt.Flags = make(map[string]bool) 325 | pkt.Regs = make(map[string]int) 326 | for _, entry := range pktTOML.Bits { 327 | if entry.Size == 1 { // flag 328 | if entry.Bytes[0] != 0 { 329 | pkt.Flags[entry.Name] = true 330 | } else { 331 | pkt.Flags[entry.Name] = false 332 | } 333 | } else if entry.Size == 16 { // register 334 | pkt.Regs[entry.Name] = entry.Bytes[0] | (entry.Bytes[1] << 8) 335 | } else { 336 | return errors.New("Invalid TOML for result packet") 337 | } 338 | } 339 | 340 | // Load ram 341 | mapRam := make(map[string]plainPacketEntryTOML) 342 | for _, entry := range pktTOML.Ram { 343 | if _, exists := mapRam[entry.Name]; exists { 344 | return errors.New("Invalid TOML data: same entry name in ram") 345 | } 346 | mapRam[entry.Name] = entry 347 | } 348 | pkt.Ram = nil 349 | if entry, ok := mapRam["ram"]; ok { 350 | if entry.Size%8 != 0 { 351 | return errors.New("Invalid RAM data: size is not multiple of 8") 352 | } 353 | pkt.Ram = make([]int, entry.Size/8) 354 | for addr := range entry.Bytes { 355 | pkt.Ram[addr] = entry.Bytes[addr] 356 | } 357 | } else { 358 | return errors.New("Invalid TOML for result packet") 359 | } 360 | 361 | // Check if the packet is correct 362 | if _, ok := pkt.Flags["finflag"]; !ok { 363 | return errors.New("Invalid TOML for result packet: 'finflag' not found") 364 | } 365 | for i := 0; i < 16; i++ { 366 | name := fmt.Sprintf("reg_x%d", i) 367 | if _, ok := pkt.Regs[name]; !ok { 368 | return errors.New("Invalid TOML for result packet: '" + name + "' not found") 369 | } 370 | } 371 | 372 | return nil 373 | } 374 | func (pkt *plainPacket) print(w io.Writer) error { 375 | fmt.Fprintf(w, "#cycle\t%d\n", pkt.NumCycles) 376 | fmt.Fprintf(w, "\n") 377 | fmt.Fprintf(w, "f0\t%t\n", pkt.Flags["finflag"]) 378 | fmt.Fprintf(w, "\n") 379 | for i := 0; i < 16; i++ { 380 | name := fmt.Sprintf("reg_x%d", i) 381 | fmt.Fprintf(w, "x%d\t%d\n", i, pkt.Regs[name]) 382 | } 383 | fmt.Fprintf(w, "\n") 384 | fmt.Fprintf(w, " \t 0 1 2 3 4 5 6 7 8 9 a b c d e f") 385 | for addr := 0; addr < len(pkt.Ram); addr++ { 386 | if addr%16 == 0 { 387 | fmt.Fprintf(w, "\n%06x\t", addr) 388 | } 389 | fmt.Fprintf(w, "%02x ", pkt.Ram[addr]) 390 | } 391 | fmt.Fprintf(w, "\n") 392 | 393 | return nil 394 | } 395 | 396 | func doCC() error { 397 | // Get the path of clang 398 | path, err := getPathOf("CLANG") 399 | if err != nil { 400 | return err 401 | } 402 | 403 | // Get the path of cahp-rt 404 | cahpRtPath, err := getPathOf("CAHP_RT") 405 | if err != nil { 406 | return err 407 | } 408 | 409 | // Run 410 | args := []string{"-target", "cahp", "-mcpu=generic", "-Oz", "--sysroot", cahpRtPath} 411 | args = append(args, os.Args[2:]...) 412 | return execCmd(path, args) 413 | } 414 | 415 | func doDebug() error { 416 | // Get the path of cahp-sim 417 | path, err := getPathOf("CAHP_SIM") 418 | if err != nil { 419 | return err 420 | } 421 | 422 | // Run 423 | return execCmd(path, os.Args[2:]) 424 | } 425 | 426 | func doEmu() error { 427 | // Parse command-line arguments. 428 | fs := flag.NewFlagSet("emu", flag.ExitOnError) 429 | var ( 430 | whichCAHPCPU = fs.String("cahp-cpu", defaultCAHPProc, "Which CAHP CPU you use, ruby or pearl") 431 | iyokanArgs arrayFlags 432 | ) 433 | fs.Var(&iyokanArgs, "iyokan-args", "Raw arguments for Iyokan") 434 | err := fs.Parse(os.Args[2:]) 435 | 436 | // Create tmp file for packing 437 | packedFile, err := ioutil.TempFile("", "") 438 | if err != nil { 439 | return err 440 | } 441 | defer os.Remove(packedFile.Name()) 442 | 443 | // Pack 444 | err = packELF(fs.Args()[0], packedFile.Name(), fs.Args()[1:], defaultROMSize, defaultRAMSize) 445 | if err != nil { 446 | return err 447 | } 448 | 449 | // Create tmp file for the result 450 | resTmpFile, err := ioutil.TempFile("", "") 451 | if err != nil { 452 | return err 453 | } 454 | defer os.Remove(resTmpFile.Name()) 455 | 456 | // Run Iyokan in plain mode 457 | blueprint, err := getPathOf(fmt.Sprintf("IYOKAN-BLUEPRINT-%s", strings.ToUpper(*whichCAHPCPU))) 458 | if err != nil { 459 | return err 460 | } 461 | err = runIyokan([]string{"plain", "-i", packedFile.Name(), "-o", resTmpFile.Name(), "--blueprint", blueprint}, iyokanArgs) 462 | if err != nil { 463 | return err 464 | } 465 | 466 | // Unpack the result 467 | result, err := runIyokanPacket("packet2toml", "--in", resTmpFile.Name()) 468 | if err != nil { 469 | return err 470 | } 471 | 472 | // Parse and print the result 473 | var pkt plainPacket 474 | if err := pkt.loadTOML(result); err != nil { 475 | return err 476 | } 477 | pkt.print(os.Stdout) 478 | 479 | return nil 480 | } 481 | 482 | func doDec() error { 483 | // Parse command-line arguments. 484 | fs := flag.NewFlagSet("dec", flag.ExitOnError) 485 | var ( 486 | keyFileName = fs.String("k", "", "Key file name") 487 | inputFileName = fs.String("i", "", "Input file name (encrypted)") 488 | ) 489 | err := fs.Parse(os.Args[2:]) 490 | if err != nil { 491 | return err 492 | } 493 | if *keyFileName == "" || *inputFileName == "" { 494 | return errors.New("Specify -k and -i options properly") 495 | } 496 | 497 | // Create tmp file for decryption 498 | packedFile, err := ioutil.TempFile("", "") 499 | if err != nil { 500 | return err 501 | } 502 | defer os.Remove(packedFile.Name()) 503 | 504 | // Decrypt 505 | _, err = runIyokanPacket("dec", 506 | "--key", *keyFileName, 507 | "--in", *inputFileName, 508 | "--out", packedFile.Name()) 509 | 510 | // Unpack 511 | result, err := runIyokanPacket("packet2toml", "--in", packedFile.Name()) 512 | if err != nil { 513 | return err 514 | } 515 | 516 | // Parse and print the result 517 | var pkt plainPacket 518 | if err := pkt.loadTOML(result); err != nil { 519 | return err 520 | } 521 | pkt.print(os.Stdout) 522 | 523 | return nil 524 | } 525 | 526 | func doEnc() error { 527 | // Parse command-line arguments. 528 | fs := flag.NewFlagSet("enc", flag.ExitOnError) 529 | var ( 530 | keyFileName = fs.String("k", "", "Secret key file name") 531 | inputFileName = fs.String("i", "", "Input file name (plain)") 532 | outputFileName = fs.String("o", "", "Output file name (encrypted)") 533 | ) 534 | err := fs.Parse(os.Args[2:]) 535 | if err != nil { 536 | return err 537 | } 538 | if *keyFileName == "" || *inputFileName == "" || *outputFileName == "" { 539 | return errors.New("Specify -k, -i, and -o options properly") 540 | } 541 | 542 | // Create tmp file for packing 543 | packedFile, err := ioutil.TempFile("", "") 544 | if err != nil { 545 | return err 546 | } 547 | defer os.Remove(packedFile.Name()) 548 | 549 | // Pack 550 | err = packELF(*inputFileName, packedFile.Name(), fs.Args(), defaultROMSize, defaultRAMSize) 551 | if err != nil { 552 | return err 553 | } 554 | 555 | // Encrypt 556 | _, err = runIyokanPacket("enc", 557 | "--key", *keyFileName, 558 | "--in", packedFile.Name(), 559 | "--out", *outputFileName) 560 | return err 561 | } 562 | 563 | func doGenkey() error { 564 | // Parse command-line arguments. 565 | fs := flag.NewFlagSet("genkey", flag.ExitOnError) 566 | var ( 567 | outputFileName = fs.String("o", "", "Output file name") 568 | ) 569 | err := fs.Parse(os.Args[2:]) 570 | if err != nil { 571 | return err 572 | } 573 | if *outputFileName == "" { 574 | return errors.New("Specify -o options properly") 575 | } 576 | 577 | _, err = runIyokanPacket("genkey", 578 | "--type", "tfhepp", 579 | "--out", *outputFileName) 580 | return err 581 | } 582 | 583 | func doGenbkey() error { 584 | // Parse command-line arguments. 585 | fs := flag.NewFlagSet("genbkey", flag.ExitOnError) 586 | var ( 587 | inputFileName = fs.String("i", "", "Input file name (secret key)") 588 | outputFileName = fs.String("o", "", "Output file name (bootstrapping key)") 589 | ) 590 | err := fs.Parse(os.Args[2:]) 591 | if err != nil { 592 | return err 593 | } 594 | if *inputFileName == "" || *outputFileName == "" { 595 | return errors.New("Specify -i and -o options properly") 596 | } 597 | 598 | _, err = runIyokanPacket("genbkey", 599 | "--in", *inputFileName, 600 | "--out", *outputFileName) 601 | 602 | return err 603 | } 604 | 605 | func doPlainpacket() error { 606 | // Parse command-line arguments. 607 | fs := flag.NewFlagSet("plainpacket", flag.ExitOnError) 608 | var ( 609 | inputFileName = fs.String("i", "", "Input file name (plain)") 610 | outputFileName = fs.String("o", "", "Output file name (encrypted)") 611 | ) 612 | err := fs.Parse(os.Args[2:]) 613 | if err != nil { 614 | return err 615 | } 616 | if *inputFileName == "" || *outputFileName == "" { 617 | return errors.New("Specify -i, and -o options properly") 618 | } 619 | 620 | return packELF(*inputFileName, *outputFileName, fs.Args(), defaultROMSize, defaultRAMSize) 621 | } 622 | 623 | func doRun() error { 624 | // Parse command-line arguments. 625 | fs := flag.NewFlagSet("run", flag.ExitOnError) 626 | var ( 627 | nClocks = fs.Uint("c", 0, "Number of clocks to run") 628 | bkeyFileName = fs.String("bkey", "", "Bootstrapping key file name") 629 | inputFileName = fs.String("i", "", "Input file name (encrypted)") 630 | outputFileName = fs.String("o", "", "Output file name (encrypted)") 631 | numGPU = fs.Uint("g", 0, "Number of GPUs (Unspecify or set 0 for CPU mode)") 632 | whichCAHPCPU = fs.String("cahp-cpu", defaultCAHPProc, "Which CAHP CPU you use, ruby or pearl") 633 | snapshotFileName = fs.String("snapshot", "", "Snapshot file name to write in") 634 | quiet = fs.Bool("quiet", false, "Be quiet") 635 | iyokanArgs arrayFlags 636 | ) 637 | fs.Var(&iyokanArgs, "iyokan-args", "Raw arguments for Iyokan") 638 | err := fs.Parse(os.Args[2:]) 639 | if err != nil { 640 | return err 641 | } 642 | 643 | if *nClocks == 0 || *bkeyFileName == "" || *inputFileName == "" || *outputFileName == "" { 644 | return errors.New("Specify -c, -bkey, -i, and -o options properly") 645 | } 646 | 647 | blueprint, err := getPathOf(fmt.Sprintf("IYOKAN-BLUEPRINT-%s", strings.ToUpper(*whichCAHPCPU))) 648 | if err != nil { 649 | return err 650 | } 651 | 652 | args := []string{ 653 | "-i", *inputFileName, 654 | "--blueprint", blueprint, 655 | } 656 | if *numGPU > 0 { 657 | args = append(args, "--enable-gpu", "--gpu_num", fmt.Sprint(*numGPU)) 658 | } 659 | 660 | return runIyokanTFHE(*nClocks, *bkeyFileName, *outputFileName, *snapshotFileName, *quiet, args, iyokanArgs) 661 | } 662 | 663 | func doResume() error { 664 | // Parse command-line arguments. 665 | fs := flag.NewFlagSet("resume", flag.ExitOnError) 666 | var ( 667 | nClocks = fs.Uint("c", 0, "Number of clocks to run") 668 | bkeyFileName = fs.String("bkey", "", "Bootstrapping key file name") 669 | inputFileName = fs.String("i", "", "Snapshot file to resume from") 670 | outputFileName = fs.String("o", "", "Output file name (encrypted)") 671 | snapshotFileName = fs.String("snapshot", "", "Snapshot file name to write in") 672 | quiet = fs.Bool("quiet", false, "Be quiet") 673 | iyokanArgs arrayFlags 674 | ) 675 | fs.Var(&iyokanArgs, "iyokan-args", "Raw arguments for Iyokan") 676 | err := fs.Parse(os.Args[2:]) 677 | if err != nil { 678 | return err 679 | } 680 | 681 | if *nClocks == 0 || *bkeyFileName == "" || *inputFileName == "" || *outputFileName == "" { 682 | return errors.New("Specify -c, -bkey, -i, and -o options properly") 683 | } 684 | 685 | args := []string{ 686 | "--resume", *inputFileName, 687 | } 688 | return runIyokanTFHE(*nClocks, *bkeyFileName, *outputFileName, *snapshotFileName, *quiet, args, iyokanArgs) 689 | } 690 | 691 | func runIyokanTFHE(nClocks uint, bkeyFileName string, outputFileName string, snapshotFileName string, quiet bool, otherArgs0 []string, otherArgs1 []string) error { 692 | var err error 693 | 694 | if snapshotFileName == "" { 695 | snapshotFileName = fmt.Sprintf( 696 | "kvsp_%s.snapshot", time.Now().Format("20060102150405")) 697 | } 698 | 699 | args := []string{ 700 | "tfhe", 701 | "--bkey", bkeyFileName, 702 | "-o", outputFileName, 703 | "-c", fmt.Sprint(nClocks), 704 | "--snapshot", snapshotFileName, 705 | } 706 | if quiet { 707 | args = append(args, "--quiet") 708 | } 709 | args = append(args, otherArgs0...) 710 | args = append(args, otherArgs1...) 711 | if err = runIyokan(args, []string{}); err != nil { 712 | return err 713 | } 714 | 715 | if !quiet { 716 | fmt.Printf("\n") 717 | fmt.Printf("Snapshot was taken as file '%s'. You can resume the process like:\n", snapshotFileName) 718 | fmt.Printf("\t$ %s resume -c %d -i %s -o %s -bkey %s\n", 719 | os.Args[0], nClocks, snapshotFileName, outputFileName, bkeyFileName) 720 | } 721 | 722 | return nil 723 | } 724 | 725 | var kvspVersion = "unk" 726 | var kvspRevision = "unk" 727 | var iyokanRevision = "unk" 728 | var iyokanL1Revision = "unk" 729 | var cahpRubyRevision = "unk" 730 | var cahpPearlRevision = "unk" 731 | var cahpRtRevision = "unk" 732 | var cahpSimRevision = "unk" 733 | var llvmCahpRevision = "unk" 734 | var yosysRevision = "unk" 735 | 736 | func doVersion() error { 737 | fmt.Printf("KVSP %s\t(rev %s)\n", kvspVersion, kvspRevision) 738 | fmt.Printf("- Iyokan\t(rev %s)\n", iyokanRevision) 739 | fmt.Printf("- Iyokan-L1\t(rev %s)\n", iyokanL1Revision) 740 | fmt.Printf("- cahp-ruby\t(rev %s)\n", cahpRubyRevision) 741 | fmt.Printf("- cahp-pearl\t(rev %s)\n", cahpPearlRevision) 742 | fmt.Printf("- cahp-rt\t(rev %s)\n", cahpRtRevision) 743 | fmt.Printf("- cahp-sim\t(rev %s)\n", cahpSimRevision) 744 | fmt.Printf("- llvm-cahp\t(rev %s)\n", llvmCahpRevision) 745 | fmt.Printf("- Yosys\t(rev %s)\n", yosysRevision) 746 | return nil 747 | } 748 | 749 | func main() { 750 | if envvarVerbose := os.Getenv("KVSP_VERBOSE"); envvarVerbose == "1" { 751 | flagVerbose = true 752 | } 753 | 754 | flag.Usage = func() { 755 | fmt.Fprintf(os.Stderr, `Usage: %s COMMAND [OPTIONS]... ARGS... 756 | 757 | KVSP is the first virtual secure platform in the world, which makes your life better. 758 | 759 | Commands: 760 | cc 761 | debug 762 | dec 763 | emu 764 | enc 765 | genkey 766 | genbkey 767 | plainpacket 768 | resume 769 | run 770 | version 771 | `, os.Args[0]) 772 | flag.PrintDefaults() 773 | } 774 | 775 | if len(os.Args) <= 1 { 776 | flag.Usage() 777 | os.Exit(1) 778 | } 779 | 780 | var err error 781 | switch os.Args[1] { 782 | case "cc": 783 | err = doCC() 784 | case "debug": 785 | err = doDebug() 786 | case "dec": 787 | err = doDec() 788 | case "emu": 789 | err = doEmu() 790 | case "enc": 791 | err = doEnc() 792 | case "genkey": 793 | err = doGenkey() 794 | case "genbkey": 795 | err = doGenbkey() 796 | case "plainpacket": 797 | err = doPlainpacket() 798 | case "resume": 799 | err = doResume() 800 | case "run": 801 | err = doRun() 802 | case "version": 803 | err = doVersion() 804 | default: 805 | flag.Usage() 806 | os.Exit(1) 807 | } 808 | 809 | if err != nil { 810 | log.Fatal(err) 811 | os.Exit(1) 812 | } 813 | } 814 | -------------------------------------------------------------------------------- /share/cahp-pearl.toml: -------------------------------------------------------------------------------- 1 | [[file]] 2 | type = "iyokanl1-json" 3 | path = "pearl-core.json" 4 | name = "core" 5 | 6 | [[builtin]] 7 | type = "rom" 8 | name = "rom" 9 | in_addr_width = 7 10 | out_rdata_width = 32 11 | 12 | [[builtin]] 13 | type = "ram" 14 | name = "ram" 15 | in_addr_width = 8 16 | in_wdata_width = 16 17 | out_rdata_width = 16 18 | 19 | [connect] 20 | "rom/addr[0:6]" = "core/io_rom_addr[0:6]" 21 | "core/io_rom_data[0:31]" = "rom/rdata[0:31]" 22 | 23 | "ram/wren" = "core/io_ram_writeEnable" 24 | "ram/addr[0:7]" = "core/io_ram_addr[0:7]" 25 | "ram/wdata[0:15]" = "core/io_ram_writeData[0:15]" 26 | "core/io_ram_readData[0:15]" = "ram/rdata[0:15]" 27 | 28 | "core/reset" = "@reset" 29 | "@finflag" = "core/io_finishFlag" 30 | 31 | "@reg_x0[0:15]" = "core/io_mainRegOut_x0[0:15]" 32 | "@reg_x1[0:15]" = "core/io_mainRegOut_x1[0:15]" 33 | "@reg_x2[0:15]" = "core/io_mainRegOut_x2[0:15]" 34 | "@reg_x3[0:15]" = "core/io_mainRegOut_x3[0:15]" 35 | "@reg_x4[0:15]" = "core/io_mainRegOut_x4[0:15]" 36 | "@reg_x5[0:15]" = "core/io_mainRegOut_x5[0:15]" 37 | "@reg_x6[0:15]" = "core/io_mainRegOut_x6[0:15]" 38 | "@reg_x7[0:15]" = "core/io_mainRegOut_x7[0:15]" 39 | "@reg_x8[0:15]" = "core/io_mainRegOut_x8[0:15]" 40 | "@reg_x9[0:15]" = "core/io_mainRegOut_x9[0:15]" 41 | "@reg_x10[0:15]" = "core/io_mainRegOut_x10[0:15]" 42 | "@reg_x11[0:15]" = "core/io_mainRegOut_x11[0:15]" 43 | "@reg_x12[0:15]" = "core/io_mainRegOut_x12[0:15]" 44 | "@reg_x13[0:15]" = "core/io_mainRegOut_x13[0:15]" 45 | "@reg_x14[0:15]" = "core/io_mainRegOut_x14[0:15]" 46 | "@reg_x15[0:15]" = "core/io_mainRegOut_x15[0:15]" 47 | -------------------------------------------------------------------------------- /share/cahp-ruby.toml: -------------------------------------------------------------------------------- 1 | [[file]] 2 | type = "iyokanl1-json" 3 | path = "ruby-core.json" 4 | name = "core" 5 | 6 | [[builtin]] 7 | type = "rom" 8 | name = "rom" 9 | in_addr_width = 7 10 | out_rdata_width = 32 11 | 12 | [[builtin]] 13 | type = "ram" 14 | name = "ram" 15 | in_addr_width = 8 16 | in_wdata_width = 16 17 | out_rdata_width = 16 18 | 19 | [connect] 20 | "rom/addr[0:6]" = "core/io_rom_addr[0:6]" 21 | "core/io_rom_data[0:31]" = "rom/rdata[0:31]" 22 | 23 | "ram/wren" = "core/io_ram_writeEnable" 24 | "ram/addr[0:7]" = "core/io_ram_addr[0:7]" 25 | "ram/wdata[0:15]" = "core/io_ram_writeData[0:15]" 26 | "core/io_ram_readData[0:15]" = "ram/rdata[0:15]" 27 | 28 | "core/reset" = "@reset" 29 | "@finflag" = "core/io_finishFlag" 30 | 31 | "@reg_x0[0:15]" = "core/io_mainRegOut_x0[0:15]" 32 | "@reg_x1[0:15]" = "core/io_mainRegOut_x1[0:15]" 33 | "@reg_x2[0:15]" = "core/io_mainRegOut_x2[0:15]" 34 | "@reg_x3[0:15]" = "core/io_mainRegOut_x3[0:15]" 35 | "@reg_x4[0:15]" = "core/io_mainRegOut_x4[0:15]" 36 | "@reg_x5[0:15]" = "core/io_mainRegOut_x5[0:15]" 37 | "@reg_x6[0:15]" = "core/io_mainRegOut_x6[0:15]" 38 | "@reg_x7[0:15]" = "core/io_mainRegOut_x7[0:15]" 39 | "@reg_x8[0:15]" = "core/io_mainRegOut_x8[0:15]" 40 | "@reg_x9[0:15]" = "core/io_mainRegOut_x9[0:15]" 41 | "@reg_x10[0:15]" = "core/io_mainRegOut_x10[0:15]" 42 | "@reg_x11[0:15]" = "core/io_mainRegOut_x11[0:15]" 43 | "@reg_x12[0:15]" = "core/io_mainRegOut_x12[0:15]" 44 | "@reg_x13[0:15]" = "core/io_mainRegOut_x13[0:15]" 45 | "@reg_x14[0:15]" = "core/io_mainRegOut_x14[0:15]" 46 | "@reg_x15[0:15]" = "core/io_mainRegOut_x15[0:15]" 47 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xeu 2 | 3 | failwith() { 4 | echo -e "\e[1;31m[ERROR]\e[0m $1" >&2 5 | exit 1 6 | } 7 | 8 | [ $# -ge 1 ] || failwith "Usage: $0 PATH-TO-BIN [ARGS-TO-KVSP-RUN]..." 9 | 10 | KVSP=$1/kvsp 11 | shift 12 | KVSP_RUN_OPTIONS="$@" 13 | 14 | # Check if KVSP is correct 15 | [ -x "$KVSP" ] || failwith "Invalid executable of kvsp" 16 | 17 | # Prepare keys 18 | [ -f _test.sk ] || "$KVSP" genkey -o _test.sk 19 | [ -f _test.bk ] || "$KVSP" genbkey -i _test.sk -o _test.bk 20 | 21 | letstest() { 22 | cmdargs="$1" 23 | expected="$2" 24 | "$KVSP" cc _test.c -o _test.exe 25 | ncycles=$("$KVSP" emu _test.exe $cmdargs | grep "#cycle" | cut -f2) 26 | "$KVSP" enc -k _test.sk -i _test.exe -o _test.enc $cmdargs 27 | "$KVSP" run -bkey _test.bk -i _test.enc -o _test.res -c 1 -snapshot _test.snapshot $KVSP_RUN_OPTIONS 28 | "$KVSP" resume -bkey _test.bk -i _test.snapshot -o _test.res -snapshot _test.snapshot -c $ncycles 29 | result=$("$KVSP" dec -k _test.sk -i _test.res | grep x8 | cut -f2) 30 | [ $result -eq $expected ] || failwith "test failed" 31 | } 32 | 33 | "$KVSP" version 34 | 35 | cat < _test.c 36 | static int fib(int n) { 37 | int a = 0, b = 1; 38 | for (int i = 0; i < n; i++) { 39 | int tmp = a + b; 40 | a = b; 41 | b = tmp; 42 | } 43 | return a; 44 | } 45 | 46 | int main(int argc, char **argv) { 47 | // Calculate n-th Fibonacci number. 48 | // n is a 1-digit number and given as command-line argument. 49 | return fib(argv[1][0] - '0'); 50 | } 51 | EOS 52 | letstest "5" "5" 53 | -------------------------------------------------------------------------------- /toolbox.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -xe 2 | 3 | case "$1" in 4 | bump-submodule ) 5 | [ $# -eq 2 ] || ( echo "Usage: $0 bump-submodule SUBMODULE-DIR"; exit 1 ) 6 | git reset 7 | diff=$(git diff "$2" | grep Subproject | cut -f3 -d' ' | (read l1; read l2; echo -e "$l1\t$l2")) 8 | echo "$diff" | egrep "^[a-f0-9]{40} [a-f0-9]{40}$" > /dev/null || ( echo "Invalid diff"; exit 1 ) 9 | git add "$2" && git commit -m \ 10 | "$(echo "$diff" | awk "{print \"Bump $2\",\"from\",\$1,\"to\",\$2}")" 11 | ;; 12 | 13 | build ) 14 | rm -rf build 15 | docker build -t kvsp-build . 16 | docker run -it -v $PWD:/build -w /build kvsp-build:latest 17 | ;; 18 | 19 | test ) 20 | cd Iyokan && \ 21 | ruby test.rb --skip-preface ../build/bin fast && \ 22 | ruby test.rb --skip-preface ../build/bin cufhe-cahp-ruby-09 && \ 23 | rm _test* 24 | ;; 25 | 26 | tag ) 27 | [ $# -eq 2 ] || ( echo "Usage: $0 tag VERSION"; exit 1 ) 28 | git tag -s "v$2" -m "v$2" 29 | ;; 30 | 31 | rebuild-kvsp ) 32 | rm -rf build/kvsp 33 | docker build -t kvsp-build . 34 | docker run -it -v $PWD:/build -w /build kvsp-build:latest make step2_kvsp 35 | build/kvsp/kvsp version 36 | ;; 37 | 38 | copy ) 39 | [ $# -eq 2 ] || ( echo "Usage: $0 copy VERSION"; exit 1 ) 40 | destdir="kvsp_v$2" 41 | mkdir "$destdir" 42 | cp -a build/bin build/share "$destdir" 43 | strip "$destdir"/bin/* || true 44 | find \ 45 | Iyokan \ 46 | Iyokan-L1 \ 47 | cahp-pearl \ 48 | cahp-rt \ 49 | cahp-ruby \ 50 | cahp-sim \ 51 | examples \ 52 | kvsp \ 53 | llvm-cahp \ 54 | yosys \ 55 | -type f -regextype posix-egrep -regex ".*(LICENSE.*|COPYING.*)" | while read line; do \ 56 | mkdir -p "$destdir/LICENSEs/$(dirname "$line")" && 57 | cp -a "$line" "$destdir/LICENSEs/$(dirname "$line")"/; 58 | done 59 | "$destdir"/bin/kvsp version 60 | ;; 61 | 62 | pack ) 63 | [ $# -eq 2 ] || ( echo "Usage: $0 pack VERSION"; exit 1 ) 64 | destdir="kvsp_v$2" 65 | rm -f kvsp.tar.gz 66 | tar -I pigz -cf kvsp.tar.gz "$destdir" 67 | ;; 68 | 69 | release ) 70 | [ $# -eq 2 ] || ( echo "Usage: $0 release VERSION"; exit 1 ) 71 | git push --tags 72 | EDITOR=nano hub release create -a kvsp.tar.gz "v$2" 73 | ;; 74 | 75 | * ) 76 | echo "Usage: $0 bump-submodule|build|tag|rebuild-kvsp|copy|pack" 77 | esac 78 | --------------------------------------------------------------------------------