Skip to content

roj234/MoSay

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ModelSay 模说

What does the model say?


项目Logo

MoSay 模说

模不,它


模说是基于大型语言模型(LLM)的文本加密工具。
将任意数据加密为文本,完全开源,易于部署,易于使用。
设计时考虑到依赖和磁盘大小,它使用llama-cpp-python而非torch
该项目只是一个概念验证(PoC),不保证能在真实世界中长期稳定 *1 运行
在 LLM 充斥互联网的时代,"AI 生成"本身就是最好的伪装——没人会怀疑一篇平庸的 AI 文章里藏着秘密。

✨ 查阅 快速开始 一节,快速开始使用/部署本项目。

特性

隐蔽:与传统基于加密、编码或文本混淆的隐写方法不同,该算法修改LLM推理的Token采样过程,最终输出的文本在语义和风格上与正常的AI文本几乎一致,实现了肉眼和统计学 *2 都难以辨别的隐蔽性。

  • 它在隐蔽性上超过大部分其它工具,因为那些方法总会留下统计学痕迹或特定格式,而本项目天然地融入了AI的“语言”,将密文伪装成了“正常的废话”或“文学作品”
  • 由于使用大型语言模型的概率分布进行编码,它可以生成任意风格的密文,总有一款是你想要的,你可以在后面看到它的意义
  • 它使用算术编码,不仅高效的利用了LLM输出的概率分布,更在统计学上让结果难以分辨
  • 缺陷:尽管如此,它仍然是一个binary -> text transformer,然而它比那些换表base64隐蔽得多
  • 请注意:如果生成时遇到了“merges”警告,代表BPE分词器存在二义性(merges规则),这可能会导致解码失败,算法没有禁止因为一长串话不出现merges本身就很可疑(大概)
  • *2: 与具有 min_p 参数下的采样几乎统计学不可区分(一般无人在原始分布上采样),此外引入了 1e-7 (float32 精度) 级别的量化误差,详见示例展示一节

安全

  • 在上述BT变换的基础上,我加入了HMAC-SHA256确定性噪声生成器,你可以把它看作是一个带IV的流密码
  • 这个噪声基于你的提示词和(可选的)密码确定性的生成,并与明文的每个比特异或
  • 请注意:不使用密码时只有隐蔽性,没有安全性
    • 具体来说,隐蔽性是指一个实体(人或机器)看到这段文本,认为它藏有秘密的概率低
    • 安全性是指一个实体确定这段文本藏有秘密之后,无法轻松把它提取
  • 省略密码时,生成结果仍然是随机的,通过单字节IV提供
  • 提供密码时,我们会使用2个字节的IV
  • 对于LLM的自回归生成来说,这应该足够了
  • 默认的IV很短可能(不如说必然)被生日攻击,而且考虑到本身小模型写的故事也很突兀,请根据实际情况改变提示词

其它

  • 使用Unishox2和/或LZMA对文本进行压缩,以减少输出大小

工作原理

  1. LLM 在每一步给出下一个 token 的概率分布 P
  2. 算术编码器常用于压缩算法,它基于predictor生成的 P 和实际的 P_i 生成比特流
  3. 我将它反过来用,编码时用解码器,基于 P 和比特流(加密后的文本)来选择 token P_i
  4. 解码时用编码器 P,根据收到的 token 反向恢复区间和比特流

快速开始

安装依赖:

python -m pip install "numpy>=2.3.3" "typing_extensions>=4.15.0"
  • 我更建议直接使用本项目中的 vendor/llama-cpp-python,以避免计算不一致
  • 当然,我还砍掉了它对jinja2的依赖
  • 您可以自行替换bin目录中的二进制

下载模型:

(本项目的chat_template实现仅支持Qwen2/3/3.5系列模型)

建议使用 unsloth/Qwen3.5-0.8B-Q4_K_M 作为公开秘密
大小:507MiB
SHA256: BD258782E35F7F458F8ACED1ADC053E6E92E89BC735BA3BE89D38A06121DC517
下载到 src/models 文件夹

编译Unishox2:

