diff --git a/.dockerignore b/.dockerignore index 6ad33b6..f582f4e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,9 +1,15 @@ # Build artifacts and VCS metadata — never needed in the image build context. target/ **/target/ +build/ .git/ .github/ +# The placeholder Face Engine graph only loads these two private model artifacts. +models/* +!models/face_embedding_generator.onnx +!models/rgbnet.onnx + # Local editor / OS cruft. .vscode/ .idea/ diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml index 2493d84..9cc9409 100644 --- a/.github/workflows/build-docker.yml +++ b/.github/workflows/build-docker.yml @@ -41,6 +41,15 @@ jobs: - name: Checkout code uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - name: Mint biometric-engines access token + id: biometric-engines-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + with: + client-id: ${{ secrets.BIOMETRIC_ENGINES_APP_ID }} + private-key: ${{ secrets.BIOMETRIC_ENGINES_APP_PRIVATE_KEY }} + owner: worldcoin + repositories: biometric-engines + - name: Resolve version id: version if: github.ref_type == 'tag' || inputs.version != '' @@ -93,6 +102,8 @@ jobs: cache-from: type=gha cache-to: type=gha,mode=max platforms: linux/amd64 + secrets: | + GITHUB_TOKEN=${{ steps.biometric-engines-token.outputs.token }} - name: Attest build provenance if: github.event_name != 'pull_request' diff --git a/.github/workflows/build-enclave-eif.yml b/.github/workflows/build-enclave-eif.yml index f1ad785..855628d 100644 --- a/.github/workflows/build-enclave-eif.yml +++ b/.github/workflows/build-enclave-eif.yml @@ -1,6 +1,5 @@ -# Builds the secure-enclave EIF and pushes the carrier image to GHCR. -# Pull requests build without publishing. -name: Build Enclave EIF Image +# Builds the secure-enclave EIF and validates its PCR generation. +name: Build Enclave EIF on: pull_request: @@ -18,11 +17,6 @@ on: tags: - "v*" workflow_dispatch: - inputs: - version: - description: "Version tag to publish (including v prefix, e.g. v0.1.0)" - required: false - type: string permissions: contents: read @@ -32,17 +26,21 @@ env: jobs: build-enclave-eif: - name: Build enclave EIF + carrier image + name: Build enclave EIF runs-on: ubuntu-latest - permissions: - contents: read - id-token: write - packages: write - attestations: write steps: - name: Checkout code uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - name: Mint biometric-engines access token + id: biometric-engines-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + with: + client-id: ${{ secrets.BIOMETRIC_ENGINES_APP_ID }} + private-key: ${{ secrets.BIOMETRIC_ENGINES_APP_PRIVATE_KEY }} + owner: worldcoin + repositories: biometric-engines + - name: Install Rust toolchain uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4 # stable @@ -52,28 +50,14 @@ jobs: path: target/eif/aws-nitro-enclaves-cli-${{ env.NITRO_CLI_VERSION }} key: nitro-cli-${{ runner.os }}-${{ env.NITRO_CLI_VERSION }} - - name: Resolve version - id: version - if: github.ref_type == 'tag' || inputs.version != '' - env: - INPUT_VERSION: ${{ inputs.version }} - run: | - if [[ -n "$INPUT_VERSION" ]]; then - VERSION="$INPUT_VERSION" - else - VERSION="$GITHUB_REF_NAME" - fi - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - if [[ "$VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "is_stable=true" >> "$GITHUB_OUTPUT" - else - echo "is_stable=false" >> "$GITHUB_OUTPUT" - fi - - name: Prepare nitro-cli log directory run: sudo install -d -m 1777 /var/log/nitro_enclaves - name: Build EIF and PCRs + env: + GIT_HUB_TOKEN: ${{ steps.biometric-engines-token.outputs.token }} + # TODO: Remove when models are injected into the enclave at runtime. + SKIP_MODEL_DOWNLOAD: "true" run: scripts/build-eif.sh target/eif - name: Publish PCR measurements @@ -91,44 +75,3 @@ jobs: name: enclave-pcrs path: target/eif/pcrs.json if-no-files-found: error - - - name: Docker meta - id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 - with: - images: ghcr.io/${{ github.repository }}-enclave-eif - tags: | - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' || steps.version.outputs.is_stable == 'true' }} - type=sha - type=raw,value=${{ steps.version.outputs.version }},enable=${{ steps.version.outputs.version != '' }} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - - - name: Login to GitHub Container Registry - if: github.event_name != 'pull_request' - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push carrier image - id: build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 - with: - # Context is the EIF output dir so the .eif is always included. - context: target/eif - file: secure-enclave/Dockerfile.eif - push: ${{ github.event_name != 'pull_request' }} - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - platforms: linux/amd64 - - - name: Attest build provenance - if: github.event_name != 'pull_request' - uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1 - with: - push-to-registry: true - subject-name: ghcr.io/${{ github.repository }}-enclave-eif - subject-digest: ${{ steps.build.outputs.digest }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7494d25..fa420ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ permissions: env: CARGO_TERM_COLOR: always + CARGO_NET_GIT_FETCH_WITH_CLI: true RUST_BACKTRACE: 1 jobs: @@ -30,10 +31,25 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Mint biometric-engines access token + id: biometric-engines-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + with: + client-id: ${{ secrets.BIOMETRIC_ENGINES_APP_ID }} + private-key: ${{ secrets.BIOMETRIC_ENGINES_APP_PRIVATE_KEY }} + owner: worldcoin + repositories: biometric-engines - uses: dtolnay/rust-toolchain@1.97.0 with: components: clippy - uses: Swatinem/rust-cache@v2 + - name: Configure private Git dependencies + env: + BIOMETRIC_ENGINES_TOKEN: ${{ steps.biometric-engines-token.outputs.token }} + run: | + git config --global \ + url."https://x-access-token:${BIOMETRIC_ENGINES_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf \ + "https://github.com/worldcoin/biometric-engines" - name: Run Clippy run: cargo clippy --locked --all-targets --all-features -- @@ -42,8 +58,23 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Mint biometric-engines access token + id: biometric-engines-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + with: + client-id: ${{ secrets.BIOMETRIC_ENGINES_APP_ID }} + private-key: ${{ secrets.BIOMETRIC_ENGINES_APP_PRIVATE_KEY }} + owner: worldcoin + repositories: biometric-engines - uses: dtolnay/rust-toolchain@1.97.0 - uses: Swatinem/rust-cache@v2 + - name: Configure private Git dependencies + env: + BIOMETRIC_ENGINES_TOKEN: ${{ steps.biometric-engines-token.outputs.token }} + run: | + git config --global \ + url."https://x-access-token:${BIOMETRIC_ENGINES_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf \ + "https://github.com/worldcoin/biometric-engines" - name: Build debug run: cargo build --locked --verbose - name: Build release @@ -54,8 +85,23 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Mint biometric-engines access token + id: biometric-engines-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + with: + client-id: ${{ secrets.BIOMETRIC_ENGINES_APP_ID }} + private-key: ${{ secrets.BIOMETRIC_ENGINES_APP_PRIVATE_KEY }} + owner: worldcoin + repositories: biometric-engines - uses: dtolnay/rust-toolchain@1.97.0 - uses: Swatinem/rust-cache@v2 + - name: Configure private Git dependencies + env: + BIOMETRIC_ENGINES_TOKEN: ${{ steps.biometric-engines-token.outputs.token }} + run: | + git config --global \ + url."https://x-access-token:${BIOMETRIC_ENGINES_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf \ + "https://github.com/worldcoin/biometric-engines" - name: Run tests run: cargo test --locked --all --verbose @@ -67,10 +113,19 @@ jobs: checks: - advisories - bans licenses sources - continue-on-error: ${{ matrix.checks == 'advisories' }} steps: - uses: actions/checkout@v4 + - name: Mint biometric-engines access token + id: biometric-engines-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3 + with: + client-id: ${{ secrets.BIOMETRIC_ENGINES_APP_ID }} + private-key: ${{ secrets.BIOMETRIC_ENGINES_APP_PRIVATE_KEY }} + owner: worldcoin + repositories: biometric-engines - uses: EmbarkStudios/cargo-deny-action@v2 + continue-on-error: ${{ matrix.checks == 'advisories' }} with: command: check ${{ matrix.checks }} rust-version: 1.97.0 + credentials: https://x-access-token:${{ steps.biometric-engines-token.outputs.token }}@github.com diff --git a/.gitignore b/.gitignore index 216cf26..07d237b 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,15 @@ Thumbs.db # Environment .env .env.local + +# Private Face Engine model artifacts +models/ + +# Python +**/__pycache__/ + +# Enclave +*.eif + +# Local biometric fixtures used by the E2E client +e2e/**/fixtures/ diff --git a/Cargo.lock b/Cargo.lock index 05f1371..61e9fd6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,28 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "ab_glyph" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + [[package]] name = "aead" version = "0.5.2" @@ -12,6 +34,18 @@ dependencies = [ "generic-array", ] +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -21,6 +55,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -36,6 +79,18 @@ version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +[[package]] +name = "anymap2" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" + +[[package]] +name = "anymap3" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5dfbc6d8d2675589ccbe4d0fd61df2419075625f8c1a62325e718e2b0049f9" + [[package]] name = "api" version = "0.1.0" @@ -56,6 +111,63 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "aquamarine" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21cc1548309245035eb18aa7f0967da6bc65587005170c56e6ef2788a4cf3f4e" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + [[package]] name = "async-trait" version = "0.1.91" @@ -79,6 +191,29 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" +[[package]] +name = "av1-grain" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom 8.0.0", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7178fe5f7d460b13895ebb9dcb28a3a6216d2df2574a0806cb51b555d297f38" +dependencies = [ + "arrayvec", +] + [[package]] name = "aws-nitro-enclaves-cose" version = "0.5.2" @@ -164,6 +299,30 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -176,6 +335,12 @@ version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + [[package]] name = "blake2" version = "0.10.6" @@ -203,12 +368,42 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + [[package]] name = "bumpalo" version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "by_address" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + [[package]] name = "bytes" version = "1.12.1" @@ -222,9 +417,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c89588d05638b5b4594a3348a2d6c20277e43a7f5c5202b05cc56888475a47b8" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec 1.15.2", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -287,6 +494,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "colorutils-rs" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2fc25857fa523662de5cae84225b0e7bfb24a2a3f9ed8802fecf03df7252b1" +dependencies = [ + "erydanos", + "half 2.7.1", + "num-traits", + "rayon", +] + [[package]] name = "const-fnv1a-hash" version = "1.1.0" @@ -308,6 +527,40 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + [[package]] name = "crunchy" version = "0.2.4" @@ -415,6 +668,29 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + +[[package]] +name = "deep_learning_backends" +version = "0.1.0" +source = "git+https://github.com/worldcoin/biometric-engines?rev=face-engine-v2.16.0#4aeb83e43fceea1a52087f008e9311f30f072637" +dependencies = [ + "flexi_logger", + "image", + "log", + "ndarray", + "ndarray-stats", + "num-traits", + "ort", + "ort-tract", + "serde", + "thiserror 1.0.69", +] + [[package]] name = "deranged" version = "0.5.8" @@ -424,6 +700,17 @@ dependencies = [ "serde_core", ] +[[package]] +name = "derive-new" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "digest" version = "0.10.7" @@ -435,12 +722,61 @@ dependencies = [ "subtle", ] +[[package]] +name = "doc-comment" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "780955b8b195a21ab8e4ac6b60dd1dbdcec1dc6c51c0617964b08c81785e12c9" + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + [[package]] name = "dyn-clone" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "dyn-hash" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15401da73a9ed8c80e3b2d4dc05fe10e7b72d7243b9f614e516a44fa99986e88" + +[[package]] +name = "either" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" + +[[package]] +name = "enclave-match-e2e" +version = "0.1.0" +dependencies = [ + "anyhow", + "ciborium", + "crypto_box", + "enclave-types", + "hex", + "pontifex", + "serde", + "serde_bytes", + "sha2", + "tokio", +] + [[package]] name = "enclave-types" version = "0.1.0" @@ -450,6 +786,26 @@ dependencies = [ "serde_bytes", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -467,46 +823,169 @@ dependencies = [ ] [[package]] -name = "fiat-crypto" -version = "0.2.9" +name = "erydanos" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +checksum = "8cbdc4987ed8e9ece64845393c2d53596b3a4ccbfb3948d799d58f6450e89fb1" +dependencies = [ + "num-traits", +] [[package]] -name = "find-msvc-tools" -version = "0.1.9" +name = "event-listener" +version = "5.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] [[package]] -name = "form_urlencoded" -version = "1.2.2" +name = "event-listener-strategy" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "percent-encoding", + "event-listener", + "pin-project-lite", ] [[package]] -name = "futures" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +name = "face-engine" +version = "2.16.0" +source = "git+https://github.com/worldcoin/biometric-engines?rev=face-engine-v2.16.0#4aeb83e43fceea1a52087f008e9311f30f072637" dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", + "approx", + "aquamarine", + "async-lock", + "cfg-if", + "deep_learning_backends", + "fast_image_resize", + "flexi_logger", + "graph", + "image", + "imageproc", + "inventory", + "itertools 0.13.0", + "log", + "nalgebra", + "ndarray", + "ndarray-stats", + "num-traits", + "schemars 0.8.22", + "serde", + "serde_with", + "serde_yaml", + "thiserror 1.0.69", + "utils", + "utils_macros", ] [[package]] -name = "futures-channel" -version = "0.3.32" +name = "fast-srgb8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + +[[package]] +name = "fast_image_resize" +version = "5.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc7fe45cf92b43817ff62a3723e862b85bd1d06288f63007f7645d1d2f7a060" +dependencies = [ + "bytemuck", + "cfg-if", + "document-features", + "image", + "num-traits", + "rayon", + "thiserror 2.0.18", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flexi_logger" +version = "0.28.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cca927478b3747ba47f98af6ba0ac0daea4f12d12f55e9104071b3dc00276310" +dependencies = [ + "chrono", + "glob", + "log", + "nu-ansi-term", + "thiserror 1.0.69", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -593,8 +1072,56 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "libc", + "r-efi", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "graph" +version = "0.1.0" +source = "git+https://github.com/worldcoin/biometric-engines?rev=face-engine-v2.16.0#4aeb83e43fceea1a52087f008e9311f30f072637" +dependencies = [ + "graph_macros", + "inventory", + "log", + "schemars 0.8.22", + "serde", + "serde_with", + "serde_yaml", + "thiserror 1.0.69", +] + +[[package]] +name = "graph_macros" +version = "0.1.0" +source = "git+https://github.com/worldcoin/biometric-engines?rev=face-engine-v2.16.0#4aeb83e43fceea1a52087f008e9311f30f072637" +dependencies = [ + "inventory", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_yaml", + "syn 2.0.118", ] [[package]] @@ -611,6 +1138,7 @@ checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ "cfg-if", "crunchy", + "num-traits", "zerocopy", ] @@ -620,12 +1148,27 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -635,6 +1178,18 @@ dependencies = [ "serde", ] +[[package]] +name = "histogram_equalization" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cba4fb49502d10e699c8907af302e4ecdd930773a1cd63a9fce6a9ab8223d93" +dependencies = [ + "colorutils-rs", + "num-traits", + "rayon", + "yuv", +] + [[package]] name = "http" version = "1.4.2" @@ -696,7 +1251,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "smallvec", + "smallvec 1.15.2", "tokio", ] @@ -745,6 +1300,76 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "image" +version = "0.25.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "image-webp", + "num-traits", + "png", + "ravif", + "rayon", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" +dependencies = [ + "byteorder-lite", + "quick-error", +] + +[[package]] +name = "imageproc" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602b4e8a4cc3e98372b766cd184ab532999bc0e839b7469e759511ccabc65d77" +dependencies = [ + "ab_glyph", + "approx", + "getrandom 0.2.17", + "image", + "itertools 0.12.1", + "nalgebra", + "num", + "rand", + "rand_distr", + "rayon", +] + +[[package]] +name = "imgref" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89194689a993ab15268672e99e7b0e19da2da3268ac682e8f02d29d4d1434cd7" + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -777,12 +1402,69 @@ dependencies = [ "generic-array", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "inventory" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b" +dependencies = [ + "rustversion", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jobserver" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" +dependencies = [ + "getrandom 0.4.3", + "libc", +] + [[package]] name = "js-sys" version = "0.3.103" @@ -794,6 +1476,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "kstring" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b609e7ca5ea38f093c20a4a102335b247221c9643b7a6bc3510f196f99499a9e" +dependencies = [ + "serde", + "static_assertions", +] + [[package]] name = "lazy_static" version = "1.5.0" @@ -806,210 +1498,970 @@ version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +[[package]] +name = "libfuzzer-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9fd2f41a1cba099f79a0b6b6c35656cf7c03351a7bae8ff0f28f25270f929d2" +dependencies = [ + "arbitrary", + "cc", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "liquid" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9338405fdbc0bce9b01695b2a2ef6b20eca5363f385d47bce48ddf8323cc25" +dependencies = [ + "doc-comment", + "liquid-core", + "liquid-derive", + "liquid-lib", + "serde", +] + +[[package]] +name = "liquid-core" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb8fed70857010ed9016ed2ce5a7f34e7cc51d5d7255c9c9dc2e3243e490b42" +dependencies = [ + "anymap2", + "itertools 0.13.0", + "kstring", + "liquid-derive", + "num-traits", + "pest", + "pest_derive", + "regex", + "serde", + "time", +] + +[[package]] +name = "liquid-derive" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b51f1d220e3fa869e24cfd75915efe3164bd09bb11b3165db3f37f57bf673e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "liquid-lib" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1794b5605e9f8864a8a4f41aa97976b42512cc81093f8c885d29fb94c6c556" +dependencies = [ + "itertools 0.13.0", + "liquid-core", + "once_cell", + "percent-encoding", + "regex", + "time", + "unicode-segmentation", +] + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "matrixmultiply" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f607c237553f086e7043417a51df26b2eb899d3caff94e6a67592ff992fedc7" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +dependencies = [ + "libc", + "wasi", + "windows-sys", +] + +[[package]] +name = "nalgebra" +version = "0.32.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5c17de023a86f59ed79891b2e5d5a94c705dbe904a5b5c9c952ea6221b03e4" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "serde", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "254a5372af8fc138e36684761d3c0cdb758a4410e938babcff1c860ce14ddbfc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", + "serde", +] + +[[package]] +name = "ndarray-stats" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ebbe97acce52d06aebed4cd4a87c0941f4b2519b59b82b4feb5bd0ce003dfd" +dependencies = [ + "indexmap 2.14.0", + "itertools 0.13.0", + "ndarray", + "noisy_float", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", +] + +[[package]] +name = "nix" +version = "0.31.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +dependencies = [ + "bitflags 2.13.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset 0.9.1", +] + +[[package]] +name = "noisy_float" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c16843be85dd410c6a12251c4eca0dd1d3ee8c5725f746c4d5e0fdcec0a864b2" +dependencies = [ + "num-traits", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "ort" +version = "2.0.0-rc.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa7e49bd669d32d7bc2a15ec540a527e7764aec722a45467814005725bcd721" +dependencies = [ + "half 2.7.1", + "ndarray", + "ort-sys", + "smallvec 2.0.0-alpha.10", + "tracing", +] + +[[package]] +name = "ort-sys" +version = "2.0.0-rc.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2aba9f5c7c479925205799216e7e5d07cc1d4fa76ea8058c60a9a30f6a4e890" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "ort-tract" +version = "0.1.0+0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41450290a215a579f8a723bb255a872666f98609b37fac8f57c9affcadfd78b" +dependencies = [ + "ort-sys", + "parking_lot", + "tract-onnx", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "palette_derive", + "phf", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec 1.15.2", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7df728be843c7070fab6ab7c328c4e9e9d78e23bf749c0669c86ee7ebfa050a2" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2dd6fc3b26b3462ee188aac870f5a41d398f1cd5e2408d16531bd71c9591fd" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a7a9205cfb6f596a9e8b689c0a15f9ceb7a1aafae7aaf788150ac65b29975b6" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "pest_meta" +version = "2.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85abd351c0de1e8384fc791a0737111a350394937e92b956b743dac12429f57c" +dependencies = [ + "pest", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "pontifex" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03233fbb7d1172ac30d6dd4035c87d11244dc538fd6cf51cd9f5f2143776745" +dependencies = [ + "aws-nitro-enclaves-cose", + "aws-nitro-enclaves-nsm-api", + "const-fnv1a-hash", + "rmp-serde", + "serde", + "serde_bytes", + "serde_cbor", + "sha2", + "thiserror 2.0.18", + "tokio", + "tokio-vsock", + "tracing", +] + +[[package]] +name = "portable-atomic" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3" [[package]] -name = "matchers" -version = "0.2.0" +name = "portable-atomic-util" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ - "regex-automata", + "portable-atomic", ] [[package]] -name = "matchit" -version = "0.8.4" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "memchr" -version = "2.8.3" +name = "ppv-lite86" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] [[package]] -name = "memoffset" -version = "0.7.1" +name = "primal-check" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "dc0d895b311e3af9902528fbb8f928688abbd95872819320517cc24ca6b2bd08" dependencies = [ - "autocfg", + "num-integer", ] [[package]] -name = "memoffset" -version = "0.9.1" +name = "proc-macro-error" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ - "autocfg", + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", ] [[package]] -name = "mime" -version = "0.3.17" +name = "proc-macro-error-attr" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] [[package]] -name = "mio" -version = "1.2.1" +name = "proc-macro2" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ - "libc", - "wasi", - "windows-sys", + "unicode-ident", ] [[package]] -name = "nix" -version = "0.26.4" +name = "profiling" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5" dependencies = [ - "bitflags 1.3.2", - "cfg-if", - "libc", - "memoffset 0.7.1", - "pin-utils", + "profiling-procmacros", ] [[package]] -name = "nix" -version = "0.31.3" +name = "profiling-procmacros" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" +checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb" dependencies = [ - "bitflags 2.13.0", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset 0.9.1", + "quote", + "syn 2.0.118", ] [[package]] -name = "nu-ansi-term" -version = "0.50.3" +name = "prost" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ - "windows-sys", + "bytes", + "prost-derive", ] [[package]] -name = "num-conv" -version = "0.2.2" +name = "prost-derive" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +dependencies = [ + "anyhow", + "itertools 0.10.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] -name = "num-traits" -version = "0.2.19" +name = "quick-error" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ - "autocfg", + "proc-macro2", ] [[package]] -name = "once_cell" -version = "1.21.4" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] -name = "opaque-debug" -version = "0.3.1" +name = "rand" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "rand_chacha" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] [[package]] -name = "pin-project-lite" -version = "0.2.17" +name = "rand_core" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] [[package]] -name = "pin-utils" -version = "0.1.0" +name = "rand_distr" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand", +] [[package]] -name = "poly1305" -version = "0.8.0" +name = "rav1e" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" dependencies = [ - "cpufeatures", - "opaque-debug", - "universal-hash", + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand", + "rand_chacha", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", ] [[package]] -name = "pontifex" -version = "1.1.2" +name = "ravif" +version = "0.11.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03233fbb7d1172ac30d6dd4035c87d11244dc538fd6cf51cd9f5f2143776745" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" dependencies = [ - "aws-nitro-enclaves-cose", - "aws-nitro-enclaves-nsm-api", - "const-fnv1a-hash", - "rmp-serde", - "serde", - "serde_bytes", - "serde_cbor", - "sha2", - "thiserror", - "tokio", - "tokio-vsock", - "tracing", + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", ] [[package]] -name = "powerfmt" -version = "0.2.0" +name = "rawpointer" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" [[package]] -name = "proc-macro2" -version = "1.0.106" +name = "rayon" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ - "unicode-ident", + "either", + "rayon-core", ] [[package]] -name = "quote" -version = "1.0.46" +name = "rayon-core" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ - "proc-macro2", + "crossbeam-deque", + "crossbeam-utils", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "redox_syscall" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "getrandom", + "bitflags 2.13.0", ] [[package]] @@ -1032,6 +2484,18 @@ dependencies = [ "syn 3.0.2", ] +[[package]] +name = "regex" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + [[package]] name = "regex-automata" version = "0.4.15" @@ -1049,6 +2513,12 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" +[[package]] +name = "rgb" +version = "0.8.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4" + [[package]] name = "rmp" version = "0.8.15" @@ -1077,6 +2547,33 @@ dependencies = [ "semver", ] +[[package]] +name = "rustfft" +version = "6.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21db5f9893e91f41798c88680037dba611ca6674703c1a18601b01a72c8adb89" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustversion" version = "1.0.23" @@ -1089,6 +2586,15 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" +[[package]] +name = "safe_arch" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" +dependencies = [ + "bytemuck", +] + [[package]] name = "salsa20" version = "0.10.2" @@ -1098,6 +2604,36 @@ dependencies = [ "cipher", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scan_fmt" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b53b0a5db882a8e2fdaae0a43f7b39e7e9082389e978398bdf223a55b581248" +dependencies = [ + "regex", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + [[package]] name = "schemars" version = "0.9.0" @@ -1122,6 +2658,24 @@ dependencies = [ "serde_json", ] +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.118", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + [[package]] name = "secure-enclave" version = "0.1.0" @@ -1130,7 +2684,9 @@ dependencies = [ "ciborium", "crypto_box", "enclave-types", + "face-engine", "hex", + "image", "pontifex", "serde", "serde_bytes", @@ -1197,6 +2753,17 @@ dependencies = [ "syn 2.0.118", ] +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "serde_json" version = "1.0.150" @@ -1232,6 +2799,15 @@ dependencies = [ "syn 3.0.2", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1270,10 +2846,23 @@ version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.118", + "darling", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.14.0", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", ] [[package]] @@ -1312,6 +2901,40 @@ dependencies = [ "libc", ] +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + [[package]] name = "slab" version = "0.4.12" @@ -1324,6 +2947,12 @@ version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" +[[package]] +name = "smallvec" +version = "2.0.0-alpha.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d44cfb396c3caf6fbfd0ab422af02631b69ddd96d2eff0b0f0724f9024051b" + [[package]] name = "socket2" version = "0.6.4" @@ -1334,6 +2963,29 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "string-interner" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f9fdfdd31a0ff38b59deb401be81b73913d76c9cc5b1aed4e1330a223420b9" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "serde", +] + [[package]] name = "strsim" version = "0.11.1" @@ -1346,6 +2998,17 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.118" @@ -1374,13 +3037,63 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck", + "pkg-config", + "toml", + "version-compare", +] + +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] @@ -1488,6 +3201,40 @@ dependencies = [ "vsock", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap 2.14.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.5.3" @@ -1587,25 +3334,199 @@ dependencies = [ "once_cell", "regex-automata", "sharded-slab", - "smallvec", + "smallvec 1.15.2", "thread_local", "tracing", "tracing-core", "tracing-log", ] +[[package]] +name = "tract-core" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7b5347639690871b124593a8c8903f1f369531498b8abaebd18eb5c58163971" +dependencies = [ + "anyhow", + "anymap3", + "bit-set", + "derive-new", + "downcast-rs", + "dyn-clone", + "lazy_static", + "log", + "maplit", + "ndarray", + "num-complex", + "num-integer", + "num-traits", + "paste", + "rustfft", + "smallvec 1.15.2", + "tract-data", + "tract-linalg", +] + +[[package]] +name = "tract-data" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0a3f476a1804e05708e9bc5e2d29dcab82bad531e357d3d14d7da80fbba0b6d" +dependencies = [ + "anyhow", + "downcast-rs", + "dyn-clone", + "dyn-hash", + "half 2.7.1", + "itertools 0.12.1", + "lazy_static", + "maplit", + "ndarray", + "nom 7.1.3", + "num-integer", + "num-traits", + "parking_lot", + "scan_fmt", + "smallvec 1.15.2", + "string-interner", +] + +[[package]] +name = "tract-hir" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dca047ba1151fe3446fb0194d4b6ddb9ae8f361337c47a267870c53605fbafb" +dependencies = [ + "derive-new", + "log", + "tract-core", +] + +[[package]] +name = "tract-linalg" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb8e0703eb53ef1bbf77050ff261675818dd5f0d6c27044c6e48ede9b845f9e0" +dependencies = [ + "byteorder", + "cc", + "derive-new", + "downcast-rs", + "dyn-clone", + "dyn-hash", + "half 2.7.1", + "lazy_static", + "liquid", + "liquid-core", + "liquid-derive", + "log", + "num-traits", + "paste", + "rayon", + "scan_fmt", + "smallvec 1.15.2", + "time", + "tract-data", + "unicode-normalization", + "walkdir", +] + +[[package]] +name = "tract-nnef" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72cb88a4367ec2c695610223cf886f01fc1deb5c9a82c7a74b1a5d32dc0b1466" +dependencies = [ + "byteorder", + "flate2", + "log", + "nom 7.1.3", + "tar", + "tract-core", + "walkdir", +] + +[[package]] +name = "tract-onnx" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5830aa672b2aa4dc98a97a36e5988eaf77b3ecee65e2601619588d2ca557008" +dependencies = [ + "bytes", + "derive-new", + "log", + "memmap2", + "num-integer", + "prost", + "smallvec 1.15.2", + "tract-hir", + "tract-nnef", + "tract-onnx-opl", +] + +[[package]] +name = "tract-onnx-opl" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121d3d224c806ba3d941f4bb50943ad33b59d1da5ae704d0e4e76d2808221f96" +dependencies = [ + "getrandom 0.2.17", + "log", + "rand", + "rand_distr", + "rustfft", + "tract-nnef", +] + +[[package]] +name = "transpose" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad61aed86bc3faea4300c7aee358b4c6d0c8d6ccc36524c96e4c92ccf26e77e" +dependencies = [ + "num-integer", + "strength_reduce", +] + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + [[package]] name = "typenum" version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + [[package]] name = "unicode-ident" version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + [[package]] name = "universal-hash" version = "0.5.1" @@ -1616,12 +3537,73 @@ dependencies = [ "subtle", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "utils" +version = "0.1.0" +source = "git+https://github.com/worldcoin/biometric-engines?rev=face-engine-v2.16.0#4aeb83e43fceea1a52087f008e9311f30f072637" +dependencies = [ + "approx", + "bincode", + "data-encoding", + "fast_image_resize", + "histogram_equalization", + "image", + "imageproc", + "inventory", + "itertools 0.13.0", + "log", + "nalgebra", + "ndarray", + "ndarray-stats", + "num-traits", + "palette", + "rustfft", + "schemars 0.8.22", + "serde", + "serde_yaml", + "sha2", + "thiserror 1.0.69", +] + +[[package]] +name = "utils_macros" +version = "0.1.0" +source = "git+https://github.com/worldcoin/biometric-engines?rev=face-engine-v2.16.0#4aeb83e43fceea1a52087f008e9311f30f072637" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + [[package]] name = "version_check" version = "0.9.5" @@ -1638,6 +3620,16 @@ dependencies = [ "nix 0.31.3", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" @@ -1689,6 +3681,25 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wide" +version = "0.7.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +dependencies = [ + "bytemuck", + "safe_arch", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -1757,6 +3768,34 @@ dependencies = [ "windows-link", ] +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + +[[package]] +name = "yuv" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d85a782d94ee43f078bcfd6fa82d4e6a5b2d1cfbbad168e4df5a9f7b39ef48c" +dependencies = [ + "num-traits", +] + [[package]] name = "zerocopy" version = "0.8.55" @@ -1788,3 +3827,18 @@ name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-jpeg" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index 8dda3ac..6520aa4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["api", "secure-enclave", "shared/enclave-types"] +members = ["api", "e2e/enclave-match-e2e", "secure-enclave", "shared/enclave-types"] resolver = "3" [workspace.package] @@ -17,7 +17,9 @@ base64 = "0.22" ciborium = "0.2" crypto_box = { version = "0.9.1", default-features = false, features = ["getrandom"] } enclave-types = { path = "shared/enclave-types" } +face-engine = { git = "https://github.com/worldcoin/biometric-engines", rev = "face-engine-v2.16.0", default-features = false, features = ["tract"] } hex = { version = "0.4", default-features = false, features = ["alloc"] } +image = { version = "=0.25.6", default-features = false, features = ["jpeg", "png", "webp"] } pontifex = { version = "1.1.2", default-features = false } serde = { version = "1.0", features = ["derive"] } serde_bytes = "0.11" diff --git a/Dockerfile b/Dockerfile index 9bcf148..78041f5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,15 +19,29 @@ RUN cargo chef prepare --recipe-path recipe.json FROM chef AS builder COPY --from=planner /app/recipe.json recipe.json -RUN cargo chef cook --release --locked \ +RUN --mount=type=secret,id=GITHUB_TOKEN,required=true \ + GITHUB_TOKEN="$(cat /run/secrets/GITHUB_TOKEN)" && \ + git config --global \ + url."https://x-access-token:${GITHUB_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf \ + "https://github.com/worldcoin/biometric-engines" && \ + CARGO_NET_GIT_FETCH_WITH_CLI=true cargo chef cook --release --locked \ --target x86_64-unknown-linux-musl \ --recipe-path recipe.json \ - --package api + --package api && \ + git config --global --unset-all \ + url."https://x-access-token:${GITHUB_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf COPY . . -RUN cargo build --release --locked \ +RUN --mount=type=secret,id=GITHUB_TOKEN,required=true \ + GITHUB_TOKEN="$(cat /run/secrets/GITHUB_TOKEN)" && \ + git config --global \ + url."https://x-access-token:${GITHUB_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf \ + "https://github.com/worldcoin/biometric-engines" && \ + CARGO_NET_GIT_FETCH_WITH_CLI=true cargo build --release --locked \ --target x86_64-unknown-linux-musl \ --package api \ - && mv target/x86_64-unknown-linux-musl/release/api /app/api-bin + && mv target/x86_64-unknown-linux-musl/release/api /app/api-bin \ + && git config --global --unset-all \ + url."https://x-access-token:${GITHUB_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf FROM scratch AS runtime WORKDIR /app diff --git a/api/src/enclave.rs b/api/src/enclave.rs index d5d5f63..d67d912 100644 --- a/api/src/enclave.rs +++ b/api/src/enclave.rs @@ -10,8 +10,7 @@ use enclave_types::{ use pontifex::client::ConnectionDetails; use tokio::time::timeout; -const REQUEST_TIMEOUT: Duration = Duration::from_secs(2); - +const CONTROL_REQUEST_TIMEOUT: Duration = Duration::from_secs(2); // Match requests can carry large payloads and require expensive computation. const MATCH_REQUEST_TIMEOUT: Duration = Duration::from_secs(30); @@ -59,7 +58,7 @@ impl PontifexEnclaveClient { impl EnclaveClient for PontifexEnclaveClient { async fn health(&self) -> Result<(), EnclaveClientError> { let response = timeout( - REQUEST_TIMEOUT, + CONTROL_REQUEST_TIMEOUT, pontifex::client::send(self.connection, &HealthRequest), ) .await @@ -71,7 +70,7 @@ impl EnclaveClient for PontifexEnclaveClient { async fn get_transit_key(&self) -> Result { let response = timeout( - REQUEST_TIMEOUT, + CONTROL_REQUEST_TIMEOUT, pontifex::client::send(self.connection, &GetTransitKeyRequest), ) .await diff --git a/api/src/routes/matches.rs b/api/src/routes/matches.rs index 986da2d..676a1f3 100644 --- a/api/src/routes/matches.rs +++ b/api/src/routes/matches.rs @@ -90,11 +90,13 @@ const fn status_for(error: &EnclaveClientError) -> StatusCode { EnclaveClientError::Operation(operation) => match operation { EnclaveError::DecryptFailed | EnclaveError::MalformedMatchPayload - | EnclaveError::InvalidHashesJson => StatusCode::BAD_REQUEST, + | EnclaveError::InvalidHashesJson + | EnclaveError::InvalidImage => StatusCode::BAD_REQUEST, // Well-formed request, but the match itself did not hold. - EnclaveError::ThumbnailHashMismatch | EnclaveError::MatchBelowThreshold => { - StatusCode::UNPROCESSABLE_ENTITY - } + EnclaveError::ThumbnailHashMismatch + | EnclaveError::MatchBelowThreshold + | EnclaveError::EmbeddingGenerationFailed => StatusCode::UNPROCESSABLE_ENTITY, + EnclaveError::EmbeddingComparisonFailed => StatusCode::INTERNAL_SERVER_ERROR, EnclaveError::NotReady | EnclaveError::SecureModuleNotInitialized | EnclaveError::AttestationFailed => StatusCode::SERVICE_UNAVAILABLE, diff --git a/deny.toml b/deny.toml index 3d7d920..fe3556f 100644 --- a/deny.toml +++ b/deny.toml @@ -19,6 +19,9 @@ deny = [ [licenses] version = 2 confidence-threshold = 1.0 +# biometric-engines is a private first-party repository whose crates are not +# published with SPDX metadata. Keep enforcing licenses for every other source. +private = { ignore = true, ignore-sources = ["https://github.com/worldcoin/biometric-engines"] } allow = [ "Apache-2.0", "BSD-3-Clause", @@ -29,3 +32,4 @@ allow = [ [sources] unknown-registry = "deny" unknown-git = "deny" +allow-git = ["https://github.com/worldcoin/biometric-engines"] diff --git a/e2e/enclave-match-e2e/Cargo.toml b/e2e/enclave-match-e2e/Cargo.toml new file mode 100644 index 0000000..d886262 --- /dev/null +++ b/e2e/enclave-match-e2e/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "enclave-match-e2e" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +publish.workspace = true + +[dependencies] +anyhow.workspace = true +ciborium.workspace = true +crypto_box = { workspace = true, features = ["seal", "salsa20"] } +enclave-types.workspace = true +hex.workspace = true +pontifex = { workspace = true, features = ["client", "nsm"] } +serde.workspace = true +serde_bytes.workspace = true +sha2.workspace = true +tokio.workspace = true diff --git a/e2e/enclave-match-e2e/src/main.rs b/e2e/enclave-match-e2e/src/main.rs new file mode 100644 index 0000000..3255df1 --- /dev/null +++ b/e2e/enclave-match-e2e/src/main.rs @@ -0,0 +1,156 @@ +use std::{env, fs, path::PathBuf}; + +use anyhow::{Context, Result, anyhow, ensure}; +use crypto_box::{PublicKey, aead::OsRng}; +use enclave_types::{GetTransitKeyRequest, MatchRequest}; +use pontifex::{SecureModule, client::ConnectionDetails}; +use serde::Serialize; +use sha2::{Digest, Sha256}; + +const DEFAULT_ENCLAVE_PORT: u32 = 1000; +const DEFAULT_MATCH_THRESHOLD: f32 = 0.9; + +/// Plaintext schema wrapped by the sealed [`MatchRequest`] payload. +/// +/// This is intentionally not part of `enclave-types`: Pontifex only transports +/// the opaque ciphertext, while this schema is the private encrypted protocol. +#[derive(Serialize)] +struct MatchInputs<'a> { + #[serde(with = "serde_bytes")] + live_image: &'a [u8], + #[serde(with = "serde_bytes")] + credential_image: &'a [u8], + #[serde(with = "serde_bytes")] + hashes_json: &'a [u8], + #[serde(with = "serde_bytes")] + challenge_image: &'a [u8], + match_threshold: f32, +} + +#[tokio::main] +async fn main() -> Result<()> { + let image_paths = image_paths()?; + let credential_image = read_image(&image_paths.credential, "credential")?; + let live_image = read_image(&image_paths.live, "live")?; + let challenge_image = read_image(&image_paths.challenge, "challenge")?; + + let enclave_cid = required_u32("ENCLAVE_CID")?; + let enclave_port = optional_u32("ENCLAVE_PORT", DEFAULT_ENCLAVE_PORT)?; + let match_threshold = optional_f32("MATCH_THRESHOLD", DEFAULT_MATCH_THRESHOLD)?; + let connection = ConnectionDetails::new(enclave_cid, enclave_port); + + let transit_response = pontifex::client::send(connection, &GetTransitKeyRequest) + .await + .context("failed to call the enclave transit-key route")? + .map_err(|error| anyhow!("enclave rejected the transit-key request: {error:?}"))?; + let attestation = SecureModule::parse_raw_attestation_doc(&transit_response.attestation) + .map_err(|error| anyhow!("failed to parse the enclave attestation document: {error:?}"))?; + let transit_key = attestation + .public_key + .context("attestation did not contain a transit public key")?; + let transit_key: [u8; 32] = transit_key + .as_ref() + .try_into() + .map_err(|_| anyhow!("attested transit public key was not 32 bytes"))?; + + let hashes_json = hashes_json_for(&credential_image); + let payload = MatchInputs { + live_image: &live_image, + credential_image: &credential_image, + hashes_json: &hashes_json, + challenge_image: &challenge_image, + match_threshold, + }; + let mut plaintext = Vec::new(); + ciborium::into_writer(&payload, &mut plaintext) + .context("failed to encode the encrypted match payload")?; + + let sealed_payload = PublicKey::from(transit_key) + .seal(&mut OsRng, &plaintext) + .map_err(|error| anyhow!("failed to seal the match payload: {error}"))?; + let response = pontifex::client::send(connection, &MatchRequest { sealed_payload }) + .await + .context("failed to call the enclave matches route")? + .map_err(|error| anyhow!("enclave rejected the match request: {error:?}"))?; + + ensure!( + response.statement.match_coefficient >= match_threshold, + "credential/live score {} did not meet threshold {}", + response.statement.match_coefficient, + match_threshold + ); + ensure!( + response.statement.live_image_hash == Sha256::digest(&live_image).as_slice(), + "statement did not commit to the live image" + ); + ensure!( + response.statement.challenger_image_hash == Sha256::digest(&challenge_image).as_slice(), + "statement did not commit to the challenge image" + ); + ensure!( + response.statement.credential_claim == Sha256::digest(&hashes_json).as_slice(), + "statement did not commit to hashes.json" + ); + + println!( + "match succeeded: credential/live similarity={:.6}, threshold={:.6}", + response.statement.match_coefficient, match_threshold + ); + Ok(()) +} + +struct ImagePaths { + credential: PathBuf, + live: PathBuf, + challenge: PathBuf, +} + +fn image_paths() -> Result { + let mut args = env::args_os().skip(1); + let usage = "usage: enclave-match-e2e "; + let credential = args.next().map(PathBuf::from).context(usage)?; + let live = args.next().map(PathBuf::from).context(usage)?; + let challenge = args.next().map(PathBuf::from).context(usage)?; + ensure!(args.next().is_none(), "{usage}"); + + Ok(ImagePaths { + credential, + live, + challenge, + }) +} + +fn read_image(path: &PathBuf, label: &str) -> Result> { + fs::read(path).with_context(|| format!("failed to read {label} image at {}", path.display())) +} + +fn hashes_json_for(image: &[u8]) -> Vec { + let hash = hex::encode(Sha256::digest(image)); + format!(r#"{{"thumbnail.png":"{hash}"}}"#).into_bytes() +} + +fn required_u32(name: &str) -> Result { + env::var(name) + .with_context(|| format!("{name} must be set")) + .and_then(|value| { + value + .parse() + .with_context(|| format!("{name} must be a valid u32")) + }) +} + +fn optional_u32(name: &str, default: u32) -> Result { + env::var(name).map_or(Ok(default), |value| { + value + .parse() + .with_context(|| format!("{name} must be a valid u32")) + }) +} + +fn optional_f32(name: &str, default: f32) -> Result { + env::var(name).map_or(Ok(default), |value| { + value + .parse() + .with_context(|| format!("{name} must be a valid f32")) + }) +} diff --git a/scripts/build-eif.sh b/scripts/build-eif.sh index b3e4804..5a38df0 100755 --- a/scripts/build-eif.sh +++ b/scripts/build-eif.sh @@ -7,7 +7,9 @@ set -euo pipefail # # Usage: scripts/build-eif.sh [output-dir] (default: target/eif) # Outputs: embedding-verifier-enclave.eif, pcrs.json -# Env: NITRO_CLI_VERSION (default v1.4.2), ENCLAVE_IMAGE_TAG +# Env: NITRO_CLI_VERSION (default v1.4.2), ENCLAVE_IMAGE_TAG, +# SKIP_MODEL_DOWNLOAD (default false), +# GIT_HUB_TOKEN (read access to private GitHub dependencies) if [ "$(uname -s)" != "Linux" ] || [ "$(uname -m)" != "x86_64" ]; then echo "[ERROR] EIF builds require Linux x86_64 (got $(uname -s)/$(uname -m))." >&2 @@ -16,6 +18,7 @@ fi NITRO_CLI_VERSION="${NITRO_CLI_VERSION:-v1.4.2}" ENCLAVE_IMAGE_TAG="${ENCLAVE_IMAGE_TAG:-embedding-verifier-enclave:local}" +SKIP_MODEL_DOWNLOAD="${SKIP_MODEL_DOWNLOAD:-false}" repo_root="$(git rev-parse --show-toplevel)" cd "$repo_root" @@ -25,7 +28,16 @@ mkdir -p "$out_dir" out_dir="$(cd "$out_dir" && pwd)" echo "[1/3] Building enclave container image ($ENCLAVE_IMAGE_TAG)..." -docker build -t "$ENCLAVE_IMAGE_TAG" -f secure-enclave/Dockerfile . +if [[ -z "${GIT_HUB_TOKEN:-}" ]]; then + echo "[ERROR] GIT_HUB_TOKEN is required to fetch private GitHub dependencies." >&2 + exit 1 +fi +docker build \ + --secret id=GITHUB_TOKEN,env=GIT_HUB_TOKEN \ + --build-arg "SKIP_MODEL_DOWNLOAD=$SKIP_MODEL_DOWNLOAD" \ + -t "$ENCLAVE_IMAGE_TAG" \ + -f secure-enclave/Dockerfile \ + . echo "[2/3] Building nitro-cli $NITRO_CLI_VERSION..." nitro_cli_dir="$out_dir/aws-nitro-enclaves-cli-$NITRO_CLI_VERSION" diff --git a/scripts/download-face-models.py b/scripts/download-face-models.py new file mode 100755 index 0000000..a212ef8 --- /dev/null +++ b/scripts/download-face-models.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +"""Download the Face Engine v2 ONNX models used by the enclave MVP.""" + +import argparse +import hashlib +import os +import shutil +import tempfile +from pathlib import Path + +# This placeholder comparison pipeline only needs: +# - RGBNet to find the subject face. +# - FaceEmbeddingGenerator (GhostFaceNet) to produce the vector being compared. +# Quality, liveness, spoof, and head-pose models are intentionally excluded until those checks +# become part of the route. +# +# Each default revision below is an immutable Hugging Face Git commit from biometric-engines +# v2.16.0's model_revisions.env. A revision identifies which repository snapshot to download; it +# is not the checksum of the ONNX file. +MODELS = ( + ( + "FaceEmbeddingGenerator", + "REV_FACEEMBEDDINGGENERATOR", + "5fcbd28a5304ca1f1a186c300261ebccafb5eeec", + ), + ("RGBNet", "REV_RGBNET", "e81cff53eaeb3881d18415407fc1a7b07c2b0600"), +) + +REQUIRED_FILES = ( + "face_embedding_generator.onnx", + "rgbnet.onnx", +) + +# These are SHA-256 digests of the downloaded ONNX bytes. They independently ensure that a pinned +# revision produced the reviewed artifacts and catch corrupt or replaced files. Changing a model +# revision therefore requires reviewing and updating its digest here as the same change. +EXPECTED_SHA256 = { + "face_embedding_generator.onnx": "3a5807e26adff1a6a25ac50dc0139cb6c5c87cbcb0594bd7065fa29bd185e19c", + "rgbnet.onnx": "25bfb4cd007f616da02e6a8484121f97a5bced67f0485d234f88220958603638", +} + + +def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--output", type=Path, default=Path("models")) + parser.add_argument("--token", default=os.environ.get("HUGGING_FACE_TOKEN")) + args = parser.parse_args() + + if not args.token: + parser.error("set HUGGING_FACE_TOKEN or pass --token") + + try: + from huggingface_hub import snapshot_download + except ImportError: + parser.error("install the downloader with: python3 -m pip install huggingface-hub") + + args.output.mkdir(parents=True, exist_ok=True) + + for model, revision_variable, default_revision in MODELS: + with tempfile.TemporaryDirectory() as temporary_directory: + destination = Path(temporary_directory) + snapshot_download( + repo_id=f"Worldcoin/{model}", + revision=os.environ.get(revision_variable, default_revision), + allow_patterns=["onnx/*"], + local_dir=destination, + token=args.token, + ) + + flavor_directory = destination / "onnx" + if not flavor_directory.is_dir(): + raise RuntimeError(f"{model} did not contain an onnx flavor") + + for model_file in flavor_directory.iterdir(): + if model_file.is_file(): + shutil.copy2(model_file, args.output / model_file.name) + + missing = [name for name in REQUIRED_FILES if not (args.output / name).is_file()] + if missing: + raise RuntimeError(f"download completed without required models: {', '.join(missing)}") + + for name, expected_digest in EXPECTED_SHA256.items(): + model_path = args.output / name + observed_digest = hashlib.sha256(model_path.read_bytes()).hexdigest() + if observed_digest != expected_digest: + raise RuntimeError( + f"checksum mismatch for {name}: expected {expected_digest}, got {observed_digest}" + ) + + +if __name__ == "__main__": + main() diff --git a/secure-enclave/Cargo.toml b/secure-enclave/Cargo.toml index 237b7b0..63aafd7 100644 --- a/secure-enclave/Cargo.toml +++ b/secure-enclave/Cargo.toml @@ -15,7 +15,9 @@ anyhow.workspace = true ciborium.workspace = true crypto_box = { workspace = true, features = ["seal", "salsa20"] } enclave-types.workspace = true +face-engine.workspace = true hex.workspace = true +image.workspace = true pontifex = { workspace = true, features = ["nsm", "server"] } serde = { workspace = true } serde_bytes.workspace = true diff --git a/secure-enclave/Dockerfile b/secure-enclave/Dockerfile index aa964e5..1b8ab75 100644 --- a/secure-enclave/Dockerfile +++ b/secure-enclave/Dockerfile @@ -17,7 +17,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ WORKDIR /src COPY . . -RUN cargo build --release --locked --package secure-enclave --bin secure-enclave +RUN --mount=type=secret,id=GITHUB_TOKEN,required=true \ + GITHUB_TOKEN="$(cat /run/secrets/GITHUB_TOKEN)" && \ + git config --global \ + url."https://x-access-token:${GITHUB_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf \ + "https://github.com/worldcoin/biometric-engines" && \ + CARGO_NET_GIT_FETCH_WITH_CLI=true \ + cargo build --release --locked --package secure-enclave --bin secure-enclave && \ + git config --global --unset-all \ + url."https://x-access-token:${GITHUB_TOKEN}@github.com/worldcoin/biometric-engines".insteadOf FROM debian:bookworm-slim @@ -27,6 +35,18 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY --from=builder /src/target/release/secure-enclave /usr/local/bin/secure-enclave +# TODO: Remove this build-time switch once models are injected into the enclave +# at runtime. CI sets it to true because private model artifacts are unavailable. +ARG SKIP_MODEL_DOWNLOAD=false +RUN --mount=from=builder,source=/src,target=/build,ro \ + if [ "$SKIP_MODEL_DOWNLOAD" = "true" ]; then \ + echo "Skipping model packaging"; \ + else \ + mkdir -p /models; \ + cp /build/models/face_embedding_generator.onnx /models/face_embedding_generator.onnx; \ + cp /build/models/rgbnet.onnx /models/rgbnet.onnx; \ + fi + ENV RUST_LOG=info ENTRYPOINT ["/usr/local/bin/secure-enclave"] diff --git a/secure-enclave/config/face_analyzer.yaml b/secure-enclave/config/face_analyzer.yaml new file mode 100644 index 0000000..fd81090 --- /dev/null +++ b/secure-enclave/config/face_analyzer.yaml @@ -0,0 +1,16 @@ +graph: + # Minimal placeholder graph: detect one subject without quality or liveness validation. + - node_name: rgb_net + node_type: RGBNet + dependencies: ["input"] + args: + # Packaged at this fixed location in the prototype enclave image. + model_path: /models/rgbnet.onnx + confidence_threshold: 0.8 + iou_threshold: 0.3 + + - node_name: largest_bounding_box_subject_extractor + node_type: LargestBoundingBoxSubjectExtractor + dependencies: ["input", "rgb_net"] + args: + correct_inferred_orientation: false diff --git a/secure-enclave/config/face_template_generator.yaml b/secure-enclave/config/face_template_generator.yaml new file mode 100644 index 0000000..e1ad9c9 --- /dev/null +++ b/secure-enclave/config/face_template_generator.yaml @@ -0,0 +1,10 @@ +graph: + # Generate the comparison embedding only; spoof and quality nodes are intentionally omitted. + - node_name: ghost_face_net + node_type: GhostFaceNet + dependencies: ["input"] + args: + # Packaged at this fixed location in the prototype enclave image. + model_path: /models/face_embedding_generator.onnx + # Match Face Engine's default by averaging embeddings for the image and its horizontal flip. + average_with_flipped: true diff --git a/secure-enclave/src/face_engine.rs b/secure-enclave/src/face_engine.rs new file mode 100644 index 0000000..2460746 --- /dev/null +++ b/secure-enclave/src/face_engine.rs @@ -0,0 +1,163 @@ +//! Face Engine initialization and in-enclave embedding comparison. + +use std::{io::Cursor, sync::Arc}; + +use enclave_types::EnclaveError; +use face_engine::{ + components::{ + captured_image_analyzer::CapturedImageAnalyzer, template_generator::TemplateGenerator, + }, + io::rgb_image::RgbImage, + matchers::cosine_similarity::CosineSimilarity, + nodes::{subject_extraction::SubjectFace, template_generation::EmbeddingVector}, +}; +use image::ImageReader; + +const FACE_ANALYZER_CONFIG: &str = include_str!("../config/face_analyzer.yaml"); +const FACE_TEMPLATE_GENERATOR_CONFIG: &str = include_str!("../config/face_template_generator.yaml"); + +// TODO: Inject production Face Engine configs and model artifacts at runtime instead of compiling +// the prototype configs and fixed `/models` paths into the enclave. +/// Similarity scores for one credential image against the live and challenge images. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct ComparisonScores { + /// Credential-to-live cosine similarity. + pub live_similarity: f32, + /// Credential-to-challenge cosine similarity. + pub challenge_similarity: f32, +} + +/// Face comparison behavior required by the enclave match operation. +pub trait FaceComparator: Send + Sync { + /// Generates one credential embedding and compares it with the live and challenge images. + /// + /// # Errors + /// + /// Returns a structured enclave error when an image is invalid, embedding generation fails, + /// or the embeddings cannot be compared. + fn compare_reference_to_probes( + &self, + credential_image: &[u8], + live_image: &[u8], + challenge_image: &[u8], + ) -> Result; +} + +/// Face Engine implementation backed by the configured ONNX models. +pub struct FaceEngine { + template_generator: TemplateGenerator, + analyzer: CapturedImageAnalyzer, + matcher: CosineSimilarity, +} + +impl Default for FaceEngine { + fn default() -> Self { + Self { + template_generator: TemplateGenerator::new(FACE_TEMPLATE_GENERATOR_CONFIG) + .expect("built-in Face Engine template generator config and model should load"), + analyzer: CapturedImageAnalyzer::new(FACE_ANALYZER_CONFIG) + .expect("built-in Face Engine analyzer config and model should load"), + matcher: CosineSimilarity::default(), + } + } +} + +impl FaceEngine { + fn generate_embedding(&self, image_bytes: &[u8]) -> Result { + let dynamic_image = ImageReader::new(Cursor::new(image_bytes)) + .with_guessed_format() + .map_err(|error| { + tracing::warn!(%error, "could not determine image format"); + EnclaveError::InvalidImage + })? + .decode() + .map_err(|error| { + tracing::warn!(%error, "could not decode face image"); + EnclaveError::InvalidImage + })?; + + let rgb_image = RgbImage::new( + dynamic_image.to_rgb8().into_vec(), + dynamic_image.height(), + dynamic_image.width(), + None, + ) + .map_err(|error| { + tracing::warn!(%error, "could not construct Face Engine RGB image"); + EnclaveError::InvalidImage + })?; + + let analysis = self + .analyzer + .run_inference_rgb(&rgb_image) + .map_err(|error| { + tracing::error!(%error, "Face Engine image analysis failed"); + EnclaveError::EmbeddingGenerationFailed + })?; + if let Some(error) = analysis.error { + tracing::warn!(?error, "Face Engine image analysis failed"); + return Err(EnclaveError::EmbeddingGenerationFailed); + } + + let subject_metadata = analysis.subject_face_extracted.ok_or_else(|| { + tracing::warn!("Face Engine did not extract a subject"); + EnclaveError::EmbeddingGenerationFailed + })?; + let subject = SubjectFace { + input_image: Arc::new(rgb_image), + metadata: subject_metadata, + }; + + let output = self + .template_generator + .run_inference(&subject) + .map_err(|error| { + tracing::error!(%error, "Face Engine template inference failed"); + EnclaveError::EmbeddingGenerationFailed + })?; + + if let Some(error) = output.metadata.error { + tracing::warn!(?error, "Face Engine rejected the generated template"); + return Err(EnclaveError::EmbeddingGenerationFailed); + } + + output.embedding_vector.ok_or_else(|| { + tracing::error!("Face Engine returned no embedding"); + EnclaveError::EmbeddingGenerationFailed + }) + } + + fn compute_score( + &self, + probe: &EmbeddingVector, + reference: &EmbeddingVector, + ) -> Result { + self.matcher + .compute_score(probe, reference) + .map_err(|error| { + tracing::error!(%error, "Face Engine embedding comparison failed"); + EnclaveError::EmbeddingComparisonFailed + }) + } +} + +impl FaceComparator for FaceEngine { + fn compare_reference_to_probes( + &self, + credential_image: &[u8], + live_image: &[u8], + challenge_image: &[u8], + ) -> Result { + let reference = self.generate_embedding(credential_image)?; + let live = self.generate_embedding(live_image)?; + let challenge = self.generate_embedding(challenge_image)?; + + let live_similarity = self.compute_score(&live, &reference)?; + let challenge_similarity = self.compute_score(&challenge, &reference)?; + + Ok(ComparisonScores { + live_similarity, + challenge_similarity, + }) + } +} diff --git a/secure-enclave/src/lib.rs b/secure-enclave/src/lib.rs index c1bc37b..4bbc587 100644 --- a/secure-enclave/src/lib.rs +++ b/secure-enclave/src/lib.rs @@ -1,4 +1,4 @@ -//! Secure-enclave runtime for private face verification. +//! Secure-enclave runtime for private face comparison. #![deny( clippy::all, @@ -8,6 +8,8 @@ dead_code )] +/// Face embedding generation and comparison. +pub mod face_engine; /// PCP binding verification (transport-free). pub mod pcp; /// Pontifex operations exposed to the API host. diff --git a/secure-enclave/src/main.rs b/secure-enclave/src/main.rs index 34f1179..e284770 100644 --- a/secure-enclave/src/main.rs +++ b/secure-enclave/src/main.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use anyhow::Context; -use secure_enclave::{pontifex_server, rng, state::EnclaveState}; +use secure_enclave::{face_engine::FaceEngine, pontifex_server, rng, state::EnclaveState}; use tracing::{error, info}; use tracing_subscriber::EnvFilter; @@ -14,7 +14,9 @@ async fn main() -> anyhow::Result<()> { .init(); rng::verify_nsm_hwrng_current().context("Nitro hardware RNG is not configured")?; - let state = Arc::new(EnclaveState::generate()); + let face_engine = Arc::new(FaceEngine::default()); + info!("initialized Face Engine"); + let state = Arc::new(EnclaveState::generate(face_engine)); info!(port = PONTIFEX_PORT, "starting enclave Pontifex server"); diff --git a/secure-enclave/src/pontifex_server/matches.rs b/secure-enclave/src/pontifex_server/matches.rs index f4a84e8..49c964d 100644 --- a/secure-enclave/src/pontifex_server/matches.rs +++ b/secure-enclave/src/pontifex_server/matches.rs @@ -6,15 +6,11 @@ use pontifex::Request; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; -use crate::pcp; -use crate::state::EnclaveState; +use crate::{pcp, state::EnclaveState}; /// Statement format version. const STATEMENT_VERSION: u8 = 1; -/// Placeholder similarity score until the face engine lands; clears any sane threshold. -const DUMMY_MATCH_COEFFICIENT: f32 = 1.0; - /// Placeholder statement signature until signing lands. const DUMMY_SIGNATURE: [u8; 64] = [0u8; 64]; @@ -48,8 +44,7 @@ impl MatchInputs { /// Runs a 3-way face match: the credential image against both the live and challenge /// images. /// -/// SKELETON: unseal, PCP binding, hashing, and the threshold gate are real; the face -/// comparisons and the statement signature are dummies. +/// The statement signature remains a placeholder. pub async fn handler( state: Arc, request: MatchRequest, @@ -83,12 +78,20 @@ pub async fn handler( let live_image_hash: [u8; 32] = Sha256::digest(&payload.live_image).into(); let challenger_image_hash: [u8; 32] = Sha256::digest(&payload.challenge_image).into(); - // DUMMY comparisons: both must clear the threshold or no statement is issued. - let live_coefficient = DUMMY_MATCH_COEFFICIENT; - let challenge_coefficient = DUMMY_MATCH_COEFFICIENT; + let scores = state.face_engine().compare_reference_to_probes( + &payload.credential_image, + &payload.live_image, + &payload.challenge_image, + )?; + let live_coefficient = scores.live_similarity; + let challenge_coefficient = scores.challenge_similarity; + if live_coefficient < payload.match_threshold || challenge_coefficient < payload.match_threshold { tracing::warn!( + live_coefficient, + challenge_coefficient, + threshold = payload.match_threshold, route = MatchRequest::ROUTE_ID, "match scored below threshold" ); @@ -120,7 +123,72 @@ mod tests { use sha2::{Digest, Sha256}; use super::{DUMMY_SIGNATURE, MatchInputs, handler}; - use crate::state::EnclaveState; + use crate::{ + face_engine::{ComparisonScores, FaceComparator}, + state::EnclaveState, + }; + + struct ExpectedImages { + credential: Vec, + live: Vec, + challenge: Vec, + } + + struct MockFaceEngine { + expected: Option, + result: Result, + } + + impl MockFaceEngine { + fn matching( + credential: &[u8], + live: &[u8], + challenge: &[u8], + live_similarity: f32, + challenge_similarity: f32, + ) -> Self { + Self { + expected: Some(ExpectedImages { + credential: credential.to_vec(), + live: live.to_vec(), + challenge: challenge.to_vec(), + }), + result: Ok(ComparisonScores { + live_similarity, + challenge_similarity, + }), + } + } + + fn unused() -> Self { + Self { + expected: None, + result: Err(EnclaveError::NotReady), + } + } + } + + impl FaceComparator for MockFaceEngine { + fn compare_reference_to_probes( + &self, + credential_image: &[u8], + live_image: &[u8], + challenge_image: &[u8], + ) -> Result { + let expected = self + .expected + .as_ref() + .expect("mock Face Engine was called unexpectedly"); + assert_eq!(credential_image, expected.credential); + assert_eq!(live_image, expected.live); + assert_eq!(challenge_image, expected.challenge); + self.result + } + } + + fn state_with(face_engine: MockFaceEngine) -> Arc { + Arc::new(EnclaveState::generate(Arc::new(face_engine))) + } fn seal_to(state: &EnclaveState, plaintext: &[u8]) -> Vec { let public_key = PublicKey::from(state.transit_public_key()); @@ -160,10 +228,12 @@ mod tests { #[tokio::test] async fn handler_produces_statement_for_valid_payload() { - let state = Arc::new(EnclaveState::generate()); let live = b"liveness-frame"; let credential = b"credential-thumbnail"; let challenge = b"challenge-frame"; + let state = state_with(MockFaceEngine::matching( + credential, live, challenge, 0.92, 0.87, + )); let hashes_json = hashes_json_for(credential); let sealed_payload = seal_match(&state, live, credential, &hashes_json, challenge, 0.5); @@ -182,14 +252,13 @@ mod tests { statement.challenger_image_hash, Sha256::digest(challenge).as_slice() ); - // Skeleton dummies. assert_eq!(response.signature, DUMMY_SIGNATURE.to_vec()); - assert_eq!(statement.match_coefficient.to_bits(), 1.0f32.to_bits()); + assert_eq!(statement.match_coefficient.to_bits(), 0.92f32.to_bits()); } #[tokio::test] async fn handler_rejects_undecryptable_payload() { - let state = Arc::new(EnclaveState::generate()); + let state = state_with(MockFaceEngine::unused()); let result = handler(state, request(vec![0u8; 64])).await; @@ -198,7 +267,7 @@ mod tests { #[tokio::test] async fn handler_rejects_non_cbor_plaintext() { - let state = Arc::new(EnclaveState::generate()); + let state = state_with(MockFaceEngine::unused()); let sealed_payload = seal_to(&state, b"not cbor framing"); let result = handler(state, request(sealed_payload)).await; @@ -208,7 +277,7 @@ mod tests { #[tokio::test] async fn handler_rejects_pcp_binding_mismatch() { - let state = Arc::new(EnclaveState::generate()); + let state = state_with(MockFaceEngine::unused()); let hashes_json = hashes_json_for(b"the-enrolled-image"); let sealed_payload = seal_match( &state, @@ -226,18 +295,14 @@ mod tests { #[tokio::test] async fn handler_rejects_match_below_threshold() { - let state = Arc::new(EnclaveState::generate()); let credential = b"credential-thumbnail"; + let live = b"liveness"; + let challenge = b"challenge"; + let state = state_with(MockFaceEngine::matching( + credential, live, challenge, 0.95, 0.85, + )); let hashes_json = hashes_json_for(credential); - // A threshold above the dummy coefficient (1.0) forces the gate to reject. - let sealed_payload = seal_match( - &state, - b"liveness", - credential, - &hashes_json, - b"challenge", - 1.5, - ); + let sealed_payload = seal_match(&state, live, credential, &hashes_json, challenge, 0.9); let result = handler(state, request(sealed_payload)).await; diff --git a/secure-enclave/src/pontifex_server/mod.rs b/secure-enclave/src/pontifex_server/mod.rs index 5a37c1c..34b32c9 100644 --- a/secure-enclave/src/pontifex_server/mod.rs +++ b/secure-enclave/src/pontifex_server/mod.rs @@ -35,11 +35,30 @@ fn router(state: Arc) -> Router> { mod tests { use std::sync::Arc; + use enclave_types::EnclaveError; + use super::router; - use crate::state::EnclaveState; + use crate::{ + face_engine::{ComparisonScores, FaceComparator}, + state::EnclaveState, + }; + + struct NoopFaceEngine; + + impl FaceComparator for NoopFaceEngine { + fn compare_reference_to_probes( + &self, + _: &[u8], + _: &[u8], + _: &[u8], + ) -> Result { + Err(EnclaveError::NotReady) + } + } #[test] fn router_registers_enclave_operations() { - let _router = router(Arc::new(EnclaveState::generate())); + let state = EnclaveState::generate(Arc::new(NoopFaceEngine)); + let _router = router(Arc::new(state)); } } diff --git a/secure-enclave/src/state.rs b/secure-enclave/src/state.rs index 3dc4d28..feab6a2 100644 --- a/secure-enclave/src/state.rs +++ b/secure-enclave/src/state.rs @@ -1,21 +1,29 @@ //! Boot-scoped state owned by the secure enclave. +use std::sync::Arc; + use crypto_box::{SecretKey, aead::OsRng}; use enclave_types::EnclaveError; +use crate::face_engine::FaceComparator; + /// Immutable state generated once during enclave boot. pub struct EnclaveState { transit_secret_key: SecretKey, + face_engine: Arc, } impl EnclaveState { - /// Generates fresh boot-scoped enclave state using the operating-system RNG. + /// Generates fresh boot-scoped enclave state with the provided Face Engine. #[must_use] - pub fn generate() -> Self { + pub fn generate(face_engine: Arc) -> Self { let transit_secret_key = SecretKey::generate(&mut OsRng); tracing::info!("generated boot-scoped transit key"); - Self { transit_secret_key } + Self { + transit_secret_key, + face_engine, + } } /// Returns the X25519 public key used to encrypt requests for this enclave boot. @@ -24,6 +32,12 @@ impl EnclaveState { self.transit_secret_key.public_key().to_bytes() } + /// Returns the Face Engine used for enclave match operations. + #[must_use] + pub fn face_engine(&self) -> &dyn FaceComparator { + self.face_engine.as_ref() + } + /// Unseals a libsodium sealed box addressed to this boot's transit public key. /// /// The client encrypts to the enclave public key with an ephemeral sender key @@ -45,19 +59,41 @@ impl EnclaveState { #[cfg(test)] mod tests { + use std::sync::Arc; + + use enclave_types::EnclaveError; + use super::EnclaveState; + use crate::face_engine::{ComparisonScores, FaceComparator}; + + struct NoopFaceEngine; + + impl FaceComparator for NoopFaceEngine { + fn compare_reference_to_probes( + &self, + _: &[u8], + _: &[u8], + _: &[u8], + ) -> Result { + Err(EnclaveError::NotReady) + } + } + + fn state() -> EnclaveState { + EnclaveState::generate(Arc::new(NoopFaceEngine)) + } #[test] fn transit_key_is_stable_for_one_state() { - let state = EnclaveState::generate(); + let state = state(); assert_eq!(state.transit_public_key(), state.transit_public_key()); } #[test] fn separate_states_receive_separate_transit_keys() { - let first = EnclaveState::generate(); - let second = EnclaveState::generate(); + let first = state(); + let second = state(); assert_ne!(first.transit_public_key(), second.transit_public_key()); } diff --git a/shared/enclave-types/src/error.rs b/shared/enclave-types/src/error.rs index 6eb9672..3ffdcdb 100644 --- a/shared/enclave-types/src/error.rs +++ b/shared/enclave-types/src/error.rs @@ -20,4 +20,10 @@ pub enum EnclaveError { ThumbnailHashMismatch, /// A comparison scored below the RP-supplied `match_threshold`. MatchBelowThreshold, + /// An input could not be decoded as a supported image. + InvalidImage, + /// Face Engine could not generate an embedding for an input image. + EmbeddingGenerationFailed, + /// Face Engine could not compare the generated embeddings. + EmbeddingComparisonFailed, }