parazyd 3 lat temu
rodzic
commit
88cba70898
1 zmienionych plików z 122 dodań i 0 usunięć
  1. 122 0
      script/research/pvss/pvss.sage

+ 122 - 0
script/research/pvss/pvss.sage

@@ -0,0 +1,122 @@
+# Publicly Verifiable Secret Sharing
+# https://www.win.tue.nl/~berry/papers/crypto99.pdf
+# This scheme depends on an honest dealer.
+
+t = 3  # Threshold
+n = 5  # Participants
+
+# Pallas
+p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
+q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
+Fp = GF(p)
+Fq = GF(q)
+Ep = EllipticCurve(Fp, (0, 5))
+Ep.set_order(q * 0x01)
+Eq = EllipticCurve(Fq, (0, 5))
+Eq.set_order(p * 0x01)
+
+# ValueCommitR Generator: g
+vcr_x = 0x07f444550fa409bb4f66235bea8d2048406ed745ee90802f0ec3c668883c5a91
+vcr_y = 0x24136777af26628c21562cc9e46fb7c2279229f1f39281460e2f46c8a772d9ca
+g = Ep([vcr_x, vcr_y])
+
+# NullifierK Generator: G
+nfk_x = 0x25e7aa169ca8198d2e375571faf4c9cf5e7eb192ccb5db9bd36f6aa7e447ca75
+nfk_y = 0x155c1f851b1a3384880473442008ff755fe0a49ec1c1b4332db8dce21ae001cc
+G = Ep([nfk_x, nfk_y])
+
+# ==============
+# Initialization
+# ==============
+# The participants create their keypairs and register their public keys
+# y_i = G^{x_i}
+x = []
+y = []
+for i in range(n):
+    x_i = Fq.random_element()
+    #x_i = Fq(i+2)
+    x.append(x_i)
+    y.append(G * x_i)
+
+# ============
+# Distribution
+# ============
+# The dealer selects a secret s:
+#s = Fp.random_element()
+s = Fq(42)
+
+# The dealer picks a random polynomial p of degree at most t-1 with
+# coefficients in Fp and sets s=alpha_0
+alpha = []
+for i in range(t):
+    alpha.append(Fq.random_element())
+    #alpha.append(Fq(i+2))
+alpha[0] = s
+R.<ω> = PolynomialRing(Fq)
+p = R(alpha)
+assert p.degree() == t-1
+assert p.coefficients()[0] == s
+
+# The dealer keeps this polynomial secret but publishes the related
+# commitments C_j = g ^ {a_j} , for 0 ≤ j < t
+C = []
+for j in range(t):
+    C.append(g * alpha[j])
+
+# The dealer also publishes the encrypted shares Y_i = y_i ^ p(i),
+# for 1 ≤ i ≤ n , using the public keys of the participants
+Y = []
+for i in range(1, n+1):
+    Y.append(y[i-1] * p(i))
+
+# Finally, let X_i = prod_{j=0}^{t-1} C_j * i^j. The verifier computes
+# this from the published commitments.
+X = []
+for i in range(1, n+1):
+    X_i = Ep(0)
+    for j in range(t):
+        X_i += C[j] * (i^j)
+    X.append(X_i)
+
+# The dealer shows that the encrypted shares are consistent by
+# producing a proof of knowledge of the unique p(i), 1 ≤ i ≤ n,
+# satisfying: X_i = g^p(i) , Y_i = y_i^p(i)
+for i in range(1, n+1):
+    assert X[i-1] == g * p(i)
+    assert Y[i-1] == y[i-1] * p(i)
+
+# For a non-interactive proof, we can use the Fiat-Shamir technique.
+# TODO: See DLEQ in the paper.
+
+# ==============
+# Reconstruction
+# ==============
+# Using its private key x_i, each participant finds the share S_i = G^p(i)
+# from Y_i by computing S_i = Y_i^(1/x_i). They publish S_i plus a proof
+# that the value S_i is a correct decryption of Y_i. To this end it
+# suffices to prove knowledge of an alpha such that y_i = G^alpha and
+# Y_i = S_i^alpha, which is accomplished by the non-interactive version
+# of the protocol DLEQ(G, y_i, S_i, Y_i).
+S = []
+for i in range(n):
+    S_i = Y[i] * (1 / x[i])
+    assert S_i == G * p(i+1)
+    S.append(S_i)
+
+# Pooling the shares. Sample a set of t shares and reconstruct secret.
+# FIXME: This is for 1,...,t, we should be able to take random ones.
+shares = S[:t]
+pooled = Ep(0)
+
+def lambda_func(i, t):
+    lambda_i = Fq(1)
+    for j in range(1, t+1):
+        if j != i:
+            lambda_i *= Fq(j) * (Fq(j-i))**(-1)
+    return lambda_i
+
+for i in range(t):
+    pooled += shares[i] * lambda_func(i+1, t)
+
+# Assert reconstructed secret
+assert G*s == G*p(0) == pooled