【问题标题】:Calculate a formula in a Finite Field计算有限域中的公式
【发布时间】:2021-06-17 17:54:48
【问题描述】:

我正在尝试将一个公式转换为该公式的有限域等效项。

公式如下:

现在我已经实现了它并且它可以正常工作,但是我需要在有限域中使用它,这意味着我引入了一个 p,比如说p = 183269mod p,但是如何上面的公式到底有没有变化?在我正常计算完公式后,我是否只需mod p

例子:

我有多项式:f(x) = 1234 + 631x + 442x^2 我生成了 6 个随机点:(x, f(x) mod p)

1. (108, 93338)
2. (413, 146507)
3. (260, 171647)
4. (819, 98605)
5. (359, 13237)
6. (894, 118490)

现在,我想要的是使用上述公式在给定任意 3 个点的情况下重建 1234,但它给出的值不正确。

这是我的代码:

// x_input = [108, 413, 260]
    var reconstructed float64 = 0.0

    for _, k := range x_input { 
        var y float64 = float64(points[k])
        var pr_x float64 = 1.0

        for _, l := range x_input {
            if l != k {
                var aux_k float64 = float64(k)
                var aux_l float64 = float64(l)
                pr_x *= (aux_l / (aux_l - aux_k))
            }
        }

        y *= pr_x
        reconstructed += y
    }

我正在尝试实现SSSS

编辑

正如@user58697 指出的那样,我的代码和对有限域的理解存在一些错误。我设法重写了我的公式,它看起来像这样:

reconstructed := 0

    for _, k := range x_input { 
        y := points[k]
        pr_x := 1
        for _, l := range x_input {
            if l != k {
                inv := mod_inverse(l - k, p)
                pr_x *= inv
            }
        }
        y *= pr_x
        reconstructed += y
    }

    return reconstructed % p

func mod_inverse(a, p int) int {

    if a < 0 { // negative numbers are not allowed
        a = a * -1
    }

    for i := 1; i < p; i++ {
        if ((a % p) * (i % p)) % p == 1 {
            return i
        }
    }

    return p
} 

不幸的是,它仍然存在一个或多个错误,因为它不会产生f(0)

【问题讨论】:

    标签: algorithm go secret-key modular-arithmetic


    【解决方案1】:

    在我正常计算完公式后,我是否只需修改 p?

    没有。首先,您必须计算 x[m] - x[j]p 的乘法逆。这是有效实施的一个棘手部分。其余的确实只是乘法和求和模p

    请记住,浮点运算不能在有限域中工作。在整数意义上,所有内容都是精确的。

    PS:为了解决除法的问题,这是有限域中除法的工作原理:

    y/x 实际上是y * z,其中zx 的乘法逆元,即x * z = 1 mod p。例如,让我们使用 7 表示 p。例如 2 的乘法逆元是 4:2 * 4 == 8 (== 1 mod 7)。这意味着3/2 mod 73 * 4 mod 7,即5

    【讨论】:

    • 但是除法的时候不能产生浮点数吗?
    • 谢谢,如果整数没有模乘逆怎么办?例如1101832?
    • 如果xp 互质,则保证存在xp 的乘法逆元。如果p 是素数,则总是如此。否则,运气不好(顺便说一句,它不再是 field 了)。这就是为什么素数在密码学中如此重要的原因。
    【解决方案2】:

    您应该记住,始终在将两个数字相乘后取模。如果a&lt;p,b&lt;p,c&lt;p 用于p=183269a*b*c 可能会导致 int 溢出。如果p 更大(如998244353),a*b 会简单地导致溢出。对于这种情况,在将两个数字 ab 相乘之前,您应该将它们转换为 int64 并将结果与​​ p 取模,最后将其转换回 int

    这里还有一点:a 在模 p 时并不总是等于 -a。实际上,在大多数情况下这是错误的。你应该改用a = (a % p + p) % p

    以下是可以产生正确结果的修改代码(我刚刚为这个问题学习了golang,所以请原谅我可能不正确的代码):

        reconstructed := 0
        for _, k := range x_input {
            y := points[k]
            pr_x := 1
            for _, l := range x_input {
                if l != k {
                    inv := mod_inverse(l - k, p)
                    // You forgot to multiply pr_x by l
                    // pr_x *= inv
                    pr_x = pr_x * inv % p * l % p
                }
            }
            y = y * pr_x % p
            reconstructed += y
        }
    
        return reconstructed % p
    
    func mod_inverse(a, p int) int {
    
        if a < 0 { // negative numbers are not allowed
            // The following line is wrong! (a % p) == (a % p + p) % p when a < 0, but not -a
            // a = a * -1
            a = ((a % p) + p) % p
        }
    
        for i := 1; i < p; i++ {
            if ((a % p) * (i % p)) % p == 1 {
                return i
            }
        }
    
        // I suspect whether you should report an error here instead of returning p
        return p
    }
    

    顺便说一句,mod_inverse 的时间复杂度是O(p),在大多数情况下效率很低。您可以使用Extended Euclidean Algorithm 计算xO(log p) 时间内模p 的乘法逆。此外,当p 为素数时,xp 的乘法逆元就是(x^(p-2)) % p,您可以使用Exponentiation by squaring 快速计算。这两种方法都有O(log p) 的复杂性,但后一种更容易实现。

    对不起,我的英语很差。欢迎指出我的错别字和错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多