pixmask 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pixmask-0.1.0/.clang-format +0 -0
- pixmask-0.1.0/.github/workflows/ci.yml +80 -0
- pixmask-0.1.0/.github/workflows/wheels.yml +67 -0
- pixmask-0.1.0/.gitignore +36 -0
- pixmask-0.1.0/CMakeLists.txt +162 -0
- pixmask-0.1.0/LICENSE +21 -0
- pixmask-0.1.0/PKG-INFO +265 -0
- pixmask-0.1.0/README.md +220 -0
- pixmask-0.1.0/architecture/CPP_ARENA_PIPELINE_REFERENCE.md +765 -0
- pixmask-0.1.0/architecture/CPP_JPEG_REFERENCE.md +603 -0
- pixmask-0.1.0/architecture/CPP_MEDIAN_REFERENCE.md +699 -0
- pixmask-0.1.0/architecture/CPP_REFERENCE.md +1067 -0
- pixmask-0.1.0/architecture/CPP_VALIDATION_REFERENCE.md +735 -0
- pixmask-0.1.0/architecture/DEBATE.md +1978 -0
- pixmask-0.1.0/architecture/DECISIONS.md +245 -0
- pixmask-0.1.0/pyproject.toml +76 -0
- pixmask-0.1.0/python/pixmask/__init__.py +279 -0
- pixmask-0.1.0/python/pixmask/__init__.pyi +85 -0
- pixmask-0.1.0/python/pixmask/_version.py +1 -0
- pixmask-0.1.0/python/pixmask/py.typed +0 -0
- pixmask-0.1.0/research/01_visual_prompt_injection.md +527 -0
- pixmask-0.1.0/research/02_adversarial_perturbations.md +400 -0
- pixmask-0.1.0/research/03_feature_squeezing_defenses.md +707 -0
- pixmask-0.1.0/research/04_frequency_domain_defenses.md +472 -0
- pixmask-0.1.0/research/05_steganography_detection.md +386 -0
- pixmask-0.1.0/research/06_malformed_image_security.md +509 -0
- pixmask-0.1.0/research/07_scaling_attacks.md +461 -0
- pixmask-0.1.0/research/08_multimodal_jailbreaks.md +342 -0
- pixmask-0.1.0/research/09_cpp_simd_optimization.md +768 -0
- pixmask-0.1.0/research/10_nanobind_build_system.md +739 -0
- pixmask-0.1.0/research/11_evaluation_methodology.md +418 -0
- pixmask-0.1.0/research/12_certified_defenses.md +501 -0
- pixmask-0.1.0/research/13_quality_preservation.md +407 -0
- pixmask-0.1.0/research/14_spatial_smoothing_algorithms.md +728 -0
- pixmask-0.1.0/research/15_existing_defense_libraries.md +351 -0
- pixmask-0.1.0/research/FINDINGS.md +144 -0
- pixmask-0.1.0/src/cpp/bindings/module.cpp +159 -0
- pixmask-0.1.0/src/cpp/include/pixmask/arena.h +84 -0
- pixmask-0.1.0/src/cpp/include/pixmask/bitdepth.h +14 -0
- pixmask-0.1.0/src/cpp/include/pixmask/decode.h +24 -0
- pixmask-0.1.0/src/cpp/include/pixmask/jpeg_roundtrip.h +26 -0
- pixmask-0.1.0/src/cpp/include/pixmask/median.h +17 -0
- pixmask-0.1.0/src/cpp/include/pixmask/pipeline.h +41 -0
- pixmask-0.1.0/src/cpp/include/pixmask/types.h +112 -0
- pixmask-0.1.0/src/cpp/include/pixmask/validate.h +89 -0
- pixmask-0.1.0/src/cpp/src/arena.cpp +140 -0
- pixmask-0.1.0/src/cpp/src/bitdepth-inl.h +57 -0
- pixmask-0.1.0/src/cpp/src/bitdepth.cpp +34 -0
- pixmask-0.1.0/src/cpp/src/decode.cpp +99 -0
- pixmask-0.1.0/src/cpp/src/jpeg_roundtrip.cpp +256 -0
- pixmask-0.1.0/src/cpp/src/median-inl.h +185 -0
- pixmask-0.1.0/src/cpp/src/median.cpp +55 -0
- pixmask-0.1.0/src/cpp/src/pipeline.cpp +143 -0
- pixmask-0.1.0/src/cpp/src/validate.cpp +355 -0
- pixmask-0.1.0/src/cpp/third_party/doctest.h +7134 -0
- pixmask-0.1.0/src/cpp/third_party/stb_image.h +7988 -0
- pixmask-0.1.0/src/cpp/third_party/stb_image_write.h +1724 -0
- pixmask-0.1.0/src/tests/cpp/test_bitdepth.cpp +222 -0
- pixmask-0.1.0/src/tests/cpp/test_decode.cpp +235 -0
- pixmask-0.1.0/src/tests/cpp/test_jpeg.cpp +260 -0
- pixmask-0.1.0/src/tests/cpp/test_median.cpp +253 -0
- pixmask-0.1.0/src/tests/cpp/test_pipeline.cpp +165 -0
- pixmask-0.1.0/src/tests/cpp/test_validate.cpp +395 -0
- pixmask-0.1.0/src/tests/python/conftest.py +127 -0
- pixmask-0.1.0/src/tests/python/test_sanitize.py +210 -0
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ci-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build-and-test:
|
|
15
|
+
name: ${{ matrix.os }} / Python ${{ matrix.python }}
|
|
16
|
+
runs-on: ${{ matrix.os }}
|
|
17
|
+
strategy:
|
|
18
|
+
fail-fast: false
|
|
19
|
+
matrix:
|
|
20
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
21
|
+
python: ["3.11", "3.12", "3.13"]
|
|
22
|
+
|
|
23
|
+
steps:
|
|
24
|
+
- uses: actions/checkout@v4
|
|
25
|
+
with:
|
|
26
|
+
submodules: true
|
|
27
|
+
|
|
28
|
+
- uses: actions/setup-python@v5
|
|
29
|
+
with:
|
|
30
|
+
python-version: ${{ matrix.python }}
|
|
31
|
+
|
|
32
|
+
- name: Install build dependencies
|
|
33
|
+
run: pip install nanobind scikit-build-core[pyproject] numpy pytest
|
|
34
|
+
|
|
35
|
+
- name: Build and install (editable)
|
|
36
|
+
run: pip install --no-build-isolation -ve .
|
|
37
|
+
|
|
38
|
+
- name: Run Python tests
|
|
39
|
+
run: pytest src/tests/python -x -q
|
|
40
|
+
|
|
41
|
+
cpp-tests:
|
|
42
|
+
name: C++ tests
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v4
|
|
46
|
+
with:
|
|
47
|
+
submodules: true
|
|
48
|
+
|
|
49
|
+
- name: Configure
|
|
50
|
+
run: cmake -S . -B build -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
|
|
51
|
+
|
|
52
|
+
- name: Build
|
|
53
|
+
run: cmake --build build -j$(nproc)
|
|
54
|
+
|
|
55
|
+
- name: Test
|
|
56
|
+
run: ctest --test-dir build --output-on-failure
|
|
57
|
+
|
|
58
|
+
asan:
|
|
59
|
+
name: ASan / UBSan
|
|
60
|
+
runs-on: ubuntu-latest
|
|
61
|
+
steps:
|
|
62
|
+
- uses: actions/checkout@v4
|
|
63
|
+
with:
|
|
64
|
+
submodules: true
|
|
65
|
+
|
|
66
|
+
- name: Install Clang
|
|
67
|
+
run: sudo apt-get update && sudo apt-get install -y clang
|
|
68
|
+
|
|
69
|
+
- name: Configure (Sanitize)
|
|
70
|
+
run: >
|
|
71
|
+
cmake -S . -B build-san
|
|
72
|
+
-DCMAKE_BUILD_TYPE=Sanitize
|
|
73
|
+
-DBUILD_TESTING=ON
|
|
74
|
+
-DCMAKE_CXX_COMPILER=clang++
|
|
75
|
+
|
|
76
|
+
- name: Build
|
|
77
|
+
run: cmake --build build-san -j$(nproc)
|
|
78
|
+
|
|
79
|
+
- name: Test under ASan/UBSan
|
|
80
|
+
run: ctest --test-dir build-san --output-on-failure
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
name: Build wheels
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: wheels-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build-wheels:
|
|
14
|
+
name: Build ${{ matrix.os }} wheels
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
20
|
+
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
with:
|
|
24
|
+
submodules: true
|
|
25
|
+
|
|
26
|
+
- uses: pypa/cibuildwheel@v2.21
|
|
27
|
+
env:
|
|
28
|
+
# aarch64 via QEMU takes 60+ min; use native ARM runners in v0.2
|
|
29
|
+
CIBW_ARCHS_LINUX: x86_64
|
|
30
|
+
CIBW_ARCHS_MACOS: arm64 x86_64
|
|
31
|
+
CIBW_ARCHS_WINDOWS: AMD64
|
|
32
|
+
|
|
33
|
+
- uses: actions/upload-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
name: wheels-${{ matrix.os }}
|
|
36
|
+
path: wheelhouse/*.whl
|
|
37
|
+
|
|
38
|
+
build-sdist:
|
|
39
|
+
name: Build source distribution
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v4
|
|
43
|
+
with:
|
|
44
|
+
submodules: true
|
|
45
|
+
|
|
46
|
+
- name: Build sdist
|
|
47
|
+
run: pipx run build --sdist
|
|
48
|
+
|
|
49
|
+
- uses: actions/upload-artifact@v4
|
|
50
|
+
with:
|
|
51
|
+
name: sdist
|
|
52
|
+
path: dist/*.tar.gz
|
|
53
|
+
|
|
54
|
+
publish:
|
|
55
|
+
name: Publish to PyPI
|
|
56
|
+
needs: [build-wheels, build-sdist]
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/download-artifact@v4
|
|
61
|
+
with:
|
|
62
|
+
path: dist
|
|
63
|
+
merge-multiple: true
|
|
64
|
+
|
|
65
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
66
|
+
with:
|
|
67
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
pixmask-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Build
|
|
2
|
+
build/
|
|
3
|
+
build-*/
|
|
4
|
+
dist/
|
|
5
|
+
wheelhouse/
|
|
6
|
+
*.egg-info/
|
|
7
|
+
*.so
|
|
8
|
+
*.dylib
|
|
9
|
+
*.dll
|
|
10
|
+
*.pyd
|
|
11
|
+
|
|
12
|
+
# Python
|
|
13
|
+
__pycache__/
|
|
14
|
+
*.pyc
|
|
15
|
+
*.pyo
|
|
16
|
+
.eggs/
|
|
17
|
+
|
|
18
|
+
# IDE
|
|
19
|
+
.vscode/
|
|
20
|
+
.idea/
|
|
21
|
+
*.swp
|
|
22
|
+
*.swo
|
|
23
|
+
*~
|
|
24
|
+
.DS_Store
|
|
25
|
+
|
|
26
|
+
# Testing
|
|
27
|
+
.pytest_cache/
|
|
28
|
+
.coverage
|
|
29
|
+
htmlcov/
|
|
30
|
+
|
|
31
|
+
# Packaging
|
|
32
|
+
*.whl
|
|
33
|
+
*.tar.gz
|
|
34
|
+
|
|
35
|
+
# Working docs (keep research/architecture out of releases)
|
|
36
|
+
PROGRESS.md
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.15...3.27)
|
|
2
|
+
|
|
3
|
+
project(pixmask VERSION 0.1.0 LANGUAGES CXX)
|
|
4
|
+
|
|
5
|
+
if(NOT SKBUILD)
|
|
6
|
+
message(WARNING
|
|
7
|
+
"This CMake file is meant to be used via scikit-build-core.\n"
|
|
8
|
+
"Dev workflow:\n"
|
|
9
|
+
" pip install nanobind scikit-build-core[pyproject]\n"
|
|
10
|
+
" pip install --no-build-isolation -ve .")
|
|
11
|
+
endif()
|
|
12
|
+
|
|
13
|
+
set(CMAKE_CXX_STANDARD 17)
|
|
14
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
15
|
+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
16
|
+
|
|
17
|
+
# ============================================================
|
|
18
|
+
# Google Highway — FetchContent
|
|
19
|
+
# ============================================================
|
|
20
|
+
include(FetchContent)
|
|
21
|
+
|
|
22
|
+
set(HWY_ENABLE_TESTS OFF CACHE BOOL "" FORCE)
|
|
23
|
+
set(HWY_ENABLE_EXAMPLES OFF CACHE BOOL "" FORCE)
|
|
24
|
+
set(HWY_ENABLE_CONTRIB OFF CACHE BOOL "" FORCE)
|
|
25
|
+
set(HWY_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)
|
|
26
|
+
|
|
27
|
+
FetchContent_Declare(highway
|
|
28
|
+
GIT_REPOSITORY https://github.com/google/highway.git
|
|
29
|
+
GIT_TAG 1.2.0
|
|
30
|
+
GIT_SHALLOW TRUE
|
|
31
|
+
)
|
|
32
|
+
FetchContent_MakeAvailable(highway)
|
|
33
|
+
|
|
34
|
+
# ============================================================
|
|
35
|
+
# Core C++ library
|
|
36
|
+
# ============================================================
|
|
37
|
+
# POSITION_INDEPENDENT_CODE required: this static lib gets linked into a
|
|
38
|
+
# shared Python extension module (.so). Without -fPIC, ld fails on Linux.
|
|
39
|
+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
40
|
+
|
|
41
|
+
add_library(pixmask_core STATIC
|
|
42
|
+
src/cpp/src/arena.cpp
|
|
43
|
+
src/cpp/src/validate.cpp
|
|
44
|
+
src/cpp/src/decode.cpp
|
|
45
|
+
src/cpp/src/bitdepth.cpp
|
|
46
|
+
src/cpp/src/median.cpp
|
|
47
|
+
src/cpp/src/jpeg_roundtrip.cpp
|
|
48
|
+
src/cpp/src/pipeline.cpp
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
target_include_directories(pixmask_core
|
|
52
|
+
PUBLIC src/cpp/include
|
|
53
|
+
PRIVATE src/cpp/third_party
|
|
54
|
+
PRIVATE src/cpp/src # for -inl.h (Highway per-target includes)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# stb_image: restrict to JPEG + PNG only at compile time (DECISIONS.md §2)
|
|
58
|
+
# STBI_ONLY_JPEG + STBI_ONLY_PNG cause stb_image.h to internally define
|
|
59
|
+
# all STBI_NO_* macros. Don't also define them here to avoid redefinition warnings.
|
|
60
|
+
target_compile_definitions(pixmask_core PRIVATE
|
|
61
|
+
STBI_ONLY_JPEG
|
|
62
|
+
STBI_ONLY_PNG
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
target_link_libraries(pixmask_core PUBLIC hwy)
|
|
66
|
+
|
|
67
|
+
# ============================================================
|
|
68
|
+
# SIMD flags per platform
|
|
69
|
+
# ============================================================
|
|
70
|
+
if(DEFINED PIXMASK_ARCH)
|
|
71
|
+
if(PIXMASK_ARCH STREQUAL "x86_64")
|
|
72
|
+
target_compile_options(pixmask_core PRIVATE -mavx2 -mfma)
|
|
73
|
+
elseif(PIXMASK_ARCH MATCHES "aarch64|arm64")
|
|
74
|
+
target_compile_options(pixmask_core PRIVATE -march=armv8-a+simd)
|
|
75
|
+
endif()
|
|
76
|
+
endif()
|
|
77
|
+
|
|
78
|
+
# ============================================================
|
|
79
|
+
# Python extension module (only when building via scikit-build-core)
|
|
80
|
+
# ============================================================
|
|
81
|
+
if(SKBUILD)
|
|
82
|
+
find_package(Python 3.9
|
|
83
|
+
REQUIRED COMPONENTS Interpreter Development.Module
|
|
84
|
+
OPTIONAL_COMPONENTS Development.SABIModule)
|
|
85
|
+
|
|
86
|
+
find_package(nanobind CONFIG REQUIRED)
|
|
87
|
+
|
|
88
|
+
nanobind_add_module(
|
|
89
|
+
pixmask_ext
|
|
90
|
+
STABLE_ABI
|
|
91
|
+
NB_STATIC
|
|
92
|
+
LTO
|
|
93
|
+
NB_DOMAIN pixmask
|
|
94
|
+
src/cpp/bindings/module.cpp
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
target_include_directories(pixmask_ext PRIVATE src/cpp/include)
|
|
98
|
+
target_link_libraries(pixmask_ext PRIVATE pixmask_core)
|
|
99
|
+
|
|
100
|
+
install(TARGETS pixmask_ext LIBRARY DESTINATION pixmask)
|
|
101
|
+
|
|
102
|
+
# Type stubs are hand-maintained in python/pixmask/__init__.pyi.
|
|
103
|
+
# py.typed marker is committed in python/pixmask/py.typed.
|
|
104
|
+
endif()
|
|
105
|
+
|
|
106
|
+
# ============================================================
|
|
107
|
+
# C++ unit tests (doctest, vendored header)
|
|
108
|
+
# ============================================================
|
|
109
|
+
if(BUILD_TESTING AND NOT SKBUILD)
|
|
110
|
+
enable_testing()
|
|
111
|
+
|
|
112
|
+
foreach(test_src
|
|
113
|
+
src/tests/cpp/test_decode.cpp
|
|
114
|
+
src/tests/cpp/test_bitdepth.cpp
|
|
115
|
+
src/tests/cpp/test_median.cpp
|
|
116
|
+
src/tests/cpp/test_validate.cpp
|
|
117
|
+
src/tests/cpp/test_jpeg.cpp
|
|
118
|
+
src/tests/cpp/test_pipeline.cpp)
|
|
119
|
+
|
|
120
|
+
get_filename_component(test_name ${test_src} NAME_WE)
|
|
121
|
+
add_executable(${test_name} ${test_src})
|
|
122
|
+
target_link_libraries(${test_name} PRIVATE pixmask_core)
|
|
123
|
+
target_include_directories(${test_name} PRIVATE src/cpp/third_party)
|
|
124
|
+
add_test(NAME ${test_name} COMMAND ${test_name})
|
|
125
|
+
endforeach()
|
|
126
|
+
endif()
|
|
127
|
+
|
|
128
|
+
# ============================================================
|
|
129
|
+
# Fuzz targets (libFuzzer; Clang only)
|
|
130
|
+
# ============================================================
|
|
131
|
+
option(PIXMASK_FUZZ "Build libFuzzer fuzz targets" OFF)
|
|
132
|
+
|
|
133
|
+
if(PIXMASK_FUZZ)
|
|
134
|
+
set(FUZZ_FLAGS -fsanitize=fuzzer,address -g -O1)
|
|
135
|
+
|
|
136
|
+
foreach(fuzz_src
|
|
137
|
+
src/tests/cpp/fuzz/fuzz_decode.cpp
|
|
138
|
+
src/tests/cpp/fuzz/fuzz_validate.cpp)
|
|
139
|
+
|
|
140
|
+
get_filename_component(fuzz_name ${fuzz_src} NAME_WE)
|
|
141
|
+
add_executable(${fuzz_name} ${fuzz_src})
|
|
142
|
+
target_link_libraries(${fuzz_name} PRIVATE pixmask_core)
|
|
143
|
+
target_compile_options(${fuzz_name} PRIVATE ${FUZZ_FLAGS})
|
|
144
|
+
target_link_options(${fuzz_name} PRIVATE ${FUZZ_FLAGS})
|
|
145
|
+
endforeach()
|
|
146
|
+
endif()
|
|
147
|
+
|
|
148
|
+
# ============================================================
|
|
149
|
+
# ASan / UBSan build type
|
|
150
|
+
# ============================================================
|
|
151
|
+
set(CMAKE_CXX_FLAGS_SANITIZE
|
|
152
|
+
"-g -O1 -fsanitize=address,undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls"
|
|
153
|
+
CACHE STRING "Flags for Sanitize build type" FORCE)
|
|
154
|
+
set(CMAKE_C_FLAGS_SANITIZE
|
|
155
|
+
"${CMAKE_CXX_FLAGS_SANITIZE}"
|
|
156
|
+
CACHE STRING "" FORCE)
|
|
157
|
+
set(CMAKE_EXE_LINKER_FLAGS_SANITIZE
|
|
158
|
+
"-fsanitize=address,undefined"
|
|
159
|
+
CACHE STRING "" FORCE)
|
|
160
|
+
set(CMAKE_SHARED_LINKER_FLAGS_SANITIZE
|
|
161
|
+
"${CMAKE_EXE_LINKER_FLAGS_SANITIZE}"
|
|
162
|
+
CACHE STRING "" FORCE)
|
pixmask-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Akasxh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
pixmask-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: pixmask
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fast image sanitization for multimodal LLMs
|
|
5
|
+
Author-Email: Akasxh <drakathakash@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Akasxh
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
29
|
+
Classifier: Programming Language :: Python :: 3
|
|
30
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
31
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
32
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
33
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
34
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
35
|
+
Classifier: Programming Language :: C++
|
|
36
|
+
Classifier: Topic :: Security
|
|
37
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
|
38
|
+
Classifier: Development Status :: 3 - Alpha
|
|
39
|
+
Project-URL: Homepage, https://github.com/Akasxh/pixmask
|
|
40
|
+
Project-URL: Repository, https://github.com/Akasxh/pixmask
|
|
41
|
+
Project-URL: Issues, https://github.com/Akasxh/pixmask/issues
|
|
42
|
+
Requires-Python: >=3.9
|
|
43
|
+
Requires-Dist: numpy>=1.24
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# pixmask
|
|
47
|
+
|
|
48
|
+
Blazing-fast image sanitization for multimodal LLM security. Pure C++ core with SIMD acceleration, Python bindings via nanobind. Zero runtime dependencies.
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
pip install pixmask
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```mermaid
|
|
55
|
+
flowchart LR
|
|
56
|
+
subgraph Input
|
|
57
|
+
A[Untrusted\nImage]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
subgraph pixmask ["pixmask Pipeline"]
|
|
61
|
+
B[Validate &\nDecode]
|
|
62
|
+
C[Bit-Depth\nReduction]
|
|
63
|
+
D[Median\nFilter]
|
|
64
|
+
E[JPEG\nRoundtrip]
|
|
65
|
+
B --> C --> D --> E
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
subgraph Output
|
|
69
|
+
F[Sanitized\nImage]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
A --> B
|
|
73
|
+
E --> F
|
|
74
|
+
F --> G[Any VLM:\nGPT-4V / Gemini /\nLLaVA / etc.]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Why pixmask?
|
|
78
|
+
|
|
79
|
+
Every image sent to a multimodal LLM is an attack surface. Adversarial perturbations, steganographic payloads, prompt injection via pixel manipulation, malformed files exploiting parser bugs -- pixmask neutralizes these threats in **<15ms** with a single function call.
|
|
80
|
+
|
|
81
|
+
| Threat | How pixmask stops it |
|
|
82
|
+
|--------|---------------------|
|
|
83
|
+
| Gradient perturbations (PGD, C&W) | Bit-depth reduction collapses adversarial increments |
|
|
84
|
+
| LSB steganography | Bit-depth crush overwrites hidden payload bits |
|
|
85
|
+
| DCT-domain steganography | JPEG roundtrip re-quantizes all DCT coefficients |
|
|
86
|
+
| Malformed/corrupt images | Strict validation gate before any decode |
|
|
87
|
+
| Scaling attacks | Safe resize with area interpolation (v0.2) |
|
|
88
|
+
| Neural steganography | Layered pipeline destroys embedded patterns |
|
|
89
|
+
|
|
90
|
+
### Compared to alternatives
|
|
91
|
+
|
|
92
|
+
| Library | Language | Latency (1080p) | Install size | VLM-focused? |
|
|
93
|
+
|---------|----------|-----------------|-------------|-------------|
|
|
94
|
+
| **pixmask** | **C++ / SIMD** | **<15ms** | **<5MB** | **Yes** |
|
|
95
|
+
| ART (IBM) | Python | 50-500ms | ~200MB | No |
|
|
96
|
+
| OpenCV preprocessing | C++ | ~10ms | ~50MB + libGL | No |
|
|
97
|
+
| DiffPure | Python + GPU | 500-5000ms | ~2GB | No |
|
|
98
|
+
|
|
99
|
+
## Quick Start
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
import pixmask
|
|
103
|
+
import numpy as np
|
|
104
|
+
|
|
105
|
+
# One-liner: sanitize any image
|
|
106
|
+
safe_image = pixmask.sanitize(image_array)
|
|
107
|
+
|
|
108
|
+
# From raw bytes (e.g., API upload)
|
|
109
|
+
safe_image = pixmask.sanitize(raw_bytes)
|
|
110
|
+
|
|
111
|
+
# From file path
|
|
112
|
+
safe_image = pixmask.sanitize("uploaded_photo.jpg")
|
|
113
|
+
|
|
114
|
+
# Presets
|
|
115
|
+
safe_image = pixmask.sanitize(image, preset="fast") # ~3ms, bit-depth + JPEG only
|
|
116
|
+
safe_image = pixmask.sanitize(image, preset="balanced") # ~15ms, full pipeline (default)
|
|
117
|
+
safe_image = pixmask.sanitize(image, preset="paranoid") # ~25ms, maximum defense
|
|
118
|
+
|
|
119
|
+
# Custom parameters
|
|
120
|
+
safe_image = pixmask.sanitize(image, bit_depth=4, jpeg_quality=(60, 80))
|
|
121
|
+
|
|
122
|
+
# Get bytes for API calls
|
|
123
|
+
safe_bytes = pixmask.sanitize(raw_bytes, output_format="jpeg")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Integration with VLM APIs
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
import pixmask
|
|
130
|
+
|
|
131
|
+
# Sanitize before sending to any VLM
|
|
132
|
+
with open("user_upload.jpg", "rb") as f:
|
|
133
|
+
raw = f.read()
|
|
134
|
+
|
|
135
|
+
safe = pixmask.sanitize(raw, output_format="jpeg")
|
|
136
|
+
|
|
137
|
+
# Now pass `safe` to your VLM API of choice
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## How It Works
|
|
141
|
+
|
|
142
|
+
pixmask applies a multi-stage defense pipeline:
|
|
143
|
+
|
|
144
|
+
### Stage 0: Input Validation
|
|
145
|
+
- Magic byte verification (PNG, JPEG, WebP only -- GIF/TIFF/SVG rejected)
|
|
146
|
+
- Dimension limits (max 8192x8192)
|
|
147
|
+
- File size limits (max 50MB)
|
|
148
|
+
- Decompression ratio check (prevents zip/PNG bombs)
|
|
149
|
+
|
|
150
|
+
### Stage 1: Safe Decode
|
|
151
|
+
- stb_image with compile-time format restriction (JPEG + PNG only)
|
|
152
|
+
- GIF, BMP, TGA, PSD, HDR, PIC, PNM all disabled at build time
|
|
153
|
+
- Pixels copied to SIMD-aligned buffer immediately, parser memory freed
|
|
154
|
+
|
|
155
|
+
### Stage 2: Bit-Depth Reduction
|
|
156
|
+
- Reduces 8-bit channels to 5-bit (configurable 1-8)
|
|
157
|
+
- Implemented with Google Highway SIMD (SSE2/AVX2/NEON)
|
|
158
|
+
- Collapses adversarial perturbations that hide in low-order bits
|
|
159
|
+
- Destroys LSB steganography as a side effect
|
|
160
|
+
|
|
161
|
+
### Stage 3: Median Filter (3x3)
|
|
162
|
+
- 19-step Bose-Nelson sorting network
|
|
163
|
+
- SIMD-accelerated via Google Highway
|
|
164
|
+
- Removes impulse noise and isolated adversarial pixels
|
|
165
|
+
- Edge-preserving for natural image content
|
|
166
|
+
|
|
167
|
+
### Stage 4: JPEG Roundtrip
|
|
168
|
+
- Encode to JPEG with **randomized** quality factor (70-85)
|
|
169
|
+
- Decode back to pixel buffer
|
|
170
|
+
- Quality randomized per-image using OS entropy (`getrandom`/`getentropy`)
|
|
171
|
+
- Destroys DCT-domain steganography and high-frequency perturbations
|
|
172
|
+
- Randomization prevents adaptive attacks that train through a fixed QF
|
|
173
|
+
|
|
174
|
+
## Architecture
|
|
175
|
+
|
|
176
|
+
```
|
|
177
|
+
pixmask/
|
|
178
|
+
src/cpp/
|
|
179
|
+
include/pixmask/ # Public C++ headers
|
|
180
|
+
types.h # ImageView, SanitizeOptions, SanitizeResult
|
|
181
|
+
arena.h # Zero-allocation bump-pointer allocator
|
|
182
|
+
validate.h # Stage 0: input validation
|
|
183
|
+
decode.h # Stage 1: stb_image wrapper
|
|
184
|
+
bitdepth.h # Stage 2: SIMD bit-depth reduction
|
|
185
|
+
median.h # Stage 3: SIMD median filter
|
|
186
|
+
jpeg_roundtrip.h # Stage 4: randomized JPEG roundtrip
|
|
187
|
+
pipeline.h # Pipeline orchestrator
|
|
188
|
+
src/ # Implementations + Highway SIMD dispatch
|
|
189
|
+
bindings/module.cpp # nanobind Python bindings
|
|
190
|
+
third_party/ # Vendored: stb_image, stb_image_write, doctest
|
|
191
|
+
python/pixmask/ # Python package
|
|
192
|
+
src/tests/ # C++ (doctest) + Python (pytest) tests
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Design Principles
|
|
196
|
+
|
|
197
|
+
- **Zero runtime dependencies** -- numpy is the only optional peer dep
|
|
198
|
+
- **Pure C++17 core** -- no OpenCV, no scipy, no Pillow required
|
|
199
|
+
- **SIMD everywhere** -- Google Highway for portable SSE2/AVX2/NEON
|
|
200
|
+
- **Arena allocator** -- zero heap allocations in the hot path
|
|
201
|
+
- **Pre-built wheels** -- `pip install` just works, no compiler needed
|
|
202
|
+
|
|
203
|
+
## Building from Source
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
# Development build
|
|
207
|
+
pip install nanobind scikit-build-core[pyproject]
|
|
208
|
+
pip install --no-build-isolation -ve .
|
|
209
|
+
|
|
210
|
+
# C++ only (no Python)
|
|
211
|
+
cmake -S . -B build -DBUILD_TESTING=ON
|
|
212
|
+
cmake --build build -j$(nproc)
|
|
213
|
+
ctest --test-dir build
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Testing
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# C++ tests
|
|
220
|
+
cmake --build build -j$(nproc)
|
|
221
|
+
ctest --test-dir build --output-on-failure
|
|
222
|
+
|
|
223
|
+
# Python tests (after pip install)
|
|
224
|
+
pytest src/tests/python/ -v
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Roadmap
|
|
228
|
+
|
|
229
|
+
### v0.2
|
|
230
|
+
- Bilateral filter (edge-preserving, Pareto-superior to median)
|
|
231
|
+
- Gaussian blur (3-pass box blur approximation)
|
|
232
|
+
- Haar wavelet denoising (strongest standalone defense)
|
|
233
|
+
- Pixel deflection (stochastic, non-differentiable)
|
|
234
|
+
- Safe resize with INTER_AREA + random jitter
|
|
235
|
+
- Upgrade decoders: libspng + libjpeg-turbo (replacing stb)
|
|
236
|
+
- Steganography detection signal (chi-square test)
|
|
237
|
+
|
|
238
|
+
### v0.3+
|
|
239
|
+
- OCR-based typographic attack detection
|
|
240
|
+
- Total variation denoising (Chambolle-Pock)
|
|
241
|
+
- Content-aware adaptive sanitization
|
|
242
|
+
- BPDA/EOT adaptive attack evaluation suite
|
|
243
|
+
|
|
244
|
+
## Limitations
|
|
245
|
+
|
|
246
|
+
pixmask is a **preprocessing defense layer**, not a complete security solution:
|
|
247
|
+
|
|
248
|
+
- **Typographic attacks** (FigStep) embed readable text in images. Pixel-level preprocessing cannot stop this -- OCR-based detection is needed (planned for v0.3).
|
|
249
|
+
- **Semantic content attacks** where the image itself is harmful content require content moderation, not sanitization.
|
|
250
|
+
- **Fully adaptive white-box adversaries** who know the exact pipeline can theoretically bypass any preprocessing defense (Athalye et al., ICML 2018). pixmask is effective against the realistic non-adaptive threat model.
|
|
251
|
+
|
|
252
|
+
## References
|
|
253
|
+
|
|
254
|
+
- Xu, Evans, Qi -- "Feature Squeezing: Detecting Adversarial Examples", NDSS 2018
|
|
255
|
+
- Guo et al. -- "Countering Adversarial Images via Input Transformations", ICLR 2018
|
|
256
|
+
- Das et al. -- "SHIELD: Fast, Practical Defense and Vaccination", KDD 2018
|
|
257
|
+
- Prakash et al. -- "Deflecting Adversarial Attacks with Pixel Deflection", CVPR 2018
|
|
258
|
+
- Qi et al. -- "Visual Adversarial Examples Jailbreak Aligned LLMs", AAAI 2024
|
|
259
|
+
- Gong et al. -- "FigStep: Jailbreaking VLMs via Typographic Prompts", AAAI 2025
|
|
260
|
+
- Athalye, Carlini, Wagner -- "Obfuscated Gradients Give a False Sense of Security", ICML 2018
|
|
261
|
+
- Quiring et al. -- "Adversarial Preprocessing: Image-Scaling Attacks", USENIX Security 2020
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
MIT
|