M. Ali Nasseri

73 papers A* 14A 3Journal 29Unranked 27
YearRankTypeTitle / Venue / Authors
2025 A* conf
ICRA
Hongli Liang, Jiali Liu, M. Ali Nasseri, Haotian Lin, Kai Huang
2025 conf
BIBM
Zhihao Zhao, Yinzheng Zhao, Junjie Yang, Xiangtong Yao, Quanmin Liang, Shahrooz Faghihroohi, Kai Huang, Nassir Navab, M. Ali Nasseri
2025 J jnl
CoRR
Zhihao Zhao, Yinzheng Zhao, Junjie Yang, Xiangtong Yao, Quanmin Liang, Shahrooz Faghihroohi, Kai Huang, Nassir Navab, M. Ali Nasseri
2025 J jnl
CoRR
Angelo Henriques, Korab Hoxha, Daniel Zapp, Peter C. Issa, Nassir Navab, M. Ali Nasseri
2025 A* conf
ICRA
Junjie Yang, Satoshi Inagaki, Zhihao Zhao, Daniel Zapp, Mathias Maier, Peter C. Issa, Kai Huang, Nassir Navab, M. Ali Nasseri
2025 J jnl
IEEE Access
Alireza Alikhani, Van Dai Nguyen, Satoshi Inagaki, Benjamin Busam, Koorosh Faridpooya, Mathias Maier, Peter Gehlbach, Iulian Iordachita, Nassir Navab, M. Ali Nasseri, Daniel Zapp
2025 A* conf
ICRA
Satoshi Inagaki, Alireza Alikhani, Nassir Navab, Peter C. Issa, M. Ali Nasseri
2025 J jnl
CoRR
Satoshi Inagaki, Alireza Alikhani, Nassir Navab, Peter C. Issa, M. Ali Nasseri
2025 A* conf
ICRA
Demir Arikan, Peiyao Zhang, Michael Sommersperger, Shervin Dehghani, Mojtaba Esfandiari, Russell H. Taylor, M. Ali Nasseri, Peter Gehlbach, Nassir Navab, Iulian Iordachita
2025 conf
ISMR
Demir Arikan, Mojtaba Esfandiari, Peiyao Zhang, Michael Sommersperger, Shervin Dehghani, Russell H. Taylor, M. Ali Nasseri, Peter Gehlbach, Nassir Navab, Iulian Iordachita
2025 conf
BIBM
Zhihao Zhao, Yinzheng Zhao, Junjie Yang, Xiangtong Yao, Quanmin Liang, Daniel Zapp, Kai Huang, Nassir Navab, M. Ali Nasseri
2025 J jnl
CoRR
Zhihao Zhao, Yinzheng Zhao, Junjie Yang, Xiangtong Yao, Quanmin Liang, Daniel Zapp, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 J jnl
CoRR
Yinzheng Zhao, Zhihao Zhao, Junjie Yang, Li Li, M. Ali Nasseri, Daniel Zapp
2024 A conf
IROS
Jun Xia, Ting Wang, Huanqi Ni, Yanlin Li, Ruoxi Chen, M. Ali Nasseri, Haotian Lin, Kai Huang
2024 A* conf
ICRA
Satoshi Inagaki, Alireza Alikhani, Nassir Navab, Mathias Maier, M. Ali Nasseri
2024 J jnl
IEEE Trans. Ind. Electron.
Hongli Liang, Ting Wang, Jun Xia, M. Ali Nasseri, Haotian Lin, Kai Huang
2024 A* conf
ICRA
Shervin Dehghani, Michael Sommersperger, Mahdi Saleh, Alireza Alikhani, Benjamin Busam, Peter Gehlbach, Iulian Iordachita, Nassir Navab, M. Ali Nasseri
2024 A* conf
ICRA
Alireza Alikhani, Satoshi Inagaki, Shervin Dehghani, Mathias Maier, Nassir Navab, M. Ali Nasseri
2024 A* conf
ICRA
Simon Pannek, Shervin Dehghani, Michael Sommersperger, Peiyao Zhang, Peter Gehlbach, M. Ali Nasseri, Iulian Iordachita, Nassir Navab
2024 J jnl
CoRR
Zhihao Zhao, Junjie Yang, Shahrooz Faghihroohi, Yinzheng Zhao, Daniel Zapp, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 conf
BIBM
Zhihao Zhao, Junjie Yang, Shahrooz Faghihroohi, Yinzheng Zhao, Daniel Zapp, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 J jnl
IEEE Robotics Autom. Lett.
Junjie Yang, Zhihao Zhao, Siyuan Shen, Daniel Zapp, Mathias Maier, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 A conf
IROS
Junjie Yang, Zhihao Zhao, Yinzheng Zhao, Daniel Zapp, Mathias Maier, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 conf
BIBM
Zhihao Zhao, Yinzheng Zhao, Junjie Yang, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 J jnl
CoRR
Zhihao Zhao, Yinzheng Zhao, Junjie Yang, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 J jnl
CoRR
Zhihao Zhao, Shahrooz Faghihroohi, Yinzheng Zhao, Junjie Yang, Shipeng Zhong, Kai Huang, Nassir Navab, Boyang Li, M. Ali Nasseri
2024 J jnl
CoRR
Demir Arikan, Peiyao Zhang, Michael Sommersperger, Shervin Dehghani, Mojtaba Esfandiari, Russell H. Taylor, M. Ali Nasseri, Peter Gehlbach, Nassir Navab, Iulian Iordachita
2024 A conf
IROS
Junjie Yang, Satoshi Inagaki, Zhihao Zhao, Daniel Zapp, Mathias Maier, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 A* conf
ICRA
Junjie Yang, Zhihao Zhao, Mathias Maier, Kai Huang, Nassir Navab, M. Ali Nasseri
2024 J jnl
CoRR
Demir Arikan, Peiyao Zhang, Michael Sommersperger, Shervin Dehghani, Mojtaba Esfandiari, Russell H. Taylor, M. Ali Nasseri, Peter Gehlbach, Nassir Navab, Iulian Iordachita
2023 J jnl
CoRR
Junjie Yang, Zhihao Zhao, Siyuan Shen, Daniel Zapp, Mathias Maier, Kai Huang, Nassir Navab, M. Ali Nasseri
2023 conf
MICCAI (3)
Zhihao Zhao, Junjie Yang, Shahrooz Faghihroohi, Kai Huang, Mathias Maier, Nassir Navab, M. Ali Nasseri
2023 conf
EMBC
Korab Hoxha, Alireza Alikhani, Satoshi Inagaki, Manuel Ferle, Mathias Maier, M. Ali Nasseri
2023 J jnl
IEEE Access
Alireza Alikhani, Satoshi Inagaki, Junjie Yang, Shervin Dehghani, Michael Sommersperger, Kai Huang, Mathias Maier, Nassir Navab, M. Ali Nasseri
2023 conf
EMBC
Alireza Alikhani, Sebastian Oßner, Shervin Dehghani, Benjamin Busam, Satoshi Inagaki, Mathias Maier, Nassir Navab, M. Ali Nasseri
2023 A* conf
ICRA
Shervin Dehghani, Michael Sommersperger, Peiyao Zhang, Alejandro Martin-Gomez, Benjamin Busam, Peter Gehlbach, Nassir Navab, M. Ali Nasseri, Iulian Iordachita
2023 J jnl
CoRR
Shervin Dehghani, Michael Sommersperger, Peiyao Zhang, Alejandro Martin-Gomez, Benjamin Busam, Peter Gehlbach, Nassir Navab, M. Ali Nasseri, Iulian Iordachita
2023 conf
MICCAI (9)
Michael Sommersperger, Shervin Dehghani, Philipp Matten, Kristina Mach, M. Ali Nasseri, Hessam Roodaki, Ulrich Eck, Nassir Navab
2023 J jnl
Robotica
Mingchuan Zhou, Felix Hennerkes, Jingsong Liu, Zhongliang Jiang, Thomas Wendler, M. Ali Nasseri, Iulian Iordachita, Nassir Navab
2022 J jnl
CoRR
Shervin Dehghani, Benjamin Busam, Nassir Navab, M. Ali Nasseri
2022 A* conf
ICRA
Shervin Dehghani, Michael Sommersperger, Junjie Yang, Mehrdad Salehi, Benjamin Busam, Kai Huang, Peter Gehlbach, Iulian Iordachita, Nassir Navab, M. Ali Nasseri
2022 conf
BIBM
Kristina Mach, Shuwen Wei, Ji Woong Kim, Alejandro Martin-Gomez, Peiyao Zhang, Jin U. Kang, M. Ali Nasseri, Peter Gehlbach, Nassir Navab, Iulian Iordachita
2021 J jnl
CoRR
Shervin Dehghani, Michael Sommersperger, Junjie Yang, Benjamin Busam, Kai Huang, Peter Gehlbach, Iulian Iordachita, Nassir Navab, M. Ali Nasseri
2021 J jnl
IEEE Robotics Autom. Lett.
Mingchuan Zhou, Jiahao Wu, Ali Ebrahimi, Niravkumar A. Patel, Yunhui Liu, Nassir Navab, Peter Gehlbach, Alois C. Knoll, M. Ali Nasseri, Iulian Iordachita
2020 J jnl
IEEE J. Biomed. Health Informatics
Mhd Hasan Sarhan, M. Ali Nasseri, Daniel Zapp, Mathias Maier, Chris P. Lohmann, Nassir Navab, Abouzar Eslami
2020 A* conf
ICRA
Jun Xia, Sean J. Bergunder, Duoru Lin, Ying Yan, Shengzhi Lin, M. Ali Nasseri, Mingchuan Zhou, Haotian Lin, Kai Huang
2020 conf
MICCAI (5)
Jakob Weiss, Michael Sommersperger, M. Ali Nasseri, Abouzar Eslami, Ulrich Eck, Nassir Navab
2020 conf
ISMR
Mingchuan Zhou, Jiahao Wu, Ali Ebrahimi, Niravkumar A. Patel, Changyan He, Peter Gehlbach, Russell H. Taylor, Alois C. Knoll, M. Ali Nasseri, Iulian Iordachita
2020 J jnl
CoRR
Mingchuan Zhou, Jiahao Wu, Ali Ebrahimi, Niravkumar A. Patel, Changyan He, Peter Gehlbach, Russell H. Taylor, Alois C. Knoll, M. Ali Nasseri, Iulian Iordachita
2020 J jnl
IEEE Trans. Ind. Electron.
Mingchuan Zhou, Qiming Yu, Kai Huang, Simeon Mahov, Abouzar Eslami, Mathias Maier, Chris P. Lohmann, Nassir Navab, Daniel Zapp, Alois C. Knoll, M. Ali Nasseri
2019 J jnl
IEEE Access
Mingchuan Zhou, Hao Xing, Abouzar Eslami, Kai Huang, Caixia Cai, Chris P. Lohmann, Nassir Navab, Alois C. Knoll, M. Ali Nasseri
2019 conf
VCBM
Jakob Weiss, Ulrich Eck, M. Ali Nasseri, Mathias Maier, Abouzar Eslami, Nassir Navab
2019 A* conf
ICRA
Mingchuan Zhou, Xijia Wang, Jakob Weiss, Abouzar Eslami, Kai Huang, Mathias Maier, Chris P. Lohmann, Nassir Navab, Alois C. Knoll, M. Ali Nasseri
2019 J jnl
J. Circuits Syst. Comput.
Mingchuan Zhou, Long Cheng, Manuel Dell'antonio, Xiebing Wang, Zhenshan Bing, M. Ali Nasseri, Kai Huang, Alois C. Knoll
2019 conf
EMBC
Hadi Askari Poor, Mingchuan Zhou, Chris P. Lohmann, Pietro Cerveri, M. Ali Nasseri
2018 J jnl
J. Medical Robotics Res.
Sabine Thürauf, Oliver Hornung, Mario Körner, Florian Vogt, Alois C. Knoll, M. Ali Nasseri
2018 A* conf
ICRA
Mingchuan Zhou, Kai Huang, Abouzar Eslami, Hessam Roodaki, Daniel Zapp, Mathias Maier, Chris P. Lohmann, Alois C. Knoll, M. Ali Nasseri
2018 J jnl
Int. J. Comput. Assist. Radiol. Surg.
Sasan Matinfar, M. Ali Nasseri, Ulrich Eck, Michael Kowalsky, Hessam Roodaki, Navid Navab, Chris P. Lohmann, Mathias Maier, Nassir Navab
2018 J jnl
IEEE Robotics Autom. Lett.
Mingchuan Zhou, Mahdi Hamad, Jakob Weiss, Abouzar Eslami, Kai Huang, Mathias Maier, Chris P. Lohmann, Nassir Navab, Alois C. Knoll, M. Ali Nasseri
2018 J jnl
CoRR
Mingchuan Zhou, Mahdi Hamad, Jakob Weiss, Abouzar Eslami, Kai Huang, Mathias Maier, Chris P. Lohmann, Nassir Navab, Alois C. Knoll, M. Ali Nasseri
2017 conf
EMBC
M. Ali Nasseri, Mathias Maier, Chris P. Lohmann
2017 conf
ROBIO
Mingchuan Zhou, Kai Huang, Abouzar Eslami, Hessam Roodaki, Haotian Lin, Chris P. Lohmann, Alois C. Knoll, M. Ali Nasseri
2017 conf
EMBC
Sabine Thürauf, Mario Körner, Florian Vogt, Oliver Hornung, M. Ali Nasseri, Alois C. Knoll
2017 conf
MICCAI (2)
Sasan Matinfar, M. Ali Nasseri, Ulrich Eck, Hessam Roodaki, Navid Navab, Chris P. Lohmann, Mathias Maier, Nassir Navab
2016 conf
BioRob
Sabine Thürauf, Markus Wolf, Mario Körner, Florian Vogt, Oliver Hornung, M. Ali Nasseri, Alois C. Knoll
2016 conf
EMBC
Sabine Thürauf, Florian Vogt, Oliver Hornung, Mario Körner, M. Ali Nasseri, Alois C. Knoll
2016 conf
EMBC
Alexander A. Bielski, Chris P. Lohmann, Mathias Maier, Daniel Zapp, M. Ali Nasseri
2015 conf
EMBC
Alexander Barthel, Diego Trematerra, M. Ali Nasseri, Daniel Zapp, Chris P. Lohmann, Alois C. Knoll, Mathias Maier
2014 conf
HAPTICS
Amin Mahdizadeh, M. Ali Nasseri, Alois C. Knoll
2013 conf
AIM
M. Ali Nasseri, Martin Eder, D. Eberts, Suraj Nair, Mathias Maier, Daniel Zapp, Chris P. Lohmann, Alois C. Knoll
2013 conf
EMBC
M. Ali Nasseri, Martin Eder, Suraj Nair, Emmanuel C. Dean-Leon, Mathias Maier, Daniel Zapp, Chris P. Lohmann, Alois C. Knoll
2012 conf
BMEI
M. Ali Nasseri, Emmanuel C. Dean-Leon, Suraj Nair, Martin Eder, Alois C. Knoll, Mathias Maier, Chris P. Lohmann
2011 conf
SWIS
M. Ali Nasseri, Masoud Asadpour
redb/extractors/decompiler/bninja/analysis/cfg_features.py
← Index redb/extractors/decompiler/bninja/analysis/cfg_features.py python
import struct
from collections import deque
from typing import Optional

