Chai-Keong Toh

86 papers A* 2B 17C 3Misc 1Journal 53Unranked 10
YearRankTypeTitle / Venue / Authors
2023 J jnl
IEEE Trans. Intell. Transp. Syst.
Jamie Wubben, Daniel Hernández, José M. Cecilia, Baldomero Imbernón, Carlos T. Calafate, Juan-Carlos Cano, Pietro Manzoni, Chai-Keong Toh
2021 J jnl
IEEE Consumer Electron. Mag.
Chai-Keong Toh, Dejan S. Milojicic
2019 J jnl
IEEE Internet Comput.
Sergio Ortíz, Carlos T. Calafate, Juan-Carlos Cano, Pietro Manzoni, Chai-Keong Toh
2019 J jnl
IET Networks
Chai-Keong Toh, Juan-Carlos Cano, Carlos Fernandez-Laguia, Pietro Manzoni, Carlos T. Calafate
2018 J jnl
IEEE Internet Things Mag.
Juan-Carlos Cano, Victor Berrios, Ben Garcia, Chai-Keong Toh
2017 J jnl
J. Commun. Networks
Javier E. Meseguer, Chai-Keong Toh, Carlos T. Calafate, Juan-Carlos Cano, Pietro Manzoni
2016 J jnl
CoRR
Javier E. Meseguer, Chai-Keong Toh, Carlos Miguel Tavares Calafate, Juan-Carlos Cano, Pietro Manzoni
2013 J jnl
Wirel. Pers. Commun.
Francisco J. Martinez, Manuel Fogué, Chai-Keong Toh, Juan-Carlos Cano, Carlos Miguel Tavares Calafate, Pietro Manzoni
2013 J jnl
J. Commun. Networks
Miguel Baguena, Chai-Keong Toh, Carlos Miguel Tavares Calafate, Juan-Carlos Cano, Pietro Manzoni
2013 J jnl
J. Commun. Networks
Pietro Manzoni, Richard D. Gitlin, Chai-Keong Toh, Tao Zhang, Sadao Obana
2012 J jnl
Wirel. Pers. Commun.
Francisco J. Martinez, Chai-Keong Toh, Juan-Carlos Cano, Carlos Miguel Tavares Calafate, Pietro Manzoni
2012 J jnl
IEEE Intell. Transp. Syst. Mag.
Chai-Keong Toh, Teruo Higashino, Juan-Carlos Cano, Michele C. Weigle
2012 conf
CASE
Chai-Keong Toh, S. L. J. Ng, Y. O. Tan
2011 J jnl
Wirel. Pers. Commun.
Francisco J. Martinez, Chai-Keong Toh, Juan-Carlos Cano, Carlos Miguel Tavares Calafate, Pietro Manzoni
2011 J jnl
Wirel. Commun. Mob. Comput.
Francisco J. Martinez, Chai-Keong Toh, Juan-Carlos Cano, Carlos Miguel Tavares Calafate, Pietro Manzoni
2011 J jnl
Wirel. Pers. Commun.
Chai-Keong Toh
2010 J jnl
IEEE Trans. Veh. Technol.
Takaaki Umedu, Kumiko Isu, Teruo Higashino, Chai-Keong Toh
2010 J jnl
J. Commun. Networks
Dong-Won Kum, Anh-Ngoc Le, You Ze Cho, Chai-Keong Toh, In-Soo Lee
2010 J jnl
IEEE Commun. Mag.
José Cano, Juan-Carlos Cano, Chai-Keong Toh, Carlos Miguel Tavares Calafate, Pietro Manzoni
2010 J jnl
IEEE Intell. Transp. Syst. Mag.
Francisco J. Martinez, Chai-Keong Toh, Juan-Carlos Cano, Carlos Miguel Tavares Calafate, Pietro Manzoni
2009 J jnl
IEEE Commun. Mag.
Chai-Keong Toh, Anh-Ngoc Le, You Ze Cho
2009 J jnl
IEEE Trans. Veh. Technol.
Dongkyun Kim, Hong-Jong Jeong, Chai-Keong Toh, Sutaek Oh
2009 B conf
WCNC
Francisco J. Martinez, Chai-Keong Toh, Juan-Carlos Cano, Carlos Miguel Tavares Calafate, Pietro Manzoni
2009 J jnl
IEICE Trans. Commun.
Anh-Ngoc Le, Dong-Won Kum, You Ze Cho, Chai-Keong Toh
2007 J jnl
Wirel. Pers. Commun.
Juan-Carlos Cano, Pietro Manzoni, Dongkyun Kim, Chai-Keong Toh
2007 conf
ICOIN
Uhjin Joung, Dongkyun Kim, Nakjung Choi, Chai-Keong Toh
2007 conf
FGCN (2)
Chai-Keong Toh
2007 J jnl
IEEE Trans. Intell. Transp. Syst.
Chai-Keong Toh
2007 J jnl
IEEE Trans. Veh. Technol.
Dongkyun Kim, Hanseok Bae, Chai-Keong Toh
2007 J jnl
Int. J. Ad Hoc Ubiquitous Comput.
Chai-Keong Toh, Guillermo Guichal, Dongkyun Kim, Victor O. K. Li
2007 B conf
PIMRC
Dongkyun Kim, Chai-Keong Toh, Hongseok Yoo
2006 conf
ICOIN
Dongkyun Kim, Eun-sook Shim, Chai-Keong Toh
2006 conf
ISWCS
Dongkyun Kim, Juan-Carlos Cano, Pietro Manzoni, Chai-Keong Toh
2006 J jnl
Wirel. Commun. Mob. Comput.
Dongkyun Kim, Chai-Keong Toh
2006 J jnl
Wirel. Pers. Commun.
Juan-Carlos Cano, Pietro Manzoni, Chai-Keong Toh
2005 conf
ICNC (3)
Ji Zheng, Xin Wang, Xiangyang Xue, Chai-Keong Toh
2005 C conf
CIT
Xin Wang, Ji Zheng, Kun Xiao, Xiangyang Xue, Chai-Keong Toh
2005 C conf
PDCAT
Heng Xu, Xin Wang, Chai-Keong Toh
2005 C conf
ISCC
Juan-Carlos Cano, Pietro Manzoni, Chai-Keong Toh
2005 conf
ICCNMC
Yanping Li, Xin Wang, Florian Baueregger, Xiangyang Xue, Chai-Keong Toh
2005 B conf
GLOBECOM
Yanping Li, Xin Wang, Florian Baueregger, Xiangyang Xue, Chai-Keong Toh
2005 B conf
WCNC
Nakjung Choi, Chai-Keong Toh, Yongho Seok, Dongkyun Kim, Yanghee Choi
2005 J jnl
IEICE Trans. Commun.
Chai-Keong Toh, Kenichi Mase, Susumu Yoshida
2005 J jnl
IEICE Trans. Commun.
Chai-Keong Toh, Petri Mähönen, Mikko A. Uusitalo
2004 B conf
PIMRC
Dongkyun Kim, Chai-Keong Toh, Hong-Jong Jeong
2003 B conf
WCNC
Dongkyun Kim, Chai-Keong Toh, Juan-Carlos Cano, Pietro Manzoni
2003 B conf
WCNC
Wei Kang Tsai, Peng Zheng, Boyun Tu, Chai-Keong Toh
2003 B conf
PIMRC
Chai-Keong Toh, Wei Kang Tsai, Victor O. K. Li, Anthony D. Scott, Guillermo Guichal
2002 B conf
PIMRC
Guillermo Guichal, Chai-Keong Toh
2002 B conf
GLOBECOM
Wei Kang Tsai, Peng Zheng, Boyun Tu, Chai-Keong Toh
2002 J jnl
IEEE Trans. Wirel. Commun.
Chai-Keong Toh, Minar Delwar, Donald Allen
2002 B conf
PIMRC
Dongkyun Kim, Hwanseok Jeong, Chai-Keong Toh, Yanghee Choi
2002 B conf
WCNC
Wei Kang Tsai, Boyun Tu, Peng Zheng, Chai-Keong Toh, Lee C. Hu
2002 J jnl
J. Commun. Networks
Chai-Keong Toh, Elvino S. Sousa, Victor O. K. Li
2001 J jnl
J. High Speed Networks
Chai-Keong Toh, Wei Kang Tsai
2001 J jnl
IEEE Commun. Mag.
Chai-Keong Toh
2001 B conf
GLOBECOM
Dongkyun Kim, Chai-Keong Toh, Yanghee Choi
2001 conf
ICC
Chai-Keong Toh, Hiroshi Cobb, David A. Scott
2001 J jnl
J. Commun. Networks
Dongkyun Kim, Chai-Keong Toh, Yanghee Choi
2000 J jnl
IEEE Netw.
Chai-Keong Toh, William W. Lu, Cengiz Evci
2000 J jnl
SIGMETRICS Perform. Evaluation Rev.
Chai-Keong Toh, Richard Chen, Minar Delwar, Donald Allen
2000 J jnl
J. Commun. Networks
Chai-Keong Toh
2000 B conf
ICCCN
Chai-Keong Toh, George Lin, Minar Delwar
2000 J jnl
Mob. Networks Appl.
Dongkyun Kim, Chai-Keong Toh
2000 B conf
WCNC
Chai-Keong Toh, Santithorn Bunchua
2000 B conf
ICCCN
Dongkyun Kim, Chai-Keong Toh, Yanghee Choi
2000 conf
ICC (3)
Dongkyun Kim, Chai-Keong Toh, Yanghee Choi
1999 J jnl
IEEE Wirel. Commun.
Elizabeth M. Royer, Chai-Keong Toh
1999 J jnl
IEEE Netw.
Sung-Ju Lee, Mario Gerla, Chai-Keong Toh
1999 J jnl
Mob. Networks Appl.
Vaduvur Bharghavan, Chai-Keong Toh
1999 B conf
WCNC
Chai-Keong Toh, C.-H. Shih, Vasos Vassiliou, Minar Delwar
1999 J jnl
IEEE J. Sel. Areas Commun.
Zygmunt J. Haas, Mario Gerla, David B. Johnson, Charles E. Perkins, Michael B. Pursley, Martha E. Steenstrup, Chai-Keong Toh, Jeremiah F. Hayes
1999 conf
ICC
George Lin, Chai-Keong Toh
1999 J jnl
ACM SIGMOBILE Mob. Comput. Commun. Rev.
Chai-Keong Toh
1998 J jnl
Int. J. Wirel. Inf. Networks
Chai-Keong Toh, Bora A. Akyol
1998 J jnl
ACM SIGMOBILE Mob. Comput. Commun. Rev.
Chai-Keong Toh
1998 J jnl
IEEE Netw.
Chai-Keong Toh, Victor O. K. Li
1997 J jnl
Comput. Commun. Rev.
Chai-Keong Toh
1997 J jnl
Wirel. Pers. Commun.
Chai-Keong Toh
1997 J jnl
ACM SIGMOBILE Mob. Comput. Commun. Rev.
Chai-Keong Toh
1997 J jnl
ACM SIGMOBILE Mob. Comput. Commun. Rev.
Chai-Keong Toh
1996 J jnl
Mob. Networks Appl.
Chai-Keong Toh
1996 Misc conf
SAC
Chai-Keong Toh
1996 J jnl
Mob. Networks Appl.
Chai-Keong Toh
1996 A* conf
INFOCOM
Chai-Keong Toh
1995 A* conf
MobiCom
Chai-Keong Toh
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