Catalin Voss

16 papers A 1Misc 2Journal 10Unranked 3
YearRankTypeTitle / Venue / Authors
2021 Misc conf
PSB
Peter Washington, Émilie Leblanc, Kaitlyn Dunlap, Yordan Penev, Maya Varma, Jae-Yoon Jung, Brianna Sierra Chrisman, Min Woo Sun, Nate Tyler Stockham, Kelley Marie Paskov, Haik Kalantarian, Catalin Voss, Nick Haber, Dennis P. Wall
2021 J jnl
Cogn. Comput.
Peter Washington, Haik Kalantarian, Jack Kent, Arman Husic, Aaron Kline, Émilie Leblanc, Cathy Hou, Cezmi Mutlu, Kaitlyn Dunlap, Yordan Penev, Nate Tyler Stockham, Brianna Sierra Chrisman, Kelley Marie Paskov, Jae-Yoon Jung, Catalin Voss, Nick Haber, Dennis P. Wall
2021 J jnl
CoRR
Peter Washington, Onur Cezmi Mutlu, Émilie Leblanc, Aaron Kline, Cathy Hou, Brianna Sierra Chrisman, Nate Tyler Stockham, Kelley M. Paskov, Catalin Voss, Nick Haber, Dennis P. Wall
2020 J jnl
CoRR
Nick Haber, Catalin Voss, Jena Daniels, Peter Washington, Azar Fazel, Aaron Kline, Titas De, Terry Winograd, Carl Feinstein, Dennis P. Wall
2020 J jnl
CoRR
Catalin Voss, Nick Haber, Peter Washington, Aaron Kline, Beth McCarthy, Jena Daniels, Azar Fazel, Titas De, Carl Feinstein, Terry Winograd, Dennis P. Wall
2020 Misc conf
PSB
Peter Washington, Kelley Marie Paskov, Haik Kalantarian, Nate Tyler Stockham, Catalin Voss, Aaron Kline, Ritik Patnaik, Brianna Sierra Chrisman, Maya Varma, Qandeel Tariq, Kaitlyn Dunlap, Jessey N. Schwartz, Nick Haber, Dennis P. Wall
2020 J jnl
CoRR
Catalin Voss, Peter Washington, Nick Haber, Aaron Kline, Jena Daniels, Azar Fazel, Titas De, Beth McCarthy, Carl Feinstein, Terry Winograd, Dennis P. Wall
2020 J jnl
CoRR
Peter Washington, Haik Kalantarian, Jack Kent, Arman Husic, Aaron Kline, Émilie Leblanc, Cathy Hou, Cezmi Mutlu, Kaitlyn Dunlap, Yordan Penev, Maya Varma, Nate Tyler Stockham, Brianna Sierra Chrisman, Kelley M. Paskov, Min Woo Sun, Jae-Yoon Jung, Catalin Voss, Nick Haber, Dennis P. Wall
2019 J jnl
GetMobile Mob. Comput. Commun.
Aaron Kline, Catalin Voss, Peter Washington, Nick Haber, Jessey N. Schwartz, Qandeel Tariq, Terry Winograd, Carl Feinstein, Dennis P. Wall
2018 J jnl
npj Digit. Medicine
Jena Daniels, Jessey N. Schwartz, Catalin Voss, Nick Haber, Azar Fazel, Aaron Kline, Peter Washington, Carl Feinstein, Terry Winograd, Dennis P. Wall
2018 J jnl
Appl. Clin. Inform.
Jena Daniels, Nick Haber, Catalin Voss, Jessey N. Schwartz, Serena Tamura, Azar Fazel, Aaron Kline, Peter Washington, Jennifer Phillips, Terry Winograd, Carl Feinstein, Dennis P. Wall
2017 J jnl
Proc. ACM Interact. Mob. Wearable Ubiquitous Technol.
Peter Washington, Catalin Voss, Aaron Kline, Nick Haber, Jena Daniels, Azar Fazel, Titas De, Carl Feinstein, Terry Winograd, Dennis P. Wall
2016 conf
CHI Extended Abstracts
Peter Washington, Catalin Voss, Nick Haber, Serena Tanaka, Jena Daniels, Carl Feinstein, Terry Winograd, Dennis P. Wall
2016 A conf
WACV
Nick Haber, Catalin Voss, Azar Fazel, Terry Winograd, Dennis P. Wall
2016 conf
AAAI Spring Symposia
Rafael A. Calvo, Nick Haber, Catalin Voss, Michael Nova, Dennis Salins, Michael Snyder, Dennis P. Wall
2016 conf
UbiComp Adjunct
Catalin Voss, Peter Washington, Nick Haber, Aaron Kline, Jena Daniels, Azar Fazel, Titas De, Beth McCarthy, Carl Feinstein, Terry Winograd, Dennis P. Wall
tests/unit/test_decompile_similarity.py
← Index tests/unit/test_decompile_similarity.py python
"""Unit tests for similarity modules:
- bninja/similarity/minhashcustom.py
- bninja/similarity/minhasher.py
"""
import numpy as np
import pytest