import blake3
import mmh3


# ---------------------------------------------------------------------------
# Task 1.1: Core Graph Utilities
# ---------------------------------------------------------------------------

def bfs_order(successors: list[list[int]], n: int) -> list[int]:
    """
    BFS traversal from node 0 (entry block), returns node indices in visit order.
    Unreachable nodes appended at the end.
    """
    if n == 0:
        return []

    visited = set()
    order = []
    queue = deque([0])
    visited.add(0)

    while queue:
        idx = queue.popleft()
        order.append(idx)
        for target in successors[idx]:
            if target not in visited:
                visited.add(target)
                queue.append(target)

    # Append unreachable blocks (dead code)
    for i in range(n):
        if i not in visited:
            order.append(i)

    return order


def bfs_max_depth(successors: list[list[int]], n: int) -> int:
    """
    Maximum BFS depth from entry block (node 0).
    Replaces the per-block depth column with a single scalar.
    """
    if n == 0:
        return 0

    depth = {0: 0}
    max_d = 0
    queue = deque([0])

    while queue:
        node = queue.popleft()
        for s in successors[node]:
            if s not in depth:
                depth[s] = depth[node] + 1
                if depth[s] > max_d:
                    max_d = depth[s]
                queue.append(s)

    return max_d


# ---------------------------------------------------------------------------
# Task 1.2: Back-Edge Detection (Iterative DFS)
# ---------------------------------------------------------------------------

