Rafael G. L. D'Oliveira

82 papers B 18Misc 3Journal 53Unranked 8
YearRankTypeTitle / Venue / Authors
2025 B conf
ITW
Benjamin D. Kim, Vipindev Adat Vasudevan, Alejandro Cohen, Rafael G. L. D'Oliveira, Thomas Stahlbuhk, Muriel Médard
2025 J jnl
CoRR
Benjamin D. Kim, Vipindev Adat Vasudevan, Alejandro Cohen, Rafael G. L. D'Oliveira, Thomas Stahlbuhk, Muriel Médard
2025 J jnl
IEEE Trans. Mob. Comput.
Natalie Lang, Nir Shlezinger, Rafael G. L. D'Oliveira, Salim El Rouayheb
2025 J jnl
CoRR
Benjamin D. Kim, Vipindev Adat Vasudevan, Rafael G. L. D'Oliveira, Alejandro Cohen, Thomas Stahlbuhk, Muriel Médard
2025 B conf
ISIT
Igor L. Aureliano, Alejandro Cohen, Rafael G. L. D'Oliveira
2025 J jnl
CoRR
Igor L. Aureliano, Alejandro Cohen, Rafael G. L. D'Oliveira
2024 B conf
ISIT
Cailyn Bass, Alejandro Cohen, Rafael G. L. D'Oliveira, Muriel Médard
2024 J jnl
CoRR
Cailyn Bass, Alejandro Cohen, Rafael G. L. D'Oliveira, Muriel Médard
2024 conf
Allerton
Fatemeh Kazemi, Ningze Wang, Alex Sprintson, Rafael G. L. D'Oliveira
2024 Misc conf
ICASSP
Benjamin D. Kim, Vipindev Adat Vasudevan, Jongchan Woo, Alejandro Cohen, Rafael G. L. D'Oliveira, Thomas Stahlbuhk, Muriel Médard
2024 B conf
ISIT
Alejandro Cohen, Rafael G. L. D'Oliveira
2024 J jnl
CoRR
Alejandro Cohen, Rafael G. L. D'Oliveira
2024 J jnl
J. Priv. Confidentiality
Yuzhou Gu, Ziqi Zhou, Onur Günlü, Rafael G. L. D'Oliveira, Parastoo Sadeghi, Muriel Médard, Rafael F. Schaefer
2024 J jnl
CoRR
Jongchan Woo, Vipindev Adat Vasudevan, Benjamin D. Kim, Rafael G. L. D'Oliveira, Alejandro Cohen, Thomas Stahlbuhk, Ken R. Duffy, Muriel Médard
2024 B conf
ISIT
Alejandro Cohen, Rafael G. L. D'Oliveira
2024 J jnl
IEEE J. Sel. Areas Inf. Theory
Sahel Torkamani, Javad B. Ebrahimi, Parastoo Sadeghi, Rafael G. L. D'Oliveira, Muriel Médard
2024 B conf
ISIT
Ryann Cartor, Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein, David A. Karpuk, Alex Sprintson
2024 J jnl
CoRR
Ryann Cartor, Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein, David A. Karpuk, Alex Sprintson
2023 B conf
ISIT
Alexander Mariona, Homa Esfahanizadeh, Rafael G. L. D'Oliveira, Muriel Médard
2023 J jnl
CoRR
Alexander Mariona, Homa Esfahanizadeh, Rafael G. L. D'Oliveira, Muriel Médard
2023 J jnl
IEEE Commun. Lett.
Alejandro Cohen, Rafael G. L. D'Oliveira, Ken R. Duffy, Jongchan Woo, Muriel Médard
2023 J jnl
IEEE J. Sel. Top. Signal Process.
Alejandro Cohen, Rafael G. L. D'Oliveira, Chia-Yi Yeh, Hichem Guerboukha, Rabi Shrestha, Zhaoji Fang, Edward W. Knightly, Muriel Médard, Daniel M. Mittleman
2023 J jnl
CoRR
Jongchan Woo, Vipindev Adat Vasudevan, Benjamin D. Kim, Alejandro Cohen, Rafael G. L. D'Oliveira, Thomas Stahlbuhk, Muriel Médard
2023 Misc conf
ICASSP
Natalie Lang, Elad Sofer, Nir Shlezinger, Rafael G. L. D'Oliveira, Salim El Rouayheb
2023 J jnl
CoRR
Benjamin D. Kim, Vipindev Adat Vasudevan, Jongchan Woo, Alejandro Cohen, Rafael G. L. D'Oliveira, Thomas Stahlbuhk, Muriel Médard
2023 J jnl
CoRR
Natalie Lang, Nir Shlezinger, Rafael G. L. D'Oliveira, Salim El Rouayheb
2023 J jnl
CoRR
Yuzhou Gu, Ziqi Zhou, Onur Günlü, Rafael G. L. D'Oliveira, Parastoo Sadeghi, Muriel Médard, Rafael F. Schaefer
2023 J jnl
CoRR
Sahel Torkamani, Javad B. Ebrahimi, Parastoo Sadeghi, Rafael G. L. D'Oliveira, Muriel Médard
2023 J jnl
CoRR
Homa Esfahanizadeh, Adam Yala, Rafael G. L. D'Oliveira, Andrea J. D. Jaba, Victor Quach, Ken R. Duffy, Tommi S. Jaakkola, Vinod Vaikuntanathan, Manya Ghobadi, Regina Barzilay, Muriel Médard
2023 J jnl
IEEE Trans. Inf. Forensics Secur.
Chia-Yi Yeh, Alejandro Cohen, Rafael G. L. D'Oliveira, Muriel Médard, Daniel M. Mittleman, Edward W. Knightly
2023 J jnl
IEEE Trans. Veh. Technol.
Kathleen Yang, Salman Salamatian, Rafael G. L. D'Oliveira, Muriel Médard
2022 B conf
ITW
Alexander Mariona, Homa Esfahanizadeh, Rafael G. L. D'Oliveira, Muriel Médard
2022 J jnl
CoRR
Alexander Mariona, Homa Esfahanizadeh, Rafael G. L. D'Oliveira, Muriel Médard
2022 J jnl
CoRR
Alejandro Cohen, Rafael G. L. D'Oliveira, Ken R. Duffy, Jongchan Woo, Muriel Médard
2022 conf
CNS
Alejandro Cohen, Rafael G. L. D'Oliveira, Chia-Yi Yeh, Hichem Guerboukha, Rabi Shrestha, Zhaoji Fang, Edward W. Knightly, Muriel Médard, Daniel M. Mittleman
2022 J jnl
CoRR
Alejandro Cohen, Rafael G. L. D'Oliveira, Chia-Yi Yeh, Hichem Guerboukha, Rabi Shrestha, Zhaoji Fang, Edward W. Knightly, Muriel Médard, Daniel M. Mittleman
2022 conf
WISEC
Chia-Yi Yeh, Alejandro Cohen, Rafael G. L. D'Oliveira, Muriel Médard, Daniel M. Mittleman, Edward W. Knightly
2022 conf
Allerton
Fatemeh Kazemi, Ningze Wang, Rafael G. L. D'Oliveira, Alex Sprintson
2022 B conf
ISIT
Sahel Torkamani, Javad B. Ebrahimi, Parastoo Sadeghi, Rafael G. L. D'Oliveira, Muriel Médard
2022 J jnl
CoRR
Sahel Torkamani, Javad B. Ebrahimi, Parastoo Sadeghi, Rafael G. L. D'Oliveira, Muriel Médard
2022 B conf
ISIT
Alejandro Cohen, Rafael G. L. D'Oliveira, Ken R. Duffy, Muriel Médard
2022 J jnl
CoRR
Alejandro Cohen, Rafael G. L. D'Oliveira, Ken R. Duffy, Muriel Médard
2022 J jnl
IEEE J. Sel. Areas Commun.
Carolina Naim, Rafael G. L. D'Oliveira, Salim El Rouayheb
2022 B conf
ISIT
Ziqi Zhou, Onur Günlü, Rafael G. L. D'Oliveira, Muriel Médard, Parastoo Sadeghi, Rafael F. Schaefer
2022 J jnl
CoRR
Ziqi Zhou, Onur Günlü, Rafael G. L. D'Oliveira, Muriel Médard, Parastoo Sadeghi, Rafael F. Schaefer
2022 J jnl
IACR Cryptol. ePrint Arch.
Ziqi Zhou, Onur Günlü, Rafael G. L. D'Oliveira, Muriel Médard, Parastoo Sadeghi, Rafael F. Schaefer
2022 J jnl
CoRR
Adam Yala, Victor Quach, Homa Esfahanizadeh, Rafael G. L. D'Oliveira, Ken R. Duffy, Muriel Médard, Tommi S. Jaakkola, Regina Barzilay
2022 J jnl
CoRR
Kathleen Yang, Salman Salamatian, Rafael G. L. D'Oliveira, Muriel Médard
2021 J jnl
Found. Trends Mach. Learn.
Peter Kairouz, H. Brendan McMahan, Brendan Avent, Aurélien Bellet, Mehdi Bennis, Arjun Nitin Bhagoji, Kallista A. Bonawitz, Zachary Charles, Graham Cormode, Rachel Cummings, Rafael G. L. D'Oliveira, Hubert Eichner, Salim El Rouayheb, David Evans, Josh Gardner, Zachary Garrett, Adrià Gascón, Badih Ghazi, Phillip B. Gibbons, Marco Gruteser, Zaïd Harchaoui, Chaoyang He, Lie He, Zhouyuan Huo, Ben Hutchinson, Justin Hsu, Martin Jaggi, Tara Javidi, Gauri Joshi, Mikhail Khodak, Jakub Konecný, Aleksandra Korolova, Farinaz Koushanfar, Sanmi Koyejo, Tancrède Lepoint, Yang Liu, Prateek Mittal, Mehryar Mohri, Richard Nock, Ayfer Özgür, Rasmus Pagh, Hang Qi, Daniel Ramage, Ramesh Raskar, Mariana Raykova, Dawn Song, Weikang Song, Sebastian U. Stich, Ziteng Sun, Ananda Theertha Suresh, Florian Tramèr, Praneeth Vepakomma, Jianyu Wang, Li Xiong, Zheng Xu, Qiang Yang, Felix X. Yu, Han Yu, Sen Zhao
2021 conf
WSA
Raphael Thesmar, Joseph Thesmar, Rafael G. L. D'Oliveira, Muriel Médard
2021 J jnl
CoRR
Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein, David A. Karpuk
2021 J jnl
IEEE J. Sel. Areas Inf. Theory
Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein, David A. Karpuk
2021 B conf
ISIT
Rafael G. L. D'Oliveira, Muriel Médard, Parastoo Sadeghi
2021 J jnl
CoRR
Rafael G. L. D'Oliveira, Muriel Médard, Parastoo Sadeghi
2021 Misc conf
REDUNDANCY
Roberto Assis Machado, Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein
2021 J jnl
CoRR
Roberto Assis Machado, Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein
2021 J jnl
IEEE J. Sel. Areas Inf. Theory
Rafael G. L. D'Oliveira, Salman Salamatian, Muriel Médard, Parastoo Sadeghi
2021 J jnl
IEEE J. Sel. Areas Inf. Theory
Alejandro Cohen, Rafael G. L. D'Oliveira, Salman Salamatian, Muriel Médard
2021 J jnl
CoRR
Adam Yala, Homa Esfahanizadeh, Rafael G. L. D'Oliveira, Ken R. Duffy, Manya Ghobadi, Tommi S. Jaakkola, Vinod Vaikuntanathan, Regina Barzilay, Muriel Médard
2021 conf
MILCOM
Rafael G. L. D'Oliveira, Alejandro Cohen, John Robinson, Thomas Stahlbuhk, Muriel Médard
2021 J jnl
CoRR
Rafael G. L. D'Oliveira, Alejandro Cohen, John Robinson, Thomas Stahlbuhk, Muriel Médard
2021 B conf
ISIT
Carolina Naim, Rafael G. L. D'Oliveira, Salim El Rouayheb
2021 J jnl
CoRR
Carolina Naim, Rafael G. L. D'Oliveira, Salim El Rouayheb
2021 B conf
SECON
Yilin Yang, Rafael G. L. D'Oliveira, Salim El Rouayheb, Xin Yang, Hulya Seferoglu, Yingying Chen
2020 J jnl
IEEE Trans. Inf. Theory
Rafael G. L. D'Oliveira, Salim El Rouayheb, David A. Karpuk
2020 J jnl
CoRR
Rafael G. L. D'Oliveira, Salman Salamatian, Muriel Médard, Parastoo Sadeghi
2020 J jnl
CoRR
Alejandro Cohen, Rafael G. L. D'Oliveira, Salman Salamatian, Muriel Médard
2020 conf
CNS
Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein, David A. Karpuk
2020 J jnl
CoRR
Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein, David A. Karpuk
2020 J jnl
IEEE Trans. Inf. Theory
Rafael G. L. D'Oliveira, Salim El Rouayheb
2020 B conf
PIMRC
Kathleen Yang, Rafael G. L. D'Oliveira, Salman Salamatian, Muriel Médard
2019 J jnl
Des. Codes Cryptogr.
Rafael G. L. D'Oliveira, Marcelo Firer
2019 J jnl
CoRR
Peter Kairouz, H. Brendan McMahan, Brendan Avent, Aurélien Bellet, Mehdi Bennis, Arjun Nitin Bhagoji, Kallista A. Bonawitz, Zachary Charles, Graham Cormode, Rachel Cummings, Rafael G. L. D'Oliveira, Salim El Rouayheb, David Evans, Josh Gardner, Zachary Garrett, Adrià Gascón, Badih Ghazi, Phillip B. Gibbons, Marco Gruteser, Zaïd Harchaoui, Chaoyang He, Lie He, Zhouyuan Huo, Ben Hutchinson, Justin Hsu, Martin Jaggi, Tara Javidi, Gauri Joshi, Mikhail Khodak, Jakub Konecný, Aleksandra Korolova, Farinaz Koushanfar, Sanmi Koyejo, Tancrède Lepoint, Yang Liu, Prateek Mittal, Mehryar Mohri, Richard Nock, Ayfer Özgür, Rasmus Pagh, Mariana Raykova, Hang Qi, Daniel Ramage, Ramesh Raskar, Dawn Song, Weikang Song, Sebastian U. Stich, Ziteng Sun, Ananda Theertha Suresh, Florian Tramèr, Praneeth Vepakomma, Jianyu Wang, Li Xiong, Zheng Xu, Qiang Yang, Felix X. Yu, Han Yu, Sen Zhao
2019 J jnl
Eur. J. Comb.
Rafael G. L. D'Oliveira, Marcelo Firer
2019 B conf
ITW
Rafael G. L. D'Oliveira, Salim El Rouayheb, Daniel Heinlein, David A. Karpuk
2019 B conf
ISIT
Rafael G. L. D'Oliveira, Salim El Rouayheb, David A. Karpuk
2018 J jnl
CoRR
Rafael G. L. D'Oliveira, Salim El Rouayheb, David A. Karpuk
2018 B conf
ISIT
Rafael G. L. D'Oliveira, Salim El Rouayheb
2018 J jnl
CoRR
Rafael G. L. D'Oliveira, Salim El Rouayheb
2018 J jnl
CoRR
Rafael G. L. D'Oliveira, Salim El Rouayheb
2018 conf
Allerton
Rafael G. L. D'Oliveira, Salim El Rouayheb, Muriel Médard
2018 J jnl
CoRR
Rafael G. L. D'Oliveira, Salim El Rouayheb, Muriel Médard
tests/unit/test_smali_normalization.py
← Index tests/unit/test_smali_normalization.py python
"""Unit tests for smali semantic normalization.

Tests the three normalization levels (category, opcode, opcode_api),
opcode categorization, ACFG feature index mapping, and integration
with MinHash computation.
"""
import pytest

