Skip to content

Commit 4eb7d17

Browse files
authored
Merge pull request #25 from AAU-Dat/ipa-and-codecomments
Ipa and codecomments
2 parents a93f197 + 41fd05f commit 4eb7d17

File tree

4 files changed

+77
-62
lines changed

4 files changed

+77
-62
lines changed

report/src/sections/02-background.tex

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,22 +66,22 @@ \subsection{Whisk}\label{subsec:related-work-whisk}
6666
The Proof-of stake protocol works in epochs of 32 slots, where each slot is 12 seconds long.
6767
In each slot a proposer is chosen to propose a block thereby allowing the network to reach consensus on the state of the blockchain.
6868

69-
The proposer DoS attack is a type of attack that targets the block proposers making them unable to propose blocks.
70-
An adversary can use the proposer DoS attack to prevent a proposer from receiving rewards, gotten from proposing a block, and increase their own rewards~\cite{EthereumSSLE2024}.
71-
As a response to the proposer DoS attack, Ethereum has proposed a new protocol called Whisk~\cite{Whisk2024} as an attempt to mitigate the attack.
69+
The proposer~\gls{dos} attack is a type of attack that targets the block proposers making them unable to propose blocks.
70+
An adversary can use the proposer~\gls{dos} attack to prevent a proposer from receiving rewards, gotten from proposing a block, and increase their own rewards~\cite{EthereumSSLE2024}.
71+
As a response to the proposer~\gls{dos} attack, Ethereum has proposed a new protocol called Whisk~\cite{Whisk2024} as an attempt to mitigate the attack.
7272
An attack on the Ethereum network that was discovered by Heimbach et al.~\cite{heimbach2024deanonymizingethereumvalidatorsp2p} is the deanonymization attack on validators.
7373
In our preliminary work~\cite{ouroldpaper}, we have shown that the attack is still possible to perform on the Ethereum network, and using the attack, a proposer~\gls{dos} can be performed.
7474

7575

76-
Whisk is a zero-knowledge Single Secret Leader Election (SSLE) system that uses a zero-knowledge argument called Curdleproofs~\cite{Curdleproofs} to verify the correctness of a shuffle without revealing the input or output~\cite{10.1145/3419614.3423258}.
76+
Whisk is a~\gls{zk}~\gls{ssle} system that uses a~\gls{zk} argument called Curdleproofs~\cite{Curdleproofs} to verify the correctness of a shuffle without revealing the input or output~\cite{10.1145/3419614.3423258}.
7777
Whisk works by selecting a list of 16,384 validator trackers and shuffles them over 8,192 slots ($\sim$1 day).
7878
Then 8,192 proposers are selected from the shuffled list to propose blocks for the next 8,192 slots while a new list is being shuffled.
7979
This way a new list of proposers is created every day.
80-
After each shuffle, Whisk uses a zero-knowledge proof to prove that the shuffle is correct.
80+
After each shuffle, Whisk uses a~\gls{zkp} to prove that the shuffle is correct.
8181
This is so that the proposer can prove that they are the correct proposer for the slot without revealing their identity, thereby mitigating the proposer~\gls{dos} attack because of the identity of the upcoming proposers being hidden now.
8282

83-
Curdleproofs is a zero-knowledge proof system that allows a prover to prove knowledge of a shuffle without revealing how it shuffled the elements.
84-
It does so by using three different zero-knowledge proofs, with one of them relying on two more zero-knowledge proofs.
83+
Curdleproofs is a~\gls{zkp} system that allows a prover to prove knowledge of a shuffle without revealing how it shuffled the elements.
84+
It does so by using three different~\glspl{zkp}, with one of them relying on two more~\glspl{zkp}.
8585
The overview can be seen in~\autoref{fig:curdleproof-protocol}.
8686

8787
\begin{figure}[!ht]
@@ -141,6 +141,7 @@ \subsection{Whisk}\label{subsec:related-work-whisk}
141141

142142
To prove that, the protocol makes use of a grand product argument.
143143
To prove that argument, Curdleproofs compiles it down to an~\gls{ipa} by expressing each multiplication of the grand product as its own equation.
144+
This~\gls{ipa} stems from the protocol originally proposed by Bootle et al.~\cite{cryptoeprint:2016/263,Curdleproofs}
144145

