Contractless-PHP-Modules/README.md

397 lines
8.9 KiB
Markdown
Raw Normal View History

# Contractless PHP Crypto Modules
These native PHP modules provide the cryptography required by
`php-contractless-rpc`:
- Skein-256 hashing through PHP-Skein-Hash
- Contractless-compatible Falcon-512 signing and verification through liboqs
Contractless uses fixed 666-byte Falcon signatures and a specific FN-DSA raw
message format. The included liboqs-php patch adds the SHAKE256 operation needed
to reproduce that format exactly.
## Supported Environment
2026-07-25 19:11:54 +00:00
The automated installer currently supports 64-bit Debian and Ubuntu systems.
This includes Ubuntu running through WSL. The modules can also be compiled
manually on other Linux distributions.
Native modules are tied to the operating system, CPU architecture, and PHP
extension API. They should normally be compiled on the machine where they will
run.
2026-07-25 19:11:54 +00:00
## Debian And Ubuntu Requirements
```bash
sudo apt update
sudo apt install -y \
php-cli php-dev \
swig cmake ninja-build \
build-essential git pkg-config libssl-dev
```
2026-07-25 19:11:54 +00:00
## Automated Debian And Ubuntu Build
```bash
chmod +x build-linux.sh install-linux.sh
./build-linux.sh
```
This downloads and compiles:
- A minimal liboqs build containing `Falcon-padded-512`
- The patched liboqs-php extension
- The PHP-Skein-Hash extension
Building does not install or enable the modules.
2026-07-25 19:11:54 +00:00
## Automated Debian And Ubuntu Installation
After a successful build:
```bash
sudo ./install-linux.sh
```
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.
2026-07-25 19:53:41 +00:00
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
php -m | grep -E '^(skein|oqsphp)$'
```
Expected output:
```text
oqsphp
skein
```
Apache or PHP-FPM may need to be restarted:
```bash
sudo systemctl restart apache2
```
or:
```bash
sudo systemctl restart php8.3-fpm
```
Use the PHP version installed on the server in the service name.
2026-07-25 19:11:54 +00:00
## Manual Build On Other Linux Distributions
Other distributions can use the same modules but may use different package
names and PHP configuration locations.
The following tools are required:
- PHP CLI and the matching PHP development package
- `phpize` and `php-config`
- SWIG
- CMake
- Ninja
- Git
- A C and C++ compiler
- Make
- OpenSSL development headers
- `pkg-config`
The PHP development package must match the PHP installation that will load the
modules. For example, an extension built for PHP 8.3 should not be loaded into
PHP 8.4.
### Fedora, RHEL, Rocky Linux, And AlmaLinux
Package names vary between system repositories and third-party PHP
repositories, but a typical installation is:
```bash
sudo dnf install \
php-cli php-devel \
swig cmake ninja-build \
gcc gcc-c++ make git pkgconf-pkg-config openssl-devel
```
### Arch Linux
```bash
sudo pacman -S --needed \
php swig cmake ninja \
base-devel git pkgconf openssl
```
### Alpine Linux
The exact PHP development package includes the installed PHP version on some
Alpine releases:
```bash
sudo apk add \
php php-dev \
swig cmake ninja \
build-base git pkgconf openssl-dev
```
Confirm the required PHP build commands exist:
```bash
php --version
phpize --version
php-config --version
swig -version
```
2026-07-25 19:53:41 +00:00
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.
2026-07-25 19:11:54 +00:00
### Build liboqs
Choose a working directory:
```bash
mkdir -p contractless-php-build
cd contractless-php-build
```
Download and compile a minimal liboqs containing the fixed-size Falcon
algorithm used by Contractless:
```bash
git clone --depth 1 https://github.com/open-quantum-safe/liboqs.git
cmake -S liboqs -B liboqs/build -GNinja \
-DBUILD_SHARED_LIBS=OFF \
-DOQS_BUILD_ONLY_LIB=ON \
-DOQS_MINIMAL_BUILD="SIG_falcon_padded_512"
ninja -C liboqs/build
```
Do not substitute `Falcon-512`. Contractless requires
`Falcon-padded-512`, which produces fixed 666-byte signatures.
### Build The Contractless liboqs-php Module
Clone the PHP wrapper:
```bash
git clone --depth 1 https://github.com/Muzosh/liboqs-php.git
```
Apply `oqsphp-contractless.patch` from this repository:
```bash
cd liboqs-php
git apply /full/path/to/Contractless-PHP-Modules/oqsphp-contractless.patch
```
Build the PHP extension against the liboqs copy compiled above:
```bash
LIBOQS_ROOT="$(cd ../liboqs && pwd)" bash build.sh
cd ..
```
The resulting module is:
```text
liboqs-php/build/oqsphp.so
```
### Build The Skein Module
```bash
git clone --depth 1 https://github.com/jedisct1/PHP-Skein-Hash.git php-skein
cd php-skein
phpize
./configure
make
cd ..
```
The resulting module is:
```text
php-skein/modules/skein.so
```
### Install The Modules Manually
Find the extension directory used by the active PHP installation:
```bash
php-config --extension-dir
```
Copy both modules into that directory:
```bash
sudo install -m 0755 \
liboqs-php/build/oqsphp.so \
"$(php-config --extension-dir)/oqsphp.so"
sudo install -m 0755 \
php-skein/modules/skein.so \
"$(php-config --extension-dir)/skein.so"
```
2026-07-25 19:53:41 +00:00
Find the PHP configuration directories:
2026-07-25 19:11:54 +00:00
```bash
php --ini
```
2026-07-25 19:53:41 +00:00
Create one dedicated extension configuration file containing:
2026-07-25 19:11:54 +00:00
```ini
extension=skein.so
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
2026-07-25 19:53:41 +00:00
`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`.
2026-07-25 19:11:54 +00:00
Restart Apache or PHP-FPM after changing its configuration. Service names vary
by distribution and installed PHP version.
Verify the manual installation:
```bash
php -m | grep -E '^(skein|oqsphp)$'
```
## Compatibility Test
The compatibility test proves that PHP and Contractless Rust produce matching
Skein hashes and mutually valid Falcon signatures:
```bash
cd interop
cargo run --release
cd ..
php tests/native.php
```
The generated private key is a disposable test fixture. Never use it as an
application wallet.
## Using The Modules
Applications normally use these modules through `php-contractless-rpc` rather
than calling them directly.
Direct Skein hashing:
```php
$digest = skein_hash($data, 256);
```
2026-07-25 20:05:20 +00:00
## Direct Falcon Signing And Verification
Contractless uses `Falcon-padded-512`. Do not substitute the variable-length
`Falcon-512` algorithm.
Falcon keys and signatures are binary data. Load and store them without text,
hexadecimal, Base64, or character-encoding conversions unless the application
explicitly performs and reverses that conversion.
Contractless Falcon signatures use a SHAKE256 prefix derived from the public
key, followed by the raw-message marker and the original message:
```text
SHAKE256(public_key, 64 bytes) || 0x00 || 0x00 || original_message
```
### Sign A Message
```php
<?php
declare(strict_types=1);
$message = 'Message to sign';
$publicKey = file_get_contents('public-key.bin');
$privateKey = file_get_contents('private-key.bin');
if ($publicKey === false || $privateKey === false) {
throw new RuntimeException('Unable to load the Falcon keys.');
}
$falcon = new OQS_SIGNATURE('Falcon-padded-512');
$adaptedMessage =
contractless_shake256($publicKey, 64)
. "\0\0"
. $message;
$signature = '';
if ($falcon->sign($signature, $adaptedMessage, $privateKey) !== 0) {
throw new RuntimeException('Falcon signing failed.');
}
if (strlen($signature) !== 666) {
throw new RuntimeException('Invalid Contractless signature length.');
}
file_put_contents('signature.bin', $signature);
```
### Verify A Signature
```php
<?php
declare(strict_types=1);
$message = 'Message to sign';
$publicKey = file_get_contents('public-key.bin');
$signature = file_get_contents('signature.bin');
if ($publicKey === false || $signature === false) {
throw new RuntimeException('Unable to load the public key or signature.');
}
if (strlen($signature) !== 666) {
throw new RuntimeException('Invalid Contractless signature length.');
}
$falcon = new OQS_SIGNATURE('Falcon-padded-512');
$adaptedMessage =
contractless_shake256($publicKey, 64)
. "\0\0"
. $message;
if ($falcon->verify($adaptedMessage, $signature, $publicKey) !== 0) {
throw new RuntimeException('Falcon signature verification failed.');
}
echo "Signature verified.\n";
```
These examples expose the low-level module behavior for testing and debugging.
Applications should normally use the `NativeCrypto` class provided by
`php-contractless-rpc`, which applies the Contractless message framing
automatically.