我写这些 sha256 #define 的方法正确吗?

问题描述 投票:0回答:1

他们是:

#define majority(a, b, c) _mm256_xor_si256(_mm256_xor_si256(_mm256_and_si256(a, b), _mm256_and_si256(b, c)), _mm256_and_si256(a, c))
#define choose(e, f, g) _mm256_xor_si256(_mm256_and_si256(e, f), _mm256_and_si256(_mm256_xor_si256(e, allones) , g))

#define ROR32_AVX(x, n) _mm256_or_si256(_mm256_srli_epi32((x), (n)), _mm256_slli_epi32((x), 32 - (n)))

#define sigma0(x) _mm256_xor_si256(_mm256_xor_si256(ROR32_AVX((x), 2), ROR32_AVX((x), 13)), ROR32_AVX((x), 22))
#define sigma1(x) _mm256_xor_si256(_mm256_xor_si256(ROR32_AVX((x), 6), ROR32_AVX((x), 11)), ROR32_AVX((x), 25))

#define step(maj, ch, s0, s1, az, bz, cz, dz, ez, fz, gz, hz, k, m) \
    ez = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(ch(e, f, g), s1(e)), hz), k), m), dz); \
    az = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(ch(e, f, g), s1(e)), hz), k), m); \
    az = _mm256_add_epi32(az, _mm256_add_epi32(maj(a, b, c), s0(a)));

我检查了 sha256 标准和维基百科页面,这里一切似乎都正常?我还没有编写压缩函数,因为我想确保我得到了#define 的正确性。

我的计划是像这样调用

step
宏:

step(majority, choose, s0, s1, a, b, c, d, e, f, g, h, k, m);
step(majority, choose, s0, s1, h, a, b, c, d, e, f, g, k, m);
step(majority, choose, s0, s1, g, h, a, b, c, d, e, f, k, m);
step(majority, choose, s0, s1, f, g, h, a, b, c, d, e, k, m);

编辑:我现在已经编写了 64 步轮次,将所有消息块设置为零,但仍然得到错误的哈希值。或者“零输入”的 sha256 仍然需要填充,例如附加的 0x80 字节?那么,“空”消息实际上应该是

0x8000.....00001
最后注明其中一条消息的长度吗?

我做了其中 64 个:

step(majority, choose, sigma0, sigma1, a, b, c, d, e, f, g, h, K0x428a2f98, m[0]);
step(majority, choose, sigma0, sigma1, h, a, b, c, d, e, f, g, K0x71374491, m[1]);
step(majority, choose, sigma0, sigma1, g, h, a, b, c, d, e, f, K0xb5c0fbcf, m[2]);
step(majority, choose, sigma0, sigma1, f, g, h, a, b, c, d, e, K0xe9b5dba5, m[3]);
step(majority, choose, sigma0, sigma1, e, f, g, h, a, b, c, d, K0x3956c25b, m[4]);

所有常量都使用另一个函数中的

_mm256_setr_epi32
设置为常量值。我还将初始工作寄存器设置为其相应的值。最后,当想知道哈希值时,我这样做:

H0x6a09e667 = _mm256_add_epi32(H0x6a09e667, a);
H0xbb67ae85 = _mm256_add_epi32(H0xbb67ae85, b);
H0x3c6ef372 = _mm256_add_epi32(H0x3c6ef372, c);
H0xa54ff53a = _mm256_add_epi32(H0xa54ff53a, d);
H0x510e527f = _mm256_add_epi32(H0x510e527f, e);
H0x9b05688c = _mm256_add_epi32(H0x9b05688c, f);
H0x1f83d9ab = _mm256_add_epi32(H0x1f83d9ab, g);
H0x5be0cd19 = _mm256_add_epi32(H0x5be0cd19, h);


unsigned int aa = _mm256_extract_epi32(H0x6a09e667, 0);
unsigned int bb = _mm256_extract_epi32(H0xbb67ae85, 0);
unsigned int cc = _mm256_extract_epi32(H0x3c6ef372, 0);
unsigned int dd = _mm256_extract_epi32(H0xa54ff53a, 0);
unsigned int ee = _mm256_extract_epi32(H0x510e527f, 0);
unsigned int ff = _mm256_extract_epi32(H0x9b05688c, 0);
unsigned int gg = _mm256_extract_epi32(H0x1f83d9ab, 0);
unsigned int hh = _mm256_extract_epi32(H0x5be0cd19, 0);

printf("%x%x%x%x%x%x%x%x\n", aa, bb, cc, dd, ee, ff, gg, hh);

完整代码如下:

https://github.com/EnesO226/SHA256AVX/blob/main/Bitcoin.cpp

c algorithm sha256 avx sha2
1个回答
0
投票

这个...

#define step(maj, ch, s0, s1, az, bz, cz, dz, ez, fz, gz, hz, k, m) \
    ez = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(ch(e, f, g), s1(e)), hz), k), m), dz); \
    az = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(ch(e, f, g), s1(e)), hz), k), m); \
    az = _mm256_add_epi32(az, _mm256_add_epi32(maj(a, b, c), s0(a)));