145146
Hence, the~\gls{sameperm} proof is done if the prover can prove the~\gls{ipa}.
146147

@@ -154,13 +155,13 @@ \subsection{Whisk}\label{subsec:related-work-whisk}
154155
To mask the ciphertexts, each prover, besides permuting the set, multiplies all ciphertexts by a scalar, $k$.
155156
This is for randomization purposes, making it harder for adversaries to track the ciphertexts~\cite{Whisk2024}.
156157
Also, all validators are still able to open their commitments if they are chosen as block proposers, even after several randomizations.
157-
So, the goal of the Same Scalar argument is to prove the existence of the scalar, $k$, such that the commitment of the permuted set is equal to the commitment of the pre-permuted set multiplied by $k$.
158+
So, the goal of the Same Scalar argument is to prove the existence of the scalar,~$k$, such that the commitment of the permuted set is equal to the commitment of the pre-permuted set multiplied by $k$.
158159

159160

160161

161162
\subsection{Zero-knowledge proofs}\label{sec:background-zkps}
162-
Curdleproofs is a zero-knowledge proof system, which means that it allows a prover to convince a verifier that they know a secret without revealing the secret itself.
163-
Within the context of Ethereum it could be the ability to convince someone that a transaction is valid without revealing information about the transaction such as the value of it.
163+
Curdleproofs is a~\gls{zkp} system, which means that it allows a prover to convince a verifier that they know a secret without revealing the secret itself.
164+
Within the context of Ethereum, it could be the ability to convince someone that a transaction is valid without revealing information about the transaction such as the value of it.
164165
In Whisk, it uses Curdleproofs to prove the validity of a shuffle.
165166

166167
\begin{definition}[Zero-Knowledge Argument of Knowledge]
@@ -169,10 +170,20 @@ \subsection{Zero-knowledge proofs}\label{sec:background-zkps}
169170

170171
Definitions for knowledge-soundness, completeness, and~\gls{hvzk} can be found in~\autoref{sec:appendix}.
171172

