Key Decryption Oracle


What you’ll do

  • Start a local test chain (anvil).
  • Deploy the on-chain Key Decryption Oracle Contract.
  • Start the off-chain Key Decryption Oracle.
  • Deploy the on-chain demo contract that talks to the key decryption oracle contract.
  • Check the results stored in the demo contract.

Required Installations

You need foundry (for the chain tooling) and jbang (to start a web service with the renderer). For installation instructions see the setup page. Apart from this we assume that cat, tr and sed are present.

The following commands should be run in a shell (macOS Terminal, Windows GitBash). You may use the copy button and just paste them into the shell.


Step-by-Step

1. Launch a local chain for testing

Run:

anvil

2. Deploy the Key Decryption Oracle Contract and the Demo Contract

2.1. Download KeyDecryptionOracle.sol and DemoContract.sol

Run:

REPO=https://gitlab.com/finmath/finmath-decryption-oracle/-/raw/main/oracle-keys

curl --create-dirs -L $REPO/src/main/solidity/IKeyDecryptionOracleCallback.sol -o IKeyDecryptionOracleCallback.sol
curl --create-dirs -L $REPO/src/main/solidity/IKeyDecryptionOracle.sol -o IKeyDecryptionOracle.sol
curl --create-dirs -L $REPO/src/main/solidity/KeyDecryptionOracle.sol -o KeyDecryptionOracle.sol
curl --create-dirs -L $REPO/src/main/solidity/DemoContract.sol -o DemoContract.sol

2.2. Build and deploy the contract KeyDecryptionOracle

Run:

export RPC_URL="http://127.0.0.1:8545"
export PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"

OWNER=$(cast wallet address --private-key "$PRIVATE_KEY")
CONTRACT_PATH=.
CONTRACT_NAME=KeyDecryptionOracle
FULFILLMENTMODE=0
PERMISSIONLESS=true

CONTRACT_ADDRESS=$(
  forge create --use 0.8.20 --broadcast --root . --json "$CONTRACT_PATH/$CONTRACT_NAME.sol:$CONTRACT_NAME" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
    --constructor-args "$OWNER" "$FULFILLMENTMODE" "$PERMISSIONLESS" \
  | tr -d '\r\n' \
  | sed -nE 's/.*"deployedTo"[[:space:]]*:[[:space:]]*"(0x[0-9a-fA-F]{40})".*/\1/p'
)

echo "Contract deployed at $CONTRACT_ADDRESS"

2.3. Build and deploy the contract DemoContract

Run:

export RPC_URL="http://127.0.0.1:8545"
export PRIVATE_KEY="0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"

OWNER=$(cast wallet address --private-key "$PRIVATE_KEY")
CONTRACT_PATH=.
CONTRACT_NAME=DemoContract

DEMO_CONTRACT_ADDRESS=$(
  forge create --use 0.8.20 --broadcast --root . --json "$CONTRACT_PATH/$CONTRACT_NAME.sol:$CONTRACT_NAME" --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" \
    --constructor-args "$CONTRACT_ADDRESS" \
  | tr -d '\r\n' \
  | sed -nE 's/.*"deployedTo"[[:space:]]*:[[:space:]]*"(0x[0-9a-fA-F]{40})".*/\1/p'
)

echo "Contract deployed at $DEMO_CONTRACT_ADDRESS"

3. Launch the KeyDecryptionOracle service (locally)

3.1. Download the script that will generate a new private key for the decryption oracle.

REPO=https://gitlab.com/finmath/finmath-decryption-oracle/-/raw/main

curl --create-dirs -L $REPO/scripts/generate-keys.sh -o generate-keys.sh
chmod 755 generate-keys.sh

3.2. Generate the private key for the key decryption oracle

export SECRETS_DIR=$(pwd)/secrets

./generate-keys.sh

3.3. Launch the KeyDecryptionOracle service (locally)

Run (in the same shell that deployed the contract and the same folder as $SECRETS_DIR):