def count_back_edges(successors: list[list[int]], n: int) -> int:
    """
    Count natural loops via iterative DFS back-edge detection.
    A back edge is an edge to a GRAY (in-stack) node.

    Iterative to avoid stack overflow on functions with 1000+ blocks
    (common in obfuscated malware, VM dispatchers, unrolled loops).
    """
    if n == 0:
        return 0

    WHITE, GRAY, BLACK = 0, 1, 2
    color = [WHITE] * n
    back_edges = 0

    stack = [(0, iter(successors[0]))]
    color[0] = GRAY

    while stack:
        u, children = stack[-1]
        try:
            v = next(children)
            if color[v] == GRAY:
                back_edges += 1
            elif color[v] == WHITE:
                color[v] = GRAY
                stack.append((v, iter(successors[v])))
        except StopIteration:
            color[u] = BLACK
            stack.pop()

    return back_edges


# ---------------------------------------------------------------------------
# Task 1.3: Topology Hash
# ---------------------------------------------------------------------------

def compute_topology_hash(
    successors: list[list[int]],
    bfs: list[int],
    n: int,
) -> bytes:
    """
    BLAKE3 hash of BFS-ordered canonical adjacency.
    Pure graph shape — ignores all block content.
    Two functions with identical control flow structure produce identical hashes.

    Returns 16 bytes (128-bit).
    """
    if n == 0:
        return b'\x00' * 16

    # Remap: original index -> BFS position
    remap = {original: position for position, original in enumerate(bfs)}

    canonical = bytearray()
    for position in range(n):
        original_idx = bfs[position]
        remapped_succs = sorted(
            remap[s] for s in successors[original_idx] if s in remap
        )
        # Pack: node_index (2 bytes) + num_successors (1 byte) + successor indices (2 bytes each)
        canonical.extend(struct.pack('<HB', position, len(remapped_succs)))
        for s in remapped_succs:
            canonical.extend(struct.pack('<H', s))

    return blake3.blake3(bytes(canonical)).digest(length=16)


