oscura 0.3.0__py3-none-any.whl → 0.4.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.
Files changed (37) hide show
  1. oscura/__init__.py +1 -7
  2. oscura/acquisition/__init__.py +147 -0
  3. oscura/acquisition/file.py +255 -0
  4. oscura/acquisition/hardware.py +186 -0
  5. oscura/acquisition/saleae.py +340 -0
  6. oscura/acquisition/socketcan.py +315 -0
  7. oscura/acquisition/streaming.py +38 -0
  8. oscura/acquisition/synthetic.py +229 -0
  9. oscura/acquisition/visa.py +376 -0
  10. oscura/analyzers/__init__.py +3 -0
  11. oscura/analyzers/digital/clock.py +9 -1
  12. oscura/analyzers/digital/edges.py +1 -1
  13. oscura/analyzers/digital/timing.py +41 -11
  14. oscura/analyzers/side_channel/__init__.py +52 -0
  15. oscura/analyzers/side_channel/power.py +690 -0
  16. oscura/analyzers/side_channel/timing.py +369 -0
  17. oscura/analyzers/signal_integrity/sparams.py +1 -1
  18. oscura/automotive/__init__.py +4 -2
  19. oscura/automotive/can/patterns.py +3 -1
  20. oscura/automotive/can/session.py +277 -78
  21. oscura/automotive/can/state_machine.py +5 -2
  22. oscura/builders/__init__.py +9 -11
  23. oscura/builders/signal_builder.py +99 -191
  24. oscura/core/exceptions.py +5 -1
  25. oscura/loaders/__init__.py +1 -0
  26. oscura/loaders/chipwhisperer.py +393 -0
  27. oscura/loaders/touchstone.py +1 -1
  28. oscura/session/session.py +54 -46
  29. oscura/sessions/__init__.py +70 -0
  30. oscura/sessions/base.py +323 -0
  31. oscura/sessions/blackbox.py +640 -0
  32. oscura/sessions/generic.py +189 -0
  33. {oscura-0.3.0.dist-info → oscura-0.4.0.dist-info}/METADATA +86 -5
  34. {oscura-0.3.0.dist-info → oscura-0.4.0.dist-info}/RECORD +37 -21
  35. {oscura-0.3.0.dist-info → oscura-0.4.0.dist-info}/WHEEL +0 -0
  36. {oscura-0.3.0.dist-info → oscura-0.4.0.dist-info}/entry_points.txt +0 -0
  37. {oscura-0.3.0.dist-info → oscura-0.4.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,189 @@
1
+ """Generic analysis session implementation.
2
+
3
+ This module provides GenericSession - a concrete implementation of AnalysisSession
4
+ for general-purpose signal analysis. It wraps the existing session.Session class
5
+ to provide the unified AnalysisSession interface while maintaining backward
6
+ compatibility.
7
+
8
+ Example:
9
+ >>> from oscura.sessions import GenericSession
10
+ >>> from oscura.acquisition import FileSource
11
+ >>>
12
+ >>> # Create generic session
13
+ >>> session = GenericSession(name="Debug Session")
14
+ >>> session.add_recording("capture1", FileSource("signal1.wfm"))
15
+ >>> session.add_recording("capture2", FileSource("signal2.wfm"))
16
+ >>>
17
+ >>> # Compare recordings
18
+ >>> diff = session.compare("capture1", "capture2")
19
+ >>> print(f"Similarity: {diff.similarity_score:.2%}")
20
+ >>>
21
+ >>> # Analyze
22
+ >>> results = session.analyze() # Generic waveform analysis
23
+
24
+ Pattern:
25
+ GenericSession is the default session type for non-domain-specific
26
+ analysis. Use domain-specific sessions (CANSession, SerialSession, etc.)
27
+ when working within a specific protocol or analysis domain.
28
+
29
+ Migration:
30
+ The existing oscura.session.Session class continues to work unchanged.
31
+ GenericSession provides the new AnalysisSession interface while
32
+ delegating to the existing Session implementation internally.
33
+
34
+ References:
35
+ Architecture Plan Phase 0.3: AnalysisSession Generic Implementation
36
+ src/oscura/session/session.py: Legacy Session class
37
+ """
38
+
39
+ from __future__ import annotations
40
+
41
+ from pathlib import Path
42
+ from typing import Any
43
+
44
+ from oscura.sessions.base import AnalysisSession
45
+
46
+
47
+ class GenericSession(AnalysisSession):
48
+ """Generic analysis session for general-purpose signal analysis.
49
+
50
+ Provides the unified AnalysisSession interface for non-domain-specific
51
+ analysis. This is the default session type when you don't need CAN,
52
+ Serial, or other specialized functionality.
53
+
54
+ Example:
55
+ >>> from oscura.sessions import GenericSession
56
+ >>> from oscura.acquisition import FileSource
57
+ >>>
58
+ >>> session = GenericSession()
59
+ >>> session.add_recording("test1", FileSource("capture1.wfm"))
60
+ >>> session.add_recording("test2", FileSource("capture2.wfm"))
61
+ >>>
62
+ >>> # Compare traces
63
+ >>> diff = session.compare("test1", "test2")
64
+ >>> print(f"Changed: {diff.changed_bytes} samples")
65
+ >>>
66
+ >>> # Generic analysis
67
+ >>> results = session.analyze()
68
+ >>> print(results["num_recordings"])
69
+ """
70
+
71
+ def analyze(self) -> dict[str, Any]:
72
+ """Perform generic waveform analysis on all recordings.
73
+
74
+ Analyzes all loaded recordings and provides summary statistics,
75
+ basic waveform measurements, and comparison results.
76
+
77
+ Returns:
78
+ Dictionary with analysis results:
79
+ - num_recordings: Number of recordings
80
+ - recordings: List of recording names
81
+ - summary: Summary statistics for each recording
82
+
83
+ Example:
84
+ >>> session = GenericSession()
85
+ >>> session.add_recording("sig", FileSource("capture.wfm"))
86
+ >>> results = session.analyze()
87
+ >>> print(results["summary"]["sig"]["mean"])
88
+ """
89
+ import numpy as np
90
+
91
+ results: dict[str, Any] = {
92
+ "num_recordings": len(self.recordings),
93
+ "recordings": self.list_recordings(),
94
+ "summary": {},
95
+ }
96
+
97
+ # Analyze each recording
98
+ from oscura.core.types import IQTrace
99
+
100
+ for name in self.list_recordings():
101
+ trace = self.get_recording(name)
102
+
103
+ # Handle IQTrace separately
104
+ if isinstance(trace, IQTrace):
105
+ raise TypeError("IQTrace analysis not yet supported in GenericSession")
106
+
107
+ # Basic statistics
108
+ summary = {
109
+ "num_samples": len(trace.data),
110
+ "sample_rate": trace.metadata.sample_rate,
111
+ "duration": len(trace.data) / trace.metadata.sample_rate,
112
+ "mean": float(np.mean(trace.data)),
113
+ "std": float(np.std(trace.data)),
114
+ "min": float(np.min(trace.data)),
115
+ "max": float(np.max(trace.data)),
116
+ "rms": float(np.sqrt(np.mean(trace.data**2))),
117
+ }
118
+
119
+ results["summary"][name] = summary
120
+
121
+ # If multiple recordings, add comparisons
122
+ if len(self.recordings) >= 2:
123
+ results["comparisons"] = {}
124
+ names = self.list_recordings()
125
+ for i in range(len(names)):
126
+ for j in range(i + 1, len(names)):
127
+ comparison_key = f"{names[i]}_vs_{names[j]}"
128
+ comp_result = self.compare(names[i], names[j])
129
+ results["comparisons"][comparison_key] = {
130
+ "similarity": comp_result.similarity_score,
131
+ "changed_samples": comp_result.changed_bytes,
132
+ }
133
+
134
+ return results
135
+
136
+ def export_results(self, format: str, path: str | Path) -> None:
137
+ """Export analysis results to file.
138
+
139
+ Extends base export with additional formats for generic analysis.
140
+
141
+ Args:
142
+ format: Export format ("report", "json", "csv").
143
+ path: Output file path.
144
+
145
+ Raises:
146
+ ValueError: If format not supported.
147
+
148
+ Example:
149
+ >>> session.export_results("report", "analysis.txt")
150
+ >>> session.export_results("json", "results.json")
151
+ """
152
+ path = Path(path)
153
+
154
+ if format == "json":
155
+ # Export as JSON
156
+ import json
157
+
158
+ results = self.analyze()
159
+
160
+ with open(path, "w") as f:
161
+ json.dump(results, f, indent=2)
162
+
163
+ elif format == "csv":
164
+ # Export summary as CSV
165
+ import csv
166
+
167
+ results = self.analyze()
168
+
169
+ with open(path, "w", newline="") as f:
170
+ if not results["summary"]:
171
+ return # No data to export
172
+
173
+ # Get fieldnames from first recording
174
+ first_rec = next(iter(results["summary"].values()))
175
+ fieldnames = ["recording"] + list(first_rec.keys())
176
+
177
+ writer = csv.DictWriter(f, fieldnames=fieldnames)
178
+ writer.writeheader()
179
+
180
+ for name, summary in results["summary"].items():
181
+ row = {"recording": name, **summary}
182
+ writer.writerow(row)
183
+
184
+ else:
185
+ # Fall back to base implementation (text report)
186
+ super().export_results(format, path)
187
+
188
+
189
+ __all__ = ["GenericSession"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oscura
3
- Version: 0.3.0
3
+ Version: 0.4.0
4
4
  Summary: Unified hardware reverse engineering framework. Extract all information from any system through signals and data. Unknown protocol discovery, state machine extraction, CRC recovery, security analysis. 16+ protocols, IEEE-compliant measurements.
5
5
  Project-URL: Homepage, https://github.com/oscura-re/oscura
6
6
  Project-URL: Documentation, https://github.com/oscura-re/oscura/tree/main/docs
@@ -57,6 +57,8 @@ Requires-Dist: pytest-timeout<3.0.0,>=2.3.0; extra == 'all'
57
57
  Requires-Dist: pytest<10.0.0,>=8.0; extra == 'all'
58
58
  Requires-Dist: python-can<5.0.0,>=4.4.0; extra == 'all'
59
59
  Requires-Dist: python-pptx<1.0.0,>=0.6.21; extra == 'all'
60
+ Requires-Dist: pyvisa-py<1.0.0,>=0.7.0; extra == 'all'
61
+ Requires-Dist: pyvisa<2.0.0,>=1.13.0; extra == 'all'
60
62
  Requires-Dist: pywavelets<2.0.0,>=1.0.0; extra == 'all'
61
63
  Requires-Dist: reportlab<6.0.0,>=4.4.7; extra == 'all'
62
64
  Requires-Dist: rigolwfm<2.0.0,>=1.0.0; extra == 'all'
@@ -82,6 +84,9 @@ Requires-Dist: pytest-timeout<3.0.0,>=2.3.0; extra == 'dev'
82
84
  Requires-Dist: pytest<10.0.0,>=8.0; extra == 'dev'
83
85
  Requires-Dist: types-pyyaml<7.0.0,>=6.0; extra == 'dev'
84
86
  Requires-Dist: yamllint<2.0.0,>=1.35; extra == 'dev'
87
+ Provides-Extra: hardware
88
+ Requires-Dist: pyvisa-py<1.0.0,>=0.7.0; extra == 'hardware'
89
+ Requires-Dist: pyvisa<2.0.0,>=1.13.0; extra == 'hardware'
85
90
  Provides-Extra: hdf5
86
91
  Requires-Dist: h5py<4.0.0,>=3.0.0; extra == 'hdf5'
87
92
  Provides-Extra: jupyter
@@ -127,11 +132,15 @@ Description-Content-Type: text/markdown
127
132
 
128
133
  Oscura is a hardware reverse engineering framework for security researchers, right-to-repair advocates, defense analysts, and commercial intelligence teams. From oscilloscope captures to complete system understanding.
129
134
 
130
- **Reverse Engineering**: Unknown protocol discovery • State machine extraction • CRC/checksum recovery • Proprietary device replication • Security vulnerability analysis
135
+ **Reverse Engineering**: Unknown protocol discovery • State machine extraction • CRC/checksum recovery • Proprietary device replication • Security vulnerability analysis • Black-box protocol analysis
131
136
 
132
- **Signal Analysis**: IEEE-compliant measurements (181/1241/1459/2414) • Comprehensive protocol decoding (16+ protocols) • Spectral analysis • Timing characterization
137
+ **Signal Analysis**: IEEE-compliant measurements (181/1241/1459/2414) • Comprehensive protocol decoding (16+ protocols) • Spectral analysis • Timing characterization • Side-channel analysis (DPA/CPA/timing attacks)
133
138
 
134
- **Built For**: ExploitationReplication Defense analysisCommercial intelligenceRight-to-repair
139
+ **Unified Acquisition**: File-basedHardware sources (SocketCAN, Saleae, PyVISA - Phase 2) Synthetic generationPolymorphic Source protocol
140
+
141
+ **Interactive Sessions**: Domain-specific analysis sessions • BlackBoxSession for protocol RE • Differential analysis • Field hypothesis generation • Protocol specification export
142
+
143
+ **Built For**: Exploitation • Replication • Defense analysis • Commercial intelligence • Right-to-repair • Cryptographic research
135
144
 
136
145
  ---
137
146
 
@@ -155,6 +164,8 @@ cd oscura
155
164
 
156
165
  ## Quick Start
157
166
 
167
+ ### Signal Analysis
168
+
158
169
  ```python
159
170
  import oscura as osc
160
171
 
@@ -171,6 +182,57 @@ decoder = UARTDecoder(baud_rate=115200)
171
182
  messages = decoder.decode(trace)
172
183
  ```
173
184
 
185
+ ### Black-Box Protocol Reverse Engineering
186
+
187
+ ```python
188
+ from oscura.sessions import BlackBoxSession
189
+ from oscura.acquisition import FileSource
190
+
191
+ # Create analysis session
192
+ session = BlackBoxSession(name="IoT Device RE")
193
+
194
+ # Add recordings from different stimuli
195
+ session.add_recording("idle", FileSource("idle.bin"))
196
+ session.add_recording("button_press", FileSource("button.bin"))
197
+
198
+ # Differential analysis
199
+ diff = session.compare("idle", "button_press")
200
+ print(f"Changed bytes: {diff.changed_bytes}")
201
+
202
+ # Generate protocol specification
203
+ spec = session.generate_protocol_spec()
204
+ print(f"Detected {len(spec['fields'])} protocol fields")
205
+
206
+ # Export Wireshark dissector
207
+ session.export_results("dissector", "protocol.lua")
208
+ ```
209
+
210
+ ### CAN Protocol Analysis
211
+
212
+ ```python
213
+ from oscura.automotive.can import CANSession
214
+ from oscura.acquisition import FileSource
215
+
216
+ # Create session
217
+ session = CANSession(name="Vehicle Analysis")
218
+
219
+ # Add recordings from CAN bus captures
220
+ session.add_recording("idle", FileSource("idle.blf"))
221
+ session.add_recording("accelerate", FileSource("accelerate.blf"))
222
+
223
+ # Analyze traffic
224
+ analysis = session.analyze()
225
+ print(f"Messages: {analysis['inventory']['total_messages']}")
226
+ print(f"Unique IDs: {len(analysis['inventory']['message_ids'])}")
227
+
228
+ # Compare recordings
229
+ diff = session.compare("idle", "accelerate")
230
+ print(f"Changed IDs: {len(diff.details['changed_ids'])}")
231
+
232
+ # Export DBC file
233
+ session.export_dbc("vehicle.dbc")
234
+ ```
235
+
174
236
  ---
175
237
 
176
238
  ## Learn by Example
@@ -285,9 +347,28 @@ uv sync --all-extras
285
347
 
286
348
  ## Documentation
287
349
 
288
- - **[Demos](demos/)** - Start here (working examples)
350
+ ### Getting Started
351
+
352
+ - **[Quick Start Guide](docs/guides/quick-start.md)** - Begin here
353
+ - **[Demos](demos/)** - Working examples for every feature
354
+ - **[Migration Guide](docs/migration/v0-to-v1.md)** - Upgrade from older versions
355
+
356
+ ### User Guides
357
+
358
+ - **[Black-Box Protocol Analysis](docs/guides/blackbox-analysis.md)** - Unknown protocol reverse engineering
359
+ - **[Hardware Acquisition](docs/guides/hardware-acquisition.md)** - Direct hardware integration (Phase 2)
360
+ - **[Side-Channel Analysis](docs/guides/side-channel-analysis.md)** - Power/timing/EM attacks
361
+ - **[Workflows](docs/guides/workflows.md)** - Complete analysis workflows
362
+
363
+ ### API Reference
364
+
289
365
  - **[API Reference](docs/api/)** - Complete API documentation
366
+ - **[Session Management](docs/api/session-management.md)** - Interactive analysis sessions
290
367
  - **[CLI Reference](docs/cli.md)** - Command line usage
368
+
369
+ ### Development
370
+
371
+ - **[Architecture](docs/architecture/)** - Design principles and patterns
291
372
  - **[Testing Guide](docs/testing/)** - Test suite architecture
292
373
  - **[CHANGELOG](CHANGELOG.md)** - Version history
293
374
 
@@ -1,21 +1,29 @@
1
- oscura/__init__.py,sha256=V1fB6L32oWxgv5OtAHJKWTAtb9DqD_QXkfAcsEge-pw,18443
1
+ oscura/__init__.py,sha256=IvoCA0vsnvD_yPvwtMWi4qX4q5FhsY7uiQFKghU85wQ,18313
2
2
  oscura/__main__.py,sha256=l1rnaD-tpI1W3cp1VHGhSdq9NDqw6Gxjf_gnqXf-zzE,11786
3
3
  oscura/convenience.py,sha256=o8f1Im8WpakGXRz8D4bV-XSNkzpgnVjsyVxnaxZ-dg4,14612
4
4
  oscura/exceptions.py,sha256=Ywyi7IhEG9XmbceCxAcLGKAddAOdP9Ph1ZT2NioMQCU,1606
5
5
  oscura/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- oscura/analyzers/__init__.py,sha256=UNSltiHbqKbkuBOSeOqy9R2VkFcBIAFwPErJ0H1pswM,896
6
+ oscura/acquisition/__init__.py,sha256=JAQt5FXsGiKPkqHuyWJoGVnGf1ElSRXqGxJdjcDLLho,4834
7
+ oscura/acquisition/file.py,sha256=nrOWunIGxUaF-B946ZKwME4f-8jbWhp3z3BadvCuUw0,8426
8
+ oscura/acquisition/hardware.py,sha256=-BrIi0aLoVBTVIh5gdTvYY5OrDPIv06wxrx28GJw7j8,6598
9
+ oscura/acquisition/saleae.py,sha256=D61v7_k-zZzor-jiYHFwjd-u8VFo93spQ3_m7Jhk_Dc,11438
10
+ oscura/acquisition/socketcan.py,sha256=ifs7Chv-pk4LLYTvfe4-9xS2-vbe4efqVd1azIYLexE,10575
11
+ oscura/acquisition/streaming.py,sha256=P57M8S33DGIeoDUSBHm3bzoKfNIDZkYE4dODPNeJy78,1191
12
+ oscura/acquisition/synthetic.py,sha256=VXhz5W0gzwE3_Ezo7hADwfFoTV5pOixpPCVNPMngNAo,7823
13
+ oscura/acquisition/visa.py,sha256=phUwdlbphvNhSCaRgIXuPb8YDP0jR4eqY-OuJXCgRCo,12272
14
+ oscura/analyzers/__init__.py,sha256=LE-KFYoVePYsiPIy2NDNB2OrzbtqYezdCu9xqqPxgrY,985
7
15
  oscura/analyzers/measurements.py,sha256=ng5Qt2jyAvfKw3JQbJY_JNUqAOJEZwPo3UWa0xSg5Xk,697
8
16
  oscura/analyzers/validation.py,sha256=vHSKmLThwcU0j5Dat9QPbWImw_dqUGaZk_Ul6XbJ958,20376
9
17
  oscura/analyzers/digital/__init__.py,sha256=CrZxLveYI-nZ7INCZg-4zp8UP_uQRpMmX2vljzudJ6s,4228
10
18
  oscura/analyzers/digital/bus.py,sha256=Wf3QUKNSxzXaWItR1rdf32kELayywrIg0TC-OhKEub0,22717
11
- oscura/analyzers/digital/clock.py,sha256=Ls9-YgH0qRLhkZWG9qVadcGw9koT21UPvFk-Ia5OuZ8,25802
19
+ oscura/analyzers/digital/clock.py,sha256=2WihQyf2fUlKTDAOKrhQSStiuUw711CvR6bMbkiliAc,26088
12
20
  oscura/analyzers/digital/correlation.py,sha256=_D-pmymVU1rTemSUfg_MklXCo03VkfAFcxSTLAV6jcY,23689
13
- oscura/analyzers/digital/edges.py,sha256=uQf00dxcN8h8dni3l-ksZ8XsMswk5Gzhtdqp7GpFkk8,20000
21
+ oscura/analyzers/digital/edges.py,sha256=-Mlyh_SFkqs7L2n11bfYlv8bHD-jrfV6UByhXS1DLp0,20018
14
22
  oscura/analyzers/digital/extraction.py,sha256=wBOPZi3H1llCHsq36txz_jkEO--Sj6pbsxPZXXGk5_c,12144
15
23
  oscura/analyzers/digital/quality.py,sha256=bMXpmAhs15tjyiWW0Ao5aZcK_8AvEKyo_E3rtxDrFlo,27413
16
24
  oscura/analyzers/digital/signal_quality.py,sha256=Ssb1MkUfqjiENJJFOslkTX8Ef6C65HFCM_Ra20Bvp4k,30130
17
25
  oscura/analyzers/digital/thresholds.py,sha256=CrGgO1rtzkUOnYb40UT3_uD_0qVA853lGL2WNL95qv4,22428
18
- oscura/analyzers/digital/timing.py,sha256=ilk6iacaIup2epB_VOnNjg0jGBFT5wBX-CpaZLFVScM,33138
26
+ oscura/analyzers/digital/timing.py,sha256=eOo1jk-FfUd3tkqDndPTz-JO5tnfW9w4dEI-klgW-QU,34862
19
27
  oscura/analyzers/eye/__init__.py,sha256=SRW0Ir-1RWLwoaenk6FZhGOIWPkuhevYTPt_-8thPw0,974
20
28
  oscura/analyzers/eye/diagram.py,sha256=T3QwuZ3nvlHzSkmjp47ariRlt3FnfsK6yh3WsPszhmI,13307
21
29
  oscura/analyzers/eye/metrics.py,sha256=QDwtMxiBPSXbUCyFnTiAgWllbVCrcI4xEo6teZc3Cm8,17210
@@ -65,10 +73,13 @@ oscura/analyzers/protocols/spi.py,sha256=gl0LVpZVI22tr7h5D1OAdDtlY_krb7CdNCNP10D
65
73
  oscura/analyzers/protocols/swd.py,sha256=NAInX2bZyZFCM03CLjjxraYTV7cCGOzcl_OEXU21qZE,10155
66
74
  oscura/analyzers/protocols/uart.py,sha256=6bf9EFHjHjkSeTxBq8b6GRlp1xWlBh65HuUcmWxWAEA,12188
67
75
  oscura/analyzers/protocols/usb.py,sha256=jBjmqfqnwys6Zvd7Ku-zZRNlOVZB7xKPmocM2NynGg4,14541
76
+ oscura/analyzers/side_channel/__init__.py,sha256=XGD7uvvL6Mf2FO6VU5fbBTtfARA-WGXa-rvHAbjNBxc,1361
77
+ oscura/analyzers/side_channel/power.py,sha256=036A5ygwGVa5jqOFoOWm1bV-x63FrztyCS8cIEc68wo,17995
78
+ oscura/analyzers/side_channel/timing.py,sha256=loNKa5dgWu9sFTsKCNt087vqYCjBIVVQn3lzQBb3pQc,12128
68
79
  oscura/analyzers/signal_integrity/__init__.py,sha256=RXt5K79WFsy3NvJuNjVxWCf0r6Z8kOIBvJSBBw4X2Y8,1410
69
80
  oscura/analyzers/signal_integrity/embedding.py,sha256=LV-8TwSfCfFe-TavXXKOw7eIeigxkvKeJktyQiqcZXg,8036
70
81
  oscura/analyzers/signal_integrity/equalization.py,sha256=cVomry8n-U5pS8F2LKuEdZBwmi1wfbQo2vyWettn2A0,9906
71
- oscura/analyzers/signal_integrity/sparams.py,sha256=uLusiE942QR6rmB5c_VfhRWjGEM4zC9nwCcMxXG2Twg,8289
82
+ oscura/analyzers/signal_integrity/sparams.py,sha256=TK4o-IOfnVVbfycBgJ0XhTgBYxHcBNdFbmC9TXhfMJs,8303
72
83
  oscura/analyzers/spectral/__init__.py,sha256=YeUKiUOtN3LkWjPmjiG55OWMldSaBJ4BE4OSem7sdm0,850
73
84
  oscura/analyzers/spectral/chunked.py,sha256=KS1Jtv_o9vripQVH3CeaTBx-Lq4AAU-eOXF9_En3rc4,8551
74
85
  oscura/analyzers/spectral/chunked_fft.py,sha256=VKslVgXv7xuSuVVx-Fk2eh255AG6D0D-hQFzAbz1Hk4,18593
@@ -99,7 +110,7 @@ oscura/api/fluent.py,sha256=Bvo1yVqqn3nmVWaoPv4C-YtYszBhHmdW8m5NdyhWEEo,15373
99
110
  oscura/api/operators.py,sha256=To4PZUrwInD43T7i2Sy8YD04eLoRsmrD6XYePuExUX8,13853
100
111
  oscura/api/optimization.py,sha256=5R6rPByVsyxla6oq4SjxjxEp9Uplog4owzsIuFcVoR0,11875
101
112
  oscura/api/profiling.py,sha256=vkYinleXrznWdd0OT5zIJN_PW289GQE_ODmR9DaCcQ0,10567
102
- oscura/automotive/__init__.py,sha256=b1LX9vQXG4FhN_XRq2LJgUNq36-xuAgMjGyEl-EzLS4,2423
113
+ oscura/automotive/__init__.py,sha256=3Wt44lFmx_zzyC1_IeukEpEnUagyM8TT0mWUnTpXb4s,2538
103
114
  oscura/automotive/visualization.py,sha256=2ILQjzNwCwj6zZ4MEsBS-QLwYFKMO0_0xDsbv3gEXu0,10692
104
115
  oscura/automotive/can/__init__.py,sha256=0WCLgE6juqQF_mTO716tWzfziOcM6cjshdb957G0edw,1283
105
116
  oscura/automotive/can/analysis.py,sha256=0z6MycxuJGusqDQhYEpHnGRmDw3OMf5yDbS8zI6GJO0,11251
@@ -108,9 +119,9 @@ oscura/automotive/can/correlation.py,sha256=B7MXSz_uzce-dSkwON4ssmFzC53hYc6GupZW
108
119
  oscura/automotive/can/discovery.py,sha256=E4Z-zc8cOP_yUklhVp2tBLOIw2I9KU4mLoSb37VsgTk,11237
109
120
  oscura/automotive/can/message_wrapper.py,sha256=xCyHLMvvTiloifWXELoeuN6Qz_vrLL8iPjxZG1FvJYY,12640
110
121
  oscura/automotive/can/models.py,sha256=fGnCt8FBKURKAz295s2duUas--w2rVfJpMEZ4O9uPvA,12046
111
- oscura/automotive/can/patterns.py,sha256=PPAnWrOFgh3EWlzgtT0H8TJcw1kA41uYZWviwOIQvts,13837
112
- oscura/automotive/can/session.py,sha256=6weEsM8AqgET7hVXwTW7QPpIGgblRVHR5RMOKJXbNnA,15597
113
- oscura/automotive/can/state_machine.py,sha256=NDwCFYw42J3M1QuigA7XNY5E9L0sfUygcvfALb6kt70,10205
122
+ oscura/automotive/can/patterns.py,sha256=XkiBnxaL20Zbpt9aK7dS8BGXQtbNe8PoyTyZNsj-BLY,13960
123
+ oscura/automotive/can/session.py,sha256=bLbDuKw2uuGvIr25E0njYJGWw1urRVhWVMckVUL2EI4,24577
124
+ oscura/automotive/can/state_machine.py,sha256=yeHwydg5RegCPg_zvzS7lLZX-JfBdfMySUcNgMszuIY,10407
114
125
  oscura/automotive/can/stimulus_response.py,sha256=y_oN297KypsFewjM6kvjGII0-7Ubpz2RZBPr8pjW-Gc,16543
115
126
  oscura/automotive/dbc/__init__.py,sha256=7s36h4LQrJKKkO3ICHeuVCoYVx8jGnHT_wKcJgOsQFQ,380
116
127
  oscura/automotive/dbc/generator.py,sha256=EqJKJikAK2Neaff2H9AGb8ZnseE8m4lFAFRMXEIwjsY,5616
@@ -138,8 +149,8 @@ oscura/batch/aggregate.py,sha256=NBc1RmSGbSRUdpuZG_3wy-vSkGlegGRSj_6WqPqhTkM,105
138
149
  oscura/batch/analyze.py,sha256=RfRJQ9w9rlutDlT9nTdqSCswi9FxAsznYbCN51Cx2-Y,4891
139
150
  oscura/batch/logging.py,sha256=ay8BxwBfH75k5qgs68gI1LdAjPJQg31ZtBxwmWs2XIo,15502
140
151
  oscura/batch/metrics.py,sha256=KrY9R0fKttVSW7wL3ra3A4XHVfAeUaLeoM0BtU3GEWI,17312
141
- oscura/builders/__init__.py,sha256=EhiubV1xFlhfERyoKtgPSD_mIj8BUW1_s0kUv7BrNl8,1187
142
- oscura/builders/signal_builder.py,sha256=SgmSkOfSFQ6vge2861rbiZ7ZCKf6g-RpezI88tfLROE,35293
152
+ oscura/builders/__init__.py,sha256=7ryrfaFlT4zAh5zKr76LLQDionMFsPv57E_1OlxrkE0,1326
153
+ oscura/builders/signal_builder.py,sha256=nH7AK6YJZZ_KoDcqL3zsxCFwgBQNFieP1k_fChnD4EU,33099
143
154
  oscura/cli/__init__.py,sha256=OsdCTexpFCKn-o7FPnwTEAZE52E2s-NbXwpADUOfhDM,275
144
155
  oscura/cli/batch.py,sha256=6WkdQF5G03cwCGxfErqr-nq2llOXJqLrfk3u2agUlXY,10773
145
156
  oscura/cli/characterize.py,sha256=yMAm4Ji_Dq4Hml3PeDftoUFq60z1BpU_6O7HJ9dUDtc,8898
@@ -185,7 +196,7 @@ oscura/core/correlation.py,sha256=3kG-scCs7Lv3uYJhvGYbnSyCsf9gQOqX9hnRTsZjAII,64
185
196
  oscura/core/cross_domain.py,sha256=ZGJGieFpLEMTHEeQ8GFZnNZL0WgKLW_fn7joEptovpE,16118
186
197
  oscura/core/debug.py,sha256=1fz5Mwx6dcMXwsGNQMhPCVduAf2ZTSGSvvwjpqIS3Cc,8160
187
198
  oscura/core/edge_cases.py,sha256=-z95foSBKZb3V2DhGQSw1A2VaVOGRBdhMfxDooWbLhg,16367
188
- oscura/core/exceptions.py,sha256=h_s0HX9SkZYcHyTmpQvDMRD93cmY47z4VYw_pfDBGf4,17500
199
+ oscura/core/exceptions.py,sha256=VOvd6iY4SQWz_fPx9EgwdbaIHpqydyFAou8SeZa7w48,17691
189
200
  oscura/core/gpu_backend.py,sha256=U7DoPKHltlGNTFk6cOhpuVUC5VuglahbBRu1jZ83nDE,17700
190
201
  oscura/core/lazy.py,sha256=XwXPznvfpgfJqRvONO2YcgLE9IxekhHLQboiLm3a2jw,26302
191
202
  oscura/core/log_query.py,sha256=qV7NrZH3W6Xq1BEsEIc6Z4ZW8k3vi6U16Br23tSynhk,17051
@@ -289,8 +300,9 @@ oscura/integrations/llm.py,sha256=sPt58GZYW6G4rkwX4956RP-FsFNDXCffyiPlBuah6Y4,58
289
300
  oscura/jupyter/__init__.py,sha256=L5un2-sVNGP46rzJ7e3qrJOyXmhj2BkhLc7DGQzSLj0,726
290
301
  oscura/jupyter/display.py,sha256=HuLg5NEIKAGEZe_3EmABaRkTzLAfdAm6VTBw9LCl030,8597
291
302
  oscura/jupyter/magic.py,sha256=O1m9N6I5nMUKhCnNANiOdr2pouQxI9oRIcLeRNtrdTc,9953
292
- oscura/loaders/__init__.py,sha256=6osTOOBd1Q7w2wwxOU9kiLD-Q2CE--kCYsN7mdEBmRI,16793
303
+ oscura/loaders/__init__.py,sha256=JKlIsEY0vKEtnXAccgQ6SJMkWYRm9ijM13SSPaqQQJg,16870
293
304
  oscura/loaders/binary.py,sha256=Y5j0jaDggSmhFRZvGHT2Fph2dvhTWsqoYWwkOHIBug4,1875
305
+ oscura/loaders/chipwhisperer.py,sha256=vUsmt6Pamybivp6cqqxe70QUlNrVPdQDn-OS5wEdqxo,12049
294
306
  oscura/loaders/configurable.py,sha256=dJKv3nFSgmWe22ZNB1kTZZyIWgiMhWTf8ZU-SNahefk,41267
295
307
  oscura/loaders/csv.py,sha256=hjToCQkXQEMUCOSBTf3a1d4AAsntvxYbW_jiccQ9JaM,918
296
308
  oscura/loaders/csv_loader.py,sha256=Y4MOJQ-95tZsi9hDdu9ru1vTJQyGtGxkhV7RUqGBLWg,14252
@@ -305,7 +317,7 @@ oscura/loaders/rigol.py,sha256=nwf5aNpH0bWerDgneUpLNlDQfouQ9E_PChv6vG8GLTA,9238
305
317
  oscura/loaders/sigrok.py,sha256=puyj357BPiJpzNB-hcv6ofp6DZFEnOv_usdi-_zs6Co,10250
306
318
  oscura/loaders/tdms.py,sha256=QngrFLJTpctfqcCtv2x3PJmNwfIeWgyug97N_xSdaMA,10483
307
319
  oscura/loaders/tektronix.py,sha256=rLqTefIwGCCmkpUwflEJMuKSfGG1qX_pAFF7Kk0j6-I,24069
308
- oscura/loaders/touchstone.py,sha256=-rg5cj6kNzVBbrloErY2a5_yfcNihlbhZKk3PfNb4sY,6128
320
+ oscura/loaders/touchstone.py,sha256=HdrpVsyHACSMD8DR86iCI5cj9vdXGXbpADNkjaQRUng,6179
309
321
  oscura/loaders/validation.py,sha256=JA_vVYQJB4gC9KFKa2lsGV5D-_agmIjP9kE_dXpv4Wk,17835
310
322
  oscura/loaders/vcd.py,sha256=YtRqU6AEkZjZhNnyNOfgBsxZ8rueB5pALrYIoiRYHQ8,13662
311
323
  oscura/loaders/wav.py,sha256=UYPc1A1ZRuw5zC7XmBdEqjZpsi2QvSW1noNmXZqpy2k,7251
@@ -393,7 +405,11 @@ oscura/search/pattern.py,sha256=pqCtlFDKZwms1LrX64Halt25EQAI1VKr3X_6W4XQ_xI,5735
393
405
  oscura/session/__init__.py,sha256=LAeHbROHU-OBSep1NWffhhcOxVuK30hoKnYgzBsnmn4,926
394
406
  oscura/session/annotations.py,sha256=btHVzA6CedrqVI-c_uFVi_lo7-NByxBLTDHoXWYtY08,8713
395
407
  oscura/session/history.py,sha256=3YAMhON7wlzNdR03HpGSYWJEuxBsrYeYq19YALc8k8M,9578
396
- oscura/session/session.py,sha256=fK5YD5nDKOGHaRTkwhLfkr6TkDTBJx2vTCImPzcMf3s,16185
408
+ oscura/session/session.py,sha256=MWx2cE_ZtyWwl5v8QR_X2MGEBn-TAaFftwKNyZktwIU,16321
409
+ oscura/sessions/__init__.py,sha256=BCmLuo95CfyutHrjEFdWSKRDzKKpDGVMcFi3989HiFA,2371
410
+ oscura/sessions/base.py,sha256=S2ka5o01w1YVBHH59EV64tmW9fXErfNuG2zu9g13-t8,10820
411
+ oscura/sessions/blackbox.py,sha256=CyYA6o7d9pMSR6rsbUOQYq6lBSfUUq-ivtr1QKUppdU,22176
412
+ oscura/sessions/generic.py,sha256=hqwhGO_DT3rS0EOKhLtcebJPu81PPLfHSLH1qVmAWj0,6642
397
413
  oscura/streaming/__init__.py,sha256=uJKpXU6-uBW1lWqh8_8WNzUKSLhMYzxrJstsNMDLVcM,959
398
414
  oscura/streaming/chunked.py,sha256=tWK7m_fHJVJKGq2y6I3RRfioUER2ObMUDPvJ78K73d0,19487
399
415
  oscura/streaming/progressive.py,sha256=YRdAd4P9Zvckerm2kG5bFWZtcuUB1FlRklpS1078s9c,13089
@@ -458,8 +474,8 @@ oscura/workflows/power.py,sha256=fpTzoIfuZi69ldtu2KAHW-Qu6jzA5jBa_9LVy6xqpTI,608
458
474
  oscura/workflows/protocol.py,sha256=x3T-M81vFVrW3mouaYA8WjxyLLzZyLATVJbiqcMAVFQ,15275
459
475
  oscura/workflows/reverse_engineering.py,sha256=K_yrqrQqQNcCoB0jRAG92e2zy8er3oiKJWSF6lU4nGk,19929
460
476
  oscura/workflows/signal_integrity.py,sha256=p-DOC-AhzQOkG_jyyBK3EUaIBAGZhAhdmo-Ub_ifC3U,8391
461
- oscura-0.3.0.dist-info/METADATA,sha256=5q5ASfeIwK-qE3ipz29nutrQyxZZMZ6odN9GtUhOVn8,13291
462
- oscura-0.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
463
- oscura-0.3.0.dist-info/entry_points.txt,sha256=QLBxd-iTjBQ5HidaVSkLBwvUsqxSG1ZTJ6i-0juu960,48
464
- oscura-0.3.0.dist-info/licenses/LICENSE,sha256=p1_oEK-oqWDXMFSv5mKbyYkgW-CPbCnFUvdICu490aY,1077
465
- oscura-0.3.0.dist-info/RECORD,,
477
+ oscura-0.4.0.dist-info/METADATA,sha256=Usu1H_SaG7TkKGT33lnwM0WfPH4FB-icct_YbUwO1EM,16212
478
+ oscura-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
479
+ oscura-0.4.0.dist-info/entry_points.txt,sha256=QLBxd-iTjBQ5HidaVSkLBwvUsqxSG1ZTJ6i-0juu960,48
480
+ oscura-0.4.0.dist-info/licenses/LICENSE,sha256=p1_oEK-oqWDXMFSv5mKbyYkgW-CPbCnFUvdICu490aY,1077
481
+ oscura-0.4.0.dist-info/RECORD,,
File without changes