oscura 0.6.0__py3-none-any.whl → 0.8.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 +1 -1
- oscura/analyzers/eye/__init__.py +5 -1
- oscura/analyzers/eye/generation.py +501 -0
- oscura/analyzers/jitter/__init__.py +6 -6
- oscura/analyzers/jitter/timing.py +419 -0
- oscura/analyzers/patterns/__init__.py +28 -0
- oscura/analyzers/patterns/reverse_engineering.py +991 -0
- oscura/analyzers/power/__init__.py +35 -12
- oscura/analyzers/statistics/__init__.py +4 -0
- oscura/analyzers/statistics/basic.py +149 -0
- oscura/analyzers/statistics/correlation.py +47 -6
- oscura/analyzers/waveform/__init__.py +2 -0
- oscura/analyzers/waveform/measurements.py +145 -23
- oscura/analyzers/waveform/spectral.py +361 -8
- oscura/automotive/__init__.py +1 -1
- oscura/core/config/loader.py +0 -1
- oscura/core/types.py +108 -0
- oscura/loaders/__init__.py +12 -4
- oscura/loaders/tss.py +456 -0
- oscura/reporting/__init__.py +88 -1
- oscura/reporting/automation.py +348 -0
- oscura/reporting/citations.py +374 -0
- oscura/reporting/core.py +54 -0
- oscura/reporting/formatting/__init__.py +11 -0
- oscura/reporting/formatting/measurements.py +279 -0
- oscura/reporting/html.py +57 -0
- oscura/reporting/interpretation.py +431 -0
- oscura/reporting/summary.py +329 -0
- oscura/reporting/visualization.py +542 -0
- oscura/visualization/__init__.py +2 -1
- oscura/visualization/batch.py +521 -0
- oscura/workflows/__init__.py +2 -0
- oscura/workflows/waveform.py +783 -0
- {oscura-0.6.0.dist-info → oscura-0.8.0.dist-info}/METADATA +37 -19
- {oscura-0.6.0.dist-info → oscura-0.8.0.dist-info}/RECORD +38 -26
- {oscura-0.6.0.dist-info → oscura-0.8.0.dist-info}/WHEEL +0 -0
- {oscura-0.6.0.dist-info → oscura-0.8.0.dist-info}/entry_points.txt +0 -0
- {oscura-0.6.0.dist-info → oscura-0.8.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
"""Jitter timing measurements.
|
|
2
|
+
|
|
3
|
+
This module provides cycle-to-cycle jitter, period jitter, and
|
|
4
|
+
duty cycle distortion measurements per IEEE 2414-2020.
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> from oscura.analyzers.jitter.timing import cycle_to_cycle_jitter
|
|
9
|
+
>>> c2c = cycle_to_cycle_jitter(periods)
|
|
10
|
+
>>> print(f"C2C RMS: {c2c.c2c_rms * 1e12:.2f} ps")
|
|
11
|
+
|
|
12
|
+
References:
|
|
13
|
+
IEEE 2414-2020: Standard for Jitter and Phase Noise
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from typing import TYPE_CHECKING
|
|
20
|
+
|
|
21
|
+
import numpy as np
|
|
22
|
+
|
|
23
|
+
from oscura.core.exceptions import InsufficientDataError
|
|
24
|
+
from oscura.core.types import DigitalTrace, WaveformTrace
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
from numpy.typing import NDArray
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class CycleJitterResult:
|
|
32
|
+
"""Result of cycle-to-cycle or period jitter measurement.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
c2c_rms: Cycle-to-cycle jitter RMS in seconds.
|
|
36
|
+
c2c_pp: Cycle-to-cycle jitter peak-to-peak in seconds.
|
|
37
|
+
c2c_values: Array of individual C2C jitter values.
|
|
38
|
+
period_mean: Mean period in seconds.
|
|
39
|
+
period_std: Standard deviation of periods in seconds.
|
|
40
|
+
n_cycles: Number of cycles analyzed.
|
|
41
|
+
histogram: Histogram of C2C values.
|
|
42
|
+
bin_centers: Bin centers for histogram.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
c2c_rms: float
|
|
46
|
+
c2c_pp: float
|
|
47
|
+
c2c_values: NDArray[np.float64]
|
|
48
|
+
period_mean: float
|
|
49
|
+
period_std: float
|
|
50
|
+
n_cycles: int
|
|
51
|
+
histogram: NDArray[np.float64] | None = None
|
|
52
|
+
bin_centers: NDArray[np.float64] | None = None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class DutyCycleDistortionResult:
|
|
57
|
+
"""Result of duty cycle distortion measurement.
|
|
58
|
+
|
|
59
|
+
Attributes:
|
|
60
|
+
dcd_seconds: DCD in seconds.
|
|
61
|
+
dcd_percent: DCD as percentage of period.
|
|
62
|
+
mean_high_time: Mean high time in seconds.
|
|
63
|
+
mean_low_time: Mean low time in seconds.
|
|
64
|
+
duty_cycle: Actual duty cycle as fraction (0.0 to 1.0).
|
|
65
|
+
period: Mean period in seconds.
|
|
66
|
+
n_cycles: Number of cycles analyzed.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
dcd_seconds: float
|
|
70
|
+
dcd_percent: float
|
|
71
|
+
mean_high_time: float
|
|
72
|
+
mean_low_time: float
|
|
73
|
+
duty_cycle: float
|
|
74
|
+
period: float
|
|
75
|
+
n_cycles: int
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def tie_from_edges(
|
|
79
|
+
edge_timestamps: NDArray[np.float64],
|
|
80
|
+
nominal_period: float | None = None,
|
|
81
|
+
) -> NDArray[np.float64]:
|
|
82
|
+
"""Calculate Time Interval Error from edge timestamps.
|
|
83
|
+
|
|
84
|
+
TIE is the deviation of each edge from its ideal position
|
|
85
|
+
based on the recovered clock period.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
edge_timestamps: Array of edge timestamps in seconds.
|
|
89
|
+
nominal_period: Expected period (computed from data if None).
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Array of TIE values in seconds.
|
|
93
|
+
|
|
94
|
+
Example:
|
|
95
|
+
>>> tie = tie_from_edges(rising_edges, nominal_period=1e-9)
|
|
96
|
+
>>> print(f"TIE range: {np.ptp(tie) * 1e12:.2f} ps")
|
|
97
|
+
|
|
98
|
+
References:
|
|
99
|
+
IEEE 2414-2020 Section 4.2: Time Interval Error Definition
|
|
100
|
+
"""
|
|
101
|
+
if len(edge_timestamps) < 3:
|
|
102
|
+
return np.array([], dtype=np.float64)
|
|
103
|
+
|
|
104
|
+
# Calculate actual periods
|
|
105
|
+
periods = np.diff(edge_timestamps)
|
|
106
|
+
|
|
107
|
+
# Use mean period if nominal not provided
|
|
108
|
+
if nominal_period is None:
|
|
109
|
+
nominal_period = np.mean(periods)
|
|
110
|
+
|
|
111
|
+
# Calculate ideal edge positions
|
|
112
|
+
n_edges = len(edge_timestamps)
|
|
113
|
+
start_time = edge_timestamps[0]
|
|
114
|
+
ideal_positions = start_time + np.arange(n_edges) * nominal_period
|
|
115
|
+
|
|
116
|
+
# TIE is actual - ideal
|
|
117
|
+
tie: NDArray[np.float64] = edge_timestamps - ideal_positions
|
|
118
|
+
|
|
119
|
+
return tie
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def cycle_to_cycle_jitter(
|
|
123
|
+
periods: NDArray[np.float64],
|
|
124
|
+
*,
|
|
125
|
+
include_histogram: bool = True,
|
|
126
|
+
n_bins: int = 50,
|
|
127
|
+
) -> CycleJitterResult:
|
|
128
|
+
"""Measure cycle-to-cycle jitter for clock quality analysis.
|
|
129
|
+
|
|
130
|
+
Cycle-to-cycle jitter measures the variation in period from
|
|
131
|
+
one clock cycle to the next: C2C[n] = |Period[n] - Period[n-1]|
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
periods: Array of measured clock periods in seconds.
|
|
135
|
+
include_histogram: Include histogram in result.
|
|
136
|
+
n_bins: Number of histogram bins.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
CycleJitterResult with C2C jitter statistics.
|
|
140
|
+
|
|
141
|
+
Raises:
|
|
142
|
+
InsufficientDataError: If fewer than 3 periods provided.
|
|
143
|
+
|
|
144
|
+
Example:
|
|
145
|
+
>>> c2c = cycle_to_cycle_jitter(periods)
|
|
146
|
+
>>> print(f"C2C: {c2c.c2c_rms * 1e12:.2f} ps RMS")
|
|
147
|
+
|
|
148
|
+
References:
|
|
149
|
+
IEEE 2414-2020 Section 5.3: Cycle-to-Cycle Jitter
|
|
150
|
+
"""
|
|
151
|
+
if len(periods) < 3:
|
|
152
|
+
raise InsufficientDataError(
|
|
153
|
+
"Cycle-to-cycle jitter requires at least 3 periods",
|
|
154
|
+
required=3,
|
|
155
|
+
available=len(periods),
|
|
156
|
+
analysis_type="cycle_to_cycle_jitter",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
# Remove NaN values
|
|
160
|
+
valid_periods = periods[~np.isnan(periods)]
|
|
161
|
+
|
|
162
|
+
if len(valid_periods) < 3:
|
|
163
|
+
raise InsufficientDataError(
|
|
164
|
+
"Cycle-to-cycle jitter requires at least 3 valid periods",
|
|
165
|
+
required=3,
|
|
166
|
+
available=len(valid_periods),
|
|
167
|
+
analysis_type="cycle_to_cycle_jitter",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Calculate cycle-to-cycle differences
|
|
171
|
+
c2c_values = np.abs(np.diff(valid_periods))
|
|
172
|
+
|
|
173
|
+
# Statistics
|
|
174
|
+
c2c_rms = float(np.sqrt(np.mean(c2c_values**2)))
|
|
175
|
+
c2c_pp = float(np.max(c2c_values) - np.min(c2c_values))
|
|
176
|
+
period_mean = float(np.mean(valid_periods))
|
|
177
|
+
period_std = float(np.std(valid_periods))
|
|
178
|
+
|
|
179
|
+
# Optional histogram
|
|
180
|
+
if include_histogram and len(c2c_values) > 10:
|
|
181
|
+
hist, bin_edges = np.histogram(c2c_values, bins=n_bins, density=True)
|
|
182
|
+
bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2
|
|
183
|
+
else:
|
|
184
|
+
hist = None
|
|
185
|
+
bin_centers = None
|
|
186
|
+
|
|
187
|
+
return CycleJitterResult(
|
|
188
|
+
c2c_rms=c2c_rms,
|
|
189
|
+
c2c_pp=c2c_pp,
|
|
190
|
+
c2c_values=c2c_values,
|
|
191
|
+
period_mean=period_mean,
|
|
192
|
+
period_std=period_std,
|
|
193
|
+
n_cycles=len(valid_periods),
|
|
194
|
+
histogram=hist,
|
|
195
|
+
bin_centers=bin_centers,
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def period_jitter(
|
|
200
|
+
periods: NDArray[np.float64],
|
|
201
|
+
nominal_period: float | None = None,
|
|
202
|
+
) -> CycleJitterResult:
|
|
203
|
+
"""Measure period jitter (deviation from nominal period).
|
|
204
|
+
|
|
205
|
+
Period jitter is the deviation of each period from the ideal
|
|
206
|
+
or nominal period. Unlike C2C jitter, it measures absolute deviation.
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
periods: Array of measured clock periods in seconds.
|
|
210
|
+
nominal_period: Expected period (uses mean if None).
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
CycleJitterResult with period jitter statistics.
|
|
214
|
+
|
|
215
|
+
Raises:
|
|
216
|
+
InsufficientDataError: If fewer than 2 periods provided.
|
|
217
|
+
|
|
218
|
+
Example:
|
|
219
|
+
>>> pj = period_jitter(periods, nominal_period=1e-9)
|
|
220
|
+
>>> print(f"Period jitter: {pj.c2c_rms * 1e12:.2f} ps RMS")
|
|
221
|
+
|
|
222
|
+
References:
|
|
223
|
+
IEEE 2414-2020 Section 5.2: Period Jitter
|
|
224
|
+
"""
|
|
225
|
+
if len(periods) < 2:
|
|
226
|
+
raise InsufficientDataError(
|
|
227
|
+
"Period jitter requires at least 2 periods",
|
|
228
|
+
required=2,
|
|
229
|
+
available=len(periods),
|
|
230
|
+
analysis_type="period_jitter",
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
valid_periods = periods[~np.isnan(periods)]
|
|
234
|
+
|
|
235
|
+
if nominal_period is None:
|
|
236
|
+
nominal_period = np.mean(valid_periods)
|
|
237
|
+
|
|
238
|
+
# Calculate deviations from nominal
|
|
239
|
+
deviations = valid_periods - nominal_period
|
|
240
|
+
|
|
241
|
+
return CycleJitterResult(
|
|
242
|
+
c2c_rms=float(np.std(valid_periods)), # RMS of period variation
|
|
243
|
+
c2c_pp=float(np.max(valid_periods) - np.min(valid_periods)),
|
|
244
|
+
c2c_values=np.abs(deviations),
|
|
245
|
+
period_mean=float(np.mean(valid_periods)),
|
|
246
|
+
period_std=float(np.std(valid_periods)),
|
|
247
|
+
n_cycles=len(valid_periods),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def measure_dcd(
|
|
252
|
+
trace: WaveformTrace | DigitalTrace,
|
|
253
|
+
clock_period: float | None = None,
|
|
254
|
+
*,
|
|
255
|
+
threshold: float = 0.5,
|
|
256
|
+
) -> DutyCycleDistortionResult:
|
|
257
|
+
"""Measure duty cycle distortion.
|
|
258
|
+
|
|
259
|
+
DCD measures the asymmetry between high and low times in a clock signal.
|
|
260
|
+
DCD = |mean_high_time - mean_low_time|
|
|
261
|
+
|
|
262
|
+
Args:
|
|
263
|
+
trace: Input waveform or digital trace.
|
|
264
|
+
clock_period: Expected clock period (computed if None).
|
|
265
|
+
threshold: Threshold level as fraction of amplitude (0.0-1.0).
|
|
266
|
+
|
|
267
|
+
Returns:
|
|
268
|
+
DutyCycleDistortionResult with DCD metrics.
|
|
269
|
+
|
|
270
|
+
Raises:
|
|
271
|
+
InsufficientDataError: If not enough edges found.
|
|
272
|
+
|
|
273
|
+
Example:
|
|
274
|
+
>>> dcd = measure_dcd(clock_trace, clock_period=1e-9)
|
|
275
|
+
>>> print(f"DCD: {dcd.dcd_percent:.1f}%")
|
|
276
|
+
|
|
277
|
+
References:
|
|
278
|
+
IEEE 2414-2020 Section 5.4: Duty Cycle Distortion
|
|
279
|
+
"""
|
|
280
|
+
# Get edge timestamps
|
|
281
|
+
rising_edges, falling_edges = _find_edges(trace, threshold)
|
|
282
|
+
|
|
283
|
+
if len(rising_edges) < 2 or len(falling_edges) < 2:
|
|
284
|
+
raise InsufficientDataError(
|
|
285
|
+
"DCD measurement requires at least 2 rising and 2 falling edges",
|
|
286
|
+
required=4,
|
|
287
|
+
available=len(rising_edges) + len(falling_edges),
|
|
288
|
+
analysis_type="dcd_measurement",
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
# Measure high times (rising to falling)
|
|
292
|
+
high_times = []
|
|
293
|
+
for r_edge in rising_edges:
|
|
294
|
+
# Find next falling edge
|
|
295
|
+
next_falling = falling_edges[falling_edges > r_edge]
|
|
296
|
+
if len(next_falling) > 0:
|
|
297
|
+
high_times.append(next_falling[0] - r_edge)
|
|
298
|
+
|
|
299
|
+
# Measure low times (falling to rising)
|
|
300
|
+
low_times = []
|
|
301
|
+
for f_edge in falling_edges:
|
|
302
|
+
# Find next rising edge
|
|
303
|
+
next_rising = rising_edges[rising_edges > f_edge]
|
|
304
|
+
if len(next_rising) > 0:
|
|
305
|
+
low_times.append(next_rising[0] - f_edge)
|
|
306
|
+
|
|
307
|
+
if len(high_times) < 1 or len(low_times) < 1:
|
|
308
|
+
raise InsufficientDataError(
|
|
309
|
+
"Could not measure high/low times",
|
|
310
|
+
required=2,
|
|
311
|
+
available=0,
|
|
312
|
+
analysis_type="dcd_measurement",
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
mean_high = float(np.mean(high_times))
|
|
316
|
+
mean_low = float(np.mean(low_times))
|
|
317
|
+
|
|
318
|
+
# Calculate DCD
|
|
319
|
+
dcd_seconds = abs(mean_high - mean_low)
|
|
320
|
+
period = mean_high + mean_low
|
|
321
|
+
|
|
322
|
+
if clock_period is None:
|
|
323
|
+
clock_period = period
|
|
324
|
+
|
|
325
|
+
dcd_percent = (dcd_seconds / clock_period) * 100
|
|
326
|
+
duty_cycle = mean_high / period
|
|
327
|
+
|
|
328
|
+
return DutyCycleDistortionResult(
|
|
329
|
+
dcd_seconds=dcd_seconds,
|
|
330
|
+
dcd_percent=dcd_percent,
|
|
331
|
+
mean_high_time=mean_high,
|
|
332
|
+
mean_low_time=mean_low,
|
|
333
|
+
duty_cycle=duty_cycle,
|
|
334
|
+
period=period,
|
|
335
|
+
n_cycles=min(len(high_times), len(low_times)),
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def _find_edges(
|
|
340
|
+
trace: WaveformTrace | DigitalTrace,
|
|
341
|
+
threshold_frac: float,
|
|
342
|
+
) -> tuple[NDArray[np.float64], NDArray[np.float64]]:
|
|
343
|
+
"""Find rising and falling edge timestamps with sub-sample interpolation.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
trace: Input trace.
|
|
347
|
+
threshold_frac: Threshold as fraction of amplitude.
|
|
348
|
+
|
|
349
|
+
Returns:
|
|
350
|
+
Tuple of (rising_edges, falling_edges) arrays in seconds.
|
|
351
|
+
"""
|
|
352
|
+
data = trace.data.astype(np.float64) if isinstance(trace, DigitalTrace) else trace.data
|
|
353
|
+
|
|
354
|
+
sample_rate = trace.metadata.sample_rate
|
|
355
|
+
sample_period = 1.0 / sample_rate
|
|
356
|
+
|
|
357
|
+
if len(data) < 3:
|
|
358
|
+
return np.array([]), np.array([])
|
|
359
|
+
|
|
360
|
+
# Find amplitude levels - use more extreme percentiles for better accuracy
|
|
361
|
+
low = np.percentile(data, 5)
|
|
362
|
+
high = np.percentile(data, 95)
|
|
363
|
+
threshold = low + threshold_frac * (high - low)
|
|
364
|
+
|
|
365
|
+
# Find crossings
|
|
366
|
+
above = data >= threshold
|
|
367
|
+
below = data < threshold
|
|
368
|
+
|
|
369
|
+
rising_indices = np.where(below[:-1] & above[1:])[0]
|
|
370
|
+
falling_indices = np.where(above[:-1] & below[1:])[0]
|
|
371
|
+
|
|
372
|
+
# Convert to timestamps with linear interpolation
|
|
373
|
+
# For a crossing between samples i and i+1:
|
|
374
|
+
# time = i * dt + (threshold - v[i]) / (v[i+1] - v[i]) * dt
|
|
375
|
+
|
|
376
|
+
rising_edges = []
|
|
377
|
+
for idx in rising_indices:
|
|
378
|
+
v1, v2 = data[idx], data[idx + 1]
|
|
379
|
+
dv = v2 - v1
|
|
380
|
+
if abs(dv) > 1e-12:
|
|
381
|
+
# Linear interpolation to find exact crossing time
|
|
382
|
+
frac = (threshold - v1) / dv
|
|
383
|
+
# Clamp to [0, 1] to handle numerical errors
|
|
384
|
+
frac = max(0.0, min(1.0, frac))
|
|
385
|
+
t_offset = frac * sample_period
|
|
386
|
+
else:
|
|
387
|
+
# Values are equal, use midpoint
|
|
388
|
+
t_offset = sample_period / 2
|
|
389
|
+
rising_edges.append(idx * sample_period + t_offset)
|
|
390
|
+
|
|
391
|
+
falling_edges = []
|
|
392
|
+
for idx in falling_indices:
|
|
393
|
+
v1, v2 = data[idx], data[idx + 1]
|
|
394
|
+
dv = v2 - v1
|
|
395
|
+
if abs(dv) > 1e-12:
|
|
396
|
+
# Linear interpolation to find exact crossing time
|
|
397
|
+
frac = (threshold - v1) / dv
|
|
398
|
+
# Clamp to [0, 1] to handle numerical errors
|
|
399
|
+
frac = max(0.0, min(1.0, frac))
|
|
400
|
+
t_offset = frac * sample_period
|
|
401
|
+
else:
|
|
402
|
+
# Values are equal, use midpoint
|
|
403
|
+
t_offset = sample_period / 2
|
|
404
|
+
falling_edges.append(idx * sample_period + t_offset)
|
|
405
|
+
|
|
406
|
+
return (
|
|
407
|
+
np.array(rising_edges, dtype=np.float64),
|
|
408
|
+
np.array(falling_edges, dtype=np.float64),
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
__all__ = [
|
|
413
|
+
"CycleJitterResult",
|
|
414
|
+
"DutyCycleDistortionResult",
|
|
415
|
+
"cycle_to_cycle_jitter",
|
|
416
|
+
"measure_dcd",
|
|
417
|
+
"period_jitter",
|
|
418
|
+
"tie_from_edges",
|
|
419
|
+
]
|
|
@@ -11,11 +11,13 @@ for digital signals and binary data, including:
|
|
|
11
11
|
- Multi-pattern search (Aho-Corasick)
|
|
12
12
|
- Fuzzy/approximate pattern matching
|
|
13
13
|
- Pattern learning and discovery
|
|
14
|
+
- Comprehensive reverse engineering toolkit
|
|
14
15
|
|
|
15
16
|
- RE-PAT-001: Binary Regex Pattern Matching
|
|
16
17
|
- RE-PAT-002: Multi-Pattern Search (Aho-Corasick)
|
|
17
18
|
- RE-PAT-003: Fuzzy Pattern Matching
|
|
18
19
|
- RE-PAT-004: Pattern Learning and Discovery
|
|
20
|
+
- RE-PAT-005: Reverse Engineering Toolkit
|
|
19
21
|
|
|
20
22
|
Author: Oscura Development Team
|
|
21
23
|
"""
|
|
@@ -91,6 +93,20 @@ detect_period_fft = detect_periods_fft
|
|
|
91
93
|
# Motif detection functions (aliases for test compatibility)
|
|
92
94
|
from typing import TYPE_CHECKING, Any, cast
|
|
93
95
|
|
|
96
|
+
# RE-PAT-005: Comprehensive Reverse Engineering Toolkit
|
|
97
|
+
from .reverse_engineering import (
|
|
98
|
+
BinaryAnalysisResult,
|
|
99
|
+
FieldDescriptor,
|
|
100
|
+
ProtocolStructure,
|
|
101
|
+
ReverseEngineer,
|
|
102
|
+
byte_frequency_distribution,
|
|
103
|
+
detect_compressed_regions,
|
|
104
|
+
detect_encrypted_regions,
|
|
105
|
+
entropy_profile,
|
|
106
|
+
search_pattern,
|
|
107
|
+
shannon_entropy,
|
|
108
|
+
sliding_entropy,
|
|
109
|
+
)
|
|
94
110
|
from .sequences import (
|
|
95
111
|
NgramResult,
|
|
96
112
|
RepeatingSequence,
|
|
@@ -233,11 +249,14 @@ def pattern_similarity(pattern1: Any, pattern2: Any) -> float:
|
|
|
233
249
|
__all__ = [
|
|
234
250
|
# RE-PAT-002: Multi-Pattern Search
|
|
235
251
|
"AhoCorasickMatcher",
|
|
252
|
+
# RE-PAT-005: Reverse Engineering Toolkit
|
|
253
|
+
"BinaryAnalysisResult",
|
|
236
254
|
# RE-PAT-001: Binary Regex Pattern Matching
|
|
237
255
|
"BinaryRegex",
|
|
238
256
|
"CandidateSignature",
|
|
239
257
|
"ClusterResult",
|
|
240
258
|
"ClusteringResult",
|
|
259
|
+
"FieldDescriptor",
|
|
241
260
|
"FuzzyMatchResult",
|
|
242
261
|
# RE-PAT-003: Fuzzy Pattern Matching
|
|
243
262
|
"FuzzyMatcher",
|
|
@@ -249,11 +268,14 @@ __all__ = [
|
|
|
249
268
|
"PatternMatchResult",
|
|
250
269
|
"PeriodResult",
|
|
251
270
|
"PeriodicPatternDetector",
|
|
271
|
+
"ProtocolStructure",
|
|
252
272
|
"RepeatingSequence",
|
|
273
|
+
"ReverseEngineer",
|
|
253
274
|
"SignatureDiscovery",
|
|
254
275
|
"StructureHypothesis",
|
|
255
276
|
"analyze_cluster",
|
|
256
277
|
"binary_regex_search",
|
|
278
|
+
"byte_frequency_distribution",
|
|
257
279
|
"cluster_by_edit_distance",
|
|
258
280
|
"cluster_by_hamming",
|
|
259
281
|
"cluster_hierarchical",
|
|
@@ -262,12 +284,15 @@ __all__ = [
|
|
|
262
284
|
"count_pattern_occurrences",
|
|
263
285
|
# Motif detection (compatibility)
|
|
264
286
|
"detect_anomalies",
|
|
287
|
+
"detect_compressed_regions",
|
|
288
|
+
"detect_encrypted_regions",
|
|
265
289
|
"detect_period",
|
|
266
290
|
"detect_period_autocorr",
|
|
267
291
|
"detect_period_fft",
|
|
268
292
|
"detect_periods_autocorr",
|
|
269
293
|
"detect_periods_fft",
|
|
270
294
|
"discover_signatures",
|
|
295
|
+
"entropy_profile",
|
|
271
296
|
"extract_motif",
|
|
272
297
|
"find_approximate_repeats",
|
|
273
298
|
"find_delimiter_candidates",
|
|
@@ -284,5 +309,8 @@ __all__ = [
|
|
|
284
309
|
"learn_patterns_from_data",
|
|
285
310
|
"multi_pattern_search",
|
|
286
311
|
"pattern_similarity",
|
|
312
|
+
"search_pattern",
|
|
313
|
+
"shannon_entropy",
|
|
314
|
+
"sliding_entropy",
|
|
287
315
|
"validate_period",
|
|
288
316
|
]
|