diff --git a/README.md b/README.md index c7efed1..3e4017f 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,10 @@ The installer copies both modules into the active PHP extension directory, creates `contractless-crypto.ini`, enables it through `phpenmod`, and verifies that PHP can see both modules. +Do not add either module directly to `php.ini`. The installer manages both +module declarations through `contractless-crypto.ini`. Loading them through +both locations causes duplicate-module warnings. + Confirm the installation manually: ```bash @@ -147,6 +151,18 @@ php-config --version swig -version ``` +Confirm that the runtime and development tools use the same PHP module API: + +```bash +php -i | grep '^PHP API' +php-config --phpapi +phpize --version +``` + +The API numbers reported by all three commands must match. A module compiled +with PHP 8.4 development tools cannot be loaded by PHP 8.3, and the reverse is +also true. `build-linux.sh` stops with an error when it detects this mismatch. + ### Build liboqs Choose a working directory: @@ -238,13 +254,13 @@ sudo install -m 0755 \ "$(php-config --extension-dir)/skein.so" ``` -Find the PHP configuration files: +Find the PHP configuration directories: ```bash php --ini ``` -Add these lines to the appropriate `php.ini` or extension configuration file: +Create one dedicated extension configuration file containing: ```ini extension=skein.so @@ -253,7 +269,9 @@ extension=oqsphp.so CLI PHP, Apache, and PHP-FPM can use different configuration directories. The modules must be enabled for every PHP runtime that uses -`php-contractless-rpc`. +`php-contractless-rpc`. Enable or link this dedicated file in each required +runtime configuration directory. Do not also add these declarations directly +to `php.ini`. Restart Apache or PHP-FPM after changing its configuration. Service names vary by distribution and installed PHP version. @@ -293,4 +311,3 @@ $digest = skein_hash($data, 256); Direct Contractless Falcon handling requires the public-key SHAKE256 prefix and raw-message marker. `php-contractless-rpc` applies that format automatically, so application developers should use its `NativeCrypto` class. - diff --git a/build-linux.sh b/build-linux.sh index cdea4a0..5c451e3 100755 --- a/build-linux.sh +++ b/build-linux.sh @@ -6,6 +6,25 @@ root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" third_party="$root/native/third-party" mkdir -p "$third_party" +runtime_api="$(php -i | sed -n 's/^PHP API => //p' | head -n 1)" +config_api="$(php-config --phpapi)" +phpize_api="$(phpize --version | sed -n 's/^PHP Api Version:[[:space:]]*//p' | head -n 1)" + +if [[ -z "$runtime_api" || -z "$config_api" || -z "$phpize_api" \ + || "$runtime_api" != "$config_api" || "$runtime_api" != "$phpize_api" ]]; then + cat >&2 </dev/null 2>&1 || true phpize ./configure make @@ -51,7 +71,6 @@ Native extensions built: $third_party/liboqs-php/build/oqsphp.so $third_party/php-skein/modules/skein.so -Add both absolute paths to php.ini: - extension=$third_party/liboqs-php/build/oqsphp.so - extension=$third_party/php-skein/modules/skein.so +Do not add these paths directly to php.ini. +Run sudo ./install-linux.sh to install and enable both modules. EOF diff --git a/install-linux.sh b/install-linux.sh index f27347a..a2a22c9 100755 --- a/install-linux.sh +++ b/install-linux.sh @@ -6,13 +6,22 @@ root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" oqs_module="$root/native/third-party/liboqs-php/build/oqsphp.so" skein_module="$root/native/third-party/php-skein/modules/skein.so" +runtime_api="$(php -i | sed -n 's/^PHP API => //p' | head -n 1)" +config_api="$(php-config --phpapi)" +if [[ -z "$runtime_api" || "$runtime_api" != "$config_api" ]]; then + echo "Active PHP and php-config use different module APIs." >&2 + echo "php API: ${runtime_api:-unknown}" >&2 + echo "php-config API: ${config_api:-unknown}" >&2 + exit 1 +fi + if [[ ! -f "$oqs_module" || ! -f "$skein_module" ]]; then echo "The modules have not been built. Run ./build-linux.sh first." >&2 exit 1 fi extension_dir="$(php-config --extension-dir)" -php_version="$(php -r 'echo PHP_MAJOR_VERSION . \".\" . PHP_MINOR_VERSION;')" +php_version="$(php -r 'echo PHP_MAJOR_VERSION, ".", PHP_MINOR_VERSION;')" ini_dir="/etc/php/$php_version/mods-available" install -m 0755 "$oqs_module" "$extension_dir/oqsphp.so" @@ -25,5 +34,33 @@ if command -v phpenmod >/dev/null 2>&1; then phpenmod contractless-crypto fi -php -m | grep -E '^(skein|oqsphp)$' +module_output="$(php -m 2>&1)" +if grep -q 'already loaded' <<<"$module_output"; then + cat >&2 <&2 + exit 1 +fi + +php -r ' + if (!function_exists("skein_hash") + || !function_exists("contractless_shake256") + || !class_exists("OQS_SIGNATURE") + ) { + fwrite(STDERR, "Required Contractless crypto functions are unavailable.\n"); + exit(1); + } +' + echo "Contractless PHP crypto modules installed and enabled for PHP $php_version." diff --git a/tests/native.php b/tests/native.php index 687708a..7dded68 100644 --- a/tests/native.php +++ b/tests/native.php @@ -3,17 +3,28 @@ declare(strict_types=1); $fixtures = dirname(__DIR__) . '/interop/fixtures'; +$fixtureFiles = [ + 'message.bin', + 'public-key.bin', + 'private-key.bin', + 'rust-signature.bin', + 'rust-skein256.bin', +]; + +foreach ($fixtureFiles as $fixtureFile) { + if (!is_file("$fixtures/$fixtureFile")) { + throw new RuntimeException( + 'Interop fixtures are missing. Run cargo run --release inside interop first.', + ); + } +} + $message = file_get_contents("$fixtures/message.bin"); $publicKey = file_get_contents("$fixtures/public-key.bin"); $privateKey = file_get_contents("$fixtures/private-key.bin"); $rustSignature = file_get_contents("$fixtures/rust-signature.bin"); $rustSkein = file_get_contents("$fixtures/rust-skein256.bin"); -if (in_array(false, [$message, $publicKey, $privateKey, $rustSignature, $rustSkein], true)) { - throw new RuntimeException( - 'Interop fixtures are missing. Run cargo run --release inside interop first.', - ); -} if (!function_exists('skein_hash') || !function_exists('contractless_shake256')) { throw new RuntimeException('The Contractless PHP crypto modules are not loaded.'); }