# ---------------------------------------------------------------------------
# Task 1.4: MD-Index (Top-Down and Bottom-Up)
# ---------------------------------------------------------------------------

def compute_md_index_topdown(
    successors: list[list[int]],
    predecessors: list[list[int]],
    bfs: list[int],
) -> int:
    """
    BinDiff-style top-down MD-index.
    Hash of (in_degree, out_degree) sequence in BFS order from entry.
    Returns UInt64.
    """
    if not bfs:
        return 0

    degree_bytes = bytearray()
    for idx in bfs:
        in_deg = min(len(predecessors[idx]), 255)
        out_deg = min(len(successors[idx]), 255)
        degree_bytes.extend(struct.pack('<BB', in_deg, out_deg))

    h = blake3.blake3(bytes(degree_bytes)).digest(length=8)
    return struct.unpack('<Q', h)[0]


def compute_md_index_bottomup(
    successors: list[list[int]],
    predecessors: list[list[int]],
    n: int,
) -> int:
    """
    Bottom-up MD-index: BFS from exit blocks (no successors),
    traversing edges in reverse.
    Returns UInt64.
    """
    if n == 0:
        return 0

    exits = [i for i in range(n) if len(successors[i]) == 0]
    if not exits:
        exits = [n - 1]  # Fallback: use last block

    visited = set(exits)
    order = []
    queue = deque(exits)

    while queue:
        idx = queue.popleft()
        order.append(idx)
        for pred in predecessors[idx]:
            if pred not in visited:
                visited.add(pred)
                queue.append(pred)

    # Append unreachable blocks
    for i in range(n):
        if i not in visited:
            order.append(i)

    degree_bytes = bytearray()
    for idx in order:
        in_deg = min(len(predecessors[idx]), 255)
        out_deg = min(len(successors[idx]), 255)
        degree_bytes.extend(struct.pack('<BB', in_deg, out_deg))

    h = blake3.blake3(bytes(degree_bytes)).digest(length=8)
    return struct.unpack('<Q', h)[0]