jbang --java 21 -Dethereum.rpcUrl=http://127.0.0.1:8545 -Dethereum.chainId=1337 -Dethereum.keydecryptionoracle.contract=$CONTRACT_ADDRESS -Dethereum.keydecryptionoracle.stateFile=oracle-state.txt net.finmath:finmath-decryption-oracle-encrypted-hashed-keys:2.5.5 > jbang.log 2>&1 </dev/null &

3.4. Show the log of the KeyDecryptionOracle

(Optional): In a new Window / shell, in the same directory, run:

tail -f jbang.log

This allows you to observe the log of the decryption oracle service. Then return to the previous shell that deployed the contract (this is important, because we will use the environment variables $CONTRACT_ADDRESS and $DEMO_CONTRACT_ADDRESS).

4. Key Generation

4.1 Trigger a key generation (through the demo contract)

Run:

ID=1
TRANSACTION=0x0002

cast send "$DEMO_CONTRACT_ADDRESS" \
  "requestGenerate(uint256,bytes)" $ID $TRANSACTION \
  --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy --gas-price 1gwei --gas-limit 300000

The demo contract will trigger a key generation and will await the result. The result will be stored under result id $ID.

4.2 Define a Helper Function to Fetch the Result form the Contract

We define a function that fetches the result from the demo contract.

After this function has been defined we may fetch a result from the contract via oracle_get_result <id>.

Run:

oracle_get_result () {
    local id="$1"
    local sig='getResult(uint256)(uint8,uint8,address,bytes,bytes,bytes,address,bytes,uint256,uint256)'
    
    # temp file to avoid subshell issues
    local tmpfile
    tmpfile="$(mktemp)"
    
    cast call "$DEMO_CONTRACT_ADDRESS" "$sig" "$id" --rpc-url "$RPC_URL" > "$tmpfile" || {
        rm -f "$tmpfile"
        echo "cast call failed" >&2
        return 1
    }
    vars=(status kind requester key encryptedKey hashedKey receiverContract transaction createdAt updatedAt)
    {
      for v in "${vars[@]}"; do
        IFS= read -r "$v" || break
      done
    } < "$tmpfile"

    rm -f "$tmpfile"
    
# Optional pretty print
cat <<RESULT
    kind..............: $kind (1=generate, 2=verify, 3=decrypt)
    status............: $status (0=None, 1=Pending, 2=Generated, 3=Verified, 4=Released, 5=Denied)
    requester.........: $requester
    key...............: $key
    encryptedKey......: $encryptedKey
    hashedKey.........: $hashedKey
    receiverContract..: $receiverContract
    transaction.......: $transaction
    createdAt.........: $createdAt
    updatedAt.........: $updatedAt
RESULT
}

4.3 Fetch the Result

Run:

oracle_get_result $ID

This will fetch the rsult. The encrypted key will be stored under $encryptedKey.

5. Key Verification

5.1. Request a Key Verification

We take the previously generated $encryptedKey and request a verification, that is, the oracle will confirm us the hash of the key, the decrypted $encryptedKey, without exposing that key.

Run:

ID=2
ENC_KEY=$encryptedKey

cast send "$DEMO_CONTRACT_ADDRESS" \
  "requestVerify(uint256,bytes)" $ID $ENC_KEY \
  --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy --gas-price 1gwei --gas-limit 300000

5.2 Fetch the Result

Run:

oracle_get_result $ID

This will fetch and display the result.

6. Decryption

6.1. Request a Key Decryption

We take the previously generated $encryptedKey and request a decryption. The decryption can only be requested to be submitted to an eligible contract (information that is contained in the key) - in our case the demo contract is eligible.

Run:

ID=3
ENC_KEY=$encryptedKey

cast send "$DEMO_CONTRACT_ADDRESS" \
  "requestDecrypt(uint256,bytes,bytes)" $ID $ENC_KEY $TRANSACTION \
  --rpc-url "$RPC_URL" --private-key "$PRIVATE_KEY" --legacy --gas-price 1gwei --gas-limit 300000

6.2 Fetch the Result

Run:

oracle_get_result $ID

This will fetch and display the result.


Last updated: 2025‑12‑24