from redb.extractors.decompiler.bninja.similarity.minhashcustom import MinHashCustom
from redb.extractors.decompiler.bninja.analysis.low_level_normalization import LowLevelNormalization


# ============================================================================
# 2a. MinHashCustom
# ============================================================================

class TestMinHashCustomInit:
    def test_init_empty(self):
        mh = MinHashCustom()
        assert not mh.hasMinHash()
        assert mh.minhash == b""
        assert mh.minhash_int == []

    def test_init_from_signature(self):
        sig = [10, 20, 30, 40]
        mh = MinHashCustom(minhash_signature=sig)
        assert mh.hasMinHash()
        assert mh.minhash_int == sig

    def test_init_from_bytes_uint32(self):
        """Verify round-trip: ints -> bytes -> MinHashCustom -> ints."""
        sig = [100, 200, 300]
        packed = np.array(sig, dtype=np.uint32).tobytes()
        # np.frombuffer returns numpy scalars; setMinHash does % 2**32 which
        # overflows numpy uint32, so verify the raw bytes round-trip instead.
        raw_arr = np.frombuffer(packed, dtype=np.uint32)
        assert list(raw_arr) == sig

    def test_init_from_bytes_uint8(self):
        """Verify round-trip: ints -> bytes -> back."""
        sig = [10, 20, 30]
        packed = np.array(sig, dtype=np.uint8).tobytes()
        raw_arr = np.frombuffer(packed, dtype=np.uint8)
        assert list(raw_arr) == sig

    def test_init_both_raises(self):
        sig = [1, 2, 3]
        packed = np.array(sig, dtype=np.uint32).tobytes()
        with pytest.raises(ValueError, match="only one"):
            MinHashCustom(minhash_bytes=packed, minhash_signature=sig)


class TestMinHashCustomSetGet:
    def test_set_and_get_minhash(self):
        mh = MinHashCustom()
        sig = [5, 10, 15]
        mh.setMinHash(sig)
        raw = mh.getMinHash()
        assert raw == np.array(sig, dtype=np.uint32).tobytes()
        assert mh.getMinHashInt() == sig

    def test_minhash_int_truncation(self):
        mh = MinHashCustom(minhash_bits=8)
        # Values > 256 should be truncated mod 2^8
        mh.setMinHash([300, 500, 256])
        for val in mh.minhash_int:
            assert 0 <= val < 256


