math/ccs-plonk.sage
ccs-plonk.sageRaw
1# Plonk-CCS (https://eprint.iacr.org/2023/552) Sage prototype
2
3# utils
4def matrix_vector_product(M, v):
5 n = M.nrows()
6 r = [F(0)] * n
7 for i in range(0, n):
8 for j in range(0, M.ncols()):
9 r[i] += M[i][j] * v[j]
10 return r
11def hadamard_product(a, b):
12 n = len(a)
13 r = [None] * n
14 for i in range(0, n):
15 r[i] = a[i] * b[i]
16 return r
17def vec_add(a, b):
18 n = len(a)
19 r = [None] * n
20 for i in range(0, n):
21 r[i] = a[i] + b[i]
22 return r
23def vec_elem_mul(a, s):
24 r = [None] * len(a)
25 for i in range(0, len(a)):
26 r[i] = a[i] * s
27 return r
28# end of utils
29
30
31# can use any finite field, using a small one for the example
32F = GF(101)
33# F = GF(21888242871839275222246405745257275088696311157297823662689037894645226208583)
34
35
36# The following CCS instance values have been provided by Carlos
37# (https://github.com/CPerezz) and Edu (https://github.com/ed255),
38# and this sage script was made to check the CCS relation.
39
40## Checks performed by this Plonk/CCS instance:
41# - binary check for x0, x1
42# - 2*x2 + 2*x3 == x4
43M0 = matrix([
44 [F(0), 1, 0, 0, 0, 0, 0],
45 [0, 0, 1, 0, 0, 0, 0],
46 [0, 0, 0, 1, 0, 0, 0],
47 [0, 0, 0, 0, 0, 0, 1],
48 ])
49M1 = matrix([
50 [F(0), 1, 0, 0, 0, 0, 0],
51 [0, 0, 1, 0, 0, 0, 0],
52 [0, 0, 0, 0, 1, 0, 0],
53 [0, 0, 0, 0, 0, 0, 1],
54 ])
55M2 = matrix([
56 [F(0), 1, 0, 0, 0, 0, 0],
57 [0, 0, 1, 0, 0, 0, 0],
58 [0, 0, 0, 0, 0, 1, 0],
59 [0, 0, 0, 0, 0, 0, 1],
60 ])
61M3 = matrix([
62 [F(1), 0, 0, 0, 0, 0, 0],
63 [1, 0, 0, 0, 0, 0, 0],
64 [0, 0, 0, 0, 0, 0, 0],
65 [0, 0, 0, 0, 0, 0, 0],
66 ])
67M4 = matrix([
68 [F(0), 0, 0, 0, 0, 0, 0],
69 [0, 0, 0, 0, 0, 0, 0],
70 [2, 0, 0, 0, 0, 0, 0],
71 [0, 0, 0, 0, 0, 0, 0],
72 ])
73M5 = matrix([
74 [F(0), 0, 0, 0, 0, 0, 0],
75 [0, 0, 0, 0, 0, 0, 0],
76 [2, 0, 0, 0, 0, 0, 0],
77 [0, 0, 0, 0, 0, 0, 0],
78 ])
79M6 = matrix([
80 [F(-1), 0, 0, 0, 0, 0, 0],
81 [-1, 0, 0, 0, 0, 0, 0],
82 [-1, 0, 0, 0, 0, 0, 0],
83 [0, 0, 0, 0, 0, 0, 0],
84 ])
85M7 = matrix([
86 [F(0), 0, 0, 0, 0, 0, 0],
87 [0, 0, 0, 0, 0, 0, 0],
88 [0, 0, 0, 0, 0, 0, 0],
89 [0, 0, 0, 0, 0, 0, 0],
90 ])
91
92z = [F(1), 0, 1, 2, 3, 10, 42]
93
94print("z:", z)
95
96assert len(z) == M0.ncols()
97
98# CCS parameters
99n = M0.ncols() # == len(z)
100m = M0.nrows()
101t=8
102q=5
103d=3
104S = [[3,0,1], [4,0], [5,1], [6,2], [7]]
105c = [1, 1, 1, 1, 1]
106
107M = [M0,M1,M2,M3,M4,M5,M6,M7]
108
109print("CCS values:")
110print("n: %s, m: %s, t: %s, q: %s, d: %s" % (n, m, t, q, d))
111print("M:", M)
112print("z:", z)
113print("S:", S)
114print("c:", c)
115
116# check CCS relation (this is agnostic to Plonk, for any CCS instance)
117r = [F(0)] * m
118for i in range(0, q):
119 hadamard_output = [F(1)]*m
120 for j in S[i]:
121 hadamard_output = hadamard_product(hadamard_output,
122 matrix_vector_product(M[j], z))
123
124 r = vec_add(r, vec_elem_mul(hadamard_output, c[i]))
125
126print("\nCCS relation check (∑ cᵢ ⋅ ◯ Mⱼ z == 0):", r == [0]*m)
127assert r == [0]*m