如果你不懂,或者信得过我的预编译DLL可以直接跳过这一节,因为我已经编译了可以直接用

  • 下载 llvm-mingw 编译器,并解压到某个文件夹
  • Windows用户请不要害怕,这也是为什么我不用MSVC,这个编译器就是个绿色软件,下载之后解压就能用的那种
  • 按如下顺序操作,每一步操作之后都要敲下回车
  1. Win + R (运行) 输入cmd
  2. 输入 cd /d "项目在你本地的路径"
  3. 输入 set PATH=%PATH%;编译器解压的位置\bin
  4. 输入 call vendor\unishox2\build_unishox2.bat
  5. 你会看到移动了 1 个文件,编译好了。

测试:

cd src
python mosay.py encode

示例展示

  • 模型默认:Qwen3.5-0.8B-Q4_K_M
  • 提示词默认:写一个一两千字的故事,不要换行。
  • 数据默认:There are some secrets in this text. (编码后 180 bits)
  • IV大小:0字节 以保证确定性
  • Min_p是超参数
    • 默认为0.05
    • 在WebUI中我给了五档,就是下面的几个
    • WebUI的服务器是单线程的,本地使用够了,千万别上生产
    • 降低该值可以提高BPT,也就是信息密度,但是会降低文本质量
    • 增加该值可以让生成结果更接近 temperature=0 时的分布,不建议超过0.2
    • 实现可能和标准 Min_p 略有差异
    • 比0.0001更小的值不会继续改善信息密度,还可能影响性能,因为精度问题导致分布偏移等
    • 毕竟,AI生成文本的熵是有上限的
Min_p Tokens BPT PPL 文本质量
0.5 361 0.63 3.30 自然
0.2 128 1.40 4.57 自然
0.05 74 2.40 7.52 良好
0.01 57 3.10 10.21 略生硬
0.0001 43 4.09 17.87 明显异常
  1. Min_p=0.5, 361 tokens, 0.63 BPT, PPL=3.3015
    仅部分成功,因为遇到了无法在解码时处理的Merges token
    通过WebUI进行编码时会自动生成随机的IV,所以不用过于担心
    这是为了不影响原始概率分布,即便这会导致编码失败
    林远坐在昏暗的房间里,手里紧紧攥着一份未寄出的信,指尖因用力而微微泛白。窗外的雨淅淅沥沥地敲打着玻璃,敲打着他的心,敲打着这个即将结束的日子。他记得母亲在临终前说:“林远,别怕,只要你还记得我们,我们就永远在一起。”那些话像一把利刃,割裂了他所有的理智,让他觉得自己像个被遗弃的孩子,在无尽的孤独中煎熬。
    
    他推开了家门,推开那扇厚重的木门,一股冷风灌入,瞬间打乱了思绪。他深吸一口气,试图从混乱中抽身,却发现自己已经无法动弹。脑海中不断回放着母亲临终前绝望的眼神,那些画面让他感到一阵寒意。他想要逃离这个封闭的房间,想要去寻找外面的世界,想要找到那个真正能让他感到温暖的人,可现实却让他明白,只要还在
    
  2. Min_p=0.2, 128 tokens, 1.40 BPT, PPL=4.5703
    暴雨如注的夜,将城市边缘的街道彻底淹没在漆黑与灰暗之中,只有那扇紧闭的铜门在风雨中发出轻微的呜咽声,仿佛在无声地诉说着这人间最荒凉的过往。老张正站在雨幕前擦拭着那柄早已磨出了毛边的旧木柄,目光穿过雨丝,穿过无数行人的匆匆背影,仿佛能看见他眼底的疲惫与对未来的某种预感。他轻轻推开那扇沉重的铁门,雨声骤歇,只余下屋内微弱的烛火和空气中弥漫的尘埃味道。
    
    门内是一间陈
    
  3. Min_p=0.05, 74 tokens, 2.40 BPT, PPL=7.5188
    在这个雨声连绵、雨丝如线般纠缠着青石板缝隙的傍晚,小镇的街道被拉成了蜿蜒的丝带,将无数行人的影子交错、重叠。微风穿过高大的老槐树,带着湿润的泥土气息和偶尔夹杂着陈年薄荷味的清香,轻轻拂过行人的脸颊,也吹散了空气中悬浮已久的尘埃。那是深秋
    
  4. Min_p=0.01, 57 tokens, 3.10 BPT, PPL=10.2094
    风卷着黄沙,像一根粗壮的无形丝线,无声地缠绕在我的颈侧,又悄无声息地滑落至案头。窗外蝉鸣嘈杂,喧嚣在人声鼎沸的街头与深夜里交织,我裹紧衣物,步伐不紧不慢地走着
    
  5. Min_p=0.0001, 43 tokens, 4.09 BPT, PPL=17.8734
    我叫林砚,一个生于废土边缘、死在毒雾漩涡中的少年,拥着一双如同古匣中开合般能读取古老气脉的眼睛。我活了五十年,在这片没有太阳也没有
    
  6. 换一个提示词,让我们写一个以特斯拉为主角的科幻故事, 109 tokens, 1.64 BPT, PPL=4.2426
    # 静默的悖论:2099 年的特斯拉·欧拉(Tesla-Eloa)
    
    ## 第一章:双螺旋的启动
    
    在 2099 年,能源不再是“充电”的概念,而是“记忆”的存储。
    
    特斯拉·欧拉(Tesla-Eloa)矗立在废弃的“静默大道”尽头,是一座悬浮在云层之上的银色建筑。她的皮肤并非由特斯拉·欧拉的合金制成,而是由液态金属重构的“记忆合金”组成
    
  7. 前面的故事文本因为模型小+主题宽泛而显得空洞。其实说明文/科普文反而更适合做载体——结构化、信息密度高、AI 写得很像,下面是个例子……
    MinP=0.2, 135 tokens, 1.32 BPT, PPL=2.8985
    **WebSocket**(全称为 **Web Sockets**)是一种允许两个或两个以上应用程序在**客户端**(Web 浏览器、Web 应用程序、移动应用 或物联网设备)之间建立**长连接**的同步协议。
    
    它与传统的浏览器的 **HTTP/HTTPS** 协议不同,HTTP 是面向请求-响应(Stateless),即每次请求独立,关闭后资源被释放;而 WebSocket 是面向连接(Stateful),意味着连接一旦建立,数据流就会持续传输,直到关闭。
    
    以下从核心概念、技术优势、应用场景及实现方式四个维度为您详细解读:
    
    ### 1. 核心概念:
    
    是的,一篇科普介绍同样可以嵌入水印,虽然存在事实性错误,但小模型就是这样的
    你可以换一个大点的模型,然后让它生成完整,发布在自己的博客上,没有人会认为这里面藏着秘密,最多吐槽一下怎么又是AI Slop

