无符号整数实现 - 将C#移植到Java

时间:2011-04-10 01:45:39

标签: c# java cryptography

我将数千行加密C#函数移植到Java项目中。 C#代码广泛使用无符号值和按位运算。

我知道必要的Java解决方案来支持无符号值。但是,如果有无符号32位和64位整数的实现,我可以放入我的代码中会更方便。请链接到这样的图书馆。

快速谷歌查询揭示了商业应用程序中的几个:

2 个答案:

答案 0 :(得分:2)

这是一种语言功能,而不是库功能,因此除非您更改语言本身,否则无法扩展Java以支持此功能,在这种情况下,您需要创建自己的编译器。

但是,如果您需要无符号右移,Java支持>>>运算符,该运算符类似于>>运算符,用于无符号类型。

但是,您可以使用签名类型制作自己的方法来执行算术,就像它们无符号一样;这应该有用,例如:

static int multiplyUnsigned(int a, int b)
{
    final bool highBitA = a < 0,    highBitB = b < 0;
    final long a2 = a & ~(1 << 31), b2 = b & ~(1 << 31);
    final long result = (highBitA ? a2 | (1 << 31) : a2)
                      * (highBitB ? b2 | (1 << 31) : b2);
    return (int)result;
}

编辑:

感谢@ Ben的评论,我们可以简化这一点:

static int multiplyUnsigned(int a, int b)
{
    final long mask = (1L << 32) - 1;
    return (int)((a & mask) * (b & mask));
}

但这两种方法都不适用于long类型。在这种情况下,您必须转换为double,否定,乘以及再次将其强制转换,这可能会导致任何和所有优化。

答案 1 :(得分:2)

当使用两个补码表示法时,有符号和无符号整数的运算大多相同,这就是Java所做的。这意味着,如果您有两个32位字ab并且想要计算它们的总和a+b,那么无论您是否考虑,相同的内部操作都将产生正确的答案单词为签名或未签名。这适用于加法,减法和乘法。

必须符号标识的操作包括:

  • 右移:签名右移复制符号位,而无符号右移始终插入零。 Java为无符号右移提供了“>>>”运算符。
  • 分裂:无符号分区与签名分区不同。使用32位整数时,您可以将值转换为64位long类型(“x & 0xFFFFFFFFL”执行“无符号转换”技巧)。
  • 比较:如果您想将ab比较为两个32位无符号字词,那么您有两个标准习语:

    if ((a + Integer.MIN_VALUE) < (b + Integer.MIN_VALUE)) { ... }

    if ((a & 0xFFFFFFFFL) < (b & 0xFFFFFFFFL)) { ... }

知道,签名的Java类型对加密代码来说并不是一件容易的事。我已经在Java中实现了许多加密原语,只要您了解自己正在编写的内容,签名类型就不是问题。例如,看看sphlib:这是一个开源库,它在C和Java中实现了许多加密哈希函数。 Java代码非常无缝地使用Java的签名类型(intlong ...),它只是有效。

Java没有运算符重载,因此获取无符号类型的Java“解决方案”将涉及自定义类(例如您链接到的UInt64类),这将意味着大量的性能损失。你真的不想这样做。

理论上,可以使用无符号类型定义类似Java的语言,并实现一个为JVM生成字节码的编译器(内部使用我在上面详细说明的移位,分割和比较的技巧)。我不知道有任何可用的工具吗?并且,正如我上面所说,Java的签名类型适用于加密代码(换句话说,如果你遇到这种签名类型的问题,那么我敢说你不太了解安全地实现加密代码,你应该避免这样做;相反,使用现有的开源库。)