You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻求适用于大规模CSV行的确定性可逆置换隐写函数方案

基于行置换的CSV隐写:高效编码解码方案

要通过置换CSV行序隐藏秘密消息,核心是实现确定性、可逆的置换-整数映射——直接枚举所有置换在大行数(如10000行)下完全不可行,最优方案是利用**阶乘数制(Factoradic)**将置换与整数双向转换,时间复杂度O(n)(或优化到O(n log n)),完全无需枚举所有可能的置换。

核心原理:阶乘数制与置换的一一对应

n个元素的置换总数是n!,每个置换可以唯一对应到0~n!-1之间的一个整数(即置换的字典序排名),反之亦然。我们可以把比特消息转成这个范围内的整数,再映射为置换;解码时反向操作即可。


实现方案

1. 编码函数(原始行列表 + 比特消息 → 置换后行列表)

步骤:

  • 将比特消息转为十进制整数k(需保证k < n!,否则消息长度超出当前行数量的存储上限)
  • 把k转换为阶乘数制表示(长度为n,数位从高位到低位对应(n-1)!到0!的系数)
  • 基于原始有序列表,通过阶乘数制的数位逐步选取元素生成置换结果
def factorial(n):
    res = 1
    for i in range(2, n+1):
        res *= i
    return res

def bits_to_int(bits_str):
    return int(bits_str, 2)

def int_to_factoradic(k, n):
    factoradic = []
    for i in range(1, n+1):
        factoradic.append(k % i)
        k = k // i
    return factoradic[::-1]  # 反转得到高位到低位的阶乘数制

def encode(A, message):
    n = len(A)
    max_perms = factorial(n)
    max_bits = max_perms.bit_length() - 1
    
    if len(message) > max_bits:
        raise ValueError(f"Message too long: max {max_bits} bits for {n} rows")
    
    k = bits_to_int(message)
    if k >= max_perms:
        raise ValueError(f"Message value {k} exceeds max permutation index {max_perms - 1}")
    
    factoradic = int_to_factoradic(k, n)
    temp = A.copy()
    result = []
    
    for idx in factoradic:
        result.append(temp.pop(idx))
    
    return result

2. 解码函数(置换后行列表 → 原始比特消息)

步骤:

  • 对比原始有序列表,确定置换后每个元素在剩余列表中的位置,生成阶乘数制表示
  • 将阶乘数制转换为整数k
  • 把k转回二进制字符串,得到原始消息
def factoradic_to_int(factoradic):
    n = len(factoradic)
    res = 0
    for i in range(n):
        res += factoradic[i] * factorial(n - 1 - i)
    return res

def int_to_bits(k, target_length):
    return bin(k)[2:].zfill(target_length)

def decode(B, original_A):
    n = len(B)
    temp = original_A.copy()
    factoradic = []
    
    for elem in B:
        pos = temp.index(elem)
        factoradic.append(pos)
        temp.pop(pos)
    
    k = factoradic_to_int(factoradic)
    max_bits = factorial(n).bit_length() - 1
    # 返回补前导零到最大比特长度的结果,或按需裁剪
    return int_to_bits(k, max_bits)

针对超大行数(如10000行)的关键优化

优化1:替换O(n)的索引查找

上述解码中list.index()是O(n)操作,n=10000时总时间复杂度会到O(n²),严重拖慢速度。可以用有序列表(SortedList)或线段树维护剩余元素的索引,将查找和删除操作降到O(log n):

from sortedcontainers import SortedList

def decode_optimized(B, original_A):
    n = len(B)
    # 预存原始元素到索引的映射
    elem_to_orig_idx = {elem: idx for idx, elem in enumerate(original_A)}
    # 用SortedList维护当前剩余的原始索引
    remaining_indices = SortedList(range(n))
    factoradic = []
    
    for elem in B:
        orig_idx = elem_to_orig_idx[elem]
        # 找到当前剩余列表中orig_idx的位置(即阶乘数制的数位)
        pos = remaining_indices.index(orig_idx)
        factoradic.append(pos)
        remaining_indices.remove(orig_idx)
    
    k = factoradic_to_int(factoradic)
    max_bits = factorial(n).bit_length() - 1
    return int_to_bits(k, max_bits)

如果不想依赖第三方库,可以自行实现线段树来支持动态索引的排名查询与删除。

优化2:避免超大整数处理

当n≥20时,n!已经超出64位整数范围,n=10000时n!更是一个数万位的大数,无法直接存储。此时可以跳过十进制整数转换,直接在比特流和阶乘数制之间双向映射,无需处理超大整数:

  • 编码时:逐位处理比特消息,直接计算阶乘数制的每个数位
  • 解码时:将阶乘数制的数位直接转换为比特流,无需合并为大数

优化3:分块存储

如果CSV行数极大但消息较短,可以将行划分为多个小模块,每个模块用自身的置换存储部分消息。比如把10000行分成100个100行的块,每个块可存储约528比特(log2(100!)≈528),既避免处理超大阶乘,也降低单块的计算压力。


示例验证

用题目中的测试案例验证:

A = [1,2,3,4,5]
# 对应置换[2,1,3,4,5]的整数是1,二进制为'000001'(6比特)
message = '000001'
B = encode(A, message)
print(B)  # 输出: [2, 1, 3, 4, 5]

recovered_msg = decode(B, A)
print(recovered_msg)  # 输出: '000001'

内容的提问来源于stack exchange,提问作者DrIDK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 09:02:53