... 看起来错误,因为嵌入宏调用的参数不是从

step()
宏的参数中提取的。 看起来您从这些宏的定义中复制了名称 + 参数列表,并仅更改了宏名称以匹配
step
的参数,而不是这些宏的参数。 尽管如此,编译器还是接受这一点,因为宏参数的命名与在您展开
step()
的范围内的适当类型变量的名称相同。 如果您在那里写的实际上是您想要的,那么您就已经使
step()
变得比需要的复杂得多。

可能你的意思更像是这样的:

#define step(maj, ch, s0, s1, az, bz, cz, dz, ez, fz, gz, hz, k, m) \
    ez = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(ch(ez, fz, gz), s1(ez)), hz), k), m), dz); \
    az = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(ch(ez, fz, gz), s1(ez)), hz), k), m); \
    az = _mm256_add_epi32(az, _mm256_add_epi32(maj(az, bz, cz), s0(az)));

(但一定要检查一下)。

此外,对于问题中描述的用法,

step()
通过接受参数
maj
ch
s0
s1
而不必要地复杂化。 显示的
step()
的所有使用都将相同的名称作为参数传递给这些参数。 即使这些名称的定义在不同的使用上下文中不同,只要名称本身相同,如果直接嵌入它们,您的代码会更短、更清晰,如下所示:

#define step(az, bz, cz, dz, ez, fz, gz, hz, k, m) \
    ez = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(choose(ez, fz, gz), sigma1(ez)), hz), k), m), dz); \
    az = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(choose(ez, fz, gz), sigma1(ez)), hz), k), m); \
    az = _mm256_add_epi32(az, _mm256_add_epi32(majority(az, bz, cz), sigma0(az)));

// ...

step(a, b, c, d, e, f, g, h, k, m);
step(h, a, b, c, d, e, f, g, k, m);
step(g, h, a, b, c, d, e, f, k, m);
step(f, g, h, a, b, c, d, e, k, m);

此外,真正的函数比类似函数的宏更受青睐。 您在评论中写道...

我尝试像之前的函数一样实现它,但出了问题;我无法像步骤、步骤、步骤等那样编写它,我必须手动写出所有大多数并手动选择和西格玛操作,这没有乐趣:)

但看起来至少,除了

step()
之外的所有宏都可以轻松地在不破坏任何东西的情况下发挥作用:

__m256i majority(__m256i a, __m256i b, __m256i c) {
    return _mm256_xor_si256(_mm256_xor_si256(_mm256_and_si256(a, b), _mm256_and_si256(b, c)), _mm256_and_si256(a, c));
}

__m256i choose(__m256i e, __m256i f, __m256i g) {
    return _mm256_xor_si256(_mm256_and_si256(e, f), _mm256_and_si256(_mm256_xor_si256(e, allones) , g));
}

__m256i ROR32_AVX(__m256i x, int n) {
    return _mm256_or_si256(_mm256_srli_epi32(x, n), _mm256_slli_epi32(x, 32 - n));
}

__m256i sigma0(__m256i x) {
    return _mm256_xor_si256(_mm256_xor_si256(ROR32_AVX(x, 2), ROR32_AVX(x, 13)), ROR32_AVX(x, 22));
}

__m256i sigma1(__m256i x) {
    return _mm256_xor_si256(_mm256_xor_si256(ROR32_AVX(x, 6), ROR32_AVX(x, 11)), ROR32_AVX(x, 25));
}

据我所知,对

step()
执行相同操作的唯一问题是它修改了一些参数,但这可以通过传递指针而不是直接值来解决:

// all arguments are pointers for consistency, though it appears that
// only az and ez really need to be
void step(__m256i *az, __m256i *bz, __m256i *cz, __m256i *dz, __m256i *ez,
          __m256i *fz, __m256i *gz, __m256i *hz, __m256i *k,  __m256i *m) {
    *ez = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(choose(*ez, *fz, *gz), sigma1(*ez)), *hz), *k), *m), *dz);
    *az = _mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(_mm256_add_epi32(choose(*ez, *fz, *gz), sigma1(*ez)), *hz), *k), *m);
    *az = _mm256_add_epi32(*az, _mm256_add_epi32(majority(*az, *bz, *cz), sigma0(*az)));
}

// ... which would be used like so:

step(&a, &b, &c, &d, &e, &f, &g, &h, &k, &m);
step(&h, &a, &b, &c, &d, &e, &f, &g, &k, &m);
step(&g, &h, &a, &b, &c, &d, &e, &f, &k, &m);
step(&f, &g, &h, &a, &b, &c, &d, &e, &k, &m);

除此之外,它还解决了宏替换文本中以前的宏参数的括号不足问题。 只要这些函数的定义和所有使用出现在同一个翻译单元中,我就希望在适当的优化级别编译时所有内容都会被内联。 如果您对此有疑问或想让意图更清楚,那么您可以声明所有这些函数

static inline
(再次假设对它们的所有调用都来自同一个 TU)。

© www.soinside.com 2019 - 2024. All rights reserved.