跳到主要内容

4. 实用函数 (Utility Functions)

本文档中的算法使用下面描述的实用函数,以及标准算术运算(加法、乘法、模约简等)和椭圆曲线点运算(点加法和标量乘法)。

为了安全起见,这些函数的实现应该 (SHOULD) 是常数时间的:简而言之,这意味着执行时间和内存访问模式不应该 (SHOULD NOT) 依赖于秘密输入、中间值或输出的值。对于这种常数时间实现,所有算术运算、比较和赋值也必须 (MUST) 以常数时间实现。第 10.3 节简要讨论了常数时间安全问题。

有关实现低级操作(以常数时间或其他方式)的指导超出了本文档的范围;读者应参考标准参考资料 [MOV96] [CFADLNV05]。

  • CMOV(a, b, c): 如果 c 为 False,CMOV 返回 a;否则返回 b。对于常数时间实现,此操作必须以独立于 c 的值的时间运行。

  • AND、OR、NOT 和 XOR 是标准的按位逻辑运算符。对于常数时间实现,必须 (MUST) 避免短路运算符。

  • is_square(x): 此函数在值 x 是域 F 中的平方数时返回 True。根据欧拉判据 (Euler's criterion),此函数可以在常数时间内计算为

is_square(x) := { True,  如果 x^((q - 1) / 2) 在 F 中为 0 或 1;
{ False, 否则。

在某些扩展域中,is_square 可以比上述指数运算更快地在常数时间内计算。[AR13] 和 [S85] 描述了扩展域的优化方法。附录 I.5 给出了 GF(p^2) 的优化直线方法。

  • sqrt(x): sqrt 运算是一个多值函数 (multi-valued function),即,当 x 是平方数时,在域 F 中存在 x 的两个根(除非 x = 0)。为了在保持实现之间兼容性的同时允许实现者进行优化,本文档不要求 sqrt() 返回特定值。相反,如第 6.4 节所述,任何调用 sqrt 的函数还指定如何确定正确的根。

计算平方根的首选方法是固定特定于 F 的确定性算法。我们在附录 I 中给出了几种算法。

  • sgn0(x): 此函数返回 0 或 1,表示 x 的"符号",其中 sgn0(x) == 1 表示 x 为"负"。(换句话说,此函数始终将 0 视为正。)第 4.1 节定义了此函数并讨论了其实现。

  • inv0(x): 此函数返回 x 在 F 中的乘法逆元,通过固定 inv0(0) == 0 扩展到整个 F。在常数时间内实现 inv0 的直接方法是计算

inv0(x) := x^(q - 2).

注意,在输入 0 时,输出按要求为 0。某些域可能允许更快的求逆方法;此类方法的详细讨论超出了本文档的范围。

  • I2OSP 和 OS2IP: 这些函数用于将字节串转换为非负整数或从非负整数转换,如 [RFC8017] 中所述。(请注意,这些函数以大端字节顺序操作字节串。)

  • a || b: 表示字节串 a 和 b 的连接。例如,"ABC" || "DEF" == "ABCDEF"。

  • substr(str, sbegin, slen): 对于字节串 str,此函数返回从位置 sbegin 开始的 slen 字节子串;位置从零开始索引。例如,substr("ABCDEFG", 2, 3) == "CDE"。

  • len(str): 对于字节串 str,此函数返回 str 的字节长度。例如,len("ABC") == 3。

  • strxor(str1, str2): 对于字节串 str1 和 str2,strxor(str1, str2) 返回两个字符串的按位异或。例如,strxor("abc", "XYZ") == "9;9"(此示例中的字符串是 ASCII 字面量,但 strxor 适用于任意字节串)。在本文档中,strxor 仅应用于长度相等的输入。

4.1. sgn0 函数 (The sgn0 Function)

本节定义了适用于任何域 F = GF(p^m) 的通用 sgn0 实现。它还为 F = GF(p) 和 F = GF(p^2) 的情况给出了简化实现。

扩展域的 sgn0 函数定义依赖于域元素的多项式基或向量表示,并遍历输入元素的整个向量表示。因此,sgn0 依赖于用于定义多项式基的原始多项式;有关此基的更多信息,请参见第 8 节,有关将扩展域元素表示为向量的讨论,请参见第 2.1 节。

sgn0(x)

参数 (Parameters):
- F,特征为 p、阶为 q = p^m 的有限域。
- p,F 的特征(见上文)。
- m,F 的扩展次数,m >= 1(见上文)。

输入 (Input): x,F 的一个元素。
输出 (Output): 0 或 1。

步骤 (Steps):
1. sign = 0
2. zero = 1
3. for i in (1, 2, ..., m):
4. sign_i = x_i mod 2
5. zero_i = x_i == 0
6. sign = sign OR (zero AND sign_i) # 避免短路逻辑运算
7. zero = zero AND zero_i
8. return sign

当 m == 1 时,sgn0 可以显著简化:

sgn0_m_eq_1(x)

输入 (Input): x,GF(p) 的一个元素。
输出 (Output): 0 或 1。

步骤 (Steps):
1. return x mod 2

m == 2 的情况只是稍微复杂一点:

sgn0_m_eq_2(x)

输入 (Input): x,GF(p^2) 的一个元素。
输出 (Output): 0 或 1。

步骤 (Steps):
1. sign_0 = x_0 mod 2
2. zero_0 = x_0 == 0
3. sign_1 = x_1 mod 2
4. s = sign_0 OR (zero_0 AND sign_1) # 避免短路逻辑运算
5. return s