# ---------------------------------------------------------------------------
# Task 1.5: Prime Product
# ---------------------------------------------------------------------------

# Small primes assigned to LLIL opcode categories.
# Keys are the integer values of binaryninja.LowLevelILOperation enum members.
# We use integer keys so this module doesn't import binaryninja.
#
# Mapping rationale: same operation class -> same prime.
# Using LLIL (not native asm) makes this architecture-independent.
#
# Populated at import time by cfg.py using the real LowLevelILOperation enum values.
# Unknown ops map to prime 1 (identity element) in compute_prime_product().
LLIL_OP_PRIMES: dict[int, int] = {}


def compute_prime_product(llil_operations: list[int]) -> int:
    """
    Product of small primes assigned to each LLIL opcode.
    Position-independent: block reordering doesn't change the result.
    Mod 2^64 for fixed-size storage.

    Args:
        llil_operations: flat list of LLIL operation enum integer values
                         for all instructions in the function.
    Returns:
        UInt64 prime product, or 0 if no instructions.
    """
    if not llil_operations:
        return 0

    product = 1
    for op in llil_operations:
        prime = LLIL_OP_PRIMES.get(op, 1)
        product = (product * prime) % (2**64)

    return product


# ---------------------------------------------------------------------------
# Task 1.6: ACFG Block Features
# ---------------------------------------------------------------------------