待办事项

  • 在输出中嵌入超参数 (用两个bit放Min_p)

缺点

请注意:其它工具可能同样存在这些缺点,只是我专门列出来了而已

该算法的缺点(*1):

  • 非常脆弱:一个字符的改变会导致后续所有数据解密失败(LLM厂商的水印算法比这鲁棒的多,当然,有效载荷也低的多)
  • 分词危机:生成的文本被重新分词后可能与原始输入不同,我加入了检测,但也因此存在可能无法解密的结果,还好我加了IV
  • 计算量大:不适合挂在服务器上为不特定公众提供服务
  • 精确运算:无法使用GPU加速
    • 代码中,我强制使用了SSE4.2指令集的GGML库,尽管如此很可能只能在相同的架构(ARM/x86)上加解密
    • 生成结果可能随GGML等后端的更新而改变,如果经常使用,请固定依赖版本并尽可能二进制分发
    • 当然,最好的办法是设计一些确定性CPU算子,不过我暂时没有编写大型C++项目的能力
  • 超参数多:加密者和解密者都需要知道:模型,提示词,Min_p,密码,IV长度,是否禁止换行符等
    • 对于应用开发者,最好设计几个下拉框,或者干脆隐藏这些配置
  • 过于隐蔽:在某些必要情况下,无法让其他人意识到这段文本中藏有信息
  • "AI 文本"的统计特征研究在不断进步,未来(也许现在,毕竟我是闭门造车)的检测器可能识别出本算法

因而,它不应用于:

  • 保护人身安全相关等高敏感信息
  • 对抗有专业能力的攻击者
  • 替代成熟的端到端加密方案(Signal、age 等)

About

Model Say, a modern text steganography algorithm / 模说,一个很新的文本加密算法

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors