如何从文件读取256位BigInteger并修复64位限制问题?
问题分析与修复方案
先改写入函数的致命问题
你写的toHH2函数根本没存完整的256位BigInteger——它只取了数值的低64位(因为调用了n.longValue()),剩下的高位直接丢失了。而且你创建了256字节的数组,但只有每8个字节的第一个位置有值,其余都是默认的0,文件里根本没存储256位的完整数据。
要正确存储256位BigInteger,直接用它的字节数组即可,补全到32字节(256位=32字节),采用大端序存储:
public static byte[] toHH2(BigInteger n) { byte[] rawBytes = n.toByteArray(); byte[] b = new byte[32]; // 256位对应32字节 // 把原始字节复制到数组尾部,保证前导零补全,大端序对齐 System.arraycopy(rawBytes, 0, b, 32 - rawBytes.length, rawBytes.length); return b; }
再修复读取逻辑
你的读取代码有两个关键问题:
- 每次用
value.longValue()把BigInteger转成long,超过64位的部分直接被截断,肯定拼不出256位数值。 - 读取逻辑和原写入逻辑完全不匹配,原写入只在每8个字节的位置写了值,你却遍历所有256字节,白忙活还出错。
对应修正后写入函数的读取代码
如果已经用上面的新写入函数把每个256位BigInteger存成32字节,读取时直接截取字节段构造BigInteger就行:
byte[] fileBytes = Files.readAllBytes(Path.of("C:\\Users\\User\\IdeaProjects\\CryptoLab1\\src\\crypto\\DigitalSignatureGOST.png")); int perValueBytes = 32; // 每个BigInteger占32字节 int totalCount = fileBytes.length / perValueBytes; // 刚好64个 for (int i = 0; i < totalCount; i++) { // 截取当前数值对应的字节区间 byte[] valueBytes = Arrays.copyOfRange(fileBytes, i * perValueBytes, (i + 1) * perValueBytes); // 用大端序构造正数BigInteger,第二个参数1表示无符号解析 BigInteger value = new BigInteger(1, valueBytes); // 这里处理你的value即可 }
要是必须兼容原错误写入的文件(不推荐)
如果没法重新生成文件,只能读取原来的错误格式(256字节里只有i=0,8,...,248的位置有值),那读取时只取这些位置,而且别用long截断:
byte[] fileBytes = Files.readAllBytes(Path.of("C:\\Users\\User\\IdeaProjects\\CryptoLab1\\src\\crypto\\DigitalSignatureGOST.png")); int perValueBytes = 256; // 原存储每个数值占256字节 int totalCount = fileBytes.length / perValueBytes; for (int i = 0; i < totalCount; i++) { BigInteger value = BigInteger.ZERO; // 只读取原写入时赋值的那些位置:每8个字节取一个 for (int j = 0; j < 256; j += 8) { int bytePos = i * perValueBytes + j; // 把字节转成无符号值,避免符号扩展搞乱数值 int byteVal = fileBytes[bytePos] & 0xFF; // 用BigInteger自身的移位和或操作,绝对不会截断 value = value.shiftLeft(8).or(BigInteger.valueOf(byteVal)); } // 处理得到的value }
核心错误总结
- 写入端:用
longValue()丢失了256位数值的高位,存储格式冗余且无效。 - 读取端:用
longValue()截断超过64位的部分,拼接逻辑和写入不匹配。
内容的提问来源于stack exchange,提问作者Alica Smith
相关产品推荐
相关产品推荐