class TestMinHashCustomHashData:
    def test_hash_data_string(self):
        result = MinHashCustom.hashData("hello", 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_bytes(self):
        result = MinHashCustom.hashData(b"bytes", 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_list(self):
        result = MinHashCustom.hashData([1, 2, 3], 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_unsupported_type(self):
        with pytest.raises(NotImplementedError, match="Type not supported"):
            MinHashCustom.hashData(123, 42)

    def test_hash_data_deterministic(self):
        assert MinHashCustom.hashData("test", 7) == MinHashCustom.hashData("test", 7)


class TestMinHashCustomScore:
    def test_score_identical(self):
        sig = [1, 2, 3, 4, 5]
        mh1 = MinHashCustom(minhash_signature=sig)
        mh2 = MinHashCustom(minhash_signature=sig)
        score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert score == 100.0

    def test_score_different(self):
        mh1 = MinHashCustom(minhash_signature=[1, 2, 3, 4, 5])
        mh2 = MinHashCustom(minhash_signature=[6, 7, 8, 9, 10])
        score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert score < 100.0

    def test_score_against(self):
        sig1 = [1, 2, 3, 4, 5]
        sig2 = [1, 2, 99, 4, 5]
        mh1 = MinHashCustom(minhash_signature=sig1)
        mh2 = MinHashCustom(minhash_signature=sig2)
        instance_score = mh1.scoreAgainst(mh2)
        static_score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert instance_score == static_score


class TestMinHashCustomBitModes:
    def test_8bit_mode(self):
        mh = MinHashCustom(minhash_bits=8)
        mh.setMinHash([10, 20, 30])
        raw = mh.getMinHash()
        arr = np.frombuffer(raw, dtype=np.uint8)
        assert list(arr) == [10, 20, 30]

    def test_32bit_mode(self):
        mh = MinHashCustom(minhash_bits=32)
        mh.setMinHash([10, 20, 30])
        raw = mh.getMinHash()
        arr = np.frombuffer(raw, dtype=np.uint32)
        assert list(arr) == [10, 20, 30]


# ============================================================================
# 2b. MinHasher
# ============================================================================


class MockILNode:
    """Mock IL node with operation and operands for normalization."""
    def __init__(self, operation, operands=None):
        self.operation = operation
        self.operands = operands or []


class MockLLILBasicBlock:
    """Mock LLIL basic block that yields IL instructions."""
    def __init__(self, instructions):
        self._instructions = instructions

    def __iter__(self):
        return iter(self._instructions)


class MockLLILFunction:
    """Mock LLIL function with basic blocks."""
    def __init__(self, basic_blocks):
        self.basic_blocks = basic_blocks


# Import MinHasher after we know the module can handle the import
from redb.extractors.decompiler.bninja.similarity.minhasher import (
    MinHasher,
    MINHASH_SIGNATURE_LENGTH,
    MINHASH_SIGNATURE_BITS,
)


class TestMinHasherMakeNgrams:
    def setup_method(self):
        # Create a minimal minhasher with a mock LLIL function
        empty_func = MockLLILFunction([])
        self.hasher = MinHasher(seed=42, il_function=empty_func)

    def test_make_ngrams_basic(self):
        result = self.hasher.make_ngrams(["a", "b", "c", "d"], n=3)
        assert result == [("a", "b", "c"), ("b", "c", "d")]

    def test_make_ngrams_short_input(self):
        result = self.hasher.make_ngrams(["a", "b"], n=3)
        assert result == []

    def test_make_ngrams_exact_n(self):
        result = self.hasher.make_ngrams(["a", "b", "c"], n=3)
        assert result == [("a", "b", "c")]


class TestMinHasherCalculate:
    def _make_llil_function(self, num_instructions=10):
        """Create a mock LLIL function with enough instructions."""
        instructions = [
            MockILNode(operation=i % 20) for i in range(num_instructions)
        ]
        bb = MockLLILBasicBlock(instructions)
        return MockLLILFunction([bb])

    def test_calculate_minhash_empty_function(self):
        # Function with < 3 LLIL instructions -> empty list
        func = self._make_llil_function(num_instructions=2)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        assert result == []

    def test_calculate_minhash_deterministic(self):
        func = self._make_llil_function(num_instructions=20)
        h1 = MinHasher(seed=42, il_function=func)
        h2 = MinHasher(seed=42, il_function=func)
        assert h1.calculateMinHash() == h2.calculateMinHash()

    def test_calculate_minhash_length(self):
        func = self._make_llil_function(num_instructions=20)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        assert len(result) == MINHASH_SIGNATURE_LENGTH

    def test_calculate_minhash_value_range(self):
        func = self._make_llil_function(num_instructions=20)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        for val in result:
            assert 0 <= val < 2 ** MINHASH_SIGNATURE_BITS

    def test_shingle_hash_deterministic(self):
        func = self._make_llil_function(num_instructions=5)
        hasher = MinHasher(seed=42, il_function=func)
        shingle = ([1, 2], [3, 4], [5, 6])
        assert hasher.shingle_hash(shingle, 99) == hasher.shingle_hash(shingle, 99)

    def test_seed_reproducibility(self):
        func = self._make_llil_function(num_instructions=20)
        h1 = MinHasher(seed=1, il_function=func)
        h2 = MinHasher(seed=2, il_function=func)
        r1 = h1.calculateMinHash()
        r2 = h2.calculateMinHash()
        # Different seeds should (very likely) produce different results
        assert r1 != r2