diff --git a/.github/actions/functest/action.yml b/.github/actions/functest/action.yml index 502b7290f..ca31ee8af 100644 --- a/.github/actions/functest/action.yml +++ b/.github/actions/functest/action.yml @@ -68,26 +68,28 @@ runs: ## Setup Architecture: $ARCH - $(uname -a) - - $(nix --version) + - $(nix --version || echo 'nix not present') - $(bash --version | grep -m1 "") + - $(python3 --version) - $(${{ inputs.cross_prefix }}${CC} --version | grep -m1 "") EOF cat >> $GITHUB_STEP_SUMMARY <<-EOF ## Setup Architecture: $ARCH - $(uname -a) - - $(nix --version) + - $(nix --version || echo 'nix not present') - $(bash --version | grep -m1 "") + - $(python3 --version) - $(${{ inputs.cross_prefix }}${CC} --version | grep -m1 "") EOF - name: ${{ env.MODE }} ${{ inputs.opt }} tests (${{ env.FUNC }}, ${{ env.KAT }}, ${{ env.NISTKAT }}) shell: ${{ env.SHELL }} run: | - tests all --cross-prefix="${{ inputs.cross_prefix }}" --cflags="${{ inputs.cflags }}" --opt=${{ inputs.opt }} --${{ env.FUNC }} --${{ env.KAT }} --${{ env.NISTKAT }} --${{ env.ACVP }} -v + ./scripts/tests all --cross-prefix="${{ inputs.cross_prefix }}" --cflags="${{ inputs.cflags }}" --opt=${{ inputs.opt }} --${{ env.FUNC }} --${{ env.KAT }} --${{ env.NISTKAT }} --${{ env.ACVP }} -v - name: Check namespacing ${{ env.MODE }} ${{ inputs.opt }} tests (${{ env.FUNC }}, ${{ env.KAT }}, ${{ env.NISTKAT }}) shell: ${{ env.SHELL }} run: | - check-namespace + ./scripts/ci/check-namespace - name: Post ${{ env.MODE }} Tests shell: ${{ env.SHELL }} if: success() || failure() diff --git a/.github/actions/setup-ubuntu/action.yml b/.github/actions/setup-ubuntu/action.yml index a63025739..eb445ca69 100644 --- a/.github/actions/setup-ubuntu/action.yml +++ b/.github/actions/setup-ubuntu/action.yml @@ -8,6 +8,9 @@ inputs: description: Space-separated list of additional packages to install required: false default: '' + sudo: + required: false + default: 'sudo' runs: using: composite @@ -15,16 +18,16 @@ runs: - name: Update package repository shell: bash run: | - sudo apt-get update + ${{ inputs.sudo }} apt-get update - name: Install base packages shell: bash run: | - sudo apt-get install python3-venv python3-pip make -y + ${{ inputs.sudo }} apt-get install python3-venv python3-pip make -y - name: Install additional packages if: ${{ inputs.packages != ''}} shell: bash run: | - sudo apt-get install ${{ inputs.packages }} -y + ${{ inputs.sudo }} apt-get install ${{ inputs.packages }} -y - name: Setup Python venv shell: bash run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8504864eb..ba8b172d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -385,7 +385,6 @@ jobs: kat: false acvp: false ec2_functests: - needs: [quickcheck, quickcheck-windows, quickcheck-c90, quickcheck-lib, examples, lint, lint-markdown-link] strategy: fail-fast: false matrix: @@ -419,6 +418,7 @@ jobs: contents: 'read' id-token: 'write' uses: ./.github/workflows/ci_ec2_reusable.yml + needs: [quickcheck, quickcheck-windows, quickcheck-c90, quickcheck-lib, examples, lint, lint-markdown-link] if: github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork with: name: ${{ matrix.target.name }} @@ -434,6 +434,44 @@ jobs: lint: false verbose: true secrets: inherit + ec2_compatibilitytests: + strategy: + fail-fast: false + matrix: + container: + - id: ubuntu-22.04:gcc-12x + - id: ubuntu-22.04:gcc-11x + - id: ubuntu-20.04:gcc-8x + - id: ubuntu-20.04:gcc-7x + - id: ubuntu-20.04:clang-9x + - id: ubuntu-20.04:clang-8x + - id: ubuntu-20.04:clang-7x-bm-framework + - id: ubuntu-20.04:clang-7x + - id: ubuntu-20.04:clang-10x + - id: ubuntu-22.04:base + - id: ubuntu-20.04:base + name: Compatibility tests (${{ matrix.container.id }}) + needs: [ec2_functests] + permissions: + contents: 'read' + id-token: 'write' + uses: ./.github/workflows/ci_ec2_reusable.yml + if: github.repository_owner == 'pq-code-package' && !github.event.pull_request.head.repo.fork + with: + container: ${{ matrix.container.id }} + name: ${{ matrix.container.id }} + ec2_instance_type: c7g.medium + ec2_ami: ubuntu-latest (custom AMI) + ec2_ami_id: ami-0f4b26c5372aa0525 # Has docker images preinstalled + compile_mode: native + opt: all + functest: true + kattest: true + nistkattest: true + acvptest: true + lint: false + verbose: true + secrets: inherit cbmc_k2: name: CBMC (ML-KEM-512) needs: [quickcheck, quickcheck-windows, quickcheck-c90, quickcheck-lib, examples, lint, lint-markdown-link] diff --git a/.github/workflows/ci_ec2_reusable.yml b/.github/workflows/ci_ec2_reusable.yml index 75ab68a2b..807ca2466 100644 --- a/.github/workflows/ci_ec2_reusable.yml +++ b/.github/workflows/ci_ec2_reusable.yml @@ -59,6 +59,9 @@ on: cbmc_mlkem_k: type: string default: 2 + container: + type: string + default: '' env: AWS_ROLE: arn:aws:iam::559050233797:role/mlkem-c-aarch64-gh-action AWS_REGION: us-east-1 @@ -112,9 +115,40 @@ jobs: ec2-instance-type: ${{ inputs.ec2_instance_type }} subnet-id: subnet-07b2729e5e065962f security-group-id: sg-0ab2e297196c8c381 + container_tests: + name: Run container tests + needs: start-ec2-runner + if: ${{ inputs.container != '' }} + runs-on: ${{ needs.start-ec2-runner.outputs.label }} + container: + localhost:5000/${{ inputs.container }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: ./.github/actions/setup-ubuntu + with: + sudo: "" + - name: make quickcheck + run: | + OPT=0 make quickcheck >/dev/null + make clean >/dev/null + OPT=1 make quickcheck >/dev/null + - name: Functional Tests + uses: ./.github/actions/multi-functest + with: + nix-shell: "" + gh_token: ${{ secrets.AWS_GITHUB_TOKEN }} + cflags: ${{ inputs.cflags }} + compile_mode: ${{ inputs.compile_mode }} + opt: ${{ inputs.opt }} + func: ${{ inputs.functest }} + kat: ${{ inputs.kattest }} + nistkat: ${{ inputs.nistkattest }} + acvp: ${{ inputs.acvptest }} + tests: - name: Run test + name: Run tests needs: start-ec2-runner + if: ${{ inputs.container == '' }} runs-on: ${{ needs.start-ec2-runner.outputs.label }} steps: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -160,6 +194,7 @@ jobs: needs: - start-ec2-runner - tests + - container_tests runs-on: ubuntu-latest if: ${{ always() }} # required to stop the runner even if the error happened in the previous jobs steps: diff --git a/mk/config.mk b/mk/config.mk index cf54aecae..b1cd0998a 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -13,11 +13,10 @@ CC ?= gcc CPP ?= cpp AR ?= ar # NOTE: gcc-ar is a wrapper around ar that ensures proper integration with GCC plugins, -# such as lto. Using gcc-ar is preferred when creating or linking static libraries -# if the binary is compiled with -flto. -# However, this doesn't apply to darwin as it is using clang instead, and there's no -# gcc-ar wrapper as well. -CC_AR ?= $(if $(findstring Darwin,$(shell uname -s)),ar,gcc-ar) +# such as lto. Using gcc-ar is preferred when creating or linking static libraries +# if the binary is compiled with -flto. However, it is not universally present, so +# only use it if available. +CC_AR ?= $(if $(shell which gcc-ar),gcc-ar,ar) CC := $(CROSS_PREFIX)$(CC) CPP := $(CROSS_PREFIX)$(CPP) diff --git a/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_scalar_v84a_asm_hybrid_opt.S b/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_scalar_v84a_asm_hybrid_opt.S index 79cc6d185..365ec8d9b 100644 --- a/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_scalar_v84a_asm_hybrid_opt.S +++ b/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_scalar_v84a_asm_hybrid_opt.S @@ -145,7 +145,7 @@ /* Mapping of Kecck-f1600 state to scalar registers * at the beginning and end of each round. */ - sAba .req x1 + tAba .req x1 /* Some compilers don't like sAba */ sAbe .req x6 sAbi .req x11 sAbo .req x16 @@ -279,7 +279,7 @@ .macro store_input_scalar idx add input_addr, input_addr, #((2 + \idx)*25*8) - stp sAba, sAbe, [input_addr, #(1*8*0)] + stp tAba, sAbe, [input_addr, #(1*8*0)] stp sAbi, sAbo, [input_addr, #(1*8*2)] stp sAbu, sAga, [input_addr, #(1*8*4)] stp sAge, sAgi, [input_addr, #(1*8*6)] @@ -297,7 +297,7 @@ .macro load_input_scalar idx add input_addr, input_addr, #((2 + \idx)*25*8) - ldp sAba, sAbe, [input_addr, #(1*8*0)] + ldp tAba, sAbe, [input_addr, #(1*8*0)] ldp sAbi, sAbo, [input_addr, #(1*8*2)] ldp sAbu, sAga, [input_addr, #(1*8*4)] ldp sAge, sAgi, [input_addr, #(1*8*6)] @@ -495,7 +495,7 @@ eor x14, x26, x6, ror #46 // .....................................................* eor x6, x27, x29, ror #41 // .....................................................* - // eor5 X, sAma, sAsa, sAba, sAga, sAka + // eor5 X, sAma, sAsa, tAba, sAga, sAka // eor5 X, sAme, sAse, sAbe, sAge, sAke // eor5 X, sAmi, sAsi, sAbi, sAgi, sAki // eor5 X, sAmo, sAso, sAbo, sAgo, sAko @@ -507,7 +507,7 @@ // eor X, X, X, ror #63 // eor X, X, X, ror #63 - // eor X, sAba, X + // eor X, tAba, X // eor X, sAbi, X // eor X, sAki, X // eor X, sAko, X @@ -558,13 +558,13 @@ // chi_step_ror sAsi, X, X, X, 25, 27 // chi_step_ror sAso, X, X, X, 60, 21 // chi_step_ror sAsu, X, X, X, 57, 53 - // chi_step_ror2 sAba, X, X, X, 63, 21 + // chi_step_ror2 tAba, X, X, X, 63, 21 // chi_step_ror sAbe, X, X, X, 42, 41 // chi_step_ror sAbi, X, X, X, 57, 35 // chi_step_ror sAbo, X, X, X, 50, 43 // chi_step_ror sAbu, X, X, X, 44, 30 - // eor sAba, sAba, X + // eor tAba, tAba, X .endm .macro vector_round @@ -753,7 +753,7 @@ eor x23, x3, x26, ror #52 // ........................................................* eor x3, x29, x30, ror #24 // ........................................................* - // eor X, sAba, sAga, ror #61 + // eor X, tAba, sAga, ror #61 // eor X, X, sAma, ror #54 // eor X, X, sAka, ror #39 // eor X, X, sAsa, ror #25 @@ -787,7 +787,7 @@ // eor X, X, X, ror #63 // eor X, X, X, ror #63 - // eor X, X, sAba + // eor X, X, tAba // eor X, X, sAbi, ror #50 // eor X, X, sAki, ror #46 // eor X, X, sAko, ror #63 @@ -840,13 +840,13 @@ // chi_step_ror sAsi, X, X, X, 25, 27 // chi_step_ror sAso, X, X, X, 60, 21 // chi_step_ror sAsu, X, X, X, 57, 53 - // chi_step_ror2 sAba, X, X, X, 63, 21 + // chi_step_ror2 tAba, X, X, X, 63, 21 // chi_step_ror sAbe, X, X, X, 42, 41 // chi_step_ror sAbi, X, X, X, 57, 35 // chi_step_ror sAbo, X, X, X, 50, 43 // chi_step_ror sAbu, X, X, X, 44, 30 - // eor sAba, sAba, X + // eor tAba, tAba, X .endm .macro final_scalar_rotate diff --git a/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm_opt.S b/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm_opt.S index a88ce7672..ddc010490 100644 --- a/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm_opt.S +++ b/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_v8a_scalar_hybrid_asm_opt.S @@ -143,7 +143,7 @@ /* Mapping of Kecck-f1600 state to scalar registers * at the beginning and end of each round. */ - sAba .req x1 + tAba .req x1 /* Some compilers don't like sAba */ sAbe .req x6 sAbi .req x11 sAbo .req x16 @@ -261,7 +261,7 @@ .macro store_input_scalar idx add input_addr, input_addr, #((2 + \idx)*25*8) - stp sAba, sAbe, [input_addr, #(1*8*0)] + stp tAba, sAbe, [input_addr, #(1*8*0)] stp sAbi, sAbo, [input_addr, #(1*8*2)] stp sAbu, sAga, [input_addr, #(1*8*4)] stp sAge, sAgi, [input_addr, #(1*8*6)] @@ -279,7 +279,7 @@ .macro load_input_scalar idx add input_addr, input_addr, #((2 + \idx)*25*8) - ldp sAba, sAbe, [input_addr, #(1*8*0)] + ldp tAba, sAbe, [input_addr, #(1*8*0)] ldp sAbi, sAbo, [input_addr, #(1*8*2)] ldp sAbu, sAga, [input_addr, #(1*8*4)] ldp sAge, sAgi, [input_addr, #(1*8*6)] @@ -477,7 +477,7 @@ eor x14, x26, x6, ror #46 // .....................................................* eor x6, x27, x29, ror #41 // .....................................................* - // eor5 X, sAma, sAsa, sAba, sAga, sAka + // eor5 X, sAma, sAsa, tAba, sAga, sAka // eor5 X, sAme, sAse, sAbe, sAge, sAke // eor5 X, sAmi, sAsi, sAbi, sAgi, sAki // eor5 X, sAmo, sAso, sAbo, sAgo, sAko @@ -489,7 +489,7 @@ // eor X, X, X, ror #63 // eor X, X, X, ror #63 - // eor X, sAba, X + // eor X, tAba, X // eor X, sAbi, X // eor X, sAki, X // eor X, sAko, X @@ -540,13 +540,13 @@ // chi_step_ror sAsi, X, X, X, 25, 27 // chi_step_ror sAso, X, X, X, 60, 21 // chi_step_ror sAsu, X, X, X, 57, 53 - // chi_step_ror2 sAba, X, X, X, 63, 21 + // chi_step_ror2 tAba, X, X, X, 63, 21 // chi_step_ror sAbe, X, X, X, 42, 41 // chi_step_ror sAbi, X, X, X, 57, 35 // chi_step_ror sAbo, X, X, X, 50, 43 // chi_step_ror sAbu, X, X, X, 44, 30 - // eor sAba, sAba, X + // eor tAba, tAba, X .endm .macro vector_round @@ -735,7 +735,7 @@ eor x23, x3, x26, ror #52 // ........................................................* eor x3, x29, x30, ror #24 // ........................................................* - // eor X, sAba, sAga, ror #61 + // eor X, tAba, sAga, ror #61 // eor X, X, sAma, ror #54 // eor X, X, sAka, ror #39 // eor X, X, sAsa, ror #25 @@ -769,7 +769,7 @@ // eor X, X, X, ror #63 // eor X, X, X, ror #63 - // eor X, X, sAba + // eor X, X, tAba // eor X, X, sAbi, ror #50 // eor X, X, sAki, ror #46 // eor X, X, sAko, ror #63 @@ -822,13 +822,13 @@ // chi_step_ror sAsi, X, X, X, 25, 27 // chi_step_ror sAso, X, X, X, 60, 21 // chi_step_ror sAsu, X, X, X, 57, 53 - // chi_step_ror2 sAba, X, X, X, 63, 21 + // chi_step_ror2 tAba, X, X, X, 63, 21 // chi_step_ror sAbe, X, X, X, 42, 41 // chi_step_ror sAbi, X, X, X, 57, 35 // chi_step_ror sAbo, X, X, X, 50, 43 // chi_step_ror sAbu, X, X, X, 44, 30 - // eor sAba, sAba, X + // eor tAba, tAba, X .endm .macro final_scalar_rotate diff --git a/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm_opt.S b/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm_opt.S index 9fc5cb15e..26ee8de97 100644 --- a/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm_opt.S +++ b/mlkem/fips202/native/aarch64/src/keccak_f1600_x4_v8a_v84a_scalar_hybrid_asm_opt.S @@ -145,7 +145,7 @@ /* Mapping of Kecck-f1600 state to scalar registers * at the beginning and end of each round. */ - sAba .req x1 + tAba .req x1 /* Some compilers don't like sAba */ sAbe .req x6 sAbi .req x11 sAbo .req x16 @@ -279,7 +279,7 @@ .macro store_input_scalar idx add input_addr, input_addr, #((2 + \idx)*25*8) - stp sAba, sAbe, [input_addr, #(1*8*0)] + stp tAba, sAbe, [input_addr, #(1*8*0)] stp sAbi, sAbo, [input_addr, #(1*8*2)] stp sAbu, sAga, [input_addr, #(1*8*4)] stp sAge, sAgi, [input_addr, #(1*8*6)] @@ -297,7 +297,7 @@ .macro load_input_scalar idx add input_addr, input_addr, #((2 + \idx)*25*8) - ldp sAba, sAbe, [input_addr, #(1*8*0)] + ldp tAba, sAbe, [input_addr, #(1*8*0)] ldp sAbi, sAbo, [input_addr, #(1*8*2)] ldp sAbu, sAga, [input_addr, #(1*8*4)] ldp sAge, sAgi, [input_addr, #(1*8*6)] @@ -495,7 +495,7 @@ eor x14, x26, x6, ror #46 // .....................................................* eor x6, x27, x29, ror #41 // .....................................................* - // eor5 X, sAma, sAsa, sAba, sAga, sAka + // eor5 X, sAma, sAsa, tAba, sAga, sAka // eor5 X, sAme, sAse, sAbe, sAge, sAke // eor5 X, sAmi, sAsi, sAbi, sAgi, sAki // eor5 X, sAmo, sAso, sAbo, sAgo, sAko @@ -507,7 +507,7 @@ // eor X, X, X, ror #63 // eor X, X, X, ror #63 - // eor X, sAba, X + // eor X, tAba, X // eor X, sAbi, X // eor X, sAki, X // eor X, sAko, X @@ -558,13 +558,13 @@ // chi_step_ror sAsi, X, X, X, 25, 27 // chi_step_ror sAso, X, X, X, 60, 21 // chi_step_ror sAsu, X, X, X, 57, 53 - // chi_step_ror2 sAba, X, X, X, 63, 21 + // chi_step_ror2 tAba, X, X, X, 63, 21 // chi_step_ror sAbe, X, X, X, 42, 41 // chi_step_ror sAbi, X, X, X, 57, 35 // chi_step_ror sAbo, X, X, X, 50, 43 // chi_step_ror sAbu, X, X, X, 44, 30 - // eor sAba, sAba, X + // eor tAba, tAba, X .endm .macro vector_round @@ -753,7 +753,7 @@ eor x23, x3, x26, ror #52 // ........................................................* eor x3, x29, x30, ror #24 // ........................................................* - // eor X, sAba, sAga, ror #61 + // eor X, tAba, sAga, ror #61 // eor X, X, sAma, ror #54 // eor X, X, sAka, ror #39 // eor X, X, sAsa, ror #25 @@ -787,7 +787,7 @@ // eor X, X, X, ror #63 // eor X, X, X, ror #63 - // eor X, X, sAba + // eor X, X, tAba // eor X, X, sAbi, ror #50 // eor X, X, sAki, ror #46 // eor X, X, sAko, ror #63 @@ -840,13 +840,13 @@ // chi_step_ror sAsi, X, X, X, 25, 27 // chi_step_ror sAso, X, X, X, 60, 21 // chi_step_ror sAsu, X, X, X, 57, 53 - // chi_step_ror2 sAba, X, X, X, 63, 21 + // chi_step_ror2 tAba, X, X, X, 63, 21 // chi_step_ror sAbe, X, X, X, 42, 41 // chi_step_ror sAbi, X, X, X, 57, 35 // chi_step_ror sAbo, X, X, X, 50, 43 // chi_step_ror sAbu, X, X, X, 44, 30 - // eor sAba, sAba, X + // eor tAba, tAba, X .endm .macro final_scalar_rotate diff --git a/scripts/lib/mlkem_test.py b/scripts/lib/mlkem_test.py index 73d24122a..aa0ad35fe 100644 --- a/scripts/lib/mlkem_test.py +++ b/scripts/lib/mlkem_test.py @@ -8,7 +8,6 @@ import logging import subprocess from functools import reduce, partial -from typing import Optional, Callable, TypedDict from util import ( TEST_TYPES, SCHEME, @@ -25,16 +24,14 @@ class CompileOptions(object): - def __init__( - self, cross_prefix: str, cflags: str, arch_flags: str, auto: bool, verbose: bool - ): + def __init__(self, cross_prefix, cflags, arch_flags, auto, verbose): self.cross_prefix = cross_prefix self.cflags = cflags self.arch_flags = arch_flags self.auto = auto self.verbose = verbose - def compile_mode(self) -> str: + def compile_mode(self): return "Cross" if self.cross_prefix else "Native" @@ -69,10 +66,14 @@ def __init__(self, test_type: TEST_TYPES, copts: CompileOptions, opt: bool): def compile_schemes( self, - extra_make_envs={}, - extra_make_args=[], + extra_make_envs=None, + extra_make_args=None, ): """compile or cross compile with some extra environment variables and makefile arguments""" + if extra_make_envs is None: + extra_make_envs = {} + if extra_make_args is None: + extra_make_args = [] if gh_env is not None: print( @@ -98,17 +99,20 @@ def dict2str(dict): f"{self.test_type}", ] + extra_make_args - make_envs = ({"CFLAGS": self.cflags} if self.cflags is not None else {}) | ( - {"ARCH_FLAGS": f"{self.arch_flags}"} if self.arch_flags is not None else {} - ) - extra_make_envs.update(make_envs) + env = os.environ.copy() + if self.cflags is not None: + env["CFLAGS"] = self.cflags + if self.arch_flags is not None: + env["ARCH_FLAGS"] = self.arch_flags + + env.update(extra_make_envs) log.info(dict2str(extra_make_envs) + " ".join(args)) p = subprocess.run( args, stdout=subprocess.DEVNULL if not self.verbose else None, - env=os.environ.copy() | extra_make_envs, + env=env, ) if p.returncode != 0: @@ -122,13 +126,30 @@ def dict2str(dict): def run_scheme( self, - scheme: SCHEME, - actual_proc: Callable[[bytes], str] = None, - expect_proc: Callable[[SCHEME, str], tuple[bool, str]] = None, - cmd_prefix: [str] = [], - extra_args: [str] = [], + scheme, + actual_proc=None, + expect_proc=None, + cmd_prefix=None, + extra_args=None, ): - """Run the binary in all different ways""" + """Run the binary in all different ways + + Arguments: + + - scheme: Scheme to test + - actual_proc: Callable to process the raw byte-output + of the test run with. + - expected_proc: Checker function. Callable receiving test type and + processed output, and returns success/failure and potentially + error string + - cmd_prefix: Command prefix; array of strings, or None + - extra_args: Extra arguments; array of strings, or None + """ + if cmd_prefix is None: + cmd_prefix = [] + if extra_args is None: + extra_args = [] + log = logger(self.test_type, scheme, self.cross_prefix, self.opt, self.i) self.i += 1 @@ -180,9 +201,9 @@ def __init__(self, test_type: TEST_TYPES, copts: CompileOptions): def compile( self, - opt: bool, - extra_make_envs={}, - extra_make_args=[], + opt, + extra_make_envs=None, + extra_make_args=None, ): self.ts["opt" if opt else "no_opt"].compile_schemes( extra_make_envs, @@ -191,13 +212,31 @@ def compile( def run_scheme( self, - opt: bool, - scheme: SCHEME, - actual_proc: Callable[[bytes], str] = None, - expect_proc: Callable[[SCHEME, str], tuple[bool, str]] = None, - cmd_prefix: [str] = [], - extra_args: [str] = [], - ) -> TypedDict: + opt, + scheme, + actual_proc=None, + expect_proc=None, + cmd_prefix=None, + extra_args=None, + ): + """Arguments: + + - opt: Whether build should include native backends or not + - scheme: Scheme to run + - actual_proc: Callable to process the raw byte-output + of the test run with. + - expected_proc: Checker function. Callable receiving test type and + processed output, and returns success/failure and potentially + error string + - cmd_prefix: Command prefix; array of strings, or None + - extra_args: Extra arguments; array of strings, or None + """ + if cmd_prefix is None: + cmd_prefix = [] + if extra_args is None: + extra_args = [] + + # Returns TypedDict k = "opt" if opt else "no_opt" results = {} @@ -209,13 +248,25 @@ def run_scheme( return results def run_schemes( - self, - opt: bool, - actual_proc: Callable[[bytes], str] = None, - expect_proc: Callable[[SCHEME, str], tuple[bool, str]] = None, - cmd_prefix: [str] = [], - extra_args: [str] = [], - ) -> TypedDict: + self, opt, actual_proc=None, expect_proc=None, cmd_prefix=None, extra_args=None + ): + """Arguments: + + - opt: Whether native backends should be enabled + - actual_proc: Functionto process the raw byte-output + of the test run with. + - expected_proc: Checker function. Receives test type and + processed output, and returns success/failure + and potentially error string + - cmd_prefix: Command prefix; array of strings + - extra_args: Extra arguments; array of strings + """ + if cmd_prefix is None: + cmd_prefix = [] + if extra_args is None: + extra_args = [] + + # Returns results = {} k = "opt" if opt else "no_opt" @@ -312,7 +363,9 @@ def __init__(self, opts: Options): def _run_func(self, opt: bool): """Underlying function for functional test""" - def expect(scheme: SCHEME, actual: str) -> tuple[bool, str]: + def expect(scheme: SCHEME, actual: str): + """Checks whether the hashed output of the scheme matches the META.yml""" + sk_bytes = parse_meta(scheme, "length-secret-key") pk_bytes = parse_meta(scheme, "length-public-key") ct_bytes = parse_meta(scheme, "length-ciphertext") @@ -355,7 +408,8 @@ def _func(opt: bool): exit(1) def _run_nistkat(self, opt: bool): - def expect_proc(scheme: SCHEME, actual: str) -> tuple[bool, str]: + def expect_proc(scheme: SCHEME, actual: str): + """Checks whether the hashed output of the scheme matches the META.yml""" expect = parse_meta(scheme, "nistkat-sha256") fail = expect != actual @@ -390,7 +444,8 @@ def _nistkat(opt: bool): exit(1) def _run_kat(self, opt: bool): - def expect_proc(scheme: SCHEME, actual: str) -> tuple[bool, str]: + def expect_proc(scheme: SCHEME, actual: str): + """Checks whether the hashed output of the scheme matches the META.yml""" expect = parse_meta(scheme, "kat-sha256") fail = expect != actual @@ -435,12 +490,11 @@ def _run_acvp(self, opt: bool, acvp_dir: str = "test/acvp_data"): with open(acvp_encapDecap_json, "r") as f: acvp_encapDecap_data = json.load(f) - def actual_proc(bs: bytes) -> str: + def actual_proc(bs: bytes): return bs.decode("utf-8") - def _expect_proc( - tc: TypedDict, scheme: SCHEME, actual: str - ) -> tuple[bool, str]: + def _expect_proc(tc, scheme, actual): + """Checks whether the ACVP result is as expected""" fail = False err = "" for l in actual.splitlines(): @@ -455,7 +509,7 @@ def _expect_proc( opt_label = "opt" if opt else "no_opt" - def init_results() -> TypedDict: + def init_results(): results = {} results[opt_label] = {} for s in SCHEME: @@ -583,7 +637,7 @@ def _run_bench( self, t: Test_Implementations, opt: bool, - ) -> TypedDict: + ): return t.run_schemes(opt, cmd_prefix=self.cmd_prefix) def bench( diff --git a/scripts/lib/util.py b/scripts/lib/util.py index 32d139478..0333712cc 100644 --- a/scripts/lib/util.py +++ b/scripts/lib/util.py @@ -6,7 +6,6 @@ import hashlib import logging from enum import IntEnum -from typing import TypedDict from functools import reduce import yaml @@ -14,11 +13,11 @@ ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) -def path(p: str): +def path(p): return os.path.relpath(os.path.join(ROOT, p), CWD) -def sha256sum(result: bytes) -> str: +def sha256sum(result): m = hashlib.sha256() m.update(result) return m.hexdigest() @@ -30,13 +29,12 @@ class SCHEME(IntEnum): MLKEM1024 = 3 def __str__(self): - match self: - case SCHEME.MLKEM512: - return "ML-KEM-512" - case SCHEME.MLKEM768: - return "ML-KEM-768" - case SCHEME.MLKEM1024: - return "ML-KEM-1024" + if self == SCHEME.MLKEM512: + return "ML-KEM-512" + if self == SCHEME.MLKEM768: + return "ML-KEM-768" + if self == SCHEME.MLKEM1024: + return "ML-KEM-1024" def __iter__(self): return self @@ -45,10 +43,15 @@ def __next__(self): return self + 1 def suffix(self): - return self.name.removeprefix("MLKEM") + if self == SCHEME.MLKEM512: + return "512" + if self == SCHEME.MLKEM768: + return "768" + if self == SCHEME.MLKEM1024: + return "1024" @classmethod - def from_str(cls, s: str): + def from_str(cls, s): # Iterate through all enum members to find a match for the given string for m in cls: if str(m) == s: @@ -70,48 +73,47 @@ def __str__(self): return self.name.lower() def desc(self): - match self: - case TEST_TYPES.MLKEM: - return "Functional Test" - case TEST_TYPES.BENCH: - return "Benchmark" - case TEST_TYPES.BENCH_COMPONENTS: - return "Benchmark Components" - case TEST_TYPES.NISTKAT: - return "Nistkat Test" - case TEST_TYPES.KAT: - return "Kat Test" - case TEST_TYPES.ACVP: - return "ACVP Test" + if self == TEST_TYPES.MLKEM: + return "Functional Test" + if self == TEST_TYPES.BENCH: + return "Benchmark" + if self == TEST_TYPES.BENCH_COMPONENTS: + return "Benchmark Components" + if self == TEST_TYPES.NISTKAT: + return "Nistkat Test" + if self == TEST_TYPES.KAT: + return "Kat Test" + if self == TEST_TYPES.ACVP: + return "ACVP Test" def bin(self): - match self: - case TEST_TYPES.MLKEM: - return "test_mlkem" - case TEST_TYPES.BENCH: - return "bench_mlkem" - case TEST_TYPES.BENCH_COMPONENTS: - return "bench_components_mlkem" - case TEST_TYPES.NISTKAT: - return "gen_NISTKAT" - case TEST_TYPES.KAT: - return "gen_KAT" - case TEST_TYPES.ACVP: - return "acvp_mlkem" - - def bin_path(self, scheme: SCHEME): + if self == TEST_TYPES.MLKEM: + return "test_mlkem" + if self == TEST_TYPES.BENCH: + return "bench_mlkem" + if self == TEST_TYPES.BENCH_COMPONENTS: + return "bench_components_mlkem" + if self == TEST_TYPES.NISTKAT: + return "gen_NISTKAT" + if self == TEST_TYPES.KAT: + return "gen_KAT" + if self == TEST_TYPES.ACVP: + return "acvp_mlkem" + + def bin_path(self, scheme): return path( f"test/build/{scheme.name.lower()}/bin/{self.bin()}{scheme.suffix()}" ) -def parse_meta(scheme: SCHEME, field: str) -> str: +def parse_meta(scheme, field): with open("META.yml", "r") as f: meta = yaml.safe_load(f) return meta["implementations"][int(scheme) - 1][field] -def github_summary(title: str, test_label: str, results: TypedDict): +def github_summary(title, test_label, results): + """Generate summary for GitHub CI""" summary_file = os.environ.get("GITHUB_STEP_SUMMARY") res = list(results.values()) @@ -197,9 +199,8 @@ def config_logger(verbose): logger.setLevel(logging.INFO) -def logger( - test_type: TEST_TYPES, scheme: SCHEME, cross_prefix: str, opt: bool, i: int = None -): +def logger(test_type, scheme, cross_prefix, opt, i=None): + """Emit line indicating the processing of the given test""" compile_mode = "cross" if cross_prefix else "native" implementation = "opt" if opt else "no_opt"