BitShifting with BigIntegers in Java

不想你离开。 提交于 2019-11-29 10:31:54

BigInteger implements infinite-precision integers, so shifting to the left will keep adding zeros to the left. You need a rotate:

private static BigInteger rotateLeft(BigInteger bi) {
    BigInteger ret = bi.shiftLeft(1);
    if (ret.testBit(32)) {
        ret = ret.clearBit(32).setBit(0);
    }
    return ret;
}

That's going to be rather inefficient for 32-bit numbers, so you might as well just use primitives to rotate DES' 28-bit halves. I'm not familiar with the DES algorithm, so I'll assume you need BigInteger for something else.

private static BigInteger rotateLeftPrimitive(BigInteger bi) {
    int value = bi.intValue();
    return BigInteger.valueOf(((value << 1) & 0xffffffe) | ((value >>> 27) & 1));
}

It seems that you need a cyclic left shift. BigInteger.shiftLeft is not cyclic. You'd have to combine shiftLeft, shiftRight, and and or, just like you would if you were using int and <<.

static BigInteger allOnes(int L) {
    return BigInteger.ZERO
        .setBit(L)
        .subtract(BigInteger.ONE);
}

static BigInteger cyclicLeftShift(BigInteger n, int L, int k) {
    return n.shiftLeft(k)
        .or(n.shiftRight(L - k))
        .and(allOnes(L));
}

Now, cyclicLeftShift(n, L, k) returns n cyclically-shifted k bits to the left, where the cycle window is L.

How this works is as follows:

                               _________L__________
                              /                    \
n :                           [ABCDE][FG...........]
                              \__k__/\_____L-k_____/



n.shiftLeft(k) :       [ABCDE][FG...........][00000]
   .or
n.shiftRight(L - k) :                        [ABCDE]

   =                   [ABCDE][FG...........][ABCDE]

                               _________L__________
   .and                       /                    \
allOnes(L) :                  [111..............111]

   =                          [FG...........][ABCDE]

See also


Note: if you have a fixed L, you can optimize this a bit by caching allOnes(L) instead of computing it every time.

Addressing the bigger question 1) DES is broken and should never be used for anything other than working with legacy systems, 2) the Sun JCE already provides an implementation (as does BouncyCastle and other crypto providers), and 3) implementing any crypto algorithm is challenging and you really want to go with a well-tested implementation for production use.

If it's a class exercise I would use a byte[] instead of a BigInteger. You'll need to do a little bit more by hand but it's a lot closer to the spirit of DES since it was designed to be easily implemented in hardware.

I think your idea of implementing DES using bit strings is reasonable as an educational tool. Instead of directly using BigIntegers to represent these bitstrings, I recommend you create a BitString class that implements exactly those bit string methods you need for your project. Inside the BitString class, you can use BigIntegers, but you may find that a simple int array with 1 bit per array element is just as easy or easier, or maybe a linked list.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!