# Attesting Function Calls The Blocky Attestation Service `attest-fn-call` command allows you to submit a function call to a TEE for execution. Below we walk you through a simple "hello world" example to use Block AS to create an attestation for a function call. ## Setup - Install the Blocky AS CLI by following the [setup instructions](/attestation-service/v0.1.0-beta.4/setup) in the Blocky AS documentation. - Make sure you also have [Docker](https://www.docker.com/) and [jq](https://jqlang.org/) installed on your system. - Clone our [https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4) repository and navigate to the `hello_world_attest_fn_call` directory. ```bash git clone git@github.com:blocky/attestation-service-examples.git cd attestation-service-examples/hello_world_attest_fn_call ``` ## Quick Start To run this example, call: ```bash make run ``` You will see the following output extracted from a Blocky AS response: ``` Log: Writing "Hello, World!" to host Output: Hello, World! ``` ## Walkthrough ### Step 1: Create a function that returns a "Hello, World!" message. Our first goal is to create a simple function that returns a `"Hello, World!"` message. We will write this function in Go and compile it to WebAssembly (WASM) to run on the Blocky AS server. If you open [main.go](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/main.go) you'll see our function there: ```go //export helloWorld func helloWorld(inputPtr uint64, secretPtr uint64) uint64 { msg := "Hello, World!" basm.Log(fmt.Sprintf("Writing \"%s\" to host\n", msg)) return basm.WriteToHost([]byte(msg)) } ``` You will notice a few things: - The `helloWorld` function is exported so that it can be invoked by the Blocky AS server in a WASM runtime. - The function takes two `uint64` arguments and returns a `uint64`. These are fat pointers to shared memory managed by the Blocky AS server, where the first 32 bits are a memory address and the second 32 bits are the size of the data. The memory space is sandboxed and shared between the TEE host program (Blocky AS server) and the WASM runtime (your function). The `inputPtr` and `secretPtr` arguments carry user-defined function input and secrets, though we don't make use of them in this example. The output of the function is also a memory pointer, whose value will be returned to the user. - The function uses `basm` [Blocky Attestation Service WASM Go SDK](https://github.com/blocky/basm-go-sdk/tree/v0.1.0-beta.4) `basm.Log` function to write a message to the Blocky AS server log, maintained separately for each function invocation. You can log messages to debug or monitor your function's behavior. - The function calls `basm.WriteToHost` to write a byte array (serialized from `msg`) to shared memory. The host (Blocky AS server) will create an attestation over that array as a part of its response. ### Step 2: Compile the function to WebAssembly (WASM) To invoke our function in the Blocky AS server, we first need to compile it into a WASM file. If you inspect the `build` target in the [Makefile](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/Makefile), you'll see the build command: ```bash @docker run --rm \ -v .:/src \ -w /src \ tinygo/tinygo:0.31.2 \ tinygo build -o tmp/x.wasm -target=wasi ./... ``` where we use `docker` to run [`tinygo`](https://tinygo.org/) to compile [main.go](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/main.go) to WASM and save it to `tmp/x.wasm`. You can build our function by calling: ```bash make build ``` ### Step 3: Invoke the function on the Blocky AS server To invoke our function, we first need to define an invocation template. We have one set up already in [fn-call.json](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/fn-call.json) that looks like: ```json { "code_file": "tmp/x.wasm", "function": "helloWorld" } ``` where `code_file` is the path to the WASM file we compiled earlier, and `function` is the name of the exported function we want to call. To invoke our function, we need to pass the invocation template to `bky-as`. If you inspect the `run` target in the [Makefile](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/Makefile), you'll see the command: ```bash cat fn-call.json | bky-as attest-fn-call > tmp/out.json ``` where we use `cat` to read the [fn-call.json](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/fn-call.json), pipe it to `bky-as attest-fn-call`, and save the output to `tmp/out.json`. So then to run our function, you can call: ```bash make run ``` The call to `bky-as attest-fn-call` will use the [config.toml](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/config.toml) configuration file. Its `host` field, set to `local-server`, will direct `bky-as` to start a local, non-TEE instance of the Blocky AS server to run our function in demo mode. You can confirm this by finding the following output: ``` 🚀 Starting local server at http://127.0.0.1:8081 ...success ``` If you'd like to send our function for execution on a Blocky AS server hosted on a TEE, you can follow the [`bky-as` configuration instructions](/attestation-service/v0.1.0-beta.4/setup#configuration) in our documentation. ### Step 4: Extract function output from the Blocky AS attestation The `run` target will extract the log and the attested output of the function call. After running: ```bash make run ``` you should see: ``` Log: Writing "Hello, World!" to host Output: Hello, World! ``` To dive deeper, let's again look at the `run` target in the [Makefile](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/Makefile). There you will see that we save the output of the `bky-as attest-fn-call` command to `tmp/out.json`, which contains: ```json { "enclave_attested_application_public_key": { "enclave_attestation": "eyJQbGF0Zm9ybSI6InBsYWl...", "claims": { "enclave_measurement": { "Platform": "plain", "Code": "plain" }, "public_key": { "curve_type": "p256k1", "data": "BN3/W1LNadnQ/AUWabtYJw0z58d4fC+oN83SlI+qUYShcUnYY67tlkE8fDnOa+pRLhaiGzvFUYguCKL/Bqo5hH0=" } } }, "transitive_attested_function_call": { "transitive_attestation": "WyJXeUpaZW14cVRucFJl...", "claims": { "hash_of_code": "c9c7439eb4aa0b3905f84654c6cf07fa9edf5730f5a5252086ece67c0b4dcc50fc7605cae70849799124aaf87332ab2a31bb1b7b9bdb52233ef4850899ebd15a", "function": "helloWorld", "hash_of_input": "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", "output": "SGVsbG8sIFdvcmxkIQ==", "hash_of_secrets": "9375447cd5307bf7473b8200f039b60a3be491282f852df9f42ce31a8a43f6f8e916c4f8264e7d233add48746a40166eec588be8b7b9b16a5eb698d4c3b06e00" }, "logs": "V3JpdGluZyAiSGVsbG8sIFdvcmxkISIgdG8gaG9zdAo=" } } ``` The `enclave_attested_application_public_key` contains the `enclave_attestation` over the Blocky AS server public key. The `transitive_attested_function_call` section contains the `transitive_attestation` over the function call. The `bky-as attest-fn-call` command verifies that the `enclave_attestation` has been signed by either the TEE hardware manufacturer's private key, when the Blocky AS server is running on an AWS Nitro Enclave TEE, or by a hardcoded development private key, when the Blocky AS server is running locally. In this example, we have set up [config.toml](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/config.toml) with `host = "local-server"`, which directs the `bky-as` to start a local server. As a part of the verification process, the `bky-as` lists `enclave_attested_application_public_key.claims` attested by the `enclave_attestation`. You can confirm that `enclave_attestation` was produced by a local Blocky AS server by seeing that `enclave_attested_application_public_key.claims.enclave_measurement.Platform` is reported as `plain`. The `bky-as` CLI also checks that the measurement of the Blocky AS server code, attested by the `enclave_attestation`, matches one in the `acceptable_measurements` list in [config.toml](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/config.toml). Again, since we are running the Blocky AS server locally in this example, the `enclave_attested_application_public_key.claims.enclave_measurement.Code` is reported as `plain`. Finally, the `bky-as` CLI extracts the enclave attested application public key, generated by the Blocky AS server on startup, and uses it to verify the signature of the `transitive_attestation` and extract its `claims`. You can learn more about this process in the [Attestations in the Blocky Attestation Service](/attestation-service/v0.1.0-beta.4/concepts#attestations-in-the-blocky-attestation-service) section in our documentation. The `claims` section contains attested information about the execution of the function. You can see: - `hash_of_code`: The hash of the WASM code executed by the Blocky AS server - `function`: The name of the function executed by the Blocky AS server - `hash_of_input`: The hash of the input data used by the function. In this example this is the hash of the empty string, since we didn't specify any input. - `hash_of_secrets`: The hash of the secrets used by the function. In this example this is the hash of the empty string, since we didn't specify any secrets. - `output`: The output of the function encoded in base64. Finally, the `logs` field contains the logs generated by the function execution and encoded in base64. Notice that while `output` is a part of the attested `claims`, the `logs` are not attested and are only a part of the server response. If you look at the `run` target in the [Makefile](https://github.com/blocky/attestation-service-examples/tree/release/v0.1.0-beta.4/hello_world_attest_fn_call/Makefile) again, you will see that we use `jq` to extract the `output` and the `logs` fields from `tmp/out.json` and decode them from base64.