Bit manipulation 在JavaCard中的64位字字节数组上向左旋转

Bit manipulation 在JavaCard中的64位字字节数组上向左旋转,bit-manipulation,64-bit,javacard,Bit Manipulation,64 Bit,Javacard,我正在尝试对JavaCard智能卡中当前表示为8字节字节字节数组的64位字执行任意数量的向左旋转(ROTL)操作 最糟糕的方法是在一个表示为8字节数组的64位字上硬编码所有64种可能的ROTL排列,但这只会使整个代码库膨胀 如何使它更精简,以便我可以在64位字(字节数组)上根据需要仅使用byte和short类型(由于JavaCard无法识别更复杂的事物,如int或long等)动态执行任意数量的ROTL操作无需对所有ROTL64排列进行硬编码。以下方法对缓冲区中的任何类型的数组执行向右旋转,而不需

我正在尝试对JavaCard智能卡中当前表示为8字节字节字节数组的64位字执行任意数量的向左旋转(ROTL)操作

最糟糕的方法是在一个表示为8字节数组的64位字上硬编码所有64种可能的ROTL排列,但这只会使整个代码库膨胀


如何使它更精简,以便我可以在64位字(字节数组)上根据需要仅使用
byte
short
类型(由于JavaCard无法识别更复杂的事物,如
int
long
等)动态执行任意数量的ROTL操作无需对所有ROTL64排列进行硬编码。

以下方法对缓冲区中的任何类型的数组执行向右旋转,而不需要额外的输出或临时数组:

注意:以前的版本要求旋转超过64位,时间常数更大,并且没有包括偏移量。它还需要一个带有循环常量的64位特定数组(现在被字节移位的
for
循环中更通用的
if
内部语句所取代)。请参见其他版本的编辑


当输出缓冲区可用时,旋转变得更加容易:此实现可以只包含初始化部分和最后4行代码。密码通常只按常量和奇数移位,因此只需使用最后4行,在不需要执行(位)移位的情况下跳过优化

我特意使用了一个稍微不同的接口,它假设旋转为64位,只是为了展示一个稍微不同的实现

public static void rotr64(byte[] inBuf, short inOff, byte[] outBuf, short outOff, short rot) {
    short byteRot = (short) ((rot & 0b00111000) >> 3); 
    short bitRot = (short) (rot & 0b00000111); 

    if (bitRot == 0) {

        if (byteRot == 0) {
            // --- no rotation
            return;
        }

        // --- only byte rotation
        for (short i = 0; i < LONG_BYTES; i++) {
            outBuf[(short) (outOff + (i + byteRot) % LONG_BYTES)] = inBuf[(short) (inOff + i)];
        }
    } else {
        // --- bit- and possibly byte rotation
        // note: also works for all other situations, but slower

        // put the last byte in t_lo
        short t = (short) (inBuf[inOff + LONG_BYTES - 1] & BYTE_MASK);
        for (short i = 0; i < LONG_BYTES; i++) {
            // shift t_lo into t_hi and add the next byte into t_lo
            t = (short) (t << BYTE_SIZE | (inBuf[(short) (inOff + i)] & BYTE_MASK));
            // find the byte to receive the shifted value within the short 
            outBuf[(short) (outOff + (i + byteRot) % LONG_BYTES)] = (byte) (t >> bitRot); 
        }
    }
}

private static final int LONG_BYTES = 8;
private static final short BYTE_MASK = 0xFF;
private static final short BYTE_SIZE = 8;


所有测试都是针对随机输入(大约一百万次运行,在JavaSE上不到一秒钟)进行的,尽管我不提供测试保证;请自己测试。

一个非常简单的实现,它在单独的参数中接收四个短路

