Bermet Talantbekova's Notebook - cps-vip/cps-cosimulation-env GitHub Wiki
Spring 2026
Week 15
Final presentation demo and preparation for the report
Week 13
An additional set of 20 trials was completed on both the 1724 and 5223 STM32 boards, further expanding the dataset and improving the overall reliability of the measurements. Increasing the number of trials helps reduce the impact of randomness and provides a clearer picture of the stability and repeatability of the PUF responses across multiple evaluations.
Alongside data collection, the existing Python scripts used for PUF analysis were significantly enhanced. The updated scripts now compute more detailed metrics, including the average bit instability for each board and the intra-chip Hamming distance represented as a percentage. These additions make it easier to quantify how much variation exists within a single device over time, which is crucial for understanding noise characteristics and determining how much error correction will be required in later stages.
Following a discussion with Hayden, it was confirmed that BCH codes are a well-suited choice for the error-correcting component of the system due to their effectiveness in handling random bit errors commonly observed in PUF outputs. With this direction established, the next phase will focus on selecting appropriate BCH parameters, such as block size and error correction capability, based on the instability metrics gathered from the experiments. This will enable a more informed and optimized implementation of the fuzzy extractor moving forward.
Week 12
Began setting up a Rust-based framework for a fuzzy extractor. Progress is somewhat blocked until an appropriate error-correcting code (ECC) is selected.
Main goal is to write program to count how many times a bit is a 0 vs a 1 for each bit then compare across runs on the same board and runs across different boards.
For each board folder (1724_SRAM4_data and 5223_SRAM4_data), it reads all .bits files, counts zeros and ones per bit position, and writes a CSV file with columns:
bit_position (index of the bit, starting at 0)
zeros_count (how many trials had a 0 at this bit in 20 trials)
ones_count (how many trials had a 1)
majority ('0', '1', or 'equal' on 20 trials)
stability (fraction of trials where the majority value occurs)
match = yes → both boards have the same majority (both 0 or both 1).
match = no → the majority values differ (one board has 0, the other has 1).
Week 9
Main goal is to write python script to parse out all of the logger info in the text files and leave just the memory in bits instead of bytes
Dump SRAM contents (specifically bottom half of 4th SRAM on STM32)
Run it ~20 times per board
Collect logs (memory dumps in files)
Separate data by board (using 4-digit labels)
Week 7
Experiment 1 - SRAM Startup Pattern Stability
Measure SRAM bits at power-up and check stability across multiple boots.
Experiment 2 - Environmental Stress Effects
Test SRAM under different temperatures (cold, normal, hot) and voltages; see if bits flip.
Experiment 3 - Randomness Test
Use SRAM dumps to check if bits form a good random number source
*Task 1 - Learn Rust and Embedded RustStatus: In progress. Team members are individually learning Rust using Rustlings
*Task 2 - Run Experiments on the STM32 SRAM: --> Run a series of experiments to validate the randomness and quality of the STM32 SRAM in preparation to building a PUF.
Task 3 - Develop a PUF-Based Key Generation System: --> Implement SRAM-PUF–derived key generation on a Raspberry Pi STM32 and use the keys to protect stored data.
Week 6
Main language is gonna be RUST language
Possible tutorials :
Planing on meeting up for the midterm presentations
We have 2 of STM32 delivered
Week 5
Next steps
VIP
Steps once we recieve SMPT32
Write code SMPT32, make sure to have good memory allocation both for the program,
Randomness !!
Create a program that creates the randomness
Get content of the more out of laptop —> Via debugging cable to print all bits—> use Python script to read the statistical analysis
How random is it?
Make sure to have pace for the linker file
Draw heat map manifacutirng defects in certain parts of the the chips, fussier —> not as good, this bit are either all 1 or 0 all across the part, draw a box -- cluster bias in certain direction
Working on research and early discoveries on papers related to the PUFS
FDI are carried out by compromising grid sensor to inject malicious data (data is mathematically consistent) or follow the physics) into the power system state estimation .
Attacker needs to know grid topology, all sensors and meters (RTUs and PMUs)
Since power grids have a lot of noise when receiving signals, standard detection only looks for the difference in “residual” which is equal to a= HC, where H→ network topology, c → desired change state
z → data coming from sensors(PMUs) about flow and voltage
H → grids structure, map that explain how one change on part of the grade affects other part
x → actual reality of the grid(voltage) that operator is figuring out
e → error, natural noise, small mistakes from sensors
An attacker uses a= HC
c → targeted lie (10 % higher the voltage)
a→ injectio vector ( by multiplying the lie with map H, attacker has fake data package)
Week 1
Planning with team members to work on meeting times with teams, and refining what task we could work this semester
Clone this repo: git clone https://github.com/cps-vip/cps-cosimulation-env.git
Go into the repo: cd cps-cosimulation-env
Switch to the Networking_team branch: git switch Networking_team
Update the Git submodules: git submodule update --init --recursive
Build the Docker image: docker build --platform=linux/amd64 -t cps-cosimulation-env:latest .
Run the Docker container: docker run -it --rm --name cps-vip --platform linux/amd64 -v .:/home/vip/cps-cosimulation-env cps-cosimulation-env:latest /bin/bash
Run the one-time setup script: ./setup.sh. Warning - this will take a long time.
Running into the issue after running the command docker run -it --rm --name cps-vip --platform linux/amd64 -v .:/home/vip/cps-cosimulation-env cps-cosimulation-env:latest /bin/bash
Week 9
Working on installing ROS-HELICS Docker container with both the cps-cosimulation-env repo and dnp3-example repo.
Week 8 Midterm Paper
Following the DNP3 implementation guide, this means configuring our outstation servers with a specific TlsServerConfig. This isn't just an abstract concept; it involves concrete setup steps:
Certificate-Based Authentication: Each outstation will be configured with its own unique X.509 certificate and private key, typically loaded from PEM files on the server's filesystem.
-- Example: An outstation for a "Circuit Breaker 1A" would load its identity from breaker_1a_cert.pem and breaker_1a_key.pem.
Enforcing Mutual Authentication: The real security boost comes from configuring mutual TLS. The outstation's TLS configuration will have the peer_cert_path parameter set, pointing to a file containing the Certificate Authority (CA) that issued the master station's certificate.
-- Example: The outstation is configured with peer_cert_path = "trusted_master_ca.pem". When a master connects, the outstation will verify that the master's certificate is signed by this trusted CA. This two-way check ensures only authorized masters can connect, effectively locking out impersonators.
Control Over Protocols and Encryption: We can enforce modern security standards by configuring the TLS server to use specific protocols like TLS 1.2 and strong cipher suites that support Forward Secrecy. This ensures that each session uses a unique key, so a compromised long-term key cannot decrypt past communications.
This link how to configure a DNP3 outstation to act as a TLS server, enabling secure encrypted communications between masters and outstations.
Core Requirements:
Must create a TlsServerConfig object
Need X.509 certificate and private key files (PEM format)
Can enable mutual authentication (client certificate verification)
Server Configuration:
text
TlsServerConfig {
certificate_path: "server_cert.pem",
private_key_path: "server_key.pem",
peer_cert_path: "client_ca.pem" // for mutual auth.
}.
Security Features:
Supports TLS 1.2 and TLS 1.3
Configurable cipher suites
Optional mutual certificate authentication
Certificate chain verification
Implementation Flow:
Load server certificate and private key
Optionally configure client CA for mutual auth
Create TLS server configuration
Apply to outstation connection
Outstation now accepts only TLS-secured connections.
Key Benefit: Provides transport-layer encryption that secures the entire DNP3 session, not just application data.
Week 6
Today I worked with the c_api_example/dnp3-module to understand how the fault handling works. I tried to set up the fault dump, but the module did not behave as expected. The current problem seems to be with how the fault is being triggered or logged, and I need to trace the flow to see where it breaks. The next step will be to check the module configuration and review the debug logs to pinpoint the root cause of the fault.
Week 5
Kaden and I worked on duplicating the set fault problem with Python Threading on virtual env
We followed the steps for the README in the c_api_example/dnp3-module directory in a Linux VM.
Week 3
Worked on goals for the networking team to work on this semester.
With new cybersecurity team we decided to work on what our "Threat Objectives" are
The reason we do this is because we do not have luxury to protect substation with every portable threats
Out LONG-TERM goals for this semester:
Accurately model all communication within a substation
Model inter-substation and inter-protocol communication
Research substation network security
Develop novel security approaches
Out SHORT-TERM goals for this semester:
Design and implement DNP3 outstation API in cosimulation repository
Architect network structure within substation
Integrate communication with HELICS
Work with device modeling team to accurately model behavior of Master
Week 2
We went through overall introduction to the power grid system
Transmission --> done via PyPower
Substation --> done via
Distribution --> done via Grid lab D
Broker --> responsible for managing all three above.
Communication --> Helicks
Spring 2025
Week 1
1st meeting on Thursday, 1/9
Introduction to team; joined the Discord Server and completed the welcome quiz
Learned basics about power grid and maintenance
Individual time
Read through syllabus; added important dates to calendar
Week 2
2nd meeting on Thursday, 1/16
Joined the Device Modeling sub-team, chose extra meeting date (Firdays, 4pm)
Introduction to kick-off presentation requirements
Learned more about specific tasks within Overall team
ROS (robot operating system simulator)
HELICS (program that coordinates and interfaces other simulation programs)
Gridlab D (physics simulator)
Gazebo (physical visualization simulator)
Individual time
Week 3
Task 1 - DNP3 Documantation
Kaden provided a reading for DNP3, to gain better understanding of DNP3 protocol, library, and usage.
DNP3 Documantation
Goal - Model how networking works in a substation (and potentially between multiple substations). The long term goal is to do security research on substation networking, but that will come after we've established an accurate simulation.
Quick run down on OSI layers
DNP3
DNP3 is a specialized networking protocol made for communication within a substation. We use DNP3 over the TCP/IP stack, but DNP3 can also run independently of TCP/IP, using its own link layer and transport layer. DNP3 packets still contain this link and transport layer information as a historic relic.
There are two ways to call the Rust library from Python:
Use a third-party library like PyO3 and Maturin to directly call Rust from Python, or
Utilize one of the existing foreign function interfaces (FFI)
Kaden used the 2nd option
The Rust library exposes functions that you can call from C, which we then call from Python. Kaden created an example repo to demonstrate this working.
Where to Start
While not necessary for what we are doing, get the simple_gridlabd_example working (see the instructions on the main README for this repo) - WORKING
Read up on the OSI model and TCP/IP basics if you aren’t already familiar - DONE
Understand what's happening in the DNP3 example repo -
Potential Areas of Work
Understanding DNP3 better - Most of the stuff we’ve worked on so far hasn’t required knowing how you use DNP3 in practice since the Rust library handles all of that for us. Having someone proficient in DNP3 would be extremely useful, even if it’s just to explain details to the people who will be implementing it.
Python API and Implementation - We need to determine how a substation device will interface with the Rust library. This involves creating more methods in the Outstation class that individual devices can call.
C work - Since we call the Rust library through the C FFI, we need to do some work in C. This mostly involves wrapping the existing C functions in a way that’s easier to call from Python.
HELICS integration - Somehow, the substation needs to communicate with the rest of the cosimulation through HELICS. We need to determine how to do this. For example, does every substation device publish to HELICS, or does everything go through the Master station? Another problem here is timing - we want DNP3 timestamps to be consistent with the rest of the cosimulation.
Human-Machine Interface - Real substations have GUIs to interact with the devices in the substation. Currently, we have no progress or even a starting point for this, but it will need to be done at some point.
Inter-substation and inter-protocol communication - So far, we are building code around one substation and one communication protocol. In the future, we may want to be able to model multiple substations and other protocols. The current design accommodates inter-substation communication by having the Master inherit from the Substation class, and inter-protocol communication can be done through a data concentrator device. This is long-term and so lower priority.
DNP3- Research
DNP3 (Distributed Network Protocol) is a communication protocol for SCADA systems in utilities (electric, water).
Efficient: Handles large data with low latency.
Reliable: Ensures error-checked, validated data.
Interoperable: Connects devices from different manufacturers.
Secure: Modern versions support encryption/authentication.
DNP3 (Distributed Network Protocol) is like the “language” that devices in a utility network (power, water, etc.) use to talk to each other. It’s commonly used in SCADA systems (those big control systems that keep critical infrastructure running).
Using DNP3 in Python:
Substation devices are programmed in Python. To use DNP3 with Python, they needed a library.
Two libraries existed before: dnp3-python and pydnp3. Both relied on a tool called opendnp3, but that tool was discontinued in 2022.
Switch to Rust:
The maintainers of opendnp3 (Step Function I/O) created a new library written in Rust, called simply DNP3.
Since there wasn’t a direct way to use this new Rust-based library in Python, the team decided to build a Python wrapper for it.
How did they connect Rust to Python?
They used an FFI (Foreign Function Interface) approach. This means they treated the Rust library as if it were a C library (because Rust can expose C-compatible functions). Then, Python can call those C functions, indirectly using Rust.
DEVICES ??????? What Devices, or devices that Chungman and Maria are working on?
sensors
breakers
other control devices used in utilities like electricity and water systems.
Master: This is the central controller or device that sends requests for data and controls the outstations.
Outstation: These are the field devices (sensors, relays, remote terminal units) that respond to requests from the master. They collect and report data such as temperatures, voltages, etc.
Data Points
binaryValue (c_bool): (1 for ON, 0 for OFF).
doubleBitBinaryValue (c_uint32): An enumerated value (usually 0-3)
binaryOutputStatusValue (c_bool): Similar to binaryValue but (ON or OFF).
counterValue (c_uint32): A 32-bit unsigned integer, representing a counter
frozenCounterValue (c_uint32): Similar to counterValue, but the counter is "frozen" (i.e., a snapshot of the counter's value taken at a certain time).
analogValue (c_double): A double-precision floating-point value representing analog measurements, such as temperature, voltage, etc.
analogOutputStatusValue (c_double): Similar to analogValue, but for analog outputs. It can represent things like the current output status of a control.
MASTER DNP3
The client_state_on_change callback handles client state changes, which prints the new state whenever it changes.
The port_state_on_change callback is structured well for printing port state changes
STEP 1
- Countered issues being not compatible MAC architecture
Runing grid-lab
nix flake issue with M3 chip, even if I have permissions set
Bash & zsh Terminals
Basic Navigation & File Management
pwd Print the current directory.
ls List files in the directory.
ls -la List all files, including hidden, with details.
cd Change directory.
cd - Go back to the last directory.
mkdir Create a new directory.
touch Create an empty file.
rm Remove a file.
rm -rf Force delete a directory and its contents.
cp Copy files or directories.
mv Move or rename files.
Process Management
top or htop. Display active processes (htop is more user-friendly).
kill . Terminate a process by PID.
kill -9 Force kill a process.
jobs List background jobs.
fg <job_id> Bring a background job to the foreground.
bg <job_id>. Resume a job in the background.
nohup & Run a command immune to logouts.
Netwokring commands
curl -O Download a file from a URL.
wget Another way to download files.
ping Test connectivity to a host.
traceroute Show the route packets take to a host.
netstat -tulnp Show open ports.
Basic Network Information
ifconfig # Show network interfaces (deprecated, use ip instead)
ip a # Display IP addresses and interfaces
ip r # Show routing table
hostname -I # Show local IP address
whois # Get WHOIS information of a domain
dig # Get DNS records of a domain
nslookup # Query a domain’s IP address
arp -a # Show ARP table (IP-MAC mappings)
iwconfig # Show wireless interface details (for Wi-Fi)
Network Scanning & Analysis
nmap -sP 192.168.1.0/24 # Scan active devices in a subnet
nmap -sV # Scan open ports and detect service versions
nmap -A # Run aggressive scan (detect OS, services)
tcpdump -i eth0 # Capture packets on interface eth0
tcpdump -nn port 80 # Capture HTTP traffic
wireshark # Open Wireshark (GUI packet analyzer)
netstat -tulnp # Show all listening ports and associated processes
ss -tulnp # Faster alternative to netstat
lsof -i :80 # List processes using port 80
Network Troubleshooting
ping # Check if a host is reachable
traceroute # Show the path packets take
mtr # Real-time traceroute with stats
curl -I # Get HTTP headers of a URL
wget --spider # Check if a website is accessible
telnet # Test if a port is open
nc -zv # Another way to check if a port is open
ethtool eth0 # Get information about Ethernet interfaces
ip link set eth0 down # Disable an interface
ip link set eth0 up # Enable an interface
Week 5
The files are hosted on my personal GT OneDrive since nowhere else has >2GB for free. Download the files there.
Steps (Linux or Mac)
Make scripts executable: chmod +x run.sh connect.sh
Make a directory for sharing files between the host and VM: mkdir share
In the first terminal, type ./run.sh share/
In the second terminal, type ./connect.sh
You should now be logged into the VM. Type ls -la and you should see some files already there named setup_linux.sh, setup_mac.sh, and setup_windows.sh.
If on Linux, run ./setup_linux.sh. If on Mac, run ./setup_mac.sh.
It will prompt for your password. Enter networking.
If nothing happens, then you are good. That setup script should've activated the share directory, so test it out by doing touch share/test.
Now, on your host machine, navigate to the same directory you've been working out of (the one with the directory named share that we created in step 4). Look inside that share directory, and you should see a file named test. This is the same one we created in step 12, which means that the shared directory between the host and VM is working.
Everything is good to go. Keep the first terminal open (the one that says "Welcome to Grub!") in the background. This is running your VM in the background, while the second terminal is ssh'd into it.
dnp-example
Install basic tools we need to run the example
sudo apt update
sudo apt install git gcc g++ cmake -y
Create a build directory for CMake to place its files
mkdir build
cd build
Build the project
make ..
make
From here, you will need to open another terminal through ssh. This means repeating steps 2, 6, 7, and 8 to get another terminal open.
In that newly connected terminal, run these commands:
cd dnp3-example/default_example/build
./outstation_example TCP
Now in the other terminal, run this:
./master_example TCP
If you see a bunch of text on both terminals, then the example is working.
Press Ctrl+c on both terminals to stop the example.
cps-costimulation-env
Week 6 - Guest Lecture
Aerospace and defense Research team within GTRI
Hardware Security in Power Grid(both physical and digital locks)
Hardware - vulnerable due to being remote
Digital is secured using cryptography
Every code runs on hardware. side effect: timing, electromagnetic radiation, power consumption
Week 7
Worked on research paper this week. OWkred on section 4, pard 5 implementing DNP3 architecture
Week 8
Day of presentation
Week 9
Details about Task 3. There are actually a lot of subtasks for this one, but these are the main two:
Read handlers - whenever the master receives values from an outstation, the DNP3 library calls a function that you specify through a function pointer. These functions are called "callbacks." There are different functions for the different types of values the master receives (e.g., a binary value vs a string). More info: https://docs.stepfunc.io/dnp3/1.6.0/guide/docs/api/master/read_handler
The functions listed in the docs there still exist in all the examples (dnp3-example/c_api_example/dnp3-module/src/dnp3/master.c, dnp3-example/ctypes_example/src/master/master.c, and dnp3-example/default_example/master_example.c).
Our goal is to be able to write the callback functions in Python, since we don't want to specify how the master actually behaves in C (since Python is easier for that). For example, we might write a function in Python that says "when I receive a new analog value representing the voltage, print it, and if it is >50 kV, tell the other outstations to shut off."
Controls - For that above example, how would we actually tell the other outstations to shut off? We need control functions. We want to be able to call the DNP3 library functions for sending commands/controls to outstations from Python. This should be pretty simple and mirrors Piper's task, which is simply exposing some methods to the Python code using the extension module API. More info: https://docs.stepfunc.io/dnp3/1.6.0/guide/docs/api/master/association/controls
#Week 10
Still working on Task3 and completing DNP documentation
Week 12 Guest Lecture
Lecute guest - Trevor M.Lewis
Cyber Network Operations
Observed problems in Critical Infrastructure:
Why do attacks on Critical Infrsatructure exits?
Vulnerabilities --> sush as knows CVs, patched, zero days
For task 3 I want to make it possible to write Python functions that act as callbacks when the device receives new data. Basically, I'm building the ability for the system to react in Python when something comes in from the field.
When a DNP3 device (like an outstation or master) receives a new value or command, it needs to know what to do. Right now, the code just logs it. But in the real world, it should actually act on that information.
In C, this is done using function pointers passed to the DNP3
I’m handling the Master, I’m working with the read handler instead of the control handler.
My goal:
Let Python functions handle these events instead of C functions.
To do that, I need to:
Create C extension methods that allow Python to set callback functions.
These must be set before creating the Outstation or Master object (because the C struct is created during that process).
That means I’ll need to write a Python class that holds these handlers and pass it as a parameter to the Outstation/Master constructor.
So, I’ll be building this out for the Master side, using dnp3_read_handler_t.
Creating a Screen Recording of Launching QEMU to Access CPS-Cosimulation: A Demonstration for macOS Users
This screen recording serves as a visual demonstration of how to successfully launch QEMU on a macOS system in order to access the CPS-co-simulation environment. The goal is to verify and showcase that the simulation setup is fully operational on a Mac device, offering a practical reference for users who may be setting this up for the first time or encountering system-specific issues.
Week 16
Working with MAria and Changmin for mo portion of my Final Paper