stegmark 1.0.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.
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: stegmark
3
+ Version: 1.0.0
4
+ Summary: Universal steganographic analysis — statistical, forensic, and neural watermark detection
5
+ Requires-Python: >=3.9
6
+ Requires-Dist: numpy<2.0,>=1.24
7
+ Requires-Dist: scipy>=1.10
8
+ Requires-Dist: scikit-image>=0.21
9
+ Requires-Dist: Pillow>=10.0
10
+ Requires-Dist: reportlab>=4.0
11
+ Requires-Dist: jpegio>=0.2.8
12
+ Requires-Dist: fastapi>=0.100
13
+ Requires-Dist: uvicorn>=0.23
14
+ Requires-Dist: python-multipart>=0.0.6
15
+ Provides-Extra: neural
16
+ Requires-Dist: trustmark>=0.1; extra == "neural"
17
+ Requires-Dist: torch>=2.0; extra == "neural"
18
+ Requires-Dist: torchvision>=0.15; extra == "neural"
19
+ Provides-Extra: all
20
+ Requires-Dist: trustmark>=0.1; extra == "all"
21
+ Requires-Dist: torch>=2.0; extra == "all"
22
+ Requires-Dist: torchvision>=0.15; extra == "all"
@@ -0,0 +1,56 @@
1
+ # Stegmark
2
+
3
+ Universal steganographic analysis — statistical, forensic, and neural watermark detection.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install stegmark # statistical + forensic detectors
9
+ pip install "stegmark[neural]" # + TrustMark / Stable Signature neural detection
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ ```python
15
+ from stegmark import analyze, robustness_test
16
+
17
+ # Analyze any image
18
+ result = analyze("image.jpg")
19
+ print(result.verdict)
20
+ print(result.confidence)
21
+ result.save_report("audit.pdf")
22
+
23
+ # Test watermark robustness
24
+ report = robustness_test("cover.jpg", secret="my_id")
25
+ print(f"Survived {report.survival_rate:.0%} of attacks")
26
+ print(f"Failed: {report.failed_attacks}")
27
+ report.save_report("robustness_audit.pdf")
28
+
29
+ # With cover image for quality metrics
30
+ result = analyze("stego.jpg", cover_path="original.jpg")
31
+ print(f"PSNR: {result.psnr:.1f} dB SSIM: {result.ssim:.4f}")
32
+ ```
33
+
34
+ ## What it detects
35
+
36
+ | Detector | Domain | Catches |
37
+ |---|---|---|
38
+ | Chi-square | JPEG DCT | LSB replacement in DCT coefficients |
39
+ | RS Analysis | Spatial | Pixel-level LSB substitution |
40
+ | SPA | Spatial | Sample pair analysis |
41
+ | EOF Detection | Forensic | Data appended after image end marker |
42
+ | EXIF Analysis | Forensic | Metadata anomalies, steg tool fingerprints |
43
+ | LSB Histogram | Forensic | LSB plane uniformity |
44
+ | Multi-channel | Forensic | Per-R/G/B channel embedding |
45
+ | TrustMark | Neural | Adobe C2PA robust watermarks |
46
+ | Stable Signature | Neural | Meta AI Stable Diffusion watermarks |
47
+ | SRNet | Neural/GPU | Adaptive spatial steg (WOW/S-UNIWARD/HILL) |
48
+
49
+ ## API
50
+
51
+ Also available as a hosted API: `https://raghav7006--stegmark-api-web.modal.run`
52
+
53
+ ```bash
54
+ curl -X POST https://raghav7006--stegmark-api-web.modal.run/analyze \
55
+ -F "stego=@image.jpg"
56
+ ```
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "stegmark"
7
+ version = "1.0.0"
8
+ description = "Universal steganographic analysis — statistical, forensic, and neural watermark detection"
9
+ requires-python = ">=3.9"
10
+ dependencies = [
11
+ "numpy>=1.24,<2.0",
12
+ "scipy>=1.10",
13
+ "scikit-image>=0.21",
14
+ "Pillow>=10.0",
15
+ "reportlab>=4.0",
16
+ "jpegio>=0.2.8",
17
+ "fastapi>=0.100",
18
+ "uvicorn>=0.23",
19
+ "python-multipart>=0.0.6",
20
+ ]
21
+
22
+ [project.optional-dependencies]
23
+ neural = ["trustmark>=0.1", "torch>=2.0", "torchvision>=0.15"]
24
+ all = ["trustmark>=0.1", "torch>=2.0", "torchvision>=0.15"]
25
+
26
+ [project.scripts]
27
+ stegmark = "stegmark.cli:main"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,27 @@
1
+ """
2
+ Stegmark — Universal Steganographic Analysis
3
+ =============================================
4
+ pip install stegmark
5
+
6
+ Usage:
7
+ from stegmark import analyze, robustness_test
8
+
9
+ # Analyze a single image
10
+ result = analyze("image.jpg")
11
+ print(result.verdict)
12
+ print(result.confidence)
13
+ result.save_report("audit.pdf")
14
+
15
+ # Test watermark robustness
16
+ report = robustness_test("cover.jpg", secret="my_watermark")
17
+ print(f"Survived {report.survival_rate:.0%} of attacks")
18
+ report.save_report("robustness_audit.pdf")
19
+ """
20
+
21
+ from stegmark.core import analyze, AnalysisResult
22
+ from stegmark.robustness import robustness_test, RobustnessResult
23
+ from stegmark.report import generate_report
24
+
25
+ __version__ = "1.0.0"
26
+ __all__ = ["analyze", "robustness_test", "generate_report",
27
+ "AnalysisResult", "RobustnessResult"]
@@ -0,0 +1,44 @@
1
+ """
2
+ stegmark._detectors — internal detector wrappers
3
+ Bridges the package API to the underlying detector modules.
4
+ """
5
+
6
+ import os, sys, dataclasses
7
+ _PKG_DIR = os.path.dirname(__file__)
8
+ sys.path.insert(0, _PKG_DIR)
9
+
10
+
11
+ def run_statistical(image_path: str, cover_path=None) -> dict:
12
+ from steganalysis import run_report
13
+ report = run_report(image_path, cover_path)
14
+ return dataclasses.asdict(report)
15
+
16
+
17
+ def run_neural(image_path: str) -> dict:
18
+ try:
19
+ from neural_watermark import run_neural_detection
20
+ nd = run_neural_detection(image_path)
21
+ return {
22
+ "attempted": True,
23
+ "any_detected": nd.any_detected,
24
+ "detected_schemes": nd.detected_schemes,
25
+ "detail": nd.detail,
26
+ "schemes": [dataclasses.asdict(s) for s in nd.schemes],
27
+ }
28
+ except ImportError:
29
+ return {
30
+ "attempted": False,
31
+ "error": "pip install trustmark torch torchvision",
32
+ "schemes": [],
33
+ }
34
+ except Exception as e:
35
+ return {"attempted": True, "error": str(e), "schemes": []}
36
+
37
+
38
+ def run_srnet_detection(image_path: str) -> dict:
39
+ try:
40
+ from srnet_detector import detect_srnet
41
+ sr = detect_srnet(image_path)
42
+ return dataclasses.asdict(sr)
43
+ except Exception as e:
44
+ return {"attempted": False, "error": str(e)}
@@ -0,0 +1,13 @@
1
+ """
2
+ stegmark CLI — installed as `stegmark` command after pip install
3
+ """
4
+ import sys, os
5
+ sys.path.insert(0, os.path.dirname(__file__))
6
+
7
+ def main():
8
+ # Delegate to run.py's main
9
+ from run import main as run_main
10
+ run_main()
11
+
12
+ if __name__ == "__main__":
13
+ main()
@@ -0,0 +1,187 @@
1
+ """
2
+ stegmark.core — main analyze() function
3
+ """
4
+
5
+ import os
6
+ import sys
7
+ import dataclasses
8
+ from typing import Optional
9
+ from dataclasses import dataclass, field
10
+
11
+ # Add package internals to path
12
+ _PKG_DIR = os.path.dirname(__file__)
13
+ sys.path.insert(0, _PKG_DIR)
14
+
15
+
16
+ @dataclass
17
+ class AnalysisResult:
18
+ """
19
+ Full steganalysis result for a single image.
20
+
21
+ Attributes:
22
+ verdict Plain-language verdict string
23
+ confidence 0.0–1.0 aggregate confidence stego is present
24
+ detected_by List of detector names that fired
25
+ image_path Path to analyzed image
26
+ cover_path Path to cover image (if provided)
27
+
28
+ # Detector results
29
+ chi_square JPEG DCT equalization score result
30
+ rs_analysis RS analysis result
31
+ spa Sample pair analysis result
32
+ eof EOF hidden data result
33
+ exif EXIF anomaly result
34
+ lsb_histogram LSB uniformity result
35
+ multi_channel Per-channel R/G/B result
36
+ neural Neural watermark detection result
37
+ srnet SRNet adaptive steg result
38
+ quality PSNR/SSIM (if cover provided)
39
+
40
+ Methods:
41
+ save_report(path) Generate and save PDF report
42
+ to_dict() Return as JSON-serializable dict
43
+ is_clean True if no stego detected
44
+ is_watermarked True if neural watermark detected
45
+ """
46
+ verdict: str
47
+ confidence: float
48
+ detected_by: list
49
+ image_path: str
50
+ cover_path: Optional[str]
51
+
52
+ # Raw detector results
53
+ chi_square: dict = field(default_factory=dict)
54
+ rs_analysis: dict = field(default_factory=dict)
55
+ spa: dict = field(default_factory=dict)
56
+ eof: dict = field(default_factory=dict)
57
+ exif: dict = field(default_factory=dict)
58
+ lsb_histogram: dict = field(default_factory=dict)
59
+ multi_channel: dict = field(default_factory=dict)
60
+ neural: dict = field(default_factory=dict)
61
+ srnet: dict = field(default_factory=dict)
62
+ quality: Optional[dict] = None
63
+
64
+ @property
65
+ def is_clean(self) -> bool:
66
+ return self.confidence < 0.05 and not self.detected_by
67
+
68
+ @property
69
+ def is_watermarked(self) -> bool:
70
+ return any("neural" in d for d in self.detected_by)
71
+
72
+ @property
73
+ def psnr(self) -> Optional[float]:
74
+ return self.quality.get("psnr_db") if self.quality else None
75
+
76
+ @property
77
+ def ssim(self) -> Optional[float]:
78
+ return self.quality.get("ssim") if self.quality else None
79
+
80
+ def save_report(self, output_path: str = None) -> str:
81
+ """Generate PDF report and save to output_path."""
82
+ from stegmark.report import generate_report
83
+ if output_path is None:
84
+ base = os.path.splitext(self.image_path)[0]
85
+ output_path = f"{base}_stegmark_report.pdf"
86
+ generate_report(self.to_dict(), output_path,
87
+ self.image_path, self.cover_path or "")
88
+ return output_path
89
+
90
+ def to_dict(self) -> dict:
91
+ return dataclasses.asdict(self)
92
+
93
+ def __repr__(self):
94
+ return (f"AnalysisResult(verdict={self.verdict!r}, "
95
+ f"confidence={self.confidence:.1%}, "
96
+ f"detected_by={self.detected_by})")
97
+
98
+
99
+ def analyze(
100
+ image_path: str,
101
+ cover_path: Optional[str] = None,
102
+ neural: bool = True,
103
+ srnet: bool = True,
104
+ verbose: bool = False,
105
+ ) -> AnalysisResult:
106
+ """
107
+ Run complete steganalysis on an image. Runs entirely locally.
108
+
109
+ Args:
110
+ image_path Path to the image to analyze (JPEG or PNG)
111
+ cover_path Path to the original cover image (optional).
112
+ Enables PSNR/SSIM quality metrics.
113
+ neural Run neural watermark detectors (TrustMark, Stable Signature).
114
+ Requires: pip install trustmark torch torchvision
115
+ srnet Run SRNet adaptive steg detector if checkpoint available.
116
+ Train with: stegmark train (runs overnight on Modal)
117
+ verbose Print progress to stdout
118
+
119
+ Returns:
120
+ AnalysisResult with .verdict, .confidence, .detected_by,
121
+ and per-detector results. Call .save_report() to get a PDF.
122
+
123
+ Example:
124
+ from stegmark import analyze
125
+
126
+ result = analyze("watermarked_image.jpg")
127
+ print(result.verdict)
128
+ # "WATERMARK DETECTED — neural (trustmark)"
129
+
130
+ result.save_report("audit_report.pdf")
131
+
132
+ # With cover for quality metrics:
133
+ result = analyze("stego.jpg", cover_path="original.jpg")
134
+ print(f"PSNR: {result.psnr:.1f} dB")
135
+ """
136
+ from stegmark._detectors import (
137
+ run_statistical, run_neural, run_srnet_detection
138
+ )
139
+
140
+ if verbose:
141
+ print(f"[stegmark] Analyzing {image_path}...")
142
+
143
+ # Phase 0: statistical + forensic
144
+ if verbose: print("[stegmark] Running statistical detectors...")
145
+ stat = run_statistical(image_path, cover_path)
146
+
147
+ # Phase 1: neural watermark detection
148
+ neural_result = {"attempted": False, "schemes": []}
149
+ if neural:
150
+ if verbose: print("[stegmark] Running neural detectors...")
151
+ neural_result = run_neural(image_path)
152
+ if neural_result.get("any_detected"):
153
+ for s in neural_result.get("schemes", []):
154
+ if s.get("detected"):
155
+ label = f"{s['scheme']}-neural"
156
+ if label not in stat["detected_by"]:
157
+ stat["detected_by"].append(label)
158
+ if stat["confidence"] < 0.5:
159
+ stat["confidence"] = 1.0
160
+ schemes = ", ".join(neural_result.get("detected_schemes", []))
161
+ stat["overall_verdict"] = f"WATERMARK DETECTED — neural ({schemes})"
162
+
163
+ # Phase 2: SRNet
164
+ srnet_result = {"attempted": False}
165
+ if srnet:
166
+ srnet_result = run_srnet_detection(image_path)
167
+ if srnet_result.get("detected"):
168
+ if "srnet-adaptive" not in stat["detected_by"]:
169
+ stat["detected_by"].append("srnet-adaptive")
170
+
171
+ return AnalysisResult(
172
+ verdict=stat["overall_verdict"],
173
+ confidence=stat["confidence"],
174
+ detected_by=stat["detected_by"],
175
+ image_path=image_path,
176
+ cover_path=cover_path,
177
+ chi_square=stat.get("chi_square", {}),
178
+ rs_analysis=stat.get("rs_analysis", {}),
179
+ spa=stat.get("spa", {}),
180
+ eof=stat.get("eof", {}),
181
+ exif=stat.get("exif", {}),
182
+ lsb_histogram=stat.get("lsb_histogram", {}),
183
+ multi_channel=stat.get("multi_channel", {}),
184
+ neural=neural_result,
185
+ srnet=srnet_result,
186
+ quality=stat.get("quality"),
187
+ )
@@ -0,0 +1,70 @@
1
+ """
2
+ stegmark.report — generate_report() function
3
+ Thin wrapper around generate_report.py
4
+ """
5
+
6
+ import os, sys
7
+ _PKG_DIR = os.path.dirname(__file__)
8
+ sys.path.insert(0, _PKG_DIR)
9
+
10
+
11
+ def generate_report(result: dict, output_path: str,
12
+ image_filename: str = "",
13
+ cover_filename: str = "") -> str:
14
+ """Generate a PDF report from an analysis result dict."""
15
+ from generate_report import generate_pdf
16
+ generate_pdf(result, output_path, image_filename, cover_filename)
17
+ return output_path
18
+
19
+
20
+ def generate_robustness_report(result, output_path: str) -> str:
21
+ """Generate a PDF robustness report from a RobustnessResult."""
22
+ import dataclasses
23
+ from generate_report import generate_pdf
24
+
25
+ # Build a result dict that generate_pdf can consume
26
+ attacks = result.attacks
27
+ survived = sum(1 for a in attacks if a.survived)
28
+
29
+ # Minimal stat result for the report
30
+ fake_result = {
31
+ "chi_square": {"equalization_score": 0, "estimated_payload_rate": 0,
32
+ "detected": False, "threshold": 0.65, "n_pairs": 0,
33
+ "detail": "Robustness test — not applicable"},
34
+ "rs_analysis": {"payload_rate": 0, "detected": False, "threshold": 0.05,
35
+ "detail": "Robustness test — not applicable"},
36
+ "spa": {"payload_rate": 0, "detected": False, "threshold": 0.07,
37
+ "detail": "Robustness test — not applicable"},
38
+ "eof": {"has_hidden_data": False, "hidden_bytes": 0, "detail": "N/A"},
39
+ "exif": {"has_exif": False, "anomalies": [], "software": None,
40
+ "suspicious": False, "detail": "N/A"},
41
+ "lsb_histogram": {"lsb_uniformity": 0, "noise_floor": 0,
42
+ "detected": False, "detail": "N/A"},
43
+ "multi_channel": {"channels": [], "most_suspicious": None, "detail": "N/A"},
44
+ "quality": {"psnr_db": result.baseline_psnr, "ssim": 0.99,
45
+ "imperceptible": result.baseline_psnr > 40,
46
+ "detail": f"Baseline PSNR={result.baseline_psnr:.2f}dB"},
47
+ "overall_verdict": (
48
+ f"ROBUSTNESS TEST — {result.secret!r} — "
49
+ f"Survived {survived}/{len(attacks)} attacks ({result.survival_rate:.0%})"
50
+ ),
51
+ "confidence": result.survival_rate,
52
+ "detected_by": ["trustmark-neural"],
53
+ "neural": {
54
+ "attempted": True, "any_detected": True,
55
+ "detected_schemes": ["trustmark"],
56
+ "detail": f"TrustMark watermark — survival rate {result.survival_rate:.0%}",
57
+ "schemes": [{
58
+ "scheme": "trustmark", "detected": True,
59
+ "confidence": 1.0, "payload": result.secret,
60
+ "bit_accuracy": 1.0, "error": None,
61
+ "description": "Adobe TrustMark — C2PA content provenance",
62
+ }]
63
+ },
64
+ "srnet": {"attempted": False},
65
+ }
66
+
67
+ generate_pdf(fake_result, output_path,
68
+ image_filename=result.image_path,
69
+ cover_filename="")
70
+ return output_path
@@ -0,0 +1,162 @@
1
+ """
2
+ stegmark.robustness — robustness_test() function
3
+ """
4
+
5
+ import os, sys, json
6
+ from dataclasses import dataclass, field
7
+ from typing import Optional, List
8
+
9
+ _PKG_DIR = os.path.dirname(__file__)
10
+ sys.path.insert(0, _PKG_DIR)
11
+
12
+
13
+ @dataclass
14
+ class AttackResult:
15
+ attack: str
16
+ psnr: float
17
+ bit_accuracy: float
18
+ survived: bool
19
+
20
+
21
+ @dataclass
22
+ class RobustnessResult:
23
+ """
24
+ Robustness test result for a watermarked image.
25
+
26
+ Attributes:
27
+ image_path Original cover image
28
+ secret Embedded secret string
29
+ baseline_psnr PSNR of watermarked vs cover
30
+ survival_rate Fraction of attacks watermark survived (0.0–1.0)
31
+ attacks Per-attack results
32
+ stego_path Path to saved watermarked image
33
+
34
+ Methods:
35
+ save_report(path) Generate and save PDF report
36
+ to_dict() Return as JSON-serializable dict
37
+ """
38
+ image_path: str
39
+ secret: str
40
+ baseline_psnr: float
41
+ survival_rate: float
42
+ attacks: List[AttackResult] = field(default_factory=list)
43
+ stego_path: str = ""
44
+
45
+ @property
46
+ def survived_attacks(self) -> List[str]:
47
+ return [a.attack for a in self.attacks if a.survived]
48
+
49
+ @property
50
+ def failed_attacks(self) -> List[str]:
51
+ return [a.attack for a in self.attacks if not a.survived]
52
+
53
+ def save_report(self, output_path: str = None) -> str:
54
+ from stegmark.report import generate_robustness_report
55
+ if output_path is None:
56
+ base = os.path.splitext(self.image_path)[0]
57
+ output_path = f"{base}_robustness_report.pdf"
58
+ generate_robustness_report(self, output_path)
59
+ return output_path
60
+
61
+ def to_dict(self) -> dict:
62
+ import dataclasses
63
+ return dataclasses.asdict(self)
64
+
65
+ def __repr__(self):
66
+ return (f"RobustnessResult(survival_rate={self.survival_rate:.0%}, "
67
+ f"survived={len(self.survived_attacks)}/{len(self.attacks)}, "
68
+ f"baseline_psnr={self.baseline_psnr:.1f}dB)")
69
+
70
+
71
+ def robustness_test(
72
+ image_path: str,
73
+ secret: str = "stegmark",
74
+ tier2: bool = False,
75
+ verbose: bool = True,
76
+ ) -> RobustnessResult:
77
+ """
78
+ Embed a TrustMark watermark and test survival across attack suite.
79
+
80
+ Args:
81
+ image_path Cover image path (JPEG or PNG)
82
+ secret String payload to embed (default: "stegmark")
83
+ tier2 Also run tier-2 attacks (brightness, contrast, noise)
84
+ verbose Print progress table
85
+
86
+ Returns:
87
+ RobustnessResult with .survival_rate, .survived_attacks,
88
+ .failed_attacks, .baseline_psnr. Call .save_report() for PDF.
89
+
90
+ Example:
91
+ from stegmark import robustness_test
92
+
93
+ report = robustness_test("cover.jpg", secret="my_company_id")
94
+ print(f"Survival rate: {report.survival_rate:.0%}")
95
+ print(f"Failed: {report.failed_attacks}")
96
+ report.save_report("robustness_audit.pdf")
97
+ """
98
+ import io
99
+ import numpy as np
100
+ from PIL import Image
101
+
102
+ try:
103
+ from trustmark import TrustMark
104
+ except ImportError:
105
+ raise ImportError("pip install trustmark torch torchvision")
106
+
107
+ from robust_watermark_test import (
108
+ TIER1_ATTACKS, TIER2_ATTACKS, psnr, bit_accuracy
109
+ )
110
+
111
+ if verbose:
112
+ print(f"[stegmark] Loading TrustMark model...")
113
+ tm = TrustMark(verbose=False, model_type="Q")
114
+
115
+ cover = Image.open(image_path).convert("RGB")
116
+ stego = tm.encode(cover, secret)
117
+
118
+ stego_path = os.path.splitext(image_path)[0] + "_stegmark_stego.png"
119
+ stego.save(stego_path)
120
+
121
+ baseline = psnr(cover, stego)
122
+ decoded_wm, detected, _ = tm.decode(stego)
123
+
124
+ if verbose:
125
+ print(f"[stegmark] Baseline: PSNR={baseline:.1f}dB detected={detected}")
126
+ print(f"\n {'Attack':<25} {'PSNR':>7} {'bit_acc':>8} {'survive':>8}")
127
+ print(f" {'-'*54}")
128
+
129
+ attacks = TIER1_ATTACKS + (TIER2_ATTACKS if tier2 else [])
130
+ results = []
131
+
132
+ for name, fn in attacks:
133
+ try:
134
+ attacked = fn(stego)
135
+ p = psnr(cover, attacked)
136
+ try:
137
+ dec, det, _ = tm.decode(attacked)
138
+ acc = bit_accuracy(dec, decoded_wm) if dec and decoded_wm else 0.0
139
+ survived = det and acc > 0.8
140
+ except Exception:
141
+ acc = 0.0; survived = False
142
+
143
+ if verbose:
144
+ print(f" {name:<25} {p:>6.1f} {acc:>7.1%} {'✓' if survived else '✗'}")
145
+ results.append(AttackResult(name, round(p,2), round(acc,3), survived))
146
+ except Exception as e:
147
+ results.append(AttackResult(name, 0.0, 0.0, False))
148
+
149
+ survived_count = sum(1 for r in results if r.survived)
150
+ rate = survived_count / len(results) if results else 0.0
151
+
152
+ if verbose:
153
+ print(f"\n Survived {survived_count}/{len(results)} ({rate:.0%})")
154
+
155
+ return RobustnessResult(
156
+ image_path=image_path,
157
+ secret=secret,
158
+ baseline_psnr=round(baseline, 2),
159
+ survival_rate=round(rate, 3),
160
+ attacks=results,
161
+ stego_path=stego_path,
162
+ )
@@ -0,0 +1,22 @@
1
+ Metadata-Version: 2.4
2
+ Name: stegmark
3
+ Version: 1.0.0
4
+ Summary: Universal steganographic analysis — statistical, forensic, and neural watermark detection
5
+ Requires-Python: >=3.9
6
+ Requires-Dist: numpy<2.0,>=1.24
7
+ Requires-Dist: scipy>=1.10
8
+ Requires-Dist: scikit-image>=0.21
9
+ Requires-Dist: Pillow>=10.0
10
+ Requires-Dist: reportlab>=4.0
11
+ Requires-Dist: jpegio>=0.2.8
12
+ Requires-Dist: fastapi>=0.100
13
+ Requires-Dist: uvicorn>=0.23
14
+ Requires-Dist: python-multipart>=0.0.6
15
+ Provides-Extra: neural
16
+ Requires-Dist: trustmark>=0.1; extra == "neural"
17
+ Requires-Dist: torch>=2.0; extra == "neural"
18
+ Requires-Dist: torchvision>=0.15; extra == "neural"
19
+ Provides-Extra: all
20
+ Requires-Dist: trustmark>=0.1; extra == "all"
21
+ Requires-Dist: torch>=2.0; extra == "all"
22
+ Requires-Dist: torchvision>=0.15; extra == "all"
@@ -0,0 +1,14 @@
1
+ README.md
2
+ pyproject.toml
3
+ stegmark/__init__.py
4
+ stegmark/_detectors.py
5
+ stegmark/cli.py
6
+ stegmark/core.py
7
+ stegmark/report.py
8
+ stegmark/robustness.py
9
+ stegmark.egg-info/PKG-INFO
10
+ stegmark.egg-info/SOURCES.txt
11
+ stegmark.egg-info/dependency_links.txt
12
+ stegmark.egg-info/entry_points.txt
13
+ stegmark.egg-info/requires.txt
14
+ stegmark.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ stegmark = stegmark.cli:main
@@ -0,0 +1,19 @@
1
+ numpy<2.0,>=1.24
2
+ scipy>=1.10
3
+ scikit-image>=0.21
4
+ Pillow>=10.0
5
+ reportlab>=4.0
6
+ jpegio>=0.2.8
7
+ fastapi>=0.100
8
+ uvicorn>=0.23
9
+ python-multipart>=0.0.6
10
+
11
+ [all]
12
+ trustmark>=0.1
13
+ torch>=2.0
14
+ torchvision>=0.15
15
+
16
+ [neural]
17
+ trustmark>=0.1
18
+ torch>=2.0
19
+ torchvision>=0.15
@@ -0,0 +1 @@
1
+ stegmark