如何在不使用C语言的整数类型的情况下将2 uint8模数乘以大数

时间:2016-01-22 14:22:52

标签: c cryptography

如果AB类型为uint8_t且我希望结果C=AxB % N N为2 ^ 16,那么我该怎么做呢我不能使用整数(所以我不能在C语言中将N声明为整数,只能uint8_t)?

注意:ABC存储在uint8数组中,因此它们被“表达”为uint8,但它们的值可能更大

2 个答案:

答案 0 :(得分:3)

一般来说,没有简单的方法可以做到这一点。

首先,您需要为每个uint8_t块实现A和B之间的乘法运算。请参阅答案here

2^16除法真正意味着“忽略”最后16位,“不要使用”最后两位uint8_t(因为你使用了int数组)。由于你有模数运算符,这意味着相反,所以你只需要得到最后两个uint8_t

uint8 A的最低a0(例如a1B)和b0(说b1uint8 }):

将每个a0h = a0 >> 4; ## the same as a0h = a0/16; a0l = a0 % 16; ## the same as a0l = a0 & 0x0f; a1h = a1 >> 4; a1l = a1 % 16; b0h = b0 >> 4; b0l = b0 % 16; b1h = b1 >> 4; b1l = b1 % 16; 拆分为高低部分

x

首先将下半部分相乘(x = a0l * b0l; 是缓冲区变量)

x

结果的第一部分是s0l的最后四位,我们称之为s0l = x % 16;

x

c = x>>4; 位的顶部是进位。

uint8

将第一个x = (a0h * b0h) + c; 的较高部分相乘并添加进位。

x

结果的第一部分是s0h的最后四位,我们称之为s0h = x % 16; c = x>>4; 。我们需要再次携带。

s0

我们现在可以合并s0 = (s0h << 4) + s0l;

x = (a1l * b1l) + c;
s1l = x % 16;
c = x>>4;
x = (a1h * b1h) + c;
s1h = x % 16;
c = x>>4;
s1 = (s1h << 4) +  s1l;

对s1做同样的事情(但不要忘记添加进位!):

c

此时您的结果是s1s0s2(您需要进行下一次乘法,例如。s3s4,{{1 }},)。正如您的公式所示%(2 ^ 16),您已经得到了结果 - s1s2。如果你必须与其他东西分开,你应该做一些类似于上面的代码,但是为了分裂。在这种情况下,小心地将除以零,它将给你NAN或其他东西!

你可以将A,B,C和S放在数组中并循环遍历索引,以使代码更清晰。

答案 1 :(得分:2)

这是我的努力。我冒昧地使用更大的整数和指针来循环遍历数组。数字由big-endian顺序的uint8_t数组表示。所有中间结果都保存在uint8_t个变量中。如果中间结果可以存储在更宽的整数变量中,则代码可以更有效!

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>

static void add_c(uint8_t *r, size_t len_r, uint8_t x)
{
    uint8_t o;

    while (len_r--) {
        o = r[len_r];
        r[len_r] += x;
        if (o <= r[len_r])
            break;
        x = 1;
    }
}

void multiply(uint8_t *res, size_t len_res,
        const uint8_t *a, size_t len_a, const uint8_t *b, size_t len_b)
{
    size_t ia, ib, ir;

    for (ir = 0; ir < len_res; ir++)
        res[ir] = 0;

    for (ia = 0; ia < len_a && ia < len_res; ia++) {
        uint8_t ah, al, t;

        t = a[len_a - ia - 1];
        ah = t >> 4;
        al = t & 0xf;

        for (ib = 0; ib < len_b && ia + ib < len_res; ib++) {
            uint8_t bh, bl, x, o, c0, c1;

            t = b[len_b - ib - 1];
            bh = t >> 4;
            bl = t & 0xf;

            c0 = al * bl;
            c1 = ah * bh;

            o = c0;
            t = al * bh;
            x = (t & 0xf) << 4;
            c0 += x;
            x = (t >> 4);
            c1 += x;
            if (o > c0)
                c1++;

            o = c0;
            t = ah * bl;
            x = (t & 0xf) << 4;
            c0 += x;
            x = (t >> 4);
            c1 += x;
            if (o > c0)
                c1++;

            add_c(res, len_res - ia - ib, c0);
            add_c(res, len_res - ia - ib - 1, c1);
        }
    }
}

int main(void)
{
    uint8_t a[2] = { 0xee, 0xdd };
    uint8_t b[2] = { 0xcc, 0xbb };
    uint8_t r[4];

    multiply(r, sizeof(r), a, sizeof(a), b, sizeof(b));
    printf("0x%02X%02X * 0x%02X%02X = 0x%02X%02X%02X%02X\n",
            a[0], a[1], b[0], b[1], r[0], r[1], r[2], r[3]);
    return 0;
}

输出:

0xEEDD * 0xCCBB = 0xBF06976F