173+
Two of the three proofs in Curdleproofs are~\glspl{ipa}.
174+
These are also~\glspl{zkp}, and will be the focus of this paper.
175+
Hence, we provide a definition on~\glspl{ipa}.
176+
177+
\begin{definition}[Inner Product Argument]
178+
Takes as input two binding vector commitments $C=\mathbf{c}\times\mathbf{G}\in\mathbb{G}$ and $D=\mathbf{d}\times\mathbf{G'}\in\mathbb{G}$ to the vectors $\mathbf{c},\mathbf{d}\in\mathbb{Z}_p^n$ and $z\in\mathbb{Z}_p$.
179+
The goal is to prove that $z=\mathbf{c}\times\mathbf{d}$.
180+
The argument has logarithmic communication by halving the dimensions of $\mathbf{c}$ and $\mathbf{d}$ in each iteration.
181+
\end{definition}
182+
172183
\subsection{Problem definition}\label{subsec:problem-definition}
173184
In Chapter 6 of Curdleproofs~\cite{Curdleproofs}, they explain the efficiency of the protocol, including also the size of the proof.
174-
They specifically mention that the proof has size $18+10 \log(\ell+4)\mathbb{G}$, $7\mathbb{F}$.
175-
As the proof size is dependent on the size of the shuffle, $\ell$, an interest in the possibility of reducing this parameter arises.
176-
The current proposal of curdleproofs only works on shuffles, where the size is a power of 2.
177-
The reason is that the underlying proofs, such as the~\gls{ipa}, needs to fold recursively down to 1, by halving the size in every round.
185+
They specifically mention that the proof has size~$18+10 \log(\ell+4)\mathbb{G}$, $7\mathbb{F}$.
186+
As the proof size is dependent on the size of the shuffle,~$\ell$, an interest in the possibility of reducing this parameter arises.
187+
The current proposal of Curdleproofs only works on shuffles, where the size is a power of 2.
188+
The reason is that the underlying proofs, such as the~\gls{ipa}, need to fold recursively down to 1, by halving the size in every round.
178189

report/src/sections/04-Approach.tex

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ \subsection{Springproofs}\label{sec:approach-springproofs}
2424
The computation is for finding the set, $T$.
2525

2626
\begin{figure}[!htb]
27-
\begin{lstlisting}[language=Python,mathescape=true,label={lst:schemefunc},numbers=right,caption={Scheme function \textbf{\textit{f}} used in CAAUrdleproofs},captionpos=b,frame=single]
27+
\begin{lstlisting}[language=Python,mathescape=true,label={lst:schemefunc},numbers=left,caption={Scheme function \textbf{\textit{f}} used in CAAUrdleproofs},captionpos=b,frame=single]
2828
input: $n$, where $n>0$
2929

3030
$\{n\}\gets n$
3131
$N\gets 2^{\lceil\log n\rceil-1}$
3232
$i_h \gets \lfloor (2N-n)/2\rfloor+1$
3333
$i_t=\lfloor n/2\rfloor$
34-
if $n\neq N$:
34+
if $n\neq N$: #Not power of 2
3535
$\{T\}\gets(i_h:i_t)\cup(N+1:n)$
36-
else if $n=N$:
37-
$\{T\}\gets(1:n)$
36+
else if $n=N$: #Power of 2
37+
$\{T\}\gets(1:n)$ #Meaning S is empty
3838
$\{S\}\gets\{n\}-\{T\}$
3939
\end{lstlisting}
4040
\label{fig:schemefunc}
@@ -67,42 +67,42 @@ \subsubsection*{Prover computation}
6767
The construction can be seen in~\autoref{lst:ipa-prover}.
6868

6969
\begin{figure}[!htb]
70-
\begin{lstlisting}[language=Python,mathescape=true,label={lst:ipa-prover},numbers=right,caption={Prover computation for CAAU-IPA in CAAUrdleproofs},captionpos=b,frame=single]
71-
$\textbf{Step 1:}$
70+
\begin{lstlisting}[language=Python,mathescape=true,label={lst:ipa-prover},numbers=left,caption={Prover computation for CAAU-IPA in CAAUrdleproofs},captionpos=b,frame=single]
71+
$\textbf{Step 1:}$ #Setup phase
7272
$(\textbf{G},\textbf{G}',H)\gets$parse$(crs_{dl_{inner}})$
73-
$\textbf{r}_C,\textbf{r}_D\overset{\$}{\leftarrow}\mathbb{F}^n$
73+
$\textbf{r}_C,\textbf{r}_D\overset{\$}{\leftarrow}\mathbb{F}^n$ #Vector blinders
7474
where $(\textbf{r}_C\times \textbf{d} + \textbf{r}_D\times \textbf{c})=0\text{ and }\textbf{r}_C\times \textbf{r}_D=0$
75-
$B_C\gets \textbf{r}_C\times \textbf{G}$
75+
$B_C\gets \textbf{r}_C\times \textbf{G}$ #Blinder commitments
7676
$B_D\gets \textbf{r}_D\times \textbf{G}'$
77-
$\alpha,\beta\gets$Hash$(C,D,z,B_C,B_C)$
78-
$\textbf{c}\gets \textbf{r}_C+\alpha \textbf{c}$
77+
$\alpha,\beta\gets$Hash$(C,D,z,B_C,B_C)$ #FS challenges
78+
$\textbf{c}\gets \textbf{r}_C+\alpha \textbf{c}$ #Blinded vectors
7979
$\textbf{d}\gets \textbf{r}_D+\alpha \textbf{d}$
8080
$H\gets\beta H$
81-
$\textbf{Step 2:}$
81+
$\textbf{Step 2:}$ #Recursive protocol
8282
$m\gets \lceil \log n\rceil$
8383
while $1\leq j\leq m:$
84-
$T,S\gets \textbf{\textit{f(}}n\textbf{\textit{)}}$
84+
$T,S\gets \textbf{\textit{f(}}n\textbf{\textit{)}}$ #Scheme function
8585
$n\gets \frac{|T|}{2}$
86-
$\textbf{c}\gets\textbf{c}_T$, $\textbf{cS}\gets\textbf{c}_S$
86+
$\textbf{c}\gets\textbf{c}_T$, $\textbf{cS}\gets\textbf{c}_S$ #Vector splitting
8787
$\textbf{d}\gets\textbf{d}_T$, $\textbf{dS}\gets\textbf{d}_S$
8888
$\textbf{G}\gets\textbf{G}_T$, $\textbf{GS}\gets\textbf{G}_S$
8989
$\textbf{G}'\gets\textbf{G}'_T$, $\textbf{GS}'\gets\textbf{G}'_T$
90-
$L_{C,j}\gets\textbf{c}_{[:n]}\times\textbf{G}_{[n:]}+(\textbf{c}_{[:n]}\times\textbf{d}_{[n:]})H$
90+
$L_{C,j}\gets\textbf{c}_{[:n]}\times\textbf{G}_{[n:]}+(\textbf{c}_{[:n]}\times\textbf{d}_{[n:]})H$ #Cross-comm
9191
$L_{D,j}\gets\textbf{d}_{[n:]}\times\textbf{G}'_{[:n]}$
9292
$R_{C,j}\gets\textbf{c}_{[n:]}\times\textbf{G}_{[:n]}+(\textbf{c}_{[n:]}\times\textbf{d}_{[:n]})H$
9393
$R_{D,j}\gets\textbf{d}_{[:n]}\times\textbf{G}'_{[n:]}$
94-
$\pi_j\gets(L_{C,j},L_{D,j},R_{C,j},R_{D,j})$
95-
$\gamma_j\gets Hash(\pi_j)$
96-
$\textbf{c}\gets\textbf{cS}\|\textbf{c}_{[:n]}+\gamma_j^{-1}\textbf{c}_{[n:]}$
94+
$\pi_j\gets(L_{C,j},L_{D,j},R_{C,j},R_{D,j})$ #Proof elements
95+
$\gamma_j\gets Hash(\pi_j)$ #Folding challenges
96+
$\textbf{c}\gets\textbf{cS}\|\textbf{c}_{[:n]}+\gamma_j^{-1}\textbf{c}_{[n:]}$ #Next round vectors
9797
$\textbf{d}\gets\textbf{dS}\|\textbf{d}_{[:n]}+\gamma_j\textbf{d}_{[n:]}$
9898
$\textbf{G}\gets\textbf{GS}\|\textbf{G}_{[:n]}+\gamma_j\textbf{G}_{[n:]}$
9999
$\textbf{G}'\gets\textbf{GS}'\|\textbf{G}'_{[:n]}+\gamma_j^{-1}\textbf{G}'_{[n:]}$
100100
$n\gets len(c)$
101-
$\textbf{Step 3:}$
101+
$\textbf{Step 3:}$ #Final proof element
102102
$c\gets c_1$
103103
$d\gets d_1$
104104

105-
return $(B_C,B_D,\mathbf{\pi},c,d)$
105+
return $(B_C,B_D,\mathbf{\pi},c,d)$ # Elements for verifier
106106
\end{lstlisting}
107107
\label{fig:ipa-prover}
108108
\end{figure}
@@ -149,33 +149,33 @@ \subsubsection*{Verifier computation}
149149
Again, the originally proposed verifying protocol has been modified according to Springproofs, which is seen in~\autoref{lst:ipa-verifier}.
150150

151151
\begin{figure}[!htb]
152-
\begin{lstlisting}[language=Python,mathescape=true,label={lst:ipa-verifier},numbers=left,caption={Verifier computation for CAAU-IPA in CAAUrdleproofs},captionpos=b,frame=single]
153-
$\textbf{Step 1:}$
152+
\begin{lstlisting}[language=Python,mathescape=true,label={lst:ipa-verifier},numbers=right,caption={Verifier computation for CAAU-IPA in CAAUrdleproofs},captionpos=b,frame=single]
153+
$\textbf{Step 1:}$ #Setup phase
154154
$(\textbf{G},\textbf{G}',H)\gets$parse$(crs_{dl_{inner}})$
155-
$(C,D,z)\gets$parse$(\phi_{dl_{inner}})$
156-
$(B_C,B_D,\mathbf{\pi},c,d)\gets$parse$(\pi_{dl_{inner}})$
157-
$\alpha,\beta\gets$Hash$(C,D,z,B_C,B_D)$
155+
$(C,D,z)\gets$parse$(\phi_{dl_{inner}})$ #Public input
156+
$(B_C,B_D,\mathbf{\pi},c,d)\gets$parse$(\pi_{dl_{inner}})$ #From prover
157+
$\alpha,\beta\gets$Hash$(C,D,z,B_C,B_D)$ #FS challenges
158158
$H\gets \beta H$
159-
$C\gets B_C+\alpha C+(\alpha^2z)H$
159+
$C\gets B_C+\alpha C+(\alpha^2z)H$ #Blinded commitments
160160
$D\gets B_D+\alpha D$
161161

162-
$\textbf{Step 2:}$
162+
$\textbf{Step 2:}$ #Recursive round
163163
$m\gets \lceil\log n\rceil$
164164
for $1\leq j\leq m$
165-
$T,S\gets \textbf{\textit{f(}}n\textbf{\textit{)}}$
165+
$T,S\gets \textbf{\textit{f(}}n\textbf{\textit{)}}$ #Scheme function
166166
$n\gets \frac{|T|}{2}$
167-
$\textbf{G}=\textbf{G}_T$, $\textbf{GS}=\textbf{G}_S$
167+
$\textbf{G}=\textbf{G}_T$, $\textbf{GS}=\textbf{G}_S$ #Vector splitting
168168
$\textbf{G}'=\textbf{G}'_T$, $\textbf{GS}'=\textbf{G}'_T$
169-
$(L_{C,j},L_{D,j},R_{C,j},R_{D,j})\gets$parse$(\pi_j)$
170-
$\gamma_j\gets$Hash$(\pi_j)$
171-
$C\gets\gamma_j L_{C,j}+C+\gamma_j^{-1}R_{C,j}$
169+
$(L_{C,j},L_{D,j},R_{C,j},R_{D,j})\gets$parse$(\pi_j)$ #Proof elem
170+
$\gamma_j\gets$Hash$(\pi_j)$ #Folding challenges
171+
$C\gets\gamma_j L_{C,j}+C+\gamma_j^{-1}R_{C,j}$ #Update comms
172172
$D\gets\gamma_j L_{D,j}+D+\gamma_j^{-1}R_{D,j}$
173-
$\textbf{G}\gets\textbf{GS}\|\textbf{G}_{[:n]}+\gamma_j\textbf{G}_{[n:]}$
173+
$\textbf{G}\gets\textbf{GS}\|\textbf{G}_{[:n]}+\gamma_j\textbf{G}_{[n:]}$ #Next round vectors
174174
$\textbf{G}'\gets\textbf{GS}'\|\textbf{G}'_{[:n]}+\gamma_j^{-1}\textbf{G}'_{[n:]}$
175175
$n\gets\text{len}(\textbf{G})$
176176

177-
$\textbf{Step 3:}$
178-
Check $C=c\times G_1+cdH$
177+
$\textbf{Step 3:}$ #Final check
178+
Check $C=c\times G_1+cdH$ #Initial ?= Folded
179179
Check $D=d\times G'_1$
180180
return 1 $\text{if both checks pass, else}$ return 0
181181
\end{lstlisting}
@@ -304,23 +304,23 @@ \subsubsection{CAAUdleproofs}
304304

305305
\begin{figure}[!htb]
306306
\begin{lstlisting}[language=Python,mathescape=true,label={lst:ipa-verifier-optimized},numbers=left,caption={Optimized verifier computation for CAAU-IPA in CAAUrdleproofs},captionpos=b,frame=single]
307-
$\textbf{Step 1:}$
307+
$\textbf{Step 1:}$ #Setup phase
308308
$(\textbf{G},H)\gets$parse$(crs_{dl_{inner}})$
309309
$(C,D,z,\mathbf{u})\gets$parse$(\phi_{dl_{inner}})$
310310
$(B_C,B_D,\mathbf{\pi},c,d)\gets$parse$(\pi_{dl_{inner}})$
311-
$\alpha,\beta\gets$Hash$(C,D,z,B_C,B_D)$
311+
$\alpha,\beta\gets$Hash$(C,D,z,B_C,B_D)$ #FS challenges
312312

313-
$\textbf{Step 2:}$
313+
$\textbf{Step 2:}$ #Recursive phase
314314
$m\gets \lceil\log n\rceil$
315315
for $1\leq j\leq m$
316-
$T,S\gets \textbf{\textit{f(}}n\textbf{\textit{)}}$
316+
$T,S\gets \textbf{\textit{f(}}n\textbf{\textit{)}}$ #Scheme function
317317
$n\gets \frac{|T|}{2}$
318-
$(L_{C,j},L_{D,j},R_{C,j},R_{D,j})\gets$parse$(\pi_j)$
319-
$\gamma_j\gets$Hash$(\pi_j)$
318+
$(L_{C,j},L_{D,j},R_{C,j},R_{D,j})\gets$parse$(\pi_j)$ #Proof elem
319+
$\gamma_j\gets$Hash$(\pi_j)$ #Folding challenges
320320
$n\gets n+\text{len}(S)$
321321

322-
$\textbf{Step 3:}$
323-
$\mathbf{CP}\text{: }\mathbf{\gamma}\gets(\gamma_m,...,\gamma_1)$
322+
$\textbf{Step 3:}$ # Accumulated checking phase
323+
$\mathbf{CP}\text{: }\mathbf{\gamma}\gets(\gamma_m,...,\gamma_1)$ #Construction difference
324324
$\mathbf{CAAUP}\text{: }\mathbf{\gamma}\gets(\gamma_1,...,\gamma_m)$
325325
$\textit{Compute }\mathbf{s}\textit{: see below for difference}$
326326

@@ -331,27 +331,27 @@ \subsubsection{CAAUdleproofs}
331331
$\text{return 1}$
332332

333333
$\textbf{s-step Curdleproofs:}$
334-
for $1\leq j\leq n$:
334+
for $1\leq j\leq n$: Simulate halving each round
335335
$s_i=\sum_{j=1}^m\delta_j^{b_{i,j}}\text{, }b_{i,j}\in\{0,1\}\text{ s.t. }i=\sum_{j=1}^mb_{i,j}2^j$
336336
$s'_i=\sum_{j=1}^m\delta_j^{-b_{i,j}}$
337337
$\textbf{s-step CAAUrdleproofs:}$
338-
$ActivePos\gets[(i,i)\text{, }i=1,\dots,n]$
338+
$ActivePos\gets[(i,i)\text{, }i=1,\dots,n]$ #Pos after round
339339
for $1\leq j\leq m:$
340340
$h\gets\frac{2^{\lceil\log n\rceil}}{2}$
341341
$f\gets n-h$
342342
$nf\gets h-f$
343343
$fs\gets \frac{nf}{2}$
344344
for $(i,k)$ in $ActivePos$:
345-
if $k\geq h:$
345+
if $k\geq h:$ #Elem has challenge j
346346
$b_{i,j}\gets1$
347347
$newPos=k-h-fs$
348-
else:
348+
else: #Elem has no challenge j
349349
$b_{i,j}\gets0$
350350
$newPos=k$
351351
$nextActivePos.push((i,newPos))$
352-
$ActivePos\gets nextActivePos$
352+
$ActivePos\gets nextActivePos$ #New positions
353353
$n\gets h$
354-
for $1\leq j\leq n$:
354+
for $1\leq j\leq n$: #Same as Curdleproofs
355355
$s_i=\sum_{j=1}^m\delta_j^{b_{i,j}}$
356356
$s'_i=\sum_{j=1}^m\delta_j^{-b_{i,j}}$
357357
\end{lstlisting}

report/src/setup/acronyms.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
\newacronym{aau}{AAU}{Aalborg University}
55
\newacronym{zkp}{ZKP}{Zero-Knowledge Proof}
6+
\newacronym{zk}{ZK}{Zero-Knowledge}
67
\newacronym{pos}{PoS}{Proof of Stake}
78
\newacronym{pow}{PoW}{Proof of Work}
89
\newacronym{zk-snark}{ZK-SNARK}{Zero-Knowledge Succinct Non-Interactive Argument of Knowledge}

report/src/setup/preamble.tex

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
\usepackage{subfig}
1818
\usepackage{circuitikz}
1919
\usetikzlibrary{arrows.meta,arrows}
20+
\lstset{
21+
commentstyle=\color{gray}
22+
}
2023

2124

2225
% Packages with options set

0 commit comments

Comments
 (0)