oscura 0.8.0__py3-none-any.whl → 0.11.0__py3-none-any.whl
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.
- oscura/__init__.py +19 -19
- oscura/__main__.py +4 -0
- oscura/analyzers/__init__.py +2 -0
- oscura/analyzers/digital/extraction.py +2 -3
- oscura/analyzers/digital/quality.py +1 -1
- oscura/analyzers/digital/timing.py +1 -1
- oscura/analyzers/ml/signal_classifier.py +6 -0
- oscura/analyzers/patterns/__init__.py +66 -0
- oscura/analyzers/power/basic.py +3 -3
- oscura/analyzers/power/soa.py +1 -1
- oscura/analyzers/power/switching.py +3 -3
- oscura/analyzers/signal_classification.py +529 -0
- oscura/analyzers/signal_integrity/sparams.py +3 -3
- oscura/analyzers/statistics/basic.py +10 -7
- oscura/analyzers/validation.py +1 -1
- oscura/analyzers/waveform/measurements.py +200 -156
- oscura/analyzers/waveform/measurements_with_uncertainty.py +91 -35
- oscura/analyzers/waveform/spectral.py +182 -84
- oscura/api/dsl/commands.py +15 -6
- oscura/api/server/templates/base.html +137 -146
- oscura/api/server/templates/export.html +84 -110
- oscura/api/server/templates/home.html +248 -267
- oscura/api/server/templates/protocols.html +44 -48
- oscura/api/server/templates/reports.html +27 -35
- oscura/api/server/templates/session_detail.html +68 -78
- oscura/api/server/templates/sessions.html +62 -72
- oscura/api/server/templates/waveforms.html +54 -64
- oscura/automotive/__init__.py +1 -1
- oscura/automotive/can/session.py +1 -1
- oscura/automotive/dbc/generator.py +638 -23
- oscura/automotive/dtc/data.json +17 -102
- oscura/automotive/flexray/fibex.py +9 -1
- oscura/automotive/uds/decoder.py +99 -6
- oscura/cli/analyze.py +8 -2
- oscura/cli/batch.py +36 -5
- oscura/cli/characterize.py +18 -4
- oscura/cli/export.py +47 -5
- oscura/cli/main.py +2 -0
- oscura/cli/onboarding/wizard.py +10 -6
- oscura/cli/pipeline.py +585 -0
- oscura/cli/visualize.py +6 -4
- oscura/convenience.py +400 -32
- oscura/core/measurement_result.py +286 -0
- oscura/core/progress.py +1 -1
- oscura/core/schemas/device_mapping.json +2 -8
- oscura/core/schemas/packet_format.json +4 -24
- oscura/core/schemas/protocol_definition.json +2 -12
- oscura/core/types.py +232 -239
- oscura/correlation/multi_protocol.py +1 -1
- oscura/export/legacy/__init__.py +11 -0
- oscura/export/legacy/wav.py +75 -0
- oscura/exporters/__init__.py +19 -0
- oscura/exporters/wireshark.py +809 -0
- oscura/hardware/acquisition/file.py +5 -19
- oscura/hardware/acquisition/saleae.py +10 -10
- oscura/hardware/acquisition/socketcan.py +4 -6
- oscura/hardware/acquisition/synthetic.py +1 -5
- oscura/hardware/acquisition/visa.py +6 -6
- oscura/hardware/security/side_channel_detector.py +5 -508
- oscura/inference/message_format.py +686 -1
- oscura/jupyter/display.py +2 -2
- oscura/jupyter/magic.py +3 -3
- oscura/loaders/__init__.py +17 -12
- oscura/loaders/binary.py +1 -1
- oscura/loaders/chipwhisperer.py +1 -2
- oscura/loaders/configurable.py +1 -1
- oscura/loaders/csv_loader.py +2 -2
- oscura/loaders/hdf5_loader.py +1 -1
- oscura/loaders/lazy.py +6 -1
- oscura/loaders/mmap_loader.py +0 -1
- oscura/loaders/numpy_loader.py +8 -7
- oscura/loaders/preprocessing.py +3 -5
- oscura/loaders/rigol.py +21 -7
- oscura/loaders/sigrok.py +2 -5
- oscura/loaders/tdms.py +3 -2
- oscura/loaders/tektronix.py +38 -32
- oscura/loaders/tss.py +20 -27
- oscura/loaders/validation.py +17 -10
- oscura/loaders/vcd.py +13 -8
- oscura/loaders/wav.py +1 -6
- oscura/pipeline/__init__.py +76 -0
- oscura/pipeline/handlers/__init__.py +165 -0
- oscura/pipeline/handlers/analyzers.py +1045 -0
- oscura/pipeline/handlers/decoders.py +899 -0
- oscura/pipeline/handlers/exporters.py +1103 -0
- oscura/pipeline/handlers/filters.py +891 -0
- oscura/pipeline/handlers/loaders.py +640 -0
- oscura/pipeline/handlers/transforms.py +768 -0
- oscura/reporting/formatting/measurements.py +55 -14
- oscura/reporting/templates/enhanced/protocol_re.html +504 -503
- oscura/sessions/legacy.py +49 -1
- oscura/side_channel/__init__.py +38 -57
- oscura/utils/builders/signal_builder.py +5 -5
- oscura/utils/comparison/compare.py +7 -9
- oscura/utils/comparison/golden.py +1 -1
- oscura/utils/filtering/convenience.py +2 -2
- oscura/utils/math/arithmetic.py +38 -62
- oscura/utils/math/interpolation.py +20 -20
- oscura/utils/pipeline/__init__.py +4 -17
- oscura/utils/progressive.py +1 -4
- oscura/utils/triggering/edge.py +1 -1
- oscura/utils/triggering/pattern.py +2 -2
- oscura/utils/triggering/pulse.py +2 -2
- oscura/utils/triggering/window.py +3 -3
- oscura/validation/hil_testing.py +11 -11
- oscura/visualization/__init__.py +46 -284
- oscura/visualization/batch.py +72 -433
- oscura/visualization/plot.py +542 -53
- oscura/visualization/styles.py +184 -318
- oscura/workflows/batch/advanced.py +1 -1
- oscura/workflows/batch/aggregate.py +12 -9
- oscura/workflows/complete_re.py +251 -23
- oscura/workflows/digital.py +27 -4
- oscura/workflows/multi_trace.py +136 -17
- oscura/workflows/waveform.py +11 -6
- oscura-0.11.0.dist-info/METADATA +460 -0
- {oscura-0.8.0.dist-info → oscura-0.11.0.dist-info}/RECORD +120 -145
- oscura/side_channel/dpa.py +0 -1025
- oscura/utils/optimization/__init__.py +0 -19
- oscura/utils/optimization/parallel.py +0 -443
- oscura/utils/optimization/search.py +0 -532
- oscura/utils/pipeline/base.py +0 -338
- oscura/utils/pipeline/composition.py +0 -248
- oscura/utils/pipeline/parallel.py +0 -449
- oscura/utils/pipeline/pipeline.py +0 -375
- oscura/utils/search/__init__.py +0 -16
- oscura/utils/search/anomaly.py +0 -424
- oscura/utils/search/context.py +0 -294
- oscura/utils/search/pattern.py +0 -288
- oscura/utils/storage/__init__.py +0 -61
- oscura/utils/storage/database.py +0 -1166
- oscura/visualization/accessibility.py +0 -526
- oscura/visualization/annotations.py +0 -371
- oscura/visualization/axis_scaling.py +0 -305
- oscura/visualization/colors.py +0 -451
- oscura/visualization/digital.py +0 -436
- oscura/visualization/eye.py +0 -571
- oscura/visualization/histogram.py +0 -281
- oscura/visualization/interactive.py +0 -1035
- oscura/visualization/jitter.py +0 -1042
- oscura/visualization/keyboard.py +0 -394
- oscura/visualization/layout.py +0 -400
- oscura/visualization/optimization.py +0 -1079
- oscura/visualization/palettes.py +0 -446
- oscura/visualization/power.py +0 -508
- oscura/visualization/power_extended.py +0 -955
- oscura/visualization/presets.py +0 -469
- oscura/visualization/protocols.py +0 -1246
- oscura/visualization/render.py +0 -223
- oscura/visualization/rendering.py +0 -444
- oscura/visualization/reverse_engineering.py +0 -838
- oscura/visualization/signal_integrity.py +0 -989
- oscura/visualization/specialized.py +0 -643
- oscura/visualization/spectral.py +0 -1226
- oscura/visualization/thumbnails.py +0 -340
- oscura/visualization/time_axis.py +0 -351
- oscura/visualization/waveform.py +0 -454
- oscura-0.8.0.dist-info/METADATA +0 -661
- {oscura-0.8.0.dist-info → oscura-0.11.0.dist-info}/WHEEL +0 -0
- {oscura-0.8.0.dist-info → oscura-0.11.0.dist-info}/entry_points.txt +0 -0
- {oscura-0.8.0.dist-info → oscura-0.11.0.dist-info}/licenses/LICENSE +0 -0
oscura/utils/search/pattern.py
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
"""Pattern search in digital traces.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
This module provides efficient bit pattern matching in digital signals
|
|
5
|
-
with wildcard support via mask parameter.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from typing import cast
|
|
9
|
-
|
|
10
|
-
import numpy as np
|
|
11
|
-
from numpy.typing import NDArray
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def find_pattern(
|
|
15
|
-
trace: NDArray[np.float64] | NDArray[np.uint8],
|
|
16
|
-
pattern: int | NDArray[np.uint8],
|
|
17
|
-
mask: int | NDArray[np.uint8] | None = None,
|
|
18
|
-
*,
|
|
19
|
-
threshold: float | None = None,
|
|
20
|
-
min_spacing: int = 1,
|
|
21
|
-
) -> list[tuple[int, NDArray[np.uint8]]]:
|
|
22
|
-
"""Find occurrences of bit patterns in digital traces.
|
|
23
|
-
|
|
24
|
-
: Pattern search with wildcard support via mask.
|
|
25
|
-
Works on both raw analog traces (with threshold) and decoded digital data.
|
|
26
|
-
|
|
27
|
-
Args:
|
|
28
|
-
trace: Input trace array. If analog (float), threshold is required.
|
|
29
|
-
If already digital (uint8), threshold is ignored.
|
|
30
|
-
pattern: Bit pattern to search for. Can be:
|
|
31
|
-
- Integer: e.g., 0b10101010 (8-bit pattern)
|
|
32
|
-
- Array: sequence of bytes to match
|
|
33
|
-
mask: Optional mask for wildcard matching. Bits set to 0 in mask
|
|
34
|
-
are "don't care" positions. Can be:
|
|
35
|
-
- Integer: e.g., 0xFF (all bits matter)
|
|
36
|
-
- Array: per-byte masks
|
|
37
|
-
If None, all bits must match (equivalent to all 1s).
|
|
38
|
-
threshold: Threshold for converting analog to digital (required if
|
|
39
|
-
trace is analog). Typically mid-level of logic family.
|
|
40
|
-
min_spacing: Minimum samples between detected patterns to avoid
|
|
41
|
-
overlapping matches (default: 1)
|
|
42
|
-
|
|
43
|
-
Returns:
|
|
44
|
-
List of (index, match) tuples where:
|
|
45
|
-
- index: Starting sample index of the pattern
|
|
46
|
-
- match: The actual matched bit sequence as uint8 array
|
|
47
|
-
|
|
48
|
-
Raises:
|
|
49
|
-
ValueError: If analog trace provided without threshold
|
|
50
|
-
ValueError: If pattern is empty
|
|
51
|
-
|
|
52
|
-
Examples:
|
|
53
|
-
>>> # Find 0xAA pattern in analog trace
|
|
54
|
-
>>> import numpy as np
|
|
55
|
-
>>> trace = np.array([0, 1, 0, 1, 0, 1, 0, 1, 0, 0])
|
|
56
|
-
>>> matches = find_pattern(trace, 0b10101010, threshold=0.5)
|
|
57
|
-
>>> print(f"Found {len(matches)} matches")
|
|
58
|
-
|
|
59
|
-
>>> # Wildcard search: find 0b1010xxxx (x = don't care)
|
|
60
|
-
>>> pattern = 0b10100000
|
|
61
|
-
>>> mask = 0b11110000 # Only upper 4 bits matter
|
|
62
|
-
>>> matches = find_pattern(trace, pattern, mask, threshold=0.5)
|
|
63
|
-
|
|
64
|
-
>>> # Search in already-decoded digital data
|
|
65
|
-
>>> digital = np.array([0xAA, 0x55, 0xAA, 0x00], dtype=np.uint8)
|
|
66
|
-
>>> matches = find_pattern(digital, 0xAA)
|
|
67
|
-
|
|
68
|
-
Notes:
|
|
69
|
-
- For analog traces, values >= threshold are interpreted as '1'
|
|
70
|
-
- Mask bits: 1 = must match, 0 = don't care
|
|
71
|
-
- Overlapping patterns can be filtered with min_spacing > 1
|
|
72
|
-
- Returns empty list if no matches found
|
|
73
|
-
|
|
74
|
-
References:
|
|
75
|
-
SRCH-001: Pattern Search
|
|
76
|
-
"""
|
|
77
|
-
if trace.size == 0:
|
|
78
|
-
return []
|
|
79
|
-
|
|
80
|
-
# Phase 1: Input normalization
|
|
81
|
-
pattern_arr = _normalize_pattern(pattern)
|
|
82
|
-
mask_arr = _normalize_mask(mask, pattern_arr)
|
|
83
|
-
|
|
84
|
-
# Phase 2: Convert trace to digital format
|
|
85
|
-
digital_packed = _convert_trace_to_digital(trace, threshold)
|
|
86
|
-
|
|
87
|
-
if digital_packed.size < pattern_arr.size:
|
|
88
|
-
return []
|
|
89
|
-
|
|
90
|
-
# Phase 3: Sliding window search with mask
|
|
91
|
-
return _sliding_window_search(digital_packed, pattern_arr, mask_arr, min_spacing)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def _normalize_pattern(pattern: int | NDArray[np.uint8]) -> NDArray[np.uint8]:
|
|
95
|
-
"""Normalize pattern input to numpy array.
|
|
96
|
-
|
|
97
|
-
Args:
|
|
98
|
-
pattern: Pattern as integer or array.
|
|
99
|
-
|
|
100
|
-
Returns:
|
|
101
|
-
Pattern as uint8 numpy array.
|
|
102
|
-
|
|
103
|
-
Raises:
|
|
104
|
-
ValueError: If pattern is negative or empty.
|
|
105
|
-
|
|
106
|
-
Example:
|
|
107
|
-
>>> _normalize_pattern(0xAA)
|
|
108
|
-
array([170], dtype=uint8)
|
|
109
|
-
>>> _normalize_pattern(0x1234)
|
|
110
|
-
array([18, 52], dtype=uint8)
|
|
111
|
-
"""
|
|
112
|
-
if isinstance(pattern, int):
|
|
113
|
-
if pattern < 0:
|
|
114
|
-
raise ValueError("Pattern must be non-negative")
|
|
115
|
-
# Convert to byte array (variable length based on value)
|
|
116
|
-
pattern_bytes = []
|
|
117
|
-
if pattern == 0:
|
|
118
|
-
pattern_bytes = [0]
|
|
119
|
-
else:
|
|
120
|
-
temp = pattern
|
|
121
|
-
while temp > 0:
|
|
122
|
-
pattern_bytes.insert(0, temp & 0xFF)
|
|
123
|
-
temp >>= 8
|
|
124
|
-
pattern_arr = np.array(pattern_bytes, dtype=np.uint8)
|
|
125
|
-
else:
|
|
126
|
-
pattern_arr = np.asarray(pattern, dtype=np.uint8)
|
|
127
|
-
|
|
128
|
-
if pattern_arr.size == 0:
|
|
129
|
-
raise ValueError("Pattern cannot be empty")
|
|
130
|
-
|
|
131
|
-
return pattern_arr
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def _normalize_mask(
|
|
135
|
-
mask: int | NDArray[np.uint8] | None, pattern_arr: NDArray[np.uint8]
|
|
136
|
-
) -> NDArray[np.uint8]:
|
|
137
|
-
"""Normalize mask input to numpy array matching pattern length.
|
|
138
|
-
|
|
139
|
-
Args:
|
|
140
|
-
mask: Mask as integer, array, or None.
|
|
141
|
-
pattern_arr: Pattern array to match length to.
|
|
142
|
-
|
|
143
|
-
Returns:
|
|
144
|
-
Mask as uint8 numpy array with same length as pattern.
|
|
145
|
-
|
|
146
|
-
Raises:
|
|
147
|
-
ValueError: If mask and pattern have different lengths.
|
|
148
|
-
|
|
149
|
-
Example:
|
|
150
|
-
>>> pattern = np.array([0xAA, 0x55], dtype=np.uint8)
|
|
151
|
-
>>> _normalize_mask(0xFF, pattern)
|
|
152
|
-
array([255, 255], dtype=uint8)
|
|
153
|
-
>>> _normalize_mask(None, pattern)
|
|
154
|
-
array([255, 255], dtype=uint8)
|
|
155
|
-
"""
|
|
156
|
-
if mask is not None:
|
|
157
|
-
if isinstance(mask, int):
|
|
158
|
-
mask_bytes: list[int] = []
|
|
159
|
-
temp = mask
|
|
160
|
-
# Match pattern length
|
|
161
|
-
for _ in range(len(pattern_arr)):
|
|
162
|
-
mask_bytes.insert(0, temp & 0xFF)
|
|
163
|
-
temp >>= 8
|
|
164
|
-
mask_arr = np.array(mask_bytes, dtype=np.uint8)
|
|
165
|
-
else:
|
|
166
|
-
mask_arr = np.asarray(mask, dtype=np.uint8)
|
|
167
|
-
|
|
168
|
-
# Ensure mask and pattern have same length
|
|
169
|
-
if mask_arr.size != pattern_arr.size:
|
|
170
|
-
raise ValueError("Mask and pattern must have same length")
|
|
171
|
-
else:
|
|
172
|
-
# Default: all bits matter
|
|
173
|
-
mask_arr = np.full(pattern_arr.size, 0xFF, dtype=np.uint8)
|
|
174
|
-
|
|
175
|
-
return mask_arr
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
def _convert_trace_to_digital(
|
|
179
|
-
trace: NDArray[np.float64] | NDArray[np.uint8], threshold: float | None
|
|
180
|
-
) -> NDArray[np.uint8]:
|
|
181
|
-
"""Convert trace to digital packed format.
|
|
182
|
-
|
|
183
|
-
If trace is already digital (uint8), returns as-is.
|
|
184
|
-
If trace is analog (float), converts using threshold and packs bits.
|
|
185
|
-
|
|
186
|
-
Args:
|
|
187
|
-
trace: Input trace (analog or digital).
|
|
188
|
-
threshold: Threshold for analog-to-digital conversion.
|
|
189
|
-
|
|
190
|
-
Returns:
|
|
191
|
-
Digital trace as packed uint8 array.
|
|
192
|
-
|
|
193
|
-
Raises:
|
|
194
|
-
ValueError: If analog trace provided without threshold.
|
|
195
|
-
|
|
196
|
-
Example:
|
|
197
|
-
>>> analog = np.array([1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0])
|
|
198
|
-
>>> _convert_trace_to_digital(analog, 0.5)
|
|
199
|
-
array([170], dtype=uint8) # 0b10101010 = 0xAA
|
|
200
|
-
"""
|
|
201
|
-
if trace.dtype != np.uint8:
|
|
202
|
-
if threshold is None:
|
|
203
|
-
raise ValueError(
|
|
204
|
-
"Threshold required for analog trace conversion. "
|
|
205
|
-
"Provide threshold parameter or pre-convert to digital."
|
|
206
|
-
)
|
|
207
|
-
# Simple threshold conversion: >= threshold is 1
|
|
208
|
-
digital = (trace >= threshold).astype(np.uint8)
|
|
209
|
-
# Pack bits into bytes (8 samples per byte)
|
|
210
|
-
# Pad to multiple of 8
|
|
211
|
-
n_pad = (8 - len(digital) % 8) % 8
|
|
212
|
-
if n_pad:
|
|
213
|
-
digital = np.pad(digital, (0, n_pad), constant_values=0)
|
|
214
|
-
# Pack bits
|
|
215
|
-
digital_packed: NDArray[np.uint8] = np.packbits(digital, bitorder="big")
|
|
216
|
-
else:
|
|
217
|
-
digital_packed = cast("NDArray[np.uint8]", trace)
|
|
218
|
-
|
|
219
|
-
return digital_packed
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
def _sliding_window_search(
|
|
223
|
-
digital_packed: NDArray[np.uint8],
|
|
224
|
-
pattern_arr: NDArray[np.uint8],
|
|
225
|
-
mask_arr: NDArray[np.uint8],
|
|
226
|
-
min_spacing: int,
|
|
227
|
-
) -> list[tuple[int, NDArray[np.uint8]]]:
|
|
228
|
-
"""Perform sliding window pattern matching with mask.
|
|
229
|
-
|
|
230
|
-
Args:
|
|
231
|
-
digital_packed: Digital trace data.
|
|
232
|
-
pattern_arr: Pattern to search for.
|
|
233
|
-
mask_arr: Mask for wildcard matching.
|
|
234
|
-
min_spacing: Minimum spacing between matches.
|
|
235
|
-
|
|
236
|
-
Returns:
|
|
237
|
-
List of (index, matched_data) tuples.
|
|
238
|
-
|
|
239
|
-
Example:
|
|
240
|
-
>>> data = np.array([0xAA, 0x55, 0xAA], dtype=np.uint8)
|
|
241
|
-
>>> pattern = np.array([0xAA], dtype=np.uint8)
|
|
242
|
-
>>> mask = np.array([0xFF], dtype=np.uint8)
|
|
243
|
-
>>> _sliding_window_search(data, pattern, mask, 1)
|
|
244
|
-
[(0, array([170], dtype=uint8)), (2, array([170], dtype=uint8))]
|
|
245
|
-
"""
|
|
246
|
-
matches: list[tuple[int, NDArray[np.uint8]]] = []
|
|
247
|
-
i = 0
|
|
248
|
-
|
|
249
|
-
while i <= len(digital_packed) - len(pattern_arr):
|
|
250
|
-
window = digital_packed[i : i + len(pattern_arr)]
|
|
251
|
-
|
|
252
|
-
# Apply mask and compare
|
|
253
|
-
if _matches_pattern(window, pattern_arr, mask_arr):
|
|
254
|
-
# NECESSARY COPY: window is a numpy view that gets reused.
|
|
255
|
-
# Without .copy(), all matches would reference same memory location.
|
|
256
|
-
# Could optimize: store indices + lazy evaluation instead of copies.
|
|
257
|
-
matches.append((i, window.copy()))
|
|
258
|
-
# Skip ahead by min_spacing to avoid overlapping matches
|
|
259
|
-
i += max(1, min_spacing)
|
|
260
|
-
else:
|
|
261
|
-
i += 1
|
|
262
|
-
|
|
263
|
-
return matches
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
def _matches_pattern(
|
|
267
|
-
window: NDArray[np.uint8], pattern: NDArray[np.uint8], mask: NDArray[np.uint8]
|
|
268
|
-
) -> bool:
|
|
269
|
-
"""Check if window matches pattern with mask.
|
|
270
|
-
|
|
271
|
-
Args:
|
|
272
|
-
window: Data window to check.
|
|
273
|
-
pattern: Pattern to match.
|
|
274
|
-
mask: Mask for wildcard positions.
|
|
275
|
-
|
|
276
|
-
Returns:
|
|
277
|
-
True if window matches pattern under mask.
|
|
278
|
-
|
|
279
|
-
Example:
|
|
280
|
-
>>> window = np.array([0xA5], dtype=np.uint8)
|
|
281
|
-
>>> pattern = np.array([0xA0], dtype=np.uint8)
|
|
282
|
-
>>> mask = np.array([0xF0], dtype=np.uint8)
|
|
283
|
-
>>> _matches_pattern(window, pattern, mask)
|
|
284
|
-
True
|
|
285
|
-
"""
|
|
286
|
-
masked_window = window & mask
|
|
287
|
-
masked_pattern = pattern & mask
|
|
288
|
-
return bool(np.array_equal(masked_window, masked_pattern))
|
oscura/utils/storage/__init__.py
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
"""Storage backends for persisting analysis results.
|
|
2
|
-
|
|
3
|
-
This module provides database backends for storing and querying
|
|
4
|
-
reverse engineering session data, protocol analysis results,
|
|
5
|
-
and decoded messages.
|
|
6
|
-
|
|
7
|
-
Example:
|
|
8
|
-
>>> from oscura.utils.storage import DatabaseBackend, DatabaseConfig
|
|
9
|
-
>>>
|
|
10
|
-
>>> # Create database backend
|
|
11
|
-
>>> config = DatabaseConfig(url="sqlite:///analysis.db")
|
|
12
|
-
>>> db = DatabaseBackend(config)
|
|
13
|
-
>>>
|
|
14
|
-
>>> # Create project and session
|
|
15
|
-
>>> project_id = db.create_project("IoT Device RE", "Unknown protocol analysis")
|
|
16
|
-
>>> session_id = db.create_session(project_id, "blackbox", {"capture": "device.bin"})
|
|
17
|
-
>>>
|
|
18
|
-
>>> # Store protocol analysis
|
|
19
|
-
>>> protocol_id = db.store_protocol(
|
|
20
|
-
... session_id,
|
|
21
|
-
... name="IoT Protocol",
|
|
22
|
-
... spec_json={"fields": [...]},
|
|
23
|
-
... confidence=0.85
|
|
24
|
-
... )
|
|
25
|
-
>>>
|
|
26
|
-
>>> # Store decoded messages
|
|
27
|
-
>>> db.store_message(protocol_id, timestamp=0.0, data=b"\\xaa\\x55", decoded={"id": 1})
|
|
28
|
-
>>>
|
|
29
|
-
>>> # Query results
|
|
30
|
-
>>> protocols = db.find_protocols(min_confidence=0.8)
|
|
31
|
-
>>> sessions = db.get_sessions(project_id)
|
|
32
|
-
>>> messages = db.query_messages(protocol_id, time_range=(0.0, 1.0))
|
|
33
|
-
|
|
34
|
-
Available classes:
|
|
35
|
-
- DatabaseConfig: Configuration dataclass
|
|
36
|
-
- DatabaseBackend: Main database interface
|
|
37
|
-
- Project/Session/Protocol/Message: Result dataclasses
|
|
38
|
-
- QueryResult: Paginated query results
|
|
39
|
-
"""
|
|
40
|
-
|
|
41
|
-
from oscura.utils.storage.database import (
|
|
42
|
-
AnalysisResult,
|
|
43
|
-
DatabaseBackend,
|
|
44
|
-
DatabaseConfig,
|
|
45
|
-
Message,
|
|
46
|
-
Project,
|
|
47
|
-
Protocol,
|
|
48
|
-
QueryResult,
|
|
49
|
-
Session,
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
__all__ = [
|
|
53
|
-
"AnalysisResult",
|
|
54
|
-
"DatabaseBackend",
|
|
55
|
-
"DatabaseConfig",
|
|
56
|
-
"Message",
|
|
57
|
-
"Project",
|
|
58
|
-
"Protocol",
|
|
59
|
-
"QueryResult",
|
|
60
|
-
"Session",
|
|
61
|
-
]
|