C:SHA-1 的输出作为小端到浮动
C: Output of SHA-1 as little endian to float
根据 this documentation,我的任务是根据字母数字标识符计算颜色值。这个想法是 运行 通过 SHA-1 的标识符字符串,并使用部分结果来计算颜色值。
我在执行以下步骤时遇到问题:
Treat the output as little endian and extract the last-significant 16 bits. (These are the first two bytes of the output, with the second byte being the most significant one.)
这是我目前的情况:
double get_CbCr_angle(const char* identifier) {
unsigned char temp[SHA_DIGEST_LENGTH];
char buf[SHA_DIGEST_LENGTH*2];
// initalise with 0s
memset(buf, 0x0, SHA_DIGEST_LENGTH*2);
memset(temp, 0x0, SHA_DIGEST_LENGTH);
// compute hash into temp
SHA1((unsigned char *)identifier, strlen(identifier), temp);
// print from temp into buf and
// interpret as (signed) chars
int i = 0;
for (i=0; i < SHA_DIGEST_LENGTH; i++) {
sprintf( (char*) &(buf[i*2]), "%02x", temp[i]);
}
printf("SHA1 is %s\n", buf);
// make a union type of char and float so we can read a char array
// as float.
union charFloat {
float f;
char s[sizeof(float)];
};
union charFloat foo;
// put first two chars (bytes) into union.
// bracket notation should be fine since both foo and buf are
// char arrays.
foo.s[0] = buf[1];
foo.s[1] = buf[0];
printf("interpreted as chars: %s\n", foo.s);
printf("interpreted as float: %f\n", foo.f); // 0.000000 - why?
}
但我无法通过这种方法获得任何合理的输出。使用更多的字节只会给我 float
的无意义值,以及将其解释为 int
.
显然,我不希望有人为我解决这个问题。我非常感谢您提供一些有关查看方向的提示。
非常感谢。
我会通过使用显式移位和 OR 将两个 char
组装成一个 uint16_t
来做到这一点:
uint16_t x = (((uint16_t)(uint8_t)temp[1]) << 8) |
(((uint18_t)(uint8_t)temp[0]) << 0);
两次强制转换是必要的,以确保每个 char
值在移位之前都是零而不是符号扩展到 uint16_t
的宽度。另请注意,我正在读取 temp
,而不是 buf
- raw SHA 哈希,而不是十六进制编码的哈希。使用十六进制编码的哈希值会限制 x
可以采用的可能值。
然后,将 x
除以 65536 将其转换为 [0, 1)
范围内的浮点数:
double f = x / 65536.0;
65536 是 216; uint16_t
的取值范围是 0 到 65535(含)。除数上的 .0
后缀是使 C 执行浮点除法而不是整数除法所必需的。为了效率,这个除法可以结合下一步乘以2π:
double f = x * (2 * M_PI / 65536);
M_PI
(在math.h
中声明)已经是一个浮点数,所以我们不再需要在65536上加上.0
后缀,但是你需要在括号里加上括号整个子表达式 2 * M_PI / 65536
以强制编译器在编译时计算该部分并仅发出一个运行时乘法。
让我们仔细看看该算法:
- Run the input through SHA-1 (RFC 3174 [4]).
- Treat the output as little endian and extract the last-significant 16 bits. (These are the first two bytes of the output, with the second
byte being the most significant one.)
- Divide the value by 65536 (use float division) and multiply it by 2π (two Pi).
该算法并不是说要将前两个字节视为浮点值。上面写着把它们当成一个16位的整数,然后把这个值转成浮点型进行下一步。
此外,在转换值时,您应该使用 temp
而不是 buf
,因为 buf
包含表示散列输出的可打印字符,而 temp
包含实际输出.
所以你会像这样转换值:
uint16_t value;
value = temp[0];
value |= temp[1] << 8;
然后将其转换为 double
以进行下一步:
double result = value * 2 * M_PI / 65536;
根据 this documentation,我的任务是根据字母数字标识符计算颜色值。这个想法是 运行 通过 SHA-1 的标识符字符串,并使用部分结果来计算颜色值。
我在执行以下步骤时遇到问题:
Treat the output as little endian and extract the last-significant 16 bits. (These are the first two bytes of the output, with the second byte being the most significant one.)
这是我目前的情况:
double get_CbCr_angle(const char* identifier) {
unsigned char temp[SHA_DIGEST_LENGTH];
char buf[SHA_DIGEST_LENGTH*2];
// initalise with 0s
memset(buf, 0x0, SHA_DIGEST_LENGTH*2);
memset(temp, 0x0, SHA_DIGEST_LENGTH);
// compute hash into temp
SHA1((unsigned char *)identifier, strlen(identifier), temp);
// print from temp into buf and
// interpret as (signed) chars
int i = 0;
for (i=0; i < SHA_DIGEST_LENGTH; i++) {
sprintf( (char*) &(buf[i*2]), "%02x", temp[i]);
}
printf("SHA1 is %s\n", buf);
// make a union type of char and float so we can read a char array
// as float.
union charFloat {
float f;
char s[sizeof(float)];
};
union charFloat foo;
// put first two chars (bytes) into union.
// bracket notation should be fine since both foo and buf are
// char arrays.
foo.s[0] = buf[1];
foo.s[1] = buf[0];
printf("interpreted as chars: %s\n", foo.s);
printf("interpreted as float: %f\n", foo.f); // 0.000000 - why?
}
但我无法通过这种方法获得任何合理的输出。使用更多的字节只会给我 float
的无意义值,以及将其解释为 int
.
显然,我不希望有人为我解决这个问题。我非常感谢您提供一些有关查看方向的提示。
非常感谢。
我会通过使用显式移位和 OR 将两个 char
组装成一个 uint16_t
来做到这一点:
uint16_t x = (((uint16_t)(uint8_t)temp[1]) << 8) |
(((uint18_t)(uint8_t)temp[0]) << 0);
两次强制转换是必要的,以确保每个 char
值在移位之前都是零而不是符号扩展到 uint16_t
的宽度。另请注意,我正在读取 temp
,而不是 buf
- raw SHA 哈希,而不是十六进制编码的哈希。使用十六进制编码的哈希值会限制 x
可以采用的可能值。
然后,将 x
除以 65536 将其转换为 [0, 1)
范围内的浮点数:
double f = x / 65536.0;
65536 是 216; uint16_t
的取值范围是 0 到 65535(含)。除数上的 .0
后缀是使 C 执行浮点除法而不是整数除法所必需的。为了效率,这个除法可以结合下一步乘以2π:
double f = x * (2 * M_PI / 65536);
M_PI
(在math.h
中声明)已经是一个浮点数,所以我们不再需要在65536上加上.0
后缀,但是你需要在括号里加上括号整个子表达式 2 * M_PI / 65536
以强制编译器在编译时计算该部分并仅发出一个运行时乘法。
让我们仔细看看该算法:
- Run the input through SHA-1 (RFC 3174 [4]).
- Treat the output as little endian and extract the last-significant 16 bits. (These are the first two bytes of the output, with the second byte being the most significant one.)
- Divide the value by 65536 (use float division) and multiply it by 2π (two Pi).
该算法并不是说要将前两个字节视为浮点值。上面写着把它们当成一个16位的整数,然后把这个值转成浮点型进行下一步。
此外,在转换值时,您应该使用 temp
而不是 buf
,因为 buf
包含表示散列输出的可打印字符,而 temp
包含实际输出.
所以你会像这样转换值:
uint16_t value;
value = temp[0];
value |= temp[1] << 8;
然后将其转换为 double
以进行下一步:
double result = value * 2 * M_PI / 65536;