ObfAx β Siamese Network for IP Theft Detection in Approximate Circuits
Model Summary
Two trained variants of a Siamese Convolutional Neural Network that decides whether a pair of 8-bit approximate multipliers shares a provenance relationship (i.e. one was derived by obfuscating the other). Each multiplier is represented as a 256Γ256 arithmetic error heat map. The model outputs a scalar similarity score in [0, 1]; values above 0.5 indicate a derived (stolen) circuit.
| File | Variant | Training data |
|---|---|---|
siamese_standard_model.pth |
Standard | Original input order |
siamese_flip_model.pth |
Flip-augmented | Input-swapped pairs included |
The dataset used for training is available at ehw-fit/obfax.
Architecture
SiameseNetwork(input_channels=1, embedding_dim=128)
βββ feature_extractor # shared CNN branch
β Conv2d(1β32, 5Γ5) + BN + ReLU + MaxPool β 128Γ128
β Conv2d(32β64, 5Γ5) + BN + ReLU + MaxPool β 64Γ64
β Conv2d(64β128, 3Γ3)+ BN + ReLU + MaxPool β 32Γ32
β Conv2d(128β256,3Γ3)+ BN + ReLU + MaxPool β 16Γ16
β Conv2d(256β512,3Γ3)+ BN + ReLU + MaxPool β 8Γ8
βββ embedding_net # 32768 β 512 β 256 β 128
βββ classifier # 256 β 64 β 32 β 1 (Sigmoid)
Both branches share weights. Their 128-dim embeddings are concatenated and passed to the classification head.
Total parameters: ~18.5 M
Usage
Load and run inference
import torch
import numpy as np
from model import SiameseNetwork
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = SiameseNetwork(input_channels=1, embedding_dim=128)
model.load_state_dict(torch.load("siamese_standard_model.pth", map_location=device))
model.eval()
model.to(device)
def heatmap_to_tensor(heatmap: np.ndarray) -> torch.Tensor:
"""Convert a (256, 256) int array to a normalised (1, 1, 256, 256) tensor."""
x = heatmap.astype(np.float32)
x = (x - x.mean()) / (x.std() + 1e-8)
return torch.from_numpy(x).unsqueeze(0).unsqueeze(0) # (1, 1, 256, 256)
# feat1 / feat2 are (256, 256) numpy arrays from the dataset
img1 = heatmap_to_tensor(feat1).to(device)
img2 = heatmap_to_tensor(feat2).to(device)
with torch.no_grad():
score = model(img1, img2).item() # float in [0, 1]
print("Derived (IP theft):", score > 0.5)
Batch evaluation
from torch.utils.data import DataLoader
from dataset import get_np_dataset
test_dataset = get_np_dataset("data/test_data.npz")
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False, num_workers=4)
model.eval()
correct = total = 0
with torch.no_grad():
for img1, img2, labels in test_loader:
img1, img2, labels = img1.to(device), img2.to(device), labels.to(device)
outputs = model(img1, img2)
predicted = (outputs > 0.5).float()
correct += (predicted == labels).sum().item()
total += labels.size(0)
print(f"Accuracy: {100 * correct / total:.2f}%")
Training
- Loss: Binary Cross-Entropy (
nn.BCELoss) - Epochs: 50
- Batch size: 16
- Optimiser: see
03_train.py - Hardware: CUDA if available, CPU fallback
Evaluation
The 04_eval.py script reports accuracy, sensitivity (recall on same=1), and specificity (recall on same=0) for every model Γ dataset combination:
python 04_eval.py # writes eval_results.txt (JSON lines)
Intended Use
- Detecting IP theft in approximate arithmetic circuits
- Research on circuit fingerprinting and hardware obfuscation
- Baseline for similarity learning on error-profile data
Out-of-Scope Use
- Production IP-protection systems without further validation
- Circuit types other than 8-bit unsigned multipliers without re-training
Citation
@inproceedings{sekanina2026obfax,
author = {Lukas Sekanina and Vojtech Mrazek},
title = {{ObfAx}: Obfuscation and {IP} Piracy Detection in Approximate Circuits},
booktitle = {Proceedings of the Great Lakes Symposium on VLSI (GLSVLSI)},
year = {2026},
doi = {10.1145/3787109.3815215}
}