You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@teaclave.apache.org by ms...@apache.org on 2020/08/04 21:12:42 UTC

[incubator-teaclave] branch master updated: Add a new builtin function for face detection (#399)

This is an automated email from the ASF dual-hosted git repository.

mssun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-teaclave.git


The following commit(s) were added to refs/heads/master by this push:
     new 47237ea  Add a new builtin function for face detection (#399)
47237ea is described below

commit 47237ea2d82b4c7d1af8388a76ed8732a31827da
Author: yc-huang <yc...@gmail.com>
AuthorDate: Tue Aug 4 14:12:28 2020 -0700

    Add a new builtin function for face detection (#399)
---
 .drone.yml                                         |  92 +++++------
 CONTRIBUTORS.md                                    |   1 +
 cmake/scripts/test.sh                              |   1 +
 cmake/tomls/Cargo.sgx_trusted_lib.toml             |   2 +-
 docker/build.ubuntu-1804.sgx-2.9.1.Dockerfile      |   2 +-
 docker/build.ubuntu-1804.sgx-dcap-1.6.Dockerfile   |   2 +-
 examples/python/builtin_face_detection.py          | 119 ++++++++++++++
 examples/python/requirments.txt                    |   5 +
 executor/Cargo.toml                                |   2 +
 executor/src/builtin.rs                            |   6 +-
 function/Cargo.toml                                |   2 +
 function/README.md                                 |   2 +
 function/src/face_detection.rs                     | 179 +++++++++++++++++++++
 function/src/lib.rs                                |   3 +
 tests/fixtures/functions/face_detection/input.jpg  | Bin 0 -> 262603 bytes
 tests/fixtures/functions/face_detection/output.jpg | Bin 0 -> 265729 bytes
 third_party/crates-sgx                             |   2 +-
 tool/enclave/src/lib.rs                            |   2 +-
 18 files changed, 369 insertions(+), 53 deletions(-)

diff --git a/.drone.yml b/.drone.yml
index 3cdd28f..02538ad 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -3,24 +3,24 @@ name: sgx-debug-ubuntu-1804
 
 steps:
 - name: prepare
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - . /opt/sgxsdk/environment
   - mkdir -p build
   - cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DTEST_MODE=ON ..
 - name: check
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make check
 - name: compile
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make VERBOSE=1 -j2
 - name: test
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   environment:
     AS_ALGO: sgx_epid
     AS_URL: https://api.trustedservices.intel.com:443
@@ -58,26 +58,26 @@ name: sgx-dcap-debug-ubuntu-1804
 
 steps:
 - name: prepare
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-dcap-1.6:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-dcap-1.6:0.1.2
   commands:
   - . /root/.cargo/env
   - . /opt/sgxsdk/environment
   - mkdir -p build
   - cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DTEST_MODE=ON -DDCAP=ON ..
 - name: check
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-dcap-1.6:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-dcap-1.6:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make check
 - name: compile
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-dcap-1.6:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-dcap-1.6:0.1.2
   commands:
   - . /root/.cargo/env
   - . /opt/sgxsdk/environment
   - sed -i 's/ias_root_ca_cert/dcap_root_ca_cert/' config/build.config.toml
   - cd build && make VERBOSE=1 -j2
 - name: test
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-dcap-1.6:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-dcap-1.6:0.1.2
   environment:
     AS_ALGO: sgx_ecdsa
     AS_URL: https://localhost:8080
@@ -125,24 +125,24 @@ name: sgx-release-ubuntu-1804
 
 steps:
 - name: prepare
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - . /opt/sgxsdk/environment
   - mkdir -p build
   - cd build && cmake -DCMAKE_BUILD_TYPE=Release -DTEST_MODE=OFF ..
 - name: check
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make check
 - name: compile
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make VERBOSE=1 -j2
 - name: test
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   privileged: true
   environment:
     AS_ALGO: sgx_epid
@@ -178,24 +178,24 @@ name: sim-debug-ubuntu-1804
 
 steps:
 - name: prepare
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - . /opt/sgxsdk/environment
   - mkdir -p build
   - cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DSGX_SIM_MODE=ON -DTEST_MODE=ON ..
 - name: check
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make check
 - name: compile
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make VERBOSE=1 -j2
 - name: test
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   environment:
     AS_ALGO: sgx_epid
     AS_URL: https://api.trustedservices.intel.com:443
@@ -217,24 +217,24 @@ name: sim-release-ubuntu-1804
 
 steps:
 - name: prepare
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - . /opt/sgxsdk/environment
   - mkdir -p build
   - cd build && cmake -DCMAKE_BUILD_TYPE=Release -DSGX_SIM_MODE=ON -DTEST_MODE=OFF ..
 - name: check
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make check
 - name: compile
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make VERBOSE=1 -j2
 - name: test
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make run-examples
@@ -249,23 +249,23 @@ node:
 
 # steps:
 # - name: prepare
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - mkdir -p build
 #   - cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DTEST_MODE=ON ..
 # - name: check
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make check
 # - name: compile
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make VERBOSE=1 -j2
 # - name: test
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   environment:
 #     AS_ALGO: sgx_epid
 #     AS_URL: https://api.trustedservices.intel.com:443
@@ -301,23 +301,23 @@ node:
 
 # steps:
 # - name: prepare
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - mkdir -p build
 #   - cd build && cmake -DTEST_MODE=ON ..
 # - name: check
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make check
 # - name: compile
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make VERBOSE=1 -j2
 # - name: test
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   privileged: true
 #   environment:
 #     AS_ALGO: sgx_epid
@@ -353,23 +353,23 @@ node:
 
 # steps:
 # - name: prepare
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - mkdir -p build
 #   - cd build && cmake -DTEST_MODE=ON ..
 # - name: check
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make check
 # - name: compile
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DSGX_SIM_MODE=ON .. && make VERBOSE=1 -j2
 # - name: test
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make run-tests
@@ -384,23 +384,23 @@ node:
 
 # steps:
 # - name: prepare
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - mkdir -p build
 #   - cd build && cmake ..
 # - name: check
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make check
 # - name: compile
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && cmake -DSGX_SIM_MODE=ON -DTEST_MODE=ON .. && make VERBOSE=1 -j2
 # - name: test
-#   image: teaclave/teaclave-build-ubuntu-1604:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1604:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make run-tests
@@ -415,19 +415,19 @@ name: lint
 
 steps:
 - name: prepare
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - . /opt/sgxsdk/environment
   - mkdir -p build
   - cd build && cmake -DRUSTFLAGS="-D warnings" -DTEST_MODE=ON ..
 - name: check
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make check
 - name: clippy
-  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+  image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
   commands:
   - . /root/.cargo/env
   - cd build && make CLP=1
@@ -442,24 +442,24 @@ node:
 
 # steps:
 # - name: prepare
-#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - mkdir -p build
 #   - cd build && cmake -DCMAKE_BUILD_TYPE=DEBUG -DCOV=ON -DTEST_MODE=ON ..
 # - name: check
-#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - cd build && make check
 # - name: compile
-#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - export RUSTFLAGS="-D warnings"
 #   - cd build && make VERBOSE=1 -j2
 # - name: test
-#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
 #   environment:
 #     AS_ALGO: sgx_epid
 #     AS_URL: https://api.trustedservices.intel.com:443
@@ -478,7 +478,7 @@ node:
 #   - cd build && make run-tests
 # - name: coverage
 #   failure: ignore
-#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
 #   commands:
 #   - cd build && make cov
 #   - bash -c "bash <(curl -s https://codecov.io/bash) -f intermediate/cov.info"
@@ -510,13 +510,13 @@ node:
 
 # steps:
 # - name: prepare
-#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
 #   commands:
 #   - . /root/.cargo/env
 #   - mkdir -p build
 #   - cd build && cmake ..
 # - name: doc
-#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.1
+#   image: teaclave/teaclave-build-ubuntu-1804-sgx-2.9.1:0.1.2
 #   failure: ignore
 #   commands:
 #   - . /root/.cargo/env
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 451ceda..2831348 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -77,6 +77,7 @@ List of external contributors of Teaclave and Teaclave SGX SDK (in alphabetical
   - [piotr-roslaniec](https://github.com/piotr-roslaniec)
   - [rebol0x6c](https://github.com/rebol0x6c)
   - [volcano](https://github.com/volcano0dr)
+  - [yc-huang](https://github.com/yc-huang)
   - [zEqueue](https://github.com/z1queue)
 
 More people tracked in GitHub:
diff --git a/cmake/scripts/test.sh b/cmake/scripts/test.sh
index 5c39793..04388f4 100755
--- a/cmake/scripts/test.sh
+++ b/cmake/scripts/test.sh
@@ -172,6 +172,7 @@ run_examples() {
   python3 builtin_private_join_and_compute.py
   python3 builtin_ordered_set_intersect.py
   python3 builtin_rsa_sign.py
+  python3 builtin_face_detection.py
   popd
 
   # kill all background services
diff --git a/cmake/tomls/Cargo.sgx_trusted_lib.toml b/cmake/tomls/Cargo.sgx_trusted_lib.toml
index 24d0b67..3837025 100644
--- a/cmake/tomls/Cargo.sgx_trusted_lib.toml
+++ b/cmake/tomls/Cargo.sgx_trusted_lib.toml
@@ -50,7 +50,7 @@ gbdt              = { git = "https://github.com/mesalock-linux/gbdt-rs", branch
 getrandom         = { git = "https://github.com/mesalock-linux/getrandom-sgx" }
 crc               = { git = "https://github.com/mesalock-linux/crc-rs-sgx" }
 # gif               = { git = "https://github.com/mesalock-linux/image-gif-sgx" }
-# image             = { git = "https://github.com/mesalock-linux/image-sgx" }
+image             = { git = "https://github.com/mesalock-linux/image-sgx" }
 # inflate           = { git = "https://github.com/mesalock-linux/inflate-sgx" }
 itoa              = { git = "https://github.com/mesalock-linux/itoa-sgx" }
 # jpeg-decoder      = { git = "https://github.com/mesalock-linux/jpeg-decoder-sgx" }
diff --git a/docker/build.ubuntu-1804.sgx-2.9.1.Dockerfile b/docker/build.ubuntu-1804.sgx-2.9.1.Dockerfile
index f9a6266..cf32ba9 100644
--- a/docker/build.ubuntu-1804.sgx-2.9.1.Dockerfile
+++ b/docker/build.ubuntu-1804.sgx-2.9.1.Dockerfile
@@ -78,7 +78,7 @@ RUN apt-get update && apt-get install -q -y \
     curl \
     python3-pip
 
-RUN pip3 install pyopenssl toml cryptography yapf
+RUN pip3 install pyopenssl toml cryptography yapf requests Pillow
 
 # clean up apt caches
 
diff --git a/docker/build.ubuntu-1804.sgx-dcap-1.6.Dockerfile b/docker/build.ubuntu-1804.sgx-dcap-1.6.Dockerfile
index e7c0c4e..361c3d4 100644
--- a/docker/build.ubuntu-1804.sgx-dcap-1.6.Dockerfile
+++ b/docker/build.ubuntu-1804.sgx-dcap-1.6.Dockerfile
@@ -81,7 +81,7 @@ RUN apt-get update && apt-get install -q -y \
     iproute2 \
     python3-pip
 
-RUN pip3 install pyopenssl toml cryptography yapf
+RUN pip3 install pyopenssl toml cryptography yapf requests Pillow
 
 # clean up apt caches
 
diff --git a/examples/python/builtin_face_detection.py b/examples/python/builtin_face_detection.py
new file mode 100644
index 0000000..c7c56ec
--- /dev/null
+++ b/examples/python/builtin_face_detection.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+
+import os
+import sys
+import base64
+import json
+
+from PIL import Image, ImageDraw
+import requests
+
+from teaclave import (AuthenticationService, FrontendService, OwnerList,
+                      AuthenticationClient, FrontendClient, DataMap,
+                      FunctionInput)
+from utils import (AUTHENTICATION_SERVICE_ADDRESS, FRONTEND_SERVICE_ADDRESS,
+                   AS_ROOT_CA_CERT_PATH, ENCLAVE_INFO_PATH, USER_ID,
+                   USER_PASSWORD)
+
+
+class BuiltinFaceDetectionExample:
+    def __init__(self, user_id, user_password):
+        self.user_id = user_id
+        self.user_password = user_password
+
+    def detect_face(self, image_base64):
+        client = AuthenticationService(
+            AUTHENTICATION_SERVICE_ADDRESS, AS_ROOT_CA_CERT_PATH,
+            ENCLAVE_INFO_PATH).connect().get_client()
+
+        print("[+] registering user")
+        client.user_register(self.user_id, self.user_password)
+
+        print("[+] login")
+        token = client.user_login(self.user_id, self.user_password)
+
+        client = FrontendService(FRONTEND_SERVICE_ADDRESS,
+                                 AS_ROOT_CA_CERT_PATH,
+                                 ENCLAVE_INFO_PATH).connect().get_client()
+        metadata = {"id": self.user_id, "token": token}
+        client.metadata = metadata
+
+        print("[+] registering function")
+        function_id = client.register_function(
+            name="builtin-face-detection",
+            description="Native Face Detection Function",
+            executor_type="builtin",
+            inputs=[],
+            arguments=[
+                "image_base64", "min_face_size", "score_thresh",
+                "pyramid_scale_factor", "slide_window_step_x",
+                "slide_window_step_y"
+            ])
+
+        print("[+] creating task")
+        task_id = client.create_task(function_id=function_id,
+                                     function_arguments={
+                                         "image_base64": image_base64,
+                                         "min_face_size": 20,
+                                         "score_thresh": 2.0,
+                                         "pyramid_scale_factor": 0.8,
+                                         "slide_window_step_x": 4,
+                                         "slide_window_step_y": 4
+                                     },
+                                     inputs_ownership=[],
+                                     executor="builtin")
+
+        print("[+] invoking task")
+        client.invoke_task(task_id)
+
+        print("[+] getting result")
+        result = client.get_task_result(task_id)
+        print("[+] done")
+
+        return bytes(result)
+
+
+def main():
+    img_file_name = 'in.jpg'
+
+    if not os.path.isfile(img_file_name):
+        image_url = 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/6e/Solvay_conference_1927.jpg/1400px-Solvay_conference_1927.jpg'
+        print("[+] retrieving image from url:", image_url)
+
+        response = requests.get(image_url).content
+        with open(img_file_name, 'wb') as file:
+            file.write(response)
+        print("[+] image saved to", img_file_name)
+    else:
+        print("[+] using cached file", img_file_name)
+
+    with open(img_file_name, 'rb') as fin:
+        image_data = fin.read()
+        base64_encoded_data = base64.b64encode(image_data).decode('utf-8')
+
+        example = BuiltinFaceDetectionExample(USER_ID, USER_PASSWORD)
+
+        rt = example.detect_face(base64_encoded_data)
+
+        print("[+] function return:", rt)
+
+        bboxes = json.loads(rt)
+
+        img = Image.open(img_file_name).convert('RGB')
+        draw = ImageDraw.Draw(img)
+
+        for bbox in bboxes:
+            box = bbox['bbox']
+            draw.rectangle([
+                box['x'], box['y'], box['x'] + box['height'],
+                box['y'] + box['width']
+            ],
+                           outline='red',
+                           width=2)
+
+        img.save('out.jpg', 'JPEG')
+        print("[+] detection result saved to out.jpg")
+
+
+if __name__ == '__main__':
+    main()
diff --git a/examples/python/requirments.txt b/examples/python/requirments.txt
new file mode 100644
index 0000000..6f3b748
--- /dev/null
+++ b/examples/python/requirments.txt
@@ -0,0 +1,5 @@
+pyopenssl
+toml
+cryptography
+requests
+Pillow
diff --git a/executor/Cargo.toml b/executor/Cargo.toml
index b86d4c2..df458ed 100644
--- a/executor/Cargo.toml
+++ b/executor/Cargo.toml
@@ -37,6 +37,7 @@ full_builtin_function = [
   "builtin_private_join_and_compute",
   "builtin_ordered_set_intersect",
   "builtin_rsa_sign",
+  "builtin_face_detection",
 ]
 
 builtin_echo = []
@@ -48,6 +49,7 @@ builtin_online_decrypt = []
 builtin_private_join_and_compute = []
 builtin_ordered_set_intersect = []
 builtin_rsa_sign = []
+builtin_face_detection = []
 
 [dependencies]
 log           = { version = "0.4.6", features = ["release_max_level_info"] }
diff --git a/executor/src/builtin.rs b/executor/src/builtin.rs
index 677e782..510db29 100644
--- a/executor/src/builtin.rs
+++ b/executor/src/builtin.rs
@@ -19,8 +19,8 @@
 use std::prelude::v1::*;
 
 use teaclave_function::{
-    Echo, GbdtPredict, GbdtTrain, LogisticRegressionPredict, LogisticRegressionTrain,
-    OnlineDecrypt, OrderedSetIntersect, PrivateJoinAndCompute, RsaSign,
+    Echo, FaceDetection, GbdtPredict, GbdtTrain, LogisticRegressionPredict,
+    LogisticRegressionTrain, OnlineDecrypt, OrderedSetIntersect, PrivateJoinAndCompute, RsaSign,
 };
 use teaclave_types::{FunctionArguments, FunctionRuntime, TeaclaveExecutor};
 
@@ -58,6 +58,8 @@ impl TeaclaveExecutor for BuiltinFunctionExecutor {
             OrderedSetIntersect::NAME => OrderedSetIntersect::new().run(arguments, runtime),
             #[cfg(feature = "builtin_rsa_sign")]
             RsaSign::NAME => RsaSign::new().run(arguments, runtime),
+            #[cfg(feature = "builtin_face_detection")]
+            FaceDetection::NAME => FaceDetection::new().run(arguments, runtime),
             _ => bail!("Function not found."),
         }
     }
diff --git a/function/Cargo.toml b/function/Cargo.toml
index deb3abd..ccb65a7 100644
--- a/function/Cargo.toml
+++ b/function/Cargo.toml
@@ -36,6 +36,8 @@ itertools     = { version = "0.8.0", default-features = false }
 ring          = { version = "0.16.5" }
 base64        = { version = "0.10.1" }
 hex           = { version = "0.4.0"  }
+image         = { version = "0.22.4" }
+rustface      = { version = "0.1.2", features = [ "include_default_model" ] }
 
 teaclave_types = { path = "../types" }
 teaclave_crypto = { path = "../crypto" }
diff --git a/function/README.md b/function/README.md
index b856b57..af104d1 100644
--- a/function/README.md
+++ b/function/README.md
@@ -25,6 +25,8 @@ Currently, we have these built-in functions:
     elements in the intersection. Users should calculate hash values of each item
     and upload them as a sorted list.
   - `builtin-rsa-sign`: Signing data with RSA key.
+  - `builtin-face-detection`: an implementation of Funnel-Structured cascade,
+    which is designed for real-time multi-view face detection.
   
 The function arguments are in JSON format and can be serialized to a Rust struct
 very easily. You can learn more about supported arguments in the implementation
diff --git a/function/src/face_detection.rs b/function/src/face_detection.rs
new file mode 100644
index 0000000..5acf5e1
--- /dev/null
+++ b/function/src/face_detection.rs
@@ -0,0 +1,179 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+extern crate base64;
+extern crate image;
+#[cfg(feature = "mesalock_sgx")]
+extern crate rustface;
+
+use std::prelude::v1::*;
+
+use std::convert::TryFrom;
+use teaclave_types::{FunctionArguments, FunctionRuntime};
+
+#[derive(Default)]
+pub struct FaceDetection;
+
+#[derive(serde::Deserialize)]
+struct FaceDetectionArguments {
+    image_base64: String,
+    /// Set the size of the sliding window.
+    ///
+    /// The minimum size is constrained as no smaller than 20.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `wnd_size` is less than 20.
+    window_size: Option<u32>,
+    /// Set the sliding window step in horizontal and vertical directions.
+    ///
+    /// The steps should take positive values.
+    /// Usually a step of 4 is a reasonable choice.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `step_x` or `step_y` is less than or equal to 0.
+    slide_window_step_x: Option<u32>,
+    slide_window_step_y: Option<u32>,
+    /// Set the minimum size of faces to detect.
+    ///
+    /// The minimum size is constrained as no smaller than 20.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `min_face_size` is less than 20.
+    min_face_size: Option<u32>,
+    /// Set the maximum size of faces to detect.
+    ///
+    /// The maximum face size actually used is computed as the minimum among:
+    /// user specified size, image width, image height.
+    max_face_size: Option<u32>,
+    /// Set the factor between adjacent scales of image pyramid.
+    ///
+    /// The value of the factor lies in (0.1, 0.99). For example, when it is set as 0.5,
+    /// an input image of size w x h will be resized to 0.5w x 0.5h, 0.25w x 0.25h,  0.125w x 0.125h, etc.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `scale_factor` is less than 0.01 or greater than 0.99
+    pyramid_scale_factor: Option<f32>,
+    /// Set the score threshold of detected faces.
+    ///
+    /// Detections with scores smaller than the threshold will not be returned.
+    /// Typical threshold values include 0.95, 2.8, 4.5. One can adjust the
+    /// threshold based on his or her own test set.
+    ///
+    /// Smaller values result in more detections (possibly increasing the number of false positives),
+    /// larger values result in fewer detections (possibly increasing the number of false negatives).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `thresh` is less than or equal to 0.
+    score_thresh: Option<f64>,
+}
+
+impl TryFrom<FunctionArguments> for FaceDetectionArguments {
+    type Error = anyhow::Error;
+
+    fn try_from(arguments: FunctionArguments) -> Result<Self, Self::Error> {
+        use anyhow::Context;
+        serde_json::from_str(&arguments.into_string()).context("Cannot deserialize arguments")
+    }
+}
+
+impl FaceDetection {
+    pub const NAME: &'static str = "builtin-face-detection";
+
+    pub fn new() -> Self {
+        Default::default()
+    }
+
+    pub fn run(
+        &self,
+        arguments: FunctionArguments,
+        _runtime: FunctionRuntime,
+    ) -> anyhow::Result<String> {
+        let arguments = FaceDetectionArguments::try_from(arguments)?;
+        let image_base64 = arguments.image_base64;
+        let vec = base64::decode(&image_base64).unwrap();
+        let bytes: &[u8] = &vec;
+        let img = image::load_from_memory(&bytes)?;
+
+        let mut detector = rustface::create_default_detector()?;
+        if let Some(window_size) = arguments.window_size {
+            detector.set_window_size(window_size);
+        }
+        if let (Some(step_x), Some(step_y)) =
+            (arguments.slide_window_step_x, arguments.slide_window_step_y)
+        {
+            detector.set_slide_window_step(step_x, step_y);
+        }
+        if let Some(min_face_size) = arguments.min_face_size {
+            detector.set_min_face_size(min_face_size);
+        }
+        if let Some(max_face_size) = arguments.max_face_size {
+            detector.set_max_face_size(max_face_size);
+        }
+        if let Some(pyramid_scale_factor) = arguments.pyramid_scale_factor {
+            detector.set_pyramid_scale_factor(pyramid_scale_factor);
+        }
+        if let Some(score_thresh) = arguments.score_thresh {
+            detector.set_score_thresh(score_thresh);
+        }
+
+        let faces = rustface::detect_faces(&mut *detector, img);
+        let result = serde_json::to_string(&faces)?;
+
+        Ok(result)
+    }
+}
+
+#[cfg(feature = "enclave_unit_test")]
+pub mod tests {
+    use super::*;
+    use serde_json::json;
+    use std::untrusted::fs;
+    use teaclave_runtime::*;
+    use teaclave_test_utils::*;
+    use teaclave_types::*;
+
+    pub fn run_tests() -> bool {
+        run_tests!(test_face_detection)
+    }
+
+    fn test_face_detection() {
+        let input = "fixtures/functions/face_detection/input.jpg";
+        let image_base64 = base64::encode(&fs::read(input).unwrap());
+        let arguments = FunctionArguments::from_json(json!({
+            "image_base64": image_base64,
+            "min_face_size": 20,
+            "score_thresh": 2.0,
+            "pyramid_scale_factor": 0.8,
+            "slide_window_step_x": 4,
+            "slide_window_step_y": 4
+        }))
+        .unwrap();
+
+        let input_files = StagedFiles::new(hashmap!());
+        let output_files = StagedFiles::new(hashmap!());
+        let runtime = Box::new(RawIoRuntime::new(input_files, output_files));
+
+        let result = FaceDetection::new().run(arguments, runtime).unwrap();
+        let json_result: serde_json::Value = serde_json::from_str(&result).unwrap();
+        assert_eq!(json_result.as_array().unwrap().len(), 28);
+    }
+}
diff --git a/function/src/lib.rs b/function/src/lib.rs
index 1ea110f..a733017 100644
--- a/function/src/lib.rs
+++ b/function/src/lib.rs
@@ -23,6 +23,7 @@ extern crate sgx_tstd as std;
 use std::prelude::v1::*;
 
 mod echo;
+mod face_detection;
 mod gbdt_predict;
 mod gbdt_train;
 mod logistic_regression_predict;
@@ -33,6 +34,7 @@ mod private_join_and_compute;
 mod rsa_sign;
 
 pub use echo::Echo;
+pub use face_detection::FaceDetection;
 pub use gbdt_predict::GbdtPredict;
 pub use gbdt_train::GbdtTrain;
 pub use logistic_regression_predict::LogisticRegressionPredict;
@@ -58,6 +60,7 @@ pub mod tests {
             private_join_and_compute::tests::run_tests(),
             ordered_set_intersect::tests::run_tests(),
             rsa_sign::tests::run_tests(),
+            face_detection::tests::run_tests(),
         )
     }
 }
diff --git a/tests/fixtures/functions/face_detection/input.jpg b/tests/fixtures/functions/face_detection/input.jpg
new file mode 100644
index 0000000..a7a8431
Binary files /dev/null and b/tests/fixtures/functions/face_detection/input.jpg differ
diff --git a/tests/fixtures/functions/face_detection/output.jpg b/tests/fixtures/functions/face_detection/output.jpg
new file mode 100644
index 0000000..7d7d319
Binary files /dev/null and b/tests/fixtures/functions/face_detection/output.jpg differ
diff --git a/third_party/crates-sgx b/third_party/crates-sgx
index 7b0f647..76012b5 160000
--- a/third_party/crates-sgx
+++ b/third_party/crates-sgx
@@ -1 +1 @@
-Subproject commit 7b0f647835e67a61304717af13a8fa934c919ce1
+Subproject commit 76012b501ac94046f227a7e905f49b95e556f354
diff --git a/tool/enclave/src/lib.rs b/tool/enclave/src/lib.rs
index 0bf1c67..4fb13f3 100644
--- a/tool/enclave/src/lib.rs
+++ b/tool/enclave/src/lib.rs
@@ -60,7 +60,7 @@ fn attestation(raw_json_input: &RawJsonInput) -> anyhow::Result<()> {
     };
     println!("Remote Attestation Report:");
     println!("{}", serde_json::to_string_pretty(&attn_report)?);
-    println!("");
+    println!();
     println!("ISV Enclave Quote Body:");
     println!("{:?}", sgx_quote_body);
     Ok(())


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@teaclave.apache.org
For additional commands, e-mail: commits-help@teaclave.apache.org