bootle16.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. # Notes from paper:
  2. # "Efficient Zero-Knowledge Arguments for Arithmetic Circuits in the
  3. # Discrete Log Setting" by Bootle and others (EUROCRYPT 2016)
  4. from finite_fields import finitefield
  5. import numpy as np
  6. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  7. fp = finitefield.IntegersModP(p)
  8. # Number of variables
  9. m = 16
  10. # Number of rows for multiplication statements
  11. n = 3
  12. N = n * m
  13. # Initialize zeroed table
  14. aux = np.full(m, fp(0))
  15. # From the zk-explainer document, we will represent the function:
  16. #
  17. # def foo(w, a, b):
  18. # if w:
  19. # return a * b
  20. # else:
  21. # return a + b
  22. #
  23. # Which can be translated mathematically to the statements:
  24. #
  25. # ab = m
  26. # w(m - a - b) = v - a - b
  27. # w^2 = w
  28. #
  29. # Where m is an intermediate value.
  30. var_one = 0
  31. aux[var_one] = fp(1)
  32. var_a = 1
  33. var_b = 2
  34. var_w = 3
  35. aux[var_a] = fp(110)
  36. aux[var_b] = fp(4)
  37. aux[var_w] = fp(1)
  38. # Calculate intermediate advice values
  39. var_m = 4
  40. aux[var_m] = aux[var_a] * aux[var_b]
  41. # Calculate public input values
  42. var_v = 5
  43. aux[var_v] = aux[var_w] * (aux[var_a] * aux[var_b]) + \
  44. (aux[var_one] - aux[var_w]) * (aux[var_a] + aux[var_b])
  45. # Just a quick enforcement check:
  46. assert aux[var_a] * aux[var_b] == aux[var_m]
  47. assert aux[var_w] * (aux[var_m] - aux[var_a] - aux[var_b]) == \
  48. aux[var_v] - aux[var_a] - aux[var_b]
  49. assert aux[var_w] * aux[var_w] == aux[var_w]
  50. # Setup the gates. For each row of a, b and c, the statement a b = c holds
  51. # R1CS, more info here:
  52. # http://www.zeroknowledgeblog.com/index.php/the-pinocchio-protocol/r1cs
  53. left = np.full((n, m), fp(0))
  54. right = np.full((n, m), fp(0))
  55. output = np.full((n, m), fp(0))
  56. # ab = m
  57. left[0][var_a] = fp(1)
  58. right[0][var_b] = fp(1)
  59. output[0][var_m] = fp(1)
  60. assert aux.dot(left[0]) * aux.dot(right[0]) == aux.dot(output[0])
  61. # w(m - a - b) = v - a - b
  62. left[1][var_w] = fp(1)
  63. right[1][var_m] = fp(1)
  64. right[1][var_a] = fp(-1)
  65. right[1][var_b] = fp(-1)
  66. output[1][var_v] = fp(1)
  67. output[1][var_a] = fp(-1)
  68. output[1][var_b] = fp(-1)
  69. assert aux.dot(left[1]) * aux.dot(right[1]) == aux.dot(output[1])
  70. # w^2 = w
  71. left[2][var_w] = fp(1)
  72. right[2][var_w] = fp(1)
  73. output[2][var_w] = fp(1)
  74. assert aux.dot(left[2]) * aux.dot(right[2]) == aux.dot(output[2])