# Instruction category indices for ACFG feature vectors
CAT_ARITHMETIC = 0
CAT_LOGIC = 1
CAT_TRANSFER = 2
CAT_CALL = 3
CAT_COMPARISON = 4
CAT_MEMORY = 5
CAT_OTHER = 6

# Maps LLIL operation integer values to category indices.
# Populated at import time by cfg.py using the real LowLevelILOperation enum.
LLIL_OP_CATEGORIES: dict[int, int] = {}


def build_block_features(
    block_llil_ops: list[list[int]],
    successors: list[list[int]],
    n: int,
) -> list[list[int]]:
    """
    Extract Gemini-style ACFG features per block.

    Args:
        block_llil_ops: per-block list of LLIL operation integer values.
                        block_llil_ops[i] is the list of ops for block i.
                        Empty list if LLIL unavailable for that block.
        successors: index-based adjacency list.
        n: number of blocks.

    Returns:
        List of [instr_count, arithmetic, logic, transfer, call, comparison,
                 memory, successor_count] per block. All values capped at 65535.
    """
    features = []
    for i in range(n):
        cats = [0, 0, 0, 0, 0, 0, 0]
        ops = block_llil_ops[i] if i < len(block_llil_ops) else []
        for op in ops:
            cat = LLIL_OP_CATEGORIES.get(op, CAT_OTHER)
            cats[cat] += 1

        instr_count = len(ops)
        features.append([
            min(instr_count, 65535),
            min(cats[CAT_ARITHMETIC], 65535),
            min(cats[CAT_LOGIC], 65535),
            min(cats[CAT_TRANSFER], 65535),
            min(cats[CAT_CALL], 65535),
            min(cats[CAT_COMPARISON], 65535),
            min(cats[CAT_MEMORY], 65535),
            min(len(successors[i]), 65535),
        ])

    return features


# ---------------------------------------------------------------------------
# Task 1.7: CFG Feature TLSH
# ---------------------------------------------------------------------------

