我想要以下 Java 代码的 C++ 版本。
BigInteger x = new BigInteger("00afd72b5835ad22ea5d68279ffac0b6527c1ab0fb31f1e646f728d75cbd3ae65d", 16);
BigInteger y = x.multiply(BigInteger.valueOf(-1));
//prints y = ff5028d4a7ca52dd15a297d860053f49ad83e54f04ce0e19b908d728a342c519a3
System.out.println("y = " + new String(Hex.encode(y.toByteArray())));
这是我尝试的解决方案。
BIGNUM* x = BN_new();
BN_CTX* ctx = BN_CTX_new();
std::vector<unsigned char> xBytes = hexStringToBytes(“00afd72b5835ad22ea5d68279ffac0b6527c1ab0fb31f1e646f728d75cbd3ae65d");
BN_bin2bn(&xBytes[0], xBytes.size(), x);
BIGNUM* negative1 = BN_new();
std::vector<unsigned char> negative1Bytes = hexStringToBytes("ff");
BN_bin2bn(&negative1Bytes[0], negative1Bytes.size(), negative1);
BIGNUM* y = BN_new();
BN_mul(y, x, negative1, ctx);
char* yHex = BN_bn2hex(y);
std::string yStr(yHex);
//prints y = AF27542CDD7775C7730ABF785AC5F59C299E964A36BFF460B031AE85607DAB76A3
std::cout <<"y = " << yStr << std::endl;
(忽略大小写。)我做错了什么?如何让我的 C++ 代码输出正确的值“ff5028d4a7ca52dd15a297d860053f49ad83e54f04ce0e19b908d728a342c519a3”。我也尝试通过执行 BN_set_word(negative1, -1) 来设置 negative1,但这也给了我错误的答案。
最佳答案
BN_set_negative
函数设置一个负数。
The negative of afd72b5835ad22ea5d68279ffac0b6527c1ab0fb31f1e646f728d75cbd3ae65d
is actually -afd72b5835ad22ea5d68279ffac0b6527c1ab0fb31f1e646f728d75cbd3ae65d
, in the same way as -2
is the negative of 2
.
ff5028d4a7ca52dd15a297d860053f49ad83e54f04ce0e19b908d728a342c519a3
是一个大的正数。
您在 Java 中看到这个数字的原因是 toByteArray
调用。 According to its documentation ,它选择整数字节的最小字段宽度,并且能够保存负数的二进制补码表示。
换句话说,通过对当前具有 1 个符号位和 256 个值位的数字使用 toByteArray
函数,您最终得到一个 264 位的字段宽度。但是,如果您的负数的第一个半字节是 7
,而不是 a
,那么(根据此文档 - 我实际上还没有尝试过)您将得到 256 - 位字段宽度输出(即 8028d4...
,而不是 ff8028d4
。
您在代码中使用的前导 00
在 OpenSSL BN 中无关紧要。我不确定它在 BigInteger 中是否重要,尽管该构造函数的文档说“字符串表示形式包含一个可选的减号或加号,后跟指定基数中的一个或多个数字序列。”;所以它接受减号的事实表明,如果不存在减号,那么输入将被视为一个大的正数,即使它的 MSB 已设置。 (希望 Java 程序员能帮我理清这一段)。
请确保您清楚较大的负值与通过对该负值进行模块化运算而获得的较大正数之间的区别,例如 toByteArray 的输出
。
所以您的问题实际上是:Openssl BN 是否具有模拟 BigInteger.toByteArray() 行为的函数?
我不知道这样的函数是否存在(恕我直言,BN 库的文档相当糟糕,而且我从未听说过它在 OpenSSL 之外使用,尤其是在 C++ 程序中)。我希望它不会,因为 toByteArray
的行为有点奇怪;在任何情况下,所有 BN 输出函数似乎都使用符号幅度格式输出,而不是二进制补码格式。
但要复制该输出,您可以将 2^256
或 2^264
添加到大负数,然后执行 BN_bn2hex
。在这种特殊情况下,添加 2^264
,通常您必须测量正在存储的数字的当前位长度并将指数四舍五入到最接近的 8 的倍数。
或者您甚至可以输出符号幅度格式(使用 BN_bn2hex
或 BN_bn2mpi
),然后遍历反转每个半字节并修复开始!
注意。您想使用 OpenSSL BN 有什么特别的原因吗? There are many alternatives .
关于c++ - 如何在 openssl 的 BIGNUM 中使用负数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24836903/