This project provides a complete solution for guaranteeing the integrity, authenticity, and traceability of Paillier-encrypted data, with a particular focus on 3D models.
It introduces one of the first practical mechanisms for integrity verification inside the encrypted domain, without external metadata and without modifying the underlying plaintext.
This is achieved through a new method we developed: Deterministic Self-Blinding (DSB).
In addition to encrypted-domain integrity, the system offers two-layer traceability:
-
Plaintext QIM (Quantization Index Modulation):
A deterministic "pre-watermark" (e.g., all zeros) is embedded directly into the plaintext vertices. -
Encrypted-Domain SQIM (Secured QIM):
A second, secret watermark is embedded using Paillier’s additively homomorphic properties.
Together, these techniques allow:
- Authenticity before decryption (via DSB integrity verification),
- Traceability after decryption (via QIM/SQIM watermarking).
If you use this work or the DSB method in your research, please cite the following paper:
"Fast Deterministic Self-Blinding for Metadata-free Integrity Verification of Paillier-Encrypted Data: Application to 3D Models" > TechRxiv, 2025. > Link: https://www.techrxiv.org/users/1001324/articles/1361781...
-
Encrypted-Domain Integrity (DSB)
A novel technique enabling signature and verification entirely on encrypted data using Paillier + ECDSA. -
Encrypted-Domain Traceability (SQIM)
A watermarking scheme that remains detectable after encryption and decryption. -
Probabilistic Self-Blinding (PSB)
An LSB-parity watermarking method included for comparison. -
Unified Command-Line Interface
scripts/cli.pyexposes key generation, encryption, watermarking, signing, verification. -
Evaluation Suite
Scripts for robustness (BER) and distortion (hausdorff) experiments.
Integrity_Control_Paillier/
├── data/
│ └── meshes/ # .obj models
├── outputs/
│ ├── figures/ # Generated plots
│ └── models/ # Generated .obj and .pkl files
├── scripts/
│ ├── cli.py # <--- MAIN USER INTERFACE
│ ├── eval_distortion.py
│ ├── eval_robustness_noise.py
│ ├── eval_robustness_qim_delta.py
│ └── visualize_mesh.py
├── src/
│ └── integrity_ctrl/ # The main Python package
│ ├── crypto/ # Paillier (PHE) helpers, ECDSA
│ ├── io/ # Mesh loading/saving (PyMeshLab)
│ └── watermarking/ # QIM, SQIM, DSB, PSB modules
├── tests/
│ ├── test_01_mesh_io.py
│ └── ... # Unit tests
├── .gitignore
├── pyproject.toml # Project configuration
├── requirements.txt
└── run_all.shThis project uses pip and venv for dependency management.
git clone git@github.com:Bellafqira/Integrity_Control_Paillier.git
cd Integrity_Control_PaillierIt is highly recommended to use a virtual environment (venv).
python -m venv venv- Windows (PowerShell/CMD):
.\venv\Scripts\activate- macOS / Linux::
source venv/bin/activateThis project is set up as a Python package. This command installs all dependencies AND makes your src/integrity_ctrl package findable by all your scripts.
From the project root, run:
pip install -e .(Don't forget the . at the end! This means "install the project in the current directory in editable mode.") This installs all dependencies (from pyproject.toml) and makes the src/integrity_ctrl package available globally.
There are two ways to interact with the system:
- running the CLI (main functionality)
- running the unit tests (development)
Before starting, you can verify that all cryptographic components and watermarking modules are working correctly on your machine.
Command:
python -m unittest discover -v testsThis command will automatically discover all test_*.py files in your tests/ directory. It will run each test function (like test_full_qim_cycle, test_dsb_signature_pipeline, etc.) and confirm that everything is working as expected.
The scripts/cli.py script is the main entry point for using the application.
Here is a complete workflow:
Step 1: Generate Keys
First, generate your Paillier (for encryption) and ECDSA (for signature) keys.
# This will create a 'my_keys' folder and save 4 key files inside it
# $env:PYTHONPATH = "."; for CMD or Windows shell
export PYTHONPATH="$PYTHONPATH:."; # Linux
python scripts/cli.py generate-keys --key-dir "my_keys_2048" --paillier-bits 2048--key-dir "my_keys": (Optional) Specifies the folder to save the keys. Default iskeys.--paillier-bits 2048: (Optional) Defines the Paillier key size (the larger, the more secure). Default is1024.
Step 2: Watermark and Sign a Model (Embed)
Next, take an .obj model, apply the full watermarking and integrity pipeline, and save the encrypted result.
The embed pipeline performs this full process:
- Loads the
.objmodel. - Quantizes the vertices.
- Applies a plaintext QIM pre-watermark (
w=0). - Encrypts the pre-watermarked model with the Paillier public key.
- Applies the second (traceability) SQIM watermark in the encrypted domain.
- Applies the final DSB integrity signature over the entire encrypted model.
- Saves the final object (encrypted data, faces, metadata) into a secure
.pklfile.
Command:
python scripts/cli.py embed --in-file "data/meshes/casting.obj" --out-file "outputs/models/casting_signed_2048_dsb.pkl" --key-dir "my_keys_2048" --delta 100 --quant 6 --sig-type dsb--in-file: (Required) The original.objmodel to protect.--out-file: (Required) The output.pklfile that will contain the encrypted data.--key-dir: The folder containing your keys (from Step 1).--delta: The QIM quantization step.--quant: The quantization factor for floats (e.g.,6for 6 decimal places).--sig-type:dsb(recommended) orpsb.
Example (PSB integrity):
python scripts/cli.py embed --in-file "data/meshes/casting.obj" --out-file "outputs/models/casting_signed_2048_psb.pkl" --key-dir "my_keys_2048" --delta 100 --quant 6 --sig-type psbStep 3: Verify and Decrypt (Verify)
Finally, take a protected .pkl file, check its integrity, and if it is authentic, decrypt it and extract the watermark.
The verify pipeline performs this full process:
- Loads the
.pklfile and all necessary keys. - Verifies the DSB integrity signature (in the encrypted domain).
- If the signature is invalid, the script stops.
- If the signature is valid, it decrypts the model with the Paillier private key.
- It extracts the internal QIM watermark (for traceability).
- It saves the final decrypted and watermarked
.objmodel.
Command :
python scripts/cli.py verify --in-file "outputs/models/casting_signed_2048_dsb.pkl" --out-model "outputs/models/casting_verified_dsb.obj" --key-dir "my_keys_2048"--in-file: (Required) The.pklfile you want to verify (from Step 2).--out-model: (Required) The output path for the final decrypted.objmodel.--key-dir: The key directory (must contain your private keys for decryption).
Verify PSB-protected model:
python scripts/cli.py verify --in-file "outputs/models/casting_signed_2048_psb.pkl" --out-model "outputs/models/casting_verified_psb.obj" --key-dir "my_keys_2048"To reproduce the analysis graphs for distortion and robustness, you can use the evaluation scripts:
# Generates the BER vs. Noise graph (robustness)
python scripts/eval_robustness_noise_majority_vote.py
# Generates the Distortion vs. Delta graph
python scripts/eval_distortion.pyThe graphs will be saved in outputs/figures/.
You can automate the full workflow using the following script:
run_all.sh (Linux/macOS)
#!/bin/bash
LOGFILE="run_pipeline_output.log"
echo "=== Pipeline started at $(date) ===" | tee -a "$LOGFILE"
run() {
echo "" | tee -a "$LOGFILE"
echo "=== Running: $1 ===" | tee -a "$LOGFILE"
bash -c "$1" 2>&1 | tee -a "$LOGFILE"
}
run "python scripts/cli.py generate-keys --key-dir 'my_keys_2048' --paillier-bits 2048"
run "python scripts/cli.py embed --in-file 'data/meshes/casting.obj' --out-file 'outputs/models/casting_signed_2048_dsb.pkl' --key-dir 'my_keys_2048' --delta 4 --quant 1000000 --sig-type dsb"
run 'python scripts/cli.py embed --in-file "data/meshes/casting.obj" --out-file "outputs/models/casting_signed_2048_psb.pkl" --key-dir "my_keys_2048" --delta 4 --quant 1000000 --sig-type psb'
run "python scripts/cli.py verify --in-file 'outputs/models/casting_signed_2048_psb.pkl' --out-model 'outputs/models/casting_verified_psb.obj' --key-dir 'my_keys_2048'"
run "python scripts/cli.py verify --in-file 'outputs/models/casting_signed_2048_dsb.pkl' --out-model 'outputs/models/casting_verified_dsb.obj' --key-dir 'my_keys_2048'"
echo "=== Pipeline finished at $(date) ===" | tee -a "$LOGFILE"
Make it executable:
chmod +x run_all.sh
./run_all.shThe full log is saved to:
run_pipeline_output.log