pvss.sage 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # Publicly Verifiable Secret Sharing
  2. # https://www.win.tue.nl/~berry/papers/crypto99.pdf
  3. # This scheme depends on an honest dealer.
  4. t = 3 # Threshold
  5. n = 5 # Participants
  6. # Pallas
  7. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  8. q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001
  9. Fp = GF(p)
  10. Fq = GF(q)
  11. Ep = EllipticCurve(Fp, (0, 5))
  12. Ep.set_order(q * 0x01)
  13. Eq = EllipticCurve(Fq, (0, 5))
  14. Eq.set_order(p * 0x01)
  15. # ValueCommitR Generator: g
  16. vcr_x = 0x07f444550fa409bb4f66235bea8d2048406ed745ee90802f0ec3c668883c5a91
  17. vcr_y = 0x24136777af26628c21562cc9e46fb7c2279229f1f39281460e2f46c8a772d9ca
  18. g = Ep([vcr_x, vcr_y])
  19. # NullifierK Generator: G
  20. nfk_x = 0x25e7aa169ca8198d2e375571faf4c9cf5e7eb192ccb5db9bd36f6aa7e447ca75
  21. nfk_y = 0x155c1f851b1a3384880473442008ff755fe0a49ec1c1b4332db8dce21ae001cc
  22. G = Ep([nfk_x, nfk_y])
  23. # ==============
  24. # Initialization
  25. # ==============
  26. # The participants create their keypairs and register their public keys
  27. # y_i = G^{x_i}
  28. x = []
  29. y = []
  30. for i in range(n):
  31. x_i = Fq.random_element()
  32. #x_i = Fq(i+2)
  33. x.append(x_i)
  34. y.append(G * x_i)
  35. # ============
  36. # Distribution
  37. # ============
  38. # The dealer selects a secret s:
  39. s = Fq.random_element()
  40. #s = Fq(42)
  41. # The dealer picks a random polynomial p of degree at most t-1 with
  42. # coefficients in Fp and sets s=alpha_0
  43. alpha = []
  44. for i in range(t):
  45. alpha.append(Fq.random_element())
  46. #alpha.append(Fq(i+2))
  47. alpha[0] = s
  48. R.<ω> = PolynomialRing(Fq)
  49. p = R(alpha)
  50. assert p.degree() == t-1
  51. assert p.coefficients()[0] == s
  52. # The dealer keeps this polynomial secret but publishes the related
  53. # commitments C_j = g ^ {a_j} , for 0 ≤ j < t
  54. C = []
  55. for j in range(t):
  56. C.append(g * alpha[j])
  57. # The dealer also publishes the encrypted shares Y_i = y_i ^ p(i),
  58. # for 1 ≤ i ≤ n , using the public keys of the participants
  59. Y = []
  60. for i in range(1, n+1):
  61. Y.append(y[i-1] * p(i))
  62. # Finally, let X_i = prod_{j=0}^{t-1} C_j * i^j. The verifier computes
  63. # this from the published commitments.
  64. X = []
  65. for i in range(1, n+1):
  66. X_i = Ep(0)
  67. for j in range(t):
  68. X_i += C[j] * (i^j)
  69. X.append(X_i)
  70. # The dealer shows that the encrypted shares are consistent by
  71. # producing a proof of knowledge of the unique p(i), 1 ≤ i ≤ n,
  72. # satisfying: X_i = g^p(i) , Y_i = y_i^p(i)
  73. for i in range(1, n+1):
  74. assert X[i-1] == g * p(i)
  75. assert Y[i-1] == y[i-1] * p(i)
  76. # For a non-interactive proof, we can use the Fiat-Shamir technique.
  77. # TODO: See DLEQ in the paper.
  78. # ==============
  79. # Reconstruction
  80. # ==============
  81. # Using its private key x_i, each participant finds the share S_i = G^p(i)
  82. # from Y_i by computing S_i = Y_i^(1/x_i). They publish S_i plus a proof
  83. # that the value S_i is a correct decryption of Y_i. To this end it
  84. # suffices to prove knowledge of an alpha such that y_i = G^alpha and
  85. # Y_i = S_i^alpha, which is accomplished by the non-interactive version
  86. # of the protocol DLEQ(G, y_i, S_i, Y_i).
  87. S = []
  88. for i in range(n):
  89. S_i = Y[i] * (1 / x[i])
  90. assert S_i == G * p(i+1)
  91. S.append(S_i)
  92. # Pooling the shares. Sample a set of t shares and reconstruct secret.
  93. # FIXME: This is for 1,...,t, we should be able to take random ones.
  94. shares = S[:t]
  95. pooled = Ep(0)
  96. def lambda_func(i, t):
  97. lambda_i = Fq(1)
  98. for j in range(1, t+1):
  99. if j != i:
  100. lambda_i *= Fq(j) * (Fq(j-i))**(-1)
  101. return lambda_i
  102. for i in range(t):
  103. pooled += shares[i] * lambda_func(i+1, t)
  104. # Assert reconstructed secret
  105. assert G*s == G*p(0) == pooled