def compute_cfg_feature_tlsh(
    bb_features: list[list[int]],
    bfs: list[int],
) -> Optional[str]:
    """
    TLSH hash of BFS-ordered per-block feature vectors.
    Captures both structure (BFS ordering) and instruction distribution.

    Returns TLSH hex string or None if too few bytes for TLSH (< 50).
    """
    import tlsh as _tlsh

    feature_bytes = bytearray()
    for idx in bfs:
        feats = bb_features[idx]
        feature_bytes.extend(struct.pack(
            '<HBBBBBBB',
            min(feats[0], 65535),
            min(feats[1], 255),
            min(feats[2], 255),
            min(feats[3], 255),
            min(feats[4], 255),
            min(feats[5], 255),
            min(feats[6], 255),
            min(feats[7], 255),
        ))

    if len(feature_bytes) < 50:
        return None

    try:
        h = _tlsh.hash(bytes(feature_bytes))
        return h if h and h != 'TNULL' else None
    except Exception:
        return None


# ---------------------------------------------------------------------------
# Task 1.8: WL-MinHash
# ---------------------------------------------------------------------------

# Pre-computed seeds for MinHash permutations.
NUM_WL_MINHASH_PERMS = 128
_WL_MINHASH_SEEDS = list(range(NUM_WL_MINHASH_PERMS))  # Seeds 0..127


def compute_wl_minhash(
    successors: list[list[int]],
    predecessors: list[list[int]],
    bb_features: list[list[int]],
    n: int,
    iterations: int = 3,
) -> list[int]:
    """
    Weisfeiler-Leman MinHash for fuzzy topology similarity.

    Initial labels: mmh3 hash of per-block ACFG feature tuple (content-aware).
    WL refinement: incorporate sorted neighbor labels at each iteration.
    MinHash: 128-permutation signature over shingle set.

    Returns list of 128 uint8 values, or [255]*128 sentinel for empty functions.
    """
    if n == 0:
        return [255] * NUM_WL_MINHASH_PERMS

    # Initial labels: hash of instruction category tuple per block
    labels = []
    for i in range(n):
        feats = bb_features[i] if i < len(bb_features) else [0] * 8
        # mmh3 with seed=0 for initial labels
        label = mmh3.hash(str(tuple(feats)), 0) & 0xFFFFFFFF
        labels.append(label)

    # Collect shingles: (iteration, label) pairs as strings for mmh3
    shingles: set[str] = set()

    # Iteration 0: individual block labels
    for label in labels:
        shingles.add(f"0:{label}")

    # WL iterations: refine labels by neighborhood aggregation
    for iteration in range(1, iterations + 1):
        new_labels = []
        for i in range(n):
            succ_labels = tuple(sorted(labels[s] for s in successors[i]))
            pred_labels = tuple(sorted(labels[p] for p in predecessors[i]))
            composite = f"{labels[i]}|{succ_labels}|{pred_labels}"
            new_label = mmh3.hash(composite, 0) & 0xFFFFFFFF
            new_labels.append(new_label)
            shingles.add(f"{iteration}:{new_label}")
        labels = new_labels

    if not shingles:
        return [255] * NUM_WL_MINHASH_PERMS

    # Compute MinHash signature using mmh3 with different seeds
    shingle_list = list(shingles)
    signature = []
    for seed in _WL_MINHASH_SEEDS:
        min_val = 0xFFFFFFFF
        for s in shingle_list:
            h = mmh3.hash(s, seed) & 0xFFFFFFFF
            if h < min_val:
                min_val = h
        # Compress to uint8 for storage
        signature.append(min_val & 0xFF)

    return signature


# ---------------------------------------------------------------------------
# Task 1.9: Packed Adjacency
# ---------------------------------------------------------------------------

def pack_adjacency(successors: list[list[int]]) -> list[int]:
    """
    Pack CFG edges as Array(UInt32).
    Each UInt32 = (source_index << 16) | target_index.
    Supports up to 65,535 blocks per function.
    """
    edges = []
    for src, targets in enumerate(successors):
        for tgt in targets:
            if src < 65536 and tgt < 65536:
                edges.append((src << 16) | tgt)
    return edges