pytestmark = [pytest.mark.unit, pytest.mark.apk, pytest.mark.decompile]


class TestCategorizeOpcode:
    """Tests for opcode -> semantic category mapping."""

    def test_arithmetic(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("add-int") == "ALU"
        assert categorize_opcode("mul-long/2addr") == "ALU"
        assert categorize_opcode("neg-int") == "ALU"

    def test_data_movement(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("move-result") == "MOV"
        assert categorize_opcode("const/4") == "CONST"
        assert categorize_opcode("const-string") == "CONST"

    def test_memory_access(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("iget-object") == "LOAD"
        assert categorize_opcode("sput-wide") == "STORE"
        assert categorize_opcode("aget-byte") == "LOAD"

    def test_invocation(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("invoke-virtual") == "CALL"
        assert categorize_opcode("invoke-static") == "CALL"
        assert categorize_opcode("invoke-direct") == "CALL"

    def test_control_flow(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("if-eqz") == "BRANCH"
        assert categorize_opcode("goto") == "JMP"
        assert categorize_opcode("goto/16") == "JMP"
        assert categorize_opcode("return-void") == "RET"

    def test_comparison(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("cmp-long") == "CMP"
        assert categorize_opcode("cmpl-float") == "CMP"
        assert categorize_opcode("cmpg-double") == "CMP"

    def test_conversion(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("int-to-long") == "CONV"
        assert categorize_opcode("float-to-int") == "CONV"

    def test_object_type(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("new-instance") == "ALLOC"
        assert categorize_opcode("check-cast") == "TYPE"
        assert categorize_opcode("instance-of") == "TYPE"

    def test_exception_sync(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("throw") == "EXC"
        assert categorize_opcode("monitor-enter") == "SYNC"

    def test_unknown(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("nop") == "OTHER"


class TestNormalizeInstruction:
    """Tests for single instruction normalization at various levels."""

    def test_category_level(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        assert normalize_instruction("add-int v0, v1, v2", "category") == "ALU"
        assert normalize_instruction("invoke-virtual {p0}, Lcom/Foo;->bar()V", "category") == "CALL"
        assert normalize_instruction("return-void", "category") == "RET"

    def test_opcode_level_strips_width(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # Width variants collapse to same base
        assert normalize_instruction("add-int v0, v1, v2", "opcode") == "add"
        assert normalize_instruction("add-long v0, v2, v4", "opcode") == "add"
        assert normalize_instruction("add-float v0, v1, v2", "opcode") == "add"
        # Addressing modes collapse too
        assert normalize_instruction("add-int/2addr v0, v1", "opcode") == "add"

    def test_opcode_api_invoke(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "invoke-virtual {p0, v0}, Lcom/example/Foo;->bar(I)V"
        )
        assert result == "CALL Lcom/example/Foo;->bar(I)V"

    def test_opcode_api_invoke_no_ref(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # If somehow no method ref is found, fallback to CALL
        assert normalize_instruction("invoke-virtual {v0}") == "CALL"

    def test_opcode_api_field_load(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iget-object v0, p0, Lcom/Foo;->mField:Ljava/lang/String;"
        )
        assert result == "LOAD Lcom/Foo;->mField:Ljava/lang/String;"

    def test_opcode_api_field_store(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iput-object v0, p0, Lcom/Foo;->mField:Ljava/lang/String;"
        )
        assert result == "STORE Lcom/Foo;->mField:Ljava/lang/String;"

    def test_opcode_api_androguard_field_format(self):
        """androguard uses space instead of colon in field references."""
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iget-object v0, p0, Lcom/Foo;->mField Ljava/lang/String;"
        )
        assert result.startswith("LOAD")
        assert "Lcom/Foo;->mField" in result

    def test_opcode_api_new_instance(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "new-instance v0, Lcom/example/MyClass;"
        )
        assert result == "ALLOC Lcom/example/MyClass;"

    def test_opcode_api_const_string(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            'const-string v0, "hello world"'
        )
        assert result == 'CONST_STR "hello world"'

    def test_opcode_api_const_string_jumbo(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            'const-string/jumbo v0, "large string"'
        )
        assert result == 'CONST_STR "large string"'

    def test_opcode_api_fallback_to_category(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # Non-special instructions fall back to category
        assert normalize_instruction("add-int v0, v1, v2") == "ALU"
        assert normalize_instruction("return-void") == "RET"
        assert normalize_instruction("nop") == "OTHER"

    def test_empty_input(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        assert normalize_instruction("") == ""
        assert normalize_instruction("   ") == ""


class TestNormalizeMethodBody:
    """Tests for full method body normalization."""

    def test_filters_directives_labels_comments(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        body = """\
.locals 2
# comment
:label_0
add-int v0, v1, v2
.line 42
invoke-virtual {p0}, Lcom/Foo;->bar()V
return-void
"""
        result = normalize_method_body(body, "category")
        assert result == ["ALU", "CALL", "RET"]

    def test_opcode_api_preserves_api_refs(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        body = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->setX(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
return-void
"""
        result = normalize_method_body(body, "opcode_api")
        assert result[0] == "CONST"
        assert result[1] == "CALL Lcom/Foo;->setX(I)V"
        assert result[2] == "LOAD Lcom/Foo;->name:Ljava/lang/String;"
        assert result[3] == "RET"

    def test_empty_body(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        assert normalize_method_body("") == []
        assert normalize_method_body("\n\n") == []


class TestNormalizationWithMinHash:
    """Integration tests: normalization + MinHash computation."""

    def test_minhash_returns_signature(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->bar(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
add-int v2, v0, v1
return-void
"""
        sig = compute_minhash(body)
        assert sig is not None
        assert len(sig) == 64
        assert all(0 <= v < 256 for v in sig)

    def test_minhash_register_invariance(self):
        """Same operations with different registers should produce identical signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_a = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->bar(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
add-int v2, v0, v1
return-void
"""
        body_b = """\
const/4 v3, 0x0
invoke-virtual {p1, v3}, Lcom/Foo;->bar(I)V
iget-object v4, p1, Lcom/Foo;->name:Ljava/lang/String;
add-int v5, v3, v4
return-void
"""
        sig_a = compute_minhash(body_a)
        sig_b = compute_minhash(body_b)
        assert sig_a == sig_b

    def test_minhash_width_invariance(self):
        """Width variants of same operations should produce identical signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_int = """\
add-int v0, v1, v2
sub-int v3, v0, v1
mul-int v4, v0, v3
return v4
"""
        body_long = """\
add-long v0, v2, v4
sub-long v6, v0, v2
mul-long v8, v0, v6
return-wide v8
"""
        sig_int = compute_minhash(body_int)
        sig_long = compute_minhash(body_long)
        # Both normalize to ALU, ALU, ALU, RET -> identical
        assert sig_int == sig_long

    def test_minhash_different_apis_differ(self):
        """Methods calling different APIs should produce different signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_a = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/crypto/AES;->encrypt([B)[B
invoke-virtual {v0}, Ljava/io/OutputStream;->write([B)V
return-void
"""
        body_b = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Ljava/lang/String;->length()I
invoke-virtual {v0}, Ljava/io/PrintStream;->println(I)V
return-void
"""
        sig_a = compute_minhash(body_a)
        sig_b = compute_minhash(body_b)
        assert sig_a != sig_b

    def test_minhash_too_few_instructions(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        assert compute_minhash("return-void\nnop") is None


class TestACFGBlockFeatures:
    """Tests for per-block ACFG feature extraction via smali_cfg."""

    def test_simple_linear_method(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
add-int v0, v1, v2
invoke-virtual {p0}, Lcom/Foo;->bar()V
return-void
"""
        metrics = compute_cfg_metrics(body)
        assert metrics.block_count >= 1
        assert len(metrics.block_features) == metrics.block_count
        # Each feature vector has 8 elements
        for feat in metrics.block_features:
            assert len(feat) == 8

    def test_branching_method_has_multiple_blocks(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
const/4 v0, 0x0
if-eqz v0, :cond_0
invoke-virtual {p0}, Lcom/Foo;->a()V
goto :goto_0
:cond_0
invoke-virtual {p0}, Lcom/Foo;->b()V
:goto_0
return-void
"""
        metrics = compute_cfg_metrics(body)
        assert metrics.block_count >= 3
        assert len(metrics.block_features) == metrics.block_count

    def test_feature_vector_arithmetic_count(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
add-int v0, v1, v2
sub-int v3, v0, v1
mul-int v4, v0, v3
return v4
"""
        metrics = compute_cfg_metrics(body)
        assert len(metrics.block_features) == 1
        feat = metrics.block_features[0]
        # feat[0] = instr_count (4), feat[1] = arithmetic (3)
        assert feat[0] == 4
        assert feat[1] >= 3  # 3 ALU ops

    def test_feature_vector_call_count(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
invoke-virtual {p0}, Lcom/A;->a()V
invoke-static {v0}, Lcom/B;->b()V
return-void
"""
        metrics = compute_cfg_metrics(body)
        feat = metrics.block_features[0]
        # feat[4] = call count
        assert feat[4] == 2