public static void rotl(byte[] buf, short off, short len, short bits) {
    final short lenBits = (short) (len * BYTE_SIZE);
    bits = (short) ((bits + lenBits) % lenBits);
    // we don't care if we pass 0 or lenBits, rotr will adjust
    rotr(buf, off, len, (short) (lenBits - bits));
}
public static void rotateRight64(short x3, short x2, short x1, short x0,
                                 short rotAmount, short[] out)
{
    assert out.length() == 4;
    rotAmount &= (1 << 6) - 1;  // limit the range to 0..63
    if (rotAmount >= 16)
        rotateRight64(x0, x3, x2, x1, rotAmount - 16, out);
    else
    {
        out[0] = (short)((x0 >>> rotAmount) | (x1 << (16-rotAmount)));
        out[1] = (short)((x1 >>> rotAmount) | (x2 << (16-rotAmount)));
        out[2] = (short)((x2 >>> rotAmount) | (x3 << (16-rotAmount)));
        out[3] = (short)((x3 >>> rotAmount) | (x0 << (16-rotAmount)));
    }
}
这样就可以轻松地将其更改为任意精度的移位/旋转


如果输入数组为
byte
,则可以将
short[4]
更改为
byte[8]
,并将所有常量从16更改为16→ 8和从4开始→ 8.事实上,它们可以毫无问题地进行推广,我只是通过硬编码使其简单易懂

我不太熟悉JavaCard,但它似乎支持按变量移位和按位操作,用它构建多字节变量轮换似乎根本没有问题(实际上与普通Java中的情况相同,但需要更多的强制转换以避免
int
),我在这里遗漏了什么?你可以按8位或16位的短类型进行移位,但除此之外,int、long等都不可用。好的,这个问题中没有
int
long
,因此它们的不可用不会真正影响它的相关性。请阅读我写的第二句话。这个主题试图对置换进行硬编码这不是我想要的。您的第一个函数没有任何输出,使用的是
int
(当然可以轻松更改为
short
byte
)。第二个需要一个数组,这意味着需要在Java卡上为它制作一个特殊的数组,特别是当数据以字节数组形式存在时。也有整数,但同样,它们可以很容易地删除。答案可能比我的更快,也不太复杂,但它与Java卡还不兼容。@MaartenBodewes谢谢,我已经找到了修正了返回问题。我不知道你在说什么,因为在那个片段中,我只有
int
Java卡通常根本没有实现
int
。正式来说,这是一个“可选功能”但由于API不使用任何整数,因此很难找到任何使用
int
的实现,也很难找到任何假定它会出现的applet设计器。因此,任何
int
都是一个
int
太多了。谢谢,我从来没有机会知道它是如何工作的。多么奇怪的Java实现啊,如果你愿意的话,这很有趣比如,数组被创建为持久数组(!),并且没有垃圾收集(!!)。所以
newshort[4]
-或任何类型的短消息数组-已经使您的实现变得不切实际。这很有趣,有时可以尝试一下。它会让您回到比特黑客的旧时代,再加上使用签名短消息和字节、各种安全要求、合规性和安全评估以及需要在中实现的加密页面小于8千磅的RAM:P
public static void rotl64(byte[] inBuf, short inOff, byte[] outBuf, short outOff, short rot) {
    rotr64(inBuf, inOff, outBuf, outOff, (short) (64 - rot & 0b00111111));
}
public static void rotateRight64(short x3, short x2, short x1, short x0,
                                 short rotAmount, short[] out)
{
    assert out.length() == 4;
    rotAmount &= (1 << 6) - 1;  // limit the range to 0..63
    if (rotAmount >= 16)
        rotateRight64(x0, x3, x2, x1, rotAmount - 16, out);
    else
    {
        out[0] = (short)((x0 >>> rotAmount) | (x1 << (16-rotAmount)));
        out[1] = (short)((x1 >>> rotAmount) | (x2 << (16-rotAmount)));
        out[2] = (short)((x2 >>> rotAmount) | (x3 << (16-rotAmount)));
        out[3] = (short)((x3 >>> rotAmount) | (x0 << (16-rotAmount)));
    }
}
public static void rotateRight(short[] out, short[] in, short rotAmount) // in ror rotAmount
{
    assert out.length() == 4 && in.length() == 4 && rotAmount >= 0 && rotAmount < 64;

    const short shift     = (short)(rotAmount % 16);
    const short limbshift = (short)(rotAmount / 16);

    short tmp = in[0];
    for (short i = 0; i < 4; ++i)
    {
        short index = (short)((i + limbshift) % 4);
        out[i]  = (short)((in[index] >>> shift) | (in[index + 1] << (16 - shift)));
    }
}