diff --git a/.gitignore b/.gitignore index ed20880f9f..e194b0dcd2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -*.pdf *.toc *.aux *.log @@ -7,6 +6,7 @@ *.blg *.fls *.fdb_latexmk +*.gz *.log docs/spec/out/ diff --git a/docs/sigmastate_protocols/sigmastate_protocols.pdf b/docs/sigmastate_protocols/sigmastate_protocols.pdf new file mode 100644 index 0000000000..d4361b87bb Binary files /dev/null and b/docs/sigmastate_protocols/sigmastate_protocols.pdf differ diff --git a/docs/spec/generated/BigInt_methods.tex b/docs/spec/generated/BigInt_methods.tex index c0ac012526..8ca31d6504 100644 --- a/docs/spec/generated/BigInt_methods.tex +++ b/docs/spec/generated/BigInt_methods.tex @@ -23,30 +23,6 @@ \subsubsection{\lst{BigInt.toByte} method (Code 106.1)} -\subsubsection{\lst{BigInt.modQ} method (Code 6.1)} -\label{sec:type:BigInt:modQ} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Returns this \lst{mod} Q, i.e. remainder of division by Q, where Q is an order of the cryprographic group. \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{BigInt} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:ModQ]{\lst{ModQ}} \\ - \hline - -\end{tabularx} - - - \subsubsection{\lst{BigInt.toShort} method (Code 106.2)} \label{sec:type:BigInt:toShort} \noindent @@ -71,30 +47,6 @@ \subsubsection{\lst{BigInt.toShort} method (Code 106.2)} -\subsubsection{\lst{BigInt.plusModQ} method (Code 6.2)} -\label{sec:type:BigInt:plusModQ} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Adds this number with \lst{other} by module Q. \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{other} & \lst{: BigInt} & \text{// Number to add to this.} \\ - \end{array}\) \\ - - \hline - \bf{Result} & \lst{BigInt} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:PlusModQ]{\lst{PlusModQ}} \\ - \hline - -\end{tabularx} - - - \subsubsection{\lst{BigInt.toInt} method (Code 106.3)} \label{sec:type:BigInt:toInt} \noindent @@ -119,30 +71,6 @@ \subsubsection{\lst{BigInt.toInt} method (Code 106.3)} -\subsubsection{\lst{BigInt.minusModQ} method (Code 6.3)} -\label{sec:type:BigInt:minusModQ} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Subtracts \lst{other} number from this by module Q. \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{other} & \lst{: BigInt} & \text{// Number to subtract from this.} \\ - \end{array}\) \\ - - \hline - \bf{Result} & \lst{BigInt} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MinusModQ]{\lst{MinusModQ}} \\ - \hline - -\end{tabularx} - - - \subsubsection{\lst{BigInt.toLong} method (Code 106.4)} \label{sec:type:BigInt:toLong} \noindent @@ -167,30 +95,6 @@ \subsubsection{\lst{BigInt.toLong} method (Code 106.4)} -\subsubsection{\lst{BigInt.multModQ} method (Code 6.4)} -\label{sec:type:BigInt:multModQ} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Multiply this number with \lst{other} by module Q. \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{other} & \lst{: BigInt} & \text{// Number to multiply with this.} \\ - \end{array}\) \\ - - \hline - \bf{Result} & \lst{BigInt} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - -\end{tabularx} - - - \subsubsection{\lst{BigInt.toBigInt} method (Code 106.5)} \label{sec:type:BigInt:toBigInt} \noindent diff --git a/docs/spec/generated/Boolean_methods.tex b/docs/spec/generated/Boolean_methods.tex index 48ce891811..e69de29bb2 100644 --- a/docs/spec/generated/Boolean_methods.tex +++ b/docs/spec/generated/Boolean_methods.tex @@ -1,22 +0,0 @@ - -\subsubsection{\lst{Boolean.toByte} method (Code 1.1)} -\label{sec:type:Boolean:toByte} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Convert true to 1 and false to 0 \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Byte} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:PropertyCall]{\lst{PropertyCall}} \\ - \hline - -\end{tabularx} diff --git a/docs/spec/generated/GroupElement_methods.tex b/docs/spec/generated/GroupElement_methods.tex index b31e24f30d..dc9922b3dc 100644 --- a/docs/spec/generated/GroupElement_methods.tex +++ b/docs/spec/generated/GroupElement_methods.tex @@ -1,28 +1,4 @@ -\subsubsection{\lst{GroupElement.isIdentity} method (Code 7.1)} -\label{sec:type:GroupElement:isIdentity} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Checks if this value is identity element of the eliptic curve group. \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Boolean} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:PropertyCall]{\lst{PropertyCall}} \\ - \hline - -\end{tabularx} - - - \subsubsection{\lst{GroupElement.getEncoded} method (Code 7.2)} \label{sec:type:GroupElement:getEncoded} \noindent diff --git a/docs/spec/generated/SCollection_methods.tex b/docs/spec/generated/SCollection_methods.tex index d75b349151..a283a0e03c 100644 --- a/docs/spec/generated/SCollection_methods.tex +++ b/docs/spec/generated/SCollection_methods.tex @@ -9,16 +9,16 @@ \subsubsection{\lst{SCollection.size} method (Code 12.1)} \hline \bf{Parameters} & \(\begin{array}{l l l} - + \end{array}\) \\ - + \hline \bf{Result} & \lst{Int} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:SizeOf]{\lst{SizeOf}} \\ \hline - + \end{tabularx} @@ -40,10 +40,10 @@ \subsubsection{\lst{SCollection.getOrElse} method (Code 12.2)} \hline \bf{Result} & \lst{IV} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:ByIndex]{\lst{ByIndex}} \\ \hline - + \end{tabularx} @@ -67,10 +67,10 @@ \subsubsection{\lst{SCollection.map} method (Code 12.3)} \hline \bf{Result} & \lst{Coll[OV]} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:MapCollection]{\lst{MapCollection}} \\ \hline - + \end{tabularx} @@ -93,10 +93,10 @@ \subsubsection{\lst{SCollection.exists} method (Code 12.4)} \hline \bf{Result} & \lst{Boolean} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:Exists]{\lst{Exists}} \\ \hline - + \end{tabularx} @@ -118,10 +118,10 @@ \subsubsection{\lst{SCollection.fold} method (Code 12.5)} \hline \bf{Result} & \lst{OV} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:Fold]{\lst{Fold}} \\ \hline - + \end{tabularx} @@ -145,10 +145,10 @@ \subsubsection{\lst{SCollection.forall} method (Code 12.6)} \hline \bf{Result} & \lst{Boolean} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:ForAll]{\lst{ForAll}} \\ \hline - + \end{tabularx} @@ -175,10 +175,10 @@ \subsubsection{\lst{SCollection.slice} method (Code 12.7)} \hline \bf{Result} & \lst{Coll[IV]} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:Slice]{\lst{Slice}} \\ \hline - + \end{tabularx} @@ -202,10 +202,10 @@ \subsubsection{\lst{SCollection.filter} method (Code 12.8)} \hline \bf{Result} & \lst{Coll[IV]} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:Filter]{\lst{Filter}} \\ \hline - + \end{tabularx} @@ -226,10 +226,10 @@ \subsubsection{\lst{SCollection.append} method (Code 12.9)} \hline \bf{Result} & \lst{Coll[IV]} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:Append]{\lst{Append}} \\ \hline - + \end{tabularx} @@ -255,76 +255,10 @@ \subsubsection{\lst{SCollection.apply} method (Code 12.10)} \hline \bf{Result} & \lst{IV} \\ \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:ByIndex]{\lst{ByIndex}} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.<<} method (Code 12.11)} -\label{sec:type:SCollection:<<} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{arg0} & \lst{: Coll[IV]} & \text{// } \\ -\lst{arg1} & \lst{: Int} & \text{// } \\ - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Coll[IV]} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.>>} method (Code 12.12)} -\label{sec:type:SCollection:>>} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{arg0} & \lst{: Coll[IV]} & \text{// } \\ -\lst{arg1} & \lst{: Int} & \text{// } \\ - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Coll[IV]} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.>>>} method (Code 12.13)} -\label{sec:type:SCollection:>>>} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ + \bf{Serialized as} & \hyperref[sec:serialization:operation:ByIndex]{\lst{ByIndex}} \\ \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{arg0} & \lst{: Coll[Boolean]} & \text{// } \\ -\lst{arg1} & \lst{: Int} & \text{// } \\ - \end{array}\) \\ - \hline - \bf{Result} & \lst{Coll[Boolean]} \\ - \hline - \end{tabularx} @@ -341,16 +275,16 @@ \subsubsection{\lst{SCollection.indices} method (Code 12.14)} \hline \bf{Parameters} & \(\begin{array}{l l l} - + \end{array}\) \\ - + \hline \bf{Result} & \lst{Coll[Int]} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:PropertyCall]{\lst{PropertyCall}} \\ \hline - + \end{tabularx} @@ -377,10 +311,10 @@ \subsubsection{\lst{SCollection.flatMap} method (Code 12.15)} \hline \bf{Result} & \lst{Coll[OV]} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ \hline - + \end{tabularx} @@ -395,16 +329,16 @@ \subsubsection{\lst{SCollection.patch} method (Code 12.19)} \hline \bf{Parameters} & \(\begin{array}{l l l} - + \end{array}\) \\ \hline \bf{Result} & \lst{Coll[IV]} \\ \hline - + \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ \hline - + \end{tabularx} @@ -419,70 +353,22 @@ \subsubsection{\lst{SCollection.updated} method (Code 12.20)} \hline \bf{Parameters} & \(\begin{array}{l l l} - + \end{array}\) \\ \hline \bf{Result} & \lst{Coll[IV]} \\ \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.updateMany} method (Code 12.21)} -\label{sec:type:SCollection:updateMany} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Coll[IV]} \\ - \hline - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.unionSets} method (Code 12.22)} -\label{sec:type:SCollection:unionSets} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - \hline - \bf{Result} & \lst{Coll[IV]} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - \end{tabularx} -\subsubsection{\lst{SCollection.diff} method (Code 12.23)} -\label{sec:type:SCollection:diff} +\subsubsection{\lst{SCollection.updateMany} method (Code 12.21)} +\label{sec:type:SCollection:updateMany} \noindent \begin{tabularx}{\textwidth}{| l | X |} \hline @@ -491,64 +377,16 @@ \subsubsection{\lst{SCollection.diff} method (Code 12.23)} \hline \bf{Parameters} & \(\begin{array}{l l l} - + \end{array}\) \\ \hline \bf{Result} & \lst{Coll[IV]} \\ \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.intersect} method (Code 12.24)} -\label{sec:type:SCollection:intersect} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Coll[IV]} \\ - \hline - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.prefixLength} method (Code 12.25)} -\label{sec:type:SCollection:prefixLength} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - \hline - \bf{Result} & \lst{Int} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - \end{tabularx} @@ -563,64 +401,16 @@ \subsubsection{\lst{SCollection.indexOf} method (Code 12.26)} \hline \bf{Parameters} & \(\begin{array}{l l l} - + \end{array}\) \\ \hline \bf{Result} & \lst{Int} \\ \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.lastIndexOf} method (Code 12.27)} -\label{sec:type:SCollection:lastIndexOf} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Int} \\ - \hline - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.find} method (Code 12.28)} -\label{sec:type:SCollection:find} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - \hline - \bf{Result} & \lst{Option[IV]} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - \end{tabularx} @@ -635,110 +425,14 @@ \subsubsection{\lst{SCollection.zip} method (Code 12.29)} \hline \bf{Parameters} & \(\begin{array}{l l l} - + \end{array}\) \\ \hline \bf{Result} & \lst{Coll[(IV,OV)]} \\ \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.distinct} method (Code 12.30)} -\label{sec:type:SCollection:distinct} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Coll[IV]} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:PropertyCall]{\lst{PropertyCall}} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.startsWith} method (Code 12.31)} -\label{sec:type:SCollection:startsWith} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Boolean} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.endsWith} method (Code 12.32)} -\label{sec:type:SCollection:endsWith} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Boolean} \\ - \hline - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ \hline - -\end{tabularx} - - - -\subsubsection{\lst{SCollection.mapReduce} method (Code 12.34)} -\label{sec:type:SCollection:mapReduce} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - \hline - \bf{Result} & \lst{Coll[(K,V)]} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - \end{tabularx} diff --git a/docs/spec/generated/SOption_methods.tex b/docs/spec/generated/SOption_methods.tex index 78419c9a7d..f44550ba58 100644 --- a/docs/spec/generated/SOption_methods.tex +++ b/docs/spec/generated/SOption_methods.tex @@ -1,25 +1,4 @@ -\subsubsection{\lst{SOption.isEmpty} method (Code 36.1)} -\label{sec:type:SOption:isEmpty} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{arg0} & \lst{: Option[T]} & \text{// } \\ - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Boolean} \\ - \hline - -\end{tabularx} - - - \subsubsection{\lst{SOption.isDefined} method (Code 36.2)} \label{sec:type:SOption:isDefined} \noindent @@ -94,59 +73,6 @@ \subsubsection{\lst{SOption.getOrElse} method (Code 36.4)} -\subsubsection{\lst{SOption.fold} method (Code 36.5)} -\label{sec:type:SOption:fold} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Returns the result of applying \lst{f} to this option's - value if the option is nonempty. Otherwise, evaluates - expression \lst{ifEmpty}. - This is equivalent to \lst{option map f getOrElse ifEmpty}. - \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{ifEmpty} & \lst{: R} & \text{// the expression to evaluate if empty} \\ -\lst{f} & \lst{: (T) => R} & \text{// the function to apply if nonempty} \\ - \end{array}\) \\ - - \hline - \bf{Result} & \lst{R} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - -\end{tabularx} - - - -\subsubsection{\lst{SOption.toColl} method (Code 36.6)} -\label{sec:type:SOption:toColl} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Convert this Option to a collection with zero or one element. \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Coll[T]} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:PropertyCall]{\lst{PropertyCall}} \\ - \hline - -\end{tabularx} - - - \subsubsection{\lst{SOption.map} method (Code 36.7)} \label{sec:type:SOption:map} \noindent @@ -197,32 +123,3 @@ \subsubsection{\lst{SOption.filter} method (Code 36.8)} \hline \end{tabularx} - - - -\subsubsection{\lst{SOption.flatMap} method (Code 36.9)} -\label{sec:type:SOption:flatMap} -\noindent -\begin{tabularx}{\textwidth}{| l | X |} - \hline - \bf{Description} & Returns the result of applying \lst{f} to this option's value if - this option is nonempty. - Returns \lst{None} if this option is empty. - Slightly different from \lst{map} in that \lst{f} is expected to - return an option (which could be \lst{one}). - \\ - - \hline - \bf{Parameters} & - \(\begin{array}{l l l} - \lst{f} & \lst{: (T) => Option[R]} & \text{// the function to apply} \\ - \end{array}\) \\ - - \hline - \bf{Result} & \lst{Option[R]} \\ - \hline - - \bf{Serialized as} & \hyperref[sec:serialization:operation:MethodCall]{\lst{MethodCall}} \\ - \hline - -\end{tabularx} diff --git a/docs/spec/generated/SigmaDslBuilder_methods.tex b/docs/spec/generated/SigmaDslBuilder_methods.tex index 0232ed2e76..611aeac9a6 100644 --- a/docs/spec/generated/SigmaDslBuilder_methods.tex +++ b/docs/spec/generated/SigmaDslBuilder_methods.tex @@ -20,3 +20,26 @@ \subsubsection{\lst{SigmaDslBuilder.groupGenerator} method (Code 106.1)} \hline \end{tabularx} + + + +\subsubsection{\lst{SigmaDslBuilder.xor} method (Code 106.2)} +\label{sec:type:SigmaDslBuilder:xor} +\noindent +\begin{tabularx}{\textwidth}{| l | X |} + \hline + \bf{Description} & \\ + + \hline + \bf{Parameters} & + \(\begin{array}{l l l} + \lst{arg0} & \lst{: SigmaDslBuilder} & \text{// } \\ +\lst{arg1} & \lst{: Coll[Byte]} & \text{// } \\ +\lst{arg2} & \lst{: Coll[Byte]} & \text{// } \\ + \end{array}\) \\ + + \hline + \bf{Result} & \lst{Coll[Byte]} \\ + \hline + +\end{tabularx} diff --git a/docs/spec/generated/ergotree_serialization1.tex b/docs/spec/generated/ergotree_serialization1.tex index 468756773c..3db72a9d30 100644 --- a/docs/spec/generated/ergotree_serialization1.tex +++ b/docs/spec/generated/ergotree_serialization1.tex @@ -1022,7 +1022,7 @@ \subsubsection{\lst{Apply} operation (OpCode 218)} \subsubsection{\lst{PropertyCall} operation (OpCode 219)} \label{sec:serialization:operation:PropertyCall} -Convert true to 1 and false to 0 + \noindent \(\begin{tabularx}{\textwidth}{| l | l | l | X |} @@ -1031,7 +1031,7 @@ \subsubsection{\lst{PropertyCall} operation (OpCode 219)} \hline $ typeCode $ & \lst{Byte} & 1 & type of the method (see Table~\ref{table:predeftypes}) \\ \hline - $ methodCode $ & \lst{Byte} & 1 & a code of the proprty \\ + $ methodCode $ & \lst{Byte} & 1 & a code of the property \\ \hline $ obj $ & \lst{Expr} & [1, *] & receiver object of this property call \\ \hline @@ -1267,6 +1267,28 @@ \subsubsection{\lst{Negation} operation (OpCode 240)} \end{tabularx}\) +\subsubsection{\lst{BinXor} operation (OpCode 244)} +\label{sec:serialization:operation:BinXor} + +Logical XOR of two operands See~\hyperref[sec:appendix:primops:BinXor]{\lst{^}} + +\noindent +\(\begin{tabularx}{\textwidth}{| l | l | l | X |} + \hline + \bf{Slot} & \bf{Format} & \bf{\#bytes} & \bf{Description} \\ + \hline + \multicolumn{4}{l}{\lst{match}~$ (left, right) $} \\ + + \multicolumn{4}{l}{~~\lst{otherwise} } \\ + \hline + ~~~~ $ left $ & \lst{Expr} & [1, *] & left operand \\ + \hline + ~~~~ $ right $ & \lst{Expr} & [1, *] & right operand \\ + \hline + \multicolumn{4}{l}{\lst{end match}} \\ +\end{tabularx}\) + + \subsubsection{\lst{XorOf} operation (OpCode 255)} \label{sec:serialization:operation:XorOf} diff --git a/docs/spec/generated/predeftypes.tex b/docs/spec/generated/predeftypes.tex index a0d2e76d8f..1d71cdec3f 100644 --- a/docs/spec/generated/predeftypes.tex +++ b/docs/spec/generated/predeftypes.tex @@ -12,11 +12,11 @@ \hline \lst{GroupElement} & $7$ & \lst{true} & \lst{true} & \lst{true} & \lst{false} & $\Set{p \in \lst{SecP256K1Point}}$ \\ \hline -\lst{SigmaProp} & $8$ & \lst{false} & \lst{true} & \lst{true} & \lst{false} & Sec.~\ref{sec:type:SigmaProp} \\ +\lst{SigmaProp} & $8$ & \lst{true} & \lst{true} & \lst{true} & \lst{false} & Sec.~\ref{sec:type:SigmaProp} \\ \hline \lst{Box} & $99$ & \lst{false} & \lst{false} & \lst{false} & \lst{false} & Sec.~\ref{sec:type:Box} \\ \hline -\lst{AvlTree} & $100$ & \lst{false} & \lst{false} & \lst{false} & \lst{false} & Sec.~\ref{sec:type:AvlTree} \\ +\lst{AvlTree} & $100$ & \lst{true} & \lst{false} & \lst{false} & \lst{false} & Sec.~\ref{sec:type:AvlTree} \\ \hline \lst{Context} & $101$ & \lst{false} & \lst{false} & \lst{false} & \lst{false} & Sec.~\ref{sec:type:Context} \\ \hline diff --git a/docs/spec/spec.pdf b/docs/spec/spec.pdf new file mode 100644 index 0000000000..c3ba73e746 Binary files /dev/null and b/docs/spec/spec.pdf differ diff --git a/docs/wpaper/sigma.pdf b/docs/wpaper/sigma.pdf new file mode 100644 index 0000000000..57ae3d40c1 Binary files /dev/null and b/docs/wpaper/sigma.pdf differ diff --git a/docs/wpaper/sigma.tex b/docs/wpaper/sigma.tex index cb0bfc85f3..12b79d0e2b 100644 --- a/docs/wpaper/sigma.tex +++ b/docs/wpaper/sigma.tex @@ -274,7 +274,7 @@ \subsection{Context Extension and Hashing} \label{sec:extension} A context can also contain typed variables that can be retrieved by numerical id using the operator \texttt{getVar}. These variables are supplied by the prover specifically for a given input box (via a \texttt{ContextExtension}) together with the proof for that box. The id can be any one-byte value (from -128 to 127) and is scoped for each box separately (so variable with id 17 for one input box in a transaction is not the same as variable with id 17 for another input box in the same transaction). -Such context enxtensions can be useful, for example, for requiring a spending transaction to produce hash preimages (the BLAKE2b-256 and SHA-256 hash functions can invoked in \langname, using keywords \texttt{blake2b256} and \texttt{sha256}). For example, +Such context enxtensions can be useful, for example, for requiring a spending transaction to produce hash preimages (the BLAKE2b-256 and SHA-256 hash functions can be invoked in \langname, using keywords \texttt{blake2b256} and \texttt{sha256}). For example, \begin{verbatim} pkA && blake2b256(getVar[Coll[Byte]](1).get) == hashOutput \end{verbatim} @@ -814,4 +814,4 @@ \section{Types} } -\end{document} \ No newline at end of file +\end{document} diff --git a/src/main/scala/sigmastate/Operations.scala b/src/main/scala/sigmastate/Operations.scala index 3771b722cd..34931e3df0 100644 --- a/src/main/scala/sigmastate/Operations.scala +++ b/src/main/scala/sigmastate/Operations.scala @@ -3,7 +3,7 @@ package sigmastate import sigmastate.lang.SigmaPredef.PredefinedFuncRegistry import sigmastate.lang.StdSigmaBuilder -/** WARNING: This file is generated by GenSerializableOps tool. +/** WARNING: This file is generated by GenInfoObjects tool. * Don't edit it directly, use the tool instead to regenerate. * The operations are alphabetically sorted. */ @@ -383,19 +383,6 @@ object Operations { val argInfos: Seq[ArgInfo] = Seq(leftArg, rightArg) } - object MinusModQInfo extends InfoObject { - private val method = SMethod.fromIds(6, 3) - val thisArg: ArgInfo = method.argInfo("this") - val otherArg: ArgInfo = method.argInfo("other") - val argInfos: Seq[ArgInfo] = Seq(thisArg, otherArg) - } - - object ModQInfo extends InfoObject { - private val method = SMethod.fromIds(6, 1) - val thisArg: ArgInfo = method.argInfo("this") - val argInfos: Seq[ArgInfo] = Seq(thisArg) - } - object ModuloInfo extends InfoObject { private val func = predefinedOps.funcs("%") val leftArg: ArgInfo = func.argInfo("left") @@ -462,19 +449,6 @@ object Operations { val argInfos: Seq[ArgInfo] = Seq(leftArg, rightArg) } - object PlusModQInfo extends InfoObject { - private val method = SMethod.fromIds(6, 2) - val thisArg: ArgInfo = method.argInfo("this") - val otherArg: ArgInfo = method.argInfo("other") - val argInfos: Seq[ArgInfo] = Seq(thisArg, otherArg) - } - - object PropertyCallInfo extends InfoObject { - private val method = SMethod.fromIds(1, 1) - val thisArg: ArgInfo = method.argInfo("this") - val argInfos: Seq[ArgInfo] = Seq(thisArg) - } - object SelectFieldInfo extends InfoObject { private val func = predefinedOps.specialFuncs("selectField") val inputArg: ArgInfo = func.argInfo("input") diff --git a/src/main/scala/sigmastate/serialization/DataJsonEncoder.scala b/src/main/scala/sigmastate/serialization/DataJsonEncoder.scala new file mode 100644 index 0000000000..4f0904fb24 --- /dev/null +++ b/src/main/scala/sigmastate/serialization/DataJsonEncoder.scala @@ -0,0 +1,256 @@ +package sigmastate.serialization + +import java.math.BigInteger + +import io.circe._ +import io.circe.syntax._ +import org.ergoplatform.ErgoBox +import org.ergoplatform.ErgoBox.NonMandatoryRegisterId +import org.ergoplatform.settings.ErgoAlgos +import scalan.RType +import scalan.RType.PairType +import scorex.crypto.hash.Digest32 +import scorex.util._ +import sigmastate.Values.{Constant, EvaluatedValue} +import sigmastate._ +import sigmastate.eval._ +import sigmastate.lang.SigmaParser +import sigmastate.lang.exceptions.SerializerException +import special.collection.{Coll, PairColl, collRType} +import special.sigma._ +import spire.syntax.all.cfor + +import scala.collection.mutable + +object DataJsonEncoder { + def encode[T <: SType](v: T#WrappedType, tpe: T): Json = { + val encodedType = tpe.toTermString + val encodedData = encodeData(v, tpe) + Json.obj( + "type" -> Json.fromString(encodedType), + "value" -> encodedData, + ) + } + + private def encodeBytes: Encoder[Array[Byte]] = (bytes: Array[Byte]) => { + ErgoAlgos.encode(bytes).asJson + } + + private def encodeData[T <: SType](v: T#WrappedType, tpe: T): Json = tpe match { + case SUnit => Json.Null + case SBoolean => v.asInstanceOf[Boolean].asJson + case SByte => v.asInstanceOf[Byte].asJson + case SShort => v.asInstanceOf[Short].asJson + case SInt => v.asInstanceOf[Int].asJson + case SLong => v.asInstanceOf[Long].asJson + case SBigInt => + encodeBytes(v.asInstanceOf[BigInt].toBytes.toArray) + case SString => + encodeBytes(v.asInstanceOf[String].getBytes) + case tColl: SCollectionType[a] => + val coll = v.asInstanceOf[tColl.WrappedType] + tColl.elemType match { + case tup: STuple => + val tArr = tup.items.toArray + if (tArr.length != 2) { + throw new SerializerException("Tuples with length not equal to 2 are not supported") + } + val rtypeArr = tArr.map(x => Evaluation.stypeToRType(x)) + + val leftSource = mutable.ArrayBuilder.make[SType#WrappedType]()(rtypeArr(0).classTag) + val rightSource = mutable.ArrayBuilder.make[SType#WrappedType]()(rtypeArr(1).classTag) + cfor(0)(_ < coll.length, _ + 1) { i => + val arr = Evaluation.fromDslTuple(coll(i), tup).asInstanceOf[tup.WrappedType] + leftSource += arr(0) + rightSource += arr(1) + } + val left = Colls.fromArray(leftSource.result())(rtypeArr(0)).asInstanceOf[SType#WrappedType] + val leftType: SType = SCollectionType(tArr(0)) + val right = Colls.fromArray(rightSource.result())(rtypeArr(1)).asInstanceOf[SType#WrappedType] + val rightType: SType = SCollectionType(tArr(1)) + + Json.fromFields(List( + "_1" -> encodeData[SType](left, leftType), + "_2" -> encodeData[SType](right, rightType) + )) + case _ => + var jsons = mutable.MutableList.empty[Json] + cfor(0)(_ < coll.length, _ + 1) { i => + val x = coll(i) + jsons += encodeData(x, tColl.elemType) + } + Json.fromValues(jsons.toList) + } + + case tOpt: SOption[a] => + val opt = v.asInstanceOf[tOpt.WrappedType] + if (opt.isDefined) { + encodeData(opt.get, tOpt.elemType) + } else { + Json.Null + } + case t: STuple => + val arr = Evaluation.fromDslTuple(v, t).asInstanceOf[t.WrappedType] + val tArr = t.items.toArray + if (tArr.length != 2) { + throw new SerializerException("Tuples with length not equal to 2 are not supported") + } + val len = arr.length + assert(len == tArr.length, s"Type $t doesn't correspond to value $arr") + var obj = mutable.MutableList.empty[(String, Json)] + cfor(0)(_ < len, _ + 1) { i => + obj += (s"_${i + 1}" -> encodeData[SType](arr(i), tArr(i))) + } + Json.fromFields(obj.toList) + case SGroupElement => + val w = SigmaSerializer.startWriter() + DataSerializer.serialize(v, tpe, w) + encodeBytes(w.toBytes) + case SAvlTree => + val w = SigmaSerializer.startWriter() + DataSerializer.serialize(v, tpe, w) + encodeBytes(w.toBytes) + case SSigmaProp => + val w = SigmaSerializer.startWriter() + DataSerializer.serialize(v, tpe, w) + encodeBytes(w.toBytes) + case SBox => + val ergoBox = v.asInstanceOf[Box] + var obj = mutable.MutableList.empty[(String, Json)] + obj += ("value" -> encodeData(ergoBox.value.asInstanceOf[SType#WrappedType], SLong)) + obj += ("ergoTree" -> encodeBytes(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(ergoBox.ergoTree))) + obj += "tokens" -> encodeData(ergoBox.additionalTokens.map { case (id, amount) => + (Colls.fromArray(id), amount) + }.asInstanceOf[SType#WrappedType], SCollectionType(STuple(SCollectionType(SByte), SLong))) + ergoBox.additionalRegisters.foreach { case (id, value) => + obj += (s"r${id.number}" -> encode[SType](value.value, value.tpe)) + } + obj += ("txId" -> encodeBytes(ergoBox.transactionId.toBytes)) + obj += ("index" -> encodeData(ergoBox.index.asInstanceOf[SType#WrappedType], SShort)) + obj += ("creationHeight" -> encodeData(ergoBox.creationHeight.asInstanceOf[SType#WrappedType], SInt)) + Json.fromFields(obj) + case t => throw new SerializerException(s"Not defined DataSerializer for type $t") + } + + private def decodeBytes(json: Json): Array[Byte] = { + val jsonStr = json.as[String] + jsonStr match { + case Right(jsonStr) => ErgoAlgos.decode(jsonStr).get + case Left(error) => throw new SerializerException(error.getMessage) + } + } + + private def decodeData[T <: SType](json: Json, tpe: T): (T#WrappedType) = { + val res = (tpe match { + case SUnit => json.asNull.get + case SBoolean => json.asBoolean.get + case SByte => json.asNumber.get.toByte.get + case SShort => json.asNumber.get.toShort.get + case SInt => json.asNumber.get.toInt.get + case SLong => json.asNumber.get.toLong.get + case SBigInt => + SigmaDsl.BigInt(new BigInteger(decodeBytes(json))) + case SString => + new String(decodeBytes(json)) + case tColl: SCollectionType[a] => + val tpeElem = tColl.elemType + decodeColl(json, tpeElem) + case tOpt: SOption[a] => + if (json == Json.Null) { + None + } else { + Some(decodeData(json, tOpt.elemType)) + } + case t: STuple => + val tArr = t.items.toArray + if (tArr.length != 2) { + throw new SerializerException("Tuples with length not equal to 2 are not supported") + } + val collSource = mutable.ArrayBuilder.make[Any]() + cfor(1)(_ <= tArr.length, _ + 1) { i => + collSource += decodeData(json.hcursor.downField(s"_${i}").focus.get, tArr(i - 1)) + } + val coll = Colls.fromArray(collSource.result())(RType.AnyType) + Evaluation.toDslTuple(coll, t) + case SGroupElement => + val str = decodeBytes(json) + val r = SigmaSerializer.startReader(str) + DataSerializer.deserialize(SGroupElement, r) + case SAvlTree => + val str = decodeBytes(json) + val r = SigmaSerializer.startReader(str) + DataSerializer.deserialize(SAvlTree, r) + case SSigmaProp => + val str = decodeBytes(json) + val r = SigmaSerializer.startReader(str) + DataSerializer.deserialize(SSigmaProp, r) + case SBox => + val value = decodeData(json.hcursor.downField(s"value").focus.get, SLong) + val tree = ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(decodeBytes(json.hcursor.downField(s"ergoTree").focus.get)) + val tokens = decodeData(json.hcursor.downField(s"tokens").focus.get, SCollectionType(STuple(SCollectionType(SByte), SLong))).asInstanceOf[Coll[(Coll[Byte], Long)]].map { + v => + val tup = v.asInstanceOf[(Coll[Byte], Long)] + (tup._1.toArray.asInstanceOf[Digest32], tup._2) + } + val txId = decodeBytes(json.hcursor.downField(s"txId").focus.get).toModifierId + val index = decodeData(json.hcursor.downField(s"index").focus.get, SShort) + val creationHeight = decodeData(json.hcursor.downField(s"creationHeight").focus.get, SInt) + val additionalRegisters = mutable.MutableList.empty[(NonMandatoryRegisterId, _ <: EvaluatedValue[_ <: SType])] + for (register <- ErgoBox.nonMandatoryRegisters) { + val opt = json.hcursor.downField(s"r${register.number}").focus + if (opt.isDefined && !opt.get.isNull) { + val (decoded, tpe) = decodeWithTpe(opt.get) + additionalRegisters += (register -> Constant(decoded, tpe)) + } + } + SigmaDsl.Box(new ErgoBox(value, tree, tokens, additionalRegisters.toMap, txId, index, creationHeight)) + case t => + throw new SerializerException(s"Not defined DataSerializer for type $t") + }).asInstanceOf[T#WrappedType] + res + } + + private def decodeColl[T <: SType](json: Json, tpe: T): Coll[T#WrappedType] = { + implicit val tItem = (tpe match { + case tTup: STuple if tTup.items.length == 2 => + Evaluation.stypeToRType(tpe) + case _: STuple => + throw new SerializerException("Tuples with length not equal to 2 are not supported") + case _ => + Evaluation.stypeToRType(tpe) + }).asInstanceOf[RType[T#WrappedType]] + + tpe match { + case tup: STuple => + val tArr = tup.items.toArray + val collSource = mutable.ArrayBuilder.make[T#WrappedType]()(tItem.classTag) + val leftColl = decodeColl(json.hcursor.downField(s"_1").focus.get, tArr(0)) + val rightColl = decodeColl(json.hcursor.downField(s"_2").focus.get, tArr(1)) + assert(leftColl.length == rightColl.length) + SigmaDsl.Colls.pairColl(leftColl, rightColl).asInstanceOf[Coll[T#WrappedType]] + case _ => + val jsonList = json.as[List[Json]] + jsonList match { + case Right(jsonList) => + val collSource = mutable.ArrayBuilder.make[T#WrappedType]()(tItem.classTag) + for (i <- jsonList) { + collSource += decodeData(i, tpe).asInstanceOf[T#WrappedType] + } + Colls.fromArray(collSource.result()) + case Left(error) => throw new SerializerException(error.getMessage) + } + } + } + + private def decodeWithTpe(json: Json): (SType#WrappedType, SType) = { + val tpe = SigmaParser.parseType(json.hcursor.downField("type").focus.get.asString.get) + val value = json.hcursor.downField("value").focus.get + val data = decodeData(value, tpe) + (data, tpe) + } + + def decode(json: Json): (SType#WrappedType) = { + val (data, _) = decodeWithTpe(json) + data + } +} diff --git a/src/main/scala/sigmastate/serialization/ModQSerializer.scala b/src/main/scala/sigmastate/serialization/ModQSerializer.scala index 6ccb69141c..9017ea23f5 100644 --- a/src/main/scala/sigmastate/serialization/ModQSerializer.scala +++ b/src/main/scala/sigmastate/serialization/ModQSerializer.scala @@ -1,6 +1,6 @@ package sigmastate.serialization -import sigmastate.Operations.ModQInfo +// import sigmastate.Operations.ModQInfo import sigmastate.Values.Value import sigmastate.lang.Terms._ import sigmastate.utils.{SigmaByteReader, SigmaByteWriter} @@ -10,7 +10,9 @@ object ModQSerializer extends ValueSerializer[ModQ] { override def opDesc = ModQ def serialize(obj: ModQ, w: SigmaByteWriter): Unit = { - w.putValue(obj.input, ModQInfo.thisArg) + // TODO soft-fork: + // w.putValue(obj.input, ModQInfo.thisArg) + w.putValue(obj.input, "this") } def parse(r: SigmaByteReader): Value[SType] = { diff --git a/src/main/scala/sigmastate/trees.scala b/src/main/scala/sigmastate/trees.scala index cbf2405069..758d0a5010 100644 --- a/src/main/scala/sigmastate/trees.scala +++ b/src/main/scala/sigmastate/trees.scala @@ -610,10 +610,14 @@ trait OpGroup[C <: ValueCompanion] { object ModQArithOp extends OpGroup[ModQArithOpCompanion] { import OpCodes._ object PlusModQ extends ModQArithOpCompanion(PlusModQCode, "PlusModQ") { - override def argInfos: Seq[ArgInfo] = PlusModQInfo.argInfos + // TODO soft-fork: + // override def argInfos: Seq[ArgInfo] = PlusModQInfo.argInfos + override def argInfos: Seq[ArgInfo] = Seq(ArgInfo("this", ""), ArgInfo("other", "")) } object MinusModQ extends ModQArithOpCompanion(MinusModQCode, "MinusModQ") { - override def argInfos: Seq[ArgInfo] = PlusModQInfo.argInfos + // TODO soft-fork: + // override def argInfos: Seq[ArgInfo] = MinusModQInfo.argInfos + override def argInfos: Seq[ArgInfo] = Seq(ArgInfo("this", ""), ArgInfo("other", "")) } val operations: Map[Byte, ModQArithOpCompanion] = Seq(PlusModQ, MinusModQ).map(o => (o.opCode, o)).toMap diff --git a/src/main/scala/sigmastate/types.scala b/src/main/scala/sigmastate/types.scala index b2d8f8af22..daa52dbca4 100644 --- a/src/main/scala/sigmastate/types.scala +++ b/src/main/scala/sigmastate/types.scala @@ -175,6 +175,7 @@ object SType { case SUnit => reflect.classTag[Unit] case SBox => reflect.classTag[ErgoBox] case SAny => reflect.classTag[Any] + case opt: SOption[a] => reflect.classTag[Option[a]] case _: STuple => reflect.classTag[Array[Any]] case tColl: SCollection[a] => val elemType = tColl.elemType diff --git a/src/test/scala/sigmastate/serialization/DataJsonEncoderSpecification.scala b/src/test/scala/sigmastate/serialization/DataJsonEncoderSpecification.scala new file mode 100644 index 0000000000..15e49ccd3e --- /dev/null +++ b/src/test/scala/sigmastate/serialization/DataJsonEncoderSpecification.scala @@ -0,0 +1,143 @@ +package sigmastate.serialization + + +import java.math.BigInteger + +import org.scalacheck.Arbitrary._ +import scalan.RType +import sigmastate.SCollection.SByteArray +import sigmastate.SType.AnyOps +import sigmastate.Values.SigmaBoolean +import sigmastate._ +import sigmastate.eval.Extensions._ +import sigmastate.eval.{Evaluation, _} +import sigmastate.interpreter.CryptoConstants.EcPointType +import sigmastate.lang.exceptions.SerializerException +import special.sigma.{AvlTree, Box} + +class DataJsonEncoderSpecification extends SerializationSpecification { + def roundtrip[T <: SType](obj: T#WrappedType, tpe: T) = { + val json = DataJsonEncoder.encode(obj, tpe) + val res = DataJsonEncoder.decode(json) + res shouldBe obj + } + + def testCollection[T <: SType](tpe: T) = { + implicit val wWrapped = wrappedTypeGen(tpe) + implicit val tT = Evaluation.stypeToRType(tpe) + implicit val tagT = tT.classTag + implicit val tAny = RType.AnyType + forAll { xs: Array[T#WrappedType] => + roundtrip[SCollection[T]](xs.toColl, SCollection(tpe)) + roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe))) + + val nested = xs.toColl.map(x => Colls.fromItems[T#WrappedType](x, x)) + roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe))) + + roundtrip[SType]( + xs.toColl.map { x => + val arr = Colls.fromItems[T#WrappedType](x, x) + (arr, arr) + }.asWrappedType, + SCollection(STuple(SCollection(tpe), SCollection(tpe))) + ) + } + } + + def testTuples[T <: SType](tpe: T) = { + implicit val wWrapped = wrappedTypeGen(tpe) + implicit val tag = tpe.classTag[T#WrappedType] + implicit val tAny = RType.AnyType + forAll { in: (T#WrappedType, T#WrappedType) => + val (x,y) = (in._1, in._2) + roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe)) + roundtrip[SType](((x, y), (x, y)).asWrappedType, STuple(STuple(tpe, tpe), STuple(tpe, tpe))) + roundtrip[SType](((x, y), ((x, y), (x, y))).asWrappedType, STuple(STuple(tpe, tpe), STuple(STuple(tpe, tpe), STuple(tpe, tpe)))) + } + } + + property("Data Json serialization round trip") { + forAll { x: Byte => roundtrip[SByte.type](x, SByte) } + forAll { x: Boolean => roundtrip[SBoolean.type](x, SBoolean) } + forAll { x: Long => roundtrip[SLong.type](x, SLong) } + forAll { x: String => roundtrip[SString.type](x, SString) } + forAll { x: BigInteger => roundtrip[SBigInt.type](x, SBigInt) } + forAll { x: EcPointType => roundtrip[SGroupElement.type](x, SGroupElement) } + forAll { x: SigmaBoolean => roundtrip[SSigmaProp.type](x, SSigmaProp) } + forAll { x: AvlTree => roundtrip[SAvlTree.type](x, SAvlTree) } + forAll { x: Array[Byte] => roundtrip[SByteArray](x.toColl, SByteArray) } + forAll { x: Box => roundtrip[SBox.type](x, SBox) } + forAll { x: Option[Byte] => roundtrip[SOption[SByte.type]](x, SOption[SByte.type]) } + testCollection(SOption[SLong.type]) + testTuples(SOption[SLong.type]) + forAll { t: SPredefType => testCollection(t) } + forAll { t: SPredefType => testTuples(t) } + } + + property("Example test") { + def toUnifiedString(from: String): String = from.replaceAll("[\n ]", "") + + toUnifiedString(DataJsonEncoder.encode((10, 20).asWrappedType, STuple(SInt, SInt)).toString()) shouldBe + toUnifiedString( + """ + |{ "type": "(Int, Int)", + | "value": { + | "_1": 10, + | "_2": 20 + | } + |}""".stripMargin) + toUnifiedString(DataJsonEncoder.encode(SigmaDsl.Colls.fromItems(1.toByte, 2.toByte, 3.toByte).asWrappedType, SCollectionType(SByte)).toString()) shouldBe + toUnifiedString( + """ + |{ "type": "Coll[Byte]", + | "value": [1, 2, 3] + |}""".stripMargin) + toUnifiedString(DataJsonEncoder.encode(SigmaDsl.Colls.fromItems((1, 10), (2, 20), (3, 30)).asWrappedType, SCollectionType(STuple(SInt, SInt))).toString()) shouldBe + toUnifiedString( + """ + |{ "type": "Coll[(Int, Int)]", + | "value": { + | "_1": [1, 2, 3], + | "_2": [10, 20, 30] + | } + |}""".stripMargin) + toUnifiedString( + DataJsonEncoder.encode(SigmaDsl.Colls.pairColl( + SigmaDsl.Colls.fromItems(1, 2, 3), + SigmaDsl.Colls.fromItems(10, 20, 30) + ).asWrappedType, SCollectionType(STuple(SInt, SInt))).toString()) shouldBe + toUnifiedString( + """ + |{ "type": "Coll[(Int, Int)]", + | "value": { + | "_1": [1, 2, 3], + | "_2": [10, 20, 30] + | } + |}""".stripMargin) + toUnifiedString(DataJsonEncoder.encode((SigmaDsl.Colls.fromItems((1, SigmaDsl.Colls.replicate(3, 1.toByte)), (2, SigmaDsl.Colls.replicate(2, 2.toByte)), (3, SigmaDsl.Colls.replicate(1, 3.toByte)), (4, SigmaDsl.Colls.replicate(0, 4.toByte))), 100.toLong).asWrappedType, + STuple(SCollectionType(STuple(SInt, SCollectionType(SByte))), SLong)).toString()) shouldBe + toUnifiedString( + """ + |{ "type": "(Coll[(Int, Coll[Byte])], Long)", + | "value": { + | "_1": { "_1": [1, 2, 3, 4], "_2": [ [1, 1, 1], [2, 2], [3], [] ] }, + | "_2": 100 + | } + |} + |""".stripMargin) + } + + def testEncodeError[T <: SType](tpe: T) = { + implicit val wWrapped = wrappedTypeGen(tpe) + implicit val tag = tpe.classTag[T#WrappedType] + implicit val tAny = RType.AnyType + forAll { x: T#WrappedType => + an[SerializerException] should be thrownBy + DataJsonEncoder.encode(TupleColl(x, x, x).asWrappedType, STuple(tpe, tpe, tpe)) + } + } + + property("Tuples with > 2 items are not supported") { + forAll { t: SPredefType => testEncodeError(t) } + } +} diff --git a/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala index b8eaea97e9..03f859320f 100644 --- a/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala +++ b/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala @@ -10,11 +10,18 @@ class PDHTSerializerSpecification extends SerializationSpecification { forAll { i: ProveDHTuple => roundTripTest(i.toSigmaProp) } + // In IntelliJ IDEA this test is executed last, at this point all statistics has been collected - // We output it here in the console -// println(CostTableStat.costTableString) -// println(ValueSerializer.printSerInfo()) -// GenSerializers.generateSerSpec() + // uncomment to output it in the console + // println(CostTableStat.costTableString) + + // uncomment to output info about serializers + // println(ValueSerializer.printSerInfo()) + + // ValueSerializer.serializerInfo is ready to be printed after all serializers are executed + // at least once during test execution. + // uncomment to save serialization info to the file + // GenSerializers.generateSerSpec() } } diff --git a/src/test/scala/sigmastate/serialization/generators/ObjectGenerators.scala b/src/test/scala/sigmastate/serialization/generators/ObjectGenerators.scala index 9943bf0486..a67374a0ad 100644 --- a/src/test/scala/sigmastate/serialization/generators/ObjectGenerators.scala +++ b/src/test/scala/sigmastate/serialization/generators/ObjectGenerators.scala @@ -6,6 +6,7 @@ import org.ergoplatform.ErgoScriptPredef.{FalseProp, TrueProp} import org.ergoplatform.validation._ import org.ergoplatform._ import org.scalacheck.Arbitrary.{arbAnyVal, arbBool, arbByte, arbInt, arbLong, arbOption, arbShort, arbString, arbUnit, arbitrary} +import org.scalacheck.Gen.frequency import org.scalacheck.{Arbitrary, Gen} import scorex.crypto.authds.{ADDigest, ADKey} import scorex.crypto.hash.Digest32 @@ -271,6 +272,8 @@ trait ObjectGenerators extends TypeGenerators with ValidationSpecification with case SAvlTree => arbAvlTree case SAny => arbAnyVal case SUnit => arbUnit + case opt: SOption[a] => + Arbitrary(frequency((5, None), (5, for (x <- wrappedTypeGen(opt.elemType)) yield Some(x)))) }).asInstanceOf[Arbitrary[T#WrappedType]].arbitrary def tupleGen(min: Int, max: Int): Gen[Tuple] = for { diff --git a/src/test/scala/sigmastate/utils/GenSerializers.scala b/src/test/scala/sigmastate/utils/GenSerializers.scala index a695d309f2..c9fc0a5f5e 100644 --- a/src/test/scala/sigmastate/utils/GenSerializers.scala +++ b/src/test/scala/sigmastate/utils/GenSerializers.scala @@ -7,6 +7,12 @@ import sigma.util.Extensions.ByteOps import sigmastate.lang.Terms.{PropertyCall, MethodCall} /** Generate contents of ErgoTree serializer format specification. + * To generate serialization formats, it is necessary that all branches of serializers + * are executed at least once. Those executions are then traced and the structure + * of the serialized formats is recorded in `ValueSerializer.serializerInfo` map, + * which lives in memory and is not stored anywhere. + * NOTE: you need to set `ValueSerializer.collectSerInfo = true`, + * don't forget to to set it back to `false` before release. */ object GenSerializers extends SpecGen { diff --git a/src/test/scala/sigmastate/utils/SpecGen.scala b/src/test/scala/sigmastate/utils/SpecGen.scala index bbcc71fd5c..32fc81e2d3 100644 --- a/src/test/scala/sigmastate/utils/SpecGen.scala +++ b/src/test/scala/sigmastate/utils/SpecGen.scala @@ -9,7 +9,7 @@ import scalan.util.PrintExtensions._ import sigmastate.Values.{FalseLeaf, Constant, TrueLeaf, BlockValue, ConstantPlaceholder, Tuple, ValDef, FunDef, ValUse, ValueCompanion, TaggedVariable, ConcreteCollection, ConcreteCollectionBooleanConstant} import sigmastate.lang.SigmaPredef.{PredefinedFuncRegistry, PredefinedFunc} import sigmastate.lang.StdSigmaBuilder -import sigmastate.lang.Terms.MethodCall +import sigmastate.lang.Terms.{MethodCall, PropertyCall} import sigmastate.serialization.OpCodes.OpCode import sigmastate.serialization.{ValueSerializer, OpCodes} import sigmastate.utxo.{SigmaPropIsProven, SelectField} @@ -57,7 +57,7 @@ trait SpecGen { } protected val predefFuncRegistry = new PredefinedFuncRegistry(StdSigmaBuilder) - val noFuncs: Set[ValueCompanion] = Set(Constant, MethodCall) + val noFuncs: Set[ValueCompanion] = Set(Constant, MethodCall, PropertyCall) val predefFuncs: Seq[PredefinedFunc] = predefFuncRegistry.funcs.values .filterNot { f => noFuncs.contains(f.docInfo.opDesc) }.toSeq val specialFuncs: Seq[PredefinedFunc] = predefFuncRegistry.specialFuncs.values.toSeq @@ -262,7 +262,10 @@ object GenPrimOpsApp extends SpecGen { // join collection of all operations with all methods by optional opCode val primOps = CollectionUtil.outerJoinSeqs(ops, methods)( - o => Some(o._1), m => m.docInfo.map(_.opDesc.opCode) + o => Some(o._1), m => m.docInfo.map(info => if (info.isFrontendOnly) { + System.err.println(s"WARNING: Operation is frontend only: $info") + None + } else info.opDesc.opCode) )( (k, o) => Some(o), // left without right (k,i) => None, // right without left