
Embute múltiplas mensagens secretas nas escolhas de tokens de chat de LLM usando codificadores esteganográficos aritméticos/Discop, com decodificação bit-exata e avaliação de esteganálise.
Código de pesquisa para esteganografia linguística em diálogos de chat com LLM, com uma linha de base single-stream e um protocolo multi-stream (HiTMS) em lote que esconde várias mensagens secretas independentes de uma só vez e explora o batching de GPU para uma vazão muito maior.
Um modelo Bob faz perguntas; um modelo Alice responde, codificando secretamente a carga útil (payload) em suas escolhas de tokens por meio de um codificador esteganográfico; Bob reexecuta o modelo na resposta de Alice para recuperar os bits. A codificação e a decodificação são bit-exatas, portanto o segredo é recuperado sem perdas.
arithmetic*.py)discop*.py)single_stream.py): sem overhead de enquadramento — cada bit de canal é carga útil (~100% de utilização).protocol.py): fluxos secretos fragmentados entre rodadas, um mapeamento fluxo→slot dirigido por PRF, slots de chamariz (decoy), cabeçalhos de comprimento de 16 bits e um keystream de preenchimento. Múltiplas respostas por rodada são geradas em , de modo que a vazão escala com o tamanho do lote.Modelos usados nos experimentos: meta-llama/Llama-3.2-3B-Instruct e google/gemma-3-4b-it. Conjuntos de dados: subconjuntos criativos/abertos de databricks/databricks-dolly-15k e HuggingFaceH4/no_robots.
| Path | Description |
|---|---|
arithmetic.py, arithmetic_batch.py | Esteganografia com codificação aritmética (codificador/decodificador de fluxo único + em lote). |
discop.py, discop_batch.py | Codificador esteganográfico Discop + PRG compartilhado (único + em lote). |
utils.py | Funções auxiliares compartilhadas (conversão bit/int, entropia, top-k, verificações de fim de frase). |
protocol.py | Protocolo multi-stream HiTMS (mapeamento de fluxos, chamarizes, cabeçalhos, preenchimento). |
single_stream.py | Protocolo single-stream (sem enquadramento; truncar no L-ésimo bit). |
round_trip.py, batch_round_trip.py | Demonstrações/testes mínimos de round-trip de uma única execução. |
multi_round_demo.py | Executor de tentativas multi-stream (run_trial) + demonstração detalhada de tentativa única. |
single_stream_demo.py | Executor de tentativas single-stream (run_single_trial) + demonstração. |
run_sweep.py | Varredura (sweep) multi-stream sobre {modelo}×{pool}×{codificador}, retomável. |
run_single_sweep.py | Varredura equivalente single-stream. |
run_scaling_sweep.py | Varredura de escalonamento do número de fluxos (x ∈ {1,2,4,8,16,32,64}), qualquer modelo/pool/codificador. |
run_x1_shards.py, run_x1_finish.sh, merge_x1_shards.py | Ablação x=1: fragmentar uma célula entre GPUs e depois mesclar com verificações de cobertura. |
judge_quality.py | Pontuador de imperceptibilidade LLM-como-juiz (um QA por chamada, retomável). |
gen_cover.py | Geração de texto "cover" sem carga útil (referência para esteganálise). |
steganalysis_bert.py | Detector cover-vs-stego (BERT / RoBERTa / DeBERTa-v3 / ELECTRA). |
data/ contém os resultados de todos os experimentos do artigo — capacidade, vazão, utilização, pontuações do juiz e AUROCs do detector — como um objeto JSON por tentativa. Consulte data/README.md para o esquema completo.
O próprio stegotexto gerado não está incluído: os logs brutos incorporam a pergunta e a resposta de cada fragmento, o que os torna ~1 GB, portanto o export_data.py remove esses campos e mantém todas as medições (~24 MB). Todos os drivers usam sementes (seeds), então reexecutar uma varredura regenera o texto exatamente.
Os diretórios de saída brutos (
sweep_logs/,single_sweep_logs/,scaling_logs/,judge_logs/,cover_logs/,run_logs/,steganalysis_logs/) estão no gitignore — eles são grandes (o último contém checkpoints de detectores treinados com vários GB) e totalmente regeneráveis.
conda create -n ems python=3.10 -y && conda activate ems
pip install torch transformers datasets numpy
pip install openai # only needed for judge_quality.py
É necessária uma GPU CUDA para executar os LLMs. Os checkpoints Llama e Gemma são restritos (gated) no Hugging Face Hub; portanto, execute huggingface-cli login (com acesso concedido a esses modelos) antes do primeiro uso.
Construa os pools de perguntas (uma vez):
python build_question_pool.py # -> dolly15k_creative_questions.json
python build_norobots_pool.py # -> norobots_creative_questions.json
Tentativa única detalhada (verificação de sanidade):
# multi-stream
CUDA_VISIBLE_DEVICES=0 python multi_round_demo.py
# single-stream
CUDA_VISIBLE_DEVICES=0 python single_stream_demo.py
# override model / coder / pool via env
ROUND_TRIP_MODEL=google/gemma-3-4b-it STEGO_ALGORITHM=discop \
STEGO_QUESTION_POOL=norobots_creative_questions.json \
CUDA_VISIBLE_DEVICES=0 python multi_round_demo.py
Experimentos completos (retomáveis — reexecute o mesmo comando para continuar):
# multi-stream (8 streams x 1024 bits), all model/pool/coder combos, 500 trials
CUDA_VISIBLE_DEVICES=0 python run_sweep.py --trials 500
# single-stream baseline
CUDA_VISIBLE_DEVICES=0 python run_single_sweep.py --trials 500
# stream-count scaling (dolly + Llama + Discop)
CUDA_VISIBLE_DEVICES=0 python run_scaling_sweep.py --x-values 4 8 16 32 64
Avaliação de imperceptibilidade (requer uma chave da OpenAI em OPENAI_API_KEY ou um arquivo local OPENAI_API_key.txt, ambos no gitignore):
python judge_quality.py --dry-run # plan only, no API calls
python judge_quality.py --limit 2 # tiny live smoke test
python judge_quality.py # full run (resumable)
python judge_quality.py --aggregate-only # recompute the score table
Cada driver define suas sementes (embaralhamento de prompts, amostragem de carga útil, RNG de amostragem, torch.manual_seed) e consome prompts de um fluxo de prompts determinístico e ciente de passada, portanto uma varredura completa é reproduzível de ponta a ponta e retoma exatamente do seu checkpoint após uma interrupção.
OPENAI_API_key.txt, *.key e .env são ignorados.export_data.py |
Constrói o espelho publicável somente-com-resumo em data/. |
build_question_pool.py, build_norobots_pool.py | Constroem os pools de perguntas a partir dos conjuntos de dados do HF. |
*_creative_questions.json | Pools de perguntas pré-construídos. |
legacy/ | Scripts/pools anteriores, mantidos para referência. |