diff --git a/.gitignore b/.gitignore
index 698d67c97c..673ff8651b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,16 @@
-sigma.pdf
-sigma.toc
-sigma.aux
-sigma.log
-sigma.out
-sigma.bbl
-sigma.blg
-sigma.fls
-sigma.synctex.gz
-sigma.fdb_latexmk
+*.pdf
+*.toc
+*.aux
+*.log
+*.out
+*.bbl
+*.blg
+*.fls
+*.fdb_latexmk
*.log
test-out/
-
+flamegraphs/
# sbt specific
.cache
.lib/
diff --git a/.travis.yml b/.travis.yml
index 48f957e73c..e2c841e681 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,8 +9,8 @@ before_cache:
# These directories are cached to S3 at the end of the build
cache:
directories:
- - $HOME/.ivy2/cache
-
+ - $HOME/.ivy2/cache
+ - $HOME/.sbt
language: scala
jdk:
diff --git a/build.sbt b/build.sbt
index 223d9f808e..adfa32043a 100644
--- a/build.sbt
+++ b/build.sbt
@@ -25,7 +25,19 @@ lazy val commonSettings = Seq(
Alexander Chepurnoy
http://chepurnoy.org/
-
+
+ aslesarenko
+ Alexander Slesarenko
+ https://github.com/aslesarenko/
+
+ ,
+ publishMavenStyle := true,
+ publishTo := {
+ val nexus = "https://oss.sonatype.org/"
+ if (isSnapshot.value) { Some("snapshots" at nexus + "content/repositories/snapshots") }
+ else { Some("releases" at nexus + "service/local/staging/deploy/maven2") }
+ }
+
)
enablePlugins(GitVersioning)
@@ -57,14 +69,24 @@ version in ThisBuild := {
}
}
-val specialVersion = "master-6eca3f22-SNAPSHOT"
-val specialCommon = "io.github.scalan" %% "common" % specialVersion
-val specialCore = "io.github.scalan" %% "core" % specialVersion
+git.gitUncommittedChanges in ThisBuild := true
+
+val bouncycastleBcprov = "org.bouncycastle" % "bcprov-jdk15on" % "1.60"
+val scrypto = "org.scorexfoundation" %% "scrypto" % "2.1.6"
+val scorexUtil = "org.scorexfoundation" %% "scorex-util" % "0.1.3"
+val macroCompat = "org.typelevel" %% "macro-compat" % "1.1.1"
+val paradise = "org.scalamacros" %% "paradise" % "2.1.0" cross CrossVersion.full
+
+val specialVersion = "master-5ffd1bf8-SNAPSHOT"
+val specialCommon = "io.github.scalan" %% "common" % specialVersion
+val specialCore = "io.github.scalan" %% "core" % specialVersion
val specialLibrary = "io.github.scalan" %% "library" % specialVersion
-val specialSigmaVersion = "master-354d6254-SNAPSHOT"
-val sigmaImpl = "io.github.scalan" %% "sigma-impl" % specialSigmaVersion
-val sigmaLibrary = "io.github.scalan" %% "sigma-library" % specialSigmaVersion
+val meta = "io.github.scalan" %% "meta" % specialVersion
+val plugin = "io.github.scalan" %% "plugin" % specialVersion
+val libraryapi = "io.github.scalan" %% "library-api" % specialVersion
+val libraryimpl = "io.github.scalan" %% "library-impl" % specialVersion
+val libraryconf = "io.github.scalan" %% "library-conf" % specialVersion
val testingDependencies = Seq(
"org.scalatest" %% "scalatest" % "3.0.5" % "test",
@@ -75,19 +97,24 @@ val testingDependencies = Seq(
specialCommon, (specialCommon % Test).classifier("tests"),
specialCore, (specialCore % Test).classifier("tests"),
specialLibrary, (specialLibrary % Test).classifier("tests"),
- sigmaImpl, (sigmaImpl % Test).classifier("tests"),
- sigmaLibrary, (sigmaLibrary % Test).classifier("tests"),
)
+lazy val testSettings = Seq(
+ libraryDependencies ++= testingDependencies,
+ parallelExecution in Test := false,
+ baseDirectory in Test := file("."),
+ publishArtifact in Test := true,
+ publishArtifact in(Test, packageSrc) := true,
+ publishArtifact in(Test, packageDoc) := false,
+ test in assembly := {})
+
libraryDependencies ++= Seq(
- "org.scorexfoundation" %% "scrypto" % "2.1.4",
- "org.scorexfoundation" %% "scorex-util" % "0.1.1",
+ scrypto,
+ scorexUtil,
"org.bouncycastle" % "bcprov-jdk15on" % "1.+",
"com.typesafe.akka" %% "akka-actor" % "2.4.+",
"org.bitbucket.inkytonik.kiama" %% "kiama" % "2.1.0",
"com.lihaoyi" %% "fastparse" % "1.0.0",
- sigmaImpl,
- sigmaLibrary,
) ++ testingDependencies
@@ -96,18 +123,9 @@ scalacOptions ++= Seq("-feature", "-deprecation")
//uncomment lines below if the Scala compiler hangs to see where it happens
//scalacOptions in Compile ++= Seq("-Xprompt", "-Ydebug", "-verbose" )
-
-publishMavenStyle := true
-
parallelExecution in Test := false
publishArtifact in Test := false
-publishTo := {
- val nexus = "https://oss.sonatype.org/"
- if (isSnapshot.value) { Some("snapshots" at nexus + "content/repositories/snapshots") }
- else { Some("releases" at nexus + "service/local/staging/deploy/maven2") }
-}
-
pomIncludeRepository := { _ => false }
credentials += Credentials(Path.userHome / ".sbt" / ".sigma-sonatype-credentials")
@@ -117,10 +135,64 @@ credentials ++= (for {
password <- Option(System.getenv().get("SONATYPE_PASSWORD"))
} yield Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", username, password)).toSeq
-lazy val sigma = (project in file(".")).settings(commonSettings: _*)
+def libraryDefSettings = commonSettings ++ testSettings ++ Seq(
+ scalacOptions ++= Seq(
+// s"-Xplugin:${file(".").absolutePath }/scalanizer/target/scala-2.12/scalanizer-assembly-better-costing-2a66ed5c-SNAPSHOT.jar"
+ )
+)
+
+lazy val sigmaconf = Project("sigma-conf", file("sigma-conf"))
+ .settings(commonSettings,
+ libraryDependencies ++= Seq(
+ plugin, libraryconf
+ ))
+
+lazy val scalanizer = Project("scalanizer", file("scalanizer"))
+ .dependsOn(sigmaconf)
+ .settings(commonSettings,
+ libraryDependencies ++= Seq(meta, plugin, libraryapi, libraryimpl),
+// publishArtifact in(Compile, packageBin) := false,
+ assemblyOption in assembly ~= { _.copy(includeScala = false, includeDependency = true) },
+ artifact in(Compile, assembly) := {
+ val art = (artifact in(Compile, assembly)).value
+ art.withClassifier(Some("assembly"))
+ },
+ addArtifact(artifact in(Compile, assembly), assembly)
+ )
+
+lazy val sigmaapi = Project("sigma-api", file("sigma-api"))
+ .settings(libraryDefSettings :+ addCompilerPlugin(paradise),
+ libraryDependencies ++= Seq(
+ specialCommon, meta, libraryapi, macroCompat, scrypto, bouncycastleBcprov
+ ))
+
+lazy val sigmaimpl = Project("sigma-impl", file("sigma-impl"))
+ .dependsOn(sigmaapi % allConfigDependency)
+ .settings(libraryDefSettings,
+ libraryDependencies ++= Seq(
+ libraryapi, libraryimpl, scrypto, bouncycastleBcprov
+ ))
+
+lazy val sigmalibrary = Project("sigma-library", file("sigma-library"))
+ .dependsOn(sigmaimpl % allConfigDependency)
+ .settings(libraryDefSettings,
+ libraryDependencies ++= Seq(
+ specialCommon, (specialCommon % Test).classifier("tests"),
+ specialCore, (specialCore % Test).classifier("tests"),
+ libraryapi, (libraryapi % Test).classifier("tests"),
+ libraryimpl, (libraryimpl % Test).classifier("tests"),
+ specialLibrary, (specialLibrary % Test).classifier("tests"),
+ scrypto,
+ bouncycastleBcprov
+ ))
+
+lazy val sigma = (project in file("."))
+ .aggregate(sigmaapi, sigmaimpl, sigmalibrary, sigmaconf, scalanizer)
+ .dependsOn(sigmaimpl % allConfigDependency, sigmalibrary % allConfigDependency)
+ .settings(commonSettings: _*)
def runErgoTask(task: String, sigmastateVersion: String, log: Logger): Unit = {
- val ergoBranch = "master"
+ val ergoBranch = "v2.0"
log.info(s"Testing current build in Ergo (branch $ergoBranch):")
val cwd = new File("").absolutePath
val ergoPath = new File(cwd + "/ergo-tests/")
@@ -138,24 +210,34 @@ def runErgoTask(task: String, sigmastateVersion: String, log: Logger): Unit = {
log.info(s"Running Ergo tests in $ergoPath with Sigmastate version $sigmastateVersion")
val res = Process(Seq("sbt", task), ergoPath, "SIGMASTATE_VERSION" -> sigmastateVersion) !
-
+
if (res != 0) sys.error(s"Ergo $task failed!")
}
-lazy val ergoUnitTest = TaskKey[Unit]("ergoUnitTest", "run ergo unit tests with current version")
-ergoUnitTest := {
+lazy val ergoUnitTestTask = TaskKey[Unit]("ergoUnitTestTask", "run ergo unit tests with current version")
+ergoUnitTestTask := {
val log = streams.value.log
val sigmastateVersion = version.value
runErgoTask("test", sigmastateVersion, log)
}
-ergoUnitTest := ergoUnitTest.dependsOn(publishLocal).value
+commands += Command.command("ergoUnitTest") { state =>
+ "clean" ::
+ "publishLocal" ::
+ "ergoUnitTestTask" ::
+ state
+}
-lazy val ergoItTest = TaskKey[Unit]("ergoItTest", "run ergo it:test with current version")
-ergoItTest := {
+lazy val ergoItTestTask = TaskKey[Unit]("ergoItTestTask", "run ergo it:test with current version")
+ergoItTestTask := {
val log = streams.value.log
val sigmastateVersion = version.value
runErgoTask("it:test", sigmastateVersion, log)
}
-ergoItTest := ergoItTest.dependsOn(publishLocal).value
+commands += Command.command("ergoItTest") { state =>
+ "clean" ::
+ "publishLocal" ::
+ "ergoItTestTask" ::
+ state
+}
diff --git a/docs/Costing.md b/docs/Costing.md
index 8db9e13912..f575aee410 100644
--- a/docs/Costing.md
+++ b/docs/Costing.md
@@ -106,7 +106,7 @@ represent cost and size (costing information, costing properties).
Note, that `cost` and `dataSize` are independent parameters because some _costed_ values may have
very small `dataSize`, but at the same time very high `cost`, e.g. result of contract may be `true`
boolean value whose `dataSize` is 1 byte, but its `cost` is the cost of executing the whole contract.
-The opposite is also possible. For example a context variable of `Col[Byte]` type have `cost` equal 0,
+The opposite is also possible. For example a context variable of `Coll[Byte]` type have `cost` equal 0,
but may have very big `dataSize`.
From this perspective Costed Graph `graphC` is a data flow graph between costed values.
@@ -210,23 +210,23 @@ CCostedPair(
CCostedPrim(true, costOf("Const:() => Boolean"), sizeOf[Boolean])))
```
-##### Costed Values of Col Type
+##### Costed Values of Coll Type
-If `Item` is a type of array element, then costed value of type `Col[Item]` is
-represented by the following specializations of `Costed[Col[Item]]` type
+If `Item` is a type of array element, then costed value of type `Coll[Item]` is
+represented by the following specializations of `Costed[Coll[Item]]` type
```scala
-class CCostedCol[Item](
+class CCostedColl[Item](
val values: Coll[Item], val costs: Coll[Int],
- val sizes: Coll[Long], val valuesCost: Int) extends CostedCol[Item] {
+ val sizes: Coll[Long], val valuesCost: Int) extends CostedColl[Item] {
def value: Coll[Item] = values
def cost: Int = valuesCost + costs.sum
def dataSize: Long = sizes.sum
- def mapCosted[Res](f: Costed[Item] => Costed[Res]): CostedCol[Res] = rewritableMethod
+ def mapCosted[Res](f: Costed[Item] => Costed[Res]): CostedColl[Res] = rewritableMethod
def foldCosted[B](zero: Costed[B], op: Costed[(B, Item)] => Costed[B]): Costed[B] = rewritableMethod
}
```
-For constant, context variables and registers values of `Col` type the costing information
-of `CCostedCol` is computed from actual data.
+For constant, context variables and registers values of `Coll` type the costing information
+of `CCostedColl` is computed from actual data.
Note methods `mapCosted` and `foldCosted`, these methods represent costed version of original
collection methods. Note the methods are defined as rewritable, meaning their implementation
@@ -309,7 +309,7 @@ explicit by using `eval` helper and also employ other idioms of staged evaluatio
```scala
case MapCollection(input, id, mapper) =>
val eIn = stypeToElem(input.tpe.elemType) // translate sigma type to Special type descriptor
- val xs = asRep[CostedCol[Any]](eval(input)) // recursively build subgraph for input argument
+ val xs = asRep[CostedColl[Any]](eval(input)) // recursively build subgraph for input argument
implicit val eAny = xs.elem.asInstanceOf[CostedElem[Coll[Any],_]].eVal.eA
assert(eIn == eAny, s"Types should be equal: but $eIn != $eAny")
val mapperC = fun { x: Rep[Costed[Any]] => // x argument is already costed
@@ -409,13 +409,13 @@ of the specific cases into reusable modules.
to hook into graph building process and perform on the fly substitution of
specific sub-graphs with equivalent but different sub-graphs.
The following rule uses auto-generated extractor `mapCosted` which recognizes invocations of method
-`CostedCol.mapCosted` (Remember, this method was used in costing rule for `MapCollection` tree node).
+`CostedColl.mapCosted` (Remember, this method was used in costing rule for `MapCollection` tree node).
```scala
override def rewriteDef[T](d: Def[T]): Rep[_] = {
- val CCM = CostedColMethods
+ val CCM = CostedCollMethods
d match {
- case CCM.mapCosted(xs: RCostedCol[a], _f: RCostedFunc[_, b]) =>
+ case CCM.mapCosted(xs: RCostedColl[a], _f: RCostedFunc[_, b]) =>
val f = asRep[Costed[a] => Costed[b]](_f)
val (calcF, costF, sizeF) = splitCostedFunc[a, b](f)
val vals = xs.values.map(calcF)
@@ -436,7 +436,7 @@ override def rewriteDef[T](d: Def[T]): Rep[_] = {
colBuilder.replicate(xs.sizes.length, typeSize(tpeB))
} else
xs.sizes.map(sizeF)
- RCCostedCol(vals, costs, sizes, xs.valuesCost)
+ RCCostedColl(vals, costs, sizes, xs.valuesCost)
case _ => super.rewriteDef(d)
}
}
diff --git a/docs/LangSpec.md b/docs/LangSpec.md
index 4c3148ce06..308d4724ac 100644
--- a/docs/LangSpec.md
+++ b/docs/LangSpec.md
@@ -19,7 +19,7 @@
- predefined primitives: `blake2b256`, `byteArrayToBigInt`, `proveDlog` etc.
- val declarations: `val h = blake2b256(pubkey)`
- if-then-else clause: `if (x > 0) 1 else 0`
-- collection literals: `Col(1, 2, 3, 4)`
+- collection literals: `Coll(1, 2, 3, 4)`
- generic high-order collection operations: `map`, `fold`, `exists`, `forall`, etc.
- accessing fields of any predefined structured objects: `box.value`
- function invocations (predefined and user defined): `proveDlog(pubkey)`
@@ -47,7 +47,7 @@ Type Name | Description
`SigmaProp` | a type which represent a logical value which can be be obtained by executing a Sigma protocol with zero-knowledge proof of knowledge
`AvlTree` | authenticated dynamic dictionary
`GroupElement` | elliptic curve points
-`Box` | a box containing a value, tokens and registers along with a guarding proposition
+`Box` | a box containing a monetary value (in NanoErgs), tokens and registers along with a guarding proposition
`Option[T]` | a container which either have some value of type `T` or none.
`Coll[T]` | a collection of arbitrary length with all values of type `T`
`(T1,...,Tn)` | tuples, a collection of element where T1, ..., Tn can be different types
@@ -120,12 +120,22 @@ class Numeric {
/** Absolute value of this numeric value.
* @since 2.0
*/
- def abs: Numeric
+ def toAbs: Numeric
/** Compares this numeric with that numeric for order. Returns a negative integer, zero, or a positive integer as the
* `this` is less than, equal to, or greater than `that`.
*/
- def compare(that: SNumeric): Int
+ def compareTo(that: Numeric): Int
+
+ /** Returns least of the two (`this` or `that`).
+ * @since 2.0
+ */
+ def min(that: Numeric): Numeric
+
+ /** Returns max of the two (`this` or `that`).
+ * @since 2.0
+ */
+ def max(that: Numeric): Numeric
}
class Short extends Numeric
@@ -445,6 +455,7 @@ class Coll[A] {
* @tparam B the element type of the returned collection.
* @return a new collection of type `Coll[B]` resulting from applying the given function
* `f` to each element of this collection and collecting the results.
+ */
def map[B](f: A => B): Coll[B]
/** For this collection (x0, ..., xN) and other collection (y0, ..., yM)
@@ -488,7 +499,7 @@ class Coll[A] {
* where `x,,1,,, ..., x,,n,,` are the elements of this collection.
* Returns `z` if this collection is empty.
*/
- def fold[B](z: B)(op: (B, A) => B): B
+ def foldLeft[B](z: B)(op: (B, A) => B): B
/** Produces the range of all indices of this collection [0 .. size-1]
* @since 2.0
@@ -499,6 +510,9 @@ class Coll[A] {
* Builds a new collection by applying a function to all elements of this collection
* and using the elements of the resulting collections.
*
+ * Function `f` is constrained to be of the form `x => x.someProperty`, otherwise
+ * it is illegal.
+ *
* @param f the function to apply to each element.
* @tparam B the element type of the returned collection.
* @return a new collection of type `Coll[B]` resulting from applying the given collection-valued function
@@ -517,6 +531,14 @@ class Coll[A] {
*/
def segmentLength(p: A => Boolean, from: Int): Int
+ /** Finds the first element of the $coll satisfying a predicate, if any.
+ *
+ * @param p the predicate used to test elements.
+ * @return an option value containing the first element in the $coll
+ * that satisfies `p`, or `None` if none exists.
+ */
+ def find(p: A => Boolean): Option[A]
+
/** Finds index of the first element satisfying some predicate after or at some start index.
*
* @param p the predicate used to test elements.
@@ -579,10 +601,39 @@ class Coll[A] {
*/
def mapReduce[K, V](m: A => (K,V), r: (V,V) => V): Coll[(K,V)]
+ /** Partitions this $coll into a map of ${coll}s according to some discriminator function.
+ *
+ * @param key the discriminator function.
+ * @tparam K the type of keys returned by the discriminator function.
+ * @return A map from keys to ${coll}s such that the following invariant holds:
+ * {{{
+ * (xs groupBy key)(k) = xs filter (x => key(x) == k)
+ * }}}
+ * That is, every key `k` is bound to a $coll of those elements `x`
+ * for which `key(x)` equals `k`.
+ */
+ def groupBy[K: RType](key: A => K): Coll[(K, Coll[A])]
+
+ /** Partitions this $coll into a map of ${coll}s according to some discriminator function.
+ * Additionally projecting each element to a new value.
+ *
+ * @param key the discriminator function.
+ * @param proj projection function to produce new value for each element of this $coll
+ * @tparam K the type of keys returned by the discriminator function.
+ * @tparam V the type of values returned by the projection function.
+ * @return A map from keys to ${coll}s such that the following invariant holds:
+ * {{{
+ * (xs groupByProjecting (key, proj))(k) = xs filter (x => key(x) == k).map(proj)
+ * }}}
+ * That is, every key `k` is bound to projections of those elements `x`
+ * for which `key(x)` equals `k`.
+ */
+ def groupByProjecting[K: RType, V: RType](key: A => K, proj: A => V): Coll[(K, Coll[V])]
+
/** Produces a new collection which contains all distinct elements of this collection and also all elements of
* a given collection that are not in this collection.
* This is order preserving operation considering only first occurrences of each distinct elements.
- * Any collection `xs` can be transformed to a sequence with distinct elements by using xs.unionSet(Col()).
+ * Any collection `xs` can be transformed to a sequence with distinct elements by using xs.unionSet(Coll()).
*
* NOTE: Use append if you don't need set semantics.
*
@@ -615,6 +666,15 @@ class Coll[A] {
*/
def intersect(that: Coll[A]): Coll[A]
+ /** Folding through all elements of this $coll starting from m.zero and applying m.plus to accumulate
+ * resulting value.
+ *
+ * @param m monoid object to use for summation
+ * @return result of the following operations (m.zero `m.plus` x1 `m.plus` x2 `m.plus` ... xN)
+ * @since 2.0
+ */
+ def sum(m: Monoid[A]): A
+
/** Selects an interval of elements. The returned collection is made up
* of all elements `x` which satisfy the invariant:
* {{{
@@ -668,7 +728,7 @@ class Coll[A] {
* @return A new collection which contains the first occurrence of every element of this collection.
* @since 2.0
*/
- def distinct: Col[A]
+ def distinct: Coll[A]
/** Tests whether this collection contains the given sequence at a given index.
*
@@ -681,14 +741,14 @@ class Coll[A] {
* index `offset`, otherwise `false`.
* @since 2.0
*/
- def startsWith[B](that: GenSeq[B], offset: Int): Boolean
+ def startsWith(that: Coll[A], offset: Int): Boolean
/** Tests whether this collection ends with the given collection.
* @param that the collection to test
* @return `true` if this collection has `that` as a suffix, `false` otherwise.
* @since 2.0
*/
- def endsWith(that: Col[A]): Boolean
+ def endsWith(that: Coll[A]): Boolean
}
```
@@ -727,7 +787,7 @@ def allOf(conditions: Coll[Boolean]): Boolean
/** Returns true if at least on element of the conditions is true */
def anyOf(conditions: Coll[Boolean]): Boolean
-/** Similar to allOf, but performing logical XOR operation instead of `||`
+/** Similar to allOf, but performing logical XOR operation instead of `&&`
* @since 2.0
*/
def xorOf(conditions: Coll[Boolean]): Boolean
@@ -830,7 +890,7 @@ def fromBase64(input: String): Coll[Byte]
/**
* It is executed in compile time.
- * The compiler takes Base64 encoding of public key as String literal and create GroupElement constant.
+ * The compiler takes Base58 encoding of public key as String literal and create GroupElement constant.
* Then the compiler used this constant to construct proveDlog public key out of it.
* @since 1.9
*/
diff --git a/docs/TypeSerialization.md b/docs/TypeSerialization.md
index 2ff91a124e..4549ecfa44 100644
--- a/docs/TypeSerialization.md
+++ b/docs/TypeSerialization.md
@@ -2,7 +2,7 @@
This document defines a binary format, which is used to store Sigma scripts in persistent stores,
to transfer them over wire and to enable cross-platform interoperation.
-It organized as the following: first we describe how the types (like `Int`, `Col[Byte]`, etc.) are serialized,
+It organized as the following: first we describe how the types (like `Int`, `Coll[Byte]`, etc.) are serialized,
then we define serialization of typed data. This will give us a basis to describe serialization of
Constant nodes of SigmaIR. From that we proceed to serialization of arbitrary SigmaIR trees.
@@ -22,9 +22,9 @@ However, we use special encoding schema to save bytes for the types that are use
We assume the most frequently used types are:
- primitive types - Int, Byte, Boolean, BigInt, GroupElement, Box, AvlTree
-- Collections of primitive types - `Col[Byte]` etc
+- Collections of primitive types - `Coll[Byte]` etc
- Options of primitive types - `Option[Int]` etc.
-- Nested arrays of primitive types - `Col[Col[Int]]` etc.
+- Nested arrays of primitive types - `Coll[Coll[Int]]` etc.
- Functions of primitive types - `Box => Boolean` etc.
- First biased pair of types - `(_, Int)` when we know the first component is a primitive type.
- Second biased pair of types - `(Int, _)` when we know the second component is a primitive type.
@@ -57,15 +57,15 @@ Id | Type
6 | BigInt (java.math.BigInteger)
7 | GroupElement (org.bouncycastle.math.ec.ECPoint)
8 | SigmaProp
-9 | reserved for Char
-10 | reserved for String
-11 | reserved for Double
+9 | reserved for Char
+10 | reserved for Double
+11 | reserved
-For each type constructor like Col or Option we use the encoding schema defined below.
-Type constructor has associated _base code_ (e.g. 12 for `Col[_]`, 24 for `Col[Col[_]]` etc. ), which is multiple of 12.
-Base code can be added to primitive type id to produce code of constructed type, for example 12 + 1 = 13 is a code of `Col[Byte]`.
+For each type constructor like Coll or Option we use the encoding schema defined below.
+Type constructor has associated _base code_ (e.g. 12 for `Coll[_]`, 24 for `Coll[Coll[_]]` etc. ), which is multiple of 12.
+Base code can be added to primitive type id to produce code of constructed type, for example 12 + 1 = 13 is a code of `Coll[Byte]`.
The code of type constructor (12 in this example) is used when type parameter is non-primitive type
-(e.g. `Col[(Byte, Int)]`), is which case recursive descent is performed.
+(e.g. `Coll[(Byte, Int)]`), is which case recursive descent is performed.
This encoding allows very simple and quick decoding by using div and mod operations.
The interval of codes for data types is divided as the following:
@@ -73,14 +73,14 @@ The interval of codes for data types is divided as the following:
Interval | Type constructor | Description
--------------------|------------------ |------------
0x01 - 0x0B(11) | | primitive types (including 2 reserved)
-0x0C(12) | `Col[_]` | Collection of non-primivite types (`Col[(Int,Boolean)]`)
-0x0D(13) - 0x17(23) | `Col[_]` | Collection of primitive types (`Col[Byte]`, `Col[Int]`, etc.)
-0x18(24) | `Col[Col[_]]` | Nested collection of non-primitive types (`Col[Col[(Int,Boolean)]]`)
-0x19(25) - 0x23(35) | `Col[Col[_]]` | Nested collection of primitive types (`Col[Col[Byte]]`, `Col[Col[Int]]`)
+0x0C(12) | `Coll[_]` | Collection of non-primivite types (`Coll[(Int,Boolean)]`)
+0x0D(13) - 0x17(23) | `Coll[_]` | Collection of primitive types (`Coll[Byte]`, `Coll[Int]`, etc.)
+0x18(24) | `Coll[Coll[_]]` | Nested collection of non-primitive types (`Coll[Coll[(Int,Boolean)]]`)
+0x19(25) - 0x23(35) | `Coll[Coll[_]]` | Nested collection of primitive types (`Coll[Coll[Byte]]`, `Coll[Coll[Int]]`)
0x24(36) | `Option[_]` | Option of non-primitive type (`Option[(Int, Byte)]`)
0x25(37) - 0x2F(47) | `Option[_]` | Option of primitive type (`Option[Int]`)
-0x30(48) | `Option[Col[_]]` | Option of Col of non-primitive type (`Option[Col[(Int, Boolean)]]`)
-0x31(49) - 0x3B(59) | `Option[Col[_]]` | Option of Col of primitive type (`Option[Col[Int]]`)
+0x30(48) | `Option[Coll[_]]` | Option of Coll of non-primitive type (`Option[Coll[(Int, Boolean)]]`)
+0x31(49) - 0x3B(59) | `Option[Coll[_]]` | Option of Coll of primitive type (`Option[Coll[Int]]`)
0x3C(60) | `(_,_)` | Pair of non-primitive types (`((Int, Byte), (Boolean,Box))`, etc.)
0x3D(61) - 0x47(71) | `(_, Int)` | Pair of types where first is primitive (`(_, Int)`)
0x48(72) | `(_,_,_)` | Triple of types
@@ -93,8 +93,9 @@ Interval | Type constructor | Description
0x63(99) | `Box` | Box type
0x64(100) | `AvlTree` | AvlTree type
0x65(101) | `Context` | Context type
-0x65(102) | | reserved for String type
-0x66(103) - 0x6E(110)| | reserved for future use
+0x65(102) | `String` | String
+0x66(103) | `IV` | TypeIdent
+0x67(104)- 0x6E(110)| | reserved for future use
0x6F(111) | | Reserved for future `Class` type (e.g. user-defined types)
@@ -118,7 +119,7 @@ When argument of the type constructor is not primitive type we fallback to simpl
In such a case we emit special code for the type constructor according to the table above and descend recursively
to every child node of the type tree.
We do this descend only for those children whose code cannot be embedded in parent code.
-For example, serialization of `Col[(Int,Boolean)]` proceeds as the following:
+For example, serialization of `Coll[(Int,Boolean)]` proceeds as the following:
1) emit 0x0C because element of collection is not primitive
2) recursively serialize `(Int, Boolean)`
3) emit 0x3D because first item in the pair is primitive
@@ -130,10 +131,10 @@ For example, serialization of `Col[(Int,Boolean)]` proceeds as the following:
Type | D | R | Bytes | #Bytes | Comments
---------------------|-----|-----|-------------------|--------|---------
`Byte` | | | 1 | 1 |
-`Col[Byte]` | | | 12 + 1 = 13 | 1 |
-`Col[Col[Byte]]` | | | 24 + 1 = 25 | 1 |
+`Coll[Byte]` | | | 12 + 1 = 13 | 1 |
+`Coll[Coll[Byte]]` | | | 24 + 1 = 25 | 1 |
`Option[Byte]` | | | 36 + 1 = 37 | 1 | register
-`Option[Col[Byte]]`| | | 48 + 1 = 49 | 1 | register
+`Option[Coll[Byte]]`| | | 48 + 1 = 49 | 1 | register
`(Int,Int)` | | | 84 + 3 = 87 | 1 | fold
`Box=>Boolean` | 7 | 2 | 198 = 7*12+2+112 | 1 | exist, forall
`(Int,Int)=>Int` | 0 | 3 | 115=0*12+3+112, 87 | 2 | fold
@@ -143,7 +144,7 @@ Type | D | R | Bytes | #Bytes | Comments
## Data and Constant serialization
The contents of a typed data structure can be fully described by a type tree.
-For example having a typed data object `d: (Int, Col[Byte], Boolean)` we can tell that `d` has 3 items,
+For example having a typed data object `d: (Int, Coll[Byte], Boolean)` we can tell that `d` has 3 items,
the first item contain 64-bit integer, the second - collection of bytes, and the third - logical true/false value.
To serialize/deserialize typed data we need to know its type descriptor (type tree).
@@ -153,10 +154,10 @@ using predefined function shown in the following table
Value: Type | Function | Format
-------------- |------------------------------ |-------
-`x: Byte` | `byte: Byte => Col[Byte]` | `[x & 0xFF]` - one byte storing value x
-`x: Short` | `short: Short => Col[Byte]` | `[x & 0xFFFF]` - two bytes in big-endian order storing value x
-`x: Int` | `int: Int => Col[Byte]` | `[x & 0xFFFFFFFF]` - four bytes in big-endian order storing value x
-`x: Long` | `long: Int => Col[Byte]` | `[x & 0xFFFFFFFFFFFFFFFF]` - eight bytes in big-endian order storing value x
+`x: Byte` | `byte: Byte => Coll[Byte]` | `[x & 0xFF]` - one byte storing value x
+`x: Short` | `short: Short => Coll[Byte]` | `[x & 0xFFFF]` - two bytes in big-endian order storing value x
+`x: Int` | `int: Int => Coll[Byte]` | `[x & 0xFFFFFFFF]` - four bytes in big-endian order storing value x
+`x: Long` | `long: Int => Coll[Byte]` | `[x & 0xFFFFFFFFFFFFFFFF]` - eight bytes in big-endian order storing value x
Thus, serialization format is defined recursively as shown in the following table
@@ -165,8 +166,8 @@ Object | Type | Format
x = 0xXX | `Byte` | `byte(x)` - one byte storing value x
b = false/true| `Boolean` | `if (b) byte(0x01) else byte(0x00)]` - one byte storing 0 or 1
n = 0xXXXXXXXXXXXXXXXX | `Int` | `[XX,XX,XX,XX,XX,XX,XX,XX]` - big endian 8 bytes
-N = new BigInteger() | `BigInt` | xs = N.toByteArray, `[serialize(xs)]` - serialize as `Col[Byte]`, see also BigInteger.toByteArray
-e = new EcPoint() | `GroupElement` | `[e.getEncoded(true)]` see also org.bouncycastle.math.ec.EcPoint.getEncoded(true)
+N = new BigInteger() | `BigInt` | xs = N.toByteArray, `[serialize(xs)]` - serialize as `Coll[Byte]`, see also BigInteger.toByteArray
+e = new EcPoint() | `GroupElement` | `[e.getEncoded]` see also use GroupElementSerializer
box = new ErgoBox() | `Box` | `[putLong(box.value), putValue(box.proposition), putArray[Any](box.registers), 32, putBytes(box.transactionId), putShort(box.boxId)]`
t = new AvlTree() | `AvlTree` | `[serialize(t.startingDigest), putInt(t.keyLength), putOpt(t.valueLengthOpt), putOpt(t.maxNumOperations), putOpt(t.maxDeletes)]`
-xs = Col(x1, .., xN) | `Col[T]` | `[xs.length & 0xXXXX, serialize(x1), ..., serialize(xN)]` - 2 bytes of length and recursive bytes of all the elements
+xs = Coll(x1, .., xN) | `Coll[T]` | `[xs.length & 0xXXXX, serialize(x1), ..., serialize(xN)]` - 2 bytes of length and recursive bytes of all the elements
diff --git a/docs/conversions.dot b/docs/conversions.dot
index cb3d906935..ad3645d052 100644
--- a/docs/conversions.dot
+++ b/docs/conversions.dot
@@ -63,6 +63,7 @@ digraph conversions {
GroupElement -> SigmaProp [label="proveDlog(...)"]
GroupElement -> Boolean [label=".isIdentity"]
GroupElement -> Bytes [label=".nonce"]
+ //todo remove compressed flag, use GroupElementSerializer
GroupElement -> Bytes [label=".getEncoded(compressed)" color=red]
String -> Bytes [label="fromBase58(...)"]
diff --git a/docs/sigma-dsl.md b/docs/sigma-dsl.md
new file mode 100644
index 0000000000..5ddf304f7b
--- /dev/null
+++ b/docs/sigma-dsl.md
@@ -0,0 +1,13 @@
+# Sigma: Scala DSL for smart contracts with zero knowledge proof of knowledge
+
+## Intro
+ SigmaDsl is a domain-specific language embedded into Scala and designed to be
+ source code compatible with SigmaScript. This means you can write SigmaDsl
+ code directly in Scala IDE (e.g. IntelliJ IDEA) and copy-paste code snippets
+ between SigmaDsl and SigmaScript.
+
+SigmaDsl is implemented as a library in the framework of
+[Special](https://github.com/scalan/special)
+
+## See also
+[Special](https://github.com/scalan/special)
diff --git a/docs/sigmastate_protocols/sigmastate_protocols.bib b/docs/sigmastate_protocols/sigmastate_protocols.bib
index e8fc15d421..18e45b7c43 100644
--- a/docs/sigmastate_protocols/sigmastate_protocols.bib
+++ b/docs/sigmastate_protocols/sigmastate_protocols.bib
@@ -1,3 +1,29 @@
+@misc{raddress,
+ year = {2018},
+ month = {06},
+ title = {Adding anti-theft feature to Bitcoin using a new address type},
+ author = {Jus12},
+ howpublished = {\url{https://bitcointalk.org/index.php?topic=4440801.0}}
+}
+@misc{langrepo,
+ author = {Scorex Foundation},
+ title = {Sigmastate Interpretter},
+ year = {2017},
+ publisher = {GitHub},
+ journal = {GitHub repository},
+ howpublished = {\url{https://github.com/ScorexFoundation/sigmastate-interpreter}}
+ commit = {6d427a2323a4ac1ecc9b18bb0b00416f6165b226}
+}
+@inproceedings{zerocoin,
+ author = {Miers, Ian and Garman, Christina and Green, Matthew and Rubin, A.D.},
+ year = {2013},
+ month = {05},
+ pages = {397-411},
+ title = {Zerocoin: Anonymous Distributed E-Cash from Bitcoin},
+ isbn = {978-1-4673-6166-8},
+ journal = {Proceedings - IEEE Symposium on Security and Privacy},
+ doi = {10.1109/SP.2013.34}
+}
@inproceedings{NW06,
author = {Turlough Neary and
Damien Woods},
diff --git a/docs/sigmastate_protocols/sigmastate_protocols.tex b/docs/sigmastate_protocols/sigmastate_protocols.tex
index 39e73f8ab7..dbff6c4a1a 100755
--- a/docs/sigmastate_protocols/sigmastate_protocols.tex
+++ b/docs/sigmastate_protocols/sigmastate_protocols.tex
@@ -8,6 +8,15 @@
\usepackage{mathtools,color,xcolor,hyperref,graphicx,wrapfig,listings,array,xspace}
\usepackage{amsfonts}
+% https://tex.stackexchange.com/questions/11719/how-do-i-backcolor-in-verbatim
+\usepackage{xcolor}
+\usepackage{alltt}
+% Compensate for fbox sep:
+\newcommand\Hi[2][lightgray]{%
+ \hspace*{-\fboxsep}%
+ \colorbox{#1}{#2}%
+ \hspace*{-\fboxsep}%
+}
\ifnum\shownotes=1
\ifnum\notesinmargins=1
@@ -52,7 +61,7 @@
\newcommand{\ignore}[1]{}
\newcommand{\langname}{ErgoScript\xspace}
-\newcommand{\mixname}{Twix\xspace}
+\newcommand{\mixname}{ErgoMix\xspace}
\newcommand{\lst}[1]{\text{\lstinline[basicstyle={\ttfamily}]$#1$}}
@@ -64,7 +73,7 @@
\begin{document}
-\title{\langname Overview (working title)}
+\title{Protocols in \langname: From Games to Mixers}
\author{authors}
@@ -73,326 +82,387 @@
\begin{abstract}
-This paper describes uses \langname to design games and mixing protocols
+%This article describes \langname via examples.
+We use \langname to create several protocols such as an XOR game (a simplified version of {\em rock-paper-scissors}), {\em reversible addresses} that have anti-theft features, and {\em \mixname}, a mixing protocol to enhance anonymity.
+
+%We create several protocols using \langname, such as games and mixing protocols.
\end{abstract}
-\section{Overview of \langname}
-\paragraph{Built-in $\Sigma$-protocols}
-Our language incorporates proofs as first-class citizens, giving developers access to cryptographic primitives for non-interactive {\em proofs of knowledge} known as $\Sigma$-protocols (pronounced ``sigma-protocols''). A transaction's output is protected by a statement known as a $\Sigma$-statement. In order to spend the output, the statement needs to be proven true (by providing a $\Sigma$-proof). The combination of the protecting script and the spending proof forms a $\Sigma$-protocol.
+\section{Overview of $\Sigma$-protocols}
+\label{intro:sigma}
+A key feature of \langname is the use of \emph{$\Sigma$-protocols} (pronounced ``sigma-protocols'') as underlying primitives. A transaction's output is protected by a statement. In order to spend the output, the statement needs to be proven true by attaching a proof. The combination of the statement and the proof forms a $\Sigma$-protocol. We refer the reader to \cite{Dam10} and \cite[Chapter 6]{HL10} for details of $\Sigma$-protocols. %Here we give a brief overview.
-\subsection{Sigma Protocols}
-For an introduction to $\Sigma$-protocols, we refer the reader to \cite{Dam10} and \cite[Chapter 6]{HL10}. Here we give a brief overview. The classic example a $\Sigma$-proof is the following 3-step identification protocol due to~\cite{Sch91}. $G$ is a cyclic multiplicative group of prime order $q$ such that computing discrete logarithms in $G$ is hard. Let $g$ be a generator of $G$. Alice has a secret $x \in \mathbb{Z}_q$, which she wants to prove knowledge of to some Bob who knows $y = g^x$.
+The classic example of a $\Sigma$-protocol is the following 3-step identification scheme due to~\cite{Sch91}. Let $G$ be a cyclic multiplicative group of prime order $q$ and $g$ a generator of $G$. Assume that computing discrete logarithms in $G$ is hard. Alice has a secret $x \in \mathbb{Z}_q$, which she wants to prove knowledge of to some Bob who knows $u = g^x$.
\begin{enumerate}
- \item \textbf{Commit:} Alice selects a random $r$, computes $u = g^r$ and sends $u$ to Bob.
+ \item \textbf{Commit:} Alice selects a random $r$, computes $t = g^r$ and sends $t$ to Bob.
\item \textbf{Challenge:} Bob selects a random $c\in\mathbb{Z}_q$ and sends $c$ to Alice.
- \item \textbf{Response:} Alice computes $z = r + cx$ and sends $z$ to Bob. Bob accepts iff $g^z = u\cdot y^c$.
+ \item \textbf{Response:} Alice computes $z = r + cx$ and sends $z$ to Bob. Bob accepts iff $g^z = t\cdot u^c$.
\end{enumerate}
-The above protocol is a proof of knowledge because Bob can extract $x$ if he can get Alice to respond twice for the same $r$ and different $c$. As an example, for $c = 1, 2$, Bob can obtain $r+x$ and $r+2x$, the difference of which gives $x$. This is also called (special) soundness. Above protocol is also (honest verifier) zero-knowledge because anyone can impersonate Alice if the challenge $c$ of Step 2 is known in advance simply by computing $z \stackrel{R}{\leftarrow} \mathbb{Z}_q$ and $u = g^z/y^c$.
+The above protocol is a proof of knowledge because Bob can extract $x$ if he can get Alice to respond twice for the same $r$ and different $c$. As an example, for $c = 1, 2$, Bob can obtain $r+x$ and $r+2x$, the difference of which gives $x$. This is also called (special) soundness. The above protocol is also (honest verifier) zero-knowledge because anyone can impersonate Alice if the challenge $c$ of Step 2 is known in advance, simply by picking random $z \in\mathbb{Z}_q$ and computing $t = g^z/u^c$. The statement ``I know the discrete log of $u$ to base $g$'' is called the {\em proposition}, which we denote by $\tau$.
-Any protocol that has the above 3-move structure (Alice $\stackrel{u}{\rightarrow}$ Bob, Alice $\stackrel{c}{\leftarrow}$ Bob, Alice $\stackrel{z}{\rightarrow}$ Bob), along with zero-knowledge and soundness property for some statement $s$ is called a $\Sigma$-protocol.
+Any protocol that has the above 3-move structure (Alice $\stackrel{t}{\rightarrow}$ Bob, Bob $\stackrel{c}{\rightarrow}$ Alice, Alice $\stackrel{z}{\rightarrow}$ Bob), along with zero-knowledge and soundness property is called a $\Sigma$-protocol.
-\subsection{Non-Interactive Sigma Protocols}
-For any $\Sigma$-protocol of some statement $s$ with messages $(u, c, z)$, we can apply the Fiat-Shamir transform to convert it into a non-interactive proof of $s$ by replacing the role of Bob in Step 2 by any hash function $H$ and computing $c$ = $H(u)$. The resulting protocol with messages $(u, H(u), z)$ can be performed by Alice alone. Intuitively, since $c$ depends deterministically on $u$, Bob cannot ``rewind'' Alice and get two different responses for the same $r$. Additionally, Alice cannot know $c$ in advance before deciding $u$ under the random oracle assumption.
+For any $\Sigma$-protocol with messages $(t, c, z)$, we can apply the Fiat-Shamir transform to convert it into a non-interactive one by replacing the role of Bob in Step 2 by any hash function $H$ and computing $c$ = $H(t)$. The resulting protocol with messages $(t, H(t), z)$ can be performed by Alice alone. Intuitively, since $c$ depends deterministically on $t$, Bob cannot ``rewind'' Alice and get two different responses for the same $r$. Additionally, Alice cannot know $c$ in advance before deciding $t$ if $H$ behaves like a random oracle.
-\subsubsection{Digital Signatures from Sigma Protocols}
-\label{digital-sig}
Conceptually, $\Sigma$-proofs \cite{Cra96} are generalizations~\cite{CL06} of digital signatures.
-In fact, Schnorr signature scheme~\cite{Sch91} (whose more recent version is popularly known as EdDSA \cite{BDLSY12,rfc8032}) is a special case of the above identification protocol with $c = H(u \Vert m)$, where $m$ is the message. The signature proves that the recipient knows the discrete logarithm of the public key (the proof is attached to a specific message, such as a particular transaction, and thus becomes a signature on the message; all $\Sigma$-proofs described here are attached to specific messages). $\Sigma$-protocols exist for proving a variety of properties and, importantly for \langname, elementary $\Sigma$-protocols can be combined into more sophisticated ones using the techniques of \cite{CDS94}.
+In fact, Schnorr signature scheme~\cite{Sch91} (whose more recent version is popularly known as EdDSA \cite{BDLSY12,rfc8032}) is a special case of the above identification protocol with $c = H(t \Vert m)$, where $m$ is the message. The signature proves that the recipient knows the discrete logarithm of the public key (the proof is attached to a specific message, such as a particular transaction, and thus becomes a signature on the message; all $\Sigma$-proofs described here are attached to specific messages). $\Sigma$-protocols exist for proving a variety of properties and, importantly for \langname, elementary $\Sigma$-protocols can be combined into more sophisticated ones using the techniques of \cite{CDS94}.
+
+\section{Overview of \langname}
+Although \langname uses $\Sigma$-protocols, it does so transparently. Developers are not required to understand the cryptography behind such protocols in order to use them. Here we describe \langname ``under the hood'' -- how it works and what primitives it uses.
+
+\subsection{Elementary $\Sigma$-Protocols}
+
+\langname provides as primitives two elementary $\Sigma$-protocols over an elliptic curve group of prime order, written here in multiplicative notation:
+\begin{enumerate}
+ \item A proof of knowledge of discrete logarithm with respect to a fixed group generator: given a group element $u$, the proof convinces a verifier that the prover knows $x$ such that $u=g^x$, where $g$ is the group generator (also known as base point), without revealing $x$. This is the Schnorr signature with public key $u$ and is essentially the protocol given in Section~\ref{intro:sigma}.
+ We call this primtive \texttt{proveDLog}$(u)$. Note that there is a default generator $g$ in the method.
+
+
+ \item A proof of equality of discrete logarithms (i.e., a proof of a Diffie-Hellman tuple): given group elements $g, h, u, v$, the prover, Alice convinces a verifier Bob that she knows $x$ such that $u={g}^x$ and $v={h}^x$. This is done by extending the protocol of Section~\ref{intro:sigma} as follows.
+ \begin{enumerate}
+ \item \textbf{Commit:} Alice picks $r \stackrel{R}{\leftarrow} \mathbb{Z}_q$, computes $(t_0, t_1) = ({g}^r, {h}^r)$ and sends $(t_0, t_1)$ to Bob.
+ \item \textbf{Challenge:} Bob picks $c \stackrel{R}{\leftarrow} \mathbb{Z}_q$ and sends $c$ to Alice.
+ \item \textbf{Response:} Alice computes $z = r + cx$ and sends $z$ to Bob, who accepts if ${g}^z = {t_0}\cdot {u}^c$ and $h^z=t_1\cdot v^c$. % for $b \in \{0,1\}$.
+ \end{enumerate}
+
+ We use the non-interactive variant of this protocol, where $c = H(t_0 \Vert t_1)$. We call this primitive \texttt{proveDHTuple}$(g, h, u, v)$.
+ %This can also be used in a DDH-easy group.
+
+\end{enumerate}
-\subsection{Combining Sigma Protocols}
-Any two $\Sigma$-protocols of statements $s_0, s_1$ with messages $(u_0, c_0, z_0), (u_1, c_1, z_1)$ respectively can be combined into a $\Sigma$-protocol of $s_0 \land s_1$ with messages $(u, c, z) = (u_0\Vert u_1,c_0\Vert c_1, c_0\Vert c_1)$. We call such a construction an $\andnode$ operator on the protocols. %Such a protocol proves both statements simultaneously.
+\subsection{Complex $\Sigma$-Protocols}
-More interestingly, as shown in \cite{orprotocol},the two protocols can also be used to construct a $\Sigma$-protocol for $s_0\lor s_1$, where Alice proves knowledge of the witness of one of the statements without revealing which one. Let $b\in \{0, 1\}$ be the bit such that Alice knows the witness for $s_b$ but not for $s_{1-b}$. Alice will run the correct protocol for $s_b$ and a simulation for $s_{1-b}$. First she generates a random challenge $c_{1-b}$. She then generates $(u_{1-b}, z_{1-b})$ by using the simulator on $c_{1-b}$. She also generates $u_b$ by following the protocol correctly. The pair $(u_0, u_1)$ is sent to Bob, who responds with a challenge $c$. Alice then computes $c_b = c\oplus c_{1-b}$. She computes $z_b$ using $(u_b, c_b)$. Her response to Bob is $((z_0, c_0), (z_1, c_1))$, who accepts if: (1) $c = c_0 \oplus c_1$ and (2) $(u_0, c_0, z_0), (u_1, c_1, z_1)$ are both accepting convesations for $s_0, s_1$ respectively. We call such a construction an $\ornode$ operator.
+Any two $\Sigma$-protocols of propositions $\tau_0, \tau_1$ with messages $(t_0, c_0, z_0), (t_1, c_1, z_1)$ respectively can be combined into a $\Sigma$-protocol of $\tau_0 \land \tau_1$ with messages $(t, c, z) = (t_0\Vert t_1,c_0\Vert c_1, c_0\Vert c_1)$. We call such a construction an $\andnode$ operator on the protocols.
+More interestingly, as shown in \cite{CDS94},the two protocols can also be used to construct a $\Sigma$-protocol for $\tau_0\lor \tau_1$, where Alice proves knowledge of the witness of one proposition, without revealing which. Let $b\in \{0, 1\}$ be the bit such that Alice knows the witness for $\tau_b$ but not for $\tau_{1-b}$. Alice will run the correct protocol for $\tau_b$ and a simulation for $\tau_{1-b}$. First she generates a random challenge $c_{1-b}$. She then generates $(t_{1-b}, z_{1-b})$ by using the simulator on $c_{1-b}$. She also generates $t_b$ by following the protocol correctly. The pair $(t_0, t_1)$ is sent to Bob, who responds with a challenge $c$. Alice then computes $c_b = c\oplus c_{1-b}$. She computes $z_b$ using $(t_b, c_b)$. Her response to Bob is $((z_0, c_0), (z_1, c_1))$, who accepts if: (1) $c = c_0 \oplus c_1$ and (2) $(t_0, c_0, z_0), (t_1, c_1, z_1)$ are both accepting convesations for $\tau_0, \tau_1$ respectively. We call such a construction an $\ornode$ operator.
Clearly, both the $\andnode$ and $\ornode$ operators also result in $\Sigma$-protocols that can be further combined or made non-interactive via the Fiat-Shamir transform.
-There is one more operator that we need called $\tnode$, which allows us to construct a $k$-out-of-$n$ $\Sigma$-protocol in the following sense~\cite{threshold}: given $n$ statements, Alice can prove knowledge of witnesses for at least $k$ statements without revealing which statements were true.
+There is one more operator that we need called $\tnode$, which allows us to construct a $k$-out-of-$n$ $\Sigma$-protocol~\cite{CDS94} as follows. Given $n$ propositions, Alice can prove knowledge of witnesses for at least $k$ propositions without revealing which.
-\snote{Describe Threshold briefly}
-\section{Primitives in ErgoScript}
+\langname gives the ability to build more sophisticated $\Sigma$-protocols using the connectives $\andnode$, $\ornode$, and $\tnode$.
+Crucially, the proof for an $\ornode$ and a $\tnode$ connective does not reveal which of the relevant values the prover knows. For example, in \langname a ring signature by public keys $u_1, \dots, u_n$ can be specified as an $\ornode$ of $\Sigma$-protocols for proving knowledge of discrete logarithms of $u_1, \dots, u_n$. The proof can be constructed with the knowledge of just one such discrete logarithm, and does not reveal which one was used in its construction.
-\langname provides as primitives two elementary $\Sigma$-protocols over an elliptic curve group of prime order, written here in multiplicative notation:
-\begin{enumerate}
-\item A proof of knowledge of discrete logarithm with respect to a fixed group generator: given a group element $y$, the proof convinces a verifier that the prover knows $x$ such that $y=g^x$, where $g$ is the group generator (also known as base point), without revealing $x$. This is the Schnorr signature with public key $y$, described in Section~\ref{digital-sig}.
-We call this primtive \texttt{ProveDLog}$(g, y)$.
-
-\snote{What is the exact input to the hash function? (what forms the message?)}
+\subsection{Other Features of \langname}
+
+%Rich context, enabling self-replication
+In addition to $\Sigma$-protocols, \langname allows for predicates over the state of the blockchain and the current transaction. These predicates can be combined, via Boolean connectives, with $\Sigma$-statements, and are used during transaction validation. The set of predicates is richer than in Bitcoin, but still lean in order to allow for efficient processing even by light clients. Like in Bitcoin, we allow the use of current height of the blockchain; unlike Bitcoin, we also allow the use of information contained in the spending transaction, such as inputs it is trying to spend and outputs it is trying to create. This feature enables self-replication and sophisticated (even Turing-complete) long-term script behaviour, as described in examples below.
+
+%\langname is statically typed (with compile-time type checking) and allows the usual operations, such as integer arithmetic.
+
+%\snote{This seems incomplete. In particular, we should describe all context variables and operations allowed, possibly using BNF or some grammar.}
+
+
+%\paragraph{Running time estimation and safety checks}
+%\lnote{someone should fill this in, because I know very little about it}
+%See Section \ref{sec:safety} for more details.
-\item A proof of equality of discrete logarithms (i.e., a proof of a Diffie-Hellman tuple): given group elements $g_0, y_0, g_1, y_1$, the prover, Alice convinces a verifier Bob that she knows $x$ such that $y_0={g_0}^x$ and $y_1={g_1}^x$, without revealing $x$. This is done as follows.
+\section{\langname Examples}
+
+We give some examples of \langname to illustrate its usage. The full code corresponding to the snippets below is available at the \langname code repository~\cite{langrepo}.
+Although \langname syntax looks similar to Scala, it is not Scala. To avoid confusion, \langname code is highlighted like \Hi{\texttt{this}}.
+
+\subsection{Short-lived Unconfirmed Transactions: Paying for Coffee}
+
+%We give another application of \langname contracts by constructing {\em timed payments}.
+Suppose you are paying for coffee using cryptocurrency. You make a payment but it is taking a long time for the transaction to confirm. You decide to pay using cash and leave. However, you are worried that your original payment will eventually confirm and then you will either lose it or have to ask for a refund. In bitcoin, you can try to double spend the transaction, which is not very convenient or sure, even if using {\em replace-by-fee}. \langname has a better solution using {\em timed-payments} so that if the transaction is not confirmed before a certain height, it is no longer valid. Timed-payments require that funds be stored in a {\em timed address}, which is created as follows.
+
+%Assume \texttt{bob} is the coffee shop public key and Alice is the customer paying for coffee.
+Alice encodes her public key \texttt{alice} inside environment \texttt{env} and creates a script \texttt{aliceScript}:
+\begin{alltt}
+ val aliceScript = compile(env, """ \Hi{\{alice && HEIGHT <= getVar[Int](1).get\}}""")
+\end{alltt}
+
+Alice's address is computed as: \texttt{val aliceAddress = Pay2SHAddress(aliceScript)}. Any funds deposited to \texttt{aliceAddress} can only be spent if the spending transaction satisfies following:
\begin{enumerate}
- \item \textbf{Commit:} Alice picks $r \stackrel{R}{\leftarrow} \mathbb{Z}_q$, computes $(u_0, u_1) = ({g_0}^r, {g_1}^r)$ and sends $(u_0, u_1)$ to Bob.
- \item \textbf{Challenge:} Bob picks $c \stackrel{R}{\leftarrow} \mathbb{Z}_q$ and sends $c$ to Alice.
- \item \textbf{Response:} Alice computes $z = r + cx$ and sends $z$ to Bob, who accepts if ${g_b}^z = {u_b}\cdot {y_b}^c$ for $b \in \{0,1\}$.
+ \item Context variable with id 1 of the UTXO to be spent must contain an integer, say $i$.
+ \item The height at mining should be less than or equal to $i$.
\end{enumerate}
-We use the non-interactive variant of this protocol, where the challenge is computed as $c = H(u_0 \Vert u_1)$. We call this primitive \texttt{ProveDLogEq}$(g_0, y_0, g_1, y_1)$.%This can also be used in a DDH-easy group.
+Observe that if the transaction is not mined before height $i$ then the transaction becomes invalid. When paying at a coffee shop, for example, Alice can set $i$ close to the height $h$ at the time of broadcast, for instance, $i = h + 10$.
+Alice can still send non-timed payments by making $i$ very large. Since the context variables are part of the message in constructing the zero-knowledge proof, a miner cannot change it (to make this transaction valid).
+
+\subsection{Preventing Theft using Reversible Addresses}
-\snote{What is the exact input to the hash function?}
+In this section, we use \langname to design useful primitives called {\em reversible addresses}, which have anti-theft features in the following sense:
+any funds sent to a reversible address can only be spent using a {\em reversible transaction}. That is, transactions spending funds from such an address must create outputs that allow funds to be reversed for a certain time. The idea was originally proposed in a Bitcoin forum~\cite{raddress} as a hardfork. In \langname, however, such addresses are easy to create.
+To motivate this feature, consider managing the hot-wallet of a mining pool or an exchange. Funds withdrawn by customers originate from this hot-wallet. Being a hot-wallet, its private is succeptible to compromise. One day you discover several unauthorized transactions from the hot-wallet, indicating a breach. You wish there was a way to reverse the transactions and cancel the withdraws but alas this is not the case. In general there is no way to recover the lost funds once the transaction is mined, even if the breach was discovered within minutes. The irreversibility of fund transfers, usually considered a feature, has now become a bug.
+
+We would like that in the event of such a compromise, we are able to save all funds stored in this wallet and move them to another address, provided that the breach is discovered within a specified time (such as 24 hours) of the first unauthorized withdraw.
+
+To achieve this, we require that all coins sent from the hot-wallet (both legitimate and by the attacker)
+have a 24 hour cooling-off period, during which the created UTXOs are ``locked'' and can only be spent by a trusted private key that is was selected {\em before} the compromise occurred. This trusted key must be different from the hot-wallet private key and should ideally be in cold storage.
+After 24 hours, these UTXOs become `normal' and can only be spent by the receiver.
+
+This is done by storing the hot-wallet funds in a special type of address denoted as {\em reversible}. Assume that \texttt{alice} is the public key of the hot-wallet and \texttt{carol} is the public key of the trusted party.\footnote{The trusted party must be decided at the time of address generation and cannot be changed later. To use a different trusted party, a new address has to be generated.} Let \texttt{blocksIn24h} be the estimated number of blocks in a 24 hour period. A reversible address is a P2SH\footnote{As in Bitcoin, a P2SH (Pay to Script Hash) address is created from the hash of a script encoding spending conditions for any UTXOs controlled by that address.} address whose script encodes the following conditions:
+\begin{enumerate}
+ \item I can only be spent by \texttt{alice}.
+ \item Any UTXO created by spending me must be protected by a script requring the following:
+ \begin{enumerate}
+ \item ``My register \texttt{R4} contains an arbitrary public key called \texttt{bob}.''
+ \item ``My register \texttt{R5} contains an arbitrary integer called \texttt{bobDeadline}.''
+ \item ``I can only be spent by \texttt{carol} if blockchain height $\leq$ \texttt{bobDeadline}.''
+ \item ``I can only be spent by \texttt{bob} if blockchain height $>$ \texttt{bobDeadline}.''
+ \end{enumerate}
+ \item Any UTXO created by spending me must satisfy the following:
+ \begin{enumerate}
+ \item Its register \texttt{R5} contains a number at least \texttt{blocksIn24h} more than the current height.
+ \end{enumerate}
\end{enumerate}
-\langname gives the ability to build more sophisticated $\Sigma$-protocols using the connectives $\andnode$, $\ornode$, and $\tnode$.
-Crucially, the proof for an $\ornode$ and a $\tnode$ connective does not reveal which of the relevant values the prover knows. For example, in \langname a ring signature by public keys $y_1, \dots, y_n$ can be specified as an $\ornode$ of $\Sigma$-protocols for proving knowledge of discrete logarithms of $y_1, \dots, y_n$. The proof can be constructed with the knowledge of just one such discrete logarithm, and does not reveal which one was used in its construction.
+Thus, all funds sent from such addresses have a temporary lock of 100 blocks. Note that the number 100 can be replaced by any desired value but it must be decided at the time of address generation. All hot-wallet funds must be stored in and sent from the above safe address only.
-%Our implementation of these protocols is in Scala \cite{scala} and Java \cite{java}. The implementation was informed by SCAPI \cite{scapi}, but does not use SCAPI code. \lnote{our code currently has subdirectories named ``scapi'' so it's hard to say we don't use it\dots} We use Bouncy Castle \cite{bouncycastle} for big integer and elliptic curve operations; the implementation of arithmetic in fields of characteristic 2 (for $\tnode$ connectives) is our own. \lnote{any other credits or background info?}
+Let \texttt{bob} be the public key of a customer who is withdrawing. The sender (\texttt{alice}) must ensure that register \texttt{R4} of the created UTXO contains \texttt{bob}. In the normal scenario, \texttt{bob} will be able to spend the UTXO after around 100 blocks (with the exact number depending on \texttt{bobDeadline}).
-\paragraph{Rich context, enabling self-replication}
-In addition to $\Sigma$-protocols, \langname allows for predicates over the state of the blockchain and the current transaction. These predicates can be combined, via Boolean connectives, with $\Sigma$-statements, and are used during transaction validation. The set of predicates is richer than in Bitcoin, but still lean in order to allow for efficient processing even by light clients. Like in Bitcoin, we allow the use of current height of the blockchain; unlike Bitcoin, we also allow the use of information contained in the spending transaction, such as inputs it is trying to spend and outputs it is trying to create. This feature enables self-replication and sophisticated (even Turing-complete) long-term script behaviour, as described in examples below.
+If an unauthorized transaction is detected from \texttt{alice}, an ``abort procedure'' is triggered via \texttt{carol}: all funds sent from \texttt{alice} currently in the locked state are suspect and need to diverted elsewhere. Additionally, UTXOs currently controlled by \texttt{alice} also need to be sent secure addresses.
-\langname is statically typed (with compile-time type checking) and allows the usual operations, such as integer arithmetic.
+Note that such reversible addresses are designed for storing large amount of funds needed for automated withdraws (such as an exchange hot-wallet). They are not designed for storing funds for personal use (such as paying for a coffee).
-\snote{This seems incomplete. In particular, we should describe all context variables and operations allowed, possibly using BNF or some grammar.}
+Concretely, such an address is created as follows. First hardcode \texttt{carol} inside \texttt{withdrawEnv}. Then create a script and compile it to get its binary version called \texttt{withdrawScript}:
+\begin{alltt}
+ val withdrawScript = compile(withdrawEnv, """ \Hi{\{}
+ \Hi{val bob = SELF.R4[SigmaProp].get // public key of customer withdrawing}
+ \Hi{val bobDeadline = SELF.R5[Int].get // max locking height}
+ \Hi{(bob && HEIGHT > bobDeadline) || (carol && HEIGHT <= bobDeadline) \}} """)
+\end{alltt}
+Compute \texttt{hash = Blake2b256(withdrawScript)}. Hardcode \texttt{alice}, \texttt{blocksIn24h} and \texttt{hash} inside \texttt{depositEnv} to create a compiled script called \texttt{depositScript}:
-\paragraph{Running time estimation and safety checks}
-\lnote{someone should fill this in, because I know very little about it}
-See Section \ref{sec:safety} for more details.
+\begin{alltt}
+ val depositScript = compile(depositEnv, """ \Hi{\{}
+ \Hi{alice && OUTPUTS.forall( \{(out:Box) =>}
+ \Hi{out.R5[Int].get >= HEIGHT + blocksIn24h && }
+ \Hi{blake2b256(out.propositionBytes) == hash\} ) \}} """)
+\end{alltt}
-\section{\langname Examples}
+Finally, the reversible address is computed as: \texttt{Pay2SHAddress(depositScript)}.
+
+\subsection{Cold-Wallet Contracts}
+
+Assume an address is protected by 2 private keys, corresponding to the public keys \texttt{alice} and \texttt{bob}. For security, we want the following conditions to hold:
+
+\begin{enumerate}
+ \item One key can spend at most 1\% or 100 Ergs (whichever is higher) in one day.
+ \item If both keys are spending then there are no restrictions.
+\end{enumerate}
+
+Let \texttt{blocksIn24h} be the number of blocks in 24 hours. Instead of hardwiring 1\% and 100 Ergs, we will use the variables \texttt{percent} and \texttt{minSpend} respectively. Set all these parameters in environment \texttt{env} along with the public keys \texttt{alice} and \texttt{bob} to get a compiled script:
+\begin{alltt}
+val script = compile(env, """ \Hi{\{}
+ \Hi{val r4 = SELF.R4[Int].get // block at which the period started}
+ \Hi{val min = SELF.R5[Long].get // min Balance needed in this period}
+ \Hi{val depth = HEIGHT - SELF.creationInfo._1 // number of confirmations}
-We give some examples of \langname to illustrate its usage.
-\subsection{Reversible Payments}
+ \Hi{val start = if (depth < r4) depth else r4 // set start to lower of two}
-Often lack of reversibility is considered a weak point of Bitcoin. We give a protocol that allows reversible payments in Ergo. The payments are reversible for a limited time, which we call the cooling off period. Let $pk_\textsf{A}$ be the public key of someone who can reverse payments. This public key can (and should) be different from the sender of the payment. Let $pk_{\textsf{B}}$ be the recipient of the payment. The sender will create the output with the following spending condition:
+ \Hi{val notExpired = HEIGHT - start <= blocksIn24h // expired if 24 hrs passed}
- $$(pk_\textsf{A}\land \texttt{depth <= coolingPeriod}) \lor (pk_\textsf{B}\land \texttt{depth > coolingPeriod})$$
+ \Hi{val newStart:Int = if (notExpired) start else HEIGHT}
+
+ \Hi{val toKeep = SELF.value - SELF.value * percent / 100}
+ \Hi{val newMin = if (notExpired) min else if (toKeep > minSpend) toKeep else 0L}
+
+ \Hi{val isValid = \{(out:Box) => if (newMin == 0) true else \{}
+ \Hi{out.propositionBytes == SELF.propositionBytes &&}
+ \Hi{out.value >= newMin && out.R4[Int].get >= newStart &&}
+ \Hi{out.R5[Long].get == newMin\}}
+ \Hi{\}}
+
+ \Hi{(alice && bob) || ((alice || bob) && OUTPUTS.exists(isValid)) \}} """)
+\end{alltt}
- \snote{This requires a `depth' instruction, which is current not present. Depth is simply current height - inclusion height.}
+Finally compute the deposit address of the wallet as \texttt{val address = Pay2SHAddress(script)}. Any funds deposited to this address can only be spent using the script given above. Spending from this address is done in periods of 24 hours or more (but never less) such that in any one period, the maximum spendable is fixed at the beginning. We do this requiring the spending transaction to have an output paying back to the address with value greater than the minumum (stored in \texttt{R5}). The start of the current period is stored in \texttt{R4}. Both registers are copied to the new output within the same period and get new values for the next period if the current period has expired.
+
+
+%\subsection{Advanced Cold-Wallet Contracts}
+%
+%We can extend the 2-party cold-wallet contract by adding a third party and the following conditions:
+%
+%\begin{enumerate}
+% \item One key can spend at most 1\% or 100 Ergs (whichever is higher) in one day.
+% \item For two keys the amount is 10\% or 1000 Ergs (whichever is higher).
+% \item If all three two keys are spending then there are no restrictions.
+%\end{enumerate}
+
\subsection{The XOR Game}
-We describe a simple game called ``Same or different'' or the XOR game. Alice and Bob both select a secret bit and submit a coin each. They then reveal their secret bits. If the bits are same, Alice gets both coins, else Bob gets both coins. The game requires at least 3 transactions.
+We describe a simple game called ``Same or Different'' or the XOR game. Alice and Bob both submit a coin each and select a bit independently. If the bits are same, Alice gets both coins, else Bob gets both coins. The game requires 3 transactions (steps).
\begin{enumerate}
- \item Alice commits to a secret bit $a$ as follows. She selects a random string $s$ and computes her commitment $h = H(s\|a)$ (i.e., hash after concatenating $s$ with a string representation of $a$).
+ \item Alice commits to a secret bit $a$ as follows. She selects a random bit-string $s$ and computes her commitment $k = H(s\|a)$ (i.e., hash after concatenating $s$ with $a$).
-% generates $a\in \mathbb{Z}_q$ and computes $h = H(a)$. We consider Alice's choice to be $\textsf{True}$ if $a < q/2$, and $\textsf{False}$ otherwise.
+ She creates an unspent box called the {\em half-game output} containing her coin and commitment $k$. This box is protected by a script called the {\em half-game script} given below. Alice waits for another player to join her game, who will do so by spending her half-game output and creating another box that satisfies the conditions given in the half-game script. Alice can also spend the half-game output herself before anyone joins, effectively aborting the game.
- She adds her commitment $h$ along with her coin protected by secret $x_0$ and public $y_0 = g^{x_0}$. This creates an unspent Box by Alice. She waits for some Bob to join the game by spending this output subject to certian conditions given by the {\em firstRoundScript} (see below). Alice can spend the box if no one joins within 100 blocks.
-% \item Alice generates $a\in \mathbb{Z}_q$ and computes $h = H(a)$. We consider Alice's choice to be $\textsf{True}$ if $a < q/2$, and $\textsf{False}$ otherwise. She adds her commitment $h$ along with her coin protected by secret $x_0$ and public $y_0 = g^{x_0}$. This creates an unspent Box by Alice. She waits for some Bob to join the game by spending this output subject to certian conditions (see below). Alice can spend the box if no one joins within 100 blocks.
- \item Bob generates bit $b\in \{0,1\}$ and adds it (in the clear) along with his coin protected by secret $x_1$ and public $y_1 = g^{x_1}$. He does this by spending Alice's box with one of his own and creating a new Box containing both coins along with Alice's commitment $h$ and his own bit $b$. Lets call this an intermediate box. Note that the transaction must satisfy the conditions given by {\em firstRoundScript}. In particular, one of the instructions in this script requires that the output must be protected by {\em secondRoundScript} (also given below).
- \item Alice opens $h$ by revealing $s$ somehow (either privately to Bob or publicly). If Alice fails to reveal $a$ within 100 blocks of creating the intermediate box then Bob automatically wins and gets to spend the intermediate box. %We consider Alice's choice to be $\textsf{True}$ if $a < q/2$, and $\textsf{False}$ otherwise.
- Anyone with knowledge of $s$ can send the price to the winner by inputting $a$ to {\em secondRoundScript}.
-
-% \item Alice opens $h$ by revealing $a$ somehow (either privately or via the blockchain). If Alice fails to reveal $a$ within 100 blocks of creating the intermediate box then Bob automatically wins and gets to spend the intermediate box. We consider Alice's choice to be $\textsf{True}$ if $a < q/2$, and $\textsf{False}$ otherwise. The winner claims the prize by inputting $a$ to the script.
-\end{enumerate}
+ \item Bob decides to join Alice's game. He generates a random bit $b$ and spends Alice's half-game output alongwith one of his own to create a new box called the {\em full-game output}. This new box holds two coins and contains $b$ (in the clear) alongwith Bob's public key in the registers.
+ Note that the full-game output must satisfy the conditions given by the half-game script. In particular, one of the conditions requires that the full-game output must be protected by the {\em full-game script} (given below).
+ \item Alice opens $k$ by revealing $s, a$. If $a = b$ then Alice wins else Bob wins. The winner spends the full-game output using his/her private key and providing $s$ and $a$ to the full-game script.
- %INPUTS.size == 2 && INPUTS(0).value == INPUTS(1).value && INPUTS(0).propositionBytes == pkA.propBytes,
-
-The script {\em secondRoundScript} is given by the following conditions:
-\begin{enumerate}
- \item The first free register (R4) is assumed to be Bob's input $b$ (boolean).
- \item The second free register (R5) contains Bob's public key.
- \item If the block height is more than 100 then Bob's public key can spend.
- \item The first typed variable (obtainable via \texttt{getVar(0)}) must be Alice's secret $s$.
- \item The second typed variable (obtainable via \texttt{getVar(1)}) must be Alice's choice $a$ (boolean).
- \item Commitment must be correctly opened (i.e., $H(s\|a)$ must equal $h$).
- \item If $(a == b)$ then Alice can spend else Bob can spend.
+ If Alice fails to open $k$ within a specified deadline (say 30 blocks after the full-game output is created) then Bob automatically wins.
\end{enumerate}
-% More security conditions:
-% The spender must not give a high fee. We can also say that the winner must be spender. This is more complex but will be a good example.
-%
-This is encoded in out Scala program as follows:
-
-\begin{verbatim}
-{
-val secondRoundScript = Compile( // Can this be implemented?
-"""val hash = INPUTS(0).R4 // Alice's original commitment
-val bobsBit = INPUTS(0).R5 // Boolean, Bob's public bit
-val aliceBytes = getVar[Array[Byte]](0) // Alice's open commitment, a 256 bit integer
-val correctlyOpened = sha256(aliceBytes) == hash
-val equals = bobsBit == aliceBytes(0) > 0 // use the LSB of aliceBytes
-(correctlyOpened &&
-(
-(pkA && equals) ||
-(pkB && !equals)
-)
-) ||
-(pkB && txHeight > 100)"""
-)
-
-val pkA = // Alice's public key. Can we extract it from INPUT(0).propositionBytes ?
-val pkB = // Bob's public key. Can we extract it from INPUT(1).propositionBytes ?
-val b = getVar[Boolean](0) // Bob's public bit
-
-(pkA && txHeight > 100) || {
-INPUTS.size == 2 &&
-INPUTS(0).value == INPUTS(1).value &&
-INPUTS(0) == SELF &&
-OUTPUTS.size == 1 &&
-OUTPUTS(0).R4 == INPUTS(0).R4 && // Copy Alice's commitment hash to output
-OUTPUTS(0).R5 == b
-OUTPUTS(0).propositionBytes == outProp
-}
-\end{verbatim}
+The full-game script encodes the following conditions: The registers \texttt{R4}, \texttt{R5} and \texttt{R6} are expected to store Bob's bit $b$, Bob's public key (stored as a \texttt{ProveDLog} proposition) and the deadline for Bob's automatic win respectively. The context variables with id 0 and 1 (provided at the time of spending the full-game box) contain $s$ and $a$ required to open Alice's commitnent $k$, which is hardwired alongwith Alice's public key \texttt{alice} via the environment \texttt{env}.
+%The remaining part encodes the spending conditon of full-game box.
+Alice compiles the full-game script to get a binary representation of its \langname code:
+\begin{alltt}
+val fullGameScript = compile(env, """ \Hi{\{}
+ \Hi{val s = getVar[Coll[Byte]](0).get // bit string s}
+ \Hi{val a = getVar[Byte](1).get // bit a (represented as a byte)}
+ \Hi{val b = SELF.R4[Byte].get // bit b (represented as a byte)}
+ \Hi{val bob = SELF.R5[SigmaProp].get // Bob's public key}
+ \Hi{val bobDeadline = SELF.R6[Int].get}
+
+ \Hi{(bob && HEIGHT > bobDeadline) || }
+ \Hi{(blake2b256(s ++ Coll(a)) == k && (alice && a == b || bob && a != b)) \}} """)
+\end{alltt}
-Alice creates her coin with the following spending condition in the output:
+Then a hash of the above compiled script is computed:
\begin{verbatim}
- {
- val outProp = Compile( // Can this be implemented?
- """val hash = INPUTS(0).R4 // Alice's original commitment
- val bobsBit = INPUTS(0).R5 // Boolean, Bob's public bit
- val aliceBytes = getVar[Array[Byte]](0) // Alice's open commitment, a 256 bit integer
- val correctlyOpened = sha256(aliceBytes) == hash
- val equals = bobsBit == aliceBytes(0) > 0 // use the LSB of aliceBytes
- (correctlyOpened &&
- (
- (pkA && equals) ||
- (pkB && !equals)
- )
- ) ||
- (pkB && txHeight > 100)"""
- )
-
- val pkA = // Alice's public key. Can we extract it from INPUT(0).propositionBytes ?
- val pkB = // Bob's public key. Can we extract it from INPUT(1).propositionBytes ?
- val b = getVar[Boolean](0) // Bob's public bit
-
- (pkA && txHeight > 100) || {
- INPUTS.size == 2 &&
- INPUTS(0).value == INPUTS(1).value &&
- INPUTS(0) == SELF &&
- OUTPUTS.size == 1 &&
- OUTPUTS(0).R4 == INPUTS(0).R4 && // Copy Alice's commitment hash to output
- OUTPUTS(0).R5 == b
- OUTPUTS(0).propositionBytes == outProp
- }
+ val scriptHash = Blake2b256(fullGameScript)
\end{verbatim}
-%\begin{verbatim}
- %INPUTS.size == 2 &&
- %INPUTS(0).value == INPUTS(1).value &&
- %INPUTS(0) == SELF &&
- %OUTPUTS.size == 1 &&
- %OUTPUTS(0).R3 == INPUTS(0).R3 &&
- %OUTPUTS(0).R4 == INPUTS(1).R3 &&
- %OUTPUTS(0).propositionBytes = COMPILE{ // hypothetical function
- %"INPUTS.size == 1 &&
- %sha256(INPUTS(0).R5) == INPUTS(0).R3 &&
- %sha256(INPUTS(0).R6) == INPUTS(1).R4 &&"
- %
- %}
- %{
- %{
- %pkA &&
- %SELF.R3 < q/2 == SELF.R4 < q/2
- %} ||
- %{
- %pkB &&
- %SELF.R3 < q/2 != SELF.R4 < q/2
- %}
- %}
-%\end{verbatim}
-%
-
-%
-%Let us try to describe this in Ergo. Let $g, h$ be two public parameters
-%Public parameters: Let g, h be two public generators such that DLog h to base g is unknown (that is, g and h are two random elements of group).
-%We commitment to a secret bit is as follows:
-%Choose a large secret x. If committing to 0, compute c = g^x else compute c = h^x.
-%In summary to commit to bit b, compute c = g^((1-b)x).h^(bx)
-%The commitment is c. In order to open c, we simply reveal x. The scheme is perfectly hiding. Note that commitment must open to either 0 or 1 else its an invalid commitment and coin is unusable.
-%Alice first creates input with 1 coin and commitment C_A and conditions as follows:
-%{ // normal protocol
-%Let Bob (an arbitrary key) input 1 coin and commitment C_B in future before height 100
- %Let Alice open commitment C_A to bit a
- %Let Bob open commitment C_B to bit b
- %if (a == b) Alice can spend both coins else Bob can spend both coins
-%}
-%// error protocol
-%If Alice does not open within 10 blocks when she has to then Bob gets both coins
-%If Alice’s commitment opens to something other than 0 or 1 then Bob gets both coins
-%If Bob does not open within 10 blocks when he has to then Alice gets both coins
-%If Bob’s commitment opens to something other than 0 or 1 then Alice gets both coins
-%If no Bob joins before height 100 then Alice can withdraw (spend) her coin
-%
-%So it’s like a “game pool”, with two different types of inputs:
-%Input type 1: a party can put their coins and wait for other party to join.
-%Input type 2: If coins already in pool, the party can join existing game
-%
+Finally, Alice sets \texttt{scriptHash} as an environment variable for the compiler and creates her half-game output with the following spending condition:
+\begin{alltt}
+ \Hi{val out = OUTPUTS(0)}
+ \Hi{val b = out.R4[Byte].get}
+ \Hi{val bobDeadline = out.R6[Int].get}
+ \Hi{val validBobInput = b == 0 || b == 1}
-\subsection{The Mixing Protocol}
+ \Hi{alice || \{ validBobInput && blake2b256(out.propositionBytes) == scriptHash &&}
+ \Hi{OUTPUTS.size == 1 && bobDeadline >= HEIGHT+30 && out.value >= SELF.value * 2 \}}
+\end{alltt}
-We now describe a mixing protocol for Ergo called \mixname, which is motivated from ZeroCash (ZC).
-The name \mixname is a portmanteau of {\em Two} and {\em Mix}.
-\mixname essentially mixes two coins and so provides ``50\% anonymity'' in one mix. A coin can be successively mixed to increase the anonymity above any desired level (say 99.99999\%). We do a formal analysis of the protocol later.
+The above script requires that the transaction spending the half-game box must either be signed by Alice or generate exactly one output box with the following properties:
-\mixname is based on the UTXO model. Like ZC, \mixname uses pooled coins for mixing. Unlike ZC, however, \mixname has two UTXO pools for providing anonymity: a {\em half-mixed} pool ($H$) and a {\em fully-mixed} pool ($F$). The $F$ pool contains coins that are anonymized. There is also the standard pool ($S$) that contains UTXOs for ordinary spending without any anonymity. The goal of the protocol is to move coins from $O$ to $F$ (possibly via $H$) and after sufficient mixing, back to $O$. The protocol contains the following transactions.
\begin{enumerate}
- \item \textbf{Half-mix:} This takes one coin from either $O$ or $F$ and puts it in $H$.
- \item \textbf{Full-mix:} This takes one coin from $H$, the other from either $O$ or $F$ and puts both coins in $F$ such that it is impossible (for outsiders) to distinguish them.
- \item \textbf{Spend:} This takes one coin from $F$ and either puts it in $O$.% or $H$.
-
-\end{enumerate}
-To participate in the mix, a user can may either add an unspent coin to the pool (which can be an output of a previous mix operation), or below operations anyone can add coins to this unspent pool.
-tained. Anyone can deposit ordinary currency, say Ethers
-(ETH) to the 2C pool and later withdraw from it at a 1:1
-exchange rate. The key difference is that the size of the 2C
-pool depends on
-Twix attempts to fix some of its drawbacks discussed below. Like
-We describe Two-Coin, a cryptocurrency for enhancing pri-
-vacy of trancactions. Two-Coin (2C), like Zero-Coin (ZC)
-uses zero-knowledge proofs but is more storage efficient than
-ZC. Similar to ZC, in 2C a pool of anonymous coins is main-
-tained. Anyone can deposit ordinary currency, say Ethers
-(ETH) to the 2C pool and later withdraw from it at a 1:1
-exchange rate. The key difference is that the size of the 2C
-pool depends on the number of unspent coins rather than
-number of deposited coins (as in ZC). This greatly enhances
-the scalability, while keeping anonymity at similar levels. In
-2C, each unspent coin can be spent twice, hence the name
-(a withdraw is treated similar to a spend). Once a coin has
-been spent twice, it is removed from the pool. Thus, un-
-like ZC, a 2C pool does not have a monotonously increasing
-set. In practice, we can replace zero-knowledge proofs with
-zk-SNARKS at the cost of lower security.
-\begin{enumerate}
- \item ZeroCash requires a pool of mixed coins, whose size increases monotonously. Once a coin is added to the pool, it
-
+ \item Its value must be at least twice that of the half-game box.
+ \item Register \texttt{R4} must contain a byte that is either 0 or 1. This encodes Bob's choice $b$.
+ \item Register \texttt{R6} must contain an integer that is at least 30 more than the height at which the box is generated. This will correspond to the height at which Bob automatically wins.
+ \item It must be protected by a script whose hash equals \texttt{scriptHash}.
\end{enumerate}
+
+The game ensure security and fairness as follows. Since Alice's choice is hidden from Bob when he creates the full-game output, he does not have any advantage in selecting $b$. Secondly, Alice is sure to lose if she commits to a value other than 0 or 1. Finally, if Alice refuses to open her commitment, then Bob is sure to win after about 30 blocks.
+\subsection{Rock-Paper-Scissors Game}
+
+Compared to Rock-Paper-Scissors (RPS), the XOR game is simpler (and efficient) because there is no draw condition and for this reason should be prefered in practice. However, it is useful to consider the RPS game as an example of more complex protocols.
+
+Let $a, b\in \mathbb{Z}_3$ be the choices of Alice and Bob, with the understanding that 0, 1 and 2 represent rock, paper and scissors respectively. If $a = b$ then the game is a draw, otherwise Alice wins if $a-b \in \{1, -2\}$ else Bob wins. The game is similar to XOR, except that Bob must now generate two outputs. In the draw case each player gets one output, otherwise the winner gets both.
+As before, Alice's commitment $k=H(a||s)$ and public key \texttt{alice} is given via \texttt{env} to the compiler :
+
+\begin{alltt}
+val fullGameScript = compile(env, """ \Hi{\{}
+ \Hi{val s = getVar[Coll[Byte]](0).get // Alice's secret byte string s}
+ \Hi{val a = getVar[Byte](1).get // Alice's secret choice a (represented as a byte)}
+ \Hi{val b = SELF.R4[Byte].get // Bob's public choice b (represented as a byte)}
+ \Hi{val bob = SELF.R5[SigmaProp].get}
+ \Hi{val bobDeadline = SELF.R6[Int].get // after this, it becomes Bob's coin}
+ \Hi{val drawPubKey = SELF.R7[SigmaProp].get}
+ \Hi{val valid_a = (a == 0 || a == 1 || a == 2) && blake2b256(s ++ Coll(a)) == k}
+
+ \Hi{(bob && HEIGHT > bobDeadline) || \{ valid_a &&}
+ \Hi{if (a == b) drawPubKey}
+ \Hi{else \{ if ((a - b) == 1 || (a - b) == -2) alice else bob \}\}\}} """)
+\end{alltt}
-The idea of Twix is quite general and can be implemented in other platforms. In Ergo, however, the protocol can be used without any additional platform support.
+The code is derived from the XOR game by adding \texttt{drawPubKey}. A hash of the above script is computed as \texttt{val scriptHash = Blake2b256(fullGameScript)} for use in the half-game script:
+\begin{alltt}
+\Hi{OUTPUTS.forall\{(out:Box) =>}
+ \Hi{val b = out.R4[Byte].get}
+ \Hi{val bobDeadline = out.R6[Int].get}
-There is a pool of unmixed coins where anyone can add theirs.
+ \Hi{bobDeadline >= HEIGHT+30 && out.value >= SELF.value &&}
+ \Hi{(b == 0 || b == 1 || b == 2) && blake2b256(out.propositionBytes) == scriptHash}
+\Hi{\} && OUTPUTS.size == 2 && OUTPUTS(0).R7[SigmaProp].get == alice }
+\end{alltt}
-The protocol is as follows:
-%The game requires at least 3 transactions.
+% // Bob needs to ensure that out.R5 contains bobPubKey
+
+The above code ensures that \texttt{R7} of the first output contains Alice's public key (for the draw scenario). Bob should ensure that \texttt{R7} of the second output contains his public key. Additionally, he must ensure that \texttt{R5} of both outputs contains his public key.
+
+\subsection{A Mixing Protocol}
+
+We describe a mixing protocol called \mixname, whose security depends on the hardness of the {\em Decision Diffie-Hellman} (DDH) Problem in $G$. The protocol is motivated from ZeroCoin~\cite{zerocoin} (ZC) to overcomes some of its drawbacks (discussed later).
+%The name \mixname is a portmanteau of {\em Two} and {\em Mix}.
+\mixname essentially mixes two coins and so provides ``50\% anonymity'' in one round. A coin can be successively mixed to increase the anonymity to any desired level (say 99.99999\%).
+
+\mixname has a pool, called the {\em Half-Mix} pool (H-pool), which contains coins ready for mixing.
+To mix an arbitrary coin (which could itself be the output of a previous mix), any one of the two actions can be performed:
+\begin{enumerate}
+ \item Pick another coin from the H-pool (if it is non-empty), ``mix'' them by converting them to two indistinguisble coins, each spendable by their respective owner. We call this the {\em mix} Step.
+ \item Add the coin to the H-pool and wait for someone to mix them. This is the {\em pool} Step.
+\end{enumerate}
+
+Without loss of generality, Alice will pool and Bob will mix. In practice, each coin must go through multiple stages of mix, with the choice of going via pool randomly decided after each mix.
\begin{enumerate}
- \item \textbf{Pool:} To add a coin to the pool, Alice picks random generator $g_\textsf{A}\in G$ and $x_\textsf{A}\in \mathbb{Z}_q$. Let $y_\textsf{A} = {g_\textsf{A}}^{x_\textsf{A}}$. Alice creates an output box $A$ containing $(g_\textsf{A}, y_\textsf{A})$ and protected by the script given below. She waits for Bob to join by spending $A$ subject to the conditions given in the script. Alice can spend $A$ if no one joins within 100 blocks.
- \item \textbf{Mix:} Bob randomly picks one unspent box from the pool, for instance, $A$. Bob then picks a random secret bit $b$ and spends $A$ with another of his own unspent box $B$. The spending transaction creates two new unspent boxes $O_0, O_1$ of equal values such that $C_b$ is spendable only by Alice and $C_{1-b}$ is spendable only by Bob. This is done as follows:
+ \item \textbf{Pool:} To add a coin to the pool, Alice picks random generator $g\in G$ and $x\in \mathbb{Z}_q$. Let $u = g^{x}$. Alice creates an output box $A$ containing $(g, u)$ and protected by the script given below. She waits for Bob to join by spending $A$ subject to the conditions given in the script.
+ Alice's spending condition for $A$ is that any transaction spending $A$ should be as follows:
\begin{enumerate}
- %\item Bob selects a secret bit $b$. Then output $O_b$ is spendable by Bob alone, while $O_{1-b}$ is spendable by Alice alone. %Lets call these the intermediate boxes.
-
- \item Bob picks secret $x_\textsf{B}\in \mathbb{Z}_q$. Let $g_\textsf{B} = {g_\textsf{A}}^{x_\textsf{B}}$ and $y_\textsf{B} = {y_\textsf{A}}^{x_\textsf{B}} = {g_\textsf{A}}^{x_\textsf{A}x_\textsf{B}}~(={g_\textsf{B}}^{x_\textsf{A}})$. %Let $c_b = g^y$ and $c_{1-b} = g^{xy}$. Bob
- The box $O_b$ contains the tuple $(g_\textsf{A}, y_\textsf{A}, g_\textsf{B}, y_\textsf{B})$ and $O_{1-b}$ contains $(g_\textsf{A}, y_\textsf{A}, y_\textsf{B}, g_\textsf{B})$. Assuming that the {\em Decision Diffie-Hellman Problem} in $G$ is hard, the distributions $(g_\textsf{A}, {g_\textsf{A}}^{x_\textsf{A}}, {g_\textsf{A}}^{x_\textsf{B}}, {g_\textsf{A}}^{x_\textsf{A}x_\textsf{B}})$ and $(g_\textsf{A}, {g_\textsf{A}}^{x_\textsf{A}}, {g_\textsf{A}}^{x_\textsf{A}x_\textsf{B}}, {g_\textsf{A}}^{x_\textsf{B}})$ are computationally indistinguishable. In other words, without knowledge of $x_\textsf{A}$ or $x_\textsf{B}$, one cannot guess $b$ with probability better than $1/2$.
+ \item It has two inputs of equal value, one of which is $A$. %The value of the second input should be the same as in $A$.
+ \item It has two outputs $(O_0, O_1)$ with data tuples $(g, c, u, d)$ and $(g, d, u, c)$ respectively. That is, the data of each output contains a 4-tuple where the first and third elements are $g$ and $u$ respectively and the second and fourth elements are swapped.
+ \item The spender of $A$ must satisfy $\texttt{proveDHTuple}(g, u, c, d)\lor \texttt{proveDHTuple}(g, u, d, c)$.
+ \item The outputs should be protected by the script $\tau_\textsf{A} \lor \tau_\textsf{B}$ given in the Mix step below.
+ \end{enumerate}
+
+
+ \item \textbf{Mix:} Bob randomly picks one unspent box from the pool, for instance, $A$. Bob then picks a random secret bit $b \in \mathbb{Z}_2$ and spends $A$ with another of his own unspent box $B$. The spending transaction creates two new unspent boxes $O_0, O_1$ of equal values (and indistinguishable) such that $O_b$ is spendable only by Alice and $O_{1-b}$ is spendable only by Bob. This is done as follows:
+
+ \begin{enumerate}
+ \item Bob picks secret $y\in \mathbb{Z}_q$. Let $h = {g}^{y}$ and $v = {u}^{y}$. %Let $c_b = g^y$ and $c_{1-b} = g^{xy}$. Bob
+ The box $O_b$ contains data $(g, h, u, v)$ and $O_{1-b}$ contains $(g, v, u, h)$. If the DDH problem in $G$ is hard, the distributions $(g, {g}^{y}, {g}^{x}, {g}^{xy})$ and
+ $(g, {g}^{xy}, {g}^{x}, {g}^{y})$ are computationally indistinguishable. In other words, without knowledge of $x$ or $y$, one cannot guess $b$ with probability better than $1/2$.
\item Let
- $s_\textsf{A}$ be the statement: ``For given $(g_\textsf{A}, y_\textsf{A}, g_\textsf{B}, y_\textsf{B})$
- prove knowledge of $x_\textsf{A}$ such that $y_\textsf{A} = {g_\textsf{A}}^{x_\textsf{A}}$ and ${y_\textsf{B}} = {g_\textsf{B}}^{x_\textsf{A}}$.'' This is encoded as $$s_\textsf{A} = (g_\textsf{A}, y_\textsf{A}, g_\textsf{B}, y_\textsf{B}) \mapsto \texttt{ProveDLogEq}(g_\textsf{A}, y_\textsf{A}, g_\textsf{B}, y_\textsf{B}).$$
+ $\tau_\textsf{A}$ be the proposition: ``Parse data as $(g, h, u, v)$ and
+ prove knowledge of $x$ such that $u = {g}^{x}$ and ${v} = {h}^{x}$.'' This is encoded as $\texttt{proveDHTuple}(g, h, u, v)$.
- \item Let $s_{\textsf{B}}$ be the statement: ``For given $(g_\textsf{A}, y_\textsf{A}, y_\textsf{B}, g_\textsf{B})$
- prove knowledge of $x_\textsf{B}$ such that $g_\textsf{B} = {g_\textsf{A}}^{x_\textsf{B}}$ and $y_\textsf{B} = {y_\textsf{A}}^{x_\textsf{B}}$.'' This is encoded as $$s_\textsf{B} = (g_\textsf{A}, y_\textsf{A}, y_\textsf{B}, g_\textsf{B}) \mapsto \texttt{ProveDLogEq}(g_\textsf{A}, g_\textsf{B}, y_\textsf{A}, y_\textsf{B}).$$
- Observe that the order of $g_\textsf{B}, y_\textsf{B}$ is reversed from $s_\textsf{A}$.
- \item Each box is protected by the statement $s_\textsf{A} \lor s_\textsf{B}$.
+ \item Let $\tau_{\textsf{B}}$ be the proposition: ``Parse data as $(g, v, u, h)$ and
+ prove knowledge of $y$ such that $h = {g}^{y}$.''
+ % Observe that $h, v$ have been swapped from $\tau_\textsf{A}$.
+ This is encoded as $\texttt{proveDlog}(h)$, keeping $g$ as the default generator.
+
+ \item Each box is protected by the proposition $\tau_\textsf{A} \lor \tau_\textsf{B}$.
\end{enumerate}
- Alice's spending condition for $A$ is that the transaction should be as follows:
-
- \begin{enumerate}
- \item It should contain two inputs, the first of which is $A$. The value of the second input should be the same as in $A$.
- \item It should contain exactly two outputs $(O_0, O_1)$ of the form $(g_\textsf{A}, y_\textsf{A}, c_0, c_1)$ and $(g_\textsf{A}, y_\textsf{A}, c_1, c_0)$ respectively;
- \item It The spender must satisfy $\texttt{ProveDLogEq}(g_\textsf{A}, c_0, y_\textsf{A}, c_1)\lor \texttt{ProveDLogEq}(g_\textsf{A}, c_1, y_\textsf{A}, c_0)$.
- \item The outputs should be protected by the script
- %Additionally, the spending condition for $O_0, O_1$ is $s_\textsf{Alice}(g_A, y_A, c_0, c_1) \lor s_\textsf{Bob}(g_A, y_A, c_0, c_1)$.
-\end{enumerate}
- \item \textbf{Spend:} Both Alice and Bob later spent their respective boxes using their secrets.
+ \item \textbf{Spend:} Both Alice and Bob later spent their respective boxes using their secrets. Bob already knows which coin belongs to him. For each output, Alice will parse the data as $(g, h, u, v)$ and select the one with $v = h^x$.
\end{enumerate}
+\textbf{Security:} We claim the security of the protocol based on the following reasoning. Before spending, the outputs are indistinguisble under the DDH assumption. Since they are both spent using a $\Sigma$-OR-proof, their indistinguishability is preserved. Also, Alice can spend exactly one output, since the other one does not contain a valid DDH tuple. Similarly, Bob can spend exactly one output, since he does not know the discrete log of $g^{xy}$ to base $g$. The output that Bob can spend is exactly the one that Alice cannot. Finally, note that Bob cannot generate invalid outputs since he must prove that they are of the correct form.
+For this to work, each output must be of a fixed value and the fee should be zero. We discuss below how to handle non-zero fee.
+
+\textbf{Comparing with ZeroCash:} Both \mixname and ZeroCash (ZC) are based on zero-knowledge proofs and use an anonymizing pool. The difference is that the size of our pool depends on the number of unspent outputs, while that of ZC depends on the number of deposits, which is monotonously increasing. Additionally, the size of proofs in \mixname is constant, unlike ZC, where the proof size is logarithmic to the pool size. Finally, unlike ZC, the proofs in \mixname do not rely on expensive NP-reductions and are instead based on a number theoretic problem. This makes \mixname far more scalable than ZC.
+
+\textbf{\langname Code:} First define two variables representing $g$ and $g^x$. Lets call them \texttt{g} and \texttt{g\_x} respectively. Then pass them to the compiler via an environment variable, say \texttt{env}:
+
+\begin{alltt}
+val fullMixScript = compile(env, """ \Hi{\{}
+ \Hi{val e = SELF.R4[GroupElement].get}
+ \Hi{val f = SELF.R5[GroupElement].get}
+ \Hi{proveDlog(f) || proveDHTuple(g, e, g_x, f) \}} """)
+\end{alltt}
+
+Compute a hash of the above compiled script: \texttt{val scriptHash = Blake2b256(fullMixScript)}
+Alice's Half-Mix box is protected by the following \langname code:
+
+\begin{alltt}
+\Hi{val c = OUTPUTS(0).R4[GroupElement].get}
+\Hi{val d = OUTPUTS(0).R5[GroupElement].get}
+
+\Hi{OUTPUTS(0).value == SELF.value && OUTPUTS(1).value == SELF.value &&}
+\Hi{blake2b256(OUTPUTS(0).propositionBytes) == scriptHash &&}
+\Hi{blake2b256(OUTPUTS(1).propositionBytes) == scriptHash &&}
+\Hi{OUTPUTS(1).R4[GroupElement].get == d && OUTPUTS(1).R5[GroupElement].get == c &&}
+\Hi{OUTPUTS.size == 2 && \{proveDHTuple(g, g_x, c, d) || proveDHTuple(g, g_x, d, c)\}}
+\end{alltt}
+
+\textbf{Handling Fee:} TBD
+%\snote{To do: describe fee handling.}
+
+\bibliographystyle{unsrt}
+\bibliography{sigmastate_protocols}
\end{document}
\ No newline at end of file
diff --git a/docs/wpaper/sigma.tex b/docs/wpaper/sigma.tex
index 6ca9ad5e54..4ae0b932fb 100644
--- a/docs/wpaper/sigma.tex
+++ b/docs/wpaper/sigma.tex
@@ -161,7 +161,7 @@ \subsection{$\Sigma$-Statements}
For syntactic convenience, multiple keys can be placed into a collection, and \texttt{anyOf} operator can be used instead of \texttt{||}, as follows:
\begin{verbatim}
- anyOf (Col (pkA, pkB, pkC))
+ anyOf (Coll (pkA, pkB, pkC))
\end{verbatim}
A conjunction is also possible: the script
@@ -184,7 +184,7 @@ \subsection{$\Sigma$-Statements}
For example, here is a script stating that the box can be spent by any 3 out of the following 6 possibilities: Alice, Bob, Charlie, David and Edie, Fran and George, Helen and Irene:
\begin{verbatim}
- atLeast(3, Col (pkA, pkB, pkC, pkD && pkE, pkF && pkG, pkH && pkI))
+ atLeast(3, Coll (pkA, pkB, pkC, pkD && pkE, pkF && pkG, pkH && pkI))
\end{verbatim}
The same result could be achieved by writing an \texttt{anyOf} of all possible 3-out-of-6 (twenty) combinations.
@@ -268,7 +268,7 @@ \subsection{Context Extension and Hashing}
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,
\begin{verbatim}
- pkA && blake2b256(getVar[Col[Byte]](1).get) == hashOutput
+ pkA && blake2b256(getVar[Coll[Byte]](1).get) == hashOutput
\end{verbatim}
says that spending can be done only using the signature of Alice, and only if the preimage of \texttt{hashOutput} is written in the context. Specifically, the script requires that the context extension should contain a variable (with id \texttt{1}), which is a collection of bytes that hashes to the value of \texttt{hashOutput} (the value of \texttt{hashOutput}, like \texttt{pkA}, is defined in the environment and is hardwired into the script at compile time). Note that although the script requires both the secret key corresponding to \texttt{pkA} and the hash preimage corresponding to \texttt{hashOutput}, there is the stark difference between how these two values are used: the secret key is not revealed in the proof (by the zero-knowledge property of $\Sigma$-proofs), while the hash preimage is explicitly written into the context extension and can be seen by anyone once the transaction takes place.
@@ -278,28 +278,28 @@ \subsection{Context Extension and Hashing}
Alice creates a random secret \texttt{x} of 256 bits (32 bytes), hashes it to obtain the value \texttt{hx}, and creates a transaction in Bob's blockchain with the output box protected by the following script:
\begin{verbatim}
- anyOf( Col(
+ anyOf( Coll(
HEIGHT > deadlineBob && pkA,
- pkB && blake2b256(getVar[Col[Byte]](1).get) == hx
+ pkB && blake2b256(getVar[Coll[Byte]](1).get) == hx
))
\end{verbatim}
Bob can receive the value of this box only upon presentation of a hash preimage of \texttt{hx}. Alice can reclaim it after \texttt{deadlineBob}.
From this output, Bob learns \texttt{hx}. He creates a transaction in Alice's blockchain with an output box protected by the following script:
\begin{verbatim}
- anyOf( Col(
+ anyOf( Coll(
HEIGHT > deadlineAlice && pkB,
- allOf( Col(
+ allOf( Coll(
pkA,
- getVar[Col[Byte]](1).get.size < 33,
- blake2b256(getVar[Col[Byte]](1).get) == hx
+ getVar[Coll[Byte]](1).get.size < 33,
+ blake2b256(getVar[Coll[Byte]](1).get) == hx
))
))
\end{verbatim}
If Alice is satisfied with the amount Bob is giving her, she claims the value of this box by revealing \texttt{x}. Alice is protected as long as the hash function is one-way and she keeps her \texttt{x} secret until she claims the value of this box. (She should be careful to submit her transaction in enough time before \texttt{deadlineAlice} to make sure it gets processed before Bob can reclaim this money, because once she submits the transaction, \texttt{x} is public and thus, if the \texttt{deadlineAlice} passes before the transaction is processed, Bob can both reclaim this box and claim the box Alice left in his blockchain.)
-Bob is protected, because in order for Alice to claim the value of this box, she must present a hash preimage of \texttt{hx} as a context extension in the transaction that uses this box as input. But once she does, Bob also learns this hash preimage, and is able to claim the value of the box that Alice placed into his blockchain. Note that Bob needs to choose \texttt{deadlineAlice} early enough to make sure that he is able to learn the preimage of \texttt{hx} from the transaction in Alice's block chain, and create a transaction in his blockchain, all before \texttt{deadlineBob} that Alice chose. Note also that \texttt{HEIGHT} in the two scripts is with respect to two different blockchains, which may be growing at a different rate. Bob also needs to make sure that he can use Alice's \texttt{x} as a context extension; to make sure Alice cannot cheat by making this \texttt{x} so long that it will not be allowed as a context extension in his blockchain, he uses the constraint \texttt{getVar[Col[Byte]](1).get.size < 33}.
+Bob is protected, because in order for Alice to claim the value of this box, she must present a hash preimage of \texttt{hx} as a context extension in the transaction that uses this box as input. But once she does, Bob also learns this hash preimage, and is able to claim the value of the box that Alice placed into his blockchain. Note that Bob needs to choose \texttt{deadlineAlice} early enough to make sure that he is able to learn the preimage of \texttt{hx} from the transaction in Alice's block chain, and create a transaction in his blockchain, all before \texttt{deadlineBob} that Alice chose. Note also that \texttt{HEIGHT} in the two scripts is with respect to two different blockchains, which may be growing at a different rate. Bob also needs to make sure that he can use Alice's \texttt{x} as a context extension; to make sure Alice cannot cheat by making this \texttt{x} so long that it will not be allowed as a context extension in his blockchain, he uses the constraint \texttt{getVar[Coll[Byte]](1).get.size < 33}.
The same approach can be used to trade different assets on the same blockchain, in case of multiasset blockchains. However, for transactions on a single blockchain, an alternative approach is also possible. We describe it below.
@@ -325,8 +325,8 @@ \subsection{Box Registers and Additional Tokens}
\begin{verbatim}
(HEIGHT > deadline && pkA) || {
- val tokenData = OUTPUTS(0).R2[Col[(Col[Byte], Long)]].get(0)
- allOf(Col(
+ val tokenData = OUTPUTS(0).R2[Coll[(Coll[Byte], Long)]].get(0)
+ allOf(Coll(
tokenData._1 == token1,
tokenData._2 >= 60L,
OUTPUTS(0).propositionBytes == pkA.propBytes,
@@ -342,7 +342,7 @@ \subsection{Box Registers and Additional Tokens}
\lnote{for some reason the example in the code we want value 1 --- why? It's not explained. Similarly, why do we need \texttt{OUTPUTS(0).value >= 1L} in the script above? } and 60 tokens of type \texttt{token1} and protect it by the following script:
\begin{verbatim}
(HEIGHT > deadline && pkB) ||
- allOf( Col(
+ allOf( Coll(
OUTPUTS(1).value >= 100,
OUTPUTS(1).propositionBytes == pkB.propBytes
))
@@ -357,8 +357,8 @@ \subsection{Box Registers and Additional Tokens}
\lnote{this seems like a pretty big security vulnerability and we should highlight it and show how to fix it. Restricting the number of inputs and outputs to just 2 is not enough. For example, suppose Alice has another box C in the UTXO with value 100 Ergo and 60 token1, and the following script:}
\begin{verbatim}
(HEIGHT > deadline && pkA) || {
- val tokenData = OUTPUTS(0).R2[Col[(Col[Byte], Long)]].get(0)
- allOf(Col(
+ val tokenData = OUTPUTS(0).R2[Coll[(Coll[Byte], Long)]].get(0)
+ allOf(Coll(
tokenData._1 == token1,
tokenData._2 >= 60L,
OUTPUTS(0).propositionBytes == pkA.propBytes,
@@ -389,10 +389,10 @@ \subsection{Self-Replicating Code}
else fixedRate - (oneEpochReduction * epoch)
val correctCoinsConsumed = coinsToIssue == (SELF.value - out.value)
val sameScriptRule = SELF.propositionBytes == out.propositionBytes
- val heightIncreased = HEIGHT > SELF.R4[Long].get
- val heightCorrect = out.R4[Long].get == HEIGHT
+ val heightIncreased = HEIGHT > SELF.R4[Int].get
+ val heightCorrect = out.R4[Int].get == HEIGHT
val lastCoins = SELF.value <= oneEpochReduction
- allOf(Col(
+ allOf(Coll(
correctCoinsConsumed,
heightCorrect,
heightIncreased,
@@ -457,50 +457,38 @@ \subsection{Verification and Safety Checks}
\begin{enumerate}
\item \textbf{Deserialization of Statement.}
-Verifier receives the statement as a collection of bytes and checks that the size
-of collection is less than predefined constant $C_1$. Deserializer parses the
-collection of bytes and checks if it is according to the format. Deserializer also
-controls the size of the constructed statement tree. It should be less than
-predefined constant $C_2$. The tree being constricted is also checked to
-satisfy typing rules. After deserialization stage we have valid tree of known
-limited size $TreeSize$. We want the complexity of all subsequent checks to
-be $O(TreeSize)$.
+Verifier receives the statement as a collection of bytes and checks that the
+size of collection is less than predefined constant $C_1$. Deserializer parses
+the collection of bytes and checks if it is according to the format.
+Deserializer also controls the size of the constructed statement tree. It should
+be less than predefined constant $C_2$. The tree being constricted is also
+checked to satisfy typing rules. After deserialization stage we have valid tree
+of known limited size $TreeSize$ and depth $TreeDepth$. We want the complexity
+of all subsequent checks to be $O(TreeSize)$.
\item \textbf{Instantiation of the Cost Function.}
Cost Function is the function of the same input (Context, variables,
-registers, etc.) as Statement function, but it computes Long value of the
+registers, etc.) as Statement function, but it computes Int value of the
computation cost of the Statement function, so it answer the question "How
many operations it is required to compute the statement?".
The Cost Function is instantiated by the following steps:
\begin{enumerate}
- \item Cost Function Tree, CFT, is obtained by:
- \begin{itemize}
- \item reading from the bytes stream immediately after Statement
- Tree. In this case the CFT is integral part of the Statement.
- \item generating from Statement Tree using algorithm $genCFT$
- \end{itemize}
- Both of these cases provide equivalent guarantees and only differ by
- the time of CFT generation
- \item After the CFT is obtained the standard interpreter is used to
- evaluate it and calculate an estimation of the computation cost of
- the Statement. (Section \ref{sec:gen-cost-function})
\end{enumerate}
- The idea is that the complexity of the Cost Function is linear in the size
- of the Statement tree in most of the cases. In the worst case it is linear
- in the size of the input data of the Statement which is strictly limited in
- size.
- We also rely on the fact that the complexity of $genCFT$ is linear in the
- size of the Statement Tree.
+ The idea is that the complexity of obtaining the Cost Function ($genCF$) is
+ linear in the size of the Statement tree. Execution time of the Cost Function
+ is linear in the size of the input data of the Statement which is strictly
+ limited in size.
\item \textbf{Evaluating the Statement cost.}
-The Cost Function is applied immediately before evaluation of the Statement
-by the following steps:
+The Cost Function is applied right before evaluation of the Statement by the
+following steps:
\begin{enumerate}
\item construct the context as it is required for Statement evaluation
- \item invoke the interpreter to evaluate the Cost Function Tree in the
+ \item invoke the interpreter to evaluate the Cost Function in the
given context
+ \item check resulting cost limit
\end{enumerate}
The generation of the CFT is further described in
@@ -1051,7 +1039,7 @@ \section{Types}
& $\mid$ & \lst{Box} & value in a box protected by proposition \\
& $\mid$ & \lst{AvlTree} & Authenticated Dynamic Dictionary \\
& $\mid$ & $(\tau_1, \dots, \tau_n) $ & binary product type \\
- & $\mid$ & $\text{\lst{Col}}[\tau]$ & collection type \\
+ & $\mid$ & $\text{\lst{Coll}}[\tau]$ & collection type \\
& $\mid$ & $\text{\lst{Option}}[\tau]$ & optional value (either $Some(\tau)$ or $None$) \\
& $\mid$ & \lst{Any} & type of any value (common supertype of all the types) \\
\end{tabular}\]
diff --git a/lock.sbt b/lock.sbt
deleted file mode 100644
index ccd17ad9c8..0000000000
--- a/lock.sbt
+++ /dev/null
@@ -1,50 +0,0 @@
-// DON'T EDIT THIS FILE.
-// This file is auto generated by sbt-lock 0.4.0.
-// https://github.com/tkawachi/sbt-lock/
-dependencyOverrides in ThisBuild ++= Seq(
- "cglib" % "cglib" % "3.2.3",
- "ch.qos.logback" % "logback-classic" % "1.3.0-alpha4",
- "ch.qos.logback" % "logback-core" % "1.3.0-alpha4",
- "com.github.kxbmap" % "configs_2.12" % "0.4.4",
- "com.google.code.findbugs" % "jsr305" % "3.0.2",
- "com.google.guava" % "guava" % "21.0",
- "com.lihaoyi" % "fastparse-utils_2.12" % "1.0.0",
- "com.lihaoyi" % "fastparse_2.12" % "1.0.0",
- "com.lihaoyi" % "sourcecode_2.12" % "0.1.4",
- "com.sun.mail" % "javax.mail" % "1.6.0",
- "com.trueaccord.lenses" % "lenses_2.12" % "0.4.12",
- "com.typesafe" % "config" % "1.3.1",
- "com.typesafe.akka" % "akka-actor_2.12" % "2.4.20",
- "com.typesafe.scala-logging" % "scala-logging_2.12" % "3.9.0",
- "commons-io" % "commons-io" % "2.5",
- "io.github.scalan" % "common_2.12" % "master-6eca3f22-SNAPSHOT",
- "io.github.scalan" % "core_2.12" % "master-6eca3f22-SNAPSHOT",
- "io.github.scalan" % "library-api_2.12" % "master-6eca3f22-SNAPSHOT",
- "io.github.scalan" % "library-impl_2.12" % "master-6eca3f22-SNAPSHOT",
- "io.github.scalan" % "library_2.12" % "master-6eca3f22-SNAPSHOT",
- "io.github.scalan" % "macros_2.12" % "master-6eca3f22-SNAPSHOT",
- "io.github.scalan" % "meta_2.12" % "master-6eca3f22-SNAPSHOT",
- "io.github.scalan" % "sigma-api_2.12" % "master-354d6254-SNAPSHOT",
- "io.github.scalan" % "sigma-impl_2.12" % "master-354d6254-SNAPSHOT",
- "io.github.scalan" % "sigma-library_2.12" % "master-354d6254-SNAPSHOT",
- "javax.activation" % "activation" % "1.1",
- "jline" % "jline" % "2.14.3",
- "org.apache.ant" % "ant" % "1.9.6",
- "org.apache.ant" % "ant-launcher" % "1.9.6",
- "org.bitbucket.inkytonik.dsinfo" % "dsinfo_2.12" % "0.4.0",
- "org.bitbucket.inkytonik.dsprofile" % "dsprofile_2.12" % "0.4.0",
- "org.bitbucket.inkytonik.kiama" % "kiama_2.12" % "2.1.0",
- "org.bouncycastle" % "bcprov-jdk15on" % "1.60",
- "org.objenesis" % "objenesis" % "2.4",
- "org.ow2.asm" % "asm" % "5.0.4",
- "org.rogach" % "scallop_2.12" % "2.1.1",
- "org.rudogma" % "supertagged_2.12" % "1.4",
- "org.scala-lang.modules" % "scala-java8-compat_2.12" % "0.8.0",
- "org.scala-lang.modules" % "scala-xml_2.12" % "1.0.6",
- "org.scorexfoundation" % "scorex-util_2.12" % "0.1.1",
- "org.scorexfoundation" % "scrypto_2.12" % "2.1.4",
- "org.slf4j" % "slf4j-api" % "1.8.0-beta1",
- "org.typelevel" % "macro-compat_2.12" % "1.1.1",
- "org.whispersystems" % "curve25519-java" % "0.5.0"
-)
-// LIBRARY_DEPENDENCIES_HASH 5e333cb35b2a537d1b2240adc607317b51f46f97
diff --git a/profile-sbt.sh b/profile-sbt.sh
new file mode 100755
index 0000000000..b6cd23b569
--- /dev/null
+++ b/profile-sbt.sh
@@ -0,0 +1,2 @@
+sbt -J-agentpath:/Applications/YourKit-Java-Profiler-2018.04.app/Contents/Resources/bin/mac/libyjpagent.jnilib
+
diff --git a/project/build.properties b/project/build.properties
index 5620cc502b..72f902892a 100644
--- a/project/build.properties
+++ b/project/build.properties
@@ -1 +1 @@
-sbt.version=1.2.1
+sbt.version=1.2.7
diff --git a/project/plugins.sbt b/project/plugins.sbt
index d7a3f85cd6..fb0a9f469c 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -1,5 +1,7 @@
logLevel := Level.Warn
-addSbtPlugin("com.github.tkawachi" % "sbt-lock" % "0.4.0")
-
+//addSbtPlugin("com.github.tkawachi" % "sbt-lock" % "0.4.0")
+addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.9")
+addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "1.0.0")
+addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.9.2")
diff --git a/scalanizer/src/main/resources/scalac-plugin.xml b/scalanizer/src/main/resources/scalac-plugin.xml
new file mode 100644
index 0000000000..7dd58fc0bb
--- /dev/null
+++ b/scalanizer/src/main/resources/scalac-plugin.xml
@@ -0,0 +1,4 @@
+
+ scalanizer
+ special.sigma.scalanizer.SigmaPlugin
+
\ No newline at end of file
diff --git a/scalanizer/src/main/scala/special/sigma/scalanizer/SigmaPlugin.scala b/scalanizer/src/main/scala/special/sigma/scalanizer/SigmaPlugin.scala
new file mode 100644
index 0000000000..1214083d68
--- /dev/null
+++ b/scalanizer/src/main/scala/special/sigma/scalanizer/SigmaPlugin.scala
@@ -0,0 +1,20 @@
+package special.sigma.scalanizer
+
+import spu.device.config.SigmaLibraryConfig
+
+import scala.tools.nsc.Global
+import scalan.meta.{ConfMap, TargetModuleConf, SourceModuleConf}
+import scalan.meta.scalanizer.ScalanizerConfig
+import scalan.plugin.{ScalanizerPluginConfig, ScalanizerPlugin}
+
+class SigmaPlugin(g: Global) extends ScalanizerPlugin(g) { plugin =>
+ override def createScalanizerConfig(): ScalanizerConfig = new SigmaScalanizerConfig
+}
+
+class SigmaScalanizerConfig extends ScalanizerPluginConfig {
+ val sigma = new SigmaLibraryConfig()
+
+ /** Modules that contain units to be virtualized by scalan-meta. */
+ override val sourceModules: ConfMap[SourceModuleConf] = ConfMap(sigma.sourceModules: _*)
+ override val targetModules: ConfMap[TargetModuleConf] = ConfMap(sigma.targetModules: _*)
+}
diff --git a/sigma-api/src/main/resources/special/sigma/CostedObjects.scalan b/sigma-api/src/main/resources/special/sigma/CostedObjects.scalan
new file mode 100644
index 0000000000..3baf3cc56a
--- /dev/null
+++ b/sigma-api/src/main/resources/special/sigma/CostedObjects.scalan
@@ -0,0 +1,56 @@
+package special.sigma {
+ import scalan._
+
+ trait CostedObjects extends Base { self: CostedObjectsModule =>
+ import AnyValue._;
+ import AvlTree._;
+ import Box._;
+ import Coll._;
+ import Context._;
+ import Header._;
+ import PreHeader._;
+ import SigmaProp._;
+ import Size._;
+ import SizeAnyValue._;
+ import SizeBox._;
+ import SizeBuilder._;
+ import SizeContext._;
+ import WOption._;
+ import WRType._;
+ @Liftable trait SizeAnyValue extends Size[AnyValue] {
+ def tVal: Rep[WRType[Any]];
+ def valueSize: Rep[Size[Any]]
+ };
+ @Liftable trait SizeSigmaProp extends Size[SigmaProp] {
+ def propBytes: Rep[Size[Coll[Byte]]]
+ };
+ @Liftable trait SizeBox extends Size[Box] {
+ def propositionBytes: Rep[Size[Coll[Byte]]];
+ def bytes: Rep[Size[Coll[Byte]]];
+ def bytesWithoutRef: Rep[Size[Coll[Byte]]];
+ def registers: Rep[Size[Coll[WOption[AnyValue]]]];
+ def getReg[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]];
+ def tokens: Rep[Size[Coll[scala.Tuple2[Coll[Byte], Long]]]]
+ };
+ @Liftable trait SizeContext extends Size[Context] {
+ def outputs: Rep[Size[Coll[Box]]];
+ def inputs: Rep[Size[Coll[Box]]];
+ def dataInputs: Rep[Size[Coll[Box]]];
+ def selfBox: Rep[Size[Box]];
+ def lastBlockUtxoRootHash: Rep[Size[AvlTree]];
+ def headers: Rep[Size[Coll[Header]]];
+ def preHeader: Rep[Size[PreHeader]];
+ def getVar[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]]
+ };
+ @Liftable trait SizeBuilder extends Def[SizeBuilder] {
+ def mkSizeAnyValue(tVal: Rep[WRType[Any]], valueSize: Rep[Size[Any]]): Rep[SizeAnyValue];
+ def mkSizeBox(propositionBytes: Rep[Size[Coll[Byte]]], bytes: Rep[Size[Coll[Byte]]], bytesWithoutRef: Rep[Size[Coll[Byte]]], registers: Rep[Size[Coll[WOption[AnyValue]]]], tokens: Rep[Size[Coll[scala.Tuple2[Coll[Byte], Long]]]]): Rep[SizeBox];
+ def mkSizeContext(outputs: Rep[Size[Coll[Box]]], inputs: Rep[Size[Coll[Box]]], dataInputs: Rep[Size[Coll[Box]]], selfBox: Rep[Size[Box]], lastBlockUtxoRootHash: Rep[Size[AvlTree]], headers: Rep[Size[Coll[Header]]], preHeader: Rep[Size[PreHeader]], vars: Rep[Coll[Size[AnyValue]]]): Rep[SizeContext]
+ };
+ trait SizeAnyValueCompanion;
+ trait SizeSigmaPropCompanion;
+ trait SizeBoxCompanion;
+ trait SizeContextCompanion;
+ trait SizeBuilderCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-api/src/main/resources/special/sigma/SigmaDsl.scalan b/sigma-api/src/main/resources/special/sigma/SigmaDsl.scalan
new file mode 100644
index 0000000000..b366a6829c
--- /dev/null
+++ b/sigma-api/src/main/resources/special/sigma/SigmaDsl.scalan
@@ -0,0 +1,225 @@
+package special.sigma {
+ import scalan._
+
+ trait SigmaDsl extends Base { self: SigmaDslModule =>
+ import AnyValue._;
+ import AvlTree._;
+ import BigInt._;
+ import Box._;
+ import Coll._;
+ import CollBuilder._;
+ import Context._;
+ import CostModel._;
+ import CostedBuilder._;
+ import GroupElement._;
+ import Header._;
+ import MonoidBuilder._;
+ import PreHeader._;
+ import SigmaContract._;
+ import SigmaDslBuilder._;
+ import SigmaProp._;
+ import WBigInteger._;
+ import WOption._;
+ import WRType._;
+ @Liftable trait CostModel extends Def[CostModel] {
+ def AccessBox: Rep[Int];
+ def AccessAvlTree: Rep[Int];
+ def GetVar: Rep[Int];
+ def DeserializeVar: Rep[Int];
+ def GetRegister: Rep[Int];
+ def DeserializeRegister: Rep[Int];
+ def SelectField: Rep[Int];
+ def CollectionConst: Rep[Int];
+ def AccessKiloByteOfData: Rep[Int];
+ @Reified(value = "T") def dataSize[T](x: Rep[T])(implicit cT: Elem[T]): Rep[Long];
+ def PubKeySize: Rep[Long]
+ };
+ @Liftable trait BigInt extends Def[BigInt] {
+ def toByte: Rep[Byte];
+ def toShort: Rep[Short];
+ def toInt: Rep[Int];
+ def toLong: Rep[Long];
+ def toBytes: Rep[Coll[Byte]];
+ def toBits: Rep[Coll[Boolean]];
+ def toAbs: Rep[BigInt];
+ def compareTo(that: Rep[BigInt]): Rep[Int];
+ def modQ: Rep[BigInt];
+ def plusModQ(other: Rep[BigInt]): Rep[BigInt];
+ def minusModQ(other: Rep[BigInt]): Rep[BigInt];
+ def multModQ(other: Rep[BigInt]): Rep[BigInt];
+ def inverseModQ: Rep[BigInt];
+ def signum: Rep[Int];
+ def add(that: Rep[BigInt]): Rep[BigInt];
+ def subtract(that: Rep[BigInt]): Rep[BigInt];
+ def multiply(that: Rep[BigInt]): Rep[BigInt];
+ def divide(that: Rep[BigInt]): Rep[BigInt];
+ def mod(m: Rep[BigInt]): Rep[BigInt];
+ def remainder(that: Rep[BigInt]): Rep[BigInt];
+ def min(that: Rep[BigInt]): Rep[BigInt];
+ def max(that: Rep[BigInt]): Rep[BigInt];
+ def negate: Rep[BigInt]
+ };
+ @Liftable trait GroupElement extends Def[GroupElement] {
+ def isInfinity: Rep[Boolean];
+ def exp(k: Rep[BigInt]): Rep[GroupElement];
+ def multiply(that: Rep[GroupElement]): Rep[GroupElement];
+ def negate: Rep[GroupElement];
+ def getEncoded: Rep[Coll[Byte]]
+ };
+ @Liftable trait SigmaProp extends Def[SigmaProp] {
+ def isValid: Rep[Boolean];
+ def propBytes: Rep[Coll[Byte]];
+ @OverloadId(value = "and_sigma") def &&(other: Rep[SigmaProp]): Rep[SigmaProp];
+ @OverloadId(value = "and_bool") def &&(other: Rep[Boolean]): Rep[SigmaProp];
+ @OverloadId(value = "or_sigma") def ||(other: Rep[SigmaProp]): Rep[SigmaProp];
+ @OverloadId(value = "or_bool") def ||(other: Rep[Boolean]): Rep[SigmaProp]
+ };
+ @Liftable trait AnyValue extends Def[AnyValue] {
+ def value: Rep[Any];
+ def tVal: Rep[WRType[Any]]
+ };
+ @Liftable trait Box extends Def[Box] {
+ def id: Rep[Coll[Byte]];
+ def value: Rep[Long];
+ def propositionBytes: Rep[Coll[Byte]];
+ def bytes: Rep[Coll[Byte]];
+ def bytesWithoutRef: Rep[Coll[Byte]];
+ def registers: Rep[Coll[AnyValue]];
+ def getReg[T](i: Rep[Int])(implicit cT: Elem[T]): Rep[WOption[T]];
+ def R0[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(0.asInstanceOf[Int]));
+ def R1[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(1.asInstanceOf[Int]));
+ def R2[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(2.asInstanceOf[Int]));
+ def R3[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(3.asInstanceOf[Int]));
+ def R4[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(4.asInstanceOf[Int]));
+ def R5[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(5.asInstanceOf[Int]));
+ def R6[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(6.asInstanceOf[Int]));
+ def R7[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(7.asInstanceOf[Int]));
+ def R8[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(8.asInstanceOf[Int]));
+ def R9[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(9.asInstanceOf[Int]));
+ def tokens: Rep[Coll[scala.Tuple2[Coll[Byte], Long]]];
+ def creationInfo: Rep[scala.Tuple2[Int, Coll[Byte]]];
+ def executeFromRegister[T](regId: Rep[Byte])(implicit cT: Elem[T]): Rep[T]
+ };
+ @Liftable trait AvlTree extends Def[AvlTree] {
+ def digest: Rep[Coll[Byte]];
+ def enabledOperations: Rep[Byte];
+ def keyLength: Rep[Int];
+ def valueLengthOpt: Rep[WOption[Int]];
+ def isInsertAllowed: Rep[Boolean];
+ def isUpdateAllowed: Rep[Boolean];
+ def isRemoveAllowed: Rep[Boolean];
+ def updateDigest(newDigest: Rep[Coll[Byte]]): Rep[AvlTree];
+ def updateOperations(newOperations: Rep[Byte]): Rep[AvlTree];
+ def contains(key: Rep[Coll[Byte]], proof: Rep[Coll[Byte]]): Rep[Boolean];
+ def get(key: Rep[Coll[Byte]], proof: Rep[Coll[Byte]]): Rep[WOption[Coll[Byte]]];
+ def getMany(keys: Rep[Coll[Coll[Byte]]], proof: Rep[Coll[Byte]]): Rep[Coll[WOption[Coll[Byte]]]];
+ def insert(operations: Rep[Coll[scala.Tuple2[Coll[Byte], Coll[Byte]]]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]];
+ def update(operations: Rep[Coll[scala.Tuple2[Coll[Byte], Coll[Byte]]]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]];
+ def remove(operations: Rep[Coll[Coll[Byte]]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]]
+ };
+ @Liftable trait PreHeader extends Def[PreHeader] {
+ def version: Rep[Byte];
+ def parentId: Rep[Coll[Byte]];
+ def timestamp: Rep[Long];
+ def nBits: Rep[Long];
+ def height: Rep[Int];
+ def minerPk: Rep[GroupElement];
+ def votes: Rep[Coll[Byte]]
+ };
+ @Liftable trait Header extends Def[Header] {
+ def id: Rep[Coll[Byte]];
+ def version: Rep[Byte];
+ def parentId: Rep[Coll[Byte]];
+ def ADProofsRoot: Rep[Coll[Byte]];
+ def stateRoot: Rep[AvlTree];
+ def transactionsRoot: Rep[Coll[Byte]];
+ def timestamp: Rep[Long];
+ def nBits: Rep[Long];
+ def height: Rep[Int];
+ def extensionRoot: Rep[Coll[Byte]];
+ def minerPk: Rep[GroupElement];
+ def powOnetimePk: Rep[GroupElement];
+ def powNonce: Rep[Coll[Byte]];
+ def powDistance: Rep[BigInt];
+ def votes: Rep[Coll[Byte]]
+ };
+ @Liftable trait Context extends Def[Context] {
+ def builder: Rep[SigmaDslBuilder];
+ def OUTPUTS: Rep[Coll[Box]];
+ def INPUTS: Rep[Coll[Box]];
+ def dataInputs: Rep[Coll[Box]];
+ def HEIGHT: Rep[Int];
+ def SELF: Rep[Box];
+ def selfBoxIndex: Rep[Int];
+ def LastBlockUtxoRootHash: Rep[AvlTree];
+ def headers: Rep[Coll[Header]];
+ def preHeader: Rep[PreHeader];
+ def minerPubKey: Rep[Coll[Byte]];
+ def getVar[T](id: Rep[Byte])(implicit cT: Elem[T]): Rep[WOption[T]];
+ def vars: Rep[Coll[AnyValue]]
+ };
+ @Liftable trait SigmaContract extends Def[SigmaContract] {
+ def builder: Rep[SigmaDslBuilder];
+ @NeverInline @Reified(value = "T") def Collection[T](items: Rep[T]*)(implicit cT: Elem[T]): Rep[Coll[T]] = delayInvoke;
+ def verifyZK(cond: Rep[Thunk[SigmaProp]]): Rep[Boolean] = this.builder.verifyZK(cond);
+ def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = this.builder.atLeast(bound, props);
+ def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = this.builder.allOf(conditions);
+ def allZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = this.builder.allZK(conditions);
+ def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = this.builder.anyOf(conditions);
+ def anyZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = this.builder.anyZK(conditions);
+ def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = this.builder.xorOf(conditions);
+ def PubKey(base64String: Rep[String]): Rep[SigmaProp] = this.builder.PubKey(base64String);
+ def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp] = this.builder.sigmaProp(b);
+ def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = this.builder.blake2b256(bytes);
+ def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = this.builder.sha256(bytes);
+ def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt] = this.builder.byteArrayToBigInt(bytes);
+ def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]] = this.builder.longToByteArray(l);
+ def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long] = this.builder.byteArrayToLong(bytes);
+ def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp] = this.builder.proveDlog(g);
+ def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp] = this.builder.proveDHTuple(g, h, u, v);
+ def groupGenerator: Rep[GroupElement] = this.builder.groupGenerator;
+ @clause def canOpen(ctx: Rep[Context]): Rep[Boolean];
+ def asFunction: Rep[scala.Function1[Context, Boolean]] = fun(((ctx: Rep[Context]) => this.canOpen(ctx)))
+ };
+ @Liftable trait SigmaDslBuilder extends Def[SigmaDslBuilder] {
+ def Colls: Rep[CollBuilder];
+ def Monoids: Rep[MonoidBuilder];
+ def Costing: Rep[CostedBuilder];
+ def CostModel: Rep[CostModel];
+ def verifyZK(cond: Rep[Thunk[SigmaProp]]): Rep[Boolean];
+ def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp];
+ def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean];
+ def allZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp];
+ def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean];
+ def anyZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp];
+ def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean];
+ def PubKey(base64String: Rep[String]): Rep[SigmaProp];
+ def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp];
+ def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]];
+ def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]];
+ def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt];
+ def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]];
+ def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long];
+ def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp];
+ def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp];
+ def groupGenerator: Rep[GroupElement];
+ @Reified(value = "T") def substConstants[T](scriptBytes: Rep[Coll[Byte]], positions: Rep[Coll[Int]], newValues: Rep[Coll[T]])(implicit cT: Elem[T]): Rep[Coll[Byte]];
+ def decodePoint(encoded: Rep[Coll[Byte]]): Rep[GroupElement];
+ def BigInt(n: Rep[WBigInteger]): Rep[BigInt];
+ def toBigInteger(n: Rep[BigInt]): Rep[WBigInteger];
+ def avlTree(operationFlags: Rep[Byte], digest: Rep[Coll[Byte]], keyLength: Rep[Int], valueLengthOpt: Rep[WOption[Int]]): Rep[AvlTree]
+ };
+ trait CostModelCompanion;
+ trait BigIntCompanion;
+ trait GroupElementCompanion;
+ trait SigmaPropCompanion;
+ trait AnyValueCompanion;
+ trait BoxCompanion;
+ trait AvlTreeCompanion;
+ trait PreHeaderCompanion;
+ trait HeaderCompanion;
+ trait ContextCompanion;
+ trait SigmaContractCompanion;
+ trait SigmaDslBuilderCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-api/src/main/resources/special/sigma/wrappers/WrappersSpec.scalan b/sigma-api/src/main/resources/special/sigma/wrappers/WrappersSpec.scalan
new file mode 100644
index 0000000000..1d3fabc31a
--- /dev/null
+++ b/sigma-api/src/main/resources/special/sigma/wrappers/WrappersSpec.scalan
@@ -0,0 +1,67 @@
+package special.sigma.wrappers {
+ import scalan._
+
+ trait WrappersSpec extends Base { self: WrappersSpecModule =>
+ import WArray._;
+ import WBigInteger._;
+ import WECPoint._;
+ import WSigmaPredef._;
+ import WrapSpecBase._;
+ trait ECPointWrapSpec extends WrapSpecBase {
+ def getEncoded[A](g: Rep[WECPoint], compressed: Rep[Boolean]): Rep[WArray[Byte]] = g.getEncoded(compressed);
+ def multiply(l: Rep[WECPoint], r: Rep[WBigInteger]): Rep[WECPoint] = l.multiply(r);
+ def add(l: Rep[WECPoint], r: Rep[WECPoint]): Rep[WECPoint] = l.add(r)
+ };
+ trait BigIntegerWrapSpec extends WrapSpecBase {
+ def fromString(s: Rep[String]): Rep[WBigInteger] = RWBigInteger(s);
+ def fromArray(sig: Rep[Int], arr: Rep[WArray[Byte]]): Rep[WBigInteger] = RWBigInteger(sig, arr);
+ def valueOf(l: Rep[Long]): Rep[WBigInteger] = RWBigInteger.valueOf(l);
+ def toByteArray(l: Rep[WBigInteger]): Rep[WArray[Byte]] = l.toByteArray;
+ def add(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.add(r);
+ def subtract(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.subtract(r);
+ def multiply(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.multiply(r);
+ def mod(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.mod(r);
+ def modInverse(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.modInverse(r);
+ def modPow(l: Rep[WBigInteger], exponent: Rep[WBigInteger], m: Rep[WBigInteger]): Rep[WBigInteger] = l.modPow(exponent, m);
+ def remainder(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.remainder(r);
+ def divide(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.divide(r);
+ def compareTo(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[Int] = l.compareTo(r);
+ def min(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.min(r);
+ def max(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.max(r);
+ def gcd(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.gcd(r);
+ def and(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.and(r);
+ def or(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.or(r);
+ def xor(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.xor(r);
+ def not(l: Rep[WBigInteger]): Rep[WBigInteger] = l.not;
+ def andNot(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.andNot(r);
+ def pow(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.pow(r);
+ def testBit(l: Rep[WBigInteger], r: Rep[Int]): Rep[Boolean] = l.testBit(r);
+ def setBit(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.setBit(r);
+ def clearBit(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.clearBit(r);
+ def flipBit(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.flipBit(r);
+ def getLowestSetBit(l: Rep[WBigInteger]): Rep[Int] = l.getLowestSetBit;
+ def bitCount(l: Rep[WBigInteger]): Rep[Int] = l.bitCount;
+ def bitLength(l: Rep[WBigInteger]): Rep[Int] = l.bitLength;
+ def isProbablePrime(l: Rep[WBigInteger], r: Rep[Int]): Rep[Boolean] = l.isProbablePrime(r);
+ def shiftLeft(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.shiftLeft(r);
+ def shiftRight(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.shiftRight(r);
+ def abs(l: Rep[WBigInteger]): Rep[WBigInteger] = l.abs;
+ def negate(l: Rep[WBigInteger]): Rep[WBigInteger] = l.negate;
+ def signum(l: Rep[WBigInteger]): Rep[Int] = l.signum;
+ def byteValue(l: Rep[WBigInteger]): Rep[Byte] = l.byteValue;
+ def shortValue(l: Rep[WBigInteger]): Rep[Short] = l.shortValue;
+ def intValue(l: Rep[WBigInteger]): Rep[Int] = l.intValue;
+ def longValue(l: Rep[WBigInteger]): Rep[Long] = l.longValue;
+ def byteValueExact(l: Rep[WBigInteger]): Rep[Byte] = l.byteValueExact;
+ def shortValueExact(l: Rep[WBigInteger]): Rep[Short] = l.shortValueExact;
+ def intValueExact(l: Rep[WBigInteger]): Rep[Int] = l.intValueExact;
+ def longValueExact(l: Rep[WBigInteger]): Rep[Long] = l.longValueExact
+ };
+ trait SigmaPredefWrapSpec extends WrapSpecBase {
+ def dataSize(v: Rep[Any]): Rep[Long] = RWSigmaPredef.dataSize[Any](v)
+ };
+ trait ECPointWrapSpecCompanion;
+ trait BigIntegerWrapSpecCompanion;
+ trait SigmaPredefWrapSpecCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-api/src/main/resources/wrappers/java/math/WBigIntegers.scalan b/sigma-api/src/main/resources/wrappers/java/math/WBigIntegers.scalan
new file mode 100644
index 0000000000..129a5e0fd6
--- /dev/null
+++ b/sigma-api/src/main/resources/wrappers/java/math/WBigIntegers.scalan
@@ -0,0 +1,61 @@
+package wrappers.java.math {
+ import scalan._
+
+ import impl._
+
+ import special.sigma.wrappers.WrappersModule
+
+ import special.sigma.wrappers.BigIntegerWrapSpec
+
+ trait WBigIntegers extends Base { self: WrappersModule =>
+ import WArray._;
+ import WBigInteger._;
+ @External("BigInteger") @Liftable trait WBigInteger extends Def[WBigInteger] { self =>
+ @External def longValueExact: Rep[Long];
+ @External def intValueExact: Rep[Int];
+ @External def shortValueExact: Rep[Short];
+ @External def byteValueExact: Rep[Byte];
+ @External def longValue: Rep[Long];
+ @External def intValue: Rep[Int];
+ @External def shortValue: Rep[Short];
+ @External def byteValue: Rep[Byte];
+ @External def signum: Rep[Int];
+ @External def negate: Rep[WBigInteger];
+ @External def abs: Rep[WBigInteger];
+ @External def shiftRight(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def shiftLeft(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def isProbablePrime(x$1: Rep[Int]): Rep[Boolean];
+ @External def bitLength: Rep[Int];
+ @External def bitCount: Rep[Int];
+ @External def getLowestSetBit: Rep[Int];
+ @External def flipBit(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def clearBit(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def setBit(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def testBit(x$1: Rep[Int]): Rep[Boolean];
+ @External def pow(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def andNot(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def not: Rep[WBigInteger];
+ @External def xor(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def or(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def and(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def gcd(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def max(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def min(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def compareTo(x$1: Rep[WBigInteger]): Rep[Int];
+ @External def divide(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def remainder(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def modPow(x$1: Rep[WBigInteger], x$2: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def modInverse(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def mod(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def multiply(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def subtract(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def add(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def toByteArray: Rep[WArray[Byte]]
+ };
+ trait WBigIntegerCompanion {
+ @Constructor @OverloadId(value = "constructor_1") def apply(x$1: Rep[Int], x$2: Rep[WArray[Byte]]): Rep[WBigInteger];
+ @Constructor @OverloadId(value = "constructor_2") def apply(x$1: Rep[String]): Rep[WBigInteger];
+ @External def valueOf(x$1: Rep[Long]): Rep[WBigInteger]
+ }
+ }
+}
\ No newline at end of file
diff --git a/sigma-api/src/main/resources/wrappers/org/bouncycastle/math/ec/WECPoints.scalan b/sigma-api/src/main/resources/wrappers/org/bouncycastle/math/ec/WECPoints.scalan
new file mode 100644
index 0000000000..0851c2fa30
--- /dev/null
+++ b/sigma-api/src/main/resources/wrappers/org/bouncycastle/math/ec/WECPoints.scalan
@@ -0,0 +1,21 @@
+package wrappers.org.bouncycastle.math.ec {
+ import scalan._
+
+ import impl._
+
+ import special.sigma.wrappers.WrappersModule
+
+ import special.sigma.wrappers.ECPointWrapSpec
+
+ trait WECPoints extends Base { self: WrappersModule =>
+ import WArray._;
+ import WBigInteger._;
+ import WECPoint._;
+ @External("ECPoint") @Liftable trait WECPoint extends Def[WECPoint] { self =>
+ @External def add(x$1: Rep[WECPoint]): Rep[WECPoint];
+ @External def multiply(x$1: Rep[WBigInteger]): Rep[WECPoint];
+ @External def getEncoded(x$1: Rep[Boolean]): Rep[WArray[Byte]]
+ };
+ trait WECPointCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-api/src/main/resources/wrappers/special/sigma/WSigmaPredefs.scalan b/sigma-api/src/main/resources/wrappers/special/sigma/WSigmaPredefs.scalan
new file mode 100644
index 0000000000..848917e56c
--- /dev/null
+++ b/sigma-api/src/main/resources/wrappers/special/sigma/WSigmaPredefs.scalan
@@ -0,0 +1,19 @@
+package wrappers.special.sigma {
+ import scalan._
+
+ import impl._
+
+ import special.sigma.wrappers.WrappersModule
+
+ import special.sigma.wrappers.SigmaPredefWrapSpec
+
+ trait WSigmaPredefs extends Base { self: WrappersModule =>
+ import WSigmaPredef._;
+ @External("SigmaPredef") trait WSigmaPredef extends Def[WSigmaPredef] { self =>
+
+ };
+ trait WSigmaPredefCompanion {
+ @External def dataSize[T](v: Rep[T]): Rep[Long]
+ }
+ }
+}
\ No newline at end of file
diff --git a/sigma-api/src/main/scala/sigma/types/Types.scala b/sigma-api/src/main/scala/sigma/types/Types.scala
new file mode 100644
index 0000000000..080891d5e9
--- /dev/null
+++ b/sigma-api/src/main/scala/sigma/types/Types.scala
@@ -0,0 +1,58 @@
+package sigma.types
+
+import scalan.{Internal, Nullable}
+import special.collection.Coll
+
+@Internal
+private[types] trait PrimView[@specialized Val] {
+ private[types] def value: Val
+}
+
+trait Boolean extends PrimView[scala.Boolean] {
+ /** Convert true to 1 and false to 0
+ * @since 2.0
+ */
+ def toByte: Byte
+
+ /** Logical XOR
+ * @since 2.0
+ */
+ def xor(y: Boolean): Boolean
+}
+
+trait Byte extends PrimView[scala.Byte] {
+// def toShort: Short
+ def toInt: Int
+// def toLong: Long
+ def + (y: Byte): Byte
+}
+
+trait Int extends PrimView[scala.Int] {
+ def toByte: Byte
+ def + (y: Int): Int
+
+ /** Returns a big-endian representation of this Int in a collection of bytes.
+ * For example, the Int value {@code 0x12131415} would yield the
+ * byte array {@code {0x12, 0x13, 0x14, 0x15}}.
+ * @since 2.0
+ */
+ def toBytes: Coll[Byte]
+
+ /** Returns a big-endian representation of this numeric in a collection of Booleans.
+ * Each boolean corresponds to one bit.
+ * @since 2.0
+ */
+ def toBits: Coll[Boolean]
+
+ /** Absolute value of this numeric value.
+ * @since 2.0
+ */
+ def abs: Int
+
+ /** Compares this numeric with that numeric for order. Returns a negative integer, zero, or a positive integer as the
+ * `this` is less than, equal to, or greater than `that`.
+ */
+ def compareTo(that: Int): Int
+}
+
+
diff --git a/sigma-api/src/main/scala/sigma/types/package.scala b/sigma-api/src/main/scala/sigma/types/package.scala
new file mode 100644
index 0000000000..99b2add48d
--- /dev/null
+++ b/sigma-api/src/main/scala/sigma/types/package.scala
@@ -0,0 +1,32 @@
+package sigma
+
+import scalan.RType
+import scala.reflect.classTag
+package types {
+ import scalan.{Internal, Nullable}
+
+ import scala.reflect.ClassTag
+
+ trait ViewType[T, Val] extends RType[T] {
+ def tVal: RType[Val]
+ }
+
+ case class PrimViewType[T, Val](classTag: ClassTag[T], tVal: RType[Val]) extends ViewType[T, Val] {
+ override def name: String = tVal.name
+ override def isConstantSize: scala.Boolean = tVal.isConstantSize
+ }
+
+ object IsPrimView {
+ def unapply(pv: PrimView[_]): Nullable[Any] = (pv match {
+ case pv: PrimView[_] => Nullable(pv.value)
+ case _ => Nullable.None
+ })
+ }
+
+}
+
+package object types {
+ implicit val booleanRType: RType[Boolean] = PrimViewType[Boolean, scala.Boolean](classTag[Boolean], RType[scala.Boolean])
+ implicit val byteRType: RType[Byte] = PrimViewType[Byte, scala.Byte](classTag[Byte], RType[scala.Byte])
+ implicit val intRType: RType[Int] = PrimViewType[Int, scala.Int](classTag[Int], RType[scala.Int])
+}
diff --git a/sigma-api/src/main/scala/special/sigma/CostTable.scala b/sigma-api/src/main/scala/special/sigma/CostTable.scala
new file mode 100644
index 0000000000..a68775b629
--- /dev/null
+++ b/sigma-api/src/main/scala/special/sigma/CostTable.scala
@@ -0,0 +1,51 @@
+package special.sigma
+
+case class CostTable(operCosts: Map[String, Double]) extends (String => Int) {
+ override def apply(operId: String): Int = {
+ operCosts.get(operId) match {
+ case Some(cost) => (cost * 1000000).toInt
+ case None => sys.error(s"Cannot find cost in CostTable for $operId")
+ }
+ }
+}
+
+object CostTable {
+ type ExpressionCost = Int
+ val DefaultCosts = CostTable.fromSeq(Seq(
+ ("Const: () => Unit", 0.000001),
+ ("Const: () => Boolean", 0.000001),
+ ("Const: () => Byte", 0.000001),
+ ("Const: () => Short", 0.000001),
+ ("Const: () => Int", 0.000001),
+ ("Const: () => Long", 0.000001),
+ ("Const: () => BigInt", 0.000001),
+ ("Const: () => String", 0.000001),
+ ("Const: () => GroupElement", 0.000001),
+ ("Const: () => SigmaProp", 0.000001),
+ ("Const: () => Array[IV]", 0.000001),
+ ("Self$: Context => Box", 0.000001),
+ ("SelectField", 0.000001),
+ ("AccessKiloByteOfData", 0.000001),
+ ("AccessBox: Context => Box", 0.000001),
+
+ ("GetVar: (Context, Byte) => Option[T]", 0.000001),
+ ("DeserializeVar: (Context, Byte) => Option[T]", 0.000001),
+
+ ("GetRegister: (Box, Byte) => Option[T]", 0.000001),
+ ("DeserializeRegister: (Box, Byte) => Option[T]", 0.000001),
+
+ ("ExtractRegisterAs: (Box,Byte) => Array[BigInt]", 0.000001),
+ ("SigmaPropIsValid: SigmaProp => Boolean", 0.000001),
+ ("SigmaPropBytes: SigmaProp => Array[Byte]", 0.000001),
+ ("BinAnd: (Boolean, Boolean) => Boolean", 0.000001),
+ ("BinOr: (Boolean, Boolean) => Boolean", 0.000001),
+ ("+: (BigInt, BigInt) => BigInt", 0.0001),
+ ("+_per_item: (BigInt, BigInt) => BigInt", 0.000001)
+ ))
+
+ def fromSeq(items: Seq[(String, Double)]): CostTable = {
+ CostTable(items.toMap)
+ }
+}
+
+
diff --git a/sigma-api/src/main/scala/special/sigma/CostedObjects.scala b/sigma-api/src/main/scala/special/sigma/CostedObjects.scala
new file mode 100644
index 0000000000..0a27b1e341
--- /dev/null
+++ b/sigma-api/src/main/scala/special/sigma/CostedObjects.scala
@@ -0,0 +1,57 @@
+package special.sigma
+
+import special.collection._
+import scalan._
+
+@scalan.Liftable
+trait SizeAnyValue extends Size[AnyValue] {
+ def tVal: RType[Any]
+ def valueSize: Size[Any]
+}
+
+@scalan.Liftable
+trait SizeSigmaProp extends Size[SigmaProp] {
+ def propBytes: Size[Coll[Byte]]
+}
+
+@scalan.Liftable
+trait SizeBox extends Size[Box] {
+ def propositionBytes: Size[Coll[Byte]]
+ def bytes: Size[Coll[Byte]]
+ def bytesWithoutRef: Size[Coll[Byte]]
+ def registers: Size[Coll[Option[AnyValue]]]
+ def getReg[T](id: Byte)(implicit tT: RType[T]): Size[Option[T]]
+ def tokens: Size[Coll[(Coll[Byte], Long)]]
+}
+
+@scalan.Liftable
+trait SizeContext extends Size[Context] {
+ def outputs: Size[Coll[Box]]
+ def inputs: Size[Coll[Box]]
+ def dataInputs: Size[Coll[Box]]
+ def selfBox: Size[Box]
+ def lastBlockUtxoRootHash: Size[AvlTree]
+ def headers: Size[Coll[Header]]
+ def preHeader: Size[PreHeader]
+ def getVar[T](id: Byte)(implicit tT: RType[T]): Size[Option[T]]
+}
+
+@scalan.Liftable
+trait SizeBuilder {
+ def mkSizeAnyValue(tVal: RType[Any], valueSize: Size[Any]): SizeAnyValue
+
+ def mkSizeBox(propositionBytes: Size[Coll[Byte]], bytes: Size[Coll[Byte]],
+ bytesWithoutRef: Size[Coll[Byte]], registers: Size[Coll[Option[AnyValue]]],
+ tokens: Size[Coll[(Coll[Byte], Long)]]): SizeBox
+
+ def mkSizeContext(outputs: Size[Coll[Box]],
+ inputs: Size[Coll[Box]],
+ dataInputs: Size[Coll[Box]],
+ selfBox: Size[Box],
+ lastBlockUtxoRootHash: Size[AvlTree],
+ headers: Size[Coll[Header]],
+ preHeader: Size[PreHeader],
+ vars: Coll[Size[AnyValue]]): SizeContext
+}
+
+
diff --git a/sigma-api/src/main/scala/special/sigma/SigmaAnnotations.scala b/sigma-api/src/main/scala/special/sigma/SigmaAnnotations.scala
new file mode 100644
index 0000000000..65cbcb68c5
--- /dev/null
+++ b/sigma-api/src/main/scala/special/sigma/SigmaAnnotations.scala
@@ -0,0 +1,9 @@
+package special.sigma
+
+import scala.annotation.Annotation
+import scalan.lang
+
+@lang("sigmalang")
+class sigmalang extends Annotation {}
+
+@sigmalang class clause extends Annotation
diff --git a/sigma-api/src/main/scala/special/sigma/SigmaDsl.scala b/sigma-api/src/main/scala/special/sigma/SigmaDsl.scala
new file mode 100644
index 0000000000..b6e989c044
--- /dev/null
+++ b/sigma-api/src/main/scala/special/sigma/SigmaDsl.scala
@@ -0,0 +1,654 @@
+package special.sigma
+
+import java.math.BigInteger
+
+import org.bouncycastle.math.ec.custom.sec.SecP256K1Point
+import org.bouncycastle.math.ec.ECPoint
+
+import scala.reflect.ClassTag
+import special.collection._
+import scalan._
+
+@scalan.Liftable
+trait CostModel {
+ def AccessBox: Int // costOf("AccessBox: Context => Box")
+ def AccessAvlTree: Int // costOf("AccessAvlTree: Context => AvlTree")
+
+ def GetVar: Int // costOf("ContextVar: (Context, Byte) => Option[T]")
+ def DeserializeVar: Int // costOf("DeserializeVar: (Context, Byte) => Option[T]")
+
+ def GetRegister: Int // costOf("AccessRegister: (Box,Byte) => Option[T]")
+ def DeserializeRegister: Int // costOf("DeserializeRegister: (Box,Byte) => Option[T]")
+
+ def SelectField: Int // costOf("SelectField")
+ def CollectionConst: Int // costOf("Const: () => Array[IV]")
+ def AccessKiloByteOfData: Int // costOf("AccessKiloByteOfData")
+ @Reified("T") def dataSize[T](x: T)(implicit cT: ClassTag[T]): Long
+ /** Size of public key in bytes */
+ def PubKeySize: Long
+}
+
+/**
+ * All `modQ` operations assume that Q is a global constant (an order of the only one cryptographically strong group
+ * which is used for all cryptographic operations).
+ * So it is globally and implicitly used in all methods.
+ * */
+@scalan.Liftable
+trait BigInt {
+ @Internal
+ private[sigma] def value: BigInteger
+ /** Convert this BigInt value to Byte.
+ * @throws ArithmeticException if overflow happens.
+ */
+ def toByte: Byte
+
+ /** Convert this BigInt value to Short.
+ * @throws ArithmeticException if overflow happens.
+ */
+ def toShort: Short
+
+ /** Convert this BigInt value to Int.
+ * @throws ArithmeticException if overflow happens.
+ */
+ def toInt: Int
+
+ /** Convert this BigInt value to Int.
+ * @throws ArithmeticException if overflow happens.
+ */
+ def toLong: Long
+
+ /** Returns a big-endian representation of this BigInt in a collection of bytes.
+ * For example, the value {@code 0x1213141516171819} would yield the
+ * byte array {@code {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}}.
+ * @since 2.0
+ */
+ def toBytes: Coll[Byte]
+
+ /** Returns a big-endian representation of this BigInt in a collection of Booleans.
+ * Each boolean corresponds to one bit of the representation.
+ * @since 2.0
+ */
+ def toBits: Coll[Boolean]
+
+ /** Absolute value of this numeric value.
+ * @since 2.0
+ */
+ def toAbs: BigInt
+
+ /** Compares this numeric with that numeric for order. Returns a negative integer, zero, or a positive integer as the
+ * `this` is less than, equal to, or greater than `that`.
+ */
+ def compareTo(that: BigInt): Int
+
+ /** Returns this `mod` Q, i.e. remainder of division by Q, where Q is an order of the cryprographic group.
+ * @since 2.0
+ */
+ def modQ: BigInt
+
+ /** Adds this number with `other` by module Q.
+ * @since 2.0
+ */
+ def plusModQ(other: BigInt): BigInt
+
+ /** Subracts this number with `other` by module Q.
+ * @since 2.0
+ */
+ def minusModQ(other: BigInt): BigInt
+
+ /** Multiply this number with `other` by module Q.
+ * @since 2.0
+ */
+ def multModQ(other: BigInt): BigInt
+
+ /** Multiply this number with `other` by module Q.
+ * @since Mainnet
+ */
+ def inverseModQ: BigInt // ??? @kushti do we need it
+
+ /** Returns the signum function of this BigInt.
+ *
+ * @return -1, 0 or 1 as the value of this BigInt is negative, zero or
+ * positive.
+ */
+ def signum: Int
+
+ /** Returns a BigInt whose value is {@code (this + that)}.
+ *
+ * @param that value to be added to this BigInt.
+ * @return { @code this + that}
+ */
+ def add(that: BigInt): BigInt
+
+ /** Returns a BigInt whose value is {@code (this - that)}.
+ *
+ * @param that value to be subtracted from this BigInt.
+ * @return { @code this - that}
+ */
+ def subtract(that: BigInt): BigInt
+
+ /** Returns a BigInt whose value is {@code (this * that)}.
+ *
+ * @implNote An implementation may offer better algorithmic
+ * performance when { @code that == this}.
+ * @param that value to be multiplied by this BigInt.
+ * @return { @code this * that}
+ */
+ def multiply(that: BigInt): BigInt
+
+ /** Returns a BigInt whose value is {@code (this / that)}.
+ *
+ * @param that value by which this BigInt is to be divided.
+ * @return { @code this / that}
+ * @throws ArithmeticException if { @code that} is zero.
+ */
+ def divide(that: BigInt): BigInt
+
+ /**
+ * Returns a BigInt whose value is {@code (this mod m}). This method
+ * differs from {@code remainder} in that it always returns a
+ * non-negative BigInteger.
+ *
+ * @param m the modulus.
+ * @return { @code this mod m}
+ * @throws ArithmeticException { @code m} ≤ 0
+ * @see #remainder
+ */
+ def mod(m: BigInt): BigInt
+
+ /**
+ * Returns a BigInt whose value is {@code (this % that)}.
+ *
+ * @param that value by which this BigInt is to be divided, and the
+ * remainder computed.
+ * @return { @code this % that}
+ * @throws ArithmeticException if { @code that} is zero.
+ */
+ def remainder(that: BigInt): BigInt
+
+ /**
+ * Returns the minimum of this BigInteger and {@code val}.
+ *
+ * @param val value with which the minimum is to be computed.
+ * @return the BigInteger whose value is the lesser of this BigInteger and
+ * { @code val}. If they are equal, either may be returned.
+ */
+ def min(that: BigInt): BigInt
+
+ /**
+ * Returns the maximum of this BigInteger and {@code val}.
+ *
+ * @param val value with which the maximum is to be computed.
+ * @return the BigInteger whose value is the greater of this and
+ * { @code val}. If they are equal, either may be returned.
+ */
+ def max(that: BigInt): BigInt
+
+ /** Returns a BigInt whose value is {@code (-this)}.
+ * @return { @code -this}
+ */
+ def negate(): BigInt
+}
+
+/** Base class for points on elliptic curves.
+ */
+@scalan.Liftable
+trait GroupElement {
+ @Internal
+ private[sigma] def value: ECPoint
+
+ def isInfinity: Boolean
+
+ /** Exponentiate this GroupElement
to the given number.
+ * @param k The power.
+ * @return this to the power of k
.
+ * @since 2.0
+ */
+ def exp(k: BigInt): GroupElement
+
+ /** Group operation. */
+ def multiply(that: GroupElement): GroupElement
+
+ /** Inverse element in the group. */
+ def negate: GroupElement
+
+ /**
+ * Get an encoding of the point value, optionally in compressed format.
+ *
+ * @return the point encoding
+ */
+ def getEncoded: Coll[Byte]
+}
+
+/** Proposition which can be proven and verified by sigma protocol. */
+@scalan.Liftable
+trait SigmaProp {
+ def isValid: Boolean
+ def propBytes: Coll[Byte]
+
+ /** Logical AND between this SigmaProp and other SigmaProp.
+ * This constructs a new CAND node of sigma tree with two children. */
+ @OverloadId("and_sigma") def &&(other: SigmaProp): SigmaProp
+
+ /** Logical AND between this `SigmaProp` and `Boolean` value on the right.
+ * The boolean value will be wrapped into `SigmaProp` using `sigmaProp` function.
+ * This constructs a new CAND node of sigma tree with two children. */
+ @OverloadId("and_bool") def &&(other: Boolean): SigmaProp
+
+ /** Logical OR between this SigmaProp and other SigmaProp.
+ * This constructs a new COR node of sigma tree with two children. */
+ @OverloadId("or_sigma") def ||(other: SigmaProp): SigmaProp
+
+ /** Logical OR between this `SigmaProp` and `Boolean` value on the right.
+ * The boolean value will be wrapped into `SigmaProp` using `sigmaProp` function.
+ * This constructs a new COR node of sigma tree with two children. */
+ @OverloadId("or_bool") def ||(other: Boolean): SigmaProp
+}
+
+@scalan.Liftable
+trait AnyValue {
+ def value: Any
+ def tVal: RType[Any]
+}
+
+@scalan.Liftable
+trait Box {
+ /** Blake2b256 hash of this box's content, basically equals to `blake2b256(bytes)` */
+ def id: Coll[Byte]
+
+ /** Mandatory: Monetary value, in Ergo tokens (NanoErg unit of measure)*/
+ def value: Long
+
+ /** Serialized bytes of guarding script, which should be evaluated to true in order to
+ * open this box. (aka spend it in a transaction)*/
+ def propositionBytes: Coll[Byte]
+
+ /** Serialized bytes of this box's content, including proposition bytes. */
+ def bytes: Coll[Byte]
+
+ /** Serialized bytes of this box's content, excluding transactionId and index of output. */
+ def bytesWithoutRef: Coll[Byte]
+
+ def registers: Coll[AnyValue]
+
+ /** Extracts register by id and type.
+ * @param regId zero-based identifier of the register.
+ * @tparam T expected type of the register.
+ * @return Some(value) if the register is defined and has given type.
+ * None otherwise
+ * @since 2.0
+ */
+ def getReg[@Reified T](i: Int)(implicit cT: RType[T]): Option[T]
+
+ /** Mandatory: Monetary value, in Ergo tokens */
+ def R0[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](0)
+
+ /** Mandatory: Guarding script */
+ def R1[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](1)
+
+ /** Mandatory: Secondary tokens */
+ def R2[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](2)
+
+ /** Mandatory: Reference to transaction and output id where the box was created */
+ def R3[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](3)
+
+ /** Non-mandatory register */
+ def R4[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](4)
+ /** Non-mandatory register */
+ def R5[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](5)
+ /** Non-mandatory register */
+ def R6[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](6)
+ /** Non-mandatory register */
+ def R7[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](7)
+ /** Non-mandatory register */
+ def R8[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](8)
+ /** Non-mandatory register */
+ def R9[@Reified T](implicit cT:RType[T]): Option[T] = this.getReg[T](9)
+
+ /** Secondary tokens */
+ def tokens: Coll[(Coll[Byte], Long)]
+
+ /** If `tx` is a transaction which generated this box, then `creationInfo._1` is a height of the tx's block.
+ * The `creationInfo._2` is a serialized transaction identifier followed by box index in the transaction outputs.
+ */
+ def creationInfo: (Int, Coll[Byte])
+
+ /** Extracts register as Coll[Byte], deserializes it to script and then executes this script in the current context.
+ * The original Coll[Byte] of the script is available as getReg[Coll[Byte]](id)
+ * @param regId identifier of the register
+ * @tparam T result type of the deserialized script.
+ * @throws IllegalArgumentException if the actual script type doesn't conform to `T`
+ * @return result of the script execution in the current context
+ * @since Mainnet
+ */
+ def executeFromRegister[@Reified T](regId: Byte)(implicit cT:RType[T]): T
+
+ @Internal
+ override def toString = s"Box(id=$id; value=$value; regs=$registers)"
+}
+
+/** Type of data which efficiently authenticates potentially huge dataset having key-value dictionary interface.
+ * Only root hash of dynamic AVL+ tree, tree height, key length, optional value length, and access flags are stored
+ * in an instance of the datatype.
+ *
+ * Please note that standard hash function from `scorex.crypto.hash` is used, and height is stored along with root hash of
+ * the tree, thus `digest` size is always CryptoConstants.hashLength + 1 bytes.
+ */
+@scalan.Liftable
+trait AvlTree {
+ /** Returns digest of the state represent by this tree.
+ * Authenticated tree digest: root hash along with tree height
+ * @since 2.0
+ */
+ def digest: Coll[Byte]
+
+ /** Flags of enabled operations packed in single byte.
+ * isInsertAllowed == (enabledOperations & 0x01) != 0
+ * isUpdateAllowed == (enabledOperations & 0x02) != 0
+ * isRemoveAllowed == (enabledOperations & 0x04) != 0
+ */
+ def enabledOperations: Byte
+
+ /** All the elements under the tree have the same length of the keys */
+ def keyLength: Int
+
+ /** If non-empty, all the values under the tree are of the same length. */
+ def valueLengthOpt: Option[Int]
+
+ /** Checks if Insert operation is allowed for this tree instance. */
+ def isInsertAllowed: Boolean
+
+ /** Checks if Update operation is allowed for this tree instance. */
+ def isUpdateAllowed: Boolean
+
+ /** Checks if Remove operation is allowed for this tree instance. */
+ def isRemoveAllowed: Boolean
+
+ /** Replace digest of this tree producing a new tree.
+ * Since AvlTree is immutable, this tree instance remains unchanged.
+ * @param newDigest a new digest
+ * @return a copy of this AvlTree instance where `this.digest` replaced by `newDigest`
+ */
+ def updateDigest(newDigest: Coll[Byte]): AvlTree
+
+ /** Enable/disable operations of this tree producing a new tree.
+ * Since AvlTree is immutable, `this` tree instance remains unchanged.
+ * @param newOperations a new flags which specify available operations on a new tree.
+ * @return a copy of this AvlTree instance where `this.enabledOperations`
+ * replaced by `newOperations`
+ */
+ def updateOperations(newOperations: Byte): AvlTree
+
+ /** Checks if an entry with key `key` exists in this tree using proof `proof`.
+ * Throws exception if proof is incorrect
+ * Return `true` if a leaf with the key `key` exists
+ * Return `false` if leaf with provided key does not exist.
+ * @param key a key of an element of this authenticated dictionary.
+ * @param proof
+ */
+ def contains(key: Coll[Byte], proof: Coll[Byte]): Boolean
+
+ /** Perform a lookup of key `key` in this tree using proof `proof`.
+ * Throws exception if proof is incorrect
+ * Return Some(bytes) of leaf with key `key` if it exists
+ * Return None if leaf with provided key does not exist.
+ * @param key a key of an element of this authenticated dictionary.
+ * @param proof
+ */
+ def get(key: Coll[Byte], proof: Coll[Byte]): Option[Coll[Byte]]
+
+ /** Perform a lookup of many keys `keys` in this tree using proof `proof`.
+ * For each key return Some(bytes) of leaf if it exists and None if is doesn't.
+ * @param keys keys of elements of this authenticated dictionary.
+ * @param proof
+ */
+ def getMany(keys: Coll[Coll[Byte]], proof: Coll[Byte]): Coll[Option[Coll[Byte]]]
+
+ /** Perform insertions of key-value entries into this tree using proof `proof`.
+ * Throws exception if proof is incorrect
+ * Return Some(newTree) if successful
+ * Return None if operations were not performed.
+ * @param operations collection of key-value pairs to insert in this authenticated dictionary.
+ * @param proof
+ */
+ def insert(operations: Coll[(Coll[Byte], Coll[Byte])], proof: Coll[Byte]): Option[AvlTree]
+
+ /** Perform updates of key-value entries into this tree using proof `proof`.
+ * Throws exception if proof is incorrect
+ * Return Some(newTree) if successful
+ * Return None if operations were not performed.
+ * @param operations collection of key-value pairs to update in this authenticated dictionary.
+ * @param proof
+ */
+ def update(operations: Coll[(Coll[Byte], Coll[Byte])], proof: Coll[Byte]): Option[AvlTree]
+
+ /** Perform removal of entries into this tree using proof `proof`.
+ * Throws exception if proof is incorrect
+ * Return Some(newTree) if successful
+ * Return None if operations were not performed.
+ * @param operations collection of keys to remove from this authenticated dictionary.
+ * @param proof
+ */
+ def remove(operations: Coll[Coll[Byte]], proof: Coll[Byte]): Option[AvlTree]
+}
+
+/** Only header fields that can be predicted by a miner.
+ * @since 2.0
+ */
+@scalan.Liftable
+trait PreHeader { // Testnet2
+ /** Block version, to be increased on every soft and hardfork. */
+ def version: Byte
+
+ /** Id of parent block */
+ def parentId: Coll[Byte] // ModifierId
+
+ /** Block timestamp (in milliseconds since beginning of Unix Epoch) */
+ def timestamp: Long
+
+ /** Current difficulty in a compressed view.
+ * NOTE: actually it is unsigned Int*/
+ def nBits: Long // actually it is unsigned Int
+
+ /** Block height */
+ def height: Int
+
+ /** Miner public key. Should be used to collect block rewards. */
+ def minerPk: GroupElement
+
+ def votes: Coll[Byte]
+}
+
+/** Represents data of the block header available in Sigma propositions.
+ * @since 2.0
+ */
+@scalan.Liftable
+trait Header {
+ /** Bytes representation of ModifierId of this Header */
+ def id: Coll[Byte]
+
+ /** Block version, to be increased on every soft and hardfork. */
+ def version: Byte
+
+ /** Bytes representation of ModifierId of the parent block */
+ def parentId: Coll[Byte] //
+
+ /** Hash of ADProofs for transactions in a block */
+ def ADProofsRoot: Coll[Byte] // Digest32. Can we build AvlTree out of it?
+
+ /** AvlTree) of a state after block application */
+ def stateRoot: AvlTree
+
+ /** Root hash (for a Merkle tree) of transactions in a block. */
+ def transactionsRoot: Coll[Byte] // Digest32
+
+ /** Block timestamp (in milliseconds since beginning of Unix Epoch) */
+ def timestamp: Long
+
+ /** Current difficulty in a compressed view.
+ * NOTE: actually it is unsigned Int*/
+ def nBits: Long
+
+ /** Block height */
+ def height: Int
+
+ /** Root hash of extension section */
+ def extensionRoot: Coll[Byte] // Digest32
+
+ /** Miner public key. Should be used to collect block rewards.
+ * Part of Autolykos solution. */
+ def minerPk: GroupElement
+
+ /** One-time public key. Prevents revealing of miners secret. */
+ def powOnetimePk: GroupElement
+
+ /** nonce */
+ def powNonce: Coll[Byte]
+
+ /** Distance between pseudo-random number, corresponding to nonce `powNonce` and a secret,
+ * corresponding to `minerPk`. The lower `powDistance` is, the harder it was to find this solution. */
+ def powDistance: BigInt
+
+ def votes: Coll[Byte] //3 bytes
+}
+
+/** Represents data available in Sigma language using `CONTEXT` global variable*/
+@scalan.Liftable
+trait Context {
+ def builder: SigmaDslBuilder
+
+ /** A collection of outputs of the current transaction. */
+ def OUTPUTS: Coll[Box]
+
+ /** A collection of inputs of the current transaction, the transaction where selfBox is one of the inputs. */
+ def INPUTS: Coll[Box]
+
+ /** A collection of inputs of the current transaction that will not be spent. */
+ def dataInputs: Coll[Box]
+
+ /** Height (block number) of the block which is currently being validated. */
+ def HEIGHT: Int
+
+ /** Box whose proposition is being currently executing */
+ def SELF: Box
+
+ /** Zero based index in `inputs` of `selfBox`. -1 if self box is not in the INPUTS collection. */
+ def selfBoxIndex: Int
+
+ /** Authenticated dynamic dictionary digest representing Utxo state before current state. */
+ def LastBlockUtxoRootHash: AvlTree
+
+ /**
+ * @since 2.0
+ */
+ def headers: Coll[Header]
+
+ /**
+ * @since 2.0
+ */
+ def preHeader: PreHeader
+
+ def minerPubKey: Coll[Byte]
+ def getVar[T](id: Byte)(implicit cT: RType[T]): Option[T]
+ def vars: Coll[AnyValue]
+}
+
+@scalan.Liftable
+trait SigmaContract {
+ def builder: SigmaDslBuilder
+
+ @NeverInline
+ @Reified("T")
+ def Collection[T](items: T*)(implicit cT: RType[T]): Coll[T] = this.builder.Colls.fromItems[T](items:_*)
+
+ /** !!! all methods should delegate to builder */
+
+ def verifyZK(cond: => SigmaProp): Boolean = this.builder.verifyZK(cond)
+ def atLeast(bound: Int, props: Coll[SigmaProp]): SigmaProp = this.builder.atLeast(bound, props)
+
+ def allOf(conditions: Coll[Boolean]): Boolean = this.builder.allOf(conditions)
+ def allZK(conditions: Coll[SigmaProp]): SigmaProp = this.builder.allZK(conditions)
+
+ def anyOf(conditions: Coll[Boolean]): Boolean = this.builder.anyOf(conditions)
+ def anyZK(conditions: Coll[SigmaProp]): SigmaProp = this.builder.anyZK(conditions)
+
+ def xorOf(conditions: Coll[Boolean]): Boolean = this.builder.xorOf(conditions)
+
+ def PubKey(base64String: String): SigmaProp = this.builder.PubKey(base64String)
+
+ def sigmaProp(b: Boolean): SigmaProp = this.builder.sigmaProp(b)
+
+ def blake2b256(bytes: Coll[Byte]): Coll[Byte] = this.builder.blake2b256(bytes)
+ def sha256(bytes: Coll[Byte]): Coll[Byte] = this.builder.sha256(bytes)
+
+ def byteArrayToBigInt(bytes: Coll[Byte]): BigInt = this.builder.byteArrayToBigInt(bytes)
+ def longToByteArray(l: Long): Coll[Byte] = this.builder.longToByteArray(l)
+ def byteArrayToLong(bytes: Coll[Byte]): Long = this.builder.byteArrayToLong(bytes)
+
+ def proveDlog(g: GroupElement): SigmaProp = this.builder.proveDlog(g)
+ def proveDHTuple(g: GroupElement, h: GroupElement, u: GroupElement, v: GroupElement): SigmaProp =
+ this.builder.proveDHTuple(g, h, u, v)
+
+ def groupGenerator: GroupElement = this.builder.groupGenerator
+
+ def decodePoint(encoded: Coll[Byte]): GroupElement = this.builder.decodePoint(encoded)
+
+ @Reified("T")
+ def substConstants[T](scriptBytes: Coll[Byte],
+ positions: Coll[Int],
+ newValues: Coll[T])
+ (implicit cT: RType[T]): Coll[Byte] = this.builder.substConstants(scriptBytes, positions, newValues)
+
+ @clause def canOpen(ctx: Context): Boolean
+
+ def asFunction: Context => Boolean = (ctx: Context) => this.canOpen(ctx)
+}
+
+@scalan.Liftable
+trait SigmaDslBuilder {
+ def Colls: CollBuilder
+ def Monoids: MonoidBuilder
+ def Costing: CostedBuilder
+ def CostModel: CostModel
+
+ def verifyZK(cond: => SigmaProp): Boolean
+
+ def atLeast(bound: Int, props: Coll[SigmaProp]): SigmaProp
+
+ def allOf(conditions: Coll[Boolean]): Boolean
+ def allZK(conditions: Coll[SigmaProp]): SigmaProp
+
+ def anyOf(conditions: Coll[Boolean]): Boolean
+ def anyZK(conditions: Coll[SigmaProp]): SigmaProp
+
+ def xorOf(conditions: Coll[Boolean]): Boolean
+
+ def PubKey(base64String: String): SigmaProp
+
+ def sigmaProp(b: Boolean): SigmaProp
+
+ def blake2b256(bytes: Coll[Byte]): Coll[Byte]
+ def sha256(bytes: Coll[Byte]): Coll[Byte]
+
+ def byteArrayToBigInt(bytes: Coll[Byte]): BigInt
+ def longToByteArray(l: Long): Coll[Byte]
+ def byteArrayToLong(bytes: Coll[Byte]): Long
+
+ def proveDlog(g: GroupElement): SigmaProp
+ def proveDHTuple(g: GroupElement, h: GroupElement, u: GroupElement, v: GroupElement): SigmaProp
+
+ def groupGenerator: GroupElement
+
+ @Reified("T")
+ def substConstants[T](scriptBytes: Coll[Byte], positions: Coll[Int], newValues: Coll[T])(implicit cT: RType[T]): Coll[Byte]
+ def decodePoint(encoded: Coll[Byte]): GroupElement
+
+ /** Create DSL big integer from existing `java.math.BigInteger`*/
+ def BigInt(n: BigInteger): BigInt
+
+ /** Extract `java.math.BigInteger` from DSL's `BigInt` type*/
+ def toBigInteger(n: BigInt): BigInteger
+
+ /** Construct a new authenticated dictionary with given parameters and tree root digest. */
+ def avlTree(operationFlags: Byte, digest: Coll[Byte], keyLength: Int, valueLengthOpt: Option[Int]): AvlTree
+}
+
diff --git a/sigma-api/src/main/scala/special/sigma/SigmaExamples.scala b/sigma-api/src/main/scala/special/sigma/SigmaExamples.scala
new file mode 100644
index 0000000000..850a506873
--- /dev/null
+++ b/sigma-api/src/main/scala/special/sigma/SigmaExamples.scala
@@ -0,0 +1,121 @@
+package special.sigma
+
+import special.collection.Coll
+
+import scalan.RType
+import RType._
+
+trait CrowdFunding extends SigmaContract {
+ def deadline: Long
+ def minToRaise: Long
+ def backerPubKey: SigmaProp
+ def projectPubKey: SigmaProp
+
+ @clause def canOpen(ctx: Context) = verifyZK {
+ val fundraisingFailure = sigmaProp(ctx.HEIGHT >= deadline) && backerPubKey
+ val enoughRaised = (outBox: Box) => {
+ outBox.value >= minToRaise &&
+ outBox.propositionBytes == projectPubKey.propBytes
+ }
+ val fundraisingSuccess = ctx.HEIGHT < deadline &&
+ projectPubKey.isValid &&
+ ctx.OUTPUTS.exists(enoughRaised)
+
+ fundraisingFailure || fundraisingSuccess
+ }
+}
+
+trait CrossChainAtomicSwap extends SigmaContract {
+ def deadlineBob: Long
+ def deadlineAlice: Long
+ def pkA: SigmaProp
+ def pkB: SigmaProp
+ def hx: Coll[Byte]
+
+ def templateForBobChain(ctx: Context) = verifyZK {
+ anyZK(Collection(
+ sigmaProp(ctx.HEIGHT > deadlineBob) && pkA,
+ pkB && blake2b256(ctx.getVar[Coll[Byte]](1).get) == hx
+ ))
+ }
+
+ def templateForAliceChain(ctx: Context) = verifyZK {
+ val x = ctx.getVar[Coll[Byte]](1).get
+ anyZK(Collection(
+ sigmaProp(ctx.HEIGHT > deadlineAlice) && pkB,
+ allZK( Collection(
+ pkA,
+ sigmaProp(x.length < 33),
+ sigmaProp(blake2b256(x) == hx)
+ ))
+ ))
+ }
+}
+
+trait InChainAtomicSwap extends SigmaContract {
+ def deadline: Long
+ def pkA: SigmaProp
+ def pkB: SigmaProp
+ def token1: Coll[Byte]
+
+ def templateForAlice(ctx: Context) = verifyZK {
+ (pkA && ctx.HEIGHT > deadline) || {
+ val tokenData = ctx.OUTPUTS(0).tokens(0)
+ allOf(Collection(
+ tokenData._1 == token1,
+ tokenData._2 >= 60L,
+ ctx.OUTPUTS(0).propositionBytes == pkA.propBytes,
+ ctx.OUTPUTS(0).value >= 1L
+ ))
+ }
+ }
+ def templateForBob(ctx: Context) = verifyZK {
+ (pkB && ctx.HEIGHT > deadline) ||
+ allOf( Collection(
+ ctx.OUTPUTS(1).value >= 100,
+ ctx.OUTPUTS(1).propositionBytes == pkB.propBytes
+ ))
+ }
+}
+
+trait CoinEmission extends SigmaContract {
+ def fixedRatePeriod: Long
+ def epochLength: Long
+ def fixedRate: Long
+ def oneEpochReduction: Long
+
+ def templateForTotalAmountBox(ctx: Context) = {
+ val epoch = 1L + ((ctx.HEIGHT - fixedRatePeriod) / epochLength)
+ val out = ctx.OUTPUTS(0)
+ val coinsToIssue =
+ if (ctx.HEIGHT < fixedRatePeriod) fixedRate
+ else fixedRate - (oneEpochReduction * epoch)
+ val correctCoinsConsumed = coinsToIssue == (ctx.SELF.value - out.value)
+ val sameScriptRule = ctx.SELF.propositionBytes == out.propositionBytes
+ val heightIncreased = ctx.HEIGHT > ctx.SELF.getReg[Long](4).get
+ val heightCorrect = out.getReg[Long](4).get == ctx.HEIGHT
+ val lastCoins = ctx.SELF.value <= oneEpochReduction
+ allOf(Collection(
+ correctCoinsConsumed,
+ heightCorrect,
+ heightIncreased,
+ sameScriptRule)) ||
+ (heightIncreased && lastCoins)
+ }
+}
+
+trait DemurrageCurrency extends SigmaContract {
+ def demurragePeriod: Int
+ def demurrageCost: Long
+ def regScript: SigmaProp
+
+ @clause def canOpen(ctx: Context) = verifyZK {
+ val c2 =
+ ctx.HEIGHT >= ctx.SELF.getReg[Int](4).get + demurragePeriod &&
+ ctx.OUTPUTS.exists(out => {
+ out.value >= ctx.SELF.value - demurrageCost && out.propositionBytes == ctx.SELF.propositionBytes
+ })
+ regScript || c2
+ }
+}
+
diff --git a/sigma-api/src/main/scala/special/sigma/SigmaPredef.scala b/sigma-api/src/main/scala/special/sigma/SigmaPredef.scala
new file mode 100644
index 0000000000..708d75d4e0
--- /dev/null
+++ b/sigma-api/src/main/scala/special/sigma/SigmaPredef.scala
@@ -0,0 +1,31 @@
+package special.sigma
+
+import org.bouncycastle.math.ec.ECPoint
+
+import scala.reflect.ClassTag
+
+object SigmaPredef {
+ def dataSize[T](v: T): Long = v match {
+ case _: Boolean => 1
+ case _: Byte => 1
+ case _: Short => 2
+ case _: Int => 4
+ case _: Long => 8
+// case b: Box => b.dataSize
+ case _ => sys.error(s"Cannot compute dataSize($v)")
+ }
+
+ //TODO chack how it can be implemented
+// def sizeOf[T](implicit cT: ClassTag[T]): Long = cT match {
+// case _: ClassTag[Boolean] => 1
+// case _: ClassTag[Byte => 1
+// case _: Short => 2
+// case _: Int => 4
+// case _: Long => 8
+// case b: Box => b.dataSize
+// case p: ECPoint => p.getEncoded(true).length
+// }
+
+}
+
+
diff --git a/sigma-api/src/main/scala/special/sigma/package.scala b/sigma-api/src/main/scala/special/sigma/package.scala
new file mode 100644
index 0000000000..04050c3612
--- /dev/null
+++ b/sigma-api/src/main/scala/special/sigma/package.scala
@@ -0,0 +1,66 @@
+package special
+
+import java.math.BigInteger
+
+import org.bouncycastle.math.ec.ECPoint
+import scalan.RType
+import scalan.RType.GeneralType
+
+import scala.reflect.{ClassTag, classTag}
+
+package sigma {
+
+ case class WrapperType[Wrapper](cWrapper: ClassTag[Wrapper]) extends RType[Wrapper] {
+ override def classTag: ClassTag[Wrapper] = cWrapper
+ override def toString: String = cWrapper.toString
+ override def name: String = cWrapper.runtimeClass.getSimpleName
+ override def isConstantSize: Boolean = false // pessimistic but safe default
+ }
+
+}
+
+package object sigma {
+ def wrapperType[W: ClassTag]: RType[W] = WrapperType(classTag[W])
+
+ // TODO make these types into GeneralType (same as Header and PreHeader)
+ implicit val BigIntRType: RType[BigInt] = new WrapperType(classTag[BigInt]) {
+ override def isConstantSize: Boolean = true
+ }
+ implicit val GroupElementRType: RType[GroupElement] = new WrapperType(classTag[GroupElement]) {
+ override def isConstantSize: Boolean = true
+ }
+ implicit val SigmaPropRType: RType[SigmaProp] = wrapperType[SigmaProp]
+ implicit val BoxRType: RType[Box] = wrapperType[Box]
+ implicit val AvlTreeRType: RType[AvlTree] = wrapperType[AvlTree]
+ implicit val ContextRType: RType[Context] = wrapperType[Context]
+
+ // these are not wrapper types since they are used directly in ErgoTree values (e.g. Constants)
+ // and no conversion is necessary
+ implicit val HeaderRType: RType[Header] = new GeneralType(classTag[Header]) {
+ override def isConstantSize: Boolean = true
+ }
+ implicit val PreHeaderRType: RType[PreHeader] = new GeneralType(classTag[PreHeader]) {
+ override def isConstantSize: Boolean = true
+ }
+
+ implicit val AnyValueRType: RType[AnyValue] = RType.fromClassTag(classTag[AnyValue])
+ implicit val CostModelRType: RType[CostModel] = RType.fromClassTag(classTag[CostModel])
+
+
+ implicit val SigmaContractRType: RType[SigmaContract] = RType.fromClassTag(classTag[SigmaContract])
+ implicit val SigmaDslBuilderRType: RType[SigmaDslBuilder] = RType.fromClassTag(classTag[SigmaDslBuilder])
+
+ implicit val BigIntegerRType: RType[BigInteger] = new GeneralType(classTag[BigInteger]) {
+ override def isConstantSize: Boolean = true
+ }
+ implicit val ECPointRType: RType[ECPoint] = new GeneralType(classTag[ECPoint]) {
+ override def isConstantSize: Boolean = true
+ }
+
+
+ implicit val SizeAnyValueRType: RType[SizeAnyValue] = RType.fromClassTag(classTag[SizeAnyValue])
+ implicit val SizeSigmaPropRType: RType[SizeSigmaProp] = RType.fromClassTag(classTag[SizeSigmaProp])
+ implicit val SizeBoxRType: RType[SizeBox] = RType.fromClassTag(classTag[SizeBox])
+ implicit val SizeContextRType: RType[SizeContext] = RType.fromClassTag(classTag[SizeContext])
+ implicit val SizeBuilderRType: RType[SizeBuilder] = RType.fromClassTag(classTag[SizeBuilder])
+}
\ No newline at end of file
diff --git a/sigma-api/src/main/scala/special/sigma/wrappers/WrappersSpec.scala b/sigma-api/src/main/scala/special/sigma/wrappers/WrappersSpec.scala
new file mode 100644
index 0000000000..64dc5499bb
--- /dev/null
+++ b/sigma-api/src/main/scala/special/sigma/wrappers/WrappersSpec.scala
@@ -0,0 +1,71 @@
+package special.sigma.wrappers
+
+import java.math.BigInteger
+
+import scalan.WrapSpec
+import special.wrappers.{WrapSpecBase}
+import org.bouncycastle.math.ec.ECPoint
+import special.sigma.SigmaPredef
+
+import scala.reflect.ClassTag
+
+trait ECPointWrapSpec extends WrapSpecBase {
+ //todo remove compressed flag, use GroupElementSerializer
+ def getEncoded[A](g: ECPoint, compressed: Boolean): Array[Byte] = g.getEncoded(compressed)
+ def multiply(l: ECPoint, r: BigInteger) = l.multiply(r)
+ def add(l: ECPoint, r: ECPoint) = l.add(r)
+}
+
+trait BigIntegerWrapSpec extends WrapSpecBase {
+ def fromString(s: String) = new BigInteger(s)
+ def fromArray(sig: Int, arr: Array[Byte]) = new BigInteger(sig, arr)
+// def ZERO = BigInteger.ZERO
+// def ONE = BigInteger.ONE
+ def valueOf(l: Long) = BigInteger.valueOf(l)
+// def toString(l: BigInteger, radix: Int) = l.toString(radix)
+ def toByteArray(l: BigInteger): Array[Byte] = l.toByteArray()
+ def add(l: BigInteger, r: BigInteger) = l.add(r)
+ def subtract(l: BigInteger, r: BigInteger) = l.subtract(r)
+ def multiply(l: BigInteger, r: BigInteger) = l.multiply(r)
+ def mod(l: BigInteger, r: BigInteger) = l.mod(r)
+ def modInverse(l: BigInteger, r: BigInteger) = l.modInverse(r)
+ def modPow(l: BigInteger, exponent: BigInteger, m: BigInteger) = l.modPow(exponent, m)
+ def remainder(l: BigInteger, r: BigInteger) = l.remainder(r)
+ def divide(l: BigInteger, r: BigInteger) = l.divide(r)
+ def compareTo(l: BigInteger, r: BigInteger) = l.compareTo(r)
+ def min(l: BigInteger, r: BigInteger) = l.min(r)
+ def max(l: BigInteger, r: BigInteger) = l.max(r)
+ def gcd(l: BigInteger, r: BigInteger) = l.gcd(r)
+ def and(l: BigInteger, r: BigInteger) = l.and(r)
+ def or(l: BigInteger, r: BigInteger) = l.or(r)
+ def xor(l: BigInteger, r: BigInteger) = l.xor(r)
+ def not(l: BigInteger) = l.not()
+ def andNot(l: BigInteger, r: BigInteger) = l.andNot(r)
+ def pow(l: BigInteger, r: Int) = l.pow(r)
+ def testBit(l: BigInteger, r: Int) = l.testBit(r)
+ def setBit(l: BigInteger, r: Int) = l.setBit(r)
+ def clearBit(l: BigInteger, r: Int) = l.clearBit(r)
+ def flipBit(l: BigInteger, r: Int) = l.flipBit(r)
+ def getLowestSetBit(l: BigInteger) = l.getLowestSetBit()
+ def bitCount(l: BigInteger) = l.bitCount()
+ def bitLength(l: BigInteger) = l.bitLength()
+ def isProbablePrime(l: BigInteger, r: Int) = l.isProbablePrime(r)
+ def shiftLeft(l: BigInteger, r: Int) = l.shiftLeft(r)
+ def shiftRight(l: BigInteger, r: Int) = l.shiftRight(r)
+ def abs(l: BigInteger) = l.abs()
+ def negate(l: BigInteger) = l.negate()
+ def signum(l: BigInteger) = l.signum()
+ def byteValue(l: BigInteger) = l.byteValue()
+ def shortValue(l: BigInteger) = l.shortValue()
+ def intValue(l: BigInteger) = l.intValue()
+ def longValue(l: BigInteger) = l.longValue()
+ def byteValueExact(l: BigInteger) = l.byteValueExact()
+ def shortValueExact(l: BigInteger) = l.shortValueExact()
+ def intValueExact(l: BigInteger) = l.intValueExact()
+ def longValueExact(l: BigInteger) = l.longValueExact()
+
+}
+
+trait SigmaPredefWrapSpec extends WrapSpecBase {
+ def dataSize(v: Any): Long = SigmaPredef.dataSize(v)
+}
diff --git a/sigma-conf/src/main/scala/spu/device/config/SigmaLibraryConfig.scala b/sigma-conf/src/main/scala/spu/device/config/SigmaLibraryConfig.scala
new file mode 100644
index 0000000000..049af6e7ff
--- /dev/null
+++ b/sigma-conf/src/main/scala/spu/device/config/SigmaLibraryConfig.scala
@@ -0,0 +1,52 @@
+package spu.device.config
+
+import special.library.config.SpecialLibraryConfig
+
+import scalan.{FunctorType, ContainerType, Liftable}
+import scalan.meta.ScalanAst.WrapperConf
+import scalan.meta.{LibraryConfig, ConfMap, TargetModuleConf, SourceModuleConf}
+
+class SigmaLibraryConfig extends LibraryConfig {
+ def name = "sigma"
+ def baseDir = ""
+ val specialLibrary = new SpecialLibraryConfig
+
+ def wrapperConfigs: Map[String, WrapperConf] = List(
+ WrapperConf(baseDir,
+ packageName = "org.bouncycastle.math.ec",
+ name = "ECPoint",
+ annotations = List(classOf[Liftable]).map(_.getSimpleName)
+ ),
+ WrapperConf(baseDir,
+ packageName = "java.math",
+ name = "BigInteger",
+ annotations = List(classOf[Liftable]).map(_.getSimpleName)
+ ),
+ WrapperConf(baseDir,
+ packageName = "special.sigma",
+ name = "SigmaPredef"
+ )
+ ).map(w => (w.name, w)).toMap
+
+ val ApiModule: SourceModuleConf = new SourceModuleConf(baseDir, "sigma-api")
+ .moduleDependencies(specialLibrary.ApiModule)
+ .addUnit("special/sigma/wrappers/WrappersSpec.scala", wrapperConfigs)
+ .addUnit("special/sigma/SigmaDsl.scala")
+ .addUnit("special/sigma/CostedObjects.scala")
+ // .addUnit("special/sigma/SigmaExamples.scala") // TODO move to downstream library
+
+ val ImplModule = new SourceModuleConf(baseDir, "sigma-impl")
+ .moduleDependencies(specialLibrary.ApiModule, specialLibrary.ImplModule)
+ .addUnit("special/sigma/SigmaDslOverArrays.scala")
+// .addUnit("special/sigma/TestContracts.scala") // TODO move to downstream library
+ .addUnit("special/sigma/SigmaDslCosted.scala")
+ .dependsOn(ApiModule)
+
+ val TargetModule = new TargetModuleConf(baseDir, "sigma-library",
+ sourceModules = ConfMap()
+ .add(ApiModule)
+ .add(ImplModule))
+
+ def sourceModules = List(ApiModule, ImplModule)
+ def targetModules = List(TargetModule)
+}
diff --git a/sigma-impl/src/main/resources/special/sigma/SigmaDslCosted.scalan b/sigma-impl/src/main/resources/special/sigma/SigmaDslCosted.scalan
new file mode 100644
index 0000000000..a9bda5e38e
--- /dev/null
+++ b/sigma-impl/src/main/resources/special/sigma/SigmaDslCosted.scalan
@@ -0,0 +1,47 @@
+package special.sigma {
+ import scalan._
+
+ trait SigmaDslCosted extends Base { self: SigmaDslCostedModule =>
+ import AnyValue._;
+ import AvlTree._;
+ import Box._;
+ import CSizeAnyValue._;
+ import CSizeBox._;
+ import CSizeContext._;
+ import Coll._;
+ import Header._;
+ import PreHeader._;
+ import Size._;
+ import SizeAnyValue._;
+ import SizeBox._;
+ import SizeBuilder._;
+ import SizeContext._;
+ import SizeSigmaProp._;
+ import WOption._;
+ import WRType._;
+ abstract class CSizeAnyValue(val tVal: Rep[WRType[Any]], val valueSize: Rep[Size[Any]]) extends SizeAnyValue {
+ @NeverInline override def dataSize: Rep[Long] = delayInvoke
+ };
+ abstract class CSizeSigmaProp(val propBytes: Rep[Size[Coll[Byte]]]) extends SizeSigmaProp {
+ @NeverInline override def dataSize: Rep[Long] = delayInvoke
+ };
+ abstract class CSizeBox(val propositionBytes: Rep[Size[Coll[Byte]]], val bytes: Rep[Size[Coll[Byte]]], val bytesWithoutRef: Rep[Size[Coll[Byte]]], val registers: Rep[Size[Coll[WOption[AnyValue]]]], val tokens: Rep[Size[Coll[scala.Tuple2[Coll[Byte], Long]]]]) extends SizeBox {
+ @NeverInline override def dataSize: Rep[Long] = delayInvoke;
+ @NeverInline override def getReg[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = delayInvoke
+ };
+ abstract class CSizeContext(val outputs: Rep[Size[Coll[Box]]], val inputs: Rep[Size[Coll[Box]]], val dataInputs: Rep[Size[Coll[Box]]], val selfBox: Rep[Size[Box]], val lastBlockUtxoRootHash: Rep[Size[AvlTree]], val headers: Rep[Size[Coll[Header]]], val preHeader: Rep[Size[PreHeader]], val vars: Rep[Coll[Size[AnyValue]]]) extends SizeContext {
+ @NeverInline override def dataSize: Rep[Long] = delayInvoke;
+ @NeverInline override def getVar[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = delayInvoke
+ };
+ abstract class CSizeBuilder extends SizeBuilder {
+ def mkSizeAnyValue(tVal: Rep[WRType[Any]], valueSize: Rep[Size[Any]]): Rep[SizeAnyValue] = RCSizeAnyValue(tVal, valueSize);
+ def mkSizeBox(propositionBytes: Rep[Size[Coll[Byte]]], bytes: Rep[Size[Coll[Byte]]], bytesWithoutRef: Rep[Size[Coll[Byte]]], registers: Rep[Size[Coll[WOption[AnyValue]]]], tokens: Rep[Size[Coll[scala.Tuple2[Coll[Byte], Long]]]]): Rep[SizeBox] = RCSizeBox(propositionBytes, bytes, bytesWithoutRef, registers, tokens);
+ def mkSizeContext(outputs: Rep[Size[Coll[Box]]], inputs: Rep[Size[Coll[Box]]], dataInputs: Rep[Size[Coll[Box]]], selfBox: Rep[Size[Box]], lastBlockUtxoRootHash: Rep[Size[AvlTree]], headers: Rep[Size[Coll[Header]]], preHeader: Rep[Size[PreHeader]], vars: Rep[Coll[Size[AnyValue]]]): Rep[SizeContext] = RCSizeContext(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars)
+ };
+ trait CSizeAnyValueCompanion;
+ trait CSizeSigmaPropCompanion;
+ trait CSizeBoxCompanion;
+ trait CSizeContextCompanion;
+ trait CSizeBuilderCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-impl/src/main/resources/special/sigma/SigmaDslOverArrays.scalan b/sigma-impl/src/main/resources/special/sigma/SigmaDslOverArrays.scalan
new file mode 100644
index 0000000000..498d26036e
--- /dev/null
+++ b/sigma-impl/src/main/resources/special/sigma/SigmaDslOverArrays.scalan
@@ -0,0 +1,53 @@
+package special.sigma {
+ import scalan._
+
+ trait SigmaDslOverArrays extends Base { self: SigmaDslOverArraysModule =>
+ import AvlTree._;
+ import BigInt._;
+ import CCostedBuilder._;
+ import Coll._;
+ import CollBuilder._;
+ import CollOverArrayBuilder._;
+ import CostModel._;
+ import CostedBuilder._;
+ import GroupElement._;
+ import MonoidBuilder._;
+ import MonoidBuilderInst._;
+ import SigmaDslBuilder._;
+ import SigmaProp._;
+ import WBigInteger._;
+ import WECPoint._;
+ import WOption._;
+ abstract class TestSigmaDslBuilder extends SigmaDslBuilder {
+ def Colls: Rep[CollBuilder] = RCollOverArrayBuilder();
+ def Monoids: Rep[MonoidBuilder] = RMonoidBuilderInst();
+ def Costing: Rep[CostedBuilder] = RCCostedBuilder();
+ @NeverInline def CostModel: Rep[CostModel] = delayInvoke;
+ @NeverInline def verifyZK(proof: Rep[Thunk[SigmaProp]]): Rep[Boolean] = delayInvoke;
+ @NeverInline def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = delayInvoke;
+ @NeverInline def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = delayInvoke;
+ @NeverInline def allZK(props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def anyZK(props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline override def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = delayInvoke;
+ @NeverInline def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = delayInvoke;
+ @NeverInline def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = delayInvoke;
+ @NeverInline def PubKey(base64String: Rep[String]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt] = delayInvoke;
+ @NeverInline def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]] = delayInvoke;
+ @NeverInline def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long] = delayInvoke;
+ @NeverInline def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def groupGenerator: Rep[GroupElement] = delayInvoke;
+ @Reified(value = "T") @NeverInline override def substConstants[T](scriptBytes: Rep[Coll[Byte]], positions: Rep[Coll[Int]], newValues: Rep[Coll[T]])(implicit cT: Elem[T]): Rep[Coll[Byte]] = delayInvoke;
+ @NeverInline override def decodePoint(encoded: Rep[Coll[Byte]]): Rep[GroupElement] = delayInvoke;
+ @NeverInline override def BigInt(n: Rep[WBigInteger]): Rep[BigInt] = delayInvoke;
+ @NeverInline override def toBigInteger(n: Rep[BigInt]): Rep[WBigInteger] = delayInvoke;
+ @NeverInline def GroupElement(p: Rep[WECPoint]): Rep[GroupElement] = delayInvoke;
+ @NeverInline def toECPoint(ge: Rep[GroupElement]): Rep[WECPoint] = delayInvoke;
+ @NeverInline override def avlTree(operationFlags: Rep[Byte], digest: Rep[Coll[Byte]], keyLength: Rep[Int], valueLengthOpt: Rep[WOption[Int]]): Rep[AvlTree] = delayInvoke
+ };
+ trait TestSigmaDslBuilderCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-impl/src/main/scala/sigma/types/Types.scala b/sigma-impl/src/main/scala/sigma/types/Types.scala
new file mode 100644
index 0000000000..5b9528537f
--- /dev/null
+++ b/sigma-impl/src/main/scala/sigma/types/Types.scala
@@ -0,0 +1,45 @@
+package sigma.types
+
+import com.google.common.primitives.Ints
+import sigma.util.Extensions._
+import special.collection.{Coll, Builder}
+
+case class CBoolean(value: scala.Boolean) extends Boolean {
+ override def toByte: Byte = CByte(if (value) 1 else 0)
+ override def xor(y: Boolean): Boolean = CBoolean(value ^ y.value)
+}
+
+case class CByte(value: scala.Byte) extends Byte {
+ override def toInt: Int = CInt(value.toInt)
+
+ override def +(y: Byte): Byte = CByte(value.addExact(y.value))
+}
+
+case class CInt(value: scala.Int) extends Int {
+ override def toByte: Byte = CByte(value.toByteExact)
+ override def +(that: Int): Int = CInt(value + that.value)
+
+ /** Returns a big-endian representation of this Int in a collection of bytes.
+ * For example, the Int value {@code 0x12131415} would yield the
+ * byte array {@code {0x12, 0x13, 0x14, 0x15}}.
+ * @since 2.0
+ */
+ def toBytes: Coll[Byte] = ??? //Builder.DefaultCollBuilder.viewColl(Ints.toByteArray(value))
+
+ /** Returns a big-endian representation of this numeric in a collection of Booleans.
+ * Each boolean corresponds to one bit.
+ * @since 2.0
+ */
+ def toBits: Coll[Boolean] = ???
+
+ /** Absolute value of this numeric value.
+ * @since 2.0
+ */
+ def abs: Int = CInt(if (value < 0) -value else value)
+
+ /** Compares this numeric with that numeric for order. Returns a negative integer, zero, or a positive integer as the
+ * `this` is less than, equal to, or greater than `that`.
+ */
+ override def compareTo(that: Int): Int = CInt(if (value < that.value) -1 else if (value == that.value) 0 else 1)
+}
+
diff --git a/sigma-impl/src/main/scala/sigma/types/View.scala b/sigma-impl/src/main/scala/sigma/types/View.scala
new file mode 100644
index 0000000000..fafb84e277
--- /dev/null
+++ b/sigma-impl/src/main/scala/sigma/types/View.scala
@@ -0,0 +1,12 @@
+package sigma.types
+
+import spire.util.Opt
+
+object View {
+ def mkPrimView[Val](value: Val): Opt[PrimView[Val]] = (value match {
+ case x: scala.Boolean => Opt(CBoolean(x))
+ case x: scala.Byte => Opt(CByte(x))
+ case x: scala.Int => Opt(CInt(x))
+ case _ => Opt.empty[Val]
+ }).asInstanceOf[Opt[PrimView[Val]]]
+}
diff --git a/sigma-impl/src/main/scala/sigma/util/Extensions.scala b/sigma-impl/src/main/scala/sigma/util/Extensions.scala
new file mode 100644
index 0000000000..c69d3e7b76
--- /dev/null
+++ b/sigma-impl/src/main/scala/sigma/util/Extensions.scala
@@ -0,0 +1,228 @@
+package sigma.util
+
+import java.math.BigInteger
+import java.nio.ByteBuffer
+
+import special.collection.{Coll, Builder}
+import com.google.common.primitives.Ints
+import scalan.{Nullable, RType}
+
+import scala.language.higherKinds
+
+object Extensions {
+ implicit class BooleanOps(val b: Boolean) extends AnyVal {
+ /** Convert true to 1 and false to 0
+ * @since 2.0
+ */
+ def toByte: Byte = if (b) 1 else 0
+ }
+
+ implicit class ByteOps(val b: Byte) extends AnyVal {
+ @inline def toUByte: Int = b & 0xFF
+ def addExact(b2: Byte): Byte = {
+ val r = b + b2
+ if (r < Byte.MinValue || r > Byte.MaxValue)
+ throw new ArithmeticException("Byte overflow")
+ r.toByte
+ }
+
+ def subtractExact(b2: Byte): Byte = {
+ val r = b - b2
+ if (r < Byte.MinValue || r > Byte.MaxValue)
+ throw new ArithmeticException("Byte overflow")
+ r.toByte
+ }
+
+ def multiplyExact(b2: Byte): Byte = {
+ val r = b * b2
+ if (r < Byte.MinValue || r > Byte.MaxValue)
+ throw new ArithmeticException("Byte overflow")
+ r.toByte
+ }
+
+ def toShort: Short = b.toShort
+ def toInt: Int = b.toInt
+ def toLong: Long = b.toLong
+
+ /** Returns a big-endian representation of this Int in a collection of bytes.
+ * For example, the Int value {@code 0x12131415} would yield the
+ * byte array {@code {0x12, 0x13, 0x14, 0x15}}.
+ * @since 2.0
+ */
+ def toBytes: Coll[Byte] = Builder.DefaultCollBuilder.fromItems(b)
+
+ /** Returns a big-endian representation of this numeric in a collection of Booleans.
+ * Each boolean corresponds to one bit.
+ * @since 2.0
+ */
+ def toBits: Coll[Boolean] = ???
+
+ /** Absolute value of this numeric value.
+ * @since 2.0
+ */
+ def toAbs: Byte = if (b < 0) (-b).toByte else b
+
+ /** Compares this numeric with that numeric for order. Returns a negative integer, zero, or a positive integer as the
+ * `this` is less than, equal to, or greater than `that`.
+ */
+ def compare(that: Byte): Byte = if (b < that) -1.toByte else if (b == that) 0.toByte else 1.toByte
+ }
+
+ implicit class ShortOps(val x: Short) extends AnyVal {
+ def toByteExact: Byte = {
+ if (x < Byte.MinValue || x > Byte.MaxValue)
+ throw new ArithmeticException("Byte overflow")
+ x.toByte
+ }
+
+ def addExact(y: Short): Short = {
+ val r = x + y
+ if (r < Short.MinValue || r > Short.MaxValue)
+ throw new ArithmeticException("Short overflow")
+ r.toShort
+ }
+
+ def subtractExact(y: Short): Short = {
+ val r = x - y
+ if (r < Short.MinValue || r > Short.MaxValue)
+ throw new ArithmeticException("Short overflow")
+ r.toShort
+ }
+
+ def multiplyExact(y: Short): Short = {
+ val r = x * y
+ if (r < Short.MinValue || r > Short.MaxValue)
+ throw new ArithmeticException("Short overflow")
+ r.toShort
+ }
+ }
+
+ implicit class IntOps(val x: Int) extends AnyVal {
+ def toByteExact: Byte = {
+ if (x < Byte.MinValue || x > Byte.MaxValue)
+ throw new ArithmeticException("Byte overflow")
+ x.toByte
+ }
+
+ def toShortExact: Short = {
+ if (x < Short.MinValue || x > Short.MaxValue)
+ throw new ArithmeticException("Short overflow")
+ x.toShort
+ }
+
+ /** Returns a big-endian representation of this Int in a collection of bytes.
+ * For example, the Int value {@code 0x12131415} would yield the
+ * byte array {@code {0x12, 0x13, 0x14, 0x15}}.
+ * @since 2.0
+ */
+ def toBytes: Coll[Byte] = Builder.DefaultCollBuilder.fromArray(Ints.toByteArray(x))
+
+ /** Returns a big-endian representation of this numeric in a collection of Booleans.
+ * Each boolean corresponds to one bit.
+ * @since 2.0
+ */
+ def toBits: Coll[Boolean] = ???
+
+ /** Absolute value of this numeric value.
+ * @since 2.0
+ */
+ def toAbs: Int = if (x < 0) -x else x
+
+ /** Compares this numeric with that numeric for order. Returns a negative integer, zero, or a positive integer as the
+ * `this` is less than, equal to, or greater than `that`.
+ */
+ def compare(that: Int): Int = if (x < that) -1 else if (x == that) 0 else 1
+ }
+
+ implicit class LongOps(val x: Long) extends AnyVal {
+ def toByteExact: Byte = {
+ if (x < Byte.MinValue || x > Byte.MaxValue)
+ throw new ArithmeticException("Byte overflow")
+ x.toByte
+ }
+
+ def toShortExact: Short = {
+ if (x < Short.MinValue || x > Short.MaxValue)
+ throw new ArithmeticException("Short overflow")
+ x.toShort
+ }
+
+ def toIntExact: Int = {
+ if (x < Int.MinValue || x > Int.MaxValue)
+ throw new ArithmeticException("Int overflow")
+ x.toInt
+ }
+ }
+
+ implicit class BigIntegerOps(val x: BigInteger) extends AnyVal {
+ /** Returns this `mod` Q, i.e. remainder of division by Q, where Q is an order of the cryprographic group.
+ * @since 2.0
+ */
+ def modQ: BigInt = ???
+
+ /** Adds this number with `other` by module Q.
+ * @since 2.0
+ */
+ def plusModQ(other: BigInt): BigInt = ???
+
+ /** Subracts this number with `other` by module Q.
+ * @since 2.0
+ */
+ def minusModQ(other: BigInt): BigInt = ???
+
+ /** Multiply this number with `other` by module Q.
+ * @since 2.0
+ */
+ def multModQ(other: BigInt): BigInt = ???
+
+ /** Multiply this number with `other` by module Q.
+ * @since Mainnet
+ */
+ def multInverseModQ: BigInt = ???
+ }
+
+ implicit class OptionOps[T](val opt: Option[T]) extends AnyVal {
+ /** Elvis operator for Option. See https://en.wikipedia.org/wiki/Elvis_operator*/
+ def ?:(whenNone: => T): T = if (opt.isDefined) opt.get else whenNone
+ }
+
+ implicit class ProductOps(val source: Product) extends AnyVal {
+ def toArray: Array[Any] = {
+ val arity = source.productArity
+ val res = new Array[Any](arity)
+ var i = 0
+ while (i < arity) {
+ res(i) = source.productElement(i)
+ i += 1
+ }
+ res
+ }
+ }
+
+ implicit class ByteBufferOps(val buf: ByteBuffer) extends AnyVal {
+ def toBytes: Array[Byte] = {
+ val res = new Array[Byte](buf.position())
+ buf.array().copyToArray(res, 0, res.length)
+ res
+ }
+ def getBytes(size: Int): Array[Byte] = {
+ val res = new Array[Byte](size)
+ buf.get(res)
+ res
+ }
+ def getOption[T](getValue: => T): Option[T] = {
+ val tag = buf.get()
+ if (tag != 0)
+ Some(getValue)
+ else
+ None
+ }
+ }
+
+ implicit class NullableOps[T](val nul: Nullable[T]) {
+ def toOption: Option[T] = nul match {
+ case Nullable(v) => Some(v)
+ case _ => None
+ }
+ }
+}
diff --git a/sigma-impl/src/main/scala/special/sigma/Exceptions.scala b/sigma-impl/src/main/scala/special/sigma/Exceptions.scala
new file mode 100644
index 0000000000..f6c90cae0a
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/Exceptions.scala
@@ -0,0 +1,4 @@
+package special.sigma
+
+final class InvalidType(message: String) extends Exception(message)
+
diff --git a/sigma-impl/src/main/scala/special/sigma/Extensions.scala b/sigma-impl/src/main/scala/special/sigma/Extensions.scala
new file mode 100644
index 0000000000..500f172696
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/Extensions.scala
@@ -0,0 +1,31 @@
+package special.sigma
+
+import org.bouncycastle.math.ec.ECPoint
+import scalan.RType
+
+/** This extensions are used from SigmaDsl.
+ * If you add something here, make sure the corresponding syntax is supported by SigmaScript. */
+class DslSyntaxExtensions(dsl: SigmaDslBuilder) {
+ implicit class BooleanOps(source: Boolean) {
+ /** Logical AND between Boolean on the left and SigmaProp value on the right. */
+ def &&(prop: SigmaProp) = dsl.sigmaProp(source) && prop
+
+ /** Logical AND between Boolean on the left and SigmaProp value on the right. */
+ def ||(prop: SigmaProp) = dsl.sigmaProp(source) || prop
+ }
+}
+
+object Extensions {
+
+ def showECPoint(p: ECPoint) = {
+ val rawX = p.getRawXCoord.toString.substring(0, 6)
+ val rawY = p.getRawYCoord.toString.substring(0, 6)
+ s"ECPoint($rawX,$rawY,...)"
+ }
+
+ implicit class GroupElementOps(source: GroupElement) {
+ def showToString: String = showECPoint(source.value)
+ }
+
+ def toAnyValue[A:RType](x: A) = new TestValue(x, RType[A].asInstanceOf[RType[Any]])
+}
diff --git a/sigma-impl/src/main/scala/special/sigma/Mocks.scala b/sigma-impl/src/main/scala/special/sigma/Mocks.scala
new file mode 100644
index 0000000000..700f4a7825
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/Mocks.scala
@@ -0,0 +1,52 @@
+package special.sigma
+
+import org.bouncycastle.crypto.ec.CustomNamedCurves
+import scalan.{NeverInline, OverloadId}
+import special.collection.Builder.DefaultCollBuilder
+import special.collection.{Coll, Builder}
+
+/**NOTE: this should extend SigmaProp because semantically it subclass of SigmaProp
+ * and DefaultSigma is used just to mixin implementations. */
+
+case class MockSigma(val _isValid: Boolean) extends SigmaProp {
+
+ def propBytes: Coll[Byte] = DefaultCollBuilder.fromItems(if(isValid) 1 else 0)
+ def isValid: Boolean = _isValid
+ def &&(other: SigmaProp): SigmaProp = MockSigma(isValid && other.isValid)
+
+ @NeverInline
+ @OverloadId("and_bool")
+ def &&(other: Boolean): SigmaProp = MockSigma(isValid && other)
+
+ @NeverInline
+ @OverloadId("or_sigma")
+ def ||(other: SigmaProp): SigmaProp = MockSigma(isValid || other.isValid)
+
+ @NeverInline
+ @OverloadId("or_bool")
+ def ||(other: Boolean): SigmaProp = MockSigma(isValid || other)
+
+}
+
+case class MockProveDlog(var isValid: Boolean, val propBytes: Coll[Byte]) extends SigmaProp {
+ val curve = CustomNamedCurves.getByName("secp256k1")
+ def value = curve.getG
+ def setValid(v: Boolean) = { isValid = v }
+ def builder = new TestSigmaDslBuilder
+ @NeverInline
+ @OverloadId("and_sigma")
+ def &&(other: SigmaProp): SigmaProp = MockSigma(isValid && other.isValid)
+
+ @NeverInline
+ @OverloadId("and_bool")
+ def &&(other: Boolean): SigmaProp = MockSigma(isValid && other)
+
+ @NeverInline
+ @OverloadId("or_sigma")
+ def ||(other: SigmaProp): SigmaProp = MockSigma(isValid || other.isValid)
+
+ @NeverInline
+ @OverloadId("or_bool")
+ def ||(other: Boolean): SigmaProp = MockSigma(isValid || other)
+}
+
diff --git a/sigma-impl/src/main/scala/special/sigma/SigmaDslCosted.scala b/sigma-impl/src/main/scala/special/sigma/SigmaDslCosted.scala
new file mode 100644
index 0000000000..8629c0284a
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/SigmaDslCosted.scala
@@ -0,0 +1,81 @@
+package special.sigma
+
+import special.collection._
+import scalan.{RType, NeverInline}
+
+class CSizeAnyValue(val tVal: RType[Any], val valueSize: Size[Any]) extends SizeAnyValue {
+ @NeverInline
+ override def dataSize: Long = valueSize.dataSize
+}
+
+class CSizeSigmaProp(val propBytes: Size[Coll[Byte]]) extends SizeSigmaProp {
+ @NeverInline
+ override def dataSize: Long = propBytes.dataSize
+}
+
+class CSizeBox(
+ val propositionBytes: Size[Coll[Byte]],
+ val bytes: Size[Coll[Byte]],
+ val bytesWithoutRef: Size[Coll[Byte]],
+ val registers: Size[Coll[Option[AnyValue]]],
+ val tokens: Size[Coll[(Coll[Byte], Long)]]
+) extends SizeBox {
+ @NeverInline
+ override def dataSize: Long = {
+ // since `bytes` already contains all serialized data we just return it here
+ // however for cost estimation this size is not equal to the sum of the components
+ // and we need each component size independently
+ bytes.dataSize
+ }
+
+ @NeverInline
+ override def getReg[T](id: Byte)(implicit tT: RType[T]): Size[Option[T]] = {
+ sys.error(s"Shouldn't be called and must be overriden by the class in sigmastate.eval package")
+ }
+}
+
+class CSizeContext(
+ val outputs: Size[Coll[Box]],
+ val inputs: Size[Coll[Box]],
+ val dataInputs: Size[Coll[Box]],
+ val selfBox: Size[Box],
+ val lastBlockUtxoRootHash: Size[AvlTree],
+ val headers: Size[Coll[Header]],
+ val preHeader: Size[PreHeader],
+ val vars: Coll[Size[AnyValue]]
+) extends SizeContext {
+ @NeverInline
+ override def dataSize: Long = {
+ outputs.dataSize + inputs.dataSize + dataInputs.dataSize +
+ lastBlockUtxoRootHash.dataSize + headers.dataSize + preHeader.dataSize +
+ 33L // minerPubKey
+ }
+
+ @NeverInline
+ override def getVar[T](id: Byte)(implicit tT: RType[T]): Size[Option[T]] = {
+ val varSize = vars(id.toInt).asInstanceOf[SizeAnyValue]
+ assert(varSize.tVal == tT, s"Unexpected context variable type found ${varSize.tVal}: expected $tT")
+ val foundSize = varSize.valueSize.asInstanceOf[Size[T]]
+ new CSizeOption[T](Some(foundSize))
+ }
+}
+
+class CSizeBuilder extends SizeBuilder {
+ def mkSizeAnyValue(tVal: RType[Any], valueSize: Size[Any]): SizeAnyValue = new CSizeAnyValue(tVal, valueSize)
+
+ def mkSizeBox(propositionBytes: Size[Coll[Byte]], bytes: Size[Coll[Byte]],
+ bytesWithoutRef: Size[Coll[Byte]], registers: Size[Coll[Option[AnyValue]]],
+ tokens: Size[Coll[(Coll[Byte], Long)]]): SizeBox = {
+ new CSizeBox(propositionBytes, bytes, bytesWithoutRef, registers, tokens)
+ }
+
+ def mkSizeContext(outputs: Size[Coll[Box]],
+ inputs: Size[Coll[Box]],
+ dataInputs: Size[Coll[Box]],
+ selfBox: Size[Box],
+ lastBlockUtxoRootHash: Size[AvlTree],
+ headers: Size[Coll[Header]],
+ preHeader: Size[PreHeader],
+ vars: Coll[Size[AnyValue]]): SizeContext =
+ new CSizeContext(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars)
+}
diff --git a/sigma-impl/src/main/scala/special/sigma/SigmaDslOverArrays.scala b/sigma-impl/src/main/scala/special/sigma/SigmaDslOverArrays.scala
new file mode 100644
index 0000000000..89ffb18e19
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/SigmaDslOverArrays.scala
@@ -0,0 +1,109 @@
+package special.sigma
+
+import java.math.BigInteger
+
+import com.google.common.primitives.Longs
+import org.bouncycastle.crypto.ec.CustomNamedCurves
+import org.bouncycastle.math.ec.ECPoint
+import org.bouncycastle.math.ec.custom.sec.SecP256K1Point
+import scalan.RType._
+import scalan.{RType, Internal, NeverInline, Reified}
+import scorex.crypto.hash.{Sha256, Blake2b256}
+import special.SpecialPredef
+import special.collection._
+
+class TestSigmaDslBuilder extends SigmaDslBuilder {
+ // manual fix
+ def Colls: CollBuilder = new CollOverArrayBuilder
+ def Monoids: MonoidBuilder = new MonoidBuilderInst
+ def Costing: CostedBuilder = new CCostedBuilder
+ @NeverInline
+ def CostModel: CostModel = new TestCostModel
+
+ @NeverInline
+ def verifyZK(proof: => SigmaProp): Boolean = proof.isValid
+
+ @NeverInline
+ def atLeast(bound: Int, props: Coll[SigmaProp]): SigmaProp = ???
+
+ @NeverInline
+ def allOf(conditions: Coll[Boolean]): Boolean = conditions.forall(c => c)
+ @NeverInline
+ def anyOf(conditions: Coll[Boolean]): Boolean = conditions.exists(c => c)
+
+ @NeverInline
+ def allZK(props: Coll[SigmaProp]): SigmaProp = MockSigma(props.forall(p => p.isValid))
+ @NeverInline
+ def anyZK(props: Coll[SigmaProp]): SigmaProp = MockSigma(props.exists(p => p.isValid))
+
+ @NeverInline
+ override def xorOf(conditions: Coll[Boolean]): Boolean = conditions.toArray.distinct.length == 2
+
+ @NeverInline
+ def sigmaProp(b: Boolean): SigmaProp = MockSigma(b)
+
+ @NeverInline
+ def blake2b256(bytes: Coll[Byte]): Coll[Byte] = Colls.fromArray(Blake2b256.hash(bytes.toArray))
+
+ @NeverInline
+ def sha256(bytes: Coll[Byte]): Coll[Byte] = Colls.fromArray(Sha256.hash(bytes.toArray))
+
+ @NeverInline
+ def PubKey(base64String: String): SigmaProp = ???
+
+ @NeverInline
+ def byteArrayToBigInt(bytes: Coll[Byte]): BigInt = {
+ val dlogGroupOrder = __curve__.getN
+ val bi = new BigInteger(1, bytes.toArray)
+ if (bi.compareTo(dlogGroupOrder) == 1) {
+ throw new RuntimeException(s"BigInt value exceeds the order of the dlog group (${__curve__}). Expected to be less than: $dlogGroupOrder, actual: $bi")
+ }
+ this.BigInt(bi)
+ }
+
+ @NeverInline
+ def longToByteArray(l: Long): Coll[Byte] = Colls.fromArray(Longs.toByteArray(l))
+ @NeverInline
+ def byteArrayToLong(bytes: Coll[Byte]): Long = Longs.fromByteArray(bytes.toArray)
+
+ @NeverInline
+ def proveDlog(g: GroupElement): SigmaProp = MockProveDlog(true, Colls.emptyColl[Byte])
+
+ @NeverInline
+ def proveDHTuple(g: GroupElement, h: GroupElement, u: GroupElement, v: GroupElement): SigmaProp = ???
+
+ @Internal val __curve__ = CustomNamedCurves.getByName("secp256k1")
+ @Internal val __g__ = __curve__.getG.asInstanceOf[SecP256K1Point]
+
+ @NeverInline
+ def groupGenerator: GroupElement = this.GroupElement(__g__)
+
+ @Reified("T")
+ @NeverInline
+ override def substConstants[T](scriptBytes: Coll[Byte],
+ positions: Coll[Int],
+ newValues: Coll[T])
+ (implicit cT: RType[T]): Coll[Byte] = ???
+
+ @NeverInline
+ override def decodePoint(encoded: Coll[Byte]): GroupElement =
+ this.GroupElement(__curve__.getCurve.decodePoint(encoded.toArray))
+
+ @NeverInline
+ override def BigInt(n: BigInteger): BigInt = SpecialPredef.rewritableMethod
+
+ @NeverInline
+ override def toBigInteger(n: BigInt): BigInteger = n.asInstanceOf[TestBigInt].value
+
+ /** Create DSL's group element from existing `org.bouncycastle.math.ec.ECPoint`. */
+ @NeverInline
+ def GroupElement(p: ECPoint): GroupElement = SpecialPredef.rewritableMethod
+
+ /** Extract `org.bouncycastle.math.ec.ECPoint` from DSL's `GroupElement` type. */
+ @NeverInline
+ def toECPoint(ge: GroupElement): ECPoint = ge.value
+
+ @NeverInline
+ override def avlTree(operationFlags: Byte, digest: Coll[Byte], keyLength: Int, valueLengthOpt: Option[Int]): AvlTree = SpecialPredef.rewritableMethod
+}
+
diff --git a/sigma-impl/src/main/scala/special/sigma/TestBigInt.scala b/sigma-impl/src/main/scala/special/sigma/TestBigInt.scala
new file mode 100644
index 0000000000..a44832979d
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/TestBigInt.scala
@@ -0,0 +1,51 @@
+package special.sigma
+
+import special.collection.{Coll}
+import java.math.BigInteger
+
+abstract class TestBigInt(private[sigma] val value: BigInteger) extends BigInt {
+ val dsl: TestSigmaDslBuilder = new TestSigmaDslBuilder
+
+ override def toByte : Byte = value.byteValueExact()
+ override def toShort: Short = value.shortValueExact()
+ override def toInt : Int = value.intValueExact()
+ override def toLong : Long = value.longValueExact()
+
+ override def toBytes: Coll[Byte] = dsl.Colls.fromArray(value.toByteArray)
+
+ override def toBits: Coll[Boolean] = ???
+
+ override def toAbs: BigInt = dsl.BigInt(value.abs())
+
+ override def compareTo(that: BigInt): Int = value.compareTo(that.value)
+
+ override def modQ: BigInt = ???
+
+ override def plusModQ(other: BigInt): BigInt = ???
+
+ override def minusModQ(other: BigInt): BigInt = ???
+
+ override def multModQ(other: BigInt): BigInt = ???
+
+ override def inverseModQ: BigInt = ???
+
+ override def signum: Int = value.signum()
+
+ override def add(that: BigInt): BigInt = dsl.BigInt(value.add(that.value))
+
+ override def subtract(that: BigInt): BigInt = dsl.BigInt(value.subtract(that.value))
+
+ override def multiply(that: BigInt): BigInt = dsl.BigInt(value.multiply(that.value))
+
+ override def divide(that: BigInt): BigInt = dsl.BigInt(value.divide(that.value))
+
+ override def mod(m: BigInt): BigInt = dsl.BigInt(value.mod(m.value))
+
+ override def remainder(that: BigInt): BigInt = dsl.BigInt(value.remainder(that.value))
+
+ override def min(that: BigInt): BigInt = dsl.BigInt(value.min(that.value))
+
+ override def max(that: BigInt): BigInt = dsl.BigInt(value.max(that.value))
+
+ override def negate(): BigInt = dsl.BigInt(value.negate())
+}
diff --git a/sigma-impl/src/main/scala/special/sigma/TestBox.scala b/sigma-impl/src/main/scala/special/sigma/TestBox.scala
new file mode 100644
index 0000000000..e9c63b219d
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/TestBox.scala
@@ -0,0 +1,46 @@
+package special.sigma
+
+import scala.reflect.ClassTag
+import special.collection.Coll
+import scalan.{NeverInline, RType, Reified}
+
+class TestBox(
+ val id: Coll[Byte],
+ val value: Long,
+ val bytes: Coll[Byte],
+ val bytesWithoutRef: Coll[Byte],
+ val propositionBytes: Coll[Byte],
+ val registers: Coll[AnyValue]) extends Box
+{
+ def builder = new TestSigmaDslBuilder
+ @NeverInline
+ def getReg[T](id: Int)(implicit cT: RType[T]): Option[T] = {
+ implicit val tag: ClassTag[T] = cT.classTag
+ if (id < 0 || id >= registers.length) return None
+ val value = registers(id)
+ if (value != null ) {
+ // once the value is not null it should be of the right type
+ value match {
+ case value: TestValue[_] if value.value != null && value.tA == cT =>
+ Some(value.value.asInstanceOf[T])
+ case _ =>
+ throw new InvalidType(s"Cannot getReg[${cT.name}]($id): invalid type of value $value at id=$id")
+ }
+ } else None
+ }
+
+ def creationInfo: (Int, Coll[Byte]) = this.getReg[(Int, Coll[Byte])](3).get
+
+ def tokens: Coll[(Coll[Byte], Long)] = {
+ this.getReg[Coll[(Coll[Byte], Long)]](2).get
+ }
+
+ @NeverInline
+ override def executeFromRegister[@Reified T](regId: Byte)(implicit cT: RType[T]): T = ???
+
+ override def hashCode(): Int = id.hashCode()
+
+ override def equals(obj: Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj != null && ( obj match {
+ case obj: Box => id == obj.id
+ }))
+}
diff --git a/sigma-impl/src/main/scala/special/sigma/TestContext.scala b/sigma-impl/src/main/scala/special/sigma/TestContext.scala
new file mode 100644
index 0000000000..bf3c98e5d3
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/TestContext.scala
@@ -0,0 +1,9 @@
+package special.sigma
+
+import scalan.RType
+
+case class TestValue[A](value: A, tVal: RType[Any]) extends AnyValue {
+ def tA: RType[A] = tVal.asInstanceOf[RType[A]]
+ override def toString = s"Value($value)"
+}
+
diff --git a/sigma-impl/src/main/scala/special/sigma/TestContracts.scala b/sigma-impl/src/main/scala/special/sigma/TestContracts.scala
new file mode 100644
index 0000000000..5e828882f4
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/TestContracts.scala
@@ -0,0 +1,18 @@
+package special.sigma
+
+class CrowdFundingContract(
+ val deadline: Long, val minToRaise: Long,
+ val backerPubKey: SigmaProp,
+ val projectPubKey: SigmaProp
+) extends CrowdFunding {
+ override def builder: SigmaDslBuilder = new TestSigmaDslBuilder
+}
+
+class DemurrageCurrencyContract(
+ val demurragePeriod: Int,
+ val demurrageCost: Long,
+ val regScript: SigmaProp
+) extends DemurrageCurrency {
+ override def builder: SigmaDslBuilder = new TestSigmaDslBuilder
+}
+
diff --git a/sigma-impl/src/main/scala/special/sigma/TestCostModel.scala b/sigma-impl/src/main/scala/special/sigma/TestCostModel.scala
new file mode 100644
index 0000000000..57babeed93
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/TestCostModel.scala
@@ -0,0 +1,22 @@
+package special.sigma
+
+import scala.reflect.ClassTag
+import scalan.Internal
+
+@Internal
+class TestCostModel extends CostModel {
+ def AccessBox: Int = CostTable.DefaultCosts("AccessBox: Context => Box")
+ def AccessAvlTree: Int = CostTable.DefaultCosts("AccessAvlTree: Context => AvlTree")
+
+ def GetVar: Int = CostTable.DefaultCosts("GetVar: (Context, Byte) => Option[T]")
+ def DeserializeVar: Int = CostTable.DefaultCosts("DeserializeVar: (Context, Byte) => Option[T]")
+
+ def GetRegister: Int = CostTable.DefaultCosts("GetRegister: (Box, Byte) => Option[T]")
+ def DeserializeRegister: Int = CostTable.DefaultCosts("DeserializeRegister: (Box, Byte) => Option[T]")
+
+ def SelectField: Int = CostTable.DefaultCosts("SelectField")
+ def CollectionConst: Int = CostTable.DefaultCosts("Const: () => Array[IV]")
+ def AccessKiloByteOfData: Int = CostTable.DefaultCosts("AccessKiloByteOfData")
+ def dataSize[T](x: T)(implicit cT: ClassTag[T]): Long = SigmaPredef.dataSize(x)
+ override def PubKeySize: Long = 32
+}
diff --git a/sigma-impl/src/main/scala/special/sigma/TestGroupElement.scala b/sigma-impl/src/main/scala/special/sigma/TestGroupElement.scala
new file mode 100644
index 0000000000..bf57777773
--- /dev/null
+++ b/sigma-impl/src/main/scala/special/sigma/TestGroupElement.scala
@@ -0,0 +1,19 @@
+package special.sigma
+
+import org.bouncycastle.math.ec.ECPoint
+import special.collection.Coll
+
+abstract class TestGroupElement(private[sigma] val value: ECPoint) extends GroupElement {
+ val dsl: TestSigmaDslBuilder = new TestSigmaDslBuilder
+
+ override def toString: String = s"GroupElement(${Extensions.showECPoint(value)})"
+
+ override def isInfinity: Boolean = value.isInfinity
+
+ override def exp(k: BigInt): GroupElement = dsl.GroupElement(value.multiply(k.value))
+
+ override def multiply(that: GroupElement): GroupElement = dsl.GroupElement(value.add(that.value))
+
+ override def negate: GroupElement = dsl.GroupElement(value.negate())
+
+}
diff --git a/sigma-impl/src/test/scala/sigma/types/TypesTests.scala b/sigma-impl/src/test/scala/sigma/types/TypesTests.scala
new file mode 100644
index 0000000000..7d183eedce
--- /dev/null
+++ b/sigma-impl/src/test/scala/sigma/types/TypesTests.scala
@@ -0,0 +1,39 @@
+package sigma.types
+
+import org.scalatest.prop.PropertyChecks
+import org.scalatest.{PropSpec, Matchers}
+import org.scalacheck.{Arbitrary, Gen}
+import org.scalacheck.Arbitrary._
+import special.collections.CollGens
+import sigma.util.Extensions._
+
+class TypesTests extends PropSpec with PropertyChecks with Matchers with CollGens { testSuite =>
+
+ val genSBoolean: Gen[Boolean] = arbBool.arbitrary.map(CBoolean(_))
+ implicit val arbSBoolean = Arbitrary(genSBoolean)
+
+ val genSByte: Gen[Byte] = arbByte.arbitrary.map(CByte(_))
+ implicit val arbSByte = Arbitrary(genSByte)
+
+ val genSInt: Gen[Int] = arbInt.arbitrary.map(CInt(_))
+ implicit val arbSInt = Arbitrary(genSInt)
+
+ property("Boolean methods") {
+ forAll { x: Boolean =>
+ x.toByte shouldBe CByte(x.value.toByte)
+ }
+ }
+
+ property("Byte methods") {
+ forAll { x: Byte =>
+ x.toInt.value shouldBe x.value.toInt
+ }
+ }
+
+ property("Int methods") {
+ forAll(valGen) { in: scala.Int =>
+ val x: Int = CInt(in)
+ x.toByte.value shouldBe x.value.toByte
+ }
+ }
+}
diff --git a/sigma-library/src/main/scala/scalan/SigmaLibrary.scala b/sigma-library/src/main/scala/scalan/SigmaLibrary.scala
new file mode 100644
index 0000000000..8db82ef30f
--- /dev/null
+++ b/sigma-library/src/main/scala/scalan/SigmaLibrary.scala
@@ -0,0 +1,132 @@
+package scalan
+
+import org.bouncycastle.crypto.ec.CustomNamedCurves
+import org.bouncycastle.math.ec.ECPoint
+import special.sigma._
+import special.sigma.wrappers.WrappersSpecModule
+
+import scala.collection.mutable.ArrayBuffer
+
+trait SigmaLibrary extends Library
+ with special.sigma.wrappers.WrappersModule
+ with WrappersSpecModule
+ with SigmaDslModule
+ with CostedObjectsModule
+ with SigmaDslOverArraysModule
+ with SigmaDslCostedModule
+{
+ import WArray._
+ import Coll._
+ import CollBuilder._
+ import SigmaProp._
+ import SigmaContract._
+ import WECPoint._
+ import SigmaDslBuilder._
+ import WRType._
+ import Size._
+
+ implicit lazy val wRTypeAnyElement = wRTypeElement(AnyElement)
+ implicit lazy val sizeAnyElement = sizeElement(AnyElement)
+
+ private val WA = WArrayMethods
+ private val CM = CollMethods
+ private val CBM = CollBuilderMethods
+ private val SM = SigmaPropMethods
+ private val SCM = SigmaContractMethods
+ private val SDBM = SigmaDslBuilderMethods
+
+ def sigmaDslBuilder: Rep[SigmaDslBuilder]
+
+ object AnyOf {
+ def unapply(d: Def[_]): Option[(Rep[CollBuilder], Seq[Rep[A]], Elem[A]) forSome {type A}] = d match {
+ case SDBM.anyOf(_, CBM.fromItems(b, items, e)) =>
+ Some((b, items, e.asInstanceOf[Elem[Any]]))
+ case _ => None
+ }
+ }
+ object AllOf {
+ def unapply(d: Def[_]): Option[(Rep[CollBuilder], Seq[Rep[A]], Elem[A]) forSome {type A}] = d match {
+ case SDBM.allOf(_, CBM.fromItems(b, items, e)) =>
+ Some((b, items, e.asInstanceOf[Elem[Any]]))
+ case _ => None
+ }
+ }
+ object AnyZk {
+ def unapply(d: Def[_]): Option[(Rep[CollBuilder], Seq[Rep[SigmaProp]], Elem[SigmaProp])] = d match {
+ case SDBM.anyZK(_, CBM.fromItems(b, items, e)) =>
+ Some((b, items.asInstanceOf[Seq[Rep[SigmaProp]]], e.asInstanceOf[Elem[SigmaProp]]))
+ case _ => None
+ }
+ }
+ object AllZk {
+ def unapply(d: Def[_]): Option[(Rep[CollBuilder], Seq[Rep[SigmaProp]], Elem[SigmaProp])] = d match {
+ case SDBM.allZK(_, CBM.fromItems(b, items, e)) =>
+ Some((b, items.asInstanceOf[Seq[Rep[SigmaProp]]], e.asInstanceOf[Elem[SigmaProp]]))
+ case _ => None
+ }
+ }
+ object HasSigmas {
+ def unapply(items: Seq[Sym]): Option[(Seq[Rep[Boolean]], Seq[Rep[SigmaProp]])] = {
+ val bs = ArrayBuffer.empty[Rep[Boolean]]
+ val ss = ArrayBuffer.empty[Rep[SigmaProp]]
+ for (i <- items) {
+ i match {
+ case SM.isValid(s) => ss += s
+ case b => bs += b.asRep[Boolean]
+ }
+ }
+ assert(items.length == bs.length + ss.length)
+ if (ss.isEmpty) None
+ else Some((bs,ss))
+ }
+ }
+
+ override def rewriteDef[T](d: Def[T]) = d match {
+ case AllOf(b, HasSigmas(bools, sigmas), _) =>
+ val zkAll = sigmaDslBuilder.allZK(b.fromItems(sigmas:_*))
+ if (bools.isEmpty)
+ zkAll.isValid
+ else
+ (sigmaDslBuilder.sigmaProp(sigmaDslBuilder.allOf(b.fromItems(bools:_*))) && zkAll).isValid
+ case AnyOf(b, HasSigmas(bs, ss), _) =>
+ val zkAny = sigmaDslBuilder.anyZK(b.fromItems(ss:_*))
+ if (bs.isEmpty)
+ zkAny.isValid
+ else
+ (sigmaDslBuilder.sigmaProp(sigmaDslBuilder.anyOf(b.fromItems(bs:_*))) || zkAny).isValid
+ case AllOf(_,items,_) if items.length == 1 => items(0)
+ case AnyOf(_,items,_) if items.length == 1 => items(0)
+ case AllZk(_,items,_) if items.length == 1 => items(0)
+ case AnyZk(_,items,_) if items.length == 1 => items(0)
+
+ case ApplyBinOp(op, lhs, rhs) =>
+ op.asInstanceOf[BinOp[_, _]] match {
+ case And =>
+ sigmaDslBuilder.allOf(sigmaDslBuilder.Colls.fromItems(Seq(lhs.asRep[Boolean], rhs.asRep[Boolean]):_*))
+ case Or =>
+ sigmaDslBuilder.anyOf(sigmaDslBuilder.Colls.fromItems(Seq(lhs.asRep[Boolean], rhs.asRep[Boolean]):_*))
+ case _ => super.rewriteDef(d)
+ }
+
+ case SDBM.sigmaProp(_, SM.isValid(p)) => p
+ case SM.isValid(SDBM.sigmaProp(_, bool)) => bool
+
+ case _ =>
+ if (currentPass.config.constantPropagation) {
+ // additional constant propagation rules (see other similar cases)
+ d match {
+ case AnyOf(_,items,_) if (items.forall(_.isConst)) =>
+ val bs = items.map { case Def(Const(b: Boolean)) => b }
+ toRep(bs.exists(_ == true))
+ case AllOf(_,items,_) if (items.forall(_.isConst)) =>
+ val bs = items.map { case Def(Const(b: Boolean)) => b }
+ toRep(bs.forall(_ == true))
+ case _ =>
+ super.rewriteDef(d)
+ }
+ }
+ else
+ super.rewriteDef(d)
+ }
+
+}
diff --git a/sigma-library/src/main/scala/special/sigma/CostedObjects.scala b/sigma-library/src/main/scala/special/sigma/CostedObjects.scala
new file mode 100644
index 0000000000..9e0ffcf3bb
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/CostedObjects.scala
@@ -0,0 +1,56 @@
+package special.sigma {
+ import scalan._
+
+ trait CostedObjects extends Base { self: SigmaLibrary =>
+ import AnyValue._;
+ import AvlTree._;
+ import Box._;
+ import Coll._;
+ import Context._;
+ import Header._;
+ import PreHeader._;
+ import SigmaProp._;
+ import Size._;
+ import SizeAnyValue._;
+ import SizeBox._;
+ import SizeBuilder._;
+ import SizeContext._;
+ import WOption._;
+ import WRType._;
+ @Liftable trait SizeAnyValue extends Size[AnyValue] {
+ def tVal: Rep[WRType[Any]];
+ def valueSize: Rep[Size[Any]]
+ };
+ @Liftable trait SizeSigmaProp extends Size[SigmaProp] {
+ def propBytes: Rep[Size[Coll[Byte]]]
+ };
+ @Liftable trait SizeBox extends Size[Box] {
+ def propositionBytes: Rep[Size[Coll[Byte]]];
+ def bytes: Rep[Size[Coll[Byte]]];
+ def bytesWithoutRef: Rep[Size[Coll[Byte]]];
+ def registers: Rep[Size[Coll[WOption[AnyValue]]]];
+ def getReg[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]];
+ def tokens: Rep[Size[Coll[scala.Tuple2[Coll[Byte], Long]]]]
+ };
+ @Liftable trait SizeContext extends Size[Context] {
+ def outputs: Rep[Size[Coll[Box]]];
+ def inputs: Rep[Size[Coll[Box]]];
+ def dataInputs: Rep[Size[Coll[Box]]];
+ def selfBox: Rep[Size[Box]];
+ def lastBlockUtxoRootHash: Rep[Size[AvlTree]];
+ def headers: Rep[Size[Coll[Header]]];
+ def preHeader: Rep[Size[PreHeader]];
+ def getVar[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]]
+ };
+ @Liftable trait SizeBuilder extends Def[SizeBuilder] {
+ def mkSizeAnyValue(tVal: Rep[WRType[Any]], valueSize: Rep[Size[Any]]): Rep[SizeAnyValue];
+ def mkSizeBox(propositionBytes: Rep[Size[Coll[Byte]]], bytes: Rep[Size[Coll[Byte]]], bytesWithoutRef: Rep[Size[Coll[Byte]]], registers: Rep[Size[Coll[WOption[AnyValue]]]], tokens: Rep[Size[Coll[scala.Tuple2[Coll[Byte], Long]]]]): Rep[SizeBox];
+ def mkSizeContext(outputs: Rep[Size[Coll[Box]]], inputs: Rep[Size[Coll[Box]]], dataInputs: Rep[Size[Coll[Box]]], selfBox: Rep[Size[Box]], lastBlockUtxoRootHash: Rep[Size[AvlTree]], headers: Rep[Size[Coll[Header]]], preHeader: Rep[Size[PreHeader]], vars: Rep[Coll[Size[AnyValue]]]): Rep[SizeContext]
+ };
+ trait SizeAnyValueCompanion;
+ trait SizeSigmaPropCompanion;
+ trait SizeBoxCompanion;
+ trait SizeContextCompanion;
+ trait SizeBuilderCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-library/src/main/scala/special/sigma/SigmaDsl.scala b/sigma-library/src/main/scala/special/sigma/SigmaDsl.scala
new file mode 100644
index 0000000000..e2aefa733d
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/SigmaDsl.scala
@@ -0,0 +1,228 @@
+package special.sigma {
+ import scalan.OverloadHack.Overloaded1 // manual fix
+ import scalan._
+
+ trait SigmaDsl extends Base { self: SigmaLibrary =>
+ import AnyValue._;
+ import AvlTree._;
+ import BigInt._;
+ import Box._;
+ import Coll._;
+ import CollBuilder._;
+ import Context._;
+ import CostModel._;
+ import CostedBuilder._;
+ import GroupElement._;
+ import Header._;
+ import MonoidBuilder._;
+ import PreHeader._;
+ import SigmaContract._;
+ import SigmaDslBuilder._;
+ import SigmaProp._;
+ import WBigInteger._;
+ import WOption._;
+ import WRType._;
+ @Liftable trait CostModel extends Def[CostModel] {
+ def AccessBox: Rep[Int];
+ def AccessAvlTree: Rep[Int];
+ def GetVar: Rep[Int];
+ def DeserializeVar: Rep[Int];
+ def GetRegister: Rep[Int];
+ def DeserializeRegister: Rep[Int];
+ def SelectField: Rep[Int];
+ def CollectionConst: Rep[Int];
+ def AccessKiloByteOfData: Rep[Int];
+ @Reified(value = "T") def dataSize[T](x: Rep[T])(implicit cT: Elem[T]): Rep[Long];
+ def PubKeySize: Rep[Long]
+ };
+ @Liftable trait BigInt extends Def[BigInt] {
+ def toByte: Rep[Byte];
+ def toShort: Rep[Short];
+ def toInt: Rep[Int];
+ def toLong: Rep[Long];
+ def toBytes: Rep[Coll[Byte]];
+ def toBits: Rep[Coll[Boolean]];
+ def toAbs: Rep[BigInt];
+ def compareTo(that: Rep[BigInt]): Rep[Int];
+ def modQ: Rep[BigInt];
+ def plusModQ(other: Rep[BigInt]): Rep[BigInt];
+ def minusModQ(other: Rep[BigInt]): Rep[BigInt];
+ def multModQ(other: Rep[BigInt]): Rep[BigInt];
+ def inverseModQ: Rep[BigInt];
+ def signum: Rep[Int];
+ def add(that: Rep[BigInt]): Rep[BigInt];
+ def subtract(that: Rep[BigInt]): Rep[BigInt];
+ def multiply(that: Rep[BigInt]): Rep[BigInt];
+ def divide(that: Rep[BigInt]): Rep[BigInt];
+ def mod(m: Rep[BigInt]): Rep[BigInt];
+ def remainder(that: Rep[BigInt]): Rep[BigInt];
+ def min(that: Rep[BigInt]): Rep[BigInt];
+ def max(that: Rep[BigInt]): Rep[BigInt];
+ def negate: Rep[BigInt]
+ };
+ @Liftable trait GroupElement extends Def[GroupElement] {
+ def isInfinity: Rep[Boolean];
+ def exp(k: Rep[BigInt]): Rep[GroupElement];
+ def multiply(that: Rep[GroupElement]): Rep[GroupElement];
+ def negate: Rep[GroupElement];
+ def getEncoded: Rep[Coll[Byte]]
+ };
+ @Liftable trait SigmaProp extends Def[SigmaProp] {
+ def isValid: Rep[Boolean];
+ def propBytes: Rep[Coll[Byte]];
+ @OverloadId(value = "and_sigma") def &&(other: Rep[SigmaProp]): Rep[SigmaProp];
+ // manual fix
+ @OverloadId(value = "and_bool") def &&(other: Rep[Boolean])(implicit o: Overloaded1): Rep[SigmaProp];
+ @OverloadId(value = "or_sigma") def ||(other: Rep[SigmaProp]): Rep[SigmaProp];
+ // manual fix
+ @OverloadId(value = "or_bool") def ||(other: Rep[Boolean])(implicit o: Overloaded1): Rep[SigmaProp];
+ };
+ @Liftable trait AnyValue extends Def[AnyValue] {
+ def value: Rep[Any];
+ def tVal: Rep[WRType[Any]]
+ };
+ @Liftable trait Box extends Def[Box] {
+ def id: Rep[Coll[Byte]];
+ def value: Rep[Long];
+ def propositionBytes: Rep[Coll[Byte]];
+ def bytes: Rep[Coll[Byte]];
+ def bytesWithoutRef: Rep[Coll[Byte]];
+ def registers: Rep[Coll[AnyValue]];
+ def getReg[T](i: Rep[Int])(implicit cT: Elem[T]): Rep[WOption[T]];
+ def R0[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(0.asInstanceOf[Int]));
+ def R1[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(1.asInstanceOf[Int]));
+ def R2[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(2.asInstanceOf[Int]));
+ def R3[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(3.asInstanceOf[Int]));
+ def R4[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(4.asInstanceOf[Int]));
+ def R5[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(5.asInstanceOf[Int]));
+ def R6[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(6.asInstanceOf[Int]));
+ def R7[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(7.asInstanceOf[Int]));
+ def R8[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(8.asInstanceOf[Int]));
+ def R9[T](implicit cT: Elem[T]): Rep[WOption[T]] = this.getReg[T](toRep(9.asInstanceOf[Int]));
+ def tokens: Rep[Coll[scala.Tuple2[Coll[Byte], Long]]];
+ def creationInfo: Rep[scala.Tuple2[Int, Coll[Byte]]];
+ def executeFromRegister[T](regId: Rep[Byte])(implicit cT: Elem[T]): Rep[T]
+ };
+ @Liftable trait AvlTree extends Def[AvlTree] {
+ def digest: Rep[Coll[Byte]];
+ def enabledOperations: Rep[Byte];
+ def keyLength: Rep[Int];
+ def valueLengthOpt: Rep[WOption[Int]];
+ def isInsertAllowed: Rep[Boolean];
+ def isUpdateAllowed: Rep[Boolean];
+ def isRemoveAllowed: Rep[Boolean];
+ def updateDigest(newDigest: Rep[Coll[Byte]]): Rep[AvlTree];
+ def updateOperations(newOperations: Rep[Byte]): Rep[AvlTree];
+ def contains(key: Rep[Coll[Byte]], proof: Rep[Coll[Byte]]): Rep[Boolean];
+ def get(key: Rep[Coll[Byte]], proof: Rep[Coll[Byte]]): Rep[WOption[Coll[Byte]]];
+ def getMany(keys: Rep[Coll[Coll[Byte]]], proof: Rep[Coll[Byte]]): Rep[Coll[WOption[Coll[Byte]]]];
+ def insert(operations: Rep[Coll[scala.Tuple2[Coll[Byte], Coll[Byte]]]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]];
+ def update(operations: Rep[Coll[scala.Tuple2[Coll[Byte], Coll[Byte]]]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]];
+ def remove(operations: Rep[Coll[Coll[Byte]]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]]
+ };
+ @Liftable trait PreHeader extends Def[PreHeader] {
+ def version: Rep[Byte];
+ def parentId: Rep[Coll[Byte]];
+ def timestamp: Rep[Long];
+ def nBits: Rep[Long];
+ def height: Rep[Int];
+ def minerPk: Rep[GroupElement];
+ def votes: Rep[Coll[Byte]]
+ };
+ @Liftable trait Header extends Def[Header] {
+ def id: Rep[Coll[Byte]];
+ def version: Rep[Byte];
+ def parentId: Rep[Coll[Byte]];
+ def ADProofsRoot: Rep[Coll[Byte]];
+ def stateRoot: Rep[AvlTree];
+ def transactionsRoot: Rep[Coll[Byte]];
+ def timestamp: Rep[Long];
+ def nBits: Rep[Long];
+ def height: Rep[Int];
+ def extensionRoot: Rep[Coll[Byte]];
+ def minerPk: Rep[GroupElement];
+ def powOnetimePk: Rep[GroupElement];
+ def powNonce: Rep[Coll[Byte]];
+ def powDistance: Rep[BigInt];
+ def votes: Rep[Coll[Byte]]
+ };
+ @Liftable trait Context extends Def[Context] {
+ def builder: Rep[SigmaDslBuilder];
+ def OUTPUTS: Rep[Coll[Box]];
+ def INPUTS: Rep[Coll[Box]];
+ def dataInputs: Rep[Coll[Box]];
+ def HEIGHT: Rep[Int];
+ def SELF: Rep[Box];
+ def selfBoxIndex: Rep[Int];
+ def LastBlockUtxoRootHash: Rep[AvlTree];
+ def headers: Rep[Coll[Header]];
+ def preHeader: Rep[PreHeader];
+ def minerPubKey: Rep[Coll[Byte]];
+ def getVar[T](id: Rep[Byte])(implicit cT: Elem[T]): Rep[WOption[T]];
+ def vars: Rep[Coll[AnyValue]]
+ };
+ @Liftable trait SigmaContract extends Def[SigmaContract] {
+ def builder: Rep[SigmaDslBuilder];
+ @NeverInline @Reified(value = "T") def Collection[T](items: Rep[T]*)(implicit cT: Elem[T]): Rep[Coll[T]] = delayInvoke;
+ def verifyZK(cond: Rep[Thunk[SigmaProp]]): Rep[Boolean] = this.builder.verifyZK(cond);
+ def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = this.builder.atLeast(bound, props);
+ def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = this.builder.allOf(conditions);
+ def allZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = this.builder.allZK(conditions);
+ def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = this.builder.anyOf(conditions);
+ def anyZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = this.builder.anyZK(conditions);
+ def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = this.builder.xorOf(conditions);
+ def PubKey(base64String: Rep[String]): Rep[SigmaProp] = this.builder.PubKey(base64String);
+ def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp] = this.builder.sigmaProp(b);
+ def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = this.builder.blake2b256(bytes);
+ def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = this.builder.sha256(bytes);
+ def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt] = this.builder.byteArrayToBigInt(bytes);
+ def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]] = this.builder.longToByteArray(l);
+ def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long] = this.builder.byteArrayToLong(bytes);
+ def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp] = this.builder.proveDlog(g);
+ def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp] = this.builder.proveDHTuple(g, h, u, v);
+ def groupGenerator: Rep[GroupElement] = this.builder.groupGenerator;
+ @clause def canOpen(ctx: Rep[Context]): Rep[Boolean];
+ def asFunction: Rep[scala.Function1[Context, Boolean]] = fun(((ctx: Rep[Context]) => this.canOpen(ctx)))
+ };
+ @Liftable trait SigmaDslBuilder extends Def[SigmaDslBuilder] {
+ def Colls: Rep[CollBuilder];
+ def Monoids: Rep[MonoidBuilder];
+ def Costing: Rep[CostedBuilder];
+ def CostModel: Rep[CostModel];
+ def verifyZK(cond: Rep[Thunk[SigmaProp]]): Rep[Boolean];
+ def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp];
+ def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean];
+ def allZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp];
+ def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean];
+ def anyZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp];
+ def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean];
+ def PubKey(base64String: Rep[String]): Rep[SigmaProp];
+ def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp];
+ def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]];
+ def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]];
+ def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt];
+ def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]];
+ def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long];
+ def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp];
+ def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp];
+ def groupGenerator: Rep[GroupElement];
+ @Reified(value = "T") def substConstants[T](scriptBytes: Rep[Coll[Byte]], positions: Rep[Coll[Int]], newValues: Rep[Coll[T]])(implicit cT: Elem[T]): Rep[Coll[Byte]];
+ def decodePoint(encoded: Rep[Coll[Byte]]): Rep[GroupElement];
+ def BigInt(n: Rep[WBigInteger]): Rep[BigInt];
+ def toBigInteger(n: Rep[BigInt]): Rep[WBigInteger];
+ def avlTree(operationFlags: Rep[Byte], digest: Rep[Coll[Byte]], keyLength: Rep[Int], valueLengthOpt: Rep[WOption[Int]]): Rep[AvlTree]
+ };
+ trait CostModelCompanion;
+ trait BigIntCompanion;
+ trait GroupElementCompanion;
+ trait SigmaPropCompanion;
+ trait AnyValueCompanion;
+ trait BoxCompanion;
+ trait AvlTreeCompanion;
+ trait PreHeaderCompanion;
+ trait HeaderCompanion;
+ trait ContextCompanion;
+ trait SigmaContractCompanion;
+ trait SigmaDslBuilderCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-library/src/main/scala/special/sigma/SigmaDslCosted.scala b/sigma-library/src/main/scala/special/sigma/SigmaDslCosted.scala
new file mode 100644
index 0000000000..85653f79bd
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/SigmaDslCosted.scala
@@ -0,0 +1,47 @@
+package special.sigma {
+ import scalan._
+
+ trait SigmaDslCosted extends Base { self: SigmaLibrary =>
+ import AnyValue._;
+ import AvlTree._;
+ import Box._;
+ import CSizeAnyValue._;
+ import CSizeBox._;
+ import CSizeContext._;
+ import Coll._;
+ import Header._;
+ import PreHeader._;
+ import Size._;
+ import SizeAnyValue._;
+ import SizeBox._;
+ import SizeBuilder._;
+ import SizeContext._;
+ import SizeSigmaProp._;
+ import WOption._;
+ import WRType._;
+ abstract class CSizeAnyValue(val tVal: Rep[WRType[Any]], val valueSize: Rep[Size[Any]]) extends SizeAnyValue {
+ @NeverInline override def dataSize: Rep[Long] = delayInvoke
+ };
+ abstract class CSizeSigmaProp(val propBytes: Rep[Size[Coll[Byte]]]) extends SizeSigmaProp {
+ @NeverInline override def dataSize: Rep[Long] = delayInvoke
+ };
+ abstract class CSizeBox(val propositionBytes: Rep[Size[Coll[Byte]]], val bytes: Rep[Size[Coll[Byte]]], val bytesWithoutRef: Rep[Size[Coll[Byte]]], val registers: Rep[Size[Coll[WOption[AnyValue]]]], val tokens: Rep[Size[Coll[scala.Tuple2[Coll[Byte], Long]]]]) extends SizeBox {
+ @NeverInline override def dataSize: Rep[Long] = delayInvoke;
+ @NeverInline override def getReg[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = delayInvoke
+ };
+ abstract class CSizeContext(val outputs: Rep[Size[Coll[Box]]], val inputs: Rep[Size[Coll[Box]]], val dataInputs: Rep[Size[Coll[Box]]], val selfBox: Rep[Size[Box]], val lastBlockUtxoRootHash: Rep[Size[AvlTree]], val headers: Rep[Size[Coll[Header]]], val preHeader: Rep[Size[PreHeader]], val vars: Rep[Coll[Size[AnyValue]]]) extends SizeContext {
+ @NeverInline override def dataSize: Rep[Long] = delayInvoke;
+ @NeverInline override def getVar[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = delayInvoke
+ };
+ abstract class CSizeBuilder extends SizeBuilder {
+ def mkSizeAnyValue(tVal: Rep[WRType[Any]], valueSize: Rep[Size[Any]]): Rep[SizeAnyValue] = RCSizeAnyValue(tVal, valueSize);
+ def mkSizeBox(propositionBytes: Rep[Size[Coll[Byte]]], bytes: Rep[Size[Coll[Byte]]], bytesWithoutRef: Rep[Size[Coll[Byte]]], registers: Rep[Size[Coll[WOption[AnyValue]]]], tokens: Rep[Size[Coll[scala.Tuple2[Coll[Byte], Long]]]]): Rep[SizeBox] = RCSizeBox(propositionBytes, bytes, bytesWithoutRef, registers, tokens);
+ def mkSizeContext(outputs: Rep[Size[Coll[Box]]], inputs: Rep[Size[Coll[Box]]], dataInputs: Rep[Size[Coll[Box]]], selfBox: Rep[Size[Box]], lastBlockUtxoRootHash: Rep[Size[AvlTree]], headers: Rep[Size[Coll[Header]]], preHeader: Rep[Size[PreHeader]], vars: Rep[Coll[Size[AnyValue]]]): Rep[SizeContext] = RCSizeContext(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars)
+ };
+ trait CSizeAnyValueCompanion;
+ trait CSizeSigmaPropCompanion;
+ trait CSizeBoxCompanion;
+ trait CSizeContextCompanion;
+ trait CSizeBuilderCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-library/src/main/scala/special/sigma/SigmaDslOverArrays.scala b/sigma-library/src/main/scala/special/sigma/SigmaDslOverArrays.scala
new file mode 100644
index 0000000000..19dd014f1c
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/SigmaDslOverArrays.scala
@@ -0,0 +1,57 @@
+package special.sigma {
+ import scalan.OverloadHack.Overloaded1 // manual fix
+ import scalan._
+
+ trait SigmaDslOverArrays extends Base { self: SigmaLibrary =>
+ import AvlTree._;
+ import BigInt._;
+ import Box._;
+ import CostedBuilder._ // manual fix
+ import CCostedBuilder._;
+ import Coll._;
+ import CollBuilder._;
+ import CollOverArrayBuilder._;
+ import CostModel._;
+ import CostedBuilder._;
+ import GroupElement._;
+ import MonoidBuilder._;
+ import MonoidBuilderInst._;
+ import SigmaDslBuilder._;
+ import SigmaProp._;
+ import WBigInteger._;
+ import WECPoint._;
+ import WOption._;
+ import WSpecialPredef._; // manual fix
+ abstract class TestSigmaDslBuilder extends SigmaDslBuilder {
+ def Colls: Rep[CollBuilder] = RCollOverArrayBuilder();
+ def Monoids: Rep[MonoidBuilder] = RMonoidBuilderInst();
+ def Costing: Rep[CostedBuilder] = RCCostedBuilder();
+ @NeverInline def CostModel: Rep[CostModel] = delayInvoke;
+ @NeverInline def verifyZK(proof: Rep[Thunk[SigmaProp]]): Rep[Boolean] = delayInvoke;
+ @NeverInline def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = delayInvoke;
+ @NeverInline def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = delayInvoke;
+ @NeverInline def allZK(props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def anyZK(props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline override def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = delayInvoke;
+ @NeverInline def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = delayInvoke;
+ @NeverInline def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = delayInvoke;
+ @NeverInline def PubKey(base64String: Rep[String]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt] = delayInvoke;
+ @NeverInline def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]] = delayInvoke;
+ @NeverInline def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long] = delayInvoke;
+ @NeverInline def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp] = delayInvoke;
+ @NeverInline def groupGenerator: Rep[GroupElement] = delayInvoke;
+ @Reified(value = "T") @NeverInline override def substConstants[T](scriptBytes: Rep[Coll[Byte]], positions: Rep[Coll[Int]], newValues: Rep[Coll[T]])(implicit cT: Elem[T]): Rep[Coll[Byte]] = delayInvoke;
+ @NeverInline override def decodePoint(encoded: Rep[Coll[Byte]]): Rep[GroupElement] = delayInvoke;
+ @NeverInline override def BigInt(n: Rep[WBigInteger]): Rep[BigInt] = delayInvoke;
+ @NeverInline override def toBigInteger(n: Rep[BigInt]): Rep[WBigInteger] = delayInvoke;
+ @NeverInline def GroupElement(p: Rep[WECPoint]): Rep[GroupElement] = delayInvoke;
+ @NeverInline def toECPoint(ge: Rep[GroupElement]): Rep[WECPoint] = delayInvoke;
+ @NeverInline override def avlTree(operationFlags: Rep[Byte], digest: Rep[Coll[Byte]], keyLength: Rep[Int], valueLengthOpt: Rep[WOption[Int]]): Rep[AvlTree] = delayInvoke
+ };
+ trait TestSigmaDslBuilderCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-library/src/main/scala/special/sigma/impl/CostedObjectsImpl.scala b/sigma-library/src/main/scala/special/sigma/impl/CostedObjectsImpl.scala
new file mode 100644
index 0000000000..17362add1d
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/impl/CostedObjectsImpl.scala
@@ -0,0 +1,1144 @@
+package special.sigma
+
+import scalan._
+import scala.reflect.runtime.universe._
+import scala.reflect._
+
+package impl {
+// Abs -----------------------------------
+trait CostedObjectsDefs extends scalan.Scalan with CostedObjects {
+ self: SigmaLibrary =>
+import IsoUR._
+import Converter._
+import AnyValue._
+import AvlTree._
+import Box._
+import Coll._
+import Context._
+import Header._
+import PreHeader._
+import SigmaProp._
+import Size._
+import SizeAnyValue._
+import SizeBox._
+import SizeBuilder._
+import SizeContext._
+import WOption._
+import WRType._
+import SizeSigmaProp._
+
+object SizeAnyValue extends EntityObject("SizeAnyValue") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SSizeAnyValue = special.sigma.SizeAnyValue
+ case class SizeAnyValueConst(
+ constValue: SSizeAnyValue
+ ) extends SizeAnyValue with LiftedConst[SSizeAnyValue, SizeAnyValue]
+ with Def[SizeAnyValue] with SizeAnyValueConstMethods {
+// manual fix
+ def eVal: Elem[AnyValue] = element[AnyValue]
+
+ val liftable: Liftable[SSizeAnyValue, SizeAnyValue] = LiftableSizeAnyValue
+ val selfType: Elem[SizeAnyValue] = liftable.eW
+ }
+
+ trait SizeAnyValueConstMethods extends SizeAnyValue with SizeConstMethods[AnyValue] { thisConst: Def[_] =>
+
+ private val SizeAnyValueClass = classOf[SizeAnyValue]
+
+ // manual fix
+ override def tVal: Rep[WRType[Any]] = {
+ asRep[WRType[Any]](mkMethodCall(self,
+ SizeAnyValueClass.getMethod("tVal"),
+ List(),
+ true, false, wRTypeElement(AnyElement)))
+ }
+
+ // manual fix
+ override def valueSize: Rep[Size[Any]] = {
+ asRep[Size[Any]](mkMethodCall(self,
+ SizeAnyValueClass.getMethod("valueSize"),
+ List(),
+ true, false, sizeElement(AnyElement)))
+ }
+ }
+
+ implicit object LiftableSizeAnyValue
+ extends Liftable[SSizeAnyValue, SizeAnyValue] {
+ lazy val eW: Elem[SizeAnyValue] = sizeAnyValueElement
+ lazy val sourceType: RType[SSizeAnyValue] = {
+ RType[SSizeAnyValue]
+ }
+ def lift(x: SSizeAnyValue): Rep[SizeAnyValue] = SizeAnyValueConst(x)
+ def unlift(w: Rep[SizeAnyValue]): SSizeAnyValue = w match {
+ case Def(SizeAnyValueConst(x: SSizeAnyValue))
+ => x.asInstanceOf[SSizeAnyValue]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for SizeAnyValue trait
+ case class SizeAnyValueAdapter(source: Rep[SizeAnyValue])
+ extends SizeAnyValue with Def[SizeAnyValue] {
+ override lazy val eVal: Elem[AnyValue] = implicitly[Elem[AnyValue]]
+ val selfType: Elem[SizeAnyValue] = element[SizeAnyValue]
+ override def transform(t: Transformer) = SizeAnyValueAdapter(t(source))
+ private val thisClass = classOf[SizeAnyValue]
+
+ // manual fix
+ def tVal: Rep[WRType[Any]] = {
+ asRep[WRType[Any]](mkMethodCall(source,
+ thisClass.getMethod("tVal"),
+ List(),
+ true, true, wRTypeElement(AnyElement)))
+ }
+
+ // manual fix
+ def valueSize: Rep[Size[Any]] = {
+ asRep[Size[Any]](mkMethodCall(source,
+ thisClass.getMethod("valueSize"),
+ List(),
+ true, true, sizeElement(AnyElement)))
+ }
+
+ def dataSize: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("dataSize"),
+ List(),
+ true, true, element[Long]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySizeAnyValue(p: Rep[SizeAnyValue]): SizeAnyValue = {
+ if (p.rhs.isInstanceOf[SizeAnyValue@unchecked]) p.rhs.asInstanceOf[SizeAnyValue]
+ else
+ SizeAnyValueAdapter(p)
+ }
+
+ // familyElem
+ class SizeAnyValueElem[To <: SizeAnyValue]
+ extends SizeElem[AnyValue, To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableSizeAnyValue.asLiftable[SSizeAnyValue, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[SizeAnyValue], classOf[SSizeAnyValue], Set(
+ "tVal", "valueSize"
+ ))
+ }
+
+ override lazy val parent: Option[Elem[_]] = Some(sizeElement(anyValueElement))
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SizeAnyValue].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SizeAnyValue] => convertSizeAnyValue(x) }
+ tryConvert(element[SizeAnyValue], this, x, conv)
+ }
+
+ def convertSizeAnyValue(x: Rep[SizeAnyValue]): Rep[To] = {
+ x.elem match {
+ case _: SizeAnyValueElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SizeAnyValueElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sizeAnyValueElement: Elem[SizeAnyValue] =
+ new SizeAnyValueElem[SizeAnyValue]
+
+ implicit case object SizeAnyValueCompanionElem extends CompanionElem[SizeAnyValueCompanionCtor] {
+ lazy val tag = weakTypeTag[SizeAnyValueCompanionCtor]
+ protected def getDefaultRep = RSizeAnyValue
+ }
+
+ abstract class SizeAnyValueCompanionCtor extends CompanionDef[SizeAnyValueCompanionCtor] with SizeAnyValueCompanion {
+ def selfType = SizeAnyValueCompanionElem
+ override def toString = "SizeAnyValue"
+ }
+ implicit def proxySizeAnyValueCompanionCtor(p: Rep[SizeAnyValueCompanionCtor]): SizeAnyValueCompanionCtor =
+ proxyOps[SizeAnyValueCompanionCtor](p)
+
+ lazy val RSizeAnyValue: Rep[SizeAnyValueCompanionCtor] = new SizeAnyValueCompanionCtor {
+ private val thisClass = classOf[SizeAnyValueCompanion]
+ }
+
+ object SizeAnyValueMethods {
+ object tVal {
+ def unapply(d: Def[_]): Nullable[Rep[SizeAnyValue]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeAnyValueElem[_]] && method.getName == "tVal" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeAnyValue]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeAnyValue]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object valueSize {
+ def unapply(d: Def[_]): Nullable[Rep[SizeAnyValue]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeAnyValueElem[_]] && method.getName == "valueSize" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeAnyValue]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeAnyValue]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SizeAnyValueCompanionMethods {
+ }
+} // of object SizeAnyValue
+ registerEntityObject("SizeAnyValue", SizeAnyValue)
+
+object SizeSigmaProp extends EntityObject("SizeSigmaProp") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SSizeSigmaProp = special.sigma.SizeSigmaProp
+ case class SizeSigmaPropConst(
+ constValue: SSizeSigmaProp
+ ) extends SizeSigmaProp with LiftedConst[SSizeSigmaProp, SizeSigmaProp]
+ with Def[SizeSigmaProp] with SizeSigmaPropConstMethods {
+ // manual fix
+ def eVal: Elem[SigmaProp] = element[SigmaProp]
+
+ val liftable: Liftable[SSizeSigmaProp, SizeSigmaProp] = LiftableSizeSigmaProp
+ val selfType: Elem[SizeSigmaProp] = liftable.eW
+ }
+
+ trait SizeSigmaPropConstMethods extends SizeSigmaProp with SizeConstMethods[SigmaProp] { thisConst: Def[_] =>
+
+ private val SizeSigmaPropClass = classOf[SizeSigmaProp]
+
+ override def propBytes: Rep[Size[Coll[Byte]]] = {
+ asRep[Size[Coll[Byte]]](mkMethodCall(self,
+ SizeSigmaPropClass.getMethod("propBytes"),
+ List(),
+ true, false, element[Size[Coll[Byte]]]))
+ }
+ }
+
+ implicit object LiftableSizeSigmaProp
+ extends Liftable[SSizeSigmaProp, SizeSigmaProp] {
+ lazy val eW: Elem[SizeSigmaProp] = sizeSigmaPropElement
+ lazy val sourceType: RType[SSizeSigmaProp] = {
+ RType[SSizeSigmaProp]
+ }
+ def lift(x: SSizeSigmaProp): Rep[SizeSigmaProp] = SizeSigmaPropConst(x)
+ def unlift(w: Rep[SizeSigmaProp]): SSizeSigmaProp = w match {
+ case Def(SizeSigmaPropConst(x: SSizeSigmaProp))
+ => x.asInstanceOf[SSizeSigmaProp]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for SizeSigmaProp trait
+ case class SizeSigmaPropAdapter(source: Rep[SizeSigmaProp])
+ extends SizeSigmaProp with Def[SizeSigmaProp] {
+ override lazy val eVal: Elem[SigmaProp] = implicitly[Elem[SigmaProp]]
+ val selfType: Elem[SizeSigmaProp] = element[SizeSigmaProp]
+ override def transform(t: Transformer) = SizeSigmaPropAdapter(t(source))
+ private val thisClass = classOf[SizeSigmaProp]
+
+ def propBytes: Rep[Size[Coll[Byte]]] = {
+ asRep[Size[Coll[Byte]]](mkMethodCall(source,
+ thisClass.getMethod("propBytes"),
+ List(),
+ true, true, element[Size[Coll[Byte]]]))
+ }
+
+ def dataSize: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("dataSize"),
+ List(),
+ true, true, element[Long]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySizeSigmaProp(p: Rep[SizeSigmaProp]): SizeSigmaProp = {
+ if (p.rhs.isInstanceOf[SizeSigmaProp@unchecked]) p.rhs.asInstanceOf[SizeSigmaProp]
+ else
+ SizeSigmaPropAdapter(p)
+ }
+
+ // familyElem
+ class SizeSigmaPropElem[To <: SizeSigmaProp]
+ extends SizeElem[SigmaProp, To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableSizeSigmaProp.asLiftable[SSizeSigmaProp, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[SizeSigmaProp], classOf[SSizeSigmaProp], Set(
+ "propBytes"
+ ))
+ }
+
+ override lazy val parent: Option[Elem[_]] = Some(sizeElement(sigmaPropElement))
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SizeSigmaProp].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SizeSigmaProp] => convertSizeSigmaProp(x) }
+ tryConvert(element[SizeSigmaProp], this, x, conv)
+ }
+
+ def convertSizeSigmaProp(x: Rep[SizeSigmaProp]): Rep[To] = {
+ x.elem match {
+ case _: SizeSigmaPropElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SizeSigmaPropElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sizeSigmaPropElement: Elem[SizeSigmaProp] =
+ new SizeSigmaPropElem[SizeSigmaProp]
+
+ implicit case object SizeSigmaPropCompanionElem extends CompanionElem[SizeSigmaPropCompanionCtor] {
+ lazy val tag = weakTypeTag[SizeSigmaPropCompanionCtor]
+ protected def getDefaultRep = RSizeSigmaProp
+ }
+
+ abstract class SizeSigmaPropCompanionCtor extends CompanionDef[SizeSigmaPropCompanionCtor] with SizeSigmaPropCompanion {
+ def selfType = SizeSigmaPropCompanionElem
+ override def toString = "SizeSigmaProp"
+ }
+ implicit def proxySizeSigmaPropCompanionCtor(p: Rep[SizeSigmaPropCompanionCtor]): SizeSigmaPropCompanionCtor =
+ proxyOps[SizeSigmaPropCompanionCtor](p)
+
+ lazy val RSizeSigmaProp: Rep[SizeSigmaPropCompanionCtor] = new SizeSigmaPropCompanionCtor {
+ private val thisClass = classOf[SizeSigmaPropCompanion]
+ }
+
+ object SizeSigmaPropMethods {
+ object propBytes {
+ def unapply(d: Def[_]): Nullable[Rep[SizeSigmaProp]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeSigmaPropElem[_]] && method.getName == "propBytes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeSigmaProp]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeSigmaProp]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SizeSigmaPropCompanionMethods {
+ }
+} // of object SizeSigmaProp
+ registerEntityObject("SizeSigmaProp", SizeSigmaProp)
+
+object SizeBox extends EntityObject("SizeBox") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SSizeBox = special.sigma.SizeBox
+ case class SizeBoxConst(
+ constValue: SSizeBox
+ ) extends SizeBox with LiftedConst[SSizeBox, SizeBox]
+ with Def[SizeBox] with SizeBoxConstMethods {
+ // manual fix
+ def eVal: Elem[Box] = element[Box]
+
+ val liftable: Liftable[SSizeBox, SizeBox] = LiftableSizeBox
+ val selfType: Elem[SizeBox] = liftable.eW
+ }
+
+ trait SizeBoxConstMethods extends SizeBox with SizeConstMethods[Box] { thisConst: Def[_] =>
+
+ private val SizeBoxClass = classOf[SizeBox]
+
+ override def propositionBytes: Rep[Size[Coll[Byte]]] = {
+ asRep[Size[Coll[Byte]]](mkMethodCall(self,
+ SizeBoxClass.getMethod("propositionBytes"),
+ List(),
+ true, false, element[Size[Coll[Byte]]]))
+ }
+
+ override def bytes: Rep[Size[Coll[Byte]]] = {
+ asRep[Size[Coll[Byte]]](mkMethodCall(self,
+ SizeBoxClass.getMethod("bytes"),
+ List(),
+ true, false, element[Size[Coll[Byte]]]))
+ }
+
+ override def bytesWithoutRef: Rep[Size[Coll[Byte]]] = {
+ asRep[Size[Coll[Byte]]](mkMethodCall(self,
+ SizeBoxClass.getMethod("bytesWithoutRef"),
+ List(),
+ true, false, element[Size[Coll[Byte]]]))
+ }
+
+ override def registers: Rep[Size[Coll[WOption[AnyValue]]]] = {
+ asRep[Size[Coll[WOption[AnyValue]]]](mkMethodCall(self,
+ SizeBoxClass.getMethod("registers"),
+ List(),
+ true, false, element[Size[Coll[WOption[AnyValue]]]]))
+ }
+
+ override def getReg[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = {
+ asRep[Size[WOption[T]]](mkMethodCall(self,
+ SizeBoxClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
+ List(id, tT),
+ true, false, element[Size[WOption[T]]]))
+ }
+
+ override def tokens: Rep[Size[Coll[(Coll[Byte], Long)]]] = {
+ asRep[Size[Coll[(Coll[Byte], Long)]]](mkMethodCall(self,
+ SizeBoxClass.getMethod("tokens"),
+ List(),
+ true, false, element[Size[Coll[(Coll[Byte], Long)]]]))
+ }
+ }
+
+ implicit object LiftableSizeBox
+ extends Liftable[SSizeBox, SizeBox] {
+ lazy val eW: Elem[SizeBox] = sizeBoxElement
+ lazy val sourceType: RType[SSizeBox] = {
+ RType[SSizeBox]
+ }
+ def lift(x: SSizeBox): Rep[SizeBox] = SizeBoxConst(x)
+ def unlift(w: Rep[SizeBox]): SSizeBox = w match {
+ case Def(SizeBoxConst(x: SSizeBox))
+ => x.asInstanceOf[SSizeBox]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for SizeBox trait
+ case class SizeBoxAdapter(source: Rep[SizeBox])
+ extends SizeBox with Def[SizeBox] {
+ override lazy val eVal: Elem[Box] = implicitly[Elem[Box]]
+ val selfType: Elem[SizeBox] = element[SizeBox]
+ override def transform(t: Transformer) = SizeBoxAdapter(t(source))
+ private val thisClass = classOf[SizeBox]
+
+ def propositionBytes: Rep[Size[Coll[Byte]]] = {
+ asRep[Size[Coll[Byte]]](mkMethodCall(source,
+ thisClass.getMethod("propositionBytes"),
+ List(),
+ true, true, element[Size[Coll[Byte]]]))
+ }
+
+ def bytes: Rep[Size[Coll[Byte]]] = {
+ asRep[Size[Coll[Byte]]](mkMethodCall(source,
+ thisClass.getMethod("bytes"),
+ List(),
+ true, true, element[Size[Coll[Byte]]]))
+ }
+
+ def bytesWithoutRef: Rep[Size[Coll[Byte]]] = {
+ asRep[Size[Coll[Byte]]](mkMethodCall(source,
+ thisClass.getMethod("bytesWithoutRef"),
+ List(),
+ true, true, element[Size[Coll[Byte]]]))
+ }
+
+ def registers: Rep[Size[Coll[WOption[AnyValue]]]] = {
+ asRep[Size[Coll[WOption[AnyValue]]]](mkMethodCall(source,
+ thisClass.getMethod("registers"),
+ List(),
+ true, true, element[Size[Coll[WOption[AnyValue]]]]))
+ }
+
+ def getReg[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = {
+ asRep[Size[WOption[T]]](mkMethodCall(source,
+ thisClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
+ List(id, tT),
+ true, true, element[Size[WOption[T]]]))
+ }
+
+ def tokens: Rep[Size[Coll[(Coll[Byte], Long)]]] = {
+ asRep[Size[Coll[(Coll[Byte], Long)]]](mkMethodCall(source,
+ thisClass.getMethod("tokens"),
+ List(),
+ true, true, element[Size[Coll[(Coll[Byte], Long)]]]))
+ }
+
+ def dataSize: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("dataSize"),
+ List(),
+ true, true, element[Long]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySizeBox(p: Rep[SizeBox]): SizeBox = {
+ if (p.rhs.isInstanceOf[SizeBox@unchecked]) p.rhs.asInstanceOf[SizeBox]
+ else
+ SizeBoxAdapter(p)
+ }
+
+ // familyElem
+ class SizeBoxElem[To <: SizeBox]
+ extends SizeElem[Box, To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableSizeBox.asLiftable[SSizeBox, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[SizeBox], classOf[SSizeBox], Set(
+ "propositionBytes", "bytes", "bytesWithoutRef", "registers", "getReg", "tokens"
+ ))
+ }
+
+ override lazy val parent: Option[Elem[_]] = Some(sizeElement(boxElement))
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SizeBox].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SizeBox] => convertSizeBox(x) }
+ tryConvert(element[SizeBox], this, x, conv)
+ }
+
+ def convertSizeBox(x: Rep[SizeBox]): Rep[To] = {
+ x.elem match {
+ case _: SizeBoxElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SizeBoxElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sizeBoxElement: Elem[SizeBox] =
+ new SizeBoxElem[SizeBox]
+
+ implicit case object SizeBoxCompanionElem extends CompanionElem[SizeBoxCompanionCtor] {
+ lazy val tag = weakTypeTag[SizeBoxCompanionCtor]
+ protected def getDefaultRep = RSizeBox
+ }
+
+ abstract class SizeBoxCompanionCtor extends CompanionDef[SizeBoxCompanionCtor] with SizeBoxCompanion {
+ def selfType = SizeBoxCompanionElem
+ override def toString = "SizeBox"
+ }
+ implicit def proxySizeBoxCompanionCtor(p: Rep[SizeBoxCompanionCtor]): SizeBoxCompanionCtor =
+ proxyOps[SizeBoxCompanionCtor](p)
+
+ lazy val RSizeBox: Rep[SizeBoxCompanionCtor] = new SizeBoxCompanionCtor {
+ private val thisClass = classOf[SizeBoxCompanion]
+ }
+
+ object SizeBoxMethods {
+ object propositionBytes {
+ def unapply(d: Def[_]): Nullable[Rep[SizeBox]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeBoxElem[_]] && method.getName == "propositionBytes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeBox]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeBox]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object bytes {
+ def unapply(d: Def[_]): Nullable[Rep[SizeBox]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeBoxElem[_]] && method.getName == "bytes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeBox]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeBox]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object bytesWithoutRef {
+ def unapply(d: Def[_]): Nullable[Rep[SizeBox]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeBoxElem[_]] && method.getName == "bytesWithoutRef" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeBox]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeBox]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object registers {
+ def unapply(d: Def[_]): Nullable[Rep[SizeBox]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeBoxElem[_]] && method.getName == "registers" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeBox]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeBox]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getReg {
+ def unapply(d: Def[_]): Nullable[(Rep[SizeBox], Rep[Byte], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SizeBoxElem[_]] && method.getName == "getReg" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SizeBox], Rep[Byte], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SizeBox], Rep[Byte], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object tokens {
+ def unapply(d: Def[_]): Nullable[Rep[SizeBox]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeBoxElem[_]] && method.getName == "tokens" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeBox]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeBox]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SizeBoxCompanionMethods {
+ }
+} // of object SizeBox
+ registerEntityObject("SizeBox", SizeBox)
+
+object SizeContext extends EntityObject("SizeContext") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SSizeContext = special.sigma.SizeContext
+ case class SizeContextConst(
+ constValue: SSizeContext
+ ) extends SizeContext with LiftedConst[SSizeContext, SizeContext]
+ with Def[SizeContext] with SizeContextConstMethods {
+ // manual fix
+ def eVal: Elem[Context] = element[Context]
+
+ val liftable: Liftable[SSizeContext, SizeContext] = LiftableSizeContext
+ val selfType: Elem[SizeContext] = liftable.eW
+ }
+
+ trait SizeContextConstMethods extends SizeContext with SizeConstMethods[Context] { thisConst: Def[_] =>
+
+ private val SizeContextClass = classOf[SizeContext]
+
+ override def outputs: Rep[Size[Coll[Box]]] = {
+ asRep[Size[Coll[Box]]](mkMethodCall(self,
+ SizeContextClass.getMethod("outputs"),
+ List(),
+ true, false, element[Size[Coll[Box]]]))
+ }
+
+ override def inputs: Rep[Size[Coll[Box]]] = {
+ asRep[Size[Coll[Box]]](mkMethodCall(self,
+ SizeContextClass.getMethod("inputs"),
+ List(),
+ true, false, element[Size[Coll[Box]]]))
+ }
+
+ override def dataInputs: Rep[Size[Coll[Box]]] = {
+ asRep[Size[Coll[Box]]](mkMethodCall(self,
+ SizeContextClass.getMethod("dataInputs"),
+ List(),
+ true, false, element[Size[Coll[Box]]]))
+ }
+
+ override def selfBox: Rep[Size[Box]] = {
+ asRep[Size[Box]](mkMethodCall(self,
+ SizeContextClass.getMethod("selfBox"),
+ List(),
+ true, false, element[Size[Box]]))
+ }
+
+ override def lastBlockUtxoRootHash: Rep[Size[AvlTree]] = {
+ asRep[Size[AvlTree]](mkMethodCall(self,
+ SizeContextClass.getMethod("lastBlockUtxoRootHash"),
+ List(),
+ true, false, element[Size[AvlTree]]))
+ }
+
+ override def headers: Rep[Size[Coll[Header]]] = {
+ asRep[Size[Coll[Header]]](mkMethodCall(self,
+ SizeContextClass.getMethod("headers"),
+ List(),
+ true, false, element[Size[Coll[Header]]]))
+ }
+
+ override def preHeader: Rep[Size[PreHeader]] = {
+ asRep[Size[PreHeader]](mkMethodCall(self,
+ SizeContextClass.getMethod("preHeader"),
+ List(),
+ true, false, element[Size[PreHeader]]))
+ }
+
+ override def getVar[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = {
+ asRep[Size[WOption[T]]](mkMethodCall(self,
+ SizeContextClass.getMethod("getVar", classOf[Sym], classOf[Elem[_]]),
+ List(id, tT),
+ true, false, element[Size[WOption[T]]]))
+ }
+ }
+
+ implicit object LiftableSizeContext
+ extends Liftable[SSizeContext, SizeContext] {
+ lazy val eW: Elem[SizeContext] = sizeContextElement
+ lazy val sourceType: RType[SSizeContext] = {
+ RType[SSizeContext]
+ }
+ def lift(x: SSizeContext): Rep[SizeContext] = SizeContextConst(x)
+ def unlift(w: Rep[SizeContext]): SSizeContext = w match {
+ case Def(SizeContextConst(x: SSizeContext))
+ => x.asInstanceOf[SSizeContext]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for SizeContext trait
+ case class SizeContextAdapter(source: Rep[SizeContext])
+ extends SizeContext with Def[SizeContext] {
+ override lazy val eVal: Elem[Context] = implicitly[Elem[Context]]
+ val selfType: Elem[SizeContext] = element[SizeContext]
+ override def transform(t: Transformer) = SizeContextAdapter(t(source))
+ private val thisClass = classOf[SizeContext]
+
+ def outputs: Rep[Size[Coll[Box]]] = {
+ asRep[Size[Coll[Box]]](mkMethodCall(source,
+ thisClass.getMethod("outputs"),
+ List(),
+ true, true, element[Size[Coll[Box]]]))
+ }
+
+ def inputs: Rep[Size[Coll[Box]]] = {
+ asRep[Size[Coll[Box]]](mkMethodCall(source,
+ thisClass.getMethod("inputs"),
+ List(),
+ true, true, element[Size[Coll[Box]]]))
+ }
+
+ def dataInputs: Rep[Size[Coll[Box]]] = {
+ asRep[Size[Coll[Box]]](mkMethodCall(source,
+ thisClass.getMethod("dataInputs"),
+ List(),
+ true, true, element[Size[Coll[Box]]]))
+ }
+
+ def selfBox: Rep[Size[Box]] = {
+ asRep[Size[Box]](mkMethodCall(source,
+ thisClass.getMethod("selfBox"),
+ List(),
+ true, true, element[Size[Box]]))
+ }
+
+ def lastBlockUtxoRootHash: Rep[Size[AvlTree]] = {
+ asRep[Size[AvlTree]](mkMethodCall(source,
+ thisClass.getMethod("lastBlockUtxoRootHash"),
+ List(),
+ true, true, element[Size[AvlTree]]))
+ }
+
+ def headers: Rep[Size[Coll[Header]]] = {
+ asRep[Size[Coll[Header]]](mkMethodCall(source,
+ thisClass.getMethod("headers"),
+ List(),
+ true, true, element[Size[Coll[Header]]]))
+ }
+
+ def preHeader: Rep[Size[PreHeader]] = {
+ asRep[Size[PreHeader]](mkMethodCall(source,
+ thisClass.getMethod("preHeader"),
+ List(),
+ true, true, element[Size[PreHeader]]))
+ }
+
+ def getVar[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = {
+ asRep[Size[WOption[T]]](mkMethodCall(source,
+ thisClass.getMethod("getVar", classOf[Sym], classOf[Elem[_]]),
+ List(id, tT),
+ true, true, element[Size[WOption[T]]]))
+ }
+
+ def dataSize: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("dataSize"),
+ List(),
+ true, true, element[Long]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySizeContext(p: Rep[SizeContext]): SizeContext = {
+ if (p.rhs.isInstanceOf[SizeContext@unchecked]) p.rhs.asInstanceOf[SizeContext]
+ else
+ SizeContextAdapter(p)
+ }
+
+ // familyElem
+ class SizeContextElem[To <: SizeContext]
+ extends SizeElem[Context, To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableSizeContext.asLiftable[SSizeContext, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[SizeContext], classOf[SSizeContext], Set(
+ "outputs", "inputs", "dataInputs", "selfBox", "lastBlockUtxoRootHash", "headers", "preHeader", "getVar"
+ ))
+ }
+
+ override lazy val parent: Option[Elem[_]] = Some(sizeElement(contextElement))
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SizeContext].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SizeContext] => convertSizeContext(x) }
+ tryConvert(element[SizeContext], this, x, conv)
+ }
+
+ def convertSizeContext(x: Rep[SizeContext]): Rep[To] = {
+ x.elem match {
+ case _: SizeContextElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SizeContextElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sizeContextElement: Elem[SizeContext] =
+ new SizeContextElem[SizeContext]
+
+ implicit case object SizeContextCompanionElem extends CompanionElem[SizeContextCompanionCtor] {
+ lazy val tag = weakTypeTag[SizeContextCompanionCtor]
+ protected def getDefaultRep = RSizeContext
+ }
+
+ abstract class SizeContextCompanionCtor extends CompanionDef[SizeContextCompanionCtor] with SizeContextCompanion {
+ def selfType = SizeContextCompanionElem
+ override def toString = "SizeContext"
+ }
+ implicit def proxySizeContextCompanionCtor(p: Rep[SizeContextCompanionCtor]): SizeContextCompanionCtor =
+ proxyOps[SizeContextCompanionCtor](p)
+
+ lazy val RSizeContext: Rep[SizeContextCompanionCtor] = new SizeContextCompanionCtor {
+ private val thisClass = classOf[SizeContextCompanion]
+ }
+
+ object SizeContextMethods {
+ object outputs {
+ def unapply(d: Def[_]): Nullable[Rep[SizeContext]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeContextElem[_]] && method.getName == "outputs" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeContext]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeContext]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object inputs {
+ def unapply(d: Def[_]): Nullable[Rep[SizeContext]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeContextElem[_]] && method.getName == "inputs" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeContext]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeContext]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object dataInputs {
+ def unapply(d: Def[_]): Nullable[Rep[SizeContext]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeContextElem[_]] && method.getName == "dataInputs" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeContext]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeContext]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object selfBox {
+ def unapply(d: Def[_]): Nullable[Rep[SizeContext]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeContextElem[_]] && method.getName == "selfBox" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeContext]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeContext]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object lastBlockUtxoRootHash {
+ def unapply(d: Def[_]): Nullable[Rep[SizeContext]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeContextElem[_]] && method.getName == "lastBlockUtxoRootHash" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeContext]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeContext]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object headers {
+ def unapply(d: Def[_]): Nullable[Rep[SizeContext]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeContextElem[_]] && method.getName == "headers" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeContext]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeContext]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object preHeader {
+ def unapply(d: Def[_]): Nullable[Rep[SizeContext]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SizeContextElem[_]] && method.getName == "preHeader" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SizeContext]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SizeContext]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getVar {
+ def unapply(d: Def[_]): Nullable[(Rep[SizeContext], Rep[Byte], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SizeContextElem[_]] && method.getName == "getVar" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SizeContext], Rep[Byte], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SizeContext], Rep[Byte], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SizeContextCompanionMethods {
+ }
+} // of object SizeContext
+ registerEntityObject("SizeContext", SizeContext)
+
+object SizeBuilder extends EntityObject("SizeBuilder") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SSizeBuilder = special.sigma.SizeBuilder
+ case class SizeBuilderConst(
+ constValue: SSizeBuilder
+ ) extends SizeBuilder with LiftedConst[SSizeBuilder, SizeBuilder]
+ with Def[SizeBuilder] with SizeBuilderConstMethods {
+ val liftable: Liftable[SSizeBuilder, SizeBuilder] = LiftableSizeBuilder
+ val selfType: Elem[SizeBuilder] = liftable.eW
+ }
+
+ trait SizeBuilderConstMethods extends SizeBuilder { thisConst: Def[_] =>
+
+ private val SizeBuilderClass = classOf[SizeBuilder]
+
+ override def mkSizeAnyValue(tVal: Rep[WRType[Any]], valueSize: Rep[Size[Any]]): Rep[SizeAnyValue] = {
+ asRep[SizeAnyValue](mkMethodCall(self,
+ SizeBuilderClass.getMethod("mkSizeAnyValue", classOf[Sym], classOf[Sym]),
+ List(tVal, valueSize),
+ true, false, element[SizeAnyValue]))
+ }
+
+ override def mkSizeBox(propositionBytes: Rep[Size[Coll[Byte]]], bytes: Rep[Size[Coll[Byte]]], bytesWithoutRef: Rep[Size[Coll[Byte]]], registers: Rep[Size[Coll[WOption[AnyValue]]]], tokens: Rep[Size[Coll[(Coll[Byte], Long)]]]): Rep[SizeBox] = {
+ asRep[SizeBox](mkMethodCall(self,
+ SizeBuilderClass.getMethod("mkSizeBox", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(propositionBytes, bytes, bytesWithoutRef, registers, tokens),
+ true, false, element[SizeBox]))
+ }
+
+ override def mkSizeContext(outputs: Rep[Size[Coll[Box]]], inputs: Rep[Size[Coll[Box]]], dataInputs: Rep[Size[Coll[Box]]], selfBox: Rep[Size[Box]], lastBlockUtxoRootHash: Rep[Size[AvlTree]], headers: Rep[Size[Coll[Header]]], preHeader: Rep[Size[PreHeader]], vars: Rep[Coll[Size[AnyValue]]]): Rep[SizeContext] = {
+ asRep[SizeContext](mkMethodCall(self,
+ SizeBuilderClass.getMethod("mkSizeContext", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars),
+ true, false, element[SizeContext]))
+ }
+ }
+
+ implicit object LiftableSizeBuilder
+ extends Liftable[SSizeBuilder, SizeBuilder] {
+ lazy val eW: Elem[SizeBuilder] = sizeBuilderElement
+ lazy val sourceType: RType[SSizeBuilder] = {
+ RType[SSizeBuilder]
+ }
+ def lift(x: SSizeBuilder): Rep[SizeBuilder] = SizeBuilderConst(x)
+ def unlift(w: Rep[SizeBuilder]): SSizeBuilder = w match {
+ case Def(SizeBuilderConst(x: SSizeBuilder))
+ => x.asInstanceOf[SSizeBuilder]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for SizeBuilder trait
+ case class SizeBuilderAdapter(source: Rep[SizeBuilder])
+ extends SizeBuilder with Def[SizeBuilder] {
+ val selfType: Elem[SizeBuilder] = element[SizeBuilder]
+ override def transform(t: Transformer) = SizeBuilderAdapter(t(source))
+ private val thisClass = classOf[SizeBuilder]
+
+ def mkSizeAnyValue(tVal: Rep[WRType[Any]], valueSize: Rep[Size[Any]]): Rep[SizeAnyValue] = {
+ asRep[SizeAnyValue](mkMethodCall(source,
+ thisClass.getMethod("mkSizeAnyValue", classOf[Sym], classOf[Sym]),
+ List(tVal, valueSize),
+ true, true, element[SizeAnyValue]))
+ }
+
+ def mkSizeBox(propositionBytes: Rep[Size[Coll[Byte]]], bytes: Rep[Size[Coll[Byte]]], bytesWithoutRef: Rep[Size[Coll[Byte]]], registers: Rep[Size[Coll[WOption[AnyValue]]]], tokens: Rep[Size[Coll[(Coll[Byte], Long)]]]): Rep[SizeBox] = {
+ asRep[SizeBox](mkMethodCall(source,
+ thisClass.getMethod("mkSizeBox", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(propositionBytes, bytes, bytesWithoutRef, registers, tokens),
+ true, true, element[SizeBox]))
+ }
+
+ def mkSizeContext(outputs: Rep[Size[Coll[Box]]], inputs: Rep[Size[Coll[Box]]], dataInputs: Rep[Size[Coll[Box]]], selfBox: Rep[Size[Box]], lastBlockUtxoRootHash: Rep[Size[AvlTree]], headers: Rep[Size[Coll[Header]]], preHeader: Rep[Size[PreHeader]], vars: Rep[Coll[Size[AnyValue]]]): Rep[SizeContext] = {
+ asRep[SizeContext](mkMethodCall(source,
+ thisClass.getMethod("mkSizeContext", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars),
+ true, true, element[SizeContext]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySizeBuilder(p: Rep[SizeBuilder]): SizeBuilder = {
+ if (p.rhs.isInstanceOf[SizeBuilder@unchecked]) p.rhs.asInstanceOf[SizeBuilder]
+ else
+ SizeBuilderAdapter(p)
+ }
+
+ // familyElem
+ class SizeBuilderElem[To <: SizeBuilder]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableSizeBuilder.asLiftable[SSizeBuilder, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[SizeBuilder], classOf[SSizeBuilder], Set(
+ "mkSizeAnyValue", "mkSizeBox", "mkSizeContext"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SizeBuilder].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SizeBuilder] => convertSizeBuilder(x) }
+ tryConvert(element[SizeBuilder], this, x, conv)
+ }
+
+ def convertSizeBuilder(x: Rep[SizeBuilder]): Rep[To] = {
+ x.elem match {
+ case _: SizeBuilderElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SizeBuilderElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sizeBuilderElement: Elem[SizeBuilder] =
+ new SizeBuilderElem[SizeBuilder]
+
+ implicit case object SizeBuilderCompanionElem extends CompanionElem[SizeBuilderCompanionCtor] {
+ lazy val tag = weakTypeTag[SizeBuilderCompanionCtor]
+ protected def getDefaultRep = RSizeBuilder
+ }
+
+ abstract class SizeBuilderCompanionCtor extends CompanionDef[SizeBuilderCompanionCtor] with SizeBuilderCompanion {
+ def selfType = SizeBuilderCompanionElem
+ override def toString = "SizeBuilder"
+ }
+ implicit def proxySizeBuilderCompanionCtor(p: Rep[SizeBuilderCompanionCtor]): SizeBuilderCompanionCtor =
+ proxyOps[SizeBuilderCompanionCtor](p)
+
+ lazy val RSizeBuilder: Rep[SizeBuilderCompanionCtor] = new SizeBuilderCompanionCtor {
+ private val thisClass = classOf[SizeBuilderCompanion]
+ }
+
+ object SizeBuilderMethods {
+ object mkSizeAnyValue {
+ def unapply(d: Def[_]): Nullable[(Rep[SizeBuilder], Rep[WRType[Any]], Rep[Size[Any]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SizeBuilderElem[_]] && method.getName == "mkSizeAnyValue" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SizeBuilder], Rep[WRType[Any]], Rep[Size[Any]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SizeBuilder], Rep[WRType[Any]], Rep[Size[Any]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object mkSizeBox {
+ def unapply(d: Def[_]): Nullable[(Rep[SizeBuilder], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[WOption[AnyValue]]]], Rep[Size[Coll[(Coll[Byte], Long)]]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SizeBuilderElem[_]] && method.getName == "mkSizeBox" =>
+ val res = (receiver, args(0), args(1), args(2), args(3), args(4))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SizeBuilder], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[WOption[AnyValue]]]], Rep[Size[Coll[(Coll[Byte], Long)]]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SizeBuilder], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[WOption[AnyValue]]]], Rep[Size[Coll[(Coll[Byte], Long)]]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object mkSizeContext {
+ def unapply(d: Def[_]): Nullable[(Rep[SizeBuilder], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Box]], Rep[Size[AvlTree]], Rep[Size[Coll[Header]]], Rep[Size[PreHeader]], Rep[Coll[Size[AnyValue]]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SizeBuilderElem[_]] && method.getName == "mkSizeContext" =>
+ val res = (receiver, args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SizeBuilder], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Box]], Rep[Size[AvlTree]], Rep[Size[Coll[Header]]], Rep[Size[PreHeader]], Rep[Coll[Size[AnyValue]]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SizeBuilder], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Box]], Rep[Size[AvlTree]], Rep[Size[Coll[Header]]], Rep[Size[PreHeader]], Rep[Coll[Size[AnyValue]]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SizeBuilderCompanionMethods {
+ }
+} // of object SizeBuilder
+ registerEntityObject("SizeBuilder", SizeBuilder)
+
+ registerModule(CostedObjectsModule)
+}
+
+object CostedObjectsModule extends scalan.ModuleInfo("special.sigma", "CostedObjects")
+}
+
+trait CostedObjectsModule extends special.sigma.impl.CostedObjectsDefs {self: SigmaLibrary =>}
diff --git a/sigma-library/src/main/scala/special/sigma/impl/SigmaDslCostedImpl.scala b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslCostedImpl.scala
new file mode 100644
index 0000000000..bcc97da2f1
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslCostedImpl.scala
@@ -0,0 +1,740 @@
+package special.sigma
+
+import scalan._
+import scala.reflect.runtime.universe._
+import scala.reflect._
+
+package impl {
+// Abs -----------------------------------
+trait SigmaDslCostedDefs extends scalan.Scalan with SigmaDslCosted {
+ self: SigmaLibrary =>
+import IsoUR._
+import Converter._
+import AnyValue._
+import AvlTree._
+import Box._
+import CSizeAnyValue._
+import CSizeBox._
+import CSizeContext._
+import Coll._
+import Header._
+import PreHeader._
+import Size._
+import SizeAnyValue._
+import SizeBox._
+import SizeBuilder._
+import SizeContext._
+import SizeSigmaProp._
+import WOption._
+import WRType._
+import CSizeBuilder._
+import CSizeSigmaProp._
+import Context._ // manual fix
+import SigmaProp._ // manual fix
+
+object CSizeAnyValue extends EntityObject("CSizeAnyValue") {
+ case class CSizeAnyValueCtor
+ (override val tVal: Rep[WRType[Any]], override val valueSize: Rep[Size[Any]])
+ extends CSizeAnyValue(tVal, valueSize) with Def[CSizeAnyValue] {
+ override lazy val eVal: Elem[AnyValue] = implicitly[Elem[AnyValue]]
+ lazy val selfType = element[CSizeAnyValue]
+ override def transform(t: Transformer) = CSizeAnyValueCtor(t(tVal), t(valueSize))
+ private val thisClass = classOf[SizeAnyValue]
+
+ override def dataSize: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ thisClass.getMethod("dataSize"),
+ List(),
+ true, false, element[Long]))
+ }
+ }
+ // elem for concrete class
+ class CSizeAnyValueElem(val iso: Iso[CSizeAnyValueData, CSizeAnyValue])
+ extends SizeAnyValueElem[CSizeAnyValue]
+ with ConcreteElem[CSizeAnyValueData, CSizeAnyValue] {
+ override lazy val parent: Option[Elem[_]] = Some(sizeAnyValueElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override def convertSizeAnyValue(x: Rep[SizeAnyValue]) = RCSizeAnyValue(x.tVal, x.valueSize)
+ override def getDefaultRep = RCSizeAnyValue(element[WRType[Any]].defaultRepValue, element[Size[Any]].defaultRepValue)
+ override lazy val tag = {
+ weakTypeTag[CSizeAnyValue]
+ }
+ }
+
+ // state representation type
+ type CSizeAnyValueData = (WRType[Any], Size[Any])
+
+ // 3) Iso for concrete class
+ class CSizeAnyValueIso
+ extends EntityIso[CSizeAnyValueData, CSizeAnyValue] with Def[CSizeAnyValueIso] {
+ override def transform(t: Transformer) = new CSizeAnyValueIso()
+ private lazy val _safeFrom = fun { p: Rep[CSizeAnyValue] => (p.tVal, p.valueSize) }
+ override def from(p: Rep[CSizeAnyValue]) =
+ tryConvert[CSizeAnyValue, (WRType[Any], Size[Any])](eTo, eFrom, p, _safeFrom)
+ override def to(p: Rep[(WRType[Any], Size[Any])]) = {
+ val Pair(tVal, valueSize) = p
+ RCSizeAnyValue(tVal, valueSize)
+ }
+ lazy val eFrom = pairElement(element[WRType[Any]], element[Size[Any]])
+ lazy val eTo = new CSizeAnyValueElem(self)
+ lazy val selfType = new CSizeAnyValueIsoElem
+ def productArity = 0
+ def productElement(n: Int) = ???
+ }
+ case class CSizeAnyValueIsoElem() extends Elem[CSizeAnyValueIso] {
+ def getDefaultRep = reifyObject(new CSizeAnyValueIso())
+ lazy val tag = {
+ weakTypeTag[CSizeAnyValueIso]
+ }
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ }
+ // 4) constructor and deconstructor
+ class CSizeAnyValueCompanionCtor extends CompanionDef[CSizeAnyValueCompanionCtor] with CSizeAnyValueCompanion {
+ def selfType = CSizeAnyValueCompanionElem
+ override def toString = "CSizeAnyValueCompanion"
+ @scalan.OverloadId("fromData")
+ def apply(p: Rep[CSizeAnyValueData]): Rep[CSizeAnyValue] = {
+ isoCSizeAnyValue.to(p)
+ }
+
+ @scalan.OverloadId("fromFields")
+ def apply(tVal: Rep[WRType[Any]], valueSize: Rep[Size[Any]]): Rep[CSizeAnyValue] =
+ mkCSizeAnyValue(tVal, valueSize)
+
+ def unapply(p: Rep[SizeAnyValue]) = unmkCSizeAnyValue(p)
+ }
+ lazy val CSizeAnyValueRep: Rep[CSizeAnyValueCompanionCtor] = new CSizeAnyValueCompanionCtor
+ lazy val RCSizeAnyValue: CSizeAnyValueCompanionCtor = proxyCSizeAnyValueCompanion(CSizeAnyValueRep)
+ implicit def proxyCSizeAnyValueCompanion(p: Rep[CSizeAnyValueCompanionCtor]): CSizeAnyValueCompanionCtor = {
+ if (p.rhs.isInstanceOf[CSizeAnyValueCompanionCtor])
+ p.rhs.asInstanceOf[CSizeAnyValueCompanionCtor]
+ else
+ proxyOps[CSizeAnyValueCompanionCtor](p)
+ }
+
+ implicit case object CSizeAnyValueCompanionElem extends CompanionElem[CSizeAnyValueCompanionCtor] {
+ lazy val tag = weakTypeTag[CSizeAnyValueCompanionCtor]
+ protected def getDefaultRep = CSizeAnyValueRep
+ }
+
+ implicit def proxyCSizeAnyValue(p: Rep[CSizeAnyValue]): CSizeAnyValue =
+ proxyOps[CSizeAnyValue](p)
+
+ implicit class ExtendedCSizeAnyValue(p: Rep[CSizeAnyValue]) {
+ def toData: Rep[CSizeAnyValueData] = {
+ isoCSizeAnyValue.from(p)
+ }
+ }
+
+ // 5) implicit resolution of Iso
+ implicit def isoCSizeAnyValue: Iso[CSizeAnyValueData, CSizeAnyValue] =
+ reifyObject(new CSizeAnyValueIso())
+
+ def mkCSizeAnyValue
+ (tVal: Rep[WRType[Any]], valueSize: Rep[Size[Any]]): Rep[CSizeAnyValue] = {
+ new CSizeAnyValueCtor(tVal, valueSize)
+ }
+ def unmkCSizeAnyValue(p: Rep[SizeAnyValue]) = p.elem.asInstanceOf[Elem[_]] match {
+ case _: CSizeAnyValueElem @unchecked =>
+ Some((asRep[CSizeAnyValue](p).tVal, asRep[CSizeAnyValue](p).valueSize))
+ case _ =>
+ None
+ }
+
+ object CSizeAnyValueMethods {
+ object dataSize {
+ def unapply(d: Def[_]): Nullable[Rep[CSizeAnyValue]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CSizeAnyValueElem] && method.getName == "dataSize" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CSizeAnyValue]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CSizeAnyValue]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object CSizeAnyValueCompanionMethods {
+ }
+} // of object CSizeAnyValue
+ registerEntityObject("CSizeAnyValue", CSizeAnyValue)
+
+object CSizeSigmaProp extends EntityObject("CSizeSigmaProp") {
+ case class CSizeSigmaPropCtor
+ (override val propBytes: Rep[Size[Coll[Byte]]])
+ extends CSizeSigmaProp(propBytes) with Def[CSizeSigmaProp] {
+ override lazy val eVal: Elem[SigmaProp] = implicitly[Elem[SigmaProp]]
+ lazy val selfType = element[CSizeSigmaProp]
+ override def transform(t: Transformer) = CSizeSigmaPropCtor(t(propBytes))
+ private val thisClass = classOf[SizeSigmaProp]
+
+ override def dataSize: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ thisClass.getMethod("dataSize"),
+ List(),
+ true, false, element[Long]))
+ }
+ }
+ // elem for concrete class
+ class CSizeSigmaPropElem(val iso: Iso[CSizeSigmaPropData, CSizeSigmaProp])
+ extends SizeSigmaPropElem[CSizeSigmaProp]
+ with ConcreteElem[CSizeSigmaPropData, CSizeSigmaProp] {
+ override lazy val parent: Option[Elem[_]] = Some(sizeSigmaPropElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override def convertSizeSigmaProp(x: Rep[SizeSigmaProp]) = RCSizeSigmaProp(x.propBytes)
+ override def getDefaultRep = RCSizeSigmaProp(element[Size[Coll[Byte]]].defaultRepValue)
+ override lazy val tag = {
+ weakTypeTag[CSizeSigmaProp]
+ }
+ }
+
+ // state representation type
+ type CSizeSigmaPropData = Size[Coll[Byte]]
+
+ // 3) Iso for concrete class
+ class CSizeSigmaPropIso
+ extends EntityIso[CSizeSigmaPropData, CSizeSigmaProp] with Def[CSizeSigmaPropIso] {
+ override def transform(t: Transformer) = new CSizeSigmaPropIso()
+ private lazy val _safeFrom = fun { p: Rep[CSizeSigmaProp] => p.propBytes }
+ override def from(p: Rep[CSizeSigmaProp]) =
+ tryConvert[CSizeSigmaProp, Size[Coll[Byte]]](eTo, eFrom, p, _safeFrom)
+ override def to(p: Rep[Size[Coll[Byte]]]) = {
+ val propBytes = p
+ RCSizeSigmaProp(propBytes)
+ }
+ lazy val eFrom = element[Size[Coll[Byte]]]
+ lazy val eTo = new CSizeSigmaPropElem(self)
+ lazy val selfType = new CSizeSigmaPropIsoElem
+ def productArity = 0
+ def productElement(n: Int) = ???
+ }
+ case class CSizeSigmaPropIsoElem() extends Elem[CSizeSigmaPropIso] {
+ def getDefaultRep = reifyObject(new CSizeSigmaPropIso())
+ lazy val tag = {
+ weakTypeTag[CSizeSigmaPropIso]
+ }
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ }
+ // 4) constructor and deconstructor
+ class CSizeSigmaPropCompanionCtor extends CompanionDef[CSizeSigmaPropCompanionCtor] with CSizeSigmaPropCompanion {
+ def selfType = CSizeSigmaPropCompanionElem
+ override def toString = "CSizeSigmaPropCompanion"
+
+ @scalan.OverloadId("fromFields")
+ def apply(propBytes: Rep[Size[Coll[Byte]]]): Rep[CSizeSigmaProp] =
+ mkCSizeSigmaProp(propBytes)
+
+ def unapply(p: Rep[SizeSigmaProp]) = unmkCSizeSigmaProp(p)
+ }
+ lazy val CSizeSigmaPropRep: Rep[CSizeSigmaPropCompanionCtor] = new CSizeSigmaPropCompanionCtor
+ lazy val RCSizeSigmaProp: CSizeSigmaPropCompanionCtor = proxyCSizeSigmaPropCompanion(CSizeSigmaPropRep)
+ implicit def proxyCSizeSigmaPropCompanion(p: Rep[CSizeSigmaPropCompanionCtor]): CSizeSigmaPropCompanionCtor = {
+ if (p.rhs.isInstanceOf[CSizeSigmaPropCompanionCtor])
+ p.rhs.asInstanceOf[CSizeSigmaPropCompanionCtor]
+ else
+ proxyOps[CSizeSigmaPropCompanionCtor](p)
+ }
+
+ implicit case object CSizeSigmaPropCompanionElem extends CompanionElem[CSizeSigmaPropCompanionCtor] {
+ lazy val tag = weakTypeTag[CSizeSigmaPropCompanionCtor]
+ protected def getDefaultRep = CSizeSigmaPropRep
+ }
+
+ implicit def proxyCSizeSigmaProp(p: Rep[CSizeSigmaProp]): CSizeSigmaProp =
+ proxyOps[CSizeSigmaProp](p)
+
+ implicit class ExtendedCSizeSigmaProp(p: Rep[CSizeSigmaProp]) {
+ def toData: Rep[CSizeSigmaPropData] = {
+ isoCSizeSigmaProp.from(p)
+ }
+ }
+
+ // 5) implicit resolution of Iso
+ implicit def isoCSizeSigmaProp: Iso[CSizeSigmaPropData, CSizeSigmaProp] =
+ reifyObject(new CSizeSigmaPropIso())
+
+ def mkCSizeSigmaProp
+ (propBytes: Rep[Size[Coll[Byte]]]): Rep[CSizeSigmaProp] = {
+ new CSizeSigmaPropCtor(propBytes)
+ }
+ def unmkCSizeSigmaProp(p: Rep[SizeSigmaProp]) = p.elem.asInstanceOf[Elem[_]] match {
+ case _: CSizeSigmaPropElem @unchecked =>
+ Some((asRep[CSizeSigmaProp](p).propBytes))
+ case _ =>
+ None
+ }
+
+ object CSizeSigmaPropMethods {
+ object dataSize {
+ def unapply(d: Def[_]): Nullable[Rep[CSizeSigmaProp]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CSizeSigmaPropElem] && method.getName == "dataSize" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CSizeSigmaProp]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CSizeSigmaProp]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object CSizeSigmaPropCompanionMethods {
+ }
+} // of object CSizeSigmaProp
+ registerEntityObject("CSizeSigmaProp", CSizeSigmaProp)
+
+object CSizeBox extends EntityObject("CSizeBox") {
+ case class CSizeBoxCtor
+ (override val propositionBytes: Rep[Size[Coll[Byte]]], override val bytes: Rep[Size[Coll[Byte]]], override val bytesWithoutRef: Rep[Size[Coll[Byte]]], override val registers: Rep[Size[Coll[WOption[AnyValue]]]], override val tokens: Rep[Size[Coll[(Coll[Byte], Long)]]])
+ extends CSizeBox(propositionBytes, bytes, bytesWithoutRef, registers, tokens) with Def[CSizeBox] {
+ override lazy val eVal: Elem[Box] = implicitly[Elem[Box]]
+ lazy val selfType = element[CSizeBox]
+ override def transform(t: Transformer) = CSizeBoxCtor(t(propositionBytes), t(bytes), t(bytesWithoutRef), t(registers), t(tokens))
+ private val thisClass = classOf[SizeBox]
+
+ override def dataSize: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ thisClass.getMethod("dataSize"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def getReg[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = {
+ asRep[Size[WOption[T]]](mkMethodCall(self,
+ thisClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
+ List(id, tT),
+ true, false, element[Size[WOption[T]]]))
+ }
+ }
+ // elem for concrete class
+ class CSizeBoxElem(val iso: Iso[CSizeBoxData, CSizeBox])
+ extends SizeBoxElem[CSizeBox]
+ with ConcreteElem[CSizeBoxData, CSizeBox] {
+ override lazy val parent: Option[Elem[_]] = Some(sizeBoxElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override def convertSizeBox(x: Rep[SizeBox]) = RCSizeBox(x.propositionBytes, x.bytes, x.bytesWithoutRef, x.registers, x.tokens)
+ override def getDefaultRep = RCSizeBox(element[Size[Coll[Byte]]].defaultRepValue, element[Size[Coll[Byte]]].defaultRepValue, element[Size[Coll[Byte]]].defaultRepValue, element[Size[Coll[WOption[AnyValue]]]].defaultRepValue, element[Size[Coll[(Coll[Byte], Long)]]].defaultRepValue)
+ override lazy val tag = {
+ weakTypeTag[CSizeBox]
+ }
+ }
+
+ // state representation type
+ type CSizeBoxData = (Size[Coll[Byte]], (Size[Coll[Byte]], (Size[Coll[Byte]], (Size[Coll[WOption[AnyValue]]], Size[Coll[(Coll[Byte], Long)]]))))
+
+ // 3) Iso for concrete class
+ class CSizeBoxIso
+ extends EntityIso[CSizeBoxData, CSizeBox] with Def[CSizeBoxIso] {
+ override def transform(t: Transformer) = new CSizeBoxIso()
+ private lazy val _safeFrom = fun { p: Rep[CSizeBox] => (p.propositionBytes, p.bytes, p.bytesWithoutRef, p.registers, p.tokens) }
+ override def from(p: Rep[CSizeBox]) =
+ tryConvert[CSizeBox, (Size[Coll[Byte]], (Size[Coll[Byte]], (Size[Coll[Byte]], (Size[Coll[WOption[AnyValue]]], Size[Coll[(Coll[Byte], Long)]]))))](eTo, eFrom, p, _safeFrom)
+ override def to(p: Rep[(Size[Coll[Byte]], (Size[Coll[Byte]], (Size[Coll[Byte]], (Size[Coll[WOption[AnyValue]]], Size[Coll[(Coll[Byte], Long)]]))))]) = {
+ val Pair(propositionBytes, Pair(bytes, Pair(bytesWithoutRef, Pair(registers, tokens)))) = p
+ RCSizeBox(propositionBytes, bytes, bytesWithoutRef, registers, tokens)
+ }
+ lazy val eFrom = pairElement(element[Size[Coll[Byte]]], pairElement(element[Size[Coll[Byte]]], pairElement(element[Size[Coll[Byte]]], pairElement(element[Size[Coll[WOption[AnyValue]]]], element[Size[Coll[(Coll[Byte], Long)]]]))))
+ lazy val eTo = new CSizeBoxElem(self)
+ lazy val selfType = new CSizeBoxIsoElem
+ def productArity = 0
+ def productElement(n: Int) = ???
+ }
+ case class CSizeBoxIsoElem() extends Elem[CSizeBoxIso] {
+ def getDefaultRep = reifyObject(new CSizeBoxIso())
+ lazy val tag = {
+ weakTypeTag[CSizeBoxIso]
+ }
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ }
+ // 4) constructor and deconstructor
+ class CSizeBoxCompanionCtor extends CompanionDef[CSizeBoxCompanionCtor] with CSizeBoxCompanion {
+ def selfType = CSizeBoxCompanionElem
+ override def toString = "CSizeBoxCompanion"
+ @scalan.OverloadId("fromData")
+ def apply(p: Rep[CSizeBoxData]): Rep[CSizeBox] = {
+ isoCSizeBox.to(p)
+ }
+
+ @scalan.OverloadId("fromFields")
+ def apply(propositionBytes: Rep[Size[Coll[Byte]]], bytes: Rep[Size[Coll[Byte]]], bytesWithoutRef: Rep[Size[Coll[Byte]]], registers: Rep[Size[Coll[WOption[AnyValue]]]], tokens: Rep[Size[Coll[(Coll[Byte], Long)]]]): Rep[CSizeBox] =
+ mkCSizeBox(propositionBytes, bytes, bytesWithoutRef, registers, tokens)
+
+ def unapply(p: Rep[SizeBox]) = unmkCSizeBox(p)
+ }
+ lazy val CSizeBoxRep: Rep[CSizeBoxCompanionCtor] = new CSizeBoxCompanionCtor
+ lazy val RCSizeBox: CSizeBoxCompanionCtor = proxyCSizeBoxCompanion(CSizeBoxRep)
+ implicit def proxyCSizeBoxCompanion(p: Rep[CSizeBoxCompanionCtor]): CSizeBoxCompanionCtor = {
+ if (p.rhs.isInstanceOf[CSizeBoxCompanionCtor])
+ p.rhs.asInstanceOf[CSizeBoxCompanionCtor]
+ else
+ proxyOps[CSizeBoxCompanionCtor](p)
+ }
+
+ implicit case object CSizeBoxCompanionElem extends CompanionElem[CSizeBoxCompanionCtor] {
+ lazy val tag = weakTypeTag[CSizeBoxCompanionCtor]
+ protected def getDefaultRep = CSizeBoxRep
+ }
+
+ implicit def proxyCSizeBox(p: Rep[CSizeBox]): CSizeBox =
+ proxyOps[CSizeBox](p)
+
+ implicit class ExtendedCSizeBox(p: Rep[CSizeBox]) {
+ def toData: Rep[CSizeBoxData] = {
+ isoCSizeBox.from(p)
+ }
+ }
+
+ // 5) implicit resolution of Iso
+ implicit def isoCSizeBox: Iso[CSizeBoxData, CSizeBox] =
+ reifyObject(new CSizeBoxIso())
+
+ def mkCSizeBox
+ (propositionBytes: Rep[Size[Coll[Byte]]], bytes: Rep[Size[Coll[Byte]]], bytesWithoutRef: Rep[Size[Coll[Byte]]], registers: Rep[Size[Coll[WOption[AnyValue]]]], tokens: Rep[Size[Coll[(Coll[Byte], Long)]]]): Rep[CSizeBox] = {
+ new CSizeBoxCtor(propositionBytes, bytes, bytesWithoutRef, registers, tokens)
+ }
+ def unmkCSizeBox(p: Rep[SizeBox]) = p.elem.asInstanceOf[Elem[_]] match {
+ case _: CSizeBoxElem @unchecked =>
+ Some((asRep[CSizeBox](p).propositionBytes, asRep[CSizeBox](p).bytes, asRep[CSizeBox](p).bytesWithoutRef, asRep[CSizeBox](p).registers, asRep[CSizeBox](p).tokens))
+ case _ =>
+ None
+ }
+
+ object CSizeBoxMethods {
+ object dataSize {
+ def unapply(d: Def[_]): Nullable[Rep[CSizeBox]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CSizeBoxElem] && method.getName == "dataSize" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CSizeBox]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CSizeBox]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getReg {
+ def unapply(d: Def[_]): Nullable[(Rep[CSizeBox], Rep[Byte], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[CSizeBoxElem] && method.getName == "getReg" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[CSizeBox], Rep[Byte], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[CSizeBox], Rep[Byte], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object CSizeBoxCompanionMethods {
+ }
+} // of object CSizeBox
+ registerEntityObject("CSizeBox", CSizeBox)
+
+object CSizeContext extends EntityObject("CSizeContext") {
+ case class CSizeContextCtor
+ (override val outputs: Rep[Size[Coll[Box]]], override val inputs: Rep[Size[Coll[Box]]], override val dataInputs: Rep[Size[Coll[Box]]], override val selfBox: Rep[Size[Box]], override val lastBlockUtxoRootHash: Rep[Size[AvlTree]], override val headers: Rep[Size[Coll[Header]]], override val preHeader: Rep[Size[PreHeader]], override val vars: Rep[Coll[Size[AnyValue]]])
+ extends CSizeContext(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars) with Def[CSizeContext] {
+ override lazy val eVal: Elem[Context] = implicitly[Elem[Context]]
+ lazy val selfType = element[CSizeContext]
+ override def transform(t: Transformer) = CSizeContextCtor(t(outputs), t(inputs), t(dataInputs), t(selfBox), t(lastBlockUtxoRootHash), t(headers), t(preHeader), t(vars))
+ private val thisClass = classOf[SizeContext]
+
+ override def dataSize: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ thisClass.getMethod("dataSize"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def getVar[T](id: Rep[Byte])(implicit tT: Elem[T]): Rep[Size[WOption[T]]] = {
+ asRep[Size[WOption[T]]](mkMethodCall(self,
+ thisClass.getMethod("getVar", classOf[Sym], classOf[Elem[_]]),
+ List(id, tT),
+ true, false, element[Size[WOption[T]]]))
+ }
+ }
+ // elem for concrete class
+ class CSizeContextElem(val iso: Iso[CSizeContextData, CSizeContext])
+ extends SizeContextElem[CSizeContext]
+ with ConcreteElem[CSizeContextData, CSizeContext] {
+ override lazy val parent: Option[Elem[_]] = Some(sizeContextElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override def convertSizeContext(x: Rep[SizeContext]) = // Converter is not generated by meta
+!!!("Cannot convert from SizeContext to CSizeContext: missing fields List(vars)")
+ override def getDefaultRep = RCSizeContext(element[Size[Coll[Box]]].defaultRepValue, element[Size[Coll[Box]]].defaultRepValue, element[Size[Coll[Box]]].defaultRepValue, element[Size[Box]].defaultRepValue, element[Size[AvlTree]].defaultRepValue, element[Size[Coll[Header]]].defaultRepValue, element[Size[PreHeader]].defaultRepValue, element[Coll[Size[AnyValue]]].defaultRepValue)
+ override lazy val tag = {
+ weakTypeTag[CSizeContext]
+ }
+ }
+
+ // state representation type
+ type CSizeContextData = (Size[Coll[Box]], (Size[Coll[Box]], (Size[Coll[Box]], (Size[Box], (Size[AvlTree], (Size[Coll[Header]], (Size[PreHeader], Coll[Size[AnyValue]])))))))
+
+ // 3) Iso for concrete class
+ class CSizeContextIso
+ extends EntityIso[CSizeContextData, CSizeContext] with Def[CSizeContextIso] {
+ override def transform(t: Transformer) = new CSizeContextIso()
+ private lazy val _safeFrom = fun { p: Rep[CSizeContext] => (p.outputs, p.inputs, p.dataInputs, p.selfBox, p.lastBlockUtxoRootHash, p.headers, p.preHeader, p.vars) }
+ override def from(p: Rep[CSizeContext]) =
+ tryConvert[CSizeContext, (Size[Coll[Box]], (Size[Coll[Box]], (Size[Coll[Box]], (Size[Box], (Size[AvlTree], (Size[Coll[Header]], (Size[PreHeader], Coll[Size[AnyValue]])))))))](eTo, eFrom, p, _safeFrom)
+ override def to(p: Rep[(Size[Coll[Box]], (Size[Coll[Box]], (Size[Coll[Box]], (Size[Box], (Size[AvlTree], (Size[Coll[Header]], (Size[PreHeader], Coll[Size[AnyValue]])))))))]) = {
+ val Pair(outputs, Pair(inputs, Pair(dataInputs, Pair(selfBox, Pair(lastBlockUtxoRootHash, Pair(headers, Pair(preHeader, vars))))))) = p
+ RCSizeContext(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars)
+ }
+ lazy val eFrom = pairElement(element[Size[Coll[Box]]], pairElement(element[Size[Coll[Box]]], pairElement(element[Size[Coll[Box]]], pairElement(element[Size[Box]], pairElement(element[Size[AvlTree]], pairElement(element[Size[Coll[Header]]], pairElement(element[Size[PreHeader]], element[Coll[Size[AnyValue]]])))))))
+ lazy val eTo = new CSizeContextElem(self)
+ lazy val selfType = new CSizeContextIsoElem
+ def productArity = 0
+ def productElement(n: Int) = ???
+ }
+ case class CSizeContextIsoElem() extends Elem[CSizeContextIso] {
+ def getDefaultRep = reifyObject(new CSizeContextIso())
+ lazy val tag = {
+ weakTypeTag[CSizeContextIso]
+ }
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ }
+ // 4) constructor and deconstructor
+ class CSizeContextCompanionCtor extends CompanionDef[CSizeContextCompanionCtor] with CSizeContextCompanion {
+ def selfType = CSizeContextCompanionElem
+ override def toString = "CSizeContextCompanion"
+ @scalan.OverloadId("fromData")
+ def apply(p: Rep[CSizeContextData]): Rep[CSizeContext] = {
+ isoCSizeContext.to(p)
+ }
+
+ @scalan.OverloadId("fromFields")
+ def apply(outputs: Rep[Size[Coll[Box]]], inputs: Rep[Size[Coll[Box]]], dataInputs: Rep[Size[Coll[Box]]], selfBox: Rep[Size[Box]], lastBlockUtxoRootHash: Rep[Size[AvlTree]], headers: Rep[Size[Coll[Header]]], preHeader: Rep[Size[PreHeader]], vars: Rep[Coll[Size[AnyValue]]]): Rep[CSizeContext] =
+ mkCSizeContext(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars)
+
+ def unapply(p: Rep[SizeContext]) = unmkCSizeContext(p)
+ }
+ lazy val CSizeContextRep: Rep[CSizeContextCompanionCtor] = new CSizeContextCompanionCtor
+ lazy val RCSizeContext: CSizeContextCompanionCtor = proxyCSizeContextCompanion(CSizeContextRep)
+ implicit def proxyCSizeContextCompanion(p: Rep[CSizeContextCompanionCtor]): CSizeContextCompanionCtor = {
+ if (p.rhs.isInstanceOf[CSizeContextCompanionCtor])
+ p.rhs.asInstanceOf[CSizeContextCompanionCtor]
+ else
+ proxyOps[CSizeContextCompanionCtor](p)
+ }
+
+ implicit case object CSizeContextCompanionElem extends CompanionElem[CSizeContextCompanionCtor] {
+ lazy val tag = weakTypeTag[CSizeContextCompanionCtor]
+ protected def getDefaultRep = CSizeContextRep
+ }
+
+ implicit def proxyCSizeContext(p: Rep[CSizeContext]): CSizeContext =
+ proxyOps[CSizeContext](p)
+
+ implicit class ExtendedCSizeContext(p: Rep[CSizeContext]) {
+ def toData: Rep[CSizeContextData] = {
+ isoCSizeContext.from(p)
+ }
+ }
+
+ // 5) implicit resolution of Iso
+ implicit def isoCSizeContext: Iso[CSizeContextData, CSizeContext] =
+ reifyObject(new CSizeContextIso())
+
+ def mkCSizeContext
+ (outputs: Rep[Size[Coll[Box]]], inputs: Rep[Size[Coll[Box]]], dataInputs: Rep[Size[Coll[Box]]], selfBox: Rep[Size[Box]], lastBlockUtxoRootHash: Rep[Size[AvlTree]], headers: Rep[Size[Coll[Header]]], preHeader: Rep[Size[PreHeader]], vars: Rep[Coll[Size[AnyValue]]]): Rep[CSizeContext] = {
+ new CSizeContextCtor(outputs, inputs, dataInputs, selfBox, lastBlockUtxoRootHash, headers, preHeader, vars)
+ }
+ def unmkCSizeContext(p: Rep[SizeContext]) = p.elem.asInstanceOf[Elem[_]] match {
+ case _: CSizeContextElem @unchecked =>
+ Some((asRep[CSizeContext](p).outputs, asRep[CSizeContext](p).inputs, asRep[CSizeContext](p).dataInputs, asRep[CSizeContext](p).selfBox, asRep[CSizeContext](p).lastBlockUtxoRootHash, asRep[CSizeContext](p).headers, asRep[CSizeContext](p).preHeader, asRep[CSizeContext](p).vars))
+ case _ =>
+ None
+ }
+
+ object CSizeContextMethods {
+ object dataSize {
+ def unapply(d: Def[_]): Nullable[Rep[CSizeContext]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CSizeContextElem] && method.getName == "dataSize" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CSizeContext]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CSizeContext]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getVar {
+ def unapply(d: Def[_]): Nullable[(Rep[CSizeContext], Rep[Byte], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[CSizeContextElem] && method.getName == "getVar" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[CSizeContext], Rep[Byte], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[CSizeContext], Rep[Byte], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object CSizeContextCompanionMethods {
+ }
+} // of object CSizeContext
+ registerEntityObject("CSizeContext", CSizeContext)
+
+object CSizeBuilder extends EntityObject("CSizeBuilder") {
+ case class CSizeBuilderCtor
+ ()
+ extends CSizeBuilder() with Def[CSizeBuilder] {
+ lazy val selfType = element[CSizeBuilder]
+ override def transform(t: Transformer) = CSizeBuilderCtor()
+ }
+ // elem for concrete class
+ class CSizeBuilderElem(val iso: Iso[CSizeBuilderData, CSizeBuilder])
+ extends SizeBuilderElem[CSizeBuilder]
+ with ConcreteElem[CSizeBuilderData, CSizeBuilder] {
+ override lazy val parent: Option[Elem[_]] = Some(sizeBuilderElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override def convertSizeBuilder(x: Rep[SizeBuilder]) = RCSizeBuilder()
+ override def getDefaultRep = RCSizeBuilder()
+ override lazy val tag = {
+ weakTypeTag[CSizeBuilder]
+ }
+ }
+
+ // state representation type
+ type CSizeBuilderData = Unit
+
+ // 3) Iso for concrete class
+ class CSizeBuilderIso
+ extends EntityIso[CSizeBuilderData, CSizeBuilder] with Def[CSizeBuilderIso] {
+ override def transform(t: Transformer) = new CSizeBuilderIso()
+ private lazy val _safeFrom = fun { p: Rep[CSizeBuilder] => () }
+ override def from(p: Rep[CSizeBuilder]) =
+ tryConvert[CSizeBuilder, Unit](eTo, eFrom, p, _safeFrom)
+ override def to(p: Rep[Unit]) = {
+ val unit = p
+ RCSizeBuilder()
+ }
+ lazy val eFrom = UnitElement
+ lazy val eTo = new CSizeBuilderElem(self)
+ lazy val selfType = new CSizeBuilderIsoElem
+ def productArity = 0
+ def productElement(n: Int) = ???
+ }
+ case class CSizeBuilderIsoElem() extends Elem[CSizeBuilderIso] {
+ def getDefaultRep = reifyObject(new CSizeBuilderIso())
+ lazy val tag = {
+ weakTypeTag[CSizeBuilderIso]
+ }
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ }
+ // 4) constructor and deconstructor
+ class CSizeBuilderCompanionCtor extends CompanionDef[CSizeBuilderCompanionCtor] with CSizeBuilderCompanion {
+ def selfType = CSizeBuilderCompanionElem
+ override def toString = "CSizeBuilderCompanion"
+ @scalan.OverloadId("fromData")
+ def apply(p: Rep[CSizeBuilderData]): Rep[CSizeBuilder] = {
+ isoCSizeBuilder.to(p)
+ }
+
+ @scalan.OverloadId("fromFields")
+ def apply(): Rep[CSizeBuilder] =
+ mkCSizeBuilder()
+
+ def unapply(p: Rep[SizeBuilder]) = unmkCSizeBuilder(p)
+ }
+ lazy val CSizeBuilderRep: Rep[CSizeBuilderCompanionCtor] = new CSizeBuilderCompanionCtor
+ lazy val RCSizeBuilder: CSizeBuilderCompanionCtor = proxyCSizeBuilderCompanion(CSizeBuilderRep)
+ implicit def proxyCSizeBuilderCompanion(p: Rep[CSizeBuilderCompanionCtor]): CSizeBuilderCompanionCtor = {
+ if (p.rhs.isInstanceOf[CSizeBuilderCompanionCtor])
+ p.rhs.asInstanceOf[CSizeBuilderCompanionCtor]
+ else
+ proxyOps[CSizeBuilderCompanionCtor](p)
+ }
+
+ implicit case object CSizeBuilderCompanionElem extends CompanionElem[CSizeBuilderCompanionCtor] {
+ lazy val tag = weakTypeTag[CSizeBuilderCompanionCtor]
+ protected def getDefaultRep = CSizeBuilderRep
+ }
+
+ implicit def proxyCSizeBuilder(p: Rep[CSizeBuilder]): CSizeBuilder =
+ proxyOps[CSizeBuilder](p)
+
+ implicit class ExtendedCSizeBuilder(p: Rep[CSizeBuilder]) {
+ def toData: Rep[CSizeBuilderData] = {
+ isoCSizeBuilder.from(p)
+ }
+ }
+
+ // 5) implicit resolution of Iso
+ implicit def isoCSizeBuilder: Iso[CSizeBuilderData, CSizeBuilder] =
+ reifyObject(new CSizeBuilderIso())
+
+ def mkCSizeBuilder
+ (): Rep[CSizeBuilder] = {
+ new CSizeBuilderCtor()
+ }
+ def unmkCSizeBuilder(p: Rep[SizeBuilder]) = p.elem.asInstanceOf[Elem[_]] match {
+ case _: CSizeBuilderElem @unchecked =>
+ Some(())
+ case _ =>
+ None
+ }
+
+ object CSizeBuilderMethods {
+ object mkSizeAnyValue {
+ def unapply(d: Def[_]): Nullable[(Rep[CSizeBuilder], Rep[WRType[Any]], Rep[Size[Any]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[CSizeBuilderElem] && method.getName == "mkSizeAnyValue" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[CSizeBuilder], Rep[WRType[Any]], Rep[Size[Any]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[CSizeBuilder], Rep[WRType[Any]], Rep[Size[Any]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object mkSizeBox {
+ def unapply(d: Def[_]): Nullable[(Rep[CSizeBuilder], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[WOption[AnyValue]]]], Rep[Size[Coll[(Coll[Byte], Long)]]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[CSizeBuilderElem] && method.getName == "mkSizeBox" =>
+ val res = (receiver, args(0), args(1), args(2), args(3), args(4))
+ Nullable(res).asInstanceOf[Nullable[(Rep[CSizeBuilder], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[WOption[AnyValue]]]], Rep[Size[Coll[(Coll[Byte], Long)]]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[CSizeBuilder], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[Byte]]], Rep[Size[Coll[WOption[AnyValue]]]], Rep[Size[Coll[(Coll[Byte], Long)]]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object mkSizeContext {
+ def unapply(d: Def[_]): Nullable[(Rep[CSizeBuilder], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Box]], Rep[Size[AvlTree]], Rep[Size[Coll[Header]]], Rep[Size[PreHeader]], Rep[Coll[Size[AnyValue]]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[CSizeBuilderElem] && method.getName == "mkSizeContext" =>
+ val res = (receiver, args(0), args(1), args(2), args(3), args(4), args(5), args(6), args(7))
+ Nullable(res).asInstanceOf[Nullable[(Rep[CSizeBuilder], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Box]], Rep[Size[AvlTree]], Rep[Size[Coll[Header]]], Rep[Size[PreHeader]], Rep[Coll[Size[AnyValue]]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[CSizeBuilder], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Coll[Box]]], Rep[Size[Box]], Rep[Size[AvlTree]], Rep[Size[Coll[Header]]], Rep[Size[PreHeader]], Rep[Coll[Size[AnyValue]]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object CSizeBuilderCompanionMethods {
+ }
+} // of object CSizeBuilder
+ registerEntityObject("CSizeBuilder", CSizeBuilder)
+
+ registerModule(SigmaDslCostedModule)
+}
+
+object SigmaDslCostedModule extends scalan.ModuleInfo("special.sigma", "SigmaDslCosted")
+}
+
+trait SigmaDslCostedModule extends special.sigma.impl.SigmaDslCostedDefs {self: SigmaLibrary =>}
diff --git a/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala
new file mode 100644
index 0000000000..aeb8185938
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala
@@ -0,0 +1,5360 @@
+package special.sigma
+
+import scalan._
+import scala.reflect.runtime.universe._
+import scala.reflect._
+
+package impl {
+ import scalan.OverloadHack.Overloaded1 // manual fix
+
+ // Abs -----------------------------------
+trait SigmaDslDefs extends scalan.Scalan with SigmaDsl {
+ self: SigmaLibrary =>
+import IsoUR._
+import Converter._
+import AnyValue._
+import AvlTree._
+import BigInt._
+import Box._
+import Coll._
+import CollBuilder._
+import Context._
+import CostModel._
+import CostedBuilder._
+import GroupElement._
+import Header._
+import MonoidBuilder._
+import PreHeader._
+import SigmaContract._
+import SigmaDslBuilder._
+import SigmaProp._
+import WBigInteger._
+import WOption._
+import WRType._
+
+object CostModel extends EntityObject("CostModel") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SCostModel = special.sigma.CostModel
+ case class CostModelConst(
+ constValue: SCostModel
+ ) extends CostModel with LiftedConst[SCostModel, CostModel]
+ with Def[CostModel] with CostModelConstMethods {
+ val liftable: Liftable[SCostModel, CostModel] = LiftableCostModel
+ val selfType: Elem[CostModel] = liftable.eW
+ }
+
+ trait CostModelConstMethods extends CostModel { thisConst: Def[_] =>
+
+ private val CostModelClass = classOf[CostModel]
+
+ override def AccessBox: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("AccessBox"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def AccessAvlTree: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("AccessAvlTree"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def GetVar: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("GetVar"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def DeserializeVar: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("DeserializeVar"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def GetRegister: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("GetRegister"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def DeserializeRegister: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("DeserializeRegister"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def SelectField: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("SelectField"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def CollectionConst: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("CollectionConst"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def AccessKiloByteOfData: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ CostModelClass.getMethod("AccessKiloByteOfData"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def dataSize[T](x: Rep[T])(implicit cT: Elem[T]): Rep[Long] = {
+ implicit val eT = x.elem
+ asRep[Long](mkMethodCall(self,
+ CostModelClass.getMethod("dataSize", classOf[Sym], classOf[Elem[_]]),
+ List(x, cT),
+ true, false, element[Long]))
+ }
+
+ override def PubKeySize: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ CostModelClass.getMethod("PubKeySize"),
+ List(),
+ true, false, element[Long]))
+ }
+ }
+
+ implicit object LiftableCostModel
+ extends Liftable[SCostModel, CostModel] {
+ lazy val eW: Elem[CostModel] = costModelElement
+ lazy val sourceType: RType[SCostModel] = {
+ RType[SCostModel]
+ }
+ def lift(x: SCostModel): Rep[CostModel] = CostModelConst(x)
+ def unlift(w: Rep[CostModel]): SCostModel = w match {
+ case Def(CostModelConst(x: SCostModel))
+ => x.asInstanceOf[SCostModel]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for CostModel trait
+ case class CostModelAdapter(source: Rep[CostModel])
+ extends CostModel with Def[CostModel] {
+ val selfType: Elem[CostModel] = element[CostModel]
+ override def transform(t: Transformer) = CostModelAdapter(t(source))
+ private val thisClass = classOf[CostModel]
+
+ def AccessBox: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("AccessBox"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def AccessAvlTree: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("AccessAvlTree"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def GetVar: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("GetVar"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def DeserializeVar: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("DeserializeVar"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def GetRegister: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("GetRegister"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def DeserializeRegister: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("DeserializeRegister"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def SelectField: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("SelectField"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def CollectionConst: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("CollectionConst"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def AccessKiloByteOfData: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("AccessKiloByteOfData"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def dataSize[T](x: Rep[T])(implicit cT: Elem[T]): Rep[Long] = {
+ implicit val eT = x.elem
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("dataSize", classOf[Sym], classOf[Elem[_]]),
+ List(x, cT),
+ true, true, element[Long]))
+ }
+
+ def PubKeySize: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("PubKeySize"),
+ List(),
+ true, true, element[Long]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyCostModel(p: Rep[CostModel]): CostModel = {
+ if (p.rhs.isInstanceOf[CostModel@unchecked]) p.rhs.asInstanceOf[CostModel]
+ else
+ CostModelAdapter(p)
+ }
+
+ // familyElem
+ class CostModelElem[To <: CostModel]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableCostModel.asLiftable[SCostModel, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[CostModel], classOf[SCostModel], Set(
+ "AccessBox", "AccessAvlTree", "GetVar", "DeserializeVar", "GetRegister", "DeserializeRegister", "SelectField", "CollectionConst", "AccessKiloByteOfData", "dataSize", "PubKeySize"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[CostModel].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[CostModel] => convertCostModel(x) }
+ tryConvert(element[CostModel], this, x, conv)
+ }
+
+ def convertCostModel(x: Rep[CostModel]): Rep[To] = {
+ x.elem match {
+ case _: CostModelElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have CostModelElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val costModelElement: Elem[CostModel] =
+ new CostModelElem[CostModel]
+
+ implicit case object CostModelCompanionElem extends CompanionElem[CostModelCompanionCtor] {
+ lazy val tag = weakTypeTag[CostModelCompanionCtor]
+ protected def getDefaultRep = RCostModel
+ }
+
+ abstract class CostModelCompanionCtor extends CompanionDef[CostModelCompanionCtor] with CostModelCompanion {
+ def selfType = CostModelCompanionElem
+ override def toString = "CostModel"
+ }
+ implicit def proxyCostModelCompanionCtor(p: Rep[CostModelCompanionCtor]): CostModelCompanionCtor =
+ proxyOps[CostModelCompanionCtor](p)
+
+ lazy val RCostModel: Rep[CostModelCompanionCtor] = new CostModelCompanionCtor {
+ private val thisClass = classOf[CostModelCompanion]
+ }
+
+ object CostModelMethods {
+ object AccessBox {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "AccessBox" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object AccessAvlTree {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "AccessAvlTree" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object GetVar {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "GetVar" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object DeserializeVar {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "DeserializeVar" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object GetRegister {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "GetRegister" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object DeserializeRegister {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "DeserializeRegister" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object SelectField {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "SelectField" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object CollectionConst {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "CollectionConst" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object AccessKiloByteOfData {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "AccessKiloByteOfData" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object dataSize {
+ def unapply(d: Def[_]): Nullable[(Rep[CostModel], Rep[T], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "dataSize" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[CostModel], Rep[T], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[CostModel], Rep[T], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object PubKeySize {
+ def unapply(d: Def[_]): Nullable[Rep[CostModel]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[CostModelElem[_]] && method.getName == "PubKeySize" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[CostModel]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[CostModel]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object CostModelCompanionMethods {
+ }
+} // of object CostModel
+ registerEntityObject("CostModel", CostModel)
+
+object BigInt extends EntityObject("BigInt") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SBigInt = special.sigma.BigInt
+ case class BigIntConst(
+ constValue: SBigInt
+ ) extends BigInt with LiftedConst[SBigInt, BigInt]
+ with Def[BigInt] with BigIntConstMethods {
+ val liftable: Liftable[SBigInt, BigInt] = LiftableBigInt
+ val selfType: Elem[BigInt] = liftable.eW
+ }
+
+ trait BigIntConstMethods extends BigInt { thisConst: Def[_] =>
+
+ private val BigIntClass = classOf[BigInt]
+
+ override def toByte: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(self,
+ BigIntClass.getMethod("toByte"),
+ List(),
+ true, false, element[Byte]))
+ }
+
+ override def toShort: Rep[Short] = {
+ asRep[Short](mkMethodCall(self,
+ BigIntClass.getMethod("toShort"),
+ List(),
+ true, false, element[Short]))
+ }
+
+ override def toInt: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ BigIntClass.getMethod("toInt"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def toLong: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ BigIntClass.getMethod("toLong"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def toBytes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ BigIntClass.getMethod("toBytes"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def toBits: Rep[Coll[Boolean]] = {
+ asRep[Coll[Boolean]](mkMethodCall(self,
+ BigIntClass.getMethod("toBits"),
+ List(),
+ true, false, element[Coll[Boolean]]))
+ }
+
+ override def toAbs: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("toAbs"),
+ List(),
+ true, false, element[BigInt]))
+ }
+
+ override def compareTo(that: Rep[BigInt]): Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ BigIntClass.getMethod("compareTo", classOf[Sym]),
+ List(that),
+ true, false, element[Int]))
+ }
+
+ override def modQ: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("modQ"),
+ List(),
+ true, false, element[BigInt]))
+ }
+
+ override def plusModQ(other: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("plusModQ", classOf[Sym]),
+ List(other),
+ true, false, element[BigInt]))
+ }
+
+ override def minusModQ(other: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("minusModQ", classOf[Sym]),
+ List(other),
+ true, false, element[BigInt]))
+ }
+
+ override def multModQ(other: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("multModQ", classOf[Sym]),
+ List(other),
+ true, false, element[BigInt]))
+ }
+
+ override def inverseModQ: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("inverseModQ"),
+ List(),
+ true, false, element[BigInt]))
+ }
+
+ override def signum: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ BigIntClass.getMethod("signum"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def add(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("add", classOf[Sym]),
+ List(that),
+ true, false, element[BigInt]))
+ }
+
+ override def subtract(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("subtract", classOf[Sym]),
+ List(that),
+ true, false, element[BigInt]))
+ }
+
+ override def multiply(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("multiply", classOf[Sym]),
+ List(that),
+ true, false, element[BigInt]))
+ }
+
+ override def divide(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("divide", classOf[Sym]),
+ List(that),
+ true, false, element[BigInt]))
+ }
+
+ override def mod(m: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("mod", classOf[Sym]),
+ List(m),
+ true, false, element[BigInt]))
+ }
+
+ override def remainder(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("remainder", classOf[Sym]),
+ List(that),
+ true, false, element[BigInt]))
+ }
+
+ override def min(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("min", classOf[Sym]),
+ List(that),
+ true, false, element[BigInt]))
+ }
+
+ override def max(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("max", classOf[Sym]),
+ List(that),
+ true, false, element[BigInt]))
+ }
+
+ override def negate: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ BigIntClass.getMethod("negate"),
+ List(),
+ true, false, element[BigInt]))
+ }
+ }
+
+ implicit object LiftableBigInt
+ extends Liftable[SBigInt, BigInt] {
+ lazy val eW: Elem[BigInt] = bigIntElement
+ lazy val sourceType: RType[SBigInt] = {
+ RType[SBigInt]
+ }
+ def lift(x: SBigInt): Rep[BigInt] = BigIntConst(x)
+ def unlift(w: Rep[BigInt]): SBigInt = w match {
+ case Def(BigIntConst(x: SBigInt))
+ => x.asInstanceOf[SBigInt]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for BigInt trait
+ case class BigIntAdapter(source: Rep[BigInt])
+ extends BigInt with Def[BigInt] {
+ val selfType: Elem[BigInt] = element[BigInt]
+ override def transform(t: Transformer) = BigIntAdapter(t(source))
+ private val thisClass = classOf[BigInt]
+
+ def toByte: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(source,
+ thisClass.getMethod("toByte"),
+ List(),
+ true, true, element[Byte]))
+ }
+
+ def toShort: Rep[Short] = {
+ asRep[Short](mkMethodCall(source,
+ thisClass.getMethod("toShort"),
+ List(),
+ true, true, element[Short]))
+ }
+
+ def toInt: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("toInt"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def toLong: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("toLong"),
+ List(),
+ true, true, element[Long]))
+ }
+
+ def toBytes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("toBytes"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def toBits: Rep[Coll[Boolean]] = {
+ asRep[Coll[Boolean]](mkMethodCall(source,
+ thisClass.getMethod("toBits"),
+ List(),
+ true, true, element[Coll[Boolean]]))
+ }
+
+ def toAbs: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("toAbs"),
+ List(),
+ true, true, element[BigInt]))
+ }
+
+ def compareTo(that: Rep[BigInt]): Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("compareTo", classOf[Sym]),
+ List(that),
+ true, true, element[Int]))
+ }
+
+ def modQ: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("modQ"),
+ List(),
+ true, true, element[BigInt]))
+ }
+
+ def plusModQ(other: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("plusModQ", classOf[Sym]),
+ List(other),
+ true, true, element[BigInt]))
+ }
+
+ def minusModQ(other: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("minusModQ", classOf[Sym]),
+ List(other),
+ true, true, element[BigInt]))
+ }
+
+ def multModQ(other: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("multModQ", classOf[Sym]),
+ List(other),
+ true, true, element[BigInt]))
+ }
+
+ def inverseModQ: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("inverseModQ"),
+ List(),
+ true, true, element[BigInt]))
+ }
+
+ def signum: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("signum"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def add(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("add", classOf[Sym]),
+ List(that),
+ true, true, element[BigInt]))
+ }
+
+ def subtract(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("subtract", classOf[Sym]),
+ List(that),
+ true, true, element[BigInt]))
+ }
+
+ def multiply(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("multiply", classOf[Sym]),
+ List(that),
+ true, true, element[BigInt]))
+ }
+
+ def divide(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("divide", classOf[Sym]),
+ List(that),
+ true, true, element[BigInt]))
+ }
+
+ def mod(m: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("mod", classOf[Sym]),
+ List(m),
+ true, true, element[BigInt]))
+ }
+
+ def remainder(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("remainder", classOf[Sym]),
+ List(that),
+ true, true, element[BigInt]))
+ }
+
+ def min(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("min", classOf[Sym]),
+ List(that),
+ true, true, element[BigInt]))
+ }
+
+ def max(that: Rep[BigInt]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("max", classOf[Sym]),
+ List(that),
+ true, true, element[BigInt]))
+ }
+
+ def negate: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("negate"),
+ List(),
+ true, true, element[BigInt]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyBigInt(p: Rep[BigInt]): BigInt = {
+ if (p.rhs.isInstanceOf[BigInt@unchecked]) p.rhs.asInstanceOf[BigInt]
+ else
+ BigIntAdapter(p)
+ }
+
+ // familyElem
+ class BigIntElem[To <: BigInt]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableBigInt.asLiftable[SBigInt, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[BigInt], classOf[SBigInt], Set(
+ "toByte", "toShort", "toInt", "toLong", "toBytes", "toBits", "toAbs", "compareTo", "modQ", "plusModQ", "minusModQ", "multModQ", "inverseModQ", "signum", "add", "subtract", "multiply", "divide", "mod", "remainder", "min", "max", "negate"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[BigInt].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[BigInt] => convertBigInt(x) }
+ tryConvert(element[BigInt], this, x, conv)
+ }
+
+ def convertBigInt(x: Rep[BigInt]): Rep[To] = {
+ x.elem match {
+ case _: BigIntElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have BigIntElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val bigIntElement: Elem[BigInt] =
+ new BigIntElem[BigInt]
+
+ implicit case object BigIntCompanionElem extends CompanionElem[BigIntCompanionCtor] {
+ lazy val tag = weakTypeTag[BigIntCompanionCtor]
+ protected def getDefaultRep = RBigInt
+ }
+
+ abstract class BigIntCompanionCtor extends CompanionDef[BigIntCompanionCtor] with BigIntCompanion {
+ def selfType = BigIntCompanionElem
+ override def toString = "BigInt"
+ }
+ implicit def proxyBigIntCompanionCtor(p: Rep[BigIntCompanionCtor]): BigIntCompanionCtor =
+ proxyOps[BigIntCompanionCtor](p)
+
+ lazy val RBigInt: Rep[BigIntCompanionCtor] = new BigIntCompanionCtor {
+ private val thisClass = classOf[BigIntCompanion]
+ }
+
+ object BigIntMethods {
+ object toByte {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "toByte" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toShort {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "toShort" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toInt {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "toInt" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toLong {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "toLong" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toBytes {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "toBytes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toBits {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "toBits" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toAbs {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "toAbs" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object compareTo {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "compareTo" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object modQ {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "modQ" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object plusModQ {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "plusModQ" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object minusModQ {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "minusModQ" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object multModQ {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "multModQ" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object inverseModQ {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "inverseModQ" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object signum {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "signum" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object add {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "add" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object subtract {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "subtract" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object multiply {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "multiply" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object divide {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "divide" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object mod {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "mod" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object remainder {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "remainder" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object min {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "min" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object max {
+ def unapply(d: Def[_]): Nullable[(Rep[BigInt], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "max" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigInt], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigInt], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object negate {
+ def unapply(d: Def[_]): Nullable[Rep[BigInt]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BigIntElem[_]] && method.getName == "negate" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[BigInt]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[BigInt]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object BigIntCompanionMethods {
+ }
+} // of object BigInt
+ registerEntityObject("BigInt", BigInt)
+
+object GroupElement extends EntityObject("GroupElement") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SGroupElement = special.sigma.GroupElement
+ case class GroupElementConst(
+ constValue: SGroupElement
+ ) extends GroupElement with LiftedConst[SGroupElement, GroupElement]
+ with Def[GroupElement] with GroupElementConstMethods {
+ val liftable: Liftable[SGroupElement, GroupElement] = LiftableGroupElement
+ val selfType: Elem[GroupElement] = liftable.eW
+ }
+
+ trait GroupElementConstMethods extends GroupElement { thisConst: Def[_] =>
+
+ private val GroupElementClass = classOf[GroupElement]
+
+ override def isInfinity: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ GroupElementClass.getMethod("isInfinity"),
+ List(),
+ true, false, element[Boolean]))
+ }
+
+ override def exp(k: Rep[BigInt]): Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ GroupElementClass.getMethod("exp", classOf[Sym]),
+ List(k),
+ true, false, element[GroupElement]))
+ }
+
+ override def multiply(that: Rep[GroupElement]): Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ GroupElementClass.getMethod("multiply", classOf[Sym]),
+ List(that),
+ true, false, element[GroupElement]))
+ }
+
+ override def negate: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ GroupElementClass.getMethod("negate"),
+ List(),
+ true, false, element[GroupElement]))
+ }
+
+ override def getEncoded: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ GroupElementClass.getMethod("getEncoded"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+ }
+
+ implicit object LiftableGroupElement
+ extends Liftable[SGroupElement, GroupElement] {
+ lazy val eW: Elem[GroupElement] = groupElementElement
+ lazy val sourceType: RType[SGroupElement] = {
+ RType[SGroupElement]
+ }
+ def lift(x: SGroupElement): Rep[GroupElement] = GroupElementConst(x)
+ def unlift(w: Rep[GroupElement]): SGroupElement = w match {
+ case Def(GroupElementConst(x: SGroupElement))
+ => x.asInstanceOf[SGroupElement]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for GroupElement trait
+ case class GroupElementAdapter(source: Rep[GroupElement])
+ extends GroupElement with Def[GroupElement] {
+ val selfType: Elem[GroupElement] = element[GroupElement]
+ override def transform(t: Transformer) = GroupElementAdapter(t(source))
+ private val thisClass = classOf[GroupElement]
+
+ def isInfinity: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("isInfinity"),
+ List(),
+ true, true, element[Boolean]))
+ }
+
+ def exp(k: Rep[BigInt]): Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ thisClass.getMethod("exp", classOf[Sym]),
+ List(k),
+ true, true, element[GroupElement]))
+ }
+
+ def multiply(that: Rep[GroupElement]): Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ thisClass.getMethod("multiply", classOf[Sym]),
+ List(that),
+ true, true, element[GroupElement]))
+ }
+
+ def negate: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ thisClass.getMethod("negate"),
+ List(),
+ true, true, element[GroupElement]))
+ }
+
+ def getEncoded: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("getEncoded"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyGroupElement(p: Rep[GroupElement]): GroupElement = {
+ if (p.rhs.isInstanceOf[GroupElement@unchecked]) p.rhs.asInstanceOf[GroupElement]
+ else
+ GroupElementAdapter(p)
+ }
+
+ // familyElem
+ class GroupElementElem[To <: GroupElement]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableGroupElement.asLiftable[SGroupElement, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[GroupElement], classOf[SGroupElement], Set(
+ "isInfinity", "exp", "multiply", "negate", "getEncoded"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[GroupElement].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[GroupElement] => convertGroupElement(x) }
+ tryConvert(element[GroupElement], this, x, conv)
+ }
+
+ def convertGroupElement(x: Rep[GroupElement]): Rep[To] = {
+ x.elem match {
+ case _: GroupElementElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have GroupElementElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val groupElementElement: Elem[GroupElement] =
+ new GroupElementElem[GroupElement]
+
+ implicit case object GroupElementCompanionElem extends CompanionElem[GroupElementCompanionCtor] {
+ lazy val tag = weakTypeTag[GroupElementCompanionCtor]
+ protected def getDefaultRep = RGroupElement
+ }
+
+ abstract class GroupElementCompanionCtor extends CompanionDef[GroupElementCompanionCtor] with GroupElementCompanion {
+ def selfType = GroupElementCompanionElem
+ override def toString = "GroupElement"
+ }
+ implicit def proxyGroupElementCompanionCtor(p: Rep[GroupElementCompanionCtor]): GroupElementCompanionCtor =
+ proxyOps[GroupElementCompanionCtor](p)
+
+ lazy val RGroupElement: Rep[GroupElementCompanionCtor] = new GroupElementCompanionCtor {
+ private val thisClass = classOf[GroupElementCompanion]
+ }
+
+ object GroupElementMethods {
+ object isInfinity {
+ def unapply(d: Def[_]): Nullable[Rep[GroupElement]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[GroupElementElem[_]] && method.getName == "isInfinity" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[GroupElement]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[GroupElement]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object exp {
+ def unapply(d: Def[_]): Nullable[(Rep[GroupElement], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[GroupElementElem[_]] && method.getName == "exp" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[GroupElement], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[GroupElement], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object multiply {
+ def unapply(d: Def[_]): Nullable[(Rep[GroupElement], Rep[GroupElement])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[GroupElementElem[_]] && method.getName == "multiply" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[GroupElement], Rep[GroupElement])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[GroupElement], Rep[GroupElement])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object negate {
+ def unapply(d: Def[_]): Nullable[Rep[GroupElement]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[GroupElementElem[_]] && method.getName == "negate" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[GroupElement]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[GroupElement]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getEncoded {
+ def unapply(d: Def[_]): Nullable[Rep[GroupElement]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[GroupElementElem[_]] && method.getName == "getEncoded" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[GroupElement]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[GroupElement]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object GroupElementCompanionMethods {
+ }
+} // of object GroupElement
+ registerEntityObject("GroupElement", GroupElement)
+
+object SigmaProp extends EntityObject("SigmaProp") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SSigmaProp = special.sigma.SigmaProp
+ case class SigmaPropConst(
+ constValue: SSigmaProp
+ ) extends SigmaProp with LiftedConst[SSigmaProp, SigmaProp]
+ with Def[SigmaProp] with SigmaPropConstMethods {
+ val liftable: Liftable[SSigmaProp, SigmaProp] = LiftableSigmaProp
+ val selfType: Elem[SigmaProp] = liftable.eW
+ }
+
+ trait SigmaPropConstMethods extends SigmaProp { thisConst: Def[_] =>
+
+ private val SigmaPropClass = classOf[SigmaProp]
+
+ override def isValid: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ SigmaPropClass.getMethod("isValid"),
+ List(),
+ true, false, element[Boolean]))
+ }
+
+ override def propBytes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ SigmaPropClass.getMethod("propBytes"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ // manual fix &&
+ override def &&(other: Rep[SigmaProp]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaPropClass.getMethod("$amp$amp", classOf[Sym]),
+ List(other),
+ true, false, element[SigmaProp]))
+ }
+
+ // manual fix &&
+ override def &&(other: Rep[Boolean])(implicit o: Overloaded1): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaPropClass.getMethod("$amp$amp", classOf[Sym], classOf[Overloaded1]),
+ List(other, o),
+ true, false, element[SigmaProp]))
+ }
+
+ // manual fix ||
+ override def ||(other: Rep[SigmaProp]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaPropClass.getMethod("$bar$bar", classOf[Sym]),
+ List(other),
+ true, false, element[SigmaProp]))
+ }
+
+ // manual fix ||
+ override def ||(other: Rep[Boolean])(implicit o: Overloaded1): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaPropClass.getMethod("$bar$bar", classOf[Sym], classOf[Overloaded1]),
+ List(other, o),
+ true, false, element[SigmaProp]))
+ }
+ }
+
+ implicit object LiftableSigmaProp
+ extends Liftable[SSigmaProp, SigmaProp] {
+ lazy val eW: Elem[SigmaProp] = sigmaPropElement
+ lazy val sourceType: RType[SSigmaProp] = {
+ RType[SSigmaProp]
+ }
+ def lift(x: SSigmaProp): Rep[SigmaProp] = SigmaPropConst(x)
+ def unlift(w: Rep[SigmaProp]): SSigmaProp = w match {
+ case Def(SigmaPropConst(x: SSigmaProp))
+ => x.asInstanceOf[SSigmaProp]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for SigmaProp trait
+ case class SigmaPropAdapter(source: Rep[SigmaProp])
+ extends SigmaProp with Def[SigmaProp] {
+ val selfType: Elem[SigmaProp] = element[SigmaProp]
+ override def transform(t: Transformer) = SigmaPropAdapter(t(source))
+ private val thisClass = classOf[SigmaProp]
+
+ def isValid: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("isValid"),
+ List(),
+ true, true, element[Boolean]))
+ }
+
+ def propBytes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("propBytes"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ // manual fix &&
+ def &&(other: Rep[SigmaProp]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("$amp$amp", classOf[Sym]),
+ List(other),
+ true, true, element[SigmaProp]))
+ }
+
+ // manual fix &&
+ def &&(other: Rep[Boolean])(implicit o: Overloaded1): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("$amp$amp", classOf[Sym], classOf[Overloaded1]),
+ List(other, o),
+ true, true, element[SigmaProp]))
+ }
+
+ // manual fix ||
+ def ||(other: Rep[SigmaProp]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("$bar$bar", classOf[Sym]),
+ List(other),
+ true, true, element[SigmaProp]))
+ }
+
+ // manual fix ||
+ def ||(other: Rep[Boolean])(implicit o: Overloaded1): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("$bar$bar", classOf[Sym], classOf[Overloaded1]),
+ List(other, o),
+ true, true, element[SigmaProp]))
+ }
+
+ def lazyAnd(other: Rep[Thunk[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("lazyAnd", classOf[Sym]),
+ List(other),
+ true, true, element[SigmaProp]))
+ }
+
+ def lazyOr(other: Rep[Thunk[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("lazyOr", classOf[Sym]),
+ List(other),
+ true, true, element[SigmaProp]))
+ }
+
+ def builder: Rep[SigmaDslBuilder] = {
+ asRep[SigmaDslBuilder](mkMethodCall(source,
+ thisClass.getMethod("builder"),
+ List(),
+ true, true, element[SigmaDslBuilder]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySigmaProp(p: Rep[SigmaProp]): SigmaProp = {
+ if (p.rhs.isInstanceOf[SigmaProp@unchecked]) p.rhs.asInstanceOf[SigmaProp]
+ else
+ SigmaPropAdapter(p)
+ }
+
+ // familyElem
+ class SigmaPropElem[To <: SigmaProp]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableSigmaProp.asLiftable[SSigmaProp, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[SigmaProp], classOf[SSigmaProp], Set(
+ "isValid", "propBytes", "$amp$amp", "$amp$amp", "$bar$bar", "$bar$bar"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SigmaProp].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SigmaProp] => convertSigmaProp(x) }
+ tryConvert(element[SigmaProp], this, x, conv)
+ }
+
+ def convertSigmaProp(x: Rep[SigmaProp]): Rep[To] = {
+ x.elem match {
+ case _: SigmaPropElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SigmaPropElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sigmaPropElement: Elem[SigmaProp] =
+ new SigmaPropElem[SigmaProp]
+
+ implicit case object SigmaPropCompanionElem extends CompanionElem[SigmaPropCompanionCtor] {
+ lazy val tag = weakTypeTag[SigmaPropCompanionCtor]
+ protected def getDefaultRep = RSigmaProp
+ }
+
+ abstract class SigmaPropCompanionCtor extends CompanionDef[SigmaPropCompanionCtor] with SigmaPropCompanion {
+ def selfType = SigmaPropCompanionElem
+ override def toString = "SigmaProp"
+ }
+ implicit def proxySigmaPropCompanionCtor(p: Rep[SigmaPropCompanionCtor]): SigmaPropCompanionCtor =
+ proxyOps[SigmaPropCompanionCtor](p)
+
+ lazy val RSigmaProp: Rep[SigmaPropCompanionCtor] = new SigmaPropCompanionCtor {
+ private val thisClass = classOf[SigmaPropCompanion]
+ }
+
+ object SigmaPropMethods {
+ object isValid {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaProp]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaPropElem[_]] && method.getName == "isValid" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaProp]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaProp]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object propBytes {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaProp]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaPropElem[_]] && method.getName == "propBytes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaProp]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaProp]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object and_sigma_&& {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaProp], Rep[SigmaProp])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaPropElem[_]] && method.getName == "$amp$amp" && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "and_sigma" } =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaProp], Rep[SigmaProp])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaProp], Rep[SigmaProp])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object and_bool_&& {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaProp], Rep[Boolean])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaPropElem[_]] && method.getName == "$amp$amp" && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "and_bool" } =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaProp], Rep[Boolean])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaProp], Rep[Boolean])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object or_sigma_|| {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaProp], Rep[SigmaProp])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaPropElem[_]] && method.getName == "$bar$bar" && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "or_sigma" } =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaProp], Rep[SigmaProp])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaProp], Rep[SigmaProp])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object or_bool_|| {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaProp], Rep[Boolean])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaPropElem[_]] && method.getName == "$bar$bar" && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "or_bool" } =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaProp], Rep[Boolean])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaProp], Rep[Boolean])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SigmaPropCompanionMethods {
+ }
+} // of object SigmaProp
+ registerEntityObject("SigmaProp", SigmaProp)
+
+object AnyValue extends EntityObject("AnyValue") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SAnyValue = special.sigma.AnyValue
+ case class AnyValueConst(
+ constValue: SAnyValue
+ ) extends AnyValue with LiftedConst[SAnyValue, AnyValue]
+ with Def[AnyValue] with AnyValueConstMethods {
+ val liftable: Liftable[SAnyValue, AnyValue] = LiftableAnyValue
+ val selfType: Elem[AnyValue] = liftable.eW
+ }
+
+ trait AnyValueConstMethods extends AnyValue { thisConst: Def[_] =>
+
+ private val AnyValueClass = classOf[AnyValue]
+
+ // manual fix
+ override def value: Rep[Any] = {
+ asRep[Any](mkMethodCall(self,
+ AnyValueClass.getMethod("value"),
+ List(),
+ true, false, AnyElement))
+ }
+
+ override def tVal: Rep[WRType[Any]] = {
+ asRep[WRType[Any]](mkMethodCall(self,
+ AnyValueClass.getMethod("tVal"),
+ List(),
+ true, false, element[WRType[Any]]))
+ }
+ }
+
+ implicit object LiftableAnyValue
+ extends Liftable[SAnyValue, AnyValue] {
+ lazy val eW: Elem[AnyValue] = anyValueElement
+ lazy val sourceType: RType[SAnyValue] = {
+ RType[SAnyValue]
+ }
+ def lift(x: SAnyValue): Rep[AnyValue] = AnyValueConst(x)
+ def unlift(w: Rep[AnyValue]): SAnyValue = w match {
+ case Def(AnyValueConst(x: SAnyValue))
+ => x.asInstanceOf[SAnyValue]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for AnyValue trait
+ case class AnyValueAdapter(source: Rep[AnyValue])
+ extends AnyValue with Def[AnyValue] {
+ val selfType: Elem[AnyValue] = element[AnyValue]
+ override def transform(t: Transformer) = AnyValueAdapter(t(source))
+ private val thisClass = classOf[AnyValue]
+
+ // manual fix
+ def value: Rep[Any] = {
+ asRep[Any](mkMethodCall(source,
+ thisClass.getMethod("value"),
+ List(),
+ true, true, AnyElement))
+ }
+
+ def tVal: Rep[WRType[Any]] = {
+ asRep[WRType[Any]](mkMethodCall(source,
+ thisClass.getMethod("tVal"),
+ List(),
+ true, true, element[WRType[Any]]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyAnyValue(p: Rep[AnyValue]): AnyValue = {
+ if (p.rhs.isInstanceOf[AnyValue@unchecked]) p.rhs.asInstanceOf[AnyValue]
+ else
+ AnyValueAdapter(p)
+ }
+
+ // familyElem
+ class AnyValueElem[To <: AnyValue]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableAnyValue.asLiftable[SAnyValue, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[AnyValue], classOf[SAnyValue], Set(
+ "value", "tVal"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[AnyValue].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[AnyValue] => convertAnyValue(x) }
+ tryConvert(element[AnyValue], this, x, conv)
+ }
+
+ def convertAnyValue(x: Rep[AnyValue]): Rep[To] = {
+ x.elem match {
+ case _: AnyValueElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have AnyValueElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val anyValueElement: Elem[AnyValue] =
+ new AnyValueElem[AnyValue]
+
+ implicit case object AnyValueCompanionElem extends CompanionElem[AnyValueCompanionCtor] {
+ lazy val tag = weakTypeTag[AnyValueCompanionCtor]
+ protected def getDefaultRep = RAnyValue
+ }
+
+ abstract class AnyValueCompanionCtor extends CompanionDef[AnyValueCompanionCtor] with AnyValueCompanion {
+ def selfType = AnyValueCompanionElem
+ override def toString = "AnyValue"
+ }
+ implicit def proxyAnyValueCompanionCtor(p: Rep[AnyValueCompanionCtor]): AnyValueCompanionCtor =
+ proxyOps[AnyValueCompanionCtor](p)
+
+ lazy val RAnyValue: Rep[AnyValueCompanionCtor] = new AnyValueCompanionCtor {
+ private val thisClass = classOf[AnyValueCompanion]
+ }
+
+ object AnyValueMethods {
+ object value {
+ def unapply(d: Def[_]): Nullable[Rep[AnyValue]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AnyValueElem[_]] && method.getName == "value" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AnyValue]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AnyValue]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object tVal {
+ def unapply(d: Def[_]): Nullable[Rep[AnyValue]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AnyValueElem[_]] && method.getName == "tVal" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AnyValue]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AnyValue]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object AnyValueCompanionMethods {
+ }
+} // of object AnyValue
+ registerEntityObject("AnyValue", AnyValue)
+
+object Box extends EntityObject("Box") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SBox = special.sigma.Box
+ case class BoxConst(
+ constValue: SBox
+ ) extends Box with LiftedConst[SBox, Box]
+ with Def[Box] with BoxConstMethods {
+ val liftable: Liftable[SBox, Box] = LiftableBox
+ val selfType: Elem[Box] = liftable.eW
+ }
+
+ trait BoxConstMethods extends Box { thisConst: Def[_] =>
+
+ private val BoxClass = classOf[Box]
+
+ override def id: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ BoxClass.getMethod("id"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def value: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ BoxClass.getMethod("value"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def propositionBytes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ BoxClass.getMethod("propositionBytes"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def bytes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ BoxClass.getMethod("bytes"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def bytesWithoutRef: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ BoxClass.getMethod("bytesWithoutRef"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def registers: Rep[Coll[AnyValue]] = {
+ asRep[Coll[AnyValue]](mkMethodCall(self,
+ BoxClass.getMethod("registers"),
+ List(),
+ true, false, element[Coll[AnyValue]]))
+ }
+
+ override def getReg[T](i: Rep[Int])(implicit cT: Elem[T]): Rep[WOption[T]] = {
+ asRep[WOption[T]](mkMethodCall(self,
+ BoxClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
+ List(i, cT),
+ true, false, element[WOption[T]]))
+ }
+
+ override def tokens: Rep[Coll[(Coll[Byte], Long)]] = {
+ asRep[Coll[(Coll[Byte], Long)]](mkMethodCall(self,
+ BoxClass.getMethod("tokens"),
+ List(),
+ true, false, element[Coll[(Coll[Byte], Long)]]))
+ }
+
+ override def creationInfo: Rep[(Int, Coll[Byte])] = {
+ asRep[(Int, Coll[Byte])](mkMethodCall(self,
+ BoxClass.getMethod("creationInfo"),
+ List(),
+ true, false, element[(Int, Coll[Byte])]))
+ }
+
+ override def executeFromRegister[T](regId: Rep[Byte])(implicit cT: Elem[T]): Rep[T] = {
+ asRep[T](mkMethodCall(self,
+ BoxClass.getMethod("executeFromRegister", classOf[Sym], classOf[Elem[_]]),
+ List(regId, cT),
+ true, false, element[T]))
+ }
+ }
+
+ implicit object LiftableBox
+ extends Liftable[SBox, Box] {
+ lazy val eW: Elem[Box] = boxElement
+ lazy val sourceType: RType[SBox] = {
+ RType[SBox]
+ }
+ def lift(x: SBox): Rep[Box] = BoxConst(x)
+ def unlift(w: Rep[Box]): SBox = w match {
+ case Def(BoxConst(x: SBox))
+ => x.asInstanceOf[SBox]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for Box trait
+ case class BoxAdapter(source: Rep[Box])
+ extends Box with Def[Box] {
+ val selfType: Elem[Box] = element[Box]
+ override def transform(t: Transformer) = BoxAdapter(t(source))
+ private val thisClass = classOf[Box]
+
+ def id: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("id"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def value: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("value"),
+ List(),
+ true, true, element[Long]))
+ }
+
+ def propositionBytes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("propositionBytes"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def bytes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("bytes"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def bytesWithoutRef: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("bytesWithoutRef"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def registers: Rep[Coll[AnyValue]] = {
+ asRep[Coll[AnyValue]](mkMethodCall(source,
+ thisClass.getMethod("registers"),
+ List(),
+ true, true, element[Coll[AnyValue]]))
+ }
+
+ def getReg[T](i: Rep[Int])(implicit cT: Elem[T]): Rep[WOption[T]] = {
+ asRep[WOption[T]](mkMethodCall(source,
+ thisClass.getMethod("getReg", classOf[Sym], classOf[Elem[_]]),
+ List(i, cT),
+ true, true, element[WOption[T]]))
+ }
+
+ def tokens: Rep[Coll[(Coll[Byte], Long)]] = {
+ asRep[Coll[(Coll[Byte], Long)]](mkMethodCall(source,
+ thisClass.getMethod("tokens"),
+ List(),
+ true, true, element[Coll[(Coll[Byte], Long)]]))
+ }
+
+ def creationInfo: Rep[(Int, Coll[Byte])] = {
+ asRep[(Int, Coll[Byte])](mkMethodCall(source,
+ thisClass.getMethod("creationInfo"),
+ List(),
+ true, true, element[(Int, Coll[Byte])]))
+ }
+
+ def executeFromRegister[T](regId: Rep[Byte])(implicit cT: Elem[T]): Rep[T] = {
+ asRep[T](mkMethodCall(source,
+ thisClass.getMethod("executeFromRegister", classOf[Sym], classOf[Elem[_]]),
+ List(regId, cT),
+ true, true, element[T]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyBox(p: Rep[Box]): Box = {
+ if (p.rhs.isInstanceOf[Box@unchecked]) p.rhs.asInstanceOf[Box]
+ else
+ BoxAdapter(p)
+ }
+
+ // familyElem
+ class BoxElem[To <: Box]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableBox.asLiftable[SBox, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[Box], classOf[SBox], Set(
+ "id", "value", "propositionBytes", "bytes", "bytesWithoutRef", "registers", "getReg", "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "tokens", "creationInfo", "executeFromRegister"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[Box].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[Box] => convertBox(x) }
+ tryConvert(element[Box], this, x, conv)
+ }
+
+ def convertBox(x: Rep[Box]): Rep[To] = {
+ x.elem match {
+ case _: BoxElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have BoxElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val boxElement: Elem[Box] =
+ new BoxElem[Box]
+
+ implicit case object BoxCompanionElem extends CompanionElem[BoxCompanionCtor] {
+ lazy val tag = weakTypeTag[BoxCompanionCtor]
+ protected def getDefaultRep = RBox
+ }
+
+ abstract class BoxCompanionCtor extends CompanionDef[BoxCompanionCtor] with BoxCompanion {
+ def selfType = BoxCompanionElem
+ override def toString = "Box"
+ }
+ implicit def proxyBoxCompanionCtor(p: Rep[BoxCompanionCtor]): BoxCompanionCtor =
+ proxyOps[BoxCompanionCtor](p)
+
+ lazy val RBox: Rep[BoxCompanionCtor] = new BoxCompanionCtor {
+ private val thisClass = classOf[BoxCompanion]
+ }
+
+ object BoxMethods {
+ object id {
+ def unapply(d: Def[_]): Nullable[Rep[Box]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "id" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Box]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Box]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object value {
+ def unapply(d: Def[_]): Nullable[Rep[Box]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "value" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Box]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Box]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object propositionBytes {
+ def unapply(d: Def[_]): Nullable[Rep[Box]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "propositionBytes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Box]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Box]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object bytes {
+ def unapply(d: Def[_]): Nullable[Rep[Box]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "bytes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Box]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Box]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object bytesWithoutRef {
+ def unapply(d: Def[_]): Nullable[Rep[Box]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "bytesWithoutRef" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Box]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Box]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object registers {
+ def unapply(d: Def[_]): Nullable[Rep[Box]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "registers" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Box]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Box]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getReg {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Rep[Int], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "getReg" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Rep[Int], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Rep[Int], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R0 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R0" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R1 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R1" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R2 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R2" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R3 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R3" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R4 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R4" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R5 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R5" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R6 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R6" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R7 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R7" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R8 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R8" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object R9 {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "R9" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object tokens {
+ def unapply(d: Def[_]): Nullable[Rep[Box]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "tokens" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Box]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Box]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object creationInfo {
+ def unapply(d: Def[_]): Nullable[Rep[Box]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "creationInfo" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Box]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Box]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object executeFromRegister {
+ def unapply(d: Def[_]): Nullable[(Rep[Box], Rep[Byte], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BoxElem[_]] && method.getName == "executeFromRegister" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Box], Rep[Byte], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Box], Rep[Byte], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object BoxCompanionMethods {
+ }
+} // of object Box
+ registerEntityObject("Box", Box)
+
+object AvlTree extends EntityObject("AvlTree") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SAvlTree = special.sigma.AvlTree
+ case class AvlTreeConst(
+ constValue: SAvlTree
+ ) extends AvlTree with LiftedConst[SAvlTree, AvlTree]
+ with Def[AvlTree] with AvlTreeConstMethods {
+ val liftable: Liftable[SAvlTree, AvlTree] = LiftableAvlTree
+ val selfType: Elem[AvlTree] = liftable.eW
+ }
+
+ trait AvlTreeConstMethods extends AvlTree { thisConst: Def[_] =>
+
+ private val AvlTreeClass = classOf[AvlTree]
+
+ override def digest: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ AvlTreeClass.getMethod("digest"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def enabledOperations: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(self,
+ AvlTreeClass.getMethod("enabledOperations"),
+ List(),
+ true, false, element[Byte]))
+ }
+
+ override def keyLength: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ AvlTreeClass.getMethod("keyLength"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def valueLengthOpt: Rep[WOption[Int]] = {
+ asRep[WOption[Int]](mkMethodCall(self,
+ AvlTreeClass.getMethod("valueLengthOpt"),
+ List(),
+ true, false, element[WOption[Int]]))
+ }
+
+ override def isInsertAllowed: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ AvlTreeClass.getMethod("isInsertAllowed"),
+ List(),
+ true, false, element[Boolean]))
+ }
+
+ override def isUpdateAllowed: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ AvlTreeClass.getMethod("isUpdateAllowed"),
+ List(),
+ true, false, element[Boolean]))
+ }
+
+ override def isRemoveAllowed: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ AvlTreeClass.getMethod("isRemoveAllowed"),
+ List(),
+ true, false, element[Boolean]))
+ }
+
+ override def updateDigest(newDigest: Rep[Coll[Byte]]): Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(self,
+ AvlTreeClass.getMethod("updateDigest", classOf[Sym]),
+ List(newDigest),
+ true, false, element[AvlTree]))
+ }
+
+ override def updateOperations(newOperations: Rep[Byte]): Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(self,
+ AvlTreeClass.getMethod("updateOperations", classOf[Sym]),
+ List(newOperations),
+ true, false, element[AvlTree]))
+ }
+
+ override def contains(key: Rep[Coll[Byte]], proof: Rep[Coll[Byte]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ AvlTreeClass.getMethod("contains", classOf[Sym], classOf[Sym]),
+ List(key, proof),
+ true, false, element[Boolean]))
+ }
+
+ override def get(key: Rep[Coll[Byte]], proof: Rep[Coll[Byte]]): Rep[WOption[Coll[Byte]]] = {
+ asRep[WOption[Coll[Byte]]](mkMethodCall(self,
+ AvlTreeClass.getMethod("get", classOf[Sym], classOf[Sym]),
+ List(key, proof),
+ true, false, element[WOption[Coll[Byte]]]))
+ }
+
+ override def getMany(keys: Rep[Coll[Coll[Byte]]], proof: Rep[Coll[Byte]]): Rep[Coll[WOption[Coll[Byte]]]] = {
+ asRep[Coll[WOption[Coll[Byte]]]](mkMethodCall(self,
+ AvlTreeClass.getMethod("getMany", classOf[Sym], classOf[Sym]),
+ List(keys, proof),
+ true, false, element[Coll[WOption[Coll[Byte]]]]))
+ }
+
+ override def insert(operations: Rep[Coll[(Coll[Byte], Coll[Byte])]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]] = {
+ asRep[WOption[AvlTree]](mkMethodCall(self,
+ AvlTreeClass.getMethod("insert", classOf[Sym], classOf[Sym]),
+ List(operations, proof),
+ true, false, element[WOption[AvlTree]]))
+ }
+
+ override def update(operations: Rep[Coll[(Coll[Byte], Coll[Byte])]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]] = {
+ asRep[WOption[AvlTree]](mkMethodCall(self,
+ AvlTreeClass.getMethod("update", classOf[Sym], classOf[Sym]),
+ List(operations, proof),
+ true, false, element[WOption[AvlTree]]))
+ }
+
+ override def remove(operations: Rep[Coll[Coll[Byte]]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]] = {
+ asRep[WOption[AvlTree]](mkMethodCall(self,
+ AvlTreeClass.getMethod("remove", classOf[Sym], classOf[Sym]),
+ List(operations, proof),
+ true, false, element[WOption[AvlTree]]))
+ }
+ }
+
+ implicit object LiftableAvlTree
+ extends Liftable[SAvlTree, AvlTree] {
+ lazy val eW: Elem[AvlTree] = avlTreeElement
+ lazy val sourceType: RType[SAvlTree] = {
+ RType[SAvlTree]
+ }
+ def lift(x: SAvlTree): Rep[AvlTree] = AvlTreeConst(x)
+ def unlift(w: Rep[AvlTree]): SAvlTree = w match {
+ case Def(AvlTreeConst(x: SAvlTree))
+ => x.asInstanceOf[SAvlTree]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for AvlTree trait
+ case class AvlTreeAdapter(source: Rep[AvlTree])
+ extends AvlTree with Def[AvlTree] {
+ val selfType: Elem[AvlTree] = element[AvlTree]
+ override def transform(t: Transformer) = AvlTreeAdapter(t(source))
+ private val thisClass = classOf[AvlTree]
+
+ def digest: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("digest"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def enabledOperations: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(source,
+ thisClass.getMethod("enabledOperations"),
+ List(),
+ true, true, element[Byte]))
+ }
+
+ def keyLength: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("keyLength"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def valueLengthOpt: Rep[WOption[Int]] = {
+ asRep[WOption[Int]](mkMethodCall(source,
+ thisClass.getMethod("valueLengthOpt"),
+ List(),
+ true, true, element[WOption[Int]]))
+ }
+
+ def isInsertAllowed: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("isInsertAllowed"),
+ List(),
+ true, true, element[Boolean]))
+ }
+
+ def isUpdateAllowed: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("isUpdateAllowed"),
+ List(),
+ true, true, element[Boolean]))
+ }
+
+ def isRemoveAllowed: Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("isRemoveAllowed"),
+ List(),
+ true, true, element[Boolean]))
+ }
+
+ def updateDigest(newDigest: Rep[Coll[Byte]]): Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(source,
+ thisClass.getMethod("updateDigest", classOf[Sym]),
+ List(newDigest),
+ true, true, element[AvlTree]))
+ }
+
+ def updateOperations(newOperations: Rep[Byte]): Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(source,
+ thisClass.getMethod("updateOperations", classOf[Sym]),
+ List(newOperations),
+ true, true, element[AvlTree]))
+ }
+
+ def contains(key: Rep[Coll[Byte]], proof: Rep[Coll[Byte]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("contains", classOf[Sym], classOf[Sym]),
+ List(key, proof),
+ true, true, element[Boolean]))
+ }
+
+ def get(key: Rep[Coll[Byte]], proof: Rep[Coll[Byte]]): Rep[WOption[Coll[Byte]]] = {
+ asRep[WOption[Coll[Byte]]](mkMethodCall(source,
+ thisClass.getMethod("get", classOf[Sym], classOf[Sym]),
+ List(key, proof),
+ true, true, element[WOption[Coll[Byte]]]))
+ }
+
+ def getMany(keys: Rep[Coll[Coll[Byte]]], proof: Rep[Coll[Byte]]): Rep[Coll[WOption[Coll[Byte]]]] = {
+ asRep[Coll[WOption[Coll[Byte]]]](mkMethodCall(source,
+ thisClass.getMethod("getMany", classOf[Sym], classOf[Sym]),
+ List(keys, proof),
+ true, true, element[Coll[WOption[Coll[Byte]]]]))
+ }
+
+ def insert(operations: Rep[Coll[(Coll[Byte], Coll[Byte])]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]] = {
+ asRep[WOption[AvlTree]](mkMethodCall(source,
+ thisClass.getMethod("insert", classOf[Sym], classOf[Sym]),
+ List(operations, proof),
+ true, true, element[WOption[AvlTree]]))
+ }
+
+ def update(operations: Rep[Coll[(Coll[Byte], Coll[Byte])]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]] = {
+ asRep[WOption[AvlTree]](mkMethodCall(source,
+ thisClass.getMethod("update", classOf[Sym], classOf[Sym]),
+ List(operations, proof),
+ true, true, element[WOption[AvlTree]]))
+ }
+
+ def remove(operations: Rep[Coll[Coll[Byte]]], proof: Rep[Coll[Byte]]): Rep[WOption[AvlTree]] = {
+ asRep[WOption[AvlTree]](mkMethodCall(source,
+ thisClass.getMethod("remove", classOf[Sym], classOf[Sym]),
+ List(operations, proof),
+ true, true, element[WOption[AvlTree]]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyAvlTree(p: Rep[AvlTree]): AvlTree = {
+ if (p.rhs.isInstanceOf[AvlTree@unchecked]) p.rhs.asInstanceOf[AvlTree]
+ else
+ AvlTreeAdapter(p)
+ }
+
+ // familyElem
+ class AvlTreeElem[To <: AvlTree]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableAvlTree.asLiftable[SAvlTree, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[AvlTree], classOf[SAvlTree], Set(
+ "digest", "enabledOperations", "keyLength", "valueLengthOpt", "isInsertAllowed", "isUpdateAllowed", "isRemoveAllowed", "updateDigest", "updateOperations", "contains", "get", "getMany", "insert", "update", "remove"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[AvlTree].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[AvlTree] => convertAvlTree(x) }
+ tryConvert(element[AvlTree], this, x, conv)
+ }
+
+ def convertAvlTree(x: Rep[AvlTree]): Rep[To] = {
+ x.elem match {
+ case _: AvlTreeElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have AvlTreeElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val avlTreeElement: Elem[AvlTree] =
+ new AvlTreeElem[AvlTree]
+
+ implicit case object AvlTreeCompanionElem extends CompanionElem[AvlTreeCompanionCtor] {
+ lazy val tag = weakTypeTag[AvlTreeCompanionCtor]
+ protected def getDefaultRep = RAvlTree
+ }
+
+ abstract class AvlTreeCompanionCtor extends CompanionDef[AvlTreeCompanionCtor] with AvlTreeCompanion {
+ def selfType = AvlTreeCompanionElem
+ override def toString = "AvlTree"
+ }
+ implicit def proxyAvlTreeCompanionCtor(p: Rep[AvlTreeCompanionCtor]): AvlTreeCompanionCtor =
+ proxyOps[AvlTreeCompanionCtor](p)
+
+ lazy val RAvlTree: Rep[AvlTreeCompanionCtor] = new AvlTreeCompanionCtor {
+ private val thisClass = classOf[AvlTreeCompanion]
+ }
+
+ object AvlTreeMethods {
+ object digest {
+ def unapply(d: Def[_]): Nullable[Rep[AvlTree]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "digest" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AvlTree]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AvlTree]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object enabledOperations {
+ def unapply(d: Def[_]): Nullable[Rep[AvlTree]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "enabledOperations" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AvlTree]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AvlTree]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object keyLength {
+ def unapply(d: Def[_]): Nullable[Rep[AvlTree]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "keyLength" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AvlTree]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AvlTree]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object valueLengthOpt {
+ def unapply(d: Def[_]): Nullable[Rep[AvlTree]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "valueLengthOpt" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AvlTree]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AvlTree]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object isInsertAllowed {
+ def unapply(d: Def[_]): Nullable[Rep[AvlTree]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "isInsertAllowed" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AvlTree]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AvlTree]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object isUpdateAllowed {
+ def unapply(d: Def[_]): Nullable[Rep[AvlTree]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "isUpdateAllowed" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AvlTree]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AvlTree]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object isRemoveAllowed {
+ def unapply(d: Def[_]): Nullable[Rep[AvlTree]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "isRemoveAllowed" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[AvlTree]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[AvlTree]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object updateDigest {
+ def unapply(d: Def[_]): Nullable[(Rep[AvlTree], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "updateDigest" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[AvlTree], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[AvlTree], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object updateOperations {
+ def unapply(d: Def[_]): Nullable[(Rep[AvlTree], Rep[Byte])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "updateOperations" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[AvlTree], Rep[Byte])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[AvlTree], Rep[Byte])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object contains {
+ def unapply(d: Def[_]): Nullable[(Rep[AvlTree], Rep[Coll[Byte]], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "contains" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[AvlTree], Rep[Coll[Byte]], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[AvlTree], Rep[Coll[Byte]], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object get {
+ def unapply(d: Def[_]): Nullable[(Rep[AvlTree], Rep[Coll[Byte]], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "get" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[AvlTree], Rep[Coll[Byte]], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[AvlTree], Rep[Coll[Byte]], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getMany {
+ def unapply(d: Def[_]): Nullable[(Rep[AvlTree], Rep[Coll[Coll[Byte]]], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "getMany" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[AvlTree], Rep[Coll[Coll[Byte]]], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[AvlTree], Rep[Coll[Coll[Byte]]], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object insert {
+ def unapply(d: Def[_]): Nullable[(Rep[AvlTree], Rep[Coll[(Coll[Byte], Coll[Byte])]], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "insert" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[AvlTree], Rep[Coll[(Coll[Byte], Coll[Byte])]], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[AvlTree], Rep[Coll[(Coll[Byte], Coll[Byte])]], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object update {
+ def unapply(d: Def[_]): Nullable[(Rep[AvlTree], Rep[Coll[(Coll[Byte], Coll[Byte])]], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "update" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[AvlTree], Rep[Coll[(Coll[Byte], Coll[Byte])]], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[AvlTree], Rep[Coll[(Coll[Byte], Coll[Byte])]], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object remove {
+ def unapply(d: Def[_]): Nullable[(Rep[AvlTree], Rep[Coll[Coll[Byte]]], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[AvlTreeElem[_]] && method.getName == "remove" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[AvlTree], Rep[Coll[Coll[Byte]]], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[AvlTree], Rep[Coll[Coll[Byte]]], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object AvlTreeCompanionMethods {
+ }
+} // of object AvlTree
+ registerEntityObject("AvlTree", AvlTree)
+
+object PreHeader extends EntityObject("PreHeader") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SPreHeader = special.sigma.PreHeader
+ case class PreHeaderConst(
+ constValue: SPreHeader
+ ) extends PreHeader with LiftedConst[SPreHeader, PreHeader]
+ with Def[PreHeader] with PreHeaderConstMethods {
+ val liftable: Liftable[SPreHeader, PreHeader] = LiftablePreHeader
+ val selfType: Elem[PreHeader] = liftable.eW
+ }
+
+ trait PreHeaderConstMethods extends PreHeader { thisConst: Def[_] =>
+
+ private val PreHeaderClass = classOf[PreHeader]
+
+ override def version: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(self,
+ PreHeaderClass.getMethod("version"),
+ List(),
+ true, false, element[Byte]))
+ }
+
+ override def parentId: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ PreHeaderClass.getMethod("parentId"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def timestamp: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ PreHeaderClass.getMethod("timestamp"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def nBits: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ PreHeaderClass.getMethod("nBits"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def height: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ PreHeaderClass.getMethod("height"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def minerPk: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ PreHeaderClass.getMethod("minerPk"),
+ List(),
+ true, false, element[GroupElement]))
+ }
+
+ override def votes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ PreHeaderClass.getMethod("votes"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+ }
+
+ implicit object LiftablePreHeader
+ extends Liftable[SPreHeader, PreHeader] {
+ lazy val eW: Elem[PreHeader] = preHeaderElement
+ lazy val sourceType: RType[SPreHeader] = {
+ RType[SPreHeader]
+ }
+ def lift(x: SPreHeader): Rep[PreHeader] = PreHeaderConst(x)
+ def unlift(w: Rep[PreHeader]): SPreHeader = w match {
+ case Def(PreHeaderConst(x: SPreHeader))
+ => x.asInstanceOf[SPreHeader]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for PreHeader trait
+ case class PreHeaderAdapter(source: Rep[PreHeader])
+ extends PreHeader with Def[PreHeader] {
+ val selfType: Elem[PreHeader] = element[PreHeader]
+ override def transform(t: Transformer) = PreHeaderAdapter(t(source))
+ private val thisClass = classOf[PreHeader]
+
+ def version: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(source,
+ thisClass.getMethod("version"),
+ List(),
+ true, true, element[Byte]))
+ }
+
+ def parentId: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("parentId"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def timestamp: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("timestamp"),
+ List(),
+ true, true, element[Long]))
+ }
+
+ def nBits: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("nBits"),
+ List(),
+ true, true, element[Long]))
+ }
+
+ def height: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("height"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def minerPk: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ thisClass.getMethod("minerPk"),
+ List(),
+ true, true, element[GroupElement]))
+ }
+
+ def votes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("votes"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyPreHeader(p: Rep[PreHeader]): PreHeader = {
+ if (p.rhs.isInstanceOf[PreHeader@unchecked]) p.rhs.asInstanceOf[PreHeader]
+ else
+ PreHeaderAdapter(p)
+ }
+
+ // familyElem
+ class PreHeaderElem[To <: PreHeader]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftablePreHeader.asLiftable[SPreHeader, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[PreHeader], classOf[SPreHeader], Set(
+ "version", "parentId", "timestamp", "nBits", "height", "minerPk", "votes"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[PreHeader].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[PreHeader] => convertPreHeader(x) }
+ tryConvert(element[PreHeader], this, x, conv)
+ }
+
+ def convertPreHeader(x: Rep[PreHeader]): Rep[To] = {
+ x.elem match {
+ case _: PreHeaderElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have PreHeaderElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val preHeaderElement: Elem[PreHeader] =
+ new PreHeaderElem[PreHeader]
+
+ implicit case object PreHeaderCompanionElem extends CompanionElem[PreHeaderCompanionCtor] {
+ lazy val tag = weakTypeTag[PreHeaderCompanionCtor]
+ protected def getDefaultRep = RPreHeader
+ }
+
+ abstract class PreHeaderCompanionCtor extends CompanionDef[PreHeaderCompanionCtor] with PreHeaderCompanion {
+ def selfType = PreHeaderCompanionElem
+ override def toString = "PreHeader"
+ }
+ implicit def proxyPreHeaderCompanionCtor(p: Rep[PreHeaderCompanionCtor]): PreHeaderCompanionCtor =
+ proxyOps[PreHeaderCompanionCtor](p)
+
+ lazy val RPreHeader: Rep[PreHeaderCompanionCtor] = new PreHeaderCompanionCtor {
+ private val thisClass = classOf[PreHeaderCompanion]
+ }
+
+ object PreHeaderMethods {
+ object version {
+ def unapply(d: Def[_]): Nullable[Rep[PreHeader]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[PreHeaderElem[_]] && method.getName == "version" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[PreHeader]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[PreHeader]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object parentId {
+ def unapply(d: Def[_]): Nullable[Rep[PreHeader]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[PreHeaderElem[_]] && method.getName == "parentId" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[PreHeader]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[PreHeader]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object timestamp {
+ def unapply(d: Def[_]): Nullable[Rep[PreHeader]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[PreHeaderElem[_]] && method.getName == "timestamp" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[PreHeader]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[PreHeader]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object nBits {
+ def unapply(d: Def[_]): Nullable[Rep[PreHeader]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[PreHeaderElem[_]] && method.getName == "nBits" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[PreHeader]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[PreHeader]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object height {
+ def unapply(d: Def[_]): Nullable[Rep[PreHeader]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[PreHeaderElem[_]] && method.getName == "height" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[PreHeader]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[PreHeader]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object minerPk {
+ def unapply(d: Def[_]): Nullable[Rep[PreHeader]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[PreHeaderElem[_]] && method.getName == "minerPk" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[PreHeader]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[PreHeader]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object votes {
+ def unapply(d: Def[_]): Nullable[Rep[PreHeader]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[PreHeaderElem[_]] && method.getName == "votes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[PreHeader]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[PreHeader]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object PreHeaderCompanionMethods {
+ }
+} // of object PreHeader
+ registerEntityObject("PreHeader", PreHeader)
+
+object Header extends EntityObject("Header") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SHeader = special.sigma.Header
+ case class HeaderConst(
+ constValue: SHeader
+ ) extends Header with LiftedConst[SHeader, Header]
+ with Def[Header] with HeaderConstMethods {
+ val liftable: Liftable[SHeader, Header] = LiftableHeader
+ val selfType: Elem[Header] = liftable.eW
+ }
+
+ trait HeaderConstMethods extends Header { thisConst: Def[_] =>
+
+ private val HeaderClass = classOf[Header]
+
+ override def id: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ HeaderClass.getMethod("id"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def version: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(self,
+ HeaderClass.getMethod("version"),
+ List(),
+ true, false, element[Byte]))
+ }
+
+ override def parentId: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ HeaderClass.getMethod("parentId"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def ADProofsRoot: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ HeaderClass.getMethod("ADProofsRoot"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def stateRoot: Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(self,
+ HeaderClass.getMethod("stateRoot"),
+ List(),
+ true, false, element[AvlTree]))
+ }
+
+ override def transactionsRoot: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ HeaderClass.getMethod("transactionsRoot"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def timestamp: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ HeaderClass.getMethod("timestamp"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def nBits: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ HeaderClass.getMethod("nBits"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def height: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ HeaderClass.getMethod("height"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def extensionRoot: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ HeaderClass.getMethod("extensionRoot"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def minerPk: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ HeaderClass.getMethod("minerPk"),
+ List(),
+ true, false, element[GroupElement]))
+ }
+
+ override def powOnetimePk: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ HeaderClass.getMethod("powOnetimePk"),
+ List(),
+ true, false, element[GroupElement]))
+ }
+
+ override def powNonce: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ HeaderClass.getMethod("powNonce"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def powDistance: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ HeaderClass.getMethod("powDistance"),
+ List(),
+ true, false, element[BigInt]))
+ }
+
+ override def votes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ HeaderClass.getMethod("votes"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+ }
+
+ implicit object LiftableHeader
+ extends Liftable[SHeader, Header] {
+ lazy val eW: Elem[Header] = headerElement
+ lazy val sourceType: RType[SHeader] = {
+ RType[SHeader]
+ }
+ def lift(x: SHeader): Rep[Header] = HeaderConst(x)
+ def unlift(w: Rep[Header]): SHeader = w match {
+ case Def(HeaderConst(x: SHeader))
+ => x.asInstanceOf[SHeader]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for Header trait
+ case class HeaderAdapter(source: Rep[Header])
+ extends Header with Def[Header] {
+ val selfType: Elem[Header] = element[Header]
+ override def transform(t: Transformer) = HeaderAdapter(t(source))
+ private val thisClass = classOf[Header]
+
+ def id: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("id"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def version: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(source,
+ thisClass.getMethod("version"),
+ List(),
+ true, true, element[Byte]))
+ }
+
+ def parentId: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("parentId"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def ADProofsRoot: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("ADProofsRoot"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def stateRoot: Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(source,
+ thisClass.getMethod("stateRoot"),
+ List(),
+ true, true, element[AvlTree]))
+ }
+
+ def transactionsRoot: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("transactionsRoot"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def timestamp: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("timestamp"),
+ List(),
+ true, true, element[Long]))
+ }
+
+ def nBits: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("nBits"),
+ List(),
+ true, true, element[Long]))
+ }
+
+ def height: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("height"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def extensionRoot: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("extensionRoot"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def minerPk: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ thisClass.getMethod("minerPk"),
+ List(),
+ true, true, element[GroupElement]))
+ }
+
+ def powOnetimePk: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ thisClass.getMethod("powOnetimePk"),
+ List(),
+ true, true, element[GroupElement]))
+ }
+
+ def powNonce: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("powNonce"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def powDistance: Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("powDistance"),
+ List(),
+ true, true, element[BigInt]))
+ }
+
+ def votes: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("votes"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyHeader(p: Rep[Header]): Header = {
+ if (p.rhs.isInstanceOf[Header@unchecked]) p.rhs.asInstanceOf[Header]
+ else
+ HeaderAdapter(p)
+ }
+
+ // familyElem
+ class HeaderElem[To <: Header]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableHeader.asLiftable[SHeader, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[Header], classOf[SHeader], Set(
+ "id", "version", "parentId", "ADProofsRoot", "stateRoot", "transactionsRoot", "timestamp", "nBits", "height", "extensionRoot", "minerPk", "powOnetimePk", "powNonce", "powDistance", "votes"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[Header].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[Header] => convertHeader(x) }
+ tryConvert(element[Header], this, x, conv)
+ }
+
+ def convertHeader(x: Rep[Header]): Rep[To] = {
+ x.elem match {
+ case _: HeaderElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have HeaderElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val headerElement: Elem[Header] =
+ new HeaderElem[Header]
+
+ implicit case object HeaderCompanionElem extends CompanionElem[HeaderCompanionCtor] {
+ lazy val tag = weakTypeTag[HeaderCompanionCtor]
+ protected def getDefaultRep = RHeader
+ }
+
+ abstract class HeaderCompanionCtor extends CompanionDef[HeaderCompanionCtor] with HeaderCompanion {
+ def selfType = HeaderCompanionElem
+ override def toString = "Header"
+ }
+ implicit def proxyHeaderCompanionCtor(p: Rep[HeaderCompanionCtor]): HeaderCompanionCtor =
+ proxyOps[HeaderCompanionCtor](p)
+
+ lazy val RHeader: Rep[HeaderCompanionCtor] = new HeaderCompanionCtor {
+ private val thisClass = classOf[HeaderCompanion]
+ }
+
+ object HeaderMethods {
+ object id {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "id" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object version {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "version" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object parentId {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "parentId" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object ADProofsRoot {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "ADProofsRoot" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object stateRoot {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "stateRoot" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object transactionsRoot {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "transactionsRoot" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object timestamp {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "timestamp" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object nBits {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "nBits" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object height {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "height" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object extensionRoot {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "extensionRoot" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object minerPk {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "minerPk" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object powOnetimePk {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "powOnetimePk" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object powNonce {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "powNonce" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object powDistance {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "powDistance" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object votes {
+ def unapply(d: Def[_]): Nullable[Rep[Header]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[HeaderElem[_]] && method.getName == "votes" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Header]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Header]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object HeaderCompanionMethods {
+ }
+} // of object Header
+ registerEntityObject("Header", Header)
+
+object Context extends EntityObject("Context") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SContext = special.sigma.Context
+ case class ContextConst(
+ constValue: SContext
+ ) extends Context with LiftedConst[SContext, Context]
+ with Def[Context] with ContextConstMethods {
+ val liftable: Liftable[SContext, Context] = LiftableContext
+ val selfType: Elem[Context] = liftable.eW
+ }
+
+ trait ContextConstMethods extends Context { thisConst: Def[_] =>
+
+ private val ContextClass = classOf[Context]
+
+ override def builder: Rep[SigmaDslBuilder] = {
+ asRep[SigmaDslBuilder](mkMethodCall(self,
+ ContextClass.getMethod("builder"),
+ List(),
+ true, false, element[SigmaDslBuilder]))
+ }
+
+ override def OUTPUTS: Rep[Coll[Box]] = {
+ asRep[Coll[Box]](mkMethodCall(self,
+ ContextClass.getMethod("OUTPUTS"),
+ List(),
+ true, false, element[Coll[Box]]))
+ }
+
+ override def INPUTS: Rep[Coll[Box]] = {
+ asRep[Coll[Box]](mkMethodCall(self,
+ ContextClass.getMethod("INPUTS"),
+ List(),
+ true, false, element[Coll[Box]]))
+ }
+
+ override def dataInputs: Rep[Coll[Box]] = {
+ asRep[Coll[Box]](mkMethodCall(self,
+ ContextClass.getMethod("dataInputs"),
+ List(),
+ true, false, element[Coll[Box]]))
+ }
+
+ override def HEIGHT: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ ContextClass.getMethod("HEIGHT"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def SELF: Rep[Box] = {
+ asRep[Box](mkMethodCall(self,
+ ContextClass.getMethod("SELF"),
+ List(),
+ true, false, element[Box]))
+ }
+
+ override def selfBoxIndex: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ ContextClass.getMethod("selfBoxIndex"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def LastBlockUtxoRootHash: Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(self,
+ ContextClass.getMethod("LastBlockUtxoRootHash"),
+ List(),
+ true, false, element[AvlTree]))
+ }
+
+ override def headers: Rep[Coll[Header]] = {
+ asRep[Coll[Header]](mkMethodCall(self,
+ ContextClass.getMethod("headers"),
+ List(),
+ true, false, element[Coll[Header]]))
+ }
+
+ override def preHeader: Rep[PreHeader] = {
+ asRep[PreHeader](mkMethodCall(self,
+ ContextClass.getMethod("preHeader"),
+ List(),
+ true, false, element[PreHeader]))
+ }
+
+ override def minerPubKey: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ ContextClass.getMethod("minerPubKey"),
+ List(),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def getVar[T](id: Rep[Byte])(implicit cT: Elem[T]): Rep[WOption[T]] = {
+ asRep[WOption[T]](mkMethodCall(self,
+ ContextClass.getMethod("getVar", classOf[Sym], classOf[Elem[_]]),
+ List(id, cT),
+ true, false, element[WOption[T]]))
+ }
+
+ override def vars: Rep[Coll[AnyValue]] = {
+ asRep[Coll[AnyValue]](mkMethodCall(self,
+ ContextClass.getMethod("vars"),
+ List(),
+ true, false, element[Coll[AnyValue]]))
+ }
+ }
+
+ implicit object LiftableContext
+ extends Liftable[SContext, Context] {
+ lazy val eW: Elem[Context] = contextElement
+ lazy val sourceType: RType[SContext] = {
+ RType[SContext]
+ }
+ def lift(x: SContext): Rep[Context] = ContextConst(x)
+ def unlift(w: Rep[Context]): SContext = w match {
+ case Def(ContextConst(x: SContext))
+ => x.asInstanceOf[SContext]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for Context trait
+ case class ContextAdapter(source: Rep[Context])
+ extends Context with Def[Context] {
+ val selfType: Elem[Context] = element[Context]
+ override def transform(t: Transformer) = ContextAdapter(t(source))
+ private val thisClass = classOf[Context]
+
+ def builder: Rep[SigmaDslBuilder] = {
+ asRep[SigmaDslBuilder](mkMethodCall(source,
+ thisClass.getMethod("builder"),
+ List(),
+ true, true, element[SigmaDslBuilder]))
+ }
+
+ def OUTPUTS: Rep[Coll[Box]] = {
+ asRep[Coll[Box]](mkMethodCall(source,
+ thisClass.getMethod("OUTPUTS"),
+ List(),
+ true, true, element[Coll[Box]]))
+ }
+
+ def INPUTS: Rep[Coll[Box]] = {
+ asRep[Coll[Box]](mkMethodCall(source,
+ thisClass.getMethod("INPUTS"),
+ List(),
+ true, true, element[Coll[Box]]))
+ }
+
+ def dataInputs: Rep[Coll[Box]] = {
+ asRep[Coll[Box]](mkMethodCall(source,
+ thisClass.getMethod("dataInputs"),
+ List(),
+ true, true, element[Coll[Box]]))
+ }
+
+ def HEIGHT: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("HEIGHT"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def SELF: Rep[Box] = {
+ asRep[Box](mkMethodCall(source,
+ thisClass.getMethod("SELF"),
+ List(),
+ true, true, element[Box]))
+ }
+
+ def selfBoxIndex: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("selfBoxIndex"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def LastBlockUtxoRootHash: Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(source,
+ thisClass.getMethod("LastBlockUtxoRootHash"),
+ List(),
+ true, true, element[AvlTree]))
+ }
+
+ def headers: Rep[Coll[Header]] = {
+ asRep[Coll[Header]](mkMethodCall(source,
+ thisClass.getMethod("headers"),
+ List(),
+ true, true, element[Coll[Header]]))
+ }
+
+ def preHeader: Rep[PreHeader] = {
+ asRep[PreHeader](mkMethodCall(source,
+ thisClass.getMethod("preHeader"),
+ List(),
+ true, true, element[PreHeader]))
+ }
+
+ def minerPubKey: Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("minerPubKey"),
+ List(),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def getVar[T](id: Rep[Byte])(implicit cT: Elem[T]): Rep[WOption[T]] = {
+ asRep[WOption[T]](mkMethodCall(source,
+ thisClass.getMethod("getVar", classOf[Sym], classOf[Elem[_]]),
+ List(id, cT),
+ true, true, element[WOption[T]]))
+ }
+
+ def vars: Rep[Coll[AnyValue]] = {
+ asRep[Coll[AnyValue]](mkMethodCall(source,
+ thisClass.getMethod("vars"),
+ List(),
+ true, true, element[Coll[AnyValue]]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyContext(p: Rep[Context]): Context = {
+ if (p.rhs.isInstanceOf[Context@unchecked]) p.rhs.asInstanceOf[Context]
+ else
+ ContextAdapter(p)
+ }
+
+ // familyElem
+ class ContextElem[To <: Context]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableContext.asLiftable[SContext, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[Context], classOf[SContext], Set(
+ "builder", "OUTPUTS", "INPUTS", "dataInputs", "HEIGHT", "SELF", "selfBoxIndex", "LastBlockUtxoRootHash", "headers", "preHeader", "minerPubKey", "getVar", "vars"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[Context].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[Context] => convertContext(x) }
+ tryConvert(element[Context], this, x, conv)
+ }
+
+ def convertContext(x: Rep[Context]): Rep[To] = {
+ x.elem match {
+ case _: ContextElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have ContextElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val contextElement: Elem[Context] =
+ new ContextElem[Context]
+
+ implicit case object ContextCompanionElem extends CompanionElem[ContextCompanionCtor] {
+ lazy val tag = weakTypeTag[ContextCompanionCtor]
+ protected def getDefaultRep = RContext
+ }
+
+ abstract class ContextCompanionCtor extends CompanionDef[ContextCompanionCtor] with ContextCompanion {
+ def selfType = ContextCompanionElem
+ override def toString = "Context"
+ }
+ implicit def proxyContextCompanionCtor(p: Rep[ContextCompanionCtor]): ContextCompanionCtor =
+ proxyOps[ContextCompanionCtor](p)
+
+ lazy val RContext: Rep[ContextCompanionCtor] = new ContextCompanionCtor {
+ private val thisClass = classOf[ContextCompanion]
+ }
+
+ object ContextMethods {
+ object builder {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "builder" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object OUTPUTS {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "OUTPUTS" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object INPUTS {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "INPUTS" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object dataInputs {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "dataInputs" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object HEIGHT {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "HEIGHT" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object SELF {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "SELF" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object selfBoxIndex {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "selfBoxIndex" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object LastBlockUtxoRootHash {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "LastBlockUtxoRootHash" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object headers {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "headers" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object preHeader {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "preHeader" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object minerPubKey {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "minerPubKey" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getVar {
+ def unapply(d: Def[_]): Nullable[(Rep[Context], Rep[Byte], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "getVar" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Context], Rep[Byte], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Context], Rep[Byte], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object vars {
+ def unapply(d: Def[_]): Nullable[Rep[Context]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[ContextElem[_]] && method.getName == "vars" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[Context]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Context]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object ContextCompanionMethods {
+ }
+} // of object Context
+ registerEntityObject("Context", Context)
+
+object SigmaContract extends EntityObject("SigmaContract") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SSigmaContract = special.sigma.SigmaContract
+ case class SigmaContractConst(
+ constValue: SSigmaContract
+ ) extends SigmaContract with LiftedConst[SSigmaContract, SigmaContract]
+ with Def[SigmaContract] with SigmaContractConstMethods {
+ val liftable: Liftable[SSigmaContract, SigmaContract] = LiftableSigmaContract
+ val selfType: Elem[SigmaContract] = liftable.eW
+ }
+
+ trait SigmaContractConstMethods extends SigmaContract { thisConst: Def[_] =>
+
+ private val SigmaContractClass = classOf[SigmaContract]
+
+ override def builder: Rep[SigmaDslBuilder] = {
+ asRep[SigmaDslBuilder](mkMethodCall(self,
+ SigmaContractClass.getMethod("builder"),
+ List(),
+ true, false, element[SigmaDslBuilder]))
+ }
+
+ override def Collection[T](items: Rep[T]*)(implicit cT: Elem[T]): Rep[Coll[T]] = {
+ asRep[Coll[T]](mkMethodCall(self,
+ SigmaContractClass.getMethod("Collection", classOf[Seq[_]], classOf[Elem[_]]),
+ List(items, cT),
+ true, false, element[Coll[T]]))
+ }
+
+ override def canOpen(ctx: Rep[Context]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ SigmaContractClass.getMethod("canOpen", classOf[Sym]),
+ List(ctx),
+ true, false, element[Boolean]))
+ }
+ }
+
+ implicit object LiftableSigmaContract
+ extends Liftable[SSigmaContract, SigmaContract] {
+ lazy val eW: Elem[SigmaContract] = sigmaContractElement
+ lazy val sourceType: RType[SSigmaContract] = {
+ RType[SSigmaContract]
+ }
+ def lift(x: SSigmaContract): Rep[SigmaContract] = SigmaContractConst(x)
+ def unlift(w: Rep[SigmaContract]): SSigmaContract = w match {
+ case Def(SigmaContractConst(x: SSigmaContract))
+ => x.asInstanceOf[SSigmaContract]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for SigmaContract trait
+ case class SigmaContractAdapter(source: Rep[SigmaContract])
+ extends SigmaContract with Def[SigmaContract] {
+ val selfType: Elem[SigmaContract] = element[SigmaContract]
+ override def transform(t: Transformer) = SigmaContractAdapter(t(source))
+ private val thisClass = classOf[SigmaContract]
+
+ def builder: Rep[SigmaDslBuilder] = {
+ asRep[SigmaDslBuilder](mkMethodCall(source,
+ thisClass.getMethod("builder"),
+ List(),
+ true, true, element[SigmaDslBuilder]))
+ }
+
+ override def Collection[T](items: Rep[T]*)(implicit cT: Elem[T]): Rep[Coll[T]] = {
+ asRep[Coll[T]](mkMethodCall(source,
+ thisClass.getMethod("Collection", classOf[Seq[_]], classOf[Elem[_]]),
+ List(items, cT),
+ true, true, element[Coll[T]]))
+ }
+
+ def canOpen(ctx: Rep[Context]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("canOpen", classOf[Sym]),
+ List(ctx),
+ true, true, element[Boolean]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySigmaContract(p: Rep[SigmaContract]): SigmaContract = {
+ if (p.rhs.isInstanceOf[SigmaContract@unchecked]) p.rhs.asInstanceOf[SigmaContract]
+ else
+ SigmaContractAdapter(p)
+ }
+
+ // familyElem
+ class SigmaContractElem[To <: SigmaContract]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableSigmaContract.asLiftable[SSigmaContract, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[SigmaContract], classOf[SSigmaContract], Set(
+ "builder", "Collection", "verifyZK", "atLeast", "allOf", "allZK", "anyOf", "anyZK", "xorOf", "PubKey", "sigmaProp", "blake2b256", "sha256", "byteArrayToBigInt", "longToByteArray", "byteArrayToLong", "proveDlog", "proveDHTuple", "groupGenerator", "canOpen", "asFunction"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SigmaContract].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SigmaContract] => convertSigmaContract(x) }
+ tryConvert(element[SigmaContract], this, x, conv)
+ }
+
+ def convertSigmaContract(x: Rep[SigmaContract]): Rep[To] = {
+ x.elem match {
+ case _: SigmaContractElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SigmaContractElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sigmaContractElement: Elem[SigmaContract] =
+ new SigmaContractElem[SigmaContract]
+
+ implicit case object SigmaContractCompanionElem extends CompanionElem[SigmaContractCompanionCtor] {
+ lazy val tag = weakTypeTag[SigmaContractCompanionCtor]
+ protected def getDefaultRep = RSigmaContract
+ }
+
+ abstract class SigmaContractCompanionCtor extends CompanionDef[SigmaContractCompanionCtor] with SigmaContractCompanion {
+ def selfType = SigmaContractCompanionElem
+ override def toString = "SigmaContract"
+ }
+ implicit def proxySigmaContractCompanionCtor(p: Rep[SigmaContractCompanionCtor]): SigmaContractCompanionCtor =
+ proxyOps[SigmaContractCompanionCtor](p)
+
+ lazy val RSigmaContract: Rep[SigmaContractCompanionCtor] = new SigmaContractCompanionCtor {
+ private val thisClass = classOf[SigmaContractCompanion]
+ }
+
+ object SigmaContractMethods {
+ object builder {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaContract]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "builder" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaContract]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaContract]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object Collection {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Seq[Rep[T]], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "Collection" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Seq[Rep[T]], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Seq[Rep[T]], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object verifyZK {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Thunk[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "verifyZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Thunk[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Thunk[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object atLeast {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Int], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "atLeast" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Int], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Int], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object allOf {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "allOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object allZK {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "allZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object anyOf {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "anyOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object anyZK {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "anyZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object xorOf {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "xorOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object PubKey {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[String])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "PubKey" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[String])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[String])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object sigmaProp {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Boolean])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "sigmaProp" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Boolean])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Boolean])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object blake2b256 {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "blake2b256" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object sha256 {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "sha256" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteArrayToBigInt {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "byteArrayToBigInt" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object longToByteArray {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Long])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "longToByteArray" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Long])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Long])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteArrayToLong {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "byteArrayToLong" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object proveDlog {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[GroupElement])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "proveDlog" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[GroupElement])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[GroupElement])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object proveDHTuple {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "proveDHTuple" =>
+ val res = (receiver, args(0), args(1), args(2), args(3))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object groupGenerator {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaContract]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "groupGenerator" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaContract]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaContract]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object canOpen {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaContract], Rep[Context])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "canOpen" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaContract], Rep[Context])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaContract], Rep[Context])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object asFunction {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaContract]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaContractElem[_]] && method.getName == "asFunction" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaContract]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaContract]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SigmaContractCompanionMethods {
+ }
+} // of object SigmaContract
+ registerEntityObject("SigmaContract", SigmaContract)
+
+object SigmaDslBuilder extends EntityObject("SigmaDslBuilder") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+ type SSigmaDslBuilder = special.sigma.SigmaDslBuilder
+ case class SigmaDslBuilderConst(
+ constValue: SSigmaDslBuilder
+ ) extends SigmaDslBuilder with LiftedConst[SSigmaDslBuilder, SigmaDslBuilder]
+ with Def[SigmaDslBuilder] with SigmaDslBuilderConstMethods {
+ val liftable: Liftable[SSigmaDslBuilder, SigmaDslBuilder] = LiftableSigmaDslBuilder
+ val selfType: Elem[SigmaDslBuilder] = liftable.eW
+ }
+
+ trait SigmaDslBuilderConstMethods extends SigmaDslBuilder { thisConst: Def[_] =>
+
+ private val SigmaDslBuilderClass = classOf[SigmaDslBuilder]
+
+ override def Colls: Rep[CollBuilder] = {
+ asRep[CollBuilder](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("Colls"),
+ List(),
+ true, false, element[CollBuilder]))
+ }
+
+ override def Monoids: Rep[MonoidBuilder] = {
+ asRep[MonoidBuilder](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("Monoids"),
+ List(),
+ true, false, element[MonoidBuilder]))
+ }
+
+ override def Costing: Rep[CostedBuilder] = {
+ asRep[CostedBuilder](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("Costing"),
+ List(),
+ true, false, element[CostedBuilder]))
+ }
+
+ override def CostModel: Rep[CostModel] = {
+ asRep[CostModel](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("CostModel"),
+ List(),
+ true, false, element[CostModel]))
+ }
+
+ override def verifyZK(cond: Rep[Thunk[SigmaProp]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("verifyZK", classOf[Sym]),
+ List(cond),
+ true, false, element[Boolean]))
+ }
+
+ override def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("atLeast", classOf[Sym], classOf[Sym]),
+ List(bound, props),
+ true, false, element[SigmaProp]))
+ }
+
+ override def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("allOf", classOf[Sym]),
+ List(conditions),
+ true, false, element[Boolean]))
+ }
+
+ override def allZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("allZK", classOf[Sym]),
+ List(conditions),
+ true, false, element[SigmaProp]))
+ }
+
+ override def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("anyOf", classOf[Sym]),
+ List(conditions),
+ true, false, element[Boolean]))
+ }
+
+ override def anyZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("anyZK", classOf[Sym]),
+ List(conditions),
+ true, false, element[SigmaProp]))
+ }
+
+ override def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("xorOf", classOf[Sym]),
+ List(conditions),
+ true, false, element[Boolean]))
+ }
+
+ override def PubKey(base64String: Rep[String]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("PubKey", classOf[Sym]),
+ List(base64String),
+ true, false, element[SigmaProp]))
+ }
+
+ override def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("sigmaProp", classOf[Sym]),
+ List(b),
+ true, false, element[SigmaProp]))
+ }
+
+ override def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("blake2b256", classOf[Sym]),
+ List(bytes),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("sha256", classOf[Sym]),
+ List(bytes),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("byteArrayToBigInt", classOf[Sym]),
+ List(bytes),
+ true, false, element[BigInt]))
+ }
+
+ override def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("longToByteArray", classOf[Sym]),
+ List(l),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("byteArrayToLong", classOf[Sym]),
+ List(bytes),
+ true, false, element[Long]))
+ }
+
+ override def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("proveDlog", classOf[Sym]),
+ List(g),
+ true, false, element[SigmaProp]))
+ }
+
+ override def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("proveDHTuple", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(g, h, u, v),
+ true, false, element[SigmaProp]))
+ }
+
+ override def groupGenerator: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("groupGenerator"),
+ List(),
+ true, false, element[GroupElement]))
+ }
+
+ override def substConstants[T](scriptBytes: Rep[Coll[Byte]], positions: Rep[Coll[Int]], newValues: Rep[Coll[T]])(implicit cT: Elem[T]): Rep[Coll[Byte]] = {
+ implicit val eT = newValues.eA
+ asRep[Coll[Byte]](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("substConstants", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Elem[_]]),
+ List(scriptBytes, positions, newValues, cT),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def decodePoint(encoded: Rep[Coll[Byte]]): Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("decodePoint", classOf[Sym]),
+ List(encoded),
+ true, false, element[GroupElement]))
+ }
+
+ override def BigInt(n: Rep[WBigInteger]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("BigInt", classOf[Sym]),
+ List(n),
+ true, false, element[BigInt]))
+ }
+
+ override def toBigInteger(n: Rep[BigInt]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("toBigInteger", classOf[Sym]),
+ List(n),
+ true, false, element[WBigInteger]))
+ }
+
+ override def avlTree(operationFlags: Rep[Byte], digest: Rep[Coll[Byte]], keyLength: Rep[Int], valueLengthOpt: Rep[WOption[Int]]): Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(self,
+ SigmaDslBuilderClass.getMethod("avlTree", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(operationFlags, digest, keyLength, valueLengthOpt),
+ true, false, element[AvlTree]))
+ }
+ }
+
+ implicit object LiftableSigmaDslBuilder
+ extends Liftable[SSigmaDslBuilder, SigmaDslBuilder] {
+ lazy val eW: Elem[SigmaDslBuilder] = sigmaDslBuilderElement
+ lazy val sourceType: RType[SSigmaDslBuilder] = {
+ RType[SSigmaDslBuilder]
+ }
+ def lift(x: SSigmaDslBuilder): Rep[SigmaDslBuilder] = SigmaDslBuilderConst(x)
+ def unlift(w: Rep[SigmaDslBuilder]): SSigmaDslBuilder = w match {
+ case Def(SigmaDslBuilderConst(x: SSigmaDslBuilder))
+ => x.asInstanceOf[SSigmaDslBuilder]
+ case _ => unliftError(w)
+ }
+ }
+
+ // entityAdapter for SigmaDslBuilder trait
+ case class SigmaDslBuilderAdapter(source: Rep[SigmaDslBuilder])
+ extends SigmaDslBuilder with Def[SigmaDslBuilder] {
+ val selfType: Elem[SigmaDslBuilder] = element[SigmaDslBuilder]
+ override def transform(t: Transformer) = SigmaDslBuilderAdapter(t(source))
+ private val thisClass = classOf[SigmaDslBuilder]
+
+ def Colls: Rep[CollBuilder] = {
+ asRep[CollBuilder](mkMethodCall(source,
+ thisClass.getMethod("Colls"),
+ List(),
+ true, true, element[CollBuilder]))
+ }
+
+ def Monoids: Rep[MonoidBuilder] = {
+ asRep[MonoidBuilder](mkMethodCall(source,
+ thisClass.getMethod("Monoids"),
+ List(),
+ true, true, element[MonoidBuilder]))
+ }
+
+ def Costing: Rep[CostedBuilder] = {
+ asRep[CostedBuilder](mkMethodCall(source,
+ thisClass.getMethod("Costing"),
+ List(),
+ true, true, element[CostedBuilder]))
+ }
+
+ def CostModel: Rep[CostModel] = {
+ asRep[CostModel](mkMethodCall(source,
+ thisClass.getMethod("CostModel"),
+ List(),
+ true, true, element[CostModel]))
+ }
+
+ def verifyZK(cond: Rep[Thunk[SigmaProp]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("verifyZK", classOf[Sym]),
+ List(cond),
+ true, true, element[Boolean]))
+ }
+
+ def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("atLeast", classOf[Sym], classOf[Sym]),
+ List(bound, props),
+ true, true, element[SigmaProp]))
+ }
+
+ def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("allOf", classOf[Sym]),
+ List(conditions),
+ true, true, element[Boolean]))
+ }
+
+ def allZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("allZK", classOf[Sym]),
+ List(conditions),
+ true, true, element[SigmaProp]))
+ }
+
+ def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("anyOf", classOf[Sym]),
+ List(conditions),
+ true, true, element[Boolean]))
+ }
+
+ def anyZK(conditions: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("anyZK", classOf[Sym]),
+ List(conditions),
+ true, true, element[SigmaProp]))
+ }
+
+ def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("xorOf", classOf[Sym]),
+ List(conditions),
+ true, true, element[Boolean]))
+ }
+
+ def PubKey(base64String: Rep[String]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("PubKey", classOf[Sym]),
+ List(base64String),
+ true, true, element[SigmaProp]))
+ }
+
+ def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("sigmaProp", classOf[Sym]),
+ List(b),
+ true, true, element[SigmaProp]))
+ }
+
+ def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("blake2b256", classOf[Sym]),
+ List(bytes),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("sha256", classOf[Sym]),
+ List(bytes),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("byteArrayToBigInt", classOf[Sym]),
+ List(bytes),
+ true, true, element[BigInt]))
+ }
+
+ def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("longToByteArray", classOf[Sym]),
+ List(l),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("byteArrayToLong", classOf[Sym]),
+ List(bytes),
+ true, true, element[Long]))
+ }
+
+ def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("proveDlog", classOf[Sym]),
+ List(g),
+ true, true, element[SigmaProp]))
+ }
+
+ def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(source,
+ thisClass.getMethod("proveDHTuple", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(g, h, u, v),
+ true, true, element[SigmaProp]))
+ }
+
+ def groupGenerator: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ thisClass.getMethod("groupGenerator"),
+ List(),
+ true, true, element[GroupElement]))
+ }
+
+ def substConstants[T](scriptBytes: Rep[Coll[Byte]], positions: Rep[Coll[Int]], newValues: Rep[Coll[T]])(implicit cT: Elem[T]): Rep[Coll[Byte]] = {
+ implicit val eT = newValues.eA
+ asRep[Coll[Byte]](mkMethodCall(source,
+ thisClass.getMethod("substConstants", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Elem[_]]),
+ List(scriptBytes, positions, newValues, cT),
+ true, true, element[Coll[Byte]]))
+ }
+
+ def decodePoint(encoded: Rep[Coll[Byte]]): Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ thisClass.getMethod("decodePoint", classOf[Sym]),
+ List(encoded),
+ true, true, element[GroupElement]))
+ }
+
+ def BigInt(n: Rep[WBigInteger]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ thisClass.getMethod("BigInt", classOf[Sym]),
+ List(n),
+ true, true, element[BigInt]))
+ }
+
+ def toBigInteger(n: Rep[BigInt]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("toBigInteger", classOf[Sym]),
+ List(n),
+ true, true, element[WBigInteger]))
+ }
+
+ def avlTree(operationFlags: Rep[Byte], digest: Rep[Coll[Byte]], keyLength: Rep[Int], valueLengthOpt: Rep[WOption[Int]]): Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(source,
+ thisClass.getMethod("avlTree", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(operationFlags, digest, keyLength, valueLengthOpt),
+ true, true, element[AvlTree]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySigmaDslBuilder(p: Rep[SigmaDslBuilder]): SigmaDslBuilder = {
+ if (p.rhs.isInstanceOf[SigmaDslBuilder@unchecked]) p.rhs.asInstanceOf[SigmaDslBuilder]
+ else
+ SigmaDslBuilderAdapter(p)
+ }
+
+ // familyElem
+ class SigmaDslBuilderElem[To <: SigmaDslBuilder]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableSigmaDslBuilder.asLiftable[SSigmaDslBuilder, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(classOf[SigmaDslBuilder], classOf[SSigmaDslBuilder], Set(
+ "Colls", "Monoids", "Costing", "CostModel", "verifyZK", "atLeast", "allOf", "allZK", "anyOf", "anyZK", "xorOf", "PubKey", "sigmaProp", "blake2b256", "sha256", "byteArrayToBigInt", "longToByteArray", "byteArrayToLong", "proveDlog", "proveDHTuple", "groupGenerator", "substConstants", "decodePoint", "BigInt", "toBigInteger", "avlTree"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SigmaDslBuilder].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SigmaDslBuilder] => convertSigmaDslBuilder(x) }
+ tryConvert(element[SigmaDslBuilder], this, x, conv)
+ }
+
+ def convertSigmaDslBuilder(x: Rep[SigmaDslBuilder]): Rep[To] = {
+ x.elem match {
+ case _: SigmaDslBuilderElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SigmaDslBuilderElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sigmaDslBuilderElement: Elem[SigmaDslBuilder] =
+ new SigmaDslBuilderElem[SigmaDslBuilder]
+
+ implicit case object SigmaDslBuilderCompanionElem extends CompanionElem[SigmaDslBuilderCompanionCtor] {
+ lazy val tag = weakTypeTag[SigmaDslBuilderCompanionCtor]
+ protected def getDefaultRep = RSigmaDslBuilder
+ }
+
+ abstract class SigmaDslBuilderCompanionCtor extends CompanionDef[SigmaDslBuilderCompanionCtor] with SigmaDslBuilderCompanion {
+ def selfType = SigmaDslBuilderCompanionElem
+ override def toString = "SigmaDslBuilder"
+ }
+ implicit def proxySigmaDslBuilderCompanionCtor(p: Rep[SigmaDslBuilderCompanionCtor]): SigmaDslBuilderCompanionCtor =
+ proxyOps[SigmaDslBuilderCompanionCtor](p)
+
+ lazy val RSigmaDslBuilder: Rep[SigmaDslBuilderCompanionCtor] = new SigmaDslBuilderCompanionCtor {
+ private val thisClass = classOf[SigmaDslBuilderCompanion]
+ }
+
+ object SigmaDslBuilderMethods {
+ object Colls {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "Colls" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object Monoids {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "Monoids" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object Costing {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "Costing" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object CostModel {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "CostModel" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object verifyZK {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Thunk[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "verifyZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Thunk[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Thunk[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object atLeast {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Int], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "atLeast" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Int], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Int], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object allOf {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "allOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object allZK {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "allZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object anyOf {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "anyOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object anyZK {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "anyZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object xorOf {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "xorOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object PubKey {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[String])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "PubKey" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[String])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[String])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object sigmaProp {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Boolean])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "sigmaProp" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Boolean])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Boolean])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object blake2b256 {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "blake2b256" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object sha256 {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "sha256" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteArrayToBigInt {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "byteArrayToBigInt" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object longToByteArray {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Long])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "longToByteArray" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Long])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Long])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteArrayToLong {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "byteArrayToLong" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object proveDlog {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[GroupElement])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "proveDlog" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[GroupElement])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[GroupElement])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object proveDHTuple {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "proveDHTuple" =>
+ val res = (receiver, args(0), args(1), args(2), args(3))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object groupGenerator {
+ def unapply(d: Def[_]): Nullable[Rep[SigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "groupGenerator" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[SigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[SigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object substConstants {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]], Rep[Coll[Int]], Rep[Coll[T]], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "substConstants" =>
+ val res = (receiver, args(0), args(1), args(2), args(3))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]], Rep[Coll[Int]], Rep[Coll[T]], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]], Rep[Coll[Int]], Rep[Coll[T]], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object decodePoint {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "decodePoint" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object BigInt {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "BigInt" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toBigInteger {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "toBigInteger" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object avlTree {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaDslBuilder], Rep[Byte], Rep[Coll[Byte]], Rep[Int], Rep[WOption[Int]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaDslBuilderElem[_]] && method.getName == "avlTree" =>
+ val res = (receiver, args(0), args(1), args(2), args(3))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaDslBuilder], Rep[Byte], Rep[Coll[Byte]], Rep[Int], Rep[WOption[Int]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaDslBuilder], Rep[Byte], Rep[Coll[Byte]], Rep[Int], Rep[WOption[Int]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SigmaDslBuilderCompanionMethods {
+ }
+} // of object SigmaDslBuilder
+ registerEntityObject("SigmaDslBuilder", SigmaDslBuilder)
+
+ registerModule(SigmaDslModule)
+}
+
+object SigmaDslModule extends scalan.ModuleInfo("special.sigma", "SigmaDsl")
+}
+
+trait SigmaDslModule extends special.sigma.impl.SigmaDslDefs {self: SigmaLibrary =>}
diff --git a/sigma-library/src/main/scala/special/sigma/impl/SigmaDslOverArraysImpl.scala b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslOverArraysImpl.scala
new file mode 100644
index 0000000000..e4a9a7aa5b
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslOverArraysImpl.scala
@@ -0,0 +1,685 @@
+package special.sigma
+
+import scalan._
+import scala.reflect.runtime.universe._
+import scala.reflect._
+
+package impl {
+// Abs -----------------------------------
+trait SigmaDslOverArraysDefs extends scalan.Scalan with SigmaDslOverArrays {
+ self: SigmaLibrary =>
+import IsoUR._
+import Converter._
+import AvlTree._
+import BigInt._
+import CCostedBuilder._
+import Coll._
+import CollBuilder._
+import CollOverArrayBuilder._
+import CostModel._
+import CostedBuilder._
+import GroupElement._
+import MonoidBuilder._
+import MonoidBuilderInst._
+import SigmaDslBuilder._
+import SigmaProp._
+import WBigInteger._
+import WECPoint._
+import WOption._
+import TestSigmaDslBuilder._
+
+object TestSigmaDslBuilder extends EntityObject("TestSigmaDslBuilder") {
+ case class TestSigmaDslBuilderCtor
+ ()
+ extends TestSigmaDslBuilder() with Def[TestSigmaDslBuilder] {
+ lazy val selfType = element[TestSigmaDslBuilder]
+ override def transform(t: Transformer) = TestSigmaDslBuilderCtor()
+ private val thisClass = classOf[SigmaDslBuilder]
+
+ override def CostModel: Rep[CostModel] = {
+ asRep[CostModel](mkMethodCall(self,
+ thisClass.getMethod("CostModel"),
+ List(),
+ true, false, element[CostModel]))
+ }
+
+ override def verifyZK(proof: Rep[Thunk[SigmaProp]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ thisClass.getMethod("verifyZK", classOf[Sym]),
+ List(proof),
+ true, false, element[Boolean]))
+ }
+
+ override def atLeast(bound: Rep[Int], props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ thisClass.getMethod("atLeast", classOf[Sym], classOf[Sym]),
+ List(bound, props),
+ true, false, element[SigmaProp]))
+ }
+
+ override def allOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ thisClass.getMethod("allOf", classOf[Sym]),
+ List(conditions),
+ true, false, element[Boolean]))
+ }
+
+ override def anyOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ thisClass.getMethod("anyOf", classOf[Sym]),
+ List(conditions),
+ true, false, element[Boolean]))
+ }
+
+ override def allZK(props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ thisClass.getMethod("allZK", classOf[Sym]),
+ List(props),
+ true, false, element[SigmaProp]))
+ }
+
+ override def anyZK(props: Rep[Coll[SigmaProp]]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ thisClass.getMethod("anyZK", classOf[Sym]),
+ List(props),
+ true, false, element[SigmaProp]))
+ }
+
+ override def xorOf(conditions: Rep[Coll[Boolean]]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ thisClass.getMethod("xorOf", classOf[Sym]),
+ List(conditions),
+ true, false, element[Boolean]))
+ }
+
+ override def sigmaProp(b: Rep[Boolean]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ thisClass.getMethod("sigmaProp", classOf[Sym]),
+ List(b),
+ true, false, element[SigmaProp]))
+ }
+
+ override def blake2b256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ thisClass.getMethod("blake2b256", classOf[Sym]),
+ List(bytes),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def sha256(bytes: Rep[Coll[Byte]]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ thisClass.getMethod("sha256", classOf[Sym]),
+ List(bytes),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def PubKey(base64String: Rep[String]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ thisClass.getMethod("PubKey", classOf[Sym]),
+ List(base64String),
+ true, false, element[SigmaProp]))
+ }
+
+ override def byteArrayToBigInt(bytes: Rep[Coll[Byte]]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ thisClass.getMethod("byteArrayToBigInt", classOf[Sym]),
+ List(bytes),
+ true, false, element[BigInt]))
+ }
+
+ override def longToByteArray(l: Rep[Long]): Rep[Coll[Byte]] = {
+ asRep[Coll[Byte]](mkMethodCall(self,
+ thisClass.getMethod("longToByteArray", classOf[Sym]),
+ List(l),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def byteArrayToLong(bytes: Rep[Coll[Byte]]): Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ thisClass.getMethod("byteArrayToLong", classOf[Sym]),
+ List(bytes),
+ true, false, element[Long]))
+ }
+
+ override def proveDlog(g: Rep[GroupElement]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ thisClass.getMethod("proveDlog", classOf[Sym]),
+ List(g),
+ true, false, element[SigmaProp]))
+ }
+
+ override def proveDHTuple(g: Rep[GroupElement], h: Rep[GroupElement], u: Rep[GroupElement], v: Rep[GroupElement]): Rep[SigmaProp] = {
+ asRep[SigmaProp](mkMethodCall(self,
+ thisClass.getMethod("proveDHTuple", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(g, h, u, v),
+ true, false, element[SigmaProp]))
+ }
+
+ override def groupGenerator: Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ thisClass.getMethod("groupGenerator"),
+ List(),
+ true, false, element[GroupElement]))
+ }
+
+ override def substConstants[T](scriptBytes: Rep[Coll[Byte]], positions: Rep[Coll[Int]], newValues: Rep[Coll[T]])(implicit cT: Elem[T]): Rep[Coll[Byte]] = {
+ implicit val eT = newValues.eA
+ asRep[Coll[Byte]](mkMethodCall(self,
+ thisClass.getMethod("substConstants", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Elem[_]]),
+ List(scriptBytes, positions, newValues, cT),
+ true, false, element[Coll[Byte]]))
+ }
+
+ override def decodePoint(encoded: Rep[Coll[Byte]]): Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ thisClass.getMethod("decodePoint", classOf[Sym]),
+ List(encoded),
+ true, false, element[GroupElement]))
+ }
+
+ override def BigInt(n: Rep[WBigInteger]): Rep[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ thisClass.getMethod("BigInt", classOf[Sym]),
+ List(n),
+ true, false, element[BigInt]))
+ }
+
+ override def toBigInteger(n: Rep[BigInt]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ thisClass.getMethod("toBigInteger", classOf[Sym]),
+ List(n),
+ true, false, element[WBigInteger]))
+ }
+
+ override def GroupElement(p: Rep[WECPoint]): Rep[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ thisClass.getMethod("GroupElement", classOf[Sym]),
+ List(p),
+ true, false, element[GroupElement]))
+ }
+
+ override def toECPoint(ge: Rep[GroupElement]): Rep[WECPoint] = {
+ asRep[WECPoint](mkMethodCall(self,
+ thisClass.getMethod("toECPoint", classOf[Sym]),
+ List(ge),
+ true, false, element[WECPoint]))
+ }
+
+ override def avlTree(operationFlags: Rep[Byte], digest: Rep[Coll[Byte]], keyLength: Rep[Int], valueLengthOpt: Rep[WOption[Int]]): Rep[AvlTree] = {
+ asRep[AvlTree](mkMethodCall(self,
+ thisClass.getMethod("avlTree", classOf[Sym], classOf[Sym], classOf[Sym], classOf[Sym]),
+ List(operationFlags, digest, keyLength, valueLengthOpt),
+ true, false, element[AvlTree]))
+ }
+ }
+ // elem for concrete class
+ class TestSigmaDslBuilderElem(val iso: Iso[TestSigmaDslBuilderData, TestSigmaDslBuilder])
+ extends SigmaDslBuilderElem[TestSigmaDslBuilder]
+ with ConcreteElem[TestSigmaDslBuilderData, TestSigmaDslBuilder] {
+ override lazy val parent: Option[Elem[_]] = Some(sigmaDslBuilderElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override def convertSigmaDslBuilder(x: Rep[SigmaDslBuilder]) = RTestSigmaDslBuilder()
+ override def getDefaultRep = RTestSigmaDslBuilder()
+ override lazy val tag = {
+ weakTypeTag[TestSigmaDslBuilder]
+ }
+ }
+
+ // state representation type
+ type TestSigmaDslBuilderData = Unit
+
+ // 3) Iso for concrete class
+ class TestSigmaDslBuilderIso
+ extends EntityIso[TestSigmaDslBuilderData, TestSigmaDslBuilder] with Def[TestSigmaDslBuilderIso] {
+ override def transform(t: Transformer) = new TestSigmaDslBuilderIso()
+ private lazy val _safeFrom = fun { p: Rep[TestSigmaDslBuilder] => () }
+ override def from(p: Rep[TestSigmaDslBuilder]) =
+ tryConvert[TestSigmaDslBuilder, Unit](eTo, eFrom, p, _safeFrom)
+ override def to(p: Rep[Unit]) = {
+ val unit = p
+ RTestSigmaDslBuilder()
+ }
+ lazy val eFrom = UnitElement
+ lazy val eTo = new TestSigmaDslBuilderElem(self)
+ lazy val selfType = new TestSigmaDslBuilderIsoElem
+ def productArity = 0
+ def productElement(n: Int) = ???
+ }
+ case class TestSigmaDslBuilderIsoElem() extends Elem[TestSigmaDslBuilderIso] {
+ def getDefaultRep = reifyObject(new TestSigmaDslBuilderIso())
+ lazy val tag = {
+ weakTypeTag[TestSigmaDslBuilderIso]
+ }
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ }
+ // 4) constructor and deconstructor
+ class TestSigmaDslBuilderCompanionCtor extends CompanionDef[TestSigmaDslBuilderCompanionCtor] with TestSigmaDslBuilderCompanion {
+ def selfType = TestSigmaDslBuilderCompanionElem
+ override def toString = "TestSigmaDslBuilderCompanion"
+ @scalan.OverloadId("fromData")
+ def apply(p: Rep[TestSigmaDslBuilderData]): Rep[TestSigmaDslBuilder] = {
+ isoTestSigmaDslBuilder.to(p)
+ }
+
+ @scalan.OverloadId("fromFields")
+ def apply(): Rep[TestSigmaDslBuilder] =
+ mkTestSigmaDslBuilder()
+
+ def unapply(p: Rep[SigmaDslBuilder]) = unmkTestSigmaDslBuilder(p)
+ }
+ lazy val TestSigmaDslBuilderRep: Rep[TestSigmaDslBuilderCompanionCtor] = new TestSigmaDslBuilderCompanionCtor
+ lazy val RTestSigmaDslBuilder: TestSigmaDslBuilderCompanionCtor = proxyTestSigmaDslBuilderCompanion(TestSigmaDslBuilderRep)
+ implicit def proxyTestSigmaDslBuilderCompanion(p: Rep[TestSigmaDslBuilderCompanionCtor]): TestSigmaDslBuilderCompanionCtor = {
+ if (p.rhs.isInstanceOf[TestSigmaDslBuilderCompanionCtor])
+ p.rhs.asInstanceOf[TestSigmaDslBuilderCompanionCtor]
+ else
+ proxyOps[TestSigmaDslBuilderCompanionCtor](p)
+ }
+
+ implicit case object TestSigmaDslBuilderCompanionElem extends CompanionElem[TestSigmaDslBuilderCompanionCtor] {
+ lazy val tag = weakTypeTag[TestSigmaDslBuilderCompanionCtor]
+ protected def getDefaultRep = TestSigmaDslBuilderRep
+ }
+
+ implicit def proxyTestSigmaDslBuilder(p: Rep[TestSigmaDslBuilder]): TestSigmaDslBuilder =
+ proxyOps[TestSigmaDslBuilder](p)
+
+ implicit class ExtendedTestSigmaDslBuilder(p: Rep[TestSigmaDslBuilder]) {
+ def toData: Rep[TestSigmaDslBuilderData] = {
+ isoTestSigmaDslBuilder.from(p)
+ }
+ }
+
+ // 5) implicit resolution of Iso
+ implicit def isoTestSigmaDslBuilder: Iso[TestSigmaDslBuilderData, TestSigmaDslBuilder] =
+ reifyObject(new TestSigmaDslBuilderIso())
+
+ def mkTestSigmaDslBuilder
+ (): Rep[TestSigmaDslBuilder] = {
+ new TestSigmaDslBuilderCtor()
+ }
+ def unmkTestSigmaDslBuilder(p: Rep[SigmaDslBuilder]) = p.elem.asInstanceOf[Elem[_]] match {
+ case _: TestSigmaDslBuilderElem @unchecked =>
+ Some(())
+ case _ =>
+ None
+ }
+
+ object TestSigmaDslBuilderMethods {
+ object Colls {
+ def unapply(d: Def[_]): Nullable[Rep[TestSigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "Colls" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[TestSigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[TestSigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object Monoids {
+ def unapply(d: Def[_]): Nullable[Rep[TestSigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "Monoids" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[TestSigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[TestSigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object Costing {
+ def unapply(d: Def[_]): Nullable[Rep[TestSigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "Costing" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[TestSigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[TestSigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object CostModel {
+ def unapply(d: Def[_]): Nullable[Rep[TestSigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "CostModel" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[TestSigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[TestSigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object verifyZK {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Thunk[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "verifyZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Thunk[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Thunk[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object atLeast {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Int], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "atLeast" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Int], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Int], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object allOf {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "allOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object anyOf {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "anyOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object allZK {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "allZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object anyZK {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[SigmaProp]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "anyZK" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[SigmaProp]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[SigmaProp]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object xorOf {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "xorOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Boolean]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object sigmaProp {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Boolean])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "sigmaProp" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Boolean])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Boolean])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object blake2b256 {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "blake2b256" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object sha256 {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "sha256" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object PubKey {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[String])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "PubKey" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[String])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[String])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteArrayToBigInt {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "byteArrayToBigInt" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object longToByteArray {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Long])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "longToByteArray" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Long])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Long])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteArrayToLong {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "byteArrayToLong" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object proveDlog {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "proveDlog" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object proveDHTuple {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "proveDHTuple" =>
+ val res = (receiver, args(0), args(1), args(2), args(3))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement], Rep[GroupElement])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object groupGenerator {
+ def unapply(d: Def[_]): Nullable[Rep[TestSigmaDslBuilder]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "groupGenerator" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[TestSigmaDslBuilder]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[TestSigmaDslBuilder]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object substConstants {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]], Rep[Coll[Int]], Rep[Coll[T]], Elem[T]) forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "substConstants" =>
+ val res = (receiver, args(0), args(1), args(2), args(3))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]], Rep[Coll[Int]], Rep[Coll[T]], Elem[T]) forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]], Rep[Coll[Int]], Rep[Coll[T]], Elem[T]) forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object decodePoint {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "decodePoint" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Coll[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object BigInt {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "BigInt" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toBigInteger {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[BigInt])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "toBigInteger" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[BigInt])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[BigInt])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object GroupElement {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[WECPoint])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "GroupElement" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[WECPoint])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[WECPoint])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toECPoint {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "toECPoint" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[GroupElement])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object avlTree {
+ def unapply(d: Def[_]): Nullable[(Rep[TestSigmaDslBuilder], Rep[Byte], Rep[Coll[Byte]], Rep[Int], Rep[WOption[Int]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[TestSigmaDslBuilderElem] && method.getName == "avlTree" =>
+ val res = (receiver, args(0), args(1), args(2), args(3))
+ Nullable(res).asInstanceOf[Nullable[(Rep[TestSigmaDslBuilder], Rep[Byte], Rep[Coll[Byte]], Rep[Int], Rep[WOption[Int]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[TestSigmaDslBuilder], Rep[Byte], Rep[Coll[Byte]], Rep[Int], Rep[WOption[Int]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object TestSigmaDslBuilderCompanionMethods {
+ }
+} // of object TestSigmaDslBuilder
+ registerEntityObject("TestSigmaDslBuilder", TestSigmaDslBuilder)
+
+ registerModule(SigmaDslOverArraysModule)
+}
+
+object SigmaDslOverArraysModule extends scalan.ModuleInfo("special.sigma", "SigmaDslOverArrays")
+}
+
+trait SigmaDslOverArraysModule extends special.sigma.impl.SigmaDslOverArraysDefs {self: SigmaLibrary =>}
diff --git a/sigma-library/src/main/scala/special/sigma/wrappers/WrappersModule.scala b/sigma-library/src/main/scala/special/sigma/wrappers/WrappersModule.scala
new file mode 100644
index 0000000000..6d57a4ea32
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/wrappers/WrappersModule.scala
@@ -0,0 +1,11 @@
+package special.sigma.wrappers
+
+import wrappers.java.math.WBigIntegersModule
+import wrappers.org.bouncycastle.math.ec.WECPointsModule
+import wrappers.special.sigma.WSigmaPredefsModule
+
+trait WrappersModule
+ extends special.wrappers.WrappersModule
+ with WSigmaPredefsModule
+ with WECPointsModule
+ with WBigIntegersModule
diff --git a/sigma-library/src/main/scala/special/sigma/wrappers/WrappersSpec.scala b/sigma-library/src/main/scala/special/sigma/wrappers/WrappersSpec.scala
new file mode 100644
index 0000000000..a456948701
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/wrappers/WrappersSpec.scala
@@ -0,0 +1,67 @@
+package special.sigma.wrappers {
+ import scalan._
+
+ trait WrappersSpec extends Base { self: SigmaLibrary =>
+ import WArray._;
+ import WBigInteger._;
+ import WECPoint._;
+ import WSigmaPredef._;
+ import WrapSpecBase._;
+ trait ECPointWrapSpec extends WrapSpecBase {
+ def getEncoded[A](g: Rep[WECPoint], compressed: Rep[Boolean]): Rep[WArray[Byte]] = g.getEncoded(compressed);
+ def multiply(l: Rep[WECPoint], r: Rep[WBigInteger]): Rep[WECPoint] = l.multiply(r);
+ def add(l: Rep[WECPoint], r: Rep[WECPoint]): Rep[WECPoint] = l.add(r)
+ };
+ trait BigIntegerWrapSpec extends WrapSpecBase {
+ def fromString(s: Rep[String]): Rep[WBigInteger] = RWBigInteger(s);
+ def fromArray(sig: Rep[Int], arr: Rep[WArray[Byte]]): Rep[WBigInteger] = RWBigInteger(sig, arr);
+ def valueOf(l: Rep[Long]): Rep[WBigInteger] = RWBigInteger.valueOf(l);
+ def toByteArray(l: Rep[WBigInteger]): Rep[WArray[Byte]] = l.toByteArray;
+ def add(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.add(r);
+ def subtract(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.subtract(r);
+ def multiply(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.multiply(r);
+ def mod(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.mod(r);
+ def modInverse(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.modInverse(r);
+ def modPow(l: Rep[WBigInteger], exponent: Rep[WBigInteger], m: Rep[WBigInteger]): Rep[WBigInteger] = l.modPow(exponent, m);
+ def remainder(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.remainder(r);
+ def divide(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.divide(r);
+ def compareTo(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[Int] = l.compareTo(r);
+ def min(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.min(r);
+ def max(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.max(r);
+ def gcd(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.gcd(r);
+ def and(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.and(r);
+ def or(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.or(r);
+ def xor(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.xor(r);
+ def not(l: Rep[WBigInteger]): Rep[WBigInteger] = l.not;
+ def andNot(l: Rep[WBigInteger], r: Rep[WBigInteger]): Rep[WBigInteger] = l.andNot(r);
+ def pow(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.pow(r);
+ def testBit(l: Rep[WBigInteger], r: Rep[Int]): Rep[Boolean] = l.testBit(r);
+ def setBit(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.setBit(r);
+ def clearBit(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.clearBit(r);
+ def flipBit(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.flipBit(r);
+ def getLowestSetBit(l: Rep[WBigInteger]): Rep[Int] = l.getLowestSetBit;
+ def bitCount(l: Rep[WBigInteger]): Rep[Int] = l.bitCount;
+ def bitLength(l: Rep[WBigInteger]): Rep[Int] = l.bitLength;
+ def isProbablePrime(l: Rep[WBigInteger], r: Rep[Int]): Rep[Boolean] = l.isProbablePrime(r);
+ def shiftLeft(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.shiftLeft(r);
+ def shiftRight(l: Rep[WBigInteger], r: Rep[Int]): Rep[WBigInteger] = l.shiftRight(r);
+ def abs(l: Rep[WBigInteger]): Rep[WBigInteger] = l.abs;
+ def negate(l: Rep[WBigInteger]): Rep[WBigInteger] = l.negate;
+ def signum(l: Rep[WBigInteger]): Rep[Int] = l.signum;
+ def byteValue(l: Rep[WBigInteger]): Rep[Byte] = l.byteValue;
+ def shortValue(l: Rep[WBigInteger]): Rep[Short] = l.shortValue;
+ def intValue(l: Rep[WBigInteger]): Rep[Int] = l.intValue;
+ def longValue(l: Rep[WBigInteger]): Rep[Long] = l.longValue;
+ def byteValueExact(l: Rep[WBigInteger]): Rep[Byte] = l.byteValueExact;
+ def shortValueExact(l: Rep[WBigInteger]): Rep[Short] = l.shortValueExact;
+ def intValueExact(l: Rep[WBigInteger]): Rep[Int] = l.intValueExact;
+ def longValueExact(l: Rep[WBigInteger]): Rep[Long] = l.longValueExact
+ };
+ trait SigmaPredefWrapSpec extends WrapSpecBase {
+ def dataSize(v: Rep[Any]): Rep[Long] = RWSigmaPredef.dataSize[Any](v)
+ };
+ trait ECPointWrapSpecCompanion;
+ trait BigIntegerWrapSpecCompanion;
+ trait SigmaPredefWrapSpecCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-library/src/main/scala/special/sigma/wrappers/impl/WrappersSpecImpl.scala b/sigma-library/src/main/scala/special/sigma/wrappers/impl/WrappersSpecImpl.scala
new file mode 100644
index 0000000000..f22878117c
--- /dev/null
+++ b/sigma-library/src/main/scala/special/sigma/wrappers/impl/WrappersSpecImpl.scala
@@ -0,0 +1,828 @@
+package special.sigma.wrappers
+
+import scalan._
+import scala.reflect.runtime.universe._
+import scala.reflect._
+
+package impl {
+// Abs -----------------------------------
+trait WrappersSpecDefs extends scalan.Scalan with WrappersSpec {
+ self: SigmaLibrary =>
+import IsoUR._
+import Converter._
+import WArray._
+import WBigInteger._
+import WECPoint._
+import WSigmaPredef._
+import WrapSpecBase._
+import BigIntegerWrapSpec._
+import ECPointWrapSpec._
+import SigmaPredefWrapSpec._
+
+object ECPointWrapSpec extends EntityObject("ECPointWrapSpec") {
+ // entityAdapter for ECPointWrapSpec trait
+ case class ECPointWrapSpecAdapter(source: Rep[ECPointWrapSpec])
+ extends ECPointWrapSpec with Def[ECPointWrapSpec] {
+ val selfType: Elem[ECPointWrapSpec] = element[ECPointWrapSpec]
+ override def transform(t: Transformer) = ECPointWrapSpecAdapter(t(source))
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyECPointWrapSpec(p: Rep[ECPointWrapSpec]): ECPointWrapSpec = {
+ if (p.rhs.isInstanceOf[ECPointWrapSpec@unchecked]) p.rhs.asInstanceOf[ECPointWrapSpec]
+ else
+ ECPointWrapSpecAdapter(p)
+ }
+
+ // familyElem
+ class ECPointWrapSpecElem[To <: ECPointWrapSpec]
+ extends WrapSpecBaseElem[To] {
+ override lazy val parent: Option[Elem[_]] = Some(wrapSpecBaseElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[ECPointWrapSpec].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[ECPointWrapSpec] => convertECPointWrapSpec(x) }
+ tryConvert(element[ECPointWrapSpec], this, x, conv)
+ }
+
+ def convertECPointWrapSpec(x: Rep[ECPointWrapSpec]): Rep[To] = {
+ x.elem match {
+ case _: ECPointWrapSpecElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have ECPointWrapSpecElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val eCPointWrapSpecElement: Elem[ECPointWrapSpec] =
+ new ECPointWrapSpecElem[ECPointWrapSpec]
+
+ implicit case object ECPointWrapSpecCompanionElem extends CompanionElem[ECPointWrapSpecCompanionCtor] {
+ lazy val tag = weakTypeTag[ECPointWrapSpecCompanionCtor]
+ protected def getDefaultRep = RECPointWrapSpec
+ }
+
+ abstract class ECPointWrapSpecCompanionCtor extends CompanionDef[ECPointWrapSpecCompanionCtor] with ECPointWrapSpecCompanion {
+ def selfType = ECPointWrapSpecCompanionElem
+ override def toString = "ECPointWrapSpec"
+ }
+ implicit def proxyECPointWrapSpecCompanionCtor(p: Rep[ECPointWrapSpecCompanionCtor]): ECPointWrapSpecCompanionCtor =
+ proxyOps[ECPointWrapSpecCompanionCtor](p)
+
+ lazy val RECPointWrapSpec: Rep[ECPointWrapSpecCompanionCtor] = new ECPointWrapSpecCompanionCtor {
+ private val thisClass = classOf[ECPointWrapSpecCompanion]
+ }
+
+ object ECPointWrapSpecMethods {
+ object getEncoded {
+ def unapply(d: Def[_]): Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[Boolean], Elem[A]) forSome {type A}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[ECPointWrapSpecElem[_]] && method.getName == "getEncoded" =>
+ val res = (receiver, args(0), args(1), args(2))
+ Nullable(res).asInstanceOf[Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[Boolean], Elem[A]) forSome {type A}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[Boolean], Elem[A]) forSome {type A}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object multiply {
+ def unapply(d: Def[_]): Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[ECPointWrapSpecElem[_]] && method.getName == "multiply" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object add {
+ def unapply(d: Def[_]): Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[WECPoint])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[ECPointWrapSpecElem[_]] && method.getName == "add" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[WECPoint])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[ECPointWrapSpec], Rep[WECPoint], Rep[WECPoint])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object ECPointWrapSpecCompanionMethods {
+ }
+} // of object ECPointWrapSpec
+ registerEntityObject("ECPointWrapSpec", ECPointWrapSpec)
+
+object BigIntegerWrapSpec extends EntityObject("BigIntegerWrapSpec") {
+ // entityAdapter for BigIntegerWrapSpec trait
+ case class BigIntegerWrapSpecAdapter(source: Rep[BigIntegerWrapSpec])
+ extends BigIntegerWrapSpec with Def[BigIntegerWrapSpec] {
+ val selfType: Elem[BigIntegerWrapSpec] = element[BigIntegerWrapSpec]
+ override def transform(t: Transformer) = BigIntegerWrapSpecAdapter(t(source))
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyBigIntegerWrapSpec(p: Rep[BigIntegerWrapSpec]): BigIntegerWrapSpec = {
+ if (p.rhs.isInstanceOf[BigIntegerWrapSpec@unchecked]) p.rhs.asInstanceOf[BigIntegerWrapSpec]
+ else
+ BigIntegerWrapSpecAdapter(p)
+ }
+
+ // familyElem
+ class BigIntegerWrapSpecElem[To <: BigIntegerWrapSpec]
+ extends WrapSpecBaseElem[To] {
+ override lazy val parent: Option[Elem[_]] = Some(wrapSpecBaseElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[BigIntegerWrapSpec].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[BigIntegerWrapSpec] => convertBigIntegerWrapSpec(x) }
+ tryConvert(element[BigIntegerWrapSpec], this, x, conv)
+ }
+
+ def convertBigIntegerWrapSpec(x: Rep[BigIntegerWrapSpec]): Rep[To] = {
+ x.elem match {
+ case _: BigIntegerWrapSpecElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have BigIntegerWrapSpecElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val bigIntegerWrapSpecElement: Elem[BigIntegerWrapSpec] =
+ new BigIntegerWrapSpecElem[BigIntegerWrapSpec]
+
+ implicit case object BigIntegerWrapSpecCompanionElem extends CompanionElem[BigIntegerWrapSpecCompanionCtor] {
+ lazy val tag = weakTypeTag[BigIntegerWrapSpecCompanionCtor]
+ protected def getDefaultRep = RBigIntegerWrapSpec
+ }
+
+ abstract class BigIntegerWrapSpecCompanionCtor extends CompanionDef[BigIntegerWrapSpecCompanionCtor] with BigIntegerWrapSpecCompanion {
+ def selfType = BigIntegerWrapSpecCompanionElem
+ override def toString = "BigIntegerWrapSpec"
+ }
+ implicit def proxyBigIntegerWrapSpecCompanionCtor(p: Rep[BigIntegerWrapSpecCompanionCtor]): BigIntegerWrapSpecCompanionCtor =
+ proxyOps[BigIntegerWrapSpecCompanionCtor](p)
+
+ lazy val RBigIntegerWrapSpec: Rep[BigIntegerWrapSpecCompanionCtor] = new BigIntegerWrapSpecCompanionCtor {
+ private val thisClass = classOf[BigIntegerWrapSpecCompanion]
+ }
+
+ object BigIntegerWrapSpecMethods {
+ object fromString {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[String])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "fromString" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[String])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[String])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object fromArray {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[Int], Rep[WArray[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "fromArray" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[Int], Rep[WArray[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[Int], Rep[WArray[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object valueOf {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[Long])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "valueOf" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[Long])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[Long])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toByteArray {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "toByteArray" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object add {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "add" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object subtract {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "subtract" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object multiply {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "multiply" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object mod {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "mod" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object modInverse {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "modInverse" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object modPow {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "modPow" =>
+ val res = (receiver, args(0), args(1), args(2))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object remainder {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "remainder" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object divide {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "divide" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object compareTo {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "compareTo" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object min {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "min" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object max {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "max" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object gcd {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "gcd" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object and {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "and" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object or {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "or" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object xor {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "xor" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object not {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "not" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object andNot {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "andNot" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object pow {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "pow" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object testBit {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "testBit" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object setBit {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "setBit" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object clearBit {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "clearBit" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object flipBit {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "flipBit" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getLowestSetBit {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "getLowestSetBit" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object bitCount {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "bitCount" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object bitLength {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "bitLength" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object isProbablePrime {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "isProbablePrime" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object shiftLeft {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "shiftLeft" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object shiftRight {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "shiftRight" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object abs {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "abs" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object negate {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "negate" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object signum {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "signum" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteValue {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "byteValue" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object shortValue {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "shortValue" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object intValue {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "intValue" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object longValue {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "longValue" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteValueExact {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "byteValueExact" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object shortValueExact {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "shortValueExact" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object intValueExact {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "intValueExact" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object longValueExact {
+ def unapply(d: Def[_]): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[BigIntegerWrapSpecElem[_]] && method.getName == "longValueExact" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[BigIntegerWrapSpec], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object BigIntegerWrapSpecCompanionMethods {
+ }
+} // of object BigIntegerWrapSpec
+ registerEntityObject("BigIntegerWrapSpec", BigIntegerWrapSpec)
+
+object SigmaPredefWrapSpec extends EntityObject("SigmaPredefWrapSpec") {
+ // entityAdapter for SigmaPredefWrapSpec trait
+ case class SigmaPredefWrapSpecAdapter(source: Rep[SigmaPredefWrapSpec])
+ extends SigmaPredefWrapSpec with Def[SigmaPredefWrapSpec] {
+ val selfType: Elem[SigmaPredefWrapSpec] = element[SigmaPredefWrapSpec]
+ override def transform(t: Transformer) = SigmaPredefWrapSpecAdapter(t(source))
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxySigmaPredefWrapSpec(p: Rep[SigmaPredefWrapSpec]): SigmaPredefWrapSpec = {
+ if (p.rhs.isInstanceOf[SigmaPredefWrapSpec@unchecked]) p.rhs.asInstanceOf[SigmaPredefWrapSpec]
+ else
+ SigmaPredefWrapSpecAdapter(p)
+ }
+
+ // familyElem
+ class SigmaPredefWrapSpecElem[To <: SigmaPredefWrapSpec]
+ extends WrapSpecBaseElem[To] {
+ override lazy val parent: Option[Elem[_]] = Some(wrapSpecBaseElement)
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[SigmaPredefWrapSpec].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[SigmaPredefWrapSpec] => convertSigmaPredefWrapSpec(x) }
+ tryConvert(element[SigmaPredefWrapSpec], this, x, conv)
+ }
+
+ def convertSigmaPredefWrapSpec(x: Rep[SigmaPredefWrapSpec]): Rep[To] = {
+ x.elem match {
+ case _: SigmaPredefWrapSpecElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have SigmaPredefWrapSpecElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val sigmaPredefWrapSpecElement: Elem[SigmaPredefWrapSpec] =
+ new SigmaPredefWrapSpecElem[SigmaPredefWrapSpec]
+
+ implicit case object SigmaPredefWrapSpecCompanionElem extends CompanionElem[SigmaPredefWrapSpecCompanionCtor] {
+ lazy val tag = weakTypeTag[SigmaPredefWrapSpecCompanionCtor]
+ protected def getDefaultRep = RSigmaPredefWrapSpec
+ }
+
+ abstract class SigmaPredefWrapSpecCompanionCtor extends CompanionDef[SigmaPredefWrapSpecCompanionCtor] with SigmaPredefWrapSpecCompanion {
+ def selfType = SigmaPredefWrapSpecCompanionElem
+ override def toString = "SigmaPredefWrapSpec"
+ }
+ implicit def proxySigmaPredefWrapSpecCompanionCtor(p: Rep[SigmaPredefWrapSpecCompanionCtor]): SigmaPredefWrapSpecCompanionCtor =
+ proxyOps[SigmaPredefWrapSpecCompanionCtor](p)
+
+ lazy val RSigmaPredefWrapSpec: Rep[SigmaPredefWrapSpecCompanionCtor] = new SigmaPredefWrapSpecCompanionCtor {
+ private val thisClass = classOf[SigmaPredefWrapSpecCompanion]
+ }
+
+ object SigmaPredefWrapSpecMethods {
+ object dataSize {
+ def unapply(d: Def[_]): Nullable[(Rep[SigmaPredefWrapSpec], Rep[Any])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[SigmaPredefWrapSpecElem[_]] && method.getName == "dataSize" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[SigmaPredefWrapSpec], Rep[Any])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[SigmaPredefWrapSpec], Rep[Any])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object SigmaPredefWrapSpecCompanionMethods {
+ }
+} // of object SigmaPredefWrapSpec
+ registerEntityObject("SigmaPredefWrapSpec", SigmaPredefWrapSpec)
+
+ registerModule(WrappersSpecModule)
+}
+
+object WrappersSpecModule extends scalan.ModuleInfo("special.sigma.wrappers", "WrappersSpec")
+}
+
+trait WrappersSpecModule extends special.sigma.wrappers.impl.WrappersSpecDefs {self: SigmaLibrary =>}
diff --git a/sigma-library/src/main/scala/wrappers/java/math/WBigIntegers.scala b/sigma-library/src/main/scala/wrappers/java/math/WBigIntegers.scala
new file mode 100644
index 0000000000..5c17b70661
--- /dev/null
+++ b/sigma-library/src/main/scala/wrappers/java/math/WBigIntegers.scala
@@ -0,0 +1,61 @@
+package wrappers.java.math {
+ import scalan._
+
+ import impl._
+
+ import special.sigma.wrappers.WrappersModule
+
+ import special.sigma.wrappers.BigIntegerWrapSpec
+
+ trait WBigIntegers extends Base { self: WrappersModule =>
+ import WArray._;
+ import WBigInteger._;
+ @External("BigInteger") @Liftable trait WBigInteger extends Def[WBigInteger] {
+ @External def longValueExact: Rep[Long];
+ @External def intValueExact: Rep[Int];
+ @External def shortValueExact: Rep[Short];
+ @External def byteValueExact: Rep[Byte];
+ @External def longValue: Rep[Long];
+ @External def intValue: Rep[Int];
+ @External def shortValue: Rep[Short];
+ @External def byteValue: Rep[Byte];
+ @External def signum: Rep[Int];
+ @External def negate: Rep[WBigInteger];
+ @External def abs: Rep[WBigInteger];
+ @External def shiftRight(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def shiftLeft(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def isProbablePrime(x$1: Rep[Int]): Rep[Boolean];
+ @External def bitLength: Rep[Int];
+ @External def bitCount: Rep[Int];
+ @External def getLowestSetBit: Rep[Int];
+ @External def flipBit(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def clearBit(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def setBit(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def testBit(x$1: Rep[Int]): Rep[Boolean];
+ @External def pow(x$1: Rep[Int]): Rep[WBigInteger];
+ @External def andNot(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def not: Rep[WBigInteger];
+ @External def xor(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def or(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def and(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def gcd(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def max(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def min(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def compareTo(x$1: Rep[WBigInteger]): Rep[Int];
+ @External def divide(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def remainder(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def modPow(x$1: Rep[WBigInteger], x$2: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def modInverse(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def mod(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def multiply(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def subtract(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def add(x$1: Rep[WBigInteger]): Rep[WBigInteger];
+ @External def toByteArray: Rep[WArray[Byte]]
+ };
+ trait WBigIntegerCompanion {
+ @Constructor @OverloadId(value = "constructor_1") def apply(x$1: Rep[Int], x$2: Rep[WArray[Byte]]): Rep[WBigInteger];
+ @Constructor @OverloadId(value = "constructor_2") def apply(x$1: Rep[String]): Rep[WBigInteger];
+ @External def valueOf(x$1: Rep[Long]): Rep[WBigInteger]
+ }
+ }
+}
\ No newline at end of file
diff --git a/sigma-library/src/main/scala/wrappers/java/math/impl/WBigIntegersImpl.scala b/sigma-library/src/main/scala/wrappers/java/math/impl/WBigIntegersImpl.scala
new file mode 100644
index 0000000000..f157b166fc
--- /dev/null
+++ b/sigma-library/src/main/scala/wrappers/java/math/impl/WBigIntegersImpl.scala
@@ -0,0 +1,1265 @@
+package wrappers.java.math
+
+import scalan._
+import impl._
+import special.sigma.wrappers.WrappersModule
+import special.sigma.wrappers.BigIntegerWrapSpec
+import scala.reflect.runtime.universe._
+import scala.reflect._
+import java.lang.reflect.Method // manual fix
+import java.math.BigInteger // manual fix
+import org.bouncycastle.math.ec.ECPoint // manual fix
+
+package impl {
+// Abs -----------------------------------
+trait WBigIntegersDefs extends scalan.Scalan with WBigIntegers {
+ self: WrappersModule =>
+import special.sigma._ // manual fix
+import IsoUR._
+import Converter._
+import WArray._
+import WBigInteger._
+
+object WBigInteger extends EntityObject("WBigInteger") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+
+ case class WBigIntegerConst(
+ constValue: BigInteger
+ ) extends WBigInteger with LiftedConst[BigInteger, WBigInteger]
+ with Def[WBigInteger] with WBigIntegerConstMethods {
+ val liftable: Liftable[BigInteger, WBigInteger] = LiftableBigInteger
+ val selfType: Elem[WBigInteger] = liftable.eW
+ }
+
+ trait WBigIntegerConstMethods extends WBigInteger { thisConst: Def[_] =>
+
+ private val WBigIntegerClass = classOf[WBigInteger]
+
+ override def longValueExact: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ WBigIntegerClass.getMethod("longValueExact"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def intValueExact: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ WBigIntegerClass.getMethod("intValueExact"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def shortValueExact: Rep[Short] = {
+ asRep[Short](mkMethodCall(self,
+ WBigIntegerClass.getMethod("shortValueExact"),
+ List(),
+ true, false, element[Short]))
+ }
+
+ override def byteValueExact: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(self,
+ WBigIntegerClass.getMethod("byteValueExact"),
+ List(),
+ true, false, element[Byte]))
+ }
+
+ override def longValue: Rep[Long] = {
+ asRep[Long](mkMethodCall(self,
+ WBigIntegerClass.getMethod("longValue"),
+ List(),
+ true, false, element[Long]))
+ }
+
+ override def intValue: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ WBigIntegerClass.getMethod("intValue"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def shortValue: Rep[Short] = {
+ asRep[Short](mkMethodCall(self,
+ WBigIntegerClass.getMethod("shortValue"),
+ List(),
+ true, false, element[Short]))
+ }
+
+ override def byteValue: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(self,
+ WBigIntegerClass.getMethod("byteValue"),
+ List(),
+ true, false, element[Byte]))
+ }
+
+ override def signum: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ WBigIntegerClass.getMethod("signum"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def negate: Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("negate"),
+ List(),
+ true, false, element[WBigInteger]))
+ }
+
+ override def abs: Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("abs"),
+ List(),
+ true, false, element[WBigInteger]))
+ }
+
+ override def shiftRight(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("shiftRight", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def shiftLeft(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("shiftLeft", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def isProbablePrime(x$1: Rep[Int]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ WBigIntegerClass.getMethod("isProbablePrime", classOf[Sym]),
+ List(x$1),
+ true, false, element[Boolean]))
+ }
+
+ override def bitLength: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ WBigIntegerClass.getMethod("bitLength"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def bitCount: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ WBigIntegerClass.getMethod("bitCount"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def getLowestSetBit: Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ WBigIntegerClass.getMethod("getLowestSetBit"),
+ List(),
+ true, false, element[Int]))
+ }
+
+ override def flipBit(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("flipBit", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def clearBit(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("clearBit", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def setBit(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("setBit", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def testBit(x$1: Rep[Int]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(self,
+ WBigIntegerClass.getMethod("testBit", classOf[Sym]),
+ List(x$1),
+ true, false, element[Boolean]))
+ }
+
+ override def pow(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("pow", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def andNot(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("andNot", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def not: Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("not"),
+ List(),
+ true, false, element[WBigInteger]))
+ }
+
+ override def xor(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("xor", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def or(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("or", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def and(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("and", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def gcd(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("gcd", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def max(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("max", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def min(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("min", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def compareTo(x$1: Rep[WBigInteger]): Rep[Int] = {
+ asRep[Int](mkMethodCall(self,
+ WBigIntegerClass.getMethod("compareTo", classOf[Sym]),
+ List(x$1),
+ true, false, element[Int]))
+ }
+
+ override def divide(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("divide", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def remainder(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("remainder", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def modPow(x$1: Rep[WBigInteger], x$2: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("modPow", classOf[Sym], classOf[Sym]),
+ List(x$1, x$2),
+ true, false, element[WBigInteger]))
+ }
+
+ override def modInverse(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("modInverse", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def mod(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("mod", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def multiply(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("multiply", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def subtract(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("subtract", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def add(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ WBigIntegerClass.getMethod("add", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+
+ override def toByteArray: Rep[WArray[Byte]] = {
+ asRep[WArray[Byte]](mkMethodCall(self,
+ WBigIntegerClass.getMethod("toByteArray"),
+ List(),
+ true, false, element[WArray[Byte]]))
+ }
+ }
+
+ implicit object LiftableBigInteger
+ extends Liftable[BigInteger, WBigInteger] {
+ lazy val eW: Elem[WBigInteger] = wBigIntegerElement
+ lazy val sourceType: RType[BigInteger] = {
+ RType[BigInteger]
+ }
+ def lift(x: BigInteger): Rep[WBigInteger] = WBigIntegerConst(x)
+ def unlift(w: Rep[WBigInteger]): BigInteger = w match {
+ case Def(WBigIntegerConst(x: BigInteger))
+ => x.asInstanceOf[BigInteger]
+ case _ => unliftError(w)
+ }
+ }
+
+ private val _BigIntegerWrapSpec = new BigIntegerWrapSpec {}
+ // entityAdapter for WBigInteger trait
+ case class WBigIntegerAdapter(source: Rep[WBigInteger])
+ extends WBigInteger with Def[WBigInteger] {
+ val selfType: Elem[WBigInteger] = element[WBigInteger]
+ override def transform(t: Transformer) = WBigIntegerAdapter(t(source))
+ private val thisClass = classOf[WBigInteger]
+
+ def longValueExact: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("longValueExact"),
+ List(),
+ true, true, element[Long]))
+ }
+
+ def intValueExact: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("intValueExact"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def shortValueExact: Rep[Short] = {
+ asRep[Short](mkMethodCall(source,
+ thisClass.getMethod("shortValueExact"),
+ List(),
+ true, true, element[Short]))
+ }
+
+ def byteValueExact: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(source,
+ thisClass.getMethod("byteValueExact"),
+ List(),
+ true, true, element[Byte]))
+ }
+
+ def longValue: Rep[Long] = {
+ asRep[Long](mkMethodCall(source,
+ thisClass.getMethod("longValue"),
+ List(),
+ true, true, element[Long]))
+ }
+
+ def intValue: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("intValue"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def shortValue: Rep[Short] = {
+ asRep[Short](mkMethodCall(source,
+ thisClass.getMethod("shortValue"),
+ List(),
+ true, true, element[Short]))
+ }
+
+ def byteValue: Rep[Byte] = {
+ asRep[Byte](mkMethodCall(source,
+ thisClass.getMethod("byteValue"),
+ List(),
+ true, true, element[Byte]))
+ }
+
+ def signum: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("signum"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def negate: Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("negate"),
+ List(),
+ true, true, element[WBigInteger]))
+ }
+
+ def abs: Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("abs"),
+ List(),
+ true, true, element[WBigInteger]))
+ }
+
+ def shiftRight(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("shiftRight", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def shiftLeft(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("shiftLeft", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def isProbablePrime(x$1: Rep[Int]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("isProbablePrime", classOf[Sym]),
+ List(x$1),
+ true, true, element[Boolean]))
+ }
+
+ def bitLength: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("bitLength"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def bitCount: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("bitCount"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def getLowestSetBit: Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("getLowestSetBit"),
+ List(),
+ true, true, element[Int]))
+ }
+
+ def flipBit(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("flipBit", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def clearBit(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("clearBit", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def setBit(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("setBit", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def testBit(x$1: Rep[Int]): Rep[Boolean] = {
+ asRep[Boolean](mkMethodCall(source,
+ thisClass.getMethod("testBit", classOf[Sym]),
+ List(x$1),
+ true, true, element[Boolean]))
+ }
+
+ def pow(x$1: Rep[Int]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("pow", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def andNot(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("andNot", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def not: Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("not"),
+ List(),
+ true, true, element[WBigInteger]))
+ }
+
+ def xor(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("xor", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def or(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("or", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def and(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("and", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def gcd(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("gcd", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def max(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("max", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def min(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("min", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def compareTo(x$1: Rep[WBigInteger]): Rep[Int] = {
+ asRep[Int](mkMethodCall(source,
+ thisClass.getMethod("compareTo", classOf[Sym]),
+ List(x$1),
+ true, true, element[Int]))
+ }
+
+ def divide(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("divide", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def remainder(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("remainder", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def modPow(x$1: Rep[WBigInteger], x$2: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("modPow", classOf[Sym], classOf[Sym]),
+ List(x$1, x$2),
+ true, true, element[WBigInteger]))
+ }
+
+ def modInverse(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("modInverse", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def mod(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("mod", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def multiply(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("multiply", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def subtract(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("subtract", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def add(x$1: Rep[WBigInteger]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(source,
+ thisClass.getMethod("add", classOf[Sym]),
+ List(x$1),
+ true, true, element[WBigInteger]))
+ }
+
+ def toByteArray: Rep[WArray[Byte]] = {
+ asRep[WArray[Byte]](mkMethodCall(source,
+ thisClass.getMethod("toByteArray"),
+ List(),
+ true, true, element[WArray[Byte]]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyWBigInteger(p: Rep[WBigInteger]): WBigInteger = {
+ if (p.rhs.isInstanceOf[WBigInteger@unchecked]) p.rhs.asInstanceOf[WBigInteger]
+ else
+ WBigIntegerAdapter(p)
+ }
+
+ // familyElem
+ class WBigIntegerElem[To <: WBigInteger]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableBigInteger.asLiftable[BigInteger, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredWrapperMethods(_BigIntegerWrapSpec, classOf[WBigInteger], Set(
+ "longValueExact", "intValueExact", "shortValueExact", "byteValueExact", "longValue", "intValue", "shortValue", "byteValue", "signum", "negate", "abs", "shiftRight", "shiftLeft", "isProbablePrime", "bitLength", "bitCount", "getLowestSetBit", "flipBit", "clearBit", "setBit", "testBit", "pow", "andNot", "not", "xor", "or", "and", "gcd", "max", "min", "compareTo", "divide", "remainder", "modPow", "modInverse", "mod", "multiply", "subtract", "add", "toByteArray"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[WBigInteger].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[WBigInteger] => convertWBigInteger(x) }
+ tryConvert(element[WBigInteger], this, x, conv)
+ }
+
+ def convertWBigInteger(x: Rep[WBigInteger]): Rep[To] = {
+ x.elem match {
+ case _: WBigIntegerElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have WBigIntegerElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val wBigIntegerElement: Elem[WBigInteger] =
+ new WBigIntegerElem[WBigInteger]
+
+ implicit case object WBigIntegerCompanionElem extends CompanionElem[WBigIntegerCompanionCtor] {
+ lazy val tag = weakTypeTag[WBigIntegerCompanionCtor]
+ protected def getDefaultRep = RWBigInteger
+ }
+
+ abstract class WBigIntegerCompanionCtor extends CompanionDef[WBigIntegerCompanionCtor] with WBigIntegerCompanion {
+ def selfType = WBigIntegerCompanionElem
+ override def toString = "WBigInteger"
+ }
+ implicit def proxyWBigIntegerCompanionCtor(p: Rep[WBigIntegerCompanionCtor]): WBigIntegerCompanionCtor =
+ proxyOps[WBigIntegerCompanionCtor](p)
+
+ lazy val RWBigInteger: Rep[WBigIntegerCompanionCtor] = new WBigIntegerCompanionCtor {
+ private val thisClass = classOf[WBigIntegerCompanion]
+
+ def apply(x$1: Rep[Int], x$2: Rep[WArray[Byte]]): Rep[WBigInteger] =
+ newObjEx[WBigInteger](x$1, x$2)
+
+ def apply(x$1: Rep[String]): Rep[WBigInteger] =
+ newObjEx[WBigInteger](x$1)
+
+ def valueOf(x$1: Rep[Long]): Rep[WBigInteger] = {
+ asRep[WBigInteger](mkMethodCall(self,
+ thisClass.getMethod("valueOf", classOf[Sym]),
+ List(x$1),
+ true, false, element[WBigInteger]))
+ }
+ }
+
+ object WBigIntegerMethods {
+ object longValueExact {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "longValueExact" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object intValueExact {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "intValueExact" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object shortValueExact {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "shortValueExact" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteValueExact {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "byteValueExact" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object longValue {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "longValue" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object intValue {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "intValue" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object shortValue {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "shortValue" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object byteValue {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "byteValue" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object signum {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "signum" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object negate {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "negate" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object abs {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "abs" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object shiftRight {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "shiftRight" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object shiftLeft {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "shiftLeft" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object isProbablePrime {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "isProbablePrime" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object bitLength {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "bitLength" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object bitCount {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "bitCount" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getLowestSetBit {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "getLowestSetBit" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object flipBit {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "flipBit" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object clearBit {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "clearBit" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object setBit {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "setBit" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object testBit {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "testBit" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object pow {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[Int])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "pow" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[Int])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[Int])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object andNot {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "andNot" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object not {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "not" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object xor {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "xor" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object or {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "or" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object and {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "and" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object gcd {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "gcd" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object max {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "max" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object min {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "min" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object compareTo {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "compareTo" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object divide {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "divide" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object remainder {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "remainder" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object modPow {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "modPow" =>
+ val res = (receiver, args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object modInverse {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "modInverse" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object mod {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "mod" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object multiply {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "multiply" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object subtract {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "subtract" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object add {
+ def unapply(d: Def[_]): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "add" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WBigInteger], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WBigInteger], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object toByteArray {
+ def unapply(d: Def[_]): Nullable[Rep[WBigInteger]] = d match {
+ case MethodCall(receiver, method, _, _) if receiver.elem.isInstanceOf[WBigIntegerElem[_]] && method.getName == "toByteArray" =>
+ val res = receiver
+ Nullable(res).asInstanceOf[Nullable[Rep[WBigInteger]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[WBigInteger]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object WBigIntegerCompanionMethods {
+ object apply_constructor_1 {
+ def unapply(d: Def[_]): Nullable[(Rep[Int], Rep[WArray[Byte]])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem == WBigIntegerCompanionElem && method.getName == "apply" && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "constructor_1" } =>
+ val res = (args(0), args(1))
+ Nullable(res).asInstanceOf[Nullable[(Rep[Int], Rep[WArray[Byte]])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[Int], Rep[WArray[Byte]])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object apply_constructor_2 {
+ def unapply(d: Def[_]): Nullable[Rep[String]] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem == WBigIntegerCompanionElem && method.getName == "apply" && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "constructor_2" } =>
+ val res = args(0)
+ Nullable(res).asInstanceOf[Nullable[Rep[String]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[String]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object valueOf {
+ def unapply(d: Def[_]): Nullable[Rep[Long]] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem == WBigIntegerCompanionElem && method.getName == "valueOf" =>
+ val res = args(0)
+ Nullable(res).asInstanceOf[Nullable[Rep[Long]]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[Long]] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+} // of object WBigInteger
+ registerEntityObject("WBigInteger", WBigInteger)
+
+ registerModule(WBigIntegersModule)
+}
+
+object WBigIntegersModule extends scalan.ModuleInfo("wrappers.java.math", "WBigIntegers")
+}
+
+trait WBigIntegersModule extends wrappers.java.math.impl.WBigIntegersDefs {self: WrappersModule =>}
diff --git a/sigma-library/src/main/scala/wrappers/org/bouncycastle/math/ec/WECPoints.scala b/sigma-library/src/main/scala/wrappers/org/bouncycastle/math/ec/WECPoints.scala
new file mode 100644
index 0000000000..d7e022f173
--- /dev/null
+++ b/sigma-library/src/main/scala/wrappers/org/bouncycastle/math/ec/WECPoints.scala
@@ -0,0 +1,21 @@
+package wrappers.org.bouncycastle.math.ec {
+ import scalan._
+
+ import impl._
+
+ import special.sigma.wrappers.WrappersModule
+
+ import special.sigma.wrappers.ECPointWrapSpec
+
+ trait WECPoints extends Base { self: WrappersModule =>
+ import WArray._;
+ import WBigInteger._;
+ import WECPoint._;
+ @External("ECPoint") @Liftable trait WECPoint extends Def[WECPoint] {
+ @External def add(x$1: Rep[WECPoint]): Rep[WECPoint];
+ @External def multiply(x$1: Rep[WBigInteger]): Rep[WECPoint];
+ @External def getEncoded(x$1: Rep[Boolean]): Rep[WArray[Byte]]
+ };
+ trait WECPointCompanion
+ }
+}
\ No newline at end of file
diff --git a/sigma-library/src/main/scala/wrappers/org/bouncycastle/math/ec/impl/WECPointsImpl.scala b/sigma-library/src/main/scala/wrappers/org/bouncycastle/math/ec/impl/WECPointsImpl.scala
new file mode 100644
index 0000000000..c760b8ed37
--- /dev/null
+++ b/sigma-library/src/main/scala/wrappers/org/bouncycastle/math/ec/impl/WECPointsImpl.scala
@@ -0,0 +1,217 @@
+package wrappers.org.bouncycastle.math.ec
+
+import scalan._
+import impl._
+import special.sigma.wrappers.WrappersModule
+import special.sigma.wrappers.ECPointWrapSpec
+import java.lang.reflect.Method // manual fix
+import java.math.BigInteger // manual fix
+
+import org.bouncycastle.math.ec.ECPoint // manual fix
+import scala.reflect.runtime.universe._
+import scala.reflect._
+
+package impl {
+// Abs -----------------------------------
+trait WECPointsDefs extends scalan.Scalan with WECPoints {
+ self: WrappersModule =>
+ import special.sigma._ // manual fix
+import IsoUR._
+import Converter._
+import WArray._
+import WBigInteger._
+import WECPoint._
+
+object WECPoint extends EntityObject("WECPoint") {
+ // entityConst: single const for each entity
+ import Liftables._
+ import scala.reflect.{ClassTag, classTag}
+
+ case class WECPointConst(
+ constValue: ECPoint
+ ) extends WECPoint with LiftedConst[ECPoint, WECPoint]
+ with Def[WECPoint] with WECPointConstMethods {
+ val liftable: Liftable[ECPoint, WECPoint] = LiftableECPoint
+ val selfType: Elem[WECPoint] = liftable.eW
+ }
+
+ trait WECPointConstMethods extends WECPoint { thisConst: Def[_] =>
+
+ private val WECPointClass = classOf[WECPoint]
+
+ override def add(x$1: Rep[WECPoint]): Rep[WECPoint] = {
+ asRep[WECPoint](mkMethodCall(self,
+ WECPointClass.getMethod("add", classOf[Sym]),
+ List(x$1),
+ true, false, element[WECPoint]))
+ }
+
+ override def multiply(x$1: Rep[WBigInteger]): Rep[WECPoint] = {
+ asRep[WECPoint](mkMethodCall(self,
+ WECPointClass.getMethod("multiply", classOf[Sym]),
+ List(x$1),
+ true, false, element[WECPoint]))
+ }
+
+ override def getEncoded(x$1: Rep[Boolean]): Rep[WArray[Byte]] = {
+ asRep[WArray[Byte]](mkMethodCall(self,
+ WECPointClass.getMethod("getEncoded", classOf[Sym]),
+ List(x$1),
+ true, false, element[WArray[Byte]]))
+ }
+ }
+
+ implicit object LiftableECPoint
+ extends Liftable[ECPoint, WECPoint] {
+ lazy val eW: Elem[WECPoint] = wECPointElement
+ lazy val sourceType: RType[ECPoint] = {
+ RType[ECPoint]
+ }
+ def lift(x: ECPoint): Rep[WECPoint] = WECPointConst(x)
+ def unlift(w: Rep[WECPoint]): ECPoint = w match {
+ case Def(WECPointConst(x: ECPoint))
+ => x.asInstanceOf[ECPoint]
+ case _ => unliftError(w)
+ }
+ }
+
+ private val _ECPointWrapSpec = new ECPointWrapSpec {}
+ // entityAdapter for WECPoint trait
+ case class WECPointAdapter(source: Rep[WECPoint])
+ extends WECPoint with Def[WECPoint] {
+ val selfType: Elem[WECPoint] = element[WECPoint]
+ override def transform(t: Transformer) = WECPointAdapter(t(source))
+ private val thisClass = classOf[WECPoint]
+
+ def add(x$1: Rep[WECPoint]): Rep[WECPoint] = {
+ asRep[WECPoint](mkMethodCall(source,
+ thisClass.getMethod("add", classOf[Sym]),
+ List(x$1),
+ true, true, element[WECPoint]))
+ }
+
+ def multiply(x$1: Rep[WBigInteger]): Rep[WECPoint] = {
+ asRep[WECPoint](mkMethodCall(source,
+ thisClass.getMethod("multiply", classOf[Sym]),
+ List(x$1),
+ true, true, element[WECPoint]))
+ }
+
+ def getEncoded(x$1: Rep[Boolean]): Rep[WArray[Byte]] = {
+ asRep[WArray[Byte]](mkMethodCall(source,
+ thisClass.getMethod("getEncoded", classOf[Sym]),
+ List(x$1),
+ true, true, element[WArray[Byte]]))
+ }
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyWECPoint(p: Rep[WECPoint]): WECPoint = {
+ if (p.rhs.isInstanceOf[WECPoint@unchecked]) p.rhs.asInstanceOf[WECPoint]
+ else
+ WECPointAdapter(p)
+ }
+
+ // familyElem
+ class WECPointElem[To <: WECPoint]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = LiftableECPoint.asLiftable[ECPoint, To]
+
+ override protected def collectMethods: Map[java.lang.reflect.Method, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredWrapperMethods(_ECPointWrapSpec, classOf[WECPoint], Set(
+ "add", "multiply", "getEncoded"
+ ))
+ }
+
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[WECPoint].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[WECPoint] => convertWECPoint(x) }
+ tryConvert(element[WECPoint], this, x, conv)
+ }
+
+ def convertWECPoint(x: Rep[WECPoint]): Rep[To] = {
+ x.elem match {
+ case _: WECPointElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have WECPointElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val wECPointElement: Elem[WECPoint] =
+ new WECPointElem[WECPoint]
+
+ implicit case object WECPointCompanionElem extends CompanionElem[WECPointCompanionCtor] {
+ lazy val tag = weakTypeTag[WECPointCompanionCtor]
+ protected def getDefaultRep = RWECPoint
+ }
+
+ abstract class WECPointCompanionCtor extends CompanionDef[WECPointCompanionCtor] with WECPointCompanion {
+ def selfType = WECPointCompanionElem
+ override def toString = "WECPoint"
+ }
+ implicit def proxyWECPointCompanionCtor(p: Rep[WECPointCompanionCtor]): WECPointCompanionCtor =
+ proxyOps[WECPointCompanionCtor](p)
+
+ lazy val RWECPoint: Rep[WECPointCompanionCtor] = new WECPointCompanionCtor {
+ private val thisClass = classOf[WECPointCompanion]
+ }
+
+ object WECPointMethods {
+ object add {
+ def unapply(d: Def[_]): Nullable[(Rep[WECPoint], Rep[WECPoint])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WECPointElem[_]] && method.getName == "add" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WECPoint], Rep[WECPoint])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WECPoint], Rep[WECPoint])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object multiply {
+ def unapply(d: Def[_]): Nullable[(Rep[WECPoint], Rep[WBigInteger])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WECPointElem[_]] && method.getName == "multiply" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WECPoint], Rep[WBigInteger])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WECPoint], Rep[WBigInteger])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+
+ object getEncoded {
+ def unapply(d: Def[_]): Nullable[(Rep[WECPoint], Rep[Boolean])] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem.isInstanceOf[WECPointElem[_]] && method.getName == "getEncoded" =>
+ val res = (receiver, args(0))
+ Nullable(res).asInstanceOf[Nullable[(Rep[WECPoint], Rep[Boolean])]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[(Rep[WECPoint], Rep[Boolean])] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+
+ object WECPointCompanionMethods {
+ }
+} // of object WECPoint
+ registerEntityObject("WECPoint", WECPoint)
+
+ registerModule(WECPointsModule)
+}
+
+object WECPointsModule extends scalan.ModuleInfo("wrappers.org.bouncycastle.math.ec", "WECPoints")
+}
+
+trait WECPointsModule extends wrappers.org.bouncycastle.math.ec.impl.WECPointsDefs {self: WrappersModule =>}
diff --git a/sigma-library/src/main/scala/wrappers/special/sigma/WSigmaPredefs.scala b/sigma-library/src/main/scala/wrappers/special/sigma/WSigmaPredefs.scala
new file mode 100644
index 0000000000..e93616d340
--- /dev/null
+++ b/sigma-library/src/main/scala/wrappers/special/sigma/WSigmaPredefs.scala
@@ -0,0 +1,17 @@
+package wrappers.special.sigma {
+ import scalan._
+
+ import impl._
+
+ import special.sigma.wrappers.WrappersModule
+
+ import special.sigma.wrappers.SigmaPredefWrapSpec
+
+ trait WSigmaPredefs extends Base { self: WrappersModule =>
+ import WSigmaPredef._;
+ @External("SigmaPredef") trait WSigmaPredef extends Def[WSigmaPredef];
+ trait WSigmaPredefCompanion {
+ @External def dataSize[T](v: Rep[T]): Rep[Long]
+ }
+ }
+}
\ No newline at end of file
diff --git a/sigma-library/src/main/scala/wrappers/special/sigma/impl/WSigmaPredefsImpl.scala b/sigma-library/src/main/scala/wrappers/special/sigma/impl/WSigmaPredefsImpl.scala
new file mode 100644
index 0000000000..884f33142c
--- /dev/null
+++ b/sigma-library/src/main/scala/wrappers/special/sigma/impl/WSigmaPredefsImpl.scala
@@ -0,0 +1,108 @@
+package wrappers.special.sigma
+
+import scalan._
+import impl._
+import special.sigma.wrappers.WrappersModule
+import special.sigma.wrappers.SigmaPredefWrapSpec
+import scala.reflect.runtime.universe._
+import scala.reflect._
+
+package impl {
+// Abs -----------------------------------
+trait WSigmaPredefsDefs extends scalan.Scalan with WSigmaPredefs {
+ self: WrappersModule =>
+import IsoUR._
+import Converter._
+import WSigmaPredef._
+
+object WSigmaPredef extends EntityObject("WSigmaPredef") {
+ // entityAdapter for WSigmaPredef trait
+ case class WSigmaPredefAdapter(source: Rep[WSigmaPredef])
+ extends WSigmaPredef with Def[WSigmaPredef] {
+ val selfType: Elem[WSigmaPredef] = element[WSigmaPredef]
+ override def transform(t: Transformer) = WSigmaPredefAdapter(t(source))
+ }
+
+ // entityProxy: single proxy for each type family
+ implicit def proxyWSigmaPredef(p: Rep[WSigmaPredef]): WSigmaPredef = {
+ if (p.rhs.isInstanceOf[WSigmaPredef@unchecked]) p.rhs.asInstanceOf[WSigmaPredef]
+ else
+ WSigmaPredefAdapter(p)
+ }
+
+ // familyElem
+ class WSigmaPredefElem[To <: WSigmaPredef]
+ extends EntityElem[To] {
+ lazy val parent: Option[Elem[_]] = None
+ override def buildTypeArgs = super.buildTypeArgs ++ TypeArgs()
+ override lazy val tag = {
+ weakTypeTag[WSigmaPredef].asInstanceOf[WeakTypeTag[To]]
+ }
+ override def convert(x: Rep[Def[_]]) = {
+ val conv = fun {x: Rep[WSigmaPredef] => convertWSigmaPredef(x) }
+ tryConvert(element[WSigmaPredef], this, x, conv)
+ }
+
+ def convertWSigmaPredef(x: Rep[WSigmaPredef]): Rep[To] = {
+ x.elem match {
+ case _: WSigmaPredefElem[_] => asRep[To](x)
+ case e => !!!(s"Expected $x to have WSigmaPredefElem[_], but got $e", x)
+ }
+ }
+ override def getDefaultRep: Rep[To] = ???
+ }
+
+ implicit lazy val wSigmaPredefElement: Elem[WSigmaPredef] =
+ new WSigmaPredefElem[WSigmaPredef]
+
+ implicit case object WSigmaPredefCompanionElem extends CompanionElem[WSigmaPredefCompanionCtor] {
+ lazy val tag = weakTypeTag[WSigmaPredefCompanionCtor]
+ protected def getDefaultRep = RWSigmaPredef
+ }
+
+ abstract class WSigmaPredefCompanionCtor extends CompanionDef[WSigmaPredefCompanionCtor] with WSigmaPredefCompanion {
+ def selfType = WSigmaPredefCompanionElem
+ override def toString = "WSigmaPredef"
+ }
+ implicit def proxyWSigmaPredefCompanionCtor(p: Rep[WSigmaPredefCompanionCtor]): WSigmaPredefCompanionCtor =
+ proxyOps[WSigmaPredefCompanionCtor](p)
+
+ lazy val RWSigmaPredef: Rep[WSigmaPredefCompanionCtor] = new WSigmaPredefCompanionCtor {
+ private val thisClass = classOf[WSigmaPredefCompanion]
+
+ def dataSize[T](v: Rep[T]): Rep[Long] = {
+ implicit val eT = v.elem
+ asRep[Long](mkMethodCall(self,
+ thisClass.getMethod("dataSize", classOf[Sym]),
+ List(v),
+ true, false, element[Long]))
+ }
+ }
+
+ object WSigmaPredefMethods {
+ }
+
+ object WSigmaPredefCompanionMethods {
+ object dataSize {
+ def unapply(d: Def[_]): Nullable[Rep[T] forSome {type T}] = d match {
+ case MethodCall(receiver, method, args, _) if receiver.elem == WSigmaPredefCompanionElem && method.getName == "dataSize" =>
+ val res = args(0)
+ Nullable(res).asInstanceOf[Nullable[Rep[T] forSome {type T}]]
+ case _ => Nullable.None
+ }
+ def unapply(exp: Sym): Nullable[Rep[T] forSome {type T}] = exp match {
+ case Def(d) => unapply(d)
+ case _ => Nullable.None
+ }
+ }
+ }
+} // of object WSigmaPredef
+ registerEntityObject("WSigmaPredef", WSigmaPredef)
+
+ registerModule(WSigmaPredefsModule)
+}
+
+object WSigmaPredefsModule extends scalan.ModuleInfo("wrappers.special.sigma", "WSigmaPredefs")
+}
+
+trait WSigmaPredefsModule extends wrappers.special.sigma.impl.WSigmaPredefsDefs {self: WrappersModule =>}
diff --git a/sigma-library/src/test/scala/scalan/SigmaLibraryTests.scala b/sigma-library/src/test/scala/scalan/SigmaLibraryTests.scala
new file mode 100644
index 0000000000..94bb25a1c9
--- /dev/null
+++ b/sigma-library/src/test/scala/scalan/SigmaLibraryTests.scala
@@ -0,0 +1,27 @@
+package scalan
+
+//private class TestSigmaLibrary extends SigmaLibrary {
+// import TestSigmaDslBuilder._
+// import CollOverArrayBuilder._
+// import CCostedBuilder._
+// import CostedBuilder._
+// import MonoidBuilder._
+//
+// lazy val colBuilder: Rep[CollBuilder] = RCollOverArrayBuilder()
+// lazy val costedBuilder: Rep[CostedBuilder] = RCCostedBuilder()
+// lazy val intPlusMonoid: Rep[Monoid[Int]] = costedBuilder.monoidBuilder.intPlusMonoid
+// lazy val longPlusMonoid: Rep[Monoid[Long]] = costedBuilder.monoidBuilder.longPlusMonoid
+// lazy val sigmaDslBuilder = RTestSigmaDslBuilder()
+//}
+//
+//class SigmaLibraryTests extends BaseCtxTests {
+//
+// test("Benchmark SigmaLibrary creation time") {
+// new Benchmark(new TestSigmaLibrary).run()
+// }
+//}
+//
+//object MeasureSigmaLibraryCreate extends App {
+// new Benchmark(new TestSigmaLibrary).run()
+//}
+
diff --git a/sigma-library/src/test/scala/special/sigma/wrappers/WBigIntegerTests.scala b/sigma-library/src/test/scala/special/sigma/wrappers/WBigIntegerTests.scala
new file mode 100644
index 0000000000..e125a0bf57
--- /dev/null
+++ b/sigma-library/src/test/scala/special/sigma/wrappers/WBigIntegerTests.scala
@@ -0,0 +1,25 @@
+package special.sigma.wrappers
+
+import java.math.BigInteger
+import special.wrappers.WrappersTests
+import scala.collection.mutable
+import scala.language.reflectiveCalls
+
+class WBigIntegerTests extends WrappersTests {
+ class Ctx extends WrappersCtx with WrappersModule {
+ }
+
+ test("invokeUnlifted") {
+ val ctx = new Ctx
+ import ctx._
+ import Liftables._
+ import WBigInteger._
+ import EnvRep._
+
+ val obj = BigInteger.valueOf(10L)
+
+ check(obj, { env: EnvRep[WBigInteger] =>
+ for { xs <- env; one <- lifted(BigInteger.ONE) } yield xs.add(one) }, obj.add(BigInteger.ONE))
+ check(obj, { env: EnvRep[WBigInteger] => for { xs <- env } yield xs.multiply(xs) }, obj.multiply(obj))
+ }
+}
diff --git a/sigma-library/src/test/scala/special/sigma/wrappers/WECPointTests.scala b/sigma-library/src/test/scala/special/sigma/wrappers/WECPointTests.scala
new file mode 100644
index 0000000000..3324246e72
--- /dev/null
+++ b/sigma-library/src/test/scala/special/sigma/wrappers/WECPointTests.scala
@@ -0,0 +1,27 @@
+package special.sigma.wrappers
+
+import java.math.BigInteger
+
+import org.bouncycastle.crypto.ec.CustomNamedCurves
+import special.wrappers.WrappersTests
+import scala.language.reflectiveCalls
+
+class WECPointTests extends WrappersTests {
+ class Ctx extends WrappersCtx with WrappersModule {
+ }
+
+ test("invokeUnlifted") {
+ val ctx = new Ctx
+ import ctx._
+ import WECPoint._
+ import WBigInteger._
+ import Liftables._
+ import EnvRep._
+
+ val obj = CustomNamedCurves.getByName("secp256k1").getG
+ val ten = BigInteger.valueOf(10L)
+ check(obj, { env: EnvRep[WECPoint] => for { xs <- env } yield xs.add(xs) }, obj.add(obj))
+ check(obj, { env: EnvRep[WECPoint] => for { xs <- env; tenL <- lifted(ten) } yield xs.multiply(tenL) }, obj.multiply(ten))
+ check(obj, { env: EnvRep[WECPoint] => for { xs <- env; arg <- lifted(true) } yield xs.getEncoded(arg) }, obj.getEncoded(true))
+ }
+}
diff --git a/src/main/scala/org/ergoplatform/ErgoAddress.scala b/src/main/scala/org/ergoplatform/ErgoAddress.scala
index be1ede37d5..54a2bc1166 100644
--- a/src/main/scala/org/ergoplatform/ErgoAddress.scala
+++ b/src/main/scala/org/ergoplatform/ErgoAddress.scala
@@ -3,12 +3,13 @@ package org.ergoplatform
import java.util
import com.google.common.primitives.Ints
-import sigmastate.basics.DLogProtocol.ProveDlog
-import scorex.crypto.hash.{Blake2b256, Digest32}
+import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
+import scorex.crypto.hash.{Digest32, Blake2b256}
import scorex.util.encode.Base58
-import sigmastate.Values.{ConcreteCollection, ConstantNode, IntConstant, Value, GetVarByteArray}
+import sigmastate.Values._
import sigmastate._
-import sigmastate.serialization.{ErgoTreeSerializer, ValueSerializer}
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.serialization._
import sigmastate.utxo.{DeserializeContext, Slice}
import scala.util.Try
@@ -38,7 +39,7 @@ import scala.util.Try
* For an address type, we form content bytes as follows:
*
* P2PK - serialized (compressed) public key
- * P2sH - 192 bit of the script
+ * P2SH - first 192 bits of the Blake2b256 hash of serialized script bytes
* P2S - serialized script
*
* Address examples for testnet:
@@ -67,7 +68,7 @@ sealed trait ErgoAddress {
val contentBytes: Array[Byte]
- val script: Value[SBoolean.type]
+ val script: ErgoTree
}
class P2PKAddress(val pubkey: ProveDlog,
@@ -78,7 +79,11 @@ class P2PKAddress(val pubkey: ProveDlog,
override val contentBytes: Array[Byte] = pubkeyBytes
- override val script: ProveDlog = pubkey
+ override val script: ErgoTree = {
+ // NOTE: we don't segregate constants because the whole tree is single constant
+ // and we want different addreses of this type to have different `script` values
+ ErgoTree(ErgoTree.DefaultHeader, IndexedSeq.empty, SigmaPropConstant(pubkey))
+ }
override def equals(obj: Any): Boolean = obj match {
case p2pk: P2PKAddress => util.Arrays.equals(pubkeyBytes, p2pk.pubkeyBytes)
@@ -94,7 +99,7 @@ object P2PKAddress {
val addressTypePrefix: Byte = 1: Byte
def apply(pubkey: ProveDlog)(implicit encoder: ErgoAddressEncoder): P2PKAddress = {
- val bs = ValueSerializer.serialize(pubkey)
+ val bs = GroupElementSerializer.toBytes(pubkey.h)
new P2PKAddress(pubkey, bs)
}
}
@@ -103,15 +108,21 @@ class Pay2SHAddress(val scriptHash: Array[Byte])(implicit val encoder: ErgoAddre
override val addressTypePrefix: Byte = Pay2SHAddress.addressTypePrefix
override val contentBytes: Array[Byte] = scriptHash
-
- //similar script checked in "P2SH - 160 bits" test in sigma repository, but here we use 192 bits
- //see ErgoLikeInterpreterSpecification."P2SH - 160 bits" test
- override val script: Value[SBoolean.type] = {
- val scriptId = 1: Byte
- val hashEquals = EQ(Slice(CalcBlake2b256(GetVarByteArray(scriptId).get), IntConstant(0), IntConstant(24)),
- scriptHash)
- val scriptIsCorrect = DeserializeContext(scriptId, SBoolean)
- AND(hashEquals, scriptIsCorrect)
+ import Pay2SHAddress._
+
+ /** The proposition which checks that `contextVar(1)` has original script,
+ * which evaluates to true and also whose hash equals to this `scriptHash`.
+ * Assumes the context variable accessed as getVar[Coll[Byte]](1)` to contain serialized original script bytes.
+ * @see ErgoLikeInterpreterSpecification."P2SH - 160 bits" test
+ * similar script checked in "P2SH - 160 bits" test in sigma repository, but here we use 192 bits
+ */
+ override val script = {
+ val hashEquals = EQ(
+ Slice(CalcBlake2b256(GetVarByteArray(scriptId).get), IntConstant(0), IntConstant(24)),
+ scriptHash
+ )
+ val scriptIsCorrect = DeserializeContext(scriptId, SSigmaProp)
+ ErgoTree.withoutSegregation(SigmaAnd(hashEquals.toSigmaProp, scriptIsCorrect))
}
override def equals(obj: Any): Boolean = obj match {
@@ -125,17 +136,17 @@ class Pay2SHAddress(val scriptHash: Array[Byte])(implicit val encoder: ErgoAddre
}
object Pay2SHAddress {
+ val scriptId = 1: Byte
+ val addressTypePrefix: Byte = 2: Byte
- def apply(script: Value[SBoolean.type])(implicit encoder: ErgoAddressEncoder): Pay2SHAddress = {
- val sb = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(script)
+ def apply(script: ErgoTree)(implicit encoder: ErgoAddressEncoder): Pay2SHAddress = {
+ val sb = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(script)
val sbh = ErgoAddressEncoder.hash192(sb)
new Pay2SHAddress(sbh)
}
-
- val addressTypePrefix: Byte = 2: Byte
}
-class Pay2SAddress(override val script: Value[SBoolean.type],
+class Pay2SAddress(override val script: ErgoTree,
val scriptBytes: Array[Byte])
(implicit val encoder: ErgoAddressEncoder) extends ErgoAddress {
override val addressTypePrefix: Byte = Pay2SAddress.addressTypePrefix
@@ -153,16 +164,16 @@ class Pay2SAddress(override val script: Value[SBoolean.type],
}
object Pay2SAddress {
- def apply(script: Value[SBoolean.type])(implicit encoder: ErgoAddressEncoder): Pay2SAddress = {
- val sb = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(script)
+ val addressTypePrefix: Byte = 3: Byte
+
+ def apply(script: ErgoTree)(implicit encoder: ErgoAddressEncoder): Pay2SAddress = {
+ val sb = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(script)
new Pay2SAddress(script, sb)
}
-
- val addressTypePrefix: Byte = 3: Byte
}
-case class ErgoAddressEncoder(networkPrefix: Byte) {
+case class ErgoAddressEncoder(networkPrefix: NetworkPrefix) {
import ErgoAddressEncoder._
@@ -177,10 +188,16 @@ case class ErgoAddressEncoder(networkPrefix: Byte) {
Base58.encode(withNetworkByte ++ checksum)
}
+ def isTestnetAddress(addrHeadByte: Byte): Boolean = addrHeadByte > TestnetNetworkPrefix
+ def isMainnetAddress(addrHeadByte: Byte): Boolean = addrHeadByte < TestnetNetworkPrefix
+
def fromString(addrStr: String): Try[ErgoAddress] = Base58.decode(addrStr).flatMap { bytes =>
Try {
val headByte = bytes.head
- require(headByte >= networkPrefix)
+ networkPrefix match {
+ case TestnetNetworkPrefix => require(isTestnetAddress(headByte), "Trying to decode mainnet address in testnet")
+ case MainnetNetworkPrefix => require(isMainnetAddress(headByte), "Trying to decode testnet address in mainnet")
+ }
val addressType = (headByte - networkPrefix).toByte
val (withoutChecksum, checksum) = bytes.splitAt(bytes.length - ChecksumLength)
@@ -188,29 +205,36 @@ case class ErgoAddressEncoder(networkPrefix: Byte) {
throw new Exception(s"Checksum check fails for $addrStr")
}
- val bs = withoutChecksum.tail
+ val contentBytes = withoutChecksum.tail
addressType match {
case P2PKAddress.addressTypePrefix =>
- val pd = ValueSerializer.deserialize(bs).asInstanceOf[ProveDlog]
- new P2PKAddress(pd, bs)
+ val r = SigmaSerializer.startReader(contentBytes)
+ val p = GroupElementSerializer.parse(r)
+ new P2PKAddress(ProveDlog(p), contentBytes)
case Pay2SHAddress.addressTypePrefix =>
- new Pay2SHAddress(bs)
+ new Pay2SHAddress(contentBytes)
case Pay2SAddress.addressTypePrefix =>
- new Pay2SAddress(ErgoTreeSerializer.DefaultSerializer.deserialize(bs).asInstanceOf[Value[SBoolean.type]], bs)
- case _ => throw new Exception("Unsupported address type: " + addressType)
+ new Pay2SAddress(ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(contentBytes), contentBytes)
+ case _ =>
+ throw new Exception("Unsupported address type: " + addressType)
}
}
}
- def fromProposition(proposition: Value[SType]): Try[ErgoAddress] = Try {
- proposition match {
- case d @ ProveDlog(_) => P2PKAddress(d)
+ def fromProposition(proposition: ErgoTree): Try[ErgoAddress] = Try {
+ proposition.root match {
+ case SigmaPropConstant(d: ProveDlog) => P2PKAddress(d)
//TODO move this pattern to PredefScripts
- case a @ AND(ConcreteCollection(Vector(EQ(Slice(_: CalcHash, ConstantNode(0, SInt), ConstantNode(24, SInt)), _), _), _)) =>
- Pay2SHAddress(a)
- case b: Value[SBoolean.type]@unchecked if b.tpe == SBoolean => Pay2SAddress(b)
- case other => throw new RuntimeException(s"Invalid proposition type: ${other.tpe}")
+ case SigmaAnd(Seq(
+ BoolToSigmaProp(
+ EQ(
+ Slice(_: CalcHash, ConstantNode(0, SInt), ConstantNode(24, SInt)),
+ ByteArrayConstant(scriptHash))),
+ DeserializeContext(Pay2SHAddress.scriptId, SSigmaProp))) => new Pay2SHAddress(scriptHash)
+ case b: Value[SSigmaProp.type]@unchecked if b.tpe == SSigmaProp => Pay2SAddress(proposition)
+ case other =>
+ throw new RuntimeException(s"Cannot create ErgoAddress form proposition: ${proposition}")
}
}
}
diff --git a/src/main/scala/org/ergoplatform/ErgoBox.scala b/src/main/scala/org/ergoplatform/ErgoBox.scala
index 11f797dbf2..d1bb1ad996 100644
--- a/src/main/scala/org/ergoplatform/ErgoBox.scala
+++ b/src/main/scala/org/ergoplatform/ErgoBox.scala
@@ -9,10 +9,9 @@ import scorex.util._
import sigmastate.Values._
import sigmastate.SType.AnyOps
import sigmastate._
-import sigmastate.serialization.Serializer
+import sigmastate.serialization.SigmaSerializer
import sigmastate.SCollection.SByteArray
import sigmastate.utils.{Helpers, SigmaByteReader, SigmaByteWriter}
-import sigmastate.utxo.CostTable.Cost
import sigmastate.utxo.ExtractCreationInfo
import scala.runtime.ScalaRunTime
@@ -35,13 +34,15 @@ import scala.runtime.ScalaRunTime
* A transaction is unsealing a box. As a box can not be open twice, any further valid transaction can not be linked
* to the same box.
*
- * @param value - amount of money associated with the box
- * @param ergoTree guarding script, which should be evaluated to true in order to open this box
- * @param additionalTokens - secondary tokens the box contains
+ * @param value - amount of money associated with the box
+ * @param ergoTree - guarding script, which should be evaluated to true in order to open this box
+ * @param additionalTokens - secondary tokens the box contains
* @param additionalRegisters - additional registers the box can carry over
- * @param transactionId - id of transaction which created the box
- * @param index - number of box (from 0 to total number of boxes the transaction with transactionId created - 1)
- * @param creationHeight - height when a transaction containing the box was included into the blockchain
+ * @param transactionId - id of transaction which created the box
+ * @param index - number of box (from 0 to total number of boxes the transaction with transactionId created - 1)
+ * @param creationHeight - height when a transaction containing the box was created.
+ * This height is declared by user and should not exceed height of the block,
+ * containing the transaction with this box.
*/
class ErgoBox private(
override val value: Long,
@@ -51,11 +52,10 @@ class ErgoBox private(
val transactionId: ModifierId,
val index: Short,
override val creationHeight: Int
-) extends ErgoBoxCandidate(value, ergoTree, creationHeight, additionalTokens, additionalRegisters) {
+ ) extends ErgoBoxCandidate(value, ergoTree, creationHeight, additionalTokens, additionalRegisters) {
import ErgoBox._
- lazy val bytes: Array[Byte] = ErgoBox.serializer.toBytes(this)
lazy val id: BoxId = ADKey @@ Blake2b256.hash(bytes)
override def dataSize: Long = bytes.length
@@ -69,6 +69,8 @@ class ErgoBox private(
}
}
+ lazy val bytes: Array[Byte] = ErgoBox.sigmaSerializer.toBytes(this)
+
override def equals(arg: Any): Boolean = arg match {
case x: ErgoBox => java.util.Arrays.equals(id, x.id)
case _ => false
@@ -81,7 +83,7 @@ class ErgoBox private(
new ErgoBoxCandidate(value, ergoTree, creationHeight, additionalTokens, additionalRegisters)
override def toString: Idn = s"ErgoBox(${Base16.encode(id)},$value,$ergoTree," +
- s"tokens: (${additionalTokens.map(t => Base16.encode(t._1)+":"+t._2)}), $transactionId, " +
+ s"tokens: (${additionalTokens.map(t => Base16.encode(t._1) + ":" + t._2)}), $transactionId, " +
s"$index, $additionalRegisters, $creationHeight)"
}
@@ -100,14 +102,17 @@ object ErgoBox {
val STokenType = STuple(SByteArray, SLong)
val STokensRegType = SCollection(STokenType)
- val SReferenceRegType = ExtractCreationInfo.ResultType
+ val SReferenceRegType: STuple = ExtractCreationInfo.ResultType
type Amount = Long
trait RegisterId {
val number: Byte
def asIndex: Int = number.toInt
+
+ override def toString: Idn = "R" + number
}
+
abstract class MandatoryRegisterId(override val number: Byte, purpose: String) extends RegisterId
abstract class NonMandatoryRegisterId(override val number: Byte) extends RegisterId
@@ -122,41 +127,43 @@ object ErgoBox {
object R8 extends NonMandatoryRegisterId(8)
object R9 extends NonMandatoryRegisterId(9)
- val ValueRegId = R0
- val ScriptRegId = R1
- val TokensRegId = R2
- val ReferenceRegId = R3
+ val ValueRegId: MandatoryRegisterId = R0
+ val ScriptRegId: MandatoryRegisterId = R1
+ val TokensRegId: MandatoryRegisterId = R2
+ val ReferenceRegId: MandatoryRegisterId = R3
val MaxTokens: Byte = 4
val maxRegisters = 10
val mandatoryRegisters: Vector[MandatoryRegisterId] = Vector(R0, R1, R2, R3)
val nonMandatoryRegisters: Vector[NonMandatoryRegisterId] = Vector(R4, R5, R6, R7, R8, R9)
- val startingNonMandatoryIndex = nonMandatoryRegisters.head.number
+ val startingNonMandatoryIndex: Byte = nonMandatoryRegisters.head.number
.ensuring(_ == mandatoryRegisters.last.number + 1)
- val allRegisters = (mandatoryRegisters ++ nonMandatoryRegisters).ensuring(_.size == maxRegisters)
- val mandatoryRegistersCount = mandatoryRegisters.size.toByte
- val nonMandatoryRegistersCount = nonMandatoryRegisters.size.toByte
+ val allRegisters: Vector[RegisterId] = (mandatoryRegisters ++ nonMandatoryRegisters).ensuring(_.size == maxRegisters)
+ val mandatoryRegistersCount: Byte = mandatoryRegisters.size.toByte
+ val nonMandatoryRegistersCount: Byte = nonMandatoryRegisters.size.toByte
val registerByName: Map[String, RegisterId] = allRegisters.map(r => s"R${r.number}" -> r).toMap
val registerByIndex: Map[Byte, RegisterId] = allRegisters.map(r => r.number -> r).toMap
def findRegisterByIndex(i: Byte): Option[RegisterId] = registerByIndex.get(i)
+ val allZerosModifierId: ModifierId = Array.fill[Byte](32)(0.toByte).toModifierId
+
def apply(value: Long,
ergoTree: ErgoTree,
creationHeight: Int,
additionalTokens: Seq[(TokenId, Long)] = Seq(),
additionalRegisters: Map[NonMandatoryRegisterId, _ <: EvaluatedValue[_ <: SType]] = Map(),
- transactionId: ModifierId = Array.fill[Byte](32)(0.toByte).toModifierId,
- boxId: Short = 0): ErgoBox =
- new ErgoBox(value, ergoTree, additionalTokens, additionalRegisters, transactionId, boxId, creationHeight)
+ transactionId: ModifierId = allZerosModifierId,
+ boxIndex: Short = 0): ErgoBox =
+ new ErgoBox(value, ergoTree, additionalTokens, additionalRegisters, transactionId, boxIndex, creationHeight)
- object serializer extends Serializer[ErgoBox, ErgoBox] {
+ object sigmaSerializer extends SigmaSerializer[ErgoBox, ErgoBox] {
- override def serializeBody(obj: ErgoBox, w: SigmaByteWriter): Unit = {
- ErgoBoxCandidate.serializer.serializeBody(obj, w)
+ override def serialize(obj: ErgoBox, w: SigmaByteWriter): Unit = {
+ ErgoBoxCandidate.serializer.serialize(obj, w)
val txIdBytes = obj.transactionId.toBytes
val txIdBytesSize = txIdBytes.length
assert(txIdBytesSize == ErgoLikeTransaction.TransactionIdBytesSize,
@@ -165,11 +172,12 @@ object ErgoBox {
w.putUShort(obj.index)
}
- override def parseBody(r: SigmaByteReader): ErgoBox = {
- val ergoBoxCandidate = ErgoBoxCandidate.serializer.parseBody(r)
+ override def parse(r: SigmaByteReader): ErgoBox = {
+ val ergoBoxCandidate = ErgoBoxCandidate.serializer.parse(r)
val transactionId = r.getBytes(ErgoLikeTransaction.TransactionIdBytesSize).toModifierId
val index = r.getUShort()
ergoBoxCandidate.toBox(transactionId, index.toShort)
}
}
+
}
diff --git a/src/main/scala/org/ergoplatform/ErgoBoxCandidate.scala b/src/main/scala/org/ergoplatform/ErgoBoxCandidate.scala
index a80c47407e..eb43e6cca4 100644
--- a/src/main/scala/org/ergoplatform/ErgoBoxCandidate.scala
+++ b/src/main/scala/org/ergoplatform/ErgoBoxCandidate.scala
@@ -10,13 +10,27 @@ import sigmastate.Values._
import sigmastate._
import sigmastate.SType.AnyOps
import sigmastate.lang.Terms._
-import sigmastate.serialization.{ErgoTreeSerializer, Serializer, ValueSerializer}
+import sigmastate.serialization.{ErgoTreeSerializer, SigmaSerializer}
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.CostTable.Cost
-import sigmastate.utils.Extensions._
+import scala.collection.mutable.WrappedArray.ofByte
import scala.runtime.ScalaRunTime
+/**
+ * Contains the same fields as `org.ergoplatform.ErgoBox`, except if transaction id and index,
+ * that will be calculated after full transaction formation.
+ *
+ * @see org.ergoplatform.ErgoBox for more details
+ *
+ * @param value - amount of money associated with the box
+ * @param ergoTree - guarding script, which should be evaluated to true in order to open this box
+ * @param creationHeight - height when a transaction containing the box was created.
+ * This height is declared by user and should not exceed height of the block,
+ * containing the transaction with this box.
+ * @param additionalTokens - secondary tokens the box contains
+ * @param additionalRegisters - additional registers the box can carry over
+ */
class ErgoBoxCandidate(val value: Long,
val ergoTree: ErgoTree,
val creationHeight: Int,
@@ -29,12 +43,12 @@ class ErgoBoxCandidate(val value: Long,
lazy val cost: Int = (dataSize / 1024 + 1).toInt * Cost.BoxPerKilobyte
- val propositionBytes: Array[Byte] = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(ergoTree.proposition)
+ lazy val propositionBytes: Array[Byte] = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(ergoTree)
lazy val bytesWithNoRef: Array[Byte] = ErgoBoxCandidate.serializer.toBytes(this)
- def toBox(txId: ModifierId, boxId: Short) =
- ErgoBox(value, ergoTree, creationHeight, additionalTokens, additionalRegisters, txId, boxId)
+ def toBox(txId: ModifierId, boxIndex: Short) =
+ ErgoBox(value, ergoTree, creationHeight, additionalTokens, additionalRegisters, txId, boxIndex)
def get(identifier: RegisterId): Option[Value[SType]] = {
identifier match {
@@ -64,26 +78,26 @@ class ErgoBoxCandidate(val value: Long,
ScalaRunTime._hashCode((value, ergoTree, additionalTokens, additionalRegisters, creationHeight))
override def toString: Idn = s"ErgoBoxCandidate($value, $ergoTree," +
- s"tokens: (${additionalTokens.map(t => Base16.encode(t._1)+":"+t._2).mkString(", ")}), " +
+ s"tokens: (${additionalTokens.map(t => Base16.encode(t._1) + ":" + t._2).mkString(", ")}), " +
s"$additionalRegisters, creationHeight: $creationHeight)"
}
object ErgoBoxCandidate {
- object serializer extends Serializer[ErgoBoxCandidate, ErgoBoxCandidate] {
+ object serializer extends SigmaSerializer[ErgoBoxCandidate, ErgoBoxCandidate] {
def serializeBodyWithIndexedDigests(obj: ErgoBoxCandidate,
- digestsInTx: Option[Array[Digest32]],
+ tokensInTx: Option[Array[ofByte]],
w: SigmaByteWriter): Unit = {
w.putULong(obj.value)
w.putBytes(ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(obj.ergoTree))
w.putUInt(obj.creationHeight)
w.putUByte(obj.additionalTokens.size)
obj.additionalTokens.foreach { case (id, amount) =>
- if (digestsInTx.isDefined) {
- val digestIndex = digestsInTx.get.indexOf(id)
- if (digestIndex == -1) sys.error(s"failed to find token id ($id) in tx's digest index")
- w.putUInt(digestIndex)
+ if (tokensInTx.isDefined) {
+ val tokenIndex = tokensInTx.get.indexOf(new ofByte(id))
+ if (tokenIndex == -1) sys.error(s"failed to find token id ($id) in tx's digest index")
+ w.putUInt(tokenIndex)
} else {
w.putBytes(id)
}
@@ -109,7 +123,7 @@ object ErgoBoxCandidate {
}
}
- override def serializeBody(obj: ErgoBoxCandidate, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: ErgoBoxCandidate, w: SigmaByteWriter): Unit = {
serializeBodyWithIndexedDigests(obj, None, w)
}
@@ -139,8 +153,9 @@ object ErgoBoxCandidate {
new ErgoBoxCandidate(value, tree, creationHeight, addTokens, regs)
}
- override def parseBody(r: SigmaByteReader): ErgoBoxCandidate = {
+ override def parse(r: SigmaByteReader): ErgoBoxCandidate = {
parseBodyWithIndexedDigests(None, r)
}
}
+
}
diff --git a/src/main/scala/org/ergoplatform/ErgoLikeContext.scala b/src/main/scala/org/ergoplatform/ErgoLikeContext.scala
index bfe3e54a2c..d552e846c7 100644
--- a/src/main/scala/org/ergoplatform/ErgoLikeContext.scala
+++ b/src/main/scala/org/ergoplatform/ErgoLikeContext.scala
@@ -1,51 +1,99 @@
package org.ergoplatform
-import org.ergoplatform.ErgoBox.ReferenceRegId
+import java.math.BigInteger
+
+import org.bouncycastle.math.ec.ECPoint
import org.ergoplatform.ErgoLikeContext.Height
-import org.ergoplatform.ErgoLikeContext.Metadata.NetworkPrefix
+import scalan.RType
+import scalan.RType.{TupleType, PairType}
import sigmastate.Values._
import sigmastate._
-import sigmastate.eval.{CostingAvlTree, CostingDataContext, Evaluation, CostingBox}
-import sigmastate.interpreter.{ContextExtension, Context}
+import sigmastate.eval._
+import sigmastate.eval.Extensions._
+import sigmastate.interpreter.{ContextExtension, Context => ErgoContext}
import sigmastate.serialization.OpCodes
import sigmastate.serialization.OpCodes.OpCode
-import sigmastate.utxo.CostTable.Cost
-import special.collection.Col
+import special.collection.{Coll, CollType}
import special.sigma
-import special.sigma.{AnyValue, TestValue, Box}
+import special.sigma.{WrapperType, Header, Box, AnyValue, TestValue, PreHeader}
+import SType._
+import RType._
+import special.sigma.Extensions._
import scala.util.Try
case class BlockchainState(currentHeight: Height, lastBlockUtxoRoot: AvlTreeData)
-// todo: write description
+/**
+ * TODO currentHeight and minerPubkey should be calculated from PreHeader
+ * TODO lastBlockUtxoRoot should be calculated from headers if it is nonEmpty
+ *
+ * @param self - box that contains the script we're evaluating
+ * @param currentHeight - height of a block with the current `spendingTransaction`
+ * @param lastBlockUtxoRoot - state root before current block application
+ * @param minerPubkey - public key of a miner of the block with the current `spendingTransaction`
+ * @param headers - fixed number of last block headers in descending order (first header is the newest one)
+ * @param preHeader - fields of block header with the current `spendingTransaction`, that can be predicted
+ * by a miner before it's formation
+ * @param dataBoxes - boxes, that corresponds to id's of `spendingTransaction.dataInputs`
+ * @param boxesToSpend - boxes, that corresponds to id's of `spendingTransaction.inputs`
+ * @param spendingTransaction - transaction that contains `self` box
+ * @param extension - prover-defined key-value pairs, that may be used inside a script
+ */
class ErgoLikeContext(val currentHeight: Height,
val lastBlockUtxoRoot: AvlTreeData,
val minerPubkey: Array[Byte],
+ val headers: Coll[Header],
+ val preHeader: PreHeader,
+ val dataBoxes: IndexedSeq[ErgoBox],
val boxesToSpend: IndexedSeq[ErgoBox],
val spendingTransaction: ErgoLikeTransactionTemplate[_ <: UnsignedInput],
val self: ErgoBox,
override val extension: ContextExtension = ContextExtension(Map())
- ) extends Context {
+ ) extends ErgoContext {
+
assert(self == null || boxesToSpend.exists(box => box.id == self.id), s"Self box if defined should be among boxesToSpend")
+ assert(preHeader == null || preHeader.height == currentHeight, "Incorrect preHeader height")
+ assert(preHeader == null || java.util.Arrays.equals(minerPubkey, preHeader.minerPk.getEncoded.toArray), "Incorrect preHeader minerPubkey")
+ assert(headers.toArray.headOption.forall(h => java.util.Arrays.equals(h.stateRoot.digest.toArray, lastBlockUtxoRoot.digest)), "Incorrect lastBlockUtxoRoot")
+ headers.toArray.indices.foreach { i =>
+ if (i > 0) assert(headers(i - 1).parentId == headers(i).id, s"Incorrect chain: ${headers(i - 1).parentId},${headers(i).id}")
+ }
+ assert(preHeader == null || headers.toArray.headOption.forall(_.id == preHeader.parentId), s"preHeader.parentId should be id of the best header")
+
override def withExtension(newExtension: ContextExtension): ErgoLikeContext =
- ErgoLikeContext(currentHeight, lastBlockUtxoRoot, minerPubkey, boxesToSpend, spendingTransaction, self, newExtension)
+ new ErgoLikeContext(
+ currentHeight, lastBlockUtxoRoot, minerPubkey, headers, preHeader,
+ dataBoxes, boxesToSpend, spendingTransaction, self, newExtension)
def withTransaction(newSpendingTransaction: ErgoLikeTransactionTemplate[_ <: UnsignedInput]): ErgoLikeContext =
- ErgoLikeContext(currentHeight, lastBlockUtxoRoot, minerPubkey, boxesToSpend, newSpendingTransaction, self, extension)
+ new ErgoLikeContext(
+ currentHeight, lastBlockUtxoRoot, minerPubkey, headers, preHeader,
+ dataBoxes, boxesToSpend, newSpendingTransaction, self, extension)
import ErgoLikeContext._
-
- override def toSigmaContext(IR: Evaluation, isCost: Boolean): sigma.Context = {
- implicit val IRForBox = IR
- val inputs = boxesToSpend.toArray.map(_.toTestBox(isCost))
- val outputs =
- if (spendingTransaction == null) noOutputs
- else spendingTransaction.outputs.toArray.map(_.toTestBox(isCost))
- val vars = contextVars(extension.values)
- val noBytes = IR.sigmaDslBuilderValue.Cols.fromArray[Byte](Array[Byte]())
- val avlTree = CostingAvlTree(IR, lastBlockUtxoRoot)
- new CostingDataContext(IR, inputs, outputs, currentHeight, self.toTestBox(isCost), avlTree, minerPubkey, vars.arr, isCost)
+ import Evaluation._
+
+ override def toSigmaContext(IR: Evaluation, isCost: Boolean, extensions: Map[Byte, AnyValue] = Map()): sigma.Context = {
+ implicit val IRForBox: Evaluation = IR
+ val dataInputs = this.dataBoxes.toArray.map(_.toTestBox(isCost)).toColl
+ val inputs = boxesToSpend.toArray.map(_.toTestBox(isCost)).toColl
+ val outputs = if (spendingTransaction == null)
+ noOutputs.toColl
+ else
+ spendingTransaction.outputs.toArray.map(_.toTestBox(isCost)).toColl
+ val varMap = extension.values.mapValues { case v: EvaluatedValue[_] =>
+ val tVal = stypeToRType[SType](v.tpe)
+ val dslData = Evaluation.toDslData(v.value, v.tpe, isCost)
+ toAnyValue(dslData.asWrappedType)(tVal)
+ }
+ val vars = contextVars(varMap ++ extensions)
+ val avlTree = CAvlTree(lastBlockUtxoRoot)
+ new CostingDataContext(
+ dataInputs, headers, preHeader, inputs, outputs, currentHeight, self.toTestBox(isCost), avlTree,
+ minerPubkey.toColl,
+ vars,
+ isCost)
}
}
@@ -55,13 +103,12 @@ object ErgoLikeContext {
val dummyPubkey: Array[Byte] = Array.fill(32)(0: Byte)
- case class Metadata(networkPrefix: NetworkPrefix)
+ val noBoxes = IndexedSeq.empty[ErgoBox]
+ val noHeaders = CostingSigmaDslBuilder.Colls.emptyColl[Header]
+ val dummyPreHeader: PreHeader = null
- object Metadata {
- type NetworkPrefix = Byte
- val MainnetNetworkPrefix: NetworkPrefix = 0.toByte
- val TestnetNetworkPrefix: NetworkPrefix = 16.toByte
- }
+ /** Maximimum number of headers in `headers` collection of the context. */
+ val MaxHeaders = 10
def apply(currentHeight: Height,
lastBlockUtxoRoot: AvlTreeData,
@@ -70,7 +117,11 @@ object ErgoLikeContext {
spendingTransaction: ErgoLikeTransactionTemplate[_ <: UnsignedInput],
self: ErgoBox,
extension: ContextExtension = ContextExtension(Map())) =
- new ErgoLikeContext(currentHeight, lastBlockUtxoRoot, minerPubkey, boxesToSpend, spendingTransaction, self, extension)
+ new ErgoLikeContext(currentHeight, lastBlockUtxoRoot, minerPubkey,
+ noHeaders,
+ dummyPreHeader,
+ noBoxes,
+ boxesToSpend, spendingTransaction, self, extension)
def dummy(selfDesc: ErgoBox) = ErgoLikeContext(currentHeight = 0,
@@ -95,34 +146,20 @@ object ErgoLikeContext {
proverExtension)
}
- val noInputs = Array[Box]()
- val noOutputs = Array[Box]()
-
- def toTestData(value: Any, tpe: SType, isCost: Boolean)(implicit IR: Evaluation): Any = (value, tpe) match {
- case (arr: Array[a], SCollectionType(elemType)) =>
- elemType match {
- case SCollectionType(_) | STuple(_) =>
- val testArr = arr.map(x => toTestData(x, elemType, isCost))
- IR.sigmaDslBuilderValue.Cols.fromArray(testArr)
- case _ =>
- IR.sigmaDslBuilderValue.Cols.fromArray(arr)
- }
- case (arr: Array[a], STuple(items)) =>
- val res = arr.zip(items).map { case (x, t) => toTestData(x, t, isCost)}
- IR.sigmaDslBuilderValue.Cols.fromArray(res)
- case (b: ErgoBox, SBox) => b.toTestBox(isCost)
- case (t: AvlTreeData, SAvlTree) => CostingAvlTree(IR, t)
- case (x, _) => x
- }
+ val noInputs: Array[Box] = Array[Box]()
+ val noOutputs: Array[Box] = Array[Box]()
+
+ import special.sigma._
+ import sigmastate.SType._
- def contextVars(m: Map[Byte, Any])(implicit IR: Evaluation): Col[AnyValue] = {
+ def contextVars(m: Map[Byte, AnyValue])(implicit IR: Evaluation): Coll[AnyValue] = {
val maxKey = if (m.keys.isEmpty) 0 else m.keys.max
val res = new Array[AnyValue](maxKey + 1)
for ((id, v) <- m) {
assert(res(id) == null, s"register $id is defined more then once")
- res(id) = new TestValue(v)
+ res(id) = v
}
- IR.sigmaDslBuilderValue.Cols.fromArray(res)
+ IR.sigmaDslBuilderValue.Colls.fromArray(res)
}
implicit class ErgoBoxOps(val ebox: ErgoBox) extends AnyVal {
@@ -171,3 +208,9 @@ case object Self extends NotReadyValueBox {
override val opCode: OpCode = OpCodes.SelfCode
def opType = SFunc(SContext, SBox)
}
+
+case object Context extends NotReadyValue[SContext.type] {
+ override val opCode: OpCode = OpCodes.ContextCode
+ override def tpe: SContext.type = SContext
+ override def opType: SFunc = SFunc(SUnit, SContext)
+}
diff --git a/src/main/scala/org/ergoplatform/ErgoLikeTransaction.scala b/src/main/scala/org/ergoplatform/ErgoLikeTransaction.scala
index 09ae687a48..143f6107c0 100644
--- a/src/main/scala/org/ergoplatform/ErgoLikeTransaction.scala
+++ b/src/main/scala/org/ergoplatform/ErgoLikeTransaction.scala
@@ -5,21 +5,33 @@ import scorex.crypto.authds.ADKey
import scorex.crypto.hash.{Blake2b256, Digest32}
import scorex.util._
import sigmastate.interpreter.ProverResult
-import sigmastate.serialization.Serializer
-
-import scala.util.Try
+import sigmastate.serialization.SigmaSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import scala.collection.mutable
-
+import scala.util.Try
trait ErgoBoxReader {
def byId(boxId: ADKey): Try[ErgoBox]
}
-
+/**
+ * Base trait of a real transaction to be used in Ergo network.
+ * May be in unsigned (`UnsignedErgoLikeTransaction`) or in signed (`ErgoLikeTransaction`) version.
+ *
+ * Consists of:
+ *
+ * @param inputs - inputs, that will be spent by this transaction.
+ * @param dataInputs - inputs, that are not going to be spent by transaction, but will be
+ * reachable from inputs scripts. `dataInputs` scripts will not be executed,
+ * thus their scripts costs are not included in transaction cost and
+ * they do not contain spending proofs.
+ * @param outputCandidates - box candidates to be created by this transaction.
+ * Differ from ordinary ones in that they do not include transaction id and index
+ */
trait ErgoLikeTransactionTemplate[IT <: UnsignedInput] {
+ val dataInputs: IndexedSeq[DataInput]
val inputs: IndexedSeq[IT]
val outputCandidates: IndexedSeq[ErgoBoxCandidate]
@@ -30,14 +42,17 @@ trait ErgoLikeTransactionTemplate[IT <: UnsignedInput] {
lazy val outputs: IndexedSeq[ErgoBox] =
outputCandidates.indices.map(idx => outputCandidates(idx).toBox(id, idx.toShort))
- lazy val messageToSign: Array[Byte] =
- ErgoLikeTransaction.flattenedTxSerializer.bytesToSign(this)
+ lazy val messageToSign: Array[Byte] = ErgoLikeTransaction.bytesToSign(this)
lazy val inputIds: IndexedSeq[ADKey] = inputs.map(_.boxId)
}
+/**
+ * Unsigned version of `ErgoLikeTransactionTemplate`
+ */
class UnsignedErgoLikeTransaction(override val inputs: IndexedSeq[UnsignedInput],
+ override val dataInputs: IndexedSeq[DataInput],
override val outputCandidates: IndexedSeq[ErgoBoxCandidate])
extends ErgoLikeTransactionTemplate[UnsignedInput] {
@@ -46,22 +61,23 @@ class UnsignedErgoLikeTransaction(override val inputs: IndexedSeq[UnsignedInput]
def toSigned(proofs: IndexedSeq[ProverResult]): ErgoLikeTransaction = {
require(proofs.size == inputs.size)
val ins = inputs.zip(proofs).map { case (ui, proof) => Input(ui.boxId, proof) }
- new ErgoLikeTransaction(ins, outputCandidates)
+ new ErgoLikeTransaction(ins, dataInputs, outputCandidates)
}
}
object UnsignedErgoLikeTransaction {
+ def apply(inputs: IndexedSeq[UnsignedInput], dataInputs: IndexedSeq[DataInput], outputCandidates: IndexedSeq[ErgoBoxCandidate]) =
+ new UnsignedErgoLikeTransaction(inputs, dataInputs, outputCandidates)
+
def apply(inputs: IndexedSeq[UnsignedInput], outputCandidates: IndexedSeq[ErgoBoxCandidate]) =
- new UnsignedErgoLikeTransaction(inputs, outputCandidates)
+ new UnsignedErgoLikeTransaction(inputs, IndexedSeq(), outputCandidates)
}
/**
- * Fully signed transaction
- *
- * @param inputs
- * @param outputCandidates
+ * Signed version of `ErgoLikeTransactionTemplate`
*/
class ErgoLikeTransaction(override val inputs: IndexedSeq[Input],
+ override val dataInputs: IndexedSeq[DataInput],
override val outputCandidates: IndexedSeq[ErgoBoxCandidate])
extends ErgoLikeTransactionTemplate[Input] {
@@ -78,90 +94,90 @@ class ErgoLikeTransaction(override val inputs: IndexedSeq[Input],
override def hashCode(): Int = id.hashCode()
}
+object ErgoLikeTransactionSerializer extends SigmaSerializer[ErgoLikeTransaction, ErgoLikeTransaction] {
-object ErgoLikeTransaction {
-
- val TransactionIdBytesSize: Short = 32
-
- def apply(inputs: IndexedSeq[Input], outputCandidates: IndexedSeq[ErgoBoxCandidate]) =
- new ErgoLikeTransaction(inputs, outputCandidates)
-
- def apply(ftx: FlattenedTransaction): ErgoLikeTransaction =
- new ErgoLikeTransaction(ftx.inputs, ftx.outputCandidates)
-
- case class FlattenedTransaction(inputs: Array[Input],
- outputCandidates: Array[ErgoBoxCandidate])
-
- object FlattenedTransaction {
- def apply(tx: ErgoLikeTransaction): FlattenedTransaction =
- FlattenedTransaction(tx.inputs.toArray, tx.outputCandidates.toArray)
+ override def serialize(tx: ErgoLikeTransaction, w: SigmaByteWriter): Unit = {
+ // serialize transaction inputs
+ w.putUShort(tx.inputs.length)
+ for (input <- tx.inputs) {
+ Input.serializer.serialize(input, w)
+ }
+ // serialize transaction data inputs
+ w.putUShort(tx.dataInputs.length)
+ for (input <- tx.dataInputs) {
+ w.putBytes(input.boxId)
+ }
+ // serialize distinct ids of tokens in transaction outputs
+ val distinctTokenIds = tx.outputCandidates
+ .flatMap(_.additionalTokens.map(t => new mutable.WrappedArray.ofByte(t._1)))
+ .distinct
+ .toArray
+ w.putUInt(distinctTokenIds.length)
+ distinctTokenIds.foreach { tokenId =>
+ w.putBytes(tokenId.array)
+ }
+ // serialize outputs
+ w.putUShort(tx.outputCandidates.length)
+ for (out <- tx.outputCandidates) {
+ ErgoBoxCandidate.serializer.serializeBodyWithIndexedDigests(out, Some(distinctTokenIds), w)
+ }
}
- object flattenedTxSerializer extends Serializer[FlattenedTransaction, FlattenedTransaction] {
+ override def parse(r: SigmaByteReader): ErgoLikeTransaction = {
+ // parse transaction inputs
+ val inputsCount = r.getUShort()
+ val inputsBuilder = mutable.ArrayBuilder.make[Input]()
+ for (_ <- 0 until inputsCount) {
+ inputsBuilder += Input.serializer.parse(r)
+ }
+ // parse transaction data inputs
+ val dataInputsCount = r.getUShort()
+ val dataInputsBuilder = mutable.ArrayBuilder.make[DataInput]()
+ for (_ <- 0 until dataInputsCount) {
+ dataInputsBuilder += DataInput(ADKey @@ r.getBytes(ErgoBox.BoxId.size))
+ }
+ // parse distinct ids of tokens in transaction outputs
+ val tokensCount = r.getUInt().toInt
+ val tokensBuilder = mutable.ArrayBuilder.make[Digest32]()
+ for (_ <- 0 until tokensCount) {
+ tokensBuilder += Digest32 @@ r.getBytes(TokenId.size)
+ }
+ // parse outputs
+ val tokens = tokensBuilder.result()
+ val outsCount = r.getUShort()
+ val outputCandidatesBuilder = mutable.ArrayBuilder.make[ErgoBoxCandidate]()
+ for (_ <- 0 until outsCount) {
+ outputCandidatesBuilder += ErgoBoxCandidate.serializer.parseBodyWithIndexedDigests(Some(tokens), r)
+ }
+ new ErgoLikeTransaction(inputsBuilder.result(), dataInputsBuilder.result(), outputCandidatesBuilder.result())
+ }
- def bytesToSign(inputs: IndexedSeq[ADKey],
- outputCandidates: IndexedSeq[ErgoBoxCandidate]): Array[Byte] = {
- //todo: set initial capacity
- val w = Serializer.startWriter()
+}
- w.putUShort(inputs.length)
- inputs.foreach { i =>
- w.putBytes(i)
- }
- w.putUShort(outputCandidates.length)
- outputCandidates.foreach { c =>
- ErgoBoxCandidate.serializer.serializeBody(c, w)
- }
- w.toBytes
- }
+object ErgoLikeTransaction {
- def bytesToSign[IT <: UnsignedInput](tx: ErgoLikeTransactionTemplate[IT]): Array[Byte] =
- bytesToSign(tx.inputs.map(_.boxId), tx.outputCandidates)
-
- override def serializeBody(ftx: FlattenedTransaction, w: SigmaByteWriter): Unit = {
- w.putUShort(ftx.inputs.length)
- for (input <- ftx.inputs) {
- Input.serializer.serializeBody(input, w)
- }
- val digests = ftx.outputCandidates.flatMap(_.additionalTokens.map(_._1)).distinct
- w.putUInt(digests.length)
- digests.foreach { digest =>
- w.putBytes(digest)
- }
- w.putUShort(ftx.outputCandidates.length)
- for (out <- ftx.outputCandidates) {
- ErgoBoxCandidate.serializer.serializeBodyWithIndexedDigests(out, Some(digests), w)
- }
- }
+ val TransactionIdBytesSize: Short = 32
- override def parseBody(r: SigmaByteReader): FlattenedTransaction = {
- val inputsCount = r.getUShort()
- val inputsBuilder = mutable.ArrayBuilder.make[Input]()
- for (_ <- 0 until inputsCount) {
- inputsBuilder += Input.serializer.parseBody(r)
- }
- val digestsCount = r.getUInt().toInt
- val digestsBuilder = mutable.ArrayBuilder.make[Digest32]()
- for (_ <- 0 until digestsCount) {
- digestsBuilder += Digest32 @@ r.getBytes(TokenId.size)
- }
- val digests = digestsBuilder.result()
- val outsCount = r.getUShort()
- val outputCandidatesBuilder = mutable.ArrayBuilder.make[ErgoBoxCandidate]()
- for (_ <- 0 until outsCount) {
- outputCandidatesBuilder += ErgoBoxCandidate.serializer.parseBodyWithIndexedDigests(Some(digests), r)
- }
- FlattenedTransaction(inputsBuilder.result(), outputCandidatesBuilder.result())
- }
+ /**
+ * Bytes that should be signed by provers.
+ * Contains all the transaction bytes except of signatures
+ */
+ def bytesToSign[IT <: UnsignedInput](tx: ErgoLikeTransactionTemplate[IT]): Array[Byte] = {
+ val emptyProofInputs = tx.inputs.map(_.inputToSign)
+ val w = SigmaSerializer.startWriter()
+ val txWithoutProofs = new ErgoLikeTransaction(emptyProofInputs, tx.dataInputs, tx.outputCandidates)
+ ErgoLikeTransactionSerializer.serialize(txWithoutProofs, w)
+ w.toBytes
}
- object serializer extends Serializer[ErgoLikeTransaction, ErgoLikeTransaction] {
+ /**
+ * Creates ErgoLikeTransaction without data inputs
+ */
+ def apply(inputs: IndexedSeq[Input], outputCandidates: IndexedSeq[ErgoBoxCandidate]) =
+ new ErgoLikeTransaction(inputs, IndexedSeq(), outputCandidates)
- override def serializeBody(tx: ErgoLikeTransaction, w: SigmaByteWriter): Unit =
- flattenedTxSerializer.serializeBody(FlattenedTransaction(tx), w)
+ // TODO unify serialization approach in Ergo/sigma with BytesSerializable
+ val serializer: SigmaSerializer[ErgoLikeTransaction, ErgoLikeTransaction] = ErgoLikeTransactionSerializer
- override def parseBody(r: SigmaByteReader): ErgoLikeTransaction =
- ErgoLikeTransaction(flattenedTxSerializer.parseBody(r))
- }
}
diff --git a/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala b/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala
index ada7c8a9ae..bfed9b0124 100644
--- a/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala
+++ b/src/main/scala/org/ergoplatform/ErgoScriptPredef.scala
@@ -1,73 +1,197 @@
package org.ergoplatform
+import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
+import org.ergoplatform.settings.MonetarySettings
import sigmastate.SCollection.SByteArray
-import sigmastate.Values.{LongConstant, FuncValue, Value, ByteArrayConstant, IntConstant, ErgoTree, ValUse, ConcreteCollection}
+import sigmastate.Values._
import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.eval.IRContext
-import sigmastate.interpreter.Interpreter.ScriptEnv
-import sigmastate.lang.{TransformingSigmaBuilder, SigmaCompiler}
+import sigmastate.interpreter.CryptoConstants
import sigmastate.lang.Terms.ValueOps
-import sigmastate.utxo.{ExtractRegisterAs, _}
import sigmastate.{SLong, _}
+import sigmastate.lang.{TransformingSigmaBuilder, SigmaCompiler}
+import sigmastate.serialization.ErgoTreeSerializer
+import sigmastate.utxo._
object ErgoScriptPredef {
+
import sigmastate.interpreter.Interpreter._
- val compiler = new SigmaCompiler(TransformingSigmaBuilder)
- def compileWithCosting(env: ScriptEnv, code: String)(implicit IR: IRContext): Value[SType] = {
+ def compileWithCosting(env: ScriptEnv, code: String, networkPrefix: NetworkPrefix)(implicit IR: IRContext): Value[SType] = {
+ val compiler = new SigmaCompiler(networkPrefix, TransformingSigmaBuilder)
val interProp = compiler.typecheck(env, code)
val IR.Pair(calcF, _) = IR.doCosting(env, interProp)
IR.buildTree(calcF)
}
+ val FalseProp = ErgoTree.withoutSegregation(FalseSigmaProp)
+ val TrueProp = ErgoTree.withoutSegregation(TrueSigmaProp)
+
+ /**
+ * Byte array value of the serialized reward output script proposition with pk being substituted
+ * with given pk
+ *
+ * @param delta - number of blocks for which miner should hold this box before spending it
+ * @param minerPkBytesVal - byte array val for pk to substitute in the reward script
+ */
+ def expectedMinerOutScriptBytesVal(delta: Int, minerPkBytesVal: Value[SByteArray]): Value[SByteArray] = {
+ val genericPk = ProveDlog(CryptoConstants.dlogGroup.generator)
+ val genericMinerProp = rewardOutputScript(delta, genericPk)
+ val genericMinerPropBytes = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(genericMinerProp)
+ // first segregated constant is delta, so key is second constant
+ val positions = IntArrayConstant(Array[Int](1))
+ val minerPubkeySigmaProp = CreateProveDlog(DecodePoint(minerPkBytesVal))
+ val newVals = Values.ConcreteCollection(Vector[SigmaPropValue](minerPubkeySigmaProp), SSigmaProp)
+ SubstConstants(genericMinerPropBytes, positions, newVals)
+ }
+
/**
* Required script of the box, that collects mining rewards
*/
- def rewardOutputScript(delta: Int): ErgoTree = {
- import ErgoTree._
- val createdAtHeight = SelectField(ExtractCreationInfo(Self), 1).asLongValue
- val root = AND(
- GE(Height, Plus(createdAtHeight, IntConstant(delta))),
- ProveDlog(DecodePoint(Values.ConstantPlaceholder(0, SByteArray)))
+ def rewardOutputScript(delta: Int, minerPk: ProveDlog): SigmaPropValue = {
+ SigmaAnd(
+ GE(Height, Plus(boxCreationHeight(Self), IntConstant(delta))).toSigmaProp,
+ SigmaPropConstant(minerPk)
+ )
+ }
+
+ /**
+ * Proposition that allows to send coins to a box which is protected by the following proposition:
+ * prove dlog of miner's public key and height is at least `delta` blocks bigger then the current one.
+ */
+ def feeProposition(delta: Int = 720): SigmaPropValue = {
+ val out = ByIndex(Outputs, IntConstant(0))
+ AND(
+ EQ(Height, boxCreationHeight(out)),
+ EQ(ExtractScriptBytes(out), expectedMinerOutScriptBytesVal(delta, MinerPubkey)),
+ EQ(SizeOf(Outputs), 1)
+ ).toSigmaProp
+ }
+
+ /**
+ * A contract that only allows to collect emission reward by a box with miner proposition.
+ */
+ def emissionBoxProp(s: MonetarySettings): SigmaPropValue = {
+ val rewardOut = ByIndex(Outputs, IntConstant(0))
+ val minerOut = ByIndex(Outputs, IntConstant(1))
+
+ val minersReward = s.fixedRate - s.foundersInitialReward
+ val minersFixedRatePeriod = s.fixedRatePeriod + 2 * s.epochLength
+ val epoch = Plus(IntConstant(1), Divide(Minus(Height, IntConstant(s.fixedRatePeriod)), IntConstant(s.epochLength)))
+ val coinsToIssue = If(LT(Height, IntConstant(minersFixedRatePeriod)),
+ minersReward,
+ Minus(s.fixedRate, Multiply(s.oneEpochReduction, epoch.upcastTo(SLong)))
+ )
+ val sameScriptRule = EQ(ExtractScriptBytes(Self), ExtractScriptBytes(rewardOut))
+ val heightCorrect = EQ(boxCreationHeight(rewardOut), Height)
+ val heightIncreased = GT(Height, boxCreationHeight(Self))
+ val correctCoinsConsumed = EQ(coinsToIssue, Minus(ExtractAmount(Self), ExtractAmount(rewardOut)))
+ val lastCoins = LE(ExtractAmount(Self), s.oneEpochReduction)
+ val outputsNum = EQ(SizeOf(Outputs), 2)
+
+ val correctMinerOutput = AND(
+ EQ(ExtractScriptBytes(minerOut), expectedMinerOutScriptBytesVal(s.minerRewardDelay, MinerPubkey)),
+ EQ(Height, boxCreationHeight(minerOut))
)
- ErgoTree(ConstantSegregationHeader, Vector(ByteArrayConstant(Array.emptyByteArray)), root)
+ AND(
+ heightIncreased,
+ correctMinerOutput,
+ OR(AND(outputsNum, sameScriptRule, correctCoinsConsumed, heightCorrect), lastCoins)
+ ).toSigmaProp
}
- def rewardOutputScriptForCurrentMiner(delta: Int): Value[SByteArray] = {
- val expectedBytes = rewardOutputScript(delta).bytes
- val currentMinerScript = SubstConstants(
- ByteArrayConstant(expectedBytes),
- ConcreteCollection(IntConstant(0)),
- ConcreteCollection(MinerPubkey))
- currentMinerScript
+ /**
+ * Script for Ergo foundation box.
+ * The script allows to spend a box, if:
+ * - first transaction output contains at least EmissionRules.remainingFoundationAtHeight coins in it
+ * - first transaction output is protected by this script
+ * - conditions from the first non-mandatory register (R4) are satisfied
+ *
+ * Thus, this script always controls the level of emission and does not allow to take
+ * more coinы than prescribed by emission rules. In addition, it is protected by
+ * custom proposition in R4 which is assumed to be a simple 2-of-3 multisignature with
+ * public keys of foundation members in the beginning. When foundation members spend
+ * this box, they are free to put any new proposition to the R4 register, thus they
+ * may add or remove members, or change it to something more complicated like
+ * `tokenThresholdScript`.
+ */
+ def foundationScript(s: MonetarySettings): SigmaPropValue = {
+ // new output of the foundation
+ val newFoundationBox = ByIndex(Outputs, IntConstant(0))
+ // calculate number of coins, that are not issued yet and should be kept in `newFoundationBox`
+ // the same as Emission.remainingFoundationRewardAtHeight rewritten in Ergo script
+ val remainingAmount = {
+ val full15reward = (s.foundersInitialReward - 2 * s.oneEpochReduction) * s.epochLength
+ val full45reward = (s.foundersInitialReward - s.oneEpochReduction) * s.epochLength
+ val fixedRatePeriodMinus1: Int = s.fixedRatePeriod - 1
+
+ If(LT(Height, IntConstant(s.fixedRatePeriod)),
+ Plus(
+ LongConstant(full15reward + full45reward),
+ Multiply(s.foundersInitialReward, Upcast(Minus(fixedRatePeriodMinus1, Height), SLong))
+ ),
+ If(LT(Height, IntConstant(s.fixedRatePeriod + s.epochLength)),
+ Plus(
+ full15reward,
+ Multiply(
+ s.foundersInitialReward - s.oneEpochReduction,
+ Upcast(Minus(fixedRatePeriodMinus1 + s.epochLength, Height), SLong)
+ )
+ ),
+ If(LT(Height, IntConstant(s.fixedRatePeriod + 2 * s.epochLength)),
+ Multiply(
+ s.foundersInitialReward - 2 * s.oneEpochReduction,
+ Upcast(Minus(fixedRatePeriodMinus1 + 2 * s.epochLength, Height), SLong)
+ ),
+ LongConstant(0)
+ )
+ )
+ )
+ }
+ // check, that `newFoundationBox` contains at least `remainingAmount`
+ val amountCorrect = GE(ExtractAmount(newFoundationBox), remainingAmount)
+ // check, that `newFoundationBox` have the same protecting script
+ val sameScriptRule = EQ(ExtractScriptBytes(Self), ExtractScriptBytes(newFoundationBox))
+ // check, that additional rules defined by foundation members are satisfied
+ val customProposition = DeserializeRegister(ErgoBox.R4, SSigmaProp)
+ // combine 3 conditions above with AND conjunction
+ SigmaAnd(amountCorrect.toSigmaProp, sameScriptRule.toSigmaProp, customProposition)
}
/**
- * Proposition of the box, that may be taken by a transaction,
+ * Creation height of a box
+ */
+ def boxCreationHeight(box: Value[SBox.type]): Value[SInt.type] =
+ SelectField(ExtractCreationInfo(box), 1).asIntValue
+
+ /**
+ * Proposition of the box that may be spent by a transaction
* which inputs contains at least `thresholdAmount` of token with id `tokenId`.
- * The logic of this script is the following
+ * The logic of this script is following
* (v1) INPUTS.flatMap(box => box.tokens.filter(t => t._1 == tokenId).map(t => t._2)).sum >= thresholdAmount
* (v2) INPUTS.flatMap(box => box.tokens).filter(t => t._1 == tokenId).sum >= thresholdAmount
* (v3) INPUTS.map(box => box.tokens.find(t => t._1 == tokenId).map(t => t._2).getOrElse(0)).sum >= thresholdAmount
*/
- def tokenThresholdScript(tokenId: Array[Byte], thresholdAmount: Long)(implicit IR: IRContext): Value[SBoolean.type] = {
- val env = emptyEnv + ("tokenId" -> tokenId, "thresholdAmount" -> thresholdAmount)
+ def tokenThresholdScript(tokenId: Array[Byte], thresholdAmount: Long, networkPrefix: NetworkPrefix)
+ (implicit IR: IRContext): SigmaPropValue = {
+ val env = emptyEnv +
+ ("tokenId" -> tokenId, "thresholdAmount" -> thresholdAmount)
val res = compileWithCosting(env,
"""{
- | val sumValues = { (xs: Coll[Long]) => xs.fold(0L, { (acc: Long, amt: Long) => acc + amt }) }
- |
- | val tokenAmounts = INPUTS.map({ (box: Box) =>
- | val tokens = box.R2[Coll[(Coll[Byte], Long)]].get
- | sumValues(tokens.map { (tokenPair: (Coll[Byte], Long)) =>
- | val ourTokenAmount = if (tokenPair._1 == tokenId) tokenPair._2 else 0L
- | ourTokenAmount
- | })
- | })
- | val total = sumValues(tokenAmounts)
- | total >= thresholdAmount
- |}
- """.stripMargin )
- res.asBoolValue
+ | val sumValues = { (xs: Coll[Long]) => xs.fold(0L, { (acc: Long, amt: Long) => acc + amt }) }
+ |
+ | val tokenAmounts = INPUTS.map({ (box: Box) =>
+ | val tokens = box.R2[Coll[(Coll[Byte], Long)]].get
+ | sumValues(tokens.map { (tokenPair: (Coll[Byte], Long)) =>
+ | val ourTokenAmount = if (tokenPair._1 == tokenId) tokenPair._2 else 0L
+ | ourTokenAmount
+ | })
+ | })
+ | val total = sumValues(tokenAmounts)
+ | sigmaProp(total >= thresholdAmount)
+ |}
+ """.stripMargin, networkPrefix)
+ res.asSigmaProp
}
}
diff --git a/src/main/scala/org/ergoplatform/Input.scala b/src/main/scala/org/ergoplatform/Input.scala
index baa199ccb7..6d76934855 100644
--- a/src/main/scala/org/ergoplatform/Input.scala
+++ b/src/main/scala/org/ergoplatform/Input.scala
@@ -4,49 +4,68 @@ import java.util
import org.ergoplatform.ErgoBox.BoxId
import scorex.crypto.authds.ADKey
-import sigmastate.interpreter.ProverResult
-import sigmastate.serialization.Serializer
+import scorex.util.encode.Base16
+import sigmastate.interpreter.{ContextExtension, ProverResult}
+import sigmastate.serialization.SigmaSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
+/**
+ * Inputs, that are used to enrich script context, but won't be spent by the transaction
+ *
+ * @param boxId - id of a box to add into context (should be in UTXO)
+ */
+case class DataInput(boxId: BoxId)
+
+/**
+ * Inputs of formed, but unsigned transaction
+ *
+ * @param boxId - id of a box to spent
+ * @param extension - user-defined variables to be put into context
+ */
+class UnsignedInput(val boxId: BoxId, val extension: ContextExtension) {
+
+ def this(boxId: BoxId) = this(boxId, ContextExtension.empty)
-class UnsignedInput(val boxId: BoxId) {
require(boxId.size == BoxId.size, s"incorrect boxId size, expected: $BoxId.size, got: ${boxId.size}")
+ // todo check whether it is correct to compare inputs (Input use the same equals) by boxId only?
override def equals(obj: Any): Boolean = obj match {
case x: UnsignedInput => util.Arrays.equals(boxId, x.boxId)
case _ => false
}
-}
-object UnsignedInput {
- object serializer extends Serializer[UnsignedInput, UnsignedInput] {
-
- @inline
- override def serializeBody(obj: UnsignedInput, w: SigmaByteWriter): Unit =
- w.putBytes(obj.boxId)
-
- @inline
- override def parseBody(r: SigmaByteReader): UnsignedInput =
- new UnsignedInput(ADKey @@ r.getBytes(BoxId.size))
- }
+ /**
+ * Input, that should be signed by prover and verified by verifier.
+ * Contains all the input data except of signature itself.
+ */
+ def inputToSign: Input = Input(boxId: BoxId, ProverResult(Array[Byte](), extension))
}
+/**
+ * Fully signed transaction input
+ *
+ * @param boxId - id of a box to spent
+ * @param spendingProof - proof of spending correctness
+ */
case class Input(override val boxId: BoxId, spendingProof: ProverResult)
- extends UnsignedInput(boxId) {
+ extends UnsignedInput(boxId, spendingProof.extension) {
+ override def toString: String = s"Input(${Base16.encode(boxId)},$spendingProof)"
}
object Input {
- object serializer extends Serializer[Input, Input] {
- override def serializeBody(obj: Input, w: SigmaByteWriter): Unit = {
+ object serializer extends SigmaSerializer[Input, Input] {
+
+ override def serialize(obj: Input, w: SigmaByteWriter): Unit = {
w.putBytes(obj.boxId)
- ProverResult.serializer.serializeBody(obj.spendingProof, w)
+ ProverResult.serializer.serialize(obj.spendingProof, w)
}
- override def parseBody(r: SigmaByteReader): Input = {
+ override def parse(r: SigmaByteReader): Input = {
val boxId = r.getBytes(BoxId.size)
- val spendingProof = ProverResult.serializer.parseBody(r)
+ val spendingProof = ProverResult.serializer.parse(r)
Input(ADKey @@ boxId, spendingProof)
}
}
+
}
diff --git a/src/main/scala/org/ergoplatform/dsl/AvlTreeHelpers.scala b/src/main/scala/org/ergoplatform/dsl/AvlTreeHelpers.scala
new file mode 100644
index 0000000000..17268a9d4c
--- /dev/null
+++ b/src/main/scala/org/ergoplatform/dsl/AvlTreeHelpers.scala
@@ -0,0 +1,43 @@
+package org.ergoplatform.dsl
+
+import scalan.RType
+import special.collection.Coll
+import sigmastate.serialization.OperationSerializer
+import sigmastate.eval.{CAvlTree, CostingSigmaDslBuilder}
+import scorex.crypto.authds.{ADKey, ADValue}
+import scorex.crypto.hash.{Digest32, Blake2b256}
+import sigmastate.{AvlTreeData, AvlTreeFlags}
+import special.sigma.AvlTree
+import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Operation, Insert}
+
+object AvlTreeHelpers {
+ val Colls = CostingSigmaDslBuilder.Colls
+
+ /** Create authenticated dictionary with given allowed operations and key-value entries. */
+ def createAvlTree(flags: AvlTreeFlags, entries: (ADKey, ADValue)*): (AvlTree, BatchAVLProver[Digest32, Blake2b256.type]) = {
+ val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
+ val ok = entries.forall { case (key, value) =>
+ avlProver.performOneOperation(Insert(key, value)).isSuccess
+ }
+ val proof = avlProver.generateProof()
+ val digest = avlProver.digest
+ val treeData = new AvlTreeData(digest, flags, 32, None)
+ (CAvlTree(treeData), avlProver)
+ }
+
+ def serializeOperations(avlProver: BatchAVLProver[Digest32, Blake2b256.type], operations: Seq[Operation]): Coll[Byte] = {
+ val serializer = new OperationSerializer(avlProver.keyLength, avlProver.valueLengthOpt)
+ val opsBytes: Array[Byte] = serializer.serializeSeq(operations)
+ Colls.fromArray(opsBytes)
+ }
+
+ implicit class ADKeyArrayOps(arr: Array[ADKey]) {
+ def toColl: Coll[Coll[Byte]] = Colls.fromArray(arr.map(x => Colls.fromArray(x)))
+ }
+ implicit class ADKeyValueArrayOps(arr: Array[(ADKey, ADValue)]) {
+ def toColl: Coll[(Coll[Byte], Coll[Byte])] = {
+ val kvs = arr.map { case (k, v) => (Colls.fromArray(k), Colls.fromArray(v)) }
+ Colls.fromArray(kvs)
+ }
+ }
+}
diff --git a/src/main/scala/org/ergoplatform/dsl/ContractSpec.scala b/src/main/scala/org/ergoplatform/dsl/ContractSpec.scala
new file mode 100644
index 0000000000..7228f92b27
--- /dev/null
+++ b/src/main/scala/org/ergoplatform/dsl/ContractSpec.scala
@@ -0,0 +1,116 @@
+package org.ergoplatform.dsl
+
+import sigmastate.SType
+import org.ergoplatform.ErgoBox.{NonMandatoryRegisterId, BoxId}
+import sigmastate.interpreter.{ProverResult, CostedProverResult}
+import scalan.RType
+import org.ergoplatform.{ErgoLikeContext, ErgoBox}
+import special.sigma.{SigmaDslBuilder, AnyValue, SigmaProp}
+import sigmastate.Values.{ErgoTree, Constant}
+import sigmastate.eval.{IRContext, CostingSigmaDslBuilder, Evaluation}
+
+import scala.util.Try
+import org.ergoplatform.dsl.ContractSyntax.{Token, TokenId, ErgoScript, Proposition}
+import scala.language.implicitConversions
+
+trait ContractSpec {
+ val dsl: SigmaDslBuilder = CostingSigmaDslBuilder
+ val Colls = dsl.Colls
+
+ implicit def Coll[T](items: Array[T])(implicit cT: RType[T]) = Colls.fromArray(items)
+
+ val IR: IRContext
+
+ trait PropositionSpec {
+ def name: String
+ def dslSpec: Proposition
+ def scriptSpec: ErgoScript
+ def ergoTree: ErgoTree
+ }
+ object PropositionSpec {
+ def apply(name: String, dslSpec: Proposition, scriptSpec: ErgoScript) = mkPropositionSpec(name, dslSpec, scriptSpec)
+ }
+
+ private[dsl] def mkPropositionSpec(name: String, dslSpec: Proposition, scriptSpec: ErgoScript): PropositionSpec
+
+
+ trait ProtocolParty {
+ def name: String
+ }
+
+ /** Represents a participant of blockchain scenario (protocol). Participants are identified by `pubKey`
+ * and may have human readable names.
+ * This type of participant can generate proof for input boxes. */
+ trait ProvingParty extends ProtocolParty {
+ /** Public key of this party represented as sigma protocol proposition.
+ * Thus, it can be used in logical `&&`, `||` and `atLeast` propositions.
+ * For example `(HEIGHT > 10 && bob.pubKey) || (HEIGHT <= 10 && alice.pubKey). */
+ def pubKey: SigmaProp
+
+ /** Generate proof for the given `inBox`. The input box has attached guarding proposition,
+ * which is executed in the Context, specifically created for `inBox`.*/
+ def prove(inBox: InputBox, extensions: Map[Byte, AnyValue] = Map()): Try[CostedProverResult]
+ }
+ object ProvingParty {
+ def apply(name: String): ProvingParty = mkProvingParty(name)
+ }
+ protected def mkProvingParty(name: String): ProvingParty
+
+ trait VerifyingParty extends ProtocolParty {
+ /** Verifies the proof generated by the ProvingParty (using `prove` method) for the given `inBox`.*/
+ def verify(inBox: InputBox, proverResult: ProverResult): Boolean
+ }
+ object VerifyingParty {
+ def apply(name: String): VerifyingParty = mkVerifyingParty(name)
+ }
+ protected def mkVerifyingParty(name: String): VerifyingParty
+
+ trait InputBox {
+ def tx: TransactionCandidate
+ def utxoBox: OutBox
+ def runDsl(extensions: Map[Byte, AnyValue] = Map()): SigmaProp
+ private [dsl] def toErgoContext: ErgoLikeContext
+ }
+
+ trait OutBox {
+ def id: BoxId
+ def tx: TransactionCandidate
+ def boxIndex: Int
+ def value: Long
+ def propSpec: PropositionSpec
+ def withTokens(tokens: Token*): OutBox
+ def withRegs(regs: (NonMandatoryRegisterId, Any)*): OutBox
+ def token(id: TokenId): Token
+ private[dsl] def ergoBox: ErgoBox
+ }
+
+ trait TransactionCandidate {
+ def block: BlockCandidate
+ def dataInputs: Seq[InputBox]
+ def inputs: Seq[InputBox]
+ def outputs: Seq[OutBox]
+ def inBox(utxoBox: OutBox): InputBox
+ def outBox(value: Long, propSpec: PropositionSpec): OutBox
+ def spending(utxos: OutBox*): TransactionCandidate
+ def withDataInputs(dataBoxes: OutBox*): TransactionCandidate
+ }
+
+ trait ChainTransaction {
+ def outputs: Seq[OutBox]
+ }
+
+ /** Block which is already in blockchain. */
+ trait ChainBlock {
+ def getTransactions(): Seq[ChainTransaction]
+ }
+
+ /** Block which serve as transaction context. */
+ trait BlockCandidate {
+ def height: Int
+ def newTransaction(): TransactionCandidate
+ }
+
+ val MinErgValue = 1
+ def error(msg: String) = sys.error(msg)
+
+}
diff --git a/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala b/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala
new file mode 100644
index 0000000000..f719164a6b
--- /dev/null
+++ b/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala
@@ -0,0 +1,59 @@
+package org.ergoplatform.dsl
+
+import org.ergoplatform.{ErgoLikeContext, ErgoBox}
+import org.ergoplatform.ErgoBox.{NonMandatoryRegisterId, BoxId}
+import scalan.RType
+import sigmastate.SType
+import sigmastate.SType.AnyOps
+import org.ergoplatform.dsl.ContractSyntax.{Token, TokenId, ErgoScript, Proposition}
+import sigmastate.Values.{ErgoTree, Constant}
+import sigmastate.eval.{IRContext, CSigmaProp, CostingSigmaDslBuilder, Evaluation}
+import sigmastate.interpreter.{ProverResult, CostedProverResult}
+import sigmastate.interpreter.Interpreter.ScriptEnv
+import special.collection.Coll
+import special.sigma.{SigmaProp, SigmaContract, AnyValue, Context, DslSyntaxExtensions, SigmaDslBuilder}
+
+import scala.language.implicitConversions
+import scala.util.Try
+
+trait ContractSyntax { contract: SigmaContract =>
+ override def builder: SigmaDslBuilder = new CostingSigmaDslBuilder
+ val spec: ContractSpec
+ val syntax = new DslSyntaxExtensions(builder)
+ def contractEnv: ScriptEnv
+
+ /** The default verifier which represents miner's role in verification of transactions.
+ * It can be overriden in derived classes. */
+ lazy val verifier: spec.VerifyingParty = spec.VerifyingParty("Miner")
+
+ def Coll[T](items: T*)(implicit cT: RType[T]) = builder.Colls.fromItems(items:_*)
+
+ def proposition(name: String, dslSpec: Proposition, scriptCode: String) = {
+ val env = contractEnv.mapValues { v =>
+ val tV = Evaluation.rtypeOf(v).get
+ val treeType = Evaluation.toErgoTreeType(tV)
+ val data = Evaluation.fromDslData(v, treeType)
+ val elemTpe = Evaluation.rtypeToSType(treeType)
+ spec.IR.builder.mkConstant[SType](data.asWrappedType, elemTpe)
+ }
+ spec.mkPropositionSpec(name, dslSpec, ErgoScript(env, scriptCode))
+ }
+
+ def Env(entries: (String, Any)*): ScriptEnv = Map(entries:_*)
+}
+object ContractSyntax {
+ type Proposition = Context => SigmaProp
+ type TokenId = Coll[Byte]
+ case class ErgoScript(env: ScriptEnv, code: String)
+ case class Token(id: TokenId, value: Long)
+}
+
+trait SigmaContractSyntax extends SigmaContract with ContractSyntax {
+ override def canOpen(ctx: Context): Boolean = ???
+}
+
+
+
+
+
+
diff --git a/src/main/scala/org/ergoplatform/dsl/ErgoContractSpec.scala b/src/main/scala/org/ergoplatform/dsl/ErgoContractSpec.scala
new file mode 100644
index 0000000000..116a769a87
--- /dev/null
+++ b/src/main/scala/org/ergoplatform/dsl/ErgoContractSpec.scala
@@ -0,0 +1,45 @@
+package org.ergoplatform.dsl
+
+import special.collection.Coll
+import sigmastate.interpreter.CostedProverResult
+import sigmastate.eval.IRContext
+import org.ergoplatform.dsl.ContractSyntax.{Token, TokenId, ErgoScript, Proposition}
+import org.ergoplatform.ErgoBox.{NonMandatoryRegisterId, BoxId}
+
+class ErgoContractSpec(implicit val IR: IRContext) extends ContractSpec {
+
+ case class ErgoOutBox(tx: TransactionCandidate, boxIndex: Int, value: Long, propSpec: PropositionSpec)
+ extends OutBox {
+ override def id: BoxId = ???
+
+ override def withTokens(tokens: Token*): OutBox = ???
+
+ override def withRegs(regs: (NonMandatoryRegisterId, Any)*): OutBox = ???
+
+ override def token(id: TokenId): Token = ???
+
+ override private[dsl] def ergoBox = ???
+ }
+
+ trait TransactionContext {
+ def block: BlockCandidate
+ def attachProof(proofs: (InputBox, CostedProverResult)*): Unit
+ def submit(): Unit
+ }
+
+ def getBlock(height: Int): ChainBlock = ???
+ def getBoxesByParty(party: ProtocolParty): Seq[OutBox] = ???
+ def getBoxById(id: Coll[Byte]): OutBox = {
+// new ErgoOutBox()
+ ???
+ }
+ def newTransactionContext: TransactionContext = ???
+
+ override private[dsl] def mkPropositionSpec(name: String,
+ dslSpec: Proposition,
+ scriptSpec: ErgoScript) = ???
+
+ override protected def mkProvingParty(name: String): ProvingParty = ???
+
+ override protected def mkVerifyingParty(name: String): VerifyingParty = ???
+}
diff --git a/src/main/scala/org/ergoplatform/dsl/StdContracts.scala b/src/main/scala/org/ergoplatform/dsl/StdContracts.scala
new file mode 100644
index 0000000000..147a648c66
--- /dev/null
+++ b/src/main/scala/org/ergoplatform/dsl/StdContracts.scala
@@ -0,0 +1,37 @@
+package org.ergoplatform.dsl
+
+import org.ergoplatform.dsl.ContractSyntax.Token
+
+trait StdContracts { self: ContractSyntax =>
+ import spec._
+ def transferErgWithChange(tx: TransactionCandidate, from: OutBox, to: PropositionSpec, ergAmt: Long): (OutBox, Option[OutBox]) = {
+ val ergChange = from.value - ergAmt
+ if (ergChange < 0)
+ error(s"Cannot transfer $ergAmt Ergs from $from to $to: not enough Ergs")
+ val destBox = tx.outBox(ergAmt, to)
+ val changeBox = if (ergChange > 0) Some(tx.outBox(ergChange, from.propSpec))
+ else None
+ (destBox, changeBox)
+ }
+
+ def transferTokenWithChange(tx: TransactionCandidate, from: OutBox, to: PropositionSpec, tokenAmt: Token): (OutBox, Option[OutBox]) = {
+ val tokenChange = from.token(tokenAmt.id).value - tokenAmt.value
+ if (tokenChange < 0)
+ error(s"Cannot transfer $tokenAmt from $from to $to: not enough amount of token")
+
+ val ergChange = from.value - MinErgValue
+ if (ergChange < MinErgValue)
+ error(s"Cannot transfer $tokenAmt from $from to $to: not enough amount of Erg for two boxes")
+
+ val destBox = tx.outBox(MinErgValue, to)
+ .withTokens(tokenAmt)
+ val changeBox =
+ if (ergChange > 0) {
+ val box = tx.outBox(ergChange, from.propSpec)
+ Some(box)
+ }
+ else None
+ (destBox, changeBox)
+ }
+
+}
diff --git a/src/main/scala/org/ergoplatform/mining/emission/EmissionRules.scala b/src/main/scala/org/ergoplatform/mining/emission/EmissionRules.scala
new file mode 100644
index 0000000000..1614de0414
--- /dev/null
+++ b/src/main/scala/org/ergoplatform/mining/emission/EmissionRules.scala
@@ -0,0 +1,132 @@
+package org.ergoplatform.mining.emission
+
+import org.ergoplatform.settings.MonetarySettings
+
+import scala.annotation.tailrec
+
+/**
+ * Ergo coin emission curve.
+ *
+ * Mainnet properties:
+ * 1000000000 nanoErgs (minimal non-divisible parts) in one Erg
+ * a block is coming every 2 minutes
+ * fixed rate 75 coins during first 2 years
+ * reward reduction for 3 coins every 3 month after that
+ * 19710000 coins after the first year
+ * 97739925 coins total
+ *
+ * @param settings - network settings
+ */
+class EmissionRules(val settings: MonetarySettings) {
+
+ lazy val (coinsTotal, blocksTotal) = {
+ @tailrec
+ def loop(height: Int, acc: Long): (Long, Int) = {
+ val currentRate = emissionAtHeight(height)
+ if (currentRate > 0) {
+ loop(height + 1, acc + currentRate)
+ } else {
+ (acc, height - 1)
+ }
+ }
+
+ loop(1, 0)
+ }
+
+ val foundersCoinsTotal: Long = remainingFoundationRewardAtHeight(0)
+ val minersCoinsTotal: Long = coinsTotal - foundersCoinsTotal
+
+ /**
+ * Returns number of coins issued at height `h` and before that
+ */
+ def issuedCoinsAfterHeight(h: Long): Long = {
+ if (h < settings.fixedRatePeriod) {
+ settings.fixedRate * h
+ } else {
+ val fixedRateIssue: Long = settings.fixedRate * (settings.fixedRatePeriod - 1)
+ val epoch = (h - settings.fixedRatePeriod) / settings.epochLength
+ val fullEpochsIssued: Long = (1 to epoch.toInt).map { e =>
+ Math.max(settings.fixedRate - settings.oneEpochReduction * e, 0) * settings.epochLength
+ }.sum
+ val heightInThisEpoch = (h - settings.fixedRatePeriod) % settings.epochLength + 1
+ val rateThisEpoch = Math.max(settings.fixedRate - settings.oneEpochReduction * (epoch + 1), 0)
+ val thisEpochIssued = heightInThisEpoch * rateThisEpoch
+
+ fullEpochsIssued + fixedRateIssue + thisEpochIssued
+ }
+ }
+
+ /**
+ * Number not issued yet coins after height `h`
+ */
+ def remainingCoinsAfterHeight(h: Long): Long = coinsTotal - issuedCoinsAfterHeight(h)
+
+ /**
+ * Number of coins to be issued at height `h`
+ */
+ def emissionAtHeight(h: Long): Long = {
+ if (h < settings.fixedRatePeriod) {
+ settings.fixedRate
+ } else {
+ val epoch = 1 + (h - settings.fixedRatePeriod) / settings.epochLength
+ Math.max(settings.fixedRate - settings.oneEpochReduction * epoch, 0)
+ }
+ }.ensuring(_ >= 0, s"Negative at $h")
+
+ /**
+ * Returns number of coins issued at height `h` in favour of a miner
+ */
+ def minersRewardAtHeight(h: Long): Long = {
+ if (h < settings.fixedRatePeriod + 2 * settings.epochLength) {
+ settings.fixedRate - settings.foundersInitialReward
+ } else {
+ val epoch = 1 + (h - settings.fixedRatePeriod) / settings.epochLength
+ Math.max(settings.fixedRate - settings.oneEpochReduction * epoch, 0)
+ }
+ }
+
+ /**
+ * Returns number of coins which should be kept in the foundation box at height `h`
+ */
+ def remainingFoundationRewardAtHeight(h: Long): Long = {
+ val foundersInitialReward = settings.foundersInitialReward
+ val oneEpochReduction = settings.oneEpochReduction
+ val epochLength = settings.epochLength
+ val fixedRatePeriod = settings.fixedRatePeriod
+ val full15reward = (foundersInitialReward - 2 * oneEpochReduction) * epochLength
+ val full45reward = (foundersInitialReward - oneEpochReduction) * epochLength
+
+ if (h < fixedRatePeriod) {
+ full15reward + full45reward + (fixedRatePeriod - h - 1) * foundersInitialReward
+ } else if (h < fixedRatePeriod + epochLength) {
+ full15reward + (foundersInitialReward - oneEpochReduction) * (fixedRatePeriod + epochLength - h - 1)
+ } else if (h < fixedRatePeriod + (2 * epochLength)) {
+ (foundersInitialReward - 2 * oneEpochReduction) * (fixedRatePeriod + (2 * epochLength) - h - 1)
+ } else {
+ 0
+ }
+ }
+
+ /**
+ * Returns number of coins issued at height `h` in favour of the foundation
+ */
+ def foundationRewardAtHeight(h: Long): Long = {
+ if (h < settings.fixedRatePeriod) {
+ settings.foundersInitialReward
+ } else if (h < settings.fixedRatePeriod + settings.epochLength) {
+ settings.foundersInitialReward - settings.oneEpochReduction
+ } else if (h < settings.fixedRatePeriod + (2 * settings.epochLength)) {
+ settings.foundersInitialReward - 2 * settings.oneEpochReduction
+ } else {
+ 0
+ }
+ }
+
+}
+
+object EmissionRules {
+
+ val CoinsInOneErgo: Long = 1000000000
+
+}
+
diff --git a/src/main/scala/org/ergoplatform/settings/MonetarySettings.scala b/src/main/scala/org/ergoplatform/settings/MonetarySettings.scala
new file mode 100644
index 0000000000..f1b1a11da5
--- /dev/null
+++ b/src/main/scala/org/ergoplatform/settings/MonetarySettings.scala
@@ -0,0 +1,25 @@
+package org.ergoplatform.settings
+
+import org.ergoplatform.ErgoScriptPredef
+import org.ergoplatform.mining.emission.EmissionRules
+import sigmastate.Values.{Value, SigmaPropValue}
+import sigmastate.{SBoolean, Values}
+
+/**
+ * Configuration file for monetary settings of Ergo chain
+ *
+ * @see src/main/resources/application.conf for parameters description
+ */
+case class MonetarySettings(fixedRatePeriod: Int = 30 * 2 * 24 * 365,
+ epochLength: Int = 90 * 24 * 30,
+ fixedRate: Long = 75L * EmissionRules.CoinsInOneErgo,
+ oneEpochReduction: Long = 3L * EmissionRules.CoinsInOneErgo,
+ minerRewardDelay: Int = 720,
+ foundersInitialReward: Long = 75L * EmissionRules.CoinsInOneErgo / 10) {
+
+ val feeProposition: SigmaPropValue = ErgoScriptPredef.feeProposition(minerRewardDelay)
+ val feePropositionBytes: Array[Byte] = feeProposition.bytes
+ val emissionBoxProposition: SigmaPropValue = ErgoScriptPredef.emissionBoxProp(this)
+ val foundersBoxProposition: SigmaPropValue = ErgoScriptPredef.foundationScript(this)
+
+}
diff --git a/src/main/scala/sigmastate/AvlTreeData.scala b/src/main/scala/sigmastate/AvlTreeData.scala
index 945203603e..94535264e8 100644
--- a/src/main/scala/sigmastate/AvlTreeData.scala
+++ b/src/main/scala/sigmastate/AvlTreeData.scala
@@ -1,53 +1,95 @@
package sigmastate
-import java.util.{Arrays, Objects}
-
+import java.util
+import java.util.{Objects, Arrays}
import scorex.crypto.authds.ADDigest
-import sigmastate.serialization.Serializer
+import sigmastate.interpreter.CryptoConstants
+import sigmastate.serialization.SigmaSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-case class AvlTreeData( startingDigest: ADDigest,
- keyLength: Int,
- valueLengthOpt: Option[Int] = None,
- maxNumOperations: Option[Int] = None,
- maxDeletes: Option[Int] = None ) {
- override def equals(arg: Any) = arg match {
+
+case class AvlTreeFlags(insertAllowed: Boolean, updateAllowed: Boolean, removeAllowed: Boolean) {
+ def serializeToByte: Byte = AvlTreeFlags.serializeFlags(this)
+}
+
+object AvlTreeFlags {
+
+ lazy val ReadOnly = AvlTreeFlags(insertAllowed = false, updateAllowed = false, removeAllowed = false)
+
+ lazy val AllOperationsAllowed = AvlTreeFlags(insertAllowed = true, updateAllowed = true, removeAllowed = true)
+
+ def apply(serializedFlags: Byte): AvlTreeFlags = {
+ val insertAllowed = (serializedFlags & 0x01) != 0
+ val updateAllowed = (serializedFlags & 0x02) != 0
+ val removeAllowed = (serializedFlags & 0x04) != 0
+ AvlTreeFlags(insertAllowed, updateAllowed, removeAllowed)
+ }
+
+ def serializeFlags(avlTreeFlags: AvlTreeFlags): Byte = {
+ val readOnly = 0
+ val i = if(avlTreeFlags.insertAllowed) readOnly | 0x01 else readOnly
+ val u = if(avlTreeFlags.updateAllowed) i | 0x02 else i
+ val r = if(avlTreeFlags.removeAllowed) u | 0x04 else u
+ r.toByte
+ }
+}
+
+/**
+ * Type of data which efficiently authenticates potentially huge dataset having key-value dictionary interface.
+ * Only root hash of dynamic AVL+ tree, tree height, key length, optional value length, and access flags are stored
+ * in an instance of the datatype.
+ *
+ * Please note that standard hash function from CryptoConstants is used, and height is stored along with root hash of
+ * the tree, thus `digest` size is always CryptoConstants.hashLength + 1 bytes.
+ *
+ * @param digest authenticated tree digest: root hash along with tree height
+ * @param treeFlags - allowed modifications. See AvlTreeFlags description for details
+ * @param keyLength - all the elements under the tree have the same length
+ * @param valueLengthOpt - if non-empty, all the values under the tree are of the same length
+ */
+
+case class AvlTreeData(digest: ADDigest,
+ treeFlags: AvlTreeFlags,
+ keyLength: Int,
+ valueLengthOpt: Option[Int] = None) {
+ override def equals(arg: Any): Boolean = arg match {
case x: AvlTreeData =>
- Arrays.equals(startingDigest, x.startingDigest) &&
+ Arrays.equals(digest, x.digest) &&
keyLength == x.keyLength &&
valueLengthOpt == x.valueLengthOpt &&
- maxNumOperations == x.maxNumOperations &&
- maxDeletes == x.maxDeletes
+ treeFlags == x.treeFlags
case _ => false
}
- override def hashCode() =
- (Arrays.hashCode(startingDigest) * 31 +
- keyLength.hashCode()) * 31 + Objects.hash(valueLengthOpt, maxNumOperations, maxDeletes)
+ override def hashCode(): Int =
+ (util.Arrays.hashCode(digest) * 31 +
+ keyLength.hashCode()) * 31 + Objects.hash(valueLengthOpt, treeFlags)
}
object AvlTreeData {
- val dummy = new AvlTreeData(ADDigest @@ Array.fill(32)(0:Byte), keyLength = 32)
+ val DigestSize: Int = CryptoConstants.hashLength + 1 //please read class comments above for details
+ val TreeDataSize = DigestSize + 3 + 4 + 4
+
+ val dummy =
+ new AvlTreeData(ADDigest @@ Array.fill(DigestSize)(0:Byte), AvlTreeFlags.AllOperationsAllowed, keyLength = 32)
- object serializer extends Serializer[AvlTreeData, AvlTreeData] {
+ object serializer extends SigmaSerializer[AvlTreeData, AvlTreeData] {
- override def serializeBody(data: AvlTreeData, w: SigmaByteWriter): Unit = {
- w.putUByte(data.startingDigest.length)
- .putBytes(data.startingDigest)
+ override def serialize(data: AvlTreeData, w: SigmaByteWriter): Unit = {
+ val tf = AvlTreeFlags.serializeFlags(data.treeFlags)
+ w.putBytes(data.digest)
+ .putUByte(tf)
.putUInt(data.keyLength)
.putOption(data.valueLengthOpt)(_.putUInt(_))
- .putOption(data.maxNumOperations)(_.putUInt(_))
- .putOption(data.maxDeletes)(_.putUInt(_))
}
- override def parseBody(r: SigmaByteReader): AvlTreeData = {
- val startingDigestLen = r.getUByte()
- val startingDigest = r.getBytes(startingDigestLen)
+ override def parse(r: SigmaByteReader): AvlTreeData = {
+ val digest = r.getBytes(DigestSize)
+ val tf = AvlTreeFlags(r.getByte())
val keyLength = r.getUInt().toInt
val valueLengthOpt = r.getOption(r.getUInt().toInt)
- val maxNumOperations = r.getOption(r.getUInt().toInt)
- val maxDeletes = r.getOption(r.getUInt().toInt)
- AvlTreeData(ADDigest @@ startingDigest, keyLength, valueLengthOpt, maxNumOperations, maxDeletes)
+ AvlTreeData(ADDigest @@ digest, tf, keyLength, valueLengthOpt)
}
}
+
}
diff --git a/src/main/scala/sigmastate/SigSerializer.scala b/src/main/scala/sigmastate/SigSerializer.scala
index dcf5fa6b1f..3f45073702 100644
--- a/src/main/scala/sigmastate/SigSerializer.scala
+++ b/src/main/scala/sigmastate/SigSerializer.scala
@@ -1,14 +1,14 @@
package sigmastate
import org.bouncycastle.util.BigIntegers
-import sigmastate.basics.DLogProtocol.{ProveDlog, SecondDLogProverMessage}
+import sigmastate.basics.DLogProtocol.{SecondDLogProverMessage, ProveDlog}
import sigmastate.basics.VerifierMessage.Challenge
-import sigmastate.Values.Value
+import sigmastate.Values.{Value, SigmaBoolean}
import sigmastate.interpreter.CryptoConstants
import sigmastate.utils.Helpers
import Helpers.xor
import gf2t.GF2_192_Poly
-import sigmastate.basics.{ProveDHTuple, SecondDiffieHellmanTupleProverMessage}
+import sigmastate.basics.{SecondDiffieHellmanTupleProverMessage, ProveDHTuple}
object SigSerializer {
@@ -63,7 +63,7 @@ object SigSerializer {
}
- def parseAndComputeChallenges(exp: Value[SBoolean.type], bytes: Array[Byte]): UncheckedTree = {
+ def parseAndComputeChallenges(exp: SigmaBoolean, bytes: Array[Byte]): UncheckedTree = {
/**
* Verifier Step 2: In a top-down traversal of the tree, obtain the challenges for the children of every
@@ -77,7 +77,7 @@ object SigSerializer {
* else it needs to be read from the proof
* @return
*/
- def traverseNode(exp: Value[SBoolean.type],
+ def traverseNode(exp: SigmaBoolean,
bytes: Array[Byte],
pos: Int,
challengeOpt: Option[Challenge] = None): (UncheckedSigmaTree, Int) = {
diff --git a/src/main/scala/sigmastate/UnprovenTree.scala b/src/main/scala/sigmastate/UnprovenTree.scala
index b00cb63f3b..59acd61967 100644
--- a/src/main/scala/sigmastate/UnprovenTree.scala
+++ b/src/main/scala/sigmastate/UnprovenTree.scala
@@ -6,9 +6,10 @@ import com.google.common.primitives.Shorts
import gf2t.GF2_192_Poly
import sigmastate.basics.DLogProtocol.{FirstDLogProverMessage, ProveDlog}
import sigmastate.basics.VerifierMessage.Challenge
-import sigmastate.Values.SigmaBoolean
-import sigmastate.basics.{FirstDiffieHellmanTupleProverMessage, FirstProverMessage, ProveDHTuple}
+import sigmastate.Values.{SigmaBoolean, SigmaPropConstant}
+import sigmastate.basics.{FirstProverMessage, ProveDHTuple, FirstDiffieHellmanTupleProverMessage}
import sigmastate.serialization.ErgoTreeSerializer
+import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer
import scala.language.existentials
@@ -138,7 +139,7 @@ object FiatShamirTree {
def traverseNode(node: ProofTree): Array[Byte] = node match {
case l: ProofTreeLeaf =>
- val propBytes = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(l.proposition)
+ val propBytes = DefaultSerializer.serializeWithSegregation(SigmaPropConstant(l.proposition))
val commitmentBytes = l.commitmentOpt.get.bytes
leafPrefix +:
((Shorts.toByteArray(propBytes.length.toShort) ++ propBytes) ++
@@ -147,12 +148,13 @@ object FiatShamirTree {
case c: ProofTreeConjecture =>
val childrenCountBytes = Shorts.toByteArray(c.children.length.toShort)
val conjBytes = Array(internalNodePrefix, c.conjectureType.id.toByte)
- // TODO: this is lame -- there should be a better way
- val thresholdByte = if (c.isInstanceOf[CThresholdUnproven]) {
- Array(c.asInstanceOf[CThresholdUnproven].k.toByte)
- } else if(c.isInstanceOf[CThresholdUncheckedNode]) {
- Array(c.asInstanceOf[CThresholdUncheckedNode].k.toByte)
- } else Array()
+ val thresholdByte = c match {
+ case unproven: CThresholdUnproven =>
+ Array(unproven.k.toByte)
+ case unchecked: CThresholdUncheckedNode =>
+ Array(unchecked.k.toByte)
+ case _ => Array()
+ }
c.children.foldLeft(conjBytes ++ thresholdByte ++ childrenCountBytes) { case (acc, ch) =>
acc ++ traverseNode(ch)
diff --git a/src/main/scala/sigmastate/Values.scala b/src/main/scala/sigmastate/Values.scala
index 934d544853..588cb4fbe7 100644
--- a/src/main/scala/sigmastate/Values.scala
+++ b/src/main/scala/sigmastate/Values.scala
@@ -7,22 +7,35 @@ import org.bitbucket.inkytonik.kiama.relation.Tree
import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{strategy, everywherebu}
import org.bouncycastle.math.ec.ECPoint
import org.ergoplatform.{ErgoLikeContext, ErgoBox}
+import scalan.Nullable
import scorex.crypto.authds.SerializedAdProof
import scorex.crypto.authds.avltree.batch.BatchAVLVerifier
import scorex.crypto.hash.{Digest32, Blake2b256}
+import scalan.util.CollectionUtil._
+import scorex.util.serialization.Serializer
import sigmastate.SCollection.SByteArray
import sigmastate.interpreter.CryptoConstants.EcPointType
import sigmastate.interpreter.{Context, CryptoConstants, CryptoFunctions}
-import sigmastate.serialization.{ValueSerializer, ErgoTreeSerializer, OpCodes, ConstantStore}
+import sigmastate.serialization._
+import sigmastate.serialization.{ErgoTreeSerializer, OpCodes, ConstantStore}
import sigmastate.serialization.OpCodes._
import sigmastate.utxo.CostTable.Cost
-import sigmastate.utils.Extensions._
+import sigma.util.Extensions._
+import sigmastate.TrivialProp.{FalseProp, TrueProp}
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.basics.ProveDHTuple
import sigmastate.lang.Terms._
import sigmastate.utxo._
+import special.sigma.Extensions._
import scala.language.implicitConversions
import scala.reflect.ClassTag
import sigmastate.lang.DefaultSigmaBuilder._
+import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer
+import sigmastate.serialization.transformers.ProveDHTupleSerializer
+import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
+import special.sigma.{Header, Extensions, AnyValue, TestValue, PreHeader}
+import sigmastate.lang.SourceContext
object Values {
@@ -42,7 +55,7 @@ object Values {
* the type of operation result. */
def tpe: S
- lazy val bytes = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(this)
+ lazy val bytes = DefaultSerializer.serializeWithSegregation(this)
/** Every value represents an operation and that operation can be associated with a function type,
* describing functional meaning of the operation, kind of operation signature.
@@ -59,6 +72,29 @@ object Values {
def opName: String = this.getClass.getSimpleName
def opId: OperationId = OperationId(opName, opType)
+
+ /** Parser has some source information like line,column in the text. We need to keep it up until RuntimeCosting.
+ * The way to do this is to add Nullable property to every Value. Since Parser is always using SigmaBuilder
+ * to create nodes,
+ * Adding additional (implicit source: SourceContext) parameter to every builder method would pollute its API
+ * and also doesn't make sence during deserialization, where Builder is also used.
+ * We can assume some indirect mechanism to pass current source context into every mkXXX method of Builder.
+ * We can pass it using `scala.util.DynamicVariable` by wrapping each mkXXX call into `withValue { }` calls.
+ * The same will happen in Typer.
+ * We can take sourceContext from untyped nodes and use it while creating typed nodes.
+ * And we can make sourceContext of every Value writeOnce value, i.e. it will be Nullable.Null by default,
+ * but can be set afterwards, but only once.
+ * This property will not participate in equality and other operations, so will be invisible for existing code.
+ * But Builder can use it to set sourceContext if it is present.
+ */
+ private[sigmastate] var _sourceContext: Nullable[SourceContext] = Nullable.None
+ def sourceContext: Nullable[SourceContext] = _sourceContext
+ def sourceContext_=(srcCtx: Nullable[SourceContext]): Unit =
+ if (_sourceContext.isEmpty) {
+ _sourceContext = srcCtx
+ } else {
+ sys.error("_sourceContext can be set only once")
+ }
}
trait ValueCompanion extends SigmaNodeCompanion {
@@ -93,7 +129,7 @@ object Values {
val value: S#WrappedType
def opType: SFunc = {
val resType = tpe match {
- case ct @ SCollection(tItem) =>
+ case ct : SCollection[_] =>
SCollection(ct.typeParams.head.ident)
case ft @ SFunc(tD, tR, _) =>
ft.getGenericType
@@ -119,8 +155,10 @@ object Values {
override def hashCode(): Int = Arrays.deepHashCode(Array(value.asInstanceOf[AnyRef], tpe))
override def toString: String = tpe.asInstanceOf[SType] match {
- case SGroupElement =>
- s"ConstantNode(${CryptoFunctions.showECPoint(value.asInstanceOf[ECPoint])},$tpe)"
+ case SGroupElement if value.isInstanceOf[ECPoint] =>
+ s"ConstantNode(${showECPoint(value.asInstanceOf[ECPoint])},$tpe)"
+ case SGroupElement =>
+ sys.error(s"Invalid value in Constant($value, $tpe)")
case SInt => s"IntConstant($value)"
case SLong => s"LongConstant($value)"
case SBoolean if value == true => "TrueLeaf"
@@ -166,7 +204,7 @@ object Values {
TaggedVariableNode(varId, tpe)
}
- case object UnitConstant extends EvaluatedValue[SUnit.type] {
+ case class UnitConstant() extends EvaluatedValue[SUnit.type] {
override val opCode = UnitConstantCode
override def tpe = SUnit
val value = ()
@@ -260,8 +298,13 @@ object Values {
}
}
+ val FalseSigmaProp = SigmaPropConstant(TrivialProp.FalseProp)
+ val TrueSigmaProp = SigmaPropConstant(TrivialProp.TrueProp)
+
+ implicit def boolToSigmaProp(b: BoolValue): SigmaPropValue = BoolToSigmaProp(b)
+
object SigmaPropConstant {
- def apply(value: SigmaBoolean): Constant[SSigmaProp.type] = Constant[SSigmaProp.type](value, SSigmaProp)
+ def apply(value: SigmaBoolean): Constant[SSigmaProp.type] = Constant[SSigmaProp.type](value, SSigmaProp)
def unapply(v: SValue): Option[SigmaBoolean] = v match {
case Constant(value: SigmaBoolean, SSigmaProp) => Some(value)
case _ => None
@@ -279,12 +322,10 @@ object Values {
implicit class AvlTreeConstantOps(val c: AvlTreeConstant) extends AnyVal {
def createVerifier(proof: SerializedAdProof) =
new BatchAVLVerifier[Digest32, Blake2b256.type](
- c.value.startingDigest,
+ c.value.digest,
proof,
c.value.keyLength,
- c.value.valueLengthOpt,
- c.value.maxNumOperations,
- c.value.maxDeletes)
+ c.value.valueLengthOpt)
}
object ContextConstant {
@@ -295,6 +336,22 @@ object Values {
}
}
+ object PreHeaderConstant {
+ def apply(value: PreHeader): Constant[SPreHeader.type] = Constant[SPreHeader.type](value, SPreHeader)
+ def unapply(v: SValue): Option[PreHeader] = v match {
+ case Constant(value: PreHeader, SPreHeader) => Some(value)
+ case _ => None
+ }
+ }
+
+ object HeaderConstant {
+ def apply(value: Header): Constant[SHeader.type] = Constant[SHeader.type](value, SHeader)
+ def unapply(v: SValue): Option[Header] = v match {
+ case Constant(value: Header, SHeader) => Some(value)
+ case _ => None
+ }
+ }
+
trait NotReadyValueByte extends NotReadyValue[SByte.type] {
override def tpe = SByte
}
@@ -491,24 +548,72 @@ object Values {
override def tpe = SBoolean
}
- /**
- * For sigma statements
+ /** Algebraic data type of sigma proposition expressions.
+ * Values of this type are used as values of SigmaProp type of SigmaScript and SigmaDsl
*/
- trait SigmaBoolean extends NotReadyValue[SBoolean.type] {
- override def tpe = SBoolean
+ trait SigmaBoolean /*extends NotReadyValue[SBoolean.type]*/ {
+ def tpe = SBoolean
- def fields: Seq[(String, SType)] = SigmaBoolean.fields
/** This is not used as operation, but rather as data value of SigmaProp type. */
def opType: SFunc = Value.notSupportedError(this, "opType")
+
+ /** Unique id of the node class used in serialization of SigmaBoolean. */
+ val opCode: OpCode
}
object SigmaBoolean {
val PropBytes = "propBytes"
- val IsProven = "isProven"
- val fields = Seq(
- PropBytes -> SByteArray,
- IsProven -> SBoolean
- )
+ val IsValid = "isValid"
+ object serializer extends SigmaSerializer[SigmaBoolean, SigmaBoolean] {
+ val dhtSerializer = ProveDHTupleSerializer(ProveDHTuple.apply)
+ val dlogSerializer = ProveDlogSerializer(ProveDlog.apply)
+
+ override def serialize(data: SigmaBoolean, w: SigmaByteWriter): Unit = {
+ w.put(data.opCode)
+ data match {
+ case dlog: ProveDlog => dlogSerializer.serialize(dlog, w)
+ case dht: ProveDHTuple => dhtSerializer.serialize(dht, w)
+ case _: TrivialProp => // besides opCode no additional bytes
+ case and: CAND =>
+ w.putUShort(and.sigmaBooleans.length)
+ for (c <- and.sigmaBooleans)
+ serializer.serialize(c, w)
+ case or: COR =>
+ w.putUShort(or.sigmaBooleans.length)
+ for (c <- or.sigmaBooleans)
+ serializer.serialize(c, w)
+ case th: CTHRESHOLD =>
+ w.putUShort(th.k)
+ w.putUShort(th.sigmaBooleans.length)
+ for (c <- th.sigmaBooleans)
+ serializer.serialize(c, w)
+ }
+ }
+
+ override def parse(r: SigmaByteReader): SigmaBoolean = {
+ val opCode = r.getByte()
+ val res = opCode match {
+ case FalseProp.opCode => FalseProp
+ case TrueProp.opCode => TrueProp
+ case ProveDlogCode => dlogSerializer.parse(r)
+ case ProveDiffieHellmanTupleCode => dhtSerializer.parse(r)
+ case AndCode =>
+ val n = r.getUShort()
+ val children = (0 until n).map(_ => serializer.parse(r))
+ CAND(children)
+ case OrCode =>
+ val n = r.getUShort()
+ val children = (0 until n).map(_ => serializer.parse(r))
+ COR(children)
+ case AtLeastCode =>
+ val k = r.getUShort()
+ val n = r.getUShort()
+ val children = (0 until n).map(_ => serializer.parse(r))
+ CTHRESHOLD(k, children)
+ }
+ res
+ }
+ }
}
trait NotReadyValueBox extends NotReadyValue[SBox.type] {
@@ -598,12 +703,25 @@ object Values {
}
implicit class SigmaBooleanOps(val sb: SigmaBoolean) extends AnyVal {
+ def toSigmaProp: SigmaPropValue = SigmaPropConstant(sb)
def isProven: Value[SBoolean.type] = SigmaPropIsProven(SigmaPropConstant(sb))
def propBytes: Value[SByteArray] = SigmaPropBytes(SigmaPropConstant(sb))
+ def toAnyValue: AnyValue = Extensions.toAnyValue(sb)(SType.SigmaBooleanRType)
+ def showToString: String = sb match {
+ case ProveDlog(v) =>
+ s"ProveDlog(${showECPoint(v)})"
+ case ProveDHTuple(gv, hv, uv, vv) =>
+ s"ProveDHTuple(${showECPoint(gv)}, ${showECPoint(hv)}, ${showECPoint(uv)}, ${showECPoint(vv)})"
+ case _ => sb.toString
+ }
}
implicit class BoolValueOps(val b: BoolValue) extends AnyVal {
- def toSigmaProp: SigmaPropValue = BoolToSigmaProp(b)
+ def toSigmaProp: SigmaPropValue = b match {
+ case b if b.tpe == SBoolean => BoolToSigmaProp(b)
+ case p if p.tpe == SSigmaProp => p.asSigmaProp
+ case _ => sys.error(s"Expected SBoolean or SSigmaProp typed value, but was: $b")
+ }
}
sealed trait BlockItem extends NotReadyValue[SType] {
@@ -732,13 +850,13 @@ object Values {
case class ErgoTree private(
header: Byte,
constants: IndexedSeq[Constant[SType]],
- root: SValue,
- proposition: SValue
+ root: SigmaPropValue,
+ proposition: SigmaPropValue
) {
assert(isConstantSegregation || constants.isEmpty)
@inline def isConstantSegregation: Boolean = ErgoTree.isConstantSegregation(header)
- @inline def bytes: Array[Byte] = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(this)
+ @inline def bytes: Array[Byte] = DefaultSerializer.serializeErgoTree(this)
}
object ErgoTree {
@@ -754,7 +872,7 @@ object Values {
/** Default header with constant segregation enabled. */
val ConstantSegregationHeader = (DefaultHeader | ConstantSegregationFlag).toByte
- @inline def isConstantSegregation(header: Byte): Boolean = (header & ErgoTree.ConstantSegregationFlag) != 0
+ @inline def isConstantSegregation(header: Byte): Boolean = (header & ConstantSegregationFlag) != 0
def substConstants(root: SValue, constants: IndexedSeq[Constant[SType]]): SValue = {
val store = new ConstantStore(constants)
@@ -766,19 +884,32 @@ object Values {
everywherebu(substRule)(root).fold(root)(_.asInstanceOf[SValue])
}
- def apply(header: Byte, constants: IndexedSeq[Constant[SType]], root: SValue) = {
- if ((header & ConstantSegregationFlag) != 0) {
- val prop = substConstants(root, constants)
+ def apply(header: Byte, constants: IndexedSeq[Constant[SType]], root: SigmaPropValue) = {
+ if (isConstantSegregation(header)) {
+ val prop = substConstants(root, constants).asSigmaProp
new ErgoTree(header, constants, root, prop)
} else
new ErgoTree(header, constants, root, root)
}
- implicit def fromProposition(prop: SValue): ErgoTree = {
- // get ErgoTree with segregated constants
- // todo rewrite with everywherebu?
- ErgoTreeSerializer.DefaultSerializer
- .deserializeErgoTree(ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(prop))
+ val EmptyConstants = IndexedSeq.empty[Constant[SType]]
+
+ def withoutSegregation(root: SigmaPropValue) = {
+ ErgoTree(ErgoTree.DefaultHeader, EmptyConstants, root)
+ }
+
+ implicit def fromProposition(prop: SigmaPropValue): ErgoTree = {
+ prop match {
+ case SigmaPropConstant(_) => withoutSegregation(prop)
+ case _ =>
+ // get ErgoTree with segregated constants
+ // todo rewrite with everywherebu?
+ DefaultSerializer.deserializeErgoTree(DefaultSerializer.serializeWithSegregation(prop))
+ }
+ }
+
+ implicit def fromSigmaBoolean(pk: SigmaBoolean): ErgoTree = {
+ withoutSegregation(pk.toSigmaProp)
}
}
diff --git a/src/main/scala/sigmastate/basics/BcDlogFp.scala b/src/main/scala/sigmastate/basics/BcDlogGroup.scala
similarity index 54%
rename from src/main/scala/sigmastate/basics/BcDlogFp.scala
rename to src/main/scala/sigmastate/basics/BcDlogGroup.scala
index 89b19f4157..8c3fc7d50a 100644
--- a/src/main/scala/sigmastate/basics/BcDlogFp.scala
+++ b/src/main/scala/sigmastate/basics/BcDlogGroup.scala
@@ -5,15 +5,15 @@ import java.math.BigInteger
import org.bouncycastle.asn1.x9.X9ECParameters
import org.bouncycastle.crypto.ec.CustomNamedCurves
import org.bouncycastle.math.ec.custom.djb.Curve25519Point
-import org.bouncycastle.math.ec.custom.sec.{SecP384R1Point, SecP521R1Point}
-import org.bouncycastle.math.ec.{ECFieldElement, ECPoint}
+import org.bouncycastle.math.ec.custom.sec.{SecP256K1Point, SecP384R1Point, SecP521R1Point}
+import org.bouncycastle.math.ec.ECPoint
import org.bouncycastle.util.BigIntegers
import scala.collection.mutable
import scala.util.Try
-abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) extends DlogGroup[ElemType] {
+abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) extends DlogGroup[ElemType] {
lazy val curve = x9params.getCurve
@@ -98,7 +98,7 @@ abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) exten
}
//map for multExponentiationsWithSameBase calculations
- private val exponentiationsMap = mutable.Map[ElemType, GroupElementsExponentiations]()
+ private val exponentiationsCache = mutable.Map[ElemType, GroupElementsExponentiations]()
//Create the generator
@@ -117,156 +117,6 @@ abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) exten
Try(curve.validatePoint(x, y)).isSuccess
}
- /**
- * This function finds the y coordinate of a point in the curve for a given x, if it exists.
- *
- * @param x
- * @return the y coordinate of point in the curve for a given x, if it exists
- * else, null
- */
- def findYInCurveEquationForX(x: BigInteger): BigInteger = {
- /* get a, b, p from group params */
- val a = x9params.getCurve.getA.toBigInteger
- val b = x9params.getCurve.getB.toBigInteger
- // compute x^3
- val x3 = x.modPow(new BigInteger("3"), p)
- // compute x^3+ax+b
- val rightSide = x3.add(a.multiply(x)).add(b).mod(p)
- //try to compute y = square_root(x^3+ax+b)
- //If it exists return it
- //else, return null
- //We compute the square root via the ECFieldElement.Fp of Bouncy Castle, since BigInteger does not implement this function.
- //ECFieldElement.Fp ySquare = new ECFieldElement.Fp(params.getQ(), rightSide);
- val ySquare = new ECFieldElement.Fp(p, rightSide)
- //TODO I am not sure which one of the square roots it returns (if they exist). We need to check this!! (Yael)
- val y = ySquare.sqrt.asInstanceOf[ECFieldElement.Fp]
- if (y != null) y.toBigInteger.mod(p)
- else null
- }
-
- /**
- * This function receives any string of size up to k bytes (as returned by CalcK), finds the coordinates of the point that is the encoding of this binary string.
- *
- * @param binaryString
- * @throws IndexOutOfBoundsException if the length of the binary array to encode is longer than k
- * @return an FpPoint with the coordinates of the corresponding GroupElement point or null if could not find the encoding in reasonable time
- */
- def findPointRepresentedByByteArray(binaryString: Array[Byte]): Try[ElemType] = Try { //Pseudo-code:
- /*If the length of binaryString exceeds k then throw IndexOutOfBoundsException.
-
- Let L be the length in bytes of p
-
- Choose a random byte array r of length L - k - 2 bytes
-
- Prepare a string newString of the following form: r || binaryString || binaryString.length (where || denotes concatenation) (i.e., the least significant byte of newString is the length of binaryString in bytes)
-
- Convert the result to a BigInteger (bIString)
-
- Compute the elliptic curve equation for this x and see if there exists a y such that (x,y) satisfies the equation.
-
- If yes, return (x,y)
-
- Else, go back to step 3 (choose a random r etc.) up to 80 times (This is an arbitrary hard-coded number).
-
- If did not find y such that (x,y) satisfies the equation after 80 trials then return null.
- */
- if (binaryString.length > k) throw new IndexOutOfBoundsException("The binary array to encode is too long.")
- val l = p.bitLength / 8
- val randomArray = new Array[Byte](l - k - 2)
- //Create a random object and make it seed itself:
- val newString = new Array[Byte](randomArray.length + 1 + binaryString.length)
- var counter = 0
- var y: BigInteger = null
- var x: BigInteger = null
- do {
- secureRandom.nextBytes(randomArray)
- System.arraycopy(randomArray, 0, newString, 0, randomArray.length)
- System.arraycopy(binaryString, 0, newString, randomArray.length, binaryString.length)
- newString(newString.length - 1) = binaryString.length.toByte
- //Convert the result to a BigInteger (bIString)
- x = new BigInteger(newString)
- if (x.compareTo(BigInteger.ZERO) < 0) {
- val temp = x.toByteArray
- val t0 = temp(0)
- temp(0) = (-t0).toByte
- x = new BigInteger(temp)
- }
- //Compute the elliptic curve equation for this x and see if there exists a y such that (x,y) satisfies the equation.
- //If yes, return (x,y)
- //Else, go back to choose a random r etc.)
- y = findYInCurveEquationForX(x)
- counter += 1
- } while ( {
- (y == null) && (counter <= 80) // todo: magic number
- }) //we limit the amount of times we try to 80 which is an arbitrary number.
-
- //If found the correct y in reasonable time then return the (x,y) FpPoint
- if (y != null) curve.createPoint(x, y).asInstanceOf[ElemType]
- else throw new Exception("Had no success within a certain number of iterations in findPointRepresentedByByteArray")
- }
-
-
- /**
- * checks if the given point is in the given dlog group with the q prime order.
- * A point is in the group if it in the q-order group which is a sub-group of the Elliptic Curve.
- * Base assumption of this function is that checkCurveMembership function is already been called and returned true.
- *
- * @param point
- * @return true if the given point is in the given dlog group.
- */
- def checkSubGroupMembership(point: ElemType): Boolean = { //we assume that the point is on the curve group
- //get the cofactor of the group
- val h = x9params.getH
- //if the cofactor is 1 the sub-group is same as the elliptic curve equation which the point is in.
- if (h == BigInteger.ONE) return true
- val y = point.getYCoord.toBigInteger
- //if the cofactor is greater than 1, the point must have order q (same as the order of the group)
- //if the cofactor is 2 and the y coefficient is 0, the point has order 2 and is not in the group
- if (h == new BigInteger("2")) if (y == BigInteger.ZERO) return false
- else return true
- // if the cofactor is 3 and p^2 = p^(-1), the point has order 3 and is not in the group
- if (h == new BigInteger("3")) {
- val power = exponentiate(point, new BigInteger("2"))
- val inverse = getInverse(point)
- if (power == inverse) return false
- else return true
- }
- // if the cofactor is 4, the point has order 2 if the y coefficient of the point is 0,
- // or the the point has order 4 if the y coefficient of the point raised to two is 0.
- // in both cases the point is not in the group.
- if (h == new BigInteger("4")) {
- if (y == BigInteger.ZERO) return false
- val power = exponentiate(point, new BigInteger("2"))
- val powerY = power.getYCoord.toBigInteger
- if (powerY == BigInteger.ZERO) return false
- else return true
- }
- // if the cofactor is bigger than 4, there is no optimized way to check the order, so we operates the naive:
- // if the point raised to q (order of the group) is the identity, the point has order q too and is in the group.
- // else, it is not in the group
- val r = q
- val pointPowR = exponentiate(point, r)
- if (pointPowR.isInfinity) true else false
- }
-
-
- /**
- * This function maps any group element to a byte array. This function does not have an inverse,
- * that is, it is not possible to re-construct the original group element from the resulting byte array.
- *
- * @param x coordinate of a point in the curve (this function does not check for membership)
- * @param y coordinate of a point in the curve (this function does not check for membership)
- * @return byte[] representation
- */
- def mapAnyGroupElementToByteArray(x: BigInteger, y: BigInteger): Array[Byte] = { //This function simply returns an array which is the result of concatenating
- //the byte array representation of x with the byte array representation of y.
- val xByteArray = x.toByteArray
- val yByteArray = y.toByteArray
- val result = new Array[Byte](xByteArray.length + yByteArray.length)
- System.arraycopy(xByteArray, 0, result, 0, xByteArray.length)
- System.arraycopy(yByteArray, 0, result, xByteArray.length, yByteArray.length)
- result
- }
/**
* This function calculates k, the maximum length in bytes of a string to be converted to a Group Element of this group.
@@ -316,37 +166,6 @@ abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) exten
override lazy val identity: ElemType = curve.getInfinity.asInstanceOf[ElemType]
- /**
- * Checks if the given element is a member of this Dlog group
- *
- * @param point
- * @return true if the given element is member of this group; false, otherwise.
- * @throws IllegalArgumentException
- */
- override def isMember(point: ElemType): Boolean = {
- //infinity point is a valid member
- if (point.isInfinity) return true
- // A point (x, y) is a member of a Dlog group with prime order q over an Elliptic Curve if it meets the following two conditions:
- // 1) P = (x,y) is a point in the Elliptic curve, i.e (x,y) is a solution of the curves equation.
- // 2) P = (x,y) is a point in the q-order group which is a sub-group of the Elliptic Curve.
- // those two checks are done in two steps:
- // 1. Checking that the point is on the curve, performed by checkCurveMembership
- // 2. Checking that the point is in the Dlog group,performed by checkSubGroupMembership
- point.isValid && checkSubGroupMembership(point)
- }
-
-
- def generateElement(x: BigInteger, y: BigInteger): ElemType = { //Creates element with the given values.
- val point = checkMembershipAndCreate(x, y).get
- //if the element was created, it is a point on the curve.
- //checks if the point is in the sub-group, too.
- val valid = checkSubGroupMembership(point)
- //if the point is not in the sub-group, throw exception.
- if (!valid) throw new IllegalArgumentException("Could not generate the element. The given (x, y) is not a point in this Dlog group")
- point
- }
-
-
def createPoint(x: BigInteger, y: BigInteger): ElemType = curve.createPoint(x, y).asInstanceOf[ElemType]
@@ -406,65 +225,6 @@ abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) exten
exponentiate(generator, randNum)
}
- /**
- * This function takes any string of length up to k bytes and encodes it to a Group Element.
- * k can be obtained by calling getMaxLengthOfByteArrayForEncoding() and it is calculated upon construction of
- * this group; it depends on the length in bits of p.
- * The encoding-decoding functionality is not a bijection, that is, it is a 1-1 function but is not onto.
- * Therefore, any string of length in bytes up to k can be encoded to a group element but not every group element
- * can be decoded to a binary string in the group of binary strings of length up to 2^k.
- * Thus, the right way to use this functionality is first to encode a byte array and then to decode it,
- * and not the opposite.
- *
- *
- * @param binaryString the byte array to convert
- * @throws IndexOutOfBoundsException if the length of the binary array to encode is longer than k
- * @return the created group Element or null if could not find the encoding in reasonable time
- */
- override def encodeByteArrayToGroupElement(binaryString: Array[Byte]): Try[ElemType] = {
- findPointRepresentedByByteArray(binaryString).map {fpPoint =>
- curve.importPoint(fpPoint).asInstanceOf[ElemType]
- }
- }
-
- /**
- * This function decodes a group element to a byte array. This function is guaranteed to work properly ONLY if
- * the group element was obtained as a result of
- * encoding a binary string of length in bytes up to k.
- * This is because the encoding-decoding functionality is not a bijection, that is, it is a 1-1 function
- * but is not onto. Therefore, any string of length in bytes up to k can be encoded to a group element but not any
- * group element can be decoded to a binary sting in the group of binary strings of length up to `2^k`.
- *
- *
- * @param point the element to convert
- * @return the created byte array
- */
- override def decodeGroupElementToByteArray(point: ElemType): Array[Byte] = {
- val xByteArray = point.getXCoord.toBigInteger.toByteArray
- val bOriginalSize = xByteArray(xByteArray.length - 1)
-
- val b2 = new Array[Byte](bOriginalSize)
- System.arraycopy(xByteArray, xByteArray.length - 1 - bOriginalSize, b2, 0, bOriginalSize)
- b2
- }
-
- /**
- * This function maps a group element of this dlog group to a byte array.
- * This function does not have an inverse function, that is, it is not possible to re-construct the original
- * group element from the resulting byte array. Moreover, the implementation of this function is such that
- * for a given group element (point in the curve), the result of applying this function
- * (mapAnyGroupElementToByteArray) and the result of applying decodeGroupElementToByteArray are not equal.
- *
- * @return a byte array representation of the given group element
- */
- override def mapAnyGroupElementToByteArray(point: ElemType): Array[Byte] = {
- //This function simply returns an array which is the result of concatenating
- //The actual work is implemented in ECFpUtility since it is independent of the underlying library (BC, Miracl, or other)
- //If we ever decide to change the implementation there will only one place to change it.
-
- point.getEncoded(true)
- }
-
/**
*
@@ -487,20 +247,6 @@ abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) exten
override def multiplyGroupElements(groupElement1: ElemType, groupElement2: ElemType): ElemType =
groupElement1.add(groupElement2).asInstanceOf[ElemType]
- /**
- * Reconstructs a GroupElement given the GroupElementSendableData data, which might have been received through a Channel open between the party holding this DlogGroup and
- * some other party.
- *
- * @param bCheckMembership whether to check that the data provided can actually reconstruct an element of this DlogGroup. Since this action is expensive it should be used only if necessary.
- * @param data the GroupElementSendableData from which we wish to "reconstruct" an element of this DlogGroup
- * @return the reconstructed GroupElement
- */
- override def reconstructElement(bCheckMembership: Boolean, data: GroupAgnosticEcElement): Try[ElemType] = Try {
- val point = createPoint(data.x, data.y)
- if(bCheckMembership) assert(isMember(point))
- point
- }
-
/**
* Computes the product of several exponentiations with distinct bases
@@ -530,10 +276,10 @@ abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) exten
*/
override def exponentiateWithPreComputedValues(base: ElemType, exponent: BigInteger): ElemType = {
//extracts from the map the GroupElementsExponentiations object corresponding to the accepted base
- val exponentiations = exponentiationsMap.getOrElse(key = base, {
+ val exponentiations = exponentiationsCache.getOrElse(key = base, {
// if there is no object that matches this base - create it and add it to the map
val exps = new GroupElementsExponentiations(base)
- exponentiationsMap.put(base, exps)
+ exponentiationsCache.put(base, exps)
exps
})
@@ -547,7 +293,7 @@ abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) exten
*
* @param base
*/
- override def endExponentiateWithPreComputedValues(base: ElemType): Unit = exponentiationsMap -= base
+ override def endExponentiateWithPreComputedValues(base: ElemType): Unit = exponentiationsCache -= base
/**
* This function returns the value k which is the maximum length of a string to be encoded to a Group Element of this group.
@@ -667,7 +413,7 @@ abstract class BcDlogFp[ElemType <: ECPoint](val x9params: X9ECParameters) exten
}
}
-object SecP384R1 extends BcDlogFp[SecP384R1Point](CustomNamedCurves.getByName("secp384r1")) with App {
+object SecP384R1 extends BcDlogGroup[SecP384R1Point](CustomNamedCurves.getByName("secp384r1")) with App {
val elems = 5000
val base = generator
val exps = (1 to elems).map { _ =>
@@ -689,7 +435,7 @@ object SecP384R1 extends BcDlogFp[SecP384R1Point](CustomNamedCurves.getByName("s
println(System.currentTimeMillis() - t0)
}
-object SecP521R1 extends BcDlogFp[SecP521R1Point](CustomNamedCurves.getByName("secp521r1")) with App {
+object SecP521R1 extends BcDlogGroup[SecP521R1Point](CustomNamedCurves.getByName("secp521r1")) with App {
val elems = 1000
val bases = (1 to elems).map(_ => createRandomGenerator()).toArray
val exps = (1 to elems).map { _ =>
@@ -716,4 +462,6 @@ object SecP521R1 extends BcDlogFp[SecP521R1Point](CustomNamedCurves.getByName("s
println(naive == ll)
}
-object Curve25519 extends BcDlogFp[Curve25519Point](CustomNamedCurves.getByName("curve25519"))
\ No newline at end of file
+object Curve25519 extends BcDlogGroup[Curve25519Point](CustomNamedCurves.getByName("curve25519"))
+
+object SecP256K1 extends BcDlogGroup[SecP256K1Point](CustomNamedCurves.getByName("secp256k1"))
\ No newline at end of file
diff --git a/src/main/scala/sigmastate/basics/DLogProtocol.scala b/src/main/scala/sigmastate/basics/DLogProtocol.scala
index 79f6fee807..31769fe14a 100644
--- a/src/main/scala/sigmastate/basics/DLogProtocol.scala
+++ b/src/main/scala/sigmastate/basics/DLogProtocol.scala
@@ -3,16 +3,14 @@ package sigmastate.basics
import java.math.BigInteger
import org.bouncycastle.util.BigIntegers
-import sigmastate.Values.Value.PropositionCode
import sigmastate.Values._
import Value.PropositionCode
import sigmastate._
import sigmastate.basics.VerifierMessage.Challenge
import sigmastate.interpreter.CryptoConstants.{EcPointType, dlogGroup}
-import sigmastate.interpreter.{Context, CryptoConstants}
-import sigmastate.serialization.OpCodes
+import sigmastate.interpreter.CryptoConstants
+import sigmastate.serialization.{GroupElementSerializer, OpCodes}
import sigmastate.serialization.OpCodes.OpCode
-import sigmastate.utxo.CostTable.Cost
object DLogProtocol {
@@ -22,29 +20,17 @@ object DLogProtocol {
}
/** Construct a new SigmaBoolean value representing public key of discrete logarithm signature protocol. */
- case class ProveDlog(value: Value[SGroupElement.type])
+ case class ProveDlog(value: EcPointType)
extends SigmaProofOfKnowledgeTree[DLogSigmaProtocol, DLogProverInput] {
override val opCode: OpCode = OpCodes.ProveDlogCode
//todo: fix, we should consider that class parameter could be not evaluated
- lazy val h: EcPointType = value.asInstanceOf[GroupElementConstant].value
- lazy val pkBytes: Array[Byte] = h.getEncoded(true)
+ lazy val h: EcPointType = value
+ lazy val pkBytes: Array[Byte] = GroupElementSerializer.toBytes(h)
}
object ProveDlog {
-
- import CryptoConstants.dlogGroup
-
- def apply(h: CryptoConstants.EcPointType): ProveDlog = ProveDlog(GroupElementConstant(h))
-
val Code: PropositionCode = 102: Byte
-
- def fromBytes(bytes: Array[Byte]): ProveDlog = {
- val (x, y) = EcPointFunctions.decodeBigIntPair(bytes).get
- val xy = GroupAgnosticEcElement(x, y)
- val h = dlogGroup.reconstructElement(bCheckMembership = true, xy).get //todo: .get
- ProveDlog(h)
- }
}
case class DLogProverInput(w: BigInteger)
@@ -70,11 +56,9 @@ object DLogProtocol {
}
}
- case class FirstDLogProverMessage(ecData: CryptoConstants.EcPointType) extends FirstProverMessage[DLogSigmaProtocol] {
+ case class FirstDLogProverMessage(ecData: EcPointType) extends FirstProverMessage[DLogSigmaProtocol] {
override def bytes: Array[Byte] = {
- val bytes = ecData.getEncoded(true)
-
- Array(bytes.length.toByte) ++ bytes
+ GroupElementSerializer.toBytes(ecData)
}
}
diff --git a/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala b/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala
index 95a6ef3c5d..2ebbc8a0c9 100644
--- a/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala
+++ b/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala
@@ -8,10 +8,10 @@ import sigmastate.Values._
import sigmastate._
import sigmastate.basics.VerifierMessage.Challenge
import sigmastate.interpreter.CryptoConstants.EcPointType
-import sigmastate.interpreter.{Context, CryptoConstants}
-import sigmastate.serialization.OpCodes
+import sigmastate.interpreter.CryptoConstants
+import sigmastate.serialization.{GroupElementSerializer, OpCodes}
import sigmastate.serialization.OpCodes.OpCode
-import sigmastate.utxo.CostTable.Cost
+
trait DiffieHellmanTupleProtocol extends SigmaProtocol[DiffieHellmanTupleProtocol] {
override type A = FirstDiffieHellmanTupleProverMessage
@@ -35,9 +35,7 @@ object DiffieHellmanTupleProverInput {
val w = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, dlogGroup.secureRandom)
val u = dlogGroup.exponentiate(g, w)
val v = dlogGroup.exponentiate(h, w)
- val ci = ProveDHTuple(
- GroupElementConstant(g), GroupElementConstant(h),
- GroupElementConstant(u), GroupElementConstant(v))
+ val ci = ProveDHTuple(g, h, u, v)
DiffieHellmanTupleProverInput(w, ci)
}
}
@@ -46,11 +44,7 @@ object DiffieHellmanTupleProverInput {
case class FirstDiffieHellmanTupleProverMessage(a: CryptoConstants.EcPointType, b: CryptoConstants.EcPointType)
extends FirstProverMessage[DiffieHellmanTupleProtocol] {
override def bytes: Array[Byte] = {
- val ba = a.getEncoded(true)
-
- val bb = b.getEncoded(true)
-
- Array(ba.length.toByte, bb.length.toByte) ++ ba ++ bb
+ GroupElementSerializer.toBytes(a) ++ GroupElementSerializer.toBytes(b)
}
}
@@ -62,19 +56,14 @@ case class SecondDiffieHellmanTupleProverMessage(z: BigInteger)
/** Construct a new SigmaProp value representing public key of Diffie Hellman signature protocol.
* Common input: (g,h,u,v)*/
-case class ProveDHTuple(gv: Value[SGroupElement.type],
- hv: Value[SGroupElement.type],
- uv: Value[SGroupElement.type],
- vv: Value[SGroupElement.type])
+case class ProveDHTuple(gv: EcPointType, hv: EcPointType, uv: EcPointType, vv: EcPointType)
extends SigmaProtocolCommonInput[DiffieHellmanTupleProtocol]
with SigmaProofOfKnowledgeTree[DiffieHellmanTupleProtocol, DiffieHellmanTupleProverInput] {
-
override val opCode: OpCode = OpCodes.ProveDiffieHellmanTupleCode
- //todo: fix code below , we should consider that class parameters could be not evaluated
- lazy val g = gv.asInstanceOf[GroupElementConstant].value
- lazy val h = hv.asInstanceOf[GroupElementConstant].value
- lazy val u = uv.asInstanceOf[GroupElementConstant].value
- lazy val v = vv.asInstanceOf[GroupElementConstant].value
+ lazy val g = gv
+ lazy val h = hv
+ lazy val u = uv
+ lazy val v = vv
}
object ProveDHTuple {
diff --git a/src/main/scala/sigmastate/basics/DlogGroup.scala b/src/main/scala/sigmastate/basics/DlogGroup.scala
index 7ad228950e..9bfced419c 100644
--- a/src/main/scala/sigmastate/basics/DlogGroup.scala
+++ b/src/main/scala/sigmastate/basics/DlogGroup.scala
@@ -2,14 +2,11 @@ package sigmastate.basics
import java.math.BigInteger
import java.security.SecureRandom
-
import org.bouncycastle.math.ec.ECPoint
-import scala.util.Try
-
/**
- * This is the general interface for the discrete logarithm group.
+ * This is the general interface for the discrete logarithm prime-order group.
* Every class in the DlogGroup family implements this interface.
*
*
@@ -43,7 +40,8 @@ trait DlogGroup[ElemType <: ECPoint] {
val secureRandom = new SecureRandom()
/**
- * The generator g of the group is an element of the group such that, when written multiplicatively, every element of the group is a power of g.
+ * The generator g of the group is an element of the group such that, when written multiplicatively, every element
+ * of the group is a power of g.
* @return the generator of this Dlog group
*/
def generator: ElemType
@@ -57,18 +55,10 @@ trait DlogGroup[ElemType <: ECPoint] {
/**
*
- * @return the identity of this Dlog group
+ * @return the identity element of this Dlog group
*/
def identity: ElemType
- /**
- * Checks if the given element is a member of this Dlog group
- * @param element possible group element for which to check that it is a member of this group
- * @return true
if the given element is a member of this group;
- * false
otherwise.
- */
- def isMember(element: ElemType): Boolean
-
/**
* Checks if the order of this group is greater than `2^numBits`
* @param numBits
@@ -127,15 +117,6 @@ trait DlogGroup[ElemType <: ECPoint] {
randGen
}
- /**
- * Reconstructs a GroupElement given the GroupElementSendableData data, which might have been received through a Channel open between the party holding this DlogGroup and
- * some other party.
- * @param bCheckMembership whether to check that the data provided can actually reconstruct an element of this DlogGroup. Since this action is expensive it should be used only if necessary.
- * @param data the GroupElementSendableData from which we wish to "reconstruct" an element of this DlogGroup
- * @return the reconstructed GroupElement
- */
- def reconstructElement(bCheckMembership: Boolean, data: GroupAgnosticEcElement): Try[ElemType]
-
/**
* Computes the product of several exponentiations with distinct bases
* and distinct exponents.
@@ -168,37 +149,6 @@ trait DlogGroup[ElemType <: ECPoint] {
*/
def endExponentiateWithPreComputedValues(base: ElemType)
- /**
- * This function takes any string of length up to k bytes and encodes it to a Group Element.
- * k can be obtained by calling getMaxLengthOfByteArrayForEncoding() and it is calculated upon
- * construction of this group; it depends on the length in bits of p.
- * The encoding-decoding functionality is not a bijection, that is, it is a 1-1 function
- * but is not onto.
- * Therefore, any string of length in bytes up to k can be encoded to a group element
- * but not every group element can be decoded to a binary string in the group of binary strings
- * of length up to `2^k`.
- * Thus, the right way to use this functionality is first to encode a byte array and then to
- * decode it, and not the opposite.
- *
- * @param binaryString the byte array to encode
- * @return the encoded group Element or null if element could not be encoded
- */
- def encodeByteArrayToGroupElement(binaryString: Array[Byte]): Try[ElemType]
-
- /**
- * This function decodes a group element to a byte array. This function is guaranteed
- * to work properly ONLY if the group element was obtained as a result of
- * encoding a binary string of length in bytes up to k.
- * This is because the encoding-decoding functionality is not a bijection, that is, it is a 1-1 function but is not onto.
- * Therefore, any string of length in bytes up to k can be encoded to a group element but not any group element can be decoded
- * to a binary sting in the group of binary strings of length up to `2^k`.
- *
- * @param groupElement the element to decode
- * @return the decoded byte array
- */
- def decodeGroupElementToByteArray(groupElement: ElemType): Array[Byte]
-
-
/**
* This function returns the value k which is the maximum length of a string to be encoded to a Group Element of this group.
* Any string of length k has a numeric value that is less than (p-1)/2 - 1.
@@ -208,10 +158,4 @@ trait DlogGroup[ElemType <: ECPoint] {
*/
def maxLengthOfByteArrayForEncoding: Int
- /**
- * This function maps a group element of this dlog group to a byte array.
- * This function does not have an inverse function, that is, it is not possible to re-construct the original group element from the resulting byte array.
- * @return a byte array representation of the given group element
- */
- def mapAnyGroupElementToByteArray(groupElement: ElemType): Array[Byte]
}
diff --git a/src/main/scala/sigmastate/basics/GroupAgnosticEcElement.scala b/src/main/scala/sigmastate/basics/GroupAgnosticEcElement.scala
deleted file mode 100644
index 8c01284014..0000000000
--- a/src/main/scala/sigmastate/basics/GroupAgnosticEcElement.scala
+++ /dev/null
@@ -1,15 +0,0 @@
-package sigmastate.basics
-
-import java.math.BigInteger
-
-
-
-/**
- * Group agnostic representation of an EC point, just two numbers. The main purpose of this data
- * object is to be sent over wire. During converting this representation into an actual EC point, membership
- * must be tested.
- * @param x
- * @param y
- */
-case class GroupAgnosticEcElement(x: BigInteger, y: BigInteger)
-
diff --git a/src/main/scala/sigmastate/eval/BigIntegerOps.scala b/src/main/scala/sigmastate/eval/BigIntegerOps.scala
index 67ebbe86a8..6b6a15cd07 100644
--- a/src/main/scala/sigmastate/eval/BigIntegerOps.scala
+++ b/src/main/scala/sigmastate/eval/BigIntegerOps.scala
@@ -2,21 +2,29 @@ package sigmastate.eval
import java.math.BigInteger
-import scala.math.{LowPriorityOrderingImplicits, BigInt, Integral, Ordering}
-import scala.math.Numeric.BigIntIsIntegral
+import scala.math.{LowPriorityOrderingImplicits,Integral, Ordering}
+import special.sigma._
+import sigma.util.Extensions._
+import sigmastate.eval.Extensions._
object OrderingOps extends LowPriorityOrderingImplicits {
def apply[T](implicit ord: Ordering[T]) = ord
+
trait BigIntegerOrdering extends Ordering[BigInteger] {
def compare(x: BigInteger, y: BigInteger) = x.compareTo(y)
}
implicit object BigInteger extends BigIntegerOrdering
+
+ trait BigIntOrdering extends Ordering[BigInt] {
+ def compare(x: BigInt, y: BigInt) = x.compareTo(y)
+ }
+ implicit object BigInt extends BigIntOrdering
}
object NumericOps {
trait BigIntegerIsIntegral extends Integral[BigInteger] {
- private val BI = implicitly[Integral[BigInt]]
+// private val BI = implicitly[Integral[BigInt]]
def quot(x: BigInteger, y: BigInteger): BigInteger = x.divide(y)
def rem(x: BigInteger, y: BigInteger): BigInteger = x.remainder(y)
def plus(x: BigInteger, y: BigInteger): BigInteger = x.add(y)
@@ -24,12 +32,28 @@ object NumericOps {
def times(x: BigInteger, y: BigInteger): BigInteger = x.multiply(y)
def negate(x: BigInteger): BigInteger = x.negate()
def fromInt(x: Int): BigInteger = BigInteger.valueOf(x)
- def toInt(x: BigInteger): Int = x.toInt()
- def toLong(x: BigInteger): Long = x.toLong()
- def toFloat(x: BigInteger): Float = x.toFloat()
- def toDouble(x: BigInteger): Double = x.toDouble()
+ def toInt(x: BigInteger): Int = x.intValueExact()
+ def toLong(x: BigInteger): Long = x.longValueExact()
+ def toFloat(x: BigInteger): Float = x.floatValue()
+ def toDouble(x: BigInteger): Double = x.doubleValue()
}
implicit object BigIntegerIsIntegral extends BigIntegerIsIntegral with OrderingOps.BigIntegerOrdering
+ trait BigIntIsIntegral extends Integral[BigInt] {
+// private val BI = implicitly[Integral[BigInt]]
+ def quot(x: BigInt, y: BigInt): BigInt = x.divide(y)
+ def rem(x: BigInt, y: BigInt): BigInt = x.remainder(y)
+ def plus(x: BigInt, y: BigInt): BigInt = x.add(y)
+ def minus(x: BigInt, y: BigInt): BigInt = x.subtract(y)
+ def times(x: BigInt, y: BigInt): BigInt = x.multiply(y)
+ def negate(x: BigInt): BigInt = x.negate()
+ def fromInt(x: Int): BigInt = x.toBigInt
+ def toInt(x: BigInt): Int = x.toInt
+ def toLong(x: BigInt): Long = x.toLong
+ def toFloat(x: BigInt): Float = CostingSigmaDslBuilder.toBigInteger(x).floatValue()
+ def toDouble(x: BigInt): Double = CostingSigmaDslBuilder.toBigInteger(x).doubleValue()
+ }
+ implicit object BigIntIsIntegral extends BigIntIsIntegral with OrderingOps.BigIntOrdering
+
}
diff --git a/src/main/scala/sigmastate/eval/CompiletimeCosting.scala b/src/main/scala/sigmastate/eval/CompiletimeCosting.scala
index 17a6589814..8610d35099 100644
--- a/src/main/scala/sigmastate/eval/CompiletimeCosting.scala
+++ b/src/main/scala/sigmastate/eval/CompiletimeCosting.scala
@@ -3,75 +3,26 @@ package sigmastate.eval
import org.ergoplatform.ErgoBox
import scala.language.{existentials, implicitConversions}
-import sigmastate.SCollection.SByteArray
import sigmastate._
-import sigmastate.Values.{Constant, NotReadyValue, SValue, SigmaBoolean, SigmaPropConstant, Value}
-import sigmastate.lang.Terms.{Apply, _}
-import sigmastate.lang.SigmaPredef._
+import sigmastate.Values.{Constant, Value}
+import sigmastate.lang.Terms._
import sigmastate.utxo._
import sigmastate.SType._
import sigmastate.SCollection._
import sigmastate.SBigInt._
import sigmastate.Values.Value.Typed
-import sigmastate.basics.{DLogProtocol, ProveDHTuple}
-import sigmastate.lang.SigmaSpecializer.error
-import sigmastate.lang.{Terms, TransformingSigmaBuilder}
+import sigmastate.lang.Terms
+import sigma.util.Extensions._
trait CompiletimeCosting extends RuntimeCosting { IR: Evaluation =>
import builder._
- override def evalNode[T <: SType](ctx: Rep[CostedContext], env: CostingEnv, node: Value[T]): RCosted[T#WrappedType] = {
+ override def evalNode[T <: SType](ctx: RCosted[Context], env: CostingEnv, node: Value[T]): RCosted[T#WrappedType] = {
def eval[T <: SType](node: Value[T]): RCosted[T#WrappedType] = evalNode(ctx, env, node)
val res: Sym = node match {
case Ident(n, _) =>
env.getOrElse(n, !!!(s"Variable $n not found in environment $env"))
- // Rule: allOf(arr) --> AND(arr)
- case Terms.Apply(AllSym, Seq(arr: Value[SCollection[SBoolean.type]]@unchecked)) =>
- eval(mkAND(arr))
-
- // Rule: anyOf(arr) --> OR(arr)
- case Terms.Apply(AnySym, Seq(arr: Value[SCollection[SBoolean.type]]@unchecked)) =>
- eval(mkOR(arr))
-
- // Rule: atLeast(bound, arr) --> AtLeast(bound, arr)
- case Terms.Apply(AtLeastSym, Seq(bound: SValue, arr: Value[SCollection[SSigmaProp.type]]@unchecked)) =>
- eval(mkAtLeast(bound.asIntValue, arr))
-
- case Terms.Apply(Blake2b256Sym, Seq(arg: Value[SByteArray]@unchecked)) =>
- eval(mkCalcBlake2b256(arg))
-
- case Terms.Apply(Sha256Sym, Seq(arg: Value[SByteArray]@unchecked)) =>
- eval(mkCalcSha256(arg))
-
- case Terms.Apply(IsMemberSym, Seq(tree: Value[SAvlTree.type]@unchecked, key: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
- eval(mkIsMember(tree, key, proof))
-
- case Terms.Apply(ProveDlogSym, Seq(g: Value[SGroupElement.type]@unchecked)) =>
- eval(mkProveDlog(g))
-
- case Terms.Apply(LongToByteArraySym, Seq(arg: Value[SLong.type]@unchecked)) =>
- eval(mkLongToByteArray(arg))
-
- case Terms.Apply(ByteArrayToBigIntSym, Seq(arr: Value[SByteArray]@unchecked)) =>
- eval(mkByteArrayToBigInt(arr))
-
- case Terms.Apply(SigmaPropSym, Seq(bool: Value[SBoolean.type]@unchecked)) =>
- eval(mkBoolToSigmaProp(bool))
-
- case Terms.Apply(ProveDHTupleSym, Seq(g, h, u, v)) =>
- eval(mkProveDiffieHellmanTuple(
- g.asGroupElement,
- h.asGroupElement,
- u.asGroupElement,
- v.asGroupElement))
-
- case Terms.Apply(TreeModificationsSym, Seq(tree: Value[SAvlTree.type]@unchecked, operations: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
- eval(mkTreeModifications(tree, operations, proof))
-
- case Terms.Apply(TreeLookupSym, Seq(tree: Value[SAvlTree.type]@unchecked, key: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
- eval(mkTreeLookup(tree, key, proof))
-
case sigmastate.Upcast(Constant(value, _), toTpe: SNumericType) =>
eval(mkConstant(toTpe.upcast(value.asInstanceOf[AnyVal]), toTpe))
@@ -83,7 +34,7 @@ trait CompiletimeCosting extends RuntimeCosting { IR: Evaluation =>
if (obj.tpe.isCollectionLike)
eval(mkSizeOf(obj.asValue[SCollection[SType]]))
else
- error(s"The type of $obj is expected to be Collection to select 'size' property")
+ error(s"The type of $obj is expected to be Collection to select 'size' property", obj.sourceContext.toOption)
// Rule: proof.isProven --> IsValid(proof)
case Select(p, SSigmaProp.IsProven, _) if p.tpe == SSigmaProp =>
@@ -96,15 +47,9 @@ trait CompiletimeCosting extends RuntimeCosting { IR: Evaluation =>
// box.R$i[valType] =>
case sel @ Select(Typed(box, SBox), regName, Some(SOption(valType))) if regName.startsWith("R") =>
val reg = ErgoBox.registerByName.getOrElse(regName,
- error(s"Invalid register name $regName in expression $sel"))
+ error(s"Invalid register name $regName in expression $sel", sel.sourceContext.toOption))
eval(mkExtractRegisterAs(box.asBox, reg, SOption(valType)).asValue[SOption[valType.type]])
- // col.getOrElse(i, default) =>
- case Terms.Apply(Select(col,"getOrElse", _), Seq(index, defaultValue)) =>
- val index1 = index.asValue[SInt.type]
- val defaultValue1 = defaultValue.asValue[SType]
- eval(mkByIndex(col.asValue[SCollection[SType]], index1, Some(defaultValue1)))
-
// opt.get =>
case Select(nrv: Value[SOption[SType]]@unchecked, SOption.Get, _) =>
eval(mkOptionGet(nrv))
@@ -123,15 +68,9 @@ trait CompiletimeCosting extends RuntimeCosting { IR: Evaluation =>
case (box, SBox.PropositionBytes) => eval(mkExtractScriptBytes(box))
case (box, SBox.Id) => eval(mkExtractId(box))
case (box, SBox.Bytes) => eval(mkExtractBytes(box))
- case (box, SBox.BytesWithNoRef) => eval(mkExtractBytesWithNoRef(box))
+ case (box, SBox.BytesWithoutRef) => eval(mkExtractBytesWithNoRef(box))
case (box, SBox.CreationInfo) => eval(mkExtractCreationInfo(box))
- case _ => error(s"Invalid access to Box property in $sel: field $field is not found")
- }
-
- case Select(obj: SigmaBoolean, field, _) =>
- field match {
- case SigmaBoolean.PropBytes => eval(SigmaPropBytes(SigmaPropConstant(obj)))
- case SigmaBoolean.IsProven => eval(SigmaPropIsProven(SigmaPropConstant(obj)))
+ case _ => error(s"Invalid access to Box property in $sel: field $field is not found", sel.sourceContext.toOption)
}
case Select(tuple, fn, _) if tuple.tpe.isTuple && fn.startsWith("_") =>
diff --git a/src/main/scala/sigmastate/eval/CostingDataContext.scala b/src/main/scala/sigmastate/eval/CostingDataContext.scala
index 52977b94ec..bb5506911c 100644
--- a/src/main/scala/sigmastate/eval/CostingDataContext.scala
+++ b/src/main/scala/sigmastate/eval/CostingDataContext.scala
@@ -4,61 +4,264 @@ import java.math.BigInteger
import org.bouncycastle.math.ec.ECPoint
import org.ergoplatform.ErgoBox
-import scorex.crypto.authds.avltree.batch.{Lookup, Operation}
-import scorex.crypto.authds.{ADKey, SerializedAdProof}
+import scorex.crypto.authds.avltree.batch._
+import scorex.crypto.authds.{ADDigest, ADKey, SerializedAdProof, ADValue}
import sigmastate.SCollection.SByteArray
-import sigmastate._
-import sigmastate.Values.{Constant, EvaluatedValue, SValue, AvlTreeConstant, ConstantNode, SomeValue, NoneValue}
+import sigmastate.{TrivialProp, _}
+import sigmastate.Values.{Constant, SValue, ConstantNode, Value, IntConstant, ErgoTree, SigmaBoolean}
import sigmastate.interpreter.CryptoConstants.EcPointType
import sigmastate.interpreter.{CryptoConstants, Interpreter}
-import sigmastate.serialization.{Serializer, OperationSerializer}
-import special.collection.{CCostedBuilder, Col, Types}
+import special.collection.{CSizePrim, Builder, Size, CSizeOption, SizeColl, CCostedBuilder, CollType, SizeOption, CostedBuilder, Coll}
import special.sigma._
+import special.sigma.Extensions._
-import scala.reflect.ClassTag
import scala.util.{Success, Failure}
-import scalan.meta.RType
+import scalan.{NeverInline, RType}
+import scorex.crypto.hash.{Digest32, Sha256, Blake2b256}
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.basics.ProveDHTuple
+import sigmastate.interpreter.Interpreter.emptyEnv
+import sigmastate.lang.Terms.OperationId
+import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer
+import sigmastate.serialization.{GroupElementSerializer, SigmaSerializer}
+
+import scala.reflect.ClassTag
+
+trait WrapperOf[T] {
+ def wrappedValue: T
+}
+
+case class CBigInt(override val wrappedValue: BigInteger) extends TestBigInt(wrappedValue) with WrapperOf[BigInteger] {
+ override val dsl = CostingSigmaDslBuilder
+}
+
+case class CGroupElement(override val wrappedValue: EcPointType) extends TestGroupElement(wrappedValue) with WrapperOf[ECPoint] {
+ override val dsl = CostingSigmaDslBuilder
+
+ override def getEncoded: Coll[Byte] = dsl.Colls.fromArray(GroupElementSerializer.toBytes(wrappedValue))
+
+}
+
+case class CSigmaProp(sigmaTree: SigmaBoolean) extends SigmaProp with WrapperOf[SigmaBoolean] {
+ override def wrappedValue: SigmaBoolean = sigmaTree
+
+ override def isValid: Boolean = sigmaTree match {
+ case p: TrivialProp => p.condition
+ case _ => sys.error(s"Method CostingSigmaProp.isValid is not defined for $sigmaTree")
+ }
+
+ override def propBytes: Coll[Byte] = {
+ // in order to have comparisons like `box.propositionBytes == pk.propBytes` we need to make sure
+ // the same serialization method is used in both cases
+ val ergoTree = ErgoTree.fromSigmaBoolean(sigmaTree)
+ val bytes = DefaultSerializer.serializeErgoTree(ergoTree)
+ Builder.DefaultCollBuilder.fromArray(bytes)
+ }
+
+ override def &&(other: SigmaProp): SigmaProp = other match {
+ case other: CSigmaProp =>
+ CSigmaProp(CAND.normalized(Seq(sigmaTree, other.sigmaTree)))
+ }
-case class CostingAvlTree(IR: Evaluation, treeData: AvlTreeData) extends AvlTree {
- override val builder = new CostingSigmaDslBuilder(IR)
- def startingDigest: Col[Byte] = builder.Cols.fromArray(treeData.startingDigest)
+ override def &&(other: Boolean): SigmaProp =
+ CSigmaProp(CAND.normalized(Seq(sigmaTree, TrivialProp(other))))
+
+ override def ||(other: SigmaProp): SigmaProp = other match {
+ case other: CSigmaProp =>
+ CSigmaProp(COR.normalized(Seq(sigmaTree, other.sigmaTree)))
+ }
+
+ override def ||(other: Boolean): SigmaProp =
+ CSigmaProp(COR.normalized(Seq(sigmaTree, TrivialProp(other))))
+
+ override def toString: String = s"SigmaProp(${wrappedValue.showToString})"
+}
+
+case class CAvlTree(treeData: AvlTreeData) extends AvlTree with WrapperOf[AvlTreeData] {
+ val builder = CostingSigmaDslBuilder
+ val Colls = builder.Colls
+
+ override def wrappedValue: AvlTreeData = treeData
+
+ def startingDigest: Coll[Byte] = Colls.fromArray(treeData.digest)
def keyLength: Int = treeData.keyLength
- def valueLengthOpt: Option[Int] = treeData.valueLengthOpt
+ def enabledOperations = treeData.treeFlags.serializeToByte
+
+ override def isInsertAllowed: Boolean = treeData.treeFlags.insertAllowed
- def maxNumOperations: Option[Int] = treeData.maxNumOperations
+ override def isUpdateAllowed: Boolean = treeData.treeFlags.updateAllowed
- def maxDeletes: Option[Int] = treeData.maxDeletes
+ override def isRemoveAllowed: Boolean = treeData.treeFlags.removeAllowed
+
+ override def updateOperations(newOperations: Byte): AvlTree = {
+ val td = treeData.copy(treeFlags = AvlTreeFlags(newOperations))
+ this.copy(treeData = td)
+ }
+
+ def valueLengthOpt: Option[Int] = treeData.valueLengthOpt
def cost: Int = 1
def dataSize: Long = SAvlTree.dataSize(treeData.asInstanceOf[SType#WrappedType])
+
+ override def digest: Coll[Byte] = Colls.fromArray(treeData.digest)
+
+ def updateDigest(newDigest: Coll[Byte]): AvlTree = {
+ val td = treeData.copy(digest = ADDigest @@ newDigest.toArray)
+ this.copy(treeData = td)
+ }
+
+ private def createVerifier(proof: Coll[Byte]): BatchAVLVerifier[Digest32, Blake2b256.type] = {
+ val adProof = SerializedAdProof @@ proof.toArray
+ val bv = new BatchAVLVerifier[Digest32, Blake2b256.type](
+ treeData.digest, adProof,
+ treeData.keyLength, treeData.valueLengthOpt)
+ bv
+ }
+
+ override def contains(key: Coll[Byte], proof: Coll[Byte]): Boolean = {
+ val keyBytes = key.toArray
+ val bv = createVerifier(proof)
+ bv.performOneOperation(Lookup(ADKey @@ keyBytes)) match {
+ case Failure(_) => false
+ case Success(r) => r match {
+ case Some(_) => true
+ case _ => false
+ }
+ }
+ }
+
+ override def get(key: Coll[Byte], proof: Coll[Byte]): Option[Coll[Byte]] = {
+ val keyBytes = key.toArray
+ val bv = createVerifier(proof)
+ bv.performOneOperation(Lookup(ADKey @@ keyBytes)) match {
+ case Failure(_) => Interpreter.error(s"Tree proof is incorrect $treeData")
+ case Success(r) => r match {
+ case Some(v) => Some(Colls.fromArray(v))
+ case _ => None
+ }
+ }
+ }
+
+ override def getMany(keys: Coll[Coll[Byte]], proof: Coll[Byte]): Coll[Option[Coll[Byte]]] = {
+ val bv = createVerifier(proof)
+ keys.map { key =>
+ bv.performOneOperation(Lookup(ADKey @@ key.toArray)) match {
+ case Failure(_) => Interpreter.error(s"Tree proof is incorrect $treeData")
+ case Success(r) => r match {
+ case Some(v) => Some(Colls.fromArray(v))
+ case _ => None
+ }
+ }
+ }
+ }
+
+ override def insert(operations: Coll[(Coll[Byte], Coll[Byte])], proof: Coll[Byte]): Option[AvlTree] = {
+ if (!isInsertAllowed) {
+ None
+ } else {
+ val bv = createVerifier(proof)
+ operations.forall { case (key, value) =>
+ val insertRes = bv.performOneOperation(Insert(ADKey @@ key.toArray, ADValue @@ value.toArray))
+ if (insertRes.isFailure) {
+ Interpreter.error(s"Incorrect insert for $treeData (key: $key, value: $value, digest: $digest)")
+ }
+ insertRes.isSuccess
+ }
+ bv.digest match {
+ case Some(d) => Some(updateDigest(Colls.fromArray(d)))
+ case _ => None
+ }
+ }
+ }
+
+ override def update(operations: Coll[(Coll[Byte], Coll[Byte])], proof: Coll[Byte]): Option[AvlTree] = {
+ if (!isUpdateAllowed) {
+ None
+ } else {
+ val bv = createVerifier(proof)
+ operations.forall { case (key, value) =>
+ bv.performOneOperation(Update(ADKey @@ key.toArray, ADValue @@ value.toArray)).isSuccess
+ }
+ bv.digest match {
+ case Some(d) => Some(updateDigest(Colls.fromArray(d)))
+ case _ => None
+ }
+ }
+ }
+
+ override def remove(operations: Coll[Coll[Byte]], proof: Coll[Byte]): Option[AvlTree] = {
+ if (!isRemoveAllowed) {
+ None
+ } else {
+ val keysToRemove = operations.toArray.map(_.toArray)
+ val bv = createVerifier(proof)
+ keysToRemove.foreach(key => bv.performOneOperation(Remove(ADKey @@ key)))
+ bv.digest match {
+ case Some(v) => Some(updateDigest(Colls.fromArray(v)))
+ case _ => None
+ }
+ }
+ }
}
-import CostingBox._
+import sigmastate.eval.CostingBox._
-class CostingBox(val IR: Evaluation,
- isCost: Boolean,
- val ebox: ErgoBox)
+class EvalSizeBox(
+ propositionBytes: Size[Coll[Byte]],
+ bytes: Size[Coll[Byte]],
+ bytesWithoutRef: Size[Coll[Byte]],
+ registers: Size[Coll[Option[AnyValue]]],
+ tokens: Size[Coll[(Coll[Byte], Long)]]
+) extends CSizeBox(propositionBytes, bytes, bytesWithoutRef, registers, tokens) {
+ override def getReg[T](id: Byte)(implicit tT: RType[T]): Size[Option[T]] = {
+ val varSize = registers.asInstanceOf[SizeColl[Option[AnyValue]]].sizes(id.toInt)
+ val foundSize = varSize.asInstanceOf[SizeOption[AnyValue]].sizeOpt
+ val regSize = foundSize match {
+ case Some(varSize: SizeAnyValue) =>
+ assert(varSize.tVal == tT, s"Unexpected register type found ${varSize.tVal}: expected $tT")
+ val regSize = varSize.valueSize.asInstanceOf[Size[T]]
+ regSize
+ case _ =>
+ val z = Zero.typeToZero(tT)
+ val zeroVal = z.zero
+ val sized = Sized.typeToSized(tT)
+ sized.size(zeroVal)
+ }
+ new CSizeOption[T](Some(regSize))
+ }
+}
+class EvalSizeBuilder extends CSizeBuilder {
+ override def mkSizeBox(propositionBytes: Size[Coll[Byte]], bytes: Size[Coll[Byte]],
+ bytesWithoutRef: Size[Coll[Byte]], registers: Size[Coll[Option[AnyValue]]],
+ tokens: Size[Coll[(Coll[Byte], Long)]]): SizeBox = {
+ new EvalSizeBox(propositionBytes, bytes, bytesWithoutRef, registers, tokens)
+ }
+}
+case class CostingBox(val IR: Evaluation,
+ isCost: Boolean,
+ val ebox: ErgoBox)
extends TestBox(
colBytes(ebox.id)(IR),
ebox.value,
colBytes(ebox.bytes)(IR),
colBytes(ebox.bytesWithNoRef)(IR),
colBytes(ebox.propositionBytes)(IR),
- regs(ebox)(IR)
- )
-{
- override val builder = new CostingSigmaDslBuilder(IR)
+ regs(ebox, isCost)(IR)
+ ) with WrapperOf[ErgoBox] {
+ override val builder = new CostingSigmaDslBuilder()
+
+ override def wrappedValue: ErgoBox = ebox
- override def getReg[T](i: Int)(implicit cT: RType[T]): Option[T] =
+ override def getReg[T](i: Int)(implicit tT: RType[T]): Option[T] =
if (isCost) {
val optV =
if (i < 0 || i >= registers.length) None
else {
val value = registers(i)
- if (value != null ) {
+ if (value != null) {
// once the value is not null it should be of the right type
value match {
case value: TestValue[_] if value.value != null =>
@@ -70,18 +273,18 @@ class CostingBox(val IR: Evaluation,
}
optV.orElse {
- val tpe = IR.elemToSType(cT.asInstanceOf[IR.Elem[_]])
- val default = builder.Costing.defaultValue(cT).asInstanceOf[SType#WrappedType]
+ val tpe = Evaluation.rtypeToSType(tT)
+ val default = builder.Costing.defaultValue(tT).asInstanceOf[SType#WrappedType]
Some(Constant[SType](default, tpe).asInstanceOf[T])
}
} else
- super.getReg(i)
+ super.getReg(i)(tT)
- override def creationInfo: (Int, Col[Byte]) = {
- import Types._
- this.R3[(Int, Col[Byte])].get.asInstanceOf[Any] match {
+ override def creationInfo: (Int, Coll[Byte]) = {
+ this.getReg[(Int, Coll[Byte])](3).get.asInstanceOf[Any] match {
+ case info: Tuple2[Int, Coll[Byte]]@unchecked => info
case ConstantNode(arr: Array[Any], STuple(IndexedSeq(SInt, SByteArray))) if arr.length == 2 =>
- (arr(0).asInstanceOf[Int], builder.Cols.fromArray(arr(1).asInstanceOf[Array[Byte]]))
+ (arr(0).asInstanceOf[Int], builder.Colls.fromArray(arr(1).asInstanceOf[Array[Byte]]))
case v =>
sys.error(s"Invalid value $v of creationInfo register R3")
}
@@ -91,107 +294,330 @@ class CostingBox(val IR: Evaluation,
object CostingBox {
- def colBytes(b: Array[Byte])(implicit IR: Evaluation): Col[Byte] = IR.sigmaDslBuilderValue.Cols.fromArray(b)
+ import Evaluation._
+ import sigmastate.SType._
+
+ def colBytes(b: Array[Byte])(implicit IR: Evaluation): Coll[Byte] = IR.sigmaDslBuilderValue.Colls.fromArray(b)
- def regs(ebox: ErgoBox)(implicit IR: Evaluation): Col[AnyValue] = {
+ def regs(ebox: ErgoBox, isCost: Boolean)(implicit IR: Evaluation): Coll[AnyValue] = {
val res = new Array[AnyValue](ErgoBox.maxRegisters)
def checkNotYetDefined(id: Int, newValue: SValue) =
require(res(id) == null, s"register $id is defined more then once: previous value ${res(id)}, new value $newValue")
- for ((k, v) <- ebox.additionalRegisters) {
+ for ((k, v: Value[t]) <- ebox.additionalRegisters) {
checkNotYetDefined(k.number, v)
- res(k.number) = new TestValue(v)
+ val dslData = toDslData(v, v.tpe, isCost)
+ res(k.number) = toAnyValue(dslData.asWrappedType)(stypeToRType(v.tpe))
}
for (r <- ErgoBox.mandatoryRegisters) {
val regId = r.number
val v = ebox.get(r).get
checkNotYetDefined(regId, v)
- res(regId) = new TestValue(v)
+ val dslData = Evaluation.toDslData(v, v.tpe, isCost)
+ res(regId) = toAnyValue(dslData.asWrappedType)(stypeToRType(v.tpe))
}
- IR.sigmaDslBuilderValue.Cols.fromArray(res)
+ IR.sigmaDslBuilderValue.Colls.fromArray(res)
}
}
-class CostingSigmaDslBuilder(val IR: Evaluation) extends TestSigmaDslBuilder { dsl =>
- override val Costing = new CCostedBuilder {
+/** This class represents context variable and register value of a functional type A => B.
+ * When variable or register is accessed using `getVar[A => B](id).get` or
+ * `box.getReg[A => B].get an instance of this class is returned.
+ *
+ * It internally transforms a given `tree` into executable function.
+ * This it similar to what happens during validation of propositions in the input boxes:
+ * - size check of underlying ErgoTree against limits
+ * - construction of `calcF` and `costF` graphs, both are stored together with resulting function.
+ * - check the types of `calcF` graph to be compatible with expected types A and B
+ * If anything goes wrong, this operation fails and if it is used in the script, the script also fails.
+ *
+ * When f is obtained as `val f = getVar[Int => Int](id).get` then any application `f(x)` involves size estimation
+ * using underlying `costF(x)`.
+ * */
+//case class CFunc[A,B](context: sigmastate.interpreter.Context, tree: SValue)
+// (implicit tDom: RType[A], tRange: RType[B], IR: IRContext) extends (A => B) {
+// import CFunc._
+//
+// private val compiled = {
+// import IR._
+// val IR.Pair(calcF, costF) = IR.doCosting(emptyEnv, tree)
+//
+// val eDom = asElem[Any](IR.rtypeToElem(tDom))
+// val eRange = asElem[Any](IR.rtypeToElem(tRange))
+//
+// IR.verifyCalcFunc[Any => Any](asRep[Context => (Any => Any)](calcF), IR.funcElement(eDom, eRange))
+//// IR.verifyCostFunc(costF).fold(t => throw t, x => x)
+//// IR.verifyIsProven(calcF).fold(t => throw t, x => x)
+//
+// // check cost
+//// val costingCtx = context.toSigmaContext(IR, isCost = true)
+//// val costFun = IR.compile[SInt.type](IR.getDataEnv, costF)
+//// val IntConstant(estimatedCost) = costFun(costingCtx)
+//// if (estimatedCost > maxCost) {
+//// throw new Error(s"Estimated expression complexity $estimatedCost exceeds the limit $maxCost in $tree")
+//// }
+// // check calc
+// val calcCtx = context.toSigmaContext(IR, isCost = false)
+// val valueFun = IR.compile[SFunc](IR.getDataEnv, asRep[Context => SFunc#WrappedType](calcF))
+// val res = valueFun(calcCtx) match {
+// case Constant(f, fTpe: SFunc) => f
+// case v => v
+// }
+// res.asInstanceOf[A => B]
+// }
+//
+// override def apply(x: A): B = compiled(x)
+//}
+object CFunc {
+ /** The cost of creating resulting function but not its execution.
+ * Thus it is expected to be small. It can be increased if useful cases are found
+ * such that `tree` should contains heavy operations. */
+ val maxCost = 1000
+}
+
+case class CPreHeader(
+ version: Byte,
+ parentId: Coll[Byte],
+ timestamp: Long,
+ nBits: Long,
+ height: Int,
+ minerPk: GroupElement,
+ votes: Coll[Byte],
+ ) extends PreHeader {}
+
+case class CHeader(
+ id: Coll[Byte],
+ version: Byte,
+ parentId: Coll[Byte],
+ ADProofsRoot: Coll[Byte],
+ stateRoot: CAvlTree,
+ transactionsRoot: Coll[Byte],
+ timestamp: Long,
+ nBits: Long,
+ height: Int,
+ extensionRoot: Coll[Byte],
+ minerPk: GroupElement,
+ powOnetimePk: GroupElement,
+ powNonce: Coll[Byte],
+ powDistance: BigInt,
+ votes: Coll[Byte],
+ ) extends Header {
+}
+
+class CCostModel extends CostModel {
+ private def costOf(opName: String, opType: SFunc): Int = {
+ val operId = OperationId(opName, opType)
+ costOf(operId)
+ }
+
+ @inline private def costOf(operId: OperationId): Int = {
+ val cost = sigmastate.utxo.CostTable.DefaultCosts(operId)
+ cost
+ }
+
+ def AccessBox: Int = costOf("AccessBox", SFunc(SContext, SBox))
+
+ def AccessAvlTree: Int = costOf("AccessAvlTree", SFunc(SContext, SAvlTree))
+
+ def GetVar: Int = costOf("GetVar", SFunc(IndexedSeq(SContext, SByte), SOption(SOption.tT)))
+
+ def DeserializeVar: Int = costOf("DeserializeVar", SFunc(IndexedSeq(SContext, SByte), SOption(SOption.tT)))
+
+ def GetRegister: Int = costOf("GetRegister", SFunc(IndexedSeq(SBox, SByte), SOption(SOption.tT)))
+
+ def DeserializeRegister: Int = costOf("DeserializeRegister", SFunc(IndexedSeq(SBox, SByte), SOption(SOption.tT)))
+
+ def SelectField: Int = costOf("SelectField", SFunc(IndexedSeq(), SUnit))
+
+ def CollectionConst: Int = costOf("Const", SFunc(IndexedSeq(), SCollection(STypeIdent("IV"))))
+
+ def AccessKiloByteOfData: Int = costOf("AccessKiloByteOfData", SFunc(IndexedSeq(), SUnit))
+
+ def dataSize[T](x: T)(implicit cT: ClassTag[T]): Long = SigmaPredef.dataSize(x)
+
+ def PubKeySize: Long = CryptoConstants.EncodedGroupElementLength
+}
+
+class CostingSigmaDslBuilder extends TestSigmaDslBuilder {
+ dsl =>
+ override val Costing: CostedBuilder = new CCostedBuilder {
+
import RType._
+
override def defaultValue[T](valueType: RType[T]): T = (valueType match {
- case ByteType | IR.ByteElement => 0.toByte
- case ShortType | IR.ShortElement=> 0.toShort
- case IntType | IR.IntElement => 0
- case LongType | IR.LongElement => 0L
- case StringType | IR.StringElement => ""
- case p: PairRType[a, b] => (defaultValue(p.tA), defaultValue(p.tB))
- case col: Types.ColRType[a] => dsl.Cols.fromArray(Array[a]()(col.tA.classTag))
- case p: IR.PairElem[a, b] => (defaultValue(p.eFst), defaultValue(p.eSnd))
- case col: IR.Col.ColElem[a,_] => dsl.Cols.fromArray(Array[a]()(col.eItem.classTag))
- case avl: IR.AvlTree.AvlTreeElem[_] => CostingAvlTree(IR, AvlTreeData.dummy)
+ case BooleanType => false
+ case ByteType => 0.toByte
+ case ShortType => 0.toShort
+ case IntType => 0
+ case LongType => 0L
+ case StringType => ""
+ case CharType => 0.toChar
+ case FloatType => 0.0f
+ case DoubleType => 0.0d
+ case p: PairType[a, b] => (defaultValue(p.tFst), defaultValue(p.tSnd))
+ case col: CollType[a] => dsl.Colls.emptyColl(col.tItem)
+ case tup: TupleType => tup.items.map(t => defaultValue(t))
+ case SType.AvlTreeDataRType => AvlTreeData.dummy
+ case AvlTreeRType => CAvlTree(AvlTreeData.dummy)
+
+ case SType.SigmaBooleanRType => TrivialProp.FalseProp
+ case SigmaPropRType => sigmaProp(false)
+
+ case ECPointRType => CryptoConstants.dlogGroup.generator
+ case GroupElementRType => groupGenerator
+
case _ => sys.error(s"Cannot create defaultValue($valueType)")
}).asInstanceOf[T]
}
- override def treeLookup(tree: AvlTree, key: Col[Byte], proof: Col[Byte]) = {
- val keyBytes = key.arr
- val proofBytes = proof.arr
- val treeData = tree.asInstanceOf[CostingAvlTree].treeData
- val bv = AvlTreeConstant(treeData).createVerifier(SerializedAdProof @@ proofBytes)
- bv.performOneOperation(Lookup(ADKey @@ keyBytes)) match {
- case Failure(_) => Interpreter.error(s"Tree proof is incorrect $treeData")
- case Success(r) => r match {
- case Some(v) => Some(Cols.fromArray(v))
- case _ => None
- }
- }
+ override def CostModel: CostModel = new CCostModel
+
+ override def BigInt(n: BigInteger): BigInt = new CBigInt(n)
+
+ override def GroupElement(p: ECPoint): GroupElement = p match {
+ case ept: EcPointType => CGroupElement(ept)
+ case m => sys.error(s"Point of type ${m.getClass} is not supported")
+ }
+
+ def SigmaProp(sigmaTree: SigmaBoolean): SigmaProp = new CSigmaProp(sigmaTree)
+
+ /** Extract `sigmastate.Values.SigmaBoolean` from DSL's `SigmaProp` type. */
+ def toSigmaBoolean(p: SigmaProp): SigmaBoolean = p.asInstanceOf[CSigmaProp].sigmaTree
+
+ /** Extract `sigmastate.AvlTreeData` from DSL's `AvlTree` type. */
+ def toAvlTreeData(p: AvlTree): AvlTreeData = p.asInstanceOf[CAvlTree].treeData
+
+ override def avlTree(operationFlags: Byte, digest: Coll[Byte], keyLength: Int, valueLengthOpt: Option[Int]): CAvlTree = {
+ val treeData = AvlTreeData(ADDigest @@ digest.toArray, AvlTreeFlags(operationFlags), keyLength, valueLengthOpt)
+ CAvlTree(treeData)
}
- override def treeModifications(tree: AvlTree, operations: Col[Byte], proof: Col[Byte]) = {
- val operationsBytes = operations.arr
- val proofBytes = proof.arr
- val treeData = tree.asInstanceOf[CostingAvlTree].treeData
- val bv = AvlTreeConstant(treeData).createVerifier(SerializedAdProof @@ proofBytes)
- val opSerializer = new OperationSerializer(bv.keyLength, bv.valueLengthOpt)
- val ops: Seq[Operation] = opSerializer.parseSeq(Serializer.startReader(operationsBytes, 0))
- ops.foreach(o => bv.performOneOperation(o))
- bv.digest match {
- case Some(v) => Some(Cols.fromArray(v))
- case _ => None
+ private def toSigmaTrees(props: Array[SigmaProp]): Array[SigmaBoolean] = {
+ props.map {
+ case csp: CSigmaProp => csp.sigmaTree
+ case m: MockSigma => TrivialProp(m.isValid) //needed for tests, e.g. "atLeast" test
}
}
- override def exponentiate(base: ECPoint, exponent: BigInteger) = {
- CryptoConstants.dlogGroup.exponentiate(base.asInstanceOf[EcPointType], exponent)
+ @inline private def toEcPointType(ge: GroupElement): EcPointType =
+ toECPoint(ge).asInstanceOf[EcPointType]
+
+ override def atLeast(bound: Int, props: Coll[SigmaProp]): SigmaProp = {
+ if (props.length > AtLeast.MaxChildrenCount)
+ throw new IllegalArgumentException(s"Expected input elements count should not exceed ${AtLeast.MaxChildrenCount}, actual: ${props.length}")
+ val sigmaTrees = toSigmaTrees(props.toArray)
+ val tree = AtLeast.reduce(bound, sigmaTrees)
+ CSigmaProp(tree)
+ }
+
+ override def allZK(props: Coll[SigmaProp]): SigmaProp = {
+ val sigmaTrees = toSigmaTrees(props.toArray)
+ val tree = CAND.normalized(sigmaTrees)
+ CSigmaProp(tree)
+ }
+
+ override def anyZK(props: Coll[SigmaProp]): SigmaProp = {
+ val sigmaTrees = toSigmaTrees(props.toArray)
+ val tree = COR.normalized(sigmaTrees)
+ CSigmaProp(tree)
+ }
+
+ override def sigmaProp(b: Boolean): SigmaProp = {
+ CSigmaProp(TrivialProp(b))
}
- override def atLeast(bound: Int, children: Col[SigmaProp]): SigmaProp = {
- Interpreter.error("Should not be called. Method calls of atLeast should be handled in Evaluation.compile.evaluate rule")
+ override def blake2b256(bytes: Coll[Byte]): Coll[Byte] = {
+ val h = Blake2b256.hash(bytes.toArray)
+ Colls.fromArray(h)
+ }
+
+ override def sha256(bytes: Coll[Byte]): Coll[Byte] = {
+ val h = Sha256.hash(bytes.toArray)
+ Colls.fromArray(h)
+ }
+
+ override def proveDlog(ge: GroupElement): SigmaProp =
+ CSigmaProp(ProveDlog(toECPoint(ge).asInstanceOf[EcPointType]))
+
+ override def proveDHTuple(g: GroupElement, h: GroupElement, u: GroupElement, v: GroupElement): SigmaProp = {
+ val dht = ProveDHTuple(toEcPointType(g), toEcPointType(h), toEcPointType(u), toEcPointType(v))
+ CSigmaProp(dht)
+ }
+
+ override def groupGenerator: GroupElement = {
+ this.GroupElement(CryptoConstants.dlogGroup.generator)
+ }
+
+ override def substConstants[T](scriptBytes: Coll[Byte],
+ positions: Coll[Int],
+ newValues: Coll[T])
+ (implicit cT: RType[T]): Coll[Byte] = {
+ val typedNewVals = newValues.toArray.map(_.asInstanceOf[Value[SType]])
+ val res = SubstConstants.eval(scriptBytes.toArray, positions.toArray, typedNewVals)
+ Colls.fromArray(res)
+ }
+
+ override def decodePoint(encoded: Coll[Byte]): GroupElement = {
+ val r = SigmaSerializer.startReader(encoded.toArray)
+ val p = GroupElementSerializer.parse(r)
+ this.GroupElement(p)
}
}
-class CostingDataContext(
- val IR: Evaluation,
- inputs: Array[Box],
- outputs: Array[Box],
- height: Int,
- selfBox: Box,
- lastBlockUtxoRootHash: AvlTree,
- minerPubKey: Array[Byte],
- vars: Array[AnyValue],
- var isCost: Boolean)
- extends TestContext(inputs, outputs, height, selfBox, lastBlockUtxoRootHash, minerPubKey, vars)
-{
- override val builder = new CostingSigmaDslBuilder(IR)
-
- override def getVar[T](id: Byte)(implicit cT: RType[T]) =
+object CostingSigmaDslBuilder extends CostingSigmaDslBuilder
+
+case class CostingDataContext(
+ _dataInputs: Coll[Box],
+ override val headers: Coll[Header],
+ override val preHeader: PreHeader,
+ inputs: Coll[Box],
+ outputs: Coll[Box],
+ height: Int,
+ selfBox: Box,
+ lastBlockUtxoRootHash: AvlTree,
+ _minerPubKey: Coll[Byte],
+ vars: Coll[AnyValue],
+ var isCost: Boolean)
+ extends Context {
+ @inline def builder: SigmaDslBuilder = CostingSigmaDslBuilder
+
+ @inline def HEIGHT: Int = height
+
+ @inline def SELF: Box = selfBox
+
+ @inline def dataInputs: Coll[Box] = _dataInputs
+
+ @inline def INPUTS = inputs
+
+ @inline def OUTPUTS = outputs
+
+ @inline def LastBlockUtxoRootHash = lastBlockUtxoRootHash
+
+ @inline def minerPubKey = _minerPubKey
+
+
+ def findSelfBoxIndex: Int = {
+ var i = 0
+ while (i < inputs.length) {
+ if (inputs(i) eq selfBox) return i
+ i += 1
+ }
+ -1
+ }
+
+ override val selfBoxIndex: Int = findSelfBoxIndex
+
+ override def getVar[T](id: Byte)(implicit tT: RType[T]): Option[T] = {
if (isCost) {
- implicit val tag: ClassTag[T] = cT.classTag
+ // implicit val tag: ClassTag[T] = cT.classTag
val optV =
if (id < 0 || id >= vars.length) None
else {
val value = vars(id)
- if (value != null ) {
+ if (value != null) {
// once the value is not null it should be of the right type
value match {
case value: TestValue[_] if value.value != null =>
@@ -201,10 +627,23 @@ class CostingDataContext(
} else None
}
optV.orElse {
- val tpe = IR.elemToSType(cT.asInstanceOf[IR.Elem[_]])
- val default = builder.Costing.defaultValue(cT).asInstanceOf[SType#WrappedType]
+ val tpe = Evaluation.rtypeToSType(tT)
+ val default = builder.Costing.defaultValue(tT).asInstanceOf[SType#WrappedType]
Some(Constant[SType](default, tpe).asInstanceOf[T])
}
- } else
- super.getVar(id)(cT)
+ } else {
+ implicit val tag: ClassTag[T] = tT.classTag
+ if (id < 0 || id >= vars.length) return None
+ val value = vars(id)
+ if (value != null) {
+ // once the value is not null it should be of the right type
+ value match {
+ case value: TestValue[_] if value.value != null && value.tA == tT =>
+ Some(value.value.asInstanceOf[T])
+ case _ =>
+ throw new InvalidType(s"Cannot getVar[${tT.name}]($id): invalid type of value $value at id=$id")
+ }
+ } else None
+ }
+ }
}
diff --git a/src/main/scala/sigmastate/eval/CostingRules.scala b/src/main/scala/sigmastate/eval/CostingRules.scala
new file mode 100644
index 0000000000..14c9ff62d6
--- /dev/null
+++ b/src/main/scala/sigmastate/eval/CostingRules.scala
@@ -0,0 +1,570 @@
+package sigmastate.eval
+
+import org.ergoplatform.{ErgoLikeContext, ErgoBox}
+import scalan.{SigmaLibrary, RType}
+import sigmastate._
+import sigmastate.Values._
+import sigmastate.SType.AnyOps
+import sigmastate.interpreter.CryptoConstants
+import sigmastate.utxo.CostTable
+import special.collection.Coll
+
+trait CostingRules extends SigmaLibrary { IR: RuntimeCosting =>
+ import Coll._
+ import BigInt._
+ import SigmaProp._
+ import AvlTree._
+ import GroupElement._
+ import CollBuilder._
+ import SizeBuilder._
+ import CostedBuilder._
+ import Costed._
+ import Size._
+ import SizePrim._
+ import SizeColl._
+ import SizeOption._
+ import SizePair._
+ import CSizePair._
+ import SizeBox._
+ import SizeContext._
+ import CCostedPrim._
+ import CCostedPair._
+ import CCostedOption._
+ import CostedFunc._
+ import CCostedFunc._
+ import CostedColl._
+ import CCostedColl._
+ import SigmaDslBuilder._
+ import CostModel._
+ import WSpecialPredef._
+ import WRType._
+ import WOption._
+ import Box._
+
+ abstract class CostingHandler[T](createCoster: (RCosted[T], SMethod, Seq[RCosted[_]]) => Coster[T]) {
+ def apply(obj: RCosted[_], method: SMethod, args: Seq[RCosted[_]]): RCosted[_] = {
+ val coster = createCoster(asCosted[T](obj), method, args)
+ val costerClass = coster.getClass
+ val costerMethod = costerClass.getMethod(method.name, Array.fill(args.length)(classOf[Sym]):_*)
+ val res = costerMethod.invoke(coster, args:_*)
+ res.asInstanceOf[RCosted[_]]
+ }
+ }
+
+ /** Special graph node to represent accumulation of the operation costs.
+ * In general, due to node sharing it is incorrect to just sum up all the `args` costs
+ * and add `resCost` to that value.
+ * Example:
+ *
+ * val x = ..
+ * val y = op1(x)
+ * val z = op2(x)
+ * val res = op3(y, z)
+ *
+ * The naive summation will lead to the cost of x` is accumulated both into `cost of y`
+ * and into `cost of z`, so in the `cost of res` it is accumulated twice.
+ * To avoid this problem OpCost nodes require special handling in during evaluation.
+ *
+ * @param args costs of the arguments, which are here represent dependency information.
+ * @param opCost operation cost, which should be added to the currently accumulated cost
+ * @see `Evaluation`
+ */
+ case class OpCost(args: Seq[Rep[Int]], opCost: Rep[Int]) extends BaseDef[Int] {
+ override def transform(t: Transformer) = OpCost(t(args), t(opCost))
+ }
+ def opCost(args: Seq[Rep[Int]], opCost: Rep[Int]): Rep[Int] = OpCost(args, opCost)
+
+ def selectFieldCost = sigmaDslBuilder.CostModel.SelectField
+
+ // TODO move initialization to init() to support resetContext
+ lazy val SizeUnit: RSize[Unit] = costedBuilder.mkSizePrim(0L, UnitElement)
+ lazy val SizeBoolean: RSize[Boolean] = costedBuilder.mkSizePrim(1L, BooleanElement)
+ lazy val SizeByte: RSize[Byte] = costedBuilder.mkSizePrim(1L, ByteElement)
+ lazy val SizeShort: RSize[Short] = costedBuilder.mkSizePrim(2L, ShortElement)
+ lazy val SizeInt: RSize[Int] = costedBuilder.mkSizePrim(4L, IntElement)
+ lazy val SizeLong: RSize[Long] = costedBuilder.mkSizePrim(8L, LongElement)
+ lazy val SizeBigInt: RSize[BigInt] = costedBuilder.mkSizePrim(SBigInt.MaxSizeInBytes, element[BigInt])
+ lazy val SizeString: RSize[String] = costedBuilder.mkSizePrim(256L, StringElement)
+ lazy val SizeAvlTree: RSize[AvlTree] = costedBuilder.mkSizePrim(AvlTreeData.TreeDataSize.toLong, element[AvlTree])
+ lazy val SizeGroupElement: RSize[GroupElement] = costedBuilder.mkSizePrim(CryptoConstants.EncodedGroupElementLength.toLong, element[GroupElement])
+
+ lazy val SizeHashBytes: RSize[Coll[Byte]] = {
+ val len: Rep[Int] = CryptoConstants.hashLength
+ val sizes = colBuilder.replicate(len, SizeByte)
+ costedBuilder.mkSizeColl(sizes)
+ }
+
+ def mkSizeSigmaProp(size: Rep[Long]): RSize[SigmaProp] = costedBuilder.mkSizePrim(size, element[SigmaProp])
+
+ def SizeOfSigmaBoolean(sb: SigmaBoolean): RSize[SigmaProp] = mkSizeSigmaProp(SSigmaProp.dataSize(sb.asWrappedType))
+
+ case class Cast[To](eTo: Elem[To], x: Rep[Def[_]]) extends BaseDef[To]()(eTo) {
+ override def transform(t: Transformer) = Cast(eTo, t(x))
+ }
+
+ def tryCast[To](x: Rep[Def[_]])(implicit eTo: Elem[To]): Rep[To] = {
+ if (eTo.runtimeClass.isAssignableFrom(x.elem.runtimeClass))
+ x.asRep[To]
+ else
+ Cast(eTo, x)
+ }
+
+ def asCostedColl[T](collC: RCosted[Coll[T]]): Rep[CostedColl[T]] = {
+ implicit val eT = collC.elem.eVal.eItem
+ tryCast[CostedColl[T]](collC)
+ }
+ def asCostedFunc[A,B](fC: RCosted[A => B]): Rep[CostedFunc[Unit,A,B]] = {
+ implicit val eA = fC.elem.eVal.eDom
+ implicit val eB = fC.elem.eVal.eRange
+ tryCast[CostedFunc[Unit, A, B]](fC)(costedFuncElement(UnitElement, eA, eB))
+ }
+ def asSizeColl[T](collS: RSize[Coll[T]]): Rep[SizeColl[T]] = {
+ implicit val eT = collS.elem.eVal.eItem
+ tryCast[SizeColl[T]](collS)
+ }
+ def asSizePair[A, B](s: RSize[(A,B)]): Rep[SizePair[A,B]] = {
+ implicit val eA = s.elem.eVal.eFst
+ implicit val eB = s.elem.eVal.eSnd
+ tryCast[SizePair[A,B]](s)
+ }
+ def asSizeOption[T](optS: RSize[WOption[T]]): Rep[SizeOption[T]] = {
+ implicit val eA = optS.elem.eVal.eItem
+ tryCast[SizeOption[T]](optS)
+ }
+ def asSizeBox(ctx: RSize[Box]): Rep[SizeBox] = tryCast[SizeBox](ctx)
+ def asSizeContext(ctx: RSize[Context]): Rep[SizeContext] = tryCast[SizeContext](ctx)
+
+ def SOME[A](x: Rep[A]): Rep[WOption[A]] = RWSpecialPredef.some(x)
+
+ def mkSizeColl[T:Elem](len: Rep[Int]): Rep[Size[Coll[T]]] = {
+ val sizes = colBuilder.replicate(len, costedBuilder.mkSizePrim(typeSize[T], element[T]): RSize[T])
+ costedBuilder.mkSizeColl(sizes)
+ }
+
+ def mkSizeColl[T](len: Rep[Int], sItem: RSize[T]): Rep[Size[Coll[T]]] = {
+ val sizes = colBuilder.replicate(len, sItem)
+ costedBuilder.mkSizeColl(sizes)
+ }
+
+ def mkSizeOption[T](size: RSize[T]): Rep[Size[WOption[T]]] = costedBuilder.mkSizeOption(SOME(size))
+ def mkSizePair[A, B](l: RSize[A], r: RSize[B]): Rep[Size[(A,B)]] = costedBuilder.mkSizePair(l, r)
+
+ def mkCostedColl[T](values: RColl[T], costs: RColl[Int], sizes: RColl[Size[T]], valuesCost: Rep[Int]): RCostedColl[T] =
+ costedBuilder.mkCostedColl(values, costs, sizes, valuesCost)
+
+ def mkCostedOption[T](value: ROption[T], costOpt: ROption[Int], sizeOpt: ROption[Size[T]], accCost: Rep[Int]): RCostedOption[T] =
+ costedBuilder.mkCostedOption(value, costOpt, sizeOpt, accCost)
+
+ def mkCostedFunc[A,R](f: RFuncCosted[A,R], cost: Rep[Int], codeSize: Rep[Long], eArg: Elem[A], eRes: Elem[R]): Rep[CostedFunc[Unit, A, R]] = {
+ val envC = RCCostedPrim((), 0, SizeUnit)
+ val sFunc = costedBuilder.mkSizeFunc(SizeUnit, codeSize, eArg, eRes)
+ RCCostedFunc(envC, f, cost, sFunc)
+ }
+
+ abstract class Coster[T](obj: RCosted[T], method: SMethod, args: Seq[RCosted[_]]) {
+ def costOfArgs = (obj +: args).map(_.cost)
+ def sizeOfArgs = args.foldLeft(obj.size.dataSize)({ case (s, e) => s + e.size.dataSize })
+
+ def constantSizeProperyAccess[R](prop: Rep[T] => Rep[R]): RCosted[R] =
+ withConstantSize(prop(obj.value), opCost(costOfArgs, selectFieldCost))
+
+ def knownSizeProperyAccess[R](prop: Rep[T] => Rep[R], size: RSize[R]): RCosted[R] =
+ RCCostedPrim(prop(obj.value), opCost(costOfArgs, selectFieldCost), size)
+
+ def knownLengthCollProperyAccess[R](prop: Rep[T] => Rep[Coll[R]], len: Rep[Int]): Rep[CostedColl[R]] =
+ mkCostedColl(prop(obj.value), len, opCost(costOfArgs, selectFieldCost))
+
+ def digest32ProperyAccess(prop: Rep[T] => Rep[Coll[Byte]]): Rep[CostedColl[Byte]] =
+ knownLengthCollProperyAccess(prop, CryptoConstants.hashLength)
+
+ def groupElementProperyAccess(prop: Rep[T] => Rep[GroupElement]): RCosted[GroupElement] =
+ knownSizeProperyAccess(prop, SizeGroupElement)
+
+ def bigIntProperyAccess(prop: Rep[T] => Rep[BigInt]): RCosted[BigInt] =
+ knownSizeProperyAccess(prop, SizeBigInt)
+
+ def defaultProperyAccess[R](prop: Rep[T] => Rep[R], propSize: RSize[T] => RSize[R]): RCosted[R] =
+ RCCostedPrim(prop(obj.value), opCost(costOfArgs, selectFieldCost), propSize(obj.size))
+
+ def defaultOptionProperyAccess[R: Elem](prop: Rep[T] => ROption[R], propSize: RSize[T] => RSize[WOption[R]], itemCost: Rep[Int]): RCostedOption[R] = {
+ val v = prop(obj.value)
+ val s = propSize(obj.size)
+ RCCostedOption(v, SOME(itemCost), asSizeOption(s).sizeOpt, opCost(costOfArgs, selectFieldCost))
+ }
+
+ def defaultCollProperyAccess[R: Elem](prop: Rep[T] => RColl[R], propSize: RSize[T] => RSize[Coll[R]], itemCost: Rep[Int]): RCostedColl[R] = {
+ val v = prop(obj.value)
+ val s = propSize(obj.size)
+ val sizes = asSizeColl(s).sizes
+ val costs = colBuilder.replicate(sizes.length, itemCost)
+ RCCostedColl(v, costs, sizes, opCost(costOfArgs, selectFieldCost))
+ }
+
+ def boxPropertyAccess(prop: Rep[T] => Rep[Box], propSize: RSize[T] => RSize[Box]): RCosted[Box] = {
+ val v = prop(obj.value)
+ val c = opCost(costOfArgs, sigmaDslBuilder.CostModel.AccessBox)
+ val s = propSize(obj.size)
+ RCCostedPrim(v, c, s)
+ }
+
+// /** Cost of collection with static size elements. */
+// def costColWithConstSizedItem[T](xs: Coll[T], len: Int, itemSize: Long): CostedColl[T] = {
+// val perItemCost = (len.toLong * itemSize / 1024L + 1L) * this.CostModel.AccessKiloByteOfData.toLong
+// val costs = this.Colls.replicate(len, perItemCost.toInt)
+// val sizes = this.Colls.replicate(len, itemSize)
+// val valueCost = this.CostModel.CollectionConst
+// this.Costing.mkCostedColl(xs, costs, sizes, valueCost)
+// }
+//
+// def costOption[T](opt: Option[T], opCost: Int)(implicit cT: RType[T]): CostedOption[T] = {
+// val none = this.Costing.mkCostedNone[T](opCost)
+// opt.fold[CostedOption[T]](none)(x => this.Costing.mkCostedSome(this.Costing.costedValue(x, SpecialPredef.some(opCost))))
+// }
+ }
+
+ class GroupElementCoster(obj: RCosted[GroupElement], method: SMethod, args: Seq[RCosted[_]]) extends Coster[GroupElement](obj, method, args){
+ import GroupElement._
+ def getEncoded: RCosted[Coll[Byte]] =
+ knownLengthCollProperyAccess(_.getEncoded, CryptoConstants.EncodedGroupElementLength.toInt)
+
+ def negate: RCosted[GroupElement] = {
+ RCCostedPrim(obj.value.negate, opCost(costOfArgs, costOf(method)), SizeGroupElement)
+ }
+ }
+
+ object GroupElementCoster extends CostingHandler[GroupElement]((obj, m, args) => new GroupElementCoster(obj, m, args))
+
+ class AvlTreeCoster(obj: RCosted[AvlTree], method: SMethod, args: Seq[RCosted[_]]) extends Coster[AvlTree](obj, method, args){
+ import AvlTree._
+ def digest() = knownLengthCollProperyAccess(_.digest, AvlTreeData.DigestSize)
+ def enabledOperations() = constantSizeProperyAccess(_.enabledOperations)
+ def keyLength() = constantSizeProperyAccess(_.keyLength)
+ def valueLengthOpt() = defaultOptionProperyAccess(_.valueLengthOpt, _ => mkSizeOption(SizeInt), 0)
+ def isInsertAllowed() = constantSizeProperyAccess(_.isInsertAllowed)
+ def isUpdateAllowed() = constantSizeProperyAccess(_.isUpdateAllowed)
+ def isRemoveAllowed() = constantSizeProperyAccess(_.isRemoveAllowed)
+
+ def updateOperations(flags: RCosted[Byte]) = {
+ RCCostedPrim(obj.value.updateOperations(flags.value), opCost(costOfArgs, costOf(method)), obj.size)
+ }
+ def contains(key: RCosted[Coll[Byte]], proof: RCosted[Coll[Byte]]): RCosted[Boolean] = {
+ withConstantSize(obj.value.contains(key.value, proof.value), opCost(costOfArgs, perKbCostOf(method, sizeOfArgs)))
+ }
+ def get(key: RCosted[Coll[Byte]], proof: RCosted[Coll[Byte]]): RCosted[WOption[Coll[Byte]]] = {
+ val value = obj.value.get(key.value, proof.value)
+ val size = sizeOfArgs
+ val c = opCost(costOfArgs, perKbCostOf(method, size))
+ val res = RCCostedOption(value,
+ RWSpecialPredef.some(0),
+ RWSpecialPredef.some(proof.size),
+ c)
+ res
+ }
+ def getMany(_keys: RCosted[Coll[Coll[Byte]]], _proof: RCosted[Coll[Byte]]): RCosted[Coll[WOption[Coll[Byte]]]] = {
+ val keysC = asCostedColl[Coll[Byte]](_keys)
+ val proofC = asCostedColl[Byte](_proof)
+ val nKeys = keysC.sizes.length
+
+ val value = obj.value.getMany(keysC.value, proofC.value)
+ val costs = colBuilder.replicate(nKeys, 0)
+ val valuesCost = opCost(costOfArgs, perKbCostOf(method, sizeOfArgs))
+
+ val treeValueLengthPerKey = proofC.sizes.length div nKeys
+ val treeValueS = mkSizeColl[Byte](treeValueLengthPerKey)
+ val sizes = colBuilder.replicate(nKeys, mkSizeOption(treeValueS))
+
+ val res = RCCostedColl(value, costs, sizes, valuesCost)
+ res
+ }
+
+ private def treeModifierMethod(meth: Rep[AvlTree] => Rep[WOption[AvlTree]]): RCosted[WOption[AvlTree]] = {
+ val value = meth(obj.value)
+ val size = sizeOfArgs
+ RCCostedOption(value,
+ RWSpecialPredef.some(0),
+ SOME(obj.size), opCost(costOfArgs, perKbCostOf(method, size)))
+ }
+
+ def insert(kvs: RCosted[Coll[(Coll[Byte], Coll[Byte])]], proof: RCosted[Coll[Byte]]): RCosted[WOption[AvlTree]] = {
+ treeModifierMethod(_.insert(kvs.value, proof.value))
+ }
+ def update(kvs: RCosted[Coll[(Coll[Byte], Coll[Byte])]], proof: RCosted[Coll[Byte]]): RCosted[WOption[AvlTree]] = {
+ treeModifierMethod(_.update(kvs.value, proof.value))
+ }
+ def remove(keys: RCosted[Coll[Coll[Byte]]], proof: RCosted[Coll[Byte]]): RCosted[WOption[AvlTree]] = {
+ treeModifierMethod(_.remove(keys.value, proof.value))
+ }
+ }
+
+ object AvlTreeCoster extends CostingHandler[AvlTree]((obj, m, args) => new AvlTreeCoster(obj, m, args))
+
+ class ContextCoster(obj: RCosted[Context], method: SMethod, args: Seq[RCosted[_]]) extends Coster[Context](obj, method, args){
+ import Context._
+ def boxCollProperty(prop: Rep[Context] => Rep[Coll[Box]], propSize: Rep[SizeContext] => RSize[Coll[Box]]) = {
+ defaultCollProperyAccess(prop, ctxS => propSize(asSizeContext(ctxS)), sigmaDslBuilder.CostModel.AccessBox)
+ }
+ def headers() = {
+ knownLengthCollProperyAccess(_.headers, ErgoLikeContext.MaxHeaders)
+ }
+ def preHeader() = constantSizeProperyAccess(_.preHeader)
+
+ def dataInputs(): RCostedColl[Box] = {
+ boxCollProperty(_.dataInputs, _.dataInputs)
+ }
+
+ def OUTPUTS: RCostedColl[Box] = {
+ boxCollProperty(_.OUTPUTS, _.outputs)
+ }
+
+ def INPUTS: RCostedColl[Box] = {
+ boxCollProperty(_.INPUTS, _.inputs)
+ }
+
+ def HEIGHT: RCosted[Int] = constantSizeProperyAccess(_.HEIGHT)
+
+ def SELF: RCosted[Box] = boxPropertyAccess(_.SELF, asSizeContext(_).selfBox)
+
+ def LastBlockUtxoRootHash: RCosted[AvlTree] =
+ knownSizeProperyAccess(_.LastBlockUtxoRootHash, SizeAvlTree)
+
+ def minerPubKey: RCostedColl[Byte] =
+ knownLengthCollProperyAccess(_.minerPubKey, CryptoConstants.EncodedGroupElementLength.toInt)
+
+ def getVar[T](id: RCosted[Byte])(implicit tT: Rep[WRType[T]]): RCostedOption[T] = { ???
+// defaultOptionProperyAccess(_.getVar(id.value)(tT.eA), asSizeContext(_).reg)
+// val opt = ctx.getVar(id)(cT)
+// dsl.costOption(opt, dsl.CostModel.GetVar)
+ }
+
+ def selfBoxIndex: RCosted[Int] = constantSizeProperyAccess(_.selfBoxIndex)
+
+ }
+
+ object ContextCoster extends CostingHandler[Context]((obj, m, args) => new ContextCoster(obj, m, args))
+
+ class BoxCoster(obj: RCosted[Box], method: SMethod, args: Seq[RCosted[_]]) extends Coster[Box](obj, method, args){
+ import Box._
+ import ErgoBox._
+
+ def creationInfo: RCosted[(Int, Coll[Byte])] = {
+ val info = obj.value.creationInfo
+ val cost = opCost(Seq(obj.cost), sigmaDslBuilder.CostModel.SelectField)
+ val l = RCCostedPrim(info._1, 0, SizeInt)
+ val r = mkCostedColl(info._2, CryptoConstants.hashLength, 0)
+ RCCostedPair(l, r, cost)
+ }
+
+ def tokens() = {
+ val tokens = obj.value.tokens
+ val sTokens = asSizeColl(asSizeBox(obj.size).tokens).sizes
+ val sTokenId = SizeHashBytes
+ val sToken = mkSizePair(sTokenId, SizeLong)
+ val len = sTokens.length
+ val sInfo = mkSizeColl(len, sToken)
+ val costs = colBuilder.replicate(len, 0)
+ val sizes = colBuilder.replicate(len, sToken)
+ RCCostedColl(tokens, costs, sizes, opCost(Seq(obj.cost), costOf(method)))
+ }
+
+// def id: CostedColl[Byte] = dsl.costColWithConstSizedItem(box.id, box.id.length, 1)
+// def valueCosted: Costed[Long] = {
+// val cost = dsl.CostModel.SelectField
+// new CCostedPrim(box.value, cost, 8L)
+// }
+// def bytes: CostedColl[Byte] = dsl.costColWithConstSizedItem(box.bytes, box.bytes.length, 1)
+// def bytesWithoutRef: CostedColl[Byte] = dsl.costColWithConstSizedItem(box.bytesWithoutRef, box.bytesWithoutRef.length, 1)
+// def propositionBytes: CostedColl[Byte] = dsl.costColWithConstSizedItem(box.propositionBytes, box.propositionBytes.length, 1)
+// def registers: CostedColl[AnyValue] = {
+// val len = box.registers.length
+// val costs = dsl.Colls.replicate(len, dsl.CostModel.AccessBox)
+// val sizes = box.registers.map(o => o.dataSize)
+// new CCostedColl(box.registers, costs, sizes, dsl.CostModel.CollectionConst)
+// }
+// def getReg[@Reified T](id: Int)(implicit cT:RType[T]): CostedOption[T] = {
+// val opt = box.getReg(id)(cT)
+// dsl.costOption(opt, dsl.CostModel.GetRegister)
+// }
+//
+// @NeverInline
+// def creationInfo: Costed[(Int, Coll[Byte])] = SpecialPredef.rewritableMethod
+ }
+
+ object BoxCoster extends CostingHandler[Box]((obj, m, args) => new BoxCoster(obj, m, args))
+
+ class HeaderCoster(obj: RCosted[Header], method: SMethod, args: Seq[RCosted[_]]) extends Coster[Header](obj, method, args){
+ import Header._
+
+ def version() = constantSizeProperyAccess(_.version)
+
+ def parentId() = digest32ProperyAccess(_.parentId)
+
+ def ADProofsRoot() = digest32ProperyAccess(_.ADProofsRoot)
+
+ def stateRoot() = knownSizeProperyAccess(_.stateRoot, SizeAvlTree)
+
+ def transactionsRoot() = digest32ProperyAccess(_.transactionsRoot)
+
+ def timestamp() = constantSizeProperyAccess(_.timestamp)
+
+ def nBits() = constantSizeProperyAccess(_.nBits)
+
+ def height() = constantSizeProperyAccess(_.height)
+
+ def extensionRoot() = digest32ProperyAccess(_.extensionRoot)
+
+ def minerPk() = groupElementProperyAccess(_.minerPk)
+
+ def powOnetimePk() = groupElementProperyAccess(_.powOnetimePk)
+
+ def powNonce() = knownLengthCollProperyAccess(_.powNonce, 8)
+
+ def powDistance() = bigIntProperyAccess(_.powDistance)
+
+ def votes() = knownLengthCollProperyAccess(_.votes, 3)
+ }
+
+ object HeaderCoster extends CostingHandler[Header]((obj, m, args) => new HeaderCoster(obj, m, args))
+
+ class PreHeaderCoster(obj: RCosted[PreHeader], method: SMethod, args: Seq[RCosted[_]]) extends Coster[PreHeader](obj, method, args){
+ import PreHeader._
+
+// def id() = digest32ProperyAccess(_.id)
+
+ def version() = constantSizeProperyAccess(_.version)
+
+ def parentId() = digest32ProperyAccess(_.parentId)
+
+ def timestamp() = constantSizeProperyAccess(_.timestamp)
+
+ def nBits() = constantSizeProperyAccess(_.nBits)
+
+ def height() = constantSizeProperyAccess(_.height)
+
+ def minerPk() = groupElementProperyAccess(_.minerPk)
+
+ def votes() = knownLengthCollProperyAccess(_.votes, 3)
+ }
+
+ object PreHeaderCoster extends CostingHandler[PreHeader]((obj, m, args) => new PreHeaderCoster(obj, m, args))
+
+ class OptionCoster[T](obj: RCosted[WOption[T]], method: SMethod, args: Seq[RCosted[_]]) extends Coster[WOption[T]](obj, method, args){
+ import WOption._
+ implicit val eT = obj.elem.eVal.eItem
+ def get(): RCosted[T] = defaultProperyAccess(_.get, asSizeOption(_).sizeOpt.get)
+
+ def getOrElse(default: RCosted[T]): RCosted[T] = {
+ val v = obj.value.getOrElse(default.value)
+ val c = opCost(costOfArgs, selectFieldCost)
+ val s = asSizeOption(obj.size).sizeOpt.getOrElse(default.size)
+ RCCostedPrim(v, c, s)
+ }
+
+ def isDefined: RCosted[Boolean] = constantSizeProperyAccess(_.isDefined)
+ def isEmpty: RCosted[Boolean] = constantSizeProperyAccess(_.isEmpty)
+ }
+
+ object OptionCoster extends CostingHandler[WOption[Any]]((obj, m, args) => new OptionCoster[Any](obj, m, args))
+
+
+ class CollCoster[T](obj: RCosted[Coll[T]], method: SMethod, args: Seq[RCosted[_]]) extends Coster[Coll[T]](obj, method, args) {
+ import Coll._
+ implicit val eT = obj.elem.eVal.eItem
+
+ def indices(): RCostedColl[Int] =
+ knownLengthCollProperyAccess(_.indices, asSizeColl(obj.size).sizes.length)
+
+ def getSizePropertyMethod[B](mc: MethodCall): RSize[T] => RColl[Size[B]] = {
+ ???
+ }
+
+ def flatMap[B](fC: RCosted[T => Coll[B]]): RCostedColl[B] = {
+ val f = fC.value
+ f match {
+ // Pattern: xs.flatMap(x => x.property)
+ case Def(Lambda(l,_,_,Def(mc @ MethodCall(x, m, Nil, _)))) if x == l.x =>
+ val sObj = asSizeColl(obj.size)
+ val sizes: RColl[Size[B]] = sObj.sizes.flatMap(fun { s: RSize[T] =>
+ val sizeProp = getSizePropertyMethod[B](mc)
+ sizeProp(s)
+ })
+ val values = obj.value.flatMap(f)
+ val costs = colBuilder.replicate(sizes.length, 0)
+ RCCostedColl(values, costs, sizes, opCost(costOfArgs, costOf(method)))
+ case _ =>
+ !!!(s"Unsupported lambda in flatMap: allowed usage `xs.flatMap(x => x.property)`")
+ }
+ }
+
+ def indexOf(elem: RCosted[T], from: RCosted[Int]): RCosted[Int] = {
+ val c = opCost(costOfArgs, perKbCostOf(method, obj.size.dataSize))
+ RCCostedPrim(obj.value.indexOf(elem.value, from.value), c, SizeInt)
+ }
+
+ def segmentLength(p: RCosted[T => Boolean], from: RCosted[Int]): RCosted[Int] = {
+// val pCost: Rep[((Int, Size[A])) => Int] = asCostedFunc(p).func.sliceCost
+ // TODO costing rule should be more accurate
+ val c = opCost(costOfArgs, costOf(method))
+ RCCostedPrim(obj.value.segmentLength(p.value, from.value), c, SizeInt)
+ }
+
+ def indexWhere(p: RCosted[T => Boolean], from: RCosted[Int]): RCosted[Int] = {
+ // TODO costing rule should be more accurate
+ val c = opCost(costOfArgs, costOf(method))
+ RCCostedPrim(obj.value.indexWhere(p.value, from.value), c, SizeInt)
+ }
+
+ def lastIndexWhere(p: RCosted[T => Boolean], end: RCosted[Int]): RCosted[Int] = {
+ // TODO costing rule should be more accurate
+ val c = opCost(costOfArgs, costOf(method))
+ RCCostedPrim(obj.value.lastIndexWhere(p.value, end.value), c, SizeInt)
+ }
+
+ def zip[B](ys: RCosted[Coll[B]]): RCosted[Coll[(T, B)]] = {
+ implicit val eB = ys.elem.eVal.eItem
+ val values = obj.value.zip(ys.value)
+ val xsC = asCostedColl(obj)
+ val ysC = asCostedColl(ys)
+ // TODO optimize: it make sence to add more high level operations to avoid building large graphs
+ val costs = xsC.costs.zip(ysC.costs).map(fun { in: Rep[(Int,Int)] => in._1 + in._2 })
+ val sizes = xsC.sizes.zip(ysC.sizes).map(fun { in: Rep[(Size[T],Size[B])] => RCSizePair(in._1, in._2): RSize[(T,B)] })
+ val c = opCost(costOfArgs, costOf(method))
+ RCCostedColl(values, costs, sizes, c)
+ }
+
+ def partition(pred: RCosted[T => Boolean]): RCosted[(Coll[T], Coll[T])] = {
+ // TODO costing rule should be more accurate
+ val xsC = asCostedColl(obj)
+ val Pair(lvalues, rvalues) = xsC.value.partition(pred.value)
+ val costs = xsC.costs
+ val sizes = xsC.sizes
+ val c = opCost(costOfArgs, costOf(method))
+ RCCostedPair(
+ RCCostedColl(lvalues, costs, sizes, CostTable.newCollValueCost),
+ RCCostedColl(rvalues, costs, sizes, CostTable.newCollValueCost), c)
+ }
+
+ def patch(from: RCosted[Int], patch: RCosted[Coll[T]], replaced: RCosted[Int]): RCosted[Coll[T]] = {
+ val xsC = asCostedColl(obj)
+ val patchC = asCostedColl(patch)
+ val values = xsC.value.patch(from.value, patch.value, replaced.value)
+ val sizes = xsC.sizes.append(patchC.sizes)
+ val costs = xsC.costs.append(patchC.costs)
+ val c = opCost(costOfArgs, costOf(method)) // TODO costing rule should be more accurate
+ RCCostedColl(values, costs, sizes, c)
+ }
+
+ def updated(index: RCosted[Int], elem: RCosted[T]): RCosted[Coll[T]] = {
+ val xsC = asCostedColl(obj)
+ val c = opCost(costOfArgs, costOf(method))
+ RCCostedColl(xsC.value.updated(index.value, elem.value), xsC.costs, xsC.sizes, c)
+ }
+
+ def updateMany(indexes: RCosted[Coll[Int]], values: RCosted[Coll[T]]): RCosted[Coll[T]] = {
+ val xsC = asCostedColl(obj)
+ val c = opCost(costOfArgs, perKbCostOf(method, values.size.dataSize)) // TODO costing rule should be more accurate with sizes
+ RCCostedColl(xsC.value.updateMany(indexes.value, values.value), xsC.costs, xsC.sizes, c)
+ }
+ }
+
+ object CollCoster extends CostingHandler[Coll[Any]]((obj, m, args) => new CollCoster[Any](obj, m, args))
+}
diff --git a/src/main/scala/sigmastate/eval/DataCosting.scala b/src/main/scala/sigmastate/eval/DataCosting.scala
index dab9d6a14c..008abb79bb 100644
--- a/src/main/scala/sigmastate/eval/DataCosting.scala
+++ b/src/main/scala/sigmastate/eval/DataCosting.scala
@@ -6,78 +6,73 @@ import scalan.Lazy
import sigmastate.utxo.CostTable.Cost.BoxConstantDeclaration
trait DataCosting extends SigmaLibrary { self: RuntimeCosting =>
- import WArray._; import Col._
+ import WArray._; import Coll._
import WOption._
import Box._
- import ColBuilder._;
- import ReplCol._;
+ import CollBuilder._;
+ import ReplColl._;
import Costed._;
import CostedPrim._;
import CCostedPrim._;
- import CostedBox._;
- import CCostedBox._;
import CostedPair._;
import CCostedPair._;
import CostedOption._;
- import CostedCol._;
- import CCostedCol._;
+ import CostedColl._;
+ import CCostedColl._;
import CCostedOption._;
- import CostedNestedCol._; import CostedPairCol._
import CostedBuilder._
import WSpecialPredef._
- def dataCost[T](x: Rep[T], optCost: Option[Rep[Int]]): Rep[Costed[T]] = {
- val res: Rep[Any] = x.elem match {
- case box: BoxElem[_] =>
- RCCostedBox(asRep[Box](x), optCost.getOrElse(0))
- case pe: PairElem[a,b] =>
- val l = dataCost(asRep[(a,b)](x)._1, None)
- val r = dataCost(asRep[(a,b)](x)._2, optCost)
- RCCostedPair(l, r)
- case optE: WOptionElem[a,_] =>
- val optX = asRep[WOption[a]](x)
- implicit val e = optE.eItem
- val tpe = elemToSType(e)
- val costOpt = optX.map(fun(x => 0))
- val sizeOpt =
- if (tpe.isConstantSize) optX.map(fun(x => typeSize(tpe)))
- else optX.map(fun(sizeOf(_)))
- val cost = costOf(OptionConstant(null, tpe))
- RCCostedOption(optX, costOpt, sizeOpt, optCost.fold(cost)(c => c + cost))
- case ce: ColElem[_,_] =>
- ce.eA match {
- case e: Elem[a] =>
- implicit val eA = e
- val xs = asRep[Col[a]](x)
- val costs = colBuilder.replicate(xs.length, 0)
- val tpe = elemToSType(e)
- val sizes = if (tpe.isConstantSize)
- colBuilder.replicate(xs.length, typeSize(tpe))
- else
- xs.map(fun(sizeOf(_)))
- val colCost = costOf(CollectionConstant(null, tpe))
- RCCostedCol(xs, costs, sizes, optCost.fold(colCost)(c => c + colCost))
-// case pe: PairElem[a,b] =>
-// val arr = asRep[Coll[(a,b)]](x)
-// implicit val ea = pe.eFst
-// implicit val eb = pe.eSnd
-// val ls = dataCost[Coll[a]](arr.map(fun[(a,b), a](_._1)(Lazy(pe))))
-// val rs = dataCost[Coll[b]](arr.map(fun[(a,b), b](_._2)(Lazy(pe))))
-// CostedPairColRep(ls, rs)
-// case ce: ColElem[a,_] =>
-// implicit val ea = ce.eA
-// val col = asRep[Coll[Coll[a]]](x)
-// val rows = col.map(fun((r: Rep[Coll[a]]) => dataCost(r)))
-// CostedNestedColRep(rows)
-// case entE: EntityElem[a] => // fallback case
-// val col = asRep[Coll[a]](x)
-// val costs = col.map(fun((r: Rep[a]) => dataCost(r).cost)(Lazy(entE)))
-// CostedColRep(col, costs)
- }
- case _ =>
- RCCostedPrim(x, optCost.getOrElse(0), sizeOf(x))
- }
- asRep[Costed[T]](res)
- }
+// def dataCost[T](x: Rep[T], optCost: Option[Rep[Int]]): Rep[Costed[T]] = {
+// val res: Rep[Any] = x.elem match {
+// case pe: PairElem[a,b] =>
+// val l = dataCost(asRep[(a,b)](x)._1, None)
+// val r = dataCost(asRep[(a,b)](x)._2, optCost)
+// RCCostedPair(l, r)
+// case optE: WOptionElem[a,_] =>
+// val optX = asRep[WOption[a]](x)
+// implicit val e = optE.eItem
+// val tpe = elemToSType(e)
+// val costOpt = optX.map(fun(x => 0))
+// val sizeOpt =
+// if (tpe.isConstantSize) optX.map(fun(x => typeSize(tpe)))
+// else optX.map(fun(sizeOf(_)))
+// val cost = costOf(OptionConstant(null, tpe))
+// RCCostedOption(optX, costOpt, sizeOpt, optCost.fold(cost)(c => c + cost))
+// case ce: CollElem[_,_] =>
+// ce.eA match {
+// case e: Elem[a] =>
+// implicit val eA = e
+// val xs = asRep[Coll[a]](x)
+// val costs = colBuilder.replicate(xs.length, 0)
+// val tpe = elemToSType(e)
+// val sizes = if (tpe.isConstantSize)
+// colBuilder.replicate(xs.length, typeSize(tpe))
+// else
+// xs.map(fun(sizeOf(_)))
+// val colCost = costOf(CollectionConstant(null, tpe))
+// RCCostedColl(xs, costs, sizes, optCost.fold(colCost)(c => c + colCost))
+//// case pe: PairElem[a,b] =>
+//// val arr = asRep[Coll[(a,b)]](x)
+//// implicit val ea = pe.eFst
+//// implicit val eb = pe.eSnd
+//// val ls = dataCost[Coll[a]](arr.map(fun[(a,b), a](_._1)(Lazy(pe))))
+//// val rs = dataCost[Coll[b]](arr.map(fun[(a,b), b](_._2)(Lazy(pe))))
+//// CostedPairCollRep(ls, rs)
+//// case ce: CollElem[a,_] =>
+//// implicit val ea = ce.eA
+//// val col = asRep[Coll[Coll[a]]](x)
+//// val rows = col.map(fun((r: Rep[Coll[a]]) => dataCost(r)))
+//// CostedNestedCollRep(rows)
+//// case entE: EntityElem[a] => // fallback case
+//// val col = asRep[Coll[a]](x)
+//// val costs = col.map(fun((r: Rep[a]) => dataCost(r).cost)(Lazy(entE)))
+//// CostedCollRep(col, costs)
+// }
+// case _ =>
+// RCCostedPrim(x, optCost.getOrElse(0), sizeOf(x))
+// }
+// asRep[Costed[T]](res)
+// }
}
diff --git a/src/main/scala/sigmastate/eval/Evaluation.scala b/src/main/scala/sigmastate/eval/Evaluation.scala
index 7efadb1e7c..c49c242914 100644
--- a/src/main/scala/sigmastate/eval/Evaluation.scala
+++ b/src/main/scala/sigmastate/eval/Evaluation.scala
@@ -1,68 +1,94 @@
package sigmastate.eval
-import java.lang.reflect.Method
import java.math.BigInteger
+import org.bouncycastle.math.ec.ECPoint
import org.ergoplatform._
import sigmastate._
-import sigmastate.Values.{BlockValue, BoolValue, BooleanConstant, CollectionConstant, ConcreteCollection, Constant, EvaluatedValue, FuncValue, GroupElementConstant, SValue, SigmaBoolean, SigmaPropConstant, ValDef, ValUse, Value}
-import sigmastate.lang.Terms.{OperationId, ValueOps}
-import sigmastate.serialization.OpCodes._
-import sigmastate.serialization.ValueSerializer
-import sigmastate.utxo.{CostTable, CostTableStat, ExtractAmount, SizeOf}
-
-import scala.collection.mutable
-import scala.collection.mutable.ArrayBuffer
-import scala.reflect.{ClassTag, classTag}
+import sigmastate.Values.{Value, GroupElementConstant, SigmaBoolean, Constant}
+import sigmastate.lang.Terms.OperationId
+import sigmastate.utxo.CostTableStat
+
+import scala.reflect.ClassTag
import scala.util.Try
-import SType._
-import org.bouncycastle.math.ec.ECPoint
+import sigmastate.SType._
import sigmastate.interpreter.CryptoConstants.EcPointType
-import sigmastate.interpreter.CryptoFunctions
import special.sigma.InvalidType
-import scalan.Nullable
+import scalan.{Nullable, RType}
+import scalan.RType._
+import sigma.types.PrimViewType
import sigmastate.basics.DLogProtocol.ProveDlog
-import sigmastate.basics.{DLogProtocol, ProveDHTuple}
+import sigmastate.basics.{ProveDHTuple, DLogProtocol}
+import special.sigma.Extensions._
+import scorex.util.Extensions._
+import sigmastate.lang.exceptions.CosterException
+import special.SpecialPredef
+import special.collection.Coll
trait Evaluation extends RuntimeCosting { IR =>
import Context._
import SigmaProp._
- import Col._
- import ReplCol._
- import CReplCol._
+ import Coll._
+ import CReplColl._
+ import PairOfCols._
+ import AnyValue._
import Box._
import AvlTree._
- import ColBuilder._
+ import CollBuilder._
import SigmaDslBuilder._
import CostedBuilder._
- import CCostedBuilder._
- import Monoid._
import MonoidBuilder._
- import MonoidBuilderInst._
- import TrivialSigma._
- import ProveDlogEvidence._
- import ProveDHTEvidence._
import WBigInteger._
import WArray._
import WOption._
- import WECPoint._
+ import WRType._
+ import GroupElement._
import Liftables._
+ import WSpecialPredef._
+ import Size._
+ import CSizePrim._
+ import SizePair._
+ import CSizePair._
+ import SizeColl._
+ import CSizeColl._
+ import SizeOption._
+ import CSizeOption._
+ import SizeFunc._
+ import CSizeFunc._
+ import SizeAnyValue._
+ import CSizeAnyValue._
+ import SizeSigmaProp._
+ import SizeBox._
+ import CSizeBox._
+ import SizeContext._
+ import CSizeContext._
val okPrintEvaluatedEntries: Boolean = false
+ private val SCM = SizeContextMethods
+ private val SBM = SizeBoxMethods
+ private val SSPM = SizeSigmaPropMethods
+ private val SAVM = SizeAnyValueMethods
+ private val SizeM = SizeMethods
+ private val SPairM = SizePairMethods
+ private val SCollM = SizeCollMethods
+ private val SOptM = SizeOptionMethods
+ private val SFuncM = SizeFuncMethods
private val ContextM = ContextMethods
private val SigmaM = SigmaPropMethods
- private val ColM = ColMethods
+ private val CollM = CollMethods
private val BoxM = BoxMethods
private val AvlM = AvlTreeMethods
- private val CBM = ColBuilderMethods
+ private val CBM = CollBuilderMethods
private val SDBM = SigmaDslBuilderMethods
private val AM = WArrayMethods
private val OM = WOptionMethods
private val BIM = WBigIntegerMethods
+ private val SPCM = WSpecialPredefCompanionMethods
def isValidCostPrimitive(d: Def[_]): Unit = d match {
case _: Const[_] =>
+ case _: OpCost | _: Cast[_] =>
case _: Tup[_,_] | _: First[_,_] | _: Second[_,_] =>
case _: FieldApply[_] =>
case _: IntPlusMonoid =>
@@ -70,22 +96,43 @@ trait Evaluation extends RuntimeCosting { IR =>
case _: ThunkDef[_] =>
case ApplyUnOp(_: NumericToLong[_] | _: NumericToInt[_], _) =>
case ApplyBinOp(_: NumericPlus[_] | _: NumericTimes[_] | _: OrderingMax[_] | _: IntegralDivide[_] ,_,_) =>
- case ContextM.SELF(_) | ContextM.OUTPUTS(_) | ContextM.INPUTS(_) | ContextM.LastBlockUtxoRootHash(_) |
- ContextM.getVar(_,_,_) |
- ContextM.cost(_) | ContextM.dataSize(_) =>
+
+ case SCM.inputs(_) | SCM.outputs(_) | SCM.dataInputs(_) | SCM.selfBox(_) | SCM.lastBlockUtxoRootHash(_) | SCM.headers(_) |
+ SCM.preHeader(_) | SCM.getVar(_,_,_) =>
+ case SBM.propositionBytes(_) | SBM.bytes(_) | SBM.bytesWithoutRef(_) | SBM.registers(_) | SBM.getReg(_,_,_) |
+ SBM.tokens(_) =>
+ case SSPM.propBytes(_) =>
+ case SAVM.tVal(_) | SAVM.valueSize(_) =>
+ case SizeM.dataSize(_) =>
+ case SPairM.l(_) | SPairM.r(_) =>
+ case SCollM.sizes(_) =>
+ case SOptM.sizeOpt(_) =>
+ case SFuncM.sizeEnv(_) =>
+ case _: CSizePairCtor[_,_] | _: CSizeFuncCtor[_,_,_] | _: CSizeOptionCtor[_] | _: CSizeCollCtor[_] |
+ _: CSizeBoxCtor | _: CSizeContextCtor | _: CSizeAnyValueCtor =>
+ case ContextM.SELF(_) | ContextM.OUTPUTS(_) | ContextM.INPUTS(_) | ContextM.dataInputs(_) | ContextM.LastBlockUtxoRootHash(_) |
+ ContextM.getVar(_,_,_) /*| ContextM.cost(_) | ContextM.dataSize(_)*/ =>
case SigmaM.propBytes(_) =>
- case ColM.length(_) | ColM.map(_,_) | ColM.sum(_,_) | ColM.zip(_,_) | ColM.slice(_,_,_) | ColM.apply(_,_) | ColM.append(_,_) =>
+ case _: CReplCollCtor[_] | _: PairOfColsCtor[_,_] =>
+ case CollM.length(_) | CollM.map(_,_) | CollM.sum(_,_) | CollM.zip(_,_) | CollM.slice(_,_,_) | CollM.apply(_,_) |
+ CollM.append(_,_) | CollM.foldLeft(_,_,_) =>
case CBM.replicate(_,_,_) | CBM.fromItems(_,_,_) =>
- case BoxM.propositionBytes(_) | BoxM.bytesWithoutRef(_) | BoxM.cost(_) | BoxM.dataSize(_) | BoxM.getReg(_,_,_) =>
- case AvlM.dataSize(_) =>
+ case BoxM.propositionBytes(_) | BoxM.bytesWithoutRef(_) /*| BoxM.cost(_) | BoxM.dataSize(_)*/ | BoxM.getReg(_,_,_) =>
+// case AvlM.dataSize(_) =>
case OM.get(_) | OM.getOrElse(_,_) | OM.fold(_,_,_) | OM.isDefined(_) =>
case _: CostOf | _: SizeOf[_] =>
case _: Upcast[_,_] =>
case _: Apply[_,_] =>
+ case SPCM.some(_) =>
case _ => !!!(s"Invalid primitive in Cost function: $d")
}
- def verifyCostFunc(costF: Rep[Context => Int]): Try[Unit] = {
+ def verifyCalcFunc[A](f: Rep[Context => A], eA: Elem[A]) = {
+ if (f.elem.eRange != eA)
+ !!!(s"Expected function of type ${f.elem.eDom.name} => ${eA.name}, but was $f: ${f.elem.name}")
+ }
+
+ def verifyCostFunc(costF: Rep[Any => Int]): Try[Unit] = {
val Def(Lambda(lam,_,_,_)) = costF
Try { lam.scheduleAll.foreach(te => isValidCostPrimitive(te.rhs)) }
}
@@ -116,19 +163,19 @@ trait Evaluation extends RuntimeCosting { IR =>
}
}
import sigmastate._
- import Values.{TrueLeaf, FalseLeaf}
import special.sigma.{Context => SigmaContext}
type ContextFunc[T <: SType] = SigmaContext => Value[T]
- val sigmaDslBuilderValue: special.sigma.SigmaDslBuilder
- val costedBuilderValue: special.collection.CCostedBuilder
+ val sigmaDslBuilderValue: CostingSigmaDslBuilder
+ val costedBuilderValue: special.collection.CostedBuilder
val monoidBuilderValue: special.collection.MonoidBuilder
def getDataEnv: DataEnv = {
val env = Map[Sym, AnyRef](
+ RWSpecialPredef -> SpecialPredef,
sigmaDslBuilder -> sigmaDslBuilderValue,
- sigmaDslBuilder.Cols -> sigmaDslBuilderValue.Cols,
+ sigmaDslBuilder.Colls -> sigmaDslBuilderValue.Colls,
costedBuilder -> costedBuilderValue,
costedBuilder.monoidBuilder -> monoidBuilderValue,
costedBuilder.monoidBuilder.intPlusMonoid -> monoidBuilderValue.intPlusMonoid,
@@ -143,12 +190,12 @@ trait Evaluation extends RuntimeCosting { IR =>
def trim[A](arr: Array[A]) = arr.take(arr.length min 100)
def show(x: Any) = x match {
case arr: Array[_] => s"Array(${trim(arr).mkString(",")})"
- case col: special.collection.Col[_] => s"Coll(${trim(col.arr).mkString(",")})"
- case p: ECPoint => CryptoFunctions.showECPoint(p)
- case ProveDlog(GroupElementConstant(g)) => s"ProveDlog(${CryptoFunctions.showECPoint(g)})"
+ case col: special.collection.Coll[_] => s"Coll(${trim(col.toArray).mkString(",")})"
+ case p: SGroupElement => p.showToString
+ case ProveDlog(GroupElementConstant(g)) => s"ProveDlog(${showECPoint(g)})"
case ProveDHTuple(
GroupElementConstant(g), GroupElementConstant(h), GroupElementConstant(u), GroupElementConstant(v)) =>
- s"ProveDHT(${CryptoFunctions.showECPoint(g)},${CryptoFunctions.showECPoint(h)},${CryptoFunctions.showECPoint(u)},${CryptoFunctions.showECPoint(v)})"
+ s"ProveDHT(${showECPoint(g)},${showECPoint(h)},${showECPoint(u)},${showECPoint(v)})"
case _ => x.toString
}
sym match {
@@ -163,10 +210,99 @@ trait Evaluation extends RuntimeCosting { IR =>
println(printEnvEntry(sym, value))
}
- def compile[T <: SType](dataEnv: Map[Sym, AnyRef], f: Rep[Context => T#WrappedType]): ContextFunc[T] = {
+ def getFromEnv(dataEnv: DataEnv, s: Sym): Any = dataEnv.get(s) match {
+ case Some(v) => v
+ case _ => error(s"Cannot find value in environment for $s (dataEnv = $dataEnv)")
+ }
+
+ def msgCostLimitError(cost: Int, limit: Long) = s"Estimated expression complexity $cost exceeds the limit $limit"
+
+ /** Incapsulate simple monotonic (add only) counter with reset. */
+ class CostCounter(initialCost: Int) {
+ private var _currentCost: Int = initialCost
+
+ @inline def += (n: Int) = {
+ this._currentCost += n
+ }
+ @inline def currentCost: Int = _currentCost
+ @inline def resetCost() = { _currentCost = initialCost }
+ }
+
+ /** Implements finite state machine with stack of graph blocks (lambdas and thunks).
+ * It accepts messages: startScope(), endScope(), add(), reset()
+ * At any time `totalCost` is the currently accumulated cost. */
+ class CostAccumulator(initialCost: Int, costLimit: Option[Long]) {
+
+ @inline private def initialStack() = List(new Scope(Set(), 0))
+ private var _scopeStack: List[Scope] = initialStack
+
+ @inline def currentVisited: Set[Sym] = _scopeStack.head.visited
+ @inline def currentScope: Scope = _scopeStack.head
+ @inline private def getCostFromEnv(dataEnv: DataEnv, s: Sym): Int = getFromEnv(dataEnv, s).asInstanceOf[Int]
+
+ class Scope(visitiedOnEntry: Set[Sym], initialCost: Int) extends CostCounter(initialCost) {
+ private var _visited: Set[Sym] = visitiedOnEntry
+ @inline def visited = _visited
+ @inline def add(op: OpCost, opCost: Int, dataEnv: DataEnv) = {
+ for (arg <- op.args) {
+ if (!_visited.contains(arg)) {
+ val argCost = getCostFromEnv(dataEnv, arg)
+ this += argCost
+ _visited += arg
+ }
+ }
+ this += opCost
+ _visited += op.opCost
+ }
+ }
+
+ /** Called once for each operation of a scope (lambda or thunk).
+ * if isCosting then delegate to the currentScope */
+ def add(op: OpCost, dataEnv: DataEnv) = {
+ val opCost = getFromEnv(dataEnv, op.opCost).asInstanceOf[Int]
+ if (costLimit.isDefined) {
+ currentScope.add(op, opCost, dataEnv)
+ // check that we are still withing the limit
+ val cost = currentScope.currentCost
+ val limit = costLimit.get
+ if (cost > limit)
+ throw new CosterException(msgCostLimitError(cost, limit), None)
+ }
+ opCost
+ }
+
+ /** Called before any operation of a new scope (lambda or thunk)*/
+ def startScope() = {
+ _scopeStack = new Scope(currentVisited, currentScope.currentCost) :: _scopeStack
+ }
+
+ /** Called after all operations of a scope are executed (lambda or thunk)*/
+ def endScope() = {
+ val cost = currentScope.currentCost
+ _scopeStack = _scopeStack.tail
+ _scopeStack.head += cost
+ }
+
+ /** Resets this accumulator into initial state to be ready for new graph execution. */
+ @inline def reset() = {
+ _scopeStack = initialStack()
+ }
+
+ /** Returns total accumulated cost */
+ @inline def totalCost: Int = currentScope.currentCost
+ }
+
- def evaluate(ctxSym: Rep[Context], te: TableEntry[_]): EnvRep[_] = EnvRep { dataEnv =>
- object In { def unapply(s: Sym): Option[Any] = Some(dataEnv(s)) }
+ /** Transform graph IR into the corresponding Scala function
+ * @param f simbol of the graph representing function from type A to B
+ * @param costLimit when Some(value) is specified, then OpCost nodes will be used to accumulate total cost of execution. */
+ def compile[SA, SB, A, B](dataEnv: Map[Sym, AnyRef], f: Rep[A => B], costLimit: Option[Long] = None)
+ (implicit lA: Liftable[SA, A], lB: Liftable[SB, B]): SA => (SB, Int) =
+ {
+ val costAccumulator = new CostAccumulator(0, costLimit)
+
+ def evaluate(te: TableEntry[_]): EnvRep[_] = EnvRep { dataEnv =>
+ object In { def unapply(s: Sym): Option[Any] = Some(getFromEnv(dataEnv, s)) }
def out(v: Any): (DataEnv, Sym) = { val vBoxed = v.asInstanceOf[AnyRef]; (dataEnv + (te.sym -> vBoxed), te.sym) }
try {
var startTime = if (okMeasureOperationTime) System.nanoTime() else 0L
@@ -177,89 +313,77 @@ trait Evaluation extends RuntimeCosting { IR =>
val valueInCtx = invokeUnlifted(ctx.elem, mc, dataEnv)
val data = valueInCtx match {
case Some(Constant(v, `declaredTpe`)) =>
- Some(ErgoLikeContext.toTestData(v, declaredTpe, ctxObj.isCost)(IR))
+ Some(Evaluation.toDslData(v, declaredTpe, ctxObj.isCost)(IR))
+ case opt @ Some(v) => opt
case None => None
case _ => throw new InvalidType(s"Expected Constant($declaredTpe) but found $valueInCtx")
}
out(data)
case d @ BoxM.getReg(box, _, elem) =>
- val ctxObj = dataEnv(ctxSym).asInstanceOf[CostingDataContext]
val mc = d.asInstanceOf[MethodCall]
val declaredTpe = elemToSType(elem)
val valueInReg = invokeUnlifted(box.elem, mc, dataEnv)
val data = valueInReg match {
case Some(Constant(v, `declaredTpe`)) =>
- Some(ErgoLikeContext.toTestData(v, declaredTpe, ctxObj.isCost)(IR))
+ Some(Evaluation.toDslData(v, declaredTpe, false)(IR))
+ case Some(v) =>
+ valueInReg
case None => None
case _ => throw new InvalidType(
s"Expected Some(Constant($declaredTpe)) but found $valueInReg value of register: $d")
}
out(data)
case Const(x) => out(x.asInstanceOf[AnyRef])
-
case Tup(In(a), In(b)) => out((a,b))
case First(In(p: Tuple2[_,_])) => out(p._1)
case Second(In(p: Tuple2[_,_])) => out(p._2)
- case FieldApply(In(data: special.collection.Col[a]), IsTupleFN(i)) =>
- out(data(i-1))
+ case FieldApply(In(data), IsTupleFN(i)) => data match {
+ case coll: special.collection.Coll[a] =>
+ out(coll(i - 1))
+ case tup: Product =>
+ out(tup.productElement(i - 1))
+ }
+
case wc: LiftedConst[_,_] => out(wc.constValue)
- case _: DslBuilder | _: ColBuilder | _: CostedBuilder | _: IntPlusMonoid | _: LongPlusMonoid =>
+
+ case _: SigmaDslBuilder | _: CollBuilder | _: CostedBuilder | _: IntPlusMonoid | _: LongPlusMonoid |
+ _: WSpecialPredefCompanion =>
out(dataEnv.getOrElse(te.sym, !!!(s"Cannot resolve companion instance for $te")))
- case SigmaM.propBytes(prop) =>
- val sigmaBool = dataEnv(prop).asInstanceOf[SigmaBoolean]
- out(sigmaDslBuilderValue.Cols.fromArray(sigmaBool.bytes))
+
case SigmaM.isValid(In(prop: AnyRef)) =>
out(prop)
- case SigmaM.and_sigma_&&(In(l: SigmaBoolean), In(r: SigmaBoolean)) =>
- out(CAND.normalized(Seq(l, r)))
-
- case SigmaM.or_sigma_||(In(l: SigmaBoolean), In(r: SigmaBoolean)) =>
- out(COR.normalized(Seq(l, r)))
-
- case SigmaM.and_bool_&&(In(l: SigmaBoolean), In(b: Boolean)) =>
- if (b) {
- out(l)
- } else
- out(TrivialProp.FalseProp)
-
- case SigmaM.or_bool_||(In(l: SigmaBoolean), In(b: Boolean)) =>
- if (b)
- out(TrivialProp.TrueProp)
- else {
- out(l)
- }
-// case SigmaM.lazyAnd(In(l: SigmaBoolean), In(y)) =>
-// val th = y.asInstanceOf[() => SigmaBoolean]
-// out(AND(l, th()).function(null, null))
-// case SigmaM.lazyOr(In(l: SigmaBoolean), In(y)) =>
-// val th = y.asInstanceOf[() => SigmaBoolean]
-// out(OR(l, th()).function(null, null))
-
- case SDBM.anyZK(_, In(items: special.collection.Col[SigmaBoolean]@unchecked)) =>
- out(COR.normalized(items.arr.toSeq))
- case SDBM.allZK(_, In(items: special.collection.Col[SigmaBoolean]@unchecked)) =>
- out(CAND.normalized(items.arr.toSeq))
- case SDBM.atLeast(dsl, In(bound: Int), In(children: special.collection.Col[SigmaBoolean]@unchecked)) =>
- out(AtLeast.reduce(bound, children.arr.toSeq))
- case SDBM.sigmaProp(_, In(b: Boolean)) =>
- val res = sigmastate.TrivialProp(b)
- out(res)
case SDBM.substConstants(_,
- In(input: special.collection.Col[Byte]@unchecked),
- In(positions: special.collection.Col[Int]@unchecked),
- In(newVals: special.collection.Col[Any]@unchecked), _) =>
- val typedNewVals = newVals.arr.map(_.asInstanceOf[Value[SType]])
- val byteArray = SubstConstants.eval(input.arr, positions.arr, typedNewVals)
- out(sigmaDslBuilderValue.Cols.fromArray(byteArray))
+ In(input: special.collection.Coll[Byte]@unchecked),
+ In(positions: special.collection.Coll[Int]@unchecked),
+ In(newVals: special.collection.Coll[Any]@unchecked), _) =>
+ val typedNewVals = newVals.toArray.map(v => builder.liftAny(v) match {
+ case Nullable(v) => v
+ case _ => sys.error(s"Cannot evaluate substConstants($input, $positions, $newVals): cannot lift value $v")
+ })
+ val byteArray = SubstConstants.eval(input.toArray, positions.toArray, typedNewVals)
+ out(sigmaDslBuilderValue.Colls.fromArray(byteArray))
case AM.length(In(arr: Array[_])) => out(arr.length)
- case CBM.replicate(In(b: special.collection.ColBuilder), In(n: Int), xSym @ In(x)) =>
- out(b.replicate(n, x)(xSym.elem.classTag))
+ case CBM.replicate(In(b: special.collection.CollBuilder), In(n: Int), xSym @ In(x)) =>
+ out(b.replicate(n, x)(asType[Any](xSym.elem.sourceType)))
+
+ case SPCM.some(In(v)) => out(Some(v))
+ case SPCM.none(_) => out(None)
// NOTE: This is a fallback rule which should be places AFTER all other MethodCall patterns
case mc @ MethodCall(obj, m, args, _) =>
- val dataRes = invokeUnlifted(obj.elem, mc, dataEnv)
+ val dataRes = obj.elem match {
+ case _: CollElem[_, _] => mc match {
+ case CollMethods.flatMap(xs, f) =>
+ val newMC = mc.copy(args = mc.args :+ f.elem.eRange)(mc.selfType, mc.isAdapterCall)
+ invokeUnlifted(obj.elem, newMC, dataEnv)
+ case _ =>
+ invokeUnlifted(obj.elem, mc, dataEnv)
+ }
+ case _ =>
+ invokeUnlifted(obj.elem, mc, dataEnv)
+ }
val res = dataRes match {
case Constant(v, _) => v
case v => v
@@ -292,11 +416,14 @@ trait Evaluation extends RuntimeCosting { IR =>
case Lambda(l, _, x, y) =>
val f = (ctx: AnyRef) => {
+ costAccumulator.startScope()
val resEnv = l.schedule.foldLeft(dataEnv + (x -> ctx)) { (env, te) =>
- val (e, _) = evaluate(ctxSym, te).run(env)
+ val (e, _) = evaluate(te).run(env)
e
}
- resEnv(y)
+ val res = resEnv(y)
+ costAccumulator.endScope()
+ res
}
out(f)
case Apply(In(_f), In(x: AnyRef), _) =>
@@ -306,51 +433,105 @@ trait Evaluation extends RuntimeCosting { IR =>
case Second(In(p: Tuple2[_,_])) => out(p._2)
case ThunkDef(y, schedule) =>
val th = () => {
+ costAccumulator.startScope()
val resEnv = schedule.foldLeft(dataEnv) { (env, te) =>
- val (e, _) = evaluate(ctxSym, te).run(env)
+ val (e, _) = evaluate(te).run(env)
e
}
- resEnv(y)
+ val res = resEnv(y)
+ costAccumulator.endScope()
+ res
}
out(th)
- case TrivialSigmaCtor(In(isValid: Boolean)) =>
- val res = sigmastate.TrivialProp(isValid)
+ case SDBM.sigmaProp(_, In(isValid: Boolean)) =>
+ val res = CSigmaProp(sigmastate.TrivialProp(isValid))
+ out(res)
+ case SDBM.proveDlog(_, In(g: EcPointType)) =>
+ val res = CSigmaProp(DLogProtocol.ProveDlog(g))
out(res)
- case ProveDlogEvidenceCtor(In(g: EcPointType)) =>
- val res = DLogProtocol.ProveDlog(GroupElementConstant(g))
+ case SDBM.proveDHTuple(_, In(g: EcPointType), In(h: EcPointType), In(u: EcPointType), In(v: EcPointType)) =>
+ val res = CSigmaProp(ProveDHTuple(g, h, u, v))
out(res)
- case ProveDHTEvidenceCtor(In(g: EcPointType), In(h: EcPointType), In(u: EcPointType), In(v: EcPointType)) =>
- val res = ProveDHTuple(GroupElementConstant(g), GroupElementConstant(h), GroupElementConstant(u), GroupElementConstant(v))
+ case SDBM.avlTree(_, In(flags: Byte),
+ In(digest: SColl[Byte]@unchecked), In(keyLength: Int),
+ In(valueLengthOpt: Option[Int]@unchecked)) =>
+ val res = sigmaDslBuilderValue.avlTree(flags, digest, keyLength, valueLengthOpt)
+ out(res)
+
+ case CReplCollCtor(valueSym @ In(value), In(len: Int)) =>
+ val res = sigmaDslBuilderValue.Colls.replicate(len, value)(asType[Any](valueSym.elem.sourceType))
out(res)
- case CReplColCtor(In(value), In(len: Int)) =>
- val res = sigmaDslBuilderValue.Cols.replicate(len, value)
+ case PairOfColsCtor(In(ls: SColl[a]@unchecked), In(rs: SColl[b]@unchecked)) =>
+ val res = sigmaDslBuilderValue.Colls.pairColl(ls, rs)
out(res)
- case CostOf(opName, tpe) =>
- val operId = OperationId(opName, tpe)
- val cost = CostTable.DefaultCosts(operId)
- out(cost)
+
+ case CSizePrimCtor(In(dataSize: Long), tVal) =>
+ val res = new special.collection.CSizePrim(dataSize, tVal.eA.sourceType)
+ out(res)
+ case CSizePairCtor(In(l: SSize[_]), In(r: SSize[_])) =>
+ val res = new special.collection.CSizePair(l, r)
+ out(res)
+ case CSizeCollCtor(In(sizes: SColl[SSize[_]] @unchecked)) =>
+ val res = new special.collection.CSizeColl(sizes)
+ out(res)
+ case CSizeOptionCtor(In(optSize: Option[SSize[_]] @unchecked)) =>
+ val res = new special.collection.CSizeOption(optSize)
+ out(res)
+ case CSizeAnyValueCtor(tVal, In(valueSize: SSize[Any] @unchecked)) =>
+ val res = new special.sigma.CSizeAnyValue(tVal.eA.sourceType.asInstanceOf[RType[Any]], valueSize)
+ out(res)
+ case CSizeBoxCtor(
+ In(propBytes: SSize[SColl[Byte]]@unchecked), In(bytes: SSize[SColl[Byte]]@unchecked),
+ In(bytesWithoutRef: SSize[SColl[Byte]]@unchecked), In(regs: SSize[SColl[Option[SAnyValue]]]@unchecked),
+ In(tokens: SSize[SColl[(SColl[Byte], Long)]]@unchecked)) =>
+ val res = new EvalSizeBox(propBytes, bytes, bytesWithoutRef, regs, tokens)
+ out(res)
+
+ case costOp: CostOf =>
+ out(costOp.eval)
+ case op: OpCost =>
+ val c = costAccumulator.add(op, dataEnv)
+ out(c)
case SizeOf(sym @ In(data)) =>
val tpe = elemToSType(sym.elem)
val size = tpe match {
- case SAvlTree => data.asInstanceOf[special.sigma.AvlTree].dataSize
- case _ => tpe.dataSize(data.asWrappedType)
+// case SAvlTree =>
+// data.asInstanceOf[special.sigma.AvlTree].dataSize
+ case _ => data match {
+ case w: WrapperOf[_] =>
+ tpe.dataSize(w.wrappedValue.asWrappedType)
+ case _ =>
+ tpe.dataSize(data.asWrappedType)
+ }
}
out(size)
case TypeSize(tpe) =>
+ assert(tpe.isConstantSize)
val size = tpe.dataSize(SType.DummyValue)
out(size)
+ case c @ Cast(eTo, In(v)) =>
+ if (!eTo.sourceType.classTag.runtimeClass.isAssignableFrom(v.getClass)) {
+ error(s"Invalid cast $c: ${eTo.sourceType.classTag.runtimeClass} is not assignable from ${v.getClass}")
+ }
+ out(v)
case Downcast(In(from), eTo) =>
val tpe = elemToSType(eTo).asNumType
- out(tpe.downcast(from.asInstanceOf[AnyVal]))
+ if (tpe == SBigInt)
+ out(sigmaDslBuilderValue.BigInt(SBigInt.downcast(from.asInstanceOf[AnyVal])))
+ else
+ out(tpe.downcast(from.asInstanceOf[AnyVal]))
case Upcast(In(from), eTo) =>
val tpe = elemToSType(eTo).asNumType
- out(tpe.upcast(from.asInstanceOf[AnyVal]))
+ if (tpe == SBigInt)
+ out(sigmaDslBuilderValue.BigInt(SBigInt.upcast(from.asInstanceOf[AnyVal])))
+ else
+ out(tpe.upcast(from.asInstanceOf[AnyVal]))
case SimpleStruct(_, fields) =>
val items = fields.map { case (_, In(fieldValue)) => fieldValue }.toArray
- out(sigmaDslBuilderValue.Cols.fromArray(items))
+ out(sigmaDslBuilderValue.Colls.fromArray(items)(AnyType))
case _ =>
!!!(s"Don't know how to evaluate($te)")
@@ -361,7 +542,7 @@ trait Evaluation extends RuntimeCosting { IR =>
te.sym.getMetadata(OperationIdKey) match {
case Some(opId: OperationId) =>
if (opId.opType.tRange.isCollection) {
- val col = res._1(res._2).asInstanceOf[SCol[Any]]
+ val col = res._1(res._2).asInstanceOf[SColl[Any]]
val colTime = if (col.length > 1) estimatedTime / col.length else estimatedTime
CostTableStat.addOpTime(opId, colTime, col.length)
}
@@ -375,29 +556,221 @@ trait Evaluation extends RuntimeCosting { IR =>
}
catch {
case e: Throwable =>
- !!!(s"Error in evaluate($te)", e)
+ !!!(s"Error in Evaluation.compile.evaluate($te)", e)
}
}
- val res = (ctx: SContext) => {
+ val res = (x: SA) => {
+ costAccumulator.reset() // reset accumulator to initial state
val g = new PGraph(f)
- val ctxSym = f.getLambda.x
- val resEnv = g.schedule.foldLeft(dataEnv + (ctxSym -> ctx)) { (env, te) =>
- val (e, _) = evaluate(ctxSym, te).run(env)
+ val xSym = f.getLambda.x
+ val resEnv = g.schedule.foldLeft(dataEnv + (xSym -> x.asInstanceOf[AnyRef])) { (env, te) =>
+ val (e, _) = evaluate(te).run(env)
e
}
- val fun = resEnv(f).asInstanceOf[SigmaContext => Any]
- fun(ctx) match {
- case sb: SigmaBoolean => builder.liftAny(sb).get
- case v: Value[_] => v
- case col: special.collection.Col[_] =>
- val et = elemToSType(f.elem.eRange).asCollection[SType]
- CollectionConstant(col.arr.asInstanceOf[Array[SType#WrappedType]], et.elemType)
- case x => builder.liftAny(x).get
- }
+ val fun = resEnv(f).asInstanceOf[SA => SB]
+ val y = fun(x)
+ (y, costAccumulator.totalCost)
}
- res.asInstanceOf[ContextFunc[T]]
+ res
}
}
+object Evaluation {
+ import special.sigma._
+ import special.collection._
+ import ErgoLikeContext._
+
+ def stypeToRType[T <: SType](t: T): RType[T#WrappedType] = (t match {
+ case SBoolean => BooleanType
+ case SByte => ByteType
+ case SShort => ShortType
+ case SInt => IntType
+ case SLong => LongType
+ case SString => StringType
+ case SAny => AnyType
+ case SBigInt => BigIntRType
+ case SBox => BoxRType
+ case SContext => ContextRType
+ case SHeader => HeaderRType
+ case SPreHeader => PreHeaderRType
+ case SGroupElement => GroupElementRType
+ case SAvlTree => AvlTreeRType
+ case SSigmaProp => SigmaPropRType
+ case STuple(Seq(tpeA, tpeB)) =>
+ pairRType(stypeToRType(tpeA), stypeToRType(tpeB))
+ case STuple(items) =>
+ val types = items.toArray
+ tupleRType(types.map(t => stypeToRType(t).asInstanceOf[SomeType]))
+ case c: SCollectionType[a] => collRType(stypeToRType(c.elemType))
+ case o: SOption[a] => optionRType(stypeToRType(o.elemType))
+ case SFunc(Seq(tpeArg), tpeRange, Nil) => funcRType(stypeToRType(tpeArg), stypeToRType(tpeRange))
+ case _ => sys.error(s"Don't know how to convert SType $t to RType")
+ }).asInstanceOf[RType[T#WrappedType]]
+
+ def rtypeToSType[T](t: RType[T]): SType = t match {
+ case BooleanType => SBoolean
+ case ByteType => SByte
+ case ShortType => SShort
+ case IntType => SInt
+ case LongType => SLong
+ case StringType => SString
+ case AnyType => SAny
+
+ case BigIntegerRType => SBigInt
+ case BigIntRType => SBigInt
+
+ case ECPointRType => SGroupElement
+ case GroupElementRType => SGroupElement
+
+ case AvlTreeRType => SAvlTree
+ case ot: OptionType[_] => sigmastate.SOption(rtypeToSType(ot.tA))
+ case BoxRType => SBox
+ case ContextRType => SContext
+ case HeaderRType => SHeader
+ case PreHeaderRType => SPreHeader
+ case SigmaPropRType => SSigmaProp
+ case SigmaBooleanRType => SSigmaProp
+ case tup: TupleType => STuple(tup.items.map(t => rtypeToSType(t)).toIndexedSeq)
+ case at: ArrayType[_] => SCollection(rtypeToSType(at.tA))
+ case ct: CollType[_] => SCollection(rtypeToSType(ct.tItem))
+ case ft: FuncType[_,_] => SFunc(rtypeToSType(ft.tDom), rtypeToSType(ft.tRange))
+ case pt: PairType[_,_] => STuple(rtypeToSType(pt.tFst), rtypeToSType(pt.tSnd))
+ case pvt: PrimViewType[_,_] => rtypeToSType(pvt.tVal)
+ case _ => sys.error(s"Don't know how to convert RType $t to SType")
+ }
+
+ /** Tries to reconstruct RType of the given value.
+ * If not successfull returns failure. */
+ def rtypeOf(value: Any): Try[RType[_]] = Try { value match {
+ case arr if arr.getClass.isArray =>
+ val itemClass = arr.getClass.getComponentType
+ if (itemClass.isPrimitive) {
+ val itemTag = ClassTag[Any](itemClass)
+ RType.fromClassTag(itemTag)
+ } else
+ sys.error(s"Cannot compute rtypeOf($value): non-primitive type of array items")
+
+ case coll: Coll[_] => collRType(coll.tItem)
+
+ // all primitive types
+ case v: Boolean => BooleanType
+ case v: Byte => ByteType
+ case v: Short => ShortType
+ case v: Int => IntType
+ case v: Long => LongType
+ case v: Char => CharType
+ case v: Float => FloatType
+ case v: Double => DoubleType
+ case v: String => StringType
+ case v: Unit => UnitType
+
+ case v: BigInteger => BigIntegerRType
+ case n: special.sigma.BigInt => BigIntRType
+
+ case v: ECPoint => ECPointRType
+ case ge: GroupElement => GroupElementRType
+
+ case b: ErgoBox => ErgoBoxRType
+ case b: Box => BoxRType
+
+ case avl: AvlTreeData => AvlTreeDataRType
+ case avl: AvlTree => AvlTreeRType
+
+ case sb: SigmaBoolean => SigmaBooleanRType
+ case p: SigmaProp => SigmaPropRType
+
+ case _ =>
+ sys.error(s"Don't know how to compute typeOf($value)")
+ }}
+
+ /** Generic translation of any ErgoDsl type to the corresponding type used in ErgoTree. */
+ def toErgoTreeType(dslType: RType[_]): RType[_] = dslType match {
+ case p: PrimitiveType[_] => p
+ case w: WrapperType[_] =>
+ w match {
+ case BigIntRType => BigIntegerRType
+ case GroupElementRType => ECPointRType
+ case SigmaPropRType => SigmaBooleanRType
+ case BoxRType => ErgoBoxRType
+ case AvlTreeRType => AvlTreeDataRType
+ case ContextRType => ErgoLikeContextRType
+ case _ => sys.error(s"Unknown WrapperType: $w")
+ }
+ case p: ArrayType[_] => arrayRType(toErgoTreeType(p.tA))
+ case p: OptionType[_] => optionRType(toErgoTreeType(p.tA))
+ case p: CollType[_] => arrayRType(toErgoTreeType(p.tItem))
+ case p: PairType[_,_] => tupleRType(Array(toErgoTreeType(p.tFst), toErgoTreeType(p.tSnd)))
+ case p: EitherType[_,_] => eitherRType(toErgoTreeType(p.tLeft), toErgoTreeType(p.tRight))
+ case p: FuncType[_,_] => funcRType(toErgoTreeType(p.tDom), toErgoTreeType(p.tRange))
+ case t: TupleType => tupleRType(t.items.map(x => toErgoTreeType(x)))
+ case HeaderRType | PreHeaderRType => dslType
+ case AnyType | AnyRefType | NothingType | StringType => dslType
+ case _ =>
+ sys.error(s"Don't know how to toErgoTreeType($dslType)")
+ }
+
+ /** Generic converter from types used in SigmaDsl to types used in ErgoTree values.
+ * @param tRes should describe ErgoTree type (i.e. it can be obtained using toErgoTreeType method)*/
+ def fromDslData[T](value: Any, tRes: RType[T]): T = {
+ val res = (value, tRes) match {
+ case (w: WrapperOf[_], _) => w.wrappedValue
+ case (coll: Coll[a], tarr: ArrayType[a1]) =>
+ val tItem = tarr.tA
+ coll.map[a1](x => fromDslData(x, tItem))(tItem).toArray
+ case (tup: Tuple2[a,b], tTup: TupleType) =>
+ val x = fromDslData(tup._1, tTup.items(0))
+ val y = fromDslData(tup._2, tTup.items(1))
+ Array[Any](x, y)
+ case _ => value
+ }
+ res.asInstanceOf[T]
+ }
+
+ /** Convert SigmaDsl representation of tuple to ErgoTree representation. */
+ def fromDslTuple(value: Any, tupleTpe: STuple): Array[Any] = value match {
+ case t: Tuple2[_,_] => Array[Any](t._1, t._2)
+ case a: Array[Any] => a
+ case _ =>
+ sys.error(s"Cannot execute fromDslTuple($value, $tupleTpe)")
+ }
+ /** Generic converter from types used in ErgoTree values to types used in ErgoDsl. */
+ def toDslData(value: Any, tpe: SType, isCost: Boolean)(implicit IR: Evaluation): Any = {
+ val dsl = IR.sigmaDslBuilderValue
+ (value, tpe) match {
+ case (c: Constant[_], tpe) => toDslData(c.value, c.tpe, isCost)
+ case (_, STuple(Seq(tpeA, tpeB))) =>
+ value match {
+ case tup: Tuple2[_,_] =>
+ val valA = toDslData(tup._1, tpeA, isCost)
+ val valB = toDslData(tup._2, tpeB, isCost)
+ (valA, valB)
+ case arr: Array[Any] =>
+ val valA = toDslData(arr(0), tpeA, isCost)
+ val valB = toDslData(arr(1), tpeB, isCost)
+ (valA, valB)
+ }
+ case (arr: Array[a], STuple(items)) =>
+ val res = arr.zip(items).map { case (x, t) => toDslData(x, t, isCost)}
+ dsl.Colls.fromArray(res)(RType.AnyType)
+ case (arr: Array[a], SCollectionType(elemType)) =>
+ implicit val elemRType: RType[SType#WrappedType] = Evaluation.stypeToRType(elemType)
+ elemRType.asInstanceOf[RType[_]] match {
+ case _: CollType[_] | _: TupleType | _: PairType[_,_] | _: WrapperType[_] =>
+ val testArr = arr.map(x => toDslData(x, elemType, isCost).asWrappedType).toArray(elemRType.classTag)
+ dsl.Colls.fromArray(testArr.asInstanceOf[Array[SType#WrappedType]])
+ case _ =>
+ dsl.Colls.fromArray(arr.asInstanceOf[Array[SType#WrappedType]])
+ }
+ case (b: ErgoBox, SBox) => b.toTestBox(isCost)
+ case (n: BigInteger, SBigInt) =>
+ dsl.BigInt(n)
+ case (p: ECPoint, SGroupElement) => dsl.GroupElement(p)
+ case (t: SigmaBoolean, SSigmaProp) => dsl.SigmaProp(t)
+ case (t: AvlTreeData, SAvlTree) => CAvlTree(t)
+ case (x, _) => x
+ }
+ }
+
+}
diff --git a/src/main/scala/sigmastate/eval/Extensions.scala b/src/main/scala/sigmastate/eval/Extensions.scala
new file mode 100644
index 0000000000..803a15f69d
--- /dev/null
+++ b/src/main/scala/sigmastate/eval/Extensions.scala
@@ -0,0 +1,39 @@
+package sigmastate.eval
+
+import java.math.BigInteger
+
+import scalan.RType
+import scalan.RType._
+import sigmastate.{SHeader, SType, SByte, SPreHeader}
+import sigmastate.Values.Constant
+import sigmastate.lang.DefaultSigmaBuilder
+import special.collection.{CSizePrim, Size, CSizeOption, Coll, CSizeColl}
+import special.sigma._
+import SType.AnyOps
+
+object Extensions {
+ private val Colls = CostingSigmaDslBuilder.Colls
+
+ implicit class ByteExt(val b: Byte) extends AnyVal {
+ @inline def toBigInt: BigInt = CostingSigmaDslBuilder.BigInt(BigInteger.valueOf(b.toLong))
+ }
+
+ implicit class IntExt(val x: Int) extends AnyVal {
+ /** Convert this value to BigInt. */
+ @inline def toBigInt: BigInt = CostingSigmaDslBuilder.BigInt(BigInteger.valueOf(x.toLong))
+ }
+
+ implicit class ArrayOps[T: RType](arr: Array[T]) {
+ @inline def toColl: Coll[T] = Colls.fromArray(arr)
+ }
+
+ implicit class DslDataOps[A](data: A)(implicit tA: RType[A]) {
+ def toTreeData: Constant[SType] = {
+ val treeType = Evaluation.toErgoTreeType(tA)
+ val treeData = Evaluation.fromDslData(data, tRes = treeType)
+ DefaultSigmaBuilder.mkConstant(treeData.asWrappedType, Evaluation.rtypeToSType(tA))
+ }
+ }
+
+
+}
diff --git a/src/main/scala/sigmastate/eval/IRContext.scala b/src/main/scala/sigmastate/eval/IRContext.scala
index 1b68b2e0a2..6a13b8521a 100644
--- a/src/main/scala/sigmastate/eval/IRContext.scala
+++ b/src/main/scala/sigmastate/eval/IRContext.scala
@@ -3,31 +3,91 @@ package sigmastate.eval
import java.lang.reflect.Method
import sigmastate.SType
-import sigmastate.Values.SValue
+import sigmastate.Values.{Value, SValue}
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigmastate.lang.TransformingSigmaBuilder
+import scala.util.Try
+
trait IRContext extends Evaluation with TreeBuilding {
import TestSigmaDslBuilder._
override val builder = TransformingSigmaBuilder
- beginPass(new DefaultPass("mypass", Pass.defaultPassConfig.copy(constantPropagation = false)))
+ /** Pass configuration which is used to turn-off constant propagation.
+ * @see `beginPass(noCostPropagationPass)` */
+ lazy val noConstPropagationPass = new DefaultPass(
+ "noCostPropagationPass",
+ Pass.defaultPassConfig.copy(constantPropagation = false))
+
+ override val sigmaDslBuilderValue = CostingSigmaDslBuilder
+ override val costedBuilderValue = sigmaDslBuilderValue.Costing
+ override val monoidBuilderValue = sigmaDslBuilderValue.Monoids
- override val sigmaDslBuilderValue = new CostingSigmaDslBuilder(this)
- override val costedBuilderValue = new special.collection.CCostedBuilder()
- override val monoidBuilderValue = new special.collection.MonoidBuilderInst()
+ type RCostingResult[T] = Rep[(Context => T, ((Int, Size[Context])) => Int)]
+ type RCostingResultEx[T] = Rep[(Context => T, ((Context, (Int, Size[Context]))) => Int)]
+
+ def doCosting[T](env: ScriptEnv, typed: SValue): RCostingResult[T] = {
+ val costed = buildCostedGraph[SType](env.map { case (k, v) => (k: Any, builder.liftAny(v).get) }, typed)
+ val f = asRep[Costed[Context] => Costed[T]](costed)
+ val calcF = f.sliceCalc
+ val costF = f.sliceCost
+ Pair(calcF, costF)
+ }
- type CostingResult[T] = Rep[(Context => T, Context => Int)]
+ def doCosting(env: ScriptEnv, typed: SValue, okRemoveIsProven: Boolean): RCostingResult[Any] = {
+ val costed = buildCostedGraph[SType](env.map { case (k, v) => (k: Any, builder.liftAny(v).get) }, typed)
+ val f = asRep[Costed[Context] => Costed[Any]](costed)
+ val calcF = f.sliceCalc(okRemoveIsProven)
+ val costF = f.sliceCost
+ Pair(calcF, costF)
+ }
- def doCosting(env: ScriptEnv, typed: SValue): CostingResult[Any] = {
+ def doCostingEx(env: ScriptEnv, typed: SValue, okRemoveIsProven: Boolean): RCostingResultEx[Any] = {
val costed = buildCostedGraph[SType](env.map { case (k, v) => (k: Any, builder.liftAny(v).get) }, typed)
- split2(asRep[Context => Costed[Any]](costed))
+ val f = asRep[Costed[Context] => Costed[Any]](costed)
+ val calcF = f.sliceCalc(okRemoveIsProven)
+ val costF = f.sliceCostEx
+ Pair(calcF, costF)
}
/** Can be overriden to to do for example logging or saving of graphs */
- private[sigmastate] def onCostingResult[T](env: ScriptEnv, tree: SValue, result: CostingResult[T]) {
+ private[sigmastate] def onCostingResult[T](env: ScriptEnv, tree: SValue, result: RCostingResultEx[T]) {
}
+
+ import Size._; import Context._;
+
+ def checkCost(ctx: SContext, exp: Value[SType],
+ costF: Rep[Size[Context] => Int], maxCost: Long): Int = {
+ val costFun = compile[SSize[SContext], Int, Size[Context], Int](getDataEnv, costF, Some(maxCost))
+ val (_, estimatedCost) = costFun(Sized.sizeOf(ctx))
+ if (estimatedCost > maxCost) {
+ throw new Error(s"Estimated expression complexity $estimatedCost exceeds the limit $maxCost in $exp")
+ }
+ estimatedCost
+ }
+
+ def checkCostEx(ctx: SContext, exp: Value[SType],
+ costF: Rep[((Int, Size[Context])) => Int], maxCost: Long): Int = {
+ val costFun = compile[(Int, SSize[SContext]), Int, (Int, Size[Context]), Int](getDataEnv, costF, Some(maxCost))
+ val (_, estimatedCost) = costFun((0, Sized.sizeOf(ctx)))
+ if (estimatedCost > maxCost) {
+ throw new Error(s"Estimated expression complexity $estimatedCost exceeds the limit $maxCost in $exp")
+ }
+ estimatedCost
+ }
+
+ def checkCostWithContext(ctx: SContext, exp: Value[SType],
+ costF: Rep[((Context, (Int, Size[Context]))) => Int], maxCost: Long): Try[Int] = Try {
+ val costFun = compile[(SContext, (Int, SSize[SContext])), Int, (Context, (Int, Size[Context])), Int](
+ getDataEnv, costF, Some(maxCost))
+ val (_, estimatedCost) = costFun((ctx, (0, Sized.sizeOf(ctx))))
+ if (estimatedCost > maxCost) {
+ throw new Error(msgCostLimitError(estimatedCost, maxCost))
+ }
+ estimatedCost
+ }
+
}
/** IR context to be used by blockchain nodes to validate transactions. */
diff --git a/src/main/scala/sigmastate/eval/RuntimeCosting.scala b/src/main/scala/sigmastate/eval/RuntimeCosting.scala
index bdfd045592..67755c86e0 100644
--- a/src/main/scala/sigmastate/eval/RuntimeCosting.scala
+++ b/src/main/scala/sigmastate/eval/RuntimeCosting.scala
@@ -5,7 +5,7 @@ import java.math.BigInteger
import scala.language.implicitConversions
import scala.language.existentials
import org.bouncycastle.math.ec.ECPoint
-import scalan.{Lazy, Nullable, SigmaLibrary}
+import scalan.{Lazy, SigmaLibrary, Nullable, RType}
import scalan.util.CollectionUtil.TraversableOps
import org.ergoplatform._
import sigmastate._
@@ -16,79 +16,111 @@ import sigmastate.lang.exceptions.CosterException
import sigmastate.serialization.OpCodes
import sigmastate.utxo.CostTable.Cost
import sigmastate.utxo._
+import sigma.util.Extensions._
import ErgoLikeContext._
import scalan.compilation.GraphVizConfig
import SType._
-import scorex.crypto.hash.{Blake2b256, Sha256}
+import scalan.RType.{StringType, AnyType, LongType, IntType, ArrayType, OptionType, TupleType, BooleanType, PairType, FuncType, ByteType, ShortType}
+import scorex.crypto.hash.{Sha256, Blake2b256}
import sigmastate.interpreter.Interpreter.ScriptEnv
-import sigmastate.lang.{SigmaCompiler, Terms}
+import sigmastate.lang.{Terms, SourceContext}
import scalan.staged.Slicing
-import sigmastate.basics.{DLogProtocol, ProveDHTuple}
-
-trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Evaluation =>
+import sigma.types.PrimViewType
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.basics.{ProveDHTuple, DLogProtocol}
+import sigmastate.eval.Evaluation.rtypeToSType
+import special.collection.CollType
+import special.sigma.{GroupElementRType, TestGroupElement, AvlTreeRType, BigIntegerRType, BoxRType, ECPointRType, BigIntRType, SigmaPropRType}
+import special.sigma.Extensions._
+
+trait RuntimeCosting extends CostingRules with DataCosting with Slicing { IR: Evaluation =>
import Context._;
+ import Header._;
+ import PreHeader._;
import WArray._;
- import WECPoint._;
- import WBigInteger._;
+ import WBigInteger._
+ import WECPoint._
+ import GroupElement._;
+ import BigInt._;
import WOption._
- import Col._;
- import ColBuilder._;
+ import Coll._;
+ import CollBuilder._;
import SigmaProp._;
- import TrivialSigma._
import Box._
- import ColOverArrayBuilder._;
+ import CollOverArrayBuilder._;
import CostedBuilder._
+ import SizeBuilder._
import CCostedBuilder._
+ import CSizeBuilder._
+ import Size._;
+ import SizeBox._;
+ import SizeColl._;
+ import SizeOption._;
+ import SizePair._;
+ import SizeContext._
+ import CSizeContext._
+ import CSizePrim._
+ import CSizePair._
+ import CSizeColl._
+ import CSizeOption._
import Costed._;
- import CostedContext._
- import CCostedContext._
import CostedPrim._;
import CCostedPrim._;
import CostedPair._;
import CCostedPair._;
import CostedFunc._;
import CCostedFunc._;
- import CostedCol._;
- import CCostedCol._;
- import CostedBox._;
- import CCostedBox._;
+ import CostedColl._;
+ import CCostedColl._;
import CostedBuilder._;
import CostedOption._;
- import CostedNone._
- import CostedSome._
- import ProveDlogEvidence._
- import ProveDHTEvidence._
+ import CCostedOption._
import SigmaDslBuilder._
- import TrivialSigma._
import MonoidBuilder._
import MonoidBuilderInst._
import AvlTree._
- import CostedAvlTree._
- import CCostedAvlTree._
import Monoid._
import IntPlusMonoid._
+ import LongPlusMonoid._
import WSpecialPredef._
import TestSigmaDslBuilder._
import CostModel._
+ import Liftables._
override val performViewsLifting = false
val okMeasureOperationTime: Boolean = false
- this.keepOriginalFunc = false // original lambda contains invocations of evalNode and we don't want that
+ this.isInlineThunksOnForce = true // this required for splitting of cost graph
+ this.keepOriginalFunc = false // original lambda of Lambda node contains invocations of evalNode and we don't want that
// this.useAlphaEquality = false
// unfoldWithOriginalFunc = unfoldWithOrig
+ /** Whether to create CostOf nodes or substutute costs from CostTable as constants in the graph.
+ * true - substitute; false - create CostOf nodes */
+ var substFromCostTable: Boolean = true
+
+// /** Pass configuration which is used by default in IRContext. */
+// val calcPass = new DefaultPass("calcPass", Pass.defaultPassConfig.copy(constantPropagation = true))
+//
+// /** Pass configuration which is used during splitting cost function out of cost graph.
+// * @see `RuntimeCosting.split2` */
+// val costPass = new DefaultPass("costPass", Pass.defaultPassConfig.copy(constantPropagation = true))
+
+/** To enable specific configuration uncomment one of the lines above and use it in the beginPass below. */
+// beginPass(costPass)
+
def createSliceAnalyzer = new SliceAnalyzer
- val ColMarking = new TraversableMarkingFor[Col]
+ val CollMarking = new TraversableMarkingFor[Coll]
val WOptionMarking = new TraversableMarkingFor[WOption]
override def createEmptyMarking[T](eT: Elem[T]): SliceMarking[T] = eT match {
- case _: BoxElem[_] | _: WBigIntegerElem[_] | _: IntPlusMonoidElem | _: ColOverArrayBuilderElem =>
+ case _: BoxElem[_] | _: BigIntElem[_] | _: IntPlusMonoidElem | _: LongPlusMonoidElem |
+ _: CollOverArrayBuilderElem | _: SigmaPropElem[_] =>
EmptyBaseMarking(eT)
- case ae: ColElem[a,_] =>
+ case ae: CollElem[a,_] =>
val eA = ae.eItem
- ColMarking(KeyPath.None, EmptyMarking(eA)).asMark[T]
+ CollMarking(KeyPath.None, EmptyMarking(eA)).asMark[T]
case ae: WOptionElem[a,_] =>
val eA = ae.eItem
WOptionMarking(KeyPath.None, EmptyMarking(eA)).asMark[T]
@@ -97,11 +129,11 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
override def createAllMarking[T](e: Elem[T]): SliceMarking[T] = e match {
- case _: BoxElem[_] | _: WBigIntegerElem[_] | _: IntPlusMonoidElem | _: ColOverArrayBuilderElem =>
+ case _: BoxElem[_] | _: BigIntElem[_] | _: IntPlusMonoidElem | _: LongPlusMonoidElem | _: CollOverArrayBuilderElem =>
AllBaseMarking(e)
- case colE: ColElem[a,_] =>
+ case colE: CollElem[a,_] =>
implicit val eA = colE.eItem
- ColMarking[a](KeyPath.All, AllMarking(eA)).asMark[T]
+ CollMarking[a](KeyPath.All, AllMarking(eA)).asMark[T]
case optE: WOptionElem[a,_] =>
implicit val eA = optE.eItem
WOptionMarking[a](KeyPath.All, AllMarking(eA)).asMark[T]
@@ -109,11 +141,59 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
super.createAllMarking(e)
}
- case class CostOf(opName: String, opType: SFunc) extends BaseDef[Int]
+ def zeroSize[V](eVal: Elem[V]): RSize[V] = asRep[Size[V]](eVal match {
+ case pe: PairElem[a,b] => costedBuilder.mkSizePair(zeroSize[a](pe.eFst), zeroSize[b](pe.eSnd))
+ case ce: CollElem[_,_] =>
+ implicit val eItem = ce.eItem
+ costedBuilder.mkSizeColl(colBuilder.fromItems(zeroSize(eItem)))
+ case oe: WOptionElem[_,_] => costedBuilder.mkSizeOption(RWSpecialPredef.some(zeroSize(oe.eItem)))
+ case _: BaseElem[_] | _: EntityElem[_] => costedBuilder.mkSizePrim(0L, eVal)
+ case _ => error(s"Cannot create zeroSize($eVal)")
+ })
+
+ case class CostOf(opName: String, opType: SFunc) extends BaseDef[Int] {
+ override def transform(t: Transformer): Def[IntPlusMonoidData] = this
+ def eval: Int = {
+ val operId = OperationId(opName, opType)
+ val cost = CostTable.DefaultCosts(operId)
+ cost
+ }
+ }
+
+ def costOf(opName: String, opType: SFunc, doEval: Boolean): Rep[Int] = {
+ val costOp = CostOf(opName, opType)
+ val res = if (doEval) toRep(costOp.eval)
+ else (costOp: Rep[Int])
+ res
+ }
+
+ def costOf(opName: String, opType: SFunc): Rep[Int] = {
+ costOf(opName, opType, substFromCostTable)
+ }
+
+ def costOf(method: SMethod): Rep[Int] = {
+ val methodTemplate = method.objType.getMethodById(method.methodId)
+ val opId = methodTemplate.opId
+ costOf(opId.name, opId.opType.copy(tpeParams = Nil), substFromCostTable)
+ }
+
+ def perKbCostOf(method: SMethod, dataSize: Rep[Long]): Rep[Int] = {
+ val methodTemplate = method.objType.getMethodById(method.methodId)
+ val opId = methodTemplate.opId
+ perKbCostOf(opId.name, opId.opType.copy(tpeParams = Nil), dataSize)
+ }
+
+ def costOfProveDlog: Rep[Int] = costOf("ProveDlogEval", SFunc(SUnit, SSigmaProp))
+ def costOfDHTuple: Rep[Int] = costOf("ProveDHTuple", SFunc(SUnit, SSigmaProp)) * 2 // cost ???
- def costOf(opName: String, opType: SFunc): Rep[Int] = CostOf(opName, opType)
- def costOfProveDlog = costOf("ProveDlogEval", SFunc(SUnit, SSigmaProp))
- def costOfDHTuple = costOf("ProveDHTuple", SFunc(SUnit, SSigmaProp)) * 2 // cost ???
+ def costOfSigmaTree(sigmaTree: SigmaBoolean): Int = sigmaTree match {
+ case dlog: ProveDlog => CostOf("ProveDlogEval", SFunc(SUnit, SSigmaProp)).eval
+ case dlog: ProveDHTuple => CostOf("ProveDHTuple", SFunc(SUnit, SSigmaProp)).eval * 2
+ case CAND(children) => children.map(costOfSigmaTree(_)).sum
+ case COR(children) => children.map(costOfSigmaTree(_)).sum
+ case CTHRESHOLD(k, children) => children.map(costOfSigmaTree(_)).sum
+ case _ => CostTable.MinimalCost
+ }
case class ConstantPlaceholder[T](index: Int)(implicit eT: LElem[T]) extends Def[T] {
def selfType: Elem[T] = eT.value
@@ -121,9 +201,13 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
def constantPlaceholder[T](index: Int)(implicit eT: LElem[T]): Rep[T] = ConstantPlaceholder[T](index)
- def perKbCostOf(node: SValue, dataSize: Rep[Long]) = {
- val opName = s"${node.getClass.getSimpleName}_per_kb"
- (dataSize.div(1024L).toInt + 1) * costOf(opName, node.opType)
+ def perKbCostOf(opName: String, opType: SFunc, dataSize: Rep[Long]): Rep[Int] = {
+ val opNamePerKb = s"${opName}_per_kb"
+ (dataSize.div(1024L).toInt + 1) * costOf(opNamePerKb, opType)
+ }
+
+ def perKbCostOf(node: SValue, dataSize: Rep[Long]): Rep[Int] = {
+ perKbCostOf(node.getClass.getSimpleName, node.opType, dataSize)
}
def perItemCostOf(node: SValue, arrLength: Rep[Int]) = {
@@ -143,11 +227,37 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
constCost(tpe)
}
- def costOf(v: SValue): Rep[Int] = {
- costOf(v.opName, v.opType)
+ def costOf(v: SValue): Rep[Int] = v match {
+ case l: Terms.Lambda =>
+ constCost(l.tpe)
+ case l: FuncValue =>
+ constCost(l.tpe)
+ case _ =>
+ costOf(v.opName, v.opType)
+ }
+
+ trait SizeStruct extends Size[Struct] {
+ def sizeFields: Rep[Struct]
}
+ case class SizeStructCtor(sizeFields: Rep[Struct]) extends SizeStruct {
+ override def transform(t: Transformer) = SizeStructCtor(t(sizeFields))
+
+ implicit val eVal: Elem[Struct] = {
+ val fields = sizeFields.elem.fields.map { case (fn, cE) => (fn, cE.asInstanceOf[SizeElem[_, _]].eVal) }
+ structElement(fields)
+ }
+ val selfType: Elem[Size[Struct]] = sizeElement(eVal)
+
+ def dataSize: Rep[Long] = {
+ val sizes = sizeFields.fields.map { case (_, cf: RSize[a]@unchecked) => cf.dataSize }
+ val sizesColl = colBuilder.fromItems(sizes:_*)
+ sizesColl.sum(longPlusMonoid)
+ }
+ }
+ def RSizeStruct(sizeFields: Rep[Struct]): Rep[Size[Struct]] = SizeStructCtor(sizeFields)
trait CostedStruct extends Costed[Struct] { }
+
case class CostedStructCtor(costedFields: Rep[Struct], structCost: Rep[Int]) extends CostedStruct {
override def transform(t: Transformer) = CostedStructCtor(t(costedFields), t(structCost))
@@ -163,19 +273,49 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
def cost: Rep[Int] = {
val costs = costedFields.fields.map { case (_, cf: RCosted[a]@unchecked) => cf.cost }
- val costsCol = colBuilder.fromItems(costs:_*)
- costsCol.sum(intPlusMonoid)
+ opCost(costs, structCost)
}
- def dataSize: Rep[Long] = {
- val sizes = costedFields.fields.map { case (_, cf: RCosted[a]@unchecked) => cf.dataSize }
- val sizesCol = colBuilder.fromItems(sizes:_*)
- sizesCol.sum(longPlusMonoid)
+ override def size: Rep[Size[Struct]] = {
+ val sizeFields = costedFields.mapFields { case cf: RCosted[a]@unchecked => cf.size }
+ SizeStructCtor(sizeFields)
}
}
def RCostedStruct(costedFields: Rep[Struct], structCost: Rep[Int]): Rep[Costed[Struct]] = CostedStructCtor(costedFields, structCost)
+ // SizeThunk =============================================
+ trait SizeThunk[A] extends Size[Thunk[A]] { }
+
+ case class SizeThunkCtor[A](sizeBlock: Rep[Thunk[Size[A]]]) extends SizeThunk[A] {
+ override def transform(t: Transformer) = SizeThunkCtor(t(sizeBlock))
+ implicit val eVal: Elem[Thunk[A]] = thunkElement(sizeBlock.elem.eItem.eVal)
+ val selfType: Elem[Size[Thunk[A]]] = sizeElement(eVal)
+
+ override def dataSize: Rep[Long] = sizeBlock.force().dataSize
+ }
+
+ def RSizeThunk[A](sizeBlock: Rep[Thunk[Size[A]]]): Rep[Size[Thunk[A]]] = SizeThunkCtor(sizeBlock)
+ // ---------------------------------------------------------
+
+
+ // CostedThunk =============================================
+ trait CostedThunk[A] extends Costed[Thunk[A]] { }
+
+ case class CostedThunkCtor[A](costedBlock: Rep[Thunk[Costed[A]]], thunkCost: Rep[Int]) extends CostedThunk[A] {
+ override def transform(t: Transformer) = CostedThunkCtor(t(costedBlock), t(thunkCost))
+ implicit val eVal: Elem[Thunk[A]] = thunkElement(costedBlock.elem.eItem.eVal)
+ val selfType: Elem[Costed[Thunk[A]]] = costedElement(eVal)
+
+ def builder: Rep[CostedBuilder] = costedBuilder
+ def value: Rep[Thunk[A]] = Thunk { costedBlock.force().value }
+ def cost: Rep[Int] = costedBlock.force().cost
+ override def size: RSize[Thunk[A]] = SizeThunkCtor(Thunk { costedBlock.force().size })
+ }
+
+ def RCostedThunk[A](costedBlock: Rep[Thunk[Costed[A]]], thunkCost: Rep[Int]): Rep[Costed[Thunk[A]]] = CostedThunkCtor(costedBlock, thunkCost)
+ // ---------------------------------------------------------
+
object ConstantSizeType {
def unapply(e: Elem[_]): Nullable[SType] = {
val tpe = elemToSType(e)
@@ -185,20 +325,10 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
override def sizeOf[T](value: Rep[T]): Rep[Long] = value.elem match {
- case _: BoxElem[_] =>
- asRep[Box](value).dataSize
- case ce: ColElem[a,_] =>
- val xs = asRep[Col[a]](value)
- implicit val eA = xs.elem.eItem
- val tpe = elemToSType(eA)
- if (tpe.isConstantSize)
- typeSize(tpe) * xs.length.toLong
- else
- xs.map(fun(sizeOf(_))).sum(longPlusMonoid)
case ConstantSizeType(tpe) =>
typeSize(tpe)
case _ =>
- super.sizeOf(value)
+ !!!(s"Cannot get sizeOf($value: ${value.elem})", value)
}
/** Graph node to represent computation of size for types with isConstantSize == true. */
@@ -207,7 +337,9 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
def typeSize(tpe: SType): Rep[Long] = {
- assert(tpe.isConstantSize)
+ assert(tpe.isConstantSize, {
+ s"Expected constant size type but was $tpe"
+ })
val size = tpe.dataSize(SType.DummyValue)
toRep(size)
}
@@ -219,77 +351,106 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
override protected def formatDef(d: Def[_])(implicit config: GraphVizConfig): String = d match {
case CostOf(name, opType) => s"CostOf($name:$opType)"
- case WECPointConst(p) => CryptoFunctions.showECPoint(p)
+ case GroupElementConst(p) => p.showToString
+ case SigmaPropConst(sp) => sp.toString
case ac: WArrayConst[_,_] =>
val trimmed = ac.constValue.take(ac.constValue.length min 10)
s"WArray(len=${ac.constValue.length}; ${trimmed.mkString(",")},...)"
case _ => super.formatDef(d)
}
- type RCol[T] = Rep[Col[T]]
- type RCostedCol[T] = Rep[CostedCol[T]]
- type RCostedFunc[A,B] = Rep[Costed[A] => Costed[B]]
+ type RColl[T] = Rep[Coll[T]]
+ type ROption[T] = Rep[WOption[T]]
+ type RCostedColl[T] = Rep[CostedColl[T]]
+ type RCostedOption[T] = Rep[CostedOption[T]]
+ type RFuncCosted[A,B] = Rep[Costed[A] => Costed[B]]
- implicit class RCostedFuncOps[A,B](f: RCostedFunc[A,B]) {
+ implicit class RFuncCostedOps[A,B](f: RFuncCosted[A,B]) {
implicit val eA = f.elem.eDom.eVal
/**NOTE: when removeIsValid == true the resulting type B may change from Boolean to SigmaProp
* This should be kept in mind at call site */
def sliceCalc(okRemoveIsProven: Boolean): Rep[A => Any] = {
- val _f = { x: Rep[A] => f(RCCostedPrim(x, 0, 0L)).value }
+ val _f = { x: Rep[A] => f(RCCostedPrim(x, 0, zeroSize(x.elem))).value }
val res = if (okRemoveIsProven) fun(removeIsProven(_f)) else fun(_f)
res
}
- def sliceCalc: Rep[A => B] = fun { x: Rep[A] => f(RCCostedPrim(x, 0, 0L)).value }
- def sliceCost: Rep[((A, (Int,Long))) => Int] = fun { in: Rep[(A, (Int, Long))] =>
- val Pair(x, Pair(c, s)) = in
- f(RCCostedPrim(x, c, s)).cost
+ def sliceCalc: Rep[A => B] = fun { x: Rep[A] => f(RCCostedPrim(x, 0, zeroSize(x.elem))).value }
+
+ def sliceCost: Rep[((Int,Size[A])) => Int] = fun { in: Rep[(Int, Size[A])] =>
+ val Pair(c, s) = in
+ f(RCCostedPrim(placeholder[A], c, s)).cost
}
- def sliceSize: Rep[Long => Long] = fun { x: Rep[Long] =>
- val arg = RCCostedPrim(variable[A], 0, x)
- f(arg).dataSize
+
+ def sliceCostEx: Rep[((A, (Int,Size[A]))) => Int] = fun { in: Rep[(A, (Int, Size[A]))] =>
+ val Pair(ctx, Pair(c, s)) = in
+ f(RCCostedPrim(ctx, c, s)).cost
}
+ def sliceSize: Rep[Size[A] => Size[B]] = fun { in: Rep[Size[A]] =>
+ val s = in
+ val arg = RCCostedPrim(placeholder[A], 0, s)
+ f(arg).size
+ }
}
- type CostedColFunc[A,B] = Costed[A] => CostedCol[B]
- type RCostedColFunc[A,B] = Rep[CostedColFunc[A, B]]
+ type CostedCollFunc[A,B] = Costed[A] => CostedColl[B]
+ type CostedOptionFunc[A,B] = Costed[A] => CostedOption[B]
+ type RCostedCollFunc[A,B] = Rep[CostedCollFunc[A, B]]
+ type RCostedOptionFunc[A,B] = Rep[CostedOptionFunc[A, B]]
- implicit class RCostedColFuncOps[A,B](f: RCostedColFunc[A,B]) {
+ implicit class RCostedCollFuncOps[A,B](f: RCostedCollFunc[A,B]) {
implicit val eA = f.elem.eDom.eVal
- def sliceValues: Rep[A => Col[B]] = fun { x: Rep[A] => f(RCCostedPrim(x, 0, 0L)).values }
- def sliceCosts: Rep[((A, (Int,Long))) => (Col[Int], Int)] = fun { in: Rep[(A, (Int, Long))] =>
- val Pair(x, Pair(c, s)) = in
- val colC = f(RCCostedPrim(x, c, s))
+ def sliceValues: Rep[A => Coll[B]] = fun { x: Rep[A] => f(RCCostedPrim(x, 0, zeroSize(x.elem))).values }
+ def sliceCosts: Rep[((Int,Size[A])) => (Coll[Int], Int)] = fun { in: Rep[(Int, Size[A])] =>
+ val Pair(c, s) = in
+ val colC = f(RCCostedPrim(placeholder[A], c, s))
Pair(colC.costs, colC.valuesCost)
}
- def sliceSizes: Rep[((A, Long)) => Col[Long]] = fun { in: Rep[(A, Long)] =>
- val Pair(x, s) = in
- f(RCCostedPrim(x, 0, s)).sizes
+ def sliceSizes: Rep[Size[A] => Coll[Size[B]]] = fun { in: Rep[Size[A]] =>
+ val s = in
+ f(RCCostedPrim(placeholder[A], 0, s)).sizes
}
}
+// implicit class RCostedOptionFuncOps[A,B](f: RCostedOptionFunc[A,B]) {
+// implicit val eA = f.elem.eDom.eVal
+// def sliceValues: Rep[A => WOption[B]] = fun { x: Rep[A] => f(RCCostedPrim(x, 0, zeroSizeData(x.elem))).values }
+// def sliceCosts: Rep[((A, (Int,Long))) => (Coll[Int], Int)] = fun { in: Rep[(A, (Int, Long))] =>
+// val Pair(x, Pair(c, s)) = in
+// val colC = f(RCCostedPrim(x, c, s))
+// Pair(colC.costs, colC.valuesCost)
+// }
+// def sliceSizes: Rep[((A, Long)) => Coll[Long]] = fun { in: Rep[(A, Long)] =>
+// val Pair(x, s) = in
+// f(RCCostedPrim(x, 0, s)).sizes
+// }
+// }
+
implicit def extendCostedFuncElem[E,A,B](e: Elem[CostedFunc[E,A,B]]): CostedFuncElem[E,A,B,_] = e.asInstanceOf[CostedFuncElem[E,A,B,_]]
+ implicit def extendSizeElem[A](elem: Elem[Size[A]]): SizeElem[A, Size[A]] =
+ elem.asInstanceOf[SizeElem[A, Size[A]]]
+
implicit def extendCostedElem[A](elem: Elem[Costed[A]]): CostedElem[A, Costed[A]] =
elem.asInstanceOf[CostedElem[A, Costed[A]]]
- implicit def extendCostedColElem[A](elem: Elem[CostedCol[A]]): CostedColElem[A, CostedCol[A]] =
- elem.asInstanceOf[CostedColElem[A, CostedCol[A]]]
+ implicit def extendCostedCollElem[A](elem: Elem[CostedColl[A]]): CostedCollElem[A, CostedColl[A]] =
+ elem.asInstanceOf[CostedCollElem[A, CostedColl[A]]]
- def splitCostedFunc2[A,B](f: RCostedFunc[A,B]): (Rep[A=>B], Rep[((A, (Int, Long))) => Int]) = {
+ def splitCostedFunc2[A,B](f: RFuncCosted[A,B]): (Rep[A=>B], Rep[((Int, Size[A])) => Int]) = {
implicit val eA = f.elem.eDom.eVal
val calcF = f.sliceCalc
val costF = f.sliceCost
(calcF, costF)
}
- def splitCostedFunc2[A, B](f: RCostedFunc[A,B], okRemoveIsValid: Boolean): (Rep[A=>Any], Rep[((A, (Int, Long))) => Int]) = {
+ def splitCostedFunc2[A, B](f: RFuncCosted[A,B], okRemoveIsValid: Boolean): (Rep[A=>Any], Rep[((Int, Size[A])) => Int]) = {
implicit val eA = f.elem.eDom.eVal
val calcF = f.sliceCalc(okRemoveIsValid)
val costF = f.sliceCost
(calcF, costF)
}
- def splitCostedFunc[A,B](f: RCostedFunc[A,B]): (Rep[A=>B], Rep[((A, (Int, Long))) => Int], Rep[Long => Long]) = {
+ def splitCostedFunc[A,B](f: RFuncCosted[A,B]): (Rep[A=>B], Rep[((Int, Size[A])) => Int], Rep[Size[A] => Size[B]]) = {
implicit val eA = f.elem.eDom.eVal
val calcF = f.sliceCalc
val costF = f.sliceCost
@@ -297,7 +458,7 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
(calcF, costF, sizeF)
}
- def splitCostedColFunc[A,B](f: RCostedColFunc[A,B]): (Rep[A=>Col[B]], Rep[((A, (Int, Long))) => (Col[Int], Int)], Rep[((A, Long)) => Col[Long]]) = {
+ def splitCostedCollFunc[A,B](f: RCostedCollFunc[A,B]): (Rep[A=>Coll[B]], Rep[((Int, Size[A])) => (Coll[Int], Int)], Rep[Size[A] => Coll[Size[B]]]) = {
implicit val eA = f.elem.eDom.eVal
val calcF = f.sliceValues
val costF = f.sliceCosts
@@ -305,46 +466,65 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
(calcF, costF, sizeF)
}
- type RWOption[T] = Rep[WOption[T]]
+// def splitCostedOptionFunc[A,B](f: RCostedOptionFunc[A,B]): (Rep[A=>WOption[B]], Rep[((A, (Int, Long))) => (WOption[Int], Int)], Rep[((A, Long)) => WOption[Long]]) = {
+// implicit val eA = f.elem.eDom.eVal
+// val calcF = f.sliceValues
+// val costF = f.sliceCosts
+// val sizeF = f.sliceSizes
+// (calcF, costF, sizeF)
+// }
object CostedFoldExtractors {
val CM = CostedMethods
val COM = CostedOptionMethods
val WOM = WOptionMethods
- type Result = (RWOption[A], Th[B], RFunc[A, Costed[B]]) forSome {type A; type B}
-
- object IsGetCost {
- def unapply(d: Def[_]): Nullable[Result] = d match {
- case CM.cost(COM.get(WOM.fold(opt, th, f))) =>
- val res = (opt, th, f).asInstanceOf[Result]
- Nullable(res)
- case _ => Nullable.None
- }
- }
- object IsGetDataSize {
- def unapply(d: Def[_]): Nullable[Result] = d match {
- case CM.dataSize(COM.get(WOM.fold(opt, th, f))) =>
- val res = (opt, th, f).asInstanceOf[Result]
- Nullable(res)
- case _ => Nullable.None
- }
- }
- object IsGet {
- def unapply(d: Def[_]): Nullable[Result] = d match {
- case COM.get(WOM.fold(opt, th, f)) =>
- val res = (opt, th, f).asInstanceOf[Result]
- Nullable(res)
- case _ => Nullable.None
- }
+ type Result = (ROption[A], Th[B], RFunc[A, Costed[B]]) forSome {type A; type B}
+
+// object IsGetCost {
+// def unapply(d: Def[_]): Nullable[Result] = d match {
+// case CM.cost(COM.get(WOM.fold(opt, th, f))) =>
+// val res = (opt, th, f).asInstanceOf[Result]
+// Nullable(res)
+// case _ => Nullable.None
+// }
+// }
+// object IsGetDataSize {
+// def unapply(d: Def[_]): Nullable[Result] = d match {
+// case CM.dataSize(COM.get(WOM.fold(opt, th, f))) =>
+// val res = (opt, th, f).asInstanceOf[Result]
+// Nullable(res)
+// case _ => Nullable.None
+// }
+// }
+// object IsGet {
+// def unapply(d: Def[_]): Nullable[Result] = d match {
+// case COM.get(WOM.fold(opt, th, f)) =>
+// val res = (opt, th, f).asInstanceOf[Result]
+// Nullable(res)
+// case _ => Nullable.None
+// }
+// }
+ }
+
+ object IsConstSizeCostedColl {
+ def unapply(d: Def[_]): Nullable[Rep[Costed[Coll[A]]] forSome {type A}] = d.selfType match {
+ case ce: CostedElem[_,_] if !ce.isInstanceOf[CostedCollElem[_, _]] =>
+ ce.eVal match {
+ case colE: CollElem[a,_] if colE.eItem.isConstantSize =>
+ val res = d.self.asInstanceOf[Rep[Costed[Coll[A]]] forSome {type A}]
+ Nullable(res)
+ case _ => Nullable.None
+ }
+ case _ => Nullable.None
}
}
- object IsConstSizeCostedCol {
- def unapply(d: Def[_]): Nullable[Rep[Costed[Col[A]]] forSome {type A}] = d.selfType match {
- case ce: CostedElem[_,_] if !ce.isInstanceOf[CostedColElem[_, _]] =>
+ object IsCostedPair {
+ def unapply(d: Def[_]): Nullable[Rep[Costed[(A, B)]] forSome {type A; type B}] = d.selfType match {
+ case ce: CostedElem[_,_] if !ce.isInstanceOf[CostedPairElem[_, _, _]] =>
ce.eVal match {
- case colE: ColElem[a,_] if colE.eItem.isConstantSize =>
- val res = d.self.asInstanceOf[Rep[Costed[Col[A]]] forSome {type A}]
+ case pE: PairElem[a,b] =>
+ val res = d.self.asInstanceOf[Rep[Costed[(A, B)]] forSome {type A; type B}]
Nullable(res)
case _ => Nullable.None
}
@@ -353,35 +533,64 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
implicit class ElemOpsForCosting(e: Elem[_]) {
- def isConstantSize: Boolean = elemToSType(e).isConstantSize
+ def isConstantSize: Boolean = e.sourceType.isConstantSize
+ }
+
+ type CostedTh[T] = Th[Costed[T]]
+
+ class ElemAccessor[T](prop: Rep[T] => Elem[_]) {
+ def unapply(s: Sym): Option[Elem[_]] = { val sR = asRep[T](s); Some(prop(sR)) }
+ }
+ object ElemAccessor {
+ def apply[T](prop: Rep[T] => Elem[_]): ElemAccessor[T] = new ElemAccessor(prop)
}
- type CostedThunk[T] = Th[Costed[T]]
+ val EValOfSizeColl = ElemAccessor[Coll[Size[Any]]](_.elem.eItem.eVal)
override def rewriteDef[T](d: Def[T]): Rep[_] = {
- val CBM = ColBuilderMethods
+ val CBM = CollBuilderMethods
val SigmaM = SigmaPropMethods
- val CCM = CostedColMethods
+ val CCM = CostedCollMethods
val CostedM = CostedMethods
val CostedOptionM = CostedOptionMethods
- val CostedBoxM = CostedBoxMethods
val WOptionM = WOptionMethods
- val CM = ColMethods
+ val WArrayM = WArrayMethods
+ val CM = CollMethods
val CostedBuilderM = CostedBuilderMethods
val SPCM = WSpecialPredefCompanionMethods
+ val SDBM = SigmaDslBuilderMethods
+ val SM = SizeMethods
+ val SBM = SizeBoxMethods
d match {
+ // Rule: cast(eTo, x) if x.elem <:< eTo ==> x
+ case Cast(eTo: Elem[to], x) if eTo.runtimeClass.isAssignableFrom(x.elem.runtimeClass) =>
+ x
+
+ case SM.dataSize(Def(CSizeCollCtor(CBM.replicate(_, n, s: RSize[a]@unchecked)))) => s.dataSize * n.toLong
+
+ case SM.dataSize(Def(CSizeCollCtor(sizes @ EValOfSizeColl(eVal)))) if eVal.isConstantSize =>
+ sizes.length.toLong * typeSize(eVal)
+
+ case CM.map(CM.zip(CBM.replicate(_, n, x: Rep[a]), ys: RColl[b]@unchecked), _f) =>
+ val f = asRep[((a,b)) => Any](_f)
+ implicit val eb = ys.elem.eItem
+ ys.map(fun { y: Rep[b] => f(Pair(x, y))})
+
+ case WArrayM.length(Def(arrC: WArrayConst[_,_])) => arrC.constValue.length
+ // Rule: l.isValid op Thunk {... root} => (l op TrivialSigma(root)).isValid
case ApplyBinOpLazy(op, SigmaM.isValid(l), Def(ThunkDef(root, sch))) if root.elem == BooleanElement =>
// don't need new Thunk because sigma logical ops always strict
- val r = asRep[SigmaProp](RTrivialSigma(asRep[Boolean](root)))
+ val r = asRep[SigmaProp](sigmaDslBuilder.sigmaProp(asRep[Boolean](root)))
val res = if (op == And)
l && r
else
l || r
res.isValid
+ // Rule: l op Thunk {... prop.isValid} => (TrivialSigma(l) op prop).isValid
case ApplyBinOpLazy(op, l, Def(ThunkDef(root @ SigmaM.isValid(prop), sch))) if l.elem == BooleanElement =>
- val l1 = asRep[SigmaProp](RTrivialSigma(asRep[Boolean](l)))
+ val l1 = asRep[SigmaProp](sigmaDslBuilder.sigmaProp(asRep[Boolean](l)))
// don't need new Thunk because sigma logical ops always strict
val res = if (op == And)
l1 && prop
@@ -389,86 +598,60 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
l1 || prop
res.isValid
- case TrivialSigmaCtor(SigmaM.isValid(p)) => p
+ case SDBM.sigmaProp(_, SigmaM.isValid(p)) => p
- case CCM.mapCosted(xs: RCostedCol[a], _f: RCostedFunc[_, b]) =>
+ case CCM.mapCosted(xs: RCostedColl[a], _f: RFuncCosted[_, b]) =>
val f = asRep[Costed[a] => Costed[b]](_f)
val (calcF, costF, sizeF) = splitCostedFunc[a, b](f)
val vals = xs.values.map(calcF)
- val mRes = AllMarking(element[Int])
- val mCostF = sliceAnalyzer.analyzeFunc(costF, mRes)
implicit val eA = xs.elem.eItem
implicit val eB = f.elem.eRange.eVal
- val costs = mCostF.mDom match {
- case PairMarking(markA,_) if markA.isEmpty =>
- val slicedCostF = fun { in: Rep[(Int, Long)] => costF(Pair(variable[a], in)) }
- xs.costs.zip(xs.sizes).map(slicedCostF)
- case _ =>
- xs.values.zip(xs.costs.zip(xs.sizes)).map(costF)
- }
- val tpeB = elemToSType(eB)
- val sizes = if (tpeB.isConstantSize) {
- colBuilder.replicate(xs.sizes.length, typeSize(tpeB))
- } else
+ val costs = xs.costs.zip(xs.sizes).map(costF)
+ val sizes = if (eB.isConstantSize) {
+ colBuilder.replicate(xs.sizes.length, constantTypeSize(eB): RSize[b])
+ } else {
xs.sizes.map(sizeF)
- RCCostedCol(vals, costs, sizes, xs.valuesCost)
+ }
+ RCCostedColl(vals, costs, sizes, xs.valuesCost) // TODO add cost of map node
- case CCM.foldCosted(xs: RCostedCol[a], zero: RCosted[b], _f) =>
+ case CCM.foldCosted(xs: RCostedColl[a], zero: RCosted[b], _f) =>
val f = asRep[Costed[(b,a)] => Costed[b]](_f)
- val (calcF, costF, sizeF) = splitCostedFunc[(b,a), b](f)
- val resV = xs.values.fold(zero.value, calcF)
- val mRes = AllMarking(element[Int])
- val mCostF = sliceAnalyzer.analyzeFunc(costF, mRes)
-
- mCostF.mDom match {
- case PairMarking(markA,_) if markA.isEmpty =>
- implicit val eA = xs.elem.eItem
- implicit val eB = zero.elem.eVal
- val slicedCostF = fun { in: Rep[(Int, Long)] => costF(Pair(variable[(b,a)], in)) }
- val cost = xs.costs.zip(xs.sizes).map(slicedCostF).sum(intPlusMonoid)
- if (elemToSType(zero.elem.eVal).isConstantSize)
- RCCostedPrim(resV, cost, zero.dataSize)
- else {
- // TODO costing: make more accurate cost estimation
- RCCostedPrim(resV, cost, zero.dataSize)
+ val (calcF/*: Rep[((b,a)) => b]*/,
+ costF/*: Rep[((Int, Size[(b,a)])) => Int]*/,
+ sizeF/*: Rep[Size[(b,a)] => Size[b]]*/) = splitCostedFunc[(b,a), b](f)
+
+ val resV = xs.values.foldLeft(zero.value, calcF)
+
+ implicit val eA: Elem[a] = xs.elem.eItem
+ implicit val eB: Elem[b] = zero.elem.eVal
+ val Pair(resS, resC) = xs.costs.zip(xs.sizes).foldLeft(
+ Pair(zero.size, 0),
+ fun { in: Rep[((Size[b], Int), (Int, Size[a]))] =>
+ val Pair(Pair(accSizeB, accCost), Pair(xCost, xSize)) = in
+ val sBA = RCSizePair(accSizeB, xSize)
+ val res = Pair(sizeF(sBA), costF(Pair(xCost, sBA)))
+ res
}
- case _ =>
- error(s"Cost of the folded function depends on data: $d")
- }
-
-// case CCM.filterCosted(xs: RCostedCol[a], _f: RCostedFunc[_,_]) =>
+ )
+ RCCostedPrim(resV, resC, resS)
+
+// case CCM.filterCosted(xs: RCostedColl[a], _f: RCostedFunc[_,_]) =>
// val f = asRep[Costed[a] => Costed[Boolean]](_f)
// val (calcF, costF, _) = splitCostedFunc[a, Boolean](f)
// val vals = xs.values.filter(calcF)
// val costs = xs.costs.zip(xs.sizes).map(costF) // TODO how to filter our sizes and costs
// val sizes = colBuilder.replicate(xs.sizes.length, 1L)
-// RCostedCol(vals, costs, sizes, xs.valuesCost)
-
- case CostedBoxM.creationInfo(boxC) =>
- val info = boxC.value.creationInfo
- val l = RCCostedPrim(info._1, 0, 4L)
- val r = mkCostedCol(info._2, 34, boxC.cost)
- RCCostedPair(l, r)
-
- case CostedOptionM.get(optC @ CostedBoxM.getReg(_, Def(Const(2)), regE)) /*if regId == ErgoBox.R2.asIndex*/ =>
- require(regE.isInstanceOf[ColElem[_,_]],
- s"Predefined register R${ErgoBox.R2.asIndex} should have Coll[(Coll[Byte], Long)] type but was $regE")
- val values = asRep[Col[(Col[Byte], Long)]](optC.value.get)
- val costs = colBuilder.replicate(values.length, 0)
- val sizes = colBuilder.replicate(values.length, Blake2b256.DigestSize.toLong + SLong.dataSize(0.asWrappedType))
- RCCostedCol(values, costs, sizes, optC.cost + sigmaDslBuilder.CostModel.SelectField)
-
- case CostedM.value(Def(CCostedFuncCtor(_, func: RCostedFunc[a,b], _,_))) =>
+// RCostedColl(vals, costs, sizes, xs.valuesCost)
+
+
+ case CostedM.cost(Def(CCostedCollCtor(_, costs, _, accCost))) => opCost(Seq(accCost), costs.sum(intPlusMonoid))
+ case CostedM.cost(Def(CCostedOptionCtor(_, costOpt, _, accCost))) => opCost(Seq(accCost), costOpt.getOrElse(Thunk(0)))
+ case CostedM.cost(Def(CCostedPairCtor(l, r, accCost))) => opCost(Seq(accCost), l.cost + r.cost)
+
+ case CostedM.value(Def(CCostedFuncCtor(_, func: RFuncCosted[a,b], _,_))) =>
func.sliceCalc
-// case CostedFoldExtractors.IsGetCost(opt: RWOption[a], th: CostedThunk[b]@unchecked, f) =>
-// implicit val eA = opt.elem.eItem
-// opt.fold(Thunk { forceThunkByMirror(th).cost }, fun { x: Rep[a] => asRep[a => Costed[b]](f)(x).cost })
-//
-// case CostedFoldExtractors.IsGetDataSize(opt: RWOption[a], th: CostedThunk[b]@unchecked, f) =>
-// implicit val eA = opt.elem.eItem
-// opt.fold(Thunk { forceThunkByMirror(th).dataSize }, fun { x: Rep[a] => asRep[a => Costed[b]](f)(x).dataSize })
// Rule: opt.fold(default, f).value ==> opt.fold(default.value, x => f(x).value)
case CostedM.value(WOptionM.fold(opt, _th @ Def(ThunkDef(_, _)), _f)) =>
@@ -484,53 +667,39 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
val f = asRep[Any => Costed[Any]](_f)
opt.fold(Thunk(forceThunkByMirror(th).cost), fun { x: Rep[Any] => f(x).cost })
- // Rule: opt.fold(default, f).dataSize ==> opt.fold(default.dataSize, x => f(x).dataSize)
- case CostedM.dataSize(WOptionM.fold(opt, _th @ Def(ThunkDef(_, _)), _f)) =>
+ // Rule: opt.fold(default, f).size ==> opt.fold(default.size, x => f(x).size)
+ case CostedM.size(WOptionM.fold(opt, _th @ Def(ThunkDef(_, _)), _f)) =>
implicit val eA: Elem[Any] = opt.elem.eItem.asElem[Any]
val th = asRep[Thunk[Costed[Any]]](_th)
val f = asRep[Any => Costed[Any]](_f)
- opt.fold(Thunk(forceThunkByMirror(th).dataSize), fun { x: Rep[Any] => f(x).dataSize })
-
- case CostedFoldExtractors.IsGet(opt: RWOption[a], _, _f) =>
- implicit val eA = opt.elem.eItem
- val f = asRep[a => CostedOption[Any]](_f)
- f(opt.get).get
-
- case CostedOptionM.getOrElse(WOptionM.fold(opt: RWOption[a], _, _f), _default) =>
- implicit val eA = opt.elem.eItem
- val f = asRep[a => CostedOption[a]](_f)
- val default = asRep[Costed[a]](_default)
- f(opt.getOrElse(Thunk(default.value))).getOrElse(default)
-
- case CostedOptionM.isDefined(WOptionM.fold(opt: RWOption[a], _, _f)) =>
- implicit val eA = opt.elem.eItem
- RCCostedPrim(opt.isDefined, costedBuilder.SelectFieldCost, 1L)
+ opt.fold(Thunk(forceThunkByMirror(th).size), fun { x: Rep[Any] => f(x).size })
case CCostedPrimCtor(v, c, s) =>
- v.elem.asInstanceOf[Elem[_]] match {
- case be: BoxElem[_] => RCCostedBox(asRep[Box](v), c)
- case be: AvlTreeElem[_] => RCCostedAvlTree(asRep[AvlTree](v), c)
- case pe: PairElem[a,b] =>
+ val res = v.elem.asInstanceOf[Elem[_]] match {
+ case pe: PairElem[a,b] /*if s.elem.isInstanceOf[CSizePairElem[_,_]]*/ =>
val p = asRep[(a,b)](v)
- // TODO costing: this is approximation (we essentially double the cost and size)
- RCCostedPair(RCCostedPrim(p._1, c, s), RCCostedPrim(p._2, c, s))
- case ce: ColElem[a,_] if ce.eItem.isConstantSize =>
- val col = asRep[Col[a]](v)
- mkCostedCol(col, col.length, c)
+ costedPrimToPair(p, c, asRep[Size[(a,b)]](s))
+ case ce: CollElem[a,_] /*if s.elem.isInstanceOf[CSizeCollElem[_]]*/ =>
+ val col = asRep[Coll[a]](v)
+ costedPrimToColl(col, c, asRep[Size[Coll[a]]](s))
+ case oe: WOptionElem[a,_] /*if s.elem.isInstanceOf[CSizeOptionElem[_]]*/ =>
+ val opt = asRep[WOption[a]](v)
+ costedPrimToOption(opt, c, asRep[Size[WOption[a]]](s))
case _ => super.rewriteDef(d)
}
+ res
- case CostedBuilderM.costedValue(b, x, SPCM.some(cost)) =>
- dataCost(x, Some(asRep[Int](cost)))
+// case CostedBuilderM.costedValue(b, x, SPCM.some(cost)) =>
+// dataCost(x, Some(asRep[Int](cost)))
- case IsConstSizeCostedCol(col) =>
- mkCostedCol(col.value, col.value.length, col.cost)
+ case IsConstSizeCostedColl(col) if !d.isInstanceOf[MethodCall] => // see also rewriteNonInvokableMethodCall
+ mkCostedColl(col.value, col.value.length, col.cost)
case _ if isCostingProcess =>
// apply special rules for costing function
d match {
- case CM.length(Def(IfThenElseLazy(_, Def(ThunkDef(t: RCol[a]@unchecked,_)), Def(ThunkDef(_e,_))))) =>
- val e = asRep[Col[a]](_e)
+ case CM.length(Def(IfThenElseLazy(_, Def(ThunkDef(t: RColl[a]@unchecked,_)), Def(ThunkDef(_e,_))))) =>
+ val e = asRep[Coll[a]](_e)
t.length max e.length
case _ => super.rewriteDef(d)
}
@@ -538,54 +707,87 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
}
-// override def transformDef[A](d: Def[A], t: Transformer): Rep[A] = d match {
-// // not the same as super because mkMethodCall can produce a more precise return type
-// case MethodCall(receiver, method, args, neverInvoke) =>
-// val args1 = args.map(transformProductParam(_, t).asInstanceOf[AnyRef])
-// val receiver1 = t(receiver)
-// // in the case neverInvoke is false, the method is invoked in rewriteDef
-// mkMethodCall(receiver1, method, args1, neverInvoke).asInstanceOf[Rep[A]]
-// case _ => super.transformDef(d, t)
-// }
+ def costedPrimToColl[A](coll: Rep[Coll[A]], c: Rep[Int], s: RSize[Coll[A]]): RCostedColl[A] = s.elem.asInstanceOf[Any] match {
+ case se: SizeElem[_,_] if se.eVal.isInstanceOf[CollElem[_,_]] =>
+ val sizes = asSizeColl(s).sizes
+ val costs = colBuilder.replicate(sizes.length, 0)
+ mkCostedColl(coll, costs, sizes, c)
+ case _ =>
+ !!!(s"Expected Size[Coll[A]] node but was $s -> ${s.rhs}")
+ }
+
+ def costedPrimToOption[A](opt: Rep[WOption[A]], c: Rep[Int], s: RSize[WOption[A]]) = s.elem.asInstanceOf[Any] match {
+ case se: SizeElem[_,_] if se.eVal.isInstanceOf[WOptionElem[_,_]] =>
+ val sizeOpt = asSizeOption(s).sizeOpt
+ mkCostedOption(opt, SOME(0), sizeOpt, c)
+ case _ =>
+ !!!(s"Expected RCSizeOption node but was $s -> ${s.rhs}")
+ }
+
+ def costedPrimToPair[A,B](p: Rep[(A,B)], c: Rep[Int], s: RSize[(A,B)]) = s.elem.asInstanceOf[Any] match {
+ case se: SizeElem[_,_] if se.eVal.isInstanceOf[PairElem[_,_]] =>
+ val sPair = asSizePair(s)
+ RCCostedPair(RCCostedPrim(p._1, 0, sPair.l), RCCostedPrim(p._2, 0, sPair.r), c)
+ case _ =>
+ !!!(s"Expected RCSizePair node but was $s -> ${s.rhs}")
+ }
- lazy val BigIntegerElement: Elem[WBigInteger] = wBigIntegerElement
+ override def rewriteNonInvokableMethodCall(mc: MethodCall): Rep[_] = mc match {
+ case IsConstSizeCostedColl(col: RCosted[Coll[Any]]@unchecked) =>
+ costedPrimToColl(col.value, col.cost, asSizeColl(col.size))
+ case IsCostedPair(p) =>
+ val v = asRep[(Any,Any)](p.value)
+ val c = p.cost
+ val s = asRep[Size[(Any,Any)]](p.size)
+ costedPrimToPair(v, c, asSizePair(s))
+ case _ =>
+ super.rewriteNonInvokableMethodCall(mc)
+ }
- override def toRep[A](x: A)(implicit eA: Elem[A]):Rep[A] = eA match {
- case BigIntegerElement => Const(x)
- case _ => super.toRep(x)
+ override def transformDef[A](d: Def[A], t: Transformer): Rep[A] = d match {
+ case c: CostOf => c.self
+ case _ => super.transformDef(d, t)
}
/** Should be specified in the final cake */
val builder: sigmastate.lang.SigmaBuilder
import builder._
- lazy val compiler = new SigmaCompiler(builder)
- var _colBuilder: Rep[ColBuilder] = _
- var _costedBuilder: Rep[CostedBuilder] = _
- var _intPlusMonoid: Rep[Monoid[Int]] = _
- var _longPlusMonoid: Rep[Monoid[Long]] = _
- var _sigmaDslBuilder: Rep[SigmaDslBuilder] = _
+ private var _colBuilder: Rep[CollBuilder] = _
+ private var _sizeBuilder: Rep[SizeBuilder] = _
+ private var _costedBuilder: Rep[CostedBuilder] = _
+ private var _intPlusMonoid: Rep[Monoid[Int]] = _
+ private var _longPlusMonoid: Rep[Monoid[Long]] = _
+ private var _sigmaDslBuilder: Rep[SigmaDslBuilder] = _
init() // initialize global context state
- def colBuilder: Rep[ColBuilder] = _colBuilder
+ def colBuilder: Rep[CollBuilder] = _colBuilder
+ def sizeBuilder: Rep[SizeBuilder] = _sizeBuilder
def costedBuilder: Rep[CostedBuilder] = _costedBuilder
def intPlusMonoid: Rep[Monoid[Int]] = _intPlusMonoid
def longPlusMonoid: Rep[Monoid[Long]] = _longPlusMonoid
def sigmaDslBuilder: Rep[SigmaDslBuilder] = _sigmaDslBuilder
protected def init(): Unit = {
- _colBuilder = RColOverArrayBuilder()
+ _colBuilder = RCollOverArrayBuilder()
+ _sizeBuilder = RCSizeBuilder()
_costedBuilder = RCCostedBuilder()
_intPlusMonoid = costedBuilder.monoidBuilder.intPlusMonoid
_longPlusMonoid = costedBuilder.monoidBuilder.longPlusMonoid
_sigmaDslBuilder = RTestSigmaDslBuilder()
}
-// This is experimental alternative which is 10x faster in MeasureIRContext benchmark
-// However it is not fully correct. It can be used if current implementation is not fast enough.
-// def colBuilder: Rep[ColBuilder] = {
-// if (_colBuilder == null) _colBuilder = RColOverArrayBuilder()
+ protected override def onReset(): Unit = {
+ super.onReset()
+ init()
+ }
+
+// TODO This is experimental alternative which is 10x faster in MeasureIRContext benchmark
+// However it is not fully correct.
+// It can be used if current implementation is not fast enough.
+// def colBuilder: Rep[CollBuilder] = {
+// if (_colBuilder == null) _colBuilder = RCollOverArrayBuilder()
// _colBuilder
// }
// def costedBuilder: Rep[CostedBuilder] = {
@@ -614,11 +816,6 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
// _sigmaDslBuilder = null
// }
- protected override def onReset(): Unit = {
- super.onReset()
- init()
- }
-
import Cost._
def removeIsProven[T,R](f: Rep[T] => Rep[Any]): Rep[T] => Rep[Any] = { x: Rep[T] =>
@@ -633,33 +830,40 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
private[sigmastate] var funUnderCosting: Sym = null
def isCostingProcess: Boolean = funUnderCosting != null
- def costingOf[T,R](f: Rep[T => Costed[R]]): Rep[T] => Rep[Int] = { x: Rep[T] =>
- funUnderCosting = f
- val c = f(x).cost;
- funUnderCosting = null
- c
- }
+// def costingOf[T,R](f: Rep[T => Costed[R]]): Rep[T] => Rep[Int] = { x: Rep[T] =>
+// funUnderCosting = f
+// val c = f(x).cost;
+// funUnderCosting = null
+// c
+// }
- def split2[T,R](f: Rep[T => Costed[R]]): Rep[(T => Any, T => Int)] = {
- implicit val eT = f.elem.eDom
- val calc = fun(removeIsProven { x: Rep[T] =>
- val y = f(x);
- y.value
- })
- val cost = fun(costingOf(f))
- Pair(calc, cost)
- }
+// def sizingOf[T,R](f: Rep[T => Costed[R]]): Rep[T] => Rep[Long] = { x: Rep[T] =>
+// funUnderCosting = f
+// val c = f(x).dataSize;
+// funUnderCosting = null
+// c
+// }
- def split3[T,R](f: Rep[T => Costed[R]]): Rep[(T => Any, (T => Int, T => Long))] = {
- implicit val eT = f.elem.eDom
- val calc = fun(removeIsProven { x: Rep[T] =>
- val y = f(x);
- y.value
- })
- val cost = fun { x: Rep[T] => f(x).cost }
- val size = fun { x: Rep[T] => f(x).dataSize }
- Tuple(calc, cost, size)
- }
+// def split2[T,R](f: Rep[((T, Size[T])) => Costed[R]]): Rep[(T => Any, T => Int)] = {
+// implicit val eT = f.elem.eDom
+// val calc = fun(removeIsProven { x: Rep[T] =>
+// val y = f(x);
+// y.value
+// })
+// val cost = fun(costingOf(f))
+// Pair(calc, cost)
+// }
+
+// def split3[T,R](f: Rep[T => Costed[R]]): Rep[(T => Any, (T => Int, T => Long))] = {
+// implicit val eT = f.elem.eDom
+// val calc = fun(removeIsProven { x: Rep[T] =>
+// val y = f(x);
+// y.value
+// })
+// val cost = fun(costingOf(f))
+// val size = fun(sizingOf(f))
+// Tuple(calc, cost, size)
+// }
def stypeToElem[T <: SType](t: T): Elem[T#WrappedType] = (t match {
case SBoolean => BooleanElement
@@ -669,13 +873,19 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
case SLong => LongElement
case SString => StringElement
case SAny => AnyElement
- case SBigInt => wBigIntegerElement
+ case SBigInt => bigIntElement
case SBox => boxElement
- case SGroupElement => wECPointElement
+ case SContext => contextElement
+ case SHeader => headerElement
+ case SPreHeader => preHeaderElement
+ case SGroupElement => groupElementElement
case SAvlTree => avlTreeElement
case SSigmaProp => sigmaPropElement
+ case STuple(Seq(a, b)) => pairElement(stypeToElem(a), stypeToElem(b))
case STuple(items) => tupleStructElement(items.map(stypeToElem(_)):_*)
- case c: SCollectionType[a] => colElement(stypeToElem(c.elemType))
+ case c: SCollectionType[a] => collElement(stypeToElem(c.elemType))
+ case o: SOption[a] => wOptionElement(stypeToElem(o.elemType))
+ case SFunc(Seq(tpeArg), tpeRange, Nil) => funcElement(stypeToElem(tpeArg), stypeToElem(tpeRange))
case _ => error(s"Don't know how to convert SType $t to Elem")
}).asElem[T#WrappedType]
@@ -687,27 +897,57 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
case LongElement => SLong
case StringElement => SString
case AnyElement => SAny
- case _: WBigIntegerElem[_] => SBigInt
- case _: WECPointElem[_] => SGroupElement
+ case _: BigIntElem[_] => SBigInt
+ case _: GroupElementElem[_] => SGroupElement
case _: AvlTreeElem[_] => SAvlTree
case oe: WOptionElem[_, _] => sigmastate.SOption(elemToSType(oe.eItem))
case _: BoxElem[_] => SBox
+ case _: ContextElem[_] => SContext
+ case _: HeaderElem[_] => SHeader
+ case _: PreHeaderElem[_] => SPreHeader
case _: SigmaPropElem[_] => SSigmaProp
case se: StructElem[_] =>
assert(se.fieldNames.zipWithIndex.forall { case (n,i) => n == s"_${i+1}" })
STuple(se.fieldElems.map(elemToSType(_)).toIndexedSeq)
- case ce: ColElem[_, _] => SCollection(elemToSType(ce.eItem))
+ case ce: CollElem[_, _] => SCollection(elemToSType(ce.eItem))
case fe: FuncElem[_, _] => SFunc(elemToSType(fe.eDom), elemToSType(fe.eRange))
case pe: PairElem[_, _] => STuple(elemToSType(pe.eFst), elemToSType(pe.eSnd))
case _ => error(s"Don't know how to convert Elem $e to SType")
}
+ def rtypeToElem(t: RType[_]): Elem[_] = t match {
+ case BooleanType => BooleanElement
+ case ByteType => ByteElement
+ case ShortType => ShortElement
+ case IntType => IntElement
+ case LongType => LongElement
+ case StringType => StringElement
+ case AnyType => AnyElement
+
+ case BigIntegerRType => wBigIntegerElement
+ case BigIntRType => bigIntElement
+
+ case ECPointRType => wECPointElement
+ case GroupElementRType => groupElementElement
+
+ case AvlTreeRType => avlTreeElement
+ case ot: OptionType[_] => wOptionElement(rtypeToElem(ot.tA))
+ case BoxRType => boxElement
+ case SigmaPropRType => sigmaPropElement
+ case tup: TupleType => tupleStructElement(tup.items.map(t => rtypeToElem(t)):_*)
+ case at: ArrayType[_] => wArrayElement(rtypeToElem(at.tA))
+ case ct: CollType[_] => collElement(rtypeToElem(ct.tItem))
+ case ft: FuncType[_,_] => funcElement(rtypeToElem(ft.tDom), rtypeToElem(ft.tRange))
+ case pt: PairType[_,_] => pairElement(rtypeToElem(pt.tFst), rtypeToElem(pt.tSnd))
+ case pvt: PrimViewType[_,_] => rtypeToElem(pvt.tVal)
+ case _ => sys.error(s"Don't know how to convert RType $t to Elem")
+ }
+
+
/** For a given data type returns the corresponding specific descendant of CostedElem[T] */
def elemToCostedElem[T](implicit e: Elem[T]): Elem[Costed[T]] = (e match {
- case e: AvlTreeElem[_] => costedAvlTreeElement
- case e: BoxElem[_] => costedBoxElement
case oe: WOptionElem[a,_] => costedOptionElement(oe.eItem)
- case ce: ColElem[a,_] => costedColElement(ce.eItem)
+ case ce: CollElem[a,_] => costedCollElement(ce.eItem)
case fe: FuncElem[_, _] => costedFuncElement(UnitElement, fe.eDom, fe.eRange)
case pe: PairElem[_, _] => costedPairElement(pe.eFst, pe.eSnd)
case _ => costedElement(e)
@@ -722,11 +962,22 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
case LongElement => LongIsLiftable
case StringElement => StringIsLiftable
case UnitElement => UnitIsLiftable
- case e: WBigIntegerElem[_] => LiftableBigInteger
- case e: WECPointElem[_] => LiftableECPoint
+ case e: BigIntElem[_] => LiftableBigInt
+ case e: GroupElementElem[_] => LiftableGroupElement
case ae: WArrayElem[t,_] =>
implicit val lt = liftableFromElem[t](ae.eItem)
liftableArray(lt)
+ case ce: CollElem[t,_] =>
+ implicit val lt = liftableFromElem[t](ce.eItem)
+ liftableColl(lt)
+ case pe: PairElem[a,b] =>
+ implicit val la = liftableFromElem[a](pe.eFst)
+ implicit val lb = liftableFromElem[b](pe.eSnd)
+ PairIsLiftable(la, lb)
+ case pe: FuncElem[a,b] =>
+ implicit val la = liftableFromElem[a](pe.eDom)
+ implicit val lb = liftableFromElem[b](pe.eRange)
+ FuncIsLiftable(la, lb)
}).asInstanceOf[Liftable[_,WT]]
import NumericOps._
@@ -735,21 +986,21 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
(ShortElement, numeric[Short]),
(IntElement, numeric[Int]),
(LongElement, numeric[Long]),
- (BigIntegerElement, numeric[BigInteger])
+ (bigIntElement, numeric[SBigInt])
)
private lazy val elemToIntegralMap = Map[Elem[_], Integral[_]](
(ByteElement, integral[Byte]),
(ShortElement, integral[Short]),
(IntElement, integral[Int]),
(LongElement, integral[Long]),
- (BigIntegerElement, integral[BigInteger])
+ (bigIntElement, integral[SBigInt])
)
private lazy val elemToOrderingMap = Map[Elem[_], Ordering[_]](
(ByteElement, implicitly[Ordering[Byte]]),
(ShortElement, implicitly[Ordering[Short]]),
(IntElement, implicitly[Ordering[Int]]),
(LongElement, implicitly[Ordering[Long]]),
- (BigIntegerElement, implicitly[Ordering[BigInteger]])
+ (bigIntElement, implicitly[Ordering[SBigInt]])
)
def elemToNumeric [T](e: Elem[T]): Numeric[T] = elemToNumericMap(e).asInstanceOf[Numeric[T]]
@@ -777,8 +1028,6 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
case _ => error(s"Cannot find BinOp for opcode $opCode")
}
- type RCosted[A] = Rep[Costed[A]]
-
/** This method works by:
* 1) staging block in the new scope of new thunk
* 2) extracting value, cost, or dataSize respectively
@@ -795,7 +1044,7 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
val s = Thunk.forced {
val costed = block
- costed.dataSize
+ costed.size
}
RCCostedPrim(v, c, s)
}
@@ -805,23 +1054,35 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
case _ => v
}
- /** Helper to create costed collection of bytes */
- def mkCostedCol[T](col: Rep[Col[T]], len: Rep[Int], cost: Rep[Int]): Rep[CostedCol[T]] = {
+ /** Helper to create costed collection of some constant size type T */
+ def mkCostedColl[T](col: Rep[Coll[T]], len: Rep[Int], cost: Rep[Int]): Rep[CostedColl[T]] = {
+ // TODO optimization: the method should be specialized on T so that mkSizePrim is not used
+ val eT = col.elem.eItem
val costs = colBuilder.replicate(len, 0)
- val sizes = colBuilder.replicate(len, typeSize(col.elem.eItem))
- RCCostedCol(col, costs, sizes, cost)
+ val sizes = colBuilder.replicate(len, costedBuilder.mkSizePrim(typeSize(eT), eT): RSize[T])
+ RCCostedColl(col, costs, sizes, cost)
}
+// def mkCostedColl[T](col: Rep[Coll[T]], cost: Rep[Int]): Rep[CostedColl[T]] = {
+// mkCostedColl(col, col.length, cost)
+// }
- def mkCosted[T](v: Rep[T], cost: Rep[Int], size: Rep[Long]): Rep[Costed[T]] = {
- val res = v.elem match {
- case colE: ColElem[a,_] =>
- val xs = asRep[Col[a]](v)
- mkCostedCol(xs, xs.length, cost)
- case _ =>
- RCCostedPrim(v, cost, size)
- }
- asRep[Costed[T]](res)
- }
+// def mkCosted[T](v: Rep[T], cost: Rep[Int], size: Rep[Long]): Rep[Costed[T]] = {
+// val res = v.elem match {
+// case colE: CollElem[a,_] =>
+// val xs = asRep[Coll[a]](v)
+// costedPrimToColl(xs, cost, size)
+// case _ =>
+// RCCostedPrim(v, cost, size)
+// }
+// asRep[Costed[T]](res)
+// }
+
+// def mkCostedOption[T](opt: Rep[WOption[T]], sizeOpt: Rep[WOption[Long]], cost: Rep[Int]): Rep[CostedOption[T]] = {
+// val costOpt = RWSpecialPredef.some(0)
+// RCCostedOption(opt, costOpt, sizeOpt, cost)
+// }
+
+ @inline final def asCosted[T](x: Rep[_]): Rep[Costed[T]] = x.asInstanceOf[Rep[Costed[T]]]
type CostingEnv = Map[Any, RCosted[_]]
@@ -835,27 +1096,65 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
protected def onTreeNodeCosted[T <: SType](
- ctx: Rep[CostedContext], env: CostingEnv,
+ ctx: RCosted[Context], env: CostingEnv,
node: Value[T], costed: RCosted[T#WrappedType]): Unit = {
if (okMeasureOperationTime && isOperationNode(node)) {
asRep[Any](costed) match {
case Def(CCostedPrimCtor(v, c, s)) =>
v.setMetadata(OperationIdKey)(node.opId)
- case Def(CCostedColCtor(vs,_,_,_)) =>
+ case Def(CCostedCollCtor(vs,_,_,_)) =>
vs.setMetadata(OperationIdKey)(node.opId)
case _ =>
}
}
}
- protected def evalNode[T <: SType](ctx: Rep[CostedContext], env: CostingEnv, node: Value[T]): RCosted[T#WrappedType] = {
+ @inline def SigmaDsl = sigmaDslBuilderValue
+ @inline def Colls = sigmaDslBuilderValue.Colls
+
+ def constantTypeSize[T](implicit eT: Elem[T]): RSize[T] = RCSizePrim(typeSize(eT), eT)
+
+ def withConstantSize[T](v: Rep[T], cost: Rep[Int]): RCosted[T] = RCCostedPrim(v, cost, constantTypeSize(v.elem))
+
+ def sizeOfData[ST,T](x: ST)(implicit lT: Liftable[ST,T]): RSize[T] = asRep[Size[T]](lT.sourceType match {
+ case BooleanType => liftConst(Sized.sizeOf(x.asInstanceOf[Boolean]))
+ case ByteType => liftConst(Sized.sizeOf(x.asInstanceOf[Byte]))
+ case ShortType => liftConst(Sized.sizeOf(x.asInstanceOf[Short]))
+ case IntType => liftConst(Sized.sizeOf(x.asInstanceOf[Int]))
+ case LongType => liftConst(Sized.sizeOf(x.asInstanceOf[Long]))
+ case BigIntRType => liftConst(Sized.sizeOf(x.asInstanceOf[SBigInt]))
+ case GroupElementRType => liftConst(Sized.sizeOf(x.asInstanceOf[SGroupElement]))
+ case AvlTreeRType => liftConst(Sized.sizeOf(x.asInstanceOf[SAvlTree]))
+ case SigmaPropRType => liftConst(Sized.sizeOf(x.asInstanceOf[SSigmaProp]))
+ case BoxRType => liftConst(Sized.sizeOf(x.asInstanceOf[SBox]))
+ case special.sigma.HeaderRType => liftConst(Sized.sizeOf(x.asInstanceOf[SHeader]))
+ case special.sigma.PreHeaderRType => liftConst(Sized.sizeOf(x.asInstanceOf[SPreHeader]))
+ case ct: CollType[a] =>
+ implicit val tA = ct.tItem
+ implicit val sizedA = Sized.typeToSized(tA)
+ liftConst(Sized.sizeOf(x.asInstanceOf[special.collection.Coll[a]]))
+ case ct: OptionType[a] =>
+ implicit val tA = ct.tA
+ implicit val sizedA = Sized.typeToSized(tA)
+ liftConst(Sized.sizeOf(x.asInstanceOf[Option[a]]))
+ case ct: PairType[a, b] =>
+ implicit val tA = ct.tFst
+ implicit val tB = ct.tSnd
+ implicit val sizedA = Sized.typeToSized(tA)
+ implicit val sizedB = Sized.typeToSized(tB)
+ liftConst(Sized.sizeOf(x.asInstanceOf[(a,b)]))
+ })
+
+ protected def evalNode[T <: SType](ctx: RCosted[Context], env: CostingEnv, node: Value[T]): RCosted[T#WrappedType] = {
import WOption._
-
def eval[T <: SType](node: Value[T]): RCosted[T#WrappedType] = evalNode(ctx, env, node)
- def withDefaultSize[T](v: Rep[T], cost: Rep[Int]): RCosted[T] = RCCostedPrim(v, cost, sizeOf(v))
object In { def unapply(v: SValue): Nullable[RCosted[Any]] = Nullable(asRep[Costed[Any]](evalNode(ctx, env, v))) }
- class InCol[T] { def unapply(v: SValue): Nullable[Rep[CostedCol[T]]] = Nullable(asRep[CostedCol[T]](evalNode(ctx, env, v))) }
- val InColByte = new InCol[Byte]; val InColAny = new InCol[Any]; val InColInt = new InCol[Int]
+ class InColl[T: Elem] { def unapply(v: SValue): Nullable[Rep[CostedColl[T]]] = Nullable(tryCast[CostedColl[T]](evalNode(ctx, env, v))) }
+ val InCollByte = new InColl[Byte]; val InCollAny = new InColl[Any]()(AnyElement); val InCollInt = new InColl[Int]
+
+ val InCollCollByte = new InColl[Coll[Byte]]
+ val InPairCollByte = new InColl[(Coll[Byte], Coll[Byte])]
+
object InSeq { def unapply(items: Seq[SValue]): Nullable[Seq[RCosted[Any]]] = {
val res = items.map { x: SValue =>
val xC = eval(x)
@@ -863,10 +1162,10 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
Nullable(res)
}}
- object InSeqUnzipped { def unapply(items: Seq[SValue]): Nullable[(Seq[Rep[Any]], Seq[Rep[Int]], Seq[Rep[Long]])] = {
+ object InSeqUnzipped { def unapply(items: Seq[SValue]): Nullable[(Seq[Rep[Any]], Seq[Rep[Int]], Seq[RSize[Any]])] = {
val res = items.mapUnzip { x: SValue =>
val xC = eval(x)
- (asRep[Any](xC.value), xC.cost, xC.dataSize)
+ (asRep[Any](xC.value), xC.cost, asRep[Size[Any]](xC.size))
}
Nullable(res)
}}
@@ -875,80 +1174,72 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
env.getOrElse(id, !!!(s"TaggedVariable $id not found in environment $env"))
case c @ Constant(v, tpe) => v match {
- case p: DLogProtocol.ProveDlog => eval(p)
- case p: ProveDHTuple => eval(p)
+ case st: SigmaBoolean =>
+ assert(tpe == SSigmaProp)
+ val p = SigmaDsl.SigmaProp(st)
+ val resV = liftConst(p)
+ RCCostedPrim(resV, costOfSigmaTree(st), SizeOfSigmaBoolean(st))
case bi: BigInteger =>
assert(tpe == SBigInt)
- val resV = liftConst(bi)
- RCCostedPrim(resV, costOf(c), SBigInt.MaxSizeInBytes)
- case ge: ECPoint =>
+ val resV = liftConst(sigmaDslBuilderValue.BigInt(bi))
+ withConstantSize(resV, costOf(c))
+ case p: ECPoint =>
assert(tpe == SGroupElement)
- val resV = liftConst(ge)
+ val resV = liftConst(sigmaDslBuilderValue.GroupElement(p): SGroupElement)
// val size = SGroupElement.dataSize(ge.asWrappedType)
- withDefaultSize(resV, costOf(c))
+ withConstantSize(resV, costOf(c))
case arr: Array[a] =>
+ val coll = Evaluation.toDslData(arr, tpe, false)(IR).asInstanceOf[SColl[a]]
val tpeA = tpe.asCollection[SType].elemType
stypeToElem(tpeA) match {
case eWA: Elem[wa] =>
implicit val l = liftableFromElem[wa](eWA).asInstanceOf[Liftable[a,wa]]
- val arrSym = liftConst[Array[a], WArray[wa]](arr)
- val resVals = colBuilder.fromArray(arrSym)
- val resCosts = colBuilder.replicate(arrSym.length, 0)
+ val resVals = liftConst[SColl[a], Coll[wa]](coll)
+ val resCosts = liftConst(Colls.replicate(coll.length, 0))
val resSizes =
if (tpeA.isConstantSize)
- colBuilder.replicate(resVals.length, typeSize(tpeA))
+ colBuilder.replicate(coll.length, constantTypeSize(eWA))
else {
- val sizesConst: Array[Long] = arr.map { x: a => tpeA.dataSize(x.asWrappedType) }
- val sizesArr = liftConst(sizesConst)
- colBuilder.fromArray(sizesArr)
+ implicit val ewa = eWA
+ tryCast[SizeColl[wa]](sizeOfData[SColl[a], Coll[wa]](coll)).sizes
}
- RCCostedCol(resVals, resCosts, resSizes, costOf(c))
+ RCCostedColl(resVals, resCosts, resSizes, costOf(c))
}
- case box: ErgoBox =>
- val boxV = liftConst(box.toTestBox(false)(IR))
- RCCostedBox(boxV, costOf(c))
+ case ergoBox: ErgoBox =>
+ val box = ergoBox.toTestBox(false)(IR)
+ val boxV = liftConst(box)
+ RCCostedPrim(boxV, costOf(c), sizeOfData(box))
case treeData: AvlTreeData =>
- val tree: special.sigma.AvlTree = CostingAvlTree(IR, treeData)
+ val tree: special.sigma.AvlTree = CAvlTree(treeData)
val treeV = liftConst(tree)
- RCCostedAvlTree(treeV, costOf(c))
+ RCCostedPrim(treeV, costOf(c), SizeAvlTree)
+ case s: String =>
+ val resV = toRep(s)(stypeToElem(tpe).asElem[String])
+ RCCostedPrim(resV, costOf(c), SizeString)
case _ =>
val resV = toRep(v)(stypeToElem(tpe))
- withDefaultSize(resV, costOf(c))
+ withConstantSize(resV, costOf(c))
}
- case _ @ DLogProtocol.ProveDlog(v) =>
- val ge = asRep[Costed[WECPoint]](eval(v))
- val resV: Rep[SigmaProp] = RProveDlogEvidence(ge.value)
- RCCostedPrim(resV, ge.cost + costOfProveDlog, CryptoConstants.groupSize.toLong)
-
- case _ @ ProveDHTuple(gv, hv, uv, vv) =>
- val gvC = asRep[Costed[WECPoint]](eval(gv))
- val hvC = asRep[Costed[WECPoint]](eval(hv))
- val uvC = asRep[Costed[WECPoint]](eval(uv))
- val vvC = asRep[Costed[WECPoint]](eval(vv))
- val resV: Rep[SigmaProp] = RProveDHTEvidence(gvC.value, hvC.value, uvC.value, vvC.value)
- val cost = gvC.cost + hvC.cost + uvC.cost + vvC.cost + costOfDHTuple
- RCCostedPrim(resV, cost, CryptoConstants.groupSize.toLong * 4)
-
- case Height => ctx.HEIGHT
- case Inputs => ctx.INPUTS
- case Outputs => ctx.OUTPUTS
- case Self => ctx.SELF
- case LastBlockUtxoRootHash => ctx.LastBlockUtxoRootHash
- case MinerPubkey => ctx.MinerPubKey
+ case org.ergoplatform.Context => ctx
+ case Height => ContextCoster(ctx, SContext.heightMethod, Nil)
+ case Inputs => ContextCoster(ctx, SContext.inputsMethod, Nil)
+ case Outputs => ContextCoster(ctx, SContext.outputsMethod, Nil)
+ case Self => ContextCoster(ctx, SContext.selfMethod, Nil)
+ case LastBlockUtxoRootHash => ContextCoster(ctx, SContext.lastBlockUtxoRootHashMethod, Nil)
+ case MinerPubkey => ContextCoster(ctx, SContext.minerPubKeyMethod, Nil)
case op @ GetVar(id, optTpe) =>
- val res = ctx.getVar(id)(stypeToElem(optTpe.elemType))
- res
-
-// case op @ TaggedVariableNode(id, tpe) =>
-// val resV = ctx.getVar(id)(stypeToElem(tpe))
-// withDefaultSize(resV, costOf(op))
+ stypeToElem(optTpe.elemType) match { case e: Elem[t] =>
+ val v = ctx.value.getVar[t](id)(e)
+ val s = tryCast[SizeContext](ctx.size).getVar(id)(e)
+ RCCostedPrim(v, sigmaDslBuilder.CostModel.GetVar, s)
+ }
case Terms.Block(binds, res) =>
var curEnv = env
- for (Val(n, _, b) <- binds) {
- if (curEnv.contains(n)) error(s"Variable $n already defined ($n = ${curEnv(n)}")
+ for (v @ Val(n, _, b) <- binds) {
+ if (curEnv.contains(n)) error(s"Variable $n already defined ($n = ${curEnv(n)}", v.sourceContext.toOption)
val bC = evalNode(ctx, curEnv, b)
curEnv = curEnv + (n -> bC)
}
@@ -957,8 +1248,8 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
case BlockValue(binds, res) =>
var curEnv = env
- for (ValDef(n, _, b) <- binds) {
- if (curEnv.contains(n)) error(s"Variable $n already defined ($n = ${curEnv(n)}")
+ for (vd @ ValDef(n, _, b) <- binds) {
+ if (curEnv.contains(n)) error(s"Variable $n already defined ($n = ${curEnv(n)}", vd.sourceContext.toOption)
val bC = evalNode(ctx, curEnv, b)
curEnv = curEnv + (n -> bC)
}
@@ -968,121 +1259,140 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
case ValUse(valId, _) =>
env.getOrElse(valId, !!!(s"ValUse $valId not found in environment $env"))
+ case CreateProveDlog(In(_v)) =>
+ val vC = asRep[Costed[GroupElement]](_v)
+ val resV: Rep[SigmaProp] = sigmaDslBuilder.proveDlog(vC.value)
+ val cost = opCost(Seq(vC.cost), costOfDHTuple)
+ RCCostedPrim(resV, cost, mkSizeSigmaProp(vC.size.dataSize))
+
+ case CreateProveDHTuple(In(_gv), In(_hv), In(_uv), In(_vv)) =>
+ val gvC = asRep[Costed[GroupElement]](_gv)
+ val hvC = asRep[Costed[GroupElement]](_hv)
+ val uvC = asRep[Costed[GroupElement]](_uv)
+ val vvC = asRep[Costed[GroupElement]](_vv)
+ val resV: Rep[SigmaProp] = sigmaDslBuilder.proveDHTuple(gvC.value, hvC.value, uvC.value, vvC.value)
+ val cost = opCost(Seq(gvC.cost, hvC.cost, uvC.cost, vvC.cost), costOfDHTuple)
+ RCCostedPrim(resV, cost, mkSizeSigmaProp(gvC.size.dataSize * 4L))
+
case sigmastate.Exponentiate(In(_l), In(_r)) =>
- val l = asRep[Costed[WECPoint]](_l)
- val r = asRep[Costed[WBigInteger]](_r)
- val value = sigmaDslBuilder.exponentiate(l.value, r.value)
- val cost = l.cost + r.cost + costOf(node)
- RCCostedPrim(value, cost, CryptoConstants.groupSize.toLong)
+ val l = asRep[Costed[GroupElement]](_l)
+ val r = asRep[Costed[BigInt]](_r)
+ val value = l.value.exp(r.value)
+ val cost = opCost(Seq(l.cost, r.cost), costOf(node))
+ RCCostedPrim(value, cost, SizeGroupElement)
case sigmastate.MultiplyGroup(In(_l), In(_r)) =>
- val l = asRep[Costed[WECPoint]](_l)
- val r = asRep[Costed[WECPoint]](_r)
- val value = l.value.add(r.value)
- val cost = l.cost + r.cost + costOf(node)
- RCCostedPrim(value, cost, CryptoConstants.groupSize.toLong)
+ val l = asRep[Costed[GroupElement]](_l)
+ val r = asRep[Costed[GroupElement]](_r)
+ val value = l.value.multiply(r.value)
+ val cost = opCost(Seq(l.cost, r.cost), costOf(node))
+ RCCostedPrim(value, cost, SizeGroupElement)
case Values.GroupGenerator =>
val value = sigmaDslBuilder.groupGenerator
- RCCostedPrim(value, costOf(node), CryptoConstants.groupSize.toLong)
+ RCCostedPrim(value, opCost(Nil, costOf(node)), SizeGroupElement)
case sigmastate.ByteArrayToBigInt(In(_arr)) =>
- val arrC = asRep[Costed[Col[Byte]]](_arr)
+ val arrC = asRep[Costed[Coll[Byte]]](_arr)
val arr = arrC.value
val value = sigmaDslBuilder.byteArrayToBigInt(arr)
- val size = arrC.dataSize
- val cost = arrC.cost + costOf(node) + costOf("new_BigInteger_per_item", node.opType) * size.toInt
- RCCostedPrim(value, cost, size)
+ val size = arrC.size.dataSize
+ val cost = opCost(Seq(arrC.cost), costOf(node) + costOf("new_BigInteger_per_item", node.opType) * size.toInt)
+ RCCostedPrim(value, cost, SizeBigInt)
case sigmastate.LongToByteArray(In(_x)) =>
val xC = asRep[Costed[Long]](_x)
- val x = xC.value
- val col = sigmaDslBuilder.longToByteArray(x) // below we assume col.length == typeSize[Long]
- val cost = xC.cost + costOf(node)
- val len = typeSize[Long].toInt
- mkCostedCol(col, len, cost)
-
- case TreeLookup(In(_tree), InColByte(key), InColByte(proof)) =>
- val tree = asRep[CostedAvlTree](_tree)
- val value = sigmaDslBuilder.treeLookup(tree.value, key.value, proof.value)
- val size = tree.dataSize + key.dataSize + proof.dataSize
- val cost = tree.cost + key.cost + proof.cost + perKbCostOf(node, size)
- value.fold[CostedOption[Col[Byte]]](
- Thunk(RCostedNone(cost)),
- fun { x: Rep[Col[Byte]] => RCostedSome(mkCostedCol(x, size.toInt, cost)) })
-
- case TreeModifications(In(_tree), InColByte(operations), InColByte(proof)) =>
- val tree = asRep[CostedAvlTree](_tree)
- val value = sigmaDslBuilder.treeModifications(tree.value, operations.value, proof.value)
- val size = tree.dataSize + operations.dataSize + proof.dataSize
- val cost = tree.cost + operations.cost + proof.cost + perKbCostOf(node, size)
- value.fold[CostedOption[Col[Byte]]](
- Thunk(RCostedNone(cost)),
- fun { x: Rep[Col[Byte]] => RCostedSome(mkCostedCol(x, size.toInt, cost)) })
+ val col = sigmaDslBuilder.longToByteArray(xC.value) // below we assume col.length == typeSize[Long]
+ val cost = opCost(Seq(xC.cost), costOf(node))
+ val len = SizeLong.dataSize.toInt
+ mkCostedColl(col, len, cost)
// opt.get =>
case utxo.OptionGet(In(_opt)) =>
- val opt = asRep[CostedOption[Any]](_opt)
- opt.get
+ OptionCoster(_opt, SOption.GetMethod, Nil)
// opt.isDefined =>
case utxo.OptionIsDefined(In(_opt)) =>
- val opt = asRep[CostedOption[Any]](_opt)
- opt.isDefined
+ OptionCoster(_opt, SOption.IsDefinedMethod, Nil)
// opt.getOrElse =>
case utxo.OptionGetOrElse(In(_opt), In(_default)) =>
- val opt = asRep[CostedOption[Any]](_opt)
- opt.getOrElse(_default)
+ OptionCoster(_opt, SOption.GetOrElseMethod, Seq(_default))
case SelectField(In(_tup), fieldIndex) =>
_tup.elem.eVal.asInstanceOf[Elem[_]] match {
case se: StructElem[_] =>
val tup = asRep[Costed[Struct]](_tup)
- val fn = STuple.componentNames(fieldIndex - 1)
- withDefaultSize(tup.value.getUntyped(fn), costedBuilder.SelectFieldCost)
+ val fn = STuple.componentNameByIndex(fieldIndex - 1)
+ val v = tup.value.getUntyped(fn)
+ val c = opCost(Seq(tup.cost), costedBuilder.SelectFieldCost)
+ val s: RSize[Any] = ??? //asRep[SizeStruct](tup.size).sizeFi.getUntyped(fn)
+ RCCostedPrim(v, c, s)
case pe: PairElem[a,b] =>
assert(fieldIndex == 1 || fieldIndex == 2, s"Invalid field index $fieldIndex of the pair ${_tup}: $pe")
- val pair = asRep[CostedPair[a,b]](_tup)
+ implicit val ea = pe.eFst
+ implicit val eb = pe.eSnd
+ val pair = tryCast[CostedPair[a,b]](_tup)
val res = if (fieldIndex == 1) pair.l else pair.r
res
}
+ case Values.Tuple(InSeq(Seq(x, y))) =>
+ RCCostedPair(x, y, opCost(Seq(x.cost, y.cost), CostTable.newPairValueCost))
+
case Values.Tuple(InSeq(items)) =>
val fields = items.zipWithIndex.map { case (x, i) => (s"_${i+1}", x)}
- RCostedStruct(struct(fields), costedBuilder.ConstructTupleCost)
+ val cost = opCost(items.map(_.cost), costedBuilder.ConstructTupleCost)
+ RCostedStruct(struct(fields), cost)
case node: BooleanTransformer[_] =>
val eIn = stypeToElem(node.input.tpe.elemType)
- val xs = asRep[CostedCol[Any]](eval(node.input))
- val eAny = xs.elem.asInstanceOf[CostedElem[Col[Any],_]].eVal.eA
+ val xs = asRep[CostedColl[Any]](eval(node.input))
+ val eAny = xs.elem.asInstanceOf[CostedElem[Coll[Any],_]].eVal.eA
assert(eIn == eAny, s"Types should be equal: but $eIn != $eAny")
- implicit val eArg: Elem[Costed[Any]] = eAny match {
- case _: BoxElem[_] => element[CostedBox].asElem[Costed[Any]]
- case _ => costedElement(eAny)
- }
- val condC = asRep[CostedFunc[Unit, Any, SType#WrappedType]](evalNode(ctx, env, node.condition)).func
+ implicit val eArg: Elem[Costed[Any]] = costedElement(eAny)
+ val conditionC = asRep[CostedFunc[Unit, Any, SType#WrappedType]](evalNode(ctx, env, node.condition))
+ val condC = conditionC.func
val (calcF, costF) = splitCostedFunc2(condC, okRemoveIsValid = true)
+ val sizeF = condC.sliceSize
val values = xs.values.map(calcF)
- val cost = xs.values.zip(xs.costs.zip(xs.sizes)).map(costF).sum(intPlusMonoid)
- val value = calcF.elem.eRange match {
+// val mRes = AllMarking(element[Int])
+// val mCostF = sliceAnalyzer.analyzeFunc(costF, mRes)
+// val cost = mCostF.mDom match {
+// case PairMarking(markA,_) if markA.isEmpty => // no dependency on values
+// val slicedCostF = fun { in: Rep[(Int, Long)] => costF(Pair(variable[Any](Lazy(eAny)), in)) }
+ val cost = xs.costs.zip(xs.sizes).map(costF).sum(intPlusMonoid)
+// case _ =>
+// xs.values.zip(xs.costs.zip(xs.sizes)).map(costF).sum(intPlusMonoid)
+// }
+ val res = calcF.elem.eRange match {
case e if e == BooleanElement =>
node match {
- case _: ForAll[_] => xs.values.forall(asRep[Any => Boolean](calcF))
- case _: Exists[_] => xs.values.exists(asRep[Any => Boolean](calcF))
+ case _: ForAll[_] =>
+ val value = xs.values.forall(asRep[Any => Boolean](calcF))
+ withConstantSize(value, cost)
+ case _: Exists[_] =>
+ val value = xs.values.exists(asRep[Any => Boolean](calcF))
+ withConstantSize(value, cost)
}
case _: SigmaPropElem[_] =>
- if (node.isInstanceOf[ForAll[_]])
- sigmaDslBuilder.allZK(asRep[Col[SigmaProp]](values))
- else
- sigmaDslBuilder.anyZK(asRep[Col[SigmaProp]](values))
+ node match {
+ case _: ForAll[_] =>
+ val children = asRep[Coll[SigmaProp]](values)
+ val size = mkSizeSigmaProp(CryptoConstants.EncodedGroupElementLength.toLong)
+ RCCostedPrim(sigmaDslBuilder.allZK(children), cost, size)
+ case _: Exists[_] =>
+ val children = asRep[Coll[SigmaProp]](values)
+ val size = mkSizeSigmaProp(CryptoConstants.EncodedGroupElementLength.toLong)
+ RCCostedPrim(sigmaDslBuilder.anyZK(children), cost, size)
+ }
}
- withDefaultSize(value, cost)
+ res
case MapCollection(input, sfunc) =>
val eIn = stypeToElem(input.tpe.elemType)
- val inputC = asRep[CostedCol[Any]](evalNode(ctx, env, input))
- implicit val eAny = inputC.elem.asInstanceOf[CostedElem[Col[Any], _]].eVal.eA
+ val inputC = asRep[CostedColl[Any]](evalNode(ctx, env, input))
+ implicit val eAny = inputC.elem.asInstanceOf[CostedElem[Coll[Any], _]].eVal.eA
assert(eIn == eAny, s"Types should be equal: but $eIn != $eAny")
val mapperC = asRep[CostedFunc[Unit, Any, SType#WrappedType]](evalNode(ctx, env, sfunc)).func
val res = inputC.mapCosted(mapperC)
@@ -1092,8 +1402,8 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
val eItem = stypeToElem(input.tpe.elemType)
val eState = stypeToElem(zero.tpe)
(eState, eItem) match { case (eState: Elem[s], eItem: Elem[a]) =>
- val inputC = asRep[CostedCol[a]](eval(input))
- implicit val eA = inputC.elem.asInstanceOf[CostedElem[Col[a],_]].eVal.eA
+ val inputC = asRep[CostedColl[a]](eval(input))
+ implicit val eA = inputC.elem.asInstanceOf[CostedElem[Coll[a],_]].eVal.eA
assert(eItem == eA, s"Types should be equal: but $eItem != $eA")
val zeroC = asRep[Costed[s]](eval(zero))
@@ -1115,30 +1425,30 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
}
case op @ Slice(In(input), In(from), In(until)) =>
- val inputC = asRep[CostedCol[Any]](input)
+ val inputC = asRep[CostedColl[Any]](input)
val fromC = asRep[Costed[Int]](from)
val untilC = asRep[Costed[Int]](until)
val f = fromC.value
val u = untilC.value
val vals = inputC.values.slice(f, u)
- val costs = inputC.costs.slice(f, u)
- val sizes = inputC.sizes.slice(f, u)
- RCCostedCol(vals, costs, sizes, inputC.valuesCost + costOf(op))
+ val costs = inputC.costs
+ val sizes = inputC.sizes
+ RCCostedColl(vals, costs, sizes, opCost(Seq(inputC.valuesCost), costOf(op)))
case Append(In(_col1), In(_col2)) =>
- val col1 = asRep[CostedCol[Any]](_col1)
- val col2 = asRep[CostedCol[Any]](_col2)
+ val col1 = asRep[CostedColl[Any]](_col1)
+ val col2 = asRep[CostedColl[Any]](_col2)
val values = col1.values.append(col2.values)
val costs = col1.costs.append(col2.costs)
val sizes = col1.sizes.append(col2.sizes)
- RCCostedCol(values, costs, sizes, costOf(node))
+ RCCostedColl(values, costs, sizes, opCost(Seq(col1.cost, col2.cost), costOf(node)))
case Terms.Apply(Select(col, "where", _), Seq(Terms.Lambda(_, Seq((n, t)), _, Some(body)))) =>
val input = col.asValue[SCollection[SType]]
val cond = body.asValue[SBoolean.type]
val eIn = stypeToElem(input.tpe.elemType)
- val inputC = asRep[CostedCol[Any]](evalNode(ctx, env, input))
- implicit val eAny = inputC.elem.asInstanceOf[CostedElem[Col[Any],_]].eVal.eA
+ val inputC = asRep[CostedColl[Any]](evalNode(ctx, env, input))
+ implicit val eAny = inputC.elem.asInstanceOf[CostedElem[Coll[Any],_]].eVal.eA
assert(eIn == eAny, s"Types should be equal: but $eIn != $eAny")
val condC = fun { x: Rep[Costed[Any]] =>
evalNode(ctx, env + (n -> x), cond)
@@ -1156,126 +1466,137 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
case Terms.Apply(f, Seq(x)) if f.tpe.isFunc =>
val fC = asRep[CostedFunc[Unit, Any, Any]](evalNode(ctx, env, f))
val xC = asRep[Costed[Any]](evalNode(ctx, env, x))
- if (f.tpe.asFunc.tRange.isCollection) {
- val (calcF, costF, sizeF) = splitCostedColFunc(asRep[CostedColFunc[Any,Any]](fC.func))
- val value = xC.value
- val values: Rep[Col[Any]] = Apply(calcF, value, false)
- val costRes: Rep[(Col[Int], Int)] = Apply(costF, Pair(value, Pair(xC.cost, xC.dataSize)), false)
- val sizes: Rep[Col[Long]]= Apply(sizeF, Pair(value, xC.dataSize), false)
- RCCostedCol(values, costRes._1, sizes, costRes._2)
- }
- else {
- val (calcF, costF, sizeF) = splitCostedFunc(fC.func)
- val value = xC.value
- val y: Rep[Any] = Apply(calcF, value, false)
- val c: Rep[Int] = Apply(costF, Pair(value, Pair(xC.cost, xC.dataSize)), false)
- val s: Rep[Long]= Apply(sizeF, xC.dataSize, false)
- RCCostedPrim(y, c, s)
+ f.tpe.asFunc.tRange match {
+ case _: SCollectionType[_] =>
+ val (calcF, costF, sizeF) = splitCostedCollFunc(asRep[CostedCollFunc[Any,Any]](fC.func))
+ val value = xC.value
+ val values: RColl[Any] = Apply(calcF, value, false)
+ val costRes: Rep[(Coll[Int], Int)] = Apply(costF, Pair(xC.cost, xC.size), false)
+ val sizes: RColl[Size[Any]] = Apply(sizeF, xC.size, false)
+ RCCostedColl(values, costRes._1, sizes, costRes._2)
+// case optTpe: SOption[_] =>
+// val (calcF, costF, sizeF) = splitCostedOptionFunc(asRep[CostedOptionFunc[Any,Any]](fC.func))
+// val value = xC.value
+// val values: Rep[WOption[Any]] = Apply(calcF, value, false)
+// val costRes: Rep[(WOption[Int], Int)] = Apply(costF, Pair(value, Pair(xC.cost, xC.dataSize)), false)
+// val sizes: Rep[WOption[Long]]= Apply(sizeF, Pair(value, xC.dataSize), false)
+// RCCostedOption(values, costRes._1, sizes, costRes._2)
+ case _ =>
+ val (calcF, costF, sizeF) = splitCostedFunc(fC.func)
+ val value = xC.value
+ val y: Rep[Any] = Apply(calcF, value, false)
+ val c: Rep[Int] = opCost(Seq(fC.cost, xC.cost), Apply(costF, Pair(xC.cost, xC.size), false))
+ val s: Rep[Size[Any]]= Apply(sizeF, xC.size, false)
+ RCCostedPrim(y, c, s)
}
case opt: OptionValue[_] =>
- error(s"Option constructors are not supported: $opt")
+ error(s"Option constructors are not supported: $opt", opt.sourceContext.toOption)
case CalcBlake2b256(In(input)) =>
- val bytesC = asRep[Costed[Col[Byte]]](input)
+ val bytesC = asRep[Costed[Coll[Byte]]](input)
val res = sigmaDslBuilder.blake2b256(bytesC.value)
- val cost = bytesC.cost + perKbCostOf(node, bytesC.dataSize)
- mkCostedCol(res, Blake2b256.DigestSize, cost)
+ val cost = opCost(Seq(bytesC.cost), perKbCostOf(node, bytesC.size.dataSize))
+ mkCostedColl(res, Blake2b256.DigestSize, cost)
case CalcSha256(In(input)) =>
- val bytesC = asRep[Costed[Col[Byte]]](input)
+ val bytesC = asRep[Costed[Coll[Byte]]](input)
val res = sigmaDslBuilder.sha256(bytesC.value)
- val cost = bytesC.cost + perKbCostOf(node, bytesC.dataSize)
- mkCostedCol(res, Sha256.DigestSize, cost)
+ val cost = opCost(Seq(bytesC.cost), perKbCostOf(node, bytesC.size.dataSize))
+ mkCostedColl(res, Sha256.DigestSize, cost)
case utxo.SizeOf(In(xs)) =>
xs.elem.eVal match {
- case ce: ColElem[a,_] =>
- val xsC = asRep[Costed[Col[a]]](xs)
+ case ce: CollElem[a,_] =>
+ val xsC = asRep[Costed[Coll[a]]](xs)
val v = xsC.value.length
- withDefaultSize(v, xsC.cost + costOf(node))
+ RCCostedPrim(v, opCost(Seq(xsC.cost), costOf(node)), SizeInt)
case se: StructElem[_] =>
val xsC = asRep[Costed[Struct]](xs)
- withDefaultSize(se.fields.length, xsC.cost + costOf(node))
+ RCCostedPrim(se.fields.length, opCost(Seq(xsC.cost), costOf(node)), SizeInt)
}
case ByIndex(xs, i, default) =>
- val xsC = asRep[CostedCol[Any]](eval(xs))
+ val xsC = asRep[CostedColl[Any]](eval(xs))
val iC = asRep[Costed[Int]](eval(i))
val iV = iC.value
- val size = xsC.sizes(iV)
+ val size = xsC.sizes(iV) // TO
default match {
case Some(defaultValue) =>
val defaultC = asRep[Costed[Any]](eval(defaultValue))
val default = defaultC.value
val value = xsC.value.getOrElse(iV, default)
- val cost = xsC.cost + iC.cost + defaultC.cost + costOf(node)
+ val cost = opCost(Seq(xsC.cost, iC.cost, defaultC.cost), costOf(node))
RCCostedPrim(value, cost, size)
case None =>
- RCCostedPrim(xsC.value(iV), xsC.cost + iC.cost + costOf(node), size)
+ RCCostedPrim(xsC.value(iV), opCost(Seq(xsC.cost, iC.cost), costOf(node)), size)
}
case SigmaPropIsProven(p) =>
val pC = asRep[Costed[SigmaProp]](eval(p))
val v = pC.value.isValid
- val c = pC.cost + costOf(node)
- val s = pC.dataSize // NOTE: we pass SigmaProp's size, this is handled in buildCostedGraph
- RCCostedPrim(v, c, s)
+ val c = opCost(Seq(pC.cost), costOf(node))
+// val s = pC.size // NOTE: we pass SigmaProp's size, this is handled in buildCostedGraph
+ RCCostedPrim(v, c, SizeBoolean)
case SigmaPropBytes(p) =>
val pC = asRep[Costed[SigmaProp]](eval(p))
val v = pC.value.propBytes
- withDefaultSize(v, pC.cost + costOf(node))
+ mkCostedColl(v, pC.size.dataSize.toInt, opCost(Seq(pC.cost), costOf(node)))
- case utxo.ExtractId(In(box)) => // TODO costing: use special CostedColFixed for fixed-size collections
+ case utxo.ExtractId(In(box)) => // TODO costing: use special CostedCollFixed for fixed-size collections
val boxC = asRep[Costed[Box]](box)
val id = boxC.value.id
- mkCostedCol(id, Blake2b256.DigestSize, boxC.cost + costOf(node))
+ mkCostedColl(id, Blake2b256.DigestSize, opCost(Seq(boxC.cost), costOf(node)))
case utxo.ExtractBytesWithNoRef(In(box)) =>
val boxC = asRep[Costed[Box]](box)
- mkCostedCol(boxC.value.bytesWithoutRef, ErgoBox.MaxBoxSize, boxC.cost + costOf(node))
+ val sBox = tryCast[SizeBox](boxC.size)
+ mkCostedColl(boxC.value.bytesWithoutRef, sBox.bytesWithoutRef.dataSize.toInt, opCost(Seq(boxC.cost), costOf(node)))
case utxo.ExtractAmount(In(box)) =>
val boxC = asRep[Costed[Box]](box)
- withDefaultSize(boxC.value.value, boxC.cost + costOf(node))
+ withConstantSize(boxC.value.value, opCost(Seq(boxC.cost), costOf(node)))
case utxo.ExtractScriptBytes(In(box)) =>
val boxC = asRep[Costed[Box]](box)
+ val sBox = tryCast[SizeBox](boxC.size)
val bytes = boxC.value.propositionBytes
- mkCostedCol(bytes, ErgoBox.MaxBoxSize, boxC.cost + costOf(node))
+ mkCostedColl(bytes, sBox.propositionBytes.dataSize.toInt, opCost(Seq(boxC.cost), costOf(node)))
case utxo.ExtractBytes(In(box)) =>
val boxC = asRep[Costed[Box]](box)
+ val sBox = tryCast[SizeBox](boxC.size)
val bytes = boxC.value.bytes
- mkCostedCol(bytes, ErgoBox.MaxBoxSize, boxC.cost + costOf(node))
+ mkCostedColl(bytes, sBox.bytes.dataSize.toInt, opCost(Seq(boxC.cost), costOf(node)))
case utxo.ExtractCreationInfo(In(box)) =>
- val boxC = asRep[CostedBox](box)
- boxC.creationInfo
+ BoxCoster(box, SBox.creationInfoMethod, Nil)
case utxo.ExtractRegisterAs(In(box), regId, optTpe) =>
- val boxC = asRep[CostedBox](box)
+ val boxC = asRep[Costed[Box]](box)
+ val sBox = asSizeBox(boxC.size)
implicit val elem = stypeToElem(optTpe.elemType).asElem[Any]
- val valueOpt = boxC.getReg(regId.number.toInt)(elem)
- valueOpt
+ val valueOpt = boxC.value.getReg(regId.number.toInt)(elem)
+ val sReg = asSizeOption(sBox.getReg(regId.number)(elem))
+ RCCostedOption(valueOpt, SOME(0), sReg.sizeOpt, opCost(Seq(boxC.cost), sigmaDslBuilder.CostModel.GetRegister))
case BoolToSigmaProp(bool) =>
val boolC = eval(bool)
val value = sigmaDslBuilder.sigmaProp(boolC.value)
- RCCostedPrim(value, boolC.cost + costOf(node), 1L)
+ RCCostedPrim(value, opCost(Seq(boolC.cost), costOf(node)), mkSizeSigmaProp(1L))
case AtLeast(bound, input) =>
- val inputC = asRep[CostedCol[Any]](evalNode(ctx, env, input))
+ val inputC = asRep[CostedColl[SigmaProp]](evalNode(ctx, env, input))
if (inputC.values.length.isConst) {
val inputCount = inputC.values.length.asValue
if (inputCount > AtLeast.MaxChildrenCount)
- error(s"Expected input elements count should not exceed ${AtLeast.MaxChildrenCount}, actual: $inputCount")
+ error(s"Expected input elements count should not exceed ${AtLeast.MaxChildrenCount}, actual: $inputCount", node.sourceContext.toOption)
}
val boundC = eval(bound)
- val res = sigmaDslBuilder.atLeast(boundC.value, asRep[Col[SigmaProp]](inputC.values))
- val cost = boundC.cost + inputC.cost + costOf(node)
- RCCostedPrim(res, cost, CryptoConstants.groupSize.toLong)
+ val res = sigmaDslBuilder.atLeast(boundC.value, inputC.values)
+ val cost = opCost(Seq(boundC.cost, inputC.cost), costOf(node))
+ val sInput = tryCast[SizeColl[SigmaProp]](inputC.size)
+ RCCostedPrim(res, cost, mkSizeSigmaProp(sInput.dataSize))
case op: ArithOp[t] if op.tpe == SBigInt =>
import OpCodes._
- val xC = asRep[Costed[WBigInteger]](eval(op.left))
- val yC = asRep[Costed[WBigInteger]](eval(op.right))
+ val xC = asRep[Costed[BigInt]](eval(op.left))
+ val yC = asRep[Costed[BigInt]](eval(op.right))
val opName = op.opName
- var v: Rep[WBigInteger] = null;
- val s: Rep[Long] = SBigInt.MaxSizeInBytes
+ var v: Rep[BigInt] = null;
op.opCode match {
case PlusCode =>
v = xC.value.add(yC.value)
@@ -1291,10 +1612,10 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
v = xC.value.min(yC.value)
case MaxCode =>
v = xC.value.max(yC.value)
- case code => error(s"Cannot perform Costing.evalNode($op): unknown opCode ${code}")
+ case code => error(s"Cannot perform Costing.evalNode($op): unknown opCode ${code}", op.sourceContext.toOption)
}
- val c = xC.cost + yC.cost + costOf(op)
- RCCostedPrim(v, c, s)
+ val c = opCost(Seq(xC.cost, yC.cost), costOf(op))
+ RCCostedPrim(v, c, SizeBigInt)
case op: ArithOp[t] =>
val tpe = op.left.tpe
@@ -1303,83 +1624,123 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
val x = evalNode(ctx, env, op.left)
val y = evalNode(ctx, env, op.right)
(x, y) match { case (x: RCosted[a], y: RCosted[b]) =>
- withDefaultSize(ApplyBinOp(binop, x.value, y.value), x.cost + y.cost + costOf(op))
+ withConstantSize(ApplyBinOp(binop, x.value, y.value), opCost(Seq(x.cost, y.cost), costOf(op)))
}
-// case ModQ(input) =>
-// val inputC = asRep[Costed[WBigInteger]](eval(input))
-// val v = inputC.value.modQ
-// RCCostedPrim(v, inputC.cost + costOf(node), SBigInt.MaxSizeInBytes)
+ case LogicalNot(input) =>
+ val inputC = evalNode(ctx, env, input)
+ withConstantSize(ApplyUnOp(Not, inputC.value), opCost(Seq(inputC.cost), costOf(node)))
+
+ case ModQ(input) =>
+ val inputC = asRep[Costed[BigInt]](eval(input))
+ val v = inputC.value.modQ
+ RCCostedPrim(v, opCost(Seq(inputC.cost), costOf(node)), SizeBigInt)
case OR(input) => input match {
case ConcreteCollection(items, tpe) =>
val itemsC = items.map(item => eval(adaptSigmaBoolean(item)))
val res = sigmaDslBuilder.anyOf(colBuilder.fromItems(itemsC.map(_.value): _*))
- val costs = colBuilder.fromItems(itemsC.map(_.cost): _*)
- val cost = costs.sum(intPlusMonoid) + perItemCostOf(node, costs.length)
- withDefaultSize(res, cost)
+ val costs = itemsC.map(_.cost)
+ val cost = opCost(costs, perItemCostOf(node, costs.length))
+ withConstantSize(res, cost)
case _ =>
- val inputC = asRep[CostedCol[Boolean]](eval(input))
+ val inputC = asRep[CostedColl[Boolean]](eval(input))
val res = sigmaDslBuilder.anyOf(inputC.value)
- val cost = inputC.cost + perItemCostOf(node, inputC.sizes.length)
- withDefaultSize(res, cost)
+ val cost = opCost(Seq(inputC.cost), perItemCostOf(node, inputC.sizes.length))
+ withConstantSize(res, cost)
}
case AND(input) => input match {
case ConcreteCollection(items, tpe) =>
val itemsC = items.map(item => eval(adaptSigmaBoolean(item)))
val res = sigmaDslBuilder.allOf(colBuilder.fromItems(itemsC.map(_.value): _*))
- val costs = colBuilder.fromItems(itemsC.map(_.cost): _*)
- val cost = costs.sum(intPlusMonoid) + perItemCostOf(node, costs.length)
- withDefaultSize(res, cost)
+ val costs = itemsC.map(_.cost)
+ val cost = opCost(costs, perItemCostOf(node, costs.length))
+ withConstantSize(res, cost)
case _ =>
- val inputC = asRep[CostedCol[Boolean]](eval(input))
+ val inputC = tryCast[CostedColl[Boolean]](eval(input))
val res = sigmaDslBuilder.allOf(inputC.value)
- val cost = inputC.cost + perItemCostOf(node, inputC.sizes.length)
- withDefaultSize(res, cost)
+ val cost = opCost(Seq(inputC.cost), perItemCostOf(node, inputC.sizes.length))
+ withConstantSize(res, cost)
+ }
+
+ case XorOf(input) => input match {
+ case ConcreteCollection(items, tpe) =>
+ val itemsC = items.map(item => eval(item))
+ val res = sigmaDslBuilder.xorOf(colBuilder.fromItems(itemsC.map(_.value): _*))
+ val costs = itemsC.map(_.cost)
+ val cost = opCost(costs, perItemCostOf(node, costs.length))
+ withConstantSize(res, cost)
+ case _ =>
+ val inputC = tryCast[CostedColl[Boolean]](eval(input))
+ val res = sigmaDslBuilder.xorOf(inputC.value)
+ val cost = opCost(Seq(inputC.cost), perItemCostOf(node, inputC.sizes.length))
+ withConstantSize(res, cost)
}
case BinOr(l, r) =>
val lC = evalNode(ctx, env, l)
- val rValTh = Thunk(evalNode(ctx, env, r).value)
- val rCost = evalNode(ctx, env, r).cost // cost graph is built without Thunk (upper bound approximation)
- withDefaultSize(Or.applyLazy(lC.value, rValTh), lC.cost + rCost + costOf(node))
+ val rC = RCostedThunk(Thunk(evalNode(ctx, env, r)), 0)
+ val v = Or.applyLazy(lC.value, rC.value)
+ val c = opCost(Seq(lC.cost, rC.cost), costOf(node))
+ withConstantSize(v, c)
+
case BinAnd(l, r) =>
val lC = evalNode(ctx, env, l)
- val rValTh = Thunk(evalNode(ctx, env, r).value)
- val rCost = evalNode(ctx, env, r).cost
- withDefaultSize(And.applyLazy(lC.value, rValTh), lC.cost + rCost + costOf(node))
+ val rC = RCostedThunk(Thunk(evalNode(ctx, env, r)), 0)
+ val v = And.applyLazy(lC.value, rC.value)
+ val c = opCost(Seq(lC.cost, rC.cost), costOf(node))
+ withConstantSize(v, c)
+
+// case BinXor(l, r) =>
+// val lC = evalNode(ctx, env, l)
+// val rC = RCostedThunk(Thunk(evalNode(ctx, env, r)), 0)
+// val v = sigmaDslBuilder.binXor(lC.value, rC.value)
+// val c = lC.cost + rC.cost + costOf(node)
+// withDefaultSize(v, c)
+
+ case neg: Negation[t] =>
+ val tpe = neg.input.tpe
+ val et = stypeToElem(tpe)
+ val op = NumericNegate(elemToNumeric(et))(et)
+ val inputC = evalNode(ctx, env, neg.input)
+ inputC match { case x: RCosted[a] =>
+ withConstantSize(ApplyUnOp(op, x.value), opCost(Seq(x.cost), costOf(neg)))
+ }
case SigmaAnd(items) =>
val itemsC = items.map(eval)
- val res = sigmaDslBuilder.allZK(colBuilder.fromItems(itemsC.map(_.value.asRep[SigmaProp]): _*))
- val costs = colBuilder.fromItems(itemsC.map(_.cost): _*)
- val cost = costs.sum(intPlusMonoid) + perItemCostOf(node, costs.length)
- withDefaultSize(res, cost)
+ val res = sigmaDslBuilder.allZK(colBuilder.fromItems(itemsC.map(s => asRep[SigmaProp](s.value)): _*))
+ val costs = itemsC.map(_.cost)
+ val cost = opCost(costs, perItemCostOf(node, costs.length))
+ val size = colBuilder.fromItems(itemsC.map(_.size.dataSize): _*).sum(longPlusMonoid)
+ RCCostedPrim(res, cost, mkSizeSigmaProp(size))
case SigmaOr(items) =>
val itemsC = items.map(eval)
- val res = sigmaDslBuilder.anyZK(colBuilder.fromItems(itemsC.map(_.value.asRep[SigmaProp]): _*))
- val costs = colBuilder.fromItems(itemsC.map(_.cost): _*)
- val cost = costs.sum(intPlusMonoid) + perItemCostOf(node, costs.length)
- withDefaultSize(res, cost)
+ val res = sigmaDslBuilder.anyZK(colBuilder.fromItems(itemsC.map(s => asRep[SigmaProp](s.value)): _*))
+ val costs = itemsC.map(_.cost)
+ val cost = opCost(costs, perItemCostOf(node, costs.length))
+ val size = colBuilder.fromItems(itemsC.map(_.size.dataSize): _*).sum(longPlusMonoid)
+ RCCostedPrim(res, cost, mkSizeSigmaProp(size))
+
+// case If(c, t, e) =>
+// val cC = evalNode(ctx, env, c)
+// val tC = RCostedThunk(Thunk(evalNode(ctx, env, t)), 0)
+// val eC = RCostedThunk(Thunk(evalNode(ctx, env, e)), 0)
+// val resV = IF (cC.value) THEN tC.value ELSE eC.value
+// val resCost = cC.cost + (tC.cost max eC.cost) + costOf("If", SFunc(Vector(SBoolean, If.tT, If.tT), If.tT))
+// mkCosted(resV, resCost, tC.dataSize max eC.dataSize)
+
+ case If(c, t, e) =>
+ val cC = evalNode(ctx, env, c)
+ def tC = evalNode(ctx, env, t)
+ def eC = evalNode(ctx, env, e)
+ val resV = IF (cC.value) THEN tC.value ELSE eC.value
+ val resCost = opCost(Seq(cC.cost, tC.cost, eC.cost), costOf("If", SFunc(Vector(SBoolean, If.tT, If.tT), If.tT)))
+ RCCostedPrim(resV, resCost, tC.size) // TODO implement tC.size max eC.size
- case op: Relation[t,_] if op.tpe == SBigInt =>
- import OpCodes._
- op.opCode match {
- case GtCode =>
- val x = asRep[Costed[WBigInteger]](evalNode(ctx, env, op.left))
- val y = asRep[Costed[WBigInteger]](evalNode(ctx, env, op.right))
- val resSize = x.dataSize.min(y.dataSize)
- val cost = x.cost + y.cost + costOf(op) + costOf(">_per_item", op.opType) * resSize.toInt
- RCCostedPrim(x.value.compareTo(y.value) > 0, cost, resSize)
- // case MinusCode => NumericMinus(elemToNumeric(eT))(eT)
- // case MultiplyCode => NumericTimes(elemToNumeric(eT))(eT)
- // case DivisionCode => IntegralDivide(elemToIntegral(eT))(eT)
- // case ModuloCode => IntegralMod(elemToIntegral(eT))(eT)
- case _ => error(s"Cannot perform Costing.evalNode($op)")
- }
case rel: Relation[t, _] =>
val tpe = rel.left.tpe
val et = stypeToElem(tpe)
@@ -1389,120 +1750,194 @@ trait RuntimeCosting extends SigmaLibrary with DataCosting with Slicing { IR: Ev
(x, y) match { case (x: RCosted[a], y: RCosted[b]) =>
val value = binop.apply(x.value, asRep[t#WrappedType](y.value))
val cost =
- if (tpe.isConstantSize) x.cost + y.cost
- else x.cost + y.cost + perKbCostOf(node, x.dataSize + y.dataSize)
- val res = withDefaultSize(value, cost)
+ if (tpe.isConstantSize) {
+ val opcost = if (tpe == SBigInt) {
+ costOf(rel.opName, SBigInt.RelationOpType)
+ } else
+ costOf(rel)
+ opCost(Seq(x.cost, y.cost), opcost)
+ }
+ else opCost(Seq(x.cost, y.cost), perKbCostOf(node, x.size.dataSize + y.size.dataSize))
+ val res = withConstantSize(value, cost)
res
}
- case If(c, t, e) =>
- val cC = evalNode(ctx, env, c)
- def tC = evalNode(ctx, env, t)
- def eC = evalNode(ctx, env, e)
- val resV = IF (cC.value) THEN tC.value ELSE eC.value
- val resCost = cC.cost + (tC.cost max eC.cost) + costOf("If", SFunc(Vector(SBoolean, If.tT, If.tT), If.tT))
- mkCosted(resV, resCost, tC.dataSize max eC.dataSize)
-
case l @ Terms.Lambda(_, Seq((n, argTpe)), tpe, Some(body)) =>
- val eAny = stypeToElem(argTpe).asElem[Any]
- val xElem = elemToCostedElem(eAny)
+ val eArg = stypeToElem(argTpe).asElem[Any]
+ val eCostedArg = elemToCostedElem(eArg)
val f = fun { x: Rep[Costed[Any]] =>
evalNode(ctx, env + (n -> x), body)
- }(Lazy(xElem))
- RCCostedFunc(RCCostedPrim((), 0, 0L), f, costOf(node), l.tpe.dataSize(SType.DummyValue))
+ }(Lazy(eCostedArg))
+ val eRes = f.elem.eRange.eVal
+ mkCostedFunc(f, opCost(Nil, costOf(node)), l.tpe.dataSize(SType.DummyValue), eArg, eRes)
case l @ FuncValue(Seq((n, argTpe)), body) =>
- val eAny = stypeToElem(argTpe).asElem[Any]
- val xElem = elemToCostedElem(eAny)
+ val eArg = stypeToElem(argTpe).asElem[Any]
+ val xElem = elemToCostedElem(eArg)
val f = fun { x: Rep[Costed[Any]] =>
evalNode(ctx, env + (n -> x), body)
}(Lazy(xElem))
- RCCostedFunc(RCCostedPrim((), 0, 0L), f, costOf(node), l.tpe.dataSize(0.asWrappedType))
+ val eRes = f.elem.eRange.eVal
+ mkCostedFunc(f, opCost(Nil, costOf(node)), l.tpe.dataSize(SType.DummyValue), eArg, eRes)
case col @ ConcreteCollection(InSeqUnzipped(vs, cs, ss), elemType) =>
implicit val eAny = stypeToElem(elemType).asElem[Any]
- val values = colBuilder.fromItems(vs: _*)
+ val values = colBuilder.fromItems(vs: _*)(eAny)
val costs = colBuilder.fromItems(cs: _*)
- val sizes = colBuilder.fromItems(ss: _*)
- RCCostedCol(values, costs, sizes, costOf(col))
+ val sizes = colBuilder.fromItems(ss: _*)(sizeElement(eAny))
+ RCCostedColl(values, costs, sizes, opCost(cs, costOf(col)))
case sigmastate.Upcast(In(inputC), tpe) =>
val elem = stypeToElem(tpe.asNumType)
val res = upcast(inputC.value)(elem)
- withDefaultSize(res, inputC.cost + costOf(node))
+ withConstantSize(res, opCost(Seq(inputC.cost), costOf(node)))
case sigmastate.Downcast(In(inputC), tpe) =>
val elem = stypeToElem(tpe.asNumType)
val res = downcast(inputC.value)(elem)
- withDefaultSize(res, inputC.cost + costOf(node))
+ withConstantSize(res, opCost(Seq(inputC.cost), costOf(node)))
case LongToByteArray(In(input)) =>
val inputC = asRep[Costed[Long]](input)
val res = sigmaDslBuilder.longToByteArray(inputC.value)
- val cost = inputC.cost + costOf(node)
- withDefaultSize(res, cost)
+ val cost = opCost(Seq(inputC.cost), costOf(node))
+ mkCostedColl(res, 8, cost)
- case Xor(InColByte(l), InColByte(r)) =>
+ case ByteArrayToLong(In(arr)) =>
+ val arrC = asRep[Costed[Coll[Byte]]](arr)
+ val value = sigmaDslBuilder.byteArrayToLong(arrC.value)
+ val cost = opCost(Seq(arrC.cost), costOf(node))
+ withConstantSize(value, cost)
+
+ case Xor(InCollByte(l), InCollByte(r)) =>
val values = colBuilder.xor(l.value, r.value)
val sizes = r.sizes
val len = sizes.length
val costs = colBuilder.replicate(len, 0)
- val cost = perKbCostOf(node, len.toLong)
- RCCostedCol(values, costs, sizes, cost)
+ val cost = opCost(Seq(l.cost, r.cost), perKbCostOf(node, len.toLong))
+ RCCostedColl(values, costs, sizes, cost)
// TODO should be
// case ErgoAddressToSigmaProp(input) =>
// val inputC = evalNode(ctx, env, input)
// withDefaultSize(inputC.value, inputC.cost + costOf(node))
+// TODO why we need this here?
case sigmastate.Values.ConstantPlaceholder(index, tpe) =>
val elem = toLazyElem(stypeToElem(tpe))
val res = constantPlaceholder(index)(elem)
- withDefaultSize(res, costOf(node))
+ withConstantSize(res, costOf(node))
- case SubstConstants(InColByte(bytes), InColInt(positions), InColAny(newValues)) =>
+ case SubstConstants(InCollByte(bytes), InCollInt(positions), InCollAny(newValues)) =>
val values = sigmaDslBuilder.substConstants(bytes.values, positions.values, newValues.values)(AnyElement)
- val len = bytes.sizes.length.toLong + newValues.sizes.sum(longPlusMonoid)
- val cost = bytes.cost + positions.cost + newValues.cost + perKbCostOf(node, len)
- mkCostedCol(values, len.toInt, cost)
+ val len = bytes.size.dataSize + newValues.size.dataSize
+ val cost = opCost(Seq(bytes.cost, positions.cost, newValues.cost), perKbCostOf(node, len))
+ mkCostedColl(values, len.toInt, cost)
- case DecodePoint(InColByte(bytes)) =>
+ case DecodePoint(InCollByte(bytes)) =>
val res = sigmaDslBuilder.decodePoint(bytes.values)
- withDefaultSize(res, costOf(node))
+ RCCostedPrim(res, opCost(Seq(bytes.cost), costOf(node)), SizeGroupElement)
+
+// case Terms.MethodCall(obj, method, args, _) if obj.tpe.isCollectionLike =>
+// val xsC = asRep[CostedColl[Any]](evalNode(ctx, env, obj))
+// val (argsVals, argsCosts) = args.map {
+// case sfunc: Value[SFunc]@unchecked if sfunc.tpe.isFunc =>
+// val funC = asRep[CostedFunc[Unit, Any, Any]](evalNode(ctx, env, sfunc)).func
+// val (calcF, costF) = splitCostedFunc2(funC, okRemoveIsValid = true)
+// val cost = xsC.values.zip(xsC.costs.zip(xsC.sizes)).map(costF).sum(intPlusMonoid)
+// (calcF, cost)
+// case a =>
+// val aC = eval(a)
+// (aC.value, aC.cost)
+// }.unzip
+// // todo add costOf(node)
+// val cost = argsCosts.foldLeft(xsC.cost)({ case (s, e) => s + e }) // + costOf(node)
+// val xsV = xsC.value
+// val value = (method.name, argsVals) match {
+// case (SCollection.IndexOfMethod.name, Seq(e, from)) => xsV.indexOf(e, asRep[Int](from))
+// case (SCollection.IndicesMethod.name, _) => xsV.indices
+// case (SCollection.FlatMapMethod.name, Seq(f)) => xsV.flatMap(asRep[Any => Coll[Any]](f))
+// case (SCollection.SegmentLengthMethod.name, Seq(f, from)) =>
+// xsV.segmentLength(asRep[Any => Boolean](f), asRep[Int](from))
+// case (SCollection.IndexWhereMethod.name, Seq(f, from)) =>
+// xsV.indexWhere(asRep[Any => Boolean](f), asRep[Int](from))
+// case (SCollection.LastIndexWhereMethod.name, Seq(f, end)) =>
+// xsV.lastIndexWhere(asRep[Any => Boolean](f), asRep[Int](end))
+// case (SCollection.ZipMethod.name, Seq(col2)) => xsV.zip(asRep[Coll[Any]](col2))
+// case (SCollection.PartitionMethod.name, Seq(f)) => xsV.partition(asRep[Any => Boolean](f))
+// case (SCollection.PatchMethod.name, Seq(from, col, repl)) =>
+// xsV.patch(asRep[Int](from), asRep[Coll[Any]](col), asRep[Int](repl))
+// case (SCollection.UpdatedMethod.name, Seq(index, elem)) =>
+// xsV.updated(asRep[Int](index), asRep[Any](elem))
+// case (SCollection.UpdateManyMethod.name, Seq(indexCol, elemCol)) =>
+// xsV.updateMany(asRep[Coll[Int]](indexCol), asRep[Coll[Any]](elemCol))
+// case _ => error(s"method $method is not supported")
+// }
+// withConstantSize(value, cost)
+//
+// case Terms.MethodCall(obj, method, args, _) if obj.tpe.isOption =>
+// val optC = asRep[CostedOption[Any]](eval(obj))
+// val argsC = args.map(eval)
+// (method.name, argsC) match {
+// case (SOption.MapMethod.name, Seq(f)) => optC.map(asRep[Costed[Any => Any]](f))
+// case (SOption.FilterMethod.name, Seq(f)) => optC.filter(asRep[Costed[Any => Boolean]](f))
+// case _ => error(s"method $method is not supported in object $obj")
+// }
+//
+// case Terms.MethodCall(obj, method, args, typeSubst) if obj.tpe.isBox =>
+// val boxC = asRep[CostedBox](eval(obj))
+// val argsC = args.map(eval)
+// (method.name, argsC) match {
+// case (SBox.getRegMethod.name, Seq(index)) =>
+// val tpe = typeSubst(SBox.tT)
+// implicit val elem = stypeToElem(tpe).asElem[Any]
+// boxC.getReg(asRep[Int](index.value))(elem)
+// case _ if method.objType.coster.isDefined =>
+// method.objType.coster.get(IR)(boxC, method, argsC)
+// case _ => error(s"method $method is not supported in object $obj")
+// }
+
+ // fallback rule for MethodCall, should be the last case in the list
+ case Terms.MethodCall(obj, method, args, _) if method.objType.coster.isDefined =>
+ val objC = eval(obj)
+ val argsC = args.map(eval)
+ method.objType.coster.get(IR)(objC, method, argsC)
case _ =>
- error(s"Don't know how to evalNode($node)")
+ error(s"Don't know how to evalNode($node)", node.sourceContext.toOption)
}
val resC = asRep[Costed[T#WrappedType]](res)
onTreeNodeCosted(ctx, env, node, resC)
resC
}
+// trait Sizable[T] {
+// def size(x: Rep[T]): RSize[T]
+// }
+// object Sizable {
+// def apply[T](sz: Sizable[T]): Sizable[T] = sz
+// }
+//
+// def SizableColl[T: Sizable]: Sizable[Coll[T]] = new Sizable[Coll[T]] {
+// override def size(x: RColl[T]): RSize[Coll[T]] = x.map()
+// }
+// def sizeColl[T](coll: RColl[T]): RSize[Coll[T]] = {
+// coll.
+// }
- def buildCostedGraph[T <: SType](envVals: Map[Any, SValue], tree: Value[T]): Rep[Context => Costed[T#WrappedType]] = {
- fun { ctx: Rep[Context] =>
- val ctxC = RCCostedContext(ctx)
+ def buildCostedGraph[T](envVals: Map[Any, SValue], tree: SValue): Rep[Costed[Context] => Costed[T]] = {
+ fun { ctxC: RCosted[Context] =>
val env = envVals.mapValues(v => evalNode(ctxC, Map(), v))
- val res = evalNode(ctxC, env, tree)
+ val res = asCosted[T](evalNode(ctxC, env, tree))
res
-// val res1 = res match {
-// case RCostedPrim(SigmaPropMethods.isProven(p), Def(ApplyBinOp(op, l, r)), s) if op.isInstanceOf[NumericPlus[_]] =>
-// RCostedPrim(p, l.asRep[Int], s)
-// case _ => res
-// }
-// res1.asRep[Costed[T#WrappedType]]
}
}
- def cost(env: ScriptEnv, code: String): Rep[Context => Costed[SType#WrappedType]] = {
- val typed = compiler.typecheck(env, code)
- cost(env, typed)
- }
-
- def cost(env: ScriptEnv, typed: SValue): Rep[Context => Costed[SType#WrappedType]] = {
- val cg = buildCostedGraph[SType](env.map { case (k, v) => (k: Any, builder.liftAny(v).get) }, typed)
+ def cost[T](env: ScriptEnv, typed: SValue): Rep[Costed[Context] => Costed[T]] = {
+ val cg = buildCostedGraph[T](env.map { case (k, v) => (k: Any, builder.liftAny(v).get) }, typed)
cg
}
def error(msg: String) = throw new CosterException(msg, None)
+ def error(msg: String, srcCtx: Option[SourceContext]) = throw new CosterException(msg, srcCtx)
}
diff --git a/src/main/scala/sigmastate/eval/Sized.scala b/src/main/scala/sigmastate/eval/Sized.scala
new file mode 100644
index 0000000000..2b51f9e927
--- /dev/null
+++ b/src/main/scala/sigmastate/eval/Sized.scala
@@ -0,0 +1,126 @@
+package sigmastate.eval
+
+import scalan.{Nullable, RType}
+import special.collection.{CSizePrim, CSizePair, Size, CSizeOption, CollType, Coll, CSizeColl}
+import scalan.RType._
+import sigmastate._
+import sigmastate.SBigInt.MaxSizeInBytes
+import special.sigma._
+import SType.AnyOps
+import sigmastate.interpreter.CryptoConstants
+
+trait Sized[T] {
+ def size(x: T): Size[T]
+}
+trait SizedLowPriority {
+ implicit def collIsSized[T: Sized: RType]: Sized[Coll[T]] = (xs: Coll[T]) => new CSizeColl(xs.map(Sized[T].size))
+ implicit def optionIsSized[T: Sized]: Sized[Option[T]] = (xs: Option[T]) => new CSizeOption(xs.map(Sized[T].size))
+ implicit def pairIsSized[A: Sized, B: Sized]: Sized[(A,B)] = (in: (A,B)) => new CSizePair(Sized[A].size(in._1), Sized[B].size(in._2))
+}
+object Sized extends SizedLowPriority {
+ def apply[T](implicit sz: Sized[T]): Sized[T] = sz
+ def sizeOf[T: Sized](x: T): Size[T] = Sized[T].size(x)
+
+ val SizeBoolean: Size[Boolean] = new CSizePrim(1L, BooleanType)
+ val SizeByte: Size[Byte] = new CSizePrim(1L, ByteType)
+ val SizeShort: Size[Short] = new CSizePrim(2L, ShortType)
+ val SizeInt: Size[Int] = new CSizePrim(4L, IntType)
+ val SizeLong: Size[Long] = new CSizePrim(8L, LongType)
+ val SizeBigInt: Size[BigInt] = new CSizePrim(MaxSizeInBytes, BigIntRType)
+ val SizeGroupElement: Size[GroupElement] = new CSizePrim(CryptoConstants.EncodedGroupElementLength, GroupElementRType)
+ val SizeAvlTree: Size[AvlTree] = new CSizePrim(AvlTreeData.TreeDataSize, AvlTreeRType)
+
+ implicit val BooleanIsSized: Sized[Boolean] = (x: Boolean) => SizeBoolean
+ implicit val ByteIsSized: Sized[Byte] = (x: Byte) => SizeByte
+ implicit val ShortIsSized: Sized[Short] = (x: Short) => SizeShort
+ implicit val IntIsSized: Sized[Int] = (x: Int) => SizeInt
+ implicit val LongIsSized: Sized[Long] = (x: Long) => SizeLong
+ implicit val BigIntIsSized: Sized[BigInt] = (x: BigInt) => SizeBigInt
+ implicit val GroupElementIsSized: Sized[GroupElement] = (x: GroupElement) => SizeGroupElement
+ implicit val AvlTreeIsSized: Sized[AvlTree] = (x: AvlTree) => SizeAvlTree
+
+ def typeToSized[T](t: RType[T]): Sized[T] = (t match {
+ case BooleanType => Sized[Boolean]
+ case ByteType => Sized[Byte]
+ case ShortType => Sized[Short]
+ case IntType => Sized[Int]
+ case LongType => Sized[Long]
+ case BigIntRType => Sized[BigInt]
+ case GroupElementRType => Sized[GroupElement]
+ case AvlTreeRType => Sized[AvlTree]
+ case SigmaPropRType => sigmaPropIsSized
+ case AnyValueRType => anyValueIsSized
+ case BoxRType => boxIsSized
+ case HeaderRType => headerIsSized
+ case PreHeaderRType => preHeaderIsSized
+ case ContextRType => contextIsSized
+ case ct: CollType[a] => collIsSized(typeToSized(ct.tItem), ct.tItem)
+ case ct: OptionType[a] => optionIsSized(typeToSized(ct.tA))
+ case ct: PairType[a, b] => pairIsSized(typeToSized(ct.tFst), typeToSized(ct.tSnd))
+ case _ => sys.error(s"Don't know how to compute Sized for type $t")
+ }).asInstanceOf[Sized[T]]
+
+ implicit val anyValueIsSized: Sized[AnyValue] = (x: AnyValue) => {
+ if (x.tVal == null) {
+ val size = new CSizePrim[Any](0L, NothingType.asInstanceOf[RType[Any]])
+ new CSizeAnyValue(NothingType.asInstanceOf[RType[Any]], size)
+ } else {
+ assert(x.value != null, s"Invalid AnyValue: non-null type ${x.tVal} and null value.")
+ val sized = typeToSized(x.tVal)
+ val size = sized.size(x.value)
+ new CSizeAnyValue(x.tVal, size)
+ }
+ }
+
+ implicit val CollByteIsSized: Sized[Coll[Byte]] = (xs: Coll[Byte]) => {
+ new CSizeColl(Colls.replicate(xs.length, SizeByte))
+ }
+
+ private def sizeOfAnyValue(v: AnyValue): Size[Option[AnyValue]] = {
+ if (v == null) return new CSizeOption[AnyValue](None)
+ val size = sizeOf(v)
+ new CSizeOption[AnyValue](Some(size))
+ }
+
+ private def sizeOfRegisters(b: Box): Size[Coll[Option[AnyValue]]] = {
+ new CSizeColl(b.registers.map(sizeOfAnyValue))
+ }
+
+ private def sizeOfTokens(b: Box): Size[Coll[(Coll[Byte], Long)]] = {
+ val sId = new CSizeColl(Colls.replicate(CryptoConstants.hashLength, SizeByte))
+ val sToken = new CSizePair(sId, SizeLong)
+ new CSizeColl(Colls.replicate(b.tokens.length, sToken))
+ }
+
+ implicit val sigmaPropIsSized: Sized[SigmaProp] = (b: SigmaProp) => {
+ new CSizeSigmaProp(sizeOf(b.propBytes))
+ }
+ implicit val boxIsSized: Sized[Box] = (b: Box) => {
+ new EvalSizeBox(
+ sizeOf(b.propositionBytes),
+ sizeOf(b.bytes),
+ sizeOf(b.bytesWithoutRef),
+ sizeOfRegisters(b),
+ sizeOfTokens(b)
+ )
+ }
+ implicit val headerIsSized: Sized[Header] = (b: Header) => new CSizePrim(SHeader.dataSize(0.asWrappedType), HeaderRType)
+ implicit val preHeaderIsSized: Sized[PreHeader] = (b: PreHeader) => new CSizePrim(SPreHeader.dataSize(0.asWrappedType), PreHeaderRType)
+ implicit val contextIsSized: Sized[Context] = (ctx: Context) => {
+ val outputs = sizeOf(ctx.OUTPUTS)
+ val inputs = sizeOf(ctx.INPUTS)
+ val dataInputs = sizeOf(ctx.dataInputs)
+ val selfBox = sizeOf(ctx.SELF)
+ val rootHash = sizeOf(ctx.LastBlockUtxoRootHash)
+ val headers = sizeOf(ctx.headers)
+ val preHeader = sizeOf(ctx.preHeader)
+ val vars = ctx.vars.map { v =>
+ val anyV = if(v == null) TestValue(null, null) else v
+ sizeOf(anyV)
+ }
+ new CSizeContext(outputs, inputs, dataInputs, selfBox, rootHash, headers, preHeader, vars)
+ }
+
+}
+
+
diff --git a/src/main/scala/sigmastate/eval/TreeBuilding.scala b/src/main/scala/sigmastate/eval/TreeBuilding.scala
index d05d656f57..c74693d4b3 100644
--- a/src/main/scala/sigmastate/eval/TreeBuilding.scala
+++ b/src/main/scala/sigmastate/eval/TreeBuilding.scala
@@ -2,7 +2,7 @@ package sigmastate.eval
import scala.collection.mutable.ArrayBuffer
import sigmastate._
-import sigmastate.Values.{BlockValue, BoolValue, BooleanConstant, ConcreteCollection, Constant, ConstantNode, FuncValue, GroupElementConstant, SValue, SigmaBoolean, SigmaPropConstant, ValDef, ValUse, Value, FalseLeaf}
+import sigmastate.Values.{BlockValue, BoolValue, BooleanConstant, ConcreteCollection, Constant, ConstantNode, EvaluatedCollection, FalseLeaf, FuncValue, GroupElementConstant, SValue, SigmaBoolean, SigmaPropConstant, ValDef, ValUse, Value}
import sigmastate.serialization.OpCodes._
import org.ergoplatform._
import java.math.BigInteger
@@ -13,6 +13,7 @@ import sigmastate.lang.Terms.{OperationId, ValueOps}
import sigmastate.serialization.OpCodes._
import sigmastate.serialization.{ConstantStore, ValueSerializer}
import sigmastate.utxo.{CostTable, ExtractAmount, SizeOf}
+import ErgoLikeContext._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
@@ -20,36 +21,37 @@ import scala.reflect.{ClassTag, classTag}
import scala.util.Try
import SType._
import org.bouncycastle.math.ec.ECPoint
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.basics.ProveDHTuple
import sigmastate.interpreter.CryptoConstants.EcPointType
-import sigmastate.lang.SigmaBuilder
+import sigmastate.lang.{SigmaBuilder, SigmaTyper}
trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
import Liftables._
import Context._
import SigmaProp._
- import Col._
+ import Coll._
import Box._
- import ColBuilder._
+ import CollBuilder._
import SigmaDslBuilder._
import CCostedBuilder._
import MonoidBuilderInst._
- import TrivialSigma._
- import ProveDlogEvidence._
- import ProveDHTEvidence._
- import WBigInteger._
+ import BigInt._
import WArray._
import WOption._
import WECPoint._
+ import AvlTree._
private val ContextM = ContextMethods
private val SigmaM = SigmaPropMethods
- private val ColM = ColMethods
+ private val CollM = CollMethods
private val BoxM = BoxMethods
- private val CBM = ColBuilderMethods
+ private val CBM = CollBuilderMethods
private val SDBM = SigmaDslBuilderMethods
private val AM = WArrayMethods
private val OM = WOptionMethods
- private val BIM = WBigIntegerMethods
+ private val BIM = BigIntMethods
+ private val AvlM = AvlTreeMethods
/** Describes assignment of valIds for symbols which become ValDefs.
* Each ValDef in current scope have entry in this map */
@@ -89,8 +91,15 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
}
object IsLogicalUnOp {
- def unapply(op: UnOp[_,_]): Option[BoolValue => Value[SBoolean.type]] = op match {
- case Not => Some({ v: BoolValue => builder.mkEQ(v, FalseLeaf) })
+ def unapply(op: UnOp[_,_]): Option[BoolValue => BoolValue] = op match {
+ case Not => Some({ v: BoolValue => builder.mkLogicalNot(v) })
+ case _ => None
+ }
+ }
+
+ object IsNumericUnOp {
+ def unapply(op: UnOp[_,_]): Option[SValue => SValue] = op match {
+ case NumericNegate(_) => Some({ v: SValue => builder.mkNegation(v.asNumValue) })
case _ => None
}
}
@@ -107,7 +116,7 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
object IsInternalDef {
def unapply(d: Def[_]): Option[Def[_]] = d match {
- case _: SigmaDslBuilder | _: ColBuilder | _: WSpecialPredefCompanion => Some(d)
+ case _: SigmaDslBuilder | _: CollBuilder | _: WSpecialPredefCompanion => Some(d)
case _ => None
}
}
@@ -125,29 +134,31 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
}
}
- def buildValue(mainG: PGraph,
+ def buildValue(ctx: Rep[Context],
+ mainG: PGraph,
env: DefEnv,
s: Sym,
defId: Int,
constantsProcessing: Option[ConstantStore]): SValue = {
import builder._
- def recurse[T <: SType](s: Sym) = buildValue(mainG, env, s, defId, constantsProcessing).asValue[T]
- object In { def unapply(s: Sym): Option[SValue] = Some(buildValue(mainG, env, s, defId, constantsProcessing)) }
+ def recurse[T <: SType](s: Sym) = buildValue(ctx, mainG, env, s, defId, constantsProcessing).asValue[T]
+ object In { def unapply(s: Sym): Option[SValue] = Some(buildValue(ctx, mainG, env, s, defId, constantsProcessing)) }
s match {
+ case _ if s == ctx => org.ergoplatform.Context
case _ if env.contains(s) =>
val (id, tpe) = env(s)
ValUse(id, tpe) // recursion base
case Def(Lambda(lam, _, x, y)) =>
val varId = defId + 1 // arguments are treated as ValDefs and occupy id space
val env1 = env + (x -> (varId, elemToSType(x.elem)))
- val block = processAstGraph(mainG, env1, lam, varId + 1, constantsProcessing)
+ val block = processAstGraph(ctx, mainG, env1, lam, varId + 1, constantsProcessing)
val rhs = mkFuncValue(Vector((varId, elemToSType(x.elem))), block)
rhs
case Def(Apply(fSym, xSym, _)) =>
val Seq(f, x) = Seq(fSym, xSym).map(recurse)
builder.mkApply(f, IndexedSeq(x))
case Def(th @ ThunkDef(root, _)) =>
- val block = processAstGraph(mainG, env, th, defId, constantsProcessing)
+ val block = processAstGraph(ctx, mainG, env, th, defId, constantsProcessing)
block
case Def(Const(x)) =>
val tpe = elemToSType(s.elem)
@@ -159,6 +170,27 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
case None =>
mkConstant[tpe.type](x.asInstanceOf[tpe.WrappedType], tpe)
}
+ case Def(wc: LiftedConst[a,_]) =>
+ val tpe = elemToSType(s.elem)
+ val t = Evaluation.stypeToRType(tpe)
+ val tRes = Evaluation.toErgoTreeType(t)
+ val v = Evaluation.fromDslData(wc.constValue, tRes)
+ mkConstant[tpe.type](v.asInstanceOf[tpe.WrappedType], tpe)
+
+ case Def(IsContextProperty(v)) => v
+
+ case Def(ApplyBinOp(IsArithOp(opCode), xSym, ySym)) =>
+ val Seq(x, y) = Seq(xSym, ySym).map(recurse)
+ mkArith(x.asNumValue, y.asNumValue, opCode)
+ case Def(ApplyBinOp(IsRelationOp(mkNode), xSym, ySym)) =>
+ val Seq(x, y) = Seq(xSym, ySym).map(recurse)
+ mkNode(x, y)
+ case Def(ApplyBinOpLazy(IsLogicalBinOp(mkNode), xSym, ySym)) =>
+ val Seq(x, y) = Seq(xSym, ySym).map(recurse)
+ mkNode(x, y)
+ case Def(ApplyUnOp(IsLogicalUnOp(mkNode), xSym)) =>
+ mkNode(recurse(xSym))
+
case CBM.fromArray(_, arr @ Def(wc: LiftedConst[a,_])) =>
val colTpe = elemToSType(s.elem)
mkConstant[colTpe.type](wc.constValue.asInstanceOf[colTpe.WrappedType], colTpe)
@@ -169,18 +201,10 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
case CBM.xor(_, colSym1, colSym2) =>
mkXor(recurse(colSym1), recurse(colSym2))
- case Def(wc: LiftedConst[a,_]) =>
- val tpe = elemToSType(s.elem)
- wc.constValue match {
- case cb: CostingBox =>
- mkConstant[tpe.type](cb.ebox.asInstanceOf[tpe.WrappedType], tpe)
- case _ =>
- mkConstant[tpe.type](wc.constValue.asInstanceOf[tpe.WrappedType], tpe)
- }
- case Def(IsContextProperty(v)) => v
case ContextM.getVar(_, Def(Const(id: Byte)), eVar) =>
val tpe = elemToSType(eVar)
mkGetVar(id, tpe)
+
case BIM.subtract(In(x), In(y)) =>
mkArith(x.asNumValue, y.asNumValue, MinusCode)
case BIM.add(In(x), In(y)) =>
@@ -195,6 +219,8 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
mkArith(x.asNumValue, y.asNumValue, MinCode)
case BIM.max(In(x), In(y)) =>
mkArith(x.asNumValue, y.asNumValue, MaxCode)
+ case BIM.modQ(In(x)) =>
+ mkModQ(x.asBigInt)
case Def(ApplyBinOp(IsArithOp(opCode), xSym, ySym)) =>
val Seq(x, y) = Seq(xSym, ySym).map(recurse)
mkArith(x.asNumValue, y.asNumValue, opCode)
@@ -206,41 +232,65 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
mkNode(x, y)
case Def(ApplyUnOp(IsLogicalUnOp(mkNode), xSym)) =>
mkNode(recurse(xSym))
+ case Def(ApplyUnOp(IsNumericUnOp(mkNode), xSym)) =>
+ mkNode(recurse(xSym))
- case ColM.apply(colSym, In(index)) =>
+ case CollM.apply(colSym, In(index)) =>
val col = recurse(colSym)
mkByIndex(col, index.asIntValue, None)
- case ColM.length(col) =>
+ case CollM.length(col) =>
utxo.SizeOf(recurse(col).asCollection[SType])
- case ColM.exists(colSym, pSym) =>
+ case CollM.exists(colSym, pSym) =>
val Seq(col, p) = Seq(colSym, pSym).map(recurse)
mkExists(col.asCollection[SType], p.asFunc)
- case ColM.forall(colSym, pSym) =>
+ case CollM.forall(colSym, pSym) =>
val Seq(col, p) = Seq(colSym, pSym).map(recurse)
mkForAll(col.asCollection[SType], p.asFunc)
- case ColM.map(colSym, fSym) =>
+ case CollM.map(colSym, fSym) =>
val Seq(col, f) = Seq(colSym, fSym).map(recurse)
mkMapCollection(col.asCollection[SType], f.asFunc)
- case ColM.getOrElse(colSym, In(index), defValSym) =>
+ case CollM.getOrElse(colSym, In(index), defValSym) =>
val col = recurse(colSym)
val defVal = recurse(defValSym)
mkByIndex(col, index.asIntValue, Some(defVal))
- case ColM.append(col1Sym, col2Sym) =>
+ case CollM.append(col1Sym, col2Sym) =>
val Seq(col1, col2) = Seq(col1Sym, col2Sym).map(recurse)
mkAppend(col1, col2)
- case ColM.slice(colSym, In(from), In(until)) =>
+ case CollM.slice(colSym, In(from), In(until)) =>
mkSlice(recurse(colSym), from.asIntValue, until.asIntValue)
- case ColM.fold(colSym, zeroSym, pSym) =>
+ case CollM.foldLeft(colSym, zeroSym, pSym) =>
val Seq(col, zero, p) = Seq(colSym, zeroSym, pSym).map(recurse)
mkFold(col, zero, p.asFunc)
+ case Def(MethodCall(receiver, m, argsSyms, _)) if receiver.elem.isInstanceOf[CollElem[_, _]] =>
+ val colSym = receiver.asInstanceOf[Rep[Coll[Any]]]
+ val args = argsSyms.map(_.asInstanceOf[Sym]).map(recurse)
+ val col = recurse(colSym).asCollection[SType]
+ val colTpe = col.tpe // elemToSType(colSym.elem).asCollection
+ val method = SCollection.methods.find(_.name == m.getName).getOrElse(error(s"unknown method Coll.${m.getName}"))
+ val typeSubst = (method, args) match {
+ case (mth @ SCollection.FlatMapMethod, Seq(f)) =>
+ val typeSubst = Map(SCollection.tOV -> f.asFunc.tpe.tRange.asCollection.elemType)
+ typeSubst
+ case (mth @ SCollection.ZipMethod, Seq(coll: EvaluatedCollection[_, _])) =>
+ val typeSubst = Map(SCollection.tOV -> coll.elementType)
+ typeSubst
+ case (mth, _) => SigmaTyper.emptySubst
+ }
+ val specMethod = method.withConcreteTypes(typeSubst + (SCollection.tIV -> colTpe.elemType))
+ builder.mkMethodCall(col, specMethod, args.toIndexedSeq, Map())
+
case BoxM.value(box) =>
mkExtractAmount(recurse[SBox.type](box))
case BoxM.propositionBytes(In(box)) =>
mkExtractScriptBytes(box.asBox)
case BoxM.getReg(In(box), regId, _) =>
val tpe = elemToSType(s.elem).asOption
- mkExtractRegisterAs(box.asBox, ErgoBox.allRegisters(regId.asValue), tpe)
+ if (regId.isConst)
+ mkExtractRegisterAs(box.asBox, ErgoBox.allRegisters(regId.asValue), tpe)
+ else
+ builder.mkMethodCall(box, SBox.getRegMethod, IndexedSeq(recurse(regId)),
+ Map(SBox.tT -> tpe.elemType))
case BoxM.creationInfo(In(box)) =>
mkExtractCreationInfo(box.asBox)
case BoxM.id(In(box)) =>
@@ -257,6 +307,19 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
case OM.isDefined(In(optionSym)) =>
mkOptionIsDefined(optionSym.asValue[SOption[SType]])
+ case SigmaM.and_bool_&&(In(prop), In(cond)) =>
+ SigmaAnd(Seq(prop.asSigmaProp, mkBoolToSigmaProp(cond.asBoolValue)))
+ case SigmaM.or_bool_||(In(prop), In(cond)) =>
+ SigmaOr(Seq(prop.asSigmaProp, mkBoolToSigmaProp(cond.asBoolValue)))
+ case SigmaM.and_sigma_&&(In(p1), In(p2)) =>
+ SigmaAnd(Seq(p1.asSigmaProp, p2.asSigmaProp))
+ case SigmaM.or_sigma_||(In(p1), In(p2)) =>
+ SigmaOr(Seq(p1.asSigmaProp, p2.asSigmaProp))
+ case SigmaM.isValid(In(prop)) =>
+ mkSigmaPropIsProven(prop.asSigmaProp)
+ case SigmaM.propBytes(In(prop)) =>
+ mkSigmaPropBytes(prop.asSigmaProp)
+
case Def(AnyZk(_, colSyms, _)) =>
val col = colSyms.map(recurse(_).asSigmaProp)
SigmaOr(col)
@@ -270,64 +333,54 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
case Def(AllOf(_, colSyms, _)) =>
val col = colSyms.map(recurse(_).asBoolValue)
mkAllOf(col)
- case Def(SDBM.allOf(_, items)) =>
+
+ case SDBM.allOf(_, items) =>
mkAND(recurse(items))
- case Def(SDBM.anyOf(_, items)) =>
+ case SDBM.anyOf(_, items) =>
mkOR(recurse(items))
- case Def(SDBM.atLeast(_, bound, items)) =>
+ case SDBM.atLeast(_, bound, items) =>
mkAtLeast(recurse(bound), recurse(items))
+ case Def(SDBM.xorOf(_, items)) =>
+ mkXorOf(recurse(items))
- case SigmaM.and_bool_&&(In(prop), In(cond)) =>
- SigmaAnd(Seq(prop.asSigmaProp, mkBoolToSigmaProp(cond.asBoolValue)))
- case SigmaM.or_bool_||(In(prop), In(cond)) =>
- SigmaOr(Seq(prop.asSigmaProp, mkBoolToSigmaProp(cond.asBoolValue)))
- case SigmaM.and_sigma_&&(In(p1), In(p2)) =>
- SigmaAnd(Seq(p1.asSigmaProp, p2.asSigmaProp))
- case SigmaM.or_sigma_||(In(p1), In(p2)) =>
- SigmaOr(Seq(p1.asSigmaProp, p2.asSigmaProp))
- // case SigmaM.lazyAnd(In(l), In(r)) =>
- // mkBinAnd(l.asSigmaProp, r.asSigmaProp)
- // case SigmaM.lazyOr(In(l), In(r)) =>
- // mkBinOr(l.asSigmaProp, r.asSigmaProp)
- case SigmaM.isValid(In(prop)) =>
- mkSigmaPropIsProven(prop.asSigmaProp)
- case SigmaM.propBytes(In(prop)) =>
- mkSigmaPropBytes(prop.asSigmaProp)
- case Def(TrivialSigmaCtor(In(cond))) =>
+ case Def(SDBM.sigmaProp(_, In(cond))) =>
mkBoolToSigmaProp(cond.asBoolValue)
- case Def(ProveDlogEvidenceCtor(In(g))) =>
+ case SDBM.proveDlog(_, In(g)) =>
g match {
- case gc: Constant[SGroupElement.type]@unchecked => SigmaPropConstant(mkProveDlog(gc))
- case _ => mkProveDlog(g.asGroupElement)
+ case gc: Constant[SGroupElement.type]@unchecked => SigmaPropConstant(ProveDlog(gc.value))
+ case _ => mkCreateProveDlog(g.asGroupElement)
}
- case Def(ProveDHTEvidenceCtor(In(g), In(h), In(u), In(v))) =>
+ case SDBM.proveDHTuple(_, In(g), In(h), In(u), In(v)) =>
(g, h, u, v) match {
case (gc: Constant[SGroupElement.type]@unchecked,
hc: Constant[SGroupElement.type]@unchecked,
uc: Constant[SGroupElement.type]@unchecked,
vc: Constant[SGroupElement.type]@unchecked) =>
- SigmaPropConstant(mkProveDiffieHellmanTuple(gc, hc, uc, vc))
+ SigmaPropConstant(ProveDHTuple(gc.value, hc.value, uc.value, vc.value))
case _ =>
- mkProveDiffieHellmanTuple(g.asGroupElement, h.asGroupElement, u.asGroupElement, v.asGroupElement)
+ mkCreateProveDHTuple(g.asGroupElement, h.asGroupElement, u.asGroupElement, v.asGroupElement)
}
-
case SDBM.sigmaProp(_, In(cond)) =>
mkBoolToSigmaProp(cond.asBoolValue)
case SDBM.byteArrayToBigInt(_, colSym) =>
mkByteArrayToBigInt(recurse(colSym))
+ case SDBM.sha256(_, colSym) =>
+ mkCalcSha256(recurse(colSym))
case SDBM.blake2b256(_, colSym) =>
mkCalcBlake2b256(recurse(colSym))
- case SDBM.treeModifications(_, treeSym, opsColSym, proofColSym) =>
- mkTreeModifications(recurse(treeSym), recurse(opsColSym), recurse(proofColSym))
- case SDBM.treeLookup(_, treeSym, keySym, proofColSym) =>
- mkTreeLookup(recurse(treeSym), recurse(keySym), recurse(proofColSym))
case SDBM.longToByteArray(_, longSym) =>
mkLongToByteArray(recurse(longSym))
+ case SDBM.byteArrayToLong(_, colSym) =>
+ mkByteArrayToLong(recurse(colSym))
+ case SDBM.decodePoint(_, colSym) =>
+ mkDecodePoint(recurse(colSym))
case Def(IfThenElseLazy(condSym, thenPSym, elsePSym)) =>
val Seq(cond, thenP, elseP) = Seq(condSym, thenPSym, elsePSym).map(recurse)
mkIf(cond, thenP, elseP)
+ case Def(Tup(In(x), In(y))) =>
+ mkTuple(Seq(x, y))
case Def(First(pair)) =>
mkSelectField(recurse(pair), 1)
case Def(Second(pair)) =>
@@ -344,12 +397,28 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
val items = fields.map { case (n, v) => recurse(v) }
mkTuple(items)
+ // Fallback MethodCall rule: should be the last in this list of cases
+ case Def(MethodCall(objSym, m, argSyms, _)) =>
+ val obj = recurse[SType](objSym)
+ val args = argSyms.collect { case argSym: Sym => recurse[SType](argSym) }
+ val method = obj.tpe.asProduct.method(m.getName)
+ .getOrElse(error(s"Cannot find method ${m.getName} in object $obj"))
+ val specMethod = method.specializeFor(obj.tpe, args.map(_.tpe))
+ builder.mkMethodCall(obj, specMethod, args.toIndexedSeq, Map())
+// val method = ((SCollection.methods.find(_.name == m.getName), args) match {
+// case (Some(mth @ SCollection.FlatMapMethod), Seq(f)) =>
+// mth.withConcreteTypes(Map(SCollection.tOV -> f.asFunc.tpe.tRange.asCollection.elemType))
+// case (Some(mth), _) => mth
+// case (None, _) => error(s"unknown method Coll.${m.getName}")
+// }).withConcreteTypes(Map(SCollection.tIV -> colTpe.elemType))
+
case Def(d) =>
!!!(s"Don't know how to buildValue($mainG, $s -> $d, $env, $defId)")
}
}
- private def processAstGraph(mainG: PGraph,
+ private def processAstGraph(ctx: Rep[Context],
+ mainG: PGraph,
env: DefEnv,
subG: AstGraph,
defId: Int,
@@ -364,15 +433,15 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
&& IsInternalDef.unapply(d).isEmpty
&& IsNonConstantDef.unapply(d).nonEmpty)
{
- val rhs = buildValue(mainG, curEnv, s, curId, constantsProcessing)
+ val rhs = buildValue(ctx, mainG, curEnv, s, curId, constantsProcessing)
curId += 1
val vd = ValDef(curId, Seq(), rhs)
- curEnv = curEnv + (s -> (curId, elemToSType(s.elem))) // assign valId to s, so it can be use in ValUse
+ curEnv = curEnv + (s -> (curId, vd.tpe)) // assign valId to s, so it can be use in ValUse
valdefs += vd
}
}
val Seq(root) = subG.roots
- val rhs = buildValue(mainG, curEnv, root, curId, constantsProcessing)
+ val rhs = buildValue(ctx, mainG, curEnv, root, curId, constantsProcessing)
val res = if (valdefs.nonEmpty) BlockValue(valdefs.toIndexedSeq, rhs) else rhs
res
}
@@ -381,7 +450,7 @@ trait TreeBuilding extends RuntimeCosting { IR: Evaluation =>
constantsProcessing: Option[ConstantStore] = None): Value[T] = {
val Def(Lambda(lam,_,_,_)) = f
val mainG = new PGraph(lam.y)
- val block = processAstGraph(mainG, Map(), mainG, 0, constantsProcessing)
+ val block = processAstGraph(asRep[Context](lam.x), mainG, Map(), mainG, 0, constantsProcessing)
block.asValue[T]
}
}
diff --git a/src/main/scala/sigmastate/eval/Zero.scala b/src/main/scala/sigmastate/eval/Zero.scala
new file mode 100644
index 0000000000..04c744988b
--- /dev/null
+++ b/src/main/scala/sigmastate/eval/Zero.scala
@@ -0,0 +1,65 @@
+package sigmastate.eval
+
+import java.math.BigInteger
+
+import scalan.{Nullable, RType}
+import special.collection.{CSizePrim, CSizePair, Size, CSizeOption, CollType, Coll, CSizeColl}
+import scalan.RType._
+import sigmastate._
+import sigmastate.SBigInt.MaxSizeInBytes
+import special.sigma._
+import SType.AnyOps
+import scorex.crypto.authds.avltree.batch.BatchAVLProver
+import scorex.crypto.hash.{Digest32, Blake2b256}
+import sigmastate.interpreter.CryptoConstants
+import sigmastate.interpreter.CryptoConstants.EcPointType
+
+trait Zero[T] {
+ def zero: T
+}
+
+case class CZero[T](zero: T) extends Zero[T]
+
+trait ZeroLowPriority {
+ implicit def collIsZero[T: Zero: RType]: Zero[Coll[T]] = CZero(Colls.emptyColl[T])
+ implicit def optionIsZero[T: Zero]: Zero[Option[T]] = CZero(Some(Zero.zeroOf[T]))
+ implicit def pairIsZero[A: Zero, B: Zero]: Zero[(A,B)] = CZero(Zero[A].zero, Zero[B].zero)
+}
+object Zero extends ZeroLowPriority {
+ def apply[T](implicit z: Zero[T]): Zero[T] = z
+ def zeroOf[T: Zero]: T = Zero[T].zero
+
+ implicit val BooleanIsZero: Zero[Boolean] = CZero(false)
+ implicit val ByteIsZero: Zero[Byte] = CZero(0.toByte)
+ implicit val ShortIsZero: Zero[Short] = CZero(0.toShort)
+ implicit val IntIsZero: Zero[Int] = CZero(0)
+ implicit val LongIsZero: Zero[Long] = CZero(0L)
+ implicit val BigIntIsZero: Zero[BigInt] = CZero(CBigInt(BigInteger.ZERO))
+ implicit val GroupElementIsZero: Zero[GroupElement] = CZero(CGroupElement(CryptoConstants.dlogGroup.identity))
+ implicit val AvlTreeIsZero: Zero[AvlTree] = CZero({
+ val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
+ val digest = avlProver.digest
+ val treeData = new AvlTreeData(digest, AvlTreeFlags.AllOperationsAllowed, 32, None)
+ CAvlTree(treeData)
+ })
+
+ def typeToZero[T](t: RType[T]): Zero[T] = (t match {
+ case BooleanType => Zero[Boolean]
+ case ByteType => Zero[Byte]
+ case ShortType => Zero[Short]
+ case IntType => Zero[Int]
+ case LongType => Zero[Long]
+ case BigIntRType => Zero[BigInt]
+ case GroupElementRType => Zero[GroupElement]
+ case AvlTreeRType => Zero[AvlTree]
+ case SigmaPropRType => sigmaPropIsZero
+ case ct: CollType[a] => collIsZero(typeToZero(ct.tItem), ct.tItem)
+ case ct: OptionType[a] => optionIsZero(typeToZero(ct.tA))
+ case ct: PairType[a, b] => pairIsZero(typeToZero(ct.tFst), typeToZero(ct.tSnd))
+ case _ => sys.error(s"Don't know how to compute Zero for type $t")
+ }).asInstanceOf[Zero[T]]
+
+ implicit val sigmaPropIsZero: Zero[SigmaProp] = CZero(CSigmaProp(TrivialProp.FalseProp))
+}
+
+
diff --git a/src/main/scala/sigmastate/eval/package.scala b/src/main/scala/sigmastate/eval/package.scala
new file mode 100644
index 0000000000..bd6c563ddd
--- /dev/null
+++ b/src/main/scala/sigmastate/eval/package.scala
@@ -0,0 +1,6 @@
+package sigmastate
+
+package object eval {
+ val SigmaDsl = CostingSigmaDslBuilder
+ val Colls = SigmaDsl.Colls
+}
diff --git a/src/main/scala/sigmastate/interpreter/Context.scala b/src/main/scala/sigmastate/interpreter/Context.scala
index ff1655324c..eb2099be7f 100644
--- a/src/main/scala/sigmastate/interpreter/Context.scala
+++ b/src/main/scala/sigmastate/interpreter/Context.scala
@@ -3,13 +3,15 @@ package sigmastate.interpreter
import sigmastate.SType
import sigmastate.Values.EvaluatedValue
import sigmastate.eval.Evaluation
-import sigmastate.serialization.Serializer
+import sigmastate.serialization.SigmaSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-import sigmastate.utils.Extensions._
import special.sigma
+import special.sigma.AnyValue
/**
- * Variables to be put into context
+ * User-defined variables to be put into context
+ *
+ * @param values - key-value pairs
*/
case class ContextExtension(values: Map[Byte, EvaluatedValue[_ <: SType]]) {
def add(bindings: (Byte, EvaluatedValue[_ <: SType])*): ContextExtension =
@@ -19,14 +21,14 @@ case class ContextExtension(values: Map[Byte, EvaluatedValue[_ <: SType]]) {
object ContextExtension {
val empty = ContextExtension(Map())
- object serializer extends Serializer[ContextExtension, ContextExtension] {
+ object serializer extends SigmaSerializer[ContextExtension, ContextExtension] {
- override def serializeBody(obj: ContextExtension, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: ContextExtension, w: SigmaByteWriter): Unit = {
w.putUByte(obj.values.size)
- obj.values.foreach{ case (id, v) => w.put(id).putValue(v) }
+ obj.values.foreach { case (id, v) => w.put(id).putValue(v) }
}
- override def parseBody(r: SigmaByteReader): ContextExtension = {
+ override def parse(r: SigmaByteReader): ContextExtension = {
val extSize = r.getByte()
val ext = (0 until extSize)
.map(_ => (r.getByte(), r.getValue().asInstanceOf[EvaluatedValue[_ <: SType]]))
@@ -34,18 +36,19 @@ object ContextExtension {
ContextExtension(ext)
}
}
+
}
-trait Context{
+trait Context {
val extension: ContextExtension
def withExtension(newExtension: ContextExtension): Context
def withBindings(bindings: (Byte, EvaluatedValue[_ <: SType])*): Context = {
- val ext = extension.add(bindings:_*)
+ val ext = extension.add(bindings: _*)
withExtension(ext)
}
- def toSigmaContext(IR: Evaluation, isCost: Boolean): sigma.Context
+ def toSigmaContext(IR: Evaluation, isCost: Boolean, extensions: Map[Byte, AnyValue] = Map()): sigma.Context
}
diff --git a/src/main/scala/sigmastate/interpreter/CryptoConstants.scala b/src/main/scala/sigmastate/interpreter/CryptoConstants.scala
new file mode 100644
index 0000000000..f097acb8af
--- /dev/null
+++ b/src/main/scala/sigmastate/interpreter/CryptoConstants.scala
@@ -0,0 +1,45 @@
+package sigmastate.interpreter
+
+import java.math.BigInteger
+import java.security.SecureRandom
+
+import org.bouncycastle.math.ec.custom.sec.SecP256K1Point
+import sigmastate.basics.{BcDlogGroup, SecP256K1}
+
+object CryptoConstants {
+ type EcPointType = SecP256K1Point
+
+ val EncodedGroupElementLength: Byte = 33
+
+ val dlogGroup: BcDlogGroup[EcPointType] = SecP256K1
+
+ val secureRandom: SecureRandom = dlogGroup.secureRandom
+
+ /** Size of the binary representation of any group element (2 ^ groupSizeBits == ) */
+ val groupSizeBits: Int = 256
+
+ /** Number of bytes to represent any group element as byte array */
+ val groupSize: Int = 256 / 8 //32 bytes
+
+ /** Group order, i.e. number of elements in the group */
+ val groupOrder: BigInteger = dlogGroup.order
+
+ /** Length of hash function used in the signature scheme. Blake2b hash function is used. */
+ val hashLengthBits = 256
+
+ val hashLength: Int = hashLengthBits / 8
+
+ //size of challenge in Sigma protocols, in bits
+ //if this anything but 192, threshold won't work, because we have polynomials over GF(2^192) and no others
+ //so DO NOT change the value without implementing polynomials over GF(2^soundnessBits) first
+ //and changing code that calls on GF2_192 and GF2_192_Poly classes!!!
+ //we get the challenge by reducing hash function output to proper value
+ implicit val soundnessBits: Int = 192.ensuring(_ < groupSizeBits, "2^t < q condition is broken!")
+
+ def secureRandomBytes(howMany: Int): Array[Byte] = {
+ val bytes = new Array[Byte](howMany)
+ secureRandom.nextBytes(bytes)
+ bytes
+ }
+
+}
diff --git a/src/main/scala/sigmastate/interpreter/CryptoFunctions.scala b/src/main/scala/sigmastate/interpreter/CryptoFunctions.scala
new file mode 100644
index 0000000000..0aa16f2480
--- /dev/null
+++ b/src/main/scala/sigmastate/interpreter/CryptoFunctions.scala
@@ -0,0 +1,19 @@
+package sigmastate.interpreter
+
+import org.bouncycastle.math.ec.ECPoint
+import scorex.crypto.hash.Blake2b256
+
+object CryptoFunctions {
+ lazy val soundnessBytes: Int = CryptoConstants.soundnessBits / 8
+
+ def hashFn(input: Array[Byte]): Array[Byte] = {
+ Blake2b256.hash(input).take(soundnessBytes)
+ }
+
+ def showECPoint(p: ECPoint): String = {
+ val rawX = p.getRawXCoord.toString.substring(0, 6)
+ val rawY = p.getRawYCoord.toString.substring(0, 6)
+ s"ECPoint($rawX,$rawY,...)"
+ }
+
+}
diff --git a/src/main/scala/sigmastate/interpreter/Interpreter.scala b/src/main/scala/sigmastate/interpreter/Interpreter.scala
index ecf44a62b6..381e9da977 100644
--- a/src/main/scala/sigmastate/interpreter/Interpreter.scala
+++ b/src/main/scala/sigmastate/interpreter/Interpreter.scala
@@ -1,79 +1,27 @@
package sigmastate.interpreter
import java.util
-import java.util.Objects
import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{strategy, rule, everywherebu}
import org.bitbucket.inkytonik.kiama.rewriting.Strategy
-import org.bouncycastle.math.ec.ECPoint
-import org.bouncycastle.math.ec.custom.djb.Curve25519Point
import sigmastate.basics.DLogProtocol.{FirstDLogProverMessage, DLogInteractiveProver}
-import scorex.crypto.authds.avltree.batch.{Lookup, Operation}
-import scorex.crypto.authds.{ADKey, SerializedAdProof}
-import scorex.crypto.hash.Blake2b256
import scorex.util.ScorexLogging
import sigmastate.SCollection.SByteArray
-import sigmastate.Values.{ByteArrayConstant, _}
-import sigmastate.eval.IRContext
-import sigmastate.interpreter.Interpreter.{VerificationResult, ScriptEnv}
-import sigmastate.lang.exceptions.InterpreterException
+import sigmastate.Values._
+import sigmastate.eval.{IRContext, Sized}
import sigmastate.lang.Terms.ValueOps
-import sigmastate.serialization.{ValueSerializer, OpCodes, Serializer, OperationSerializer}
-import sigmastate.basics.{BcDlogFp, Curve25519, DiffieHellmanTupleInteractiveProver, FirstDiffieHellmanTupleProverMessage}
-import sigmastate.interpreter.Interpreter.VerificationResult
-import sigmastate.lang.exceptions.InterpreterException
-import sigmastate.serialization.{OpCodes, OperationSerializer, Serializer, ValueSerializer}
-import sigmastate.utils.Extensions._
-import sigmastate.utils.Helpers
-import sigmastate.utxo.{GetVar, DeserializeContext, Transformer}
+import sigmastate.basics._
+import sigmastate.interpreter.Interpreter.{VerificationResult, ScriptEnv}
+import sigmastate.lang.exceptions.{InterpreterException, CosterException}
+import sigmastate.serialization.ValueSerializer
+import sigmastate.utxo.DeserializeContext
import sigmastate.{SType, _}
-import special.sigma.InvalidType
-
-import scala.util.{Success, Failure, Try}
-
-
-object CryptoConstants {
- type EcPointType = Curve25519Point
-
- val dlogGroup: BcDlogFp[EcPointType] = Curve25519
- lazy val secureRandom = dlogGroup.secureRandom
-
- def secureRandomBytes(howMany: Int) = {
- val bytes = new Array[Byte](howMany)
- secureRandom.nextBytes(bytes)
- bytes
- }
- /** Size of the binary representation of any group element (2 ^ groupSizeBits == ) */
- val groupSizeBits: Int = 256
+import scala.util.Try
- /** Number of bytes to represent any group element as byte array */
- val groupSize: Int = 256 / 8 //32 bytes
-
- //size of challenge in Sigma protocols, in bits
- //if this anything but 192, threshold won't work, because we have polynomials over GF(2^192) and no others
- //so DO NOT change the value without implementing polynomials over GF(2^soundnessBits) first
- //and changing code that calls on GF2_192 and GF2_192_Poly classes!!!
- implicit val soundnessBits: Int = 192.ensuring(_ < groupSizeBits, "2^t < q condition is broken!")
-}
-
-object CryptoFunctions {
- lazy val soundnessBytes = CryptoConstants.soundnessBits / 8
-
- def hashFn(input: Array[Byte]): Array[Byte] = {
- Blake2b256.hash(input).take(soundnessBytes)
- }
-
- def showECPoint(p: ECPoint) = {
- val rawX = p.getRawXCoord.toString.substring(0, 6)
- val rawY = p.getRawYCoord.toString.substring(0, 6)
- s"ECPoint($rawX,$rawY,...)"
- }
-}
trait Interpreter extends ScorexLogging {
- import CryptoConstants._
import Interpreter.ReductionResult
type CTX <: Context
@@ -118,6 +66,31 @@ trait Interpreter extends ScorexLogging {
res
}
+ def checkCost(context: CTX, exp: Value[SType], costF: Rep[((Int, IR.Size[IR.Context])) => Int]): Int = {
+ import IR.Size._; import IR.Context._;
+ val costingCtx = context.toSigmaContext(IR, isCost = true)
+ val costFun = IR.compile[(Int, SSize[SContext]), Int, (Int, Size[Context]), Int](IR.getDataEnv, costF, Some(maxCost))
+ val (_, estimatedCost) = costFun((0, Sized.sizeOf(costingCtx)))
+ if (estimatedCost > maxCost) {
+ throw new Error(s"Estimated expression complexity $estimatedCost exceeds the limit $maxCost in $exp")
+ }
+ estimatedCost
+ }
+
+ def calcResult(context: special.sigma.Context, calcF: Rep[IR.Context => Any]): special.sigma.SigmaProp = {
+ import IR._; import Context._; import SigmaProp._
+ val res = calcF.elem.eRange.asInstanceOf[Any] match {
+ case sp: SigmaPropElem[_] =>
+ val valueFun = compile[SContext, SSigmaProp, Context, SigmaProp](getDataEnv, asRep[Context => SigmaProp](calcF))
+ val (sp, _) = valueFun(context)
+ sp
+ case BooleanElement =>
+ val valueFun = compile[SContext, Boolean, IR.Context, Boolean](IR.getDataEnv, asRep[Context => Boolean](calcF))
+ val (b, _) = valueFun(context)
+ sigmaDslBuilderValue.sigmaProp(b)
+ }
+ res
+ }
/**
* As the first step both prover and verifier are applying context-specific transformations and then estimating
* cost of the intermediate expression. If cost is above limit, abort. Otherwise, both prover and verifier are
@@ -128,39 +101,35 @@ trait Interpreter extends ScorexLogging {
* @return
*/
def reduceToCrypto(context: CTX, env: ScriptEnv, exp: Value[SType]): Try[ReductionResult] = Try {
- val costingRes @ IR.Pair(calcF, costF) = doCosting(env, exp)
+ import IR._; import Size._; import Context._; import SigmaProp._
+ val costingRes @ Pair(calcF, costF) = doCostingEx(env, exp, true)
IR.onCostingResult(env, exp, costingRes)
- IR.verifyCostFunc(costF).fold(t => throw t, x => x)
+ verifyCostFunc(asRep[Any => Int](costF)).fold(t => throw t, x => x)
- IR.verifyIsProven(calcF).fold(t => throw t, x => x)
+ verifyIsProven(calcF).fold(t => throw t, x => x)
- // check cost
val costingCtx = context.toSigmaContext(IR, isCost = true)
- val costFun = IR.compile[SInt.type](IR.getDataEnv, costF)
- val IntConstant(estimatedCost) = costFun(costingCtx)
- if (estimatedCost > maxCost) {
- throw new Error(s"Estimated expression complexity $estimatedCost exceeds the limit $maxCost in $exp")
- }
+ val estimatedCost = checkCostWithContext(costingCtx, exp, costF, maxCost)
+ .fold(t => throw new CosterException(
+ s"Script cannot be executed $exp: ", exp.sourceContext.toList.headOption, Some(t)), identity)
+
+// println(s"reduceToCrypto: estimatedCost: $estimatedCost")
+
// check calc
val calcCtx = context.toSigmaContext(IR, isCost = false)
- val valueFun = IR.compile[SBoolean.type](IR.getDataEnv, calcF.asRep[IR.Context => SBoolean.WrappedType])
- val res = valueFun(calcCtx)
- val resValue = res match {
- case SigmaPropConstant(sb) => sb
- case _ => res
- }
- resValue -> estimatedCost
+ val res = calcResult(calcCtx, calcF)
+ SigmaDsl.toSigmaBoolean(res) -> estimatedCost
}
def reduceToCrypto(context: CTX, exp: Value[SType]): Try[ReductionResult] =
reduceToCrypto(context, Interpreter.emptyEnv, exp)
- def verify(env: ScriptEnv, exp: Value[SBoolean.type],
+ def verify(env: ScriptEnv, exp: ErgoTree,
context: CTX,
proof: Array[Byte],
message: Array[Byte]): Try[VerificationResult] = Try {
- val propTree = applyDeserializeContext(context, exp)
+ val propTree = applyDeserializeContext(context, exp.proposition)
val (cProp, cost) = reduceToCrypto(context, env, propTree).get
val checkingResult = cProp match {
@@ -169,6 +138,7 @@ trait Interpreter extends ScorexLogging {
case cProp: SigmaBoolean =>
cProp match {
case TrivialProp.TrueProp => true
+ case TrivialProp.FalseProp => false
case _ =>
// Perform Verifier Steps 1-3
SigSerializer.parseAndComputeChallenges(cProp, proof) match {
@@ -187,7 +157,7 @@ trait Interpreter extends ScorexLogging {
util.Arrays.equals(newRoot.challenge, expectedChallenge)
}
}
- case _: Value[_] => false
+// case _: Value[_] => false
}
checkingResult -> cost
}
@@ -211,7 +181,7 @@ trait Interpreter extends ScorexLogging {
case _ => ???
})
- def verify(exp: Value[SBoolean.type],
+ def verify(exp: ErgoTree,
context: CTX,
proverResult: ProverResult,
message: Array[Byte]): Try[VerificationResult] = {
@@ -219,7 +189,7 @@ trait Interpreter extends ScorexLogging {
verify(Interpreter.emptyEnv, exp, ctxv, proverResult.proof, message)
}
- def verify(env: ScriptEnv, exp: Value[SBoolean.type],
+ def verify(env: ScriptEnv, exp: ErgoTree,
context: CTX,
proverResult: ProverResult,
message: Array[Byte]): Try[VerificationResult] = {
@@ -229,21 +199,23 @@ trait Interpreter extends ScorexLogging {
//todo: do we need the method below?
- def verify(exp: Value[SBoolean.type],
+ def verify(exp: ErgoTree,
context: CTX,
proof: ProofT,
message: Array[Byte]): Try[VerificationResult] = {
verify(Interpreter.emptyEnv, exp, context, SigSerializer.toBytes(proof), message)
}
+
}
object Interpreter {
type VerificationResult = (Boolean, Long)
- type ReductionResult = (Value[SBoolean.type], Long)
+ type ReductionResult = (SigmaBoolean, Long)
type ScriptEnv = Map[String, Any]
- val emptyEnv: ScriptEnv = Map()
+ val emptyEnv: ScriptEnv = Map.empty[String, Any]
val ScriptNameProp = "ScriptName"
def error(msg: String) = throw new InterpreterException(msg)
+
}
diff --git a/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala b/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala
index 0f5cd6e415..438edf07b8 100644
--- a/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala
+++ b/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala
@@ -2,25 +2,33 @@ package sigmastate.interpreter
import java.util
+import gf2t.{GF2_192, GF2_192_Poly}
import org.bitbucket.inkytonik.kiama.attribution.AttributionCore
import sigmastate.basics.DLogProtocol._
import sigmastate._
import sigmastate.utils.{Helpers, SigmaByteReader, SigmaByteWriter}
-import sigmastate.utils.Extensions._
import Values._
-
+import scalan.util.CollectionUtil._
import scala.util.Try
import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{everywherebu, everywheretd, rule}
import org.bitbucket.inkytonik.kiama.rewriting.Strategy
+import scalan.util.CollectionUtil._
+import scorex.util.encode.Base16
+import sigmastate.Values._
+import sigmastate._
+import sigmastate.basics.DLogProtocol._
import sigmastate.basics.VerifierMessage.Challenge
-import sigmastate.serialization.Serializer
-import gf2t.GF2_192
-import gf2t.GF2_192_Poly
import sigmastate.basics.{DiffieHellmanTupleInteractiveProver, DiffieHellmanTupleProverInput, ProveDHTuple, SigmaProtocolPrivateInput}
-import sigmastate.lang.exceptions.InterpreterException
+import sigmastate.serialization.SigmaSerializer
+import sigmastate.utils.{Helpers, SigmaByteReader, SigmaByteWriter}
+
+import scala.util.Try
/**
- * Proof generated by a prover along with possible context extensions
+ * Proof of correctness of tx spending
+ *
+ * @param proof - proof that satisfies final sigma proposition
+ * @param extension - user-defined variables to be put into context
*/
class ProverResult(val proof: Array[Byte], val extension: ContextExtension) {
override def hashCode(): Int = util.Arrays.hashCode(proof) * 31 + extension.hashCode()
@@ -30,28 +38,32 @@ class ProverResult(val proof: Array[Byte], val extension: ContextExtension) {
util.Arrays.equals(proof, obj.proof) && extension == obj.extension
case _ => false
}
+
+ override def toString: Idn = s"ProverResult(${Base16.encode(proof)},$extension)"
}
object ProverResult {
+ val empty: ProverResult = ProverResult(Array[Byte](), ContextExtension.empty)
def apply(proof: Array[Byte], extension: ContextExtension): ProverResult =
new ProverResult(proof, extension)
- object serializer extends Serializer[ProverResult, ProverResult] {
+ object serializer extends SigmaSerializer[ProverResult, ProverResult] {
- override def serializeBody(obj: ProverResult, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: ProverResult, w: SigmaByteWriter): Unit = {
w.putUShort(obj.proof.length)
w.putBytes(obj.proof)
- ContextExtension.serializer.serializeBody(obj.extension, w)
+ ContextExtension.serializer.serialize(obj.extension, w)
}
- override def parseBody(r: SigmaByteReader): ProverResult = {
+ override def parse(r: SigmaByteReader): ProverResult = {
val sigBytesCount = r.getUShort()
val proofBytes = r.getBytes(sigBytesCount)
- val ce = ContextExtension.serializer.parseBody(r)
+ val ce = ContextExtension.serializer.parse(r)
ProverResult(proofBytes, ce)
}
}
+
}
case class CostedProverResult(override val proof: Array[Byte],
@@ -62,17 +74,14 @@ case class CostedProverResult(override val proof: Array[Byte],
* Interpreter with enhanced functionality to prove statements.
*/
trait ProverInterpreter extends Interpreter with AttributionCore {
- import Interpreter._
+
import CryptoConstants.secureRandomBytes
+ import Interpreter._
override type ProofT = UncheckedTree
val secrets: Seq[SigmaProtocolPrivateInput[_, _]]
- def contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = Map()
-
- val knownExtensions = ContextExtension(contextExtenders)
-
/**
* The comments in this section are taken from the algorithm for the
* Sigma-protocol prover as described in the white paper
@@ -118,16 +127,16 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
convertToUnchecked(step9)
}
- def prove(exp: Value[SBoolean.type], context: CTX, message: Array[Byte]): Try[CostedProverResult] =
+ def prove(exp: ErgoTree, context: CTX, message: Array[Byte]): Try[CostedProverResult] =
prove(emptyEnv, exp, context, message)
- def prove(env: ScriptEnv, exp: Value[SBoolean.type], context: CTX, message: Array[Byte]): Try[CostedProverResult] = Try {
+ def prove(env: ScriptEnv, exp: ErgoTree, ctx: CTX, message: Array[Byte]): Try[CostedProverResult] = Try {
import TrivialProp._
- val ctx = context.withExtension(knownExtensions).asInstanceOf[CTX]
- val propTree = applyDeserializeContext(ctx, exp)
- val (reducedProp, cost) = reduceToCrypto(ctx, env, propTree).get
+ val propTree = applyDeserializeContext(ctx, exp.proposition)
+ val tried = reduceToCrypto(ctx, env, propTree)
+ val (reducedProp, cost) = tried.fold(t => throw t, identity)
- def errorReducedToFalse = Interpreter.error("Script reduced to false")
+ def errorReducedToFalse = error("Script reduced to false")
val proofTree = reducedProp match {
case BooleanConstant(boolResult) =>
@@ -138,27 +147,29 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
case TrueProp => NoProof
case FalseProp => errorReducedToFalse
case _ =>
- val ct = convertToUnproven(sigmaBoolean)
- prove(ct, message)
+ val unprovenTree = convertToUnproven(sigmaBoolean)
+ prove(unprovenTree, message)
}
case _ =>
- // TODO this case should be removed, because above cases should cover all possible variants
- val sigmaBoolean = Try { reducedProp.asInstanceOf[SigmaBoolean] }
- .recover { case _ => throw new InterpreterException(s"failed to cast to SigmaBoolean: $reducedProp") }
- .get
- val ct = convertToUnproven(sigmaBoolean)
- prove(ct, message)
+ error(s"Unexpected result of reduceToCrypto($ctx, $env, $propTree)")
+ // TODO this case should be removed, because above cases should cover all possible variants
+ // val sigmaBoolean = Try { reducedProp.asInstanceOf[SigmaBoolean] }
+ // .recover { case _ => throw new InterpreterException(s"failed to cast to SigmaBoolean: $reducedProp") }
+ // .get
+ // val ct = convertToUnproven(sigmaBoolean)
+ // prove(ct, message)
}
// Prover Step 10: output the right information into the proof
val proof = SigSerializer.toBytes(proofTree)
- CostedProverResult(proof, knownExtensions, cost)
+ CostedProverResult(proof, ctx.extension, cost)
}
/**
* Prover Step 1: This step will mark as "real" every node for which the prover can produce a real proof.
* This step may mark as "real" more nodes than necessary if the prover has more than the minimal
* necessary number of witnesses (for example, more than one child of an OR).
- * This will be corrected in the next step. In a bottom-up traversal of the tree, do the following for each node:
+ * This will be corrected in the next step.
+ * In a bottom-up traversal of the tree, do the following for each node:
*/
val markReal: Strategy = everywherebu(rule[UnprovenTree] {
case and: CAndUnproven =>
@@ -171,8 +182,10 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
or.copy(simulated = simulated)
case t: CThresholdUnproven =>
// If the node is TRESHOLD(k), mark it "real" if at least k of its children are marked real; else mark it "simulated"
- val c = t.children.foldLeft(0) {(count, child) => count + {if(child.asInstanceOf[UnprovenTree].simulated) 0 else 1}}
- t.copy(simulated = c
+ count + (if (child.asInstanceOf[UnprovenTree].simulated) 0 else 1)
+ }
+ t.copy(simulated = c < t.k)
case su: UnprovenSchnorr =>
// If the node is a leaf, mark it "real'' if the witness for it is available; else mark it "simulated"
val secretKnown = secrets.exists {
@@ -188,7 +201,7 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
}
dhu.copy(simulated = !secretKnown)
case t =>
- error(s"Don't know how to markSimulated($t)")
+ error(s"Don't know how to markReal($t)")
})
/**
@@ -235,9 +248,11 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
val kid = child.asInstanceOf[UnprovenTree]
val (newKid, newCountOfReal) = kid.real match {
case false => (kid, countOfReal)
- case true => ({if (countOfReal>=t.k) kid.withSimulated(true) else kid}, countOfReal+1)
+ case true => ( {
+ if (countOfReal >= t.k) kid.withSimulated(true) else kid
+ }, countOfReal + 1)
}
- (children:+newKid, newCountOfReal)
+ (children :+ newKid, newCountOfReal)
}._1
t.copy(children = newChildren)
}
@@ -258,15 +273,15 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
// random challenge in {0,1}^t.
case and: CAndUnproven if and.real => and // A real AND node has no simulated children
- //real OR or Threshold case
+ //real OR or Threshold case
case uc: UnprovenConjecture if uc.real =>
val newChildren = uc.children.cast[UnprovenTree].map(c =>
if (c.real) c
else c.withChallenge(Challenge @@ secureRandomBytes(CryptoFunctions.soundnessBytes))
)
uc match {
- case or: COrUnproven => or.copy(children = newChildren)
- case t: CThresholdUnproven => t.copy(children = newChildren)
+ case or: COrUnproven => or.copy(children = newChildren)
+ case t: CThresholdUnproven => t.copy(children = newChildren)
case _ => ???
}
@@ -301,45 +316,45 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
assert(t.challengeOpt.isDefined)
val n = t.children.length
val unprovenChildren = t.children.cast[UnprovenTree]
- val q = GF2_192_Poly.fromByteArray(t.challengeOpt.get, secureRandomBytes(CryptoFunctions.soundnessBytes*(n-t.k)) )
+ val q = GF2_192_Poly.fromByteArray(t.challengeOpt.get, secureRandomBytes(CryptoFunctions.soundnessBytes * (n - t.k)))
val newChildren = unprovenChildren.foldLeft((Seq[UnprovenTree](), 1)) {
case ((childSeq, childIndex), child) =>
(childSeq :+ child.withChallenge(Challenge @@ q.evaluate(childIndex.toByte).toByteArray), childIndex + 1)
}._1
- t.withPolynomial(q).copy(children=newChildren)
-
- // The algorithm with better resistance to timing attacks is as follows.
- // Pick n-k fresh uniformly random values e_1, ..., e_{n-k}
- // as challenges for the children number 1, ..., n-k.
- // Let i_0 = 0. Viewing 0, 1, 2, ..., n and e_0, ..., e_{n-k} as elements of GF(2^t),
- // find (via polynomial interpolation) the
- // lowest-degree polynomial Q(x)=sum_{i=0}^{n-k} a_i x^i over GF(2^t) that is equal to e_j at j for each j
- // from 0 to n-k (this polynomial will have n-k+1 coefficients, and the lowest coefficient will be e_0).
- // Set the challenge at child j for n-k
- val (newPoints, newValues) =
- if (count <= n - t.k) {
- (p :+ count.toByte, v :+ new GF2_192(child.challengeOpt.get))
- }
- else (p, v)
- (newPoints, newValues, count + 1)
- }
- val q = GF2_192_Poly.interpolate(points, values, new GF2_192(t.challengeOpt.get))
+ t.withPolynomial(q).copy(children = newChildren)
+
+ // The algorithm with better resistance to timing attacks is as follows.
+ // Pick n-k fresh uniformly random values e_1, ..., e_{n-k}
+ // as challenges for the children number 1, ..., n-k.
+ // Let i_0 = 0. Viewing 0, 1, 2, ..., n and e_0, ..., e_{n-k} as elements of GF(2^t),
+ // find (via polynomial interpolation) the
+ // lowest-degree polynomial Q(x)=sum_{i=0}^{n-k} a_i x^i over GF(2^t) that is equal to e_j at j for each j
+ // from 0 to n-k (this polynomial will have n-k+1 coefficients, and the lowest coefficient will be e_0).
+ // Set the challenge at child j for n-k
+ val (newPoints, newValues) =
+ if (count <= n - t.k) {
+ (p :+ count.toByte, v :+ new GF2_192(child.challengeOpt.get))
+ }
+ else (p, v)
+ (newPoints, newValues, count + 1)
+ }
+ val q = GF2_192_Poly.interpolate(points, values, new GF2_192(t.challengeOpt.get))
- val newChildren = unprovenChildren.slice(n-t.k, n).foldLeft((childrenWithRandomChallenges, n-t.k+1)) {
- case ((childSeq, childIndex), child) =>
- (childSeq :+ child.withChallenge(Challenge @@ q.evaluate(childIndex.toByte).toByteArray), childIndex + 1)
- }._1
- t.withPolynomial(q).copy(children=newChildren)
- */
+ val newChildren = unprovenChildren.slice(n-t.k, n).foldLeft((childrenWithRandomChallenges, n-t.k+1)) {
+ case ((childSeq, childIndex), child) =>
+ (childSeq :+ child.withChallenge(Challenge @@ q.evaluate(childIndex.toByte).toByteArray), childIndex + 1)
+ }._1
+ t.withPolynomial(q).copy(children=newChildren)
+ */
@@ -374,7 +389,7 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
case upt: UnprovenTree => upt.challengeOpt
case sn: UncheckedSchnorr => Some(sn.challenge)
case dh: UncheckedDiffieHellmanTuple => Some(dh.challenge)
- case _ => ???
+ case _ => error(s"Cannot extractChallenge($pt)")
}
/**
@@ -412,17 +427,17 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
// i of the node, if the child is marked "real", compute its challenge as Q(i) (if the child is marked
// "simulated", its challenge is already Q(i), by construction of Q).
assert(t.challengeOpt.isDefined)
- val (points, values, _) = t.children.foldLeft(Array[Byte](), Array[GF2_192](),1) {
+ val (points, values, _) = t.children.foldLeft(Array[Byte](), Array[GF2_192](), 1) {
case ((p, v, count), child) =>
val (newPoints, newValues) = {
// This is the easiest way to find out whether a child is simulated -- just to check if it alread
// has a challenge. Other ways are more of a pain because the children can be of different types
val challengeOpt = extractChallenge(child)
if (challengeOpt.isEmpty) (p, v)
- else (p:+count.toByte, v:+new GF2_192(challengeOpt.get))
+ else (p :+ count.toByte, v :+ new GF2_192(challengeOpt.get))
}
- (newPoints, newValues, count+1)
+ (newPoints, newValues, count + 1)
}
val q = GF2_192_Poly.interpolate(points, values, new GF2_192(t.challengeOpt.get))
val newChildren = t.children.foldLeft(Seq[ProofTree](), 1) {
@@ -431,14 +446,14 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
case r: UnprovenTree if r.real => r.withChallenge(Challenge @@ q.evaluate(count.toByte).toByteArray())
case p: ProofTree => p
}
- (s:+newChild, count+1)
+ (s :+ newChild, count + 1)
}._1
- t.withPolynomial(q).copy(children=newChildren)
+ t.withPolynomial(q).copy(children = newChildren)
// If the node is a leaf marked "real", compute its response according to the second prover step
// of the Sigma-protocol given the commitment, challenge, and witness
case su: UnprovenSchnorr if su.real =>
- assert(su.challengeOpt.isDefined)
+ assert(su.challengeOpt.isDefined, s"Real UnprovenTree $su should have challenge defined")
val privKey = secrets
.filter(_.isInstanceOf[DLogProverInput])
.find(_.asInstanceOf[DLogProverInput].publicImage == su.proposition)
@@ -462,32 +477,34 @@ trait ProverInterpreter extends Interpreter with AttributionCore {
case ut: UnprovenTree => ut
- case a: Any => log.warn("Wrong input in prove(): ", a); ???
+ case a: Any => log.warn("Wrong input in prove(): ", a); ???
})
//converts SigmaTree => UnprovenTree
- val convertToUnproven: SigmaBoolean => UnprovenTree = attr {
- case CAND(sigmaTrees) =>
- CAndUnproven(CAND(sigmaTrees), None, simulated = false, sigmaTrees.map(convertToUnproven))
- case COR(children) =>
- COrUnproven(COR(children), None, simulated = false, children.map(convertToUnproven))
- case CTHRESHOLD(k, children) =>
- CThresholdUnproven(CTHRESHOLD(k, children), None, simulated = false, k, children.map(convertToUnproven), None)
+ def convertToUnproven(sigmaTree: SigmaBoolean): UnprovenTree = sigmaTree match {
+ case and@CAND(sigmaTrees) =>
+ CAndUnproven(and, None, simulated = false, sigmaTrees.map(convertToUnproven))
+ case or@COR(children) =>
+ COrUnproven(or, None, simulated = false, children.map(convertToUnproven))
+ case threshold@CTHRESHOLD(k, children) =>
+ CThresholdUnproven(threshold, None, simulated = false, k, children.map(convertToUnproven), None)
case ci: ProveDlog =>
UnprovenSchnorr(ci, None, None, None, simulated = false)
case dh: ProveDHTuple =>
UnprovenDiffieHellmanTuple(dh, None, None, None, simulated = false)
+ case _ =>
+ error(s"Cannot convertToUnproven($sigmaTree)")
}
//converts ProofTree => UncheckedSigmaTree
val convertToUnchecked: ProofTree => UncheckedSigmaTree = attr {
case and: CAndUnproven =>
- CAndUncheckedNode(and.challengeOpt.get, and.children.map(convertToUnchecked))
+ CAndUncheckedNode(and.challengeOpt.get, and.children.map(convertToUnchecked))
case or: COrUnproven =>
- COrUncheckedNode(or.challengeOpt.get, or.children.map(convertToUnchecked))
+ COrUncheckedNode(or.challengeOpt.get, or.children.map(convertToUnchecked))
case t: CThresholdUnproven =>
- CThresholdUncheckedNode(t.challengeOpt.get, t.children.map(convertToUnchecked), t.k, t.polynomialOpt)
+ CThresholdUncheckedNode(t.challengeOpt.get, t.children.map(convertToUnchecked), t.k, t.polynomialOpt)
case s: UncheckedSchnorr => s
case d: UncheckedDiffieHellmanTuple => d
case _ => ???
diff --git a/src/main/scala/sigmastate/lang/SigmaBinder.scala b/src/main/scala/sigmastate/lang/SigmaBinder.scala
index 02d0ba9e95..777d424b5f 100644
--- a/src/main/scala/sigmastate/lang/SigmaBinder.scala
+++ b/src/main/scala/sigmastate/lang/SigmaBinder.scala
@@ -1,96 +1,96 @@
package sigmastate.lang
import java.lang.reflect.InvocationTargetException
-import java.math.BigInteger
-import org.bitbucket.inkytonik.kiama.rewriting.Rewriter._
-import sigmastate.lang.Terms._
-import sigmastate._
-import Values._
+import org.bitbucket.inkytonik.kiama.rewriting.CallbackRewriter
+import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
import org.ergoplatform._
-import scorex.util.encode.Base58
+import scalan.Nullable
+import sigmastate.Values._
+import sigmastate._
import sigmastate.interpreter.Interpreter.ScriptEnv
-import sigmastate.lang.exceptions.{BinderException, InvalidTypeArguments, InvalidArguments}
-import sigmastate.serialization.ValueSerializer
+import sigmastate.lang.SigmaPredef.PredefinedFuncRegistry
+import sigmastate.lang.Terms._
+import sigmastate.lang.exceptions.{BinderException, InvalidArguments}
+import sigma.util.Extensions._
-class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder) {
+object SrcCtxCallbackRewriter extends CallbackRewriter {
+ override def rewriting[T](oldTerm: T, newTerm: T): T = (oldTerm, newTerm) match {
+ case (o: SValue, n: SValue) if o.sourceContext.isDefined && n.sourceContext.isEmpty =>
+ n.withSrcCtx(o.sourceContext).asInstanceOf[T]
+ case _ => newTerm
+ }
+}
+
+/**
+ * @param env
+ * @param builder
+ * @param networkPrefix network prefix to decode an ergo address from string (PK op)
+ */
+class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder,
+ networkPrefix: NetworkPrefix,
+ predefFuncRegistry: PredefinedFuncRegistry) {
import SigmaBinder._
- import SigmaPredef._
import builder._
+ import SrcCtxCallbackRewriter._
+
+ private val PKFunc = predefFuncRegistry.PKFunc(networkPrefix)
/** Rewriting of AST with respect to environment to resolve all references to global names
* and infer their types. */
private def eval(e: SValue, env: ScriptEnv): SValue = rewrite(reduce(strategy[SValue]({
- case Ident(n, NoType) => env.get(n) match {
- case Some(v) => Option(liftAny(v).get)
- case None => predefinedEnv.get(n) match {
- case Some(v) => Some(Ident(n, v.tpe))
- case None => n match {
- case "HEIGHT" => Some(Height)
- case "MinerPubkey" => Some(MinerPubkey)
- case "INPUTS" => Some(Inputs)
- case "OUTPUTS" => Some(Outputs)
- case "LastBlockUtxoRootHash" => Some(LastBlockUtxoRootHash)
- case "EmptyByteArray" => Some(ByteArrayConstant(Array.emptyByteArray))
- case "SELF" => Some(Self)
- case "None" => Some(mkNoneValue(NoType))
- case _ => None
- }
+ case i @ Ident(n, NoType) => env.get(n) match {
+ case Some(v) => Option(liftAny(v).get.withPropagatedSrcCtx(i.sourceContext))
+ case None => n match {
+ case "HEIGHT" => Some(Height)
+ case "MinerPubkey" => Some(MinerPubkey)
+ case "INPUTS" => Some(Inputs)
+ case "OUTPUTS" => Some(Outputs)
+ case "LastBlockUtxoRootHash" => Some(LastBlockUtxoRootHash)
+ case "EmptyByteArray" => Some(ByteArrayConstant(Array.emptyByteArray))
+ case "SELF" => Some(Self)
+ case "CONTEXT" => Some(Context)
+ case "None" => Some(mkNoneValue(NoType))
+ case _ => None
}
}
- // Rule: Array[Int](...) -->
+ // Rule: Coll[Int](...) -->
case e @ Apply(ApplyTypes(Ident("Coll", _), Seq(tpe)), args) =>
- val resTpe = if (args.isEmpty) tpe
- else {
- val elemType = args(0).tpe
- if (elemType != tpe)
- error(s"Invalid construction of array $e: expected type $tpe, actual type $elemType")
- elemType
- }
- Some(mkConcreteCollection(args, resTpe))
+// args.foreach{ e =>
+// if (e.tpe != tpe)
+// error(s"Invalid construction of collection $e: expected type $tpe, actual type ${e.tpe}",
+// e.sourceContext)
+// }
+ Some(mkConcreteCollection(args, tpe))
- // Rule: Array(...) -->
+ // Rule: Coll(...) -->
case Apply(Ident("Coll", _), args) =>
val tpe = if (args.isEmpty) NoType else args(0).tpe
Some(mkConcreteCollection(args, tpe))
// Rule: Some(x) -->
- case Apply(Ident("Some", _), args) =>
- val arg =
- if (args.length == 1) args(0)
- else error(s"Invalid arguments of Some: expected one argument but found $args")
- Some(mkSomeValue(arg))
+ case Apply(i @ Ident("Some", _), args) => args match {
+ case Seq(arg) => Some(mkSomeValue(arg))
+ case _ => error(s"Invalid arguments of Some: expected one argument but found $args", i.sourceContext)
+ }
// Rule: min(x, y) -->
- case Apply(Ident("min", _), args) => args match {
+ case Apply(i @ Ident("min", _), args) => args match {
case Seq(l: SValue, r: SValue) =>
Some(mkMin(l.asNumValue, r.asNumValue))
case _ =>
- throw new InvalidArguments(s"Invalid arguments for min: $args")
+ throw new InvalidArguments(s"Invalid arguments for min: $args", i.sourceContext.toOption)
}
// Rule: max(x, y) -->
- case Apply(Ident("max", _), args) => args match {
+ case Apply(i @ Ident("max", _), args) => args match {
case Seq(l: SValue, r: SValue) =>
Some(mkMax(l.asNumValue, r.asNumValue))
case _ =>
- throw new InvalidArguments(s"Invalid arguments for max: $args")
+ throw new InvalidArguments(s"Invalid arguments for max: $args", i.sourceContext.toOption)
}
- // Rule getVar[T](id) --> GetVar(id)
- case e @ Apply(ApplyTypes(GetVarSym, targs), args) =>
- if (targs.length != 1 || args.length != 1)
- error(s"Wrong number of arguments in $e: expected one type argument and one variable id")
- val id = args.head match {
- case LongConstant(i) => SByte.downcast(i)
- case IntConstant(i) => SByte.downcast(i)
- case ShortConstant(i) => SByte.downcast(i)
- case ByteConstant(i) => i
- case v => error(s"invalid type for var id, expected numeric, got $v")
- }
- Some(mkGetVar(id, targs.head))
-
// Rule: lambda (...) = ... --> lambda (...): T = ...
case lam @ Lambda(params, args, t, Some(body)) =>
require(params.isEmpty)
@@ -102,10 +102,12 @@ class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder) {
case Block(Seq(), body) => Some(body)
case block @ Block(binds, t) =>
- val newBinds = for (Val(n, t, b) <- binds) yield {
- if (env.contains(n)) error(s"Variable $n already defined ($n = ${env(n)}")
+ val newBinds = for (v @ Val(n, t, b) <- binds) yield {
+ if (env.contains(n)) error(s"Variable $n already defined ($n = ${env(n)}", v.sourceContext)
val b1 = eval(b, env)
- mkVal(n, if (t != NoType) t else b1.tpe, b1)
+ builder.currentSrcCtx.withValue(v.sourceContext) {
+ mkVal(n, if (t != NoType) t else b1.tpe, b1)
+ }
}
val t1 = eval(t, env)
val newBlock = mkBlock(newBinds, t1)
@@ -113,19 +115,10 @@ class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder) {
Some(newBlock)
else
None
- case e @ Apply(ApplyTypes(DeserializeSym, targs), args) =>
- if (targs.length != 1)
- throw new InvalidTypeArguments(s"Wrong number of type arguments in $e: expected one type argument")
- if (args.length != 1)
- throw new InvalidArguments(s"Wrong number of arguments in $e: expected one argument")
- val str = args.head match {
- case StringConstant(s) => s
- case _ =>
- throw new InvalidArguments(s"invalid argument in $e: expected a string constant")
- }
- val bytes = Base58.decode(str).get
- Some(
- ValueSerializer.deserialize(bytes))
+
+ case a @ Apply(PKFunc.symNoType, args) =>
+ Some(PKFunc.irBuilder(PKFunc.sym, args).withPropagatedSrcCtx(a.sourceContext))
+
})))(e)
def bind(e: SValue): SValue =
@@ -134,5 +127,5 @@ class SigmaBinder(env: ScriptEnv, builder: SigmaBuilder) {
}
object SigmaBinder {
- def error(msg: String) = throw new BinderException(msg, None)
+ def error(msg: String, srcCtx: Nullable[SourceContext]) = throw new BinderException(msg, srcCtx.toOption)
}
diff --git a/src/main/scala/sigmastate/lang/SigmaBuilder.scala b/src/main/scala/sigmastate/lang/SigmaBuilder.scala
index e4845b5f20..2184663534 100644
--- a/src/main/scala/sigmastate/lang/SigmaBuilder.scala
+++ b/src/main/scala/sigmastate/lang/SigmaBuilder.scala
@@ -5,7 +5,8 @@ import java.math.BigInteger
import org.ergoplatform.ErgoBox
import org.ergoplatform.ErgoBox.RegisterId
import sigmastate.SCollection.SByteArray
-import sigmastate.Values.{BigIntValue, BlockItem, BlockValue, BoolValue, ConcreteCollection, Constant, ConstantNode, ConstantPlaceholder, FalseLeaf, FuncValue, GroupElementValue, NoneValue, SValue, SigmaBoolean, SigmaPropValue, SomeValue, TaggedVariable, TaggedVariableNode, TrueLeaf, Tuple, ValUse, Value}
+import sigmastate.Values.{StringConstant, FuncValue, FalseLeaf, Constant, SValue, TrueLeaf, BlockValue, ConstantNode, SomeValue, ConstantPlaceholder, BigIntValue, BoolValue, Value, SigmaPropValue, Tuple, GroupElementValue, TaggedVariableNode, SigmaBoolean, BlockItem, ValUse, TaggedVariable, ConcreteCollection, NoneValue}
+import sigmastate.Values._
import sigmastate._
import sigmastate.interpreter.CryptoConstants
import sigmastate.lang.Constraints.{TypeConstraint2, onlyNumeric2, sameType2}
@@ -16,10 +17,22 @@ import sigmastate.lang.exceptions.ConstraintFailed
import sigmastate.serialization.OpCodes
import sigmastate.utxo._
import scalan.Nullable
+import sigmastate.SOption.SIntOption
import sigmastate.basics.ProveDHTuple
+import sigmastate.eval.{CostingSigmaDslBuilder, Evaluation}
+import sigmastate.eval.Extensions._
+import sigmastate.interpreter.CryptoConstants.EcPointType
+import special.collection.Coll
+import special.sigma.{AvlTree, SigmaProp, GroupElement}
+import sigmastate.lang.SigmaTyper.STypeSubst
+import special.sigma.{GroupElement, SigmaProp}
+
+import scala.util.DynamicVariable
trait SigmaBuilder {
+ val currentSrcCtx = new DynamicVariable[Nullable[SourceContext]](Nullable.None)
+
def mkEQ[T <: SType](left: Value[T], right: Value[T]): Value[SBoolean.type]
def mkNEQ[T <: SType](left: Value[T], right: Value[T]): Value[SBoolean.type]
@@ -39,6 +52,7 @@ trait SigmaBuilder {
def mkOR(input: Value[SCollection[SBoolean.type]]): BoolValue
def mkAND(input: Value[SCollection[SBoolean.type]]): BoolValue
+ def mkXorOf(input: Value[SCollection[SBoolean.type]]): BoolValue
def mkAnyOf(input: Seq[Value[SBoolean.type]]): BoolValue
def mkAllOf(input: Seq[Value[SBoolean.type]]): BoolValue
@@ -54,23 +68,16 @@ trait SigmaBuilder {
right: Value[SGroupElement.type]): Value[SGroupElement.type]
def mkXor(left: Value[SByteArray], right: Value[SByteArray]): Value[SByteArray]
- def mkTreeModifications(tree: Value[SAvlTree.type],
- operations: Value[SByteArray],
- proof: Value[SByteArray]): Value[SOption[SByteArray]]
-
def mkTreeLookup(tree: Value[SAvlTree.type],
- key: Value[SByteArray],
- proof: Value[SByteArray]): Value[SOption[SByteArray]]
-
- def mkIsMember(tree: Value[SAvlTree.type],
- key: Value[SByteArray],
- proof: Value[SByteArray]): Value[SBoolean.type]
+ key: Value[SByteArray],
+ proof: Value[SByteArray]): Value[SOption[SByteArray]]
def mkIf[T <: SType](condition: Value[SBoolean.type],
trueBranch: Value[T],
falseBranch: Value[T]): Value[T]
def mkLongToByteArray(input: Value[SLong.type]): Value[SByteArray]
+ def mkByteArrayToLong(input: Value[SByteArray]): Value[SLong.type]
def mkByteArrayToBigInt(input: Value[SByteArray]): Value[SBigInt.type]
def mkUpcast[T <: SNumericType, R <: SNumericType](input: Value[T], tpe: R): Value[R]
def mkDowncast[T <: SNumericType, R <: SNumericType](input: Value[T], tpe: R): Value[R]
@@ -99,15 +106,15 @@ trait SigmaBuilder {
def mkForAll[IV <: SType](input: Value[SCollection[IV]],
condition: Value[SFunc]): Value[SBoolean.type]
- def mkFuncValue(args: IndexedSeq[(Int,SType)], body: Value[SType]): Value[SFunc]
+ def mkFuncValue(args: IndexedSeq[(Int, SType)], body: Value[SType]): Value[SFunc]
def mkFold[IV <: SType, OV <: SType](input: Value[SCollection[IV]],
- zero: Value[OV],
- foldOp: Value[SFunc]): Value[OV]
+ zero: Value[OV],
+ foldOp: Value[SFunc]): Value[OV]
def mkByIndex[IV <: SType](input: Value[SCollection[IV]],
- index: Value[SInt.type],
- default: Option[Value[IV]] = None): Value[IV]
+ index: Value[SInt.type],
+ default: Option[Value[IV]] = None): Value[IV]
def mkSelectField(input: Value[STuple], fieldIndex: Byte): Value[SType]
def mkSizeOf[IV <: SType](input: Value[SCollection[IV]]): Value[SInt.type]
@@ -119,8 +126,8 @@ trait SigmaBuilder {
def mkExtractCreationInfo(input: Value[SBox.type]): Value[STuple]
def mkExtractRegisterAs[IV <: SType](input: Value[SBox.type],
- registerId: RegisterId,
- tpe: SOption[IV]): Value[SType]
+ registerId: RegisterId,
+ tpe: SOption[IV]): Value[SType]
def mkDeserializeContext[T <: SType](id: Byte, tpe: T): Value[T]
def mkDeserializeRegister[T <: SType](reg: RegisterId,
@@ -129,11 +136,17 @@ trait SigmaBuilder {
def mkTuple(items: Seq[Value[SType]]): Value[SType]
- def mkProveDiffieHellmanTuple(gv: Value[SGroupElement.type],
- hv: Value[SGroupElement.type],
- uv: Value[SGroupElement.type],
- vv: Value[SGroupElement.type]): SigmaBoolean
- def mkProveDlog(value: Value[SGroupElement.type]): SigmaBoolean
+ def mkCreateProveDHTuple(gv: Value[SGroupElement.type],
+ hv: Value[SGroupElement.type],
+ uv: Value[SGroupElement.type],
+ vv: Value[SGroupElement.type]): SigmaPropValue
+
+ def mkCreateProveDlog(value: Value[SGroupElement.type]): SigmaPropValue
+
+ def mkCreateAvlTree(operationFlags: ByteValue,
+ digest: Value[SByteArray],
+ keyLength: IntValue,
+ valueLengthOpt: Value[SIntOption]): AvlTreeValue
/** Logically inverse to mkSigmaPropIsProven */
def mkBoolToSigmaProp(value: BoolValue): SigmaPropValue
@@ -162,24 +175,27 @@ trait SigmaBuilder {
def mkApply(func: Value[SType], args: IndexedSeq[Value[SType]]): Value[SType]
def mkApplyTypes(input: Value[SType], tpeArgs: Seq[SType]): Value[SType]
def mkMethodCallLike(obj: Value[SType],
- name: String,
- args: IndexedSeq[Value[SType]],
- tpe: SType = NoType): Value[SType]
+ name: String,
+ args: IndexedSeq[Value[SType]],
+ tpe: SType = NoType): Value[SType]
+
def mkMethodCall(obj: Value[SType],
- method: SMethod,
- args: IndexedSeq[Value[SType]]): Value[SType]
- def mkLambda(args: IndexedSeq[(String,SType)],
- givenResType: SType,
- body: Option[Value[SType]]): Value[SFunc]
- def mkGenLambda(tpeParams: Seq[STypeParam], args: IndexedSeq[(String,SType)],
+ method: SMethod,
+ args: IndexedSeq[Value[SType]],
+ typeSubst: STypeSubst): Value[SType]
+ def mkLambda(args: IndexedSeq[(String, SType)],
givenResType: SType,
body: Option[Value[SType]]): Value[SFunc]
+ def mkGenLambda(tpeParams: Seq[STypeParam], args: IndexedSeq[(String, SType)],
+ givenResType: SType,
+ body: Option[Value[SType]]): Value[SFunc]
+
def mkConstant[T <: SType](value: T#WrappedType, tpe: T): Constant[T]
def mkConstantPlaceholder[T <: SType](id: Int, tpe: T): Value[SType]
def mkCollectionConstant[T <: SType](values: Array[T#WrappedType],
elementType: T): Constant[SCollection[T]]
- def mkStringConcat(left: Value[SString.type], right: Value[SString.type]): Value[SString.type]
+ def mkStringConcat(left: Constant[SString.type], right: Constant[SString.type]): Value[SString.type]
def mkGetVar[T <: SType](varId: Byte, tpe: T): Value[SOption[T]]
def mkOptionGet[T <: SType](input: Value[SOption[T]]): Value[T]
@@ -197,8 +213,11 @@ trait SigmaBuilder {
def mkBitOr[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitAnd[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
def mkBitXor[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
- def mkBitShiftRight[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
- def mkBitShiftLeft[T <: SNumericType](left: Value[T], right: Value[T]): Value[T]
+ def mkBitShiftRight[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T]
+ def mkBitShiftLeft[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T]
+ def mkBitShiftRightZeroed[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T]
+
+ def mkUnitConstant: Value[SUnit.type]
def liftAny(v: Any): Nullable[SValue] = v match {
case arr: Array[Boolean] => Nullable(mkCollectionConstant[SBoolean.type](arr, SBoolean))
@@ -212,52 +231,71 @@ trait SigmaBuilder {
case v: Short => Nullable(mkConstant[SShort.type](v, SShort))
case v: Int => Nullable(mkConstant[SInt.type](v, SInt))
case v: Long => Nullable(mkConstant[SLong.type](v, SLong))
+
case v: BigInteger => Nullable(mkConstant[SBigInt.type](v, SBigInt))
- case v: CryptoConstants.EcPointType => Nullable(mkConstant[SGroupElement.type](v, SGroupElement))
+ case n: special.sigma.BigInt => Nullable(mkConstant[SBigInt.type](CostingSigmaDslBuilder.toBigInteger(n), SBigInt))
+
+ case v: EcPointType => Nullable(mkConstant[SGroupElement.type](v, SGroupElement))
+ case ge: GroupElement => Nullable(mkConstant[SGroupElement.type](CostingSigmaDslBuilder.toECPoint(ge).asInstanceOf[EcPointType], SGroupElement))
+
case b: Boolean => Nullable(if(b) TrueLeaf else FalseLeaf)
case v: String => Nullable(mkConstant[SString.type](v, SString))
case b: ErgoBox => Nullable(mkConstant[SBox.type](b, SBox))
+
case avl: AvlTreeData => Nullable(mkConstant[SAvlTree.type](avl, SAvlTree))
+ case avl: AvlTree => Nullable(mkConstant[SAvlTree.type](CostingSigmaDslBuilder.toAvlTreeData(avl), SAvlTree))
+
case sb: SigmaBoolean => Nullable(mkConstant[SSigmaProp.type](sb, SSigmaProp))
+ case p: SigmaProp => Nullable(mkConstant[SSigmaProp.type](CostingSigmaDslBuilder.toSigmaBoolean(p), SSigmaProp))
+
+ case coll: Coll[a] =>
+ implicit val tA = coll.tItem
+ Nullable(coll.toTreeData)
case v: SValue => Nullable(v)
case _ => Nullable.None
}
+
+ def unliftAny(v: SValue): Nullable[Any] = v match {
+ case Constant(v, t) => Nullable(v)
+ case _ => Nullable.None
+ }
}
class StdSigmaBuilder extends SigmaBuilder {
protected def equalityOp[T <: SType, R](left: Value[T],
- right: Value[T],
- cons: (Value[T], Value[T]) => R): R = cons(left, right)
-
- protected def comparisonOp[T <: SType, R](left: Value[T],
right: Value[T],
cons: (Value[T], Value[T]) => R): R = cons(left, right)
- protected def arithOp[T <: SNumericType, R](left: Value[T],
+ protected def comparisonOp[T <: SType, R](left: Value[T],
right: Value[T],
cons: (Value[T], Value[T]) => R): R = cons(left, right)
+ protected def arithOp[T <: SNumericType, R](left: Value[T],
+ right: Value[T],
+ cons: (Value[T], Value[T]) => R): R = cons(left, right)
+
override def mkEQ[T <: SType](left: Value[T], right: Value[T]): Value[SBoolean.type] =
- equalityOp(left, right, EQ.apply[T])
+ equalityOp(left, right, EQ.apply[T]).withSrcCtx(currentSrcCtx.value)
override def mkNEQ[T <: SType](left: Value[T], right: Value[T]): Value[SBoolean.type] =
- equalityOp(left, right, NEQ.apply[T])
+ equalityOp(left, right, NEQ.apply[T]).withSrcCtx(currentSrcCtx.value)
override def mkGT[T <: SType](left: Value[T], right: Value[T]): Value[SBoolean.type] =
- comparisonOp(left, right, GT.apply[T])
+ comparisonOp(left, right, GT.apply[T]).withSrcCtx(currentSrcCtx.value)
override def mkGE[T <: SType](left: Value[T], right: Value[T]): Value[SBoolean.type] =
- comparisonOp(left, right, GE.apply[T])
+ comparisonOp(left, right, GE.apply[T]).withSrcCtx(currentSrcCtx.value)
override def mkLT[T <: SType](left: Value[T], right: Value[T]): Value[SBoolean.type] =
- comparisonOp(left, right, LT.apply[T])
+ comparisonOp(left, right, LT.apply[T]).withSrcCtx(currentSrcCtx.value)
override def mkLE[T <: SType](left: Value[T], right: Value[T]): Value[SBoolean.type] =
- comparisonOp(left, right, LE.apply[T])
+ comparisonOp(left, right, LE.apply[T]).withSrcCtx(currentSrcCtx.value)
override def mkArith[T <: SNumericType](left: Value[T], right: Value[T], opCode: Byte): Value[T] =
arithOp(left, right, { (l: Value[T], r: Value[T]) => ArithOp[T](l, r, opCode) })
+ .withSrcCtx(currentSrcCtx.value)
override def mkPlus[T <: SNumericType](left: Value[T], right: Value[T]): Value[T] =
mkArith(left, right, OpCodes.PlusCode)
@@ -281,300 +319,325 @@ class StdSigmaBuilder extends SigmaBuilder {
mkArith(left, right, OpCodes.MaxCode)
override def mkOR(input: Value[SCollection[SBoolean.type]]): Value[SBoolean.type] =
- OR(input)
+ OR(input).withSrcCtx(currentSrcCtx.value)
override def mkAND(input: Value[SCollection[SBoolean.type]]): Value[SBoolean.type] =
- AND(input)
+ AND(input).withSrcCtx(currentSrcCtx.value)
+
+ override def mkXorOf(input: Value[SCollection[SBoolean.type]]): BoolValue =
+ XorOf(input).withSrcCtx(currentSrcCtx.value)
- override def mkAnyOf(input: Seq[Value[SBoolean.type]]) = OR(input)
- override def mkAllOf(input: Seq[Value[SBoolean.type]]) = AND(input)
+ override def mkAnyOf(input: Seq[Value[SBoolean.type]]) =
+ OR(input).withSrcCtx(currentSrcCtx.value)
+ override def mkAllOf(input: Seq[Value[SBoolean.type]]) =
+ AND(input).withSrcCtx(currentSrcCtx.value)
- override def mkBinOr(left: BoolValue, right: BoolValue) = BinOr(left, right)
+ override def mkBinOr(left: BoolValue, right: BoolValue) =
+ BinOr(left, right).withSrcCtx(currentSrcCtx.value)
- override def mkBinAnd(left: BoolValue, right: BoolValue) = BinAnd(left, right)
+ override def mkBinAnd(left: BoolValue, right: BoolValue) =
+ BinAnd(left, right).withSrcCtx(currentSrcCtx.value)
override def mkAtLeast(bound: Value[SInt.type], input: Value[SCollection[SSigmaProp.type]]): SigmaPropValue =
- AtLeast(bound, input)
+ AtLeast(bound, input).withSrcCtx(currentSrcCtx.value)
- override def mkBinXor(left: BoolValue, right: BoolValue): BoolValue = BinXor(left, right)
+ override def mkBinXor(left: BoolValue, right: BoolValue): BoolValue =
+ BinXor(left, right).withSrcCtx(currentSrcCtx.value)
override def mkExponentiate(left: Value[SGroupElement.type], right: Value[SBigInt.type]): Value[SGroupElement.type] =
- Exponentiate(left, right)
+ Exponentiate(left, right).withSrcCtx(currentSrcCtx.value)
override def mkMultiplyGroup(left: Value[SGroupElement.type], right: Value[SGroupElement.type]): Value[SGroupElement.type] =
- MultiplyGroup(left, right)
+ MultiplyGroup(left, right).withSrcCtx(currentSrcCtx.value)
override def mkXor(left: Value[SByteArray], right: Value[SByteArray]): Value[SByteArray] =
- Xor(left, right)
+ Xor(left, right).withSrcCtx(currentSrcCtx.value)
override def mkTreeLookup(tree: Value[SAvlTree.type],
- key: Value[SByteArray],
- proof: Value[SByteArray]): Value[SOption[SByteArray]] =
- TreeLookup(tree, key, proof)
-
- override def mkTreeModifications(tree: Value[SAvlTree.type],
- operations: Value[SByteArray],
- proof: Value[SByteArray]): Value[SOption[SByteArray]] =
- TreeModifications(tree, operations, proof)
-
- override def mkIsMember(tree: Value[SAvlTree.type],
- key: Value[SByteArray],
- proof: Value[SByteArray]): Value[SBoolean.type] =
- OptionIsDefined(TreeLookup(tree, key, proof))
+ key: Value[SByteArray],
+ proof: Value[SByteArray]): Value[SOption[SByteArray]] =
+ TreeLookup(tree, key, proof).withSrcCtx(currentSrcCtx.value)
override def mkIf[T <: SType](condition: Value[SBoolean.type],
trueBranch: Value[T],
falseBranch: Value[T]): Value[T] =
- If(condition, trueBranch, falseBranch)
+ If(condition, trueBranch, falseBranch).withSrcCtx(currentSrcCtx.value)
override def mkLongToByteArray(input: Value[SLong.type]): Value[SByteArray] =
- LongToByteArray(input)
+ LongToByteArray(input).withSrcCtx(currentSrcCtx.value)
+
+ override def mkByteArrayToLong(input: Value[SByteArray]): Value[SLong.type] =
+ ByteArrayToLong(input).withSrcCtx(currentSrcCtx.value)
override def mkByteArrayToBigInt(input: Value[SByteArray]): Value[SBigInt.type] =
- ByteArrayToBigInt(input)
+ ByteArrayToBigInt(input).withSrcCtx(currentSrcCtx.value)
override def mkUpcast[T <: SNumericType, R <: SNumericType](input: Value[T],
tpe: R): Value[R] =
- Upcast(input, tpe)
+ Upcast(input, tpe).withSrcCtx(currentSrcCtx.value)
override def mkDowncast[T <: SNumericType, R <: SNumericType](input: Value[T], tpe: R): Value[R] =
- Downcast(input, tpe)
+ Downcast(input, tpe).withSrcCtx(currentSrcCtx.value)
override def mkCalcBlake2b256(input: Value[SByteArray]): Value[SByteArray] =
- CalcBlake2b256(input)
+ CalcBlake2b256(input).withSrcCtx(currentSrcCtx.value)
override def mkCalcSha256(input: Value[SByteArray]): Value[SByteArray] =
- CalcSha256(input)
+ CalcSha256(input).withSrcCtx(currentSrcCtx.value)
override def mkDecodePoint(input: Value[SByteArray]): GroupElementValue =
- DecodePoint(input)
+ DecodePoint(input).withSrcCtx(currentSrcCtx.value)
override def mkMapCollection[IV <: SType, OV <: SType](input: Value[SCollection[IV]],
mapper: Value[SFunc]): Value[SCollection[OV]] =
- MapCollection(input, mapper)
+ MapCollection(input, mapper).withSrcCtx(currentSrcCtx.value)
override def mkAppend[IV <: SType](input: Value[SCollection[IV]],
col2: Value[SCollection[IV]]): Value[SCollection[IV]] =
- Append(input, col2)
+ Append(input, col2).withSrcCtx(currentSrcCtx.value)
override def mkSlice[IV <: SType](input: Value[SCollection[IV]],
from: Value[SInt.type],
until: Value[SInt.type]): Value[SCollection[IV]] =
- Slice(input, from, until)
+ Slice(input, from, until).withSrcCtx(currentSrcCtx.value)
override def mkFilter[IV <: SType](input: Value[SCollection[IV]],
id: Byte,
condition: Value[SBoolean.type]): Value[SCollection[IV]] =
- Filter(input, id, condition)
+ Filter(input, id, condition).withSrcCtx(currentSrcCtx.value)
override def mkExists[IV <: SType](input: Value[SCollection[IV]],
condition: Value[SFunc]): Value[SBoolean.type] =
- Exists(input, condition)
+ Exists(input, condition).withSrcCtx(currentSrcCtx.value)
override def mkForAll[IV <: SType](input: Value[SCollection[IV]],
condition: Value[SFunc]): Value[SBoolean.type] =
- ForAll(input, condition)
+ ForAll(input, condition).withSrcCtx(currentSrcCtx.value)
def mkFuncValue(args: IndexedSeq[(Int,SType)], body: Value[SType]): Value[SFunc] =
- FuncValue(args, body)
+ FuncValue(args, body).withSrcCtx(currentSrcCtx.value)
override def mkFold[IV <: SType, OV <: SType](input: Value[SCollection[IV]],
zero: Value[OV],
foldOp: Value[SFunc]): Value[OV] =
- Fold(input, zero, foldOp)
+ Fold(input, zero, foldOp).withSrcCtx(currentSrcCtx.value)
override def mkByIndex[IV <: SType](input: Value[SCollection[IV]],
index: Value[SInt.type],
default: Option[Value[IV]] = None): Value[IV] =
- ByIndex(input, index, default)
+ ByIndex(input, index, default).withSrcCtx(currentSrcCtx.value)
override def mkSelectField(input: Value[STuple], fieldIndex: Byte): Value[SType] =
- SelectField(input, fieldIndex)
+ SelectField(input, fieldIndex).withSrcCtx(currentSrcCtx.value)
override def mkSizeOf[V <: SType](input: Value[SCollection[V]]): Value[SInt.type] =
- SizeOf(input)
+ SizeOf(input).withSrcCtx(currentSrcCtx.value)
override def mkExtractAmount(input: Value[SBox.type]): Value[SLong.type] =
- ExtractAmount(input)
+ ExtractAmount(input).withSrcCtx(currentSrcCtx.value)
override def mkExtractScriptBytes(input: Value[SBox.type]): Value[SByteArray] =
- ExtractScriptBytes(input)
+ ExtractScriptBytes(input).withSrcCtx(currentSrcCtx.value)
override def mkExtractBytes(input: Value[SBox.type]): Value[SByteArray] =
- ExtractBytes(input)
+ ExtractBytes(input).withSrcCtx(currentSrcCtx.value)
override def mkExtractBytesWithNoRef(input: Value[SBox.type]): Value[SByteArray] =
- ExtractBytesWithNoRef(input)
+ ExtractBytesWithNoRef(input).withSrcCtx(currentSrcCtx.value)
override def mkExtractId(input: Value[SBox.type]): Value[SByteArray] =
- ExtractId(input)
+ ExtractId(input).withSrcCtx(currentSrcCtx.value)
override def mkExtractCreationInfo(input: Value[SBox.type]): Value[STuple] =
- ExtractCreationInfo(input)
+ ExtractCreationInfo(input).withSrcCtx(currentSrcCtx.value)
override def mkExtractRegisterAs[IV <: SType](input: Value[SBox.type],
registerId: RegisterId,
tpe: SOption[IV]): Value[SType] =
- ExtractRegisterAs(input, registerId, tpe)
+ ExtractRegisterAs(input, registerId, tpe).withSrcCtx(currentSrcCtx.value)
override def mkDeserializeContext[T <: SType](id: Byte, tpe: T): Value[T] =
- DeserializeContext(id, tpe)
+ DeserializeContext(id, tpe).withSrcCtx(currentSrcCtx.value)
override def mkDeserializeRegister[T <: SType](reg: RegisterId,
tpe: T,
default: Option[Value[T]] = None): Value[T] =
- DeserializeRegister(reg, tpe, default)
+ DeserializeRegister(reg, tpe, default).withSrcCtx(currentSrcCtx.value)
override def mkTuple(items: Seq[Value[SType]]): Value[SType] =
- Tuple(items.toIndexedSeq)
-
- override def mkProveDiffieHellmanTuple(gv: Value[SGroupElement.type],
- hv: Value[SGroupElement.type],
- uv: Value[SGroupElement.type],
- vv: Value[SGroupElement.type]): SigmaBoolean =
- ProveDHTuple(gv, hv, uv, vv)
-
- override def mkProveDlog(value: Value[SGroupElement.type]): SigmaBoolean =
- ProveDlog(value)
+ Tuple(items.toIndexedSeq).withSrcCtx(currentSrcCtx.value)
+
+ override def mkCreateProveDHTuple(gv: Value[SGroupElement.type],
+ hv: Value[SGroupElement.type],
+ uv: Value[SGroupElement.type],
+ vv: Value[SGroupElement.type]): SigmaPropValue =
+ CreateProveDHTuple(gv, hv, uv, vv)
+
+ override def mkCreateProveDlog(value: Value[SGroupElement.type]): SigmaPropValue =
+ CreateProveDlog(value)
+
+ override def mkCreateAvlTree(operationFlags: ByteValue,
+ digest: Value[SByteArray],
+ keyLength: IntValue,
+ valueLengthOpt: Value[SIntOption]): AvlTreeValue = {
+ CreateAvlTree(operationFlags, digest, keyLength, valueLengthOpt)
+ }
- override def mkBoolToSigmaProp(value: BoolValue) = BoolToSigmaProp(value)
+ override def mkBoolToSigmaProp(value: BoolValue): SigmaPropValue =
+ BoolToSigmaProp(value).withSrcCtx(currentSrcCtx.value)
- override def mkSigmaPropIsProven(value: Value[SSigmaProp.type]) = SigmaPropIsProven(value)
+ override def mkSigmaPropIsProven(value: Value[SSigmaProp.type]): BoolValue =
+ SigmaPropIsProven(value).withSrcCtx(currentSrcCtx.value)
- override def mkSigmaPropBytes(value: Value[SSigmaProp.type]) = SigmaPropBytes(value)
+ override def mkSigmaPropBytes(value: Value[SSigmaProp.type]): Value[SByteArray] =
+ SigmaPropBytes(value).withSrcCtx(currentSrcCtx.value)
- override def mkSigmaAnd(items: Seq[SigmaPropValue]): SigmaPropValue = SigmaAnd(items)
+ override def mkSigmaAnd(items: Seq[SigmaPropValue]): SigmaPropValue =
+ SigmaAnd(items).withSrcCtx(currentSrcCtx.value)
- override def mkSigmaOr(items: Seq[SigmaPropValue]): SigmaPropValue = SigmaOr(items)
+ override def mkSigmaOr(items: Seq[SigmaPropValue]): SigmaPropValue =
+ SigmaOr(items).withSrcCtx(currentSrcCtx.value)
override def mkConcreteCollection[T <: SType](items: IndexedSeq[Value[T]],
elementType: T): Value[SCollection[T]] =
- ConcreteCollection(items, elementType)
+ ConcreteCollection(items, elementType).withSrcCtx(currentSrcCtx.value)
override def mkTaggedVariable[T <: SType](varId: Byte, tpe: T): TaggedVariable[T] =
- TaggedVariableNode(varId, tpe)
+ TaggedVariableNode(varId, tpe).withSrcCtx(currentSrcCtx.value).asInstanceOf[TaggedVariable[T]]
- override def mkSomeValue[T <: SType](x: Value[T]): Value[SOption[T]] = SomeValue(x)
- override def mkNoneValue[T <: SType](elemType: T): Value[SOption[T]] = NoneValue(elemType)
+ override def mkSomeValue[T <: SType](x: Value[T]): Value[SOption[T]] =
+ SomeValue(x).withSrcCtx(currentSrcCtx.value)
+ override def mkNoneValue[T <: SType](elemType: T): Value[SOption[T]] =
+ NoneValue(elemType).withSrcCtx(currentSrcCtx.value)
override def mkBlock(bindings: Seq[Val], result: Value[SType]): Value[SType] =
- Block(bindings, result)
+ Block(bindings, result).withSrcCtx(currentSrcCtx.value)
override def mkBlockValue(items: IndexedSeq[BlockItem], result: Value[SType]): Value[SType] =
- BlockValue(items, result)
+ BlockValue(items, result).withSrcCtx(currentSrcCtx.value)
override def mkValUse(valId: Int, tpe: SType): Value[SType] =
- ValUse(valId, tpe)
+ ValUse(valId, tpe).withSrcCtx(currentSrcCtx.value)
override def mkZKProofBlock(body: Value[SSigmaProp.type]): BoolValue =
- ZKProofBlock(body)
+ ZKProofBlock(body).withSrcCtx(currentSrcCtx.value)
- override def mkVal(name: String, givenType: SType, body: Value[SType]): Val =
- ValNode(name, givenType, body)
+ override def mkVal(name: String,
+ givenType: SType,
+ body: Value[SType]): Val = {
+ ValNode(name, givenType, body).withSrcCtx(currentSrcCtx.value).asInstanceOf[Val]
+ }
override def mkSelect(obj: Value[SType],
field: String,
resType: Option[SType] = None): Value[SType] =
- Select(obj, field, resType)
+ Select(obj, field, resType).withSrcCtx(currentSrcCtx.value)
- override def mkIdent(name: String, tpe: SType): Value[SType] = Ident(name, tpe)
+ override def mkIdent(name: String, tpe: SType): Value[SType] =
+ Ident(name, tpe).withSrcCtx(currentSrcCtx.value)
override def mkApply(func: Value[SType], args: IndexedSeq[Value[SType]]): Value[SType] =
- Apply(func, args)
+ Apply(func, args).withSrcCtx(currentSrcCtx.value)
override def mkApplyTypes(input: Value[SType], tpeArgs: Seq[SType]): Value[SType] =
- ApplyTypes(input, tpeArgs)
+ ApplyTypes(input, tpeArgs).withSrcCtx(currentSrcCtx.value)
override def mkMethodCallLike(obj: Value[SType],
name: String,
args: IndexedSeq[Value[SType]],
tpe: SType): Value[SType] =
- MethodCallLike(obj, name, args, tpe)
+ MethodCallLike(obj, name, args, tpe).withSrcCtx(currentSrcCtx.value)
override def mkMethodCall(obj: Value[SType],
method: SMethod,
- args: IndexedSeq[Value[SType]]): Value[SType] =
- MethodCall(obj, method, args)
+ args: IndexedSeq[Value[SType]],
+ typeSubst: STypeSubst = Map()): Value[SType] =
+ MethodCall(obj, method, args, typeSubst).withSrcCtx(currentSrcCtx.value)
override def mkLambda(args: IndexedSeq[(String, SType)],
givenResType: SType,
body: Option[Value[SType]]): Value[SFunc] =
- Lambda(Nil, args, givenResType, body)
+ Lambda(Nil, args, givenResType, body).withSrcCtx(currentSrcCtx.value)
def mkGenLambda(tpeParams: Seq[STypeParam],
args: IndexedSeq[(String, SType)],
givenResType: SType,
body: Option[Value[SType]]) =
- Lambda(tpeParams, args, givenResType, body)
+ Lambda(tpeParams, args, givenResType, body).withSrcCtx(currentSrcCtx.value)
override def mkConstant[T <: SType](value: T#WrappedType, tpe: T): Constant[T] =
- ConstantNode[T](value, tpe)
+ ConstantNode[T](value, tpe).withSrcCtx(currentSrcCtx.value).asInstanceOf[Constant[T]]
override def mkConstantPlaceholder[T <: SType](id: Int, tpe: T): Value[SType] =
- ConstantPlaceholder[T](id, tpe)
+ ConstantPlaceholder[T](id, tpe).withSrcCtx(currentSrcCtx.value)
override def mkCollectionConstant[T <: SType](values: Array[T#WrappedType],
elementType: T): Constant[SCollection[T]] =
ConstantNode[SCollection[T]](values, SCollection(elementType))
+ .withSrcCtx(currentSrcCtx.value).asInstanceOf[ConstantNode[SCollection[T]]]
- override def mkStringConcat(left: Value[SString.type], right: Value[SString.type]): Value[SString.type] =
- StringConcat(left, right)
+ override def mkStringConcat(left: Constant[SString.type], right: Constant[SString.type]): Value[SString.type] =
+ StringConstant(left.value + right.value).withSrcCtx(currentSrcCtx.value)
override def mkGetVar[T <: SType](varId: Byte, tpe: T): Value[SOption[T]] =
- GetVar(varId, tpe)
+ GetVar(varId, tpe).withSrcCtx(currentSrcCtx.value)
override def mkOptionGet[T <: SType](input: Value[SOption[T]]): Value[T] =
- OptionGet(input)
+ OptionGet(input).withSrcCtx(currentSrcCtx.value)
override def mkOptionGetOrElse[T <: SType](input: Value[SOption[T]], default: Value[T]): Value[T] =
- OptionGetOrElse(input, default)
+ OptionGetOrElse(input, default).withSrcCtx(currentSrcCtx.value)
override def mkOptionIsDefined[T <: SType](input: Value[SOption[T]]): Value[SBoolean.type] =
- OptionIsDefined(input)
+ OptionIsDefined(input).withSrcCtx(currentSrcCtx.value)
override def mkModQ(input: Value[SBigInt.type]): Value[SBigInt.type] =
- ModQ(input)
+ ModQ(input).withSrcCtx(currentSrcCtx.value)
override def mkPlusModQ(left: Value[SBigInt.type], right: Value[SBigInt.type]): Value[SBigInt.type] =
- ModQArithOp(left, right, OpCodes.PlusModQCode)
+ ModQArithOp(left, right, OpCodes.PlusModQCode).withSrcCtx(currentSrcCtx.value)
override def mkMinusModQ(left: Value[SBigInt.type], right: Value[SBigInt.type]): Value[SBigInt.type] =
- ModQArithOp(left, right, OpCodes.MinusModQCode)
+ ModQArithOp(left, right, OpCodes.MinusModQCode).withSrcCtx(currentSrcCtx.value)
override def mkLogicalNot(input: Value[SBoolean.type]): Value[SBoolean.type] =
- LogicalNot(input)
+ LogicalNot(input).withSrcCtx(currentSrcCtx.value)
override def mkNegation[T <: SNumericType](input: Value[T]): Value[T] =
- Negation(input)
+ Negation(input).withSrcCtx(currentSrcCtx.value)
override def mkBitInversion[T <: SNumericType](input: Value[T]): Value[T] =
- BitInversion(input)
+ BitInversion(input).withSrcCtx(currentSrcCtx.value)
override def mkBitOr[T <: SNumericType](left: Value[T], right: Value[T]): Value[T] =
- BitOp(left, right, OpCodes.BitOrCode)
+ BitOp(left, right, OpCodes.BitOrCode).withSrcCtx(currentSrcCtx.value)
override def mkBitAnd[T <: SNumericType](left: Value[T], right: Value[T]): Value[T] =
- BitOp(left, right, OpCodes.BitAndCode)
+ BitOp(left, right, OpCodes.BitAndCode).withSrcCtx(currentSrcCtx.value)
override def mkBitXor[T <: SNumericType](left: Value[T], right: Value[T]): Value[T] =
- BitOp(left, right, OpCodes.BitXorCode)
+ BitOp(left, right, OpCodes.BitXorCode).withSrcCtx(currentSrcCtx.value)
override def mkBitShiftRight[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T] =
- BitOp(bits, shift, OpCodes.BitShiftRightCode)
+ BitOp(bits, shift, OpCodes.BitShiftRightCode).withSrcCtx(currentSrcCtx.value)
override def mkBitShiftLeft[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T] =
- BitOp(bits, shift, OpCodes.BitShiftLeftCode)
+ BitOp(bits, shift, OpCodes.BitShiftLeftCode).withSrcCtx(currentSrcCtx.value)
+ override def mkBitShiftRightZeroed[T <: SNumericType](bits: Value[T], shift: Value[T]): Value[T] =
+ BitOp(bits, shift, OpCodes.BitShiftRightZeroedCode).withSrcCtx(currentSrcCtx.value)
+
+ override def mkUnitConstant: Value[SUnit.type] = UnitConstant().withSrcCtx(currentSrcCtx.value)
}
trait TypeConstraintCheck {
def check2[T <: SType](left: Value[T],
- right: Value[T],
- constraints: Seq[TypeConstraint2]): Unit =
+ right: Value[T],
+ constraints: Seq[TypeConstraint2]): Unit =
constraints.foreach { c =>
if (!c(left.tpe, right.tpe))
throw new ConstraintFailed(s"Failed constraint $c for binary operation parameters ($left(tpe: ${left.tpe}), $right(tpe: ${right.tpe}))")
@@ -583,7 +646,7 @@ trait TypeConstraintCheck {
trait TransformingSigmaBuilder extends StdSigmaBuilder with TypeConstraintCheck {
- private def applyUpcast[T <: SType](left: Value[T], right: Value[T]):(Value[T], Value[T]) =
+ private def applyUpcast[T <: SType](left: Value[T], right: Value[T]): (Value[T], Value[T]) =
(left.tpe, right.tpe) match {
case (t1: SNumericType, t2: SNumericType) if t1 != t2 =>
val tmax = t1 max t2
@@ -595,16 +658,16 @@ trait TransformingSigmaBuilder extends StdSigmaBuilder with TypeConstraintCheck
}
override protected def equalityOp[T <: SType, R](left: Value[T],
- right: Value[T],
- cons: (Value[T], Value[T]) => R): R = {
+ right: Value[T],
+ cons: (Value[T], Value[T]) => R): R = {
val (l, r) = applyUpcast(left, right)
check2(l, r, Seq(sameType2))
cons(l, r)
}
override protected def comparisonOp[T <: SType, R](left: Value[T],
- right: Value[T],
- cons: (Value[T], Value[T]) => R): R = {
+ right: Value[T],
+ cons: (Value[T], Value[T]) => R): R = {
check2(left, right, Seq(onlyNumeric2))
val (l, r) = applyUpcast(left, right)
check2(l, r, Seq(sameType2))
@@ -612,8 +675,8 @@ trait TransformingSigmaBuilder extends StdSigmaBuilder with TypeConstraintCheck
}
override protected def arithOp[T <: SNumericType, R](left: Value[T],
- right: Value[T],
- cons: (Value[T], Value[T]) => R): R = {
+ right: Value[T],
+ cons: (Value[T], Value[T]) => R): R = {
val (l, r) = applyUpcast(left, right)
cons(l, r)
}
@@ -622,22 +685,22 @@ trait TransformingSigmaBuilder extends StdSigmaBuilder with TypeConstraintCheck
trait CheckingSigmaBuilder extends StdSigmaBuilder with TypeConstraintCheck {
override protected def equalityOp[T <: SType, R](left: Value[T],
- right: Value[T],
- cons: (Value[T], Value[T]) => R): R = {
+ right: Value[T],
+ cons: (Value[T], Value[T]) => R): R = {
check2(left, right, Seq(sameType2))
cons(left, right)
}
override protected def comparisonOp[T <: SType, R](left: Value[T],
- right: Value[T],
- cons: (Value[T], Value[T]) => R): R = {
+ right: Value[T],
+ cons: (Value[T], Value[T]) => R): R = {
check2(left, right, Seq(onlyNumeric2, sameType2))
cons(left, right)
}
override protected def arithOp[T <: SNumericType, R](left: Value[T],
- right: Value[T],
- cons: (Value[T], Value[T]) => R): R = {
+ right: Value[T],
+ cons: (Value[T], Value[T]) => R): R = {
check2(left, right, Seq(sameType2))
cons(left, right)
}
diff --git a/src/main/scala/sigmastate/lang/SigmaCompiler.scala b/src/main/scala/sigmastate/lang/SigmaCompiler.scala
index 2c5c76e70b..3468ec010c 100644
--- a/src/main/scala/sigmastate/lang/SigmaCompiler.scala
+++ b/src/main/scala/sigmastate/lang/SigmaCompiler.scala
@@ -1,27 +1,37 @@
package sigmastate.lang
-import sigmastate.SType
-import sigmastate.lang.syntax.ParserException
import fastparse.core.Parsed
import fastparse.core.Parsed.Success
import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
-import sigmastate.Values.{SValue, SigmaTree, Value}
+import org.ergoplatform.ErgoLikeContext
+import scalan.RType
+import sigmastate.{SBoolean, SType}
+import sigmastate.Values.{TrueLeaf, Value, Constant, SValue}
+import sigmastate.eval.{Evaluation, IRContext}
+import sigmastate.interpreter.Interpreter
import sigmastate.interpreter.Interpreter.ScriptEnv
+import sigmastate.lang.SigmaPredef.PredefinedFuncRegistry
+import sigmastate.lang.syntax.ParserException
-class SigmaCompiler(builder: SigmaBuilder) {
+/**
+ * @param networkPrefix network prefix to decode an ergo address from string (PK op)
+ * @param builder
+ */
+class SigmaCompiler(networkPrefix: NetworkPrefix, builder: SigmaBuilder) {
def parse(x: String): SValue = {
SigmaParser(x, builder) match {
case Success(v, i) => v
- case f: Parsed.Failure[_,_] =>
- throw new ParserException(s"Syntax error: $f", Some(f))
+ case f: Parsed.Failure[_,String] =>
+ throw new ParserException(s"Syntax error: $f", Some(SourceContext.fromParserFailure(f)))
}
}
def typecheck(env: ScriptEnv, parsed: SValue): Value[SType] = {
- val binder = new SigmaBinder(env, builder)
+ val predefinedFuncRegistry = new PredefinedFuncRegistry(builder)
+ val binder = new SigmaBinder(env, builder, networkPrefix, predefinedFuncRegistry)
val bound = binder.bind(parsed)
- val typer = new SigmaTyper(builder)
+ val typer = new SigmaTyper(builder, predefinedFuncRegistry)
val typed = typer.typecheck(bound)
typed
}
@@ -31,14 +41,21 @@ class SigmaCompiler(builder: SigmaBuilder) {
typecheck(env, parsed)
}
- def compile(env: ScriptEnv, code: String, networkPrefix: NetworkPrefix): Value[SType] = {
+ private[sigmastate] def compileWithoutCosting(env: ScriptEnv, code: String): Value[SType] = {
val typed = typecheck(env, code)
- val spec = new SigmaSpecializer(builder, networkPrefix)
+ val spec = new SigmaSpecializer(builder)
val ir = spec.specialize(typed)
ir
}
+
+ def compile(env: ScriptEnv, code: String)(implicit IR: IRContext): Value[SType] = {
+ val interProp = typecheck(env, code)
+ val IR.Pair(calcF, _) = IR.doCosting(env, interProp, true)
+ IR.buildTree(calcF)
+ }
}
object SigmaCompiler {
- def apply(builder: SigmaBuilder = TransformingSigmaBuilder): SigmaCompiler = new SigmaCompiler(builder)
+ def apply(networkPrefix: NetworkPrefix, builder: SigmaBuilder = TransformingSigmaBuilder): SigmaCompiler =
+ new SigmaCompiler(networkPrefix, builder)
}
diff --git a/src/main/scala/sigmastate/lang/SigmaParser.scala b/src/main/scala/sigmastate/lang/SigmaParser.scala
index fbfbddec73..07f6988e20 100644
--- a/src/main/scala/sigmastate/lang/SigmaParser.scala
+++ b/src/main/scala/sigmastate/lang/SigmaParser.scala
@@ -4,16 +4,27 @@ import fastparse.core.Logger
import fastparse.core
import sigmastate._
import Values._
+import scalan.Nullable
import sigmastate.lang.Terms._
import sigmastate.SCollection.SByteArray
import sigmastate.lang.syntax.Basic._
import sigmastate.lang.syntax.{Core, Exprs}
import scala.collection.mutable
+import scala.util.DynamicVariable
object SigmaParser extends Exprs with Types with Core {
import fastparse.noApi._
import WhitespaceApi._
+ import builder._
+
+ val currentInput = new DynamicVariable[String]("")
+
+ override def atSrcPos[A](parserIndex: Int)(thunk: => A): A =
+ builder.currentSrcCtx.withValue(Nullable(srcCtx(parserIndex))) { thunk }
+
+ override def srcCtx(parserIndex: Int): SourceContext =
+ SourceContext.fromParserIndex(parserIndex, currentInput.value)
val TmplBody = {
val Prelude = P( (Annot ~ OneNLMax).rep )
@@ -25,9 +36,12 @@ object SigmaParser extends Exprs with Types with Core {
// P( (Id | `this`).! ~ LambdaDef ).map { case (name, lam) => builder.mkVal(name, NoType, lam) }
// }
- val ValVarDef = P( BindPattern/*.rep(1, ",".~/)*/ ~ (`:` ~/ Type).? ~ (`=` ~/ FreeCtx.Expr) ).map {
- case (Ident(n,_), t, body) => builder.mkVal(n, t.getOrElse(NoType), body)
- case (pat,_,_) => error(s"Only single name patterns supported but was $pat")
+ val ValVarDef = P( Index ~ BindPattern/*.rep(1, ",".~/)*/ ~ (`:` ~/ Type).? ~ (`=` ~/ FreeCtx.Expr) ).map {
+ case (index, Ident(n,_), t, body) =>
+ atSrcPos(index) {
+ mkVal(n, t.getOrElse(NoType), body)
+ }
+ case (index, pat,_,_) => error(s"Only single name patterns supported but was $pat", Some(srcCtx(index)))
}
val BlockDef = P( Dcl )
@@ -44,50 +58,54 @@ object SigmaParser extends Exprs with Types with Core {
val logged = mutable.Buffer.empty[String]
implicit val logger = Logger(m => this.synchronized { logged.append(m) })
- def mkUnaryOp(opName: String, arg: Value[SType]) = opName match {
- case "-" if arg.isInstanceOf[Constant[_]] && arg.tpe.isNumType =>
- arg match {
- case IntConstant(value) =>
- builder.mkConstant[SInt.type](-value, SInt)
- case LongConstant(value) =>
- builder.mkConstant[SLong.type](-value, SLong)
- case _ => error(s"cannot prefix $arg with op $opName")
+ def mkUnaryOp(opName: String, arg: Value[SType]) =
+ builder.currentSrcCtx.withValue(arg.sourceContext) {
+ opName match {
+ case "-" if arg.isInstanceOf[Constant[_]] && arg.tpe.isNumType =>
+ arg match {
+ case IntConstant(value) =>
+ mkConstant[SInt.type](-value, SInt)
+ case LongConstant(value) =>
+ mkConstant[SLong.type](-value, SLong)
+ case _ => error(s"cannot prefix $arg with op $opName", arg.sourceContext)
+ }
+ case "!" => mkLogicalNot(arg.asBoolValue)
+ case "-" => mkNegation(arg.asNumValue)
+ case "~" => mkBitInversion(arg.asNumValue)
+ case _ => error(s"Unknown prefix operation $opName for $arg", arg.sourceContext)
}
- case "!" => builder.mkLogicalNot(arg.asBoolValue)
- case "-" => builder.mkNegation(arg.asNumValue)
- case "~" => builder.mkBitInversion(arg.asNumValue)
- case _ => error(s"Unknown prefix operation $opName for $arg")
- }
+ }
val parseAsMethods = Set("*", "++", "||", "&&", "+", "^", "<<", ">>", ">>>")
- def mkBinaryOp(l: Value[SType], opName: String, r: Value[SType]): Value[SType] = opName match {
- case "==" => EQ(l, r)
- case "!=" => NEQ(l, r)
- case ">=" => GE(l, r)
- case ">" => GT(l, r)
- case "<=" => LE(l, r)
- case "<" => LT(l, r)
- case "-" => builder.mkMinus(l.asValue[SLong.type], r.asValue[SLong.type])
- case "|" => builder.mkBitOr(l.asNumValue, r.asNumValue)
- case "&" => builder.mkBitAnd(l.asNumValue, r.asNumValue)
- case _ if parseAsMethods.contains(opName) =>
- MethodCallLike(l, opName, IndexedSeq(r))
- case "/" => builder.mkDivide(l.asValue[SLong.type], r.asValue[SLong.type])
- case "%" => builder.mkModulo(l.asValue[SLong.type], r.asValue[SLong.type])
- case _ => error(s"Unknown binary operation $opName")
- }
-
- def apply(str: String, sigmaBuilder: SigmaBuilder): core.Parsed[Value[_ <: SType], Char, String] = {
- builder = sigmaBuilder
- (StatCtx.Expr ~ End).parse(str)
- }
+ def mkBinaryOp(l: Value[SType], opName: String, r: Value[SType]): Value[SType] =
+ builder.currentSrcCtx.withValue(l.sourceContext) {
+ opName match {
+ case "==" => mkEQ(l, r)
+ case "!=" => mkNEQ(l, r)
+ case ">=" => mkGE(l, r)
+ case ">" => mkGT(l, r)
+ case "<=" => mkLE(l, r)
+ case "<" => mkLT(l, r)
+ case "-" => mkMinus(l.asValue[SLong.type], r.asValue[SLong.type])
+ case "|" => mkBitOr(l.asNumValue, r.asNumValue)
+ case "&" => mkBitAnd(l.asNumValue, r.asNumValue)
+ case _ if parseAsMethods.contains(opName) => mkMethodCallLike(l, opName, IndexedSeq(r))
+ case "/" => mkDivide(l.asValue[SLong.type], r.asValue[SLong.type])
+ case "%" => mkModulo(l.asValue[SLong.type], r.asValue[SLong.type])
+ case _ => error(s"Unknown binary operation $opName", l.sourceContext)
+ }
+ }
def parsedType(str: String): core.Parsed[SType, Char, String] = (Type ~ End).parse(str)
- def parseType(x: String): SType = {
- val res = parsedType(x).get.value
+ def parseType(str: String): SType = {
+ val res = parsedType(str).get.value
res
}
+ def apply(script: String, sigmaBuilder: SigmaBuilder): core.Parsed[Value[_ <: SType], Char, String] =
+ currentInput.withValue(script) {
+ (StatCtx.Expr ~ End).parse(script)
+ }
}
diff --git a/src/main/scala/sigmastate/lang/SigmaPredef.scala b/src/main/scala/sigmastate/lang/SigmaPredef.scala
index 7cccb51d80..57c231e464 100644
--- a/src/main/scala/sigmastate/lang/SigmaPredef.scala
+++ b/src/main/scala/sigmastate/lang/SigmaPredef.scala
@@ -1,13 +1,21 @@
package sigmastate.lang
+import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix
+import org.ergoplatform.{ErgoAddressEncoder, P2PKAddress}
+import scalan.Nullable
+import scorex.util.encode.{Base58, Base64}
import sigmastate.SCollection.{SByteArray, SIntArray}
-import sigmastate.Values.{Value, SValue}
+import sigmastate.SOption._
+import sigmastate.Values.{BoolValue, ByteArrayConstant, Constant, EvaluatedValue, IntValue, SValue, SigmaPropConstant, SigmaPropValue, StringConstant, Value}
import sigmastate._
-import sigmastate.lang.Terms.{Lambda, STypeParam}
-import sigmastate.lang.TransformingSigmaBuilder._
+import sigmastate.lang.Terms._
+import sigmastate.lang.exceptions.InvalidArguments
+import sigmastate.serialization.ValueSerializer
object SigmaPredef {
+ type IrBuilderFunc = PartialFunction[(SValue, Seq[SValue]), SValue]
+
case class PredefinedFunc(
/** A name which is used in scripts */
name: String,
@@ -15,77 +23,283 @@ object SigmaPredef {
declaration: Lambda,
/** Builder of SigmaIR node which is equivalent to function application
* Rule: Apply(f, args) --> irBuilder(f, args) */
- irBuilder: (SValue, Seq[SValue]) => SValue
- )
-
- /** Type variable used in the signatures of global functions below.*/
- private val tT = STypeIdent("T")
-
- val predefinedEnv: Map[String, SValue] = Seq(
- "allOf" -> mkLambda(Vector("conditions" -> SCollection(SBoolean)), SBoolean, None),
- "anyOf" -> mkLambda(Vector("conditions" -> SCollection(SBoolean)), SBoolean, None),
- "atLeast" -> mkLambda(Vector("k" -> SInt, "conditions" -> SCollection(SSigmaProp)), SSigmaProp, None),
- "ZKProof" -> mkLambda(Vector("block" -> SSigmaProp), SBoolean, None),
- "sigmaProp" -> mkLambda(Vector("condition" -> SBoolean), SSigmaProp, None),
-
- "blake2b256" -> mkLambda(Vector("input" -> SByteArray), SByteArray, None),
- "sha256" -> mkLambda(Vector("input" -> SByteArray), SByteArray, None),
- "byteArrayToBigInt" -> mkLambda(Vector("input" -> SByteArray), SBigInt, None),
- "byteArrayToLong" -> mkLambda(Vector("input" -> SByteArray), SLong, None),
- "decodePoint" -> mkLambda(Vector("input" -> SByteArray), SGroupElement, None),
- "longToByteArray" -> mkLambda(Vector("input" -> SLong), SByteArray, None),
-
- "getVar" -> mkGenLambda(Seq(STypeParam(tT)), Vector("varId" -> SByte), SOption(tT), None),
-
- "proveDHTuple" -> mkLambda(Vector("g" -> SGroupElement, "h" -> SGroupElement, "u" -> SGroupElement, "v" -> SGroupElement), SSigmaProp, None),
- "proveDlog" -> mkLambda(Vector("value" -> SGroupElement), SSigmaProp, None),
-
- "isMember" -> mkLambda(Vector("tree" -> SAvlTree, "key" -> SByteArray, "proof" -> SByteArray), SBoolean, None),
- "treeLookup" -> mkLambda(Vector("tree" -> SAvlTree, "key" -> SByteArray, "proof" -> SByteArray), SOption[SByteArray], None),
- "treeModifications" -> mkLambda(Vector("tree" -> SAvlTree, "ops" -> SByteArray, "proof" -> SByteArray), SOption[SByteArray], None),
-
- "fromBase58" -> mkLambda(Vector("input" -> SString), SByteArray, None),
- "fromBase64" -> mkLambda(Vector("input" -> SString), SByteArray, None),
- "PK" -> mkLambda(Vector("input" -> SString), SSigmaProp, None),
- "deserialize" -> mkGenLambda(Seq(STypeParam(tT)), Vector("str" -> SString), SOption(tT), None),
- "substConstants" -> mkGenLambda(
- Seq(STypeParam(tT)),
- Vector("scriptBytes" -> SByteArray, "positions" -> SIntArray, "newValues" -> SCollection(tT)),
- SByteArray, None),
- ).toMap
-
- def PredefIdent(name: String): Value[SType] = {
- val v = predefinedEnv(name)
- mkIdent(name, v.tpe)
+ irBuilder: IrBuilderFunc) {
+
+ val sym: Ident = Ident(name, declaration.tpe)
+ val symNoType: Ident = Ident(name, NoType)
}
- val AllSym = PredefIdent("allOf")
- val AnySym = PredefIdent("anyOf")
- val AtLeastSym = PredefIdent("atLeast")
- val ZKProofSym = PredefIdent("ZKProof")
- val SigmaPropSym = PredefIdent("sigmaProp")
+ class PredefinedFuncRegistry(builder: SigmaBuilder) {
+
+ import builder._
+
+ /** Type variable used in the signatures of global functions below. */
+ private val tT = STypeIdent("T")
+ private val tK = STypeIdent("K")
+ private val tL = STypeIdent("L")
+ private val tR = STypeIdent("R")
+ private val tO = STypeIdent("O")
+
+ private val undefined: IrBuilderFunc =
+ PartialFunction.empty[(SValue, Seq[SValue]), SValue]
+
+ val AllOfFunc = PredefinedFunc("allOf",
+ Lambda(IndexedSeq("conditions" -> SCollection(SBoolean)), SBoolean, None),
+ { case (_, Seq(col: Value[SCollection[SBoolean.type]]@unchecked)) => mkAND(col) }
+ )
+
+ val AnyOfFunc = PredefinedFunc("anyOf",
+ Lambda(Vector("conditions" -> SCollection(SBoolean)), SBoolean, None),
+ { case (_, Seq(col: Value[SCollection[SBoolean.type]]@unchecked)) => mkOR(col) }
+ )
+
+ val AtLeastFunc = PredefinedFunc("atLeast",
+ Lambda(Vector("k" -> SInt, "conditions" -> SCollection(SSigmaProp)), SSigmaProp, None),
+ { case (_, Seq(bound: IntValue@unchecked, arr: Value[SCollection[SSigmaProp.type]]@unchecked)) =>
+ mkAtLeast(bound, arr)
+ }
+ )
+
+ val OuterJoinFunc = PredefinedFunc(
+ "outerJoin",
+ Lambda(
+ Seq(STypeParam(tK), STypeParam(tL), STypeParam(tR), STypeParam(tO)),
+ Vector(
+ "left" -> SCollection(STuple(tK, tL)),
+ "right" -> SCollection(STuple(tK, tR)),
+ "l" -> SFunc(IndexedSeq(tK, tL), tO),
+ "r" -> SFunc(IndexedSeq(tK, tR), tO),
+ "inner" -> SFunc(IndexedSeq(tK, tL, tR), tO),
+ ),
+ SCollection(STuple(tK, tO)), None),
+ undefined
+ )
+
+ val ZKProofFunc = PredefinedFunc("ZKProof",
+ Lambda(Vector("block" -> SSigmaProp), SBoolean, None),
+ { case (_, Seq(block: SigmaPropValue@unchecked)) => mkZKProofBlock(block) }
+ )
+
+ val SigmaPropFunc = PredefinedFunc("sigmaProp",
+ Lambda(Vector("condition" -> SBoolean), SSigmaProp, None),
+ { case (_, Seq(b: BoolValue@unchecked)) => mkBoolToSigmaProp(b) }
+ )
+
+ val GetVarFunc = PredefinedFunc("getVar",
+ Lambda(Seq(STypeParam(tT)), Vector("varId" -> SByte), SOption(tT), None),
+ { case (Ident(_, SFunc(_, SOption(rtpe), _)), Seq(id: Constant[SNumericType]@unchecked)) =>
+ mkGetVar(SByte.downcast(id.value.asInstanceOf[AnyVal]), rtpe)
+ }
+ )
+
+ def PKFunc(networkPrefix: NetworkPrefix) = PredefinedFunc("PK",
+ Lambda(Vector("input" -> SString), SSigmaProp, None),
+ { case (_, Seq(arg: EvaluatedValue[SString.type]@unchecked)) =>
+ ErgoAddressEncoder(networkPrefix).fromString(arg.value).get match {
+ case a: P2PKAddress => mkConstant[SSigmaProp.type](a.pubkey, SSigmaProp)
+ case a@_ => sys.error(s"unsupported address $a")
+ }
+ }
+ )
+
+ val DeserializeFunc = PredefinedFunc("deserialize",
+ Lambda(Seq(STypeParam(tT)), Vector("str" -> SString), tT, None),
+ { case (Ident(_, SFunc(_, tpe, _)), args) =>
+ if (args.length != 1)
+ throw new InvalidArguments(s"Wrong number of arguments in $args: expected one argument")
+ val str = args.head match {
+ case StringConstant(s) => s
+ case _ =>
+ throw new InvalidArguments(s"invalid argument in $args: expected a string constant")
+ }
+ val bytes = Base58.decode(str).get
+ val res = ValueSerializer.deserialize(bytes)
+ if (res.tpe != tpe)
+ throw new InvalidArguments(s"Wrong type after deserialization, expected $tpe, got ${res.tpe}")
+ res
+ }
+ )
- val GetVarSym = PredefIdent("getVar")
+ val FromBase58Func = PredefinedFunc("fromBase58",
+ Lambda(Vector("input" -> SString), SByteArray, None),
+ { case (_, Seq(arg: EvaluatedValue[SString.type]@unchecked)) =>
+ ByteArrayConstant(Base58.decode(arg.value).get)
+ }
+ )
- val Blake2b256Sym = PredefIdent("blake2b256")
- val Sha256Sym = PredefIdent("sha256")
- val IsMemberSym = PredefIdent("isMember")
- val TreeLookupSym = PredefIdent("treeLookup")
- val TreeModificationsSym = PredefIdent("treeModifications")
- val ProveDlogSym = PredefIdent("proveDlog")
- val ProveDHTupleSym = PredefIdent("proveDHTuple")
+ val FromBase64Func = PredefinedFunc("fromBase64",
+ Lambda(Vector("input" -> SString), SByteArray, None),
+ { case (_, Seq(arg: EvaluatedValue[SString.type]@unchecked)) =>
+ ByteArrayConstant(Base64.decode(arg.value).get)
+ }
+ )
- val LongToByteArraySym = PredefIdent("longToByteArray")
- val ByteArrayToBigIntSym = PredefIdent("byteArrayToBigInt")
- val ByteArrayToLongSym = PredefIdent("byteArrayToLong") // mutually inverse to longToByteArray
+ val Blake2b256Func = PredefinedFunc("blake2b256",
+ Lambda(Vector("input" -> SByteArray), SByteArray, None),
+ { case (_, Seq(arg: Value[SByteArray]@unchecked)) =>
+ mkCalcBlake2b256(arg)
+ }
+ )
- /** Implemented as CryptoConstants.dlogGroup.curve.decodePoint(bytes)*/
- val DecodePointSym = PredefIdent("decodePoint")
+ val Sha256Func = PredefinedFunc("sha256",
+ Lambda(Vector("input" -> SByteArray), SByteArray, None),
+ { case (_, Seq(arg: Value[SByteArray]@unchecked)) =>
+ mkCalcSha256(arg)
+ }
+ )
- val FromBase58Sym = PredefIdent("fromBase58")
- val FromBase64Sym = PredefIdent("fromBase64")
+ val ByteArrayToBigIntFunc = PredefinedFunc("byteArrayToBigInt",
+ Lambda(Vector("input" -> SByteArray), SBigInt, None),
+ { case (_, Seq(arg: Value[SByteArray]@unchecked)) =>
+ mkByteArrayToBigInt(arg)
+ }
+ )
- val PKSym = PredefIdent("PK")
+ val ByteArrayToLongFunc = PredefinedFunc("byteArrayToLong",
+ Lambda(Vector("input" -> SByteArray), SLong, None),
+ { case (_, Seq(arg: Value[SByteArray]@unchecked)) =>
+ mkByteArrayToLong(arg)
+ }
+ )
- val DeserializeSym = PredefIdent("deserialize")
+ val DecodePointFunc = PredefinedFunc("decodePoint",
+ Lambda(Vector("input" -> SByteArray), SGroupElement, None),
+ { case (_, Seq(arg: Value[SByteArray]@unchecked)) =>
+ mkDecodePoint(arg)
+ }
+ )
+
+ val LongToByteArrayFunc = PredefinedFunc("longToByteArray",
+ Lambda(Vector("input" -> SLong), SByteArray, None),
+ { case (_, Seq(arg: Value[SLong.type]@unchecked)) =>
+ mkLongToByteArray(arg)
+ }
+ )
+
+ val ProveDHTupleFunc = PredefinedFunc("proveDHTuple",
+ Lambda(Vector("g" -> SGroupElement, "h" -> SGroupElement, "u" -> SGroupElement, "v" -> SGroupElement), SSigmaProp, None),
+ { case (_, Seq(g, h, u, v)) =>
+ mkCreateProveDHTuple(g.asGroupElement, h.asGroupElement, u.asGroupElement, v.asGroupElement)
+ }
+ )
+
+ val ProveDlogFunc = PredefinedFunc("proveDlog",
+ Lambda(Vector("value" -> SGroupElement), SSigmaProp, None),
+ { case (_, Seq(arg: Value[SGroupElement.type]@unchecked)) =>
+ mkCreateProveDlog(arg)
+ }
+ )
+ val AvlTreeFunc = PredefinedFunc("avlTree",
+ Lambda(Vector("operationFlags" -> SByte, "digest" -> SByteArray, "keyLength" -> SInt, "valueLengthOpt" -> SIntOption), SAvlTree, None),
+ { case (_, Seq(arg: Value[SGroupElement.type]@unchecked)) =>
+ mkCreateProveDlog(arg)
+ }
+ )
+
+// val IsMemberFunc = PredefinedFunc("isMember",
+// Lambda(Vector("tree" -> SAvlTree, "key" -> SByteArray, "proof" -> SByteArray), SBoolean, None),
+// { case (_, Seq(tree: Value[SAvlTree.type]@unchecked, key: Value[SByteArray]@unchecked,
+// proof: Value[SByteArray]@unchecked)) =>
+// mkIsMember(tree, key, proof)
+// }
+// )
+//
+// val TreeLookupFunc = PredefinedFunc("treeLookup",
+// Lambda(Vector("tree" -> SAvlTree, "key" -> SByteArray, "proof" -> SByteArray), SOption[SByteArray], None),
+// { case (_, Seq(tree: Value[SAvlTree.type]@unchecked, key: Value[SByteArray]@unchecked,
+// proof: Value[SByteArray]@unchecked)) =>
+// mkTreeLookup(tree, key, proof)
+// }
+// )
+//
+// val TreeModificationsFunc = PredefinedFunc("treeModifications",
+// Lambda(Vector("tree" -> SAvlTree, "ops" -> SByteArray, "proof" -> SByteArray), SOption[SByteArray], None),
+// { case (_, Seq(tree: Value[SAvlTree.type]@unchecked, operations: Value[SByteArray]@unchecked,
+// proof: Value[SByteArray]@unchecked)) =>
+// mkTreeModifications(tree, operations, proof)
+// }
+// )
+//
+// val TreeInsertsFunc = PredefinedFunc("treeInserts",
+// Lambda(Vector("tree" -> SAvlTree, "ops" -> SCollection(STuple(IndexedSeq(SByteArray, SByteArray))), "proof" -> SByteArray),
+// SOption[SByteArray], None),
+// { case (_, Seq(tree: Value[SAvlTree.type]@unchecked, operations: Value[SCollection[STuple]]@unchecked,
+// proof: Value[SByteArray]@unchecked)) =>
+// mkTreeInserts(tree, operations, proof)
+// }
+// )
+//
+// val TreeRemovalsFunc = PredefinedFunc("treeRemovals",
+// Lambda(Vector("tree" -> SAvlTree, "ops" -> SCollection[SByteArray], "proof" -> SByteArray), SOption[SByteArray], None),
+// { case (_, Seq(tree: Value[SAvlTree.type]@unchecked, operations: Value[SCollection[SByteArray]]@unchecked,
+// proof: Value[SByteArray]@unchecked)) =>
+// mkTreeRemovals(tree, operations, proof)
+// }
+// )
+
+ val XorOfFunc = PredefinedFunc("xorOf",
+ Lambda(Vector("conditions" -> SCollection(SBoolean)), SBoolean, None),
+ { case (_, Seq(col: Value[SCollection[SBoolean.type]]@unchecked)) => mkXorOf(col) }
+ )
+
+ val SubstConstantsFunc = PredefinedFunc("substConstants",
+ Lambda(
+ Seq(STypeParam(tT)),
+ Vector("scriptBytes" -> SByteArray, "positions" -> SIntArray, "newValues" -> SCollection(tT)),
+ SByteArray, None
+ ),
+ undefined
+ )
+
+ val ExecuteFromVarFunc = PredefinedFunc("executeFromVar",
+ Lambda(
+ Seq(STypeParam(tT)),
+ Vector("id" -> SByte),
+ tT, None
+ ),
+ undefined
+ )
+
+ val funcs: Seq[PredefinedFunc] = Seq(
+ AllOfFunc,
+ AnyOfFunc,
+ AtLeastFunc,
+ OuterJoinFunc,
+ ZKProofFunc,
+ SigmaPropFunc,
+ GetVarFunc,
+ DeserializeFunc,
+ FromBase64Func,
+ FromBase58Func,
+ Blake2b256Func,
+ Sha256Func,
+ ByteArrayToBigIntFunc,
+ ByteArrayToLongFunc,
+ DecodePointFunc,
+ LongToByteArrayFunc,
+ ProveDHTupleFunc,
+ ProveDlogFunc,
+ AvlTreeFunc,
+ XorOfFunc,
+ SubstConstantsFunc,
+ ExecuteFromVarFunc,
+ )
+
+ private val funcNameToIrBuilderMap: Map[String, IrBuilderFunc] =
+ funcs.filter(_.irBuilder != undefined)
+ .map(f => f.name -> f.irBuilder)
+ .toMap
+
+ def irBuilderForFunc(name: String): Option[IrBuilderFunc] = funcNameToIrBuilderMap.get(name)
+ }
+
+ object PredefinedFuncApply {
+ def unapply(apply: Apply)(implicit registry: PredefinedFuncRegistry): Nullable[SValue] = apply.func match {
+ case Ident(name, _) =>
+ registry.irBuilderForFunc(name)
+ .filter(_.isDefinedAt(apply.func, apply.args))
+ .map(b => Nullable(b(apply.func, apply.args))).getOrElse(Nullable.None)
+ case _ => Nullable.None
+ }
+ }
}
diff --git a/src/main/scala/sigmastate/lang/SigmaSpecializer.scala b/src/main/scala/sigmastate/lang/SigmaSpecializer.scala
index 596e55acad..a7315c06f7 100644
--- a/src/main/scala/sigmastate/lang/SigmaSpecializer.scala
+++ b/src/main/scala/sigmastate/lang/SigmaSpecializer.scala
@@ -3,6 +3,7 @@ package sigmastate.lang
import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{reduce, rewrite, strategy}
import org.ergoplatform.ErgoAddressEncoder.{NetworkPrefix, TestnetNetworkPrefix}
import org.ergoplatform._
+import scalan.Nullable
import scorex.util.encode.{Base58, Base64}
import sigmastate.SCollection._
import sigmastate.Values.Value.Typed
@@ -12,12 +13,14 @@ import sigmastate.lang.SigmaPredef._
import sigmastate.lang.Terms.{Apply, ApplyTypes, Block, Ident, Lambda, Select, Val, ValueOps}
import sigmastate.lang.exceptions.SpecializerException
import sigmastate.utxo._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
-class SigmaSpecializer(val builder: SigmaBuilder, val networkPrefix: NetworkPrefix) {
+class SigmaSpecializer(val builder: SigmaBuilder) {
import SigmaSpecializer._
import builder._
+ private implicit val predefFuncRegistry: PredefinedFuncRegistry = new PredefinedFuncRegistry(builder)
+
/** Create name -> TaggedXXX(tag) pair to be used in environment. */
def mkTagged(name: String, tpe: SType, tag: Byte): TaggedVariable[SType] = {
val tagged = mkTaggedVariable(tag, tpe)
@@ -31,67 +34,14 @@ class SigmaSpecializer(val builder: SigmaBuilder, val networkPrefix: NetworkPref
case _ @ Block(binds, res) =>
var curEnv = env
- for (Val(n, _, b) <- binds) {
- if (curEnv.contains(n)) error(s"Variable $n already defined ($n = ${curEnv(n)}")
+ for (v @ Val(n, _, b) <- binds) {
+ if (curEnv.contains(n)) error(s"${v.sourceContext} Variable $n already defined ($n = ${curEnv(n)}")
val b1 = eval(curEnv, b)
curEnv = curEnv + (n -> b1)
}
val res1 = eval(curEnv, res)
Some(res1)
- // Rule: allOf(arr) --> AND(arr)
- case Apply(AllSym, Seq(arr: Value[SCollection[SBoolean.type]]@unchecked)) =>
- Some(mkAND(arr))
-
- // Rule: anyOf(arr) --> OR(arr)
- case Apply(AnySym, Seq(arr: Value[SCollection[SBoolean.type]]@unchecked)) =>
- Some(mkOR(arr))
-
- // Rule: atLeast(bound, arr) --> AtLeast(bound, arr)
- case Apply(AtLeastSym, Seq(bound: SValue, arr: Value[SCollection[SSigmaProp.type]]@unchecked)) =>
- Some(mkAtLeast(bound.asIntValue, arr))
-
- // Rule: ZKProof(block) --> ZKProofBlock(block)
- case Apply(ZKProofSym, Seq(block: SigmaPropValue@unchecked)) =>
- Some(mkZKProofBlock(block))
-
- // Rule: sigmaProp(condition) --> BoolToSigmaProp(condition)
- case Apply(SigmaPropSym, Seq(condition: BoolValue@unchecked)) =>
- Some(mkBoolToSigmaProp(condition))
-
- case Apply(Blake2b256Sym, Seq(arg: Value[SByteArray]@unchecked)) =>
- Some(mkCalcBlake2b256(arg))
-
- case Apply(Sha256Sym, Seq(arg: Value[SByteArray]@unchecked)) =>
- Some(mkCalcSha256(arg))
-
- case Apply(IsMemberSym, Seq(tree: Value[SAvlTree.type]@unchecked, key: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
- Some(mkIsMember(tree, key, proof))
-
- case Apply(TreeLookupSym, Seq(tree: Value[SAvlTree.type]@unchecked, key: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
- Some(mkTreeLookup(tree, key, proof))
-
- case Apply(TreeModificationsSym, Seq(tree: Value[SAvlTree.type]@unchecked, operations: Value[SByteArray]@unchecked, proof: Value[SByteArray]@unchecked)) =>
- Some(mkTreeModifications(tree, operations, proof))
-
- case Apply(ProveDlogSym, Seq(g: Value[SGroupElement.type]@unchecked)) =>
- Some(SigmaPropConstant(mkProveDlog(g)))
-
- case Apply(ProveDHTupleSym, Seq(g, h, u, v)) =>
- Some(SigmaPropConstant(mkProveDiffieHellmanTuple(g.asGroupElement, h.asGroupElement, u.asGroupElement, v.asGroupElement)))
-
- case Apply(LongToByteArraySym, Seq(arg: Value[SLong.type]@unchecked)) =>
- Some(mkLongToByteArray(arg))
-
- case Apply(FromBase58Sym, Seq(arg: EvaluatedValue[SString.type]@unchecked)) =>
- Some(ByteArrayConstant(Base58.decode(arg.value).get))
-
- case Apply(FromBase64Sym, Seq(arg: EvaluatedValue[SString.type]@unchecked)) =>
- Some(ByteArrayConstant(Base64.decode(arg.value).get))
-
- case Apply(ByteArrayToBigIntSym, Seq(arg: Value[SByteArray]@unchecked)) =>
- Some(mkByteArrayToBigInt(arg))
-
case Upcast(Constant(value, tpe), toTpe: SNumericType) =>
Some(mkConstant(toTpe.upcast(value.asInstanceOf[AnyVal]), toTpe))
@@ -124,14 +74,6 @@ class SigmaSpecializer(val builder: SigmaBuilder, val networkPrefix: NetworkPref
case Select(p, SSigmaProp.PropBytes, _) if p.tpe == SSigmaProp =>
Some(SigmaPropBytes(p.asSigmaProp))
- case Apply(PKSym, Seq(arg: EvaluatedValue[SString.type]@unchecked)) =>
- Some(
- ErgoAddressEncoder(networkPrefix).fromString(arg.value).get match {
- case a: P2PKAddress => a.pubkey
- case a@_ => error(s"unsupported address $a")
- }
- )
-
case sel @ Select(Typed(box, SBox), regName, Some(SOption(valType))) if regName.startsWith("R") =>
val reg = ErgoBox.registerByName.getOrElse(regName,
error(s"Invalid register name $regName in expression $sel"))
@@ -146,34 +88,24 @@ class SigmaSpecializer(val builder: SigmaBuilder, val networkPrefix: NetworkPref
case Select(nrv: NotReadyValue[SOption[SType]]@unchecked, SOption.IsDefined, _) =>
Some(mkOptionIsDefined(nrv))
- case sel @ Select(e @ Apply(ApplyTypes(f @ GetVarSym, targs), args), "get", Some(regType)) =>
- if (targs.length != 1 || args.length != 1)
- error(s"Wrong number of arguments in $e: expected one type argument and one variable id")
- val id = args.head match {
- case LongConstant(i) => i.toByteExact //TODO use SByte.downcast once it is implemented
- case IntConstant(i) => i.toByteExact
- case ByteConstant(i) => i
- }
- Some(mkTaggedVariable(id, targs.head))
-
case sel @ Select(obj, field, _) if obj.tpe == SBox =>
(obj.asValue[SBox.type], field) match {
case (box, SBox.Value) => Some(mkExtractAmount(box))
case (box, SBox.PropositionBytes) => Some(mkExtractScriptBytes(box))
case (box, SBox.Id) => Some(mkExtractId(box))
case (box, SBox.Bytes) => Some(mkExtractBytes(box))
- case (box, SBox.BytesWithNoRef) => Some(mkExtractBytesWithNoRef(box))
+ case (box, SBox.BytesWithoutRef) => Some(mkExtractBytesWithNoRef(box))
case (box, SBox.CreationInfo) => Some(mkExtractCreationInfo(box))
case (box, _) if box.tpe.hasMethod(field) =>
None // leave it as it is and handle on a level of parent node
case _ => error(s"Invalid access to Box property in $sel: field $field is not found")
}
- case node @ Select(obj: SigmaBoolean, field, _) =>
- field match {
- case SigmaBoolean.PropBytes => Some(ByteArrayConstant(obj.bytes))
- case _ => None
- }
+// case node @ Select(obj: SigmaBoolean, field, _) =>
+// field match {
+// case SigmaBoolean.PropBytes => Some(ByteArrayConstant(obj.bytes))
+// case _ => None
+// }
case Select(tuple, fn, _) if tuple.tpe.isTuple && fn.startsWith("_") =>
val index = fn.substring(1).toByte
@@ -199,11 +131,6 @@ class SigmaSpecializer(val builder: SigmaBuilder, val networkPrefix: NetworkPref
case Apply(Select(col, FoldMethod.name, _), Seq(zero, l @ Lambda(_, _, _, _))) =>
Some(mkFold(col.asValue[SCollection[SType]], zero, l))
- case Apply(Select(col, GetOrElseMethod.name, _), Seq(index, defaultValue)) =>
- val index1 = eval(env, index).asValue[SInt.type]
- val defaultValue1 = eval(env, defaultValue).asValue[SType]
- Some(mkByIndex(col.asValue[SCollection[SType]], index1, Some(defaultValue1)))
-
case Apply(col, Seq(index)) if col.tpe.isCollection =>
Some(ByIndex(col.asCollection[SType], index.asValue[SInt.type]))
@@ -226,8 +153,8 @@ class SigmaSpecializer(val builder: SigmaBuilder, val networkPrefix: NetworkPref
case v => IndexedSeq(v)
}, SBoolean)))
- case StringConcat(StringConstant(l), StringConstant(r)) =>
- Some(StringConstant(l + r))
+ case PredefinedFuncApply(irNode) =>
+ Some(irNode)
})))(e)
@@ -244,4 +171,5 @@ class SigmaSpecializer(val builder: SigmaBuilder, val networkPrefix: NetworkPref
object SigmaSpecializer {
def error(msg: String) = throw new SpecializerException(msg, None)
+ def error(msg: String, srcCtx: SourceContext) = throw new SpecializerException(msg, Some(srcCtx))
}
diff --git a/src/main/scala/sigmastate/lang/SigmaTyper.scala b/src/main/scala/sigmastate/lang/SigmaTyper.scala
index ba54ac4694..d37842231e 100644
--- a/src/main/scala/sigmastate/lang/SigmaTyper.scala
+++ b/src/main/scala/sigmastate/lang/SigmaTyper.scala
@@ -2,42 +2,52 @@ package sigmastate.lang
import org.bitbucket.inkytonik.kiama.rewriting.Rewriter._
import org.ergoplatform._
-import sigmastate.SCollection.SByteArray
+import sigmastate.SCollection._
import sigmastate.Values._
import sigmastate._
import SCollection.SBooleanArray
+import scalan.Nullable
import sigmastate.lang.Terms._
-import sigmastate.lang.exceptions.{InvalidBinaryOperationParameters, MethodNotFound, TyperException, NonApplicableMethod}
+import sigmastate.lang.exceptions._
import sigmastate.lang.SigmaPredef._
import sigmastate.serialization.OpCodes
import sigmastate.utxo._
+import sigma.util.Extensions._
import scala.collection.mutable.ArrayBuffer
/**
* Type inference and analysis for Sigma expressions.
*/
-class SigmaTyper(val builder: SigmaBuilder) {
+class SigmaTyper(val builder: SigmaBuilder, predefFuncRegistry: PredefinedFuncRegistry) {
import SigmaTyper._
import builder._
+ import predefFuncRegistry._
+
+ private implicit val implicitPredefFuncRegistry: PredefinedFuncRegistry = predefFuncRegistry
private val tT = STypeIdent("T") // to be used in typing rules
+ private val predefinedEnv: Map[String, SType] =
+ predefFuncRegistry.funcs.map(f => f.name -> f.declaration.tpe).toMap
+
/**
* Rewrite tree to typed tree. Checks constituent names and types. Uses
* the env map to resolve bound variables and their types.
*/
def assignType(env: Map[String, SType],
bound: SValue,
- expected: Option[SType] = None): SValue = bound match {
+ expected: Option[SType] = None): SValue = ( bound match {
case Block(bs, res) =>
var curEnv = env
val bs1 = ArrayBuffer[Val]()
- for (Val(n, _, b) <- bs) {
- if (curEnv.contains(n)) error(s"Variable $n already defined ($n = ${curEnv(n)}")
+ for (v @ Val(n, _, b) <- bs) {
+ if (curEnv.contains(n)) error(s"Variable $n already defined ($n = ${curEnv(n)}", v.sourceContext)
val b1 = assignType(curEnv, b)
curEnv = curEnv + (n -> b1.tpe)
- bs1 += mkVal(n, b1.tpe, b1)
+ builder.currentSrcCtx.withValue(v.sourceContext) {
+ bs1 += mkVal(n, b1.tpe, b1)
+ }
}
val res1 = assignType(curEnv, res)
mkBlock(bs1, res1)
@@ -52,46 +62,86 @@ class SigmaTyper(val builder: SigmaBuilder) {
case Ident(n, _) =>
env.get(n) match {
case Some(t) => mkIdent(n, t)
- case None => error(s"Cannot assign type for variable '$n' because it is not found in env $env")
- }
-
- case sel @ Select(obj: SigmaBoolean, n, None) =>
- val newObj = assignType(env, obj).asSigmaBoolean
- val iField = newObj.fields.indexWhere(_._1 == n)
- val tRes = if (iField != -1) {
- obj.fields(iField)._2
+ case None =>
+ error(s"Cannot assign type for variable '$n' because it is not found in env $env", bound.sourceContext)
}
- else
- error(s"Cannot find field '$n' in the object $obj of Sigma type with fields ${obj.fields}")
- mkSelect(newObj, n, Some(tRes))
case sel @ Select(obj, n, None) =>
val newObj = assignType(env, obj)
newObj.tpe match {
- case s: SProduct =>
- val iField = s.methodIndex(n)
- val tRes = if (iField != -1) {
- s.methods(iField).stype
+ case tNewObj: SProduct =>
+ val iField = tNewObj.methodIndex(n)
+ val method = if (iField != -1) {
+ tNewObj.methods(iField)
} else
- throw new MethodNotFound(s"Cannot find method '$n' in in the object $obj of Product type with methods ${s.methods}")
- mkSelect(newObj, n, Some(tRes))
+ throw new MethodNotFound(s"Cannot find method '$n' in in the object $obj of Product type with methods ${tNewObj.methods}", obj.sourceContext.toOption)
+ val tMeth = method.stype
+ val tRes = tMeth match {
+ case SFunc(args, _, _) =>
+ val tThis = args(0) // first arg corresponds to method's receiver
+ val tMethSpec = unifyTypes(tThis, tNewObj) match {
+ case Some(subst) if subst.nonEmpty => applySubst(tMeth, subst).asFunc // specialize for concrete receiver type
+ case _ => tMeth.asFunc
+ }
+ if (tMethSpec.tDom.length == 1 && tMethSpec.tpeParams.isEmpty) tMethSpec.tRange
+ else tMethSpec.copy(tDom = tMethSpec.tDom.tail, tRange = tMethSpec.tRange)
+ case _ => tMeth
+ }
+ if (method.irBuilder.isDefined && !tRes.isFunc) {
+ // this is MethodCall of parameter-less property, so invoke builder and/or fallback to just MethodCall
+ val methodConcrType = method.withSType(SFunc(newObj.tpe, tRes))
+ methodConcrType.irBuilder.flatMap(_.lift(builder, newObj, methodConcrType, IndexedSeq(), Map()))
+ .getOrElse(mkMethodCall(newObj, methodConcrType, IndexedSeq(), Map()))
+ } else {
+ mkSelect(newObj, n, Some(tRes))
+ }
case t =>
- error(s"Cannot get field '$n' in in the object $obj of non-product type $t")
+ error(s"Cannot get field '$n' in in the object $obj of non-product type $t", sel.sourceContext)
}
case lam @ Lambda(tparams, args, t, body) =>
for ((name, t) <- args)
if (t == NoType)
- error(s"Invalid function $lam: undefined type of argument $name")
+ error(s"Invalid function $lam: undefined type of argument $name", lam.sourceContext)
val lambdaEnv = env ++ args
val newBody = body.map(assignType(lambdaEnv, _))
if (t != NoType) {
if (newBody.isDefined && t != newBody.get.tpe)
- error(s"Invalid function $lam: resulting expression type ${newBody.get.tpe} doesn't equal declared type $t")
+ error(s"Invalid function $lam: resulting expression type ${newBody.get.tpe} doesn't equal declared type $t", lam.sourceContext)
}
val res = mkGenLambda(tparams, args, newBody.fold(t)(_.tpe), newBody)
res
+ case Apply(ApplyTypes(sel @ Select(obj, n, _), Seq(rangeTpe)), args) =>
+ val newObj = assignType(env, obj)
+ val newArgs = args.map(assignType(env, _))
+ obj.tpe match {
+ case p: SProduct =>
+ p.method(n) match {
+ case Some(method @ SMethod(_, _, genFunTpe @ SFunc(_, _, _), _, _)) =>
+ val subst = Map(genFunTpe.tpeParams.head.ident -> rangeTpe)
+ val concrFunTpe = applySubst(genFunTpe, subst)
+ val expectedArgs = concrFunTpe.asFunc.tDom.tail
+ val newArgTypes = newArgs.map(_.tpe)
+ if (expectedArgs.length != newArgTypes.length
+ || !expectedArgs.zip(newArgTypes).forall { case (ea, na) => ea == SAny || ea == na })
+ error(s"For method $n expected args: $expectedArgs; actual: $newArgTypes", sel.sourceContext)
+ if (method.irBuilder.isDefined) {
+ method.irBuilder.flatMap(_.lift(builder, newObj, method, newArgs, subst))
+ .getOrElse(mkMethodCall(newObj, method, newArgs, subst))
+ } else {
+ val newSelect = mkSelect(newObj, n, Some(concrFunTpe)).withSrcCtx(sel.sourceContext)
+ mkApply(newSelect, newArgs)
+ }
+ case Some(method) =>
+ error(s"Don't know how to handle method $method in obj $p", sel.sourceContext)
+ case None =>
+ throw new MethodNotFound(s"Cannot find method '$n' in in the object $obj of Product type with methods ${p.methods}", obj.sourceContext.toOption)
+ }
+ case _ =>
+ error(s"Cannot get field '$n' in in the object $obj of non-product type ${obj.tpe}", sel.sourceContext)
+ }
+
case app @ Apply(sel @ Select(obj, n, _), args) =>
val newSel = assignType(env, sel)
val newArgs = args.map(assignType(env, _))
@@ -99,53 +149,68 @@ class SigmaTyper(val builder: SigmaBuilder) {
case genFunTpe @ SFunc(argTypes, tRes, _) =>
// If it's a function then the application has type of that function's return type.
val newObj = assignType(env, obj)
- val actualTypes = newObj.tpe +: newArgs.map(_.tpe)
- unifyTypeLists(argTypes, actualTypes) match {
+ val newArgTypes = newArgs.map(_.tpe)
+ unifyTypeLists(argTypes, newArgTypes) match {
case Some(subst) =>
val concrFunTpe = applySubst(genFunTpe, subst)
- val newApply = mkApply(mkSelect(newObj, n, Some(concrFunTpe)), newArgs)
- newApply
+ newObj.tpe.asInstanceOf[SProduct].method(n) match {
+ case Some(method) if method.irBuilder.isDefined =>
+ val expectedArgs = concrFunTpe.asFunc.tDom
+ if (expectedArgs.length != newArgTypes.length
+ || !expectedArgs.zip(newArgTypes).forall { case (ea, na) => ea == SAny || ea == na })
+ error(s"For method $n expected args: $expectedArgs; actual: $newArgTypes", sel.sourceContext)
+ val methodConcrType = method.withSType(concrFunTpe.asFunc.withReceiverType(newObj.tpe))
+ methodConcrType.irBuilder.flatMap(_.lift(builder, newObj, methodConcrType, newArgs, Map()))
+ .getOrElse(mkMethodCall(newObj, methodConcrType, newArgs, Map()))
+ case _ =>
+ val newSelect = mkSelect(newObj, n, Some(concrFunTpe)).withSrcCtx(sel.sourceContext)
+ mkApply(newSelect, newArgs)
+ }
case None =>
- error(s"Invalid argument type of application $app: expected $argTypes; actual: $actualTypes")
+ error(s"Invalid argument type of application $app: expected $argTypes; actual: $newArgTypes", sel.sourceContext)
}
case _ =>
- mkApply(newSel, args.map(assignType(env, _)))
+ mkApply(newSel, newArgs)
}
case app @ Apply(f, args) =>
val new_f = assignType(env, f)
- new_f.tpe match {
+ (new_f.tpe match {
case SFunc(argTypes, tRes, _) =>
// If it's a pre-defined function application
if (args.length != argTypes.length)
- error(s"Invalid argument type of application $app: invalid number of arguments")
- val new_args = args.zip(argTypes).map {
+ error(s"Invalid argument type of application $app: invalid number of arguments", app.sourceContext)
+ val typedArgs = args.zip(argTypes).map {
case (arg, expectedType) => assignType(env, arg, Some(expectedType))
}
- val newArgs = new_f match {
- case AllSym | AnySym =>
- adaptSigmaPropToBoolean(new_args, argTypes)
- case _ => new_args
+ val adaptedTypedArgs = (new_f, typedArgs) match {
+ case (AllOfFunc.sym | AnyOfFunc.sym, _) =>
+ adaptSigmaPropToBoolean(typedArgs, argTypes)
+ case (Ident(GetVarFunc.name | ExecuteFromVarFunc.name, _), Seq(id: Constant[SNumericType]@unchecked))
+ if id.tpe.isNumType =>
+ Seq(ByteConstant(SByte.downcast(id.value.asInstanceOf[AnyVal])).withSrcCtx(id.sourceContext))
+ case _ => typedArgs
}
- val actualTypes = newArgs.map(_.tpe)
+ val actualTypes = adaptedTypedArgs.map(_.tpe)
if (actualTypes != argTypes)
- error(s"Invalid argument type of application $app: expected $argTypes; actual after typing: $actualTypes")
- mkApply(new_f, newArgs.toIndexedSeq)
+ error(s"Invalid argument type of application $app: expected $argTypes; actual after typing: $actualTypes", app.sourceContext)
+ mkApply(new_f, adaptedTypedArgs.toIndexedSeq)
case _: SCollectionType[_] =>
// If it's a collection then the application has type of that collection's element.
args match {
- case Seq(Constant(index, _: SNumericType)) =>
- mkByIndex[SType](new_f.asCollection, SInt.upcast(index.asInstanceOf[AnyVal]), None)
+ case Seq(c @ Constant(index, _: SNumericType)) =>
+ val indexConst = IntConstant(SInt.upcast(index.asInstanceOf[AnyVal])).withSrcCtx(c.sourceContext)
+ mkByIndex[SType](new_f.asCollection, indexConst, None)
case Seq(index) =>
val typedIndex = assignType(env, index)
typedIndex.tpe match {
case _: SNumericType =>
mkByIndex[SType](new_f.asCollection, typedIndex.upcastTo(SInt), None)
case _ =>
- error(s"Invalid argument type of array application $app: expected numeric type; actual: ${typedIndex.tpe}")
+ error(s"Invalid argument type of array application $app: expected numeric type; actual: ${typedIndex.tpe}", index.sourceContext)
}
case _ =>
- error(s"Invalid argument of array application $app: expected integer value; actual: $args")
+ error(s"Invalid argument of array application $app: expected integer value; actual: $args", app.sourceContext)
}
case STuple(_) =>
// If it's a tuple then the type of the application depend on the index.
@@ -159,48 +224,76 @@ class SigmaTyper(val builder: SigmaBuilder) {
case _: SNumericType =>
mkByIndex(new_f.asCollection[SAny.type], typedIndex.upcastTo(SInt), None)
case _ =>
- error(s"Invalid argument type of tuple application $app: expected numeric type; actual: ${typedIndex.tpe}")
+ error(s"Invalid argument type of tuple application $app: expected numeric type; actual: ${typedIndex.tpe}", typedIndex.sourceContext)
}
case _ =>
- error(s"Invalid argument of tuple application $app: expected integer value; actual: $args")
+ error(s"Invalid argument of tuple application $app: expected integer value; actual: $args", app.sourceContext)
}
case t =>
- error(s"Invalid array application $app: array type is expected but was $t")
+ error(s"Invalid array application $app: array type is expected but was $t", app.sourceContext)
+ }) match {
+ case PredefinedFuncApply(irNode) => irNode
+ case v => v
}
case mc @ MethodCallLike(obj, m, args, _) =>
val newObj = assignType(env, obj)
val newArgs = args.map(assignType(env, _))
newObj.tpe match {
- case tCol: SCollectionType[a] => (m, newArgs) match {
+ case tColl: SCollectionType[a] => (m, newArgs) match {
case ("++", Seq(r)) =>
- if (r.tpe == tCol)
+ if (r.tpe == tColl)
mkAppend(newObj.asCollection[a], r.asCollection[a])
else
- error(s"Invalid argument type for $m, expected $tCol but was ${r.tpe}")
+ error(s"Invalid argument type for $m, expected $tColl but was ${r.tpe}", r.sourceContext)
+ case (SCollection(method), _) =>
+ val typeSubst = method.stype match {
+ case sfunc @ SFunc(_, _, _) =>
+ val newArgsTypes = newArgs.map(_.tpe)
+ val actualTypes = newObj.tpe +: newArgsTypes
+ unifyTypeLists(sfunc.tDom, actualTypes) match {
+ case Some(subst) =>
+ val concrFunTpe = applySubst(sfunc, subst).asFunc
+ val newMethod = method.withSType(concrFunTpe)
+ val concrFunArgsTypes = concrFunTpe.tDom.tail
+ if (newArgsTypes != concrFunArgsTypes)
+ error(s"Invalid method $newMethod argument type: expected $concrFunArgsTypes; actual: $newArgsTypes", mc.sourceContext)
+ subst
+ case None =>
+ error(s"Invalid argument type of method call $mc : expected ${sfunc.tDom}; actual: $actualTypes", mc.sourceContext)
+ }
+ case _ => emptySubst
+ }
+ method.irBuilder.flatMap(_.lift(builder, newObj, method, newArgs, typeSubst))
+ .getOrElse(mkMethodCall(newObj, method, newArgs, typeSubst))
+
case _ =>
- throw new NonApplicableMethod(s"Unknown symbol $m, which is used as operation with arguments $newObj and $newArgs")
+ throw new NonApplicableMethod(s"Unknown symbol $m, which is used as operation with arguments $newObj and $newArgs", mc.sourceContext.toOption)
}
case SGroupElement => (m, newArgs) match {
case ("*", Seq(r)) =>
if (r.tpe == SGroupElement)
mkMultiplyGroup(newObj.asGroupElement, r.asGroupElement)
else
- error(s"Invalid argument type for $m, expected $SGroupElement but was ${r.tpe}")
+ error(s"Invalid argument type for $m, expected $SGroupElement but was ${r.tpe}", r.sourceContext)
case _ =>
- throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)")
+ throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)", mc.sourceContext.toOption)
}
case _: SNumericType => (m, newArgs) match {
- case("+" | "*", Seq(r)) => r.tpe match {
+ case("+" | "*" | "^" | ">>" | "<<" | ">>>", Seq(r)) => r.tpe match {
case _: SNumericType => m match {
case "*" => bimap(env, "*", newObj.asNumValue, r.asNumValue)(mkMultiply)(tT, tT)
case "+" => bimap(env, "+", newObj.asNumValue, r.asNumValue)(mkPlus)(tT, tT)
+ case "^" => bimap(env, "^", newObj.asNumValue, r.asNumValue)(mkBitXor)(tT, tT)
+ case ">>" => bimap(env, ">>", newObj.asNumValue, r.asNumValue)(mkBitShiftRight)(tT, tT)
+ case "<<" => bimap(env, "<<", newObj.asNumValue, r.asNumValue)(mkBitShiftLeft)(tT, tT)
+ case ">>>" => bimap(env, ">>>", newObj.asNumValue, r.asNumValue)(mkBitShiftRightZeroed)(tT, tT)
}
case _ =>
- throw new InvalidBinaryOperationParameters(s"Invalid argument type for $m, expected ${newObj.tpe} but was ${r.tpe}")
+ throw new InvalidBinaryOperationParameters(s"Invalid argument type for $m, expected ${newObj.tpe} but was ${r.tpe}", r.sourceContext.toOption)
}
case _ =>
- throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)")
+ throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)", mc.sourceContext.toOption)
}
case SSigmaProp => (m, newArgs) match {
@@ -214,55 +307,58 @@ class SigmaTyper(val builder: SigmaBuilder) {
val res = if (m == "||") mkSigmaOr(Seq(a,b)) else mkSigmaAnd(Seq(a,b))
res
case _ =>
- error(s"Invalid argument type for $m, expected $SSigmaProp but was ${r.tpe}")
+ error(s"Invalid argument type for $m, expected $SSigmaProp but was ${r.tpe}", r.sourceContext)
}
case _ =>
- throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)")
+ throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)", mc.sourceContext.toOption)
}
case SBoolean => (m, newArgs) match {
- case ("||" | "&&", Seq(r)) => r.tpe match {
- case SBoolean =>
- val res = if (m == "||") mkBinOr(newObj.asBoolValue, r.asBoolValue) else mkBinAnd(newObj.asBoolValue, r.asBoolValue)
- res
+ case ("||" | "&&" | "^", Seq(r)) => r.tpe match {
+ case SBoolean => m match {
+ case "||" => mkBinOr(newObj.asBoolValue, r.asBoolValue)
+ case "&&" => mkBinAnd(newObj.asBoolValue, r.asBoolValue)
+ case "^" => mkBinXor(newObj.asBoolValue, r.asBoolValue)
+
+ }
case SSigmaProp =>
val (a,b) = (newObj.asBoolValue, Select(r, SSigmaProp.IsProven, Some(SBoolean)).asBoolValue)
val res = if (m == "||") mkBinOr(a,b) else mkBinAnd(a,b)
res
case _ =>
- error(s"Invalid argument type for $m, expected ${newObj.tpe} but was ${r.tpe}")
+ error(s"Invalid argument type for $m, expected ${newObj.tpe} but was ${r.tpe}", r.sourceContext)
}
case _ =>
- throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)")
+ throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)", mc.sourceContext.toOption)
}
case _: SString.type => (m, newArgs) match {
- case ("+", Seq(r)) => r.tpe match {
- case _: SString.type =>
- bimap(env, "+", newObj.asStringValue, r.asStringValue)(mkStringConcat)(tT, tT)
+ case ("+", Seq(r)) => (newObj, r) match {
+ case (cl : Constant[SString.type]@unchecked, cr : Constant[SString.type]@unchecked) =>
+ mkStringConcat(cl, cr)
case _ =>
- throw new InvalidBinaryOperationParameters(s"Invalid argument type for $m, expected ${newObj.tpe} but was ${r.tpe}")
+ throw new InvalidBinaryOperationParameters(s"Invalid argument type for $m, expected ${newObj.tpe} but was ${r.tpe}", r.sourceContext.toOption)
}
case _ =>
- throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)")
+ throw new NonApplicableMethod(s"Unknown symbol $m, which is used as ($newObj) $m ($newArgs)", mc.sourceContext.toOption)
}
case t =>
- error(s"Invalid operation $mc on type $t")
+ error(s"Invalid operation $mc on type $t", mc.sourceContext)
}
case app @ ApplyTypes(input, targs) =>
- def update(input: SValue, newTpe: SType) = input match {
- case Select(obj, n, _) => mkSelect(obj, n, Some(newTpe))
- }
val newInput = assignType(env, input)
newInput.tpe match {
case genFunTpe @ SFunc(_, _, tpeParams) =>
if (tpeParams.lengthCompare(targs.length) != 0)
error(s"Wrong number of type arguments $app: expected $tpeParams but provided $targs. " +
- s"Note that partial application of type parameters is not supported.")
+ s"Note that partial application of type parameters is not supported.", app.sourceContext)
val subst = tpeParams.map(_.ident).zip(targs).toMap
val concrFunTpe = applySubst(genFunTpe, subst).asFunc
- update(newInput, concrFunTpe.tRange)
+ newInput match {
+ case Select(obj, n, _) => mkSelect(obj, n, Some(concrFunTpe.tRange))
+ case Ident(name, _) => mkIdent(name, concrFunTpe)
+ }
case _ =>
- error(s"Invalid application of type arguments $app: function $input doesn't have type parameters")
+ error(s"Invalid application of type arguments $app: function $input doesn't have type parameters", input.sourceContext)
}
// case app @ ApplyTypes(in, targs) =>
@@ -276,21 +372,21 @@ class SigmaTyper(val builder: SigmaBuilder) {
val e1 = assignType(env, e)
val ite = mkIf(c1, t1, e1)
if (c1.tpe != SBoolean)
- error(s"Invalid type of condition in $ite: expected Boolean; actual: ${c1.tpe}")
+ error(s"Invalid type of condition in $ite: expected Boolean; actual: ${c1.tpe}", c.sourceContext)
if (t1.tpe != e1.tpe)
- error(s"Invalid type of condition $ite: both branches should have the same type but was ${t1.tpe} and ${e1.tpe}")
+ error(s"Invalid type of condition $ite: both branches should have the same type but was ${t1.tpe} and ${e1.tpe}", t1.sourceContext)
ite
case op @ AND(input) =>
val input1 = assignType(env, input).asValue[SCollection[SBoolean.type]]
if (!(input1.tpe.isCollection && input1.tpe.elemType == SBoolean))
- error(s"Invalid operation AND: $op")
+ error(s"Invalid operation AND: $op", op.sourceContext)
mkAND(input1)
case op @ OR(input) =>
val input1 = assignType(env, input).asValue[SCollection[SBoolean.type]]
if (!(input1.tpe.isCollection && input1.tpe.elemType == SBoolean))
- error(s"Invalid operation OR: $op")
+ error(s"Invalid operation OR: $op", op.sourceContext)
mkOR(input1)
case GE(l, r) => bimap(env, ">=", l, r)(mkGE[SType])(tT, SBoolean)
@@ -308,6 +404,10 @@ class SigmaTyper(val builder: SigmaBuilder) {
case ArithOp(l, r, OpCodes.MinCode) => bimap(env, "min", l.asNumValue, r.asNumValue)(mkMin)(tT, tT)
case ArithOp(l, r, OpCodes.MaxCode) => bimap(env, "max", l.asNumValue, r.asNumValue)(mkMax)(tT, tT)
+ case BitOp(l, r, OpCodes.BitOrCode) => bimap(env, "|", l.asNumValue, r.asNumValue)(mkBitOr)(tT, tT)
+ case BitOp(l, r, OpCodes.BitAndCode) => bimap(env, "&", l.asNumValue, r.asNumValue)(mkBitAnd)(tT, tT)
+ case BitOp(l, r, OpCodes.BitXorCode) => bimap(env, "^", l.asNumValue, r.asNumValue)(mkBitXor)(tT, tT)
+
case Xor(l, r) => bimap(env, "|", l, r)(mkXor)(SByteArray, SByteArray)
case MultiplyGroup(l, r) => bimap(env, "*", l, r)(mkMultiplyGroup)(SGroupElement, SGroupElement)
@@ -315,49 +415,54 @@ class SigmaTyper(val builder: SigmaBuilder) {
val l1 = assignType(env, l).asGroupElement
val r1 = assignType(env, r).asBigInt
if (l1.tpe != SGroupElement || r1.tpe != SBigInt)
- error(s"Invalid binary operation Exponentiate: expected argument types ($SGroupElement, $SBigInt); actual: (${l.tpe}, ${r.tpe})")
+ error(s"Invalid binary operation Exponentiate: expected argument types ($SGroupElement, $SBigInt); actual: (${l.tpe}, ${r.tpe})", l.sourceContext)
mkExponentiate(l1, r1)
case ByIndex(col, i, defaultValue) =>
val c1 = assignType(env, col).asCollection[SType]
if (!c1.tpe.isCollectionLike)
- error(s"Invalid operation ByIndex: expected Collection argument type; actual: (${col.tpe})")
+ error(s"Invalid operation ByIndex: expected Collection argument type; actual: (${col.tpe})", col.sourceContext)
defaultValue match {
case Some(v) if v.tpe.typeCode != c1.tpe.elemType.typeCode =>
- error(s"Invalid operation ByIndex: expected default value type (${c1.tpe.elemType}); actual: (${v.tpe})")
- case ref @ _ => ByIndex(c1, i, ref)
+ error(s"Invalid operation ByIndex: expected default value type (${c1.tpe.elemType}); actual: (${v.tpe})", v.sourceContext)
+ case ref @ _ => mkByIndex(c1, i, ref)
}
case SizeOf(col) =>
val c1 = assignType(env, col).asCollection[SType]
if (!c1.tpe.isCollectionLike)
- error(s"Invalid operation SizeOf: expected argument types ($SCollection); actual: (${col.tpe})")
+ error(s"Invalid operation SizeOf: expected argument types ($SCollection); actual: (${col.tpe})", col.sourceContext)
mkSizeOf(c1)
case SigmaPropIsProven(p) =>
val p1 = assignType(env, p)
if (!p1.tpe.isSigmaProp)
- error(s"Invalid operation IsValid: expected argument types ($SSigmaProp); actual: (${p.tpe})")
+ error(s"Invalid operation IsValid: expected argument types ($SSigmaProp); actual: (${p.tpe})", p.sourceContext)
SigmaPropIsProven(p1.asSigmaProp)
case SigmaPropBytes(p) =>
val p1 = assignType(env, p)
if (!p1.tpe.isSigmaProp)
- error(s"Invalid operation ProofBytes: expected argument types ($SSigmaProp); actual: (${p.tpe})")
+ error(s"Invalid operation ProofBytes: expected argument types ($SSigmaProp); actual: (${p.tpe})", p.sourceContext)
SigmaPropBytes(p1.asSigmaProp)
+ case LogicalNot(i) => unmap(env, "!", i.asBoolValue)(mkLogicalNot)(SBoolean)
+ case Negation(i) => unmap[SNumericType](env, "-", i.asNumValue)(mkNegation)(tT)
+ case BitInversion(i) => unmap[SNumericType](env, "~", i.asNumValue)(mkBitInversion)(tT)
+
case SomeValue(x) => SomeValue(assignType(env, x))
case v: NoneValue[_] => v
+ case Context => Context
case Height => Height
case MinerPubkey => MinerPubkey
case Self => Self
case Inputs => Inputs
case Outputs => Outputs
case LastBlockUtxoRootHash => LastBlockUtxoRootHash
- case LongConstant(i) if expected.isDefined && expected.get == SByte =>
+ case c @ LongConstant(i) if expected.isDefined && expected.get == SByte =>
if (i >= 0 && i <= Byte.MaxValue) ByteConstant(i.toByte)
- else error(s"Value $i of type Long cannot be converted to Byte.")
+ else error(s"Value $i of type Long cannot be converted to Byte.", c.sourceContext)
case v: ContextVariable[_] => v
case v: GetVar[_] => v
case v: OptionGet[_] => v
@@ -366,20 +471,20 @@ class SigmaTyper(val builder: SigmaBuilder) {
case v: Upcast[_, _] => v
case v @ Select(_, _, Some(_)) => v
case v =>
- error(s"Don't know how to assignType($v)")
- }
+ error(s"Don't know how to assignType($v)", v.sourceContext)
+ }).withEnsuredSrcCtx(bound.sourceContext)
def assignConcreteCollection(cc: ConcreteCollection[SType], newItems: IndexedSeq[Value[SType]]) = {
val types = newItems.map(_.tpe).distinct
val tItem = if (cc.items.isEmpty) {
if (cc.elementType == NoType)
- error(s"Undefined type of empty collection $cc")
+ error(s"Undefined type of empty collection $cc", cc.sourceContext)
cc.elementType
} else {
msgTypeOf(types).getOrElse(
- error(s"All element of array $cc should have the same type but found $types"))
+ error(s"All element of array $cc should have the same type but found $types", cc.sourceContext))
}
- ConcreteCollection(newItems)(tItem)
+ builder.currentSrcCtx.withValue(cc.sourceContext) { mkConcreteCollection(newItems, tItem) }
}
def adaptSigmaPropToBoolean(items: Seq[Value[SType]], expectedTypes: Seq[SType]): Seq[Value[SType]] = {
@@ -401,10 +506,13 @@ class SigmaTyper(val builder: SigmaBuilder) {
val r1 = assignType(env, r).asValue[T]
val safeMkNode = { (left: Value[T], right: Value[T]) =>
try {
- mkNode(left, right)
+ val node = mkNode(left, right)
+ if (node.tpe == NoType)
+ error("No type can be assigned to expression", l.sourceContext)
+ node
} catch {
case e: Throwable =>
- throw new InvalidBinaryOperationParameters(s"operation: $op: $e")
+ throw new InvalidBinaryOperationParameters(s"operation: $op: $e", l.sourceContext.toOption)
}
}
(l1.tpe, r1.tpe) match {
@@ -415,7 +523,7 @@ class SigmaTyper(val builder: SigmaBuilder) {
if (substOpt.isDefined)
safeMkNode(l1, r1)
else
- throw new InvalidBinaryOperationParameters(s"Invalid binary operation $op: expected argument types ($tArg, $tArg); actual: (${l1.tpe }, ${r1.tpe })")
+ throw new InvalidBinaryOperationParameters(s"Invalid binary operation $op: expected argument types ($tArg, $tArg); actual: (${l1.tpe }, ${r1.tpe })", l.sourceContext.toOption)
}
}
@@ -429,13 +537,28 @@ class SigmaTyper(val builder: SigmaBuilder) {
newNode(l1, r1)
} catch {
case e: Throwable =>
- throw new InvalidBinaryOperationParameters(s"operation $op: $e")
+ throw new InvalidBinaryOperationParameters(s"operation $op: $e", l.sourceContext.toOption)
+ }
+ }
+
+ def unmap[T <: SType](env: Map[String, SType], op: String, i: Value[T])
+ (newNode: Value[T] => SValue)
+ (tArg: SType): SValue = {
+ val i1 = assignType(env, i).asValue[T]
+ if (!i1.tpe.isNumType && i1.tpe != tArg)
+ throw new InvalidUnaryOperationParameters(s"Invalid unary op $op: expected argument type $tArg, actual: ${i1.tpe}", i.sourceContext.toOption)
+ try {
+ newNode(i1)
+ } catch {
+ case e: Throwable =>
+ throw new InvalidUnaryOperationParameters(s"operation $op error: $e", i.sourceContext.toOption)
}
}
def typecheck(bound: SValue): SValue = {
- val assigned = assignType(SigmaPredef.predefinedEnv.mapValues(_.tpe), bound)
- if (assigned.tpe == NoType) error(s"No type can be assigned to expression $assigned")
+ val assigned = assignType(predefinedEnv, bound)
+ if (assigned.tpe == NoType)
+ error(s"No type can be assigned to expression $assigned", bound.sourceContext)
// traverse the tree bottom-up checking that all the nodes have a type
var untyped: SValue = null
@@ -446,7 +569,7 @@ class SigmaTyper(val builder: SigmaBuilder) {
}))(assigned)
if (untyped != null)
- error(s"Errors found in $bound while assigning types to expression: $untyped assigned NoType")
+ error(s"Errors found in $bound while assigning types to expression: $untyped assigned NoType", untyped.sourceContext)
assigned
}
@@ -498,12 +621,10 @@ object SigmaTyper {
case (STypeApply(name1, args1), STypeApply(name2, args2))
if name1 == name2 && args1.length == args2.length =>
unifyTypeLists(args1, args2)
- case (SBoolean, SSigmaProp) =>
+ case (SBoolean, SSigmaProp) => // it is necessary for implicit conversion in Coll(bool, prop, bool)
unifiedWithoutSubst
case (SPrimType(e1), SPrimType(e2)) if e1 == e2 =>
unifiedWithoutSubst
- case (e1: SProduct, e2: SProduct) if e1.sameMethods(e2) =>
- unifyTypeLists(e1.methods.map(_.stype), e2.methods.map(_.stype))
case (SAny, _) =>
unifiedWithoutSubst
case _ => None
@@ -541,5 +662,5 @@ object SigmaTyper {
}
}
- def error(msg: String) = throw new TyperException(msg, None)
+ def error(msg: String, srcCtx: Nullable[SourceContext]) = throw new TyperException(msg, srcCtx.toOption)
}
diff --git a/src/main/scala/sigmastate/lang/SourceContext.scala b/src/main/scala/sigmastate/lang/SourceContext.scala
new file mode 100644
index 0000000000..29d0178c2a
--- /dev/null
+++ b/src/main/scala/sigmastate/lang/SourceContext.scala
@@ -0,0 +1,31 @@
+package sigmastate.lang
+
+import fastparse.core.Parsed.Failure
+
+import scala.io.Source
+
+case class SourceContext(line: Int, column: Int, sourceLine: String) {
+
+}
+
+object SourceContext {
+
+ def fromParserIndex(index: Int, input: String): SourceContext = {
+ val lines = Source.fromString(input).getLines.toSeq
+ if (lines.isEmpty)
+ SourceContext(0, 0, "")
+ else
+ lines.tail
+ .scanLeft((0, lines.head.length)) { case ((_, end), line) => (end + 1, end + 1 + line.length) }
+ .zip(lines)
+ .zipWithIndex
+ .find { case (((start, end), _), _) => index >= start && index <= end }
+ .map {
+ case (((start, _), line), lineIndex) =>
+ SourceContext(lineIndex + 1, index - start + 1, line)
+ }.get
+ }
+
+ def fromParserFailure(e: Failure[_, String]): SourceContext =
+ fromParserIndex(e.index , e.extra.input.slice(0, e.extra.input.length))
+}
diff --git a/src/main/scala/sigmastate/lang/Terms.scala b/src/main/scala/sigmastate/lang/Terms.scala
index cce422ffea..57378f5d1c 100644
--- a/src/main/scala/sigmastate/lang/Terms.scala
+++ b/src/main/scala/sigmastate/lang/Terms.scala
@@ -1,16 +1,20 @@
package sigmastate.lang
-import org.ergoplatform.Self
+import org.bitbucket.inkytonik.kiama.rewriting.Rewriter._
+import scalan.Nullable
import sigmastate.SCollection.SByteArray
import sigmastate.Values._
import sigmastate.utils.Overloading.Overload1
import sigmastate._
+import sigmastate.lang.SigmaTyper.STypeSubst
import sigmastate.serialization.OpCodes
import sigmastate.serialization.OpCodes.OpCode
-import sigmastate.interpreter.Context
import sigmastate.lang.TransformingSigmaBuilder._
import sigmastate.utxo.CostTable.Cost
import sigmastate.utxo.{ExtractRegisterAs, SigmaPropIsProven, Slice}
+import special.sigma.{AnyValue, TestValue}
+
+import scala.language.implicitConversions
object Terms {
@@ -53,7 +57,9 @@ object Terms {
val body: SValue
}
- case class ValNode(name: String, givenType: SType, body: SValue) extends Val {
+ case class ValNode(name: String,
+ givenType: SType,
+ body: SValue) extends Val {
override val opCode: OpCode = OpCodes.Undefined
override def tpe: SType = givenType ?: body.tpe
/** This is not used as operation, but rather to form a program structure */
@@ -96,7 +102,7 @@ object Terms {
override val opCode: OpCode = OpCodes.FuncApplyCode
override lazy val tpe: SType = func.tpe match {
case SFunc(_, r, _) => r
- case tCol: SCollectionType[_] => tCol.elemType
+ case tColl: SCollectionType[_] => tColl.elemType
case _ => NoType
}
override def opType: SFunc = SFunc(Vector(func.tpe +: args.map(_.tpe):_*), tpe)
@@ -107,7 +113,6 @@ object Terms {
override val opCode: OpCode = OpCodes.Undefined
override lazy val tpe: SType = input.tpe match {
case funcType: SFunc =>
- require(funcType.tpeParams.length == tpeArgs.length, s"Invalid number of type parameters in $node")
val subst = funcType.tpeParams.map(_.ident).zip(tpeArgs).toMap
SigmaTyper.applySubst(input.tpe, subst)
case _ => input.tpe
@@ -124,20 +129,21 @@ object Terms {
override def opType: SFunc = SFunc(obj.tpe +: args.map(_.tpe), tpe)
}
- /** Represents in ErgoTree an invocation of method of the object `obj` with arguments `args`.*/
- case class MethodCall(obj: Value[SType], method: SMethod, args: IndexedSeq[Value[SType]]) extends Value[SType] {
+ /** Represents in ErgoTree an invocation of method of the object `obj` with arguments `args`.
+ * @param obj object on which method will be invoked
+ * @param method method to be invoked
+ * @param args arguments passed to the method on invocation
+ * @param typeSubst a map of concrete type for each generic type parameter
+ */
+ case class MethodCall(obj: Value[SType],
+ method: SMethod,
+ args: IndexedSeq[Value[SType]],
+ typeSubst: Map[STypeIdent, SType]) extends Value[SType] {
override val opCode: OpCode = if (args.isEmpty) OpCodes.PropertyCallCode else OpCodes.MethodCallCode
override def opType: SFunc = SFunc(obj.tpe +: args.map(_.tpe), tpe)
override val tpe: SType = method.stype match {
- case f: SFunc => f.tRange
- case t => t
- }
- }
- object MethodCall {
- def fromIds(typeId: Byte, methodId: Byte): SMethod = {
- val typeCompanion = SType.types.getOrElse(typeId, sys.error(s"Cannot find STypeCompanion instance for typeId=$typeId"))
- val method = typeCompanion.getMethodById(methodId)
- method
+ case f: SFunc => f.tRange.withSubstTypes(typeSubst)
+ case t => t.withSubstTypes(typeSubst)
}
}
@@ -145,6 +151,9 @@ object Terms {
assert(upperBound.isEmpty && lowerBound.isEmpty, s"Type parameters with bounds are not supported, but found $this")
override def toString = ident.toString + upperBound.fold("")(u => s" <: $u") + lowerBound.fold("")(l => s" >: $l")
}
+ object STypeParam {
+ implicit def typeIdentToTypeParam(id: STypeIdent): STypeParam = STypeParam(id)
+ }
/** Frontend implementation of lambdas. Should be transformed to FuncValue. */
case class Lambda(
@@ -165,6 +174,8 @@ object Terms {
object Lambda {
def apply(args: IndexedSeq[(String,SType)], resTpe: SType, body: Value[SType]): Lambda =
Lambda(Nil, args, resTpe, Some(body))
+ def apply(args: IndexedSeq[(String,SType)], resTpe: SType, body: Option[Value[SType]]): Lambda =
+ Lambda(Nil, args, resTpe, body)
def apply(args: IndexedSeq[(String,SType)], body: Value[SType]): Lambda = Lambda(Nil, args, NoType, Some(body))
}
@@ -175,15 +186,17 @@ object Terms {
def asNumValue: Value[SNumericType] = v.asInstanceOf[Value[SNumericType]]
def asStringValue: Value[SString.type] = v.asInstanceOf[Value[SString.type]]
def asBoolValue: Value[SBoolean.type] = v.asInstanceOf[Value[SBoolean.type]]
+ def asByteValue: Value[SByte.type] = v.asInstanceOf[Value[SByte.type]]
+ def asShortValue: Value[SShort.type] = v.asInstanceOf[Value[SShort.type]]
def asIntValue: Value[SInt.type] = v.asInstanceOf[Value[SInt.type]]
def asLongValue: Value[SLong.type] = v.asInstanceOf[Value[SLong.type]]
- def asSigmaBoolean: SigmaBoolean = v.asInstanceOf[SigmaBoolean]
+ def asBigInt: Value[SBigInt.type] = v.asInstanceOf[Value[SBigInt.type]]
def asBox: Value[SBox.type] = v.asInstanceOf[Value[SBox.type]]
def asGroupElement: Value[SGroupElement.type] = v.asInstanceOf[Value[SGroupElement.type]]
def asSigmaProp: Value[SSigmaProp.type] = v.asInstanceOf[Value[SSigmaProp.type]]
def asByteArray: Value[SByteArray] = v.asInstanceOf[Value[SByteArray]]
- def asBigInt: Value[SBigInt.type] = v.asInstanceOf[Value[SBigInt.type]]
def asCollection[T <: SType]: Value[SCollection[T]] = v.asInstanceOf[Value[SCollection[T]]]
+ def asOption[T <: SType]: Value[SOption[T]] = v.asInstanceOf[Value[SOption[T]]]
def asTuple: Value[STuple] = v.asInstanceOf[Value[STuple]]
def asFunc: Value[SFunc] = v.asInstanceOf[Value[SFunc]]
def asConcreteCollection[T <: SType]: ConcreteCollection[T] = v.asInstanceOf[ConcreteCollection[T]]
@@ -195,7 +208,31 @@ object Terms {
s"Invalid upcast from $tV to $targetType: target type should be larger than source type.")
if (targetType == tV.tpe) v.asValue[T]
else
- mkUpcast(tV, targetType)
+ mkUpcast(tV, targetType).withSrcCtx(v.sourceContext)
+ }
+ def withSrcCtx[T <: SType](sourceContext: Nullable[SourceContext]): Value[T] = {
+ v.sourceContext = sourceContext
+ v.asValue[T]
+ }
+ /**
+ * Set source context only if it's empty
+ */
+ def withEnsuredSrcCtx[T <: SType](sourceContext: Nullable[SourceContext]): Value[T] = {
+ if (v.sourceContext.isEmpty) v.sourceContext = sourceContext
+ v.asValue[T]
}
+ /**
+ * Set source context to all nodes missing source context in the given tree.
+ * @param tree AST to traverse
+ * @param srcCtx source context to set
+ * @return AST where all nodes with missing source context are set to the given srcCtx
+ */
+ def withPropagatedSrcCtx[T <: SType](srcCtx: Nullable[SourceContext]): Value[T] = {
+ rewrite(everywherebu(rule[SValue] {
+ case node if node != null && node.sourceContext.isEmpty =>
+ node.withSrcCtx(srcCtx)
+ }))(v).asValue[T]
+ }
+
}
}
diff --git a/src/main/scala/sigmastate/lang/Types.scala b/src/main/scala/sigmastate/lang/Types.scala
index 13dd8e4401..d13f62d4f8 100644
--- a/src/main/scala/sigmastate/lang/Types.scala
+++ b/src/main/scala/sigmastate/lang/Types.scala
@@ -21,8 +21,13 @@ trait Types extends Core {
/** This map should be in sync with SType.allPredefTypes*/
val predefTypes = Map(
- "Boolean" -> SBoolean, "Byte" -> SByte, "Short" -> SShort, "Int" -> SInt,"Long" -> SLong, "BigInt" -> SBigInt, "ByteArray" -> SByteArray,
- "AvlTree" -> SAvlTree, "Context" -> SContext, "GroupElement" -> SGroupElement, "SigmaProp" -> SSigmaProp, "Box" -> SBox, "Unit" -> SUnit, "Any" -> SAny
+ "Boolean" -> SBoolean, "Byte" -> SByte, "Short" -> SShort, "Int" -> SInt,"Long" -> SLong, "BigInt" -> SBigInt,
+ "ByteArray" -> SByteArray,
+ "AvlTree" -> SAvlTree, "Context" -> SContext, "GroupElement" -> SGroupElement, "SigmaProp" -> SSigmaProp,
+ "Header" -> SHeader,
+ "PreHeader" -> SPreHeader,
+ "String" -> SString,
+ "Box" -> SBox, "Unit" -> SUnit, "Any" -> SAny
)
def typeFromName(tn: String): Option[SType] = predefTypes.get(tn)
@@ -46,17 +51,18 @@ trait Types extends Core {
val InfixType = {
val RightAssoc = 1; val LeftAssoc = -1
/** All operators op1,…,opn must have the same associativity */
- def checkAssoc(ops: Seq[String]): Int = {
+ def checkAssoc(ops: Seq[String], index: Int): Int = {
val right = ops.forall(_.endsWith(":"))
if (right) RightAssoc
else {
val left = ops.forall(!_.endsWith(":"))
if (left) LeftAssoc
- else error(s"All operators $ops must have the same associativity.")
+ else
+ error(s"All operators $ops must have the same associativity.", Some(srcCtx(index)))
}
}
- def buildInfix(head: SType, tail: Seq[(String, SType)]): SType = {
- val associativity = checkAssoc(tail.map(_._1))
+ def buildInfix(head: SType, tail: Seq[(String, SType)], index: Int): SType = {
+ val associativity = checkAssoc(tail.map(_._1), index)
if (associativity == RightAssoc) {
tail.foldRight(head) { case ((op, t), acc) => STypeApply(op, IndexedSeq(t, acc)) }
}
@@ -64,15 +70,17 @@ trait Types extends Core {
tail.foldLeft(head) { case (acc, (op, t)) => STypeApply(op, IndexedSeq(acc, t)) }
}
}
- P( CompoundType ~~ (NotNewline ~ Id.! ~~ OneNLMax ~ CompoundType).repX ).map { case (t, h) => buildInfix(t,h) }
+ P( Index ~ CompoundType ~~ (NotNewline ~ Id.! ~~ OneNLMax ~ CompoundType).repX ).map {
+ case (index, t, h) => buildInfix(t, h, index)
+ }
}
val CompoundType = {
// val Refinement = P( OneNLMax ~ `{` ~/ Dcl.repX(sep=Semis) ~ `}` )
val NamedType = P( (Pass ~ AnnotType).rep(1, `with`.~/) )
- P( NamedType /*~~ Refinement.? | Refinement*/ ).map {
- case Seq(t) => t
- case ts => error(s"Compound types are not supported: $ts")
+ P( Index ~ NamedType /*~~ Refinement.? | Refinement*/ ).map {
+ case (_, Seq(t)) => t
+ case (index, ts) => error(s"Compound types are not supported: $ts", Some(srcCtx(index)))
}
}
val NLAnnot = P( NotNewline ~ Annot )
@@ -84,7 +92,7 @@ trait Types extends Core {
case Some(t) => t
case None => STypeApply(tn)
}
- case path => error(s"Path types are not supported: $path")
+ case path => error(s"Path types are not supported: $path", path.sourceContext)
}
val TypeArgs = P( "[" ~/ Type.repTC() ~ "]" )
@@ -94,27 +102,31 @@ trait Types extends Core {
// or `() => T`! only cut after parsing one type
val TupleType = P( "(" ~/ Type.repTC() ~ ")" ).map(items => STuple(items.toIndexedSeq))
val BasicType = P( TupleType | TypeId )
- P( BasicType ~ TypeArgs.rep ).map {
- case (t: STuple, Seq()) => t
- case (STypeApply("Coll", IndexedSeq()), Seq(Seq(t))) => SCollection(t)
- case (STypeApply("Option", IndexedSeq()), Seq(Seq(t))) => SOption(t)
- case (SPrimType(t), Seq()) => t
- case (STypeApply(tn, IndexedSeq()), args) if args.isEmpty => STypeIdent(tn)
- case t =>
- error(s"Unsupported type $t")
+ P( Index ~ BasicType ~ TypeArgs.rep ).map {
+ case (_, t: STuple, Seq()) => t
+ case (_, STypeApply("Coll", IndexedSeq()), Seq(Seq(t))) => SCollection(t)
+ case (_, STypeApply("Option", IndexedSeq()), Seq(Seq(t))) => SOption(t)
+ case (_, SPrimType(t), Seq()) => t
+ case (_, STypeApply(tn, IndexedSeq()), args) if args.isEmpty => STypeIdent(tn)
+ case (index, t, typeArgs) =>
+ error(s"Unsupported type $t[$typeArgs]", Some(srcCtx(index)))
+ }
+ }
+
+ val FunSig = {
+ val FunArg = P( Annot.rep ~ Id.! ~ (`:` ~/ Type).? ).map {
+ case (n, Some(t)) => (n, t)
+ case (n, None) => (n, NoType)
}
+ val Args = P( FunArg.repTC(1) )
+ val FunArgs = P( OneNLMax ~ "(" ~/ Args.? ~ ")" ).map(_.toSeq.flatten)
+ val FunTypeArgs = P( "[" ~/ (Annot.rep ~ TypeArg).repTC(1) ~ "]" )
+ P( FunTypeArgs.? ~~ FunArgs.rep )
}
-// val FunSig = {
-// val FunArg = P( Annot.rep ~ Id.! ~ (`:` ~/ Type).? ).map {
-// case (n, Some(t)) => (n, t)
-// case (n, None) => (n, NoType)
-// }
-// val Args = P( FunArg.repTC(1) )
-// val FunArgs = P( OneNLMax ~ "(" ~/ Args.? ~ ")" ).map(_.toSeq.flatten)
-// val FunTypeArgs = P( "[" ~/ (Annot.rep ~ TypeArg).repTC(1) ~ "]" )
-// P( FunTypeArgs.? ~~ FunArgs.rep )
-// }
+ // extension method subject (type that being extended)
+ // see dotty extension method http://dotty.epfl.ch/blog/2019/01/21/12th-dotty-milestone-release.html
+ val DottyExtMethodSubj = P( "(" ~/ Id.! ~ `:` ~/ Type ~ ")" )
val TypeBounds: P0 = P( (`>:` ~/ Type).? ~ (`<:` ~/ Type).? ).ignore
val TypeArg: P0 = {
diff --git a/src/main/scala/sigmastate/lang/exceptions/Exceptions.scala b/src/main/scala/sigmastate/lang/exceptions/Exceptions.scala
index 59a9e14a69..93145ee15d 100644
--- a/src/main/scala/sigmastate/lang/exceptions/Exceptions.scala
+++ b/src/main/scala/sigmastate/lang/exceptions/Exceptions.scala
@@ -1,9 +1,16 @@
package sigmastate.lang.exceptions
-case class SourceContext(index: Int)
+import sigmastate.lang.SourceContext
-class SigmaException(val message: String, val source: Option[SourceContext] = None)
- extends Exception(message)
+class SigmaException(val message: String, val source: Option[SourceContext] = None, val cause: Option[Throwable] = None)
+ extends Exception(message, cause.orNull) {
+
+ override def getMessage: String = source.map { srcCtx =>
+ val lineNumberStrPrefix = s"line ${srcCtx.line}: "
+ "\n" + lineNumberStrPrefix +
+ s"${srcCtx.sourceLine}\n${" " * (lineNumberStrPrefix.length + srcCtx.column - 1)}^\n" + message
+ }.getOrElse(message)
+}
class BinderException(message: String, source: Option[SourceContext] = None)
extends SigmaException(message, source)
@@ -20,8 +27,8 @@ class SerializerException(message: String, source: Option[SourceContext] = None)
class BuilderException(message: String, source: Option[SourceContext] = None)
extends SigmaException(message, source)
-class CosterException(message: String, source: Option[SourceContext])
- extends SigmaException(message, source)
+class CosterException(message: String, source: Option[SourceContext], cause: Option[Throwable] = None)
+ extends SigmaException(message, source, cause)
class InterpreterException(message: String, source: Option[SourceContext] = None)
extends SigmaException(message, source)
diff --git a/src/main/scala/sigmastate/lang/exceptions/SigmaBinderExceptions.scala b/src/main/scala/sigmastate/lang/exceptions/SigmaBinderExceptions.scala
index b6608dda6e..65d59a4c91 100644
--- a/src/main/scala/sigmastate/lang/exceptions/SigmaBinderExceptions.scala
+++ b/src/main/scala/sigmastate/lang/exceptions/SigmaBinderExceptions.scala
@@ -1,5 +1,7 @@
package sigmastate.lang.exceptions
+import sigmastate.lang.SourceContext
+
final class InvalidArguments(message: String, source: Option[SourceContext] = None)
extends BinderException(message, source)
diff --git a/src/main/scala/sigmastate/lang/exceptions/SigmaBuilderExceptions.scala b/src/main/scala/sigmastate/lang/exceptions/SigmaBuilderExceptions.scala
index 897bbb4e72..f9af8e43a3 100644
--- a/src/main/scala/sigmastate/lang/exceptions/SigmaBuilderExceptions.scala
+++ b/src/main/scala/sigmastate/lang/exceptions/SigmaBuilderExceptions.scala
@@ -1,5 +1,7 @@
package sigmastate.lang.exceptions
+import sigmastate.lang.SourceContext
+
final class ConstraintFailed(message: String, source: Option[SourceContext] = None)
extends BuilderException(message, source)
diff --git a/src/main/scala/sigmastate/lang/exceptions/SigmaInterpreterExceptions.scala b/src/main/scala/sigmastate/lang/exceptions/SigmaInterpreterExceptions.scala
index e89f472103..f8edf935c8 100644
--- a/src/main/scala/sigmastate/lang/exceptions/SigmaInterpreterExceptions.scala
+++ b/src/main/scala/sigmastate/lang/exceptions/SigmaInterpreterExceptions.scala
@@ -1,5 +1,7 @@
package sigmastate.lang.exceptions
+import sigmastate.lang.SourceContext
+
final class OptionUnwrapNone(message: String, source: Option[SourceContext] = None)
extends InterpreterException(message, source)
diff --git a/src/main/scala/sigmastate/lang/exceptions/SigmaSerializerExceptions.scala b/src/main/scala/sigmastate/lang/exceptions/SigmaSerializerExceptions.scala
index 435992746d..04211a82a8 100644
--- a/src/main/scala/sigmastate/lang/exceptions/SigmaSerializerExceptions.scala
+++ b/src/main/scala/sigmastate/lang/exceptions/SigmaSerializerExceptions.scala
@@ -1,5 +1,7 @@
package sigmastate.lang.exceptions
+import sigmastate.lang.SourceContext
+
final class InvalidTypePrefix(message: String, source: Option[SourceContext] = None)
extends SerializerException(message, source)
diff --git a/src/main/scala/sigmastate/lang/exceptions/SigmaTyperExceptions.scala b/src/main/scala/sigmastate/lang/exceptions/SigmaTyperExceptions.scala
index 10ead07d57..5073268613 100644
--- a/src/main/scala/sigmastate/lang/exceptions/SigmaTyperExceptions.scala
+++ b/src/main/scala/sigmastate/lang/exceptions/SigmaTyperExceptions.scala
@@ -1,8 +1,13 @@
package sigmastate.lang.exceptions
+import sigmastate.lang.SourceContext
+
final class InvalidBinaryOperationParameters(message: String, source: Option[SourceContext] = None)
extends TyperException(message, source)
+final class InvalidUnaryOperationParameters(message: String, source: Option[SourceContext] = None)
+ extends TyperException(message, source)
+
final class MethodNotFound(message: String, source: Option[SourceContext] = None)
extends TyperException(message, source)
diff --git a/src/main/scala/sigmastate/lang/syntax/Basic.scala b/src/main/scala/sigmastate/lang/syntax/Basic.scala
index fcce76c7c3..9f5d064ef2 100644
--- a/src/main/scala/sigmastate/lang/syntax/Basic.scala
+++ b/src/main/scala/sigmastate/lang/syntax/Basic.scala
@@ -2,9 +2,10 @@ package sigmastate.lang.syntax
import fastparse.all._
import fastparse.CharPredicates._
-import fastparse.all
-import fastparse.core.Parsed.Failure
-import sigmastate.lang.exceptions.{SigmaException, SourceContext}
+import scalan.Nullable
+import sigmastate.lang.SourceContext
+import sigmastate.lang.exceptions.SigmaException
+import sigma.util.Extensions._
object Basic {
val digits = "0123456789"
@@ -38,12 +39,12 @@ object Basic {
val Lower: Parser[Unit] = P( CharPred(c => isLower(c) || c == '$' | c == '_') )
val Upper: Parser[Unit] = P( CharPred(isUpper) )
- def error(msg: String, parseError: Option[Failure[_,_]] = None) =
- throw new ParserException(msg, parseError)
+ def error(msg: String, srcCtx: Option[SourceContext]) = throw new ParserException(msg, srcCtx)
+ def error(msg: String, srcCtx: Nullable[SourceContext]) = throw new ParserException(msg, srcCtx.toOption)
}
-class ParserException(message: String, val parseError: Option[Failure[_,_]])
- extends SigmaException(message, parseError.map(e => SourceContext(e.index)))
+class ParserException(message: String, source: Option[SourceContext])
+ extends SigmaException(message, source)
/**
* Most keywords don't just require the correct characters to match,
diff --git a/src/main/scala/sigmastate/lang/syntax/Core.scala b/src/main/scala/sigmastate/lang/syntax/Core.scala
index bf5ded27d5..935113e680 100644
--- a/src/main/scala/sigmastate/lang/syntax/Core.scala
+++ b/src/main/scala/sigmastate/lang/syntax/Core.scala
@@ -39,7 +39,7 @@ trait Core extends syntax.Literals {
val `_` = W("_")
val `type` = W("type")
val `val` = W("val")
- val `fun` = W("fun")
+ val `def` = W("def")
val `case` = W("case")
val `then` = W("then")
val `else` = W("else")
@@ -107,8 +107,10 @@ trait Core extends syntax.Literals {
// val ClassQualifier = P( "[" ~ Id ~ "]" )
// val ThisSuper = P( `this` | `super` ~ ClassQualifier.? )
// val ThisPath: P0 = P( ThisSuper ~ ("." ~ PostDotCheck ~/ Id).rep )
- val IdPath = P( Id.! ~ ("." ~ PostDotCheck ~/ (`this`.! | Id.!)).rep /*~ ("." ~ ThisPath).?*/ ).map {
- case (h, t) => t.foldLeft[SValue](Ident(h))(builder.mkSelect(_, _))
+ val IdPath = P( Index ~ Id.! ~ ("." ~ PostDotCheck ~/ Index ~ (`this`.! | Id.!)).rep /*~ ("." ~ ThisPath).?*/ ).map {
+ case (hi, hs, t) => t.foldLeft[SValue](atSrcPos(hi){builder.mkIdent(hs, NoType)}){
+ case (obj, (i, s)) => atSrcPos(i) { builder.mkSelect(obj, s) }
+ }
}
P( /*ThisPath |*/ IdPath )
}
diff --git a/src/main/scala/sigmastate/lang/syntax/Exprs.scala b/src/main/scala/sigmastate/lang/syntax/Exprs.scala
index 521992d39d..1fae7a1481 100644
--- a/src/main/scala/sigmastate/lang/syntax/Exprs.scala
+++ b/src/main/scala/sigmastate/lang/syntax/Exprs.scala
@@ -1,11 +1,12 @@
package sigmastate.lang.syntax
import fastparse.noApi._
+import scalan.Nullable
import sigmastate._
import sigmastate.Values._
-import sigmastate.lang.SigmaPredef.ZKProofSym
-import sigmastate.lang.Terms.{Lambda, ApplyTypes, MethodCallLike, Apply, Val, ValueOps, Select, Ident}
+import sigmastate.lang.Terms.{Ident, Val, ValueOps}
import sigmastate.lang._
+import sigmastate.lang.SigmaPredef._
import sigmastate.lang.syntax.Basic._
import scala.annotation.tailrec
@@ -14,6 +15,7 @@ import scala.annotation.tailrec
trait Exprs extends Core with Types {
import WhitespaceApi._
+ import builder._
def AnonTmpl: P0
def BlockDef: P[Value[SType]]
@@ -30,6 +32,9 @@ trait Exprs extends Core with Types {
val TypeExpr = ExprCtx.Expr
+ private val predefFuncRegistry = new PredefinedFuncRegistry(builder)
+ import predefFuncRegistry._
+
//noinspection TypeAnnotation,ForwardReference
class WsCtx(semiInference: Boolean, arrowTypeAscriptions: Boolean){
@@ -39,29 +44,29 @@ trait Exprs extends Core with Types {
val Expr: P[Value[SType]] = {
val If = {
val Else = P( Semi.? ~ `else` ~/ Expr )
- P( `if` ~/ "(" ~ ExprCtx.Expr ~ ")" ~ Expr ~ Else ).map {
- case (c, t, e) => builder.mkIf(c.asValue[SBoolean.type], t, e)
+ P( Index ~ `if` ~/ "(" ~ ExprCtx.Expr ~ ")" ~ Expr ~ Else ).map {
+ case (i, c, t, e) => atSrcPos(i) { mkIf(c.asValue[SBoolean.type], t, e) }
}
}
-// val Fun = P( /* `fun` ~/ */ FunDef)
+ val Fun = P(`def` ~ FunDef)
- val LambdaRhs = if (semiInference) P( BlockChunk.map {
- case (_ , b) => mkBlock(b)
+ val LambdaRhs = if (semiInference) P( (Index ~ BlockChunk).map {
+ case (index, (_ , b)) => atSrcPos(index) { block(b) }
} )
else P( Expr )
// val ParenedLambda = P( Parened ~~ (WL ~ `=>` ~ LambdaRhs.? /*| ExprSuffix ~~ PostfixSuffix ~ SuperPostfixSuffix*/) ).map {
// case (args, None) => mkLambda(args, UnitConstant)
// case (args, Some(body)) => mkLambda(args, body)
// }
- val PostfixLambda = P( PostfixExpr ~ (`=>` ~ LambdaRhs.? | SuperPostfixSuffix).? ).map {
- case (e, None) => e
- case (e, Some(None)) => e
- case (Tuple(args), Some(Some(body))) => mkLambda(args, body)
- case (e, Some(body)) => error(s"Invalid declaration of lambda $e => $body")
+ val PostfixLambda = P( Index ~ PostfixExpr ~ (`=>` ~ LambdaRhs.? | SuperPostfixSuffix).? ).map {
+ case (_, e, None) => e
+ case (_, e, Some(None)) => e
+ case (i, Tuple(args), Some(Some(body))) => atSrcPos(i) { lambda(args, body) }
+ case (i, e, Some(body)) => error(s"Invalid declaration of lambda $e => $body", Some(srcCtx(i)))
}
val SmallerExprOrLambda = P( /*ParenedLambda |*/ PostfixLambda )
-// val Arg = (Id.! ~ `:` ~/ Type).map { case (n, t) => Ident(IndexedSeq(n), t)}
- P( If /*| Fun*/ | SmallerExprOrLambda )
+// val Arg = (Id.! ~ `:` ~/ Type).map { case (n, t) => mkIdent(IndexedSeq(n), t)}
+ P( If | Fun | SmallerExprOrLambda )
}
val SuperPostfixSuffix = P( (`=` ~/ Expr).? /*~ MatchAscriptionSuffix.?*/ )
@@ -70,7 +75,7 @@ trait Exprs extends Core with Types {
val MatchAscriptionSuffix = P(`match` ~/ "{" ~ CaseClauses | Ascription)
val ExprPrefix = P( WL ~ CharIn("-+!~").! ~~ !syntax.Basic.OpChar ~ WS)
val ExprSuffix = P(
- (WL ~ "." ~/ Id.!.map(Ident(_))
+ (WL ~ "." ~/ (Index ~ Id.!).map{ case (i, s) => atSrcPos(i) { mkIdent(s, NoType)} }
| WL ~ TypeArgs.map(items => STypeApply("", items.toIndexedSeq))
| NoSemis ~ ArgList ).repX /* ~~ (NoSemis ~ `_`).? */
)
@@ -87,7 +92,8 @@ trait Exprs extends Core with Types {
val rhs = applySuffix(f, args)
(op, rhs)
}
- val PostFix = P( NoSemis ~~ WL ~~ Id.! ~ Newline.? ).map(Ident(_))
+ val PostFix = P( NoSemis ~~ WL ~~ (Index ~ Id.!) ~ Newline.? )
+ .map{ case (i, s) => atSrcPos(i) { mkIdent(s, NoType)} }
val PostfixSuffix = P( InfixSuffix.repX ~~ PostFix.?)
@@ -97,7 +103,9 @@ trait Exprs extends Core with Types {
val obj = mkInfixTree(lhs, infixOps)
postfix.fold(obj) {
case Ident(name, _) =>
- builder.mkMethodCallLike(obj, name, IndexedSeq.empty)
+ builder.currentSrcCtx.withValue(obj.sourceContext) {
+ mkMethodCallLike(obj, name, IndexedSeq.empty)
+ }
}
}
@@ -107,32 +115,21 @@ trait Exprs extends Core with Types {
P( /*New | */ BlockExpr
| ExprLiteral
- | StableId //.map { case Ident(ps, t) => mkIdent(ps, t) }
- | `_`.!.map(Ident(_))
- | Parened.map(items =>
- if (items.isEmpty) UnitConstant
- else if (items.lengthCompare(1) == 0) items.head
- else builder.mkTuple(items)) )
+ | StableId //.map { case Ident(ps, t) => Ident(ps, t) }
+ | (Index ~ `_`.!).map { case (i, lit) => atSrcPos(i) { mkIdent(lit, NoType) } }
+ | (Index ~ Parened).map {
+ case (index, Seq()) => atSrcPos(index) { mkUnitConstant }
+ case (_, Seq(item)) => item
+ case (index, items) => atSrcPos(index) { mkTuple(items) }
+ }
+ )
}
val Guard : P0 = P( `if` ~/ PostfixExpr ).ignore
}
- protected def mkIdent(nameParts: String, tpe: SType = NoType): SValue = {
- builder.mkIdent(nameParts, tpe)
- }
-
- protected def mkLambda(args: Seq[Value[SType]], body: Value[SType]): Value[SType] = {
+ protected def lambda(args: Seq[Value[SType]], body: Value[SType]): Value[SType] = {
val names = args.map { case Ident(n, t) => (n, t) }
- builder.mkLambda(names.toIndexedSeq, NoType, Some(body))
- }
-
- protected def mkApply(func: Value[SType], args: IndexedSeq[Value[SType]]): Value[SType] = (func, args) match {
- case _ => builder.mkApply(func, args)
- }
-
- def mkApplyTypes(input: Value[SType], targs: IndexedSeq[SType]): Value[SType] = {
-// val subst = targs.zipWithIndex.map { case (t, i) => (STypeIdent(s"_${i + 1}") -> t) }.toMap
- builder.mkApplyTypes(input, targs)
+ mkLambda(names.toIndexedSeq, NoType, Some(body))
}
/** The precedence of an infix operator is determined by the operator's first character.
@@ -185,36 +182,52 @@ trait Exprs extends Core with Types {
protected def applySuffix(f: Value[SType], args: Seq[SigmaNode]): Value[SType] = {
- val rhs = args.foldLeft(f)((acc, arg) => arg match {
- case Ident(name, _) => builder.mkSelect(acc, name)
- case UnitConstant => mkApply(acc, IndexedSeq.empty)
- case Tuple(xs) => mkApply(acc, xs)
- case STypeApply("", targs) => mkApplyTypes(acc, targs)
- case arg: SValue => acc match {
- case Ident(name, _) if name == "ZKProof" => arg match {
- case Terms.Block(_, body) => Apply(ZKProofSym, IndexedSeq(body))
- case nonBlock => error(s"expected block parameter for ZKProof, got $nonBlock")
+ builder.currentSrcCtx.withValue(f.sourceContext) {
+ val rhs = args.foldLeft(f)((acc, arg) => arg match {
+ case Ident(name, _) => mkSelect(acc, name)
+ case UnitConstant() => mkApply(acc, IndexedSeq.empty)
+ case Tuple(xs) => mkApply(acc, xs)
+ case STypeApply("", targs) => mkApplyTypes(acc, targs)
+ case arg: SValue => acc match {
+ case Ident(name, _) if name == ZKProofFunc.name => arg match {
+ case Terms.Block(_, body) =>
+ mkApply(mkIdent(ZKProofFunc.name, ZKProofFunc.declaration.tpe), IndexedSeq(body))
+ case nonBlock =>
+ error(s"expected block parameter for ZKProof, got $nonBlock", nonBlock.sourceContext)
+ }
+ case _ => mkApply(acc, IndexedSeq(arg))
}
- case _ => mkApply(acc, IndexedSeq(arg))
- }
- case _ => error(s"Error after expression $f: invalid suffixes $args")
- })
- rhs
+ case _ => error(s"Error after expression $f: invalid suffixes $args", f.sourceContext)
+ })
+ rhs
+ }
}
-// val FunDef = {
-// val Body = P( WL ~ `=>` ~ StatCtx.Expr )
-// P( FunSig ~ (`:` ~/ Type).? ~~ Body ).map {
-// case (_ @ Seq(args), resType, body) => builder.mkLambda(args.toIndexedSeq, resType.getOrElse(NoType), Some(body))
-// case (secs, resType, body) => error(s"Function can only have single argument list: fun ($secs): $resType = $body")
-// }
-// }
+ val FunDef = {
+ val Body = P( WL ~ `=` ~/ FreeCtx.Expr )
+ P(Index ~ DottyExtMethodSubj.? ~ Id.! ~ FunSig ~ (`:` ~/ Type).? ~~ Body ).map {
+ case (index, None, n, args, resType, body) =>
+ atSrcPos(index) {
+ val lambda = mkLambda(args.headOption.getOrElse(Seq()).toIndexedSeq, resType.getOrElse(NoType), Some(body))
+ mkVal(n, resType.getOrElse(NoType), lambda)
+ }
+ case (index, Some(dottyExtSubj), n, args, resType, body) if args.length <= 1 =>
+ val combinedArgs = Seq(dottyExtSubj) ++ args.headOption.getOrElse(Seq())
+ atSrcPos(index) {
+ val lambda = mkLambda(combinedArgs.toIndexedSeq, resType.getOrElse(NoType), Some(body))
+ mkVal(n, resType.getOrElse(NoType), lambda)
+ }
+ case (index, dottyExt, n, secs, resType, body) =>
+ error(s"Function can only have single argument list: def ${dottyExt.getOrElse("")} $n($secs): ${resType.getOrElse(NoType)} = $body", Some(srcCtx(index)))
+ }
+ }
val SimplePattern = {
val TupleEx = P( "(" ~/ Pattern.repTC() ~ ")" )
val Extractor = P( StableId /* ~ TypeArgs.?*/ ~ TupleEx.? )
// val Thingy = P( `_` ~ (`:` ~/ TypePat).? ~ !("*" ~~ !syntax.Basic.OpChar) )
- P( /*Thingy | PatLiteral |*/ TupleEx | Extractor | VarId.!.map(Ident(_)))
+ P( /*Thingy | PatLiteral |*/ TupleEx | Extractor
+ | (Index ~ VarId.!).map { case (i, lit) => atSrcPos(i) { mkIdent(lit, NoType) } })
}
val BlockExpr = P( "{" ~/ (/*CaseClauses |*/ Block ~ "}") )
@@ -240,34 +253,39 @@ trait Exprs extends Core with Types {
if (stats.nonEmpty) {
val lets = stats.iterator.take(stats.size - 1).map {
case l: Val => l
- case _ => error(s"Block should contain a list of Val bindings and one expression: but was $stats")
+ case v => error(s"Block should contain a list of Val bindings and one expression: but was $stats",
+ v.sourceContext)
}
(lets.toList, stats.last)
}
else
- (Seq(), UnitConstant)
+ (Seq(), mkUnitConstant)
}
- protected def mkBlock(stats: Seq[SValue]): SValue = {
+ protected def block(stats: Seq[SValue]): SValue = {
val (lets, body) = extractBlockStats(stats)
- builder.mkBlock(lets, body)
+ mkBlock(lets, body)
}
def BaseBlock(end: P0)(implicit name: sourcecode.Name): P[Value[SType]] = {
val BlockEnd = P( Semis.? ~ &(end) )
val Body = P( BlockChunk.repX(sep = Semis) )
- P( Semis.? ~ BlockLambda.? ~ Body ~/ BlockEnd ).map {
- case (Some(args), Seq((Seq(), Seq(b)))) =>
- builder.mkLambda(args.toIndexedSeq, NoType, Some(b))
- case (Some(args), bodyItems) =>
- val block = mkBlock(bodyItems.flatMap {
- case (Seq(), exprs) => exprs
- })
- builder.mkLambda(args.toIndexedSeq, NoType, Some(block))
- case (None, bodyItems) =>
- mkBlock(bodyItems.flatMap {
- case (Seq(), exprs) => exprs
- })
+ P( Index ~ Semis.? ~ BlockLambda.? ~ Body ~/ BlockEnd ).map {
+ case (index, Some(args), Seq((Seq(), Seq(b)))) =>
+ atSrcPos(index) { mkLambda(args.toIndexedSeq, NoType, Some(b)) }
+ case (index, Some(args), bodyItems) =>
+ atSrcPos(index) {
+ val b = block(bodyItems.flatMap {
+ case (Seq(), exprs) => exprs
+ })
+ mkLambda(args.toIndexedSeq, NoType, Some(b))
+ }
+ case (index, None, bodyItems) =>
+ atSrcPos(index) {
+ block(bodyItems.flatMap {
+ case (Seq(), exprs) => exprs
+ })
+ }
}
}
val Block = BaseBlock("}")
@@ -284,9 +302,9 @@ trait Exprs extends Core with Types {
}
val TypePat = P( CompoundType )
- val ParenArgList = P( "(" ~/ Exprs /*~ (`:` ~/ `_*`).?*/.? ~ TrailingComma ~ ")" ).map {
- case Some(exprs) => builder.mkTuple(exprs)
- case None => UnitConstant
+ val ParenArgList = P( "(" ~/ Index ~ Exprs /*~ (`:` ~/ `_*`).?*/.? ~ TrailingComma ~ ")" ).map {
+ case (index, Some(exprs)) => atSrcPos(index) { mkTuple(exprs) }
+ case (index, None) => atSrcPos(index) { mkUnitConstant }
}
val ArgList = P( ParenArgList | OneNLMax ~ BlockExpr )
diff --git a/src/main/scala/sigmastate/lang/syntax/Literals.scala b/src/main/scala/sigmastate/lang/syntax/Literals.scala
index 5e9772da78..989e01939f 100644
--- a/src/main/scala/sigmastate/lang/syntax/Literals.scala
+++ b/src/main/scala/sigmastate/lang/syntax/Literals.scala
@@ -8,10 +8,13 @@ import fastparse.{all, core}
import java.lang.Long.parseLong
import java.lang.Integer.parseInt
-import sigmastate.lang.{SigmaBuilder, StdSigmaBuilder}
+import sigmastate.lang.{SigmaBuilder, SourceContext, StdSigmaBuilder}
trait Literals { l =>
- var builder: SigmaBuilder = StdSigmaBuilder
+ val builder: SigmaBuilder = StdSigmaBuilder
+ import builder._
+ def atSrcPos[A](parserIndex: Int)(thunk: => A): A
+ def srcCtx(parserIndex: Int): SourceContext
def Block: P[Value[SType]]
def Pattern: P0
@@ -55,7 +58,10 @@ trait Literals { l =>
val Int: Parser[Unit] = P( (HexNum | DecNum) ~ CharIn("Ll").? )
- val Bool: Parser[BooleanConstant] = P( Key.W("true").map(_ => TrueLeaf) | Key.W("false").map(_ => FalseLeaf) )
+ val Bool: Parser[BooleanConstant] =
+ P( (Index ~ (Key.W("true").! | Key.W("false").!)).map {
+ case (i, lit) => atSrcPos(i) { mkConstant[SBoolean.type](if (lit == "true") true else false, SBoolean) }
+ })
// Comments cannot have cuts in them, because they appear before every
// terminal node. That means that a comment before any terminal will
@@ -84,21 +90,25 @@ trait Literals { l =>
class InterpCtx(interp: Option[P0]){
//noinspection TypeAnnotation
val Literal = P(
- ("-".!.? ~ /*Float |*/ Int.!).map {
- case (signOpt, lit) =>
+ ("-".!.? ~ Index ~ ( /*Float |*/ Int.!)).map {
+ case (signOpt, index, lit) =>
val sign = if (signOpt.isDefined) -1 else 1
val suffix = lit.charAt(lit.length - 1)
val (digits, radix) = if (lit.startsWith("0x")) (lit.substring(2), 16) else (lit, 10)
- if (suffix == 'L' || suffix == 'l')
- builder.mkConstant[SLong.type](sign * parseLong(digits.substring(0, digits.length - 1), radix), SLong)
- else
- builder.mkConstant[SInt.type](sign * parseInt(digits, radix), SInt)
+ atSrcPos(index) {
+ if (suffix == 'L' || suffix == 'l')
+ mkConstant[SLong.type](sign * parseLong(digits.substring(0, digits.length - 1), radix), SLong)
+ else
+ mkConstant[SInt.type](sign * parseInt(digits, radix), SInt)
+ }
}
| Bool
- | (String | "'" ~/ (Char | Symbol) | Null).!.map { lit: String =>
+ | (Index ~ (String | "'" ~/ (Char | Symbol) | Null).!).map { case (index, lit) =>
// strip single or triple quotes
def strip(s: String): String = if (!s.startsWith("\"")) s else strip(s.stripPrefix("\"").stripSuffix("\""))
- builder.mkConstant[SString.type](strip(lit), SString)
+ atSrcPos(index) {
+ mkConstant[SString.type](strip(lit), SString)
+ }
})
val Interp: Parser[Unit] = interp match{
diff --git a/src/main/scala/sigmastate/serialization/ApplySerializer.scala b/src/main/scala/sigmastate/serialization/ApplySerializer.scala
index bc790ba2c7..5042b04b4e 100644
--- a/src/main/scala/sigmastate/serialization/ApplySerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ApplySerializer.scala
@@ -11,12 +11,12 @@ case class ApplySerializer(cons: (Value[SType], IndexedSeq[Value[SType]]) => Val
override val opCode: OpCode = FuncApplyCode
- override def serializeBody(obj: Apply, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: Apply, w: SigmaByteWriter): Unit = {
w.putValue(obj.func)
w.putValues(obj.args)
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val func = r.getValue()
val args = r.getValues()
cons(func, args)
diff --git a/src/main/scala/sigmastate/serialization/BlockValueSerializer.scala b/src/main/scala/sigmastate/serialization/BlockValueSerializer.scala
index d0db9ffe53..6b8638dab8 100644
--- a/src/main/scala/sigmastate/serialization/BlockValueSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/BlockValueSerializer.scala
@@ -3,7 +3,7 @@ package sigmastate.serialization
import sigmastate.Values._
import sigmastate._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
case class BlockValueSerializer(cons: (IndexedSeq[BlockItem], Value[SType]) => Value[SType])
@@ -11,13 +11,13 @@ case class BlockValueSerializer(cons: (IndexedSeq[BlockItem], Value[SType]) => V
override val opCode: OpCode = BlockValueCode
- override def serializeBody(obj: BlockValue, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: BlockValue, w: SigmaByteWriter): Unit = {
w.putUInt(obj.items.length)
- obj.items.foreach(w.putValue)
+ obj.items.foreach(w.putValue(_))
w.putValue(obj.result)
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val itemsSize = r.getUInt().toIntExact
val values = (1 to itemsSize).map(_ => r.getValue().asInstanceOf[BlockItem])
val result = r.getValue()
diff --git a/src/main/scala/sigmastate/serialization/BoolToSigmaPropSerializer.scala b/src/main/scala/sigmastate/serialization/BoolToSigmaPropSerializer.scala
index 4f3e3acc52..045ca3a010 100644
--- a/src/main/scala/sigmastate/serialization/BoolToSigmaPropSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/BoolToSigmaPropSerializer.scala
@@ -10,11 +10,11 @@ case class BoolToSigmaPropSerializer(cons: BoolValue => SigmaPropValue) extends
override val opCode: Byte = BoolToSigmaPropCode
- def serializeBody(obj: BoolToSigmaProp, w: SigmaByteWriter): Unit = {
+ def serialize(obj: BoolToSigmaProp, w: SigmaByteWriter): Unit = {
w.putValue(obj.value)
}
- def parseBody(r: SigmaByteReader): Values.Value[SType] = {
+ def parse(r: SigmaByteReader): Values.Value[SType] = {
val p = r.getValue().asBoolValue
cons(p)
}
diff --git a/src/main/scala/sigmastate/serialization/CaseObjectSerialization.scala b/src/main/scala/sigmastate/serialization/CaseObjectSerialization.scala
index 3a37e96e80..a42e18ae8c 100644
--- a/src/main/scala/sigmastate/serialization/CaseObjectSerialization.scala
+++ b/src/main/scala/sigmastate/serialization/CaseObjectSerialization.scala
@@ -8,7 +8,7 @@ import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
case class CaseObjectSerialization[V <: Value[SType]](override val opCode: OpCode, obj: V)
extends ValueSerializer[V] {
- override def serializeBody(obj: V, w: SigmaByteWriter): Unit = ()
+ override def serialize(obj: V, w: SigmaByteWriter): Unit = ()
- override def parseBody(r: SigmaByteReader): V = obj
+ override def parse(r: SigmaByteReader): V = obj
}
diff --git a/src/main/scala/sigmastate/serialization/ConcreteCollectionBooleanConstantSerializer.scala b/src/main/scala/sigmastate/serialization/ConcreteCollectionBooleanConstantSerializer.scala
index 3d5267c1af..02f3d45061 100644
--- a/src/main/scala/sigmastate/serialization/ConcreteCollectionBooleanConstantSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ConcreteCollectionBooleanConstantSerializer.scala
@@ -10,7 +10,7 @@ case class ConcreteCollectionBooleanConstantSerializer(cons: (IndexedSeq[Value[S
override val opCode: Byte = ConcreteCollectionBooleanConstantCode
- override def serializeBody(cc: ConcreteCollection[SBoolean.type], w: SigmaByteWriter): Unit = {
+ override def serialize(cc: ConcreteCollection[SBoolean.type], w: SigmaByteWriter): Unit = {
w.putUShort(cc.items.size)
w.putBits(
cc.items.map {
@@ -19,7 +19,7 @@ case class ConcreteCollectionBooleanConstantSerializer(cons: (IndexedSeq[Value[S
}.toArray)
}
- override def parseBody(r: SigmaByteReader): Value[SCollection[SBoolean.type]] = {
+ override def parse(r: SigmaByteReader): Value[SCollection[SBoolean.type]] = {
val size = r.getUShort()
val booleanConstants = r.getBits(size).map(v => BooleanConstant.fromBoolean(v))
cons(booleanConstants, SBoolean)
diff --git a/src/main/scala/sigmastate/serialization/ConcreteCollectionSerializer.scala b/src/main/scala/sigmastate/serialization/ConcreteCollectionSerializer.scala
index 15105cd547..2cab981248 100644
--- a/src/main/scala/sigmastate/serialization/ConcreteCollectionSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ConcreteCollectionSerializer.scala
@@ -4,20 +4,20 @@ import sigmastate.{SCollection, SType}
import sigmastate.Values._
import sigmastate.serialization.OpCodes._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
case class ConcreteCollectionSerializer(cons: (IndexedSeq[Value[SType]], SType) => Value[SCollection[SType]])
extends ValueSerializer[ConcreteCollection[_ <: SType]] {
override val opCode: Byte = ConcreteCollectionCode
- override def serializeBody(cc: ConcreteCollection[_ <: SType], w: SigmaByteWriter): Unit = {
+ override def serialize(cc: ConcreteCollection[_ <: SType], w: SigmaByteWriter): Unit = {
w.putUShort(cc.items.size)
w.putType(cc.tpe.elemType)
- cc.items.foreach(w.putValue)
+ cc.items.foreach(w.putValue(_))
}
- override def parseBody(r: SigmaByteReader): Value[SCollection[SType]] = {
+ override def parse(r: SigmaByteReader): Value[SCollection[SType]] = {
val size = r.getUShort()
val tItem = r.getType()
val values = (1 to size).map(_ => r.getValue())
diff --git a/src/main/scala/sigmastate/serialization/ConstantPlaceholderSerializer.scala b/src/main/scala/sigmastate/serialization/ConstantPlaceholderSerializer.scala
index 0eb88d0ead..d9481bba20 100644
--- a/src/main/scala/sigmastate/serialization/ConstantPlaceholderSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ConstantPlaceholderSerializer.scala
@@ -10,11 +10,11 @@ case class ConstantPlaceholderSerializer(cons: (Int, SType) => Value[SType])
override val opCode: OpCode = ConstantPlaceholderIndexCode
- override def serializeBody(obj: ConstantPlaceholder[SType], w: SigmaByteWriter): Unit = {
+ override def serialize(obj: ConstantPlaceholder[SType], w: SigmaByteWriter): Unit = {
w.putUInt(obj.id)
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val id = r.getUInt().toInt
val constant = r.constantStore.get(id)
if (r.resolvePlaceholdersToConstants)
diff --git a/src/main/scala/sigmastate/serialization/ConstantSerializer.scala b/src/main/scala/sigmastate/serialization/ConstantSerializer.scala
index 505510b9c0..cb3867ec12 100644
--- a/src/main/scala/sigmastate/serialization/ConstantSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ConstantSerializer.scala
@@ -5,7 +5,6 @@ import sigmastate.Values._
import sigmastate.lang.SigmaBuilder
import sigmastate.lang.Terms.OperationId
import sigmastate.serialization.OpCodes.OpCode
-import sigmastate.utils.Extensions._
import sigmastate.utils.{SigmaByteWriter, SigmaByteReader}
import sigmastate.utxo.CostTable.Cost
@@ -15,11 +14,9 @@ case class ConstantSerializer(builder: SigmaBuilder)
val opCode: OpCode = OpCodes.ConstantCode
- override def opCost(opId: OperationId) = Cost.ConstantNode
+ override def opCost(opId: OperationId): Int = Cost.ConstantNode
- def parseBody(r: SigmaByteReader): Value[SType] = deserialize(r)
-
- def serializeBody(obj: Constant[SType], w: SigmaByteWriter): Unit = serialize(obj, w)
+ override def parse(r: SigmaByteReader): Value[SType] = deserialize(r)
override def serialize(c: Constant[SType], w: SigmaByteWriter): Unit = {
w.putType(c.tpe)
@@ -31,5 +28,6 @@ case class ConstantSerializer(builder: SigmaBuilder)
val obj = DataSerializer.deserialize(tpe, r)
builder.mkConstant(obj, tpe)
}
+
}
diff --git a/src/main/scala/sigmastate/serialization/CreateAvlTreeSerializer.scala b/src/main/scala/sigmastate/serialization/CreateAvlTreeSerializer.scala
new file mode 100644
index 0000000000..15fa88db47
--- /dev/null
+++ b/src/main/scala/sigmastate/serialization/CreateAvlTreeSerializer.scala
@@ -0,0 +1,32 @@
+package sigmastate.serialization
+
+import sigmastate.SCollection._
+import sigmastate.SOption.SIntOption
+import sigmastate.serialization.OpCodes.OpCode
+import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
+import sigmastate._
+import sigmastate.Values._
+import sigmastate.lang.Terms.ValueOps
+
+case class CreateAvlTreeSerializer(
+ cons: (ByteValue, Value[SByteArray], IntValue, Value[SIntOption]) => AvlTreeValue
+ )
+ extends ValueSerializer[CreateAvlTree]
+{
+ override val opCode: OpCode = OpCodes.AvlTreeCode
+
+ override def serialize(obj: CreateAvlTree, w: SigmaByteWriter): Unit = {
+ w.putValue(obj.operationFlags)
+ w.putValue(obj.digest)
+ w.putValue(obj.keyLength)
+ w.putValue(obj.valueLengthOpt)
+ }
+
+ override def parse(r: SigmaByteReader) = {
+ val flags = r.getValue().asByteValue
+ val digest = r.getValue().asByteArray
+ val keyLength = r.getValue().asIntValue
+ val valueLength = r.getValue().asOption[SInt.type]
+ cons(flags, digest, keyLength, valueLength)
+ }
+}
diff --git a/src/main/scala/sigmastate/serialization/DataSerializer.scala b/src/main/scala/sigmastate/serialization/DataSerializer.scala
index b3ef05d088..6bd9789fd8 100644
--- a/src/main/scala/sigmastate/serialization/DataSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/DataSerializer.scala
@@ -6,8 +6,9 @@ import java.nio.charset.StandardCharsets
import org.ergoplatform.ErgoBox
import sigmastate.Values.SigmaBoolean
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate._
+import sigmastate.eval.Evaluation
import sigmastate.interpreter.CryptoConstants.EcPointType
import scala.collection.mutable
@@ -31,28 +32,28 @@ object DataSerializer {
w.putUShort(data.length)
w.putBytes(data)
case SGroupElement =>
- GroupElementSerializer.serializeBody(v.asInstanceOf[EcPointType], w)
+ GroupElementSerializer.serialize(v.asInstanceOf[EcPointType], w)
case SSigmaProp =>
val p = v.asInstanceOf[SigmaBoolean]
- w.putValue(p)
+ SigmaBoolean.serializer.serialize(p, w)
case SBox =>
- ErgoBox.serializer.serializeBody(v.asInstanceOf[ErgoBox], w)
+ ErgoBox.sigmaSerializer.serialize(v.asInstanceOf[ErgoBox], w)
case SAvlTree =>
- AvlTreeData.serializer.serializeBody(v.asInstanceOf[AvlTreeData], w)
- case tCol: SCollectionType[a] =>
- val arr = v.asInstanceOf[tCol.WrappedType]
+ AvlTreeData.serializer.serialize(v.asInstanceOf[AvlTreeData], w)
+ case tColl: SCollectionType[a] =>
+ val arr = v.asInstanceOf[tColl.WrappedType]
w.putUShort(arr.length)
- tCol.elemType match {
+ tColl.elemType match {
case SBoolean =>
w.putBits(arr.asInstanceOf[Array[Boolean]])
case SByte =>
w.putBytes(arr.asInstanceOf[Array[Byte]])
case _ =>
- arr.foreach(x => serialize(x, tCol.elemType, w))
+ arr.foreach(x => serialize(x, tColl.elemType, w))
}
case t: STuple =>
- val arr = v.asInstanceOf[t.WrappedType]
+ val arr = Evaluation.fromDslTuple(v, t).asInstanceOf[t.WrappedType]
val len = arr.length
assert(arr.length == t.items.length, s"Type $t doesn't correspond to value $arr")
if (len > 0xFFFF)
@@ -82,20 +83,19 @@ object DataSerializer {
val valueBytes = r.getBytes(size)
new BigInteger(valueBytes)
case SGroupElement =>
- GroupElementSerializer.parseBody(r)
+ GroupElementSerializer.parse(r)
case SSigmaProp =>
- val p = r.getValue().asInstanceOf[SigmaBoolean]
- p
+ SigmaBoolean.serializer.parse(r)
case SBox =>
- ErgoBox.serializer.parseBody(r)
+ ErgoBox.sigmaSerializer.parse(r)
case SAvlTree =>
- AvlTreeData.serializer.parseBody(r)
- case tCol: SCollectionType[a] =>
+ AvlTreeData.serializer.parse(r)
+ case tColl: SCollectionType[a] =>
val len = r.getUShort()
- if (tCol.elemType == SByte)
+ if (tColl.elemType == SByte)
r.getBytes(len)
else
- deserializeArray(len, tCol.elemType, r)
+ deserializeArray(len, tColl.elemType, r)
case tuple: STuple =>
val arr = tuple.items.map { t =>
deserialize(t, r)
diff --git a/src/main/scala/sigmastate/serialization/ErgoTreeSerializer.scala b/src/main/scala/sigmastate/serialization/ErgoTreeSerializer.scala
index f1d29608f6..e9ee45f3cf 100644
--- a/src/main/scala/sigmastate/serialization/ErgoTreeSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ErgoTreeSerializer.scala
@@ -6,7 +6,7 @@ import sigmastate.lang.DeserializationSigmaBuilder
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.Append
import sigmastate.{SGroupElement, SType}
-
+import sigmastate.lang.Terms.ValueOps
import scala.collection.mutable
class ErgoTreeSerializer {
@@ -14,7 +14,7 @@ class ErgoTreeSerializer {
/** Default serialization of ErgoTree. Doesn't apply any transformations and guarantee to preserve original
* structure after deserialization. */
def serializeErgoTree(ergoTree: ErgoTree): Array[Byte] = {
- val w = Serializer.startWriter()
+ val w = SigmaSerializer.startWriter()
serializeHeader(ergoTree, w)
ValueSerializer.serialize(ergoTree.root, w)
w.toBytes
@@ -23,7 +23,7 @@ class ErgoTreeSerializer {
/** Default deserialization of ErgoTree (should be inverse to `serializeErgoTree`).
* Doesn't apply any transformations to the parsed tree. */
def deserializeErgoTree(bytes: Array[Byte]): ErgoTree = {
- val r = Serializer.startReader(bytes)
+ val r = SigmaSerializer.startReader(bytes)
deserializeErgoTree(r)
}
@@ -32,7 +32,7 @@ class ErgoTreeSerializer {
val previousConstantStore = r.constantStore
r.constantStore = new ConstantStore(cs)
// reader with constant store attached is required (to get tpe for a constant placeholder)
- val root = ValueSerializer.deserialize(r)
+ val root = ValueSerializer.deserialize(r).asSigmaProp
r.constantStore = previousConstantStore
ErgoTree(h, cs, root)
}
@@ -76,13 +76,13 @@ class ErgoTreeSerializer {
* then appending `treeBytes` */
def serializeWithSegregation(tree: Value[SType]): Array[Byte] = {
val constantStore = new ConstantStore()
- val treeWriter = Serializer.startWriter(constantStore)
+ val treeWriter = SigmaSerializer.startWriter(constantStore)
// serialize tree and segregate constants into constantStore
ValueSerializer.serialize(tree, treeWriter)
val extractedConstants = constantStore.getAll
- val w = Serializer.startWriter()
+ val w = SigmaSerializer.startWriter()
serializeHeader(ErgoTree(ErgoTree.ConstantSegregationHeader, extractedConstants, null), w)
// write tree bytes with ConstantsPlaceholders (which were injected during serialization)
@@ -98,7 +98,7 @@ class ErgoTreeSerializer {
}
def deserialize(bytes: Array[Byte], resolvePlaceholdersToConstants: Boolean = true): Value[SType] = {
- deserialize(Serializer.startReader(bytes), resolvePlaceholdersToConstants)
+ deserialize(SigmaSerializer.startReader(bytes), resolvePlaceholdersToConstants)
}
/** Deserialize Value replacing placeholders with constants if the parameter is true. */
@@ -118,7 +118,7 @@ class ErgoTreeSerializer {
}
def deserializeWithConstantInjection(constantStore: ConstantStore, treeBytes: Array[Byte]): Value[SType] = {
- val r = Serializer.startReader(treeBytes, constantStore, resolvePlaceholdersToConstants = true)
+ val r = SigmaSerializer.startReader(treeBytes, constantStore, resolvePlaceholdersToConstants = true)
val tree = ValueSerializer.deserialize(r)
tree
}
@@ -145,9 +145,9 @@ class ErgoTreeSerializer {
newVals: Array[Value[SType]]): Array[Byte] = {
require(positions.length == newVals.length,
s"expected positions and newVals to have the same length, got: positions: ${positions.toSeq},\n newVals: ${newVals.toSeq}")
- val r = Serializer.startReader(scriptBytes)
+ val r = SigmaSerializer.startReader(scriptBytes)
val (header, constants, treeBytes) = deserializeHeaderWithTreeBytes(r)
- val w = Serializer.startWriter()
+ val w = SigmaSerializer.startWriter()
w.put(header)
w.putUInt(constants.length)
val constantSerializer = ConstantSerializer(DeserializationSigmaBuilder)
@@ -157,7 +157,7 @@ class ErgoTreeSerializer {
val newVal = newVals(positions.indexOf(i))
// we need to get newVal's serialized constant value (see ProveDlogSerializer for example)
val constantStore = new ConstantStore()
- val valW = Serializer.startWriter(constantStore)
+ val valW = SigmaSerializer.startWriter(constantStore)
ValueSerializer.serialize(newVal, valW)
val newConsts = constantStore.getAll
assert(newConsts.length == 1)
diff --git a/src/main/scala/sigmastate/serialization/FuncValueSerializer.scala b/src/main/scala/sigmastate/serialization/FuncValueSerializer.scala
index 2e5b016ec7..fb63f8bc68 100644
--- a/src/main/scala/sigmastate/serialization/FuncValueSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/FuncValueSerializer.scala
@@ -3,7 +3,7 @@ package sigmastate.serialization
import sigmastate.Values._
import sigmastate._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import scala.collection.mutable
@@ -13,13 +13,13 @@ case class FuncValueSerializer(cons: (IndexedSeq[(Int, SType)], Value[SType]) =>
override val opCode: OpCode = FuncValueCode
- override def serializeBody(obj: FuncValue, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: FuncValue, w: SigmaByteWriter): Unit = {
w.putUInt(obj.args.length)
obj.args.foreach{ case (idx, tpe) => w.putUInt(idx).putType(tpe) }
w.putValue(obj.body)
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val argsSize = r.getUInt().toIntExact
val argsBuilder = mutable.ArrayBuilder.make[(Int, SType)]()
for (_ <- 0 until argsSize) {
diff --git a/src/main/scala/sigmastate/serialization/GetVarSerializer.scala b/src/main/scala/sigmastate/serialization/GetVarSerializer.scala
index e2c3968e43..a29b0fcbf8 100644
--- a/src/main/scala/sigmastate/serialization/GetVarSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/GetVarSerializer.scala
@@ -3,7 +3,7 @@ package sigmastate.serialization
import sigmastate.Values._
import sigmastate._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.GetVar
@@ -12,11 +12,11 @@ case class GetVarSerializer(cons: (Byte, SType) => Value[SOption[SType]])
override val opCode: OpCode = GetVarCode
- override def serializeBody(obj: GetVar[_ <: SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: GetVar[_ <: SType], w: SigmaByteWriter): Unit =
w.put(obj.varId)
.putType(obj.tpe.elemType)
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val varId = r.getByte()
val tpe = r.getType()
cons(varId, tpe)
diff --git a/src/main/scala/sigmastate/serialization/GroupElementSerializer.scala b/src/main/scala/sigmastate/serialization/GroupElementSerializer.scala
index 0a2baec38b..cb8adb79aa 100644
--- a/src/main/scala/sigmastate/serialization/GroupElementSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/GroupElementSerializer.scala
@@ -4,28 +4,43 @@ import sigmastate.interpreter.CryptoConstants
import sigmastate.interpreter.CryptoConstants.EcPointType
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-object GroupElementSerializer extends Serializer[EcPointType, EcPointType] {
+/**
+ * A serializer which encodes group elements, so elliptic curve points in our case, to bytes, and decodes points
+ * from bytes.
+ * Every point is encoded in compressed form (so only X coordinate and sign of Y are stored).
+ * Thus for secp256k1 point, 33 bytes are needed. The first bytes is whether equals 2 or 3 depending on the sign of
+ * Y coordinate(==2 is Y is positive, ==3, if Y is negative). Other 32 bytes are containing the X coordinate.
+ * Special case is infinity point, which is encoded by 33 zeroes.
+ * Thus elliptic curve point is always encoded with 33 bytes.
+ */
+object GroupElementSerializer extends SigmaSerializer[EcPointType, EcPointType] {
private val curve = CryptoConstants.dlogGroup
+ private val encodingSize = 1 + CryptoConstants.groupSize
+ private lazy val identityPointEncoding = Array.fill(encodingSize)(0: Byte)
- override def serializeBody(obj: EcPointType, w: SigmaByteWriter): Unit = {
- val bytes = obj.getEncoded(true)
+ override def serialize(point: EcPointType, w: SigmaByteWriter): Unit = {
+ val bytes = if (point.isInfinity) {
+ identityPointEncoding
+ } else {
+ val normed = point.normalize()
+ val ySign = normed.getAffineYCoord.testBitZero()
+ val X = normed.getXCoord.getEncoded
+ val PO = new Array[Byte](X.length + 1)
+ PO(0) = (if (ySign) 0x03 else 0x02).toByte
+ System.arraycopy(X, 0, PO, 1, X.length)
+ PO
+ }
w.putBytes(bytes)
}
- override def parseBody(r: SigmaByteReader): EcPointType = r.getByte() match {
- case 0 =>
- // infinity point is always compressed as 1 byte (X9.62 s 4.3.6)
- val point = curve.curve.decodePoint(Array(0)).asInstanceOf[EcPointType]
- point
- case m if m == 2 || m == 3 =>
- val consumed = 1 + (curve.curve.getFieldSize + 7) / 8
- r.position = r.position - 1
- val encoded = r.getBytes(consumed)
- val point = curve.curve.decodePoint(encoded).asInstanceOf[EcPointType]
- point
- case m =>
- throw new Error(s"Only compressed encoding is supported, $m given")
+ override def parse(r: SigmaByteReader): EcPointType = {
+ val encoded = r.getBytes(encodingSize)
+ if (encoded.head != 0) {
+ curve.curve.decodePoint(encoded).asInstanceOf[EcPointType]
+ } else {
+ curve.identity
+ }
}
}
diff --git a/src/main/scala/sigmastate/serialization/LogicalNotSerializer.scala b/src/main/scala/sigmastate/serialization/LogicalNotSerializer.scala
new file mode 100644
index 0000000000..01deb7af4c
--- /dev/null
+++ b/src/main/scala/sigmastate/serialization/LogicalNotSerializer.scala
@@ -0,0 +1,14 @@
+package sigmastate.serialization
+
+import sigmastate.LogicalNot
+import sigmastate.Values.BoolValue
+import sigmastate.lang.Terms._
+import sigmastate.serialization.OpCodes.OpCode
+import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
+
+case class LogicalNotSerializer(cons: BoolValue => BoolValue)
+ extends ValueSerializer[LogicalNot] {
+ override val opCode: OpCode = OpCodes.LogicalNotCode
+ override def serialize(obj: LogicalNot, w: SigmaByteWriter): Unit = w.putValue(obj.input)
+ override def parse(r: SigmaByteReader): BoolValue = cons(r.getValue().asBoolValue)
+}
diff --git a/src/main/scala/sigmastate/serialization/MethodCallSerializer.scala b/src/main/scala/sigmastate/serialization/MethodCallSerializer.scala
index f9ff2ca540..56afa33726 100644
--- a/src/main/scala/sigmastate/serialization/MethodCallSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/MethodCallSerializer.scala
@@ -2,14 +2,14 @@ package sigmastate.serialization
import sigmastate.Values._
import sigmastate._
-import sigmastate.lang.Terms.MethodCall
-import sigmastate.serialization.OpCodes._
+import sigmastate.lang.SigmaTyper.STypeSubst
+import sigmastate.lang.Terms.{MethodCall, STypeParam}
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-case class MethodCallSerializer(opCode: Byte, cons: (Value[SType], SMethod, IndexedSeq[Value[SType]]) => Value[SType])
+case class MethodCallSerializer(opCode: Byte, cons: (Value[SType], SMethod, IndexedSeq[Value[SType]], STypeSubst) => Value[SType])
extends ValueSerializer[MethodCall] {
- override def serializeBody(mc: MethodCall, w: SigmaByteWriter): Unit = {
+ override def serialize(mc: MethodCall, w: SigmaByteWriter): Unit = {
w.put(mc.method.objType.typeId)
w.put(mc.method.methodId)
w.putValue(mc.obj)
@@ -17,17 +17,36 @@ case class MethodCallSerializer(opCode: Byte, cons: (Value[SType], SMethod, Inde
assert(mc.args.nonEmpty)
w.putValues(mc.args)
}
+// mc.method.stype match {
+// case genType: SGenericType if mc.typeSubst.nonEmpty =>
+// w.putUByte(mc.typeSubst.size)
+// genType.substitutedTypeParams.foreach { tp =>
+// w.putType(mc.typeSubst(tp.ident))
+// }
+// case _ => w.putUByte(0)
+// }
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val typeId = r.getByte()
val methodId = r.getByte()
val obj = r.getValue()
- val args = if (opCode == OpCodes.MethodCallCode) {
- r.getValues()
- }
- else IndexedSeq()
- val method = MethodCall.fromIds(typeId, methodId)
- cons(obj, method, args)
+ val args = if (opCode == OpCodes.MethodCallCode) r.getValues() else IndexedSeq()
+ val method = SMethod.fromIds(typeId, methodId)
+ val specMethod = method.specializeFor(obj.tpe, args.map(_.tpe))
+// val typeSubst: STypeSubst = method.stype match {
+// case genType: SGenericType =>
+// val typeSubstSize = r.getUByte()
+// val xs = new Array[(STypeIdent, SType)](typeSubstSize)
+// for (i <- 0 until typeSubstSize) {
+// val ti = genType.substitutedTypeParams(i).ident
+// xs(i) = (ti, r.getType())
+// }
+// xs.toMap
+// case _ =>
+// r.getUByte() // read 0
+// Map()
+// }
+ cons(obj, specMethod, args, Map())
}
}
diff --git a/src/main/scala/sigmastate/serialization/ModQArithOpSerializer.scala b/src/main/scala/sigmastate/serialization/ModQArithOpSerializer.scala
index 32b7691812..3a88c64a14 100644
--- a/src/main/scala/sigmastate/serialization/ModQArithOpSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ModQArithOpSerializer.scala
@@ -8,12 +8,12 @@ import sigmastate.{ModQArithOp, SType}
case class ModQArithOpSerializer(override val opCode: Byte, cons: (BigIntValue, BigIntValue) => BigIntValue)
extends ValueSerializer[ModQArithOp] {
- override def serializeBody(obj: ModQArithOp, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: ModQArithOp, w: SigmaByteWriter): Unit = {
w.putValue(obj.left)
.putValue(obj.right)
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val arg1 = r.getValue().asBigInt
val arg2 = r.getValue().asBigInt
cons(arg1, arg2)
diff --git a/src/main/scala/sigmastate/serialization/ModQSerializer.scala b/src/main/scala/sigmastate/serialization/ModQSerializer.scala
index ea9defb325..823d75cc6b 100644
--- a/src/main/scala/sigmastate/serialization/ModQSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ModQSerializer.scala
@@ -9,11 +9,11 @@ object ModQSerializer extends ValueSerializer[ModQ] {
override val opCode: Byte = OpCodes.ModQCode
- def serializeBody(obj: ModQ, w: SigmaByteWriter): Unit = {
+ def serialize(obj: ModQ, w: SigmaByteWriter): Unit = {
w.putValue(obj.input)
}
- def parseBody(r: SigmaByteReader): Value[SType] = {
+ def parse(r: SigmaByteReader): Value[SType] = {
val p = r.getValue().asBigInt
ModQ(p)
}
diff --git a/src/main/scala/sigmastate/serialization/OneArgumentOperationSerializer.scala b/src/main/scala/sigmastate/serialization/OneArgumentOperationSerializer.scala
new file mode 100644
index 0000000000..6cf9393926
--- /dev/null
+++ b/src/main/scala/sigmastate/serialization/OneArgumentOperationSerializer.scala
@@ -0,0 +1,13 @@
+package sigmastate.serialization
+
+import sigmastate.Values.{SValue, Value}
+import sigmastate.lang.Terms._
+import sigmastate.serialization.OpCodes.OpCode
+import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
+import sigmastate.{OneArgumentOperation, SNumericType, SType}
+
+case class OneArgumentOperationSerializer[T <: SType](opCode: OpCode, cons: Value[T] => SValue)
+ extends ValueSerializer[OneArgumentOperation[T, SType]] {
+ override def serialize(obj: OneArgumentOperation[T, SType], w: SigmaByteWriter): Unit = w.putValue(obj.input)
+ override def parse(r: SigmaByteReader): SValue = cons(r.getValue().asValue[T])
+}
diff --git a/src/main/scala/sigmastate/serialization/OpCodes.scala b/src/main/scala/sigmastate/serialization/OpCodes.scala
index 4d38830867..b36018f5d1 100644
--- a/src/main/scala/sigmastate/serialization/OpCodes.scala
+++ b/src/main/scala/sigmastate/serialization/OpCodes.scala
@@ -108,10 +108,14 @@ object OpCodes extends ValueCodes {
val AppendCode : OpCode = (LastConstantCode + 67).toByte
val SliceCode : OpCode = (LastConstantCode + 68).toByte
val FilterCode : OpCode = (LastConstantCode + 69).toByte
- val TreeLookupCode : OpCode = (LastConstantCode + 70).toByte
- val StringConcatCode : OpCode = (LastConstantCode + 71).toByte
- val TreeModificationsCode: OpCode = (LastConstantCode + 72).toByte
- // reserved 73 - 80 (8)
+ val AvlTreeCode : OpCode = (LastConstantCode + 70).toByte
+ val AvlTreeGetCode : OpCode = (LastConstantCode + 71).toByte
+// val TreeUpdatesCode : OpCode = (LastConstantCode + 71).toByte
+// val TreeInsertsCode : OpCode = (LastConstantCode + 72).toByte
+// val TreeRemovalsCode : OpCode = (LastConstantCode + 73).toByte
+// val TreeGetManyCode : OpCode = (LastConstantCode + 74).toByte
+// val TreeContainsCode : OpCode = (LastConstantCode + 75).toByte
+ // reserved 72 - 80 (9)
// Type casts codes
val ExtractAmountCode : OpCode = (LastConstantCode + 81).toByte
@@ -127,10 +131,12 @@ object OpCodes extends ValueCodes {
val CalcSha256Code : OpCode = (LastConstantCode + 92).toByte
val ProveDlogCode : OpCode = (LastConstantCode + 93).toByte
val ProveDiffieHellmanTupleCode: OpCode = (LastConstantCode + 94).toByte
- val SigmaPropIsProvenCode : OpCode = (LastConstantCode + 95).toByte
+ val SigmaPropIsProvenCode : OpCode = (LastConstantCode + 95).toByte
val SigmaPropBytesCode : OpCode = (LastConstantCode + 96).toByte
- val BoolToSigmaPropCode : OpCode = (LastConstantCode + 97 ).toByte
- val TrivialProofCode : OpCode = (LastConstantCode + 98).toByte // reserved 99 (1)
+ val BoolToSigmaPropCode : OpCode = (LastConstantCode + 97).toByte
+ // we don't rely on this yet but it's nice to have TrivialPropFalseCode.toUByte < TrivialPropTrueCode.toUByte
+ val TrivialPropFalseCode : OpCode = (LastConstantCode + 98).toByte
+ val TrivialPropTrueCode : OpCode = (LastConstantCode + 99).toByte
// Deserialization codes
val DeserializeContextCode : OpCode = (LastConstantCode + 100).toByte
@@ -184,5 +190,6 @@ object OpCodes extends ValueCodes {
val CollRotateLeftCode : OpCode = (LastConstantCode + 140).toByte
val CollRotateRightCode : OpCode = (LastConstantCode + 141).toByte
- // reserved 142 - 143 (2)
+ val ContextCode : OpCode = (LastConstantCode + 142).toByte
+ val XorOfCode : OpCode = (LastConstantCode + 143).toByte
}
diff --git a/src/main/scala/sigmastate/serialization/OperationSerializer.scala b/src/main/scala/sigmastate/serialization/OperationSerializer.scala
index 12ee43af74..85b0eeb695 100644
--- a/src/main/scala/sigmastate/serialization/OperationSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/OperationSerializer.scala
@@ -6,27 +6,27 @@ import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import scala.annotation.tailrec
-class OperationSerializer(keyLength: Int, valueLengthOpt: Option[Int]) extends Serializer[Operation, Operation] {
+class OperationSerializer(keyLength: Int, valueLengthOpt: Option[Int]) extends SigmaSerializer[Operation, Operation] {
def parseSeq(r: SigmaByteReader): Seq[Operation] = {
@tailrec
- def parse(r: SigmaByteReader, acc: Seq[Operation]): Seq[Operation] = if (r.remaining > 0) {
- val op = parseBody(r)
- parse(r, op +: acc)
+ def parseOps(r: SigmaByteReader, acc: Seq[Operation]): Seq[Operation] = if (r.remaining > 0) {
+ val op = parse(r)
+ parseOps(r, op +: acc)
} else {
acc.reverse
}
- parse(r, Seq())
+ parseOps(r, Seq())
}
def serializeSeq(ops: Seq[Operation]): Array[Byte] = {
- val w = Serializer.startWriter()
- ops.foreach(o => serializeBody(o, w))
+ val w = SigmaSerializer.startWriter()
+ ops.foreach(o => serialize(o, w))
w.toBytes
}
- override def parseBody(r: SigmaByteReader): Operation = {
+ override def parse(r: SigmaByteReader): Operation = {
def parseValue(): ADValue = {
val vl: Int = valueLengthOpt.getOrElse(r.getShort())
ADValue @@ r.getBytes(vl)
@@ -43,7 +43,7 @@ class OperationSerializer(keyLength: Int, valueLengthOpt: Option[Int]) extends S
}
}
- override def serializeBody(o: Operation, w: SigmaByteWriter): Unit = {
+ override def serialize(o: Operation, w: SigmaByteWriter): Unit = {
def serializeKey(tp: Byte, key: Array[Byte]): Unit = {
w.put(tp)
w.putBytes(key)
diff --git a/src/main/scala/sigmastate/serialization/OptionGetOrElseSerializer.scala b/src/main/scala/sigmastate/serialization/OptionGetOrElseSerializer.scala
index e3e9161cdf..d2f6945a51 100644
--- a/src/main/scala/sigmastate/serialization/OptionGetOrElseSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/OptionGetOrElseSerializer.scala
@@ -4,7 +4,7 @@ import sigmastate.Values._
import sigmastate._
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.OptionGetOrElse
@@ -13,12 +13,12 @@ case class OptionGetOrElseSerializer(cons: (Value[SOption[SType]], Value[SType])
override val opCode: OpCode = OptionGetOrElseCode
- override def serializeBody(obj: OptionGetOrElse[_ <: SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: OptionGetOrElse[_ <: SType], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.putValue(obj.default)
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val input = r.getValue().asValue[SOption[SType]]
val default = r.getValue()
cons(input, default)
diff --git a/src/main/scala/sigmastate/serialization/ProveDlogSerializer.scala b/src/main/scala/sigmastate/serialization/ProveDlogSerializer.scala
index d21204d9c5..8b49e3e7ad 100644
--- a/src/main/scala/sigmastate/serialization/ProveDlogSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ProveDlogSerializer.scala
@@ -1,21 +1,37 @@
package sigmastate.serialization
import sigmastate.basics.DLogProtocol.ProveDlog
-import sigmastate.SGroupElement
-import sigmastate.Values.{SigmaBoolean, Value}
+import sigmastate.{SGroupElement, CreateProveDlog}
+import sigmastate.Values.{Value, SigmaPropValue}
+import sigmastate.interpreter.CryptoConstants.EcPointType
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-import sigmastate.utils.Extensions._
-case class ProveDlogSerializer(cons: Value[SGroupElement.type] => SigmaBoolean)
- extends ValueSerializer[ProveDlog] {
+case class ProveDlogSerializer(cons: EcPointType => ProveDlog)
+ extends SigmaSerializer[ProveDlog, ProveDlog] {
+ override def serialize(obj: ProveDlog, w: SigmaByteWriter): Unit =
+ DataSerializer.serialize[SGroupElement.type](obj.value, SGroupElement, w)
+
+ override def parse(r: SigmaByteReader) = {
+ val res = DataSerializer.deserialize(SGroupElement, r)
+ cons(res)
+ }
+}
+
+case class CreateProveDlogSerializer(cons: Value[SGroupElement.type] => SigmaPropValue)
+ extends ValueSerializer[CreateProveDlog] {
override val opCode: OpCode = OpCodes.ProveDlogCode
- override def serializeBody(obj: ProveDlog, w: SigmaByteWriter): Unit =
+ override def serialize(obj: CreateProveDlog, w: SigmaByteWriter): Unit = {
w.putValue(obj.value)
+ }
- override def parseBody(r: SigmaByteReader): SigmaBoolean =
- cons(r.getValue().asValue[SGroupElement.type])
+ override def parse(r: SigmaByteReader) = {
+ val v = r.getValue().asValue[SGroupElement.type]
+ cons(v)
+ }
}
+
+
diff --git a/src/main/scala/sigmastate/serialization/SelectFieldSerializer.scala b/src/main/scala/sigmastate/serialization/SelectFieldSerializer.scala
index 712028803f..6ea32e10d9 100644
--- a/src/main/scala/sigmastate/serialization/SelectFieldSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/SelectFieldSerializer.scala
@@ -3,7 +3,7 @@ package sigmastate.serialization
import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.SelectField
import sigmastate.{STuple, SType}
@@ -12,11 +12,11 @@ case class SelectFieldSerializer(cons: (Value[STuple], Byte) => Value[SType]) ex
override val opCode: Byte = SelectFieldCode
- override def serializeBody(obj: SelectField, w: SigmaByteWriter): Unit =
+ override def serialize(obj: SelectField, w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.put(obj.fieldIndex)
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val tuple = r.getValue().asValue[STuple]
val fieldIndex = r.getByte()
cons(tuple, fieldIndex)
diff --git a/src/main/scala/sigmastate/serialization/Serializer.scala b/src/main/scala/sigmastate/serialization/Serializer.scala
deleted file mode 100644
index 50317f97cf..0000000000
--- a/src/main/scala/sigmastate/serialization/Serializer.scala
+++ /dev/null
@@ -1 +0,0 @@
-package sigmastate.serialization
diff --git a/src/main/scala/sigmastate/serialization/SigmaPropBytesSerializer.scala b/src/main/scala/sigmastate/serialization/SigmaPropBytesSerializer.scala
index 90aa2426f7..37acddf546 100644
--- a/src/main/scala/sigmastate/serialization/SigmaPropBytesSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/SigmaPropBytesSerializer.scala
@@ -2,7 +2,7 @@ package sigmastate.serialization
import sigmastate.{Values, SType}
import sigmastate.lang.Terms._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.serialization.OpCodes._
import sigmastate.utils.{SigmaByteWriter, SigmaByteReader}
import sigmastate.utxo.SigmaPropBytes
@@ -10,11 +10,11 @@ import sigmastate.utxo.SigmaPropBytes
object SigmaPropBytesSerializer extends ValueSerializer[SigmaPropBytes] {
override val opCode: Byte = SigmaPropBytesCode
- def serializeBody(obj: SigmaPropBytes, w: SigmaByteWriter): Unit = {
+ def serialize(obj: SigmaPropBytes, w: SigmaByteWriter): Unit = {
w.putValue(obj.input)
}
- def parseBody(r: SigmaByteReader): Values.Value[SType] = {
+ def parse(r: SigmaByteReader): Values.Value[SType] = {
val p = r.getValue().asSigmaProp
SigmaPropBytes(p)
}
diff --git a/src/main/scala/sigmastate/serialization/SigmaPropIsProvenSerializer.scala b/src/main/scala/sigmastate/serialization/SigmaPropIsProvenSerializer.scala
index 9a8c523913..5be17248da 100644
--- a/src/main/scala/sigmastate/serialization/SigmaPropIsProvenSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/SigmaPropIsProvenSerializer.scala
@@ -5,16 +5,17 @@ import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes._
import sigmastate.utils.{SigmaByteWriter, SigmaByteReader}
import sigmastate.utxo.SigmaPropIsProven
+import scorex.util.Extensions._
object SigmaPropIsProvenSerializer extends ValueSerializer[SigmaPropIsProven] {
override val opCode: Byte = SigmaPropIsProvenCode
- def serializeBody(obj: SigmaPropIsProven, w: SigmaByteWriter): Unit = {
+ def serialize(obj: SigmaPropIsProven, w: SigmaByteWriter): Unit = {
w.putValue(obj.input)
}
- def parseBody(r: SigmaByteReader): Values.Value[SType] = {
+ def parse(r: SigmaByteReader): Values.Value[SType] = {
val p = r.getValue().asSigmaProp
SigmaPropIsProven(p)
}
diff --git a/src/main/scala/sigmastate/serialization/SigmaSerializer.scala b/src/main/scala/sigmastate/serialization/SigmaSerializer.scala
index 5358f01617..68d579b67e 100644
--- a/src/main/scala/sigmastate/serialization/SigmaSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/SigmaSerializer.scala
@@ -2,28 +2,17 @@ package sigmastate.serialization
import java.nio.ByteBuffer
+import scorex.util.ByteArrayBuilder
import sigmastate.lang.exceptions.SerializerException
import sigmastate.utils._
+import scorex.util.serialization._
-trait Serializer[TFamily, T <: TFamily] {
-
- def parseBody(r: SigmaByteReader): TFamily
- def serializeBody(obj: T, w: SigmaByteWriter): Unit
- def error(msg: String) = throw new SerializerException(msg, None)
-
- final def toBytes(obj: T): Array[Byte] = {
- val w = Serializer.startWriter()
- serializeBody(obj, w)
- w.toBytes
- }
-}
-
-object Serializer {
+object SigmaSerializer {
type Position = Int
type Consumed = Int
val MaxInputSize: Int = 1024 * 1024 * 1
- val MaxTreeDepth: Int = 100
+ val MaxTreeDepth: Int = 110
/** Helper function to be use in serializers.
* Starting position is marked and then used to compute number of consumed bytes.
@@ -33,7 +22,7 @@ object Serializer {
def startReader(bytes: Array[Byte], pos: Int = 0): SigmaByteReader = {
val buf = ByteBuffer.wrap(bytes)
buf.position(pos)
- val r = new SigmaByteReader(buf, new ConstantStore(), resolvePlaceholdersToConstants = false)
+ val r = new SigmaByteReader(new VLQByteBufferReader(buf), new ConstantStore(), resolvePlaceholdersToConstants = false)
.mark()
r
}
@@ -42,7 +31,7 @@ object Serializer {
constantStore: ConstantStore,
resolvePlaceholdersToConstants: Boolean): SigmaByteReader = {
val buf = ByteBuffer.wrap(bytes)
- val r = new SigmaByteReader(buf, constantStore, resolvePlaceholdersToConstants)
+ val r = new SigmaByteReader(new VLQByteBufferReader(buf), constantStore, resolvePlaceholdersToConstants)
.mark()
r
}
@@ -54,19 +43,36 @@ object Serializer {
* res */
def startWriter(): SigmaByteWriter = {
val b = new ByteArrayBuilder()
- val w = new SigmaByteWriter(b, constantExtractionStore = None)
+ val wi = new VLQByteBufferWriter(b)
+ val w = new SigmaByteWriter(wi, constantExtractionStore = None)
w
}
def startWriter(constantExtractionStore: ConstantStore): SigmaByteWriter = {
val b = new ByteArrayBuilder()
- val w = new SigmaByteWriter(b, constantExtractionStore = Some(constantExtractionStore))
+ val wi = new VLQByteBufferWriter(b)
+ val w = new SigmaByteWriter(wi, constantExtractionStore = Some(constantExtractionStore))
w
}
}
-trait SigmaSerializer[TFamily, T <: TFamily] extends Serializer[TFamily, T] {
- val companion: SigmaSerializerCompanion[TFamily]
+trait SigmaSerializer[TFamily, T <: TFamily] extends Serializer[TFamily, T, SigmaByteReader, SigmaByteWriter] {
+
+ def serializeWithGenericWriter(obj: T, w: Writer): Unit = {
+ serialize(obj, new SigmaByteWriter(w, None))
+ }
+
+ def parseWithGenericReader(r: Reader): TFamily = {
+ parse(new SigmaByteReader(r, new ConstantStore(), resolvePlaceholdersToConstants = false))
+ }
+
+ def error(msg: String) = throw new SerializerException(msg, None)
+
+ final def toBytes(obj: T): Array[Byte] = {
+ val w = SigmaSerializer.startWriter()
+ serialize(obj, w)
+ w.toBytes
+ }
}
trait SigmaSerializerCompanion[TFamily] {
diff --git a/src/main/scala/sigmastate/serialization/SubstConstantsSerializer.scala b/src/main/scala/sigmastate/serialization/SubstConstantsSerializer.scala
index fd8f8dfb96..81074174bd 100644
--- a/src/main/scala/sigmastate/serialization/SubstConstantsSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/SubstConstantsSerializer.scala
@@ -10,13 +10,13 @@ object SubstConstantsSerializer extends ValueSerializer[SubstConstants[SType]] {
override val opCode: Byte = OpCodes.SubstConstantsCode
- def serializeBody(obj: SubstConstants[SType], w: SigmaByteWriter): Unit = {
+ def serialize(obj: SubstConstants[SType], w: SigmaByteWriter): Unit = {
w.putValue(obj.scriptBytes)
w.putValue(obj.positions)
w.putValue(obj.newValues)
}
- def parseBody(r: SigmaByteReader): Value[SType] = {
+ def parse(r: SigmaByteReader): Value[SType] = {
val scriptBytes = r.getValue().asValue[SByteArray]
val positions = r.getValue().asValue[SIntArray]
val newVals = r.getValue().asValue[SCollection[SType]]
diff --git a/src/main/scala/sigmastate/serialization/TaggedVariableSerializer.scala b/src/main/scala/sigmastate/serialization/TaggedVariableSerializer.scala
index 9e2fc51cd2..6f2d6ba533 100644
--- a/src/main/scala/sigmastate/serialization/TaggedVariableSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/TaggedVariableSerializer.scala
@@ -3,7 +3,7 @@ package sigmastate.serialization
import sigmastate.Values._
import sigmastate._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
case class TaggedVariableSerializer(cons: (Byte, SType) => Value[SType])
@@ -11,11 +11,11 @@ case class TaggedVariableSerializer(cons: (Byte, SType) => Value[SType])
override val opCode: OpCode = TaggedVariableCode
- override def serializeBody(obj: TaggedVariable[_ <: SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: TaggedVariable[_ <: SType], w: SigmaByteWriter): Unit =
w.put(obj.varId)
.putType(obj.tpe)
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val varId = r.getByte()
val tpe = r.getType()
cons(varId, tpe)
diff --git a/src/main/scala/sigmastate/serialization/TupleSerializer.scala b/src/main/scala/sigmastate/serialization/TupleSerializer.scala
index cba2f5ecf1..4f2e7517cf 100644
--- a/src/main/scala/sigmastate/serialization/TupleSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/TupleSerializer.scala
@@ -3,7 +3,7 @@ package sigmastate.serialization
import sigmastate.SType
import sigmastate.Values._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
case class TupleSerializer(cons: Seq[Value[SType]] => Value[SType])
@@ -11,13 +11,13 @@ case class TupleSerializer(cons: Seq[Value[SType]] => Value[SType])
override val opCode: Byte = TupleCode
- override def serializeBody(obj: Tuple, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: Tuple, w: SigmaByteWriter): Unit = {
val length = obj.length
w.putUByte(length)
- obj.items.foreach(w.putValue)
+ obj.items.foreach(w.putValue(_))
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val size = r.getByte()
val values = (1 to size).map(_ => r.getValue())
cons(values)
diff --git a/src/main/scala/sigmastate/serialization/TwoArgumentsSerializer.scala b/src/main/scala/sigmastate/serialization/TwoArgumentsSerializer.scala
index 2a7803adee..a2a36283b1 100644
--- a/src/main/scala/sigmastate/serialization/TwoArgumentsSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/TwoArgumentsSerializer.scala
@@ -4,7 +4,7 @@ import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.utils.{SigmaByteWriter, SigmaByteReader}
import sigmastate.{TwoArgumentsOperation, SType, SBigInt}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import OpCodes._
import sigmastate.utxo.CostTable._
@@ -12,13 +12,13 @@ case class TwoArgumentsSerializer[LIV <: SType, RIV <: SType, OV <: Value[SType]
(override val opCode: Byte, constructor: (Value[LIV], Value[RIV]) => Value[SType])
extends ValueSerializer[OV] {
- override def serializeBody(obj: OV, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: OV, w: SigmaByteWriter): Unit = {
val typedOp = obj.asInstanceOf[TwoArgumentsOperation[LIV, RIV, LIV]]
w.putValue(typedOp.left)
.putValue(typedOp.right)
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val arg1 = r.getValue().asValue[LIV]
val arg2 = r.getValue().asValue[RIV]
constructor(arg1, arg2)
diff --git a/src/main/scala/sigmastate/serialization/TypeSerializer.scala b/src/main/scala/sigmastate/serialization/TypeSerializer.scala
index f1fb483fb3..2c7521bc91 100644
--- a/src/main/scala/sigmastate/serialization/TypeSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/TypeSerializer.scala
@@ -28,6 +28,9 @@ object TypeSerializer extends ByteBufferSerializer[SType] {
case SUnit => w.put(SUnit.typeCode)
case SBox => w.put(SBox.typeCode)
case SAvlTree => w.put(SAvlTree.typeCode)
+ case SContext => w.put(SContext.typeCode)
+ case SHeader => w.put(SHeader.typeCode)
+ case SPreHeader => w.put(SPreHeader.typeCode)
case c: SCollectionType[a] => c.elemType match {
case p: SEmbeddable =>
val code = p.embedIn(CollectionTypeCode)
@@ -111,8 +114,8 @@ object TypeSerializer extends ByteBufferSerializer[SType] {
override def deserialize(r: SigmaByteReader): SType = deserialize(r, 0)
private def deserialize(r: SigmaByteReader, depth: Int): SType = {
- if (depth > Serializer.MaxTreeDepth)
- throw new TypeDeserializeCallDepthExceeded(s"deserialize call depth exceeds ${Serializer.MaxTreeDepth}")
+ if (depth > SigmaSerializer.MaxTreeDepth)
+ throw new TypeDeserializeCallDepthExceeded(s"deserialize call depth exceeds ${SigmaSerializer.MaxTreeDepth}")
val c = r.getUByte()
if (c <= 0)
throw new InvalidTypePrefix(s"Cannot deserialize type prefix $c. Unexpected buffer $r with bytes ${r.getBytes(r.remaining)}")
@@ -178,6 +181,9 @@ object TypeSerializer extends ByteBufferSerializer[SType] {
case SUnit.typeCode => SUnit
case SBox.typeCode => SBox
case SAvlTree.typeCode => SAvlTree
+ case SContext.typeCode => SContext
+ case SHeader.typeCode => SHeader
+ case SPreHeader.typeCode => SPreHeader
case STypeIdent.TypeCode => {
val nameLength = r.getUByte()
val name = new String(r.getBytes(nameLength), StandardCharsets.UTF_8)
diff --git a/src/main/scala/sigmastate/serialization/ValDefSerializer.scala b/src/main/scala/sigmastate/serialization/ValDefSerializer.scala
index edf43edab1..72cb0b1a8f 100644
--- a/src/main/scala/sigmastate/serialization/ValDefSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ValDefSerializer.scala
@@ -3,25 +3,25 @@ package sigmastate.serialization
import sigmastate.Values._
import sigmastate._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import scala.collection.mutable
case class ValDefSerializer(override val opCode: OpCode) extends ValueSerializer[ValDef] {
- override def serializeBody(obj: ValDef, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: ValDef, w: SigmaByteWriter): Unit = {
w.putUInt(obj.id)
if (opCode == FunDefCode) {
require(!obj.isValDef, s"expected FunDef, got $obj")
require(obj.tpeArgs.nonEmpty, s"expected FunDef with type args, got $obj")
w.put(obj.tpeArgs.length.toByteExact)
- obj.tpeArgs.foreach(w.putType)
+ obj.tpeArgs.foreach(w.putType(_))
}
w.putValue(obj.rhs)
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val id = r.getUInt().toInt
val tpeArgs: Seq[STypeIdent] = opCode match {
case FunDefCode =>
diff --git a/src/main/scala/sigmastate/serialization/ValUseSerializer.scala b/src/main/scala/sigmastate/serialization/ValUseSerializer.scala
index 0486702a09..7d0ac0f8a9 100644
--- a/src/main/scala/sigmastate/serialization/ValUseSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ValUseSerializer.scala
@@ -9,11 +9,11 @@ case class ValUseSerializer(cons: (Int, SType) => Value[SType]) extends ValueSer
override val opCode: OpCode = ValUseCode
- override def serializeBody(obj: ValUse[SType], w: SigmaByteWriter): Unit = {
+ override def serialize(obj: ValUse[SType], w: SigmaByteWriter): Unit = {
w.putUInt(obj.valId)
}
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val id = r.getUInt().toInt
val tpe = r.valDefTypeStore(id)
cons(id, tpe)
diff --git a/src/main/scala/sigmastate/serialization/ValueSerializer.scala b/src/main/scala/sigmastate/serialization/ValueSerializer.scala
index 2d64240a72..2545eb350f 100644
--- a/src/main/scala/sigmastate/serialization/ValueSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/ValueSerializer.scala
@@ -9,14 +9,14 @@ import sigmastate.lang.Terms.OperationId
import sigmastate.lang.exceptions.{InputSizeLimitExceeded, InvalidOpCode, ValueDeserializeCallDepthExceeded}
import sigmastate.serialization.OpCodes._
import sigmastate.serialization.transformers._
-import sigmastate.serialization.trees.{QuadrupleSerializer, Relation2Serializer, Relation3Serializer}
-import sigmastate.utils.Extensions._
+import sigmastate.serialization.trees.{QuadrupleSerializer, Relation2Serializer}
+import sigma.util.Extensions._
import sigmastate.utils._
import sigmastate.utxo.CostTable._
trait ValueSerializer[V <: Value[SType]] extends SigmaSerializer[Value[SType], V] {
- override val companion = ValueSerializer
+ val companion = ValueSerializer
/** Code of the corresponding tree node (Value.opCode) which is used to lookup this serizalizer
* during deserialization. It is emitted immediately before the body of this node in serialized byte array. */
@@ -46,10 +46,14 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
Relation2Serializer(LeCode, mkLE[SType]),
Relation2Serializer(EqCode, mkEQ[SType]),
Relation2Serializer(NeqCode, mkNEQ[SType]),
- QuadrupleSerializer(TreeLookupCode, mkTreeLookup),
- QuadrupleSerializer(TreeModificationsCode, mkTreeModifications),
+ CreateAvlTreeSerializer(mkCreateAvlTree),
+ QuadrupleSerializer(AvlTreeGetCode, mkTreeLookup),
+// QuadrupleSerializer(TreeUpdatesCode, mkTreeUpdates),
+// QuadrupleSerializer(TreeInsertsCode, mkTreeInserts),
+// QuadrupleSerializer(TreeRemovalsCode, mkTreeRemovals),
Relation2Serializer(BinOrCode, mkBinOr),
Relation2Serializer(BinAndCode, mkBinAnd),
+ Relation2Serializer(BinXorCode, mkBinXor),
QuadrupleSerializer[SBoolean.type, SLong.type, SLong.type, SLong.type](IfCode, mkIf),
TwoArgumentsSerializer(XorCode, mkXor),
TwoArgumentsSerializer(ExponentiateCode, mkExponentiate),
@@ -61,14 +65,18 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
TwoArgumentsSerializer(PlusCode, mkPlus[SNumericType]),
TwoArgumentsSerializer(MinCode, mkMin[SNumericType]),
TwoArgumentsSerializer(MaxCode, mkMax[SNumericType]),
- TwoArgumentsSerializer(StringConcatCode, mkStringConcat),
- ProveDiffieHellmanTupleSerializer(mkProveDiffieHellmanTuple),
- ProveDlogSerializer(mkProveDlog),
+ TwoArgumentsSerializer(BitOrCode, mkBitOr[SNumericType]),
+ TwoArgumentsSerializer(BitAndCode, mkBitAnd[SNumericType]),
+ TwoArgumentsSerializer(BitXorCode, mkBitXor[SNumericType]),
+ TwoArgumentsSerializer(BitShiftLeftCode, mkBitShiftLeft[SNumericType]),
+ TwoArgumentsSerializer(BitShiftRightCode, mkBitShiftRight[SNumericType]),
+ TwoArgumentsSerializer(BitShiftRightZeroedCode, mkBitShiftRightZeroed[SNumericType]),
CaseObjectSerialization(TrueCode, TrueLeaf),
CaseObjectSerialization(FalseCode, FalseLeaf),
SigmaPropIsProvenSerializer,
SigmaPropBytesSerializer,
ConcreteCollectionBooleanConstantSerializer(mkConcreteCollection),
+ CaseObjectSerialization(ContextCode, Context),
CaseObjectSerialization(HeightCode, Height),
CaseObjectSerialization(MinerPubkeyCode, MinerPubkey),
CaseObjectSerialization(InputsCode, Inputs),
@@ -79,6 +87,7 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
ConcreteCollectionSerializer(mkConcreteCollection),
LogicalTransformerSerializer(AndCode, mkAND),
LogicalTransformerSerializer(OrCode, mkOR),
+ LogicalTransformerSerializer(XorOfCode, mkXorOf),
TaggedVariableSerializer(mkTaggedVariable),
GetVarSerializer(mkGetVar),
MapCollectionSerializer(mkMapCollection),
@@ -93,6 +102,7 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
SimpleTransformerSerializer[SBox.type, SByteArray](ExtractIdCode, mkExtractId),
SimpleTransformerSerializer[SBox.type, STuple](ExtractCreationInfoCode, mkExtractCreationInfo),
SimpleTransformerSerializer[SLong.type, SByteArray](LongToByteArrayCode, mkLongToByteArray),
+ SimpleTransformerSerializer[SByteArray, SLong.type](ByteArrayToLongCode, mkByteArrayToLong),
SimpleTransformerSerializer[SByteArray, SBigInt.type](ByteArrayToBigIntCode, mkByteArrayToBigInt),
SimpleTransformerSerializer[SByteArray, SByteArray](CalcBlake2b256Code, mkCalcBlake2b256),
SimpleTransformerSerializer[SByteArray, SByteArray](CalcSha256Code, mkCalcSha256),
@@ -125,6 +135,11 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
ModQArithOpSerializer(PlusModQCode, mkPlusModQ),
ModQArithOpSerializer(MinusModQCode, mkMinusModQ),
SubstConstantsSerializer,
+ CreateProveDlogSerializer(mkCreateProveDlog),
+ CreateProveDHTupleSerializer(mkCreateProveDHTuple),
+ LogicalNotSerializer(mkLogicalNot),
+ OneArgumentOperationSerializer(NegationCode, mkNegation[SNumericType]),
+ OneArgumentOperationSerializer(BitInversionCode, mkBitInversion[SNumericType]),
))
private def serializable(v: Value[SType]): Value[SType] = v match {
@@ -136,7 +151,7 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
override def getSerializer(opCode: Tag): ValueSerializer[_ <: Value[SType]] = {
val serializer = serializers.get(opCode)
if (serializer == null)
- throw new InvalidOpCode(s"Cannot find serializer for Value with opCode=$opCode")
+ throw new InvalidOpCode(s"Cannot find serializer for Value with opCode = LastConstantCode + ${opCode.toUByte - LastConstantCode}")
serializer
}
@@ -146,7 +161,7 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
case Some(constantStore) =>
val ph = constantStore.put(c)(DeserializationSigmaBuilder)
w.put(ph.opCode)
- constantPlaceholderSerializer.serializeBody(ph, w)
+ constantPlaceholderSerializer.serialize(ph, w)
case None =>
constantSerializer.serialize(c, w)
}
@@ -154,16 +169,16 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
val opCode = v.opCode
w.put(opCode)
// help compiler recognize the type
- getSerializer(opCode).asInstanceOf[ValueSerializer[v.type]].serializeBody(v, w)
+ getSerializer(opCode).asInstanceOf[ValueSerializer[v.type]].serialize(v, w)
}
override def deserialize(r: SigmaByteReader): Value[SType] = {
val bytesRemaining = r.remaining
- if (bytesRemaining > Serializer.MaxInputSize)
- throw new InputSizeLimitExceeded(s"input size $bytesRemaining exceeds ${ Serializer.MaxInputSize}")
+ if (bytesRemaining > SigmaSerializer.MaxInputSize)
+ throw new InputSizeLimitExceeded(s"input size $bytesRemaining exceeds ${ SigmaSerializer.MaxInputSize}")
val depth = r.level
- if (depth > Serializer.MaxTreeDepth)
- throw new ValueDeserializeCallDepthExceeded(s"nested value deserialization call depth($depth) exceeds allowed maximum ${Serializer.MaxTreeDepth}")
+ if (depth > SigmaSerializer.MaxTreeDepth)
+ throw new ValueDeserializeCallDepthExceeded(s"nested value deserialization call depth($depth) exceeds allowed maximum ${SigmaSerializer.MaxTreeDepth}")
r.level = depth + 1
val firstByte = r.peekByte().toUByte
val v = if (firstByte <= LastConstantCode) {
@@ -172,19 +187,19 @@ object ValueSerializer extends SigmaSerializerCompanion[Value[SType]] {
}
else {
val opCode = r.getByte()
- getSerializer(opCode).parseBody(r)
+ getSerializer(opCode).parse(r)
}
r.level = depth - 1
v
}
def serialize(v: Value[SType]): Array[Byte] = {
- val w = Serializer.startWriter()
+ val w = SigmaSerializer.startWriter()
serialize(v, w)
w.toBytes
}
- def deserialize(bytes: Array[Byte], pos: Serializer.Position = 0): Value[SType] =
- deserialize(Serializer.startReader(bytes, pos))
+ def deserialize(bytes: Array[Byte], pos: SigmaSerializer.Position = 0): Value[SType] =
+ deserialize(SigmaSerializer.startReader(bytes, pos))
}
diff --git a/src/main/scala/sigmastate/serialization/transformers/AppendSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/AppendSerializer.scala
index ae45382e7f..82504539ac 100644
--- a/src/main/scala/sigmastate/serialization/transformers/AppendSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/AppendSerializer.scala
@@ -4,7 +4,7 @@ import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.Append
import sigmastate.{SCollection, SType}
@@ -14,11 +14,11 @@ case class AppendSerializer(cons: (Value[SCollection[SType]], Value[SCollection[
override val opCode: OpCode = OpCodes.AppendCode
- override def serializeBody(obj: Append[SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: Append[SType], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.putValue(obj.col2)
- override def parseBody(r: SigmaByteReader): Value[SCollection[SType]] = {
+ override def parse(r: SigmaByteReader): Value[SCollection[SType]] = {
val input = r.getValue().asCollection[SType]
val col2 = r.getValue().asCollection[SType]
cons(input, col2)
diff --git a/src/main/scala/sigmastate/serialization/transformers/AtLeastSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/AtLeastSerializer.scala
index 5aeed72aca..dc72586218 100644
--- a/src/main/scala/sigmastate/serialization/transformers/AtLeastSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/AtLeastSerializer.scala
@@ -4,19 +4,24 @@ import sigmastate.Values.{SigmaPropValue, Value}
import sigmastate._
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
+import sigmastate.serialization.{ValueSerializer, OpCodes}
+import scorex.util.Extensions._
+import sigmastate.utils.{SigmaByteWriter, SigmaByteReader}
+import sigmastate._
import sigmastate.serialization.{OpCodes, ValueSerializer}
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
+import scorex.util.Extensions._
case class AtLeastSerializer(cons: (Value[SInt.type], Value[SCollection[SSigmaProp.type]]) => SigmaPropValue)
extends ValueSerializer[AtLeast] {
override val opCode: OpCode = OpCodes.AtLeastCode
- override def serializeBody(obj: AtLeast, w: SigmaByteWriter): Unit =
+ override def serialize(obj: AtLeast, w: SigmaByteWriter): Unit =
w.putValue(obj.bound)
.putValue(obj.input)
- override def parseBody(r: SigmaByteReader): SigmaPropValue = {
+ override def parse(r: SigmaByteReader): SigmaPropValue = {
val bound = r.getValue().asIntValue
val input = r.getValue().asCollection[SSigmaProp.type]
cons(bound, input)
diff --git a/src/main/scala/sigmastate/serialization/transformers/BooleanTransformerSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/BooleanTransformerSerializer.scala
index be2deb64fb..701887aeea 100644
--- a/src/main/scala/sigmastate/serialization/transformers/BooleanTransformerSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/BooleanTransformerSerializer.scala
@@ -7,6 +7,7 @@ import sigmastate.serialization.ValueSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.BooleanTransformer
import sigmastate.{SBoolean, SCollection, SFunc, SType}
+import scorex.util.Extensions._
case class BooleanTransformerSerializer[T <: SType]
(code: OpCode,
@@ -14,11 +15,11 @@ case class BooleanTransformerSerializer[T <: SType]
override val opCode: OpCode = code
- override def serializeBody(obj: BooleanTransformer[T], w: SigmaByteWriter): Unit =
+ override def serialize(obj: BooleanTransformer[T], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.putValue(obj.condition)
- override def parseBody(r: SigmaByteReader): Value[SBoolean.type] = {
+ override def parse(r: SigmaByteReader): Value[SBoolean.type] = {
val input = r.getValue().asCollection[T]
val condition = r.getValue().asFunc
f(input, condition)
diff --git a/src/main/scala/sigmastate/serialization/transformers/ByIndexSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/ByIndexSerializer.scala
index 1322e7d5ec..506d6a26c5 100644
--- a/src/main/scala/sigmastate/serialization/transformers/ByIndexSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/ByIndexSerializer.scala
@@ -4,7 +4,7 @@ import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.ByIndex
import sigmastate.{SCollection, SInt, SType}
@@ -14,12 +14,12 @@ case class ByIndexSerializer(cons: (Value[SCollection[SType]], Value[SInt.type],
override val opCode: OpCode = OpCodes.ByIndexCode
- override def serializeBody(obj: ByIndex[SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: ByIndex[SType], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.putValue(obj.index)
.putOption(obj.default)(_.putValue(_))
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val input = r.getValue().asCollection[SType]
val index = r.getValue().upcastTo(SInt)
val default = r.getOption(r.getValue())
diff --git a/src/main/scala/sigmastate/serialization/transformers/DeserializeContextSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/DeserializeContextSerializer.scala
index d4e5cda942..a66600a613 100644
--- a/src/main/scala/sigmastate/serialization/transformers/DeserializeContextSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/DeserializeContextSerializer.scala
@@ -4,7 +4,7 @@ import sigmastate.SType
import sigmastate.Values.Value
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.DeserializeContext
@@ -13,11 +13,11 @@ case class DeserializeContextSerializer(cons: (Byte, SType) => Value[SType])
override val opCode: OpCode = OpCodes.DeserializeContextCode
- override def serializeBody(obj: DeserializeContext[SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: DeserializeContext[SType], w: SigmaByteWriter): Unit =
w.putType(obj.tpe)
.put(obj.id)
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val tpe = r.getType()
val id = r.getByte()
cons(id, tpe)
diff --git a/src/main/scala/sigmastate/serialization/transformers/DeserializeRegisterSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/DeserializeRegisterSerializer.scala
index 6ebafdcbee..8adc2d6e49 100644
--- a/src/main/scala/sigmastate/serialization/transformers/DeserializeRegisterSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/DeserializeRegisterSerializer.scala
@@ -6,7 +6,7 @@ import sigmastate.SType
import sigmastate.Values.Value
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.DeserializeRegister
@@ -15,12 +15,12 @@ case class DeserializeRegisterSerializer(cons: (RegisterId, SType, Option[Value[
override val opCode: OpCode = OpCodes.DeserializeRegisterCode
- override def serializeBody(obj: DeserializeRegister[SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: DeserializeRegister[SType], w: SigmaByteWriter): Unit =
w.put(obj.reg.number)
.putType(obj.tpe)
.putOption(obj.default)(_.putValue(_))
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val registerId = ErgoBox.findRegisterByIndex(r.getByte()).get
val tpe = r.getType()
val dv = r.getOption(r.getValue())
diff --git a/src/main/scala/sigmastate/serialization/transformers/ExtractRegisterAsSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/ExtractRegisterAsSerializer.scala
index fea6889407..077b63a75a 100644
--- a/src/main/scala/sigmastate/serialization/transformers/ExtractRegisterAsSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/ExtractRegisterAsSerializer.scala
@@ -5,7 +5,7 @@ import org.ergoplatform.ErgoBox.RegisterId
import sigmastate.Values.Value
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.ExtractRegisterAs
import sigmastate.{SBox, SOption, SType}
@@ -14,12 +14,12 @@ case class ExtractRegisterAsSerializer(cons: (Value[SBox.type], RegisterId, SOpt
extends ValueSerializer[ExtractRegisterAs[SType]] {
override val opCode: OpCode = OpCodes.ExtractRegisterAs
- override def serializeBody(obj: ExtractRegisterAs[SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: ExtractRegisterAs[SType], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.put(obj.registerId.number)
.putType(obj.tpe.elemType)
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val input = r.getValue()
val regId = r.getByte()
val register = ErgoBox.findRegisterByIndex(regId).get
diff --git a/src/main/scala/sigmastate/serialization/transformers/FilterSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/FilterSerializer.scala
index a286c1c0f8..7d3ea6e22d 100644
--- a/src/main/scala/sigmastate/serialization/transformers/FilterSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/FilterSerializer.scala
@@ -4,7 +4,7 @@ import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.Filter
import sigmastate.{SBoolean, SCollection, SType}
@@ -13,12 +13,12 @@ case class FilterSerializer(cons: (Value[SCollection[SType]], Byte, Value[SBoole
override val opCode: OpCode = OpCodes.FilterCode
- override def serializeBody(obj: Filter[SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: Filter[SType], w: SigmaByteWriter): Unit =
w.put(obj.id)
.putValue(obj.input)
.putValue(obj.condition)
- override def parseBody(r: SigmaByteReader): Value[SCollection[SType]] = {
+ override def parse(r: SigmaByteReader): Value[SCollection[SType]] = {
val id = r.getByte()
val input = r.getValue().asCollection[SType]
val condition = r.getValue().asValue[SBoolean.type]
diff --git a/src/main/scala/sigmastate/serialization/transformers/FoldSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/FoldSerializer.scala
index e1e0b82a51..7bf7ff673c 100644
--- a/src/main/scala/sigmastate/serialization/transformers/FoldSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/FoldSerializer.scala
@@ -4,6 +4,7 @@ import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.Fold
import sigmastate.{SCollection, SFunc, SType}
@@ -12,12 +13,12 @@ case class FoldSerializer(cons: (Value[SCollection[SType]], Value[SType], Value[
extends ValueSerializer[Fold[SType, SType]] {
override val opCode: OpCode = OpCodes.FoldCode
- override def serializeBody(obj: Fold[SType, SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: Fold[SType, SType], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.putValue(obj.zero)
.putValue(obj.foldOp)
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val input = r.getValue().asCollection[SType]
val zero = r.getValue()
val foldOp = r.getValue().asFunc
diff --git a/src/main/scala/sigmastate/serialization/transformers/LogicalTransformerSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/LogicalTransformerSerializer.scala
index 8756256a81..39f0456735 100644
--- a/src/main/scala/sigmastate/serialization/transformers/LogicalTransformerSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/LogicalTransformerSerializer.scala
@@ -4,7 +4,7 @@ import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.ValueSerializer
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.Transformer
import sigmastate.{SBoolean, SCollection}
@@ -16,9 +16,9 @@ case class LogicalTransformerSerializer[I <: SCollection[SBoolean.type], O <: SB
override val opCode: OpCode = code
- override def serializeBody(obj: Transformer[I, O], w: SigmaByteWriter): Unit =
+ override def serialize(obj: Transformer[I, O], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
- override def parseBody(r: SigmaByteReader): Value[SBoolean.type] =
+ override def parse(r: SigmaByteReader): Value[SBoolean.type] =
cons(r.getValue().asCollection[SBoolean.type])
}
diff --git a/src/main/scala/sigmastate/serialization/transformers/MapCollectionSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/MapCollectionSerializer.scala
index 17d5ceb70b..af6e098d6b 100644
--- a/src/main/scala/sigmastate/serialization/transformers/MapCollectionSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/MapCollectionSerializer.scala
@@ -4,7 +4,6 @@ import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.MapCollection
import sigmastate.{SCollection, SFunc, SType}
@@ -14,11 +13,11 @@ case class MapCollectionSerializer(cons: (Value[SCollection[SType]], Value[SFunc
override val opCode: OpCode = OpCodes.MapCollectionCode
- override def serializeBody(obj: MapCollection[SType, SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: MapCollection[SType, SType], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.putValue(obj.mapper)
- override def parseBody(r: SigmaByteReader): Value[SType] = {
+ override def parse(r: SigmaByteReader): Value[SType] = {
val input = r.getValue().asValue[SCollection[SType]]
val mapper = r.getValue().asFunc
cons(input, mapper)
diff --git a/src/main/scala/sigmastate/serialization/transformers/NumericCastSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/NumericCastSerializer.scala
index 48a765f59f..4a8a735858 100644
--- a/src/main/scala/sigmastate/serialization/transformers/NumericCastSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/NumericCastSerializer.scala
@@ -5,7 +5,7 @@ import sigmastate._
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.ValueSerializer
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.Transformer
@@ -15,11 +15,11 @@ case class NumericCastSerializer(code: OpCode,
override val opCode: OpCode = code
- override def serializeBody(obj: Transformer[SNumericType, SNumericType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: Transformer[SNumericType, SNumericType], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.putType(obj.tpe)
- override def parseBody(r: SigmaByteReader): Value[SNumericType] = {
+ override def parse(r: SigmaByteReader): Value[SNumericType] = {
val input = r.getValue().asNumValue
val tpe = r.getType().asNumType
cons(input, tpe)
diff --git a/src/main/scala/sigmastate/serialization/transformers/ProveDHTupleSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/ProveDHTupleSerializer.scala
new file mode 100644
index 0000000000..82a4edd621
--- /dev/null
+++ b/src/main/scala/sigmastate/serialization/transformers/ProveDHTupleSerializer.scala
@@ -0,0 +1,54 @@
+package sigmastate.serialization.transformers
+
+import sigmastate.{SGroupElement, CreateProveDHTuple}
+import sigmastate.Values.{Value, SigmaPropValue}
+import sigmastate.basics.ProveDHTuple
+import sigmastate.interpreter.CryptoConstants.EcPointType
+import sigmastate.lang.Terms._
+import sigmastate.serialization.OpCodes.OpCode
+import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
+import sigmastate.serialization.{ValueSerializer, DataSerializer, OpCodes, SigmaSerializer}
+
+case class ProveDHTupleSerializer(
+ cons: (EcPointType, EcPointType, EcPointType, EcPointType) => ProveDHTuple
+ ) extends SigmaSerializer[ProveDHTuple, ProveDHTuple] {
+
+ override def serialize(obj: ProveDHTuple, w: SigmaByteWriter): Unit = {
+ DataSerializer.serialize[SGroupElement.type](obj.gv, SGroupElement, w)
+ DataSerializer.serialize[SGroupElement.type](obj.hv, SGroupElement, w)
+ DataSerializer.serialize[SGroupElement.type](obj.uv, SGroupElement, w)
+ DataSerializer.serialize[SGroupElement.type](obj.vv, SGroupElement, w)
+ }
+
+ override def parse(r: SigmaByteReader) = {
+ val gv = DataSerializer.deserialize(SGroupElement, r)
+ val hv = DataSerializer.deserialize(SGroupElement, r)
+ val uv = DataSerializer.deserialize(SGroupElement, r)
+ val vv = DataSerializer.deserialize(SGroupElement, r)
+ cons(gv, hv, uv, vv)
+ }
+}
+
+case class CreateProveDHTupleSerializer(cons: (Value[SGroupElement.type],
+ Value[SGroupElement.type],
+ Value[SGroupElement.type],
+ Value[SGroupElement.type]) => SigmaPropValue)
+ extends ValueSerializer[CreateProveDHTuple] {
+
+ override val opCode: OpCode = OpCodes.ProveDiffieHellmanTupleCode
+
+ override def serialize(obj: CreateProveDHTuple, w: SigmaByteWriter): Unit = {
+ w.putValue(obj.gv)
+ w.putValue(obj.hv)
+ w.putValue(obj.uv)
+ w.putValue(obj.vv)
+ }
+
+ override def parse(r: SigmaByteReader) = {
+ val gv = r.getValue().asValue[SGroupElement.type]
+ val hv = r.getValue().asValue[SGroupElement.type]
+ val uv = r.getValue().asValue[SGroupElement.type]
+ val vv = r.getValue().asValue[SGroupElement.type]
+ cons(gv, hv, uv, vv)
+ }
+}
diff --git a/src/main/scala/sigmastate/serialization/transformers/ProveDiffieHellmanTupleSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/ProveDiffieHellmanTupleSerializer.scala
deleted file mode 100644
index ac5531e0b3..0000000000
--- a/src/main/scala/sigmastate/serialization/transformers/ProveDiffieHellmanTupleSerializer.scala
+++ /dev/null
@@ -1,63 +0,0 @@
-package sigmastate.serialization.transformers
-
-import sigmastate.SGroupElement
-import sigmastate.Values.{Constant, GroupElementConstant, SigmaBoolean, Value}
-import sigmastate.basics.ProveDHTuple
-import sigmastate.lang.Terms._
-import sigmastate.serialization.OpCodes.OpCode
-import sigmastate.serialization.{DataSerializer, OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
-import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-
-case class ProveDiffieHellmanTupleSerializer(cons:
- (Value[SGroupElement.type],
- Value[SGroupElement.type],
- Value[SGroupElement.type],
- Value[SGroupElement.type]) => SigmaBoolean)
- extends ValueSerializer[ProveDHTuple] {
-
- override val opCode: OpCode = OpCodes.ProveDiffieHellmanTupleCode
-
- private val constCodePrefix: Byte = 0
-
- override def serializeBody(obj: ProveDHTuple, w: SigmaByteWriter): Unit = obj match {
- case ProveDHTuple(
- gv @ Constant(_, SGroupElement),
- hv @ Constant(_, SGroupElement),
- uv @ Constant(_, SGroupElement),
- vv @ Constant(_, SGroupElement)) =>
- w.put(constCodePrefix)
- w.putType(SGroupElement)
- DataSerializer.serialize(gv.value, gv.tpe, w)
- DataSerializer.serialize(hv.value, hv.tpe, w)
- DataSerializer.serialize(uv.value, uv.tpe, w)
- DataSerializer.serialize(vv.value, vv.tpe, w)
- case _ =>
- w.putValue(obj.gv)
- w.putValue(obj.hv)
- w.putValue(obj.uv)
- w.putValue(obj.vv)
- }
-
- override def parseBody(r: SigmaByteReader): SigmaBoolean = {
- if (r.peekByte() == constCodePrefix) {
- val _ = r.getByte() // skip prefix code
- r.getType() match {
- case SGroupElement =>
- val gv = GroupElementConstant(DataSerializer.deserialize(SGroupElement, r))
- val hv = GroupElementConstant(DataSerializer.deserialize(SGroupElement, r))
- val uv = GroupElementConstant(DataSerializer.deserialize(SGroupElement, r))
- val vv = GroupElementConstant(DataSerializer.deserialize(SGroupElement, r))
- cons(gv, hv, uv, vv)
- case _ =>
- error("only SGroupElement tpe are supported")
- }
- } else {
- val gv = r.getValue().asValue[SGroupElement.type]
- val hv = r.getValue().asValue[SGroupElement.type]
- val uv = r.getValue().asValue[SGroupElement.type]
- val vv = r.getValue().asValue[SGroupElement.type]
- cons(gv, hv, uv, vv)
- }
- }
-}
diff --git a/src/main/scala/sigmastate/serialization/transformers/SigmaTransformerSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/SigmaTransformerSerializer.scala
index 9adb284e34..c5e4e6861d 100644
--- a/src/main/scala/sigmastate/serialization/transformers/SigmaTransformerSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/SigmaTransformerSerializer.scala
@@ -14,12 +14,10 @@ case class SigmaTransformerSerializer[I <: SigmaPropValue, O <: SigmaPropValue]
override val opCode: OpCode = code
- override def serializeBody(obj: SigmaTransformer[I, O], w: SigmaByteWriter): Unit = {
- w.putUInt(obj.items.length)
- obj.items.foreach(w.putValue)
- }
+ override def serialize(obj: SigmaTransformer[I, O], w: SigmaByteWriter): Unit =
+ w.putValues(obj.items)
- override def parseBody(r: SigmaByteReader): SigmaPropValue = {
+ override def parse(r: SigmaByteReader): SigmaPropValue = {
val itemsSize = r.getUInt().toInt
val b = mutable.ArrayBuilder.make[SigmaPropValue]()
for (_ <- 0 until itemsSize) {
diff --git a/src/main/scala/sigmastate/serialization/transformers/SimpleTransformerSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/SimpleTransformerSerializer.scala
index c8a4df38eb..2bf23b3cd2 100644
--- a/src/main/scala/sigmastate/serialization/transformers/SimpleTransformerSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/SimpleTransformerSerializer.scala
@@ -7,7 +7,7 @@ import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.ValueSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.Transformer
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
case class SimpleTransformerSerializer[I <: SType, O <: SType]
(code: OpCode,
@@ -15,9 +15,9 @@ case class SimpleTransformerSerializer[I <: SType, O <: SType]
override val opCode: OpCode = code
- override def serializeBody(obj: Transformer[I, O], w: SigmaByteWriter): Unit =
+ override def serialize(obj: Transformer[I, O], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
- override def parseBody(r: SigmaByteReader): Value[O] =
+ override def parse(r: SigmaByteReader): Value[O] =
cons(r.getValue().asValue[I])
}
diff --git a/src/main/scala/sigmastate/serialization/transformers/SliceSerializer.scala b/src/main/scala/sigmastate/serialization/transformers/SliceSerializer.scala
index 06bdafe564..6f86bff5fc 100644
--- a/src/main/scala/sigmastate/serialization/transformers/SliceSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/transformers/SliceSerializer.scala
@@ -4,7 +4,7 @@ import sigmastate.Values.Value
import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.serialization.{OpCodes, ValueSerializer}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.utxo.Slice
import sigmastate.{SCollection, SInt, SType}
@@ -14,12 +14,12 @@ case class SliceSerializer(cons: (Value[SCollection[SType]], Value[SInt.type], V
override val opCode: OpCode = OpCodes.SliceCode
- override def serializeBody(obj: Slice[SType], w: SigmaByteWriter): Unit =
+ override def serialize(obj: Slice[SType], w: SigmaByteWriter): Unit =
w.putValue(obj.input)
.putValue(obj.from)
.putValue(obj.until)
- override def parseBody(r: SigmaByteReader): Value[SCollection[SType]] = {
+ override def parse(r: SigmaByteReader): Value[SCollection[SType]] = {
val input = r.getValue().asCollection[SType]
val from = r.getValue().asValue[SInt.type]
val until = r.getValue().asValue[SInt.type]
diff --git a/src/main/scala/sigmastate/serialization/trees/QuadrupleSerializer.scala b/src/main/scala/sigmastate/serialization/trees/QuadrupleSerializer.scala
index f4c97784c5..d9fc6bcb6d 100644
--- a/src/main/scala/sigmastate/serialization/trees/QuadrupleSerializer.scala
+++ b/src/main/scala/sigmastate/serialization/trees/QuadrupleSerializer.scala
@@ -5,20 +5,20 @@ import sigmastate.lang.Terms._
import sigmastate.serialization.ValueSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
import sigmastate.{Quadruple, _}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
case class QuadrupleSerializer[S1 <: SType, S2 <: SType, S3 <: SType, S4 <: SType]
(override val opCode: Byte,
cons: (Value[S1], Value[S2], Value[S3]) => Value[S4])
extends ValueSerializer[Quadruple[S1, S2, S3, S4]] {
- override def serializeBody(obj: Quadruple[S1, S2, S3, S4], w: SigmaByteWriter): Unit = {
+ override def serialize(obj: Quadruple[S1, S2, S3, S4], w: SigmaByteWriter): Unit = {
w.putValue(obj.first)
w.putValue(obj.second)
w.putValue(obj.third)
}
- override def parseBody(r: SigmaByteReader): Value[S4] = {
+ override def parse(r: SigmaByteReader): Value[S4] = {
val arg1 = r.getValue().asValue[S1]
val arg2 = r.getValue().asValue[S2]
val arg3 = r.getValue().asValue[S3]
diff --git a/src/main/scala/sigmastate/serialization/trees/Relation2Serializer.scala b/src/main/scala/sigmastate/serialization/trees/Relation2Serializer.scala
index 858704545f..0b68cd5e22 100644
--- a/src/main/scala/sigmastate/serialization/trees/Relation2Serializer.scala
+++ b/src/main/scala/sigmastate/serialization/trees/Relation2Serializer.scala
@@ -6,14 +6,14 @@ import sigmastate.lang.Terms._
import sigmastate.serialization.OpCodes._
import sigmastate.serialization.ValueSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
case class Relation2Serializer[S1 <: SType, S2 <: SType, R <: Value[SBoolean.type]]
(override val opCode: Byte,
constructor: (Value[S1], Value[S2]) => Value[SBoolean.type]) extends ValueSerializer[R] {
- override def serializeBody(obj: R, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: R, w: SigmaByteWriter): Unit = {
val typedRel = obj.asInstanceOf[Relation[S1, S2]]
(typedRel.left, typedRel.right) match {
case (Constant(left, ltpe), Constant(right, rtpe)) if ltpe == SBoolean && rtpe == SBoolean =>
@@ -25,7 +25,7 @@ case class Relation2Serializer[S1 <: SType, S2 <: SType, R <: Value[SBoolean.typ
}
}
- override def parseBody(r: SigmaByteReader): R = {
+ override def parse(r: SigmaByteReader): R = {
if (r.peekByte() == ConcreteCollectionBooleanConstantCode) {
val _ = r.getByte() // skip collection op code
val booleans = r.getBits(2)
diff --git a/src/main/scala/sigmastate/serialization/trees/Relation3Serializer.scala b/src/main/scala/sigmastate/serialization/trees/Relation3Serializer.scala
index 36f7413795..0a9bf4bdf8 100644
--- a/src/main/scala/sigmastate/serialization/trees/Relation3Serializer.scala
+++ b/src/main/scala/sigmastate/serialization/trees/Relation3Serializer.scala
@@ -5,20 +5,20 @@ import sigmastate._
import sigmastate.lang.Terms._
import sigmastate.serialization.ValueSerializer
import sigmastate.utils.{SigmaByteReader, SigmaByteWriter}
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
case class Relation3Serializer[S1 <: SType, S2 <: SType, S3 <: SType, R <: Value[SBoolean.type]]
(override val opCode: Byte,
cons: (Value[S1], Value[S2], Value[S3]) => R) extends ValueSerializer[R] {
- override def serializeBody(obj: R, w: SigmaByteWriter): Unit = {
+ override def serialize(obj: R, w: SigmaByteWriter): Unit = {
val rel = obj.asInstanceOf[Relation3[S1, S2, S3]]
w.putValue(rel.first)
w.putValue(rel.second)
w.putValue(rel.third)
}
- override def parseBody(r: SigmaByteReader): R = {
+ override def parse(r: SigmaByteReader): R = {
val arg1 = r.getValue().asValue[S1]
val arg2 = r.getValue().asValue[S2]
val arg3 = r.getValue().asValue[S3]
diff --git a/src/main/scala/sigmastate/trees.scala b/src/main/scala/sigmastate/trees.scala
index 4a1e856f51..a7a9502db3 100644
--- a/src/main/scala/sigmastate/trees.scala
+++ b/src/main/scala/sigmastate/trees.scala
@@ -1,9 +1,10 @@
package sigmastate
-import scorex.crypto.hash.{Blake2b256, CryptographicHash32, Sha256}
-import sigmastate.SCollection.{SByteArray, SIntArray}
+import scorex.crypto.hash.{Sha256, Blake2b256, CryptographicHash32}
+import sigmastate.SCollection.{SIntArray, SByteArray}
+import sigmastate.SOption.SIntOption
import sigmastate.Values._
-import sigmastate.basics.{SigmaProtocol, SigmaProtocolCommonInput, SigmaProtocolPrivateInput}
+import sigmastate.basics.{SigmaProtocol, SigmaProtocolPrivateInput, SigmaProtocolCommonInput}
import sigmastate.serialization.OpCodes._
import sigmastate.serialization._
import sigmastate.utxo.Transformer
@@ -15,7 +16,8 @@ import scala.collection.mutable.ArrayBuffer
* AND conjunction for sigma propositions
*/
case class CAND(sigmaBooleans: Seq[SigmaBoolean]) extends SigmaBoolean {
- override val opCode: OpCode = OpCodes.Undefined
+ /** The same code is used for AND operation, but they belong to different type hierarchies. */
+ override val opCode: OpCode = OpCodes.AndCode
}
object CAND {
import TrivialProp._
@@ -39,7 +41,8 @@ object CAND {
* OR disjunction for sigma propositions
*/
case class COR(sigmaBooleans: Seq[SigmaBoolean]) extends SigmaBoolean {
- override val opCode: OpCode = OpCodes.Undefined
+ /** The same code is also used for OR operation, but they belong to different type hierarchies. */
+ override val opCode: OpCode = OpCodes.OrCode
}
object COR {
import TrivialProp._
@@ -75,12 +78,26 @@ trait SigmaProofOfKnowledgeTree[SP <: SigmaProtocol[SP], S <: SigmaProtocolPriva
/** Represents boolean values (true/false) in SigmaBoolean tree.
* Participates in evaluation of CAND, COR, THRESHOLD connectives over SigmaBoolean values.
* See CAND.normalized, COR.normalized and AtLeast.reduce. */
-case class TrivialProp(condition: Boolean) extends SigmaBoolean {
- override val opCode: OpCode = OpCodes.TrivialProofCode
+abstract class TrivialProp(val condition: Boolean) extends SigmaBoolean with Product1[Boolean] {
+ override def _1: Boolean = condition
+ override def canEqual(that: Any): Boolean = that != null && that.isInstanceOf[TrivialProp]
}
object TrivialProp {
- val TrueProp = TrivialProp(true)
- val FalseProp = TrivialProp(false)
+ // NOTE: the corresponding unapply is missing because any implementation (even using Nullable)
+ // will lead to Boolean boxing, which we want to avoid
+ // So, instead of `case TrivialProp(b) => ... b ...` use more efficient
+ // `case p: TrivialProp => ... p.condition ...
+
+ def apply(b: Boolean): TrivialProp = if (b) TrueProp else FalseProp
+
+ val FalseProp = new TrivialProp(false) {
+ override val opCode: OpCode = OpCodes.TrivialPropFalseCode
+ override def toString = "FalseProp"
+ }
+ val TrueProp = new TrivialProp(true) {
+ override val opCode: OpCode = OpCodes.TrivialPropTrueCode
+ override def toString = "TrueProp"
+ }
}
/** Embedding of Boolean values to SigmaProp values. As an example, this operation allows boolean experesions
@@ -93,6 +110,40 @@ case class BoolToSigmaProp(value: BoolValue) extends SigmaPropValue {
val opType = SFunc(SBoolean, SSigmaProp)
}
+/** ErgoTree operation to create a new SigmaProp value representing public key
+ * of discrete logarithm signature protocol. */
+case class CreateProveDlog(value: Value[SGroupElement.type]) extends SigmaPropValue {
+ override val opCode: OpCode = OpCodes.ProveDlogCode
+ override def tpe = SSigmaProp
+ override def opType = SFunc(SGroupElement, SSigmaProp)
+}
+
+/** ErgoTree operation to create a new SigmaProp value representing public key
+ * of discrete logarithm signature protocol. */
+case class CreateAvlTree(operationFlags: ByteValue,
+ digest: Value[SByteArray],
+ keyLength: IntValue,
+ valueLengthOpt: Value[SIntOption]) extends AvlTreeValue {
+ override val opCode: OpCode = OpCodes.AvlTreeCode
+ override def tpe = SAvlTree
+ override def opType = CreateAvlTree.opType
+}
+object CreateAvlTree {
+ val opType = SFunc(IndexedSeq(SByte, SByteArray, SInt, SIntOption), SAvlTree)
+}
+
+/** ErgoTree operation to create a new SigmaProp value representing public key
+ * of Diffie Hellman signature protocol.
+ * Common input: (g,h,u,v)*/
+case class CreateProveDHTuple(gv: Value[SGroupElement.type],
+ hv: Value[SGroupElement.type],
+ uv: Value[SGroupElement.type],
+ vv: Value[SGroupElement.type]) extends SigmaPropValue {
+ override val opCode: OpCode = OpCodes.ProveDiffieHellmanTupleCode
+ override def tpe = SSigmaProp
+ override def opType = SFunc(IndexedSeq(SGroupElement, SGroupElement, SGroupElement, SGroupElement), SSigmaProp)
+}
+
trait SigmaTransformer[IV <: SigmaPropValue, OV <: SigmaPropValue] extends SigmaPropValue {
val items: Seq[IV]
}
@@ -140,6 +191,21 @@ object OR {
def apply(head: Value[SBoolean.type], tail: Value[SBoolean.type]*): OR = apply(head +: tail)
}
+/** Similar to allOf, but performing logical XOR operation instead of `&&`
+ */
+case class XorOf(input: Value[SCollection[SBoolean.type]])
+ extends Transformer[SCollection[SBoolean.type], SBoolean.type] with NotReadyValueBoolean {
+ override val opCode: OpCode = XorOfCode
+ override val opType = SFunc(SCollection.SBooleanArray, SBoolean)
+}
+
+object XorOf {
+ def apply(children: Seq[Value[SBoolean.type]]): XorOf =
+ XorOf(ConcreteCollection(children.toIndexedSeq))
+
+ def apply(head: Value[SBoolean.type], tail: Value[SBoolean.type]*): XorOf = apply(head +: tail)
+}
+
/**
* AND logical conjunction
*/
@@ -352,6 +418,11 @@ sealed trait Triple[LIV <: SType, RIV <: SType, OV <: SType] extends NotReadyVal
override def opType = SFunc(Vector(left.tpe, right.tpe), tpe)
}
+sealed trait OneArgumentOperation[IV <: SType, OV <: SType] extends NotReadyValue[OV] {
+ val input: Value[IV]
+ override def opType = SFunc(input.tpe, tpe)
+}
+
// TwoArgumentsOperation
sealed trait TwoArgumentsOperation[LIV <: SType, RIV <: SType, OV <: SType]
extends Triple[LIV, RIV, OV]
@@ -385,16 +456,14 @@ object ArithOp {
}
}
-case class Negation[T <: SNumericType](input: Value[T]) extends NotReadyValue[T] {
+case class Negation[T <: SType](input: Value[T]) extends OneArgumentOperation[T, T] {
override val opCode: OpCode = OpCodes.NegationCode
override def tpe: T = input.tpe
- override def opType: SFunc = SFunc(input.tpe, tpe)
}
-case class BitInversion[T <: SNumericType](input: Value[T]) extends NotReadyValue[T] {
+case class BitInversion[T <: SNumericType](input: Value[T]) extends OneArgumentOperation[T, T] {
override val opCode: OpCode = OpCodes.BitInversionCode
override def tpe: T = input.tpe
- override def opType: SFunc = SFunc(input.tpe, tpe)
}
case class BitOp[T <: SNumericType](left: Value[T], right: Value[T], opCode: OpCode)
@@ -442,13 +511,6 @@ case class MultiplyGroup(override val left: Value[SGroupElement.type],
override val opCode: OpCode = MultiplyGroupCode
}
-case class StringConcat(left: Value[SString.type], right: Value[SString.type])
- extends TwoArgumentsOperation[SString.type, SString.type, SString.type] with NotReadyValue[SString.type] {
- override def tpe: SString.type = left.tpe
-
- override val opCode: OpCode = StringConcatCode
-}
-
// Relation
sealed trait Relation[LIV <: SType, RIV <: SType] extends Triple[LIV, RIV, SBoolean.type]
@@ -559,37 +621,18 @@ sealed trait Relation3[IV1 <: SType, IV2 <: SType, IV3 <: SType]
* Return None if leaf with provided key does not exist.
*/
case class TreeLookup(tree: Value[SAvlTree.type],
- key: Value[SByteArray],
- proof: Value[SByteArray]) extends Quadruple[SAvlTree.type, SByteArray, SByteArray, SOption[SByteArray]] {
+ key: Value[SByteArray],
+ proof: Value[SByteArray]) extends Quadruple[SAvlTree.type, SByteArray, SByteArray, SOption[SByteArray]] {
override def tpe = SOption[SByteArray]
- override val opCode: OpCode = OpCodes.TreeLookupCode
+ override val opCode: OpCode = OpCodes.AvlTreeGetCode
override lazy val first = tree
override lazy val second = key
override lazy val third = proof
}
-/**
- * Perform modification of in the tree with root `tree` using proof `proof`.
- * Throws exception if proof is incorrect
- * Return Some(newTree) if successfull
- * Return None if operations were not performed.
- */
-case class TreeModifications(tree: Value[SAvlTree.type],
- operations: Value[SByteArray],
- proof: Value[SByteArray]) extends Quadruple[SAvlTree.type, SByteArray, SByteArray, SOption[SByteArray]] {
-
- override def tpe = SOption[SByteArray]
-
- override val opCode: OpCode = OpCodes.TreeModificationsCode
-
- override lazy val first = tree
- override lazy val second = operations
- override lazy val third = proof
-}
-
/**
* If conditional function.
* Non-lazy - evaluate both branches.
diff --git a/src/main/scala/sigmastate/types.scala b/src/main/scala/sigmastate/types.scala
index 3fd518b67a..8f93d54b02 100644
--- a/src/main/scala/sigmastate/types.scala
+++ b/src/main/scala/sigmastate/types.scala
@@ -3,30 +3,37 @@ package sigmastate
import java.math.BigInteger
import org.ergoplatform.{ErgoLikeContext, ErgoBox}
+import scalan.RType
import sigmastate.SType.{TypeCode, AnyOps}
import sigmastate.interpreter.CryptoConstants
import sigmastate.utils.Overloading.Overload1
-import sigmastate.utils.Extensions._
+import sigma.util.Extensions._
import sigmastate.Values._
import sigmastate.lang.Terms._
-import sigmastate.lang.SigmaTyper
+import sigmastate.lang.{SigmaBuilder, SigmaTyper}
import sigmastate.SCollection._
-import sigmastate.interpreter.CryptoConstants.EcPointType
+import sigmastate.interpreter.CryptoConstants.{EcPointType, hashLength}
import sigmastate.serialization.OpCodes
-import sigmastate.utxo.CostTable.Cost
-import special.collection.Col
+import special.collection.Coll
+import sigmastate.eval.RuntimeCosting
-import scala.collection.mutable
import scala.language.implicitConversions
import scala.reflect.ClassTag
+import scala.reflect.{ClassTag, classTag}
import scalan.meta.ScalanAst.STypeArgAnnotation
import sigmastate.SBoolean.typeCode
import sigmastate.SByte.typeCode
+import sigmastate.SMethod.MethodCallIrBuilder
import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.basics.ProveDHTuple
+import sigmastate.utxo.{ExtractCreationInfo, ByIndex}
+import special.sigma.{Header, Box, wrapperType, SigmaProp, AvlTree, PreHeader}
+import sigmastate.lang.SigmaTyper.STypeSubst
+import sigmastate.utxo.ByIndex
+import special.sigma.{AvlTree, Box, SigmaProp, wrapperType}
//import sigmastate.SNumericType._
import sigmastate.SSigmaProp.{IsProven, PropBytes}
-
+import sigmastate.eval.SigmaDsl
/** Base type for all AST nodes of sigma lang. */
trait SigmaNode extends Product
@@ -67,11 +74,20 @@ sealed trait SType extends SigmaNode {
/** Construct tree node Constant for a given data object. */
def mkConstant(v: WrappedType): Value[this.type] =
sys.error(s"Don't know how mkConstant for data value $v with T = $this")
+
+ def withSubstTypes(subst: Map[STypeIdent, SType]): SType =
+ if (subst.isEmpty) this
+ else
+ SigmaTyper.applySubst(this, subst)
+
}
object SType {
/** Representation of type codes used in serialization. */
type TypeCode = Byte
+ object Codes {
+
+ }
val DummyValue = 0.asWrappedType
@@ -88,24 +104,31 @@ object SType {
implicit def typeCollection[V <: SType](implicit tV: V): SCollection[V] = SCollection[V]
+ implicit val SigmaBooleanRType: RType[SigmaBoolean] = RType.fromClassTag(classTag[SigmaBoolean])
+ implicit val ErgoBoxRType: RType[ErgoBox] = RType.fromClassTag(classTag[ErgoBox])
+ implicit val AvlTreeDataRType: RType[AvlTreeData] = RType.fromClassTag(classTag[AvlTreeData])
+ implicit val ErgoLikeContextRType: RType[ErgoLikeContext] = RType.fromClassTag(classTag[ErgoLikeContext])
+
/** All pre-defined types should be listed here. Note, NoType is not listed.
* Should be in sync with sigmastate.lang.Types.predefTypes. */
- val allPredefTypes = Seq(SBoolean, SByte, SShort, SInt, SLong, SBigInt, SContext, SAvlTree, SGroupElement, SSigmaProp, SBox, SUnit, SAny)
+ val allPredefTypes = Seq(SBoolean, SByte, SShort, SInt, SLong, SBigInt, SContext, SHeader, SPreHeader, SAvlTree, SGroupElement, SSigmaProp, SString, SBox, SUnit, SAny)
val typeCodeToType = allPredefTypes.map(t => t.typeCode -> t).toMap
/** A mapping of object types supporting MethodCall operations. For each serialized typeId this map contains
* a companion object which can be used to access the list of corresponding methods.
* NOTE: in the current implementation only monomorphic methods are supported (without type parameters)*/
val types: Map[Byte, STypeCompanion] = Seq(
- SNumericType, SString, STuple, SGroupElement, SSigmaProp, SContext,
- SAvlTree, SBox
+ SNumericType, SString, STuple, SGroupElement, SSigmaProp, SContext, SHeader, SPreHeader,
+ SAvlTree, SBox, SOption, SCollection, SBigInt
).map { t => (t.typeId, t) }.toMap
implicit class STypeOps(val tpe: SType) extends AnyVal {
def isCollectionLike: Boolean = tpe.isInstanceOf[SCollection[_]]
def isCollection: Boolean = tpe.isInstanceOf[SCollectionType[_]]
def isOption: Boolean = tpe.isInstanceOf[SOption[_]]
+ def isBox: Boolean = tpe.isInstanceOf[SBox.type]
def isSigmaProp: Boolean = tpe.isInstanceOf[SSigmaProp.type]
+ def isAvlTree: Boolean = tpe.isInstanceOf[SAvlTree.type]
def isFunc : Boolean = tpe.isInstanceOf[SFunc]
def isTuple: Boolean = tpe.isInstanceOf[STuple]
def canBeTypedAs(expected: SType): Boolean = (tpe, expected) match {
@@ -120,6 +143,7 @@ object SType {
def isNumType: Boolean = tpe.isInstanceOf[SNumericType]
def asNumType: SNumericType = tpe.asInstanceOf[SNumericType]
def asFunc: SFunc = tpe.asInstanceOf[SFunc]
+ def asProduct: SProduct = tpe.asInstanceOf[SProduct]
def asOption[T <: SType]: SOption[T] = tpe.asInstanceOf[SOption[T]]
def whenFunc[T](action: SFunc => Unit) = if(tpe.isInstanceOf[SFunc]) action(tpe.asFunc)
def asCollection[T <: SType] = tpe.asInstanceOf[SCollection[T]]
@@ -137,8 +161,8 @@ object SType {
case SBox => reflect.classTag[ErgoBox]
case SAny => reflect.classTag[Any]
case t: STuple => reflect.classTag[Array[Any]]
- case tCol: SCollection[a] =>
- val elemType = tCol.elemType
+ case tColl: SCollection[a] =>
+ val elemType = tColl.elemType
implicit val ca = elemType.classTag[elemType.WrappedType]
reflect.classTag[Array[elemType.WrappedType]]
case _ => sys.error(s"Cannot get ClassTag for type $tpe")
@@ -176,16 +200,23 @@ object SType {
/** Basic interface for all type companions */
trait STypeCompanion {
+
/** Type identifier to use in method serialization */
def typeId: Byte
+
/** List of methods defined for instances of this type. */
def methods: Seq[SMethod]
- def getMethodById(methodId: Byte): SMethod = {
- methods(methodId - 1)
- }
+ def getMethodById(methodId: Byte): SMethod =
+ methods.filter(_.objType == this).apply(methodId - 1)
def getMethodByName(name: String): SMethod = methods.find(_.name == name).get
+
+ def coster: Option[CosterFactory] = None
+}
+
+trait MethodByNameUnapply extends STypeCompanion {
+ def unapply(methodName: String): Option[SMethod] = methods.find(_.name == methodName)
}
/** Base trait for all types which have methods (and properties) */
@@ -195,8 +226,19 @@ trait SProduct extends SType {
def methodIndex(name: String): Int = methods.indexWhere(_.name == name)
def hasMethod(name: String): Boolean = methodIndex(name) != -1
- /** Returns all the methods of this product type. */
- def methods: Seq[SMethod]
+ /** This method should be overriden in derived classes to add new methods in addition to inherited.
+ * Typical override: `super.getMethods() ++ Seq(m1, m2, m3)` */
+ protected def getMethods(): Seq[SMethod] = Seq()
+
+ /** Returns all the methods of this type. */
+ lazy val methods: Seq[SMethod] = {
+ val ms = getMethods()
+ assert(ms.map(_.name).distinct.length == ms.length, s"Duplicate method names in $this")
+ ms.groupBy(_.objType).foreach { case (comp, ms) =>
+ assert(ms.map(_.methodId).distinct.length == ms.length, s"Duplicate method ids in $comp: $ms")
+ }
+ ms
+ }
/** Checks if `this` product has exactly the same methods as `that`. */
def sameMethods(that: SProduct): Boolean = {
@@ -207,18 +249,78 @@ trait SProduct extends SType {
}
true
}
+
+ def method(methodName: String): Option[SMethod] = methods.find(_.name == methodName)
}
/** Base trait implemented by all generic types (those which has type parameters,
* e.g. Array[T], Option[T], etc.)*/
trait SGenericType {
def typeParams: Seq[STypeParam]
- def tparamSubst: Map[String, SType]
+ def tparamSubst: Map[STypeIdent, SType]
+
+ lazy val substitutedTypeParams: Seq[STypeParam] =
+ typeParams.map { tp =>
+ tparamSubst.getOrElse(tp.ident, tp.ident) match {
+ case v: STypeIdent => STypeParam(v)
+ case _ => tp
+ }
+ }
+
+}
+
+trait CosterFactory {
+ def apply[Ctx <: RuntimeCosting](IR: Ctx): IR.CostingHandler[_]
+}
+
+case class Coster(selector: RuntimeCosting => RuntimeCosting#CostingHandler[_]) extends CosterFactory {
+ def apply[Ctx <: RuntimeCosting](IR: Ctx): IR.CostingHandler[_] = selector(IR).asInstanceOf[IR.CostingHandler[_]]
}
/** Method info including name, arg type and result type.
- * When stype is SFunc, then tDom - arg type and tRange - result type. */
-case class SMethod(objType: STypeCompanion, name: String, stype: SType, methodId: Byte) {
+ * Here stype.tDom - arg type and stype.tRange - result type.
+ * `methodId` should be unique among methods of the same objType. */
+case class SMethod(
+ objType: STypeCompanion,
+ name: String,
+ stype: SFunc,
+ methodId: Byte,
+ irBuilder: Option[PartialFunction[(SigmaBuilder, SValue, SMethod, Seq[SValue], STypeSubst), SValue]]) {
+
+ def withSType(newSType: SFunc): SMethod = copy(stype = newSType)
+
+ def withConcreteTypes(subst: Map[STypeIdent, SType]): SMethod =
+ withSType(stype.withSubstTypes(subst).asFunc)
+
+ def opId: OperationId = {
+ val opName = objType.getClass.getSimpleName + "." + name
+ OperationId(opName, stype)
+ }
+
+ def specializeFor(objTpe: SType, args: Seq[SType]): SMethod = {
+ SigmaTyper.unifyTypeLists(stype.tDom, objTpe +: args) match {
+ case Some(subst) if subst.nonEmpty =>
+ withConcreteTypes(subst)
+ case _ => this
+ }
+ }
+}
+
+object SMethod {
+ type RCosted[A] = RuntimeCosting#RCosted[A]
+ val MethodCallIrBuilder: Option[PartialFunction[(SigmaBuilder, SValue, SMethod, Seq[SValue], STypeSubst), SValue]] = Some {
+ case (builder, obj, method, args, tparamSubst) =>
+ builder.mkMethodCall(obj, method, args.toIndexedSeq, tparamSubst)
+ }
+
+ def apply(objType: STypeCompanion, name: String, stype: SFunc, methodId: Byte): SMethod =
+ SMethod(objType, name, stype, methodId, None)
+
+ def fromIds(typeId: Byte, methodId: Byte): SMethod = {
+ val typeCompanion = SType.types.getOrElse(typeId, sys.error(s"Cannot find STypeCompanion instance for typeId=$typeId"))
+ val method = typeCompanion.getMethodById(methodId)
+ method
+ }
}
/** Special type to represent untyped values.
@@ -259,7 +361,7 @@ object SPrimType {
def unapply(t: SType): Option[SType] = SType.allPredefTypes.find(_ == t)
/** Type code of the last valid prim type so that (1 to LastPrimTypeCode) is a range of valid codes. */
- final val LastPrimTypeCode: Byte = 9: Byte
+ final val LastPrimTypeCode: Byte = 8: Byte
/** Upper limit of the interval of valid type codes for primitive types */
final val MaxPrimTypeCode: Byte = 11: Byte
@@ -270,7 +372,11 @@ object SPrimType {
trait SNumericType extends SProduct {
import SNumericType._
override def ancestors: Seq[SType] = Nil
- def methods = SNumericType.methods
+ protected override def getMethods(): Seq[SMethod] = {
+ super.getMethods() ++ SNumericType.methods.map {
+ m => m.copy(stype = SigmaTyper.applySubst(m.stype, Map(tNum -> this)).asFunc)
+ }
+ }
def isCastMethod (name: String): Boolean = castMethods.contains(name)
def upcast(i: AnyVal): WrappedType
@@ -285,18 +391,22 @@ trait SNumericType extends SProduct {
}
object SNumericType extends STypeCompanion {
final val allNumericTypes = Array(SByte, SShort, SInt, SLong, SBigInt)
- def typeId: TypeCode = 1: Byte
+ def typeId: TypeCode = 106: Byte
val ToByte = "toByte"
val ToShort = "toShort"
val ToInt = "toInt"
val ToLong = "toLong"
val ToBigInt = "toBigInt"
+
+ val tNum = STypeIdent("TNum")
val methods = Vector(
- SMethod(this, ToByte, SByte, 1), // see Downcast
- SMethod(this, ToShort, SShort, 2), // see Downcast
- SMethod(this, ToInt, SInt, 3), // see Downcast
- SMethod(this, ToLong, SLong, 4), // see Downcast
- SMethod(this, ToBigInt, SBigInt, 5) // see Downcast
+ SMethod(this, ToByte, SFunc(tNum, SByte), 1), // see Downcast
+ SMethod(this, ToShort, SFunc(tNum, SShort), 2), // see Downcast
+ SMethod(this, ToInt, SFunc(tNum, SInt), 3), // see Downcast
+ SMethod(this, ToLong, SFunc(tNum, SLong), 4), // see Downcast
+ SMethod(this, ToBigInt, SFunc(tNum, SBigInt), 5), // see Downcast
+ SMethod(this, "toBytes", SFunc(tNum, SByteArray), 6, MethodCallIrBuilder),
+ SMethod(this, "toBits", SFunc(tNum, SBooleanArray), 7, MethodCallIrBuilder),
)
val castMethods: Array[String] = Array(ToByte, ToShort, ToInt, ToLong, ToBigInt)
}
@@ -304,21 +414,29 @@ object SNumericType extends STypeCompanion {
trait SLogical extends SType {
}
-case object SBoolean extends SPrimType with SEmbeddable with SLogical with SProduct with STypeCompanion {
+/** Monomorphic type descriptor i.e. a type without generic parameters.
+ * @see `SGenericType`
+ */
+trait SMonoType extends SType with STypeCompanion {
+ protected def property(name: String, tpe: SType, id: Byte) =
+ SMethod(this, name, SFunc(this, tpe), id, MethodCallIrBuilder)
+}
+
+case object SBoolean extends SPrimType with SEmbeddable with SLogical with SProduct with SMonoType {
override type WrappedType = Boolean
override val typeCode: TypeCode = 1: Byte
override def typeId = typeCode
override def ancestors: Seq[SType] = Nil
val ToByte = "toByte"
- override val methods = Vector(
- SMethod(this, ToByte, SByte, 1),
+ protected override def getMethods() = super.getMethods() ++ Seq(
+ SMethod(this, ToByte, SFunc(this, SByte), 1),
)
override def mkConstant(v: Boolean): Value[SBoolean.type] = BooleanConstant(v)
override def dataSize(v: SType#WrappedType): Long = 1
override def isConstantSize = true
}
-case object SByte extends SPrimType with SEmbeddable with SNumericType with STypeCompanion {
+case object SByte extends SPrimType with SEmbeddable with SNumericType with SMonoType {
override type WrappedType = Byte
override val typeCode: TypeCode = 2: Byte //TODO change to 4 after SByteArray is removed
override def typeId = typeCode
@@ -339,7 +457,7 @@ case object SByte extends SPrimType with SEmbeddable with SNumericType with STyp
}
//todo: make PreservingNonNegativeInt type for registers which value should be preserved?
-case object SShort extends SPrimType with SEmbeddable with SNumericType with STypeCompanion {
+case object SShort extends SPrimType with SEmbeddable with SNumericType with SMonoType {
override type WrappedType = Short
override val typeCode: TypeCode = 3: Byte
override def typeId = typeCode
@@ -360,9 +478,10 @@ case object SShort extends SPrimType with SEmbeddable with SNumericType with STy
}
//todo: make PreservingNonNegativeInt type for registers which value should be preserved?
-case object SInt extends SPrimType with SEmbeddable with SNumericType {
+case object SInt extends SPrimType with SEmbeddable with SNumericType with SMonoType {
override type WrappedType = Int
override val typeCode: TypeCode = 4: Byte
+ override def typeId = typeCode
override def mkConstant(v: Int): Value[SInt.type] = IntConstant(v)
override def dataSize(v: SType#WrappedType): Long = 4
override def isConstantSize = true
@@ -382,9 +501,10 @@ case object SInt extends SPrimType with SEmbeddable with SNumericType {
}
//todo: make PreservingNonNegativeInt type for registers which value should be preserved?
-case object SLong extends SPrimType with SEmbeddable with SNumericType {
+case object SLong extends SPrimType with SEmbeddable with SNumericType with SMonoType {
override type WrappedType = Long
override val typeCode: TypeCode = 5: Byte
+ override def typeId = typeCode
override def mkConstant(v: Long): Value[SLong.type] = LongConstant(v)
override def dataSize(v: SType#WrappedType): Long = 8
override def isConstantSize = true
@@ -404,12 +524,16 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType {
}
}
-case object SBigInt extends SPrimType with SEmbeddable with SNumericType with STypeCompanion {
+/** Type of 256 bit integet values. Implemented using [[java.math.BigInteger]]. */
+case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SMonoType {
override type WrappedType = BigInteger
override val typeCode: TypeCode = 6: Byte
- override def typeId: TypeCode = typeCode
+ override def typeId = typeCode
override def mkConstant(v: BigInteger): Value[SBigInt.type] = BigIntConstant(v)
+ /** Type of Relation binary op like GE, LE, etc. */
+ val RelationOpType = SFunc(Vector(SBigInt, SBigInt), SBoolean)
+
/** The maximum size of BigInteger value in byte array representation. */
val MaxSizeInBytes: Long = 32L
@@ -436,88 +560,101 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with ST
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
- val ModQMethod = SMethod(this, "modQ", SBigInt, 1)
- val PlusModQMethod = SMethod(this, "plusModQ", SFunc(IndexedSeq(SBigInt, SBigInt), SBigInt), 2)
- val MinusModQMethod = SMethod(this, "minusModQ", SFunc(IndexedSeq(SBigInt, SBigInt), SBigInt), 3)
- override val methods: Vector[SMethod] = Vector(
+ val ModQMethod = SMethod(this, "modQ", SFunc(this, SBigInt), 1)
+ val PlusModQMethod = SMethod(this, "plusModQ", SFunc(IndexedSeq(this, SBigInt), SBigInt), 2)
+ val MinusModQMethod = SMethod(this, "minusModQ", SFunc(IndexedSeq(this, SBigInt), SBigInt), 3)
+ val MultModQMethod = SMethod(this, "multModQ", SFunc(IndexedSeq(this, SBigInt), SBigInt), 4, MethodCallIrBuilder)
+ protected override def getMethods() = super.getMethods() ++ Seq(
ModQMethod,
PlusModQMethod,
MinusModQMethod,
+ MultModQMethod,
)
}
/** NOTE: this descriptor both type and type companion */
-case object SString extends SProduct with STypeCompanion {
+case object SString extends SProduct with SMonoType {
override type WrappedType = String
override def ancestors: Seq[SType] = Nil
- override val typeCode: TypeCode = 101: Byte
+ override val typeCode: TypeCode = 102: Byte
override def typeId = typeCode
- override val methods: Seq[SMethod] = Nil
override def mkConstant(v: String): Value[SString.type] = StringConstant(v)
override def dataSize(v: SType#WrappedType): Long = v.asInstanceOf[String].length
override def isConstantSize = false
}
/** NOTE: this descriptor both type and type companion */
-case object SGroupElement extends SProduct with SPrimType with SEmbeddable with STypeCompanion {
+case object SGroupElement extends SProduct with SPrimType with SEmbeddable with SMonoType {
override type WrappedType = EcPointType
override val typeCode: TypeCode = 7: Byte
override def typeId = typeCode
- override val methods: Seq[SMethod] = Seq(
- SMethod(this, "isIdentity", SBoolean, 1),
- SMethod(this, "nonce", SByteArray, 2),
- SMethod(this, "getEncoded", SFunc(IndexedSeq(this, SBoolean), SByteArray), 3)
+ override def coster: Option[CosterFactory] = Some(Coster(_.GroupElementCoster))
+ protected override def getMethods(): Seq[SMethod] = super.getMethods() ++ Seq(
+ SMethod(this, "isIdentity", SFunc(this, SBoolean), 1),
+ SMethod(this, "nonce", SFunc(this, SByteArray), 2),
+ SMethod(this, "getEncoded", SFunc(IndexedSeq(this), SByteArray), 3, MethodCallIrBuilder),
+ SMethod(this, "exp", SFunc(IndexedSeq(this, SBigInt), this), 4, Some {
+ case (builder, obj, method, Seq(arg), tparamSubst) =>
+ builder.mkExponentiate(obj.asGroupElement, arg.asBigInt)
+ }),
+ SMethod(this, "multiply", SFunc(IndexedSeq(this, SGroupElement), this), 5, Some {
+ case (builder, obj, method, Seq(arg), tparamSubst) =>
+ builder.mkMultiplyGroup(obj.asGroupElement, arg.asGroupElement)
+ }),
+ SMethod(this, "negate", SFunc(this, this), 6, MethodCallIrBuilder)
)
override def mkConstant(v: EcPointType): Value[SGroupElement.type] = GroupElementConstant(v)
- override def dataSize(v: SType#WrappedType): Long = 32
+ override def dataSize(v: SType#WrappedType): Long = CryptoConstants.EncodedGroupElementLength.toLong
override def isConstantSize = true
def ancestors = Nil
}
-case object SSigmaProp extends SProduct with SPrimType with SEmbeddable with SLogical with STypeCompanion {
+case object SSigmaProp extends SProduct with SPrimType with SEmbeddable with SLogical with SMonoType {
import SType._
override type WrappedType = SigmaBoolean
override val typeCode: TypeCode = 8: Byte
override def typeId = typeCode
override def mkConstant(v: SigmaBoolean): Value[SSigmaProp.type] = SigmaPropConstant(v)
override def dataSize(v: SType#WrappedType): Long = v match {
- case ProveDlog(GroupElementConstant(g)) =>
+ case ProveDlog(g) =>
SGroupElement.dataSize(g.asWrappedType) + 1
- case ProveDHTuple(
- GroupElementConstant(gv), GroupElementConstant(hv),
- GroupElementConstant(uv), GroupElementConstant(vv)) =>
+ case ProveDHTuple(gv, hv, uv, vv) =>
SGroupElement.dataSize(gv.asWrappedType) * 4 + 1
- case CAND(inputs) => inputs.map(i => dataSize(i.asWrappedType)).sum
- case _ => ???
+ case CAND(inputs) => inputs.map(i => dataSize(i.asWrappedType)).sum + 1
+ case COR(inputs) => inputs.map(i => dataSize(i.asWrappedType)).sum + 1
+ case CTHRESHOLD(k, inputs) => 4 + inputs.map(i => dataSize(i.asWrappedType)).sum + 1
+ case t: TrivialProp => 1
+ case _ => sys.error(s"Cannot get SigmaProp.dataSize($v)")
}
override def isConstantSize = false
def ancestors = Nil
val PropBytes = "propBytes"
val IsProven = "isProven"
- val methods = Seq(
- SMethod(this, PropBytes, SByteArray, 1),
- SMethod(this, IsProven, SBoolean, 2)
+ protected override def getMethods() = super.getMethods() ++ Seq(
+ SMethod(this, PropBytes, SFunc(this, SByteArray), 1),
+ SMethod(this, IsProven, SFunc(this, SBoolean), 2)
)
}
/** Any other type is implicitly subtype of this type. */
case object SAny extends SPrimType {
override type WrappedType = Any
- override val typeCode: Byte = 97: Byte
+ override val typeCode: TypeCode = 97: Byte
override def isConstantSize = false
}
/** The type with single inhabitant value `()` */
case object SUnit extends SPrimType {
override type WrappedType = Unit
- override val typeCode: Byte = 98: Byte
+ override val typeCode: TypeCode = 98: Byte
override def dataSize(v: SType#WrappedType) = 1
override def isConstantSize = true
}
/** Type description of optional values. Instances of `Option`
* are either constructed by `Some` or by `None` constructors. */
-case class SOption[ElemType <: SType](elemType: ElemType) extends SProduct {
+case class SOption[ElemType <: SType](elemType: ElemType) extends SProduct with SGenericType { // TODO make SOption inherit SGenericType
+ import SOption._
override type WrappedType = Option[ElemType#WrappedType]
override val typeCode: TypeCode = SOption.OptionTypeCode
override def dataSize(v: SType#WrappedType) = {
@@ -526,13 +663,16 @@ case class SOption[ElemType <: SType](elemType: ElemType) extends SProduct {
}
override def isConstantSize = elemType.isConstantSize
def ancestors = Nil
- override lazy val methods: Seq[SMethod] = {
- val subst = Map(SOption.tT -> elemType)
- SOption.methods.map { method =>
- method.copy(stype = SigmaTyper.applySubst(method.stype, subst))
- }
- }
+ protected override def getMethods() = super.getMethods() ++ SOption.methods
+// override lazy val methods: Seq[SMethod] = {
+// val subst = Map(SOption.tT -> elemType)
+// SOption.methods.map { method =>
+// method.copy(stype = SigmaTyper.applySubst(method.stype, subst))
+// }
+// }
override def toString = s"Option[$elemType]"
+ val typeParams: Seq[STypeParam] = Seq(STypeParam(tT))
+ def tparamSubst: Map[STypeIdent, SType] = Map(tT -> elemType)
}
object SOption extends STypeCompanion {
@@ -542,17 +682,27 @@ object SOption extends STypeCompanion {
val OptionCollectionTypeCode: TypeCode = ((SPrimType.MaxPrimTypeCode + 1) * OptionCollectionTypeConstrId).toByte
override def typeId = OptionTypeCode
- implicit val optionTypeByte = SOption(SByte)
- implicit val optionTypeByteArray = SOption(SByteArray)
- implicit val optionTypeShort = SOption(SShort)
- implicit val optionTypeInt = SOption(SInt)
- implicit val optionTypeLong = SOption(SLong)
- implicit val optionTypeBigInt = SOption(SBigInt)
- implicit val optionTypeBoolean = SOption(SBoolean)
- implicit val optionTypeAvlTree = SOption(SAvlTree)
- implicit val optionTypeGroupElement = SOption(SGroupElement)
- implicit val optionTypeSigmaProp = SOption(SSigmaProp)
- implicit val optionTypeBox = SOption(SBox)
+ type SBooleanOption = SOption[SBoolean.type]
+ type SByteOption = SOption[SByte.type]
+ type SShortOption = SOption[SShort.type]
+ type SIntOption = SOption[SInt.type]
+ type SLongOption = SOption[SLong.type]
+ type SBigIntOption = SOption[SBigInt.type]
+ type SGroupElementOption = SOption[SGroupElement.type]
+ type SBoxOption = SOption[SBox.type]
+ type SAvlTreeOption = SOption[SAvlTree.type]
+
+ implicit val SByteOption = SOption(SByte)
+ implicit val SByteArrayOption = SOption(SByteArray)
+ implicit val SShortOption = SOption(SShort)
+ implicit val SIntOption = SOption(SInt)
+ implicit val SLongOption = SOption(SLong)
+ implicit val SBigIntOption = SOption(SBigInt)
+ implicit val SBooleanOption = SOption(SBoolean)
+ implicit val SAvlTreeOption = SOption(SAvlTree)
+ implicit val SGroupElementOption = SOption(SGroupElement)
+ implicit val SSigmaPropOption = SOption(SSigmaProp)
+ implicit val SBoxOption = SOption(SBox)
implicit def optionTypeCollection[V <: SType](implicit tV: V): SOption[SCollection[V]] = SOption(SCollection[V])
@@ -562,14 +712,36 @@ object SOption extends STypeCompanion {
val GetOrElse = "getOrElse"
val Fold = "fold"
- private val tT = STypeIdent("T")
- private val tR = STypeIdent("R")
- val IsEmptyMethod = SMethod(this, IsEmpty, SBoolean, 1)
- val IsDefinedMethod = SMethod(this, IsDefined, SBoolean, 2)
- val GetMethod = SMethod(this, Get, tT, 3)
- val GetOrElseMethod = SMethod(this, GetOrElse, SFunc(IndexedSeq(SOption(tT), tT), tT, Seq(STypeParam(tT))), 4)
- val FoldMethod = SMethod(this, Fold, SFunc(IndexedSeq(SOption(tT), tR, SFunc(tT, tR)), tR, Seq(STypeParam(tT), STypeParam(tR))), 5)
- val methods: Seq[SMethod] = Seq(IsEmptyMethod, IsDefinedMethod, GetMethod, GetOrElseMethod, FoldMethod)
+ val tT = STypeIdent("T")
+ val tR = STypeIdent("R")
+ val ThisType = SOption(tT)
+
+ val IsEmptyMethod = SMethod(this, IsEmpty, SFunc(ThisType, SBoolean), 1)
+ val IsDefinedMethod = SMethod(this, IsDefined, SFunc(ThisType, SBoolean), 2)
+ val GetMethod = SMethod(this, Get, SFunc(ThisType, tT), 3)
+ val GetOrElseMethod = SMethod(this, GetOrElse, SFunc(IndexedSeq(ThisType, tT), tT, Seq(tT)), 4)
+ val FoldMethod = SMethod(this, Fold, SFunc(IndexedSeq(ThisType, tR, SFunc(tT, tR)), tR, Seq(tT, tR)), 5)
+ val ToCollMethod = SMethod(this, "toColl", SFunc(IndexedSeq(ThisType), SCollection(tT), Seq(tT)), 6, MethodCallIrBuilder)
+ val MapMethod = SMethod(this, "map",
+ SFunc(IndexedSeq(ThisType, SFunc(tT, tR)), SOption(tR), Seq(STypeParam(tT), STypeParam(tR))),
+ 7, MethodCallIrBuilder)
+ val FilterMethod = SMethod(this, "filter",
+ SFunc(IndexedSeq(ThisType, SFunc(tT, SBoolean)), ThisType, Seq(STypeParam(tT))),
+ 8, MethodCallIrBuilder)
+ val FlatMapMethod = SMethod(this, "flatMap",
+ SFunc(IndexedSeq(ThisType, SFunc(tT, SOption(tR))), SOption(tR), Seq(STypeParam(tT), STypeParam(tR))),
+ 9, MethodCallIrBuilder)
+ val methods: Seq[SMethod] = Seq(
+ IsEmptyMethod,
+ IsDefinedMethod,
+ GetMethod,
+ GetOrElseMethod,
+ FoldMethod,
+ ToCollMethod,
+ MapMethod,
+ FilterMethod,
+ FlatMapMethod,
+ )
def apply[T <: SType](implicit elemType: T, ov: Overload1): SOption[T] = SOption(elemType)
def unapply[T <: SType](tOpt: SOption[T]): Option[T] = Some(tOpt.elemType)
}
@@ -588,7 +760,7 @@ case class SCollectionType[T <: SType](elemType: T) extends SCollection[T] {
CollectionConstant(v, elemType).asValue[this.type]
override def dataSize(v: SType#WrappedType): Long = {
- val arr = (v match { case col: Col[_] => col.arr case _ => v}).asInstanceOf[Array[T#WrappedType]]
+ val arr = (v match { case col: Coll[_] => col.toArray case _ => v}).asInstanceOf[Array[T#WrappedType]]
val header = 2
val res =
if (arr.isEmpty)
@@ -599,9 +771,9 @@ case class SCollectionType[T <: SType](elemType: T) extends SCollection[T] {
arr.map(x => elemType.dataSize(x)).sum
res
}
- def typeParams = SCollectionType.typeParams
- def tparamSubst = Map(tIV.name -> elemType)
- override def methods = SCollection.methods
+ def typeParams: Seq[STypeParam] = SCollectionType.typeParams
+ def tparamSubst: Map[STypeIdent, SType] = Map(tIV -> elemType)
+ protected override def getMethods() = super.getMethods() ++ SCollection.methods
override def toString = s"Coll[$elemType]"
}
@@ -613,23 +785,111 @@ object SCollectionType {
val typeParams = Seq(STypeParam(tIV.name))
}
-object SCollection extends STypeCompanion {
+object SCollection extends STypeCompanion with MethodByNameUnapply {
override def typeId = SCollectionType.CollectionTypeCode
+ override def coster: Option[CosterFactory] = Some(Coster(_.CollCoster))
val tIV = STypeIdent("IV")
+ val paramIV = STypeParam(tIV)
val tOV = STypeIdent("OV")
- val SizeMethod = SMethod(this, "size", SInt, 1)
- val GetOrElseMethod = SMethod(this, "getOrElse", SFunc(IndexedSeq(SCollection(tIV), SInt, tIV), tIV, Seq(STypeParam(tIV))), 2)
- val MapMethod = SMethod(this, "map", SFunc(IndexedSeq(SCollection(tIV), SFunc(tIV, tOV)), SCollection(tOV), Seq(STypeParam(tIV), STypeParam(tOV))), 3)
- val ExistsMethod = SMethod(this, "exists", SFunc(IndexedSeq(SCollection(tIV), SFunc(tIV, SBoolean)), SBoolean, Seq(STypeParam(tIV))), 4)
- val FoldMethod = SMethod(this, "fold", SFunc(IndexedSeq(SCollection(tIV), tOV, SFunc(IndexedSeq(tOV, tIV), tOV)), tOV, Seq(STypeParam(tIV), STypeParam(tOV))), 5)
- val ForallMethod = SMethod(this, "forall", SFunc(IndexedSeq(SCollection(tIV), SFunc(tIV, SBoolean)), SBoolean, Seq(STypeParam(tIV))), 6)
- val SliceMethod = SMethod(this, "slice", SFunc(IndexedSeq(SCollection(tIV), SInt, SInt), SCollection(tIV), Seq(STypeParam(tIV))), 7)
- val FilterMethod = SMethod(this, "filter", SFunc(IndexedSeq(SCollection(tIV), SFunc(tIV, SBoolean)), SCollection(tIV), Seq(STypeParam(tIV))), 8)
- val AppendMethod = SMethod(this, "append", SFunc(IndexedSeq(SCollection(tIV), SCollection(tIV)), SCollection(tIV), Seq(STypeParam(tIV))), 9)
- val ApplyMethod = SMethod(this, "apply", SFunc(IndexedSeq(SCollection(tIV), SInt), tIV, Seq(STypeParam(tIV))), 10)
-
- val methods = Seq(
+ val paramOV = STypeParam(tOV)
+ val tK = STypeIdent("K")
+ val tV = STypeIdent("V")
+ val ThisType = SCollection(tIV)
+ val tOVColl = SCollection(tOV)
+ val tPredicate = SFunc(tIV, SBoolean)
+
+ val SizeMethod = SMethod(this, "size", SFunc(ThisType, SInt), 1)
+ val GetOrElseMethod = SMethod(this, "getOrElse", SFunc(IndexedSeq(ThisType, SInt, tIV), tIV, Seq(paramIV)), 2, Some {
+ case (builder, obj, method, Seq(index, defaultValue), _) =>
+ val index1 = index.asValue[SInt.type]
+ val defaultValue1 = defaultValue.asValue[SType]
+ builder.mkByIndex(obj.asValue[SCollection[SType]], index1, Some(defaultValue1))
+ }
+ )
+ val MapMethod = SMethod(this, "map", SFunc(IndexedSeq(ThisType, SFunc(tIV, tOV)), tOVColl, Seq(paramIV, paramOV)), 3)
+ val ExistsMethod = SMethod(this, "exists", SFunc(IndexedSeq(ThisType, tPredicate), SBoolean, Seq(paramIV)), 4)
+ val FoldMethod = SMethod(this, "fold", SFunc(IndexedSeq(ThisType, tOV, SFunc(IndexedSeq(tOV, tIV), tOV)), tOV, Seq(paramIV, paramOV)), 5)
+ val ForallMethod = SMethod(this, "forall", SFunc(IndexedSeq(ThisType, tPredicate), SBoolean, Seq(paramIV)), 6)
+ val SliceMethod = SMethod(this, "slice", SFunc(IndexedSeq(ThisType, SInt, SInt), ThisType, Seq(paramIV)), 7)
+ val FilterMethod = SMethod(this, "filter", SFunc(IndexedSeq(ThisType, tPredicate), ThisType, Seq(paramIV)), 8)
+ val AppendMethod = SMethod(this, "append", SFunc(IndexedSeq(ThisType, ThisType), ThisType, Seq(paramIV)), 9)
+ val ApplyMethod = SMethod(this, "apply", SFunc(IndexedSeq(ThisType, SInt), tIV, Seq(tIV)), 10)
+ val BitShiftLeftMethod = SMethod(this, "<<",
+ SFunc(IndexedSeq(ThisType, SInt), ThisType, Seq(paramIV)), 11)
+ val BitShiftRightMethod = SMethod(this, ">>",
+ SFunc(IndexedSeq(ThisType, SInt), ThisType, Seq(paramIV)), 12)
+ val BitShiftRightZeroedMethod = SMethod(this, ">>>",
+ SFunc(IndexedSeq(SCollection(SBoolean), SInt), SCollection(SBoolean)), 13)
+ val IndicesMethod = SMethod(this, "indices", SFunc(ThisType, SCollection(SInt)), 14, MethodCallIrBuilder)
+ val FlatMapMethod = SMethod(this, "flatMap",
+ SFunc(
+ IndexedSeq(ThisType, SFunc(tIV, tOVColl)),
+ tOVColl,
+ Seq(paramIV, paramOV)),
+ 15, MethodCallIrBuilder)
+ val SegmentLengthMethod = SMethod(this, "segmentLength",
+ SFunc(IndexedSeq(ThisType, tPredicate, SInt), SInt, Seq(paramIV)),
+ 16, MethodCallIrBuilder)
+ val IndexWhereMethod = SMethod(this, "indexWhere",
+ SFunc(IndexedSeq(ThisType, tPredicate, SInt), SInt, Seq(paramIV)),
+ 17, MethodCallIrBuilder)
+ val LastIndexWhereMethod = SMethod(this, "lastIndexWhere",
+ SFunc(IndexedSeq(ThisType, tPredicate, SInt), SInt, Seq(paramIV)),
+ 18, MethodCallIrBuilder)
+ val PatchMethod = SMethod(this, "patch",
+ SFunc(IndexedSeq(ThisType, SInt, ThisType, SInt), ThisType, Seq(paramIV)),
+ 19, MethodCallIrBuilder)
+ val UpdatedMethod = SMethod(this, "updated",
+ SFunc(IndexedSeq(ThisType, SInt, tIV), ThisType, Seq(paramIV)),
+ 20, MethodCallIrBuilder)
+ val UpdateManyMethod = SMethod(this, "updateMany",
+ SFunc(IndexedSeq(ThisType, SCollection(SInt), ThisType), ThisType, Seq(paramIV)),
+ 21, MethodCallIrBuilder)
+ val UnionSetsMethod = SMethod(this, "unionSets",
+ SFunc(IndexedSeq(ThisType, ThisType), ThisType, Seq(paramIV)),
+ 22, MethodCallIrBuilder)
+ val DiffMethod = SMethod(this, "diff",
+ SFunc(IndexedSeq(ThisType, ThisType), ThisType, Seq(paramIV)),
+ 23, MethodCallIrBuilder)
+ val IntersectMethod = SMethod(this, "intersect",
+ SFunc(IndexedSeq(ThisType, ThisType), ThisType, Seq(paramIV)),
+ 24, MethodCallIrBuilder)
+ val PrefixLengthMethod = SMethod(this, "prefixLength",
+ SFunc(IndexedSeq(ThisType, tPredicate), SInt, Seq(paramIV)),
+ 25, MethodCallIrBuilder)
+ val IndexOfMethod = SMethod(this, "indexOf",
+ SFunc(IndexedSeq(ThisType, tIV, SInt), SInt, Seq(paramIV)),
+ 26, MethodCallIrBuilder)
+ val LastIndexOfMethod = SMethod(this, "lastIndexOf",
+ SFunc(IndexedSeq(ThisType, tIV, SInt), SInt, Seq(paramIV)),
+ 27, MethodCallIrBuilder)
+ lazy val FindMethod = SMethod(this, "find",
+ SFunc(IndexedSeq(ThisType, tPredicate), SOption(tIV), Seq(paramIV)),
+ 28, MethodCallIrBuilder)
+ val ZipMethod = SMethod(this, "zip",
+ SFunc(IndexedSeq(ThisType, tOVColl),
+ SCollection(STuple(tIV, tOV)), Seq(tIV, tOV)),
+ 29, MethodCallIrBuilder)
+ val DistinctMethod = SMethod(this, "distinct",
+ SFunc(IndexedSeq(ThisType), ThisType, Seq(tIV)), 30, MethodCallIrBuilder)
+ val StartsWithMethod = SMethod(this, "startsWith",
+ SFunc(IndexedSeq(ThisType, ThisType, SInt), SBoolean, Seq(paramIV)),
+ 31, MethodCallIrBuilder)
+ val EndsWithMethod = SMethod(this, "endsWith",
+ SFunc(IndexedSeq(ThisType, ThisType), SBoolean, Seq(paramIV)),
+ 32, MethodCallIrBuilder)
+ val PartitionMethod = SMethod(this, "partition",
+ SFunc(IndexedSeq(ThisType, tPredicate), STuple(ThisType, ThisType), Seq(paramIV)),
+ 33, MethodCallIrBuilder)
+ val MapReduceMethod = SMethod(this, "mapReduce",
+ SFunc(
+ IndexedSeq(ThisType, SFunc(tIV, STuple(tK, tV)), SFunc(STuple(tV, tV), tV)),
+ SCollection(STuple(tK, tV)),
+ Seq(paramIV, STypeParam(tK), STypeParam(tV))),
+ 34, MethodCallIrBuilder)
+
+ lazy val methods: Seq[SMethod] = Seq(
SizeMethod,
GetOrElseMethod,
MapMethod,
@@ -639,11 +899,35 @@ object SCollection extends STypeCompanion {
SliceMethod,
FilterMethod,
AppendMethod,
- ApplyMethod
+ ApplyMethod,
+ BitShiftLeftMethod,
+ BitShiftRightMethod,
+ BitShiftRightZeroedMethod,
+ IndicesMethod,
+ FlatMapMethod,
+ SegmentLengthMethod,
+ IndexWhereMethod,
+ LastIndexWhereMethod,
+ PatchMethod,
+ UpdatedMethod,
+ UpdateManyMethod,
+ UnionSetsMethod,
+ DiffMethod,
+ IntersectMethod,
+ PrefixLengthMethod,
+ IndexOfMethod,
+ LastIndexOfMethod,
+ FindMethod,
+ ZipMethod,
+ DistinctMethod,
+ StartsWithMethod,
+ EndsWithMethod,
+ PartitionMethod,
+ MapReduceMethod,
)
def apply[T <: SType](elemType: T): SCollection[T] = SCollectionType(elemType)
def apply[T <: SType](implicit elemType: T, ov: Overload1): SCollection[T] = SCollectionType(elemType)
- def unapply[T <: SType](tCol: SCollection[T]): Option[T] = Some(tCol.elemType)
+ def unapply[T <: SType](tColl: SCollection[T]): Option[T] = Some(tColl.elemType)
type SBooleanArray = SCollection[SBoolean.type]
type SByteArray = SCollection[SByte.type]
@@ -657,6 +941,7 @@ object SCollection extends STypeCompanion {
val SBooleanArray = SCollection(SBoolean)
val SByteArray = SCollection(SByte)
+ val SByteArray2 = SCollection(SCollection(SByte))
val SShortArray = SCollection(SShort)
val SIntArray = SCollection(SInt)
val SLongArray = SCollection(SLong)
@@ -665,27 +950,44 @@ object SCollection extends STypeCompanion {
val SSigmaPropArray = SCollection(SSigmaProp)
val SBoxArray = SCollection(SBox)
val SAvlTreeArray = SCollection(SAvlTree)
+ val SHeaderArray = SCollection(SHeader)
}
case class STuple(items: IndexedSeq[SType]) extends SCollection[SAny.type] {
import STuple._
override val typeCode = STuple.TupleTypeCode
+ override def isConstantSize: Boolean = {
+ items.forall(t => t.isConstantSize)
+ }
+
override def dataSize(v: SType#WrappedType) = {
- val arr = (v match { case col: Col[_] => col.arr case _ => v}).asInstanceOf[Array[Any]]
- assert(arr.length == items.length)
- var sum: Long = 2 // header
- for (i <- arr.indices) {
- sum += items(i).dataSize(arr(i).asInstanceOf[SType#WrappedType])
+ if (isConstantSize) {
+ var sum: Long = 2 // header
+ for (item <- items) {
+ sum += item.dataSize(v)
+ }
+ sum
+ } else {
+ val arr = (v match {
+ case col: Coll[_] => col.toArray
+ case p: Tuple2[_,_] => p.toArray
+ case _ => v
+ }).asInstanceOf[Array[Any]]
+ assert(arr.length == items.length)
+ var sum: Long = 2 // header
+ for (i <- arr.indices) {
+ sum += items(i).dataSize(arr(i).asInstanceOf[SType#WrappedType])
+ }
+ sum
}
- sum
}
override def elemType: SAny.type = SAny
- override val methods: Seq[SMethod] = {
+ protected override def getMethods() = {
val tupleMethods = Array.tabulate(items.size) { i =>
- SMethod(STuple, componentNames(i), items(i), (i + 1).toByte)
+ SMethod(STuple, componentNameByIndex(i), SFunc(this, items(i)), (i + 1).toByte)
}
colMethods ++ tupleMethods
}
@@ -716,23 +1018,31 @@ object STuple extends STypeCompanion {
def typeId = TupleTypeCode
- val colMethods = {
+ lazy val colMethods = {
val subst = Map(SCollection.tIV -> SAny)
SCollection.methods.map { m =>
- m.copy(stype = SigmaTyper.applySubst(m.stype, subst))
+ m.copy(stype = SigmaTyper.applySubst(m.stype, subst).asFunc)
}
}
def methods: Seq[SMethod] = sys.error(s"Shouldn't be called.")
def apply(items: SType*): STuple = STuple(items.toIndexedSeq)
- val componentNames = Array.tabulate(31){ i => s"_${i + 1}" }
+ val MaxTupleLength = 255
+ private val componentNames = Array.tabulate(MaxTupleLength){ i => s"_${i + 1}" }
+ def componentNameByIndex(i: Int): String =
+ try componentNames(i)
+ catch {
+ case e: IndexOutOfBoundsException =>
+ throw new IllegalArgumentException(
+ s"Tuple component '_${i+1}' is not defined: valid range (1 .. $MaxTupleLength)", e)
+ }
}
case class SFunc(tDom: IndexedSeq[SType], tRange: SType, tpeParams: Seq[STypeParam] = Nil)
extends SType with SGenericType
{
- override type WrappedType = Seq[Any] => tRange.WrappedType
+ override type WrappedType = Any => tRange.WrappedType
override val typeCode = SFunc.FuncTypeCode
override def isConstantSize = false
override def toString = {
@@ -741,13 +1051,16 @@ case class SFunc(tDom: IndexedSeq[SType], tRange: SType, tpeParams: Seq[STypePa
}
override def dataSize(v: SType#WrappedType) = 8L
import SFunc._
- val typeParams: Seq[STypeParam] = (tDom.zipWithIndex.map { case (t, i) => STypeParam(tD.name + (i + 1)) }) :+ STypeParam(tR.name)
- val tparamSubst = typeParams.zip(tDom).map { case (p, t) => p.ident.name -> t }.toMap + (tR.name -> tRange)
+ val typeParams: Seq[STypeParam] = tpeParams
+ val tparamSubst: Map[STypeIdent, SType] = Map() // defined in MethodCall.typeSubst
def getGenericType: SFunc = {
+ val typeParams: Seq[STypeParam] = tDom.zipWithIndex
+ .map { case (t, i) => STypeParam(tD.name + (i + 1)) } :+ STypeParam(tR.name)
val ts = typeParams.map(_.ident)
SFunc(ts.init.toIndexedSeq, ts.last, Nil)
}
+ def withReceiverType(objType: SType) = this.copy(tDom = objType +: tDom)
}
object SFunc {
@@ -775,11 +1088,11 @@ case class STypeIdent(name: String) extends SType {
override def toString = name
}
object STypeIdent {
- val TypeCode = 102: Byte
+ val TypeCode: TypeCode = 103: Byte
implicit def liftString(n: String): STypeIdent = STypeIdent(n)
}
-case object SBox extends SProduct with SPredefType with STypeCompanion {
+case object SBox extends SProduct with SPredefType with SMonoType {
override type WrappedType = ErgoBox
override val typeCode: TypeCode = 99: Byte
override def typeId = typeCode
@@ -796,49 +1109,105 @@ case object SBox extends SProduct with SPredefType with STypeCompanion {
override def isConstantSize = false
def ancestors = Nil
- private val tT = STypeIdent("T")
+ val tT = STypeIdent("T")
def registers(idOfs: Int): Seq[SMethod] = {
(1 to 10).map { i =>
- SMethod(this, s"R$i", SFunc(IndexedSeq(), SOption(tT), Seq(STypeParam(tT))), (idOfs + i).toByte)
+ SMethod(this, s"R$i", SFunc(IndexedSeq(SBox), SOption(tT), Seq(STypeParam(tT))), (idOfs + i).toByte)
}
}
val PropositionBytes = "propositionBytes"
val Value = "value"
val Id = "id"
val Bytes = "bytes"
- val BytesWithNoRef = "bytesWithNoRef"
+ val BytesWithoutRef = "bytesWithoutRef"
val CreationInfo = "creationInfo"
- // should be lazy to solve resursive initialization
- lazy val methods = Vector(
- SMethod(this, Value, SLong, 1), // see ExtractAmount
- SMethod(this, PropositionBytes, SCollectionType(SByte), 2), // see ExtractScriptBytes
- SMethod(this, Bytes, SCollectionType(SByte), 3), // see ExtractBytes
- SMethod(this, BytesWithNoRef, SCollectionType(SByte), 4), // see ExtractBytesWithNoRef
- SMethod(this, Id, SCollectionType(SByte), 5), // see ExtractId
- SMethod(this, CreationInfo, STuple(SInt, SCollectionType(SByte)), 6), // see ExtractCreationInfo
- SMethod(this, s"getReg", SFunc(IndexedSeq(SByte), SOption(tT), Seq(STypeParam(tT))), 7)
- ) ++ registers(7)
-}
-
-case object SAvlTree extends SProduct with SPredefType with STypeCompanion {
+ val GetReg = "getReg"
+ // should be lazy, otherwise lead to initialization error
+ lazy val creationInfoMethod = SMethod(this, CreationInfo, ExtractCreationInfo.OpType, 6) // see ExtractCreationInfo
+ lazy val getRegMethod = SMethod(this, "getReg", SFunc(IndexedSeq(SBox, SByte), SOption(tT), Seq(STypeParam(tT))), 7)
+ lazy val tokensMethod = SMethod(this, "tokens", SFunc(SBox, ErgoBox.STokensRegType), 8, MethodCallIrBuilder)
+ // should be lazy to solve recursive initialization
+ protected override def getMethods() = super.getMethods() ++ Vector(
+ SMethod(this, Value, SFunc(SBox, SLong), 1), // see ExtractAmount
+ SMethod(this, PropositionBytes, SFunc(SBox, SByteArray), 2), // see ExtractScriptBytes
+ SMethod(this, Bytes, SFunc(SBox, SByteArray), 3), // see ExtractBytes
+ SMethod(this, BytesWithoutRef, SFunc(SBox, SByteArray), 4), // see ExtractBytesWithNoRef
+ SMethod(this, Id, SFunc(SBox, SByteArray), 5), // see ExtractId
+ creationInfoMethod,
+ getRegMethod,
+ tokensMethod,
+ ) ++ registers(8)
+ override val coster = Some(Coster(_.BoxCoster))
+}
+
+case object SAvlTree extends SProduct with SPredefType with SMonoType {
override type WrappedType = AvlTreeData
override val typeCode: TypeCode = 100: Byte
override def typeId = typeCode
override def mkConstant(v: AvlTreeData): Value[SAvlTree.type] = AvlTreeConstant(v)
override def dataSize(v: SType#WrappedType): Long = {
val tree = v.asInstanceOf[AvlTreeData]
- tree.startingDigest.length +
+ AvlTreeData.DigestSize + // digest
+ 1 + // flags
4 + // keyLength
- tree.valueLengthOpt.fold(0)(_ => 4) +
- tree.maxNumOperations.fold(0)(_ => 4) +
- tree.maxDeletes.fold(0)(_ => 4)
+ tree.valueLengthOpt.fold(0)(_ => 4)
}
override def isConstantSize = false
def ancestors = Nil
- val methods = Nil
+
+ import SOption._
+ val TCollOptionCollByte = SCollection(SByteArrayOption)
+ val CollKeyValue = SCollection(STuple(SByteArray, SByteArray))
+
+ val digestMethod = SMethod(this, "digest", SFunc(this, SByteArray), 1, MethodCallIrBuilder)
+ val enabledOperationsMethod = SMethod(this, "enabledOperations", SFunc(this, SByte), 2, MethodCallIrBuilder)
+ val keyLengthMethod = SMethod(this, "keyLength", SFunc(this, SInt), 3, MethodCallIrBuilder)
+ val valueLengthOptMethod = SMethod(this, "valueLengthOpt", SFunc(this, SIntOption), 4, MethodCallIrBuilder)
+ val isInsertAllowedMethod = SMethod(this, "isInsertAllowed", SFunc(this, SBoolean), 5, MethodCallIrBuilder)
+ val isUpdateAllowedMethod = SMethod(this, "isUpdateAllowed", SFunc(this, SBoolean), 6, MethodCallIrBuilder)
+ val isRemoveAllowedMethod = SMethod(this, "isRemoveAllowed", SFunc(this, SBoolean), 7, MethodCallIrBuilder)
+
+ val updateOperationsMethod = SMethod(this, "updateOperations",
+ SFunc(IndexedSeq(SAvlTree, SByte), SAvlTreeOption), 8, MethodCallIrBuilder)
+
+ val containsMethod = SMethod(this, "contains",
+ SFunc(IndexedSeq(SAvlTree, SByteArray, SByteArray), SBoolean), 9, MethodCallIrBuilder)
+
+ val getMethod = SMethod(this, "get",
+ SFunc(IndexedSeq(SAvlTree, SByteArray, SByteArray), SByteArrayOption), 10, MethodCallIrBuilder)
+
+ val getManyMethod = SMethod(this, "getMany",
+ SFunc(IndexedSeq(SAvlTree, SByteArray2, SByteArray), TCollOptionCollByte), 11, MethodCallIrBuilder)
+
+ val insertMethod = SMethod(this, "insert",
+ SFunc(IndexedSeq(SAvlTree, CollKeyValue, SByteArray), SAvlTreeOption), 12, MethodCallIrBuilder)
+
+ val updateMethod = SMethod(this, "update",
+ SFunc(IndexedSeq(SAvlTree, CollKeyValue, SByteArray), SAvlTreeOption), 13, MethodCallIrBuilder)
+
+ val removeMethod = SMethod(this, "remove",
+ SFunc(IndexedSeq(SAvlTree, SByteArray2, SByteArray), SAvlTreeOption), 14, MethodCallIrBuilder)
+
+ protected override def getMethods(): Seq[SMethod] = super.getMethods() ++ Seq(
+ digestMethod,
+ enabledOperationsMethod,
+ keyLengthMethod,
+ valueLengthOptMethod,
+ isInsertAllowedMethod,
+ isUpdateAllowedMethod,
+ isRemoveAllowedMethod,
+ updateOperationsMethod,
+ containsMethod,
+ getMethod,
+ getManyMethod,
+ insertMethod,
+ updateMethod,
+ removeMethod
+ )
+ override val coster = Some(Coster(_.AvlTreeCoster))
}
-case object SContext extends SProduct with SPredefType with STypeCompanion {
+case object SContext extends SProduct with SPredefType with SMonoType {
override type WrappedType = ErgoLikeContext
override val typeCode: TypeCode = 101: Byte
override def typeId = typeCode
@@ -846,14 +1215,111 @@ case object SContext extends SProduct with SPredefType with STypeCompanion {
/** Approximate data size of the given context without ContextExtension. */
override def dataSize(v: SType#WrappedType): Long = {
- val ctx = v.asInstanceOf[ErgoLikeContext]
- val avlSize = SAvlTree.dataSize(ctx.lastBlockUtxoRoot.asWrappedType)
- val inputSize = ctx.boxesToSpend.foldLeft(0L)((acc, b) => acc + b.dataSize)
- val outputSize = ctx.spendingTransaction.outputs.foldLeft(0L)((acc, b) => acc + b.dataSize)
- 8L + // Height
- avlSize + ctx.minerPubkey.length + inputSize + outputSize
+ sys.error(s"Should not be used, use SizeContext and Sized typeclass instead")
}
override def isConstantSize = false
def ancestors = Nil
- val methods = Nil
+
+ val tT = STypeIdent("T")
+ val dataInputsMethod = property("dataInputs", SBoxArray, 1)
+ val headersMethod = property("headers", SHeaderArray, 2)
+ val preHeaderMethod = property("preHeader", SPreHeader, 3)
+ val inputsMethod = property("INPUTS", SBoxArray, 4)
+ val outputsMethod = property("OUTPUTS", SBoxArray, 5)
+ val heightMethod = property("HEIGHT", SInt, 6)
+ val selfMethod = property("SELF", SBox, 7)
+ val selfBoxIndexMethod = property("selfBoxIndex", SInt, 8)
+ val lastBlockUtxoRootHashMethod = property("LastBlockUtxoRootHash", SAvlTree, 9)
+ val minerPubKeyMethod = property("minerPubKey", SByteArray, 10)
+ val getVarMethod = SMethod(this, "getVar", SFunc(IndexedSeq(SContext, SByte), SOption(tT), Seq(STypeParam(tT))), 11)
+
+ protected override def getMethods() = super.getMethods() ++ Seq(
+ dataInputsMethod, headersMethod, preHeaderMethod, inputsMethod, outputsMethod, heightMethod, selfMethod,
+ selfBoxIndexMethod, lastBlockUtxoRootHashMethod, minerPubKeyMethod, getVarMethod
+ )
+ override val coster = Some(Coster(_.ContextCoster))
+}
+
+case object SHeader extends SProduct with SPredefType with SMonoType {
+ override type WrappedType = Header
+ override val typeCode: TypeCode = 104: Byte
+ override def typeId = typeCode
+ override def mkConstant(v: Header): Value[SHeader.type] = HeaderConstant(v)
+
+ /** Approximate data size of the given context without ContextExtension. */
+ override def dataSize(v: SType#WrappedType): Long = {
+ hashLength + // parentId
+ 1 + // version
+ hashLength + // parentId
+ hashLength + // ADProofsRoot
+ AvlTreeData.TreeDataSize +
+ hashLength + // transactionsRoot
+ 8 + // timestamp
+ 8 + // nBits
+ 4 + // height
+ hashLength + // extensionRoot
+ CryptoConstants.EncodedGroupElementLength + // minerPk
+ CryptoConstants.EncodedGroupElementLength + // powOnetimePk,
+ 8 + // powNonce
+ SBigInt.dataSize(0.asWrappedType) + // powDistance
+ 3 // votes
+ }
+ override def isConstantSize = true
+ def ancestors = Nil
+
+ val idMethod = property("id", SByteArray, 1)
+ val versionMethod = property("version", SByte, 2)
+ val parentIdMethod = property("parentId", SByteArray, 3)
+ val ADProofsRootMethod = property("ADProofsRoot", SByteArray, 4)
+ val stateRootMethod = property("stateRoot", SAvlTree, 5)
+ val transactionsRootMethod = property("transactionsRoot", SByteArray, 6)
+ val timestampMethod = property("timestamp", SLong, 7)
+ val nBitsMethod = property("nBits", SLong, 8)
+ val heightMethod = property("height", SInt, 9)
+ val extensionRootMethod = property("extensionRoot", SByteArray, 10)
+ val minerPkMethod = property("minerPk", SGroupElement, 11)
+ val powOnetimePkMethod = property("powOnetimePk", SGroupElement, 12)
+ val powNonceMethod = property("powNonce", SByteArray, 13)
+ val powDistanceMethod = property("powDistance", SBigInt, 14)
+ val votesMethod = property("votes", SByteArray, 15)
+
+ protected override def getMethods() = super.getMethods() ++ Seq(
+ idMethod, versionMethod, parentIdMethod, ADProofsRootMethod, stateRootMethod, transactionsRootMethod,
+ timestampMethod, nBitsMethod, heightMethod, extensionRootMethod, minerPkMethod, powOnetimePkMethod,
+ powNonceMethod, powDistanceMethod, votesMethod
+ )
+ override val coster = Some(Coster(_.HeaderCoster))
+}
+
+case object SPreHeader extends SProduct with SPredefType with SMonoType {
+ override type WrappedType = PreHeader
+ override val typeCode: TypeCode = 105: Byte
+ override def typeId = typeCode
+ override def mkConstant(v: PreHeader): Value[SPreHeader.type] = PreHeaderConstant(v)
+
+ /** Approximate data size of the given context without ContextExtension. */
+ override def dataSize(v: SType#WrappedType): Long = {
+ 1 + // version
+ hashLength + // parentId
+ 8 + // timestamp
+ 8 + // nBits
+ 4 + // height
+ CryptoConstants.EncodedGroupElementLength + // minerPk
+ 3 // votes
+ }
+ override def isConstantSize = true
+ def ancestors = Nil
+
+ val versionMethod = property("version", SByte, 1)
+ val parentIdMethod = property("parentId", SByteArray, 2)
+ val timestampMethod = property("timestamp", SLong, 3)
+ val nBitsMethod = property("nBits", SLong, 4)
+ val heightMethod = property("height", SInt, 5)
+ val minerPkMethod = property("minerPk", SGroupElement, 6)
+ val votesMethod = property("votes", SByteArray, 7)
+
+ protected override def getMethods() = super.getMethods() ++ Seq(
+ versionMethod, parentIdMethod, timestampMethod, nBitsMethod, heightMethod, minerPkMethod, votesMethod
+ )
+ override val coster = Some(Coster(_.PreHeaderCoster))
}
diff --git a/src/main/scala/sigmastate/utils/ByteArrayBuilder.java b/src/main/scala/sigmastate/utils/ByteArrayBuilder.java
deleted file mode 100644
index 3d47077141..0000000000
--- a/src/main/scala/sigmastate/utils/ByteArrayBuilder.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package sigmastate.utils;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-
-/** Similar to StringBuilder but works with underlying Array[Byte].
-* Borrowed from https://github.com/odnoklassniki/one-nio/blob/master/src/one/nio/util/ByteArrayBuilder.java
-* Modifications of the underlying array is performed via ByteBuffer wrapper, so that saved bytes can
-* be read back via ByteBuffer API. */
-public class ByteArrayBuilder {
-
- protected byte[] arr;
- protected ByteBuffer buf;
-
- public ByteArrayBuilder() {
- this(256);
- }
-
- public ByteArrayBuilder(int capacity) {
- this.arr = new byte[capacity];
- this.buf = ByteBuffer.wrap(this.arr);
- }
-
- public final byte[] array() {
- return arr;
- }
-
- public final int length() {
- return buf.position();
- }
-
- public final void setLength(int newPosition) {
- buf.position(newPosition);
- }
-
- public final int capacity() {
- return arr.length;
- }
-
- public final byte byteAt(int index) {
- return arr[index];
- }
-
- public final void crop(int offset) {
- int count = buf.position();
- if (offset < count) {
- count -= offset;
- System.arraycopy(arr, offset, arr, 0, count);
- } else {
- count = 0;
- }
- }
-
- public final byte[] trim() {
- int count = buf.position();
- if (arr.length > count) {
- arr = Arrays.copyOf(arr, count);
- buf = ByteBuffer.wrap(arr);
- }
- return arr;
- }
-
- public final byte[] toBytes() {
- int count = buf.position();
- byte[] result = new byte[count];
- System.arraycopy(arr, 0, result, 0, count);
- return result;
- }
-
- public final ByteArrayBuilder append(byte b) {
- ensureCapacity(1);
- buf.put(b);
- return this;
- }
-
- public final ByteArrayBuilder append(byte[] b) {
- return append(b, 0, b.length);
- }
-
- public final ByteArrayBuilder append(byte[] b, int offset, int length) {
- ensureCapacity(length);
- buf.put(b, offset, length);
- return this;
- }
-
- public final ByteArrayBuilder append(boolean b) {
- append((byte)(b ? 0x01 : 0x00));
- return this;
- }
-
- public final ByteArrayBuilder append(char c) {
- ensureCapacity(1);
- buf.putChar(c);
- return this;
- }
-
- public final ByteArrayBuilder append(short n) {
- ensureCapacity(2);
- buf.putShort(n);
- return this;
- }
-
- public final ByteArrayBuilder append(int n) {
- ensureCapacity(4);
- buf.putInt(n);
- return this;
- }
-
- public final ByteArrayBuilder append(long n) {
- ensureCapacity(8);
- buf.putLong(n);
- return this;
- }
-
- private void ensureCapacity(int required) {
- int count = buf.position();
- if (count + required > arr.length) {
- arr = Arrays.copyOf(arr, Math.max(count + required, arr.length << 1));
- newBuffer(arr);
- }
- }
-
- private void newBuffer(byte[] newArr) {
- ByteBuffer newBuf = ByteBuffer.wrap(newArr);
- newBuf.position(buf.position());
- buf = newBuf;
- }
-
-}
diff --git a/src/main/scala/sigmastate/utils/ByteReader.scala b/src/main/scala/sigmastate/utils/ByteReader.scala
index c67cb12238..e69de29bb2 100644
--- a/src/main/scala/sigmastate/utils/ByteReader.scala
+++ b/src/main/scala/sigmastate/utils/ByteReader.scala
@@ -1,206 +0,0 @@
-package sigmastate.utils
-
-import java.nio.ByteBuffer
-import java.util._
-
-import sigmastate.utils.Extensions._
-import sigmastate.utils.ByteBufferReader.decodeZigZagLong
-
-trait ByteReader {
-
- /**
- * Get a byte at current position without advancing the position.
- * @return byte at current position
- */
- def peekByte(): Byte
- def getByte(): Byte
- def getUByte(): Int
- def getShort(): Short
-
- /**
- * Decode positive Short.
- * Use '''only''' for values previously encoded with [[ByteArrayWriter.putUShort]]
- * @return signed Int
- */
- def getUShort(): Int
-
- /**
- * Decode signed Int.
- * Use '''only''' for values previously encoded with [[ByteArrayWriter.putInt]]
- * @return signed Int
- */
- def getInt(): Int
-
- /**
- * Decode positive Int.
- * Use '''only''' for values previously encoded with [[ByteArrayWriter.putUInt]]
- * @return signed Long
- */
- def getUInt(): Long
-
- /**
- * Decode signed Long.
- * Use '''only''' for values previously encoded with [[ByteArrayWriter.putLong]]
- * @return signed Long
- */
- def getLong(): Long
-
- /**
- * Decode positive Long.
- * Use '''only''' for values previously encoded with [[ByteArrayWriter.putULong]]
- * @return signed Long
- */
- def getULong(): Long
-
- def getBytes(size: Int): Array[Byte]
-
- /**
- * Decode array of boolean values previously encode with [[ByteArrayWriter.putBits]]
- * @param size expected size of decoded array
- * @return decoded array of boolean values
- */
- def getBits(size: Int): Array[Boolean]
- def getOption[T](getValue: => T): Option[T]
- def mark(): ByteReader
- def consumed: Int
- def position: Int
- def position_=(p: Int)
- def remaining: Int
- def level: Int
- def level_=(v: Int)
-}
-
-/**
- * Not thread safe
- */
-class ByteBufferReader(buf: ByteBuffer) extends ByteReader {
-
- @inline override def peekByte(): Byte = buf.array()(buf.position())
- @inline override def getByte(): Byte = buf.get
- @inline override def getUByte(): Int = buf.get & 0xFF
- @inline override def getShort(): Short = buf.getShort()
-
- /**
- * Decode Short previously encoded with [[ByteArrayWriter.putUShort]] using VLQ.
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @return Int
- * @throws AssertionError for deserialized values not in unsigned Short range
- */
- @inline override def getUShort(): Int = {
- val x = getULong().toInt
- assert(x >= 0 && x <= 0xFFFF, s"$x is out of unsigned short range")
- x
- }
-
- /**
- * Decode signed Int previously encoded with [[ByteArrayWriter.putInt]] using VLQ with ZigZag.
- *
- * @note Uses ZigZag encoding. Should be used to decode '''only''' a value that was previously
- * encoded with [[ByteArrayWriter.putInt]].
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @return signed Int
- */
- @inline override def getInt(): Int =
- // should only be changed simultaneously with `putInt`
- ByteBufferReader.decodeZigZagInt(getULong().toInt)
-
- /**
- * Decode Int previously encoded with [[ByteArrayWriter.putUInt]] using VLQ.
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @return Long
- */
- @inline override def getUInt(): Long = {
- val x = getULong()
- assert(x >= 0L && x <= 0xFFFFFFFFL, s"$x is out of unsigned int range")
- x
- }
-
- /**
- * Decode signed Long previously encoded with [[ByteArrayWriter.putLong]] using VLQ with ZigZag.
- *
- * @note Uses ZigZag encoding. Should be used to decode '''only''' a value that was previously
- * encoded with [[ByteArrayWriter.putLong]].
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @return signed Long
- */
- @inline override def getLong(): Long = decodeZigZagLong(getULong())
-
- /**
- * Decode Long previously encoded with [[ByteArrayWriter.putULong]] using VLQ.
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @return Long
- */
- @inline override def getULong(): Long = {
- // should be fast if java -> scala conversion did not botched it
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/main/java/com/google/protobuf/CodedInputStream.java#L2653
- // for faster version see: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/main/java/com/google/protobuf/CodedInputStream.java#L1085
- var result: Long = 0
- var shift = 0
- while (shift < 64) {
- val b = buf.get()
- result = result | ((b & 0x7F).toLong << shift)
- if ((b & 0x80) == 0) return result
- shift += 7
- }
- sys.error(s"Cannot deserialize Long value. Unexpected buffer $buf with bytes remaining ${buf.getBytes(buf.remaining)}")
- // see https://rosettacode.org/wiki/Variable-length_quantity for implementations in other languages
- }
-
- @inline override def getBytes(size: Int): Array[Byte] = buf.getBytes(size)
-
- @inline override def getBits(size: Int): Array[Boolean] = {
- if (size == 0) return Array[Boolean]()
- val bitSet = BitSet.valueOf(buf.getBytes((size + 7) / 8))
- val boolArray = new Array[Boolean](size)
- var i = 0
- while (i < size) {
- boolArray(i) = bitSet.get(i)
- i += 1
- }
- boolArray
- }
-
- @inline override def getOption[T](getValue: => T): Option[T] = buf.getOption(getValue)
-
- private var _mark: Int = _
- @inline override def mark(): ByteReader = {
- _mark = buf.position()
- this
- }
- @inline override def consumed: Int = buf.position() - _mark
-
- @inline override def position: Int = buf.position()
-
- @inline override def position_=(p: Int): Unit = buf.position(p)
-
- @inline override def remaining: Int = buf.remaining()
-
- private var lvl: Int = 0
- @inline override def level: Int = lvl
- @inline override def level_=(v: Int): Unit = lvl = v
-}
-
-object ByteBufferReader {
-
- /**
- * Decode a signed value previously ZigZag-encoded with [[ByteArrayWriter.encodeZigZagInt]]
- *
- * @see [[https://developers.google.com/protocol-buffers/docs/encoding#types]]
- * @param n unsigned Int previously encoded with [[ByteArrayWriter.encodeZigZagInt]]
- * @return signed Int
- */
- def decodeZigZagInt(n: Int): Int =
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/main/java/com/google/protobuf/CodedInputStream.java#L553
- (n >>> 1) ^ -(n & 1)
-
- /**
- * Decode a signed value previously ZigZag-encoded with [[ByteArrayWriter.encodeZigZagLong]]
- *
- * @see [[https://developers.google.com/protocol-buffers/docs/encoding#types]]
- * @param n unsigned Long previously encoded with [[ByteArrayWriter.encodeZigZagLong]]
- * @return signed Long
- */
- def decodeZigZagLong(n: Long): Long =
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/main/java/com/google/protobuf/CodedInputStream.java#L566
- (n >>> 1) ^ -(n & 1)
-}
diff --git a/src/main/scala/sigmastate/utils/ByteWriter.scala b/src/main/scala/sigmastate/utils/ByteWriter.scala
index 77d5e6397f..e69de29bb2 100644
--- a/src/main/scala/sigmastate/utils/ByteWriter.scala
+++ b/src/main/scala/sigmastate/utils/ByteWriter.scala
@@ -1,227 +0,0 @@
-package sigmastate.utils
-
-import java.util._
-
-import sigmastate.utils.ByteArrayWriter.{encodeZigZagInt, encodeZigZagLong}
-import sigmastate.utils.Extensions._
-
-trait ByteWriter {
- def put(x: Byte): this.type
-
- /** Encode integer as an unsigned byte asserting the range check
- * @param x integer value to encode
- * @return
- * @throws AssertionError if x is outside of the unsigned byte range
- */
- def putUByte(x: Int): this.type = {
- assert(x >= 0 && x <= 0xFF, s"$x is out of unsigned byte range")
- put(x.toByte)
- }
- def putBoolean(x: Boolean): this.type
- def putShort(x: Short): this.type
-
- /**
- * Encode Short that are positive
- *
- * Use [[putShort]] to encode values that might be negative.
- * @param x Short
- */
- def putUShort(x: Int): this.type
-
- /**
- * Encode signed Int.
- * Use [[putUInt]] to encode values that are positive.
- *
- * @param x Int
- */
- def putInt(x: Int): this.type
-
- /**
- * Encode Int that are positive.
- * Use [[putInt]] to encode values that might be negative.
- *
- * @param x Int
- */
- def putUInt(x: Long): this.type
-
- /**
- * Encode signed Long.
- * Use [[putULong]] to encode values that are positive.
- *
- * @param x Long
- */
- def putLong(x: Long): this.type
-
- /**
- * Encode Long that are positive.
- * Use [[putLong]] to encode values that might be negative.
- *
- * @param x Long
- */
- def putULong(x: Long): this.type
-
- def putBytes(xs: Array[Byte]): this.type
-
- /**
- * Encode an array of boolean values as a bit array
- *
- * @param xs array of boolean values
- */
- def putBits(xs: Array[Boolean]): this.type
- def putOption[T](x: Option[T])(putValue: (this.type, T) => Unit): this.type
- def toBytes: Array[Byte]
-}
-
-/**
- * Not thread safe
- */
-class ByteArrayWriter(b: ByteArrayBuilder) extends ByteWriter {
- @inline override def put(x: Byte): this.type = { b.append(x); this }
- @inline override def putBoolean(x: Boolean): this.type = { b.append(x); this }
- @inline override def putShort(x: Short): this.type = { b.append(x); this }
-
- /**
- * Encode unsigned Short value using VLQ.
- * Only positive values are supported, Use [[putShort]]
- * to encode negative and positive values.
- *
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @param x unsigned Short
- * @throws AssertionError for values not in unsigned Short range
- */
- @inline override def putUShort(x: Int): this.type = {
- assert(x >= 0 && x <= 0xFFFF, s"$x is out of unsigned short range")
- putUInt(x)
- }
-
-
- /**
- * Encode signed Int using VLQ with ZigZag.
- * Both negative and positive values are supported, but due to ZigZag encoding positive
- * values is done less efficiently than by [[putUInt]].
- * Use [[putUInt]] to encode values that are positive.
- *
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @note Have to be decoded '''only''' with [[ByteBufferReader.getInt]]
- * The resulting varint uses ZigZag encoding, which is much more efficient at
- * encoding negative values than pure VLQ.
- * @param x prefer signed Int
- */
- @inline override def putInt(x: Int): this.type = putULong(encodeZigZagInt(x))
-
- /**
- * Encode unsigned Int value using VLQ.
- * Only positive values are supported. Use [[putInt]]
- * to encode negative and positive values.
- *
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @param x unsigned Int
- * @throws AssertionError for values not in unsigned Int range
- */
- @inline override def putUInt(x: Long): this.type = {
- assert(x >= 0 && x <= 0xFFFFFFFFL, s"$x is out of unsigned int range")
- putULong(x)
- }
-
- /**
- * Encode signed Long using VLQ with ZigZag.
- * Both negative and positive values are supported, but due to ZigZag encoding positive
- * values is done less efficiently than by [[putULong]].
- * Use [[putULong]] to encode values that are positive.
- *
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @note Have to be decoded '''only''' with [[ByteBufferReader.getLong]]
- * The resulting varint uses ZigZag encoding, which is much more efficient at
- * encoding negative values than pure VLQ.
- * @param x prefer signed Long
- */
- @inline override def putLong(x: Long): this.type = putULong(encodeZigZagLong(x))
-
- /**
- * Encode signed Long value using VLQ.
- * Both negative and positive values are supported, but only positive values are encoded
- * efficiently, negative values are taking a toll and use six bytes. Use [[putLong]]
- * to encode negative and positive values.
- *
- * @see [[https://en.wikipedia.org/wiki/Variable-length_quantity]]
- * @note Don't use it for negative values, the resulting varint is always ten
- * bytes long – it is, effectively, treated like a very large unsigned integer.
- * If you use [[putLong]], the resulting varint uses ZigZag encoding,
- * which is much more efficient.
- * @param x prefer unsigned Long (signed value will produce a significant overhead,
- * see note above)
- */
- @inline override def putULong(x: Long): this.type = {
- val buffer = new Array[Byte](10) // TODO optimize allocation by removing this buffer, it seems to not necessary
- var position = 0
- var value = x
- // should be fast if java -> scala conversion did not botched it
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java#L1387
- while (true) {
- if ((value & ~0x7FL) == 0) {
- buffer(position) = value.asInstanceOf[Byte]
- position += 1
- b.append(Arrays.copyOf(buffer, position))
- return this
- } else {
- buffer(position) = ((value.asInstanceOf[Int] & 0x7F) | 0x80).toByte
- position += 1
- value >>>= 7
- }
- }
- this
- // see https://rosettacode.org/wiki/Variable-length_quantity for implementations in other languages
- }
-
- @inline override def putBytes(xs: Array[Byte]): this.type = { b.append(xs); this }
-
- @inline override def putBits(xs: Array[Boolean]): this.type = {
- if (xs.isEmpty) return this
- val bitSet = new BitSet(xs.length)
- xs.zipWithIndex.foreach { case (bool, i) => bitSet.set(i, bool)}
- // pad the byte array to fix the "no bit was set" behaviour
- // see https://stackoverflow.com/questions/11209600/how-do-i-convert-a-bitset-initialized-with-false-in-a-byte-containing-0-in-java
- val bytes = Arrays.copyOf(bitSet.toByteArray, (xs.length + 7) / 8)
- b.append(bytes)
- this
- }
-
- @inline override def putOption[T](x: Option[T])(putValue: (this.type, T) => Unit): this.type = { b.appendOption(x)(v => putValue(this, v)); this }
-
- @inline override def toBytes: Array[Byte] = b.toBytes
-}
-
-object ByteArrayWriter {
-
- /**
- * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers
- * into values that can be efficiently encoded with varint. (Otherwise,
- * negative values must be sign-extended to 64 bits to be varint encoded,
- * thus always taking 10 bytes on the wire.)
- *
- * @see [[https://developers.google.com/protocol-buffers/docs/encoding#types]]
- *
- * @param n signed Int
- * @return unsigned Int stored in a signed Int
- */
- def encodeZigZagInt(n: Int): Int =
- // Note: the right-shift must be arithmetic
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java#L934
- (n << 1) ^ (n >> 31)
-
- /**
- * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers
- * into values that can be efficiently encoded with varint. (Otherwise,
- * negative values must be sign-extended to 64 bits to be varint encoded,
- * thus always taking 10 bytes on the wire.)
- *
- * @see [[https://developers.google.com/protocol-buffers/docs/encoding#types]]
- * @param n signed Long
- * @return unsigned Long stored in a signed Long
- */
- def encodeZigZagLong(n: Long): Long =
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java#L949
- // Note: the right-shift must be arithmetic
- (n << 1) ^ (n >> 63)
-
-}
diff --git a/src/main/scala/sigmastate/utils/Extensions.scala b/src/main/scala/sigmastate/utils/Extensions.scala
deleted file mode 100644
index c023c54edd..0000000000
--- a/src/main/scala/sigmastate/utils/Extensions.scala
+++ /dev/null
@@ -1,174 +0,0 @@
-package sigmastate.utils
-
-import java.nio.ByteBuffer
-
-import sigmastate.SType
-import sigmastate.Values.{SValue, Value}
-import sigmastate.serialization.{TypeSerializer, ValueSerializer}
-
-import scala.collection.generic.CanBuildFrom
-import scala.language.higherKinds
-import scala.reflect.ClassTag
-
-object Extensions {
-
- implicit class ByteOps(val b: Byte) extends AnyVal {
- @inline def toUByte: Int = b & 0xFF
- def addExact(b2: Byte): Byte = {
- val r = b + b2
- if (r < Byte.MinValue || r > Byte.MaxValue)
- throw new ArithmeticException("Byte overflow")
- r.toByte
- }
-
- def subtractExact(b2: Byte): Byte = {
- val r = b - b2
- if (r < Byte.MinValue || r > Byte.MaxValue)
- throw new ArithmeticException("Byte overflow")
- r.toByte
- }
-
- def multiplyExact(b2: Byte): Byte = {
- val r = b * b2
- if (r < Byte.MinValue || r > Byte.MaxValue)
- throw new ArithmeticException("Byte overflow")
- r.toByte
- }
- }
-
- implicit class ShortOps(val x: Short) extends AnyVal {
- def toByteExact: Byte = {
- if (x < Byte.MinValue || x > Byte.MaxValue)
- throw new ArithmeticException("Byte overflow")
- x.toByte
- }
-
- def addExact(y: Short): Short = {
- val r = x + y
- if (r < Short.MinValue || r > Short.MaxValue)
- throw new ArithmeticException("Short overflow")
- r.toShort
- }
-
- def subtractExact(y: Short): Short = {
- val r = x - y
- if (r < Short.MinValue || r > Short.MaxValue)
- throw new ArithmeticException("Short overflow")
- r.toShort
- }
-
- def multiplyExact(y: Short): Short = {
- val r = x * y
- if (r < Short.MinValue || r > Short.MaxValue)
- throw new ArithmeticException("Short overflow")
- r.toShort
- }
- }
-
- implicit class IntOps(val x: Int) extends AnyVal {
- def toByteExact: Byte = {
- if (x < Byte.MinValue || x > Byte.MaxValue)
- throw new ArithmeticException("Byte overflow")
- x.toByte
- }
-
- def toShortExact: Short = {
- if (x < Short.MinValue || x > Short.MaxValue)
- throw new ArithmeticException("Short overflow")
- x.toShort
- }
- }
-
- implicit class LongOps(val x: Long) extends AnyVal {
- def toByteExact: Byte = {
- if (x < Byte.MinValue || x > Byte.MaxValue)
- throw new ArithmeticException("Byte overflow")
- x.toByte
- }
-
- def toShortExact: Short = {
- if (x < Short.MinValue || x > Short.MaxValue)
- throw new ArithmeticException("Short overflow")
- x.toShort
- }
-
- def toIntExact: Int = {
- if (x < Int.MinValue || x > Int.MaxValue)
- throw new ArithmeticException("Int overflow")
- x.toInt
- }
- }
-
- implicit class OptionOps[T](val opt: Option[T]) extends AnyVal {
- /** Elvis operator for Option. See https://en.wikipedia.org/wiki/Elvis_operator*/
- def ?:(whenNone: => T): T = if (opt.isDefined) opt.get else whenNone
- }
-
- implicit class TraversableOps[A, Source[X] <: Traversable[X]](val xs: Source[A]) extends AnyVal {
-
- /** Applies 'f' to elements of 'xs' until 'f' returns Some(b),
- * which is immediately returned as result of this method.
- * If not such element found, returns None as result. */
- def findMap[B](f: A => Option[B]): Option[B] = {
- for (x <- xs) {
- val y = f(x)
- if (y.isDefined) return y
- }
- None
- }
-
- def cast[B:ClassTag](implicit cbf: CanBuildFrom[Source[A], B, Source[B]]): Source[B] = {
- for (x <- xs) {
- assert(x match { case _: B => true case _ => false}, s"Value $x doesn't conform to type ${reflect.classTag[B]}")
- }
- xs.asInstanceOf[Source[B]]
- }
-
- def filterMap[B](f: A => Option[B])(implicit cbf: CanBuildFrom[Source[A], B, Source[B]]): Source[B] = {
- val b = cbf()
- for (x <- xs) {
- f(x) match {
- case Some(y) =>
- b += y
- case None =>
- }
- }
- b.result()
- }
- }
-
- implicit class ByteArrayBuilderOps(val b: ByteArrayBuilder) extends AnyVal {
- def appendOption[T](opt: Option[T])(putValue: T => Unit): ByteArrayBuilder = {
- opt match {
- case Some(v) =>
- b.append(1.toByte)
- putValue(v)
- b
- case None =>
- b.append(0.toByte)
- }
- }
- }
-
- implicit class ByteBufferOps(val buf: ByteBuffer) extends AnyVal {
- def toBytes: Array[Byte] = {
- val res = new Array[Byte](buf.position())
- buf.array().copyToArray(res, 0, res.length)
- res
- }
- def getBytes(size: Int): Array[Byte] = {
- val res = new Array[Byte](size)
- buf.get(res)
- res
- }
- def getOption[T](getValue: => T): Option[T] = {
- val tag = buf.get()
- if (tag != 0)
- Some(getValue)
- else
- None
- }
- }
-
-}
-
diff --git a/src/main/scala/sigmastate/utils/Helpers.scala b/src/main/scala/sigmastate/utils/Helpers.scala
index fb311f738d..ae7c42a2fa 100644
--- a/src/main/scala/sigmastate/utils/Helpers.scala
+++ b/src/main/scala/sigmastate/utils/Helpers.scala
@@ -7,9 +7,31 @@ import scala.reflect.ClassTag
object Helpers {
def xor(ba1: Array[Byte], ba2: Array[Byte]): Array[Byte] = ba1.zip(ba2).map(t => (t._1 ^ t._2).toByte)
+ /** Same as `xor` but makes in-place update of the first argument (hence suffix `U`)
+ * This is boxing-free version.
+ * @return reference to the updated first argument to easy chaining of calls. */
+ def xorU(ba1: Array[Byte], ba2: Array[Byte]): Array[Byte] = {
+ var i = 0
+ while (i < ba1.length) {
+ ba1(i) = (ba1(i) ^ ba2(i)).toByte
+ i += 1
+ }
+ ba1
+ }
+
def xor(bas: Array[Byte]*): Array[Byte] =
bas.reduce({case (ba, ba1) => xor(ba, ba1)}: ((Array[Byte], Array[Byte]) => Array[Byte]))
+ /** Same as `xor` but makes in-place update of the first argument (hence suffix `U`)
+ * This is boxing-free version.
+ * @return reference to the updated first argument to easy chaining of calls. */
+ def xorU(target: Array[Byte], xss: Seq[Array[Byte]]): Array[Byte] = {
+ for (xs <- xss) {
+ xorU(target, xs)
+ }
+ target
+ }
+
def anyOf(arr: Array[Boolean]): Boolean = arr.exists(identity)
def allOf(arr: Array[Boolean]): Boolean = arr.forall(identity)
@@ -54,20 +76,6 @@ object Helpers {
case _ => false
}
- /**
- * Helper to construct a byte array from a bunch of bytes. The inputs are actually ints so that I
- * can use hex notation and not get stupid errors about precision.
- */
- def bytesFromInts(bytesAsInts: Int*): Array[Byte] = {
- val a = new Array[Byte](bytesAsInts.length)
- for (i <- a.indices) {
- val v = bytesAsInts(i)
- // values from unsigned byte range will be encoded as negative values which is expected here
- assert(v >= Byte.MinValue && v <= 0xFF, s"$v is out of the signed/unsigned Byte range")
- a(i) = v.toByte
- }
- a
- }
}
object Overloading {
diff --git a/src/main/scala/sigmastate/utils/SigmaByteReader.scala b/src/main/scala/sigmastate/utils/SigmaByteReader.scala
index 9c71f2829a..07b826505f 100644
--- a/src/main/scala/sigmastate/utils/SigmaByteReader.scala
+++ b/src/main/scala/sigmastate/utils/SigmaByteReader.scala
@@ -2,25 +2,72 @@ package sigmastate.utils
import java.nio.ByteBuffer
+import scorex.util.serialization.{Reader, VLQByteBufferReader}
import sigmastate.SType
import sigmastate.Values.SValue
-import sigmastate.serialization.{ValDefTypeStore, TypeSerializer, ValueSerializer, ConstantStore}
-import sigmastate.utils.Extensions._
+import sigmastate.serialization.{ConstantStore, TypeSerializer, ValDefTypeStore, ValueSerializer}
+import scorex.util.Extensions._
-class SigmaByteReader(b: ByteBuffer,
+class SigmaByteReader(val r: Reader,
var constantStore: ConstantStore,
var resolvePlaceholdersToConstants: Boolean)
- extends ByteBufferReader(b) {
+ extends Reader {
val valDefTypeStore: ValDefTypeStore = new ValDefTypeStore()
- @inline override def mark(): SigmaByteReader = {
- super.mark()
+
+ override type CH = r.CH
+
+ @inline
+ override def newReader(chunk: CH): Reader.Aux[CH] = r.newReader(chunk)
+
+ @inline override def getChunk(size: Int): CH = r.getChunk(size)
+
+ @inline override def getShortString(): String = r.getShortString()
+
+ @inline override def peekByte(): Byte = r.peekByte()
+
+ @inline override def getByte(): Byte = r.getByte()
+
+ @inline override def getUByte(): Int = r.getUByte()
+
+ @inline override def getShort(): Short = r.getShort()
+
+ @inline override def getUShort(): Int = r.getUShort()
+
+ @inline override def getInt(): Int = r.getInt()
+
+ @inline override def getUInt(): Long = r.getUInt()
+
+ @inline override def getLong(): Long = r.getLong()
+
+ @inline override def getULong(): Long = r.getULong()
+
+ @inline override def getBytes(size: Int): Array[Byte] = r.getBytes(size)
+
+ @inline override def getBits(size: Int): Array[Boolean] = r.getBits(size)
+
+ @inline override def getOption[T](getValue: => T): Option[T] = r.getOption(getValue)
+
+ @inline override def consumed: Int = r.consumed
+
+ @inline override def position: Int = r.position
+
+ @inline override def position_=(p: Int): Unit = r.position_=(p)
+
+ @inline override def remaining: Int = r.remaining
+
+ @inline override def mark(): this.type = {
+ r.mark()
this
}
@inline def getType(): SType = TypeSerializer.deserialize(this)
@inline def getValue(): SValue = ValueSerializer.deserialize(this)
+
+ private var lvl: Int = 0
+ @inline def level: Int = lvl
+ @inline def level_=(v: Int): Unit = lvl = v
@inline def getValues(): IndexedSeq[SValue] = {
val size = getUInt().toIntExact
val xs = new Array[SValue](size)
diff --git a/src/main/scala/sigmastate/utils/SigmaByteWriter.scala b/src/main/scala/sigmastate/utils/SigmaByteWriter.scala
index df8ba9e01d..96377e8176 100644
--- a/src/main/scala/sigmastate/utils/SigmaByteWriter.scala
+++ b/src/main/scala/sigmastate/utils/SigmaByteWriter.scala
@@ -1,17 +1,65 @@
package sigmastate.utils
+import scorex.util.serialization.{VLQByteStringWriter, VLQByteBufferWriter, Writer}
+import scorex.util.serialization.Writer.Aux
import sigmastate.SType
import sigmastate.Values.Value
-import sigmastate.serialization.{ConstantStore, TypeSerializer, ValueSerializer}
+import sigmastate.serialization.{TypeSerializer, ValueSerializer, ConstantStore}
-class SigmaByteWriter(b: ByteArrayBuilder,
- val constantExtractionStore: Option[ConstantStore]) extends ByteArrayWriter(b) {
+class SigmaByteWriter(val w: Writer,
+ val constantExtractionStore: Option[ConstantStore]) extends Writer {
- @inline def putType[T <: SType](x: T): SigmaByteWriter = { TypeSerializer.serialize(x, this); this }
- @inline def putValue[T <: SType](x: Value[T]): SigmaByteWriter = { ValueSerializer.serialize(x, this); this }
- @inline def putValues[T <: SType](xs: Seq[Value[T]]): SigmaByteWriter = {
+ type CH = w.CH
+
+ @inline override def length(): Int = w.length()
+
+ @inline override def newWriter(): Aux[CH] = w.newWriter()
+
+ @inline override def putChunk(chunk: CH): this.type = { w.putChunk(chunk); this }
+
+ @inline override def result(): CH = w.result()
+
+ @inline def put(x: Byte): this.type = { w.put(x); this }
+
+ @inline def putBoolean(x: Boolean): this.type = { w.putBoolean(x); this }
+
+ @inline def putShort(x: Short): this.type = { w.putShort(x); this }
+
+ @inline def putUShort(x: Int): this.type = { w.putUShort(x); this }
+
+ @inline def putInt(x: Int): this.type = { w.putInt(x); this }
+
+ @inline def putUInt(x: Long): this.type = { w.putUInt(x); this }
+
+ @inline def putLong(x: Long): this.type = { w.putLong(x); this }
+
+ @inline def putULong(x: Long): this.type = { w.putULong(x); this }
+
+ @inline def putBytes(xs: Array[Byte]): this.type = { w.putBytes(xs); this }
+
+ @inline def putBits(xs: Array[Boolean]): this.type = { w.putBits(xs); this }
+
+ @inline def putOption[T](x: Option[T])(putValueC: (this.type, T) => Unit): this.type = {
+ w.putOption(x) { (_, v) =>
+ putValueC(this, v)
+ }
+ this
+ }
+
+ @inline def putShortString(s: String): this.type = { w.putShortString(s); this }
+
+ // todo move to Writer
+ @inline def toBytes: Array[Byte] = w match {
+ case wr: VLQByteStringWriter => wr.result().asByteBuffer.array()
+ case wr: VLQByteBufferWriter => wr.toBytes
+ }
+
+ @inline def putType[T <: SType](x: T): this.type = { TypeSerializer.serialize(x, this); this }
+ @inline def putValue[T <: SType](x: Value[T]): this.type = { ValueSerializer.serialize(x, this); this }
+ @inline def putValues[T <: SType](xs: Seq[Value[T]]): this.type = {
putUInt(xs.length)
xs.foreach(putValue(_))
this
}
+
}
diff --git a/src/main/scala/sigmastate/utxo/CostTable.scala b/src/main/scala/sigmastate/utxo/CostTable.scala
index 2cb0a9329e..d06f4d5a23 100644
--- a/src/main/scala/sigmastate/utxo/CostTable.scala
+++ b/src/main/scala/sigmastate/utxo/CostTable.scala
@@ -3,13 +3,20 @@ package sigmastate.utxo
import sigmastate.{Downcast, Upcast}
import sigmastate.lang.SigmaParser
import sigmastate.lang.Terms.OperationId
-
import scala.collection.mutable
case class CostTable(operCosts: Map[OperationId, Int]) extends (OperationId => Int) {
+ @inline private def cleanOperId(operId: OperationId): OperationId = {
+ if (operId.opType.tpeParams.isEmpty) operId
+ else operId.copy(opType = operId.opType.copy(tpeParams = Nil))
+ }
+ @inline final def get(operId: OperationId): Option[Int] = {
+ val cleanId = cleanOperId(operId)
+ operCosts.get(cleanId)
+ }
override def apply(operId: OperationId): Int = {
- val cleanOperId = operId.copy(opType = operId.opType.copy(tpeParams = Nil))
- operCosts.get(cleanOperId) match {
+ val costOpt = this.get(operId)
+ costOpt match {
case Some(cost) => cost
case None => //costToInt(MinimalCost)
sys.error(s"Cannot find cost in CostTable for $operId")
@@ -24,8 +31,18 @@ object CostTable {
val expCost = 5000
val multiplyGroup = 50
+ val negateGroup = 50
val groupElementConst = 1
val constCost = 1
+ val lambdaCost = 1
+
+ /** Cost of creating new instances (kind of memory allocation cost).
+ * When the instance already exists them the corresponding Access/Extract cost should be added.
+ */
+ val newPrimValueCost = 1
+ val newCollValueCost = 1
+ val newPairValueCost = 1
+ val newOptionValueCost = 1
val plusMinus = 2
val multiply = 10
@@ -65,12 +82,20 @@ object CostTable {
("Const", "() => SigmaProp", constCost),
("Const", "() => Coll[IV]", constCost),
("Const", "() => Box", constCost),
+ ("Const", "() => AvlTree", constCost),
+
+ ("Lambda", "() => (D1) => R", lambdaCost),
+
("ConcreteCollection", "() => Coll[IV]", constCost),
("GroupGenerator$", "() => GroupElement", constCost),
("Self$", "Context => Box", constCost),
+ ("AccessAvlTree", "Context => AvlTree", constCost),
+ ("SelectField", "() => Unit", extractCost),
+ ("AccessKiloByteOfData", "() => Unit", extractCost),
("AccessBox", "Context => Box", extractCost),
("GetVar", "(Context, Byte) => Option[T]", extractCost),
+ ("GetRegister", "(Box, Byte) => Option[T]", extractCost),
("AccessRegister", "Box => Option[T]", extractCost),
("ExtractAmount", "(Box) => Long", extractCost),
("ExtractId", "(Box) => Coll[Byte]", extractCost),
@@ -78,27 +103,29 @@ object CostTable {
("ExtractScriptBytes", "(Box) => Coll[Byte]", extractCost),
("ExtractBytesWithNoRef", "(Box) => Coll[Byte]", extractCost),
("ExtractRegisterAs", "(Box,Byte) => Coll[BigInt]", extractCost),
+ ("SBox$.tokens", "(Box) => Coll[(Coll[Byte],Long)]", extractCost),
("Exponentiate", "(GroupElement,BigInt) => GroupElement", expCost),
("MultiplyGroup", "(GroupElement,GroupElement) => GroupElement", multiplyGroup),
("ByteArrayToBigInt", "(Coll[Byte]) => BigInt", castOp),
("new_BigInteger_per_item", "(Coll[Byte]) => BigInt", MinimalCost),
+ ("SGroupElement$.negate", "(GroupElement) => GroupElement", negateGroup),
("Slice", "(Coll[IV],Int,Int) => Coll[IV]", collToColl),
("Append", "(Coll[IV],Coll[IV]) => Coll[IV]", collToColl),
("SizeOf", "(Coll[IV]) => Int", collAccess),
("ByIndex", "(Coll[IV],Int) => IV", collAccess),
+ ("SCollection$.indexOf_per_kb", "(Coll[IV],IV,Int) => Int", collToColl),
+ ("SCollection$.segmentLength", "(Coll[IV],(IV) => Boolean,Int) => Int", collToColl),
+ ("SCollection$.indexWhere", "(Coll[IV],(IV) => Boolean,Int) => Int", collToColl),
+ ("SCollection$.lastIndexWhere", "(Coll[IV],(IV) => Boolean,Int) => Int", collToColl),
+ ("SCollection$.zip", "(Coll[IV],Coll[OV]) => Coll[(IV,OV)]", collToColl),
+ ("SCollection$.partition", "(Coll[IV],(IV) => Boolean) => (Coll[IV],Coll[IV])", collToColl),
+ ("SCollection$.patch", "(Coll[IV],Int,Coll[IV],Int) => Coll[IV]", collToColl),
+ ("SCollection$.updated", "(Coll[IV],Int,IV) => Coll[IV]", collToColl),
+ ("SCollection$.updateMany_per_kb", "(Coll[IV],Coll[Int],Coll[IV]) => Coll[IV]", collToColl),
("If", "(Boolean, T, T) => T", logicCost),
- // ("If", "(Boolean, Unit, Unit) => Unit", MinimalCost),
- // ("If", "(Boolean, Byte, Byte) => Byte", MinimalCost),
- // ("If", "(Boolean, Short, Short) => Short", MinimalCost),
- // ("If", "(Boolean, Int, Int) => Int", MinimalCost),
- // ("If", "(Boolean, Long, Long) => Long", MinimalCost),
- // ("If", "(Boolean, BigInt, BigInt) => BigInt", MinimalCost),
- // ("If", "(Boolean, GroupElement, GroupElement) => GroupElement", MinimalCost),
- // ("If", "(Boolean, SigmaProp, SigmaProp) => SigmaProp", MinimalCost),
- // ("If", "(Boolean, Array[IV], Array[IV]) => Array[IV]", MinimalCost),
("SigmaPropIsProven", "SigmaProp => Boolean", logicCost),
("BoolToSigmaProp", "Boolean => SigmaProp", logicCost),
@@ -112,6 +139,16 @@ object CostTable {
("CalcBlake2b256_per_kb", "(Coll[Byte]) => Coll[Byte]", hashPerKb),
("CalcSha256_per_kb", "(Coll[Byte]) => Coll[Byte]", hashPerKb),
("Xor_per_kb", "(Coll[Byte],Coll[Byte]) => Coll[Byte]", hashPerKb / 2),
+ ("XorOf_per_item", "(Coll[Boolean]) => Boolean", logicCost),
+ ("LogicalNot", "(Boolean) => Boolean", logicCost),
+
+ ("GT", "(T,T) => Boolean", comparisonCost),
+ ("GE", "(T,T) => Boolean", comparisonCost),
+ ("LE", "(T,T) => Boolean", comparisonCost),
+ ("LT", "(T,T) => Boolean", comparisonCost),
+ ("EQ", "(T,T) => Boolean", comparisonCost),
+ ("NEQ", "(T,T) => Boolean", comparisonCost),
+
("GT_per_kb", "(T,T) => Boolean", comparisonCost),
("GE_per_kb", "(T,T) => Boolean", comparisonCost),
("LE_per_kb", "(T,T) => Boolean", comparisonCost),
@@ -119,6 +156,14 @@ object CostTable {
("EQ_per_kb", "(T,T) => Boolean", comparisonCost),
("NEQ_per_kb", "(T,T) => Boolean", comparisonCost),
+ ("GT", "(BigInt,BigInt) => Boolean", plusMinusBigInt),
+ ("GE", "(BigInt,BigInt) => Boolean", plusMinusBigInt),
+ ("LE", "(BigInt,BigInt) => Boolean", plusMinusBigInt),
+ ("LT", "(BigInt,BigInt) => Boolean", plusMinusBigInt),
+ ("EQ", "(BigInt,BigInt) => Boolean", plusMinusBigInt),
+ ("NEQ", "(BigInt,BigInt) => Boolean", plusMinusBigInt),
+// (">_per_item", "(BigInt, BigInt) => BigInt", MinimalCost),
+
("+", "(Byte, Byte) => Byte", plusMinus),
("+", "(Short, Short) => Short", plusMinus),
("+", "(Int, Int) => Int", plusMinus),
@@ -144,8 +189,11 @@ object CostTable {
("%", "(Int, Int) => Int", multiply),
("%", "(Long, Long) => Long", multiply),
- ("GT", "(BigInt,BigInt) => Boolean", plusMinusBigInt),
- (">_per_item", "(BigInt, BigInt) => BigInt", MinimalCost),
+ ("Negation", "(Byte) => Byte", MinimalCost),
+ ("Negation", "(Short) => Short", MinimalCost),
+ ("Negation", "(Int) => Int", MinimalCost),
+ ("Negation", "(Long) => Long", MinimalCost),
+ ("Negation", "(BigInt) => BigInt", MinimalCost),
("+", "(BigInt, BigInt) => BigInt", plusMinusBigInt),
("+_per_item", "(BigInt, BigInt) => BigInt", MinimalCost),
@@ -162,6 +210,8 @@ object CostTable {
("%", "(BigInt, BigInt) => BigInt", multiplyBigInt),
("%_per_item", "(BigInt, BigInt) => BigInt", MinimalCost),
+ ("ModQ", "(BigInt) => BigInt", MinimalCost),
+
("Downcast", s"(${Downcast.tT}) => ${Downcast.tR}", castOp),
("Upcast", s"(${Upcast.tT}) => ${Upcast.tR}", castOp),
@@ -179,10 +229,15 @@ object CostTable {
("max", "(BigInt, BigInt) => BigInt", comparisonCost),
("max_per_item", "(BigInt, BigInt) => BigInt", comparisonCost),
- ("TreeModifications_per_kb", "(AvlTree, Coll[Byte], Coll[Byte]) => Option[Coll[Byte]]", hashPerKb * 2),
- ("TreeLookup_per_kb", "(AvlTree, Coll[Byte], Coll[Byte]) => Option[Coll[Byte]]", hashPerKb * 2),
+ ("SAvlTree$.insert_per_kb", "(AvlTree, Coll[(Coll[Byte], Coll[Byte])], Coll[Byte]) => Option[AvlTree]", hashPerKb * 2),
+ ("SAvlTree$.update_per_kb", "(AvlTree, Coll[(Coll[Byte], Coll[Byte])], Coll[Byte]) => Option[AvlTree]", hashPerKb * 2),
+ ("SAvlTree$.remove_per_kb", "(AvlTree, Coll[Coll[Byte]], Coll[Byte]) => Option[AvlTree]", hashPerKb * 2),
+ ("SAvlTree$.contains_per_kb", "(AvlTree,Coll[Byte],Coll[Byte]) => Boolean", hashPerKb * 2),
+ ("SAvlTree$.get_per_kb", "(AvlTree,Coll[Byte],Coll[Byte]) => Option[Coll[Byte]]", hashPerKb * 2),
+ ("SAvlTree$.getMany_per_kb", "(AvlTree,Coll[Coll[Byte]],Coll[Byte]) => Coll[Option[Coll[Byte]]]", hashPerKb * 2),
("LongToByteArray", "(Long) => Coll[Byte]", castOp),
+ ("ByteArrayToLong", "(Coll[Byte]) => Long", castOp),
("ProveDlogEval", "(Unit) => SigmaProp", groupElementConst + constCost + 2 * expCost + multiplyGroup),
@@ -340,8 +395,8 @@ object CostTableStat {
stat.map { case (opId, item) =>
val cost = item.sum / item.count
val avgLen = item.sumLen / item.count
- val isCol = opId.opType.tRange.isCollection
- "\n" + s"""("${opId.name}", "${opId.opType}", $cost), // count=${item.count}${if (isCol) s"; minLen=${item.minLen}; maxLen=${item.maxLen}; avgLen=$avgLen" else ""}"""
+ val isColl = opId.opType.tRange.isCollection
+ "\n" + s"""("${opId.name}", "${opId.opType}", $cost), // count=${item.count}${if (isColl) s"; minLen=${item.minLen}; maxLen=${item.maxLen}; avgLen=$avgLen" else ""}"""
}.mkString("Seq(", "", "\n)")
}
}
diff --git a/src/main/scala/sigmastate/utxo/transformers.scala b/src/main/scala/sigmastate/utxo/transformers.scala
index 9bb10249f0..9b8e38c6ed 100644
--- a/src/main/scala/sigmastate/utxo/transformers.scala
+++ b/src/main/scala/sigmastate/utxo/transformers.scala
@@ -41,8 +41,8 @@ case class Slice[IV <: SType](input: Value[SCollection[IV]], from: Value[SInt.ty
override val opCode: OpCode = OpCodes.SliceCode
override val tpe = input.tpe
override def opType = {
- val tpeCol = SCollection(input.tpe.typeParams.head.ident)
- SFunc(Vector(tpeCol, SInt, SInt), tpeCol)
+ val tpeColl = SCollection(input.tpe.typeParams.head.ident)
+ SFunc(Vector(tpeColl, SInt, SInt), tpeColl)
}
}
@@ -96,10 +96,10 @@ object Fold {
)
def concat[T <: SType](input: Value[SCollection[SCollection[T]]])(implicit tT: T): Fold[SCollection[T], T] = {
- val tCol = SCollection(tT)
+ val tColl = SCollection(tT)
Fold[SCollection[T], T](input,
ConcreteCollection()(tT).asValue[T],
- FuncValue(Vector((1, tCol), (2, tCol)), Append(ValUse(1, tCol), ValUse(2, tCol)))
+ FuncValue(Vector((1, tColl), (2, tColl)), Append(ValUse(1, tColl), ValUse(2, tColl)))
)
}
}
@@ -204,7 +204,7 @@ trait Deserialize[V <: SType] extends NotReadyValue[V]
/** Extracts context variable as Coll[Byte], deserializes it to script and then executes this script in the current context.
* The original `Coll[Byte]` of the script is available as `getVar[Coll[Byte]](id)`
* @param id identifier of the context variable
- * @tparam T result type of the deserialized script.
+ * @tparam V result type of the deserialized script.
* @throws InterpreterException if the actual script type doesn't conform to T
* @return result of the script execution in the current context
* @since 2.0
diff --git a/src/test/scala/org/ergoplatform/EmissionSpec.scala b/src/test/scala/org/ergoplatform/EmissionSpec.scala
new file mode 100644
index 0000000000..224e4b7b95
--- /dev/null
+++ b/src/test/scala/org/ergoplatform/EmissionSpec.scala
@@ -0,0 +1,59 @@
+package org.ergoplatform
+
+import org.ergoplatform.mining.emission.EmissionRules
+import org.ergoplatform.settings.MonetarySettings
+import org.scalacheck.Gen
+import sigmastate.helpers.SigmaTestingCommons
+
+class EmissionSpec extends SigmaTestingCommons {
+
+ private val settings = MonetarySettings(30 * 2 * 24 * 365, 90 * 24 * 30, 75L * EmissionRules.CoinsInOneErgo,
+ 3L * EmissionRules.CoinsInOneErgo, 720, 75L * EmissionRules.CoinsInOneErgo / 10)
+ private val emission = new EmissionRules(settings)
+
+ def collectedFoundationReward(height: Int): Long = {
+ (1 to height).map { h =>
+ emission.foundationRewardAtHeight(h)
+ }.sum
+ }
+
+ property("emission rules vectors") {
+ emission.blocksTotal shouldBe 2080799
+ emission.coinsTotal shouldBe 97739925L * EmissionRules.CoinsInOneErgo
+ emission.foundersCoinsTotal shouldBe 4330792.5 * EmissionRules.CoinsInOneErgo
+ emission.minersCoinsTotal shouldBe 93409132.5 * EmissionRules.CoinsInOneErgo
+
+ emission.issuedCoinsAfterHeight(emission.blocksTotal) shouldBe emission.coinsTotal
+ emission.issuedCoinsAfterHeight(1) shouldBe settings.fixedRate
+ }
+
+ property("correct sum from miner and foundation parts") {
+ // collect coins after the fixed rate period
+ forAll(Gen.choose(1, emission.blocksTotal)) { height =>
+ val currentRate = emission.emissionAtHeight(height)
+ val minerPart = emission.minersRewardAtHeight(height)
+ val foundationPart = emission.foundationRewardAtHeight(height)
+ foundationPart + minerPart shouldBe currentRate
+ }
+ }
+
+ property("correct remainingFoundationRewardAtHeight") {
+ val totalFoundersReward = collectedFoundationReward(emission.blocksTotal)
+
+ def checkHeight(height: Int) = {
+ val collectedFoundersPart = collectedFoundationReward(height)
+ val remainingFoundersPart = emission.remainingFoundationRewardAtHeight(height)
+ remainingFoundersPart + collectedFoundersPart shouldBe totalFoundersReward
+
+ }
+ // collect coins after the fixed rate period
+ forAll(Gen.choose(1, emission.blocksTotal)) { height =>
+ checkHeight(height)
+ }
+ checkHeight(settings.fixedRatePeriod)
+ checkHeight(settings.fixedRatePeriod + settings.epochLength)
+ checkHeight(settings.fixedRatePeriod + 2 * settings.epochLength)
+ checkHeight(settings.fixedRatePeriod + 8 * settings.epochLength)
+ }
+
+}
diff --git a/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala b/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala
index 73a05fad04..7674324db1 100644
--- a/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala
+++ b/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala
@@ -2,13 +2,16 @@ package org.ergoplatform
import java.math.BigInteger
+import org.ergoplatform.ErgoAddressEncoder.{MainnetNetworkPrefix, TestnetNetworkPrefix}
import org.scalatest.prop.PropertyChecks
-import org.scalatest.{Assertion, Matchers, PropSpec, TryValues}
-import sigmastate.Values
+import org.scalatest.{PropSpec, Assertion, Matchers, TryValues}
import sigmastate.basics.DLogProtocol
import sigmastate.basics.DLogProtocol.DLogProverInput
-import sigmastate.serialization.{ErgoTreeSerializer, ValueSerializer}
+import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer
+import sigmastate.serialization.ValueSerializer
import sigmastate.serialization.generators.ValueGenerators
+import org.ergoplatform.ErgoScriptPredef._
+import sigmastate.Values.ErgoTree
class ErgoAddressSpecification extends PropSpec
with ValueGenerators
@@ -17,7 +20,7 @@ class ErgoAddressSpecification extends PropSpec
with TryValues {
private implicit val ergoAddressEncoder: ErgoAddressEncoder =
- new ErgoAddressEncoder(ErgoAddressEncoder.TestnetNetworkPrefix)
+ new ErgoAddressEncoder(TestnetNetworkPrefix)
def addressRoundtrip(addr: ErgoAddress): Assertion = {
ergoAddressEncoder.fromString(ergoAddressEncoder.toString(addr)).get shouldBe addr
@@ -31,45 +34,56 @@ class ErgoAddressSpecification extends PropSpec
property("SHA roundtrip") {
forAll(proveDlogGen) { pk =>
- addressRoundtrip(Pay2SHAddress(pk))
+ addressRoundtrip(Pay2SHAddress(ErgoTree.fromSigmaBoolean(pk)))
}
}
property("SA roundtrip") {
forAll(proveDlogGen) { pk =>
- addressRoundtrip(Pay2SAddress(pk))
+ addressRoundtrip(Pay2SAddress(ErgoTree.fromSigmaBoolean(pk)))
}
}
property("P2SH proper bytes to track") {
- forAll(proveDlogGen) { s =>
- val p2sh = Pay2SHAddress(s)
+ forAll(proveDlogGen) { pk =>
+ val p2sh = Pay2SHAddress(ErgoTree.fromSigmaBoolean(pk))
//search we're doing to find a box potentially corresponding to some address
- ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(p2sh.script).containsSlice(p2sh.contentBytes) shouldBe true
+ DefaultSerializer.serializeErgoTree(p2sh.script).containsSlice(p2sh.contentBytes) shouldBe true
}
}
property("P2S proper bytes to track") {
- forAll(proveDlogGen) { s =>
- val p2s = Pay2SAddress(s)
+ forAll(proveDlogGen) { pk =>
+ val p2s = Pay2SAddress(ErgoTree.fromSigmaBoolean(pk))
//search we're doing to find a box potentially corresponding to some address
- ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(p2s.script).containsSlice(p2s.contentBytes) shouldBe true
+ DefaultSerializer.serializeErgoTree(p2s.script).containsSlice(p2s.contentBytes) shouldBe true
}
}
property("fromProposition() should properly distinct all types of addresses from script AST") {
-
val pk: DLogProtocol.ProveDlog = DLogProverInput(BigInteger.ONE).publicImage
- val sh: Array[Byte] = ErgoAddressEncoder.hash192(ValueSerializer.serialize(pk))
- val p2s: Pay2SAddress = Pay2SAddress(Values.TrueLeaf)
- val p2sh: Pay2SHAddress = new Pay2SHAddress(sh)
+ val p2s: Pay2SAddress = Pay2SAddress(TrueProp)
+ val p2sh: Pay2SHAddress = Pay2SHAddress(pk)
val p2pk: P2PKAddress = P2PKAddress(pk)
- ergoAddressEncoder.fromProposition(p2s.script).success.value.isInstanceOf[Pay2SAddress] shouldBe true
- ergoAddressEncoder.fromProposition(p2sh.script).success.value.isInstanceOf[Pay2SHAddress] shouldBe true
+ ergoAddressEncoder.fromProposition(p2s.script).success.value shouldBe p2s
+ ergoAddressEncoder.fromProposition(p2sh.script).success.value shouldBe p2sh
ergoAddressEncoder.fromProposition(p2pk.script).success.value.isInstanceOf[P2PKAddress] shouldBe true
}
+
+ property("decode with wrong network prefix") {
+ forAll(proveDlogGen) { pk =>
+ val mainnetEncoder = new ErgoAddressEncoder(MainnetNetworkPrefix)
+ val testnetEncoder = new ErgoAddressEncoder(TestnetNetworkPrefix)
+ val mnAddr = P2PKAddress(pk)(mainnetEncoder)
+ val tnAddr = P2PKAddress(pk)(testnetEncoder)
+
+ an[RuntimeException] should be thrownBy mainnetEncoder.fromString(tnAddr.toString).get
+ an[RuntimeException] should be thrownBy testnetEncoder.fromString(mnAddr.toString).get
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala b/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala
new file mode 100644
index 0000000000..06433d0a8c
--- /dev/null
+++ b/src/test/scala/org/ergoplatform/ErgoLikeTransactionSpec.scala
@@ -0,0 +1,158 @@
+package org.ergoplatform
+
+import org.scalatest.prop.GeneratorDrivenPropertyChecks
+import org.scalatest.{Matchers, PropSpec}
+import scorex.util.Random
+import sigmastate.Values.ByteArrayConstant
+import sigmastate.helpers.SigmaTestingCommons
+import sigmastate.interpreter.{ContextExtension, ProverResult}
+import sigmastate.serialization.SigmaSerializer
+import sigmastate.serialization.generators.ValueGenerators
+
+class ErgoLikeTransactionSpec extends PropSpec
+ with GeneratorDrivenPropertyChecks
+ with Matchers
+ with ValueGenerators
+ with SigmaTestingCommons {
+
+ property("ErgoLikeTransaction: Serializer round trip") {
+ forAll { t: ErgoLikeTransaction => roundTripTest(t)(ErgoLikeTransaction.serializer) }
+ forAll { t: ErgoLikeTransaction => roundTripTestWithPos(t)(ErgoLikeTransaction.serializer) }
+ }
+
+ property("ErgoLikeTransaction with same token in different outputs : Serializer round trip") {
+ forAll { txIn: ErgoLikeTransaction =>
+ whenever(txIn.outputCandidates.head.additionalTokens.nonEmpty) {
+ val out = txIn.outputCandidates.head
+ val outputs = (0 until 10).map { i =>
+ new ErgoBoxCandidate(out.value, out.ergoTree, i, out.additionalTokens, out.additionalRegisters)
+ }
+ val tx = new ErgoLikeTransaction(txIn.inputs, txIn.dataInputs, txIn.outputCandidates ++ outputs)
+ roundTripTestWithPos(tx)(ErgoLikeTransaction.serializer)
+
+ // check that token id is written only once
+ val w = SigmaSerializer.startWriter()
+ ErgoLikeTransaction.serializer.serialize(tx, w)
+ val bytes = w.toBytes
+
+ tx.outputCandidates.flatMap(_.additionalTokens).foreach { token =>
+ bytes.indexOfSlice(token._1) should not be -1
+ bytes.indexOfSlice(token._1) shouldBe bytes.lastIndexOfSlice(token._1)
+ }
+ }
+ }
+ }
+
+ property("ErgoLikeTransaction fields modification should change messageToSign") {
+ forAll { tx0: ErgoLikeTransaction =>
+ // generate transaction with same token in different outputs
+ val headOut = tx0.outputCandidates.head
+ whenever(headOut.additionalTokens.nonEmpty && headOut.additionalRegisters.nonEmpty) {
+
+ val outputs = (0 until 10).map { i =>
+ new ErgoBoxCandidate(headOut.value, headOut.ergoTree, i, headOut.additionalTokens, headOut.additionalRegisters)
+ }
+ val di = tx0.dataInputs
+ val txIn = new ErgoLikeTransaction(tx0.inputs, di, tx0.outputCandidates ++ outputs)
+ val tailOuts = txIn.outputCandidates.tail
+ val headInput = txIn.inputs.head
+ val tailInputs = txIn.inputs.tail
+ val initialMessage = txIn.messageToSign
+
+ // transaction with the same fields should have the same message to sign
+ val otx2 = new ErgoLikeTransaction(headInput +: tailInputs, di, headOut +: tailOuts)
+ (otx2.messageToSign sameElements initialMessage) shouldBe true
+
+ /**
+ * Check inputs modifications
+ */
+ // transaction with decreased number of inputs
+ val itx3 = new ErgoLikeTransaction(tailInputs, di, txIn.outputCandidates)
+ (itx3.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with increased number of inputs
+ val itx4 = new ErgoLikeTransaction(headInput +: txIn.inputs, di, txIn.outputCandidates)
+ (itx4.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with shuffled inputs
+ if (tailInputs.nonEmpty) {
+ val itx5 = new ErgoLikeTransaction(tailInputs ++ Seq(headInput), di, txIn.outputCandidates)
+ (itx5.messageToSign sameElements initialMessage) shouldBe false
+ }
+
+ // transaction with modified input boxId
+ val headInput6 = headInput.copy(boxId = txIn.outputs.head.id)
+ val itx6 = new ErgoLikeTransaction(headInput6 +: tailInputs, di, txIn.outputCandidates)
+ (itx6.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with modified input extension
+ val newExtension7 = ContextExtension(headInput.spendingProof.extension.values ++ Map(Byte.MinValue -> ByteArrayConstant(Random.randomBytes(32))))
+ val newProof7 = new ProverResult(headInput.spendingProof.proof, newExtension7)
+ val headInput7 = headInput.copy(spendingProof = newProof7)
+ val itx7 = new ErgoLikeTransaction(headInput7 +: tailInputs, di, txIn.outputCandidates)
+ (itx7.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with modified input proof should not affect messageToSign
+ val newProof8 = new ProverResult(headInput.spendingProof.proof, headInput.spendingProof.extension)
+ val headInput8 = headInput.copy(spendingProof = newProof8)
+ val itx8 = new ErgoLikeTransaction(headInput8 +: tailInputs, di, txIn.outputCandidates)
+ (itx8.messageToSign sameElements initialMessage) shouldBe true
+
+ /**
+ * Check data inputs modifications
+ */
+ // transaction with decreased number of data inputs
+ if (di.nonEmpty) {
+ val dtx3 = new ErgoLikeTransaction(txIn.inputs, di.tail, txIn.outputCandidates)
+ (dtx3.messageToSign sameElements initialMessage) shouldBe false
+ }
+
+ // transaction with increased number of data inputs
+ val di4 = DataInput(txIn.outputs.head.id)
+ val dtx4 = new ErgoLikeTransaction(txIn.inputs, di4 +: di, txIn.outputCandidates)
+ (dtx4.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with shuffled data inputs
+ if (di.size > 1) {
+ val dtx5 = new ErgoLikeTransaction(txIn.inputs, di.tail ++ Seq(di.head), txIn.outputCandidates)
+ (dtx5.messageToSign sameElements initialMessage) shouldBe false
+ }
+
+ // transaction with modified data input boxId
+ if (di.nonEmpty) {
+ val di6 = DataInput(txIn.outputs.head.id)
+ val dtx6 = new ErgoLikeTransaction(txIn.inputs, di6 +: di.tail, txIn.outputCandidates)
+ (dtx6.messageToSign sameElements initialMessage) shouldBe false
+ }
+
+ /**
+ * Check outputs modifications
+ */
+ // transaction with decreased number of outputs
+ val otx3 = new ErgoLikeTransaction(txIn.inputs, di, tailOuts)
+ (otx3.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with increased number of outputs
+ val otx4 = new ErgoLikeTransaction(txIn.inputs, di, headOut +: txIn.outputCandidates)
+ (otx4.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with shuffled outputs
+ val otx5 = new ErgoLikeTransaction(txIn.inputs, di, tailOuts ++ Seq(txIn.outputCandidates.head))
+ (otx5.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with modified output value
+ val headOut6 = new ErgoBoxCandidate(headOut.value - 1, headOut.ergoTree, headOut.creationHeight, headOut.additionalTokens, headOut.additionalRegisters)
+ val otx6 = new ErgoLikeTransaction(txIn.inputs, di, headOut6 +: tailOuts)
+ (otx6.messageToSign sameElements initialMessage) shouldBe false
+
+ // transaction with modified output tokens
+ val newTokens = headOut.additionalTokens.map(t => t._1 -> (t._2 - 1))
+ val headOut7 = new ErgoBoxCandidate(headOut.value, headOut.ergoTree, headOut.creationHeight, newTokens, headOut.additionalRegisters)
+ val otx7 = new ErgoLikeTransaction(txIn.inputs, di, headOut7 +: tailOuts)
+ (otx7.messageToSign sameElements initialMessage) shouldBe false
+
+ }
+ }
+ }
+
+}
diff --git a/src/test/scala/org/ergoplatform/ErgoScriptPredefSpec.scala b/src/test/scala/org/ergoplatform/ErgoScriptPredefSpec.scala
index dbe3967a1e..3db29e8816 100644
--- a/src/test/scala/org/ergoplatform/ErgoScriptPredefSpec.scala
+++ b/src/test/scala/org/ergoplatform/ErgoScriptPredefSpec.scala
@@ -1,23 +1,206 @@
package org.ergoplatform
-import scorex.crypto.hash.{Blake2b256, Digest32}
-import sigmastate.AvlTreeData
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix
+import org.ergoplatform.ErgoBox.R4
+import org.ergoplatform.mining.emission.EmissionRules
+import org.ergoplatform.settings.MonetarySettings
+import org.scalacheck.Gen
+import scorex.crypto.hash.{Digest32, Blake2b256}
+import scorex.util.Random
+import sigmastate.Values.{SigmaPropConstant, CollectionConstant, Value, ByteArrayConstant, SigmaPropValue, IntConstant}
+import sigmastate._
+import sigmastate.basics.DLogProtocol.{ProveDlog, DLogProverInput}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, SigmaTestingCommons, ErgoLikeTestInterpreter}
import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
-import sigmastate.interpreter.{ContextExtension, ProverResult}
-import sigmastate.utxo.ErgoLikeTestInterpreter
+import sigmastate.interpreter.{ProverResult, ContextExtension}
+import sigmastate.lang.Terms.ValueOps
+import sigmastate.serialization.ValueSerializer
+import sigmastate.utxo.{ExtractCreationInfo, ByIndex, SelectField, CostTable}
+import scalan.util.BenchmarkUtil._
+import ErgoScriptPredef._
import scala.util.Try
class ErgoScriptPredefSpec extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext {
+ private implicit lazy val IR: TestingIRContext = new TestingIRContext {
override val okPrintEvaluatedEntries: Boolean = false
}
- val emptyProverResult: ProverResult = ProverResult(Array.emptyByteArray, ContextExtension.empty)
- property("tokenThreshold") {
- val prover = new ErgoLikeTestProvingInterpreter
+ private val emptyProverResult: ProverResult = ProverResult(Array.emptyByteArray, ContextExtension.empty)
+ private val settings = MonetarySettings(30 * 2 * 24 * 365, 90 * 24 * 30, 75L * EmissionRules.CoinsInOneErgo,
+ 3L * EmissionRules.CoinsInOneErgo, 720, 75L * EmissionRules.CoinsInOneErgo / 10)
+ private val emission = new EmissionRules(settings)
+
+ property("boxCreationHeight") {
+ val verifier = new ErgoLikeTestInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
+ val minerProp = prover.dlogSecrets.head.publicImage
+ val pk = minerProp.pkBytes
+
+ val nextHeight = 1
+ val prop = EQ(Height, ErgoScriptPredef.boxCreationHeight(ByIndex(Outputs, IntConstant(0)))).toSigmaProp
+ val propInlined = EQ(Height, SelectField(ExtractCreationInfo(ByIndex(Outputs, IntConstant(0))), 1).asIntValue).toSigmaProp
+ prop shouldBe propInlined
+ val inputBox = ErgoBox(1, prop, nextHeight, Seq(), Map())
+ val inputBoxes = IndexedSeq(inputBox)
+ val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult))
+ val minerBox = new ErgoBoxCandidate(1, SigmaPropConstant(minerProp), nextHeight, Seq(), Map())
+
+ val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(minerBox))
+
+ val ctx = ErgoLikeContext(
+ currentHeight = nextHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = pk,
+ boxesToSpend = inputBoxes,
+ spendingTransaction,
+ self = inputBox)
+ val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
+ verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true
+ }
+
+ property("collect coins from the founders' box") {
+ def remaining(h: Int) = emission.remainingFoundationRewardAtHeight(h)
+
+ val prover = new ContextEnrichingTestProvingInterpreter
+ val prop = ErgoScriptPredef.foundationScript(settings)
+
+ def R4Prop(ableToProve: Boolean): CollectionConstant[SByte.type] = if (ableToProve) {
+ val pks = (DLogProverInput.random() +: prover.dlogSecrets.take(2)).map(s => SigmaPropConstant(s.publicImage))
+ ByteArrayConstant(ValueSerializer.serialize(AtLeast(IntConstant(2), pks)))
+ } else {
+ val pk = (new ContextEnrichingTestProvingInterpreter).dlogSecrets.head.publicImage
+ ByteArrayConstant(ValueSerializer.serialize(SigmaPropConstant(pk)))
+ }
+
+ val verifier = new ErgoLikeTestInterpreter
+
+ checkAtHeight(1)
+ checkAtHeight(settings.fixedRatePeriod)
+ checkAtHeight(settings.fixedRatePeriod + 1)
+ checkAtHeight(settings.fixedRatePeriod + settings.epochLength)
+ checkAtHeight(settings.fixedRatePeriod + settings.epochLength + 1)
+ checkAtHeight(settings.fixedRatePeriod + 2 * settings.epochLength)
+ checkAtHeight(settings.fixedRatePeriod + 2 * settings.epochLength + 1)
+
+ def checkAtHeight(height: Int) = {
+ // collect correct amount of coins, correct new script, able to satisfy R4 conditions
+ checkSpending(remaining(height), height, prop, R4Prop(true)) shouldBe 'success
+ // unable to satisfy R4 conditions
+ checkSpending(remaining(height), height, prop, R4Prop(false)) shouldBe 'failure
+ // incorrect new script
+ checkSpending(remaining(height), height, TrivialProp.TrueProp, R4Prop(true)) shouldBe 'failure
+ // collect less coins then possible
+ checkSpending(remaining(height) + 1, height, prop, R4Prop(true)) shouldBe 'success
+ // collect more coins then possible
+ checkSpending(remaining(height) - 1, height, prop, R4Prop(true)) shouldBe 'failure
+ }
+
+ def checkSpending(remainingAmount: Long,
+ height: Int,
+ newProp: SigmaPropValue,
+ inputR4Val: CollectionConstant[SByte.type]): Try[Unit] = Try {
+ val outputR4Val: CollectionConstant[SByte.type] = ByteArrayConstant(Random.randomBytes())
+ val inputBoxes = IndexedSeq(ErgoBox(emission.foundersCoinsTotal, prop, 0, Seq(), Map(R4 -> inputR4Val)))
+ val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult))
+ val newFoundersBox = ErgoBox(remainingAmount, newProp, 0, Seq(), Map(R4 -> outputR4Val))
+ val collectedBox = ErgoBox(inputBoxes.head.value - remainingAmount, TrueProp, 0)
+ val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(newFoundersBox, collectedBox))
+ val ctx = ErgoLikeContext(
+ currentHeight = height,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = inputBoxes,
+ spendingTransaction,
+ self = inputBoxes.head)
+ val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
+ verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true
+ }
+ }
+
+ property("collect coins from rewardOutputScript") {
+ val prover = new ContextEnrichingTestProvingInterpreter
+ val minerPk = prover.dlogSecrets.head.publicImage
+ val prop = ErgoScriptPredef.rewardOutputScript(settings.minerRewardDelay, minerPk)
val verifier = new ErgoLikeTestInterpreter
+ val inputBoxes = IndexedSeq(ErgoBox(20, prop, 0, Seq(), Map()))
+ val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult))
+ val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(ErgoBox(inputBoxes.head.value, TrueProp, 0)))
+
+ val ctx = ErgoLikeContext(
+ currentHeight = inputBoxes.head.creationHeight + settings.minerRewardDelay,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = inputBoxes,
+ spendingTransaction,
+ self = inputBoxes.head)
+ val prevBlockCtx = ErgoLikeContext(
+ currentHeight = inputBoxes.head.creationHeight + settings.minerRewardDelay - 1,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = inputBoxes,
+ spendingTransaction,
+ self = inputBoxes.head)
+
+ // should not be able to collect before minerRewardDelay
+ val prove = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
+ verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, prevBlockCtx, prove, fakeMessage)
+ .fold(t => throw t, x => x) should matchPattern { case (false,_) => }
+
+ // should be able to collect after minerRewardDelay
+ val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
+ verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true
+ }
+
+ property("create transaction collecting the emission box") {
+ val prover = new ContextEnrichingTestProvingInterpreter
+ val minerPk = prover.dlogSecrets.head.publicImage
+ val prop = ErgoScriptPredef.emissionBoxProp(settings)
+ val emissionBox = ErgoBox(emission.coinsTotal, prop, 0, Seq(), Map())
+ val minerProp = ErgoScriptPredef.rewardOutputScript(settings.minerRewardDelay, minerPk)
+
+ // collect coins during the fixed rate period
+ forAll(Gen.choose(1, settings.fixedRatePeriod)) { height =>
+ val currentRate = emission.minersRewardAtHeight(height)
+ createRewardTx(currentRate, height, minerProp) shouldBe 'success
+ createRewardTx(currentRate + 1, height, minerProp) shouldBe 'failure
+ createRewardTx(currentRate - 1, height, minerProp) shouldBe 'failure
+ }
+
+ // collect coins after the fixed rate period
+ forAll(Gen.choose(1, emission.blocksTotal - 1)) { height =>
+ val currentRate = emission.minersRewardAtHeight(height)
+ createRewardTx(currentRate, height, minerProp) shouldBe 'success
+ createRewardTx(currentRate + 1, height, minerProp) shouldBe 'failure
+ createRewardTx(currentRate - 1, height, minerProp) shouldBe 'failure
+ }
+
+ // collect coins to incorrect proposition
+ forAll(Gen.choose(1, emission.blocksTotal - 1)) { height =>
+ val currentRate = emission.minersRewardAtHeight(height)
+ val pk2 = prover.dlogSecrets(1).publicImage
+ val correctProp = ErgoScriptPredef.rewardOutputScript(settings.minerRewardDelay, minerPk)
+ val incorrectDelay = ErgoScriptPredef.rewardOutputScript(settings.minerRewardDelay + 1, minerPk)
+ val incorrectPk = ErgoScriptPredef.rewardOutputScript(settings.minerRewardDelay, pk2)
+ createRewardTx(currentRate, height, correctProp) shouldBe 'success
+ createRewardTx(currentRate, height, incorrectDelay) shouldBe 'failure
+ createRewardTx(currentRate, height, incorrectPk) shouldBe 'failure
+ createRewardTx(currentRate, height, minerPk) shouldBe 'failure
+ }
+
+ def createRewardTx(emissionAmount: Long, nextHeight: Int, minerProp: SigmaPropValue): Try[ErgoLikeTransaction] = {
+ checkRewardTx(minerPk,
+ minerProp,
+ emissionBox,
+ emissionAmount,
+ nextHeight)(prover)
+ }
+
+ }
+
+ property("tokenThreshold") {
+ val prover = new ContextEnrichingTestProvingInterpreter(CostTable.ScriptLimit * 2)
+ val verifier = new ErgoLikeTestInterpreter(CostTable.ScriptLimit * 2)
val pubkey = prover.dlogSecrets.head.publicImage
@@ -26,12 +209,12 @@ class ErgoScriptPredefSpec extends SigmaTestingCommons {
val wrongId2: Digest32 = Blake2b256(wrongId)
val tokenAmount: Int = 50
- val prop = ErgoScriptPredef.tokenThresholdScript(tokenId, tokenAmount)
+ val prop = ErgoScriptPredef.tokenThresholdScript(tokenId, tokenAmount, TestnetNetworkPrefix)
def check(inputBoxes: IndexedSeq[ErgoBox]): Try[Unit] = Try {
val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult))
val amount = inputBoxes.map(_.value).sum
- val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(ErgoBox(amount, pubkey, 0)))
+ val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(ErgoBox(amount, pubkey.toSigmaProp, 0)))
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -41,39 +224,85 @@ class ErgoScriptPredefSpec extends SigmaTestingCommons {
spendingTransaction,
self = inputBoxes.head)
- val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
+ val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).fold(t => throw t, x => x)
verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true
}
- // transaction with the only input with enough token should pass
- val inputs0 = IndexedSeq(
- ErgoBox(20, prop, 0, Seq((wrongId, tokenAmount), (tokenId, tokenAmount), (wrongId2, tokenAmount)), Map())
- )
- check(inputs0) shouldBe 'success
-
- // transaction with the only input with insufficient token should fail
- val inputs1 = IndexedSeq(
- ErgoBox(20, prop, 0, Seq((wrongId, tokenAmount), (tokenId, tokenAmount - 1)), Map())
- )
- check(inputs1) shouldBe 'failure
-
- // transaction with multiple inputs with insufficient token should fail
- val inputs2 = IndexedSeq(
- ErgoBox(20, prop, 0, Seq((wrongId, tokenAmount), (tokenId, tokenAmount - 2)), Map()),
- ErgoBox(20, prop, 0, Seq((wrongId, tokenAmount)), Map()),
- ErgoBox(20, prop, 0, Seq((tokenId, 1), (wrongId2, tokenAmount)), Map())
- )
- check(inputs2) shouldBe 'failure
-
- // transaction with multiple inputs with enough token should pass
- val inputs3 = IndexedSeq(
- ErgoBox(20, prop, 0, Seq((wrongId, 1), (tokenId, tokenAmount / 2)), Map()),
- ErgoBox(20, prop, 0, Seq((wrongId, 1)), Map()),
- ErgoBox(20, prop, 0, Seq((tokenId, tokenAmount / 2 + 1), (wrongId2, 1)), Map())
- )
- check(inputs3) shouldBe 'success
+ measure(10) { i =>
+ // transaction with the only input with enough token should pass
+ val inputs0 = IndexedSeq(
+ ErgoBox(20, prop, 0, Seq((wrongId, tokenAmount), (tokenId, tokenAmount), (wrongId2, tokenAmount)), Map())
+ )
+ check(inputs0).get shouldBe(())
+
+ // transaction with the only input with insufficient token should fail
+ val inputs1 = IndexedSeq(
+ ErgoBox(20, prop, 0, Seq((wrongId, tokenAmount), (tokenId, tokenAmount - 1)), Map())
+ )
+ check(inputs1) shouldBe 'failure
+
+ // transaction with multiple inputs with insufficient token should fail
+ val inputs2 = IndexedSeq(
+ ErgoBox(20, prop, 0, Seq((wrongId, tokenAmount), (tokenId, tokenAmount - 2)), Map()),
+ ErgoBox(20, prop, 0, Seq((wrongId, tokenAmount)), Map()),
+ ErgoBox(20, prop, 0, Seq((tokenId, 1), (wrongId2, tokenAmount)), Map())
+ )
+ check(inputs2) shouldBe 'failure
+
+ // transaction with multiple inputs with enough token should pass
+ val inputs3 = IndexedSeq(
+ ErgoBox(20, prop, 0, Seq((wrongId, 1), (tokenId, tokenAmount / 2)), Map()),
+ ErgoBox(20, prop, 0, Seq((wrongId, 1)), Map()),
+ ErgoBox(20, prop, 0, Seq((tokenId, tokenAmount / 2 + 1), (wrongId2, 1)), Map())
+ )
+ check(inputs3).fold(t => throw t, identity)
+
+ // A transaction which contains input with no tokens
+ val inputs4 = IndexedSeq(
+ ErgoBox(20, prop, 0, Seq((wrongId, 1), (tokenId, tokenAmount / 2)), Map()),
+ ErgoBox(20, prop, 0, Seq(), Map()),
+ ErgoBox(20, prop, 0, Seq((tokenId, tokenAmount / 2 + 1), (wrongId2, 1)), Map())
+ )
+ check(inputs4) shouldBe 'success
+ }
+ /*
+ Iter 0: 777 ms
+ Iter 1: 353 ms
+ Iter 2: 304 ms
+ Iter 10: 110 ms
+ Iter 30: 80 ms
+ Iter 40: 72 ms
+ Iter 60: 68 ms
+ */
+ }
+
+ def checkRewardTx(minerPk: ProveDlog,
+ minerProp: SigmaPropValue,
+ emissionBox: ErgoBox,
+ emissionAmount: Long,
+ nextHeight: Int)(prover: ContextEnrichingTestProvingInterpreter): Try[ErgoLikeTransaction] = Try {
+ val verifier = new ErgoLikeTestInterpreter
+ val prop = emissionBox.ergoTree
+ val inputBoxes = IndexedSeq(emissionBox)
+ val inputs = inputBoxes.map(b => Input(b.id, emptyProverResult))
+ val pkBytes = minerPk.pkBytes
+
+ val newEmissionBox = new ErgoBoxCandidate(emissionBox.value - emissionAmount, prop, nextHeight, Seq(), Map())
+ val minerBox = new ErgoBoxCandidate(emissionAmount, minerProp, nextHeight, Seq(), Map())
+
+ val spendingTransaction = ErgoLikeTransaction(inputs, IndexedSeq(newEmissionBox, minerBox))
+ val ctx = ErgoLikeContext(
+ currentHeight = nextHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = pkBytes,
+ boxesToSpend = inputBoxes,
+ spendingTransaction,
+ self = inputBoxes.head)
+ val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).fold(t => throw t, identity)
+ verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).fold(t => throw t, identity)._1 shouldBe true
+ spendingTransaction
}
}
diff --git a/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala b/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala
new file mode 100644
index 0000000000..1cf41a5f81
--- /dev/null
+++ b/src/test/scala/org/ergoplatform/dsl/TestContractSpec.scala
@@ -0,0 +1,177 @@
+package org.ergoplatform.dsl
+
+import sigmastate.interpreter.Interpreter.ScriptNameProp
+
+import scala.collection.mutable
+import sigmastate.interpreter.{ProverResult, CostedProverResult}
+
+import scala.collection.mutable.ArrayBuffer
+import org.ergoplatform.ErgoBox.NonMandatoryRegisterId
+import org.ergoplatform.ErgoLikeContext.{dummyPreHeader, noHeaders}
+import scalan.Nullable
+import scorex.crypto.hash.Digest32
+
+import scala.util.Try
+import org.ergoplatform.{ErgoLikeContext, ErgoBox}
+import org.ergoplatform.dsl.ContractSyntax.{Token, TokenId, ErgoScript, Proposition}
+import sigmastate.{AvlTreeData, SType}
+import sigmastate.Values.{ErgoTree, EvaluatedValue}
+import sigmastate.eval.{IRContext, CSigmaProp, Evaluation}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, SigmaTestingCommons, ErgoLikeTestInterpreter}
+import sigmastate.lang.Terms.ValueOps
+import special.sigma.{AnyValue, TestValue, SigmaProp}
+
+case class TestContractSpec(testSuite: SigmaTestingCommons)(implicit val IR: IRContext) extends ContractSpec {
+
+ case class TestPropositionSpec(name: String, dslSpec: Proposition, scriptSpec: ErgoScript) extends PropositionSpec {
+ lazy val ergoTree: ErgoTree = {
+ val value = testSuite.compile(scriptSpec.env, scriptSpec.code)
+ val tree: ErgoTree = value.asSigmaProp
+ tree
+ }
+ }
+
+ override private[dsl] def mkPropositionSpec(name: String, dslSpec: Proposition, scriptSpec: ErgoScript) =
+ TestPropositionSpec(name, dslSpec, scriptSpec)
+
+
+ case class TestProvingParty(name: String) extends ProvingParty {
+ private val prover = new ContextEnrichingTestProvingInterpreter
+
+ val pubKey: SigmaProp = CSigmaProp(prover.dlogSecrets.head.publicImage)
+
+ import SType.AnyOps
+ def prove(inBox: InputBox, extensions: Map[Byte, AnyValue] = Map()): Try[CostedProverResult] = {
+ val boxToSpend = inBox.utxoBox
+ val propSpec: PropositionSpec = boxToSpend.propSpec
+ val bindings = extensions.mapValues { case v: TestValue[a] =>
+ implicit val tA = v.tA
+ val treeType = Evaluation.toErgoTreeType(tA)
+ val treeData = Evaluation.fromDslData(v.value, tRes = treeType)
+ IR.builder.mkConstant(treeData.asWrappedType, Evaluation.rtypeToSType(v.tA))
+ }
+ val ctx = inBox.toErgoContext
+// val newExtension = ContextExtension(ctx.extension.values ++ bindings)
+ val env = propSpec.scriptSpec.env + (ScriptNameProp -> (propSpec.name + "_prove"))
+ val prop = propSpec.ergoTree
+ val p = bindings.foldLeft(prover) { (p, b) => p.withContextExtender(b._1, b._2) }
+ val proof = p.prove(env, prop, ctx, testSuite.fakeMessage)
+ proof
+ }
+ }
+
+ override protected def mkProvingParty(name: String): ProvingParty = TestProvingParty(name)
+
+ case class TestVerifyingParty(name: String) extends VerifyingParty {
+ private val verifier = new ErgoLikeTestInterpreter
+
+ def verify(inBox: InputBox, proverResult: ProverResult) = {
+ val boxToSpend = inBox.utxoBox
+ val propSpec = boxToSpend.propSpec
+ val ctx = inBox.toErgoContext
+ val env = propSpec.scriptSpec.env + (ScriptNameProp -> (propSpec.name + "_verify"))
+ val prop = propSpec.ergoTree
+ verifier.verify(env, prop, ctx, proverResult, testSuite.fakeMessage).get._1
+ }
+ }
+
+ override protected def mkVerifyingParty(name: String): VerifyingParty = TestVerifyingParty(name)
+
+ case class TestInputBox(tx: TransactionCandidate, utxoBox: OutBox) extends InputBox {
+ private [dsl] def toErgoContext: ErgoLikeContext = {
+ val propSpec = utxoBox.propSpec
+ val ctx = new ErgoLikeContext(
+ currentHeight = tx.block.height,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ headers = noHeaders,
+ preHeader = dummyPreHeader,
+ dataBoxes = tx.dataInputs.map(_.utxoBox.ergoBox).toIndexedSeq,
+ boxesToSpend = tx.inputs.map(_.utxoBox.ergoBox).toIndexedSeq,
+ spendingTransaction = testSuite.createTransaction(tx.outputs.map(_.ergoBox).toIndexedSeq),
+ self = utxoBox.ergoBox)
+ ctx
+ }
+ def runDsl(extensions: Map[Byte, AnyValue] = Map()): SigmaProp = {
+ val ctx = toErgoContext.toSigmaContext(IR, false, extensions)
+ val res = utxoBox.propSpec.dslSpec(ctx)
+ res
+ }
+ }
+
+ case class TestOutBox(tx: TransactionCandidate, boxIndex: Int, value: Long, propSpec: PropositionSpec) extends OutBox {
+ private var _tokens: Seq[Token] = Seq()
+ private var _regs: Map[NonMandatoryRegisterId, _ <: EvaluatedValue[_ <: SType]] = Map()
+
+ def withTokens(tokens: Token*) = { _tokens = tokens.toSeq; this }
+ def withRegs(regs: (NonMandatoryRegisterId, Any)*) = {
+ _regs = regs.map { case (id, v) =>
+ val lifted = IR.builder.liftAny(v) match {
+ case Nullable(v) => v
+ case _ =>
+ sys.error(s"Invalid value for register R${id.number}: $v")
+ }
+ (id, lifted.asInstanceOf[EvaluatedValue[_ <: SType]])
+ }.toMap
+ this
+ }
+
+ override def token(id: TokenId): Token = {
+ val optToken = _tokens.collectFirst { case t if t.id == id => t }
+ optToken.getOrElse(sys.error(s"Token with id=$id not found in the box $this"))
+ }
+
+ private[dsl] lazy val ergoBox: ErgoBox = {
+ val tokens = _tokens.map { t => (Digest32 @@ t.id.toArray, t.value) }
+ ErgoBox(value, propSpec.ergoTree, tx.block.height, tokens, _regs)
+ }
+ def id = ergoBox.id
+ }
+
+ case class MockTransaction(block: BlockCandidate) extends TransactionCandidate {
+ private val _inputs: ArrayBuffer[InputBox] = mutable.ArrayBuffer.empty[InputBox]
+ def inputs: Seq[InputBox] = _inputs
+
+ private val _dataInputs: ArrayBuffer[InputBox] = mutable.ArrayBuffer.empty[InputBox]
+ def dataInputs: Seq[InputBox] = _dataInputs
+
+ private val _outputs = mutable.ArrayBuffer.empty[OutBox]
+ def outputs: Seq[OutBox] = _outputs
+
+ def inBox(utxoBox: OutBox) = {
+ val box = TestInputBox(this, utxoBox)
+ _inputs += box
+ box
+ }
+
+ def dataBox(dataBox: OutBox) = {
+ val box = TestInputBox(this, dataBox)
+ _dataInputs += box
+ box
+ }
+
+ def outBox(value: Long, propSpec: PropositionSpec) = {
+ val box = TestOutBox(this, _outputs.size, value, propSpec)
+ _outputs += box
+ box
+ }
+
+ def spending(utxos: OutBox*) = {
+ for (b <- utxos) inBox(b)
+ this
+ }
+
+ def withDataInputs(dataBoxes: OutBox*) = {
+ for (b <- dataBoxes) dataBox(b)
+ this
+ }
+
+ }
+
+ case class BBlockCandidate(height: Int) extends BlockCandidate {
+ def newTransaction() = MockTransaction(this)
+// def onTopOf(chain: ChainBlock*)
+ }
+
+ def candidateBlock(height: Int): BlockCandidate = BBlockCandidate(height)
+}
diff --git a/src/test/scala/sigmastate/CalcSha256Specification.scala b/src/test/scala/sigmastate/CalcSha256Specification.scala
index c2e238f5e3..39f1fea9ef 100644
--- a/src/test/scala/sigmastate/CalcSha256Specification.scala
+++ b/src/test/scala/sigmastate/CalcSha256Specification.scala
@@ -1,11 +1,10 @@
package sigmastate
import org.ergoplatform.ErgoLikeContext
-import org.scalatest.prop.{PropertyChecks, TableFor2, GeneratorDrivenPropertyChecks}
-import org.scalatest.Matchers
+import org.scalatest.prop.TableFor2
import scorex.util.encode.Base16
import sigmastate.Values.{CollectionConstant, ByteArrayConstant}
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, SigmaTestingCommons}
class CalcSha256Specification extends SigmaTestingCommons {
implicit lazy val IR = new TestingIRContext
@@ -30,13 +29,13 @@ class CalcSha256Specification extends SigmaTestingCommons {
)
property("CalcSha256: Should pass standard tests.") {
- val int = new ErgoLikeTestProvingInterpreter()
+ val int = new ContextEnrichingTestProvingInterpreter()
val ctx = ErgoLikeContext.dummy(fakeSelf)
forAll(objects) { (in, result) =>
- val calcSha256 = CalcSha256(stringToByteConstant(in))
val expectedResult = decodeString(result)
+ val calcSha256 = EQ(CalcSha256(stringToByteConstant(in)), expectedResult)
val res = int.reduceToCrypto(ctx, calcSha256).get._1
- res shouldBe expectedResult
+ res shouldBe TrivialProp.TrueProp
}
}
diff --git a/src/test/scala/sigmastate/FailingToProveSpec.scala b/src/test/scala/sigmastate/FailingToProveSpec.scala
new file mode 100644
index 0000000000..2dc1ecfb6d
--- /dev/null
+++ b/src/test/scala/sigmastate/FailingToProveSpec.scala
@@ -0,0 +1,84 @@
+package sigmastate
+
+import org.ergoplatform.{ErgoBox, ErgoLikeContext, ErgoLikeInterpreter, ErgoLikeTransaction}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
+import sigmastate.lang.Terms._
+import org.scalatest.TryValues._
+import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
+import org.ergoplatform.ErgoScriptPredef._
+
+class FailingToProveSpec extends SigmaTestingCommons {
+ implicit lazy val IR = new TestingIRContext
+ /**
+ * Both properties should work fine.
+ * Currently the problem in first case is that even if we evaluate `withdrawCondition1 == true`
+ * we are still try to evaluate `withdrawCondition2` which leads to something like IndexOutOfBoundsError.
+ * Cause second condition has 3 outputs in body, while we are have only two in tx.
+ */
+ property("successfully evaluate proof 1") {
+ val interpreter = new ContextEnrichingTestProvingInterpreter
+ val verifier = new ErgoLikeTestInterpreter()
+
+ val env = Map.empty[String, Any]
+ val compiledScript = compile(env,
+ s"""
+ | {
+ | val withdrawCondition1 =
+ | OUTPUTS(0).value == 101L && OUTPUTS(1).value == 99L
+ | val withdrawCondition2 =
+ | OUTPUTS(0).value == 102L && OUTPUTS(1).value == 98L && OUTPUTS(2).value == 100L
+ |
+ | withdrawCondition1 || withdrawCondition2
+ | }
+ """.stripMargin).asBoolValue.toSigmaProp
+
+ val selfBox = ErgoBox(200L, compiledScript, 0)
+ val o1 = ErgoBox(101L, TrueProp, 5001)
+ val o2 = ErgoBox(99L, TrueProp, 5001)
+ val tx = createTransaction(IndexedSeq(o1, o2))
+ val ctx = ErgoLikeContext(
+ currentHeight = 5001,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ boxesToSpend = IndexedSeq(selfBox),
+ spendingTransaction = tx,
+ self = selfBox,
+ minerPubkey = ErgoLikeContext.dummyPubkey)
+ val proof = interpreter.prove(emptyEnv + (ScriptNameProp -> "prove"), compiledScript, ctx, fakeMessage).success.value.proof
+ verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), compiledScript, ctx, proof, fakeMessage) should be a 'success
+ }
+
+ property("successfully evaluate proof 2") {
+ val interpreter = new ContextEnrichingTestProvingInterpreter
+ val verifier = new ErgoLikeTestInterpreter()
+
+ val env = Map.empty[String, Any]
+ val compiledScript = compile(env,
+ s"""
+ | {
+ |
+ | val withdrawCondition1 =
+ | OUTPUTS(0).value == 101L && OUTPUTS(1).value == 99L
+ | val withdrawCondition2 =
+ | OUTPUTS(0).value == 102L && OUTPUTS(1).value == 98L && OUTPUTS(2).value == 100L
+ |
+ | withdrawCondition1 || withdrawCondition2
+ | }
+ """.stripMargin).asBoolValue.toSigmaProp
+
+ val selfBox = ErgoBox(200L, compiledScript, 0)
+ val o1 = ErgoBox(102L, TrueProp, 5001)
+ val o2 = ErgoBox(98L, TrueProp, 5001)
+ val o3 = ErgoBox(100L, TrueProp, 5001)
+ val tx = createTransaction(IndexedSeq(o1, o2, o3))
+ val ctx = ErgoLikeContext(
+ currentHeight = 5001,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ boxesToSpend = IndexedSeq(selfBox),
+ spendingTransaction = tx,
+ self = selfBox,
+ minerPubkey = ErgoLikeContext.dummyPubkey)
+ val proof = interpreter.prove(emptyEnv + (ScriptNameProp -> "prove"), compiledScript, ctx, fakeMessage).success.value.proof
+ verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), compiledScript, ctx, proof, fakeMessage) should be a 'success
+ }
+
+}
diff --git a/src/test/scala/sigmastate/TestingInterpreterSpecification.scala b/src/test/scala/sigmastate/TestingInterpreterSpecification.scala
index 8fbffeb0bf..10c682ac14 100644
--- a/src/test/scala/sigmastate/TestingInterpreterSpecification.scala
+++ b/src/test/scala/sigmastate/TestingInterpreterSpecification.scala
@@ -1,63 +1,61 @@
package sigmastate
-import org.scalatest.prop.{PropertyChecks, GeneratorDrivenPropertyChecks}
-import org.scalatest.{PropSpec, Matchers}
import sigmastate.basics.DLogProtocol.{ProveDlog, DLogProverInput}
import scorex.crypto.hash.Blake2b256
import sigmastate.Values._
import sigmastate.interpreter._
import Interpreter._
-import sigmastate.lang.{TransformingSigmaBuilder, SigmaCompiler}
-import sigmastate.utxo.CostTable
import sigmastate.lang.Terms._
-import sigmastate.eval.{IRContext, CostingDataContext, Evaluation, CostingBox}
-import special.sigma
-import org.ergoplatform.{Height, ErgoBox, ErgoLikeContext}
+import org.ergoplatform._
import scorex.util.encode.Base58
-import sigmastate.helpers.SigmaTestingCommons
+import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons, ErgoLikeTestInterpreter}
import sigmastate.serialization.ValueSerializer
-import special.sigma.{AnyValue, Box, TestAvlTree}
import TrivialProp._
import scala.util.Random
-
-
class TestingInterpreterSpecification extends SigmaTestingCommons {
implicit lazy val IR = new TestingIRContext
-
- lazy val TestingInterpreter = new TestingInterpreter
- import TestingInterpreter._
+ lazy val prover = new ErgoLikeTestProvingInterpreter()
+ lazy val verifier = new ErgoLikeTestInterpreter
implicit val soundness = CryptoConstants.soundnessBits
+
+ def testingContext(h: Int) =
+ ErgoLikeContext(h,
+ AvlTreeData.dummy, ErgoLikeContext.dummyPubkey, IndexedSeq(fakeSelf),
+ ErgoLikeTransaction(IndexedSeq.empty, IndexedSeq.empty),
+ fakeSelf)
property("Reduction to crypto #1") {
forAll() { (h: Int) =>
whenever(h > 0 && h < Int.MaxValue - 1) {
val dk1 = SigmaPropConstant(DLogProverInput.random().publicImage).isProven
- val ctx = TestingContext(h)
- reduceToCrypto(ctx, AND(GE(Height, IntConstant(h - 1)), dk1)).get._1 should(
+ val ctx = testingContext(h)
+ prover.reduceToCrypto(ctx, AND(GE(Height, IntConstant(h - 1)), dk1)).get._1 should(
matchPattern { case sb: SigmaBoolean => })
- reduceToCrypto(ctx, AND(GE(Height, IntConstant(h)), dk1)).get._1 should (
+ prover.reduceToCrypto(ctx, AND(GE(Height, IntConstant(h)), dk1)).get._1 should (
matchPattern { case sb: SigmaBoolean => })
{
- val res = reduceToCrypto(ctx, AND(GE(Height, IntConstant(h + 1)), dk1)).get._1
+ val res = prover.reduceToCrypto(ctx, AND(GE(Height, IntConstant(h + 1)), dk1)).get._1
res should matchPattern { case FalseProp => }
}
{
- val res = reduceToCrypto(ctx, OR(GE(Height, IntConstant(h - 1)), dk1)).get._1
+ val res = prover.reduceToCrypto(ctx, OR(GE(Height, IntConstant(h - 1)), dk1)).get._1
res should matchPattern { case TrueProp => }
}
{
- val res = reduceToCrypto(ctx, OR(GE(Height, IntConstant(h)), dk1)).get._1
+ val res = prover.reduceToCrypto(ctx, OR(GE(Height, IntConstant(h)), dk1)).get._1
res should matchPattern { case TrueProp => }
}
- reduceToCrypto(ctx, OR(GE(Height, IntConstant(h + 1)), dk1)).get._1 should(
- matchPattern { case sb: SigmaBoolean => })
+ {
+ val res = prover.reduceToCrypto(ctx, OR(GE(Height, IntConstant(h + 1)), dk1)).get._1
+ res should matchPattern { case sb: SigmaBoolean => }
+ }
}
}
}
@@ -70,25 +68,25 @@ class TestingInterpreterSpecification extends SigmaTestingCommons {
val dk1 = DLogProverInput.random().publicImage.isProven
val dk2 = DLogProverInput.random().publicImage.isProven
- val ctx = TestingContext(h)
+ val ctx = testingContext(h)
- assert(reduceToCrypto(ctx, OR(
+ assert(prover.reduceToCrypto(ctx, OR(
AND(LE(Height, IntConstant(h + 1)), AND(dk1, dk2)),
AND(GT(Height, IntConstant(h + 1)), dk1)
)).get._1.isInstanceOf[CAND])
- assert(reduceToCrypto(ctx, OR(
+ assert(prover.reduceToCrypto(ctx, OR(
AND(LE(Height, IntConstant(h - 1)), AND(dk1, dk2)),
AND(GT(Height, IntConstant(h - 1)), dk1)
)).get._1.isInstanceOf[ProveDlog])
- reduceToCrypto(ctx, OR(
+ prover.reduceToCrypto(ctx, OR(
AND(LE(Height, IntConstant(h - 1)), AND(dk1, dk2)),
AND(GT(Height, IntConstant(h + 1)), dk1)
)).get._1 shouldBe FalseProp
- reduceToCrypto(ctx,
+ prover.reduceToCrypto(ctx,
OR(
OR(
AND(LE(Height, IntConstant(h - 1)), AND(dk1, dk2)),
@@ -106,23 +104,23 @@ class TestingInterpreterSpecification extends SigmaTestingCommons {
val reg1 = ErgoBox.nonMandatoryRegisters.head
val reg2 = ErgoBox.nonMandatoryRegisters(1)
- val dk1 = ProveDlog(secrets(0).publicImage.h)
- val dk2 = ProveDlog(secrets(1).publicImage.h)
- val ctx = TestingContext(99)
+ val dk1 = prover.dlogSecrets(0).publicImage
+ val dk2 = prover.dlogSecrets(1).publicImage
+ val ctx = testingContext(99)
val env = Map(
"dk1" -> dk1,
"dk2" -> dk2,
"bytes1" -> Array[Byte](1, 2, 3),
"bytes2" -> Array[Byte](4, 5, 6),
- "box1" -> ErgoBox(10, TrueLeaf, 0, Seq(), Map(
+ "box1" -> ErgoBox(10, ErgoScriptPredef.TrueProp, 0, Seq(), Map(
reg1 -> IntArrayConstant(Array[Int](1, 2, 3)),
reg2 -> BoolArrayConstant(Array[Boolean](true, false, true)))))
- val prop = compileWithCosting(env, code).asBoolValue
+ val prop = compile(env, code).asBoolValue.toSigmaProp
println(code)
println(prop)
val challenge = Array.fill(32)(Random.nextInt(100).toByte)
- val proof1 = TestingInterpreter.prove(prop, ctx, challenge).get.proof
- verify(Interpreter.emptyEnv, prop, ctx, proof1, challenge).map(_._1).getOrElse(false) shouldBe true
+ val proof1 = prover.prove(prop, ctx, challenge).get.proof
+ verifier.verify(Interpreter.emptyEnv, prop, ctx, proof1, challenge).map(_._1).getOrElse(false) shouldBe true
}
property("Evaluate array ops") {
@@ -203,10 +201,10 @@ class TestingInterpreterSpecification extends SigmaTestingCommons {
property("Evaluate numeric casting ops") {
def testWithCasting(castSuffix: String): Unit = {
- testEval(s"Coll(1).size.toByte.$castSuffix == 1.$castSuffix")
- testEval(s"Coll(1).size.toShort.$castSuffix == 1.$castSuffix")
- testEval(s"Coll(1).size.toInt.$castSuffix == 1.$castSuffix")
- testEval(s"Coll(1).size.toLong.$castSuffix == 1.$castSuffix")
+ testEval(s"OUTPUTS.size.toByte.$castSuffix == 0.$castSuffix")
+ testEval(s"OUTPUTS.size.toShort.$castSuffix == 0.$castSuffix")
+ testEval(s"OUTPUTS.size.toInt.$castSuffix == 0.$castSuffix")
+ testEval(s"OUTPUTS.size.toLong.$castSuffix == 0.$castSuffix")
}
testWithCasting("toByte")
testWithCasting("toShort")
@@ -252,83 +250,83 @@ class TestingInterpreterSpecification extends SigmaTestingCommons {
}
property("Evaluation example #1") {
- val dk1 = ProveDlog(secrets(0).publicImage.h).isProven
- val dk2 = ProveDlog(secrets(1).publicImage.h).isProven
+ val dk1 = prover.dlogSecrets(0).publicImage.isProven
+ val dk2 = prover.dlogSecrets(1).publicImage.isProven
- val env1 = TestingContext(99)
- val env2 = TestingContext(101)
+ val env1 = testingContext(99)
+ val env2 = testingContext(101)
val prop = OR(
AND(LE(Height, IntConstant(100)), AND(dk1, dk2)),
AND(GT(Height, IntConstant(100)), dk1)
- )
+ ).toSigmaProp
val challenge = Array.fill(32)(Random.nextInt(100).toByte)
- val proof1 = TestingInterpreter.prove(prop, env1, challenge).get.proof
+ val proof1 = prover.prove(prop, env1, challenge).get.proof
- verify(emptyEnv, prop, env1, proof1, challenge).map(_._1).getOrElse(false) shouldBe true
+ verifier.verify(emptyEnv, prop, env1, proof1, challenge).map(_._1).getOrElse(false) shouldBe true
- verify(emptyEnv, prop, env2, proof1, challenge).map(_._1).getOrElse(false) shouldBe false
+ verifier.verify(emptyEnv, prop, env2, proof1, challenge).map(_._1).getOrElse(false) shouldBe false
}
property("Evaluation - no real proving - true case") {
- val prop1 = TrueLeaf
+ val prop1 = ErgoScriptPredef.TrueProp
val challenge = Array.fill(32)(Random.nextInt(100).toByte)
val proof = NoProof
- val env = TestingContext(99)
+ val env = testingContext(99)
- verify(prop1, env, proof, challenge).map(_._1).getOrElse(false) shouldBe true
+ verifier.verify(prop1, env, proof, challenge).map(_._1).fold(t => throw t, identity) shouldBe true
- val prop2 = OR(TrueLeaf, FalseLeaf)
- verify(prop2, env, proof, challenge).map(_._1).getOrElse(false) shouldBe true
+ val prop2 = OR(TrueLeaf, FalseLeaf).toSigmaProp
+ verifier.verify(prop2, env, proof, challenge).map(_._1).fold(t => throw t, identity) shouldBe true
- val prop3 = AND(TrueLeaf, TrueLeaf)
- verify(prop3, env, proof, challenge).map(_._1).getOrElse(false) shouldBe true
+ val prop3 = AND(TrueLeaf, TrueLeaf).toSigmaProp
+ verifier.verify(prop3, env, proof, challenge).map(_._1).fold(t => throw t, identity) shouldBe true
- val prop4 = GT(Height, IntConstant(90))
- verify(prop4, env, proof, challenge).map(_._1).getOrElse(false) shouldBe true
+ val prop4 = GT(Height, IntConstant(90)).toSigmaProp
+ verifier.verify(prop4, env, proof, challenge).map(_._1).fold(t => throw t, identity) shouldBe true
}
property("Evaluation - no real proving - false case") {
- val prop1 = FalseLeaf
+ val prop1 = ErgoScriptPredef.FalseProp
val challenge = Array.fill(32)(Random.nextInt(100).toByte)
val proof = NoProof
- val env = TestingContext(99)
+ val env = testingContext(99)
- verify(prop1, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
+ verifier.verify(prop1, env, proof, challenge).map(_._1).fold(t => throw t, identity) shouldBe false
- val prop2 = OR(FalseLeaf, FalseLeaf)
- verify(prop2, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
+ val prop2 = OR(FalseLeaf, FalseLeaf).toSigmaProp
+ verifier.verify(prop2, env, proof, challenge).map(_._1).fold(t => throw t, identity) shouldBe false
- val prop3 = AND(FalseLeaf, TrueLeaf)
- verify(prop3, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
+ val prop3 = AND(FalseLeaf, TrueLeaf).toSigmaProp
+ verifier.verify(prop3, env, proof, challenge).map(_._1).fold(t => throw t, identity) shouldBe false
- val prop4 = GT(Height, LongConstant(100))
- verify(prop4, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
+ val prop4 = GT(Height, LongConstant(100)).toSigmaProp
+ verifier.verify(prop4, env, proof, challenge).map(_._1).fold(t => throw t, identity) shouldBe false
}
property("Evaluation - hash function") {
val bytes = "hello world".getBytes
val hash = Blake2b256(bytes)
- val prop1 = EQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(hash))
+ val prop1 = EQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(hash)).toSigmaProp
val challenge = Array.fill(32)(Random.nextInt(100).toByte)
val proof = NoProof
- val env = TestingContext(99)
+ val env = testingContext(99)
- verify(prop1, env, proof, challenge).map(_._1).getOrElse(false) shouldBe true
+ verifier.verify(prop1, env, proof, challenge).map(_._1).getOrElse(false) shouldBe true
- val prop2 = NEQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(hash))
+ val prop2 = NEQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(hash)).toSigmaProp
- verify(prop2, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
+ verifier.verify(prop2, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
- val prop3 = EQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(bytes))
+ val prop3 = EQ(CalcBlake2b256(ByteArrayConstant(bytes)), ByteArrayConstant(bytes)).toSigmaProp
- verify(prop3, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
+ verifier.verify(prop3, env, proof, challenge).map(_._1).getOrElse(false) shouldBe false
}
property("passing a lambda argument") {
@@ -355,7 +353,7 @@ class TestingInterpreterSpecification extends SigmaTestingCommons {
// block with nested lambda (assigned to a val)
testEval(
""" Coll[Int](1,2,3).exists { (a: Int) =>
- | val g = { (c: Int) => c == 1 }
+ | def g(c: Int) = c == 1
| Coll[Int](1).exists(g)
| } == true """.stripMargin)
}
@@ -366,31 +364,3 @@ class TestingInterpreterSpecification extends SigmaTestingCommons {
}
}
-
-case class TestingContext(height: Int,
- override val extension: ContextExtension = ContextExtension(values = Map())
- ) extends Context {
- override def withExtension(newExtension: ContextExtension): TestingContext = this.copy(extension = newExtension)
-
- override def toSigmaContext(IR: Evaluation, isCost: Boolean): sigma.Context = {
- val inputs = Array[Box]()
- val outputs = Array[Box]()
- val vars = Array[AnyValue]()
- val noBytes = IR.sigmaDslBuilderValue.Cols.fromArray[Byte](Array[Byte]())
- val emptyAvlTree = TestAvlTree(noBytes, 0, None, None, None)
- new CostingDataContext(IR, inputs, outputs, height, selfBox = null,
- lastBlockUtxoRootHash = emptyAvlTree, minerPubKey = ErgoLikeContext.dummyPubkey,
- vars = vars, isCost = isCost)
- }
-
-}
-
-/** An interpreter for tests with 2 random secrets*/
-class TestingInterpreter(implicit val IR: IRContext) extends Interpreter with ProverInterpreter {
- override type CTX = TestingContext
-
- override val maxCost = CostTable.ScriptLimit
-
- override lazy val secrets: Seq[DLogProverInput] =
- Seq(DLogProverInput.random(), DLogProverInput.random())
-}
diff --git a/src/test/scala/sigmastate/crypto/GroupLawsSpecification.scala b/src/test/scala/sigmastate/crypto/GroupLawsSpecification.scala
new file mode 100644
index 0000000000..f2cd2ca808
--- /dev/null
+++ b/src/test/scala/sigmastate/crypto/GroupLawsSpecification.scala
@@ -0,0 +1,34 @@
+package sigmastate.crypto
+
+import java.math.BigInteger
+
+import sigmastate.helpers.SigmaTestingCommons
+import sigmastate.interpreter.CryptoConstants
+
+class GroupLawsSpecification extends SigmaTestingCommons {
+ private val group = CryptoConstants.dlogGroup
+
+ property("multiplication law is complete") {
+ val identity = group.identity
+ val ge = group.createRandomGenerator()
+
+ group.multiplyGroupElements(ge, ge) shouldBe group.exponentiate(ge, new BigInteger("2"))
+ group.multiplyGroupElements(ge, identity) shouldBe group.exponentiate(ge, BigInteger.ONE)
+ group.multiplyGroupElements(ge, identity) shouldBe ge
+ group.multiplyGroupElements(identity, identity) shouldBe identity
+
+ val inverse = group.getInverse(ge)
+ group.multiplyGroupElements(ge, inverse) shouldBe identity
+ }
+
+ property("exponentiation") {
+ val identity = group.identity
+ val ge = group.createRandomGenerator()
+
+ group.exponentiate(ge, BigInteger.ZERO) shouldBe identity
+ group.exponentiate(ge, BigInteger.ONE) shouldBe ge
+ group.exponentiate(ge, group.order) shouldBe identity
+ group.exponentiate(ge, group.order.add(BigInteger.ONE)) shouldBe ge
+ }
+
+}
diff --git a/src/test/scala/sigmastate/eval/BasicOpsTests.scala b/src/test/scala/sigmastate/eval/BasicOpsTests.scala
new file mode 100644
index 0000000000..7de0d29af8
--- /dev/null
+++ b/src/test/scala/sigmastate/eval/BasicOpsTests.scala
@@ -0,0 +1,99 @@
+package sigmastate.eval
+
+import java.math.BigInteger
+
+import org.bouncycastle.crypto.ec.CustomNamedCurves
+import org.scalatest.{FunSuite, Matchers}
+import special.sigma.Extensions._
+import special.sigma.{Box, Context, ContractsTestkit, MockSigma, SigmaContract, SigmaDslBuilder, SigmaProp, TestBox, TestSigmaDslBuilder}
+
+import scala.language.implicitConversions
+
+class BasicOpsTests extends FunSuite with ContractsTestkit with Matchers {
+ override val SigmaDsl: SigmaDslBuilder = CostingSigmaDslBuilder
+
+ implicit def boolToSigma(b: Boolean): SigmaProp = MockSigma(b)
+
+ test("atLeast") {
+ val props = Colls.fromArray(Array[SigmaProp](false, true, true, false))
+
+ // border cases
+ SigmaDsl.atLeast(0, props).isValid shouldBe true
+ SigmaDsl.atLeast(5, props).isValid shouldBe false
+
+ // normal cases
+ SigmaDsl.atLeast(1, props).isValid shouldBe true
+ SigmaDsl.atLeast(2, props).isValid shouldBe true
+ SigmaDsl.atLeast(3, props).isValid shouldBe false
+ }
+
+ test("ByteArrayToBigInt should always produce a positive big int") {
+ SigmaDsl.byteArrayToBigInt(collection[Byte](-1)).signum shouldBe 1
+ }
+
+ test("ByteArrayToBigInt should always produce big int less than dlog group order") {
+ val groupOrder = CustomNamedCurves.getByName("secp256k1").getN
+
+ SigmaDsl.byteArrayToBigInt(
+ Colls.fromArray(groupOrder.subtract(BigInteger.ONE).toByteArray)
+ ).compareTo(SigmaDsl.BigInt(BigInteger.ONE)) shouldBe 1
+
+ SigmaDsl.byteArrayToBigInt(
+ Colls.fromArray(groupOrder.toByteArray)
+ ).compareTo(SigmaDsl.BigInt(BigInteger.ONE)) shouldBe 1
+
+ an [RuntimeException] should be thrownBy
+ SigmaDsl.byteArrayToBigInt(Colls.fromArray(groupOrder.add(BigInteger.ONE).toByteArray))
+
+ an [RuntimeException] should be thrownBy
+ SigmaDsl.byteArrayToBigInt(Colls.fromArray(Array.fill[Byte](500)(1)))
+ }
+
+ def test(f: Context => Boolean, ctx: Context, expected: Boolean) = {
+ val contr = NoEnvContract(f)
+ val res = contr.canOpen(ctx)
+ res shouldBe expected
+ }
+
+ test("Coll.append") {
+ val c1 = collection[Byte](1, 2)
+ val c2 = collection[Byte](3, 4)
+ c1.append(c2).toArray shouldBe Array[Byte](1, 2, 3, 4)
+ }
+ test("examples from wpaper") {
+ val selfId = collection[Byte](0, 1)
+ val self = new TestBox(selfId, 10, noBytes, noBytes, noBytes, noRegisters)
+ val ctx = testContext(noInputs, noOutputs, height = 200, self, emptyAvlTree, dummyPubkey, Array())
+ }
+
+ test("box.creationInfo._1 is Int") {
+ val box = newAliceBox(1, 100, Map(3 -> toAnyValue((20 -> SigmaDsl.Colls.fromArray(Array.emptyByteArray)))))
+ box.creationInfo._1 shouldBe a [Integer]
+ }
+
+
+ case class Contract1(base64_pk1: String) extends SigmaContract {
+ override def builder: SigmaDslBuilder = new TestSigmaDslBuilder
+ override def canOpen(ctx: Context): Boolean = {
+ val pk: SigmaProp = SigmaDsl.PubKey(base64_pk1)
+ pk.isValid
+ }
+ }
+
+ case class Contract2(base64_pkA: String, base64_pkB: String, base64_pkC: String) extends SigmaContract {
+ override def builder: SigmaDslBuilder = new TestSigmaDslBuilder
+ override def canOpen(ctx: Context): Boolean = {
+ val pkA: SigmaProp = SigmaDsl.PubKey(base64_pkA)
+ val pkB: SigmaProp = SigmaDsl.PubKey(base64_pkB)
+ val pkC: SigmaProp = SigmaDsl.PubKey(base64_pkC)
+ verifyZK(pkA || pkB || pkC)
+ }
+ }
+
+ case class FriendContract(friend: Box) extends SigmaContract {
+ override def builder: SigmaDslBuilder = new TestSigmaDslBuilder
+ override def canOpen(ctx: Context): Boolean = {ctx.INPUTS.length == 2 && ctx.INPUTS(0).id == friend.id}
+ }
+
+
+}
diff --git a/src/test/scala/sigmastate/eval/CompilerItTest.scala b/src/test/scala/sigmastate/eval/CompilerItTest.scala
index 98403347a1..8cb34d58f3 100644
--- a/src/test/scala/sigmastate/eval/CompilerItTest.scala
+++ b/src/test/scala/sigmastate/eval/CompilerItTest.scala
@@ -7,16 +7,17 @@ import org.ergoplatform._
import sigmastate.SCollection.SByteArray
import sigmastate._
import sigmastate.Values.{BigIntArrayConstant, BigIntConstant, ByteArrayConstant, FalseLeaf, GroupElementConstant, IntConstant, LongConstant, SigmaBoolean, SigmaPropConstant, TrueLeaf, ValUse}
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
+import sigmastate.helpers.ContextEnrichingTestProvingInterpreter
import sigmastate.interpreter.{ContextExtension, CryptoConstants}
import sigmastate.lang.DefaultSigmaBuilder.mkTaggedVariable
import sigmastate.lang.LangTests
import sigmastate.utxo._
-import special.collection.{Col => VCol}
+import special.collection.{Coll => VColl}
import special.sigma.{TestValue => VTestValue}
import scalan.BaseCtxTests
import scalan.util.BenchmarkUtil._
import sigmastate.basics.DLogProtocol
+import special.sigma._
class CompilerItTest extends BaseCtxTests
with LangTests with ExampleContracts with ErgoScriptTestkit {
@@ -24,16 +25,17 @@ class CompilerItTest extends BaseCtxTests
import builder._
import WArray._
import WOption._
- import ColBuilder._
+ import CollBuilder._
+ import SigmaDslBuilder._
import Context._
- import Col._
+ import Coll._
import SigmaProp._
- import CostedCol._
- import CCostedCol._
+ import CostedColl._
+ import CCostedColl._
import WBigInteger._
import WECPoint._
- import ProveDlogEvidence._
- import ProveDHTEvidence._
+ import BigInt._
+ import GroupElement._
import sigmastate.serialization.OpCodes._
import Liftables._
import SType.AnyOps
@@ -43,21 +45,21 @@ class CompilerItTest extends BaseCtxTests
Case(env, "intConst", "1", ergoCtx,
calc = {_ => 1 },
cost = {_ => constCost[Int]},
- size = {_ => sizeOf(1)},
+ size = null,
tree = IntConstant(1), Result(1, 1, 4))
}
- test("intConstCase") {
+ ignore("intConstCase") {
intConstCase.doReduce
}
def bigIntegerConstCase = {
Case(env, "bigIntegerConst", "big", ergoCtx,
calc = {_ => bigSym },
- cost = {_ => constCost[WBigInteger]},
- size = {_ => SBigInt.MaxSizeInBytes },
+ cost = {_ => constCost[BigInt]},
+ size = null,
tree = BigIntConstant(big), Result(big, 1, 32))
}
- test("bigIntegerConstCase") {
+ ignore("bigIntegerConstCase") {
bigIntegerConstCase.doReduce
}
@@ -66,73 +68,69 @@ class CompilerItTest extends BaseCtxTests
val res = big.add(n1)
Case(env, "addBigIntegerConsts", "big + n1", ergoCtx,
calc = {_ => bigSym.add(n1Sym) },
- cost = {_ => constCost[WBigInteger] + constCost[WBigInteger] +
+ cost = {_ => constCost[BigInt] + constCost[BigInt] +
costOf("+", SFunc(Vector(SBigInt, SBigInt), SBigInt)) },
- size = {_ => SBigInt.MaxSizeInBytes },
+ size = null,
tree = mkPlus(BigIntConstant(big), BigIntConstant(n1)),
Result(res, 12, 32))
}
- test("addBigIntegerConstsCase") {
+ ignore("addBigIntegerConstsCase") {
addBigIntegerConstsCase.doReduce()
}
def arrayConstCase = {
val arr1 = env("arr1").asInstanceOf[Array[Byte]]
- val arr1Sym = liftConst(arr1)
- val col1Sym = colBuilder.fromArray[Byte](arr1Sym)
- val res = Cols.fromArray(arr1).arr
+ val col1Sym = liftConst(Colls.fromArray(arr1))
+ val res = Colls.fromArray(arr1).toArray
Case(env, "arrayConst", "arr1", ergoCtx,
calc = {_ => col1Sym },
- cost = {_ => constCost[Col[Byte]] },
- size = {_ => sizeOf(col1Sym) },
+ cost = {_ => constCost[Coll[Byte]] },
+ size = null,
tree = ByteArrayConstant(arr1), Result(res, 1, 2))
}
- test("arrayConstCase") {
+ ignore("arrayConstCase") {
arrayConstCase.doReduce()
}
def sigmaPropConstCase = {
- val resSym = RProveDlogEvidence(liftConst(g1.asInstanceOf[ECPoint]))
- val res = DLogProtocol.ProveDlog(g1) // NOTE! this value cannot be produced by test script
+ val res = dslValue.SigmaProp(p1)
+ val resSym = liftConst(res)
Case(env, "sigmaPropConst", "p1", ergoCtx,
calc = {_ => resSym },
cost = null,
- size = {_ => CryptoConstants.groupSize.toLong },
- tree = SigmaPropConstant(p1), Result(res, 10053, 32))
+ size = null,
+ tree = SigmaPropConstant(p1), Result(p1, 10052, 33))
}
- test("sigmaPropConstCase") {
+ ignore("sigmaPropConstCase") {
sigmaPropConstCase.doReduce()
}
def andSigmaPropConstsCase = {
import SigmaDslBuilder._
- val p1Sym: Rep[SigmaProp] = RProveDlogEvidence(liftConst(g1.asInstanceOf[ECPoint]))
- val p2Sym: Rep[SigmaProp] = RProveDlogEvidence(liftConst(g2.asInstanceOf[ECPoint]))
+ val p1Dsl = dslValue.SigmaProp(p1)
+ val p2Dsl = dslValue.SigmaProp(p2)
+ val p1Sym: Rep[SigmaProp] = liftConst(p1Dsl)
+ val p2Sym: Rep[SigmaProp] = liftConst(p2Dsl)
Case(env, "andSigmaPropConsts", "p1 && p2", ergoCtx,
calc = {_ => dsl.allZK(colBuilder.fromItems(p1Sym, p2Sym)) },
cost = null,
size = null,
tree = SigmaAnd(Seq(SigmaPropConstant(p1), SigmaPropConstant(p2))),
- Result(CAND(Seq(p1, p2)), 20126, 66))
+ Result(CAND(Seq(p1, p2)), 20124, 67))
}
- test("andSigmaPropConstsCase") {
+ ignore("andSigmaPropConstsCase") {
andSigmaPropConstsCase.doReduce()
}
def bigIntArray_Map_Case = {
import SCollection._
- val res = Cols.fromArray(bigIntArr1).map(n => n.add(n1)).arr
- val arrSym = colBuilder.fromArray(liftConst(bigIntArr1))
+ val res = Colls.fromArray(bigIntegerArr1).map(n => n.add(n1)).toArray
Case(env, "bigIntArray_Map",
"bigIntArr1.map { (i: BigInt) => i + n1 }", ergoCtx,
calc = { ctx =>
- val arr = liftConst(bigIntArr1)
- val vals = colBuilder.fromArray(arr)
- val costs = colBuilder.replicate(arr.length, constCost[WBigInteger])
- val sizes = colBuilder.fromArray(liftConst(bigIntArr1.map(x => SBigInt.dataSize(x.asWrappedType))))
- val arrC = RCCostedCol(vals, costs, sizes, constCost[Col[WBigInteger]])
- vals.map(fun(n => n.add(liftConst(n1))))
+ val vals = liftConst(Colls.fromArray(bigIntegerArr1.map(dslValue.BigInt(_))))
+ vals.map(fun(n => n.add(liftConst(dslValue.BigInt(n1)))))
},
cost = null,
// {_ =>
@@ -148,13 +146,11 @@ class CompilerItTest extends BaseCtxTests
// val costs = colBuilder.replicate(arr.length, 0).zip(arrSizes).map(f)
// constCost[Coll[WBigInteger]] + costs.sum(intPlusMonoid)
// },
- size = {_ =>
- typeSize[WBigInteger] * liftConst(bigIntArr1).length.toLong
- },
- tree = mkMapCollection(BigIntArrayConstant(bigIntArr1), mkFuncValue(Vector((1,SBigInt)), ArithOp(ValUse(1,SBigInt), BigIntConstant(10L), -102))),
+ size = null,
+ tree = mkMapCollection(BigIntArrayConstant(bigIntegerArr1), mkFuncValue(Vector((1,SBigInt)), ArithOp(ValUse(1,SBigInt), BigIntConstant(10L), -102))),
Result(res, 23, 64))
}
- test("bigIntArray_Map_Case") {
+ ignore("bigIntArray_Map_Case") {
bigIntArray_Map_Case.doReduce()
}
@@ -166,9 +162,9 @@ class CompilerItTest extends BaseCtxTests
cost = null,
size = null,
tree = null,
- Result(bigIntArr1.slice(0, 1), 21, 32))
+ Result(bigIntegerArr1.slice(0, 1), 21, 32))
}
- test("bigIntArray_Slice_Case") {
+ ignore("bigIntArray_Slice_Case") {
bigIntArray_Slice_Case.doReduce()
}
@@ -194,12 +190,20 @@ class CompilerItTest extends BaseCtxTests
cost = null,
size = null,
tree = null,
- Result(bigIntArr1, 2, 64L))
+ Result(bigIntegerArr1, 11, 64L))
}
- test("register_BigIntArr_Case") {
+ ignore("register_BigIntArr_Case") {
measure(5) { i =>
register_BigIntArr_Case.doReduce()
}
+ /*
+ Iter 0: 3074 ms
+ Iter 1: 29 ms
+ Iter 2: 31 ms
+ Iter 3: 26 ms
+ Iter 4: 24 ms
+ Total time: 3184 ms
+ */
}
def register_BigIntArr_Map_Case = {
@@ -210,9 +214,9 @@ class CompilerItTest extends BaseCtxTests
cost = null,
size = null,
tree = null,
- Result(bigIntArr1.map(i => i.add(n1)), 24, 64L))
+ Result(bigIntegerArr1.map(i => i.add(n1)), 33, 64L))
}
- test("register_BigIntArr_Map_Case") {
+ ignore("register_BigIntArr_Map_Case") {
register_BigIntArr_Map_Case.doReduce()
}
@@ -224,29 +228,28 @@ class CompilerItTest extends BaseCtxTests
cost = null,
size = null,
tree = null,
- Result(bigIntArr1.slice(0,1)/*,207, 1L*/))
+ Result(bigIntegerArr1.slice(0,1)/*,207, 1L*/))
}
- test("register_BigIntArr_Slice_Case") {
+ ignore("register_BigIntArr_Slice_Case") {
register_BigIntArr_Slice_Case.doReduce()
}
def crowdFunding_Case = {
import SCollection._
- import TrivialSigma._
import SigmaDslBuilder._
import Box._
import Values._
- val prover = new ErgoLikeTestProvingInterpreter()
- val backerPK @ DLogProtocol.ProveDlog(GroupElementConstant(backer: ECPoint)) = prover.dlogSecrets(0).publicImage
- val projectPK @ DLogProtocol.ProveDlog(GroupElementConstant(project: ECPoint)) = prover.dlogSecrets(1).publicImage
+ val prover = new ContextEnrichingTestProvingInterpreter()
+ val backerPK = prover.dlogSecrets(0).publicImage
+ val projectPK = prover.dlogSecrets(1).publicImage
val env = envCF ++ Seq("projectPubKey" -> projectPK, "backerPubKey" -> backerPK)
Case(env, "crowdFunding_Case", crowdFundingScript, ergoCtx,
{ ctx: Rep[Context] =>
- val backerPubKey = RProveDlogEvidence(liftConst(backer)).asRep[SigmaProp] //ctx.getVar[SigmaProp](backerPubKeyId).get
- val projectPubKey = RProveDlogEvidence(liftConst(project)).asRep[SigmaProp] //ctx.getVar[SigmaProp](projectPubKeyId).get
- val c1 = RTrivialSigma(ctx.HEIGHT >= toRep(timeout)).asRep[SigmaProp] && backerPubKey
- val c2 = RTrivialSigma(dsl.allOf(colBuilder.fromItems(
+ val backerPubKey = liftConst(dslValue.SigmaProp(backerPK))
+ val projectPubKey = liftConst(dslValue.SigmaProp(projectPK))
+ val c1 = dsl.sigmaProp(ctx.HEIGHT >= toRep(timeout)).asRep[SigmaProp] && backerPubKey
+ val c2 = dsl.sigmaProp(dsl.allOf(colBuilder.fromItems(
ctx.HEIGHT < toRep(timeout),
ctx.OUTPUTS.exists(fun { out =>
out.value >= toRep(minToRaise) lazy_&& Thunk(out.propositionBytes === projectPubKey.propBytes)
@@ -272,10 +275,10 @@ class CompilerItTest extends BaseCtxTests
)))),
ValUse(1,SSigmaProp)
))))),
- Result({ TrivialProp.FalseProp }, 40674, 1L)
+ Result({ TrivialProp.FalseProp }, 40736, 1L)
)
}
- test("crowdFunding_Case") {
+ ignore("crowdFunding_Case") {
crowdFunding_Case.doReduce()
}
diff --git a/src/test/scala/sigmastate/eval/CostingTest.scala b/src/test/scala/sigmastate/eval/CostingTest.scala
index ffc3aca4e3..e2b6e83c50 100644
--- a/src/test/scala/sigmastate/eval/CostingTest.scala
+++ b/src/test/scala/sigmastate/eval/CostingTest.scala
@@ -6,7 +6,7 @@ import com.google.common.base.Strings
import org.bouncycastle.math.ec.ECPoint
import sigmastate._
import sigmastate.Values.{ConstantPlaceholder, _}
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
+import sigmastate.helpers.ContextEnrichingTestProvingInterpreter
import sigmastate.interpreter.CryptoConstants
import sigmastate.lang.{LangTests, SigmaCompiler, TransformingSigmaBuilder}
import sigmastate.utxo.CostTable.Cost
@@ -28,15 +28,15 @@ class CostingTest extends BaseCtxTests with LangTests with ExampleContracts with
import IR._
import WArray._
import WECPoint._
+ import GroupElement._
import WBigInteger._
- import ProveDlogEvidence._
+ import BigInt._
import Context._; import SigmaContract._
- import Cost._; import ColBuilder._; import Col._; import Box._; import SigmaProp._;
+ import Cost._; import CollBuilder._; import Coll._; import Box._; import SigmaProp._;
import SigmaDslBuilder._; import WOption._
- import TrivialSigma._
import Liftables._
- test("SType.dataSize") {
+ ignore("SType.dataSize") {
def check(tpe: SType, v: Any, exp: Long) =
tpe.dataSize(v.asWrappedType) shouldBe exp
@@ -54,52 +54,53 @@ class CostingTest extends BaseCtxTests with LangTests with ExampleContracts with
check(SGroupElement, g, CryptoConstants.groupSize)
check(SSigmaProp, DLogProtocol.ProveDlog(g), CryptoConstants.groupSize + 1)
check(sigmastate.SOption(SInt), Some(10), 1 + 4)
- def checkCol(elemTpe: SType, arr: Array[Any], exp: Long) =
+ def checkColl(elemTpe: SType, arr: Array[Any], exp: Long) =
check(sigmastate.SCollection(SInt), arr, exp)
- checkCol(SInt, Array(10,20), 2 + 2L * 4)
- checkCol(SInt, Array(), 2)
- checkCol(SBigInt, Array(BigInteger.ZERO, BigInteger.valueOf(Long.MaxValue)), 2 + 0 + 8)
+ checkColl(SInt, Array(10,20), 2 + 2L * 4)
+ checkColl(SInt, Array(), 2)
+ checkColl(SBigInt, Array(BigInteger.ZERO, BigInteger.valueOf(Long.MaxValue)), 2 + 0 + 8)
check(STuple(SInt, STuple(SInt, SInt)), Array(10, Array[Any](20, 30)), 2 + 4 + (2 + 4 + 4))
}
- test("constants") {
- check("int", "1", _ => 1, _ => constCost[Int], _ => sizeOf(1))
- check("long", "1L", _ => 1L, _ => constCost[Long], _ => sizeOf(1L))
- check("boolean", "true", _ => true, _ => constCost[Boolean], _ => sizeOf(true))
- checkInEnv(env, "byte", "b1", _ => 1.toByte, _ => constCost[Byte], _ => sizeOf(1.toByte))
-
+ ignore("constants") {
+// check("int", "1", _ => 1, _ => constCost[Int], _ => sizeOf(1))
+// check("long", "1L", _ => 1L, _ => constCost[Long], _ => sizeOf(1L))
+// check("boolean", "true", _ => true, _ => constCost[Boolean], _ => sizeOf(true))
+// checkInEnv(env, "byte", "b1", _ => 1.toByte, _ => constCost[Byte], _ => sizeOf(1.toByte))
+//
val arr1 = env("arr1").asInstanceOf[Array[Byte]]
- val symArr1 = colBuilder.fromArray(liftConst(arr1))
+ val symArr1 = liftConst(Colls.fromArray(arr1))
checkInEnv(env, "arr", "arr1",
- {_ => symArr1}, {_ => constCost[Col[Byte]]}, { _ => typeSize[Byte] * symArr1.length.toLong } )
+ {_ => symArr1},
+ {_ => constCost[Coll[Byte]]})
checkInEnv(env, "arr2", "arr1.size",
- {_ => colBuilder.fromArray(liftConst(arr1)).length },
+ {_ => liftConst(Colls.fromArray(arr1)).length },
{ _ =>
val c = ByteArrayConstant(arr1)
costOf(c) + costOf(utxo.SizeOf(c))
})
- val n1Sym = liftConst(n1)
- checkInEnv(env, "bigint", "n1", {_ => n1Sym }, { _ => constCost[WBigInteger] }, { _ => sizeOf(n1Sym) })
+ val n1Sym = liftConst(dslValue.BigInt(n1))
+ checkInEnv(env, "bigint", "n1", {_ => n1Sym }, { _ => constCost[BigInt] })
- val g1Sym = liftConst(g1.asInstanceOf[ECPoint])
- checkInEnv(env, "group", "g1", {_ => g1Sym }, {_ => constCost[WECPoint]}, { _ => typeSize[WECPoint] })
+ val g1Sym = liftConst(g1)
+ checkInEnv(env, "group", "g1", {_ => g1Sym }, {_ => constCost[GroupElement]})
checkInEnv(env, "sigmaprop", "p1.propBytes",
- { _ => RProveDlogEvidence(g1Sym).asRep[SigmaProp].propBytes }
+ { _ => liftConst(dslValue.SigmaProp(p1)).propBytes }
)
}
- test("operations") {
+ ignore("operations") {
import NumericOps._
import builder._
check("one+one", "1 + 1", _ => toRep(1) + 1,
{_ => val c1 = IntConstant(1); costOf(c1) + costOf(c1) + costOf(Plus(c1, c1)) })
- checkInEnv(env, "one+one2", "big - n1", {_ => liftConst(big).subtract(liftConst(n1))})
+ checkInEnv(env, "one+one2", "big - n1", {_ => liftConst(dslValue.BigInt(big)).subtract(liftConst(dslValue.BigInt(n1)))})
check("one_gt_one", "1 > 1", {_ => toRep(1) > 1},
{ _ =>
val c1 = IntConstant(1);
- costOf(c1) + costOf(c1)
+ costOf(c1) + costOf(c1) + costOf(GT(c1,c1))
})
// checkInEnv(env, "or", "1 > 1 || n1 < big", {_ => (toRep(1) > 1) lazy_|| Thunk(toRep(n1) < big)},
// { _ =>
@@ -145,13 +146,15 @@ class CostingTest extends BaseCtxTests with LangTests with ExampleContracts with
// ctx => ctx.OUTPUTS.filter(fun(out => { out.value >= 0L })))
}
- test("lambdas") {
+ ignore("lambdas") {
check("lam1", "{ (out: Box) => out.value >= 0L }",
ctx => fun { out: Rep[Box] => out.value >= 0L }, null, {_ => 8L})
check("lam2", "{ val f = { (out: Box) => out.value >= 0L }; f }",
ctx => fun { out: Rep[Box] => out.value >= 0L }, null, {_ => 8L})
check("lam3", "{ val f = { (out: Box) => out.value >= 0L }; f(SELF) }",
ctx => { val f = fun { out: Rep[Box] => out.value >= 0L }; Apply(f, ctx.SELF, false) })
+ check("lam4", "{ def f(out: Box) = out.value >= 0L ; f }",
+ ctx => fun { out: Rep[Box] => out.value >= 0L }, null, {_ => 8L})
}
test("if then else") {
@@ -159,29 +162,19 @@ class CostingTest extends BaseCtxTests with LangTests with ExampleContracts with
{ ctx => val x = IF (ctx.OUTPUTS.length > 0) THEN ctx.OUTPUTS(0).value ELSE ctx.SELF.value; x })
}
-
- test("substConstants") {
- import org.ergoplatform.ErgoScriptPredef._
- val minerRewardDelay = 720
- val prop = rewardOutputScriptForCurrentMiner(minerRewardDelay)
- val costed = cost(env, prop)
- val res @ Tuple(calcF, costF, sizeF) = split3(costed.asRep[Context => Costed[Any]])
- emit("substConstants", calcF, costF, sizeF)
- }
-
- test("Crowd Funding") {
- val prover = new ErgoLikeTestProvingInterpreter()
- val backerPK @ DLogProtocol.ProveDlog(GroupElementConstant(backer: ECPoint)) = prover.dlogSecrets(0).publicImage
- val projectPK @ DLogProtocol.ProveDlog(GroupElementConstant(project: ECPoint)) = prover.dlogSecrets(1).publicImage
+ ignore("Crowd Funding") {
+ val prover = new ContextEnrichingTestProvingInterpreter()
+ val backerPK = prover.dlogSecrets(0).publicImage
+ val projectPK = prover.dlogSecrets(1).publicImage
val env = envCF ++ Seq("projectPubKey" -> projectPK, "backerPubKey" -> backerPK)
checkInEnv(env, "CrowdFunding", crowdFundingScript,
{ ctx: Rep[Context] =>
- val backerPubKey = RProveDlogEvidence(liftConst(backer)).asRep[SigmaProp] //ctx.getVar[SigmaProp](backerPubKeyId).get
- val projectPubKey = RProveDlogEvidence(liftConst(project)).asRep[SigmaProp] //ctx.getVar[SigmaProp](projectPubKeyId).get
+ val backerPubKey = liftConst(dslValue.SigmaProp(backerPK))
+ val projectPubKey = liftConst(dslValue.SigmaProp(projectPK))
val projectBytes = projectPubKey.propBytes
- val c1 = RTrivialSigma(ctx.HEIGHT >= toRep(timeout)).asRep[SigmaProp] && backerPubKey
- val c2 = RTrivialSigma(dsl.allOf(colBuilder.fromItems(
+ val c1 = dsl.sigmaProp(ctx.HEIGHT >= toRep(timeout)).asRep[SigmaProp] && backerPubKey
+ val c2 = dsl.sigmaProp(dsl.allOf(colBuilder.fromItems(
ctx.HEIGHT < toRep(timeout),
ctx.OUTPUTS.exists(fun { out =>
out.value >= toRep(minToRaise) lazy_&& Thunk(out.propositionBytes === projectBytes)
@@ -193,9 +186,9 @@ class CostingTest extends BaseCtxTests with LangTests with ExampleContracts with
}
test("Crowd Funding: measure") {
- val prover = new ErgoLikeTestProvingInterpreter()
- val backerPK @ DLogProtocol.ProveDlog(GroupElementConstant(backer: ECPoint)) = prover.dlogSecrets(0).publicImage
- val projectPK @ DLogProtocol.ProveDlog(GroupElementConstant(project: ECPoint)) = prover.dlogSecrets(1).publicImage
+ val prover = new ContextEnrichingTestProvingInterpreter()
+ val backerPK @ DLogProtocol.ProveDlog(backer: ECPoint) = prover.dlogSecrets(0).publicImage
+ val projectPK @ DLogProtocol.ProveDlog(project: ECPoint) = prover.dlogSecrets(1).publicImage
val env = envCF ++ Seq("projectPubKey" -> projectPK, "backerPubKey" -> backerPK)
val parsed = compiler.parse(crowdFundingScript)
val env2 = env ++ Seq("timeout" -> (timeout + 1))
@@ -211,42 +204,45 @@ class CostingTest extends BaseCtxTests with LangTests with ExampleContracts with
res = eval(i)
println("Processing ...")
- measure(1) { k =>
- for (i <- 1 to 2000)
+ measure(3) { k =>
+ for (i <- 1 to 1000)
res = eval(i)
}
emit("Crowd_Funding_measure", res)
+ /*
+ Warming up ...
+ Processing ...
+ Iter 0: 2138 ms
+ Iter 1: 1864 ms
+ Iter 2: 1864 ms
+ Total time: 5866 ms
+ */
}
test("Demurrage") {
- val prover = new ErgoLikeTestProvingInterpreter()
- val regScriptPK @ DLogProtocol.ProveDlog(GroupElementConstant(script: ECPoint)) = prover.dlogSecrets(0).publicImage
+ val prover = new ContextEnrichingTestProvingInterpreter()
+ val regScriptPK = prover.dlogSecrets(0).publicImage
val env = envDem ++ Seq("regScript" -> regScriptPK)
- checkInEnv(env, "Demurrage", demurrageScript,
- { ctx: Rep[Context] =>
- val regScript = RProveDlogEvidence(liftConst(script)).asRep[SigmaProp]
- val selfBytes = ctx.SELF.propositionBytes
- val selfValue = ctx.SELF.value
- val c2 = dsl.allOf(colBuilder.fromItems(
- ctx.HEIGHT >= ctx.SELF.getReg[Int](4).get + demurragePeriod,
- ctx.OUTPUTS.exists(fun { out =>
- (out.value >= selfValue - demurrageCost) lazy_&& Thunk{out.propositionBytes === selfBytes}
- })
- ))
- regScript.isValid lazy_|| Thunk{c2}
- }
- )
+ checkInEnv(env, "Demurrage", demurrageScript, null)
}
test("measure: costed context data") {
var res: Rep[Any] = null
measure(2) { j => // 10 warm up iterations when j == 0
- measure(j*500 + 10, false) { i =>
+ measure(j*1000 + 10, false) { i =>
res = check("", s"INPUTS.size + OUTPUTS.size + $i", null
- /*ctx => ctx.INPUTS.length + ctx.OUTPUTS.length + i*/)
+ /*ctx => ctx.INPUTS.length + ctx.OUTPUTS.length + i*/, printGraphs = false)
}
}
+ emit("costed_context_data", res)
+ /*
+ Total time: 2676 ms
+ Iter 0: 2676 ms
+ Total time: 6966 ms
+ Iter 1: 6970 ms
+ Total time: 9646 ms
+ */
}
diff --git a/src/test/scala/sigmastate/eval/DataCostingTest.scala b/src/test/scala/sigmastate/eval/DataCostingTest.scala
index 1adcb2a225..6071fc02e0 100644
--- a/src/test/scala/sigmastate/eval/DataCostingTest.scala
+++ b/src/test/scala/sigmastate/eval/DataCostingTest.scala
@@ -1,21 +1,19 @@
package sigmastate.eval
-import sigmastate.lang.{LangTests, TransformingSigmaBuilder, SigmaCompiler}
-
+import sigmastate.lang.LangTests
import scalan.BaseCtxTests
class DataCostingTest extends BaseCtxTests with LangTests with ErgoScriptTestkit {
import IR._
- import Col._
- lazy val compiler = new SigmaCompiler(builder)
+ import Coll._
- test("split cols") {
- emit("split_cols",
- split3(fun { in: Rep[(Col[Int], Byte)] =>
- dataCost(in, None)
- })
- )
- }
+// test("split cols") {
+// emit("split_cols",
+// split3(fun { in: Rep[(Coll[Int], Byte)] =>
+// dataCost(in, None)
+// })
+// )
+// }
// test("split pair cols") {
// ctx.emit("split_pair_col",
diff --git a/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala b/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala
index 4322473da1..b28d386d20 100644
--- a/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala
+++ b/src/test/scala/sigmastate/eval/ErgoScriptTestkit.scala
@@ -1,17 +1,20 @@
package sigmastate.eval
+import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix
+
import scala.util.Success
-import sigmastate.{AvlTreeData, SInt, SLong, SType}
-import sigmastate.Values.{BigIntArrayConstant, Constant, EvaluatedValue, IntConstant, LongConstant, SValue, SigmaPropConstant, TrueLeaf, Value}
-import org.ergoplatform.{ErgoBox, ErgoLikeContext, ErgoLikeTransaction}
+import sigmastate.{SInt, AvlTreeData, SLong, SType}
+import sigmastate.Values.{LongConstant, Constant, EvaluatedValue, SValue, TrueLeaf, SigmaPropConstant, Value, IntConstant, BigIntArrayConstant}
+import org.ergoplatform.{ErgoLikeContext, ErgoLikeTransaction, ErgoBox, ErgoScriptPredef}
import sigmastate.utxo.CostTable
-import special.sigma.{ContractsTestkit, Box => DBox, Context => DContext, SigmaContract => DContract, TestBox => DTestBox, TestContext => DTestContext}
import scalan.BaseCtxTests
-import sigmastate.lang.LangTests
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
+import sigmastate.lang.{LangTests, SigmaCompiler}
+import sigmastate.helpers.ContextEnrichingTestProvingInterpreter
import sigmastate.interpreter.ContextExtension
import sigmastate.interpreter.Interpreter.ScriptEnv
-import sigmastate.serialization.{ConstantStore, ErgoTreeSerializer}
+import sigmastate.serialization.ErgoTreeSerializer
+import special.sigma.{ContractsTestkit, Context => DContext, _}
+import special.sigma.Extensions._
import scala.language.implicitConversions
@@ -23,12 +26,14 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
import IR._
import Liftables._
import Context._
- import WBigInteger._
-
+ import Size._
+// import WBigInteger._
+ import BigInt._
+ lazy val compiler = new SigmaCompiler(TestnetNetworkPrefix, IR.builder)
def newErgoContext(height: Int, boxToSpend: ErgoBox, extension: Map[Byte, EvaluatedValue[SType]] = Map()): ErgoLikeContext = {
- val tx1 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq())
+ val tx1 = new ErgoLikeTransaction(IndexedSeq(), IndexedSeq(), IndexedSeq(boxToSpend))
val ergoCtx = ErgoLikeContext(
currentHeight = height,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -47,28 +52,29 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
def contract(canOpen: DContext => Boolean) = new NoEnvContract(canOpen)
lazy val dsl = sigmaDslBuilder
- lazy val bigSym = liftConst(big)
- lazy val n1Sym = liftConst(n1)
+ lazy val dslValue = sigmaDslBuilderValue
+ lazy val bigSym = liftConst(dslValue.BigInt(big))
+ lazy val n1Sym = liftConst(dslValue.BigInt(n1))
val timeout = 100
val minToRaise = 1000L
val backerPubKeyId = 1.toByte
val projectPubKeyId = 2.toByte
- lazy val backerProver = new ErgoLikeTestProvingInterpreter
- lazy val projectProver = new ErgoLikeTestProvingInterpreter
+ lazy val backerProver = new ContextEnrichingTestProvingInterpreter
+ lazy val projectProver = new ContextEnrichingTestProvingInterpreter
lazy val backerPubKey = backerProver.dlogSecrets.head.publicImage
lazy val projectPubKey = projectProver.dlogSecrets.head.publicImage
lazy val ctxVars = contextVars(Map(
- backerPubKeyId -> backerPubKey,
- projectPubKeyId -> projectPubKey,
- 3.toByte -> bigIntArr1
- )).arr
+ backerPubKeyId -> backerPubKey.toAnyValue,
+ projectPubKeyId -> projectPubKey.toAnyValue,
+ 3.toByte -> toAnyValue(bigIntegerArr1)
+ )).toArray
- val boxToSpend = ErgoBox(10, TrueLeaf, 0,
- additionalRegisters = Map(ErgoBox.R4 -> BigIntArrayConstant(bigIntArr1)))
+ val boxToSpend = ErgoBox(10, ErgoScriptPredef.TrueProp, 0,
+ additionalRegisters = Map(ErgoBox.R4 -> BigIntArrayConstant(bigIntegerArr1)))
lazy val tx1Output1 = ErgoBox(minToRaise, projectPubKey, 0)
lazy val tx1Output2 = ErgoBox(1, projectPubKey, 0)
- lazy val tx1 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(tx1Output1, tx1Output2))
+ lazy val tx1 = new ErgoLikeTransaction(IndexedSeq(), IndexedSeq(), IndexedSeq(tx1Output1, tx1Output2))
lazy val ergoCtx = ErgoLikeContext(
currentHeight = timeout - 1,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -79,7 +85,7 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
extension = ContextExtension(Map(
backerPubKeyId -> SigmaPropConstant(backerPubKey),
projectPubKeyId -> SigmaPropConstant(projectPubKey),
- 3.toByte -> BigIntArrayConstant(bigIntArr1)
+ 3.toByte -> BigIntArrayConstant(bigIntegerArr1)
)))
case class Result(calc: Option[Any], cost: Option[Int], size: Option[Long])
@@ -108,6 +114,10 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
printGraphs: Boolean = true,
measureTime: Boolean = false)
{
+ lazy val tree = script match {
+ case Code(code) => compiler.typecheck(env, code)
+ case Tree(t) => t
+ }
lazy val expectedCalcF = expectedCalc.map(f => fun(removeIsProven(f)))
lazy val expectedCostF = expectedCost.map(fun(_))
lazy val expectedSizeF = expectedSize.map(fun(_))
@@ -126,12 +136,12 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
case _ => Pair(xs.head, pairify(xs.tail))
}
- def doCosting: Rep[(Context => Any, (Context => Int, Context => Long))] = {
- val costed = script match {
- case Code(code) => cost(env, code)
- case Tree(tree) => cost(env, tree)
- }
- val res @ Tuple(calcF, costF, sizeF) = split3(costed.asRep[Context => Costed[Any]])
+ def doCosting: Rep[(Context => Any, (Size[Context] => Int, Size[Context] => Long))] = {
+ val costed = cost[Any](env, tree)
+ val calcF = costed.sliceCalc
+ val costF = fun { sCtx: RSize[Context] => costed.sliceCost(Pair(0, sCtx)) }
+ val sizeF = fun { sCtx: RSize[Context] => costed.sliceSize(sCtx).dataSize }
+ val res = Tuple(calcF, costF, sizeF)
if (printGraphs) {
val str = struct(
"calc" -> calcF,
@@ -153,8 +163,8 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
}
def doReduce(): Unit = {
- val Tuple(calcF, costF, sizeF) = doCosting
- verifyCostFunc(costF) shouldBe Success(())
+ val Pair(calcF, Pair(costF, sizeF)) = doCosting
+ verifyCostFunc(asRep[Any => Int](costF)) shouldBe Success(())
verifyIsProven(calcF) shouldBe Success(())
if (expectedTree.isDefined) {
@@ -175,25 +185,23 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
// check cost
val costCtx = ergoCtx.get.toSigmaContext(IR, isCost = true)
- val costFun = IR.compile[SInt.type](getDataEnv, costF)
- val IntConstant(estimatedCost) = costFun(costCtx)
- checkExpected(estimatedCost, expectedResult.cost,
- "Cost evaluation: estimatedCost = %s, expectedResult.cost = %s")
- (estimatedCost < CostTable.ScriptLimit) shouldBe true
+ val estimatedCost = IR.checkCost(costCtx, tree, costF, CostTable.ScriptLimit)
// check size
- val sizeFun = IR.compile[SLong.type](getDataEnv, sizeF)
- val LongConstant(estimatedSize) = sizeFun(costCtx)
- checkExpected(estimatedSize, expectedResult.size,
- "Size evaluation: estimatedSize = %s, expectedResult.size: %s"
- )
+ {
+ val lA = sizeF.elem.eDom.liftable.asLiftable[SSize[SContext], Size[Context]]
+ val sizeFun = IR.compile[SSize[SContext], Long, Size[Context], Long](getDataEnv, sizeF)(lA, liftable[Long, Long])
+ val estimatedSize = sizeFun(Sized.sizeOf(costCtx))
+ checkExpected(estimatedSize, expectedResult.size,
+ "Size evaluation: estimatedSize = %s, expectedResult.size: %s"
+ )
+ }
// check calc
- val valueFun = IR.compile[SType](getDataEnv, calcF.asRep[Context => SType#WrappedType])
- val res = valueFun(calcCtx) match {
- case Constant(res: Any, _) => res
- case v => v
- }
+ val lA = calcF.elem.eDom.liftable.asLiftable[SContext, Context]
+ val lB = calcF.elem.eRange.liftable.asLiftable[Any, Any]
+ val valueFun = IR.compile(getDataEnv, calcF)(lA, lB)
+ val (res, _) = valueFun(calcCtx)
checkExpected(res, expectedResult.calc,
"Calc evaluation:\n value = %s,\n expectedResult.calc: %s\n")
}
@@ -224,13 +232,14 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
def checkInEnv(env: ScriptEnv, name: String, script: String,
expectedCalc: Rep[Context] => Rep[Any],
expectedCost: Rep[Context] => Rep[Int] = null,
- expectedSize: Rep[Context] => Rep[Long] = null
- ): Rep[(Context => Any, (Context => Int, Context => Long))] =
+ expectedSize: Rep[Context] => Rep[Long] = null,
+ printGraphs: Boolean = true
+ ): Rep[(Context => Any, (Size[Context] => Int, Size[Context] => Long))] =
{
val tc = EsTestCase(name, env, Code(script), None, None,
Option(expectedCalc),
Option(expectedCost),
- Option(expectedSize), expectedTree = None, expectedResult = NoResult, printGraphs = true )
+ Option(expectedSize), expectedTree = None, expectedResult = NoResult, printGraphs)
val res = tc.doCosting
res
}
@@ -238,10 +247,11 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
def check(name: String, script: String,
expectedCalc: Rep[Context] => Rep[Any],
expectedCost: Rep[Context] => Rep[Int] = null,
- expectedSize: Rep[Context] => Rep[Long] = null
- ): Rep[(Context => Any, (Context => Int, Context => Long))] =
+ expectedSize: Rep[Context] => Rep[Long] = null,
+ printGraphs: Boolean = true
+ ): Rep[(Context => Any, (Size[Context] => Int, Size[Context] => Long))] =
{
- checkInEnv(Map(), name, script, expectedCalc, expectedCost, expectedSize)
+ checkInEnv(Map(), name, script, expectedCalc, expectedCost, expectedSize, printGraphs)
}
def reduce(env: ScriptEnv, name: String, script: String, ergoCtx: ErgoLikeContext, expectedResult: Any): Unit = {
@@ -254,11 +264,19 @@ trait ErgoScriptTestkit extends ContractsTestkit with LangTests { self: BaseCtxT
tcase.doReduce()
}
+ def compileAndCost[T](env: ScriptEnv, code: String): Rep[Costed[Context] => Costed[T]] = {
+ val typed = compiler.typecheck(env, code)
+ cost[T](env, typed)
+ }
+
def build(env: ScriptEnv, name: String, script: String, expected: SValue): Unit = {
- val costed = cost(env, script)
- val Tuple(valueF, costF, sizeF) = split3(costed)
+ val costed = compileAndCost[Any](env, script)
+ val valueF = costed.sliceCalc(true)
+ val costF = costed.sliceCost
+ val sizeF = costed.sliceSize
+
emit(name, valueF, costF, sizeF)
- verifyCostFunc(costF) shouldBe(Success(()))
+ verifyCostFunc(asRep[Any => Int](costF)) shouldBe(Success(()))
verifyIsProven(valueF) shouldBe(Success(()))
IR.buildTree(valueF) shouldBe expected
}
diff --git a/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala b/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala
index f170a92ac6..5fdb5d5d21 100644
--- a/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala
+++ b/src/test/scala/sigmastate/eval/ErgoTreeBuildingTest.scala
@@ -5,7 +5,7 @@ import org.ergoplatform.{Height, Inputs, Outputs, Self}
import sigmastate._
import sigmastate.lang.Terms.ValueOps
import sigmastate.Values.{BlockValue, FalseLeaf, FuncValue, GroupElementConstant, IntConstant, LongConstant, SigmaPropConstant, TaggedVariable, TrueLeaf, ValDef, ValUse}
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
+import sigmastate.helpers.ContextEnrichingTestProvingInterpreter
import sigmastate.serialization.OpCodes._
import sigmastate.interpreter.Interpreter._
import scalan.BaseCtxTests
@@ -17,6 +17,10 @@ import sigmastate.utxo._
class ErgoTreeBuildingTest extends BaseCtxTests
with LangTests with ExampleContracts with ErgoScriptTestkit {
+ implicit override lazy val IR = new TestContext with IRContext with CompiletimeCosting {
+ beginPass(noConstPropagationPass)
+ }
+
test("constants") {
build(emptyEnv, "oneInt", "1", IntConstant(1))
build(emptyEnv, "oneLong", "1L", LongConstant(1L))
@@ -76,12 +80,13 @@ class ErgoTreeBuildingTest extends BaseCtxTests
ValDef(1,List(),FuncValue(Vector((1,SLong)), Plus(Upcast(Height, SLong), ValUse(1,SLong))))),
Plus(Apply(ValUse(1,SFunc(SLong, SLong)),Vector(LongConstant(10))).asNumValue,
Apply(ValUse(1,SFunc(SLong, SLong)),Vector(LongConstant(20))).asNumValue)))
+ build(emptyEnv, "lam7", "{ def f(x: Long) = HEIGHT + x; f }", FuncValue(Vector((1,SLong)), mkPlus(Height, ValUse(1,SLong))))
}
test("Crowd Funding") {
- val prover = new ErgoLikeTestProvingInterpreter()
- val backerPK @ DLogProtocol.ProveDlog(GroupElementConstant(backer: ECPoint)) = prover.dlogSecrets(0).publicImage
- val projectPK @ DLogProtocol.ProveDlog(GroupElementConstant(project: ECPoint)) = prover.dlogSecrets(1).publicImage
+ val prover = new ContextEnrichingTestProvingInterpreter()
+ val backerPK = prover.dlogSecrets(0).publicImage
+ val projectPK = prover.dlogSecrets(1).publicImage
val env = envCF ++ Seq("projectPubKey" -> projectPK, "backerPubKey" -> backerPK)
build(env, "CrowdFunding", crowdFundingScript,
BlockValue(Vector(
diff --git a/src/test/scala/sigmastate/eval/EvaluationTest.scala b/src/test/scala/sigmastate/eval/EvaluationTest.scala
index 549d5e1bc3..e92d900c81 100644
--- a/src/test/scala/sigmastate/eval/EvaluationTest.scala
+++ b/src/test/scala/sigmastate/eval/EvaluationTest.scala
@@ -1,16 +1,14 @@
package sigmastate.eval
import org.ergoplatform.ErgoBox
-import sigmastate.Values.{ByteArrayConstant, CollectionConstant, ConcreteCollection, Constant, IntArrayConstant, IntConstant, SigmaPropConstant, SigmaPropValue, Value}
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
+import sigmastate.Values.{ConcreteCollection, IntArrayConstant, IntConstant, SigmaPropConstant, SigmaPropValue, Value}
+import sigmastate.helpers.ContextEnrichingTestProvingInterpreter
import sigmastate.interpreter.Interpreter._
import scalan.BaseCtxTests
import sigmastate.lang.LangTests
-import special.sigma.{TestContext => DContext}
import scalan.util.BenchmarkUtil._
import sigmastate._
import sigmastate.basics.DLogProtocol.{DLogProverInput, ProveDlog}
-import sigmastate.interpreter.CryptoConstants
import sigmastate.serialization.ErgoTreeSerializer
class EvaluationTest extends BaseCtxTests
@@ -29,15 +27,15 @@ class EvaluationTest extends BaseCtxTests
reduce(emptyEnv, "one_gt_one", "1 > 1", ctx, false)
reduce(emptyEnv, "or", "1 > 1 || 2 < 1", ctx, false)
reduce(emptyEnv, "or2", "1 > 1 || 2 < 1 || 2 > 1", ctx, true)
- reduce(emptyEnv, "or3", "OUTPUTS.size > 1 || OUTPUTS.size < 1", ctx, true)
+ reduce(emptyEnv, "or3", "OUTPUTS.size > 1 || OUTPUTS.size <= 1", ctx, true)
reduce(emptyEnv, "and", "1 > 1 && 2 < 1", ctx, false)
reduce(emptyEnv, "and2", "1 > 1 && 2 < 1 && 2 > 1", ctx, false)
reduce(emptyEnv, "and3", "1 == 1 && (2 < 1 || 2 > 1)", ctx, true)
- reduce(emptyEnv, "and4", "OUTPUTS.size > 1 && OUTPUTS.size < 1", ctx, false)
+ reduce(emptyEnv, "and4", "OUTPUTS.size > 1 && OUTPUTS.size <= 1", ctx, false)
}
test("lazy logical ops") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val pk = prover.dlogSecrets.head.publicImage
val self = ErgoBox(1, pk, 0, additionalRegisters = Map(ErgoBox.R4 -> IntConstant(10)))
val ctx = newErgoContext(height = 1, self)
@@ -59,6 +57,8 @@ class EvaluationTest extends BaseCtxTests
reduce(emptyEnv, "value", "SELF.value + 1L", ctx, 11L)
}
+ // TODO Caused by: java.lang.AssertionError: assertion failed:
+ // Invalid cast Cast(SizeCollElem, s1572): interface special.collection.SizeColl is not assignable from class special.collection.CSizePrim
test("lambdas") {
val ctx = newErgoContext(height = 1, boxToSpend)
reduce(emptyEnv, "lam3", "{ val f = { (out: Box) => out.value >= 0L }; f(SELF) }", ctx, true)
@@ -66,8 +66,8 @@ class EvaluationTest extends BaseCtxTests
// access R5 and call g only if f returns false
reduce(emptyEnv, "lam4",
"""{
- | val f = { (out: Box) => out.value >= 0L };
- | val g = { (x: Int) => x < 0 };
+ | def f(out: Box) = out.value >= 0L;
+ | def g(x: Int) = x < 0;
| f(SELF) || g(SELF.R5[Int].get)
| }""".stripMargin, ctx, true)
@@ -85,7 +85,18 @@ class EvaluationTest extends BaseCtxTests
ctx = new RuntimeIRContext
}
println(s"Def count: ${ctx.defCount}")
+ /*
+ Iter 0: 4 ms
+ ...
+ Iter 96: 2 ms
+ Iter 97: 1 ms
+ Iter 98: 2 ms
+ Iter 99: 2 ms
+ Total time: 244 ms
+ Def count: 20
+ */
}
+
// test("Crowd Funding") {
// val backerProver = new ErgoLikeProvingInterpreter
// val projectProver = new ErgoLikeProvingInterpreter
@@ -101,7 +112,7 @@ class EvaluationTest extends BaseCtxTests
// val boxToSpend = ErgoBox(10, TrueLeaf)
// val tx1Output1 = ErgoBox(minToRaise, projectPubKey)
// val tx1Output2 = ErgoBox(1, projectPubKey)
-// val tx1 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(tx1Output1, tx1Output2))
+// val tx1 = createTransaction(IndexedSeq(tx1Output1, tx1Output2))
// val ergoCtx = ErgoLikeContext(
// currentHeight = timeout - 1,
// lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -116,16 +127,17 @@ class EvaluationTest extends BaseCtxTests
// }
test("SubstConst") {
- def script(pk: ProveDlog): Value[SType] = AND(EQ(IntConstant(1), IntConstant(1)), pk)
+ def script(pk: ProveDlog): Value[SType] = AND(EQ(IntConstant(1), IntConstant(1)), SigmaPropConstant(pk).isProven)
val pk1 = DLogProverInput.random().publicImage
val pk2 = DLogProverInput.random().publicImage
val script1 = script(pk1)
+ val script2 = script(pk2)
val inputBytes = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(script1)
val positions = IntArrayConstant(Array[Int](2))
// in ergo we have only byte array of a serialized group element
- val newVals = ConcreteCollection(Vector[SigmaPropValue](ProveDlog(DecodePoint(pk2.pkBytes))), SSigmaProp)
- val script2 = script(pk2)
+ val newVals = ConcreteCollection(Vector[SigmaPropValue](CreateProveDlog(DecodePoint(pk2.pkBytes))), SSigmaProp)
+
val expectedBytes = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(script2)
val ctx = newErgoContext(height = 1, boxToSpend)
reduce(emptyEnv, "SubstConst",
diff --git a/src/test/scala/sigmastate/eval/MeasureIRContext.scala b/src/test/scala/sigmastate/eval/MeasureIRContext.scala
index cb21f10bff..2308fa252a 100644
--- a/src/test/scala/sigmastate/eval/MeasureIRContext.scala
+++ b/src/test/scala/sigmastate/eval/MeasureIRContext.scala
@@ -12,6 +12,11 @@ object MeasureIRContext extends App {
ctx = new RuntimeIRContext
}
println(s"Def count: ${ctx.defCount}")
+ /*
+ Total time: 2485 ms
+ Total time: 2714 ms
+ Def count: 20
+ */
}
class SigmaLibraryTests extends BaseCtxTests {
@@ -23,5 +28,9 @@ class SigmaLibraryTests extends BaseCtxTests {
object MeasureSigmaLibraryCreate extends App {
new Benchmark(new RuntimeIRContext).run()
+ /*
+ Total time: 12932 ms
+ Def count: 20, total: 15774 msec
+ */
}
diff --git a/src/test/scala/sigmastate/helpers/ContextEnrichingProverInterpreter.scala b/src/test/scala/sigmastate/helpers/ContextEnrichingProverInterpreter.scala
new file mode 100644
index 0000000000..df2d5fb521
--- /dev/null
+++ b/src/test/scala/sigmastate/helpers/ContextEnrichingProverInterpreter.scala
@@ -0,0 +1,31 @@
+package sigmastate.helpers
+
+import sigmastate.SType
+import sigmastate.Values.{ErgoTree, EvaluatedValue}
+import sigmastate.interpreter.Interpreter.ScriptEnv
+import sigmastate.interpreter.{ContextExtension, CostedProverResult, ProverInterpreter}
+
+import scala.util.Try
+
+/**
+ * Proving interpreter that keeps dictionary with possible variables and
+ * automatically enrich context when needed
+ *
+ * Note: context is included into message (under hash function), thus changed context
+ * also changes message. This trait may be useful for tests, that sign fake messages,
+ * or for transactions which inputs does not require signatures.
+ */
+trait ContextEnrichingProverInterpreter extends ProverInterpreter {
+
+ def contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = Map()
+
+ val knownExtensions = ContextExtension(contextExtenders)
+
+ /**
+ * Replace context.extension to knownExtensions and prove script in different context.
+ */
+ override def prove(env: ScriptEnv, exp: ErgoTree, context: CTX, message: Array[Byte]): Try[CostedProverResult] = {
+ val enrichedContext = context.withExtension(knownExtensions).asInstanceOf[CTX]
+ super.prove(env, exp, enrichedContext, message)
+ }
+}
diff --git a/src/test/scala/sigmastate/helpers/ContextEnrichingTestProvingInterpreter.scala b/src/test/scala/sigmastate/helpers/ContextEnrichingTestProvingInterpreter.scala
new file mode 100644
index 0000000000..11f8cb74fe
--- /dev/null
+++ b/src/test/scala/sigmastate/helpers/ContextEnrichingTestProvingInterpreter.scala
@@ -0,0 +1,48 @@
+package sigmastate.helpers
+
+import scorex.utils.Random
+import sigmastate.SType
+import sigmastate.Values._
+import sigmastate.basics.DLogProtocol.DLogProverInput
+import sigmastate.basics.DiffieHellmanTupleProverInput
+import sigmastate.eval.IRContext
+import sigmastate.utxo.CostTable
+
+class ContextEnrichingTestProvingInterpreter(override val maxCost: Long = CostTable.ScriptLimit)(implicit override val IR: IRContext)
+ extends ErgoLikeTestProvingInterpreter(maxCost) with ContextEnrichingProverInterpreter {
+
+ override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = (1 to 10).map { i =>
+ val ba = Random.randomBytes(75)
+ i.toByte -> ByteArrayConstant(ba)
+ }.toMap
+
+ def withContextExtender(tag: Byte, value: EvaluatedValue[_ <: SType]): ContextEnrichingTestProvingInterpreter = {
+ val s = secrets
+ val ce = contextExtenders
+
+ new ContextEnrichingTestProvingInterpreter(maxCost) {
+ override lazy val secrets = s
+ override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = ce + (tag -> value)
+ }
+ }
+
+ def withSecrets(additionalSecrets: Seq[DLogProverInput]): ContextEnrichingTestProvingInterpreter = {
+ val ce = contextExtenders
+ val s = secrets ++ additionalSecrets
+
+ new ContextEnrichingTestProvingInterpreter(maxCost) {
+ override lazy val secrets = s
+ override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = ce
+ }
+ }
+
+ def withDHSecrets(additionalSecrets: Seq[DiffieHellmanTupleProverInput]): ContextEnrichingTestProvingInterpreter = {
+ val ce = contextExtenders
+ val s = secrets ++ additionalSecrets
+
+ new ContextEnrichingTestProvingInterpreter(maxCost) {
+ override lazy val secrets = s
+ override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = ce
+ }
+ }
+}
diff --git a/src/test/scala/sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala b/src/test/scala/sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala
index 479e26c858..328d971f39 100644
--- a/src/test/scala/sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala
+++ b/src/test/scala/sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala
@@ -1,13 +1,10 @@
package sigmastate.helpers
import sigmastate.basics.DLogProtocol.DLogProverInput
-import scorex.utils.Random
-import sigmastate.SType
-import sigmastate.Values._
-import sigmastate.eval.IRContext
import sigmastate.basics.{DiffieHellmanTupleProverInput, SigmaProtocolPrivateInput}
+import sigmastate.eval.IRContext
import sigmastate.interpreter.ProverInterpreter
-import sigmastate.utxo.{CostTable, ErgoLikeTestInterpreter}
+import sigmastate.utxo.CostTable
class ErgoLikeTestProvingInterpreter(override val maxCost: Long = CostTable.ScriptLimit)(implicit override val IR: IRContext)
extends ErgoLikeTestInterpreter(maxCost) with ProverInterpreter {
@@ -23,28 +20,4 @@ class ErgoLikeTestProvingInterpreter(override val maxCost: Long = CostTable.Scri
lazy val dhSecrets: Seq[DiffieHellmanTupleProverInput] =
secrets.filter(_.isInstanceOf[DiffieHellmanTupleProverInput]).asInstanceOf[Seq[DiffieHellmanTupleProverInput]]
- override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = (1 to 10).map { i =>
- val ba = Random.randomBytes(75)
- i.toByte -> ByteArrayConstant(ba)
- }.toMap
-
- def withContextExtender(tag: Byte, value: EvaluatedValue[_ <: SType]): ErgoLikeTestProvingInterpreter = {
- val s = secrets
- val ce = contextExtenders
-
- new ErgoLikeTestProvingInterpreter(maxCost) {
- override lazy val secrets = s
- override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = ce + (tag -> value)
- }
- }
-
- def withSecrets(additionalSecrets: Seq[DLogProverInput]): ErgoLikeTestProvingInterpreter = {
- val ce = contextExtenders
- val s = secrets ++ additionalSecrets
-
- new ErgoLikeTestProvingInterpreter(maxCost) {
- override lazy val secrets = s
- override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = ce
- }
- }
}
diff --git a/src/test/scala/sigmastate/utxo/ErgoTransactionValidator.scala b/src/test/scala/sigmastate/helpers/ErgoTransactionValidator.scala
similarity index 89%
rename from src/test/scala/sigmastate/utxo/ErgoTransactionValidator.scala
rename to src/test/scala/sigmastate/helpers/ErgoTransactionValidator.scala
index 289b85a4b6..3b5c965928 100644
--- a/src/test/scala/sigmastate/utxo/ErgoTransactionValidator.scala
+++ b/src/test/scala/sigmastate/helpers/ErgoTransactionValidator.scala
@@ -1,11 +1,11 @@
-package sigmastate.utxo
+package sigmastate.helpers
-import sigmastate.eval.{RuntimeIRContext, IRContext}
-import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
-import org.ergoplatform.ErgoLikeContext.Metadata
import org.ergoplatform._
+import sigmastate.eval.IRContext
+import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
+import sigmastate.utxo.CostTable
-import scala.util.{Success, Failure}
+import scala.util.{Failure, Success}
class ErgoLikeTestInterpreter(override val maxCost: Long = CostTable.ScriptLimit)(implicit override val IR: IRContext) extends ErgoLikeInterpreter(maxCost) {
override type CTX = ErgoLikeContext
@@ -41,7 +41,7 @@ class ErgoTransactionValidator(implicit IR: IRContext) {
tx, box, proverExtension)
val verificationResult = verifier.verify(
emptyEnv + (ScriptNameProp -> s"height_${blockchainState.currentHeight }_verify"),
- box.proposition, context, proof, msg)
+ box.ergoTree, context, proof, msg)
val scriptCost: Long = verificationResult match {
case Success((res, cost)) =>
if(!res) return Left[Throwable, Long](new Exception(s"Validation failed for input #$idx"))
diff --git a/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala b/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala
index 2c6a627386..93a1491c41 100644
--- a/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala
+++ b/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala
@@ -1,22 +1,31 @@
package sigmastate.helpers
+import java.math.BigInteger
+
import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix
-import org.ergoplatform.{ErgoAddressEncoder, ErgoBox}
import org.ergoplatform.ErgoBox.{NonMandatoryRegisterId, TokenId}
-import org.scalatest.prop.{PropertyChecks, GeneratorDrivenPropertyChecks}
-import org.scalatest.{PropSpec, Matchers}
+import org.ergoplatform.ErgoScriptPredef.TrueProp
+import org.ergoplatform.{ErgoBox, ErgoBoxCandidate, ErgoLikeContext, ErgoLikeTransaction}
+import org.scalacheck.Arbitrary.arbByte
+import org.scalacheck.Gen
+import org.scalatest.prop.{GeneratorDrivenPropertyChecks, PropertyChecks}
+import org.scalatest.{Assertion, Matchers, PropSpec}
+import scalan.{Nullable, RType, TestContexts, TestUtils}
import scorex.crypto.hash.Blake2b256
-import scorex.util._
-import sigmastate.Values.{EvaluatedValue, SValue, TrueLeaf, Value, GroupElementConstant}
-import sigmastate.eval.{CompiletimeCosting, IRContext, Evaluation}
-import sigmastate.interpreter.CryptoConstants
-import sigmastate.interpreter.Interpreter.{ScriptNameProp, ScriptEnv}
-import sigmastate.lang.{TransformingSigmaBuilder, SigmaCompiler}
-import sigmastate.{SGroupElement, SBoolean, SType}
+import scorex.util.serialization.{VLQByteStringReader, VLQByteStringWriter}
+import sigma.types.{IsPrimView, PrimViewType, View}
+import sigmastate.Values.{Constant, ErgoTree, EvaluatedValue, GroupElementConstant, SValue, Value}
+import sigmastate.eval.{CompiletimeCosting, Evaluation, IRContext}
+import sigmastate.interpreter.Interpreter.{ScriptEnv, ScriptNameProp}
+import sigmastate.interpreter.{CryptoConstants, Interpreter}
+import sigmastate.lang.{SigmaCompiler, TransformingSigmaBuilder}
+import sigmastate.serialization.{ErgoTreeSerializer, SigmaSerializer}
+import sigmastate.{SGroupElement, SType}
+import special.sigma._
+import spire.util.Opt
import scala.annotation.tailrec
import scala.language.implicitConversions
-import scalan.{TestUtils, TestContexts}
trait SigmaTestingCommons extends PropSpec
with PropertyChecks
@@ -24,7 +33,7 @@ trait SigmaTestingCommons extends PropSpec
with Matchers with TestUtils with TestContexts {
- val fakeSelf: ErgoBox = createBox(0, TrueLeaf)
+ val fakeSelf: ErgoBox = createBox(0, TrueProp)
//fake message, in a real-life a message is to be derived from a spending transaction
val fakeMessage = Blake2b256("Hello World")
@@ -33,31 +42,48 @@ trait SigmaTestingCommons extends PropSpec
implicit def grLeafConvert(elem: CryptoConstants.EcPointType): Value[SGroupElement.type] = GroupElementConstant(elem)
- val compiler = new SigmaCompiler(TransformingSigmaBuilder)
+ val compiler = SigmaCompiler(TestnetNetworkPrefix, TransformingSigmaBuilder)
- def compile(env: ScriptEnv, code: String): Value[SType] = {
- compiler.compile(env, code, TestnetNetworkPrefix)
+ def checkSerializationRoundTrip(v: SValue): Unit = {
+ val compiledTreeBytes = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(v)
+ withClue(s"(De)Serialization roundtrip failed for the tree:") {
+ ErgoTreeSerializer.DefaultSerializer.deserialize(compiledTreeBytes) shouldEqual v
+ }
}
- def compileWithCosting(env: ScriptEnv, code: String)(implicit IR: IRContext): Value[SType] = {
- val interProp = compiler.typecheck(env, code)
- val IR.Pair(calcF, _) = IR.doCosting(env, interProp)
- IR.buildTree(calcF)
+ def compileWithoutCosting(env: ScriptEnv, code: String): Value[SType] = compiler.compileWithoutCosting(env, code)
+
+ def compile(env: ScriptEnv, code: String)(implicit IR: IRContext): Value[SType] = {
+ val tree = compiler.compile(env, code)
+ checkSerializationRoundTrip(tree)
+ tree
}
def createBox(value: Int,
- proposition: Value[SBoolean.type],
+ proposition: ErgoTree,
additionalTokens: Seq[(TokenId, Long)] = Seq(),
additionalRegisters: Map[NonMandatoryRegisterId, _ <: EvaluatedValue[_ <: SType]] = Map())
- = ErgoBox(value, proposition, 0, additionalTokens, additionalRegisters)
+ = ErgoBox(value, proposition, 0, additionalTokens, additionalRegisters)
def createBox(value: Int,
- proposition: Value[SBoolean.type],
+ proposition: ErgoTree,
creationHeight: Int)
- = ErgoBox(value, proposition, creationHeight, Seq(), Map(), Array.fill[Byte](32)(0.toByte).toModifierId)
+ = ErgoBox(value, proposition, creationHeight, Seq(), Map(), ErgoBox.allZerosModifierId)
+
+ /**
+ * Create fake transaction with provided outputCandidates, but without inputs and data inputs.
+ * Normally, this transaction will be invalid as far as it will break rule that sum of
+ * coins in inputs should not be less then sum of coins in outputs, but we're not checking it
+ * in our test cases
+ */
+ def createTransaction(outputCandidates: IndexedSeq[ErgoBoxCandidate]): ErgoLikeTransaction = {
+ new ErgoLikeTransaction(IndexedSeq(), IndexedSeq(), outputCandidates)
+ }
+
+ def createTransaction(box: ErgoBoxCandidate): ErgoLikeTransaction = createTransaction(IndexedSeq(box))
class TestingIRContext extends TestContext with IRContext with CompiletimeCosting {
- override def onCostingResult[T](env: ScriptEnv, tree: SValue, res: CostingResult[T]): Unit = {
+ override def onCostingResult[T](env: ScriptEnv, tree: SValue, res: RCostingResultEx[T]): Unit = {
env.get(ScriptNameProp) match {
case Some(name: String) =>
emit(name, res)
@@ -66,6 +92,104 @@ trait SigmaTestingCommons extends PropSpec
}
}
+ private def fromPrimView[A](in: A) = {
+ in match {
+ case IsPrimView(v) => v
+ case _ => in
+ }
+ }
+
+ def func[A: RType, B: RType](func: String)(implicit IR: IRContext): A => B = {
+ import IR._
+ import IR.Context._;
+ val tA = RType[A]
+ val tB = RType[B]
+ val tpeA = Evaluation.rtypeToSType(tA)
+ val tpeB = Evaluation.rtypeToSType(tB)
+ val code =
+ s"""{
+ | val func = $func
+ | val res = func(getVar[${tA.name}](1).get)
+ | res
+ |}
+ """.stripMargin
+ val env = Interpreter.emptyEnv
+ val interProp = compiler.typecheck(env, code)
+ val IR.Pair(calcF, _) = IR.doCosting[Any](env, interProp)
+ val tree = IR.buildTree(calcF)
+ checkSerializationRoundTrip(tree)
+ val lA = calcF.elem.eDom.liftable.asLiftable[SContext, IR.Context]
+ val lB = calcF.elem.eRange.liftable.asLiftable[Any, Any]
+ val valueFun = IR.compile[SContext, Any, IR.Context, Any](IR.getDataEnv, calcF)(lA, lB)
+
+ (in: A) => {
+ implicit val cA = tA.classTag
+ val x = fromPrimView(in)
+ val context = ErgoLikeContext.dummy(createBox(0, TrueProp))
+ .withBindings(1.toByte -> Constant[SType](x.asInstanceOf[SType#WrappedType], tpeA))
+ val calcCtx = context.toSigmaContext(IR, isCost = false)
+ val (res, _) = valueFun(calcCtx)
+ res.asInstanceOf[B]
+// (TransformingSigmaBuilder.unliftAny(res) match {
+// case Nullable(x) => // x is a value extracted from Constant
+// tB match {
+// case _: PrimViewType[_, _] => // need to wrap value into PrimValue
+// View.mkPrimView(x) match {
+// case Opt(pv) => pv
+// case _ => x // cannot wrap, so just return as is
+// }
+// case _ => Evaluation.toDslData(x, tpeB, isCost = false) // don't need to wrap
+// }
+// case _ => Evaluation.toDslData(res, tpeB, isCost = false)
+// }).asInstanceOf[B]
+ }
+ }
+
+// def func2[A: RType, B: RType, R: RType](func: String)(implicit IR: IRContext): (A, B) => R = {
+// val tA = RType[A]
+// val tB = RType[B]
+// val tR = RType[R]
+// val tpeA = Evaluation.rtypeToSType(tA)
+// val tpeB = Evaluation.rtypeToSType(tB)
+// val tpeR = Evaluation.rtypeToSType(tR)
+// val code =
+// s"""{
+// | val func = $func
+// | val res = func(getVar[${tA.name}](1).get, getVar[${tB.name}](2).get)
+// | res
+// |}
+// """.stripMargin
+// val env = Interpreter.emptyEnv
+// val interProp = compiler.typecheck(env, code)
+// val IR.Pair(calcF, _) = IR.doCosting(env, interProp)
+// val valueFun = IR.compile[tpeR.type](IR.getDataEnv, IR.asRep[IR.Context => tpeR.WrappedType](calcF))
+//
+// (in1: A, in2: B) => {
+// implicit val cA = tA.classTag
+// implicit val cB = tB.classTag
+// val x = fromPrimView(in1)
+// val y = fromPrimView(in2)
+// val context = ErgoLikeContext.dummy(createBox(0, TrueProp))
+// .withBindings(
+// 1.toByte -> Constant[SType](x.asInstanceOf[SType#WrappedType], tpeA),
+// 2.toByte -> Constant[SType](y.asInstanceOf[SType#WrappedType], tpeB))
+// val calcCtx = context.toSigmaContext(IR, isCost = false)
+// val res = valueFun(calcCtx)
+// (TransformingSigmaBuilder.unliftAny(res) match {
+// case Nullable(x) => // x is a value extracted from Constant
+// tB match {
+// case _: PrimViewType[_, _] => // need to wrap value into PrimValue
+// View.mkPrimView(x) match {
+// case Opt(pv) => pv
+// case _ => x // cannot wrap, so just return as is
+// }
+// case _ => x // don't need to wrap
+// }
+// case _ => res
+// }).asInstanceOf[R]
+// }
+// }
+
def assertExceptionThrown(fun: => Any, assertion: Throwable => Boolean): Unit = {
try {
fun
@@ -74,7 +198,7 @@ trait SigmaTestingCommons extends PropSpec
catch {
case e: Throwable =>
if (!assertion(e))
- fail(s"exception check failed on $e (caused by: ${e.getCause}")
+ fail(s"exception check failed on $e (root cause: ${rootCause(e)})")
}
}
@@ -82,4 +206,27 @@ trait SigmaTestingCommons extends PropSpec
final def rootCause(t: Throwable): Throwable =
if (t.getCause == null) t
else rootCause(t.getCause)
+
+ protected def roundTripTest[T](v: T)(implicit serializer: SigmaSerializer[T, T]): Assertion = {
+ // using default sigma reader/writer
+ val bytes = serializer.toBytes(v)
+ bytes.nonEmpty shouldBe true
+ serializer.parse(SigmaSerializer.startReader(bytes)) shouldBe v
+
+ // using ergo's(scorex) reader/writer
+ val w = new VLQByteStringWriter()
+ serializer.serializeWithGenericWriter(v, w)
+ val byteStr = w.result()
+ byteStr.nonEmpty shouldBe true
+ serializer.parseWithGenericReader(new VLQByteStringReader(byteStr)) shouldEqual v
+ }
+
+ protected def roundTripTestWithPos[T](v: T)(implicit serializer: SigmaSerializer[T, T]): Assertion = {
+ val randomBytesCount = Gen.chooseNum(1, 20).sample.get
+ val randomBytes = Gen.listOfN(randomBytesCount, arbByte.arbitrary).sample.get.toArray
+ val bytes = serializer.toBytes(v)
+ serializer.parse(SigmaSerializer.startReader(bytes)) shouldBe v
+ serializer.parse(SigmaSerializer.startReader(randomBytes ++ bytes, randomBytesCount)) shouldBe v
+ }
+
}
diff --git a/src/test/scala/sigmastate/lang/LangTests.scala b/src/test/scala/sigmastate/lang/LangTests.scala
index 3bba4654c0..5714d309da 100644
--- a/src/test/scala/sigmastate/lang/LangTests.scala
+++ b/src/test/scala/sigmastate/lang/LangTests.scala
@@ -1,18 +1,20 @@
package sigmastate.lang
-import sigmastate.lang.Terms.{Ident, MethodCallLike}
-import sigmastate.Values.{ConcreteCollection, GroupElementConstant, LongConstant, SValue, SigmaBoolean, Value}
+import sigmastate.lang.Terms.{MethodCallLike, Ident}
+import sigmastate.Values.{LongConstant, SValue, Value, SigmaBoolean, GroupElementConstant, ConcreteCollection}
import sigmastate._
import java.math.BigInteger
import org.bouncycastle.math.ec.ECPoint
+import org.scalatest.Matchers
import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.SCollection.SByteArray
import sigmastate.basics.ProveDHTuple
+import sigmastate.eval.CostingSigmaDslBuilder
import sigmastate.interpreter.CryptoConstants
import sigmastate.interpreter.Interpreter.ScriptEnv
-trait LangTests {
+trait LangTests extends Matchers {
def BoolIdent(name: String): Value[SBoolean.type] = Ident(name).asValue[SBoolean.type]
def IntIdent(name: String): Value[SLong.type] = Ident(name).asValue[SLong.type]
@@ -30,19 +32,22 @@ trait LangTests {
val arr1 = Array[Byte](1, 2)
val arr2 = Array[Byte](10, 20)
val dlog = CryptoConstants.dlogGroup
- val g1 = dlog.generator
- val g2 = dlog.multiplyGroupElements(g1, g1)
- val g3 = dlog.multiplyGroupElements(g2, g2)
- val g4 = dlog.multiplyGroupElements(g3, g3)
+ val ecp1 = dlog.generator
+ val ecp2 = dlog.multiplyGroupElements(ecp1, ecp1)
+ val ecp3 = dlog.multiplyGroupElements(ecp2, ecp2)
+ val ecp4 = dlog.multiplyGroupElements(ecp3, ecp3)
+ val g1 = CostingSigmaDslBuilder.GroupElement(ecp1.asInstanceOf[ECPoint])
+ val g2 = CostingSigmaDslBuilder.GroupElement(ecp2.asInstanceOf[ECPoint])
+ val g3 = CostingSigmaDslBuilder.GroupElement(ecp3.asInstanceOf[ECPoint])
+ val g4 = CostingSigmaDslBuilder.GroupElement(ecp4.asInstanceOf[ECPoint])
protected val n1: BigInteger = BigInt(10).underlying()
protected val n2: BigInteger = BigInt(20).underlying()
- protected val bigIntArr1: Array[BigInteger] = Array(n1, n2)
+ protected val bigIntegerArr1: Array[BigInteger] = Array(n1, n2)
protected val big: BigInteger = BigInt(Long.MaxValue).underlying().pow(2)
- protected val p1: SigmaBoolean = ProveDlog(GroupElementConstant(g1))
- protected val p2: SigmaBoolean = ProveDlog(GroupElementConstant(g2))
- protected val dht1: SigmaBoolean = ProveDHTuple(
- GroupElementConstant(g1), GroupElementConstant(g2), GroupElementConstant(g3), GroupElementConstant(g4))
+ protected val p1: SigmaBoolean = ProveDlog(ecp1)
+ protected val p2: SigmaBoolean = ProveDlog(ecp2)
+ protected val dht1: SigmaBoolean = ProveDHTuple(ecp1, ecp2, ecp3, ecp4)
val env = Map(
"x" -> 10, "y" -> 11, "c1" -> true, "c2" -> false,
@@ -60,9 +65,18 @@ trait LangTests {
"n1" -> n1,
"n2" -> n2,
"big" -> big,
- "bigIntArr1" -> bigIntArr1
+ "bigIntArr1" -> bigIntegerArr1
)
/** Parses string to SType tree */
def ty(s: String): SType = SigmaParser.parseType(s)
+
+ def assertSrcCtxForAllNodes(tree: SValue): Unit = {
+ import org.bitbucket.inkytonik.kiama.rewriting.Rewriter._
+ rewrite(everywherebu(rule[SValue] {
+ case node =>
+ withClue(s"Missing sourceContext for $node") { node.sourceContext.isDefined shouldBe true }
+ node
+ }))(tree)
+ }
}
diff --git a/src/test/scala/sigmastate/lang/SigmaBinderTest.scala b/src/test/scala/sigmastate/lang/SigmaBinderTest.scala
index 177a73768f..9e1d256a26 100644
--- a/src/test/scala/sigmastate/lang/SigmaBinderTest.scala
+++ b/src/test/scala/sigmastate/lang/SigmaBinderTest.scala
@@ -1,14 +1,16 @@
package sigmastate.lang
-import org.ergoplatform.{Height, Outputs, Self, Inputs}
+import org.ergoplatform.{Height, Inputs, Outputs, Self}
+import org.ergoplatform.ErgoAddressEncoder._
import org.scalatest.prop.PropertyChecks
-import org.scalatest.{PropSpec, Matchers}
+import org.scalatest.{Matchers, PropSpec}
import scorex.util.encode.Base58
import sigmastate.Values._
import sigmastate._
import sigmastate.interpreter.Interpreter.ScriptEnv
+import sigmastate.lang.SigmaPredef.PredefinedFuncRegistry
import sigmastate.lang.Terms._
-import sigmastate.lang.exceptions.{BinderException, InvalidTypeArguments, InvalidArguments}
+import sigmastate.lang.exceptions.{BinderException, InvalidArguments, InvalidTypeArguments}
import sigmastate.serialization.ValueSerializer
import sigmastate.utxo._
@@ -18,8 +20,24 @@ class SigmaBinderTest extends PropSpec with PropertyChecks with Matchers with La
def bind(env: ScriptEnv, x: String): SValue = {
val builder = TransformingSigmaBuilder
val ast = SigmaParser(x, builder).get.value
- val binder = new SigmaBinder(env, builder)
- binder.bind(ast)
+ val binder = new SigmaBinder(env, builder, TestnetNetworkPrefix,
+ new PredefinedFuncRegistry(builder))
+ val res = binder.bind(ast)
+ res.sourceContext.isDefined shouldBe true
+ assertSrcCtxForAllNodes(res)
+ res
+ }
+
+ private def fail(env: ScriptEnv, x: String, expectedLine: Int, expectedCol: Int): Unit = {
+ val builder = TransformingSigmaBuilder
+ val ast = SigmaParser(x, builder).get.value
+ val binder = new SigmaBinder(env, builder, TestnetNetworkPrefix,
+ new PredefinedFuncRegistry(builder))
+ val exception = the[BinderException] thrownBy binder.bind(ast)
+ withClue(s"Exception: $exception, is missing source context:") { exception.source shouldBe defined }
+ val sourceContext = exception.source.get
+ sourceContext.line shouldBe expectedLine
+ sourceContext.column shouldBe expectedCol
}
property("simple expressions") {
@@ -42,18 +60,19 @@ class SigmaBinderTest extends PropSpec with PropertyChecks with Matchers with La
// todo should be g1.exp(n1)
// ( see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/324 )
// bind(env, "g1 ^ n1") shouldBe Exponentiate(g1, n1)
- bind(env, "g1 * g2") shouldBe MethodCallLike(g1, "*", IndexedSeq(g2))
+ bind(env, "g1 * g2") shouldBe MethodCallLike(ecp1, "*", IndexedSeq(ecp2))
}
property("predefined functions") {
- bind(env, "getVar[Byte](10)") shouldBe GetVar(10.toByte, SByte)
- bind(env, "getVar[Byte](10L)") shouldBe GetVar(10.toByte, SByte)
- an[BinderException] should be thrownBy bind(env, "getVar[Byte](\"ha\")")
bind(env, "min(1, 2)") shouldBe Min(IntConstant(1), IntConstant(2))
bind(env, "max(1, 2)") shouldBe Max(IntConstant(1), IntConstant(2))
bind(env, "min(1, 2L)") shouldBe Min(Upcast(IntConstant(1), SLong), LongConstant(2))
- an[InvalidArguments] should be thrownBy bind(env, "min(1, 2, 3)")
- an[InvalidArguments] should be thrownBy bind(env, "max(1)")
+ bind(env, "max(1, 2L)") shouldBe Max(Upcast(IntConstant(1), SLong), LongConstant(2))
+ }
+
+ property("min/max fail (invalid arguments)") {
+ fail(env, "min(1, 2, 3)", 1, 1)
+ fail(env, "max(1)", 1, 1)
}
property("val constructs") {
@@ -91,7 +110,7 @@ class SigmaBinderTest extends PropSpec with PropertyChecks with Matchers with La
}
property("tuple constructor") {
- bind(env, "()") shouldBe UnitConstant
+ bind(env, "()") shouldBe UnitConstant()
bind(env, "(1)") shouldBe IntConstant(1)
bind(env, "(1, 2)") shouldBe Tuple(IntConstant(1), IntConstant(2))
bind(env, "(1, x - 1)") shouldBe Tuple(IntConstant(1), Minus(10, 1))
@@ -178,24 +197,24 @@ class SigmaBinderTest extends PropSpec with PropertyChecks with Matchers with La
bind(env, "Coll[Int]()") shouldBe ConcreteCollection()(SInt)
}
- property("deserialize") {
- def roundtrip[T <: SType](c: EvaluatedValue[T], typeSig: String) = {
- val bytes = ValueSerializer.serialize(c)
- val str = Base58.encode(bytes)
- bind(env, s"deserialize[$typeSig](" + "\"" + str + "\")") shouldBe c
- }
- roundtrip(ByteArrayConstant(Array[Byte](2)), "Coll[Byte]")
- roundtrip(Tuple(ByteArrayConstant(Array[Byte](2)), LongConstant(4)), "(Coll[Byte], Long)")
- }
-
- property("deserialize fails") {
- // more than one type
- an[InvalidTypeArguments] should be thrownBy bind(env, """deserialize[Int, Byte]("test")""")
- // more then one argument
- an[InvalidArguments] should be thrownBy bind(env, """deserialize[Int]("test", "extra argument")""")
- // not a string constant
- an[InvalidArguments] should be thrownBy bind(env, """deserialize[Int]("a" + "b")""")
- // invalid chat in Base58 string
- an[AssertionError] should be thrownBy bind(env, """deserialize[Int]("0")""")
+ property("val fails (already defined in env)") {
+ val script= "{ val x = 10; x > 2 }"
+ (the[BinderException] thrownBy bind(env, script)).source shouldBe
+ Some(SourceContext(1, 7, script))
+ }
+
+ property("val fails (already defined in env) multiline") {
+ val script= """{
+ |val x = 10
+ |x > 2
+ |
+ |}""".stripMargin
+ val e = the[BinderException] thrownBy bind(env, script)
+ e.source shouldBe Some(SourceContext(2, 5, "val x = 10"))
+ }
+
+ property("fail Some (invalid arguments)") {
+ fail(env, "Some(1, 2)", 1, 1)
+ fail(env, "Some()", 1, 1)
}
}
diff --git a/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala b/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala
index d2caf65e40..b4a30ec4da 100644
--- a/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala
+++ b/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala
@@ -1,36 +1,54 @@
package sigmastate.lang
import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix
-import org.scalatest.exceptions.TestFailedException
-import org.scalatest.{Matchers, PropSpec}
-import org.scalatest.prop.PropertyChecks
-import sigmastate._
+import org.ergoplatform._
+import scorex.util.encode.Base58
import sigmastate.Values._
+import sigmastate._
+import sigmastate.helpers.SigmaTestingCommons
import sigmastate.interpreter.Interpreter.ScriptEnv
-import sigmastate.lang.syntax.ParserException
-import sigmastate.utxo.ByIndex
-
-class SigmaCompilerTest extends PropSpec with PropertyChecks with Matchers with LangTests {
- val compiler = new SigmaCompiler(TransformingSigmaBuilder)
-
- def comp(env: ScriptEnv, x: String) = compiler.compile(env, x, TestnetNetworkPrefix)
-
- def fail(env: ScriptEnv, x: String, index: Int, expected: Any): Unit = {
- try {
- val res = compiler.compile(env, x, TestnetNetworkPrefix)
- assert(false, s"Error expected")
- } catch {
- case e: TestFailedException =>
- throw e
- case pe: ParserException if pe.parseError.isDefined =>
- val p = pe
- val i = pe.parseError.get.index
- val l = pe.parseError.get.lastParser
- i shouldBe index
- l.toString shouldBe expected.toString
- }
+import sigmastate.lang.Terms.{Apply, Ident, Lambda, ZKProofBlock}
+import sigmastate.lang.exceptions.{CosterException, InvalidArguments, TyperException}
+import sigmastate.serialization.ValueSerializer
+import sigmastate.serialization.generators.ValueGenerators
+import sigmastate.utxo.{ByIndex, ExtractAmount, GetVar, SelectField}
+
+class SigmaCompilerTest extends SigmaTestingCommons with LangTests with ValueGenerators {
+ import CheckingSigmaBuilder._
+ implicit lazy val IR: TestingIRContext = new TestingIRContext {
+ beginPass(noConstPropagationPass)
+ }
+
+ private def comp(env: ScriptEnv, x: String): Value[SType] = compile(env, x)
+ private def comp(x: String): Value[SType] = compile(env, x)
+ private def compWOCosting(x: String): Value[SType] = compileWithoutCosting(env, x)
+
+ private def testMissingCosting(script: String, expected: SValue): Unit = {
+ val tree = compWOCosting(script)
+ tree shouldBe expected
+ checkSerializationRoundTrip(tree)
+ // when implemented in coster this should be changed to a positive expectation
+ an [CosterException] should be thrownBy comp(env, script)
+ }
+
+ private def testMissingCostingWOSerialization(script: String, expected: SValue): Unit = {
+ val tree = compWOCosting(script)
+ tree shouldBe expected
+ // when implemented in coster this should be changed to a positive expectation
+ an [CosterException] should be thrownBy comp(env, script)
}
+ private def costerFail(env: ScriptEnv, x: String, expectedLine: Int, expectedCol: Int): Unit = {
+ val exception = the[CosterException] thrownBy comp(env, x)
+ withClue(s"Exception: $exception, is missing source context:") { exception.source shouldBe defined }
+ val sourceContext = exception.source.get
+ sourceContext.line shouldBe expectedLine
+ sourceContext.column shouldBe expectedCol
+ }
+
+ private def costerFail(x: String, expectedLine: Int, expectedCol: Int): Unit =
+ costerFail(env, x, expectedLine, expectedCol)
+
property("array indexed access") {
comp(env, "Coll(1)(0)") shouldBe
ByIndex(ConcreteCollection(IndexedSeq(IntConstant(1)))(SInt), 0)
@@ -56,6 +74,7 @@ class SigmaCompilerTest extends PropSpec with PropertyChecks with Matchers with
property("predefined functions") {
comp(env, "anyOf(Coll(c1, c2))") shouldBe OR(ConcreteCollection(Vector(TrueLeaf, FalseLeaf)))
comp(env, "blake2b256(getVar[Coll[Byte]](10).get)") shouldBe CalcBlake2b256(GetVarByteArray(10).get)
+ comp(env, "sha256(getVar[Coll[Byte]](10).get)") shouldBe CalcSha256(GetVarByteArray(10).get)
comp(env, "10.toByte") shouldBe ByteConstant(10)
comp(env, "Coll(1)(0).toByte") shouldBe
Downcast(ByIndex(ConcreteCollection(Vector(IntConstant(1)),SInt),IntConstant(0),None), SByte)
@@ -64,12 +83,509 @@ class SigmaCompilerTest extends PropSpec with PropertyChecks with Matchers with
comp(env, "getVar[Coll[Byte]](10).get") shouldBe GetVarByteArray(10).get
}
- property("negative tests") {
- fail(env, "(10", 3, "\")\"")
- fail(env, "10)", 2, "End")
- fail(env, "X)", 1, "End")
- fail(env, "(X", 2, "\")\"")
- fail(env, "{ X", 3, "\"}\"")
- fail(env, "{ val X", 7, "\"=\"")
+ property("user-defined functions") {
+ comp("{ def f(i: Int) = { i + 1 }; f(2) }") shouldBe Apply(
+ FuncValue(Vector((1,SInt)),Plus(ValUse(1,SInt), IntConstant(1))),
+ Vector(IntConstant(2)))
+ }
+
+ property("allOf") {
+ comp("allOf(Coll[Boolean](true, false))") shouldBe AND(TrueLeaf, FalseLeaf)
+ }
+
+ property("anyOf") {
+ comp("anyOf(Coll[Boolean](true, false))") shouldBe OR(TrueLeaf, FalseLeaf)
+ }
+
+ property("atLeast") {
+ comp("atLeast(2, Coll[SigmaProp](p1, p2))") shouldBe AtLeast(2, p1, p2)
+ }
+
+ property("ZKProof") {
+ testMissingCostingWOSerialization("ZKProof { sigmaProp(HEIGHT > 1000) }",
+ ZKProofBlock(BoolToSigmaProp(GT(Height, IntConstant(1000)))))
+ }
+
+ property("sigmaProp") {
+ comp("sigmaProp(HEIGHT > 1000)") shouldBe BoolToSigmaProp(GT(Height, IntConstant(1000)))
+ }
+
+ property("getVar") {
+ comp("getVar[Byte](10).get") shouldBe GetVar(10.toByte, SByte).get
+ comp("getVar[Byte](10L).get") shouldBe GetVar(10.toByte, SByte).get
+ an[TyperException] should be thrownBy comp("getVar[Byte](\"ha\")")
+ }
+
+ property("PK (testnet network prefix)") {
+ implicit val ergoAddressEncoder: ErgoAddressEncoder = new ErgoAddressEncoder(TestnetNetworkPrefix)
+ val dk1 = proveDlogGen.sample.get
+ val encodedP2PK = P2PKAddress(dk1).toString
+ val code = s"""PK("$encodedP2PK")"""
+ val res = comp(code)
+ res shouldEqual SigmaPropConstant(dk1)
+ }
+
+ property("fromBaseX") {
+ comp(""" fromBase58("r") """) shouldBe ByteArrayConstant(Array(49))
+ comp(""" fromBase64("MQ") """) shouldBe ByteArrayConstant(Array(49))
+ comp(""" fromBase64("M" + "Q") """) shouldBe ByteArrayConstant(Array(49))
+ }
+
+ property("deserialize") {
+ def roundtrip[T <: SType](c: EvaluatedValue[T], typeSig: String) = {
+ val bytes = ValueSerializer.serialize(c)
+ val str = Base58.encode(bytes)
+ comp(env, s"deserialize[$typeSig](" + "\"" + str + "\")") shouldBe c
+ }
+ roundtrip(ByteArrayConstant(Array[Byte](2)), "Coll[Byte]")
+ roundtrip(Tuple(ByteArrayConstant(Array[Byte](2)), LongConstant(4)), "(Coll[Byte], Long)")
+ an[InvalidArguments] should be thrownBy roundtrip(ByteArrayConstant(Array[Byte](2)), "Coll[Long]")
+ }
+
+ property("deserialize fails") {
+ // more then one argument
+ an[TyperException] should be thrownBy comp(env, """deserialize[Int]("test", "extra argument")""")
+ // invalid chat in Base58 string
+ an[AssertionError] should be thrownBy comp(env, """deserialize[Int]("0")""")
+ // more than one type
+ an[TyperException] should be thrownBy comp(env, """deserialize[Int, Byte]("test")""")
+ // not a string constant
+ an[TyperException] should be thrownBy comp(env, """deserialize[Int](1)""")
+ }
+
+ property("longToByteArray") {
+ comp("longToByteArray(1L)") shouldBe LongToByteArray(LongConstant(1))
+ }
+
+ property("byteArrayToBigInt") {
+ comp("byteArrayToBigInt(longToByteArray(1L))") shouldBe ByteArrayToBigInt(LongToByteArray(LongConstant(1)))
+ }
+
+ property("failed fromBaseX (invalid input)") {
+ an[AssertionError] should be thrownBy comp(""" fromBase58("^%$#@")""")
+ an[IllegalArgumentException] should be thrownBy comp(""" fromBase64("^%$#@")""")
+ }
+
+ property("decodePoint") {
+ comp(env, "decodePoint(Coll[Byte](1.toByte))") shouldBe DecodePoint(ConcreteCollection(ByteConstant(1)))
+ }
+
+ property("logicalNot") {
+ comp("!true") shouldBe LogicalNot(TrueLeaf)
+ }
+
+ property("Negation") {
+ comp("-HEIGHT") shouldBe Negation(Height)
+ }
+
+ property("BitInversion") {
+ testMissingCosting("~1", BitInversion(IntConstant(1)))
+ }
+
+ property("LogicalXor") {
+ testMissingCosting("true ^ false", BinXor(TrueLeaf, FalseLeaf))
+ }
+
+ property("BitwiseOr") {
+ testMissingCosting("1 | 2", mkBitOr(IntConstant(1), IntConstant(2)))
+ }
+
+ property("BitwiseAnd") {
+ testMissingCosting("1 & 2", mkBitAnd(IntConstant(1), IntConstant(2)))
+ }
+
+ property("BitwiseXor") {
+ testMissingCosting("1 ^ 2", mkBitXor(IntConstant(1), IntConstant(2)))
+ }
+
+ property("BitShiftRight") {
+ testMissingCosting("1 >> 2", mkBitShiftRight(IntConstant(1), IntConstant(2)))
+ }
+
+ property("BitShiftLeft") {
+ testMissingCosting("1 << 2", mkBitShiftLeft(IntConstant(1), IntConstant(2)))
+ }
+
+ property("BitShiftRightZeroed") {
+ testMissingCosting("1 >>> 2", mkBitShiftRightZeroed(IntConstant(1), IntConstant(2)))
+ }
+
+ // TODO related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/418
+ ignore("Collection.BitShiftLeft") {
+ comp("Coll(1,2) << 2") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.BitShiftLeftMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(IntConstant(2)), Map())
+ }
+
+ // TODO related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/418
+ ignore("Collection.BitShiftRight") {
+ testMissingCosting("Coll(1,2) >> 2",
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.BitShiftRightMethod,
+ Vector(IntConstant(2)),
+ Map(SCollection.tIV -> SInt))
+ )
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("Collection.BitShiftRightZeroed") {
+ comp("Coll(true, false) >>> 2") shouldBe
+ mkMethodCall(
+ ConcreteCollection(TrueLeaf, FalseLeaf),
+ SCollection.BitShiftRightZeroedMethod,
+ Vector(IntConstant(2))
+ )
+ }
+
+ property("Collection.indices") {
+ comp("Coll(true, false).indices") shouldBe
+ mkMethodCall(
+ ConcreteCollection(TrueLeaf, FalseLeaf),
+ SCollection.IndicesMethod.withConcreteTypes(Map(SCollection.tIV -> SBoolean)),
+ Vector()
+ )
+ }
+
+ // TODO enable after such lambda is implemented in CollCoster.flatMap
+ ignore("SCollection.flatMap") {
+ comp("OUTPUTS.flatMap({ (out: Box) => Coll(out.value >= 1L) })") shouldBe
+ mkMethodCall(Outputs,
+ SCollection.FlatMapMethod.withConcreteTypes(Map(SCollection.tIV -> SBox, SCollection.tOV -> SBoolean)),
+ Vector(FuncValue(1,SBox,
+ ConcreteCollection(Vector(GE(ExtractAmount(ValUse(1, SBox)), LongConstant(1))), SBoolean))), Map())
+ }
+
+ // TODO should be fixed
+ ignore("SNumeric.toBytes") {
+ comp("4.toBytes") shouldBe
+ mkMethodCall(IntConstant(4), SInt.method("toBytes").get, IndexedSeq())
+ }
+
+ // TODO should be fixed
+ ignore("SNumeric.toBits") {
+ comp("4.toBits") shouldBe
+ mkMethodCall(IntConstant(4), SInt.method("toBits").get, IndexedSeq())
+ }
+
+ // TODO should be fixed
+ ignore("SBigInt.multModQ") {
+ comp("1.toBigInt.multModQ(2.toBigInt)") shouldBe
+ mkMethodCall(BigIntConstant(1), SBigInt.MultModQMethod, IndexedSeq(BigIntConstant(2)))
+ }
+
+ property("SBox.tokens") {
+ comp("SELF.tokens") shouldBe
+ mkMethodCall(Self, SBox.tokensMethod, IndexedSeq())
+ }
+
+ // TODO add rule to OptionCoster
+ ignore("SOption.toColl") {
+ comp("getVar[Int](1).toColl") shouldBe
+ mkMethodCall(GetVarInt(1),
+ SOption.ToCollMethod.withConcreteTypes(Map(SOption.tT -> SInt)), IndexedSeq(), Map())
+ }
+
+ property("SContext.dataInputs") {
+ comp("CONTEXT.dataInputs") shouldBe
+ mkMethodCall(Context, SContext.dataInputsMethod, IndexedSeq())
+ }
+
+ property("SAvlTree.digest") {
+ comp("getVar[AvlTree](1).get.digest") shouldBe
+ mkMethodCall(GetVar(1.toByte, SAvlTree).get, SAvlTree.digestMethod, IndexedSeq())
+ }
+
+ // TODO add costing rule
+ ignore("SGroupElement.exp") {
+ comp("g1.exp(1.toBigInt)") shouldBe
+ mkMethodCall(GroupElementConstant(ecp1),
+ SGroupElement.method("exp").get,
+ IndexedSeq(BigIntConstant(1)))
+ }
+
+ //TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/422
+ // TODO add rule to OptionCoster
+ ignore("SOption.map") {
+ testMissingCosting("getVar[Int](1).map({(i: Int) => i + 1})",
+ mkMethodCall(GetVarInt(1),
+ SOption.MapMethod.withConcreteTypes(Map(SOption.tT -> SInt, SOption.tR -> SInt)),
+ IndexedSeq(Terms.Lambda(
+ Vector(("i", SInt)),
+ SInt,
+ Some(Plus(Ident("i", SInt).asIntValue, IntConstant(1))))), Map())
+ )
+ }
+
+ //TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/422
+
+ // TODO add rule to OptionCoster
+ ignore("SOption.filter") {
+ testMissingCosting("getVar[Int](1).filter({(i: Int) => i > 0})",
+ mkMethodCall(GetVarInt(1),
+ SOption.FilterMethod.withConcreteTypes(Map(SOption.tT -> SInt)),
+ IndexedSeq(Terms.Lambda(
+ Vector(("i", SInt)),
+ SBoolean,
+ Some(GT(Ident("i", SInt).asIntValue, IntConstant(0))))), Map())
+ )
+ }
+
+ // TODO add rule to OptionCoster
+ ignore("SOption.flatMap") {
+ comp("getVar[Int](1).flatMap({(i: Int) => getVar[Int](2)})") shouldBe
+ mkMethodCall(GetVarInt(1),
+ SOption.FlatMapMethod.withConcreteTypes(Map(SOption.tT -> SInt, SOption.tR -> SInt)),
+ IndexedSeq(Terms.Lambda(
+ Vector(("i", SInt)),
+ SOption(SInt),
+ Some(GetVarInt(2)))),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.segmentLength") {
+ comp("OUTPUTS.segmentLength({ (out: Box) => out.value >= 1L }, 0)") shouldBe
+ mkMethodCall(Outputs,
+ SCollection.SegmentLengthMethod.withConcreteTypes(Map(SCollection.tIV -> SBox)),
+ Vector(
+ FuncValue(
+ Vector((1, SBox)),
+ GE(ExtractAmount(ValUse(1, SBox)), LongConstant(1))),
+ IntConstant(0)
+ ),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.indexWhere") {
+ comp("OUTPUTS.indexWhere({ (out: Box) => out.value >= 1L }, 0)") shouldBe
+ mkMethodCall(Outputs,
+ SCollection.IndexWhereMethod.withConcreteTypes(Map(SCollection.tIV -> SBox)),
+ Vector(
+ FuncValue(
+ Vector((1, SBox)),
+ GE(ExtractAmount(ValUse(1, SBox)), LongConstant(1))),
+ IntConstant(0)
+ ),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.lastIndexWhere") {
+ comp("OUTPUTS.lastIndexWhere({ (out: Box) => out.value >= 1L }, 1)") shouldBe
+ mkMethodCall(Outputs,
+ SCollection.LastIndexWhereMethod.withConcreteTypes(Map(SCollection.tIV -> SBox)),
+ Vector(
+ FuncValue(
+ Vector((1, SBox)),
+ GE(ExtractAmount(ValUse(1, SBox)), LongConstant(1))),
+ IntConstant(1)
+ ),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.patch") {
+ comp("Coll(1, 2).patch(1, Coll(3), 1)") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.PatchMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(IntConstant(1), ConcreteCollection(IntConstant(3)), IntConstant(1)),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.updated") {
+ comp("Coll(1, 2).updated(1, 1)") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.UpdatedMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(IntConstant(1), IntConstant(1)),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.updateMany") {
+ comp("Coll(1, 2).updateMany(Coll(1), Coll(3))") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.UpdateManyMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(ConcreteCollection(IntConstant(1)), ConcreteCollection(IntConstant(3))),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.unionSets") {
+ comp("Coll(1, 2).unionSets(Coll(1))") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.UnionSetsMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(ConcreteCollection(IntConstant(1))),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.diff") {
+ comp("Coll(1, 2).diff(Coll(1))") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.DiffMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(ConcreteCollection(IntConstant(1))),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.intersect") {
+ comp("Coll(1, 2).intersect(Coll(1))") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.IntersectMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(ConcreteCollection(IntConstant(1))),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.prefixLength") {
+ comp("OUTPUTS.prefixLength({ (out: Box) => out.value >= 1L })") shouldBe
+ mkMethodCall(Outputs,
+ SCollection.PrefixLengthMethod.withConcreteTypes(Map(SCollection.tIV -> SBox)),
+ Vector(
+ Terms.Lambda(
+ Vector(("out",SBox)),
+ SBoolean,
+ Some(GE(ExtractAmount(Ident("out",SBox).asBox),LongConstant(1))))
+ ),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.indexOf") {
+ comp("Coll(1, 2).indexOf(1, 0)") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.IndexOfMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(IntConstant(1), IntConstant(0)),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.lastIndexOf") {
+ comp("Coll(1, 2).lastIndexOf(1, 0)") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.LastIndexOfMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(IntConstant(1), IntConstant(0)),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.find") {
+ comp("OUTPUTS.find({ (out: Box) => out.value >= 1L })") shouldBe
+ mkMethodCall(Outputs,
+ SCollection.FindMethod.withConcreteTypes(Map(SCollection.tIV -> SBox)),
+ Vector(
+ Terms.Lambda(
+ Vector(("out",SBox)),
+ SBoolean,
+ Some(GE(ExtractAmount(Ident("out",SBox).asBox),LongConstant(1))))
+ ),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("Collection.distinct") {
+ comp("Coll(true, false).distinct") shouldBe
+ mkMethodCall(
+ ConcreteCollection(TrueLeaf, FalseLeaf),
+ SCollection.DistinctMethod.withConcreteTypes(Map(SCollection.tIV -> SBoolean)),
+ Vector()
+ )
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.startsWith") {
+ comp("Coll(1, 2).startsWith(Coll(1), 1)") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.StartsWithMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(ConcreteCollection(IntConstant(1)), IntConstant(1)),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.endsWith") {
+ comp("Coll(1, 2).endsWith(Coll(1))") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.EndsWithMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(ConcreteCollection(IntConstant(1))),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.zip") {
+ comp("Coll(1, 2).zip(Coll(1, 1))") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.ZipMethod.withConcreteTypes(Map(SCollection.tIV -> SInt, SCollection.tOV -> SInt)),
+ Vector(ConcreteCollection(IntConstant(1), IntConstant(1)))
+ )
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.partition") {
+ comp("Coll(1, 2).partition({ (i: Int) => i > 0 })") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.PartitionMethod.withConcreteTypes(Map(SCollection.tIV -> SInt)),
+ Vector(FuncValue(
+ Vector((1, SInt)),
+ GT(ValUse(1, SInt), IntConstant(0))
+ )),
+ Map())
+ }
+
+ // TODO 1) implement method for special.collection.Coll 2) add rule to CollCoster
+ ignore("SCollection.mapReduce") {
+ comp(
+ "Coll(1, 2).mapReduce({ (i: Int) => (i > 0, i.toLong) }, { (tl: (Long, Long)) => tl._1 + tl._2 })") shouldBe
+ mkMethodCall(
+ ConcreteCollection(IntConstant(1), IntConstant(2)),
+ SCollection.MapReduceMethod.withConcreteTypes(Map(SCollection.tIV -> SInt, SCollection.tK -> SBoolean, SCollection.tV -> SLong)),
+ Vector(
+ Lambda(List(),
+ Vector(("i", SInt)),
+ STuple(SBoolean, SLong),
+ Some(Tuple(Vector(
+ GT(Ident("i", SInt).asIntValue, IntConstant(0)),
+ Upcast(Ident("i", SInt).asIntValue, SLong)
+ )))
+ ),
+ Lambda(List(),
+ Vector(("tl", STuple(SLong, SLong))),
+ SLong,
+ Some(Plus(
+ SelectField(Ident("tl", STuple(SLong, SLong)).asValue[STuple], 1).asInstanceOf[Value[SLong.type]],
+ SelectField(Ident("tl", STuple(SLong, SLong)).asValue[STuple], 2).asInstanceOf[Value[SLong.type]])
+ )
+ )
+ ),
+ Map())
+ }
+
+ property("failed option constructors (not supported)") {
+ costerFail("None", 1, 1)
+ costerFail("Some(10)", 1, 1)
+ }
+
+ property("byteArrayToLong") {
+ comp("byteArrayToLong(longToByteArray(1L))") shouldBe ByteArrayToLong(LongToByteArray(LongConstant(1)))
+ }
+
+ property("xorOf") {
+ comp("xorOf(Coll[Boolean](true, false))") shouldBe XorOf(Seq(TrueLeaf, FalseLeaf))
}
}
diff --git a/src/test/scala/sigmastate/lang/SigmaParserTest.scala b/src/test/scala/sigmastate/lang/SigmaParserTest.scala
index c3a78fa3c7..6abcd0e8a1 100644
--- a/src/test/scala/sigmastate/lang/SigmaParserTest.scala
+++ b/src/test/scala/sigmastate/lang/SigmaParserTest.scala
@@ -1,12 +1,13 @@
package sigmastate.lang
-import fastparse.core.{ParseError, Parsed}
-import org.scalatest.exceptions.TestFailedException
+import fastparse.core.Parsed
+import org.ergoplatform.{ErgoAddressEncoder, ErgoBox}
import org.scalatest.prop.PropertyChecks
-import org.scalatest.{Matchers, PropSpec}
-import sigmastate.SCollection.SByteArray
+import org.scalatest.{PropSpec, Matchers}
+import sigmastate.SCollection._
import sigmastate.Values._
import sigmastate._
+import sigmastate.lang.SigmaPredef.PredefinedFuncRegistry
import sigmastate.lang.Terms._
import sigmastate.lang.syntax.ParserException
import sigmastate.serialization.OpCodes
@@ -14,9 +15,15 @@ import sigmastate.serialization.OpCodes
class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with LangTests {
import StdSigmaBuilder._
+ private val predefFuncRegistry = new PredefinedFuncRegistry(StdSigmaBuilder)
+ import predefFuncRegistry._
+
def parse(x: String): SValue = {
SigmaParser(x, TransformingSigmaBuilder) match {
- case Parsed.Success(v, _) => v
+ case Parsed.Success(v, _) =>
+ v.sourceContext.isDefined shouldBe true
+ assertSrcCtxForAllNodes(v)
+ v
case f@Parsed.Failure(_, _, extra) =>
val traced = extra.traced
println(s"\nTRACE: ${traced.trace}")
@@ -28,17 +35,13 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
SigmaParser.parseType(x)
}
- def fail(x: String, index: Int): Unit = {
- try {
- val res = SigmaParser(x, TransformingSigmaBuilder).get.value
- assert(false, s"Error expected")
- } catch {
- case e: TestFailedException =>
- throw e
- case pe: ParseError[_,_] =>
- val l = pe.failure.index
- l shouldBe index
- }
+ def fail(x: String, expectedLine: Int, expectedCol: Int): Unit = {
+ val compiler = SigmaCompiler(ErgoAddressEncoder.TestnetNetworkPrefix)
+ val exception = the[ParserException] thrownBy compiler.parse(x)
+ withClue(s"Exception: $exception, is missing source context:") { exception.source shouldBe defined }
+ val sourceContext = exception.source.get
+ sourceContext.line shouldBe expectedLine
+ sourceContext.column shouldBe expectedCol
}
def and(l: SValue, r: SValue) = MethodCallLike(l, "&&", IndexedSeq(r))
@@ -115,7 +118,7 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
}
property("tuple operations") {
- parse("()") shouldBe UnitConstant
+ parse("()") shouldBe UnitConstant()
parse("(1)") shouldBe IntConstant(1)
parse("(1, 2)") shouldBe Tuple(IntConstant(1), IntConstant(2))
parse("(1, X - 1)") shouldBe Tuple(IntConstant(1), mkMinus(IntIdent("X"), 1))
@@ -228,11 +231,11 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
}
property("array literals") {
- val emptyCol = Apply(Ident("Coll"), IndexedSeq.empty)
- parse("Coll()") shouldBe emptyCol
- val emptyCol2 = Apply(Ident("Coll"), IndexedSeq(emptyCol))
- parse("Coll(Coll())") shouldBe emptyCol2
- parse("Coll(Coll(Coll()))") shouldBe Apply(Ident("Coll"), IndexedSeq(emptyCol2))
+ val emptyColl = Apply(Ident("Coll"), IndexedSeq.empty)
+ parse("Coll()") shouldBe emptyColl
+ val emptyColl2 = Apply(Ident("Coll"), IndexedSeq(emptyColl))
+ parse("Coll(Coll())") shouldBe emptyColl2
+ parse("Coll(Coll(Coll()))") shouldBe Apply(Ident("Coll"), IndexedSeq(emptyColl2))
parse("Coll(1)") shouldBe Apply(Ident("Coll"), IndexedSeq(IntConstant(1)))
parse("Coll(1, X)") shouldBe Apply(Ident("Coll"), IndexedSeq(IntConstant(1), Ident("X")))
@@ -401,7 +404,7 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
// nested lambda
parse(
"""f { (a: Int) =>
- |val g = { (c: Int) => c - 1 }
+ |def g(c: Int) = c - 1
|a - g(a)
|}""".stripMargin) shouldBe Apply(Ident("f"), IndexedSeq(
Lambda(IndexedSeq("a" -> SInt),
@@ -412,7 +415,7 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
)))
}
- property("function definitions") {
+ property("function definitions via val") {
parse("{val f = { (x: Int) => x - 1 }; f}") shouldBe
Block(Val("f", Lambda(IndexedSeq("x" -> SInt), mkMinus(IntIdent("x"), 1))), Ident("f"))
parse(
@@ -422,6 +425,97 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
Block(Val("f", Lambda(IndexedSeq("x" -> SInt), mkMinus(IntIdent("x"), 1))), Ident("f"))
}
+ property("function (one arg) definition expr body") {
+ parse("{ def f(x: Int): Int = x - 1 }") shouldBe Block(List(),
+ Val("f", SInt, Lambda(IndexedSeq("x" -> SInt), SInt, mkMinus(IntIdent("x"), 1))))
+ }
+
+ property("function (one arg) definition with no res type, expr body") {
+ parse("{ def f(x: Int) = x - 1 }") shouldBe Block(List(),
+ Val("f", NoType, Lambda(IndexedSeq("x" -> SInt), NoType, mkMinus(IntIdent("x"), 1))))
+ }
+
+ property("function (one arg) definition brackets body") {
+ val expectedTree = Block(List(),
+ Val("f", SInt, Lambda(IndexedSeq("x" -> SInt), SInt, Block(List(), mkMinus(IntIdent("x"), 1)))))
+ parse("{ def f(x: Int): Int = { x - 1 } }") shouldBe expectedTree
+ parse(
+ """{
+ def f(x: Int): Int = {
+ x - 1
+ }
+ }
+ """.stripMargin) shouldBe expectedTree
+ }
+
+ property("function(two arg) definition expr body") {
+ parse("{ def f(x: Int, y: Int): Int = x - y }") shouldBe Block(List(),
+ Val("f", SInt,
+ Lambda(IndexedSeq("x" -> SInt, "y" -> SInt), SInt, mkMinus(IntIdent("x"), IntIdent("y")))))
+ }
+
+ property("function definition and application") {
+ parse(
+ """{
+ def f(x: Int): Int = {
+ x - 1
+ }
+ f(5)
+ }
+ """.stripMargin) shouldBe Block(
+ Val("f", SInt,
+ Lambda(IndexedSeq("x" -> SInt), SInt, Block(List(), mkMinus(IntIdent("x"), 1)))),
+ Apply(Ident("f"), Vector(IntConstant(5)))
+ )
+ }
+
+ property("function with type args") {
+ val tA = STypeIdent("A")
+ val tB = STypeIdent("B")
+ parse("{ def f[A, B](x: A, y: B): (A, B) = (x, y) }") shouldBe Block(List(),
+ Val("f",
+ STuple(tA, tB),
+ Lambda(IndexedSeq("x" -> tA, "y" -> tB),
+ STuple(tA, tB),
+ Tuple(Ident("x"), Ident("y"))
+ )
+ )
+ )
+ }
+
+ property("function (no args) definition expr body") {
+ parse("{ def f: Int = 1 }") shouldBe Block(List(),
+ Val("f", SInt, Lambda(IndexedSeq(), SInt, IntConstant(1))))
+ }
+
+ property("method extension(dotty)(no args) with type args") {
+ val tA = STypeIdent("A")
+ val tB = STypeIdent("B")
+ parse("{ def (pairs: Coll[(A,B)]) f[A, B]: Coll[(B, A)] = pairs.magicSwap }") shouldBe Block(List(),
+ Val("f",
+ SCollection(STuple(tB, tA)),
+ Lambda(IndexedSeq("pairs" -> SCollection(STuple(tA, tB))),
+ SCollection(STuple(tB, tA)),
+ Select(Ident("pairs"), "magicSwap")
+ )
+ )
+ )
+ }
+
+ property("method extension(dotty)(one arg) with type args") {
+ val tA = STypeIdent("A")
+ val tB = STypeIdent("B")
+ parse("{ def (pairs: Coll[(A,B)]) take[A, B](i: Int): Coll[(A, B)] = pairs.drop(i) }") shouldBe Block(List(),
+ Val("take",
+ SCollection(STuple(tA, tB)),
+ Lambda(IndexedSeq("pairs" -> SCollection(STuple(tA, tB)), "i" -> SInt),
+ SCollection(STuple(tA, tB)),
+ Apply(Select(Ident("pairs"), "drop"), Vector(Ident("i")))
+ )
+ )
+ )
+ }
+
property("get field of ref") {
parse("XXX.YYY") shouldBe Select(Ident("XXX"), "YYY")
parse("""
@@ -456,24 +550,24 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
parseType("Int") shouldBe SInt
parseType("(Int, Long)") shouldBe STuple(SInt, SLong)
parseType("Coll[(Int, Long)]") shouldBe SCollection(STuple(SInt, SLong))
- parseType("Coll[(Coll[Byte], Long)]") shouldBe SCollection(STuple(SCollection(SByte), SLong))
- parseType("Coll[(Coll[Byte], Coll[Long])]") shouldBe SCollection(STuple(SCollection(SByte), SCollection(SLong)))
- parseType("Coll[(Coll[Byte], (Coll[Long], Long))]") shouldBe SCollection(STuple(SCollection(SByte), STuple(SCollection(SLong), SLong)))
+ parseType("Coll[(Coll[Byte], Long)]") shouldBe ErgoBox.STokensRegType
+ parseType("Coll[(Coll[Byte], Coll[Long])]") shouldBe SCollection(STuple(SByteArray, SLongArray))
+ parseType("Coll[(Coll[Byte], (Coll[Long], Long))]") shouldBe SCollection(STuple(SByteArray, STuple(SLongArray, SLong)))
}
property("negative tests") {
- fail("(10", 3)
- fail("10)", 2)
- fail("X)", 1)
- fail("(X", 2)
- fail("{ X", 3)
- fail("{ val X", 7)
- fail("\"str", 4)
+ fail("(10", 1, 4)
+ fail("10)", 1, 3)
+ fail("X)", 1, 2)
+ fail("(X", 1, 3)
+ fail("{ X", 1, 4)
+ fail("{ val X", 1, 8)
+ fail("\"str", 1, 5)
}
property("not(yet) supported lambda syntax") {
// passing a lambda without curly braces is not supported yet :)
- fail("arr.exists ( (a: Int) => a >= 1 )", 15)
+ fail("arr.exists ( (a: Int) => a >= 1 )", 1, 16)
// no argument type
an[ParserException] should be thrownBy parse("arr.exists ( a => a >= 1 )")
an[ParserException] should be thrownBy parse("arr.exists { a => a >= 1 }")
@@ -503,8 +597,8 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
}
property("fromBaseX string decoding") {
- parse("""fromBase58("111")""") shouldBe Apply(Ident("fromBase58"), IndexedSeq(StringConstant("111")))
- parse("""fromBase64("111")""") shouldBe Apply(Ident("fromBase64"), IndexedSeq(StringConstant("111")))
+ parse("""fromBase58("111")""") shouldBe Apply(FromBase58Func.symNoType, IndexedSeq(StringConstant("111")))
+ parse("""fromBase64("111")""") shouldBe Apply(FromBase64Func.symNoType, IndexedSeq(StringConstant("111")))
}
property("PK") {
@@ -513,24 +607,25 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
property("deserialize") {
parse("""deserialize[GroupElement]("12345")""") shouldBe
- Apply(ApplyTypes(Ident("deserialize"), Seq(SGroupElement)), IndexedSeq(StringConstant("12345")))
+ Apply(ApplyTypes(DeserializeFunc.symNoType, Seq(SGroupElement)), IndexedSeq(StringConstant("12345")))
parse("""deserialize[(GroupElement, Coll[(Int, Byte)])]("12345")""") shouldBe
- Apply(ApplyTypes(Ident("deserialize"), Seq(STuple(SGroupElement, SCollection(STuple(SInt, SByte))))), IndexedSeq(StringConstant("12345")))
+ Apply(ApplyTypes(DeserializeFunc.symNoType, Seq(STuple(SGroupElement, SCollection(STuple(SInt, SByte))))), IndexedSeq(StringConstant("12345")))
}
property("ZKProof") {
- parse("ZKProof { condition }") shouldBe Apply(SigmaPredef.ZKProofSym, IndexedSeq(Ident("condition")))
+ parse("ZKProof { condition }") shouldBe Apply(ZKProofFunc.sym, IndexedSeq(Ident("condition")))
parse("ZKProof { sigmaProp(HEIGHT > 1000) }") shouldBe
- Apply(SigmaPredef.ZKProofSym,
- IndexedSeq(Apply(Ident("sigmaProp"), IndexedSeq(GT(Ident("HEIGHT"), IntConstant(1000))))))
+ Apply(ZKProofFunc.sym,
+ IndexedSeq(Apply(SigmaPropFunc.symNoType, IndexedSeq(GT(Ident("HEIGHT"), IntConstant(1000))))))
}
property("invalid ZKProof (non block parameter)") {
- an[ParserException] should be thrownBy parse("ZKProof HEIGHT > 1000 ")
+ fail("ZKProof 1 > 1", 1, 9)
}
property("sigmaProp") {
- parse("sigmaProp(HEIGHT > 1000)") shouldBe Apply(Ident("sigmaProp"), IndexedSeq(GT(Ident("HEIGHT"), IntConstant(1000))))
+ parse("sigmaProp(HEIGHT > 1000)") shouldBe Apply(SigmaPropFunc.symNoType,
+ IndexedSeq(GT(Ident("HEIGHT"), IntConstant(1000))))
}
property("SBigInt.toBytes") {
@@ -558,7 +653,7 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
property("byteArrayToLong") {
parse("byteArrayToLong(Coll[Byte](1.toByte))") shouldBe
- Apply(Ident("byteArrayToLong"), Vector(
+ Apply(ByteArrayToLongFunc.symNoType, Vector(
Apply(
ApplyTypes(Ident("Coll", NoType), Vector(SByte)),
Vector(Select(IntConstant(1), "toByte", None)))
@@ -567,7 +662,7 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
property("decodePoint") {
parse("decodePoint(Coll[Byte](1.toByte))") shouldBe
- Apply(Ident("decodePoint"), Vector(
+ Apply(DecodePointFunc.symNoType, Vector(
Apply(
ApplyTypes(Ident("Coll", NoType), Vector(SByte)),
Vector(Select(IntConstant(1), "toByte", None)))
@@ -576,7 +671,7 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
property("xorOf") {
parse("xorOf(Coll[Boolean](true, false))") shouldBe
- Apply(Ident("xorOf"), Vector(
+ Apply(XorOfFunc.symNoType, Vector(
Apply(
ApplyTypes(Ident("Coll", NoType), Vector(SBoolean)),
Vector(TrueLeaf, FalseLeaf))
@@ -724,7 +819,7 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
| { (b, i) => (b + i).toLong },
| { (b, s, i) => (b + s + i).toLong }
| )""".stripMargin) shouldBe Apply(
- ApplyTypes(Ident("outerJoin", NoType), Vector(SByte, SShort, SInt, SLong)),
+ ApplyTypes(OuterJoinFunc.symNoType, Vector(SByte, SShort, SInt, SLong)),
Vector(
Apply(
ApplyTypes(Ident("Coll", NoType), Vector(STuple(SByte, SShort))),
@@ -761,4 +856,52 @@ class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with La
)
}
+ property("substConstants") {
+ parse("substConstants[Long](Coll[Byte](1.toByte), Coll[Int](1), Coll[Long](1L))") shouldBe Apply(
+ ApplyTypes(SubstConstantsFunc.symNoType, Vector(SLong)),
+ Vector(
+ Apply(ApplyTypes(Ident("Coll", NoType), Vector(SByte)), Vector(Select(IntConstant(1), "toByte", None))),
+ Apply(ApplyTypes(Ident("Coll", NoType), Vector(SInt)), Vector(IntConstant(1))),
+ Apply(ApplyTypes(Ident("Coll", NoType), Vector(SLong)), Vector(LongConstant(1)))
+ )
+ )
+ }
+
+ property("executeFromVar") {
+ parse("executeFromVar[Boolean](1)") shouldBe Apply(
+ ApplyTypes(ExecuteFromVarFunc.symNoType, Vector(SBoolean)), Vector(IntConstant(1))
+ )
+ }
+
+ property("single name pattern fail") {
+ fail("{val (a,b) = (1,2)}", 1, 6)
+ }
+
+ property("unknown prefix in unary op") {
+ fail("+1", 1, 2)
+ }
+
+ property("empty lines before invalid op") {
+ fail(
+ """
+ |
+ |
+ |+1""".stripMargin, 4, 2)
+ }
+
+ property("unknown binary op") {
+ fail("1**1", 1, 1)
+ }
+
+ property("compound types not supported") {
+ fail("Coll[Int with Sortable](1)", 1, 6)
+ }
+
+ property("path types not supported") {
+ fail("Coll[Int.A](1)", 1, 10)
+ }
+
+ property("block contains non-Val binding before expression") {
+ fail("{1 ; 1 == 1}", 1, 2)
+ }
}
\ No newline at end of file
diff --git a/src/test/scala/sigmastate/lang/SigmaSpecializerTest.scala b/src/test/scala/sigmastate/lang/SigmaSpecializerTest.scala
index e5d2e79109..ce89578081 100644
--- a/src/test/scala/sigmastate/lang/SigmaSpecializerTest.scala
+++ b/src/test/scala/sigmastate/lang/SigmaSpecializerTest.scala
@@ -4,12 +4,13 @@ import org.ergoplatform.ErgoAddressEncoder.{NetworkPrefix, TestnetNetworkPrefix}
import org.ergoplatform.ErgoBox.R4
import org.ergoplatform._
import org.scalatest.prop.PropertyChecks
-import org.scalatest.{PropSpec, Matchers}
+import org.scalatest.{Matchers, PropSpec}
import sigmastate.Values._
import sigmastate._
+import sigmastate.lang.SigmaPredef.PredefinedFuncRegistry
import sigmastate.lang.Terms.{Ident, ZKProofBlock}
import sigmastate.lang.exceptions.SpecializerException
-import sigmastate.serialization.generators.{ValueGenerators, TransformerGenerators, ConcreteCollectionGenerators}
+import sigmastate.serialization.generators.{ConcreteCollectionGenerators, TransformerGenerators, ValueGenerators}
import sigmastate.utxo._
import sigmastate.lang.Terms._
@@ -33,14 +34,15 @@ class SigmaSpecializerTest extends PropSpec
def typed(env: Map[String, SValue], x: String): SValue = {
val builder = TransformingSigmaBuilder
val parsed = SigmaParser(x, builder).get.value
- val binder = new SigmaBinder(env, builder)
+ val predefinedFuncRegistry = new PredefinedFuncRegistry(builder)
+ val binder = new SigmaBinder(env, builder, TestnetNetworkPrefix, predefinedFuncRegistry)
val bound = binder.bind(parsed)
- val typer = new SigmaTyper(builder)
+ val typer = new SigmaTyper(builder, predefinedFuncRegistry)
val typed = typer.typecheck(bound)
typed
}
def spec(env: Map[String, SValue], typed: SValue, networkPrefix: NetworkPrefix = TestnetNetworkPrefix): SValue = {
- val spec = new SigmaSpecializer(TransformingSigmaBuilder, networkPrefix)
+ val spec = new SigmaSpecializer(TransformingSigmaBuilder)
spec.specialize(env, typed)
}
def spec(code: String): SValue = {
@@ -130,9 +132,9 @@ class SigmaSpecializerTest extends PropSpec
}
property("AND flattening, CAND/COR untouched") {
- val sigmaBooleans1 = AND(Seq(TrueLeaf, CAND(Seq(proveDlogGen.sample.get, proveDHTGen.sample.get))))
+ val sigmaBooleans1 = AND(Seq(TrueLeaf, CAND(Seq(proveDlogGen.sample.get, proveDHTGen.sample.get)).toSigmaProp.isProven))
spec(Map(), sigmaBooleans1) shouldBe sigmaBooleans1
- val sigmaBooleans2 = AND(Seq(TrueLeaf, COR(Seq(proveDlogGen.sample.get, proveDHTGen.sample.get))))
+ val sigmaBooleans2 = AND(Seq(TrueLeaf, COR(Seq(proveDlogGen.sample.get, proveDHTGen.sample.get)).toSigmaProp.isProven))
spec(Map(), sigmaBooleans2) shouldBe sigmaBooleans2
}
@@ -151,9 +153,9 @@ class SigmaSpecializerTest extends PropSpec
}
property("OR flattening, CAND/COR untouched") {
- val sigmaBooleans1 = OR(Seq(TrueLeaf, CAND(Seq(proveDlogGen.sample.get, proveDHTGen.sample.get))))
+ val sigmaBooleans1 = OR(Seq(TrueLeaf, CAND(Seq(proveDlogGen.sample.get, proveDHTGen.sample.get)).toSigmaProp.isProven))
spec(Map(), sigmaBooleans1) shouldBe sigmaBooleans1
- val sigmaBooleans2 = OR(Seq(TrueLeaf, COR(Seq(proveDlogGen.sample.get, proveDHTGen.sample.get))))
+ val sigmaBooleans2 = OR(Seq(TrueLeaf, COR(Seq(proveDlogGen.sample.get, proveDHTGen.sample.get)).toSigmaProp.isProven))
spec(Map(), sigmaBooleans2) shouldBe sigmaBooleans2
}
@@ -182,37 +184,6 @@ class SigmaSpecializerTest extends PropSpec
an[ArithmeticException] should be thrownBy spec(s"${Long.MaxValue}L.toInt")
}
- property("byteArrayToBigInt") {
- spec("byteArrayToBigInt(longToByteArray(1L))") shouldBe ByteArrayToBigInt(LongToByteArray(LongConstant(1)))
- }
-
- property("fromBaseX") {
- spec(""" fromBase58("r") """) shouldBe ByteArrayConstant(Array(49))
- spec(""" fromBase64("MQ") """) shouldBe ByteArrayConstant(Array(49))
- spec(""" fromBase64("M" + "Q") """) shouldBe ByteArrayConstant(Array(49))
- }
-
- property("failed fromBaseX (invalid input)") {
- an[AssertionError] should be thrownBy spec(""" fromBase58("^%$#@")""")
- an[IllegalArgumentException] should be thrownBy spec(""" fromBase64("^%$#@")""")
- }
-
- private def testPK(networkPrefix: NetworkPrefix) = {
- implicit val ergoAddressEncoder: ErgoAddressEncoder = new ErgoAddressEncoder(networkPrefix)
- val dk1 = proveDlogGen.sample.get
- val encodedP2PK = P2PKAddress(dk1).toString
- val code = s"""PK("$encodedP2PK")"""
- spec(Map(), typed(Map(), code), networkPrefix) shouldEqual dk1
- }
-
- property("PK (testnet network prefix)") {
- testPK(TestnetNetworkPrefix)
- }
-
- property("PK (mainnet network prefix)") {
- testPK(ErgoAddressEncoder.MainnetNetworkPrefix)
- }
-
property("ExtractRegisterAs") {
spec("SELF.R4[Int]") shouldBe ExtractRegisterAs[SInt.type](Self, R4)
}
diff --git a/src/test/scala/sigmastate/lang/SigmaTyperTest.scala b/src/test/scala/sigmastate/lang/SigmaTyperTest.scala
index 8cd34de1a7..4f5ce080fe 100644
--- a/src/test/scala/sigmastate/lang/SigmaTyperTest.scala
+++ b/src/test/scala/sigmastate/lang/SigmaTyperTest.scala
@@ -1,29 +1,37 @@
package sigmastate.lang
-import org.ergoplatform.{Height, Inputs}
+import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix
+import org.ergoplatform._
import org.scalatest.prop.PropertyChecks
-import org.scalatest.{Matchers, PropSpec}
-import sigmastate.SCollection.SByteArray
+import org.scalatest.{PropSpec, Matchers}
+import sigmastate.SCollection._
import sigmastate.Values._
import sigmastate._
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.interpreter.CryptoConstants
import sigmastate.interpreter.Interpreter.ScriptEnv
import sigmastate.lang.SigmaPredef._
-import sigmastate.lang.Terms.{Ident, Select}
-import sigmastate.lang.exceptions.{InvalidBinaryOperationParameters, MethodNotFound, NonApplicableMethod, TyperException}
+import sigmastate.lang.Terms.Select
+import sigmastate.lang.exceptions.{NonApplicableMethod, TyperException, InvalidBinaryOperationParameters, MethodNotFound}
import sigmastate.serialization.generators.ValueGenerators
-import sigmastate.utxo.{Append, ExtractCreationInfo, SizeOf}
+import sigmastate.utxo.{ExtractCreationInfo, Append}
class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with LangTests with ValueGenerators {
+ private val predefFuncRegistry = new PredefinedFuncRegistry(StdSigmaBuilder)
+ import predefFuncRegistry._
+
def typecheck(env: ScriptEnv, x: String, expected: SValue = null): SType = {
try {
val builder = TransformingSigmaBuilder
val parsed = SigmaParser(x, builder).get.value
- val binder = new SigmaBinder(env, builder)
+ val predefinedFuncRegistry = new PredefinedFuncRegistry(builder)
+ val binder = new SigmaBinder(env, builder, TestnetNetworkPrefix, predefinedFuncRegistry)
val bound = binder.bind(parsed)
val st = new SigmaTree(bound)
- val typer = new SigmaTyper(builder)
+ val typer = new SigmaTyper(builder, predefinedFuncRegistry)
val typed = typer.typecheck(bound)
+ assertSrcCtxForAllNodes(typed)
if (expected != null) typed shouldBe expected
typed.tpe
} catch {
@@ -31,23 +39,19 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
}
}
- def typefail(env: ScriptEnv, x: String, messageSubstr: String = ""): Unit = {
- try {
- val builder = TransformingSigmaBuilder
- val parsed = SigmaParser(x, builder).get.value
- val binder = new SigmaBinder(env, builder)
- val bound = binder.bind(parsed)
- val st = new SigmaTree(bound)
- val typer = new SigmaTyper(builder)
- val typed = typer.typecheck(bound)
- assert(false, s"Should not typecheck: $x")
- } catch {
- case e: TyperException =>
- if (messageSubstr.nonEmpty)
- if (!e.getMessage.contains(messageSubstr)) {
- throw new AssertionError(s"Error message '${e.getMessage}' doesn't contain '$messageSubstr'.", e)
- }
- }
+ def typefail(env: ScriptEnv, x: String, expectedLine: Int, expectedCol: Int): Unit = {
+ val builder = TransformingSigmaBuilder
+ val parsed = SigmaParser(x, builder).get.value
+ val predefinedFuncRegistry = new PredefinedFuncRegistry(builder)
+ val binder = new SigmaBinder(env, builder, TestnetNetworkPrefix, predefinedFuncRegistry)
+ val bound = binder.bind(parsed)
+ val st = new SigmaTree(bound)
+ val typer = new SigmaTyper(builder, predefinedFuncRegistry)
+ val exception = the[TyperException] thrownBy typer.typecheck(bound)
+ withClue(s"Exception: $exception, is missing source context:") { exception.source shouldBe defined }
+ val sourceContext = exception.source.get
+ sourceContext.line shouldBe expectedLine
+ sourceContext.column shouldBe expectedCol
}
property("simple expressions") {
@@ -65,12 +69,12 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, "INPUTS.size") shouldBe SInt
typecheck(env, "INPUTS.size > 1", GT(Select(Inputs, "size", Some(SInt)), 1)) shouldBe SBoolean
// todo: restore in https://github.com/ScorexFoundation/sigmastate-interpreter/issues/324
-// typecheck(env, "arr1 | arr2", Xor(ByteArrayConstant(arr1), ByteArrayConstant(arr2))) shouldBe SByteArray
+ // typecheck(env, "arr1 | arr2", Xor(ByteArrayConstant(arr1), ByteArrayConstant(arr2))) shouldBe SByteArray
typecheck(env, "arr1 ++ arr2", Append(ByteArrayConstant(arr1), ByteArrayConstant(arr2))) shouldBe SByteArray
typecheck(env, "col1 ++ col2") shouldBe SCollection(SLong)
// todo should be g1.exp(n1)
// ( see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/324 )
-// typecheck(env, "g1 ^ n1") shouldBe SGroupElement
+ // typecheck(env, "g1 ^ n1") shouldBe SGroupElement
typecheck(env, "g1 * g2") shouldBe SGroupElement
typecheck(env, "p1 || p2") shouldBe SSigmaProp
typecheck(env, "p1 && p2") shouldBe SSigmaProp
@@ -87,7 +91,7 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
}
property("predefined functions") {
- typecheck(env, "allOf") shouldBe AllSym.tpe
+ typecheck(env, "allOf") shouldBe AllOfFunc.declaration.tpe
typecheck(env, "allOf(Coll(c1, c2))") shouldBe SBoolean
typecheck(env, "getVar[Byte](10).get") shouldBe SByte
typecheck(env, "getVar[Coll[Byte]](10).get") shouldBe SByteArray
@@ -103,8 +107,15 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, "max(1L, 2)") shouldBe SLong
typecheck(env, """fromBase58("111")""") shouldBe SByteArray
typecheck(env, """fromBase64("111")""") shouldBe SByteArray
- typecheck(env, """PK("111")""") shouldBe SSigmaProp
- typecheck(env, """PK("111")""") shouldBe SSigmaProp
+
+ typecheck(env, {
+ implicit val ergoAddressEncoder: ErgoAddressEncoder = new ErgoAddressEncoder(TestnetNetworkPrefix)
+ val pk = ProveDlog(CryptoConstants.dlogGroup.generator)
+ val addr = P2PKAddress(pk)
+ val str = addr.toString
+ s"""PK("${str}")"""
+ }) shouldBe SSigmaProp
+
typecheck(env, "sigmaProp(HEIGHT > 1000)") shouldBe SSigmaProp
typecheck(env, "ZKProof { sigmaProp(HEIGHT > 1000) }") shouldBe SBoolean
}
@@ -115,8 +126,8 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, """{val X = 10 + 1; X >= X}""".stripMargin) shouldBe SBoolean
typecheck(env,
"""{val X = 10
- |val Y = X + 1
- |X < Y}
+ |val Y = X + 1
+ |X < Y}
""".stripMargin) shouldBe SBoolean
typecheck(env, "{val X = (10, true); X._1 > 2 && X._2}") shouldBe SBoolean
typecheck(env, "{val X = (Coll(1,2,3), 1); X}") shouldBe STuple(SCollection(SInt), SInt)
@@ -147,7 +158,7 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, "(1, 2L)._2") shouldBe SLong
typecheck(env, "(1, 2L, 3)._3") shouldBe SInt
- an[MethodNotFound] should be thrownBy typecheck(env, "(1, 2L)._3")
+ typefail(env, "(1, 2L)._3", 1, 1)
// tuple as collection
typecheck(env, "(1, 2L).size") shouldBe SInt
@@ -179,16 +190,16 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
}
property("array literals") {
- typefail(env, "Coll()", "Undefined type of empty collection")
- typefail(env, "Coll(Coll())", "Undefined type of empty collection")
- typefail(env, "Coll(Coll(Coll()))", "Undefined type of empty collection")
+ typefail(env, "Coll()", 1, 1)
+ typefail(env, "Coll(Coll())", 1, 6)
+ typefail(env, "Coll(Coll(Coll()))", 1, 11)
typecheck(env, "Coll(1)") shouldBe SCollection(SInt)
typecheck(env, "Coll(1, x)") shouldBe SCollection(SInt)
typecheck(env, "Coll(Coll(x + 1))") shouldBe SCollection(SCollection(SInt))
- typefail(env, "Coll(1, x + 1, Coll())")
- typefail(env, "Coll(1, false)")
+ typefail(env, "Coll(1, x + 1, Coll())", 1, 16)
+ typefail(env, "Coll(1, false)", 1, 1)
}
property("Option constructors") {
@@ -204,23 +215,23 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
}
property("array indexed access") {
- typefail(env, "Coll()(0)", "Undefined type of empty collection")
+ typefail(env, "Coll()(0)", 1, 1)
typecheck(env, "Coll(0)(0)") shouldBe SInt
- typefail(env, "Coll(0)(0)(0)", "array type is expected")
+ typefail(env, "Coll(0)(0)(0)", 1, 1)
}
property("array indexed access with evaluation") {
typecheck(env, "Coll(0)(1 - 1)") shouldBe SInt
typecheck(env, "Coll(0)((1 - 1) + 0)") shouldBe SInt
- typefail(env, "Coll(0)(0 == 0)", "Invalid argument type of array application")
- typefail(env, "Coll(0)(1,1,1)", "Invalid argument of array application")
+ typefail(env, "Coll(0)(0 == 0)", 1, 9)
+ typefail(env, "Coll(0)(1,1,1)", 1, 1)
}
property("array indexed access with default value") {
typecheck(env, "Coll(0).getOrElse(0, 1)") shouldBe SInt
- typefail(env, "Coll(0).getOrElse(true, 1)", "Invalid argument type of application")
- typefail(env, "Coll(true).getOrElse(0, 1)", "Invalid argument type of application")
- typefail(env, "Coll(0).getOrElse(0, Coll(1))", "Invalid argument type of application")
+ typefail(env, "Coll(0).getOrElse(true, 1)", 1, 1)
+ typefail(env, "Coll(true).getOrElse(0, 1)", 1, 1)
+ typefail(env, "Coll(0).getOrElse(0, Coll(1))", 1, 1)
}
property("array indexed access with default value with evaluation") {
@@ -239,13 +250,17 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, "{ (p: (Int, SigmaProp), box: Box) => p._1 > box.value && p._2.isProven }") shouldBe
SFunc(IndexedSeq(STuple(SInt, SSigmaProp), SBox), SBoolean)
- typefail(env, "{ (a) => a + 1 }", "undefined type of argument")
+ typefail(env, "{ (a) => a + 1 }", 1, 3)
}
- property("function definitions") {
+ property("function definitions via val") {
typecheck(env, "{ val f = { (x: Int) => x + 1 }; f }") shouldBe SFunc(IndexedSeq(SInt), SInt)
}
+ property("function definitions") {
+ typecheck(env, "{ def f(x: Int) = { x + 1 }; f }") shouldBe SFunc(IndexedSeq(SInt), SInt)
+ }
+
property("predefined primitives") {
typecheck(env, "{ (box: Box) => box.value }") shouldBe SFunc(IndexedSeq(SBox), SLong)
typecheck(env, "{ (box: Box) => box.propositionBytes }") shouldBe SFunc(IndexedSeq(SBox), SByteArray)
@@ -260,15 +275,14 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, "SELF.R1[Int].isDefined") shouldBe SBoolean
typecheck(env, "SELF.R1[Int].isEmpty") shouldBe SBoolean
typecheck(env, "SELF.R1[Int].get") shouldBe SInt
- typefail(env, "x[Int]", "doesn't have type parameters")
- typefail(env, "arr1[Int]", "doesn't have type parameters")
+ typefail(env, "x[Int]", 1, 1)
+ typefail(env, "arr1[Int]", 1, 1)
typecheck(env, "SELF.R1[(Int,Boolean)]") shouldBe SOption(STuple(SInt, SBoolean))
typecheck(env, "SELF.R1[(Int,Boolean)].get") shouldBe STuple(SInt, SBoolean)
- an[IllegalArgumentException] should be thrownBy typecheck(env, "SELF.R1[Int,Boolean].get")
+ typefail(env, "SELF.R1[Int,Boolean].get", 1, 6)
typecheck(env, "Coll[Int]()") shouldBe SCollection(SInt)
}
-
property("compute unifying type substitution: prim types") {
import SigmaTyper._
forAll { t: SPredefType =>
@@ -428,25 +442,23 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
}
property("invalid binary operations type check") {
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 == false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 != false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 > false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 >= false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 < false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 <= false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 + false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 - false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 / false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 % false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "min(1, false)")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "max(1, false)")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 * false")
- an[InvalidBinaryOperationParameters] should be thrownBy typecheck(env, "1 + \"a\"")
- an[NonApplicableMethod] should be thrownBy typecheck(env, "1 || 1")
- an[NonApplicableMethod] should be thrownBy typecheck(env, "col1 || col2")
- an[NonApplicableMethod] should be thrownBy typecheck(env, "g1 || g2")
- an[NonApplicableMethod] should be thrownBy typecheck(env, "true ++ false")
- an[NonApplicableMethod] should be thrownBy typecheck(env, "\"a\" ++ \"a\"")
+ typefail(env, "1 == false", 1, 1)
+ typefail(env, "1 != false", 1, 1)
+ typefail(env, "1 > false", 1, 1)
+ typefail(env, "1 < false", 1, 1)
+ typefail(env, "1 + false", 1, 5)
+ typefail(env, "1 - false", 1, 1)
+ typefail(env, "1 / false", 1, 1)
+ typefail(env, "1 % false", 1, 1)
+ typefail(env, "min(1, false)", 1, 5)
+ typefail(env, "max(1, false)", 1, 5)
+ typefail(env, "1 * false", 1, 5)
+ typefail(env, "1 + \"a\"", 1, 5)
+ typefail(env, "1 || 1", 1, 1)
+ typefail(env, "col1 || col2", 1, 1)
+ typefail(env, "g1 || g2", 1, 1)
+ typefail(env, "true ++ false", 1, 1)
+ typefail(env, "\"a\" ++ \"a\"", 1, 1)
}
property("upcast for binary operations with numeric types") {
@@ -473,7 +485,7 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
}
property("invalid cast method for numeric types") {
- an[MethodNotFound] should be thrownBy typecheck(env, "1.toSuperBigInteger")
+ typefail(env, "1.toSuperBigInteger", 1, 1)
}
property("string concat") {
@@ -484,8 +496,144 @@ class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with Lan
typecheck(env, "10.toBigInt.modQ") shouldBe SBigInt
typecheck(env, "10.toBigInt.plusModQ(2.toBigInt)") shouldBe SBigInt
typecheck(env, "10.toBigInt.minusModQ(2.toBigInt)") shouldBe SBigInt
- an[MethodNotFound] should be thrownBy typecheck(env, "10.modQ")
- an[TyperException] should be thrownBy typecheck(env, "10.toBigInt.plusModQ(1)")
- an[TyperException] should be thrownBy typecheck(env, "10.toBigInt.minusModQ(1)")
+ typefail(env, "10.modQ", 1, 1)
+ typefail(env, "10.toBigInt.plusModQ(1)", 1, 1)
+ typefail(env, "10.toBigInt.minusModQ(1)", 1, 1)
+ }
+
+ property("byteArrayToLong") {
+ typecheck(env, "byteArrayToLong(Coll[Byte](1.toByte))") shouldBe SLong
+ typefail(env, "byteArrayToLong(Coll[Int](1))", 1, 1)
+ }
+
+ property("decodePoint") {
+ typecheck(env, "decodePoint(Coll[Byte](1.toByte))") shouldBe SGroupElement
+ typefail(env, "decodePoint(Coll[Int](1))", 1, 1)
+ }
+
+ property("xorOf") {
+ typecheck(env, "xorOf(Coll[Boolean](true, false))") shouldBe SBoolean
+ typefail(env, "xorOf(Coll[Int](1))", 1, 1)
+ }
+
+ property("outerJoin") {
+ typecheck(env,
+ """outerJoin[Byte, Short, Int, Long](
+ | Coll[(Byte, Short)]((1.toByte, 2.toShort)),
+ | Coll[(Byte, Int)]((1.toByte, 3.toInt)),
+ | { (b: Byte, s: Short) => (b + s).toLong },
+ | { (b: Byte, i: Int) => (b + i).toLong },
+ | { (b: Byte, s: Short, i: Int) => (b + s + i).toLong }
+ | )""".stripMargin) shouldBe SCollection(STuple(SByte, SLong))
+ }
+
+ property("AtLeast (invalid parameters)") {
+ typefail(env, "atLeast(2, 2)", 1, 1)
+ }
+
+ property("substConstants") {
+ typecheck(env, "substConstants[Long](Coll[Byte](1.toByte), Coll[Int](1), Coll[Long](1L))") shouldBe SByteArray
+ }
+
+ property("executeFromVar") {
+ typecheck(env, "executeFromVar[Boolean](1)") shouldBe SBoolean
+ }
+
+ property("LogicalNot") {
+ typecheck(env, "!true") shouldBe SBoolean
+ typefail(env, "!getVar[SigmaProp](1).get", 1, 2)
+ }
+
+ property("Negation") {
+ typecheck(env, "-HEIGHT") shouldBe SInt
+ typefail(env, "-true", 1, 2)
+ }
+
+ property("BitInversion") {
+ typecheck(env, "~1") shouldBe SInt
+ typefail(env, "~true", 1, 2)
+ }
+
+ property("LogicalXor") {
+ typecheck(env, "true ^ false") shouldBe SBoolean
+ }
+
+ property("BitwiseOr") {
+ typecheck(env, "1 | 2") shouldBe SInt
+ typefail(env, "true | false", 1, 1)
+ }
+
+ property("BitwiseAnd") {
+ typecheck(env, "1 & 2") shouldBe SInt
+ typefail(env, "true & false", 1, 1)
+ }
+
+ property("BitwiseXor") {
+ typecheck(env, "1 ^ 2") shouldBe SInt
+ }
+
+ property("BitShiftRight") {
+ typecheck(env, "1 >> 2") shouldBe SInt
+ typefail(env, "true >> false", 1, 1)
+ }
+
+ property("BitShiftLeft") {
+ typecheck(env, "1 << 2") shouldBe SInt
+ typefail(env, "true << false", 1, 1)
+ }
+
+ property("BitShiftRightZeroed") {
+ typecheck(env, "1 >>> 2") shouldBe SInt
+ typefail(env, "true >>> false", 1, 1)
+ }
+
+ property("Collection.BitShiftLeft") {
+ typecheck(env, "Coll(1,2) << 2") shouldBe SCollection(SInt)
+ an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) << true")
+ an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) << 2L")
+ an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) << (2L, 3)")
+ }
+
+ property("Collection.BitShiftRight") {
+ typecheck(env, "Coll(1,2) >> 2") shouldBe SCollection(SInt)
+ an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) >> 2L")
+ an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) >> true")
+ an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) >> (2L, 3)")
+ }
+
+ property("Collection.BitShiftRightZeroed") {
+ typecheck(env, "Coll(true, false) >>> 2") shouldBe SCollection(SBoolean)
+ an [TyperException] should be thrownBy typecheck(env, "Coll(1,2) >>> 2")
+ an [TyperException] should be thrownBy typecheck(env, "Coll(true, false) >>> true")
+ an [TyperException] should be thrownBy typecheck(env, "Coll(true, false) >>> (2L, 3)")
+ }
+
+ property("SCollection.indices") {
+ typecheck(env, "Coll(1).indices") shouldBe SCollection(SInt)
+ typecheck(env, "INPUTS.indices") shouldBe SCollection(SInt)
+ }
+
+ property("SCollection.flatMap") {
+ typecheck(env, "OUTPUTS.flatMap({ (out: Box) => Coll(out.value >= 1L) })") shouldBe SCollection(SBoolean)
+ }
+
+ property("SBox.tokens") {
+ typecheck(env, "SELF.tokens") shouldBe ErgoBox.STokensRegType
+ }
+
+ property("SOption.toColl") {
+ typecheck(env, "getVar[Int](1).toColl") shouldBe SIntArray
+ }
+
+ property("SContext.dataInputs") {
+ typecheck(env, "CONTEXT.dataInputs") shouldBe SCollection(SBox)
+ }
+
+ property("SAvlTree.digest") {
+ typecheck(env, "getVar[AvlTree](1).get.digest") shouldBe SByteArray
+ }
+
+ property("SGroupElement.exp") {
+ typecheck(env, "g1.exp(1.toBigInt)") shouldBe SGroupElement
}
}
diff --git a/src/test/scala/sigmastate/serialization/AndSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/AndSerializerSpecification.scala
index 7a38c91c8e..0895ce4036 100644
--- a/src/test/scala/sigmastate/serialization/AndSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/AndSerializerSpecification.scala
@@ -3,7 +3,7 @@ package sigmastate.serialization
import sigmastate.Values.{BooleanConstant, Constant, IntConstant}
import sigmastate._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.ByteArrayWriter.encodeZigZagInt
+import scorex.util.encode.ZigZagEncoder.encodeZigZagInt
class AndSerializerSpecification extends TableSerializationSpecification {
diff --git a/src/test/scala/sigmastate/serialization/AvlTreeSpecification.scala b/src/test/scala/sigmastate/serialization/AvlTreeSpecification.scala
new file mode 100644
index 0000000000..e8a1e796b7
--- /dev/null
+++ b/src/test/scala/sigmastate/serialization/AvlTreeSpecification.scala
@@ -0,0 +1,31 @@
+package sigmastate.serialization
+
+import sigmastate.Values.AvlTreeConstant
+import sigmastate.AvlTreeFlags
+
+class AvlTreeSpecification extends SerializationSpecification {
+
+ private val flags = Array(
+ AvlTreeFlags(false, false, false),
+ AvlTreeFlags(false, false, true),
+ AvlTreeFlags(false, true, false),
+ AvlTreeFlags(false, true, true),
+ AvlTreeFlags(true, false, false),
+ AvlTreeFlags(true, false, true),
+ AvlTreeFlags(true, true, false),
+ AvlTreeFlags(true, true, true)
+ )
+
+ property("roundtrip for all the possible AVL tree flags") {
+ flags.foreach { f =>
+ AvlTreeFlags(AvlTreeFlags.serializeFlags(f)) shouldBe f
+ }
+ }
+
+ property("roundtrip for an AVL tree") {
+ forAll(avlTreeDataGen) { t =>
+ val v = AvlTreeConstant(t)
+ roundTripTest(v)
+ }
+ }
+}
diff --git a/src/test/scala/sigmastate/serialization/BlockSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/BlockSerializerSpecification.scala
index 061be04bee..94890a1bb9 100644
--- a/src/test/scala/sigmastate/serialization/BlockSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/BlockSerializerSpecification.scala
@@ -25,10 +25,10 @@ class BlockSerializerSpecification extends SerializationSpecification {
val store = new ConstantStore(IndexedSeq())
val placeholder = store.put(v.asInstanceOf[Constant[SType]])
val s = ConstantPlaceholderSerializer(DeserializationSigmaBuilder.mkConstantPlaceholder)
- val w = Serializer.startWriter()
- s.serializeBody(placeholder, w)
- val r = Serializer.startReader(w.toBytes, store, resolvePlaceholdersToConstants = false)
- s.parseBody(r) shouldEqual placeholder
+ val w = SigmaSerializer.startWriter()
+ s.serialize(placeholder, w)
+ val r = SigmaSerializer.startReader(w.toBytes, store, resolvePlaceholdersToConstants = false)
+ s.parse(r) shouldEqual placeholder
}
}
diff --git a/src/test/scala/sigmastate/serialization/ConcreteCollectionSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/ConcreteCollectionSerializerSpecification.scala
index eea31bb38c..2af3ac39a4 100644
--- a/src/test/scala/sigmastate/serialization/ConcreteCollectionSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/ConcreteCollectionSerializerSpecification.scala
@@ -52,7 +52,7 @@ class ConcreteCollectionSerializerSpecification extends TableSerializationSpecif
property("ConcreteCollection: deserialize collection of a crazy size") {
val bytes = Array[Byte](OpCodes.ConcreteCollectionCode) ++
- Serializer.startWriter().putUInt(Int.MaxValue).toBytes
+ SigmaSerializer.startWriter().putUInt(Int.MaxValue).toBytes
an[AssertionError] should be thrownBy ValueSerializer.deserialize(bytes)
}
}
diff --git a/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala
index ff8aa9c6cb..538df8b213 100644
--- a/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala
@@ -74,6 +74,7 @@ class ConstantSerializerSpecification extends TableSerializationSpecification {
("object", "bytes"),
(FalseLeaf, Array[Byte](1, 0)),
(TrueLeaf, Array[Byte](1, 1)),
+ caseObjectValue(Context),
caseObjectValue(Height),
caseObjectValue(Inputs),
caseObjectValue(Outputs),
diff --git a/src/test/scala/sigmastate/serialization/DataSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/DataSerializerSpecification.scala
index 59b01f8200..c031fc12be 100644
--- a/src/test/scala/sigmastate/serialization/DataSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/DataSerializerSpecification.scala
@@ -12,14 +12,14 @@ import sigmastate.interpreter.CryptoConstants.EcPointType
class DataSerializerSpecification extends SerializationSpecification {
def roundtrip[T <: SType](obj: T#WrappedType, tpe: T) = {
- val w = Serializer.startWriter()
+ val w = SigmaSerializer.startWriter()
DataSerializer.serialize(obj, tpe, w)
val bytes = w.toBytes
- val r = Serializer.startReader(bytes, 0)
+ val r = SigmaSerializer.startReader(bytes, 0)
val res = DataSerializer.deserialize(tpe, r)
res shouldBe obj
val randomPrefix = arrayGen[Byte].sample.get
- val r2 = Serializer.startReader(randomPrefix ++ bytes, randomPrefix.length)
+ val r2 = SigmaSerializer.startReader(randomPrefix ++ bytes, randomPrefix.length)
val res2 = DataSerializer.deserialize(tpe, r2)
res2 shouldBe obj
}
diff --git a/src/test/scala/sigmastate/serialization/DeserializationResilience.scala b/src/test/scala/sigmastate/serialization/DeserializationResilience.scala
index a8824fcf4d..b47bb2092c 100644
--- a/src/test/scala/sigmastate/serialization/DeserializationResilience.scala
+++ b/src/test/scala/sigmastate/serialization/DeserializationResilience.scala
@@ -2,7 +2,7 @@ package sigmastate.serialization
import sigmastate.lang.exceptions.{InputSizeLimitExceeded, InvalidOpCode, InvalidTypePrefix, ValueDeserializeCallDepthExceeded}
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
import sigmastate.{AND, SBoolean}
class DeserializationResilience extends SerializationSpecification {
@@ -12,9 +12,9 @@ class DeserializationResilience extends SerializationSpecification {
}
property("max size limit") {
- val bytes = Array.fill[Byte](Serializer.MaxInputSize + 1)(1)
+ val bytes = Array.fill[Byte](SigmaSerializer.MaxInputSize + 1)(1)
an[InputSizeLimitExceeded] should be thrownBy ValueSerializer.deserialize(bytes)
- an[InputSizeLimitExceeded] should be thrownBy ValueSerializer.deserialize(Serializer.startReader(bytes, 0))
+ an[InputSizeLimitExceeded] should be thrownBy ValueSerializer.deserialize(SigmaSerializer.startReader(bytes, 0))
}
property("zeroes (invalid type code in constant deserialization path") {
@@ -23,28 +23,28 @@ class DeserializationResilience extends SerializationSpecification {
}
property("AND/OR nested crazy deep") {
- val evilBytes = List.tabulate(Serializer.MaxTreeDepth + 1)(_ => Array[Byte](AndCode, ConcreteCollectionCode, 2, SBoolean.typeCode))
+ val evilBytes = List.tabulate(SigmaSerializer.MaxTreeDepth + 1)(_ => Array[Byte](AndCode, ConcreteCollectionCode, 2, SBoolean.typeCode))
.toArray.flatten
an[ValueDeserializeCallDepthExceeded] should be thrownBy
- Serializer.startReader(evilBytes, 0).getValue()
+ SigmaSerializer.startReader(evilBytes, 0).getValue()
// test other API endpoints
an[ValueDeserializeCallDepthExceeded] should be thrownBy
ValueSerializer.deserialize(evilBytes, 0)
an[ValueDeserializeCallDepthExceeded] should be thrownBy
- ValueSerializer.deserialize(Serializer.startReader(evilBytes, 0))
+ ValueSerializer.deserialize(SigmaSerializer.startReader(evilBytes, 0))
// guard should not be tripped up by a huge collection
- val goodBytes = Serializer.startWriter()
- .putValue(AND(List.tabulate(Serializer.MaxTreeDepth + 1)(_ => booleanExprGen.sample.get)))
+ val goodBytes = SigmaSerializer.startWriter()
+ .putValue(AND(List.tabulate(SigmaSerializer.MaxTreeDepth + 1)(_ => booleanExprGen.sample.get)))
.toBytes
ValueSerializer.deserialize(goodBytes, 0)
// test other API endpoints
- ValueSerializer.deserialize(Serializer.startReader(goodBytes, 0))
- Serializer.startReader(goodBytes, 0).getValue()
+ ValueSerializer.deserialize(SigmaSerializer.startReader(goodBytes, 0))
+ SigmaSerializer.startReader(goodBytes, 0).getValue()
}
property("invalid op code") {
an[InvalidOpCode] should be thrownBy
- ValueSerializer.deserialize(Array.fill[Byte](1)(255.toByte))
+ ValueSerializer.deserialize(Array.fill[Byte](1)(117.toByte))
}
}
diff --git a/src/test/scala/sigmastate/serialization/ErgoTreeSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/ErgoTreeSerializerSpecification.scala
index ad26cc82c8..abd11b3c58 100644
--- a/src/test/scala/sigmastate/serialization/ErgoTreeSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/ErgoTreeSerializerSpecification.scala
@@ -13,7 +13,9 @@ import sigmastate.utxo.ExtractAmount
class ErgoTreeSerializerSpecification extends SerializationSpecification with SigmaTestingCommons {
- implicit lazy val IR: TestingIRContext = new TestingIRContext
+ implicit lazy val IR: TestingIRContext = new TestingIRContext {
+ beginPass(noConstPropagationPass)
+ }
private def passThroughTreeBuilder(tree: Value[SType]): Value[SType] = {
val env = Map[String, Any]()
@@ -39,9 +41,9 @@ class ErgoTreeSerializerSpecification extends SerializationSpecification with Si
val ergoTree = extractConstants(tree)
val bytes = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(ergoTree)
val (_, deserializedConstants, treeBytes) = ErgoTreeSerializer.DefaultSerializer
- .deserializeHeaderWithTreeBytes(Serializer.startReader(bytes))
+ .deserializeHeaderWithTreeBytes(SigmaSerializer.startReader(bytes))
deserializedConstants shouldEqual ergoTree.constants
- val r = Serializer.startReader(treeBytes, new ConstantStore(deserializedConstants),
+ val r = SigmaSerializer.startReader(treeBytes, new ConstantStore(deserializedConstants),
resolvePlaceholdersToConstants = true)
val deserializedTree = ValueSerializer.deserialize(r)
deserializedTree shouldEqual tree
@@ -59,7 +61,7 @@ class ErgoTreeSerializerSpecification extends SerializationSpecification with Si
val tree = Plus(10, 20)
val bytes = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(tree)
val (_, deserializedConstants, _) = ErgoTreeSerializer.DefaultSerializer.
- deserializeHeaderWithTreeBytes(Serializer.startReader(bytes))
+ deserializeHeaderWithTreeBytes(SigmaSerializer.startReader(bytes))
deserializedConstants.length shouldBe 2
val deserializedTree = ErgoTreeSerializer.DefaultSerializer.deserialize(bytes)
deserializedTree shouldEqual tree
@@ -71,14 +73,14 @@ class ErgoTreeSerializerSpecification extends SerializationSpecification with Si
val bytes1 = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(tree1)
val bytes2 = ErgoTreeSerializer.DefaultSerializer.serializeWithSegregation(tree2)
val (_, _, treeBytes1) = ErgoTreeSerializer.DefaultSerializer
- .deserializeHeaderWithTreeBytes(Serializer.startReader(bytes1))
+ .deserializeHeaderWithTreeBytes(SigmaSerializer.startReader(bytes1))
val (_, _, treeBytes2) = ErgoTreeSerializer.DefaultSerializer
- .deserializeHeaderWithTreeBytes(Serializer.startReader(bytes2))
+ .deserializeHeaderWithTreeBytes(SigmaSerializer.startReader(bytes2))
treeBytes1 shouldEqual treeBytes2
}
property("(de)serialize round trip (without constants)") {
- val prop = EQ(ExtractAmount(Self), LongConstant(0))
+ val prop = EQ(ExtractAmount(Self), LongConstant(0)).toSigmaProp
val tree = ErgoTree(DefaultHeader, IndexedSeq(), prop, prop)
val bytes = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(tree)
val deserializedProp = ErgoTreeSerializer.DefaultSerializer.deserializeErgoTree(bytes).proposition
@@ -101,7 +103,7 @@ class ErgoTreeSerializerSpecification extends SerializationSpecification with Si
val ergoTree = extractConstants(processedTree)
val bytes = ErgoTreeSerializer.DefaultSerializer.serializeErgoTree(ergoTree)
val (_, deserializedConstants, treeBytes) = ErgoTreeSerializer.DefaultSerializer
- .deserializeHeaderWithTreeBytes(Serializer.startReader(bytes))
+ .deserializeHeaderWithTreeBytes(SigmaSerializer.startReader(bytes))
val c = new ConstantStore(deserializedConstants)
val deserializedTree = ErgoTreeSerializer.DefaultSerializer.deserializeWithConstantInjection(c, treeBytes)
deserializedTree shouldEqual processedTree
diff --git a/src/test/scala/sigmastate/serialization/GroupElementSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/GroupElementSerializerSpecification.scala
new file mode 100644
index 0000000000..d4860358d4
--- /dev/null
+++ b/src/test/scala/sigmastate/serialization/GroupElementSerializerSpecification.scala
@@ -0,0 +1,27 @@
+package sigmastate.serialization
+
+import sigmastate.interpreter.CryptoConstants
+
+
+class GroupElementSerializerSpecification extends SerializationSpecification {
+
+ property("Identity point serialization") {
+ val group = CryptoConstants.dlogGroup
+ val identity = group.identity
+
+ val bytes = GroupElementSerializer.toBytes(identity)
+ bytes.length shouldBe CryptoConstants.EncodedGroupElementLength
+ bytes.forall(_ == 0) shouldBe true
+ GroupElementSerializer.parse(SigmaSerializer.startReader(bytes, 0)).isInfinity shouldBe true
+ }
+
+ property("point roundtrip") {
+ forAll(groupElementConstGen){ge =>
+ val bytes = GroupElementSerializer.toBytes(ge.value)
+ bytes.length shouldBe CryptoConstants.EncodedGroupElementLength
+ val restored = GroupElementSerializer.parse(SigmaSerializer.startReader(bytes, 0))
+ restored.normalize().getAffineXCoord shouldBe ge.value.normalize().getAffineXCoord
+ restored.normalize().getAffineYCoord shouldBe ge.value.normalize().getAffineYCoord
+ }
+ }
+}
diff --git a/src/test/scala/sigmastate/serialization/MethodCallSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/MethodCallSerializerSpecification.scala
index 3f9802a873..0124cbfb74 100644
--- a/src/test/scala/sigmastate/serialization/MethodCallSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/MethodCallSerializerSpecification.scala
@@ -1,14 +1,28 @@
package sigmastate.serialization
-import sigmastate.SNumericType
-import sigmastate.Values.IntConstant
+import org.ergoplatform.Outputs
+import sigmastate.Values.{FuncValue, ValUse}
import sigmastate.lang.Terms.MethodCall
+import sigmastate.utxo.ExtractScriptBytes
+import sigmastate._
class MethodCallSerializerSpecification extends SerializationSpecification {
property("MethodCall deserialization round trip") {
- val expr = MethodCall(IntConstant(10), SNumericType.getMethodByName("toByte"), IndexedSeq.empty)
+ val expr = MethodCall(Outputs,
+ SCollection.FlatMapMethod.withConcreteTypes(Map(SCollection.tIV -> SBox, SCollection.tOV -> SByte)),
+ Vector(FuncValue(1, SBox, ExtractScriptBytes(ValUse(1, SBox)))),
+ Map()
+ )
roundTripTest(expr)
}
+ property("MethodCall deserialization round trip (non-generic method)") {
+ val expr = MethodCall(Outputs,
+ SMethod(SCollection, "size", SFunc(SCollection[SBox.type], SInt), 1),
+ Vector(),
+ Map()
+ )
+ roundTripTest(expr)
+ }
}
diff --git a/src/test/scala/sigmastate/serialization/OperationSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/OperationSerializerSpecification.scala
index 617cf12bf2..4eee6528a1 100644
--- a/src/test/scala/sigmastate/serialization/OperationSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/OperationSerializerSpecification.scala
@@ -12,7 +12,7 @@ class OperationSerializerSpecification extends SerializationSpecification {
forAll(Gen.nonEmptyListOf(operationGen)) { ops =>
val serializer = new OperationSerializer(keyLength, None)
val bytes = serializer.serializeSeq(ops)
- val parsed = serializer.parseSeq(Serializer.startReader(bytes, 0))
+ val parsed = serializer.parseSeq(SigmaSerializer.startReader(bytes, 0))
val bytes2 = serializer.serializeSeq(parsed)
bytes2 shouldEqual bytes
}
@@ -21,7 +21,7 @@ class OperationSerializerSpecification extends SerializationSpecification {
property("operation serialization") {
def roundTrip(op: Operation, serializer: OperationSerializer) = {
val randValueBytes = serializer.toBytes(op)
- val randValueRecovered = serializer.parseBody(Serializer.startReader(randValueBytes, 0))
+ val randValueRecovered = serializer.parse(SigmaSerializer.startReader(randValueBytes, 0))
serializer.toBytes(randValueRecovered) shouldEqual randValueBytes
}
diff --git a/src/test/scala/sigmastate/serialization/OrSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/OrSerializerSpecification.scala
index 94f51aa2ee..b65a0b79e3 100644
--- a/src/test/scala/sigmastate/serialization/OrSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/OrSerializerSpecification.scala
@@ -3,7 +3,7 @@ package sigmastate.serialization
import sigmastate.Values.{BooleanConstant, Constant, IntConstant}
import sigmastate._
import sigmastate.serialization.OpCodes._
-import sigmastate.utils.ByteArrayWriter.encodeZigZagInt
+import scorex.util.encode.ZigZagEncoder.encodeZigZagInt
class OrSerializerSpecification extends TableSerializationSpecification {
diff --git a/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala
index 03b9743bb5..cd00750883 100644
--- a/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/PDHTSerializerSpecification.scala
@@ -7,7 +7,7 @@ class PDHTSerializerSpecification extends SerializationSpecification {
property("ProveDiffieHellmanTupleSerializer: Serializer round trip") {
forAll { i: ProveDHTuple =>
- roundTripTest(i)
+ 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
diff --git a/src/test/scala/sigmastate/serialization/ProveDlogSerializerSpec.scala b/src/test/scala/sigmastate/serialization/ProveDlogSerializerSpec.scala
index ce940c9a33..1705fc325e 100644
--- a/src/test/scala/sigmastate/serialization/ProveDlogSerializerSpec.scala
+++ b/src/test/scala/sigmastate/serialization/ProveDlogSerializerSpec.scala
@@ -6,7 +6,7 @@ class ProveDlogSerializerSpec extends SerializationSpecification {
property("ProveDlog: Serializer round trip") {
forAll { pd: ProveDlog =>
- roundTripTest(pd)
+ roundTripTest(pd.toSigmaProp)
}
}
diff --git a/src/test/scala/sigmastate/serialization/RelationsSpecification.scala b/src/test/scala/sigmastate/serialization/RelationsSpecification.scala
index e827a7f5a6..fc9d18330f 100644
--- a/src/test/scala/sigmastate/serialization/RelationsSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/RelationsSpecification.scala
@@ -4,7 +4,7 @@ import sigmastate.Values._
import sigmastate._
import sigmastate.serialization.OpCodes._
import sigmastate.serialization.ValueSerializer._
-import sigmastate.utils.ByteArrayWriter.encodeZigZagLong
+import scorex.util.encode.ZigZagEncoder.encodeZigZagLong
class RelationsSpecification extends TableSerializationSpecification {
diff --git a/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala
index d1ad28df42..780a4d8070 100644
--- a/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala
@@ -4,13 +4,12 @@ import java.util
import org.ergoplatform.ErgoLikeContext
import org.scalacheck.{Arbitrary, Gen}
-import org.scalatest.prop.{GeneratorDrivenPropertyChecks, PropertyChecks}
-import org.scalatest.{Assertion, Matchers, PropSpec}
-import sigmastate.Values.{TrueLeaf, Value}
+import org.scalatest.Assertion
+import sigmastate.Values.{Value, SigmaPropConstant, SigmaBoolean, SigmaPropValue}
import sigmastate._
import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.basics.ProveDHTuple
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, SigmaTestingCommons}
import sigmastate.serialization.generators.ValueGenerators
import sigmastate.utxo.Transformer
@@ -18,9 +17,9 @@ import scala.util.Random
class SigSerializerSpecification extends SigmaTestingCommons with ValueGenerators {
implicit lazy val IR = new TestingIRContext
- private lazy implicit val arbExprGen: Arbitrary[Value[SBoolean.type]] = Arbitrary(exprTreeGen)
+ private lazy implicit val arbExprGen: Arbitrary[SigmaBoolean] = Arbitrary(exprTreeGen)
- private lazy val prover = new ErgoLikeTestProvingInterpreter()
+ private lazy val prover = new ContextEnrichingTestProvingInterpreter()
private lazy val interpreterProveDlogGen: Gen[ProveDlog] =
Gen.oneOf(prover.dlogSecrets.map(secret => ProveDlog(secret.publicImage.h)))
@@ -31,20 +30,19 @@ class SigSerializerSpecification extends SigmaTestingCommons with ValueGenerator
.map(_.commonInput)
.map(ci => ProveDHTuple(ci.g, ci.h, ci.u, ci.v)))
- private def exprTreeNodeGen: Gen[Transformer[SCollection[SBoolean.type], SBoolean.type]] = for {
+ private def exprTreeNodeGen: Gen[SigmaBoolean] = for {
left <- exprTreeGen
right <- exprTreeGen
node <- Gen.oneOf(
- OR(left, right),
- AND(left, right)
+ COR(Seq(left, right)),
+ CAND(Seq(left, right))
)
} yield node
- private def exprTreeGen: Gen[Value[SBoolean.type]] =
+ private def exprTreeGen: Gen[SigmaBoolean] =
Gen.oneOf(interpreterProveDlogGen, interpreterProveDHTGen, Gen.delay(exprTreeNodeGen))
- private def isEquivalent(expected: ProofTree,
- actual: ProofTree): Boolean = (expected, actual) match {
+ private def isEquivalent(expected: ProofTree, actual: ProofTree): Boolean = (expected, actual) match {
case (NoProof, NoProof) => true
case (dht1: UncheckedDiffieHellmanTuple, dht2: UncheckedDiffieHellmanTuple) =>
// `firstMessageOpt` is not serialized
@@ -59,18 +57,19 @@ class SigSerializerSpecification extends SigmaTestingCommons with ValueGenerator
}
- private def roundTrip(uncheckedTree: UncheckedTree, exp: Value[SBoolean.type]): Assertion = {
+ private def roundTrip(uncheckedTree: UncheckedTree, exp: SigmaBoolean): Assertion = {
val bytes = SigSerializer.toBytes(uncheckedTree)
val parsedUncheckedTree = SigSerializer.parseAndComputeChallenges(exp, bytes)
isEquivalent(uncheckedTree, parsedUncheckedTree) shouldBe true
}
property("SigSerializer no proof round trip") {
- roundTrip(NoProof, TrueLeaf)
+ roundTrip(NoProof, TrivialProp.TrueProp)
}
property("SigSerializer round trip") {
- forAll { expr: Value[SBoolean.type] =>
+ forAll { sb: SigmaBoolean =>
+ val expr = sb.toSigmaProp
val challenge = Array.fill(32)(Random.nextInt(100).toByte)
val ctx = ErgoLikeContext(
diff --git a/src/test/scala/sigmastate/serialization/TransformersSerializationSpec.scala b/src/test/scala/sigmastate/serialization/TransformersSerializationSpec.scala
index 725257062c..f8952055b3 100644
--- a/src/test/scala/sigmastate/serialization/TransformersSerializationSpec.scala
+++ b/src/test/scala/sigmastate/serialization/TransformersSerializationSpec.scala
@@ -176,4 +176,14 @@ class TransformersSerializationSpec extends SerializationSpecification {
property("BoolToSigmaProp: Serializer round trip") {
forAll(boolToSigmaPropGen) { v => roundTripTest(v) }
}
+
+ property("ByteArrayToLong: Serializer round trip") {
+ forAll(byteArrayToLongGen) { roundTripTest(_) }
+ }
+
+ property("XorOf: Serializer round trip") {
+ forAll(logicalExprTreeNodeGen(Seq(XorOf.apply))) { tree =>
+ roundTripTest(tree)
+ }
+ }
}
diff --git a/src/test/scala/sigmastate/serialization/TwoArgumentSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/TwoArgumentSerializerSpecification.scala
index 1f8b263846..bd2c6fd3de 100644
--- a/src/test/scala/sigmastate/serialization/TwoArgumentSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/TwoArgumentSerializerSpecification.scala
@@ -6,7 +6,7 @@ import sigmastate.Values._
import sigmastate.serialization.OpCodes.OpCode
import sigmastate.utxo.Append
import OpCodes._
-import sigmastate.utils.ByteArrayWriter.encodeZigZagLong
+import scorex.util.encode.ZigZagEncoder.encodeZigZagLong
class TwoArgumentSerializerSpecification extends TableSerializationSpecification {
diff --git a/src/test/scala/sigmastate/serialization/TypeSerializerSpecification.scala b/src/test/scala/sigmastate/serialization/TypeSerializerSpecification.scala
index abd319195a..92a19ddd37 100644
--- a/src/test/scala/sigmastate/serialization/TypeSerializerSpecification.scala
+++ b/src/test/scala/sigmastate/serialization/TypeSerializerSpecification.scala
@@ -4,12 +4,12 @@ import org.scalacheck.Arbitrary._
import org.scalatest.Assertion
import sigmastate._
import sigmastate.lang.exceptions.TypeDeserializeCallDepthExceeded
-import sigmastate.utils.Extensions._
+import scorex.util.Extensions._
class TypeSerializerSpecification extends SerializationSpecification {
private def roundtrip[T <: SType](tpe: T, expected: Array[Byte]): Assertion = {
- val w = Serializer.startWriter()
+ val w = SigmaSerializer.startWriter()
.putType(tpe)
val bytes = w.toBytes
bytes shouldBe expected
@@ -17,14 +17,14 @@ class TypeSerializerSpecification extends SerializationSpecification {
}
private def roundtrip[T <: SType](tpe: T): Assertion = {
- val w = Serializer.startWriter()
+ val w = SigmaSerializer.startWriter()
.putType(tpe)
val bytes = w.toBytes
- val r = Serializer.startReader(bytes, 0)
+ val r = SigmaSerializer.startReader(bytes, 0)
val res = r.getType()
res shouldBe tpe
val randomPrefix = arrayGen[Byte].sample.get
- val r2 = Serializer.startReader(randomPrefix ++ bytes, randomPrefix.length)
+ val r2 = SigmaSerializer.startReader(randomPrefix ++ bytes, randomPrefix.length)
val res2 = r2.getType()
res2 shouldBe tpe
}
@@ -95,9 +95,9 @@ class TypeSerializerSpecification extends SerializationSpecification {
}
property("tuple of tuples crazy deep") {
- val bytes = List.tabulate(Serializer.MaxTreeDepth + 1)(_ => Array[Byte](TupleTypeCode, 2))
+ val bytes = List.tabulate(SigmaSerializer.MaxTreeDepth + 1)(_ => Array[Byte](TupleTypeCode, 2))
.toArray.flatten
- an[TypeDeserializeCallDepthExceeded] should be thrownBy Serializer.startReader(bytes, 0).getType()
+ an[TypeDeserializeCallDepthExceeded] should be thrownBy SigmaSerializer.startReader(bytes, 0).getType()
}
property("STypeIdent serialization roundtrip") {
diff --git a/src/test/scala/sigmastate/serialization/generators/TransformerGenerators.scala b/src/test/scala/sigmastate/serialization/generators/TransformerGenerators.scala
index a1fa0b11d9..2432531b44 100644
--- a/src/test/scala/sigmastate/serialization/generators/TransformerGenerators.scala
+++ b/src/test/scala/sigmastate/serialization/generators/TransformerGenerators.scala
@@ -276,6 +276,9 @@ trait TransformerGenerators {
val boolToSigmaPropGen: Gen[BoolToSigmaProp] = for {
b <- booleanConstGen
- } yield mkBoolToSigmaProp(b)
+ } yield mkBoolToSigmaProp(b).asInstanceOf[BoolToSigmaProp]
+ val byteArrayToLongGen: Gen[ByteArrayToLong] =
+ arbByteArrayConstant.arbitrary.map { v =>
+ mkByteArrayToLong(v).asInstanceOf[ByteArrayToLong] }
}
diff --git a/src/test/scala/sigmastate/serialization/generators/ValueGenerators.scala b/src/test/scala/sigmastate/serialization/generators/ValueGenerators.scala
index 5bdb40da83..7f5e17afce 100644
--- a/src/test/scala/sigmastate/serialization/generators/ValueGenerators.scala
+++ b/src/test/scala/sigmastate/serialization/generators/ValueGenerators.scala
@@ -3,6 +3,7 @@ package sigmastate.serialization.generators
import org.ergoplatform
import org.ergoplatform._
import org.ergoplatform.ErgoBox._
+import org.ergoplatform.ErgoScriptPredef.{TrueProp, FalseProp}
import org.scalacheck.Arbitrary._
import org.scalacheck.{Arbitrary, Gen}
import scorex.crypto.authds.{ADDigest, ADKey}
@@ -12,7 +13,8 @@ import sigmastate._
import sigmastate.Values._
import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.basics.ProveDHTuple
-import sigmastate.interpreter.{ContextExtension, CryptoConstants, ProverResult}
+import sigmastate.interpreter.CryptoConstants.EcPointType
+import sigmastate.interpreter.{ProverResult, ContextExtension, CryptoConstants}
import scala.collection.JavaConverters._
import scala.collection.mutable.ListBuffer
@@ -75,10 +77,14 @@ trait ValueGenerators extends TypeGenerators {
length <- Gen.chooseNum(1, 100)
ints <- Gen.listOfN(length, arbInt.arbitrary)
} yield mkCollectionConstant[SInt.type](ints.toArray, SInt)
- val groupElementConstGen: Gen[GroupElementConstant] = for {
+
+ val groupElementGen: Gen[EcPointType] = for {
_ <- Gen.const(1)
- el = CryptoConstants.dlogGroup.createRandomGenerator()
- } yield mkConstant[SGroupElement.type](el, SGroupElement)
+ } yield CryptoConstants.dlogGroup.createRandomElement()
+
+ val groupElementConstGen: Gen[GroupElementConstant] = for {
+ p <- groupElementGen
+ } yield mkConstant[SGroupElement.type](p, SGroupElement)
def taggedVar[T <: SType](implicit aT: Arbitrary[T]): Gen[TaggedVariable[T]] = for {
t <- aT.arbitrary
@@ -86,14 +92,13 @@ trait ValueGenerators extends TypeGenerators {
} yield mkTaggedVariable(id, t)
- val proveDlogGen: Gen[ProveDlog] =
- arbGroupElementConstant.arbitrary.map(v => mkProveDlog(v).asInstanceOf[ProveDlog])
+ val proveDlogGen: Gen[ProveDlog] = for { v <- groupElementGen } yield ProveDlog(v)
val proveDHTGen: Gen[ProveDHTuple] = for {
- gv: Value[SGroupElement.type] <- groupElementConstGen
- hv: Value[SGroupElement.type] <- groupElementConstGen
- uv: Value[SGroupElement.type] <- groupElementConstGen
- vv: Value[SGroupElement.type] <- groupElementConstGen
- } yield mkProveDiffieHellmanTuple(gv, hv, uv, vv).asInstanceOf[ProveDHTuple]
+ gv <- groupElementGen
+ hv <- groupElementGen
+ uv <- groupElementGen
+ vv <- groupElementGen
+ } yield ProveDHTuple(gv, hv, uv, vv)
val sigmaBooleanGen: Gen[SigmaBoolean] = Gen.oneOf(proveDlogGen, proveDHTGen)
val sigmaPropGen: Gen[SigmaPropValue] =
@@ -148,7 +153,12 @@ trait ValueGenerators extends TypeGenerators {
val unsignedInputGen: Gen[UnsignedInput] = for {
boxId <- boxIdGen
- } yield new UnsignedInput(boxId)
+ contextExt <- contextExtensionGen
+ } yield new UnsignedInput(boxId, contextExt)
+
+ val dataInputGen: Gen[DataInput] = for {
+ boxId <- boxIdGen
+ } yield DataInput(boxId)
val inputGen: Gen[Input] = for {
boxId <- boxIdGen
@@ -167,13 +177,18 @@ trait ValueGenerators extends TypeGenerators {
yield varId.toByte -> v.asInstanceOf[EvaluatedValue[SType]]
}
+ def avlTreeFlagsGen: Gen[AvlTreeFlags] = for {
+ insert <- arbBool.arbitrary
+ update <- arbBool.arbitrary
+ remove <- arbBool.arbitrary
+ } yield AvlTreeFlags(insert, update, remove)
+
def avlTreeDataGen: Gen[AvlTreeData] = for {
- digest <- Gen.listOfN(32, arbByte.arbitrary).map(_.toArray)
+ digest <- Gen.listOfN(AvlTreeData.DigestSize, arbByte.arbitrary).map(_.toArray)
+ flags <- avlTreeFlagsGen
keyLength <- unsignedIntGen
vl <- arbOption[Int](Arbitrary(unsignedIntGen)).arbitrary
- mn <- arbOption[Int](Arbitrary(unsignedIntGen)).arbitrary
- md <- arbOption[Int](Arbitrary(unsignedIntGen)).arbitrary
- } yield AvlTreeData(ADDigest @@ digest, keyLength, vl, mn, md)
+ } yield AvlTreeData(ADDigest @@ digest, flags, keyLength, vl)
def avlTreeConstantGen: Gen[AvlTreeConstant] = avlTreeDataGen.map { v => AvlTreeConstant(v) }
@@ -218,7 +233,7 @@ trait ValueGenerators extends TypeGenerators {
val ergoBoxGen: Gen[ErgoBox] = for {
l <- arbLong.arbitrary
p <- proveDlogGen
- b <- Gen.oneOf(TrueLeaf, FalseLeaf, p)
+ b <- Gen.oneOf(TrueProp, FalseProp, ErgoTree.fromSigmaBoolean(p))
tId <- Gen.listOfN(32, arbByte.arbitrary)
boxId <- unsignedShortGen
tokensCount <- Gen.chooseNum[Byte](0, ErgoBox.MaxTokens)
@@ -231,7 +246,7 @@ trait ValueGenerators extends TypeGenerators {
def ergoBoxCandidateGen(availableTokens: Seq[TokenId]): Gen[ErgoBoxCandidate] = for {
l <- arbLong.arbitrary
p <- proveDlogGen
- b <- Gen.oneOf(TrueLeaf, FalseLeaf, p)
+ b <- Gen.oneOf(TrueProp, FalseProp, ErgoTree.fromSigmaBoolean(p))
regNum <- Gen.chooseNum[Byte](0, ErgoBox.nonMandatoryRegistersCount)
ar <- Gen.sequence(additionalRegistersGen(regNum))
tokensCount <- Gen.chooseNum[Byte](0, ErgoBox.MaxTokens)
@@ -252,11 +267,12 @@ trait ValueGenerators extends TypeGenerators {
} yield tokens
val ergoTransactionGen: Gen[ErgoLikeTransaction] = for {
- inputs <- Gen.listOf(inputGen)
+ inputs <- Gen.nonEmptyListOf(inputGen)
tokens <- tokensGen
+ dataInputs <- Gen.listOf(dataInputGen)
outputsCount <- Gen.chooseNum(50, 200)
outputCandidates <- Gen.listOfN(outputsCount, ergoBoxCandidateGen(tokens))
- } yield ErgoLikeTransaction(inputs.toIndexedSeq, outputCandidates.toIndexedSeq)
+ } yield new ErgoLikeTransaction(inputs.toIndexedSeq, dataInputs.toIndexedSeq, outputCandidates.toIndexedSeq)
// distinct list of elements from a given generator
// with a maximum number of elements to discard
diff --git a/src/test/scala/sigmastate/utils/ByteArrayBuilderTests.scala b/src/test/scala/sigmastate/utils/ByteArrayBuilderTests.scala
index a8a40a3554..e69de29bb2 100644
--- a/src/test/scala/sigmastate/utils/ByteArrayBuilderTests.scala
+++ b/src/test/scala/sigmastate/utils/ByteArrayBuilderTests.scala
@@ -1,29 +0,0 @@
-package sigmastate.utils
-
-import org.scalatest.{PropSpec, Matchers}
-import org.scalatest.prop.PropertyChecks
-
-class ByteArrayBuilderTests extends PropSpec with PropertyChecks with Matchers {
-
- property("Append basic types") {
- val b = new ByteArrayBuilder(1)
-
- b.append(1.toByte) // Byte
- b.toBytes shouldBe(Array[Byte](1))
- b.capacity() shouldBe 1
-
- b.append(1) // Int
- b.toBytes shouldBe(Array[Byte](1, 0, 0, 0, 1))
- b.capacity() shouldBe 5
-
- b.append(1L << 32) // Long
- b.toBytes shouldBe(Array[Byte](1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0))
- b.capacity() shouldBe 13
-
- b.append(Array[Byte](10, 20)) // Long
- b.toBytes shouldBe(Array[Byte](1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 10, 20))
- b.capacity() shouldBe 26
-
- }
-
-}
diff --git a/src/test/scala/sigmastate/utils/ByteReaderWriterImpSpecification.scala b/src/test/scala/sigmastate/utils/ByteReaderWriterImpSpecification.scala
index a270971961..e69de29bb2 100644
--- a/src/test/scala/sigmastate/utils/ByteReaderWriterImpSpecification.scala
+++ b/src/test/scala/sigmastate/utils/ByteReaderWriterImpSpecification.scala
@@ -1,313 +0,0 @@
-package sigmastate.utils
-
-import java.nio.ByteBuffer
-
-import org.scalacheck.{Arbitrary, Gen}
-import org.scalatest.prop.PropertyChecks
-import org.scalatest.{Assertion, Matchers, PropSpec}
-import sigmastate.serialization.generators.ValueGenerators
-import sigmastate.utils.ByteArrayWriter.{encodeZigZagInt, encodeZigZagLong}
-import sigmastate.utils.ByteBufferReader.{decodeZigZagInt, decodeZigZagLong}
-import sigmastate.utils.Helpers.bytesFromInts
-
-class ByteReaderWriterImpSpecification extends PropSpec
- with ValueGenerators
- with PropertyChecks
- with Matchers {
-
- private val seqPrimValGen: Gen[Seq[Any]] = for {
- length <- Gen.chooseNum(1, 1000)
- anyValSeq <- Gen.listOfN(length,
- Gen.oneOf(
- Arbitrary.arbByte.arbitrary,
- Arbitrary.arbShort.arbitrary,
- Arbitrary.arbInt.arbitrary,
- Arbitrary.arbLong.arbitrary,
- arrayGen[Byte],
- arrayGen[Boolean]))
- } yield anyValSeq
-
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java#L239
- private val expectedValues: Seq[(Array[Byte], Long)] = Seq(
- (bytesFromInts(0x00), 0),
- (bytesFromInts(0x01), 1),
- (bytesFromInts(0x7f), 127),
- // 14882
- (bytesFromInts(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)),
- // 2961488830
- (bytesFromInts(0xbe, 0xf7, 0x92, 0x84, 0x0b),
- (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28)),
- // 64-bit
- // 7256456126
- (bytesFromInts(0xbe, 0xf7, 0x92, 0x84, 0x1b),
- (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28)),
- // 41256202580718336
- (bytesFromInts(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
- (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)),
- // 11964378330978735131 (-6482365742730816485)
- (bytesFromInts(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
- (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | (0x05L << 49) | (0x26L << 56) | (0x01L << 63))
- )
-
- private def byteBufReader(bytes: Array[Byte]): ByteBufferReader = {
- val buf = ByteBuffer.wrap(bytes)
- buf.position(0)
- new ByteBufferReader(buf)
- }
-
- private def byteArrayWriter(): ByteArrayWriter = new ByteArrayWriter(new ByteArrayBuilder())
-
- property("predefined long values and serialized data round trip") {
- expectedValues.foreach { case (bytes, v) =>
- val writer = byteArrayWriter()
- writer.putULong(v)
- val encodedBytes = writer.toBytes
- encodedBytes shouldEqual bytes
-
- val r = byteBufReader(encodedBytes)
- r.getULong() shouldEqual v
- r.remaining shouldBe 0
- }
- }
-
- property("round trip serialization/deserialization of arbitrary value list") {
- // increase threshold to make sure we cover a lot of types combination
- // and a good diversity withing a values of the each type
- forAll(seqPrimValGen, minSuccessful(500)) { values: Seq[Any] =>
- val writer = byteArrayWriter()
- for(any <- values) {
- any match {
- case v: Byte => writer.put(v)
- case v: Short =>
- writer.putShort(v)
- if (v >= 0) writer.putUShort(v)
- case v: Int =>
- writer.putInt(v)
- if (v >= 0) writer.putUInt(v)
- case v: Long =>
- // test all paths
- writer.putLong(v)
- writer.putULong(v)
- case v: Array[Byte] => writer.putUShort(v.length.toShort).putBytes(v)
- case v: Array[Boolean] => writer.putUShort(v.length.toShort).putBits(v)
- case _ => fail(s"writer: unsupported value type: ${any.getClass}");
- }
- }
- val reader = byteBufReader(writer.toBytes)
- values.foreach {
- case v: Byte => reader.getByte() shouldEqual v
- case v: Short =>
- // test all paths
- reader.getShort() shouldEqual v
- if (v >= 0) reader.getUShort().toShort shouldEqual v
- case v: Int =>
- reader.getInt() shouldEqual v
- if (v >= 0) reader.getUInt() shouldEqual v
- case v: Long =>
- // test all paths
- reader.getLong() shouldEqual v
- reader.getULong() shouldEqual v
- case v: Array[Byte] =>
- val size = reader.getUShort()
- reader.getBytes(size) shouldEqual v
- case v: Array[Boolean] =>
- val size = reader.getUShort()
- reader.getBits(size) shouldEqual v
- case ref@_ => fail(s"reader: unsupported value type: ${ref.getClass}");
- }
- }
- }
-
- private def bytesLong(v: Long): Array[Byte] =
- byteArrayWriter().putULong(v).toBytes
-
- private def checkSize(low: Long, high: Long, size: Int): Assertion = {
- // Gen.choose does not always include range limit values
- bytesLong(low).length shouldBe size
- bytesLong(high).length shouldBe size
- forAll(Gen.choose(low, high)) { v: Long =>
- bytesLong(v).length shouldBe size
- }
- }
-
- property("size of serialized data") {
- // source: http://github.com/scodec/scodec/blob/055eed8386aa85ff27dba3f72b104a8aa3d6012d/unitTests/src/test/scala/scodec/codecs/VarLongCodecTest.scala#L16
- checkSize(0L, 127L, 1)
- checkSize(128L, 16383L, 2)
- checkSize(16384L, 2097151L, 3)
- checkSize(2097152L, 268435455L, 4)
- checkSize(268435456L, 34359738367L, 5)
- checkSize(34359738368L, 4398046511103L, 6)
- checkSize(4398046511104L, 562949953421311L, 7)
- checkSize(562949953421312L, 72057594037927935L, 8)
- checkSize(72057594037927936L, Long.MaxValue, 9)
- checkSize(Long.MinValue, -1L, 10)
- }
-
- private def bytesZigZaggedLong(v: Long): Array[Byte] =
- byteArrayWriter().putULong(encodeZigZagLong(v)).toBytes
-
- private def checkSizeZigZagged(low: Long, high: Long, size: Int): Unit = {
- // Gen.choose does not always include range limit values
- bytesZigZaggedLong(low).length shouldBe size
- bytesZigZaggedLong(high).length shouldBe size
- forAll(Gen.choose(low, high)) { v: Long =>
- bytesZigZaggedLong(v).length shouldBe size
- }
- }
-
- property("size of serialized zigzag'ed data") {
- checkSizeZigZagged(-64L, 64L - 1, 1)
-
- checkSizeZigZagged(-8192L, -64L - 1, 2)
- checkSizeZigZagged(64L, 8192L - 1, 2)
-
- checkSizeZigZagged(-1048576L, -8192L - 1, 3)
- checkSizeZigZagged(8192L, 1048576L - 1, 3)
-
- checkSizeZigZagged(-134217728L, -1048576L - 1, 4)
- checkSizeZigZagged(1048576L, 134217728L - 1, 4)
-
- checkSizeZigZagged(-17179869184L, -134217728L - 1, 5)
- checkSizeZigZagged(134217728L, 17179869184L - 1, 5)
-
- checkSizeZigZagged(-2199023255552L, -17179869184L - 1, 6)
- checkSizeZigZagged(17179869184L, 2199023255552L - 1, 6)
-
- checkSizeZigZagged(-281474976710656L, -2199023255552L - 1, 7)
- checkSizeZigZagged(2199023255552L, 281474976710656L - 1, 7)
-
- checkSizeZigZagged(-36028797018963968L, -281474976710656L - 1, 8)
- checkSizeZigZagged(281474976710656L, 36028797018963968L - 1, 8)
-
- checkSizeZigZagged(Long.MinValue / 2, -36028797018963968L - 1, 9)
- checkSizeZigZagged(36028797018963968L, Long.MaxValue / 2, 9)
-
- checkSizeZigZagged(Long.MinValue, Long.MinValue / 2 - 1, 10)
- checkSizeZigZagged(Long.MaxValue / 2 + 1, Long.MaxValue, 10)
- }
-
- property("fail deserialization by deliberately messing with different methods") {
- forAll(Gen.chooseNum(1, Long.MaxValue)) { v: Long =>
- val writer = byteArrayWriter()
- writer.putULong(v)
- writer.putLong(v)
- val reader = byteBufReader(writer.toBytes)
- reader.getLong() should not be v
- reader.getULong() should not be v
- }
- }
-
- property("malformed input for deserialization") {
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java#L281
- assertThrows[RuntimeException](byteBufReader(bytesFromInts(0x80)).getULong())
- assertThrows[RuntimeException](byteBufReader(bytesFromInts(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00)).getULong())
- }
-
- property("ZigZag encoding format") {
- // source: http://github.com/google/protobuf/blob/a7252bf42df8f0841cf3a0c85fdbf1a5172adecb/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java#L281
- assert(0 == encodeZigZagInt(0))
- assert(1 == encodeZigZagInt(-1))
- assert(2 == encodeZigZagInt(1))
- assert(3 == encodeZigZagInt(-2))
- assert(0x7FFFFFFE == encodeZigZagInt(0x3FFFFFFF))
- assert(0x7FFFFFFF == encodeZigZagInt(0xC0000000))
- assert(0xFFFFFFFE == encodeZigZagInt(0x7FFFFFFF))
- assert(0xFFFFFFFF == encodeZigZagInt(0x80000000))
-
- assert(0 == encodeZigZagLong(0))
- assert(1 == encodeZigZagLong(-1))
- assert(2 == encodeZigZagLong(1))
- assert(3 == encodeZigZagLong(-2))
- assert(0x000000007FFFFFFEL == encodeZigZagLong(0x000000003FFFFFFFL))
- assert(0x000000007FFFFFFFL == encodeZigZagLong(0xFFFFFFFFC0000000L))
- assert(0x00000000FFFFFFFEL == encodeZigZagLong(0x000000007FFFFFFFL))
- assert(0x00000000FFFFFFFFL == encodeZigZagLong(0xFFFFFFFF80000000L))
- assert(0xFFFFFFFFFFFFFFFEL == encodeZigZagLong(0x7FFFFFFFFFFFFFFFL))
- assert(0xFFFFFFFFFFFFFFFFL == encodeZigZagLong(0x8000000000000000L))
- }
-
- property("ZigZag Long round trip") {
- forAll(Gen.chooseNum(Long.MinValue, Long.MaxValue)) { v: Long =>
- decodeZigZagLong(encodeZigZagLong(v)) shouldBe v
- }
- }
-
- property("ZigZag Int round trip") {
- forAll(Gen.chooseNum(Int.MinValue, Int.MaxValue)) { v: Int =>
- decodeZigZagInt(encodeZigZagInt(v)) shouldBe v
- }
- }
-
- property("Coll[Boolean] bit encoding format") {
- val expectations = Seq[(Array[Boolean], Array[Byte])](
- Array[Boolean]() -> Array[Byte](),
- Array(false) -> Array(0),
- Array(true) -> Array(1),
- Array(false, false, true) -> Array(4), // 00000100
- Array(true, true, false) -> Array(3), // 00000011
- Array(true, false, true) -> Array(5), // 00000101
- (Array.fill(8)(false) :+ true) -> Array(0, 1), // 00000000 00000001
- (Array.fill(9)(false) :+ true) -> Array(0, 2), // 00000000 00000010
- (Array.fill(10)(false) :+ true) -> Array(0, 4) // 00000000 00000100
- )
- expectations.foreach { case (bools, bytes) =>
- byteArrayWriter().putBits(bools).toBytes shouldEqual bytes
- byteBufReader(bytes).getBits(bools.length) shouldEqual bools
- }
- }
-
- property("putUByte range check assertion") {
- val w = byteArrayWriter()
- w.putUByte(0)
- w.putUByte(255)
- an[AssertionError] should be thrownBy w.putUByte(-1)
- an[AssertionError] should be thrownBy w.putUByte(256)
- }
-
- property("putUShort range check assertion") {
- val w = byteArrayWriter()
- w.putUShort(0)
- w.putUShort(0xFFFF)
- an[AssertionError] should be thrownBy w.putUShort(-1)
- an[AssertionError] should be thrownBy w.putUShort(0xFFFF + 1)
- }
-
- property("putUInt range check assertion") {
- val w = byteArrayWriter()
- w.putUInt(0)
- w.putUInt(0xFFFFFFFFL)
- an[AssertionError] should be thrownBy w.putUInt(-1)
- an[AssertionError] should be thrownBy w.putUInt(0xFFFFFFFFL + 1)
- }
-
- property("getUShort range check assertion") {
- def check(in: Int): Unit =
- byteBufReader(byteArrayWriter().putUInt(in).toBytes).getUShort() shouldBe in
-
- def checkFail(in: Int): Unit =
- an[AssertionError] should be thrownBy
- byteBufReader(byteArrayWriter().putUInt(in).toBytes).getUShort()
-
- check(0)
- check(0xFFFF)
- checkFail(-1)
- checkFail(0xFFFF + 1)
- checkFail(Int.MaxValue)
- }
-
- property("getUInt range check assertion") {
- def check(in: Long): Unit =
- byteBufReader(byteArrayWriter().putULong(in).toBytes).getUInt() shouldBe in
-
- def checkFail(in: Long): Unit =
- an[AssertionError] should be thrownBy
- byteBufReader(byteArrayWriter().putULong(in).toBytes).getUInt()
-
- check(0)
- check(0xFFFFFFFFL)
- checkFail(-1)
- checkFail(0xFFFFFFFFL + 1L)
- checkFail(Long.MaxValue)
- }
-}
diff --git a/src/test/scala/sigmastate/utils/HelpersTests.scala b/src/test/scala/sigmastate/utils/HelpersTests.scala
new file mode 100644
index 0000000000..0dee6298fe
--- /dev/null
+++ b/src/test/scala/sigmastate/utils/HelpersTests.scala
@@ -0,0 +1,28 @@
+package sigmastate.utils
+
+import org.scalatest.prop.PropertyChecks
+import org.scalatest.{PropSpec, Matchers}
+import sigmastate.serialization.generators.ValueGenerators
+import Helpers._
+
+class HelpersTests extends PropSpec with PropertyChecks with Matchers with ValueGenerators {
+ property("xorU") {
+ forAll(arrayGen[Byte]) { arr =>
+
+ val x = xor(arr, arr)
+ val cloned = arr.clone()
+ xorU(cloned, arr)
+ cloned shouldBe x
+
+ val arr1 = x
+ val arr2 = cloned
+ val arr3 = xor(arr1, arr2)
+ val res1 = xor(cloned, arr1, arr2, arr3)
+ val res2 = cloned
+ xorU(res2, Seq(arr1, arr2, arr3))
+
+ res1 shouldBe res2
+ println(arr.length)
+ }
+ }
+}
diff --git a/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala b/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala
index d337aaa75b..60b2b180ec 100644
--- a/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala
@@ -1,124 +1,191 @@
package sigmastate.utxo
import com.google.common.primitives.Longs
+import org.ergoplatform.ErgoScriptPredef.TrueProp
import org.ergoplatform._
+import org.ergoplatform.dsl.{SigmaContractSyntax, ContractSpec, TestContractSpec}
import scorex.crypto.authds.avltree.batch._
import scorex.crypto.authds.{ADKey, ADValue}
-import scorex.crypto.hash.{Digest32, Blake2b256}
+import scorex.crypto.hash.{Blake2b256, Digest32}
import sigmastate.SCollection.SByteArray
import sigmastate.Values._
import sigmastate._
+import sigmastate.eval.{IRContext, CSigmaProp}
+import sigmastate.eval.Extensions._
import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
import sigmastate.lang.Terms._
-import sigmastate.serialization.OperationSerializer
+import special.collection.Coll
+import special.sigma.{Context, AvlTree}
-class AVLTreeScriptsSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
- private val reg1 = ErgoBox.nonMandatoryRegisters.head
+
+class AVLTreeScriptsSpecification extends SigmaTestingCommons { suite =>
+ import org.ergoplatform.dsl.AvlTreeHelpers._
+ lazy val spec = TestContractSpec(suite)(new TestingIRContext)
+ lazy val prover = spec.ProvingParty("Alice")
+ private implicit lazy val IR: IRContext = spec.IR
+
+ private val reg1 = ErgoBox.nonMandatoryRegisters(0)
private val reg2 = ErgoBox.nonMandatoryRegisters(1)
def genKey(str: String): ADKey = ADKey @@ Blake2b256("key: " + str)
-
def genValue(str: String): ADValue = ADValue @@ Blake2b256("val: " + str)
- property("avl tree modification") {
- val prover = new ErgoLikeTestProvingInterpreter
- val verifier = new ErgoLikeTestInterpreter
- val pubkey = prover.dlogSecrets.head.publicImage
+ val inKey = genKey("init key")
+ val inValue = genValue("init value")
+
+ property("avl tree - removals") {
+ case class AvlTreeContract[Spec <: ContractSpec]
+ (ops: Coll[Coll[Byte]], proof: Coll[Byte], prover: Spec#ProvingParty)
+ (implicit val spec: Spec) extends SigmaContractSyntax
+ {
+ def pkProver = prover.pubKey
+ import syntax._
+ lazy val contractEnv = Env("pkProver" -> pkProver, "ops" -> ops, "proof" -> proof)
+
+ lazy val treeProp = proposition("treeProp", { ctx: Context => import ctx._
+ sigmaProp(SELF.R4[AvlTree].get.remove(ops, proof).get == SELF.R5[AvlTree].get)
+ },
+ """{
+ | sigmaProp(SELF.R4[AvlTree].get.remove(ops, proof).get == SELF.R5[AvlTree].get)
+ |}
+ """.stripMargin)
- val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
- val inKey = genKey("init key")
- avlProver.performOneOperation(Insert(inKey, genValue("init value")))
- avlProver.generateProof()
- val digest = avlProver.digest
- val treeData = new AvlTreeData(digest, 32, None)
+ lazy val proverSig = proposition("proverSig", { _ => pkProver }, "pkProver")
+ }
- val operations: Seq[Operation] = (0 to 10).map(i => Insert(genKey(i.toString), genValue(i.toString))) :+
- Update(inKey, genValue("updated value"))
- val serializer = new OperationSerializer(avlProver.keyLength, avlProver.valueLengthOpt)
- val opsBytes: Array[Byte] = serializer.serializeSeq(operations)
- operations.foreach(o => avlProver.performOneOperation(o))
- val proof = avlProver.generateProof()
- val endDigest = avlProver.digest
+ val entries = (0 to 10).map { i => (genKey(i.toString) -> genValue(i.toString)) }
+ val (tree, avlProver) = createAvlTree(AvlTreeFlags.AllOperationsAllowed, entries:_*)
- val prop = EQ(TreeModifications(ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
- ByteArrayConstant(opsBytes),
- ByteArrayConstant(proof)).get, ByteArrayConstant(endDigest))
- val env = Map("ops" -> opsBytes, "proof" -> proof, "endDigest" -> endDigest)
- val propCompiled = compileWithCosting(env, """treeModifications(SELF.R4[AvlTree].get, ops, proof).get == endDigest""").asBoolValue
- prop shouldBe propCompiled
+ val removalKeys = (0 to 10).map(i => genKey(i.toString)).toArray
+ val removals: Seq[Operation] = removalKeys.map(k => Remove(k))
+ removals.foreach(o => avlProver.performOneOperation(o))
- val newBox1 = ErgoBox(10, pubkey, 0)
- val newBoxes = IndexedSeq(newBox1)
+ val proof = avlProver.generateProof().toColl
+ val endDigest = avlProver.digest.toColl
+ val endTree = tree.updateDigest(endDigest)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val contract = AvlTreeContract[spec.type](removalKeys.toColl, proof, prover)(spec)
+ import contract.spec._
- val s = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
+ val mockTx = candidateBlock(0).newTransaction()
+ val s = mockTx
+ .outBox(20, contract.treeProp)
+ .withRegs(reg1 -> tree, reg2 -> endTree)
- val ctx = ErgoLikeContext(
- currentHeight = 50,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(s),
- spendingTransaction,
- self = s)
+ val spendingTx = candidateBlock(50).newTransaction().spending(s)
+ val newBox1 = spendingTx.outBox(10, contract.proverSig)
+
+ val in1 = spendingTx.inputs(0)
+ val res = in1.runDsl()
+ res shouldBe CSigmaProp(TrivialProp.TrueProp)
- val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
- verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true
+ val pr = prover.prove(in1).get
+ contract.verifier.verify(in1, pr) shouldBe true
}
- property("avl tree lookup") {
- val prover = new ErgoLikeTestProvingInterpreter
- val verifier = new ErgoLikeTestInterpreter
+ property("avl tree - inserts") {
+ case class AvlTreeContract[Spec <: ContractSpec]
+ (ops: Coll[(Coll[Byte], Coll[Byte])], proof: Coll[Byte], prover: Spec#ProvingParty)
+ (implicit val spec: Spec) extends SigmaContractSyntax
+ {
+ def pkProver = prover.pubKey
+ import syntax._
+ lazy val contractEnv = Env("pkProver" -> pkProver, "ops" -> ops, "proof" -> proof)
+
+ lazy val treeProp = proposition("treeProp", { ctx: Context => import ctx._
+ val tree = SELF.R4[AvlTree].get
+ val endTree = SELF.R5[AvlTree].get
+ sigmaProp(tree.insert(ops, proof).get == endTree)
+ },
+ """{
+ | val tree = SELF.R4[AvlTree].get
+ | val endTree = SELF.R5[AvlTree].get
+ | sigmaProp(tree.insert(ops, proof).get == endTree)
+ |}""".stripMargin)
- val pubkey = prover.dlogSecrets.head.publicImage
+ lazy val proverSig = proposition("proverSig", { _ => pkProver }, "pkProver")
+ }
- val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
+ val (tree, avlProver) = createAvlTree(AvlTreeFlags.AllOperationsAllowed)
+ val insertPairs = (0 to 10).map { i => (genKey(i.toString), genValue(i.toString)) }.toArray
+ insertPairs.foreach { case (k, v) => avlProver.performOneOperation(Insert(k, v)) }
- val key = genKey("key")
- val value = genValue("value")
- avlProver.performOneOperation(Insert(key, value))
- avlProver.performOneOperation(Insert(genKey("key2"), genValue("value2")))
- avlProver.generateProof()
+ val proof = avlProver.generateProof().toColl
+ val endDigest = avlProver.digest.toColl
+ val endTree = tree.updateDigest(endDigest)
- avlProver.performOneOperation(Lookup(genKey("key")))
+ val contract = AvlTreeContract[spec.type](insertPairs.toColl, proof, prover)(spec)
+ import contract.spec._
- val digest = avlProver.digest
- val proof = avlProver.generateProof()
+ val mockTx = candidateBlock(0).newTransaction()
+ val s = mockTx
+ .outBox(20, contract.treeProp)
+ .withRegs(reg1 -> tree, reg2 -> endTree)
- val treeData = new AvlTreeData(digest, 32, None)
+ val spendingTx = candidateBlock(50).newTransaction().spending(s)
+ val newBox1 = spendingTx.outBox(10, contract.proverSig)
+ val in1 = spendingTx.inputs(0)
+ val res = in1.runDsl()
+ res shouldBe CSigmaProp(TrivialProp.TrueProp)
- val prop = EQ(TreeLookup(ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
- ByteArrayConstant(key),
- ByteArrayConstant(proof)).get, ByteArrayConstant(value))
+ val pr = prover.prove(in1).get
+ contract.verifier.verify(in1, pr) shouldBe true
+ }
- val env = Map("key" -> key, "proof" -> proof, "value" -> value)
- val propCompiled = compileWithCosting(env, """treeLookup(SELF.R4[AvlTree].get, key, proof).get == value""").asBoolValue
- prop shouldBe propCompiled
+ property("avl tree lookup") {
+ case class AvlTreeContract[Spec <: ContractSpec]
+ (key: Coll[Byte], proof: Coll[Byte], value: Coll[Byte], prover: Spec#ProvingParty)
+ (implicit val spec: Spec) extends SigmaContractSyntax
+ {
+ def pkProver = prover.pubKey
+ import syntax._
+ lazy val contractEnv = Env("pkProver" -> pkProver, "key" -> key, "proof" -> proof, "value" -> value)
+
+ lazy val treeProp = proposition("treeProp", { ctx: Context => import ctx._
+ val tree = SELF.R4[AvlTree].get
+ sigmaProp(tree.get(key, proof).get == value)
+ },
+ """{
+ | val tree = SELF.R4[AvlTree].get
+ | sigmaProp(tree.get(key, proof).get == value)
+ |}""".stripMargin)
- val newBox1 = ErgoBox(10, pubkey, 0)
- val newBoxes = IndexedSeq(newBox1)
+ lazy val proverSig = proposition("proverSig", { _ => pkProver }, "pkProver")
+ }
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val key = genKey("key")
+ val value = genValue("value")
+ val (tree, avlProver) = createAvlTree(AvlTreeFlags.AllOperationsAllowed, key -> value, genKey("key2") -> genValue("value2"))
+ avlProver.performOneOperation(Lookup(genKey("key")))
- val s = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
+ val digest = avlProver.digest
+ val proof = avlProver.generateProof().toColl
+ val treeData = new AvlTreeData(digest, AvlTreeFlags.ReadOnly, 32, None)
- val ctx = ErgoLikeContext(
- currentHeight = 50,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(s),
- spendingTransaction,
- self = s)
+ val contract = AvlTreeContract[spec.type](key.toColl, proof, value.toColl, prover)(spec)
+ import contract.spec._
+
+ val mockTx = candidateBlock(0).newTransaction()
+ val s = mockTx
+ .outBox(20, contract.treeProp)
+ .withRegs(reg1 -> treeData)
+
+ val spendingTx = candidateBlock(50).newTransaction().spending(s)
+ val newBox1 = spendingTx.outBox(10, contract.proverSig)
- val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
- verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true
+ val in1 = spendingTx.inputs(0)
+ val res = in1.runDsl()
+ res shouldBe CSigmaProp(TrivialProp.TrueProp)
+
+ val pr = prover.prove(in1).get
+ contract.verifier.verify(in1, pr) shouldBe true
}
property("avl tree - simplest case") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
@@ -134,22 +201,24 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons {
val digest = avlProver.digest
val proof = avlProver.generateProof()
- val treeData = new AvlTreeData(digest, 32, None)
+ val treeData = new AvlTreeData(digest, AvlTreeFlags.ReadOnly, 32, None)
val env = Map("key" -> key, "proof" -> proof)
- val prop = compileWithCosting(env, """isMember(SELF.R4[AvlTree].get, key, proof)""").asBoolValue
+ val prop = compile(env, """SELF.R4[AvlTree].get.contains(key, proof)""").asBoolValue.toSigmaProp
- val propTree = OptionIsDefined(TreeLookup(ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
- ByteArrayConstant(key),
- ByteArrayConstant(proof)))
+ val propTree = IR.builder.mkMethodCall(
+ ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
+ SAvlTree.containsMethod,
+ IndexedSeq(ByteArrayConstant(key), ByteArrayConstant(proof))
+ ).asBoolValue.toSigmaProp
prop shouldBe propTree
val newBox1 = ErgoBox(10, pubkey, 0)
val newBoxes = IndexedSeq(newBox1)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
- val s = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
+ val s = ErgoBox(20, TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -163,47 +232,48 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons {
verifier.verify(prop, ctx, pr, fakeMessage).get._1 shouldBe true
}
- property("avl tree - leaf satisfying condition exists") {
+ property("avl tree - contains key satisfying condition") {
val elements = Seq(123, 22)
val treeElements = elements.map(i => Longs.toByteArray(i)).map(s => (ADKey @@ Blake2b256(s), ADValue @@ s))
val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
treeElements.foreach(s => avlProver.performOneOperation(Insert(s._1, s._2)))
avlProver.generateProof()
- val treeData = new AvlTreeData(avlProver.digest, 32, None)
+ val treeData = new AvlTreeData(avlProver.digest, AvlTreeFlags.ReadOnly, 32, None)
val proofId = 0: Byte
val elementId = 1: Byte
- val prop: Value[SBoolean.type] = AND(
+ val prop = AND(
GE(GetVarLong(elementId).get, LongConstant(120)),
- OptionIsDefined(TreeLookup(ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
- CalcBlake2b256(LongToByteArray(GetVarLong(elementId).get)),
- GetVarByteArray(proofId).get))
- )
+ IR.builder.mkMethodCall(
+ ExtractRegisterAs[SAvlTree.type](Self, reg1).get, SAvlTree.containsMethod,
+ IndexedSeq(CalcBlake2b256(LongToByteArray(GetVarLong(elementId).get)), GetVarByteArray(proofId).get)
+ ).asBoolValue
+ ).toSigmaProp
val env = Map("proofId" -> proofId.toLong, "elementId" -> elementId.toLong)
- val propCompiled = compileWithCosting(env,
+ val propCompiled = compile(env,
"""{
| val tree = SELF.R3[AvlTree].get
| val proof = getVar[Coll[Byte]](proofId).get
| val element = getVar[Long](elementId).get
| val elementKey = blake2b256(longToByteArray(element))
- | element >= 120 && isMember(tree, elementKey, proof)
- |}""".stripMargin).asBoolValue
+ | element >= 120 && tree.contains(elementKey, proof)
+ |}""".stripMargin).asBoolValue.toSigmaProp
- // TODO propCompiled shouldBe prop
+ //TODO: propCompiled shouldBe prop
- val recipientProposition = new ErgoLikeTestProvingInterpreter().dlogSecrets.head.publicImage
- val selfBox = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
+ val recipientProposition = new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage
+ val selfBox = ErgoBox(20, TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
val ctx = ErgoLikeContext(
currentHeight = 50,
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(selfBox),
- new ErgoLikeTransaction(IndexedSeq(), IndexedSeq(ErgoBox(1, recipientProposition, 0))),
+ createTransaction(ErgoBox(1, recipientProposition, 0)),
self = selfBox)
avlProver.performOneOperation(Lookup(treeElements.head._1))
val bigLeafProof = avlProver.generateProof()
- val prover = new ErgoLikeTestProvingInterpreter()
+ val prover = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(proofId, ByteArrayConstant(bigLeafProof))
.withContextExtender(elementId, LongConstant(elements.head))
val proof = prover.prove(prop, ctx, fakeMessage).get
@@ -212,7 +282,7 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons {
avlProver.performOneOperation(Lookup(treeElements.last._1))
val smallLeafTreeProof = avlProver.generateProof()
- val smallProver = new ErgoLikeTestProvingInterpreter()
+ val smallProver = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(proofId, ByteArrayConstant(smallLeafTreeProof))
.withContextExtender(elementId, LongConstant(elements.head))
smallProver.prove(prop, ctx, fakeMessage).isSuccess shouldBe false
@@ -232,35 +302,36 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons {
val digest = avlProver.digest
val proof = avlProver.generateProof()
- val treeData = new AvlTreeData(digest, 32, None)
+ val treeData = new AvlTreeData(digest, AvlTreeFlags.ReadOnly, 32, None)
val proofId = 31: Byte
- val prover = new ErgoLikeTestProvingInterpreter().withContextExtender(proofId, ByteArrayConstant(proof))
+ val prover = new ContextEnrichingTestProvingInterpreter().withContextExtender(proofId, ByteArrayConstant(proof))
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
val env = Map("proofId" -> proofId.toLong)
- val prop = compileWithCosting(env,
+ val prop = compile(env,
"""{
| val tree = SELF.R4[AvlTree].get
| val key = SELF.R5[Coll[Byte]].get
| val proof = getVar[Coll[Byte]](proofId).get
- | isMember(tree, key, proof)
- |}""".stripMargin).asBoolValue
+ | tree.contains(key, proof)
+ |}""".stripMargin).asBoolValue.toSigmaProp
- val propTree = OptionIsDefined(TreeLookup(
+ val propTree = IR.builder.mkMethodCall(
ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
- ExtractRegisterAs[SByteArray](Self, reg2).get,
- GetVarByteArray(proofId).get))
+ SAvlTree.containsMethod,
+ IndexedSeq(ExtractRegisterAs[SByteArray](Self, reg2).get, GetVarByteArray(proofId).get)
+ ).asBoolValue.toSigmaProp
prop shouldBe propTree
val newBox1 = ErgoBox(10, pubkey, 0)
val newBoxes = IndexedSeq(newBox1)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
- val s = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData), reg2 -> ByteArrayConstant(key)))
+ val s = ErgoBox(20, TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData), reg2 -> ByteArrayConstant(key)))
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -273,4 +344,57 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons {
val ctxv = ctx.withExtension(pr.extension)
verifier.verify(prop, ctxv, pr, fakeMessage).get._1 shouldBe true
}
-}
\ No newline at end of file
+
+ property("avl tree - getMany") {
+ val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
+
+ (1 to 10).foreach {i =>
+ val key = genKey(s"$i")
+ avlProver.performOneOperation(Insert(key, genValue(s"${i + 100}")))
+ }
+ avlProver.generateProof()
+
+ (3 to 5).foreach { i =>
+ val key = genKey(s"$i")
+ avlProver.performOneOperation(Lookup(key))
+ }
+ val digest = avlProver.digest
+ val proof = avlProver.generateProof()
+
+ val proofId = 31: Byte
+
+ val prover = new ContextEnrichingTestProvingInterpreter().withContextExtender(proofId, ByteArrayConstant(proof))
+ val verifier = new ErgoLikeTestInterpreter
+ val pubkey = prover.dlogSecrets.head.publicImage
+
+ val treeData = new AvlTreeData(digest, AvlTreeFlags.ReadOnly, 32, None)
+
+ val env = Map("proofId" -> proofId.toLong,
+ "keys" -> ConcreteCollection(genKey("3"), genKey("4"), genKey("5")))
+ val prop = compile(env,
+ """{
+ | val tree = SELF.R4[AvlTree].get
+ | val proof = getVar[Coll[Byte]](proofId).get
+ | sigmaProp(tree.getMany(keys, proof).forall( { (o: Option[Coll[Byte]]) => o.isDefined }))
+ |}""".stripMargin).asBoolValue.toSigmaProp
+
+ val newBox1 = ErgoBox(10, pubkey, 0)
+ val newBoxes = IndexedSeq(newBox1)
+
+ val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+
+ val s = ErgoBox(20, TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
+
+ val ctx = ErgoLikeContext(
+ currentHeight = 50,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(s),
+ spendingTransaction, self = s)
+ val pr = prover.prove(env + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
+
+ val ctxv = ctx.withExtension(pr.extension)
+ verifier.verify(env + (ScriptNameProp -> "verify"), prop, ctxv, pr, fakeMessage).get._1 shouldBe true
+ }
+
+}
diff --git a/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
index a0e1ce99ad..a20c119f21 100644
--- a/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
@@ -1,20 +1,21 @@
package sigmastate.utxo
-import java.lang.reflect.InvocationTargetException
-
-import org.ergoplatform.ErgoBox.{R4, R6, R8}
-import org.ergoplatform.{ErgoBox, ErgoLikeContext, Height, Self}
+import org.ergoplatform.ErgoBox.{R6, R8}
+import org.ergoplatform.ErgoLikeContext.dummyPubkey
+import org.ergoplatform._
import sigmastate.SCollection.SByteArray
import sigmastate.Values._
import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.interpreter.Interpreter._
import sigmastate.lang.Terms._
import special.sigma.InvalidType
-import scalan.BaseCtxTests
+
class BasicOpsSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
+ implicit lazy val IR = new TestingIRContext {
+ override val okPrintEvaluatedEntries: Boolean = false
+ }
private val reg1 = ErgoBox.nonMandatoryRegisters.head
private val reg2 = ErgoBox.nonMandatoryRegisters.tail.head
@@ -49,7 +50,7 @@ class BasicOpsSpecification extends SigmaTestingCommons {
ext: Seq[(Byte, EvaluatedValue[_ <: SType])],
script: String, propExp: SValue,
onlyPositive: Boolean = true) = {
- val prover = new ErgoLikeTestProvingInterpreter() {
+ val prover = new ContextEnrichingTestProvingInterpreter() {
override lazy val contextExtenders: Map[Byte, EvaluatedValue[_ <: SType]] = {
val p1 = dlogSecrets(0).publicImage
val p2 = dlogSecrets(1).publicImage
@@ -57,72 +58,79 @@ class BasicOpsSpecification extends SigmaTestingCommons {
}
}
- val prop = compileWithCosting(env, script).asBoolValue
- prop shouldBe propExp
+ val prop = compile(env, script).asBoolValue.toSigmaProp
+ if (propExp != null)
+ prop shouldBe propExp
val p3 = prover.dlogSecrets(2).publicImage
- val outputToSpend = ErgoBox(10, prop, additionalRegisters = Map(
+ val boxToSpend = ErgoBox(10, prop, additionalRegisters = Map(
reg1 -> SigmaPropConstant(p3),
reg2 -> IntConstant(1)),
creationHeight = 5)
- val ctx = ErgoLikeContext.dummy(outputToSpend)
+ val newBox1 = ErgoBox(10, prop, creationHeight = 0, boxIndex = 0, additionalRegisters = Map(
+ reg1 -> IntConstant(1),
+ reg2 -> IntConstant(10)))
+ val tx = createTransaction(newBox1)
+
+ val ctx = ErgoLikeContext(currentHeight = 0,
+ lastBlockUtxoRoot = AvlTreeData.dummy, dummyPubkey, boxesToSpend = IndexedSeq(boxToSpend),
+ spendingTransaction = tx, self = boxToSpend)
- val namedEnv = env + (ScriptNameProp -> name)
- val pr = prover.prove(namedEnv, prop, ctx, fakeMessage).get
+ val pr = prover.prove(env + (ScriptNameProp -> s"${name}_prove"), prop, ctx, fakeMessage).fold(t => throw t, identity)
val ctxExt = ctx.withExtension(pr.extension)
val verifier = new ErgoLikeTestInterpreter
if (!onlyPositive)
- verifier.verify(namedEnv, prop, ctx, pr.proof, fakeMessage).map(_._1).getOrElse(false) shouldBe false //context w/out extensions
- verifier.verify(namedEnv, prop, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true
+ verifier.verify(env + (ScriptNameProp -> s"${name}_verify"), prop, ctx, pr.proof, fakeMessage).map(_._1).getOrElse(false) shouldBe false //context w/out extensions
+ verifier.verify(env + (ScriptNameProp -> s"${name}_verify_ext"), prop, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true
}
property("Relation operations") {
test("R1", env, ext,
"{ allOf(Coll(getVar[Boolean](trueVar).get, true, true)) }",
- AND(GetVarBoolean(booleanVar).get, TrueLeaf, TrueLeaf)
+ AND(GetVarBoolean(booleanVar).get, TrueLeaf, TrueLeaf).toSigmaProp
)
test("R2", env, ext,
"{ anyOf(Coll(getVar[Boolean](trueVar).get, true, false)) }",
- OR(GetVarBoolean(booleanVar).get, TrueLeaf, FalseLeaf)
+ OR(GetVarBoolean(booleanVar).get, TrueLeaf, FalseLeaf).toSigmaProp
)
test("R3", env, ext,
"{ getVar[Int](intVar2).get > getVar[Int](intVar1).get && getVar[Int](intVar1).get < getVar[Int](intVar2).get }",
BlockValue(
Vector(ValDef(1, GetVarInt(2).get), ValDef(2, GetVarInt(1).get)),
- BinAnd(GT(ValUse(1, SInt), ValUse(2, SInt)), LT(ValUse(2, SInt), ValUse(1, SInt)))),
+ BinAnd(GT(ValUse(1, SInt), ValUse(2, SInt)), LT(ValUse(2, SInt), ValUse(1, SInt)))).asBoolValue.toSigmaProp
)
test("R4", env, ext,
"{ getVar[Int](intVar2).get >= getVar[Int](intVar1).get && getVar[Int](intVar1).get <= getVar[Int](intVar2).get }",
BlockValue(
Vector(ValDef(1, GetVarInt(2).get), ValDef(2, GetVarInt(1).get)),
- BinAnd(GE(ValUse(1, SInt), ValUse(2, SInt)), LE(ValUse(2, SInt), ValUse(1, SInt)))),
+ BinAnd(GE(ValUse(1, SInt), ValUse(2, SInt)), LE(ValUse(2, SInt), ValUse(1, SInt)))).asBoolValue.toSigmaProp
)
test("R5", env, ext,
"{ getVar[Byte](byteVar2).get > getVar[Byte](byteVar1).get && getVar[Byte](byteVar1).get < getVar[Byte](byteVar2).get }",
BlockValue(
Vector(ValDef(1, GetVarByte(4).get), ValDef(2, GetVarByte(3).get)),
- BinAnd(GT(ValUse(1, SByte), ValUse(2, SByte)), LT(ValUse(2, SByte), ValUse(1, SByte)))),
+ BinAnd(GT(ValUse(1, SByte), ValUse(2, SByte)), LT(ValUse(2, SByte), ValUse(1, SByte)))).asBoolValue.toSigmaProp
)
test("R6", env, ext,
"{ getVar[Byte](byteVar2).get >= getVar[Byte](byteVar1).get && getVar[Byte](byteVar1).get <= getVar[Byte](byteVar2).get }",
BlockValue(
Vector(ValDef(1, GetVarByte(4).get), ValDef(2, List(), GetVarByte(3).get)),
- BinAnd(GE(ValUse(1, SByte), ValUse(2, SByte)), LE(ValUse(2, SByte), ValUse(1, SByte)))),
+ BinAnd(GE(ValUse(1, SByte), ValUse(2, SByte)), LE(ValUse(2, SByte), ValUse(1, SByte)))).asBoolValue.toSigmaProp
)
test("R7", env, ext,
"{ getVar[BigInt](bigIntVar2).get > getVar[BigInt](bigIntVar1).get && getVar[BigInt](bigIntVar1).get < getVar[BigInt](bigIntVar2).get }",
BlockValue(
Vector(ValDef(1, GetVarBigInt(6).get), ValDef(2, List(), GetVarBigInt(5).get)),
- BinAnd(GT(ValUse(1, SBigInt), ValUse(2, SBigInt)), LT(ValUse(2, SBigInt), ValUse(1, SBigInt)))),
+ BinAnd(GT(ValUse(1, SBigInt), ValUse(2, SBigInt)), LT(ValUse(2, SBigInt), ValUse(1, SBigInt)))).asBoolValue.toSigmaProp
)
test("R8", env, ext,
"{ getVar[BigInt](bigIntVar2).get >= getVar[BigInt](bigIntVar1).get && getVar[BigInt](bigIntVar1).get <= getVar[BigInt](bigIntVar2).get }",
BlockValue(
Vector(ValDef(1, GetVarBigInt(6).get), ValDef(2, List(), GetVarBigInt(5).get)),
- BinAnd(GE(ValUse(1, SBigInt), ValUse(2, SBigInt)), LE(ValUse(2, SBigInt), ValUse(1, SBigInt)))),
+ BinAnd(GE(ValUse(1, SBigInt), ValUse(2, SBigInt)), LE(ValUse(2, SBigInt), ValUse(1, SBigInt)))).asBoolValue.toSigmaProp
)
}
@@ -183,7 +191,7 @@ class BasicOpsSpecification extends SigmaTestingCommons {
)
test("Prop13", env, ext,
"{ SELF.R4[SigmaProp].get.propBytes != getVar[SigmaProp](proofVar1).get.propBytes }",
- NEQ(ExtractRegisterAs[SSigmaProp.type](Self, reg1).get.propBytes, GetVarSigmaProp(propVar1).get.propBytes),
+ NEQ(ExtractRegisterAs[SSigmaProp.type](Self, reg1).get.propBytes, GetVarSigmaProp(propVar1).get.propBytes).toSigmaProp,
true
)
}
@@ -191,95 +199,95 @@ class BasicOpsSpecification extends SigmaTestingCommons {
property("Arith operations") {
test("Arith1", env, ext,
"{ getVar[Int](intVar2).get * 2 + getVar[Int](intVar1).get == 5 }",
- EQ(Plus(Multiply(GetVarInt(intVar2).get, IntConstant(2)), GetVarInt(intVar1).get), IntConstant(5))
+ EQ(Plus(Multiply(GetVarInt(intVar2).get, IntConstant(2)), GetVarInt(intVar1).get), IntConstant(5)).toSigmaProp
)
test("Arith2", env, ext :+ (bigIntVar3 -> BigIntConstant(50)),
"{ getVar[BigInt](bigIntVar2).get * 2 + getVar[BigInt](bigIntVar1).get == getVar[BigInt](bigIntVar3).get }",
EQ(
Plus(Multiply(GetVarBigInt(bigIntVar2).get, BigIntConstant(2)),
GetVarBigInt(bigIntVar1).get),
- GetVarBigInt(bigIntVar3).get)
+ GetVarBigInt(bigIntVar3).get).toSigmaProp
)
test("Arith3", env, ext :+ (byteVar3 -> ByteConstant(5)),
"{ getVar[Byte](byteVar2).get * 2.toByte + getVar[Byte](byteVar1).get == 5.toByte }",
EQ(
Plus(Multiply(GetVarByte(byteVar2).get, ByteConstant(2)),
- GetVarByte(byteVar1).get), ByteConstant(5))
+ GetVarByte(byteVar1).get), ByteConstant(5)).toSigmaProp
)
test("Arith4", env, ext,
"{ getVar[Int](intVar2).get / 2 + getVar[Int](intVar1).get == 2 }",
- EQ(Plus(Divide(GetVarInt(2).get, IntConstant(2)), GetVarInt(1).get),IntConstant(2)),
+ EQ(Plus(Divide(GetVarInt(2).get, IntConstant(2)), GetVarInt(1).get),IntConstant(2)).toSigmaProp
)
test("Arith5", env, ext,
"{ getVar[Int](intVar2).get % 2 + getVar[Int](intVar1).get == 1 }",
- EQ(Plus(Modulo(GetVarInt(intVar2).get, IntConstant(2)), GetVarInt(intVar1).get), IntConstant(1))
+ EQ(Plus(Modulo(GetVarInt(intVar2).get, IntConstant(2)), GetVarInt(intVar1).get), IntConstant(1)).toSigmaProp
)
}
property("Tuple operations") {
test("Tup1", env, ext,
"{ (getVar[Int](intVar1).get, getVar[Int](intVar2).get)._1 == 1 }",
- EQ(GetVarInt(intVar1).get, IntConstant(1))
+ EQ(GetVarInt(intVar1).get, IntConstant(1)).toSigmaProp
)
test("Tup2", env, ext,
"{ (getVar[Int](intVar1).get, getVar[Int](intVar2).get)._2 == 2 }",
- EQ(GetVarInt(intVar2).get, IntConstant(2))
+ EQ(GetVarInt(intVar2).get, IntConstant(2)).toSigmaProp
)
test("Tup3", env, ext,
"""{ val p = (getVar[Int](intVar1).get, getVar[Int](intVar2).get)
| val res = p._1 + p._2
| res == 3 }""".stripMargin,
{
- EQ(Plus(GetVarInt(intVar1).get, GetVarInt(intVar2).get), IntConstant(3))
+ EQ(Plus(GetVarInt(intVar1).get, GetVarInt(intVar2).get), IntConstant(3)).toSigmaProp
}
)
}
property("Tuple as Collection operations") {
- test("TupCol1", env, ext,
- """{ val p = (getVar[Int](intVar1).get, getVar[Byte](byteVar2).get)
- | p.size == 2 }""".stripMargin,
- {
- TrueLeaf
- }, true)
- test("TupCol2", env, ext,
- """{ val p = (getVar[Int](intVar1).get, getVar[Byte](byteVar2).get)
- | p(0) == 1 }""".stripMargin,
- {
- EQ(GetVarInt(intVar1).get, IntConstant(1))
- })
+// test("TupColl1", env, ext,
+// """{ val p = (getVar[Int](intVar1).get, getVar[Byte](byteVar2).get)
+// | p.size == 2 }""".stripMargin,
+// {
+// TrueLeaf
+// }, true)
+// test("TupColl2", env, ext,
+// """{ val p = (getVar[Int](intVar1).get, getVar[Byte](byteVar2).get)
+// | p(0) == 1 }""".stripMargin,
+// {
+// EQ(GetVarInt(intVar1).get, IntConstant(1))
+// })
val dataVar = (lastExtVar + 1).toByte
- val Cols = IR.sigmaDslBuilderValue.Cols
+ val Colls = IR.sigmaDslBuilderValue.Colls
val data = Array(Array[Any](Array[Byte](1,2,3), 10L))
val env1 = env + ("dataVar" -> dataVar)
- val dataType = SCollection(STuple(SCollection(SByte), SLong))
+ val dataType = SCollection(STuple(SByteArray, SLong))
val ext1 = ext :+ ((dataVar, Constant[SCollection[STuple]](data, dataType)))
- test("TupCol3", env1, ext1,
- """{
- | val data = getVar[Coll[(Coll[Byte], Long)]](dataVar).get
- | data.size == 1
- |}""".stripMargin,
- {
- val data = GetVar(dataVar, dataType).get
- EQ(SizeOf(data), IntConstant(1))
- }
- )
- test("TupCol4", env1, ext1,
- """{
- | val data = getVar[Coll[(Coll[Byte], Long)]](dataVar).get
- | data.exists({ (p: (Coll[Byte], Long)) => p._2 == 10L })
- |}""".stripMargin,
- {
- val data = GetVar(dataVar, dataType).get
- Exists(data,
- FuncValue(
- Vector((1, STuple(SByteArray, SLong))),
- EQ(SelectField(ValUse(1, STuple(SByteArray, SLong)), 2), LongConstant(10)))
- )
- }
- )
- test("TupCol5", env1, ext1,
+// test("TupColl3", env1, ext1,
+// """{
+// | val data = getVar[Coll[(Coll[Byte], Long)]](dataVar).get
+// | data.size == 1
+// |}""".stripMargin,
+// {
+// val data = GetVar(dataVar, dataType).get
+// EQ(SizeOf(data), IntConstant(1))
+// }
+// )
+// test("TupColl4", env1, ext1,
+// """{
+// | val data = getVar[Coll[(Coll[Byte], Long)]](dataVar).get
+// | data.exists({ (p: (Coll[Byte], Long)) => p._2 == 10L })
+// |}""".stripMargin,
+// {
+// val data = GetVar(dataVar, dataType).get
+// Exists(data,
+// FuncValue(
+// Vector((1, STuple(SByteArray, SLong))),
+// EQ(SelectField(ValUse(1, STuple(SByteArray, SLong)), 2), LongConstant(10)))
+// )
+// }
+// )
+ test("TupColl5", env1, ext1,
"""{
| val data = getVar[Coll[(Coll[Byte], Long)]](dataVar).get
| data.forall({ (p: (Coll[Byte], Long)) => p._1.size > 0 })
@@ -290,17 +298,17 @@ class BasicOpsSpecification extends SigmaTestingCommons {
FuncValue(
Vector((1, STuple(SByteArray, SLong))),
GT(SizeOf(SelectField(ValUse(1, STuple(SByteArray, SLong)), 1).asCollection[SByte.type]), IntConstant(0)))
- )
+ ).toSigmaProp
}
)
- test("TupCol6", env1, ext1,
+ test("TupColl6", env1, ext1,
"""{
| val data = getVar[Coll[(Coll[Byte], Long)]](dataVar).get
| data.map({ (p: (Coll[Byte], Long)) => (p._2, p._1)}).size == 1
|}""".stripMargin,
{
val data = GetVar(dataVar, dataType).get
- EQ(SizeOf(data), IntConstant(1))
+ EQ(SizeOf(data), IntConstant(1)).toSigmaProp
}
)
@@ -317,42 +325,58 @@ class BasicOpsSpecification extends SigmaTestingCommons {
property("GetVar") {
test("GetVar1", env, ext,
"{ getVar[Int](intVar2).get == 2 }",
- EQ(GetVarInt(intVar2).get, IntConstant(2))
+ EQ(GetVarInt(intVar2).get, IntConstant(2)).toSigmaProp
)
// wrong type
assertExceptionThrown(
test("GetVar2", env, ext,
"{ getVar[Byte](intVar2).isDefined }",
- GetVarByte(intVar2).isDefined,
+ GetVarByte(intVar2).isDefined.toSigmaProp,
true
),
- _.getCause.isInstanceOf[InvalidType])
+ rootCause(_).isInstanceOf[InvalidType])
}
property("ExtractRegisterAs") {
- test("Extract1", env, ext,
- "{ SELF.R4[SigmaProp].get.isProven }",
- ExtractRegisterAs[SSigmaProp.type](Self, reg1).get,
- true
- )
+// test("Extract1", env, ext,
+// "{ SELF.R4[SigmaProp].get.isProven }",
+// ExtractRegisterAs[SSigmaProp.type](Self, reg1).get,
+// true
+// )
// wrong type
assertExceptionThrown(
test("Extract2", env, ext,
- "{ SELF.R4[Int].isDefined }",
- ExtractRegisterAs[SInt.type](Self, reg1).isDefined,
+ "{ SELF.R4[Long].isDefined }",
+ ExtractRegisterAs[SLong.type](Self, reg1).isDefined.toSigmaProp,
true
),
- _.getCause.isInstanceOf[InvalidType])
+ rootCause(_).isInstanceOf[InvalidType])
+ }
+
+ // TODO related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/416
+ ignore("Box.getReg") {
+ test("Extract1", env, ext,
+ "{ SELF.getReg[Int]( (getVar[Int](intVar1).get + 4).toByte ).get == 1}",
+ BoolToSigmaProp(
+ EQ(
+ MethodCall(Self, SBox.getRegMethod,
+ IndexedSeq(Plus(GetVarInt(1).get, IntConstant(4))), Map(SBox.tT -> SInt)
+ ).asInstanceOf[Value[SOption[SType]]].get,
+ IntConstant(1)
+ )
+ ),
+ true
+ )
}
property("OptionGet success (SomeValue)") {
test("Opt1", env, ext,
"{ getVar[Int](intVar2).get == 2 }",
- EQ(GetVarInt(intVar2).get, IntConstant(2))
+ EQ(GetVarInt(intVar2).get, IntConstant(2)).toSigmaProp
)
test("Opt2", env, ext,
"{ val v = getVar[Int](intVar2); v.get == 2 }",
- EQ(GetVarInt(intVar2).get, IntConstant(2))
+ EQ(GetVarInt(intVar2).get, IntConstant(2)).toSigmaProp
)
}
@@ -360,39 +384,39 @@ class BasicOpsSpecification extends SigmaTestingCommons {
assertExceptionThrown(
test("OptGet1", env, ext,
"{ getVar[Int](99).get == 2 }",
- EQ(GetVarInt(99).get, IntConstant(2))
+ EQ(GetVarInt(99).get, IntConstant(2)).toSigmaProp
),
- _.getCause.getCause.isInstanceOf[InvocationTargetException])
+ rootCause(_).isInstanceOf[NoSuchElementException])
assertExceptionThrown(
test("OptGet2", env, ext,
"{ SELF.R8[SigmaProp].get.propBytes != getVar[SigmaProp](proofVar1).get.propBytes }",
- NEQ(ExtractRegisterAs[SSigmaProp.type](Self, R8).get.propBytes, GetVarSigmaProp(propVar1).get.propBytes),
+ NEQ(ExtractRegisterAs[SSigmaProp.type](Self, R8).get.propBytes, GetVarSigmaProp(propVar1).get.propBytes).toSigmaProp,
true
),
- _.getCause.getCause.isInstanceOf[InvocationTargetException])
+ rootCause(_).isInstanceOf[NoSuchElementException])
}
property("OptionGetOrElse") {
test("OptGet1", env, ext,
"{ SELF.R5[Int].getOrElse(3) == 1 }",
- EQ(ExtractRegisterAs[SInt.type](Self, reg2).getOrElse(IntConstant(3)), IntConstant(1)),
+ EQ(ExtractRegisterAs[SInt.type](Self, reg2).getOrElse(IntConstant(3)), IntConstant(1)).toSigmaProp,
true
)
// register should be empty
test("OptGet2", env, ext,
"{ SELF.R6[Int].getOrElse(3) == 3 }",
- EQ(ExtractRegisterAs(Self, R6, SOption(SInt)).getOrElse(IntConstant(3)), IntConstant(3)),
+ EQ(ExtractRegisterAs(Self, R6, SOption(SInt)).getOrElse(IntConstant(3)), IntConstant(3)).toSigmaProp,
true
)
test("OptGet3", env, ext,
"{ getVar[Int](intVar2).getOrElse(3) == 2 }",
- EQ(GetVarInt(intVar2).getOrElse(IntConstant(3)), IntConstant(2)),
+ EQ(GetVarInt(intVar2).getOrElse(IntConstant(3)), IntConstant(2)).toSigmaProp,
true
)
// there should be no variable with this id
test("OptGet4", env, ext,
"{ getVar[Int](99).getOrElse(3) == 3 }",
- EQ(GetVarInt(99).getOrElse(IntConstant(3)), IntConstant(3)),
+ EQ(GetVarInt(99).getOrElse(IntConstant(3)), IntConstant(3)).toSigmaProp,
true
)
}
@@ -400,25 +424,25 @@ class BasicOpsSpecification extends SigmaTestingCommons {
property("OptionIsDefined") {
test("Def1", env, ext,
"{ SELF.R4[SigmaProp].isDefined }",
- ExtractRegisterAs[SSigmaProp.type](Self, reg1).isDefined,
+ ExtractRegisterAs[SSigmaProp.type](Self, reg1).isDefined.toSigmaProp,
true
)
// no value
test("Def2", env, ext,
"{ SELF.R8[Int].isDefined == false }",
- EQ(ExtractRegisterAs[SInt.type](Self, R8).isDefined, FalseLeaf),
+ LogicalNot(ExtractRegisterAs[SInt.type](Self, R8).isDefined).toSigmaProp,
true
)
test("Def3", env, ext,
"{ getVar[Int](intVar2).isDefined }",
- GetVarInt(intVar2).isDefined,
+ GetVarInt(intVar2).isDefined.toSigmaProp,
true
)
// there should be no variable with this id
test("Def4", env, ext,
"{ getVar[Int](99).isDefined == false }",
- EQ(GetVarInt(99).isDefined, FalseLeaf),
+ LogicalNot(GetVarInt(99).isDefined).toSigmaProp,
true
)
}
@@ -426,7 +450,7 @@ class BasicOpsSpecification extends SigmaTestingCommons {
property("ByteArrayToBigInt: big int should always be positive") {
test("BATBI1", env, ext,
"{ byteArrayToBigInt(Coll[Byte](-1.toByte)) > 0 }",
- GT(ByteArrayToBigInt(ConcreteCollection(ByteConstant(-1))), BigIntConstant(0)),
+ GT(ByteArrayToBigInt(ConcreteCollection(ByteConstant(-1))), BigIntConstant(0)).toSigmaProp,
onlyPositive = true
)
}
@@ -437,7 +461,7 @@ class BasicOpsSpecification extends SigmaTestingCommons {
assertExceptionThrown(
test("BATBI1", env, ext,
s"{ byteArrayToBigInt(Coll[Byte]($itemsStr)) > 0 }",
- GT(ByteArrayToBigInt(ConcreteCollection(bytes.map(ByteConstant(_)))), BigIntConstant(0)),
+ GT(ByteArrayToBigInt(ConcreteCollection(bytes.map(ByteConstant(_)))), BigIntConstant(0)).toSigmaProp,
onlyPositive = true
),
_.getCause.isInstanceOf[RuntimeException]
@@ -447,13 +471,13 @@ class BasicOpsSpecification extends SigmaTestingCommons {
property("ExtractCreationInfo") {
test("Info1", env, ext,
"SELF.creationInfo._1 == 5",
- EQ(SelectField(ExtractCreationInfo(Self),1),IntConstant(5)),
+ EQ(SelectField(ExtractCreationInfo(Self),1),IntConstant(5)).toSigmaProp,
true
)
// suppose to be tx.id + box index
test("Info2", env, ext,
"SELF.creationInfo._2.size == 34",
- EQ(SizeOf(SelectField(ExtractCreationInfo(Self),2).asValue[SByteArray]),IntConstant(34)),
+ EQ(SizeOf(SelectField(ExtractCreationInfo(Self),2).asValue[SByteArray]),IntConstant(34)).toSigmaProp,
true
)
}
@@ -474,12 +498,12 @@ class BasicOpsSpecification extends SigmaTestingCommons {
property("numeric cast") {
test("downcast", env, ext,
"{ getVar[Int](intVar2).get.toByte == 2.toByte }",
- EQ(Downcast(GetVarInt(2).get, SByte), ByteConstant(2)),
+ EQ(Downcast(GetVarInt(2).get, SByte), ByteConstant(2)).toSigmaProp,
onlyPositive = true
)
test("upcast", env, ext,
"{ getVar[Int](intVar2).get.toLong == 2L }",
- EQ(Upcast(GetVarInt(2).get, SLong), LongConstant(2)),
+ EQ(Upcast(GetVarInt(2).get, SLong), LongConstant(2)).toSigmaProp,
onlyPositive = true
)
}
@@ -488,7 +512,84 @@ class BasicOpsSpecification extends SigmaTestingCommons {
val byteArrayVar1Value = ByteArrayConstant(Array[Byte](1.toByte, 2.toByte))
test("EQArrayCollection", env + ("byteArrayVar1" -> byteArrayVar1Value), ext,
"byteArrayVar1 == Coll[Byte](1.toByte, 2.toByte)",
- EQ(byteArrayVar1Value, ConcreteCollection(Vector(ByteConstant(1), ByteConstant(2)), SByte)),
+ EQ(byteArrayVar1Value, ConcreteCollection(Vector(ByteConstant(1), ByteConstant(2)), SByte)).toSigmaProp,
+ true
+ )
+ }
+
+ property("user defined function") {
+ test("function", env, ext,
+ "{ def inc(i: Int) = i + 1; inc(2) == 3 }",
+ EQ(
+ Apply(
+ FuncValue(Vector((1, SInt)), Plus(ValUse(1, SInt), IntConstant(1))),
+ Vector(IntConstant(2))
+ ),
+ IntConstant(3)).toSigmaProp,
+ )
+ }
+
+ property("missing variable in env buildValue error") {
+ test("missingVar", env, ext,
+ """
+ |OUTPUTS.forall({(out:Box) =>
+ | out.R5[Int].get >= HEIGHT + 10 &&
+ | blake2b256(out.propositionBytes) != Coll[Byte](1.toByte)
+ |})
+ """.stripMargin,
+ ForAll(Outputs, FuncValue(Vector((1,SBox)),
+ BinAnd(
+ GE(ExtractRegisterAs(ValUse(1,SBox), ErgoBox.R5, SOption(SInt)).get, Plus(Height, IntConstant(10))),
+ NEQ(CalcBlake2b256(ExtractScriptBytes(ValUse(1,SBox))), ConcreteCollection(Vector(ByteConstant(1.toByte)), SByte))
+ ))).toSigmaProp,
+ true
+ )
+ }
+
+ property("Nested logical ops 1") {
+ test("nestedLogic1", env, ext,
+ """{
+ | val c = OUTPUTS(0).R4[Int].get
+ | val d = OUTPUTS(0).R5[Int].get
+ |
+ | OUTPUTS.size == 2 &&
+ | OUTPUTS(0).value == SELF.value &&
+ | OUTPUTS(1).value == SELF.value
+ |} == false""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ property("Nested logical ops 2") {
+ test("nestedLogic2", env, ext,
+ """{
+ | val c = OUTPUTS(0).R4[Int].get
+ | val d = OUTPUTS(0).R5[Int].get
+ |
+ | OUTPUTS.size == 1 &&
+ | OUTPUTS(0).value == SELF.value &&
+ | {{ c != d || d == c } && { true || false } }
+ |} """.stripMargin,
+ null,
+ true
+ )
+ }
+
+ //TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/425
+ ignore("Option.map") {
+ test("Option.map", env, ext,
+ "getVar[Int](intVar1).map({(i: Int) => i + 1}).get == 2",
+ null,
+ true
+ )
+ }
+
+ //TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/425
+ ignore("Option.filter") {
+ test("Option.filter", env, ext,
+ "getVar[Int](intVar1).filter({(i: Int) => i > 0}).get == 1",
+ null,
true
)
}
diff --git a/src/test/scala/sigmastate/utxo/BlockchainSimulationSpecification.scala b/src/test/scala/sigmastate/utxo/BlockchainSimulationSpecification.scala
index d005d5c697..eabd8e2b00 100644
--- a/src/test/scala/sigmastate/utxo/BlockchainSimulationSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/BlockchainSimulationSpecification.scala
@@ -3,8 +3,6 @@ package sigmastate.utxo
import java.io.{FileWriter, File}
import org.ergoplatform
-import org.ergoplatform.ErgoLikeContext.Metadata
-import org.ergoplatform.ErgoLikeContext.Metadata._
import org.ergoplatform._
import org.scalacheck.Gen
import org.scalatest.prop.{PropertyChecks, GeneratorDrivenPropertyChecks}
@@ -14,12 +12,11 @@ import scorex.crypto.authds.{ADDigest, ADKey, ADValue}
import scorex.crypto.hash.{Digest32, Blake2b256}
import scorex.util._
import sigmastate.Values.LongConstant
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
-import sigmastate.helpers.{SigmaTestingCommons}
+import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons, ErgoTransactionValidator}
import sigmastate.interpreter.ContextExtension
import sigmastate.eval.IRContext
import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
-import sigmastate.{GE, AvlTreeData}
+import sigmastate.{GE, AvlTreeData, AvlTreeFlags}
import scala.annotation.tailrec
import scala.collection.concurrent.TrieMap
@@ -48,7 +45,7 @@ class BlockchainSimulationSpecification extends SigmaTestingCommons {
box,
ContextExtension.empty)
val env = emptyEnv + (ScriptNameProp -> s"height_${state.state.currentHeight}_prove")
- val proverResult = miner.prove(env, box.proposition, context, tx.messageToSign).get
+ val proverResult = miner.prove(env, box.ergoTree, context, tx.messageToSign).get
tx.toSigned(IndexedSeq(proverResult))
}.toIndexedSeq.ensuring(_.nonEmpty, s"Failed to create txs from boxes $boxesToSpend at height $height")
@@ -205,7 +202,7 @@ object BlockchainSimulationSpecification {
assert(blockCost <= maxCost, s"Block cost $blockCost exceeds limit $maxCost")
boxesReader.applyBlock(block)
- val newState = BlockchainState(height, state.lastBlockUtxoRoot.copy(startingDigest = boxesReader.digest))
+ val newState = BlockchainState(height, state.lastBlockUtxoRoot.copy(digest = boxesReader.digest))
ValidationState(newState, boxesReader)
}
}
@@ -216,7 +213,7 @@ object BlockchainSimulationSpecification {
val initBlock = Block(
(0 until windowSize).map { i =>
val txId = hash.hash(i.toString.getBytes ++ scala.util.Random.nextString(12).getBytes).toModifierId
- val boxes = (1 to 50).map(_ => ErgoBox(10, GE(Height, LongConstant(i)), 0, Seq(), Map(heightReg -> LongConstant(i)), txId))
+ val boxes = (1 to 50).map(_ => ErgoBox(10, GE(Height, LongConstant(i)).toSigmaProp, 0, Seq(), Map(heightReg -> LongConstant(i)), txId))
ergoplatform.ErgoLikeTransaction(IndexedSeq(), boxes)
},
ErgoLikeContext.dummyPubkey
@@ -227,7 +224,7 @@ object BlockchainSimulationSpecification {
val prover = new BatchProver(keySize, None)
val digest = prover.digest
- val utxoRoot = AvlTreeData(digest, keySize)
+ val utxoRoot = AvlTreeData(digest, AvlTreeFlags.AllOperationsAllowed, keySize)
val bs = BlockchainState(currentHeight = -2, utxoRoot)
diff --git a/src/test/scala/sigmastate/utxo/CollectionOperationsSpecification.scala b/src/test/scala/sigmastate/utxo/CollectionOperationsSpecification.scala
index 327ee75b51..e2af51afd3 100644
--- a/src/test/scala/sigmastate/utxo/CollectionOperationsSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/CollectionOperationsSpecification.scala
@@ -1,40 +1,45 @@
package sigmastate.utxo
import org.ergoplatform
+import org.ergoplatform.ErgoScriptPredef.TrueProp
import sigmastate.Values._
import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.lang.Terms._
import org.ergoplatform._
-import sigmastate.interpreter.Interpreter.{emptyEnv, ScriptNameProp}
+import sigmastate.SCollection._
+import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
import sigmastate.serialization.OpCodes._
class CollectionOperationsSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
+ implicit lazy val IR: TestingIRContext = new TestingIRContext
private val reg1 = ErgoBox.nonMandatoryRegisters.head
private def context(boxesToSpend: IndexedSeq[ErgoBox] = IndexedSeq(),
outputs: IndexedSeq[ErgoBox]): ErgoLikeContext =
- ergoplatform.ErgoLikeContext(
- currentHeight = 50,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = boxesToSpend,
- spendingTransaction = ErgoLikeTransaction(IndexedSeq(), outputs),
- self = null)
+ {
+ // TODO this means the context is not totally correct
+ val (selfBox, toSpend) = if (boxesToSpend.isEmpty) (fakeSelf, IndexedSeq(fakeSelf)) else (boxesToSpend(0), boxesToSpend)
+ ergoplatform.ErgoLikeContext(
+ currentHeight = 50,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = toSpend,
+ spendingTransaction = createTransaction(outputs),
+ self = selfBox)
+ }
private def assertProof(code: String,
- expectedComp: Value[SType],
+ expectedComp: SigmaPropValue,
outputBoxValues: IndexedSeq[Long],
boxesToSpendValues: IndexedSeq[Long] = IndexedSeq()) = {
- val (prover, verifier, prop, ctx) = buildEnv(code, expectedComp, outputBoxValues,
- boxesToSpendValues)
+ val (prover, verifier, prop, ctx) = buildEnv(code, expectedComp, outputBoxValues, boxesToSpendValues)
val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).fold(t => throw t, x => x)
verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, pr, fakeMessage).get._1 shouldBe true
}
private def assertProverFail(code: String,
- expectedComp: Value[SType],
+ expectedComp: SigmaPropValue,
outputBoxValues: IndexedSeq[Long],
boxesToSpendValues: IndexedSeq[Long] = IndexedSeq()) = {
val (prover, _, prop, ctx) = buildEnv(code, expectedComp, outputBoxValues, boxesToSpendValues)
@@ -45,11 +50,11 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
expectedComp: Value[SType],
outputBoxValues: IndexedSeq[Long],
boxesToSpendValues: IndexedSeq[Long]) = {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
- val prop = compileWithCosting(Map(), code).asBoolValue
+ val prop = compile(Map(), code).asBoolValue.toSigmaProp
prop shouldBe expectedComp
val ctx = context(boxesToSpendValues.map(ErgoBox(_, pubkey, 0)),
@@ -58,24 +63,24 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
}
property("exists") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
- val pubkey = prover.dlogSecrets.head.publicImage.isProven
+ val pubkey = prover.dlogSecrets.head.publicImage.toSigmaProp
- val prop = compileWithCosting(Map(), "OUTPUTS.exists({ (box: Box) => box.value + 5 > 10 })").asBoolValue
+ val prop = compile(Map(), "OUTPUTS.exists({ (box: Box) => box.value + 5 > 10 })").asBoolValue.toSigmaProp
val expProp = Exists(Outputs,
FuncValue(Vector((1, SBox)),
GT(Plus(ExtractAmount(ValUse(1, SBox)), LongConstant(5)), LongConstant(10)))
- )
+ ).toSigmaProp
prop shouldBe expProp
val newBox1 = ErgoBox(16, pubkey, 0)
val newBox2 = ErgoBox(15, pubkey, 0)
val newBoxes = IndexedSeq(newBox1, newBox2)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -91,22 +96,22 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
}
property("forall") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
- val prop = compileWithCosting(Map(), "OUTPUTS.forall({ (box: Box) => box.value == 10 })").asBoolValue
+ val prop = compile(Map(), "OUTPUTS.forall({ (box: Box) => box.value == 10 })").asBoolValue.toSigmaProp
val propTree = ForAll(Outputs,
FuncValue(Vector((1, SBox)), EQ(ExtractAmount(ValUse(1, SBox)), LongConstant(10)))
- )
+ ).toSigmaProp
prop shouldBe propTree
val newBox1 = ErgoBox(10, pubkey, 0)
val newBox2 = ErgoBox(10, pubkey, 0)
val newBoxes = IndexedSeq(newBox1, newBox2)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -123,21 +128,21 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
property("forall - fail") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
- val prop = compileWithCosting(Map(), "OUTPUTS.forall({ (box: Box) => box.value == 10 })").asBoolValue
+ val prop = compile(Map(), "OUTPUTS.forall({ (box: Box) => box.value == 10 })").asBoolValue.toSigmaProp
val propTree = ForAll(Outputs,
FuncValue(Vector((1, SBox)), EQ(ExtractAmount(ValUse(1, SBox)), LongConstant(10)))
- )
+ ).toSigmaProp
prop shouldBe propTree
val newBox1 = ErgoBox(10, pubkey, 0)
val newBox2 = ErgoBox(11, pubkey, 0)
val newBoxes = IndexedSeq(newBox1, newBox2)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -151,15 +156,15 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
}
property("counter") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
- val pubkey = prover.dlogSecrets.head.publicImage.isProven
+ val pubkey = prover.dlogSecrets.head.publicImage.toSigmaProp
- val prop = compileWithCosting(Map(),
+ val prop = compile(Map(),
"""OUTPUTS.exists { (box: Box) =>
| box.R4[Long].get == SELF.R4[Long].get + 1
- }""".stripMargin).asBoolValue
+ }""".stripMargin).asBoolValue.toSigmaProp
val propTree = Exists(Outputs,
FuncValue(
@@ -168,16 +173,16 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
ExtractRegisterAs[SLong.type](ValUse(1, SBox), reg1).get,
Plus(ExtractRegisterAs[SLong.type](Self, reg1).get, LongConstant(1)))
)
- )
+ ).toSigmaProp
prop shouldBe propTree
val newBox1 = ErgoBox(10, pubkey, 0, Seq(), Map(reg1 -> LongConstant(3)))
val newBox2 = ErgoBox(10, pubkey, 0, Seq(), Map(reg1 -> LongConstant(6)))
val newBoxes = IndexedSeq(newBox1, newBox2)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
- val s = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> LongConstant(5)))
+ val s = ErgoBox(20, TrueProp, 0, Seq(), Map(reg1 -> LongConstant(5)))
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -192,15 +197,15 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
}
property("counter - no register in outputs") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
- val prop = compileWithCosting(Map(),
+ val prop = compile(Map(),
"""OUTPUTS.exists { (box: Box) =>
| box.R4[Long].getOrElse(0L) == SELF.R4[Long].get + 1
- }""".stripMargin).asBoolValue
+ }""".stripMargin).asBoolValue.toSigmaProp
val propTree = Exists(Outputs,
FuncValue(
@@ -210,7 +215,7 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
Plus(ExtractRegisterAs[SLong.type](Self, reg1).get, LongConstant(1))
)
)
- )
+ ).toSigmaProp
prop shouldBe propTree
@@ -218,9 +223,9 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
val newBox2 = ErgoBox(10, pubkey, 0, Seq(), Map(reg1 -> LongConstant(6)))
val newBoxes = IndexedSeq(newBox1, newBox2)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
- val s = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> LongConstant(5)))
+ val s = ErgoBox(20, TrueProp, 0, Seq(), Map(reg1 -> LongConstant(5)))
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -235,13 +240,13 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
}
property("sizeof - num of outputs = num of inputs + 1") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
val env = Map("pubkey" -> pubkey)
- val prop = compileWithCosting(env, """pubkey && OUTPUTS.size == INPUTS.size + 1""").asBoolValue
+ val prop = compile(env, """pubkey && OUTPUTS.size == INPUTS.size + 1""").asSigmaProp
val propTree = SigmaAnd(pubkey, BoolToSigmaProp(EQ(SizeOf(Outputs), Plus(SizeOf(Inputs), IntConstant(1)))))
prop shouldBe propTree
@@ -249,7 +254,7 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
val newBox2 = ErgoBox(10, pubkey, 0)
val newBoxes = IndexedSeq(newBox1, newBox2)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val s = ErgoBox(21, pubkey, 0)
@@ -265,7 +270,7 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
verifier.verify(prop, ctx, pr, fakeMessage)
- val fProp = AND(pubkey, EQ(SizeOf(Outputs), SizeOf(Inputs)))
+ val fProp = SigmaAnd(pubkey, EQ(SizeOf(Outputs), SizeOf(Inputs)))
prover.prove(fProp, ctx, fakeMessage).isSuccess shouldBe false
}
@@ -275,7 +280,7 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
val expectedPropTree = ForAll(
Slice(Outputs, IntConstant(1), SizeOf(Outputs)),
FuncValue(Vector((1, SBox)), EQ(ExtractAmount(ValUse(1, SBox)), LongConstant(10)))
- )
+ ).toSigmaProp
assertProof(code, expectedPropTree, outputBoxValues)
}
@@ -350,15 +355,15 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
"""OUTPUTS
|.map({ (box: Box) => box.value })
|.fold(true, { (acc: Boolean, val: Long) => acc && (val < 0) }) == false""".stripMargin
- val expectedPropTree = EQ(
+ val expectedPropTree = LogicalNot(
Fold(
MapCollection(Outputs, FuncValue(Vector((1, SBox)), ExtractAmount(ValUse(1, SBox)))),
TrueLeaf,
FuncValue(Vector((1, STuple(SBoolean, SLong))),
BinAnd(
SelectField(ValUse(1, STuple(SBoolean, SLong)), 1).asBoolValue,
- LT(SelectField(ValUse(1, STuple(SBoolean, SLong)), 2), LongConstant(0))))),
- FalseLeaf)
+ LT(SelectField(ValUse(1, STuple(SBoolean, SLong)), 2), LongConstant(0)))))
+ )
assertProof(code, expectedPropTree, outputBoxValues)
}
@@ -379,7 +384,7 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
val code =
"""{
| val indexCollection = Coll(0, 1, 2, 3, 4, 5)
- | val elementRule = {(index: Int) =>
+ | def elementRule(index: Int) = {
| val boundaryIndex = if (index == 0) 5 else (index - 1)
| boundaryIndex >= 0 && boundaryIndex <= 5
| }
@@ -434,4 +439,161 @@ class CollectionOperationsSpecification extends SigmaTestingCommons {
assertProof(code, expectedPropTree, outputBoxValues)
}
+
+ //TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/423
+ // TODO costing rule in CollCoster
+ ignore("flatMap") {
+ assertProof("OUTPUTS.flatMap({ (out: Box) => out.propositionBytes })(0) == 0.toByte",
+ EQ(
+ ByIndex(
+ MethodCall(Outputs,
+ FlatMapMethod.withConcreteTypes(Map(tIV -> SBox, tOV -> SByte)),
+ Vector(FuncValue(1, SBox,
+ ExtractScriptBytes(ValUse(1, SBox))
+ )),
+ Map()
+ ).asCollection[SByte.type],
+ IntConstant(0)
+ ),
+ ByteConstant(0)
+ ),
+ IndexedSeq(1L, 1L))
+ }
+
+ property("indexOf") {
+ assertProof("OUTPUTS.map({ (b: Box) => b.value }).indexOf(1L, 0) == 0",
+ EQ(
+ MethodCall(MapCollection(Outputs, FuncValue(Vector((1, SBox)), ExtractAmount(ValUse(1, SBox)))),
+ IndexOfMethod.withConcreteTypes(Map(tIV -> SLong)),
+ Vector(LongConstant(1), IntConstant(0)),
+ Map()),
+ IntConstant(0)
+ ),
+ IndexedSeq(1L, 1L))
+ }
+
+ //TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/421
+ property("indices") {
+ assertProof("OUTPUTS.indices == Coll(0, 1)",
+ EQ(MethodCall(Outputs, IndicesMethod.withConcreteTypes(Map(tIV -> SBox)), Vector(), Map()), ConcreteCollection(IntConstant(0), IntConstant(1))),
+ IndexedSeq(1L, 1L))
+ }
+
+ property("segmentLength") {
+ assertProof("OUTPUTS.segmentLength({ (out: Box) => out.value == 1L }, 0) == 1",
+ EQ(
+ MethodCall(Outputs,
+ SegmentLengthMethod.withConcreteTypes(Map(tIV -> SBox)),
+ Vector(
+ FuncValue(Vector((1, SBox)),EQ(ExtractAmount(ValUse(1, SBox)), LongConstant(1))),
+ IntConstant(0)
+ ),
+ Map()),
+ IntConstant(1)),
+ IndexedSeq(1L, 2L))
+ }
+
+ property("indexWhere") {
+ assertProof("OUTPUTS.indexWhere({ (out: Box) => out.value == 1L }, 0) == 0",
+ EQ(
+ MethodCall(Outputs,
+ IndexWhereMethod.withConcreteTypes(Map(tIV -> SBox)),
+ Vector(
+ FuncValue(Vector((1, SBox)), EQ(ExtractAmount(ValUse(1, SBox)), LongConstant(1))),
+ IntConstant(0)
+ ),
+ Map()),
+ IntConstant(0)),
+ IndexedSeq(1L, 2L))
+ }
+
+ property("lastIndexWhere") {
+ assertProof("OUTPUTS.lastIndexWhere({ (out: Box) => out.value == 1L }, 1) == 0",
+ EQ(
+ MethodCall(Outputs,
+ LastIndexWhereMethod.withConcreteTypes(Map(tIV -> SBox)),
+ Vector(
+ FuncValue(Vector((1, SBox)), EQ(ExtractAmount(ValUse(1, SBox)), LongConstant(1))),
+ IntConstant(1)
+ ),
+ Map()),
+ IntConstant(0)),
+ IndexedSeq(1L, 2L))
+ }
+
+ property("zip") {
+ assertProof("OUTPUTS.zip(Coll(1,2)).size == 2",
+ EQ(
+ SizeOf(MethodCall(Outputs,
+ SCollection.ZipMethod.withConcreteTypes(Map(SCollection.tIV -> SBox, SCollection.tOV -> SInt)),
+ Vector(
+ ConcreteCollection(IntConstant(1), IntConstant(2))
+ ),
+ Map()).asCollection[STuple]),
+ IntConstant(2)),
+ IndexedSeq(1L, 2L))
+ }
+
+ property("partition") {
+ assertProof("OUTPUTS.partition({ (box: Box) => box.value < 2L})._1.size == 1",
+ EQ(
+ SizeOf(
+ SelectField(
+ MethodCall(Outputs,
+ PartitionMethod.withConcreteTypes(Map(tIV -> SBox)),
+ Vector(
+ FuncValue(Vector((1, SBox)), LT(ExtractAmount(ValUse(1, SBox)), LongConstant(2)))
+ ),
+ Map()).asValue[STuple],
+ 1
+ ).asCollection[SType]
+ ),
+ IntConstant(1)),
+ IndexedSeq(1L, 2L))
+ }
+
+ property("patch") {
+ assertProof("OUTPUTS.map({ (b: Box) => b.value }).patch(0, Coll(3L), 1)(0) == 3L",
+ EQ(
+ ByIndex(
+ MethodCall(
+ MapCollection(Outputs, FuncValue(Vector((1, SBox)), ExtractAmount(ValUse(1, SBox)))),
+ PatchMethod.withConcreteTypes(Map(tIV -> SLong)),
+ Vector(IntConstant(0), ConcreteCollection(LongConstant(3)), IntConstant(1)),
+ Map()).asCollection[SType],
+ IntConstant(0)
+ ),
+ LongConstant(3)),
+ IndexedSeq(1L, 2L))
+ }
+
+ property("updated") {
+ assertProof("OUTPUTS.map({ (b: Box) => b.value }).updated(0, 3L)(0) == 3L",
+ EQ(
+ ByIndex(
+ MethodCall(
+ MapCollection(Outputs, FuncValue(Vector((1, SBox)), ExtractAmount(ValUse(1, SBox)))),
+ UpdatedMethod.withConcreteTypes(Map(tIV -> SLong)),
+ Vector(IntConstant(0), LongConstant(3)),
+ Map()).asCollection[SType],
+ IntConstant(0)
+ ),
+ LongConstant(3)),
+ IndexedSeq(1L, 2L))
+ }
+
+ property("updateMany") {
+ assertProof("OUTPUTS.map({ (b: Box) => b.value }).updateMany(Coll(0), Coll(3L))(0) == 3L",
+ EQ(
+ ByIndex(
+ MethodCall(
+ MapCollection(Outputs, FuncValue(Vector((1, SBox)), ExtractAmount(ValUse(1, SBox)))),
+ UpdateManyMethod.withConcreteTypes(Map(tIV -> SLong)),
+ Vector(ConcreteCollection(IntConstant(0)), ConcreteCollection(LongConstant(3))),
+ Map()).asCollection[SType],
+ IntConstant(0)
+ ),
+ LongConstant(3)),
+ IndexedSeq(1L, 2L))
+ }
}
diff --git a/src/test/scala/sigmastate/utxo/ComplexSigSpecification.scala b/src/test/scala/sigmastate/utxo/ComplexSigSpecification.scala
index c336f5173d..3977232709 100644
--- a/src/test/scala/sigmastate/utxo/ComplexSigSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/ComplexSigSpecification.scala
@@ -2,36 +2,36 @@ package sigmastate.utxo
import org.ergoplatform.{ErgoLikeContext, Height}
import org.scalacheck.Gen
-import sigmastate.Values.{IntConstant, LongConstant}
+import sigmastate.Values.IntConstant
import sigmastate._
import sigmastate.lang.Terms._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import scala.util.Random
class ComplexSigSpecification extends SigmaTestingCommons {
implicit lazy val IR = new TestingIRContext
- private def proverGen: Gen[ErgoLikeTestProvingInterpreter] = for {
+ private def proverGen: Gen[ContextEnrichingTestProvingInterpreter] = for {
_ <- Gen.const(1)
- } yield new ErgoLikeTestProvingInterpreter()
+ } yield new ContextEnrichingTestProvingInterpreter()
- private def proversGen(min: Int, max: Int): Gen[Seq[ErgoLikeTestProvingInterpreter]] =
+ private def proversGen(min: Int, max: Int): Gen[Seq[ContextEnrichingTestProvingInterpreter]] =
Gen.listOfN(Gen.chooseNum(min, max).sample.get, proverGen)
/**
* Whether A or B, or both are able to sign a transaction
*/
property("simplest linear-sized ring signature (1-out-of-2 OR)") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkeyA = proverA.dlogSecrets.head.publicImage
val pubkeyB = proverB.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB)
- val compiledProp = compileWithCosting(env, """pubkeyA || pubkeyB""").asBoolValue
+ val compiledProp = compile(env, """pubkeyA || pubkeyB""").asSigmaProp
val prop = SigmaOr(pubkeyA, pubkeyB)
compiledProp shouldBe prop
@@ -54,9 +54,9 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("simplest linear-sized ring signature (1-out-of-3 OR), with anyOf syntax") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkeyA = proverA.dlogSecrets.head.publicImage
@@ -64,7 +64,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyC = proverC.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC)
- val compiledProp = compileWithCosting(env, """anyOf(Coll(pubkeyA, pubkeyB, pubkeyC))""").asBoolValue
+ val compiledProp = compile(env, """anyOf(Coll(pubkeyA, pubkeyB, pubkeyC))""").asSigmaProp
val prop = SigmaOr(pubkeyA, pubkeyB, pubkeyC)
compiledProp shouldBe prop
@@ -88,9 +88,9 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("simplest linear-sized ring signature (1-out-of-3 OR), with || syntax") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkeyA = proverA.dlogSecrets.head.publicImage
@@ -98,7 +98,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyC = proverC.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC)
- val compiledProp = compileWithCosting(env, """pubkeyA || pubkeyB || pubkeyC""").asBoolValue
+ val compiledProp = compile(env, """pubkeyA || pubkeyB || pubkeyC""").asSigmaProp
val prop = SigmaOr(SigmaOr(pubkeyA, pubkeyB), pubkeyC)
compiledProp shouldBe prop
@@ -123,7 +123,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
//two secrets are known, nevertheless, one will be simulated
property("simplest linear-sized ring signature (1-out-of-4 OR), all secrets are known") {
- val proverA = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -133,7 +133,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyA4 = proverA.dlogSecrets(3).publicImage
val env = Map("pubkeyA1" -> pubkeyA1, "pubkeyA2" -> pubkeyA2, "pubkeyA3" -> pubkeyA3, "pubkeyA4" -> pubkeyA4)
- val compiledProp = compileWithCosting(env, """anyOf(Coll(pubkeyA1, pubkeyA2, pubkeyA3, pubkeyA4))""").asBoolValue
+ val compiledProp = compile(env, """anyOf(Coll(pubkeyA1, pubkeyA2, pubkeyA3, pubkeyA4))""").asSigmaProp
val prop = SigmaOr(pubkeyA1, pubkeyA2, pubkeyA3, pubkeyA4)
compiledProp shouldBe prop
@@ -151,10 +151,10 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - OR of two ANDs") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
- val proverD = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
+ val proverD = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -164,7 +164,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyD = proverD.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD)
- val compiledProp = compileWithCosting(env, """pubkeyA && pubkeyB || pubkeyC && pubkeyD""").asBoolValue
+ val compiledProp = compile(env, """pubkeyA && pubkeyB || pubkeyC && pubkeyD""").asSigmaProp
val prop = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, pubkeyD))
compiledProp shouldBe prop
@@ -192,10 +192,10 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - OR of AND and OR") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
- val proverD = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
+ val proverD = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -205,7 +205,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyD = proverD.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD)
- val compiledProp = compileWithCosting(env, """pubkeyA && pubkeyB || (pubkeyC || pubkeyD)""").asBoolValue
+ val compiledProp = compile(env, """pubkeyA && pubkeyB || (pubkeyC || pubkeyD)""").asSigmaProp
val prop = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD))
compiledProp shouldBe prop
@@ -233,8 +233,8 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("simple sig scheme - AND of two") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -242,7 +242,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyB = proverB.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB)
- val compiledProp = compileWithCosting(env, """pubkeyA && pubkeyB""").asBoolValue
+ val compiledProp = compile(env, """pubkeyA && pubkeyB""").asSigmaProp
val prop = SigmaAnd(pubkeyA, pubkeyB)
compiledProp shouldBe prop
@@ -264,9 +264,9 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - OR of AND and DLOG") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -275,7 +275,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyC = proverC.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC)
- val compiledProp = compileWithCosting(env, """(pubkeyA && pubkeyB) || pubkeyC""").asBoolValue
+ val compiledProp = compile(env, """(pubkeyA && pubkeyB) || pubkeyC""").asSigmaProp
val prop = SigmaOr(SigmaAnd(pubkeyA, pubkeyB), pubkeyC)
compiledProp shouldBe prop
@@ -302,10 +302,10 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - AND of two ORs") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
- val proverD = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
+ val proverD = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -315,7 +315,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyD = proverD.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD)
- val compiledProp = compileWithCosting(env, """(pubkeyA || pubkeyB) && (pubkeyC || pubkeyD)""").asBoolValue
+ val compiledProp = compile(env, """(pubkeyA || pubkeyB) && (pubkeyC || pubkeyD)""").asSigmaProp
val prop = SigmaAnd(SigmaOr(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD))
compiledProp shouldBe prop
@@ -343,10 +343,10 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - AND of AND and OR") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
- val proverD = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
+ val proverD = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -356,7 +356,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyD = proverD.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD)
- val compiledProp = compileWithCosting(env, """(pubkeyA && pubkeyB) && (pubkeyC || pubkeyD)""").asBoolValue
+ val compiledProp = compile(env, """(pubkeyA && pubkeyB) && (pubkeyC || pubkeyD)""").asSigmaProp
val prop = SigmaAnd(SigmaAnd(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD))
compiledProp shouldBe prop
@@ -387,10 +387,10 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - OR of two ORs") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
- val proverD = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
+ val proverD = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -400,7 +400,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyD = proverD.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC, "pubkeyD" -> pubkeyD)
- val compiledProp = compileWithCosting(env, """(pubkeyA || pubkeyB) || (pubkeyC || pubkeyD)""").asBoolValue
+ val compiledProp = compile(env, """(pubkeyA || pubkeyB) || (pubkeyC || pubkeyD)""").asSigmaProp
val prop = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaOr(pubkeyC, pubkeyD))
compiledProp shouldBe prop
@@ -427,9 +427,9 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - OR w. predicate") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -437,7 +437,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyB = proverB.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB)
- val compiledProp = compileWithCosting(env, """anyOf(Coll(pubkeyA, pubkeyB, HEIGHT > 500))""").asBoolValue
+ val compiledProp = compile(env, """anyOf(Coll(pubkeyA, pubkeyB, HEIGHT > 500))""").asSigmaProp
// rewritten by http://github.com/aslesarenko/sigma/blob/2740b51c86bdf1917f688d4ccdb1a0eae9755e0c/sigma-library/src/main/scala/scalan/SigmaLibrary.scala#L91
val prop = SigmaOr(GT(Height, IntConstant(500)).toSigmaProp, SigmaOr(pubkeyA, pubkeyB))
@@ -468,9 +468,9 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - OR of OR and AND w. predicate, parentheses") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -479,8 +479,8 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyC = proverC.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC)
- val compiledProp = compileWithCosting(env,
- """anyOf(Coll(pubkeyA || pubkeyB, pubkeyC && HEIGHT > 500))""").asBoolValue
+ val compiledProp = compile(env,
+ """anyOf(Coll(pubkeyA || pubkeyB, pubkeyC && HEIGHT > 500))""").asSigmaProp
val prop = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, GT(Height, IntConstant(500)).toSigmaProp))
compiledProp shouldBe prop
@@ -517,9 +517,9 @@ class ComplexSigSpecification extends SigmaTestingCommons {
}
property("complex sig scheme - OR of OR and AND w. predicate, no parentheses") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -528,7 +528,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
val pubkeyC = proverC.dlogSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC)
- val compiledProp = compileWithCosting(env, """pubkeyA || pubkeyB || (pubkeyC && HEIGHT > 500)""").asBoolValue
+ val compiledProp = compile(env, """pubkeyA || pubkeyB || (pubkeyC && HEIGHT > 500)""").asSigmaProp
val prop = SigmaOr(SigmaOr(pubkeyA, pubkeyB), SigmaAnd(pubkeyC, GT(Height, IntConstant(500)).toSigmaProp))
compiledProp shouldBe prop
@@ -568,7 +568,7 @@ class ComplexSigSpecification extends SigmaTestingCommons {
// disable scalacheck shrinking otherwise other constraints start to fail
import org.scalacheck.Shrink
- implicit val noShrink: Shrink[Seq[ErgoLikeTestProvingInterpreter]] = Shrink.shrinkAny
+ implicit val noShrink: Shrink[Seq[ContextEnrichingTestProvingInterpreter]] = Shrink.shrinkAny
forAll(proversGen(3, 6), minSuccessful(10 /*test is heavy*/)) { allProvers =>
val verifier = new ErgoLikeTestInterpreter
@@ -579,8 +579,8 @@ class ComplexSigSpecification extends SigmaTestingCommons {
.toSeq
.filter(_.length == k)
- val prop = OR(
- kNumKeysCombinations.map(combs => AND(combs.map(_.publicImage.isProven)))
+ val prop = COR(
+ kNumKeysCombinations.map(combs => CAND(combs.map(_.publicImage)))
)
val ctx = ErgoLikeContext(
diff --git a/src/test/scala/sigmastate/utxo/ContextEnrichingSpecification.scala b/src/test/scala/sigmastate/utxo/ContextEnrichingSpecification.scala
index 9151aaabfb..8751fcc6f6 100644
--- a/src/test/scala/sigmastate/utxo/ContextEnrichingSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/ContextEnrichingSpecification.scala
@@ -6,22 +6,24 @@ import scorex.crypto.hash.Blake2b256
import sigmastate.Values._
import sigmastate._
import sigmastate.lang.Terms._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
-import sigmastate.lang.exceptions.OptionUnwrapNone
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
+
class ContextEnrichingSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
+
+ implicit lazy val IR: TestingIRContext = new TestingIRContext
+
property("context enriching mixed w. crypto") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val preimage = prover.contextExtenders(1).value.asInstanceOf[Array[Byte]]
val pubkey = prover.dlogSecrets.head.publicImage
val env = Map("blake" -> Blake2b256(preimage), "pubkey" -> pubkey)
- val compiledScript = compileWithCosting(env,
+ val compiledScript = compile(env,
"""{
| pubkey && blake2b256(getVar[Coll[Byte]](1).get) == blake
|}
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
val prop = SigmaAnd(
pubkey,
EQ(CalcBlake2b256(GetVarByteArray(1).get), ByteArrayConstant(Blake2b256(preimage))).toSigmaProp
@@ -39,17 +41,17 @@ class ContextEnrichingSpecification extends SigmaTestingCommons {
}
property("context enriching mixed w. crypto 2") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val preimage1 = prover.contextExtenders(1).value.asInstanceOf[Array[Byte]]
val preimage2 = prover.contextExtenders(2).value.asInstanceOf[Array[Byte]]
val pubkey = prover.dlogSecrets.head.publicImage
val env = Map("blake" -> Blake2b256(preimage1 ++ preimage2), "pubkey" -> pubkey)
- val compiledScript = compileWithCosting(env,
+ val compiledScript = compile(env,
"""{
| pubkey && blake2b256(getVar[Coll[Byte]](1).get ++ getVar[Coll[Byte]](2).get) == blake
|}
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
val prop = SigmaAnd(
pubkey,
@@ -70,8 +72,8 @@ class ContextEnrichingSpecification extends SigmaTestingCommons {
verifier.verify(env, compiledScript, ctxv, pr.proof, fakeMessage).get._1 shouldBe true
}
- // todo: fix broken XOR for byte arrays
- // in https://github.com/ScorexFoundation/sigmastate-interpreter/issues/324
+ // todo: ignored because of https://github.com/ScorexFoundation/sigmastate-interpreter/issues/419
+ // todo: and https://github.com/ScorexFoundation/sigmastate-interpreter/issues/420
ignore("prover enriching context - xor") {
val v1 = Base16.decode("abcdef7865").get
val k1 = 21: Byte
@@ -81,18 +83,23 @@ class ContextEnrichingSpecification extends SigmaTestingCommons {
val r = Base16.decode("bb6633db20").get
- val prover = new ErgoLikeTestProvingInterpreter()
+ val prover = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(k1, ByteArrayConstant(v1))
.withContextExtender(k2, ByteArrayConstant(v2))
val env = Map("k1" -> k1.toInt, "k2" -> k2.toInt, "r" -> r)
- val compiledScript = compileWithCosting(env,
+ val compiledScript = compile(env,
"""{
- | (getVar[Coll[Byte]](k1).get | getVar[Coll[Byte]](k2).get) == r
+ |
+ | // def Xor(c1: Coll[Byte], c2: Coll[Byte]): Coll[Byte] = c1.zipWith(c2, { (x, y) => x ^ y })
+ |
+ | def Xor(c1: Coll[Byte], c2: Coll[Byte]): Coll[Byte] = c1.zip(c2).map({ (t : (Byte, Byte)) => t._1 ^ t._2 })
+ |
+ | Xor(getVar[Coll[Byte]](k1).get, getVar[Coll[Byte]](k2).get) == r
|}
- """.stripMargin)
+ """.stripMargin).asBoolValue.toSigmaProp
- val prop = EQ(Xor(GetVarByteArray(k1).get, GetVarByteArray(k2).get), ByteArrayConstant(r))
+ val prop = EQ(Xor(GetVarByteArray(k1).get, GetVarByteArray(k2).get), ByteArrayConstant(r)).toSigmaProp
compiledScript shouldBe prop
val ctx = ErgoLikeContext.dummy(fakeSelf)
@@ -113,17 +120,17 @@ class ContextEnrichingSpecification extends SigmaTestingCommons {
* The script is asking for a hash function preimage. The "proof" could be replayed, so not really a proof.
*/
property("prover enriching context") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val preimage = prover.contextExtenders(1: Byte).value.asInstanceOf[Array[Byte]]
val env = Map("blake" -> Blake2b256(preimage))
- val compiledScript = compileWithCosting(env,
+ val compiledScript = compile(env,
"""{
| blake2b256(getVar[Coll[Byte]](1).get) == blake
|}
- """.stripMargin)
+ """.stripMargin).asBoolValue.toSigmaProp
- val prop = EQ(CalcBlake2b256(GetVarByteArray(1).get), ByteArrayConstant(Blake2b256(preimage)))
+ val prop = EQ(CalcBlake2b256(GetVarByteArray(1).get), ByteArrayConstant(Blake2b256(preimage))).toSigmaProp
compiledScript shouldBe prop
val ctx = ErgoLikeContext.dummy(fakeSelf)
@@ -134,24 +141,24 @@ class ContextEnrichingSpecification extends SigmaTestingCommons {
val verifier = new ErgoLikeTestInterpreter
//context w/out extensions
assertExceptionThrown(verifier.verify(env, prop, ctx, pr.proof, fakeMessage).get,
- rootCause(_).isInstanceOf[NoSuchElementException])
+ rootCause(_).isInstanceOf[ArrayIndexOutOfBoundsException])
verifier.verify(env, prop, ctxv, pr.proof, fakeMessage).get._1 shouldBe true
}
property("prover enriching context 2") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val preimage1 = prover.contextExtenders(1).value.asInstanceOf[Array[Byte]]
val preimage2 = prover.contextExtenders(2).value.asInstanceOf[Array[Byte]]
val env = Map("blake" -> Blake2b256(preimage2 ++ preimage1))
- val compiledScript = compileWithCosting(env,
+ val compiledScript = compile(env,
"""{
| blake2b256(getVar[Coll[Byte]](2).get ++ getVar[Coll[Byte]](1).get) == blake
|}
- """.stripMargin)
+ """.stripMargin).asBoolValue.toSigmaProp
val prop = EQ(CalcBlake2b256(Append(GetVarByteArray(2).get, GetVarByteArray(1).get)),
- ByteArrayConstant(Blake2b256(preimage2 ++ preimage1)))
+ ByteArrayConstant(Blake2b256(preimage2 ++ preimage1))).toSigmaProp
compiledScript shouldBe prop
val ctx = ErgoLikeContext.dummy(fakeSelf)
@@ -163,7 +170,7 @@ class ContextEnrichingSpecification extends SigmaTestingCommons {
//context w/out extensions
assertExceptionThrown(
verifier.verify(env, prop, ctx, pr.proof, fakeMessage).get,
- rootCause(_).isInstanceOf[NoSuchElementException]
+ rootCause(_).isInstanceOf[ArrayIndexOutOfBoundsException]
)
verifier.verify(env, prop, ctxv, pr.proof, fakeMessage).get._1 shouldBe true
}
diff --git a/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala b/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala
index bf361cb8a4..27d9a1c176 100644
--- a/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala
@@ -6,44 +6,45 @@ import org.ergoplatform._
import org.scalatest.TryValues._
import scorex.crypto.hash.Blake2b256
import sigmastate.SCollection.SByteArray
+import sigmastate.TrivialProp.{FalseProp, TrueProp}
import sigmastate.Values._
import sigmastate._
import sigmastate.interpreter.Interpreter._
-import sigmastate.basics.DLogProtocol.{DLogProverInput, ProveDlog}
+import sigmastate.basics.DLogProtocol.ProveDlog
import sigmastate.basics.ProveDHTuple
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.lang.Terms._
import sigmastate.serialization.ValueSerializer
class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
+ implicit lazy val IR: TestingIRContext = new TestingIRContext
private val reg1 = ErgoBox.nonMandatoryRegisters.head
property("scripts EQ/NEQ") {
- val prover1 = new ErgoLikeTestProvingInterpreter
- val prover2 = new ErgoLikeTestProvingInterpreter
+ val prover1 = new ContextEnrichingTestProvingInterpreter
+ val prover2 = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
- val h1 = prover1.dlogSecrets.head.publicImage
- val h2 = prover2.dlogSecrets.head.publicImage
+ val h1 = SigmaPropConstant(prover1.dlogSecrets.head.publicImage)
+ val h2 = SigmaPropConstant(prover2.dlogSecrets.head.publicImage)
val ctx = ErgoLikeContext.dummy(fakeSelf)
- val e = compileWithCosting(Map("h1" -> h1.bytes, "h2" -> h2.bytes), "h1 == h1")
+ val e = compile(Map("h1" -> h1.bytes, "h2" -> h2.bytes), "h1 == h1")
val exp = TrueLeaf
e shouldBe exp
- verifier.reduceToCrypto(ctx, exp)
- .get._1.isInstanceOf[TrueLeaf.type] shouldBe true
+ val res = verifier.reduceToCrypto(ctx, exp).get._1
+ res shouldBe TrueProp
- verifier.reduceToCrypto(ctx, EQ(ByteArrayConstant(h1.bytes), ByteArrayConstant(h2.bytes)))
- .get._1.isInstanceOf[FalseLeaf.type] shouldBe true
+ val res2 = verifier.reduceToCrypto(ctx, EQ(ByteArrayConstant(h1.bytes), ByteArrayConstant(h2.bytes))).get._1
+ res2 shouldBe FalseProp
}
property("DH tuple") {
- val prover = new ErgoLikeTestProvingInterpreter
- val fakeProver = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
+ val fakeProver = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -55,8 +56,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val wrongProp = SigmaPropConstant(ProveDHTuple(ci.g, ci.h, ci.u, ci.u))
val env = Map("g" -> ci.g, "h" -> ci.h, "u" -> ci.u, "v" -> ci.v, "s" -> secret.publicImage)
- val compiledProp1 = compileWithCosting(env, "s.isProven").asBoolValue
- val compiledProp2 = compileWithCosting(env, "proveDHTuple(g, h, u, v).isProven").asBoolValue
+ val compiledProp1 = compile(env, "s").asSigmaProp
+ val compiledProp2 = compile(env, "proveDHTuple(g, h, u, v)").asSigmaProp
compiledProp1 shouldBe prop
compiledProp2 shouldBe prop
@@ -69,16 +70,16 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
spendingTransaction = null,
self = fakeSelf)
- val pr = prover.prove(prop.isProven, ctx, fakeMessage).get
- verifier.verify(prop.isProven, ctx, pr, fakeMessage).get._1 shouldBe true
+ val pr = prover.prove(prop, ctx, fakeMessage).get
+ verifier.verify(prop, ctx, pr, fakeMessage).get._1 shouldBe true
- fakeProver.prove(prop.isProven, ctx, fakeMessage).isSuccess shouldBe false
- prover.prove(wrongProp.isProven, ctx, fakeMessage).isSuccess shouldBe false
+ fakeProver.prove(prop, ctx, fakeMessage).isSuccess shouldBe false
+ prover.prove(wrongProp, ctx, fakeMessage).isSuccess shouldBe false
}
property("DH tuple - simulation") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -86,7 +87,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val pubdhB = proverB.dhSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubdhB" -> pubdhB)
- val compiledProp = compileWithCosting(env, """pubkeyA || pubdhB""").asBoolValue
+ val compiledProp = compile(env, """pubkeyA || pubdhB""").asSigmaProp
val prop = SigmaOr(pubkeyA, pubdhB)
compiledProp shouldBe prop
@@ -104,8 +105,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
}
property("DH tuple and DLOG") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -113,7 +114,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val pubdhA = proverA.dhSecrets.head.publicImage
val env = Map("pubkeyA" -> pubkeyA, "pubdhA" -> pubdhA)
- val compiledProp = compileWithCosting(env, """pubkeyA && pubdhA""").asBoolValue
+ val compiledProp = compile(env, """pubkeyA && pubdhA""").asSigmaProp
val prop = SigmaAnd(pubkeyA, pubdhA)
compiledProp shouldBe prop
@@ -133,10 +134,12 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
proverB.prove(compiledProp, ctx, fakeMessage).isSuccess shouldBe false
}
- ignore("mixing scenario w. timeout") { // TODO Cost of the folded function depends on data
+ // related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/428
+ // checks that cost of the folded function doesn't depend on data
+ property("mixing scenario w. timeout") {
val height = 50
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
@@ -155,30 +158,19 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val properHash = Blake2b256(properBytes)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
def mixingRequestProp(sender: ProveDlog, timeout: Int) = {
val env = Map("sender" -> sender, "timeout" -> timeout, "properHash" -> properHash)
- val compiledProp = compileWithCosting(env,
+ val compiledProp = compile(env,
"""{
| val notTimePassed = HEIGHT <= timeout
- | val outBytes = OUTPUTS.map({(box: Box) => box.bytesWithNoRef})
+ | val outBytes = OUTPUTS.map({(box: Box) => box.bytesWithoutRef})
| val outSumBytes = outBytes.fold(Coll[Byte](), {(arr1: Coll[Byte], arr2: Coll[Byte]) => arr1 ++ arr2})
| val timePassed = HEIGHT > timeout
| notTimePassed && blake2b256(outSumBytes) == properHash || timePassed && sender
- }""".stripMargin).asBoolValue
-
- val prop = BinOr(
- BinAnd(LE(Height, LongConstant(timeout)),
- EQ(CalcBlake2b256(
- Fold.concat[SByte.type](
- MapCollection(Outputs, FuncValue(Vector((1, SBox)), ExtractBytesWithNoRef(ValUse(1, SBox))))
- ).asByteArray
- ),
- ByteArrayConstant(properHash))),
- BinAnd(GT(Height, LongConstant(timeout)), sender.isProven)
- )
- compiledProp shouldBe prop
+ }""".stripMargin).asSigmaProp
+
compiledProp
}
@@ -186,7 +178,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
currentHeight = height,
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(),
+ boxesToSpend = IndexedSeq(fakeSelf),
spendingTransaction,
self = fakeSelf)
@@ -203,20 +195,20 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
}
property("map + sum") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
val env = Map("pubkey" -> pubkey)
- val prop = compileWithCosting(env,
+ val prop = compile(env,
"""{
| val outValues = OUTPUTS.map({ (box: Box) => box.value })
| pubkey && outValues.fold(0L, { (x: Long, y: Long) => x + y }) > 20
- }""".stripMargin).asBoolValue
+ }""".stripMargin).asSigmaProp
val propExp = SigmaAnd(
- List(
+ Seq(
SigmaPropConstant(pubkey),
BoolToSigmaProp(
GT(
@@ -232,7 +224,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val newBox2 = ErgoBox(10, pubkey, 0)
val newBoxes = IndexedSeq(newBox1, newBox2)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -247,13 +239,13 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
}
property("byindex") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
val env = Map("pubkey" -> pubkey)
- val compiledProp = compileWithCosting(env, """pubkey && OUTPUTS(0).value > 10""").asBoolValue
+ val compiledProp = compile(env, """pubkey && OUTPUTS(0).value > 10""").asSigmaProp
val prop = SigmaAnd(pubkey, BoolToSigmaProp(GT(ExtractAmount(ByIndex(Outputs, 0)), LongConstant(10))))
compiledProp shouldBe prop
@@ -262,7 +254,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val newBox2 = ErgoBox(10, pubkey, 0)
val newBoxes = IndexedSeq(newBox1, newBox2)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -276,17 +268,17 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
verifier.verify(compiledProp, ctx, pr, fakeMessage)
- val fProp1 = AND(pubkey, GT(ExtractAmount(ByIndex(Outputs, 0)), LongConstant(11)))
+ val fProp1 = SigmaAnd(pubkey, GT(ExtractAmount(ByIndex(Outputs, 0)), LongConstant(11)))
prover.prove(fProp1, ctx, fakeMessage).isSuccess shouldBe false
- val fProp2 = AND(pubkey, GT(ExtractAmount(ByIndex(Outputs, 1)), LongConstant(11)))
+ val fProp2 = SigmaAnd(pubkey, GT(ExtractAmount(ByIndex(Outputs, 1)), LongConstant(11)))
prover.prove(fProp2, ctx, fakeMessage).isSuccess shouldBe false
}
property("P2SH") {
val scriptId = 21.toByte
- val prover0 = new ErgoLikeTestProvingInterpreter()
+ val prover0 = new ContextEnrichingTestProvingInterpreter()
val script = SigmaPropConstant(prover0.dlogSecrets.head.publicImage)
val scriptBytes = ValueSerializer.serialize(script)
@@ -295,17 +287,17 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val prover = prover0.withContextExtender(scriptId, ByteArrayConstant(scriptBytes))
val hashEquals = EQ(CalcBlake2b256(GetVarByteArray(scriptId).get), scriptHash)
- val scriptIsCorrect = DeserializeContext(scriptId, SSigmaProp).isProven
- val prop = AND(hashEquals, scriptIsCorrect)
+ val scriptIsCorrect = DeserializeContext(scriptId, SSigmaProp)
+ val prop = SigmaAnd(hashEquals, scriptIsCorrect)
- val recipientProposition = SigmaPropConstant(new ErgoLikeTestProvingInterpreter().dlogSecrets.head.publicImage).isProven
- val selfBox = ErgoBox(20, TrueLeaf, 0, Seq(), Map())
+ val recipientProposition = SigmaPropConstant(new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage)
+ val selfBox = ErgoBox(20, ErgoScriptPredef.TrueProp, 0, Seq(), Map())
val ctx = ErgoLikeContext(
currentHeight = 50,
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(selfBox),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(ErgoBox(1, recipientProposition, 0))),
+ createTransaction(ErgoBox(1, recipientProposition, 0)),
self = selfBox)
val proof = prover.prove(prop, ctx, fakeMessage).get
@@ -314,7 +306,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
}
property("Prove keys from registers") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey1 = prover.dlogSecrets.head.publicImage
@@ -324,25 +316,25 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val regPubkey1 = ErgoBox.nonMandatoryRegisters.head
val regPubkey2 = ErgoBox.nonMandatoryRegisters.tail.head
- val prop = compileWithCosting(Map(),
+ val prop = compile(Map(),
"""{
| val pubkey1 = SELF.R4[GroupElement].get
| val pubkey2 = SELF.R5[GroupElement].get
| proveDlog(pubkey1) && proveDlog(pubkey2)
- |}""".stripMargin).asBoolValue
+ |}""".stripMargin).asSigmaProp
val propTree = SigmaAnd(
- ProveDlog(ExtractRegisterAs[SGroupElement.type](Self, regPubkey1).get).asSigmaProp,
- ProveDlog(ExtractRegisterAs[SGroupElement.type](Self, regPubkey2).get).asSigmaProp)
+ CreateProveDlog(ExtractRegisterAs[SGroupElement.type](Self, regPubkey1).get),
+ CreateProveDlog(ExtractRegisterAs[SGroupElement.type](Self, regPubkey2).get))
prop shouldBe propTree
val newBox1 = ErgoBox(10, pubkey3, 0)
val newBoxes = IndexedSeq(newBox1)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
- val s1 = ErgoBox(20, TrueLeaf, 0, Seq(),
- Map(regPubkey1 -> pubkey1.value.asInstanceOf[GroupElementConstant],
- regPubkey2 -> pubkey2.value.asInstanceOf[GroupElementConstant]))
+ val s1 = ErgoBox(20, ErgoScriptPredef.TrueProp, 0, Seq(),
+ Map(regPubkey1 -> GroupElementConstant(pubkey1.value),
+ regPubkey2 -> GroupElementConstant(pubkey2.value)))
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -357,8 +349,8 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
//make sure that wrong case couldn't be proved
- val s2 = ErgoBox(20, TrueLeaf, 0, Seq(),
- Map(regPubkey1 -> pubkey1.value.asInstanceOf[GroupElementConstant]))
+ val s2 = ErgoBox(20, ErgoScriptPredef.TrueProp, 0, Seq(),
+ Map(regPubkey1 -> GroupElementConstant(pubkey1.value)))
val wrongCtx = ErgoLikeContext(
currentHeight = 50,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -378,27 +370,28 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val bitsCount = 160
val bytesCount = bitsCount / 8
- val prover0 = new ErgoLikeTestProvingInterpreter()
+ val prover0 = new ContextEnrichingTestProvingInterpreter()
- val customScript = prover0.dlogSecrets.head.publicImage.isProven
+ val customScript = prover0.dlogSecrets.head.publicImage.toSigmaProp
val scriptBytes = ValueSerializer.serialize(customScript)
val scriptHash = Blake2b256(scriptBytes).take(bytesCount)
val prover = prover0.withContextExtender(scriptId, ByteArrayConstant(scriptBytes))
- val hashEquals = EQ(Slice(CalcBlake2b256(GetVarByteArray(scriptId).get), IntConstant(0), IntConstant(bytesCount)),
+ val hashEquals = EQ(
+ Slice(CalcBlake2b256(GetVarByteArray(scriptId).get), IntConstant(0), IntConstant(bytesCount)),
scriptHash)
- val scriptIsCorrect = DeserializeContext(scriptId, SBoolean)
- val prop = AND(hashEquals, scriptIsCorrect)
+ val scriptIsCorrect = DeserializeContext(scriptId, SSigmaProp)
+ val prop = SigmaAnd(hashEquals.toSigmaProp, scriptIsCorrect)
- val recipientProposition = new ErgoLikeTestProvingInterpreter().dlogSecrets.head.publicImage.isProven
- val selfBox = ErgoBox(20, TrueLeaf, 0, Seq(), Map())
+ val recipientProposition = new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage
+ val selfBox = ErgoBox(20, TrueProp, 0, Seq(), Map())
val ctx = ErgoLikeContext(
currentHeight = 50,
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(selfBox),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(ErgoBox(1, recipientProposition, 0))),
+ createTransaction(ErgoBox(1, recipientProposition, 0)),
self = selfBox)
val proof = prover.prove(prop, ctx, fakeMessage).get
@@ -412,36 +405,36 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
* (and no more boxes could be provided as an input of a spending transaction).
*/
property("Along with a brother (using Box constant in environment)") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey1 = prover.dlogSecrets.head.publicImage
val pubkey2 = prover.dlogSecrets(1).publicImage
val brother = ErgoBox(10, pubkey1, 0)
- val brotherWithWrongId = ErgoBox(10, pubkey1, 0, boxId = 120: Short)
+ val brotherWithWrongId = ErgoBox(10, pubkey1, 0, boxIndex = 120: Short)
val newBox = ErgoBox(20, pubkey2, 0)
val newBoxes = IndexedSeq(newBox)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val env = Map("brother" -> brother)
- val prop = compileWithCosting(env,
+ val prop = compile(env,
"""{
| val okInputs = INPUTS.size == 2
| val okIds = INPUTS(0).id == brother.id
| okInputs && okIds
- }""".stripMargin).asBoolValue
+ }""".stripMargin).asBoolValue.toSigmaProp
val propExpected = BinAnd(
EQ(SizeOf(Inputs), IntConstant(2)),
- EQ(ExtractId(ByIndex(Inputs, 0)), ExtractId(BoxConstant(brother))))
+ EQ(ExtractId(ByIndex(Inputs, 0)), ExtractId(BoxConstant(brother)))).toSigmaProp
prop shouldBe propExpected
// try a version of the script that matches the white paper
val altEnv = Map("friend" -> brother)
- val altProp = compileWithCosting(altEnv, """INPUTS.size == 2 && INPUTS(0).id == friend.id""")
+ val altProp = compile(altEnv, """INPUTS.size == 2 && INPUTS(0).id == friend.id""").asBoolValue.toSigmaProp
altProp shouldBe prop
val s = ErgoBox(10, prop, 0, Seq(), Map())
@@ -468,12 +461,12 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
prover.prove(prop, wrongCtx, fakeMessage).isFailure shouldBe true
verifier.verify(prop, wrongCtx, pr, fakeMessage).fold(t => throw t, x => x)._1 shouldBe false
- val prop2 = compileWithCosting(env,
+ val prop2 = compile(env,
"""{
| val okInputs = INPUTS.size == 3
| val okIds = INPUTS(0).id == brother.id
| okInputs && okIds
- }""".stripMargin).asBoolValue
+ }""".stripMargin).asBoolValue.toSigmaProp
prover.prove(emptyEnv + (ScriptNameProp -> "prove_prop2"), prop2, ctx, fakeMessage).isFailure shouldBe true
verifier
@@ -486,27 +479,27 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
* (and possibly others, too).
*/
property("Along with a friend and maybe others (!!! Box constant in environment)") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val pubkey1 = prover.dlogSecrets.head.publicImage
val pubkey2 = prover.dlogSecrets(1).publicImage
val friend = ErgoBox(10, pubkey1, 0)
- val friendWithWrongId = ErgoBox(10, pubkey1, 0, boxId = 120: Short)
+ val friendWithWrongId = ErgoBox(10, pubkey1, 0, boxIndex = 120: Short)
val newBox = ErgoBox(20, pubkey2, 0)
val newBoxes = IndexedSeq(newBox)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val env = Map("friend" -> friend)
- val prop = compileWithCosting(env,
+ val prop = compile(env,
"""{
|
- | val isFriend = { (inputBox: Box) => inputBox.id == friend.id }
+ | def isFriend(inputBox: Box) = inputBox.id == friend.id
| INPUTS.exists (isFriend)
- }""".stripMargin).asBoolValue
+ }""".stripMargin).asBoolValue.toSigmaProp
val propExpected = Exists(Inputs,
FuncValue(
@@ -516,12 +509,12 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
ExtractId(BoxConstant(friend))
)
)
- )
+ ).toSigmaProp
prop shouldBe propExpected
// same script written differently
- val altProp = compileWithCosting(env, "INPUTS.exists ({ (inputBox: Box) => inputBox.id == friend.id })")
+ val altProp = compile(env, "INPUTS.exists ({ (inputBox: Box) => inputBox.id == friend.id })").asBoolValue.toSigmaProp
altProp shouldBe prop
val s = ErgoBox(10, prop, 0, Seq(), Map())
@@ -564,10 +557,10 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
}
property("If") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
- val pubkey = prover.dlogSecrets.head.publicImage.isProven
+ val pubkey = prover.dlogSecrets.head.publicImage
val preimageHello = "hello world".getBytes("UTF-8")
val preimageWrong = "wrong".getBytes("UTF-8")
@@ -575,7 +568,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val helloHash = Blake2b256.hash(preimageHello)
val env = Map("helloHash" -> helloHash)
- val prop = compileWithCosting(env,
+ val prop = compile(env,
"""{
| val cond = INPUTS(0).value > 10
| val preimage = if (cond)
@@ -583,13 +576,13 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
| else
| INPUTS(1).R4[Coll[Byte]].get
| helloHash == blake2b256(preimage)
- }""".stripMargin).asBoolValue
+ }""".stripMargin).asBoolValue.toSigmaProp
val propExpected = EQ(ByteArrayConstant(helloHash),
CalcBlake2b256(
If(GT(ExtractAmount(ByIndex(Inputs, 0)), LongConstant(10)),
ExtractRegisterAs[SByteArray](ByIndex(Inputs, 2), reg1).get,
- ExtractRegisterAs[SByteArray](ByIndex(Inputs, 1), reg1).get)))
+ ExtractRegisterAs[SByteArray](ByIndex(Inputs, 1), reg1).get))).toSigmaProp
prop shouldBe propExpected
val input0 = ErgoBox(10, pubkey, 0, Seq(), Map())
@@ -599,7 +592,7 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
val output = ErgoBox(22, pubkey, 0, Seq(), Map())
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(output))
+ val spendingTransaction = createTransaction(output)
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -616,22 +609,22 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
}
property("DeserializeRegister value type mismatch") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val sigmaProp = SigmaPropConstant(prover.dlogSecrets.head.publicImage)
// put SigmaProp into the register
val regValue = ByteArrayConstant(ValueSerializer.serialize(sigmaProp))
- val box = ErgoBox(20, TrueLeaf, 0, Seq(), Map(R4 -> regValue))
+ val box = ErgoBox(20, TrueProp, 0, Seq(), Map(R4 -> regValue))
// expect SBoolean in the register
- val prop = DeserializeRegister(R4, SBoolean)
+ val prop = DeserializeRegister(R4, SBoolean).toSigmaProp
val ctx = ErgoLikeContext(
currentHeight = 50,
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(box),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(ErgoBox(10, TrueLeaf, 0))),
+ createTransaction(IndexedSeq(ErgoBox(10, TrueProp, 0))),
self = box)
an[RuntimeException] should be thrownBy
@@ -640,12 +633,12 @@ class ErgoLikeInterpreterSpecification extends SigmaTestingCommons {
property("non-const ProveDHT") {
import sigmastate.interpreter.CryptoConstants.dlogGroup
- compileWithCosting(Map("gA" -> dlogGroup.generator),
+ compile(Map("gA" -> dlogGroup.generator),
"proveDHTuple(gA, OUTPUTS(0).R4[GroupElement].get, gA, gA)"
- ).asInstanceOf[BlockValue].result shouldBe a [ProveDHTuple]
+ ).asInstanceOf[BlockValue].result shouldBe a [CreateProveDHTuple]
}
property("non-const ProveDlog") {
- compileWithCosting(Map(), "proveDlog(OUTPUTS(0).R4[GroupElement].get)" ) shouldBe a [ProveDlog]
+ compile(Map(), "proveDlog(OUTPUTS(0).R4[GroupElement].get)" ) shouldBe a [CreateProveDlog]
}
}
diff --git a/src/test/scala/sigmastate/utxo/FuncVarSpecification.scala b/src/test/scala/sigmastate/utxo/FuncVarSpecification.scala
new file mode 100644
index 0000000000..0a89571dff
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/FuncVarSpecification.scala
@@ -0,0 +1,29 @@
+package sigmastate.utxo
+
+import org.ergoplatform.ErgoLikeContext
+import sigmastate.Values.Constant
+import sigmastate.eval.CFunc
+import sigmastate.SType.AnyOps
+import sigmastate.{SInt, SFunc}
+import sigmastate.helpers.{SigmaTestingCommons, ContextEnrichingTestProvingInterpreter}
+import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
+import sigmastate.lang.Terms.ValueOps
+
+class FuncVarSpecification extends SigmaTestingCommons {
+ implicit lazy val IR = new TestingIRContext {
+ override val okPrintEvaluatedEntries: Boolean = false
+ }
+
+ // TODO : related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/417
+ ignore("Func context variable") {
+// val scriptId = 21.toByte
+// val code = compileWithCosting(emptyEnv, s"{ (x: Int) => x + 1 }")
+// val ctx = ErgoLikeContext.dummy(fakeSelf)
+//
+// val prover = new ContextEnrichingTestProvingInterpreter()
+// .withContextExtender(scriptId, Constant(CFunc[Int, Int](ctx, code).asWrappedType, SFunc(SInt, SInt)))
+// val prop = compileWithCosting(emptyEnv, s"{ val f = getVar[Int => Int](1).get; f(10) > 0 }").asBoolValue.asSigmaProp
+// val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).fold(t => throw t, identity)
+//
+ }
+}
diff --git a/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala b/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala
index 690d8db3be..59e6acbec5 100644
--- a/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala
+++ b/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala
@@ -1,32 +1,17 @@
package sigmastate.utxo
-import org.ergoplatform.{ErgoBoxCandidate, ErgoLikeTransaction}
-import org.ergoplatform._
-import org.scalacheck.Arbitrary._
-import org.scalacheck.Gen
+import org.ergoplatform.{ErgoBoxCandidate, ErgoLikeTransaction, _}
import org.scalatest.prop.GeneratorDrivenPropertyChecks
-import org.scalatest.{Assertion, Matchers, PropSpec}
+import org.scalatest.{Matchers, PropSpec}
+import sigmastate.helpers.SigmaTestingCommons
import sigmastate.interpreter.{ContextExtension, ProverResult}
-import sigmastate.serialization.Serializer
import sigmastate.serialization.generators.ValueGenerators
class SerializationRoundTripSpec extends PropSpec
with GeneratorDrivenPropertyChecks
with Matchers
- with ValueGenerators {
-
- private def roundTripTest[T](v: T)(implicit serializer: Serializer[T, T]): Assertion = {
- val bytes = serializer.toBytes(v)
- serializer.parseBody(Serializer.startReader(bytes)) shouldBe v
- }
-
- private def roundTripTestWithPos[T](v: T)(implicit serializer: Serializer[T, T]): Assertion = {
- val randomBytesCount = Gen.chooseNum(1, 20).sample.get
- val randomBytes = Gen.listOfN(randomBytesCount, arbByte.arbitrary).sample.get.toArray
- val bytes = serializer.toBytes(v)
- serializer.parseBody(Serializer.startReader(bytes)) shouldBe v
- serializer.parseBody(Serializer.startReader(randomBytes ++ bytes, randomBytesCount)) shouldBe v
- }
+ with ValueGenerators
+ with SigmaTestingCommons {
property("ErgoBoxCandidate: Serializer round trip") {
forAll { t: ErgoBoxCandidate => roundTripTest(t)(ErgoBoxCandidate.serializer) }
@@ -34,13 +19,8 @@ class SerializationRoundTripSpec extends PropSpec
}
property("ErgoBox: Serializer round trip") {
- forAll { t: ErgoBox => roundTripTest(t)(ErgoBox.serializer) }
- forAll { t: ErgoBox => roundTripTestWithPos(t)(ErgoBox.serializer) }
- }
-
- property("ErgoLikeTransaction: Serializer round trip") {
- forAll { t: ErgoLikeTransaction => roundTripTest(t)(ErgoLikeTransaction.serializer) }
- forAll { t: ErgoLikeTransaction => roundTripTestWithPos(t)(ErgoLikeTransaction.serializer) }
+ forAll { t: ErgoBox => roundTripTest(t)(ErgoBox.sigmaSerializer) }
+ forAll { t: ErgoBox => roundTripTestWithPos(t)(ErgoBox.sigmaSerializer) }
}
property("ContextExtension: Serializer round trip") {
@@ -53,11 +33,6 @@ class SerializationRoundTripSpec extends PropSpec
forAll { t: ProverResult => roundTripTestWithPos(t)(ProverResult.serializer) }
}
- property("UnsignedInput: Serializer round trip") {
- forAll { t: UnsignedInput => roundTripTest(t)(UnsignedInput.serializer) }
- forAll { t: UnsignedInput => roundTripTestWithPos(t)(UnsignedInput.serializer) }
- }
-
property("Input: Serializer round trip") {
forAll { t: Input => roundTripTest(t)(Input.serializer) }
forAll { t: Input => roundTripTestWithPos(t)(Input.serializer) }
diff --git a/src/test/scala/sigmastate/utxo/SigmaCompilerSpecification.scala b/src/test/scala/sigmastate/utxo/SigmaCompilerSpecification.scala
index 58828c5633..fafd4818f0 100644
--- a/src/test/scala/sigmastate/utxo/SigmaCompilerSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/SigmaCompilerSpecification.scala
@@ -11,27 +11,30 @@ import sigmastate._
* Specification for compile function
*/
class SigmaCompilerSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
+ implicit lazy val IR: TestingIRContext = new TestingIRContext
- private def compile(code: String, env: ScriptEnv = Map()): Value[SType] = compileWithCosting(env, code)
+ private def compile(code: String, env: ScriptEnv = Map()): Value[SType] = compile(env, code)
property(">= compile") {
val elementId = 1: Byte
val env = Map("elementId" -> elementId)
val propTree = GE(GetVarInt(elementId).get, IntConstant(120))
- val propComp = compileWithCosting(env,
+ val propComp = compile(env,
"""{
| getVar[Int](elementId).get >= 120
|}""".stripMargin).asBoolValue
propComp shouldBe propTree
}
- // TODO: enable after https://github.com/ScorexFoundation/sigmastate-interpreter/issues/324 is done
- ignore("modular arithmetic ops") {
+ property("modular arithmetic ops: ModQ") {
compile("10.toBigInt.modQ") shouldEqual ModQ(BigIntConstant(10))
+ }
+
+ // TODO: enable after https://github.com/ScorexFoundation/sigmastate-interpreter/issues/324 is done
+ ignore("modular arithmetic ops: BinOps") {
compile("10.toBigInt.plusModQ(2.toBigInt)") shouldEqual
- PlusModQ(BigIntConstant(10), BigIntConstant(2))
+ PlusModQ(BigIntConstant(10), BigIntConstant(2))
compile("10.toBigInt.minusModQ(2.toBigInt)") shouldEqual
- MinusModQ(BigIntConstant(10), BigIntConstant(2))
+ MinusModQ(BigIntConstant(10), BigIntConstant(2))
}
}
diff --git a/src/test/scala/sigmastate/utxo/SigmaContract.scala b/src/test/scala/sigmastate/utxo/SigmaContract.scala
index 8beff425d9..0d2ef4529a 100644
--- a/src/test/scala/sigmastate/utxo/SigmaContract.scala
+++ b/src/test/scala/sigmastate/utxo/SigmaContract.scala
@@ -1,7 +1,8 @@
package sigmastate.utxo
+import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix
import sigmastate.lang.{SigmaCompiler, TransformingSigmaBuilder}
abstract class SigmaContract {
- val compiler = new SigmaCompiler(TransformingSigmaBuilder)
+ val compiler = new SigmaCompiler(TestnetNetworkPrefix, TransformingSigmaBuilder)
}
diff --git a/src/test/scala/sigmastate/utxo/SpamSpecification.scala b/src/test/scala/sigmastate/utxo/SpamSpecification.scala
index dc88daa8db..b3756163fd 100644
--- a/src/test/scala/sigmastate/utxo/SpamSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/SpamSpecification.scala
@@ -1,23 +1,26 @@
package sigmastate.utxo
-import org.ergoplatform
import org.ergoplatform._
import org.scalacheck.Gen
+import scalan.util.BenchmarkUtil
import scorex.crypto.authds.{ADKey, ADValue}
-import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert, Lookup}
-import scorex.crypto.hash.{Blake2b256, Digest32}
+import scorex.crypto.authds.avltree.batch.{Lookup, BatchAVLProver, Insert}
+import scorex.crypto.hash.{Digest32, Blake2b256}
import scorex.utils.Random
+import sigmastate.SCollection.SByteArray
import sigmastate.Values._
+import sigmastate.lang.Terms._
import sigmastate._
import sigmastate.interpreter.Interpreter._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, SigmaTestingCommons, ErgoLikeTestInterpreter}
+import sigmastate.lang.exceptions.CosterException
/**
* Suite of tests where a malicious prover tries to feed a verifier with a script which is costly to verify
*/
class SpamSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
+ implicit lazy val IR: TestingIRContext = new TestingIRContext
//we assume that verifier must finish verification of any script in less time than 3M hash calculations
// (for the Blake2b256 hash function over a single block input)
lazy val Timeout: Long = {
@@ -28,7 +31,7 @@ class SpamSpecification extends SigmaTestingCommons {
(1 to 1000000).foreach(_ => hf(block))
val t0 = System.currentTimeMillis()
- (1 to 20000000).foreach(_ => hf(block))
+ (1 to 3000000).foreach(_ => hf(block))
val t = System.currentTimeMillis()
t - t0
}
@@ -47,18 +50,15 @@ class SpamSpecification extends SigmaTestingCommons {
val id = 11: Byte
val id2 = 12: Byte
- val prover = new ErgoLikeTestProvingInterpreter(CostTable.ScriptLimit * 10)
+ val prover = new ContextEnrichingTestProvingInterpreter(CostTable.ScriptLimit * 10)
.withContextExtender(id, ByteArrayConstant(ba))
.withContextExtender(id2, ByteArrayConstant(ba))
- val spamScript = EQ(CalcBlake2b256(GetVarByteArray(id).get), CalcBlake2b256(GetVarByteArray(id2).get))
+ val spamScript = EQ(CalcBlake2b256(GetVarByteArray(id).get), CalcBlake2b256(GetVarByteArray(id2).get)).toSigmaProp
val ctx = ErgoLikeContext.dummy(fakeSelf)
- val prt = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), spamScript, ctx, fakeMessage)
-// prt.isSuccess shouldBe true
-
- val pr = prt.get
+ val pr = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), spamScript, ctx, fakeMessage).get
val verifier = new ErgoLikeTestInterpreter
val (res, terminated) = termination(() =>
@@ -76,19 +76,18 @@ class SpamSpecification extends SigmaTestingCommons {
* The scripts with more than 150 levels are considered malicious.
*/
property("big byte array with a lot of operations") {
-// fail("fix the stack overflow in this test")
val ba = Random.randomBytes(5000000)
val id = 21: Byte
- val prover = new ErgoLikeTestProvingInterpreter(CostTable.ScriptLimit * 10).withContextExtender(id, ByteArrayConstant(ba))
+ val prover = new ContextEnrichingTestProvingInterpreter(CostTable.ScriptLimit * 10).withContextExtender(id, ByteArrayConstant(ba))
val bigSubScript = (1 to 100).foldLeft(CalcBlake2b256(GetVarByteArray(id).get)) { case (script, _) =>
CalcBlake2b256(script)
}
- val spamScript = NEQ(bigSubScript, CalcBlake2b256(ByteArrayConstant(Array.fill(32)(0: Byte))))
+ val spamScript = NEQ(bigSubScript, CalcBlake2b256(ByteArrayConstant(Array.fill(32)(0: Byte)))).toSigmaProp
val ctx = ErgoLikeContext.dummy(fakeSelf)
@@ -107,18 +106,18 @@ class SpamSpecification extends SigmaTestingCommons {
}
property("ring signature - maximum ok ring size") {
- val prover = new ErgoLikeTestProvingInterpreter(maxCost = CostTable.ScriptLimit * 2)
+ val prover = new ContextEnrichingTestProvingInterpreter(maxCost = CostTable.ScriptLimit * 2)
val verifier = new ErgoLikeTestInterpreter
val secret = prover.dlogSecrets.head
val simulated = (1 to 98).map { _ =>
- new ErgoLikeTestProvingInterpreter().dlogSecrets.head.publicImage
+ new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage
}
val ctx = ErgoLikeContext.dummy(fakeSelf)
val publicImages = secret.publicImage +: simulated
- val prop = OR(publicImages.map(image => SigmaPropConstant(image).isProven))
+ val prop = OR(publicImages.map(image => SigmaPropConstant(image).isProven)).toSigmaProp
val pt0 = System.currentTimeMillis()
val proof = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
@@ -135,12 +134,12 @@ class SpamSpecification extends SigmaTestingCommons {
whenever(orCnt > 10 && outCnt > 200) {
val orCnt = 10
val outCnt = 5
- val prover = new ErgoLikeTestProvingInterpreter(maxCost = CostTable.ScriptLimit * 1000000L)
+ val prover = new ContextEnrichingTestProvingInterpreter(maxCost = CostTable.ScriptLimit * 1000000L)
- val propToCompare = OR((1 to orCnt).map(_ => EQ(LongConstant(6), LongConstant(5))))
+ val propToCompare = OR((1 to orCnt).map(_ => EQ(LongConstant(6), LongConstant(5)))).toSigmaProp
val spamProp = OR((1 until orCnt).map(_ => EQ(LongConstant(6), LongConstant(5))) :+
- EQ(LongConstant(6), LongConstant(6)))
+ EQ(LongConstant(6), LongConstant(6))).toSigmaProp
val spamScript =
Exists(Outputs,
@@ -150,10 +149,10 @@ class SpamSpecification extends SigmaTestingCommons {
EQ(ExtractScriptBytes(ValUse(1, SBox)), ByteArrayConstant(propToCompare.bytes))
)
)
- )
+ ).toSigmaProp
val txOutputs = ((1 to outCnt) map (_ => ErgoBox(11, spamProp, 0))) :+ ErgoBox(11, propToCompare, 0)
- val tx = ErgoLikeTransaction(IndexedSeq(), txOutputs)
+ val tx = createTransaction(txOutputs)
val ctx = ErgoLikeContext.dummy(createBox(0, propToCompare)).withTransaction(tx)
@@ -170,7 +169,7 @@ class SpamSpecification extends SigmaTestingCommons {
}
}
- property("transaction with many inputs and outputs") { // TODO avoid too complex cost function by approximating INPUT and OUTPUT sizes
+ property("transaction with many inputs and outputs") {
implicit lazy val IR = new TestingIRContext {
this.useAlphaEquality = true
override val okPrintEvaluatedEntries = false
@@ -179,41 +178,56 @@ class SpamSpecification extends SigmaTestingCommons {
println(printEnvEntry(sym, value))
}
}
- val prover = new ErgoLikeTestProvingInterpreter(maxCost = Long.MaxValue)
+ val prover = new ContextEnrichingTestProvingInterpreter()
+ val limitlessProver = new ContextEnrichingTestProvingInterpreter(maxCost = Long.MaxValue)
val prop = Exists(Inputs,
FuncValue(Vector((1, SBox)),
Exists(Outputs,
- FuncValue(Vector((2, SBox)), EQ(ExtractScriptBytes(ValUse(1, SBox)), ExtractScriptBytes(ValUse(2, SBox)))))))
+ FuncValue(Vector((2, SBox)), EQ(ExtractScriptBytes(ValUse(1, SBox)), ExtractScriptBytes(ValUse(2, SBox))))))).toSigmaProp
- val inputScript = OR((1 to 200).map(_ => EQ(LongConstant(6), LongConstant(5))))
- val outputScript = OR((1 to 200).map(_ => EQ(LongConstant(6), LongConstant(6))))
+ val inputScript = OR((1 to 200).map(_ => EQ(LongConstant(6), LongConstant(5)))).toSigmaProp
+ val outputScript = OR((1 to 200).map(_ => EQ(LongConstant(6), LongConstant(6)))).toSigmaProp
val inputs = ((1 to 999) map (_ => ErgoBox(11, inputScript, 0))) :+ ErgoBox(11, outputScript, 0)
val outputs = (1 to 1000) map (_ => ErgoBox(11, outputScript, 0))
- val tx = ergoplatform.ErgoLikeTransaction(IndexedSeq(), outputs)
+ val tx = createTransaction(outputs)
val ctx = new ErgoLikeContext(currentHeight = 0,
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
+ dataBoxes = ErgoLikeContext.noBoxes,
+ headers = ErgoLikeContext.noHeaders,
+ preHeader = ErgoLikeContext.dummyPreHeader,
boxesToSpend = inputs,
spendingTransaction = tx,
- self = null)
+ self = inputs(0))
println(s"Timeout: ${Timeout / 1000.0} seconds")
+ // check that execution terminated within timeout due to costing exception and cost limit
val pt0 = System.currentTimeMillis()
- val proof = prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage).get
+ val (res, terminated) = termination(() => prover.prove(emptyEnv + (ScriptNameProp -> "prove"), prop, ctx, fakeMessage))
val pt = System.currentTimeMillis()
println(s"Prover time: ${(pt - pt0) / 1000.0} seconds")
-
- val verifier = new ErgoLikeTestInterpreter
- val (res, terminated) = termination(() => verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, proof, fakeMessage))
- val pt2 = System.currentTimeMillis()
- println(s"Verifier time: ${(pt2 - pt) / 1000.0} seconds")
terminated shouldBe true
- res.isFailure shouldBe true
+ assertExceptionThrown(
+ res.fold(t => throw t, identity),
+ t => {
+ rootCause(t).isInstanceOf[CosterException] && t.getMessage.contains("Script cannot be executed")
+ }
+ )
+
+ // measure time required to execute the script itself and it is more then timeout
+ val (_, calcTime) = BenchmarkUtil.measureTime {
+ import limitlessProver.IR._
+ val costingRes @ Pair(calcF, costF) = doCostingEx(emptyEnv, prop, true)
+ val calcCtx = ctx.toSigmaContext(limitlessProver.IR, isCost = false)
+ limitlessProver.calcResult(calcCtx, calcF)
+ }
+ println(s"Full time to execute the script: ${calcTime / 1000.0} seconds")
+ assert(calcTime > Timeout)
}
property("too heavy avl tree lookup") {
@@ -221,7 +235,7 @@ class SpamSpecification extends SigmaTestingCommons {
def genKey(str: String): ADKey = ADKey @@ Blake2b256("key: " + str)
def genValue(str: String): ADValue = ADValue @@ Blake2b256("val: " + str)
- val prover = new ErgoLikeTestProvingInterpreter(Long.MaxValue)
+ val prover = new ContextEnrichingTestProvingInterpreter(Long.MaxValue)
val verifier = new ErgoLikeTestInterpreter
val pubkey = prover.dlogSecrets.head.publicImage
@@ -243,21 +257,27 @@ class SpamSpecification extends SigmaTestingCommons {
println("proof size: " + proof.length)
- val treeData = new AvlTreeData(digest, 32, None)
+ val treeData = new AvlTreeData(digest, AvlTreeFlags.ReadOnly, 32, None)
val key1 = genKey("key1")
val value1 = genValue("value1")
- val prop = EQ(TreeLookup(ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
- ByteArrayConstant(key1),
- ByteArrayConstant(proof)).get, ByteArrayConstant(value1))
+ val prop = ErgoTree(ErgoTree.DefaultHeader, ErgoTree.EmptyConstants,
+ EQ(
+ IR.builder.mkMethodCall(
+ ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
+ SAvlTree.getMethod,
+ IndexedSeq(ByteArrayConstant(key1), ByteArrayConstant(proof))).asOption[SByteArray].get,
+ ByteArrayConstant(value1)
+ ).toSigmaProp
+ )
val newBox1 = ErgoBox(10, pubkey, 0)
val newBoxes = IndexedSeq(newBox1)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
- val s = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
+ val s = ErgoBox(20, ErgoScriptPredef.TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
val ctx = ErgoLikeContext(
currentHeight = 50,
diff --git a/src/test/scala/sigmastate/utxo/ThresholdSpecification.scala b/src/test/scala/sigmastate/utxo/ThresholdSpecification.scala
index 42233f9c0a..1833431704 100644
--- a/src/test/scala/sigmastate/utxo/ThresholdSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/ThresholdSpecification.scala
@@ -4,7 +4,7 @@ import org.ergoplatform.ErgoLikeContext
import sigmastate.basics.DLogProtocol.{DLogProverInput, ProveDlog}
import sigmastate.Values.{ConcreteCollection, FalseLeaf, IntConstant, SigmaPropConstant, SigmaPropValue, TrueLeaf}
import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.lang.Terms._
import sigmastate.lang.exceptions.CosterException
@@ -15,10 +15,10 @@ class ThresholdSpecification extends SigmaTestingCommons {
}
property("basic threshold compilation/execution") {
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
- val proverD = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
+ val proverD = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val skA = proverA.dlogSecrets.head
@@ -45,16 +45,16 @@ class ThresholdSpecification extends SigmaTestingCommons {
val env = Map("pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "pubkeyC" -> pubkeyC)
// Basic compilation
- val compiledProp1 = compileWithCosting(env, """atLeast(2, Coll(pubkeyA, pubkeyB, pubkeyC))""")
+ val compiledProp1 = compile(env, """atLeast(2, Coll(pubkeyA, pubkeyB, pubkeyC))""")
val prop1 = AtLeast(2, pubkeyA, pubkeyB, pubkeyC)
compiledProp1 shouldBe prop1
// this example is from the white paper
- val compiledProp2 = compileWithCosting(env,
+ val compiledProp2 = compile(env,
"""{
| val array = Coll(pubkeyA, pubkeyB, pubkeyC)
| atLeast(array.size, array)
- |}""".stripMargin).asBoolValue
+ |}""".stripMargin).asSigmaProp
val prop2 = AtLeast(IntConstant(3),
@@ -69,15 +69,15 @@ class ThresholdSpecification extends SigmaTestingCommons {
prover.prove(compiledProp2, ctx, fakeMessage).isFailure shouldBe true
}
- val prop2And = AND(pubkeyA, pubkeyB, pubkeyC)
+ val prop2And = CAND(Seq(pubkeyA, pubkeyB, pubkeyC)).toSigmaProp
proverA.reduceToCrypto(ctx, compiledProp2).get._1 shouldBe proverA.reduceToCrypto(ctx, prop2And).get._1
// this example is from the white paper
- val compiledProp3 = compileWithCosting(env,
+ val compiledProp3 = compile(env,
"""{
| val array = Coll(pubkeyA, pubkeyB, pubkeyC)
| atLeast(1, array)
- |}""".stripMargin).asBoolValue
+ |}""".stripMargin).asSigmaProp
val prop3 = AtLeast(1, pubkeyA, pubkeyB, pubkeyC)
compiledProp3 shouldBe prop3
@@ -88,14 +88,14 @@ class ThresholdSpecification extends SigmaTestingCommons {
}
proverD.prove(compiledProp3, ctx, fakeMessage).isFailure shouldBe true
- val prop3Or = OR(pubkeyA, pubkeyB, pubkeyC)
+ val prop3Or = COR(Seq(pubkeyA, pubkeyB, pubkeyC)).toSigmaProp
proverA.reduceToCrypto(ctx, compiledProp3).get._1 shouldBe proverA.reduceToCrypto(ctx, prop3Or).get._1
- val compiledProp4 = compileWithCosting(env,
+ val compiledProp4 = compile(env,
"""{
| val array = Coll(pubkeyA, pubkeyB, pubkeyC)
| atLeast(2, array)
- |}""".stripMargin).asBoolValue
+ |}""".stripMargin).asSigmaProp
val prop4 = AtLeast(2, pubkeyA, pubkeyB, pubkeyC)
compiledProp4 shouldBe prop4
@@ -112,7 +112,7 @@ class ThresholdSpecification extends SigmaTestingCommons {
property("threshold reduce to crypto") {
import TrivialProp._
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
val ctx = ErgoLikeContext(
currentHeight = 1,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -235,15 +235,15 @@ class ThresholdSpecification extends SigmaTestingCommons {
property("3-out-of-6 threshold") {
// This example is from the white paper
- val proverA = new ErgoLikeTestProvingInterpreter
- val proverB = new ErgoLikeTestProvingInterpreter
- val proverC = new ErgoLikeTestProvingInterpreter
- val proverD = new ErgoLikeTestProvingInterpreter
- val proverE = new ErgoLikeTestProvingInterpreter
- val proverF = new ErgoLikeTestProvingInterpreter
- val proverG = new ErgoLikeTestProvingInterpreter
- val proverH = new ErgoLikeTestProvingInterpreter
- val proverI = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
+ val proverB = new ContextEnrichingTestProvingInterpreter
+ val proverC = new ContextEnrichingTestProvingInterpreter
+ val proverD = new ContextEnrichingTestProvingInterpreter
+ val proverE = new ContextEnrichingTestProvingInterpreter
+ val proverF = new ContextEnrichingTestProvingInterpreter
+ val proverG = new ContextEnrichingTestProvingInterpreter
+ val proverH = new ContextEnrichingTestProvingInterpreter
+ val proverI = new ContextEnrichingTestProvingInterpreter
val skA = proverA.dlogSecrets.head
val skB = proverB.dlogSecrets.head
@@ -269,8 +269,8 @@ class ThresholdSpecification extends SigmaTestingCommons {
val env = Map("pkA" -> pkA, "pkB" -> pkB, "pkC" -> pkC,
"pkD" -> pkD, "pkE" -> pkE, "pkF" -> pkF,
"pkG" -> pkG, "pkH" -> pkH, "pkI" -> pkI)
- val compiledProp = compileWithCosting(env,
- """atLeast(3, Coll (pkA, pkB, pkC, pkD && pkE, pkF && pkG, pkH && pkI))""").asBoolValue
+ val compiledProp = compile(env,
+ """atLeast(3, Coll (pkA, pkB, pkC, pkD && pkE, pkF && pkG, pkH && pkI))""").asSigmaProp
val prop = AtLeast(3, pkA, pkB, pkC, SigmaAnd(pkD, pkE), SigmaAnd(pkF, pkG), SigmaAnd(pkH, pkI))
compiledProp shouldBe prop
@@ -325,7 +325,7 @@ class ThresholdSpecification extends SigmaTestingCommons {
// the integer indicates how many subpropositions the prover can prove
- var provers = Seq[(Int, ErgoLikeTestProvingInterpreter)]((0, new ErgoLikeTestProvingInterpreter))
+ var provers = Seq[(Int, ContextEnrichingTestProvingInterpreter)]((0, new ContextEnrichingTestProvingInterpreter))
// create 32 different provers
for (i <- secrets.indices) {
provers = provers ++ provers.map(p => (p._1 + 1, p._2.withSecrets(secrets(i))))
@@ -340,13 +340,13 @@ class ThresholdSpecification extends SigmaTestingCommons {
val verifier = new ErgoLikeTestInterpreter
- def canProve(prover: ErgoLikeTestProvingInterpreter, proposition: SigmaPropValue): Unit = {
- val proof = prover.prove(proposition.isProven, ctx, fakeMessage).get
- verifier.verify(proposition.isProven, ctx, proof, fakeMessage).get._1 shouldBe true
+ def canProve(prover: ContextEnrichingTestProvingInterpreter, proposition: SigmaPropValue): Unit = {
+ val proof = prover.prove(proposition, ctx, fakeMessage).get
+ verifier.verify(proposition, ctx, proof, fakeMessage).get._1 shouldBe true
}
- def cannotProve(prover: ErgoLikeTestProvingInterpreter, proposition: SigmaPropValue): Unit = {
- prover.prove(proposition.isProven, ctx, fakeMessage).isFailure shouldBe true
+ def cannotProve(prover: ContextEnrichingTestProvingInterpreter, proposition: SigmaPropValue): Unit = {
+ prover.prove(proposition, ctx, fakeMessage).isFailure shouldBe true
}
@@ -403,22 +403,22 @@ class ThresholdSpecification extends SigmaTestingCommons {
}
property("fail compilation when input limit exceeded") {
- val proverA = new ErgoLikeTestProvingInterpreter
+ val proverA = new ContextEnrichingTestProvingInterpreter
val skA = proverA.dlogSecrets.head
val pubkeyA = skA.publicImage
val keyName = "pubkeyA"
val env = Map(keyName -> pubkeyA)
val pubKeysStrExceeding = Array.fill[String](AtLeast.MaxChildrenCount + 1)(keyName).mkString(",")
- an[CosterException] should be thrownBy compileWithCosting(env, s"""atLeast(2, Coll($pubKeysStrExceeding))""")
+ an[CosterException] should be thrownBy compile(env, s"""atLeast(2, Coll($pubKeysStrExceeding))""")
an[CosterException] should be thrownBy
- compileWithCosting(env, s"""{ val arr = Coll($pubKeysStrExceeding); atLeast(2, arr) }""")
+ compile(env, s"""{ val arr = Coll($pubKeysStrExceeding); atLeast(2, arr) }""")
// max children should work fine
val pubKeysStrMax = Array.fill[String](AtLeast.MaxChildrenCount)(keyName).mkString(",")
- compileWithCosting(env, s"""atLeast(2, Coll($pubKeysStrMax))""")
- compileWithCosting(env, s"""{ val arr = Coll($pubKeysStrMax); atLeast(2, arr) }""")
+ compile(env, s"""atLeast(2, Coll($pubKeysStrMax))""")
+ compile(env, s"""{ val arr = Coll($pubKeysStrMax); atLeast(2, arr) }""")
// collection with unknown items should pass
- compileWithCosting(env, s"""atLeast(2, getVar[Coll[SigmaProp]](1).get)""")
+ compile(env, s"""atLeast(2, getVar[Coll[SigmaProp]](1).get)""")
}
}
diff --git a/src/test/scala/sigmastate/utxo/UsingContextPropertiesSpecification.scala b/src/test/scala/sigmastate/utxo/UsingContextPropertiesSpecification.scala
new file mode 100644
index 0000000000..adde25a799
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/UsingContextPropertiesSpecification.scala
@@ -0,0 +1,87 @@
+package sigmastate.utxo
+
+import sigmastate.TrivialProp
+import sigmastate.eval.{IRContext, CSigmaProp}
+import sigmastate.eval.Extensions._
+import special.sigma.Context
+import sigmastate.helpers.SigmaTestingCommons
+import org.ergoplatform.dsl.{SigmaContractSyntax, ContractSpec, TestContractSpec}
+import org.ergoplatform.ErgoBox
+import scorex.crypto.hash.Blake2b256
+
+class UsingContextPropertiesSpecification extends SigmaTestingCommons { suite =>
+ lazy val spec = TestContractSpec(suite)(new TestingIRContext)
+ lazy val prover = spec.ProvingParty("Alice")
+ private implicit lazy val IR: IRContext = spec.IR
+
+ private val reg1 = ErgoBox.nonMandatoryRegisters(0)
+
+ def hash(str: String) = Blake2b256(str)
+ val id = hash("some id")
+
+ property("Accessing context properties") {
+ case class ContextContract[Spec <: ContractSpec]
+ (prover: Spec#ProvingParty)
+ (implicit val spec: Spec) extends SigmaContractSyntax
+ {
+ def pkProver = prover.pubKey
+ lazy val contractEnv = Env("pkProver" -> pkProver)
+
+ lazy val dataInputsProp = proposition("dataInputsProp",
+ { CONTEXT: Context => import CONTEXT._
+ sigmaProp(CONTEXT.dataInputs.size == 1 && INPUTS.size == 2)
+ },
+ "{ sigmaProp(CONTEXT.dataInputs.size == 1 && INPUTS.size == 2) } ")
+
+ lazy val dataBoxProp = proposition("dataBoxProp",
+ { CONTEXT: Context => import CONTEXT._
+ sigmaProp(CONTEXT.dataInputs(0).value > INPUTS(0).value)
+ },
+ "{ sigmaProp(CONTEXT.dataInputs(0).value > INPUTS(0).value) } ")
+
+ lazy val headerProp = proposition("headerProp",
+ { CONTEXT: Context => import CONTEXT._
+ sigmaProp(CONTEXT.headers(0).version == 0)
+ },
+ "{ sigmaProp(CONTEXT.headers(0).version == 0) } ")
+
+ lazy val proverSig = proposition("proverSig", { _ => pkProver }, "pkProver")
+ }
+
+ val contract = ContextContract[spec.type](prover)(spec)
+ import contract.spec._
+
+ val mockTx = candidateBlock(0).newTransaction()
+ val d = mockTx
+ .outBox(100, contract.proverSig)
+ .withRegs(reg1 -> id.toColl)
+ val s1 = mockTx
+ .outBox(20, contract.dataInputsProp)
+ val s2 = mockTx
+ .outBox(20, contract.dataBoxProp)
+
+ val spendingTx = candidateBlock(1).newTransaction()
+ .withDataInputs(d)
+ .spending(s1, s2)
+
+ val newBox1 = spendingTx.outBox(10, contract.proverSig)
+
+ {
+ val in = spendingTx.inputs(0)
+ val res = in.runDsl()
+ res shouldBe CSigmaProp(TrivialProp.TrueProp)
+
+ val pr = prover.prove(in).get
+ contract.verifier.verify(in, pr) shouldBe true
+ }
+
+ {
+ val in = spendingTx.inputs(1)
+ val res = in.runDsl()
+ res shouldBe CSigmaProp(TrivialProp.TrueProp)
+ val pr = prover.prove(in).get
+ contract.verifier.verify(in, pr) shouldBe true
+ }
+ }
+
+}
diff --git a/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingContract.scala b/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingContract.scala
index 42b7157d76..1ef6cc5102 100644
--- a/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingContract.scala
+++ b/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingContract.scala
@@ -1,17 +1,17 @@
package sigmastate.utxo.benchmarks
import org.ergoplatform.ErgoLikeContext
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter}
import sigmastate.interpreter.Interpreter
-import sigmastate.utxo.{ErgoLikeTestInterpreter, SigmaContract}
+import sigmastate.utxo.SigmaContract
import scala.util.Try
abstract class CrowdFundingContract(
val timeout: Int,
val minToRaise: Long,
- val backerProver: ErgoLikeTestProvingInterpreter,
- val projectProver: ErgoLikeTestProvingInterpreter
+ val backerProver: ContextEnrichingTestProvingInterpreter,
+ val projectProver: ContextEnrichingTestProvingInterpreter
) extends SigmaContract {
//a blockchain node verifying a block containing a spending transaction
val verifier = new ErgoLikeTestInterpreter()(backerProver.IR)
diff --git a/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingKernelContract.scala b/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingKernelContract.scala
index 77b81706db..9bca79221c 100644
--- a/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingKernelContract.scala
+++ b/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingKernelContract.scala
@@ -8,7 +8,7 @@ import sigmastate.basics.DLogProtocol.{DLogInteractiveProver, DLogProverInput, F
import sigmastate.basics.VerifierMessage.Challenge
import scorex.crypto.hash.Blake2b256
import sigmastate._
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
+import sigmastate.helpers.ContextEnrichingTestProvingInterpreter
import sigmastate.interpreter.{CryptoConstants, Interpreter}
import sigmastate.utils.Helpers
@@ -17,8 +17,8 @@ import scala.util.Try
class CrowdFundingKernelContract(
timeout: Int,
minToRaise: Long,
- override val backerProver: ErgoLikeTestProvingInterpreter,
- override val projectProver: ErgoLikeTestProvingInterpreter
+ override val backerProver: ContextEnrichingTestProvingInterpreter,
+ override val projectProver: ContextEnrichingTestProvingInterpreter
) extends CrowdFundingContract(timeout, minToRaise, backerProver, projectProver) {
def isProven(pubKey: ProveDlog, message: Array[Byte]): projectProver.ProofT = {
@@ -57,7 +57,7 @@ class CrowdFundingKernelContract(
val c2 = Array(
ctx.currentHeight < timeout,
ctx.spendingTransaction.outputs.exists(out => {
- out.value >= minToRaise && util.Arrays.equals(out.propositionBytes, projectPubKey.bytes)
+ out.value >= minToRaise && util.Arrays.equals(out.propositionBytes, projectPubKey.toSigmaProp.bytes)
})
).forall(identity)
var proof: projectProver.ProofT = null
diff --git a/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingScriptContract.scala b/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingScriptContract.scala
index 2e6f429925..24057cca7f 100644
--- a/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingScriptContract.scala
+++ b/src/test/scala/sigmastate/utxo/benchmarks/CrowdFundingScriptContract.scala
@@ -1,10 +1,9 @@
package sigmastate.utxo.benchmarks
-import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix
import org.ergoplatform.ErgoLikeContext
import sigmastate.SBoolean
-import sigmastate.Values.Value
-import sigmastate.helpers.ErgoLikeTestProvingInterpreter
+import sigmastate.Values.{Value, SigmaPropValue}
+import sigmastate.helpers.ContextEnrichingTestProvingInterpreter
import sigmastate.interpreter.Interpreter
import sigmastate.interpreter.Interpreter._
import sigmastate.lang.Terms._
@@ -14,18 +13,18 @@ import scala.util.Try
class CrowdFundingScriptContract(
timeout: Int,
minToRaise: Long,
- override val backerProver: ErgoLikeTestProvingInterpreter,
- override val projectProver: ErgoLikeTestProvingInterpreter
+ override val backerProver: ContextEnrichingTestProvingInterpreter,
+ override val projectProver: ContextEnrichingTestProvingInterpreter
) extends CrowdFundingContract(timeout, minToRaise, backerProver, projectProver) {
- val compiledProposition: Value[SBoolean.type] = {
+ val compiledProposition: SigmaPropValue = {
val env = Map(
"timeout" -> timeout,
"minToRaise" -> minToRaise,
"backerPubKey" -> backerPubKey,
"projectPubKey" -> projectPubKey
)
- val compiledScript = compiler.compile(env,
+ val compiledScript = compiler.compileWithoutCosting(env,
"""{
| val c1 = HEIGHT >= timeout && backerPubKey
| val c2 = allOf(Coll(
@@ -37,8 +36,7 @@ class CrowdFundingScriptContract(
| ))
| c1 || c2
| }
- """.stripMargin,
- TestnetNetworkPrefix).asBoolValue
+ """.stripMargin).asSigmaProp
compiledScript
}
diff --git a/src/test/scala/sigmastate/utxo/benchmarks/CrowdfundingBenchmark.scala b/src/test/scala/sigmastate/utxo/benchmarks/CrowdfundingBenchmark.scala
index 2cf59bd69a..7309f546b5 100644
--- a/src/test/scala/sigmastate/utxo/benchmarks/CrowdfundingBenchmark.scala
+++ b/src/test/scala/sigmastate/utxo/benchmarks/CrowdfundingBenchmark.scala
@@ -1,21 +1,21 @@
package sigmastate.utxo.benchmarks
-import org.ergoplatform.{ErgoBox, ErgoLikeContext, ErgoLikeTransaction}
+import org.ergoplatform.{ErgoLikeContext, ErgoLikeTransaction, ErgoBox, ErgoScriptPredef}
import sigmastate.Values._
import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, SigmaTestingCommons}
import scalan.util.BenchmarkUtil._
class CrowdfundingBenchmark extends SigmaTestingCommons {
implicit lazy val IR = new TestingIRContext
def createTestContext(contract: CrowdFundingContract): ErgoLikeContext = {
- val outputToSpend = ErgoBox(10, TrueLeaf, 0)
+ val outputToSpend = ErgoBox(10, ErgoScriptPredef.TrueProp, 0)
//First case: height < timeout, project is able to claim amount of tokens not less than required threshold
val tx1Output1 = ErgoBox(contract.minToRaise, contract.projectPubKey, 0)
val tx1Output2 = ErgoBox(1, contract.projectPubKey, 0)
//normally this transaction would invalid, but we're not checking it in this test
- val tx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(tx1Output1, tx1Output2))
+ val tx = createTransaction(IndexedSeq(tx1Output1, tx1Output2))
val ctx = ErgoLikeContext(
currentHeight = contract.timeout - 1, // HEIGHT < timeout,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -34,9 +34,9 @@ class CrowdfundingBenchmark extends SigmaTestingCommons {
ignore("Evaluation by Precompiled Kernel(!!! ignore)") {
runTasks(nTasks) { iTask =>
//backer's prover with his private key
- val backerProver = new ErgoLikeTestProvingInterpreter
+ val backerProver = new ContextEnrichingTestProvingInterpreter
//project's prover with his private key
- val projectProver = new ErgoLikeTestProvingInterpreter
+ val projectProver = new ContextEnrichingTestProvingInterpreter
val contract = new CrowdFundingKernelContract(timeout, minToRaise, backerProver, projectProver)
val ctx = createTestContext(contract)
@@ -57,9 +57,9 @@ class CrowdfundingBenchmark extends SigmaTestingCommons {
ignore("Evaluation by Script Interpretation(!!! ignore)") {
runTasks(nTasks) { iTask =>
//backer's prover with his private key
- val backerProver = new ErgoLikeTestProvingInterpreter
+ val backerProver = new ContextEnrichingTestProvingInterpreter
//project's prover with his private key
- val projectProver = new ErgoLikeTestProvingInterpreter
+ val projectProver = new ContextEnrichingTestProvingInterpreter
val contract = new CrowdFundingScriptContract(timeout, minToRaise, backerProver, projectProver)
val ctx = createTestContext(contract)
diff --git a/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationSpecification.scala b/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationSpecification.scala
new file mode 100644
index 0000000000..9214d0bb12
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationSpecification.scala
@@ -0,0 +1,97 @@
+package sigmastate.utxo.blockchain
+
+import java.io.{File, FileWriter}
+
+import org.scalacheck.Gen
+import sigmastate.Values.{BooleanConstant, ErgoTree, GetVarBoolean, TrueLeaf}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestProvingInterpreter}
+import sigmastate.interpreter.ContextExtension
+import sigmastate.utxo.blockchain.BlockchainSimulationTestingCommons._
+
+import scala.collection.concurrent.TrieMap
+import scala.util.Random
+
+
+class BlockchainSimulationSpecification extends BlockchainSimulationTestingCommons {
+
+ implicit lazy val IR = new TestingIRContext
+
+ property("apply one valid block") {
+ val state = ValidationState.initialState()
+ val miner = new ErgoLikeTestProvingInterpreter()
+ val block = generateBlock(state, miner, 0)
+ val updStateTry = state.applyBlock(block)
+ updStateTry.isSuccess shouldBe true
+ }
+
+ property("too costly block") {
+ val state = ValidationState.initialState()
+ val miner = new ErgoLikeTestProvingInterpreter()
+ val block = generateBlock(state, miner, 0)
+ val updStateTry = state.applyBlock(block, maxCost = 1)
+ updStateTry.isSuccess shouldBe false
+ }
+
+ property("apply many blocks") {
+ val state = ValidationState.initialState()
+ val miner = new ErgoLikeTestProvingInterpreter()
+ checkState(state, miner, 0, randomDeepness)
+ }
+
+ property("apply many blocks with enriched context") {
+ val state = ValidationState.initialState()
+ val miner = new ErgoLikeTestProvingInterpreter()
+ val varId = 1.toByte
+ val prop = GetVarBoolean(varId).get.toSigmaProp
+ // unable to spend boxes without correct context extension
+ an[RuntimeException] should be thrownBy checkState(state, miner, 0, randomDeepness, Some(prop))
+
+ // spend boxes with context extension
+ val contextExtension = ContextExtension(Map(varId -> TrueLeaf))
+ checkState(state, miner, 0, randomDeepness, Some(prop), contextExtension)
+ }
+
+ ignore(s"benchmarking applying many blocks (!!! ignored)") {
+ val results = new TrieMap[Int, Long]
+
+ def bench(numberOfBlocks: Int): Unit = {
+
+ val state = ValidationState.initialState()
+ val miner = new ContextEnrichingTestProvingInterpreter()
+
+ val (_, time) = (0 until numberOfBlocks).foldLeft(state -> 0L) { case ((s, timeAcc), h) =>
+ val b = generateBlock(state, miner, h)
+
+ val t0 = System.currentTimeMillis()
+ val updStateTry = s.applyBlock(b)
+ val t = System.currentTimeMillis()
+
+ updStateTry shouldBe 'success
+ updStateTry.get -> (timeAcc + (t - t0))
+ }
+
+ println(s"Total time for $numberOfBlocks blocks: $time ms")
+ results.put(numberOfBlocks, time)
+ }
+
+ bench(100)
+ bench(200)
+ bench(300)
+ bench(400)
+
+ printResults(results.toMap)
+
+ def printResults(results: Map[Int, Long]): Unit = {
+ val file = new File("target/bench")
+ file.mkdirs()
+ val writer = new FileWriter(s"target/bench/result.csv", false)
+ val sorted = results.toList.sortBy { case (i, _) => i }
+ val header = sorted.map(_._1).mkString(",")
+ writer.write(s"$header\n")
+ val values = sorted.map(_._2).mkString(",")
+ writer.write(s"$values\n")
+ writer.flush()
+ writer.close()
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala b/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala
new file mode 100644
index 0000000000..320ef74bd0
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/blockchain/BlockchainSimulationTestingCommons.scala
@@ -0,0 +1,171 @@
+package sigmastate.utxo.blockchain
+
+import org.ergoplatform
+import org.ergoplatform._
+import scorex.crypto.authds.{ADDigest, ADKey, ADValue}
+import scorex.crypto.authds.avltree.batch.{Remove, BatchAVLProver, Insert}
+import scorex.crypto.hash.{Digest32, Blake2b256}
+import sigmastate.{GE, AvlTreeData, Values, AvlTreeFlags}
+import sigmastate.Values.{LongConstant, ErgoTree}
+import sigmastate.eval.IRContext
+import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons, ErgoTransactionValidator}
+
+import scala.collection.mutable
+import scala.util.{Random, Try}
+import scorex.util._
+import sigmastate.interpreter.ContextExtension
+import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
+import sigmastate.utxo.blockchain.BlockchainSimulationTestingCommons.{ValidationState, FullBlock}
+
+import scala.annotation.tailrec
+
+trait BlockchainSimulationTestingCommons extends SigmaTestingCommons {
+
+ @tailrec
+ protected final def checkState(state: ValidationState,
+ miner: ErgoLikeTestProvingInterpreter,
+ currentLevel: Int,
+ limit: Int,
+ propOpt: Option[ErgoTree] = None,
+ extension: ContextExtension = ContextExtension.empty): Unit = currentLevel match {
+ case i if i >= limit => ()
+ case _ =>
+ val block = generateBlock(state, miner, currentLevel, propOpt, extension)
+ val updStateTry = state.applyBlock(block)
+ updStateTry.isSuccess shouldBe true
+ checkState(updStateTry.get, miner, currentLevel + 1, limit, propOpt, extension)
+ }
+
+ protected def generateBlock(state: ValidationState,
+ prover: ErgoLikeTestProvingInterpreter,
+ height: Int,
+ propOpt: Option[ErgoTree] = None,
+ extension: ContextExtension = ContextExtension.empty): FullBlock = {
+ val prop: ErgoTree = propOpt.getOrElse(prover.dlogSecrets.head.publicImage.toSigmaProp)
+ val minerPubkey = prover.dlogSecrets.head.publicImage.pkBytes
+
+ val boxesToSpend = state.boxesReader.randomBoxes(50 + height)
+
+ val txs = boxesToSpend.map { box =>
+ val newBoxCandidate =
+ new ErgoBoxCandidate(10, prop, height, Seq(), Map())
+ val unsignedInput = new UnsignedInput(box.id)
+ val tx = UnsignedErgoLikeTransaction(IndexedSeq(unsignedInput), IndexedSeq(newBoxCandidate))
+ val context = ErgoLikeContext(height + 1,
+ state.state.lastBlockUtxoRoot,
+ minerPubkey,
+ IndexedSeq(box),
+ tx,
+ box,
+ extension)
+ val env = emptyEnv + (ScriptNameProp -> s"height_${state.state.currentHeight}_prove")
+ val proverResult = prover.prove(env, box.ergoTree, context, tx.messageToSign).get
+ proverResult.extension shouldBe extension
+
+ tx.toSigned(IndexedSeq(proverResult))
+ }.toIndexedSeq.ensuring(_.nonEmpty, s"Failed to create txs from boxes $boxesToSpend at height $height")
+
+ FullBlock(txs, minerPubkey)
+ }
+
+ protected def randomDeepness: Int = 10 + Random.nextInt(10)
+
+}
+
+object BlockchainSimulationTestingCommons extends SigmaTestingCommons {
+
+ private val MaxBlockCost = 700000
+
+ case class FullBlock(txs: IndexedSeq[ErgoLikeTransaction], minerPubkey: Array[Byte])
+
+ class InMemoryErgoBoxReader(prover: ValidationState.BatchProver) extends ErgoBoxReader {
+ private type KeyType = mutable.WrappedArray.ofByte
+
+ private def getKey(id: Array[Byte]): KeyType = new mutable.WrappedArray.ofByte(id)
+
+ private val boxes = mutable.Map[KeyType, ErgoBox]()
+
+ override def byId(boxId: ADKey): Try[ErgoBox] = byId(getKey(boxId))
+
+ def byId(boxId: KeyType): Try[ErgoBox] = Try(boxes(boxId))
+
+ def randomBoxes(howMany: Int): Iterable[ErgoBox] = {
+ scala.util.Random.shuffle(boxes.values).take(howMany)
+ }
+
+ def byTwoInts(r1Id: ErgoBox.RegisterId, int1: Int,
+ r2Id: ErgoBox.RegisterId, int2: Int): Option[ErgoBox] =
+ boxes.values.find { box =>
+ box.get(r1Id).getOrElse(LongConstant(int1 + 1)) == LongConstant(int1) &&
+ box.get(r2Id).getOrElse(LongConstant(int2 + 1)) == LongConstant(int2)
+ }
+
+ def allIds: Iterable[KeyType] = boxes.keys
+
+ def applyBlock(block: FullBlock): Unit = {
+ val toRemove = block.txs.flatMap(_.inputs).map(_.boxId)
+ toRemove.foreach(k => prover.performOneOperation(Remove(k)))
+ toRemove.foreach(k => boxes.remove(getKey(k)))
+
+ val toAdd = block.txs.flatMap(_.outputs)
+ toAdd.foreach(b => prover.performOneOperation(Insert(b.id, ADValue @@ b.bytes)))
+ toAdd.foreach(b => boxes.put(getKey(b.id), b))
+
+ prover.generateProof()
+ }
+
+ def digest: ADDigest = prover.digest
+ }
+
+
+ case class ValidationState(state: BlockchainState, boxesReader: InMemoryErgoBoxReader)(implicit IR: IRContext) {
+ val validator = new ErgoTransactionValidator
+
+ def applyBlock(block: FullBlock, maxCost: Int = MaxBlockCost): Try[ValidationState] = Try {
+ val height = state.currentHeight + 1
+
+ val blockCost = block.txs.foldLeft(0L) { case (accCost, tx) =>
+ validator.validate(tx, state.copy(currentHeight = height),
+ block.minerPubkey,
+ boxesReader) match {
+ case Left(throwable) => throw throwable
+ case Right(cost) => accCost + cost
+ }
+ }
+
+ assert(blockCost <= maxCost, s"Block cost $blockCost exceeds limit $maxCost")
+
+ boxesReader.applyBlock(block)
+ val newState = BlockchainState(height, state.lastBlockUtxoRoot.copy(digest = boxesReader.digest))
+ ValidationState(newState, boxesReader)
+ }
+ }
+
+ object ValidationState {
+ type BatchProver = BatchAVLProver[Digest32, Blake2b256.type]
+
+ val initBlock = FullBlock(
+ (0 until 10).map { i =>
+ val txId = Blake2b256.hash(i.toString.getBytes ++ scala.util.Random.nextString(12).getBytes).toModifierId
+ val boxes = (1 to 50).map(_ => ErgoBox(10, Values.TrueLeaf.toSigmaProp, i, Seq(), Map(), txId))
+ createTransaction(boxes)
+ },
+ ErgoLikeContext.dummyPubkey
+ )
+
+ def initialState(block: FullBlock = initBlock)(implicit IR: IRContext): ValidationState = {
+ val keySize = 32
+ val prover = new BatchProver(keySize, None)
+
+ val digest = prover.digest
+ val utxoRoot = AvlTreeData(digest, AvlTreeFlags.AllOperationsAllowed, keySize)
+
+ val bs = BlockchainState(currentHeight = -2, utxoRoot)
+
+ val boxReader = new InMemoryErgoBoxReader(prover)
+
+ ValidationState(bs, boxReader).applyBlock(block).get
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchange.scala b/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchange.scala
new file mode 100644
index 0000000000..3cee860569
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchange.scala
@@ -0,0 +1,114 @@
+package sigmastate.utxo.examples
+
+import org.ergoplatform.dsl.ContractSyntax.Token
+import special.sigma.Context
+import org.ergoplatform.ErgoBox.R4
+import special.collection.Coll
+import org.ergoplatform.dsl.{SigmaContractSyntax, ContractSpec, StdContracts}
+
+/** Contract specification for assets atomic exchange transactions.
+ * @param deadline block header after which the transfer can be cancelled.
+ * @param tokenId id of the token to exchange
+ * @param tokenBuyer The party, who wants to buy some amount of token with id == `tokenId`.
+ * @param tokenSeller The party, who wants to sell some amount of token with id == `tokenId`.
+ * */
+case class AssetsAtomicExchange[Spec <: ContractSpec]
+ (val deadline: Int, val tokenId: Coll[Byte],
+ val tokenBuyer: Spec#ProvingParty,
+ val tokenSeller: Spec#ProvingParty)
+ (implicit val spec: Spec)
+ extends SigmaContractSyntax with StdContracts
+{
+ import syntax._
+ def pkA = tokenBuyer.pubKey
+ def pkB = tokenSeller.pubKey
+
+ lazy val contractEnv = Env("pkA" -> pkA, "pkB" -> pkB, "deadline" -> deadline, "tokenId" -> tokenId)
+
+ lazy val buyerProp = proposition("buyer", { ctx: Context =>
+ import ctx._
+ (HEIGHT > deadline && pkA) || {
+ val tokenData = OUTPUTS(0).R2[Coll[(Coll[Byte], Long)]].get(0)
+ val knownId = OUTPUTS(0).R4[Coll[Byte]].get == SELF.id
+ allOf(Coll(
+ tokenData._1 == tokenId,
+ tokenData._2 >= 60L,
+ OUTPUTS(0).propositionBytes == pkA.propBytes,
+ knownId
+ ))
+ }
+ },
+ """{
+ | (HEIGHT > deadline && pkA) || {
+ | val tokenData = OUTPUTS(0).R2[Coll[(Coll[Byte], Long)]].get(0)
+ | val c = allOf(Coll(
+ | tokenData._1 == tokenId,
+ | tokenData._2 >= 60L,
+ | OUTPUTS(0).propositionBytes == pkA.propBytes,
+ | OUTPUTS(0).R4[Coll[Byte]].get == SELF.id
+ | ))
+ | c
+ | }
+ |}
+ """.stripMargin)
+
+ lazy val sellerProp = proposition("seller", {ctx: Context =>
+ import ctx._
+ (HEIGHT > deadline && pkB) || {
+ val knownBoxId = OUTPUTS(1).R4[Coll[Byte]].get == SELF.id
+ allOf(Coll(
+ OUTPUTS(1).value >= 100,
+ knownBoxId,
+ OUTPUTS(1).propositionBytes == pkB.propBytes
+ ))
+ }
+ },
+ """{
+ | (HEIGHT > deadline && pkB) ||
+ | allOf(Coll(
+ | OUTPUTS(1).value >= 100,
+ | OUTPUTS(1).R4[Coll[Byte]].get == SELF.id,
+ | OUTPUTS(1).propositionBytes == pkB.propBytes
+ | ))
+ |}
+ """.stripMargin)
+
+ lazy val buyerSignature = proposition("buyerSignature", _ => pkA, "pkA")
+ lazy val sellerSignature = proposition("sellerSignature", _ => pkB, "pkB")
+
+ import spec._
+
+ /** This methods starts exchange protocol using two boxes.
+ * It requires that the boxes are protected by `buyerSignature` and `sellerSignature` correspondingly.
+ * It creates a transaction in the target block with two holder boxes and two change boxes.
+ * @return a pair of holder boxes
+ */
+ def startExchange(targetBlock: BlockCandidate, buyerErgBox: OutBox, sellerTokenBox: OutBox, ergAmt: Long, tokenAmt: Token): (OutBox, OutBox) = {
+ require(buyerErgBox.propSpec == buyerSignature && sellerTokenBox.propSpec == sellerSignature)
+
+ val tx = targetBlock.newTransaction().spending(buyerErgBox, sellerTokenBox)
+ val (buyerHolder, _) = transferErgWithChange(tx, buyerErgBox, buyerProp, ergAmt)
+ val (sellerHolder, _) = transferTokenWithChange(tx, sellerTokenBox, sellerProp, tokenAmt)
+ (buyerHolder, sellerHolder)
+ }
+
+ /** Having two boxes prepared for token exchange, this method creates spending transaction which
+ * completes the exchange protocol.
+ * @param targetBlock block in which the spending transaction will be created
+ * @param buyerHolder holder box with buyer's Ergs
+ * @param sellerHolder holder box with seller's tokens
+ * @return a pair of boxes with buyers's tokens and seller's Ergs
+ * */
+ def finishExchange(targetBlock: BlockCandidate, buyerHolder: OutBox, sellerHolder: OutBox): (OutBox, OutBox) = {
+ require(buyerHolder.propSpec == buyerProp && sellerHolder.propSpec == sellerProp)
+ val spendingTx = targetBlock.newTransaction().spending(buyerHolder, sellerHolder)
+ val buyerTokens = spendingTx
+ .outBox(sellerHolder.value, buyerSignature)
+ .withTokens(Token(tokenId, sellerHolder.token(tokenId).value))
+ .withRegs(R4 -> buyerHolder.id)
+ val sellerErgs = spendingTx
+ .outBox(buyerHolder.value, sellerSignature)
+ .withRegs(R4 -> sellerHolder.id)
+ (buyerTokens, sellerErgs)
+ }
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeErgoTests.scala b/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeErgoTests.scala
new file mode 100644
index 0000000000..67304c39b1
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeErgoTests.scala
@@ -0,0 +1,55 @@
+package sigmastate.utxo.examples
+
+import sigmastate.helpers.SigmaTestingCommons
+import org.ergoplatform.dsl.ContractSyntax.Token
+import org.ergoplatform.dsl.ErgoContractSpec
+import special.collection.Coll
+import scorex.crypto.hash.Blake2b256
+
+class AssetsAtomicExchangeErgoTests extends SigmaTestingCommons { suite =>
+ lazy val spec = new ErgoContractSpec()(new TestingIRContext)
+ private lazy val tokenId: Coll[Byte] = spec.Coll(Blake2b256("token1"))
+ lazy val buyer = spec.ProvingParty("Alice")
+ lazy val seller = spec.ProvingParty("Bob")
+ val ergAmt = 100
+ val tAmt = 60
+ lazy val buyerBoxId: Coll[Byte] = spec.Coll(Blake2b256("BBox"))
+ lazy val sellerBoxId: Coll[Byte] = spec.Coll(Blake2b256("SBox"))
+
+ // TODO should be enabled after ErgoContractSpec is implemented
+ ignore("atomic exchange spec") {
+ val contract = AssetsAtomicExchange[spec.type](70, tokenId, buyer, seller)(spec)
+ import contract.spec._
+
+ // ARRANGE
+// val startBlock = getBlock(50)
+// val txs = startBlock.getTransactions()
+// val buyerBox = txs(0).outputs(0)
+// val sellerBox = getBoxesByParty(seller).collectFirst { case b if b.value > ergAmt => b }.get
+ val buyerBox = getBoxById(buyerBoxId)
+ val sellerBox = getBoxById(sellerBoxId)
+ val txCtx = newTransactionContext
+ // ACT
+
+
+ // start exchange protocol
+ val (ergHolder, tokenHolder) = contract.startExchange(txCtx.block, buyerBox, sellerBox, 100, Token(contract.tokenId, 60))
+
+ // setup spending transaction
+ val (buyerTokens, sellerErgs) = contract.finishExchange(txCtx.block, ergHolder, tokenHolder)
+
+ // ASSERT
+ val input0 = buyerTokens.tx.inputs(0)
+// val res = input0.runDsl()
+// res shouldBe CSigmaProp(TrivialProp.TrueProp)
+
+ val buyerProof = contract.tokenBuyer.prove(input0).get
+
+ txCtx.attachProof(input0 -> buyerProof)
+ try {
+ txCtx.submit()
+ } catch {
+ case t: Throwable =>
+ }
+ }
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeSpecification.scala b/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeSpecification.scala
deleted file mode 100644
index d1a2cc5855..0000000000
--- a/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeSpecification.scala
+++ /dev/null
@@ -1,270 +0,0 @@
-package sigmastate.utxo.examples
-
-import org.ergoplatform.ErgoBox.R4
-import org.ergoplatform._
-import scorex.crypto.hash.Blake2b256
-import sigmastate.SCollection.SByteArray
-import sigmastate.Values.{BlockValue, ByteArrayConstant, ConcreteCollection, IntConstant, LongConstant, ShortConstant, SigmaPropConstant, ValDef, ValUse, Value}
-import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
-import sigmastate.interpreter.ContextExtension
-import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
-import sigmastate.utxo._
-import sigmastate.lang.Terms._
-import sigmastate.utxo._
-
-/**
- * An example of an atomic ergo <=> asset exchange.
- * Let's assume that Alice is willing to buy 60 assets of type "token1" for 100 ergo coins, and Bob
- * is willing to be a counterparty in this deal.
- *
- * Alice is creating a box of 100 coins protected by the script "I demand a spending transaction to create a box
- * which is protected by my public key pubkey_A and contains at least 60 assets of type "token1" and also 1 ergo coin"
- * (the last condition ensures that the box is easily spendable).
- *
- * Similarly, Bob is creating a box protected by a script like "I demand a spending transaction to create a box
- * which is protected by my public ket pubkey_B and contains at least 100 ergo tokens".
- *
- * (Please note that we are skipping some practically important details, for example, order cancellation conditions).
- *
- * Please note that once both box are on the blockchain, a correct exchange transaction could be created and
- * posted by anyone.
- *
- * Please note that more complex protocols could be build on top of the atomic exchange. For example, transactions
- * creating both boxes could be sent off-chain to a matching service, and be posted on the blockchain along with
- * the exchange transaction.
- *
- * //todo: make an example of multiple orders being matched
- */
-class AssetsAtomicExchangeSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
-
- /**
- * A simpler example with single-chain atomic exchange contracts.
- */
- property("atomic exchange") {
- val tokenBuyer = new ErgoLikeTestProvingInterpreter
- val tokenSeller = new ErgoLikeTestProvingInterpreter
- val verifier = new ErgoLikeTestInterpreter
-
- val tokenId = Blake2b256("token1")
- val deadline = 70
- val tokenBuyerKey = tokenBuyer.dlogSecrets.head.publicImage
- val tokenSellerKey = tokenBuyer.dlogSecrets.head.publicImage
-
- def extractToken(box: Value[SBox.type]) = ByIndex(
- ExtractRegisterAs(box, ErgoBox.TokensRegId)(ErgoBox.STokensRegType).get, 0)
-
- val buyerProp = BlockValue(
- Vector(
- ValDef(1, ByIndex(Outputs, 0)),
- // token
- ValDef(2, extractToken(ValUse(1, SBox)))
- ),
- SigmaOr(List(
- SigmaAnd(List(
- GT(Height, deadline).toSigmaProp,
- SigmaPropConstant(tokenSellerKey))
- ),
- AND(
- // extract toked id
- EQ(SelectField(ValUse(2, STuple(SByteArray, SLong)), 1), ByteArrayConstant(tokenId)),
- // extract token amount
- GE(SelectField(ValUse(2, STuple(SByteArray, SLong)), 2), LongConstant(60)),
- // right protection buyer
- EQ(ExtractScriptBytes(ValUse(1, SBox)), SigmaPropConstant(tokenSellerKey).propBytes),
- EQ(ExtractRegisterAs(ValUse(1, SBox), R4, SOption(SCollection(SByte))).get, ExtractId(Self))
- ).toSigmaProp
- ))
- ).asBoolValue
-
- val buyerEnv = Map(
- ScriptNameProp -> "buyer",
- "pkA" -> tokenBuyerKey, "deadline" -> deadline, "token1" -> tokenId)
- val altBuyerProp = compileWithCosting(buyerEnv,
- """(HEIGHT > deadline && pkA) || {
- | val tokenData = OUTPUTS(0).R2[Coll[(Coll[Byte], Long)]].get(0)
- | allOf(Coll(
- | tokenData._1 == token1,
- | tokenData._2 >= 60L,
- | OUTPUTS(0).propositionBytes == pkA.propBytes,
- | OUTPUTS(0).R4[Coll[Byte]].get == SELF.id
- | ))
- |}
- """.stripMargin).asBoolValue
- altBuyerProp shouldBe buyerProp
-
- val sellerProp = BlockValue(
- Vector(
- ValDef(1, SigmaPropConstant(tokenSellerKey)),
- ValDef(2, ByIndex(Outputs, 1))
- ),
- SigmaOr(
- SigmaAnd(
- GT(Height, deadline).toSigmaProp,
- ValUse(1, SSigmaProp)),
- AND(
- GE(ExtractAmount(ValUse(2, SBox)), LongConstant(100)),
- EQ(ExtractRegisterAs(ValUse(2, SBox), R4, SOption(SCollection(SByte))).get, ExtractId(Self)),
- // right protection seller
- EQ(ExtractScriptBytes(ValUse(2, SBox)), ValUse(1, SSigmaProp).propBytes)
- ).toSigmaProp
- )
- ).asBoolValue
-
- val sellerEnv = Map(
- ScriptNameProp -> "seller",
- "pkB" -> tokenSellerKey, "deadline" -> deadline)
- val altSellerProp = compileWithCosting(sellerEnv,
- """ (HEIGHT > deadline && pkB) ||
- | allOf(Coll(
- | OUTPUTS(1).value >= 100,
- | OUTPUTS(1).R4[Coll[Byte]].get == SELF.id,
- | OUTPUTS(1).propositionBytes == pkB.propBytes
- | ))
- """.stripMargin).asBoolValue
-
- altSellerProp shouldBe sellerProp
-
- //tx inputs
- val input0 = ErgoBox(100, buyerProp, 0)
- val input1 = ErgoBox(1, sellerProp, 0, Seq(tokenId -> 60))
-
- //tx outputs
- val newBox1 = ErgoBox(1, tokenBuyerKey, 0, Seq(tokenId -> 60), Map(R4 -> ByteArrayConstant(input0.id)))
- val newBox2 = ErgoBox(100, tokenSellerKey, 0, Seq(), Map(R4 -> ByteArrayConstant(input1.id)))
- val newBoxes = IndexedSeq(newBox1, newBox2)
-
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
-
- val buyerCtx = ErgoLikeContext(
- currentHeight = 50,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(input0, input1),
- spendingTransaction,
- self = input0)
-
- //Though we use separate provers below, both inputs do not contain any secrets, thus
- //a spending transaction could be created and posted by anyone.
- val pr = tokenBuyer.prove(emptyEnv + (ScriptNameProp -> "tokenBuyer_prove"), buyerProp, buyerCtx, fakeMessage).get
- verifier.verify(emptyEnv + (ScriptNameProp -> "tokenBuyer_verify"), buyerProp, buyerCtx, pr, fakeMessage).get._1 shouldBe true
-
- val sellerCtx = ErgoLikeContext(
- currentHeight = 50,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(input0, input1),
- spendingTransaction,
- self = input1)
-
- val pr2 = tokenSeller.prove(sellerProp, sellerCtx, fakeMessage).get
- verifier.verify(sellerProp, sellerCtx, pr2, fakeMessage).get._1 shouldBe true
-
- }
-
- /**
- * An example with order contracts which could be only partially filled
- */
- property("partial filling") {
- val tokenBuyer = new ErgoLikeTestProvingInterpreter
- val tokenSeller = new ErgoLikeTestProvingInterpreter
- val verifier = new ErgoLikeTestInterpreter
-
- val tokenId = Blake2b256("token1")
- val deadline = 70L
- val tokenBuyerKey = tokenBuyer.dlogSecrets.head.publicImage
- val tokenSellerKey = tokenBuyer.dlogSecrets.head.publicImage
-
- val buyerEnv = Map("pkA" -> tokenBuyerKey, "deadline" -> deadline, "token1" -> tokenId)
-
- //the contract assumes no tokens in the input box
- val buyerProp = compile(buyerEnv,
- """(HEIGHT > deadline && pkA) || {
- |
- | val outIdx = getVar[Short](127).get
- | val out = OUTPUTS(outIdx)
- | val tokenData = out.R2[Coll[(Coll[Byte], Long)]].get(0)
- | val tokenId = tokenData._1
- | val tokenValue = tokenData._2
- | val outValue = out.value
- | val price = 500
- |
- | allOf(Coll(
- | tokenId == token1,
- | tokenValue >= 1,
- | (SELF.value - outValue) <= tokenValue * price,
- | out.propositionBytes == pkA.propBytes,
- | out.R4[Coll[Byte]].get == SELF.id
- | ))
- |}
- """.stripMargin).asBoolValue
-
- val sellerEnv = Map("pkB" -> tokenSellerKey, "deadline" -> deadline)
- val sellerProp = compile(sellerEnv,
- """ (HEIGHT > deadline && pkB) || {
- | val outIdx = getVar[Short](127).get
- | val out = OUTPUTS(outIdx)
- |
- | val tokenData = out.R2[Coll[(Coll[Byte], Long)]].get(0)
- | val tokenId = tokenData._1
- | val selfTokenData = SELF.R2[Coll[(Coll[Byte], Long)]].get(0)
- | val selfTokenId = selfTokenData._1
- | val tokenValue = tokenData._2
- | val selfTokenValue = selfTokenData._2
- |
- | val selfValue = SELF.value
- | val outValue = out.value
- |
- | val sold = selfTokenValue - tokenValue
- |
- | val price = 495
- |
- | allOf(Coll(
- | sold >= 1,
- | (outValue - selfValue) >= sold*price,
- | out.R4[Coll[Byte]].get == SELF.id,
- | out.propositionBytes == pkB.propBytes
- | ))
- | }
- """.stripMargin).asBoolValue
-
- //tx inputs
- val input0 = ErgoBox(10000, buyerProp, 0)
- val input1 = ErgoBox(0, sellerProp, 0, Seq(tokenId -> 60))
-
- //tx outputs
- val newBox1 = ErgoBox(5050, tokenBuyerKey, 0, Seq(tokenId -> 10), Map(R4 -> ByteArrayConstant(input0.id)))
- val newBox2 = ErgoBox(4950, tokenSellerKey, 0, Seq(tokenId -> 50), Map(R4 -> ByteArrayConstant(input1.id)))
- val newBoxes = IndexedSeq(newBox1, newBox2)
-
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
-
- val buyerCtx = ErgoLikeContext(
- currentHeight = 50,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(input0, input1),
- spendingTransaction,
- self = input0,
- extension = ContextExtension(Map(Byte.MaxValue -> ShortConstant(0))))
-
- //Though we use separate provers below, both inputs do not contain any secrets, thus
- //a spending transaction could be created and posted by anyone.
- val pr = tokenBuyer.withContextExtender(Byte.MaxValue, ShortConstant(0)).prove(buyerProp, buyerCtx, fakeMessage).get
- verifier.verify(buyerProp, buyerCtx, pr, fakeMessage).get._1 shouldBe true
-
- val sellerCtx = ErgoLikeContext(
- currentHeight = 50,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(input0, input1),
- spendingTransaction,
- self = input1,
- extension = ContextExtension(Map(Byte.MaxValue -> ShortConstant(1))))
-
- val pr2 = tokenSeller.withContextExtender(Byte.MaxValue, ShortConstant(1)).prove(sellerProp, sellerCtx, fakeMessage).get
- verifier.verify(sellerProp, sellerCtx, pr2, fakeMessage).get._1 shouldBe true
-
- }
-}
diff --git a/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeTests.scala b/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeTests.scala
new file mode 100644
index 0000000000..ae3c1b527c
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchangeTests.scala
@@ -0,0 +1,159 @@
+package sigmastate.utxo.examples
+
+import org.ergoplatform.{Height, Outputs, ErgoBox, Self}
+import org.ergoplatform.ErgoBox.R4
+import sigmastate.helpers.SigmaTestingCommons
+import org.ergoplatform.dsl.ContractSyntax.Token
+import org.ergoplatform.dsl.TestContractSpec
+import scorex.crypto.hash.Blake2b256
+import sigmastate.SCollection.SByteArray
+import sigmastate._
+import sigmastate.Values.{LongConstant, BlockValue, Value, ByteArrayConstant, ValDef, ValUse}
+import sigmastate.eval.CSigmaProp
+import sigmastate.eval.Extensions._
+import sigmastate.lang.Terms.ValueOps
+import sigmastate.utxo._
+import special.collection.Coll
+import special.sigma.Extensions._
+
+/** An example of an atomic ergo <=> asset exchange.
+ * Let's assume that Alice is willing to buy 60 assets of type "token1" for 100 ergo coins, and Bob
+ * is willing to be a counterparty in this deal.
+ *
+ * Alice is creating a box of 100 coins protected by the script "I demand a spending transaction to create a box
+ * which is protected by my public key pubkey_A and contains at least 60 assets of type "token1" and also 1 ergo coin"
+ * (the last condition ensures that the box is easily spendable).
+ *
+ * Similarly, Bob is creating a box protected by a script like "I demand a spending transaction to create a box
+ * which is protected by my public ket pubkey_B and contains at least 100 ergo tokens".
+ *
+ * (Please note that we are skipping some practically important details, for example, order cancellation conditions).
+ *
+ * Please note that once both box are on the blockchain, a correct exchange transaction could be created and
+ * posted by anyone.
+ *
+ * Please note that more complex protocols could be build on top of the atomic exchange. For example, transactions
+ * creating both boxes could be sent off-chain to a matching service, and be posted on the blockchain along with
+ * the exchange transaction.
+ *
+ * //todo: make an example of multiple orders being matched
+ */
+class AssetsAtomicExchangeTests extends SigmaTestingCommons { suite =>
+ lazy val spec = TestContractSpec(suite)(new TestingIRContext)
+ private lazy val tokenId: Coll[Byte] = spec.Coll(Blake2b256("token1"))
+ lazy val buyer = spec.ProvingParty("Alice")
+ lazy val seller = spec.ProvingParty("Bob")
+
+ property("atomic exchange spec") {
+ val contract = new AssetsAtomicExchange[spec.type](70, tokenId, buyer, seller)(spec) {
+ import spec._
+
+ def extractToken(box: Value[SBox.type]) = ByIndex(
+ ExtractRegisterAs(box, ErgoBox.TokensRegId)(ErgoBox.STokensRegType).get, 0)
+
+ val expectedBuyerTree = BlockValue(
+ Vector(
+ ValDef(1, ByIndex(Outputs, 0)),
+ // token
+ ValDef(2, extractToken(ValUse(1, SBox)))
+ ),
+ SigmaOr(List(
+ SigmaAnd(List(
+ GT(Height, deadline).toSigmaProp,
+ tokenBuyer.pubKey.toTreeData.asSigmaProp
+ )),
+ AND(
+ // extract toked id
+ EQ(SelectField(ValUse(2, STuple(SByteArray, SLong)), 1), ByteArrayConstant(tokenId.toArray)),
+ // extract token amount
+ GE(SelectField(ValUse(2, STuple(SByteArray, SLong)), 2), LongConstant(60)),
+ // right protection buyer
+ EQ(ExtractScriptBytes(ValUse(1, SBox)), tokenBuyer.pubKey.toTreeData.asSigmaProp.propBytes),
+ EQ(ExtractRegisterAs(ValUse(1, SBox), R4, SOption(SCollection(SByte))).get, ExtractId(Self))
+ ).toSigmaProp
+ ))
+ ).asBoolValue
+ buyerProp.ergoTree.proposition shouldBe expectedBuyerTree
+ }
+ import contract.spec._
+
+ // ARRANGE
+ // block, tx, and output boxes which we will spend
+ val mockTx = candidateBlock(0).newTransaction()
+ // setup buyer's box from which we will transfer Ergs to holder box
+ val mockBuyerBox = mockTx
+ .outBox(100, contract.buyerSignature)
+ // setup seller's box from which we will transfer tokens to holder boxes
+ val mockSellerBox = mockTx
+ .outBox(MinErgValue * 2, contract.sellerSignature)
+ .withTokens(Token(contract.tokenId, 60))
+
+ // ACT
+ val startBlock = candidateBlock(50)
+ // start exchange protocol
+ val (ergHolder, tokenHolder) = contract.startExchange(startBlock, mockBuyerBox, mockSellerBox, 100, Token(contract.tokenId, 60))
+ // setup spending transaction
+ val (buyerTokens, sellerErgs) = contract.finishExchange(startBlock, ergHolder, tokenHolder)
+
+ // ASSERT
+ val input0 = buyerTokens.tx.inputs(0)
+ val res = input0.runDsl()
+ res shouldBe CSigmaProp(TrivialProp.TrueProp)
+
+ val buyerProof = contract.tokenBuyer.prove(input0).get
+ contract.verifier.verify(input0, buyerProof) shouldBe true
+
+ val input1 = buyerTokens.tx.inputs(1)
+ val res1 = input1.runDsl()
+ res1 shouldBe CSigmaProp(TrivialProp.TrueProp)
+ val sellerProof = contract.tokenSeller.prove(input1).get
+ contract.verifier.verify(input1, sellerProof) shouldBe true
+ }
+
+ property("partial filling") {
+ val contract = AssetsPartialFilling[spec.type](70, tokenId, buyer, seller)(spec)
+ import contract.spec._
+
+ // ARRANGE
+ // block, tx, and output boxes which will be spent
+ val mockTx = candidateBlock(0).newTransaction()
+ // setup buyer's box from which we will transfer Ergs to holder box
+ val mockBuyerBox = mockTx
+ .outBox(10000, contract.buyerSignature)
+ // setup seller's box from which we will transfer tokens to holder boxes
+ val mockSellerBox = mockTx
+ .outBox(MinErgValue * 2, contract.sellerSignature)
+ .withTokens(Token(contract.token1, 60))
+
+ // ACT
+ val startBlock = candidateBlock(0)
+ // start exchange protocol
+ val (buyerHolder, sellerHolder) = contract.startExchange(startBlock, mockBuyerBox, mockSellerBox, 10000, Token(contract.token1, 60))
+
+ // setup spending transaction
+ val spendingTx = candidateBlock(0).newTransaction().spending(buyerHolder, sellerHolder)
+ spendingTx.outBox(5050, contract.buyerSignature)
+ .withTokens(Token(contract.token1, 10))
+ .withRegs(R4 -> buyerHolder.id)
+ spendingTx.outBox(4950 + sellerHolder.value, contract.sellerSignature)
+ .withTokens(Token(contract.token1, 50))
+ .withRegs(R4 -> sellerHolder.id)
+
+ // ASSERT
+ val input0 = spendingTx.inputs(0)
+ val buyerExt = Map(Byte.MaxValue -> toAnyValue(0.toShort))
+ val res = input0.runDsl(buyerExt)
+ res shouldBe CSigmaProp(TrivialProp.TrueProp)
+
+ val buyerProof = contract.tokenBuyer.prove(input0, buyerExt).get
+ contract.verifier.verify(input0, buyerProof) shouldBe true
+
+ val input1 = spendingTx.inputs(1)
+ val sellerExt = Map(Byte.MaxValue -> toAnyValue(1.toShort))
+ val res1 = input1.runDsl(sellerExt)
+ res1 shouldBe CSigmaProp(TrivialProp.TrueProp)
+ val sellerProof = contract.tokenSeller.prove(input1, sellerExt).get
+ contract.verifier.verify(input1, sellerProof) shouldBe true
+ }
+
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala b/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala
new file mode 100644
index 0000000000..d223acc47c
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala
@@ -0,0 +1,143 @@
+package sigmastate.utxo.examples
+
+import org.ergoplatform.dsl.ContractSyntax.Token
+import special.sigma.Context
+import org.ergoplatform.ErgoBox.R4
+import special.collection.Coll
+import org.ergoplatform.dsl.{SigmaContractSyntax, ContractSpec, StdContracts}
+
+/**
+ * @param tokenBuyer The party, who wants to buy some amount of token with id == `tokenId`.
+ * @param tokenSeller The party, who wants to sell some amount of token with id == `tokenId`. */
+case class AssetsPartialFilling[Spec <: ContractSpec]
+ (deadline: Int, token1: Coll[Byte],
+ tokenBuyer: Spec#ProvingParty,
+ tokenSeller: Spec#ProvingParty)
+ (implicit val spec: Spec) extends SigmaContractSyntax with StdContracts
+{
+ import syntax._
+
+ def pkA = tokenBuyer.pubKey
+ def pkB = tokenSeller.pubKey
+
+ lazy val contractEnv = Env("pkA" -> pkA, "pkB" -> pkB, "deadline" -> deadline, "token1" -> token1)
+
+ lazy val buyerProp = proposition("buyer", { ctx: Context =>
+ import ctx._
+ (HEIGHT > deadline && pkA) || {
+
+ val outIdx = getVar[Short](127).get
+ val out = OUTPUTS(outIdx)
+ val tokenData = out.R2[Coll[(Coll[Byte], Long)]].get(0)
+ val tokenId = tokenData._1
+ val tokenValue = tokenData._2
+ val outValue = out.value
+ val price = 500
+
+ allOf(Coll(
+ tokenId == token1,
+ tokenValue >= 1,
+ (SELF.value - outValue) <= tokenValue * price,
+ out.propositionBytes == pkA.propBytes,
+ out.R4[Coll[Byte]].get == SELF.id
+ ))
+ }
+ },
+ """(HEIGHT > deadline && pkA) || {
+ |
+ | val outIdx = getVar[Short](127).get
+ | val out = OUTPUTS(outIdx)
+ | val tokenData = out.R2[Coll[(Coll[Byte], Long)]].get(0)
+ | val tokenId = tokenData._1
+ | val tokenValue = tokenData._2
+ | val outValue = out.value
+ | val price = 500
+ |
+ | allOf(Coll(
+ | tokenId == token1,
+ | tokenValue >= 1,
+ | (SELF.value - outValue) <= tokenValue * price,
+ | out.propositionBytes == pkA.propBytes,
+ | out.R4[Coll[Byte]].get == SELF.id
+ | ))
+ |}
+ """.stripMargin)
+
+ lazy val sellerProp = proposition("seller", {ctx: Context =>
+ import ctx._
+ (HEIGHT > deadline && pkB) || {
+ val outIdx = getVar[Short](127).get
+ val out = OUTPUTS(outIdx)
+
+ val tokenData = out.R2[Coll[(Coll[Byte], Long)]].get(0)
+ val tokenId = tokenData._1
+ val tokenValue = tokenData._2
+
+ val selfTokenData = SELF.R2[Coll[(Coll[Byte], Long)]].get(0)
+ val selfTokenId = selfTokenData._1
+ val selfTokenValue = selfTokenData._2
+
+ val selfValue = SELF.value
+ val outValue = out.value
+
+ val sold = selfTokenValue - tokenValue
+
+ val price = 495
+ val outR4 = out.R4[Coll[Byte]].get
+
+ allOf(Coll(
+ sold >= 1,
+ (outValue - selfValue) >= sold*price,
+ outR4 == SELF.id,
+ out.propositionBytes == pkB.propBytes
+ ))
+ }
+ },
+ """ (HEIGHT > deadline && pkB) || {
+ | val outIdx = getVar[Short](127).get
+ | val out = OUTPUTS(outIdx)
+ |
+ | val tokenData = out.R2[Coll[(Coll[Byte], Long)]].get(0)
+ | val tokenId = tokenData._1
+ | val tokenValue = tokenData._2
+ |
+ | val selfTokenData = SELF.R2[Coll[(Coll[Byte], Long)]].get(0)
+ | val selfTokenId = selfTokenData._1
+ | val selfTokenValue = selfTokenData._2
+ |
+ | val selfValue = SELF.value
+ | val outValue = out.value
+ |
+ | val sold = selfTokenValue - tokenValue
+ |
+ | val price = 495
+ |
+ | allOf(Coll(
+ | sold >= 1,
+ | (outValue - selfValue) >= sold*price,
+ | out.R4[Coll[Byte]].get == SELF.id,
+ | out.propositionBytes == pkB.propBytes
+ | ))
+ | }
+ """.stripMargin)
+
+ lazy val buyerSignature = proposition("buyerSignature", _ => pkA, "pkA")
+ lazy val sellerSignature = proposition("sellerSignature", _ => pkB, "pkB")
+
+ import spec._
+
+ /** This methods starts exchange protocol using two boxes.
+ * It requires that the boxes are protected by `buyerSignature` and `sellerSignature` correspondingly.
+ * It creates a transaction in the target block with two holder boxes and two change boxes.
+ * @return a pair of holder boxes
+ */
+ def startExchange(targetBlock: BlockCandidate, buyerErgBox: OutBox, sellerTokenBox: OutBox, ergAmt: Long, tokenAmt: Token): (OutBox, OutBox) = {
+ require(buyerErgBox.propSpec == buyerSignature && sellerTokenBox.propSpec == sellerSignature)
+
+ val tx = targetBlock.newTransaction().spending(buyerErgBox, sellerTokenBox)
+ val (buyerHolder, _) = transferErgWithChange(tx, buyerErgBox, buyerProp, ergAmt)
+ val (sellerHolder, _) = transferTokenWithChange(tx, sellerTokenBox, sellerProp, tokenAmt)
+ (buyerHolder, sellerHolder)
+ }
+
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/AtomicSwapExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/AtomicSwapExampleSpecification.scala
index 1a76f75bcd..89f27fdfb2 100644
--- a/src/test/scala/sigmastate/utxo/examples/AtomicSwapExampleSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/AtomicSwapExampleSpecification.scala
@@ -6,9 +6,9 @@ import scorex.utils.Random
import sigmastate.Values._
import sigmastate._
import interpreter.Interpreter._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.lang.Terms._
-import sigmastate.utxo.{ErgoLikeTestInterpreter, GetVar, SizeOf}
+import sigmastate.utxo.{GetVar, SizeOf}
class AtomicSwapExampleSpecification extends SigmaTestingCommons {
implicit lazy val IR = new TestingIRContext
@@ -23,8 +23,8 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons {
*/
property("atomic cross-chain trading") {
val x = Random.randomBytes(32)
- val proverA = (new ErgoLikeTestProvingInterpreter).withContextExtender(1, ByteArrayConstant(x))
- val proverB = new ErgoLikeTestProvingInterpreter
+ val proverA = (new ContextEnrichingTestProvingInterpreter).withContextExtender(1, ByteArrayConstant(x))
+ val proverB = new ContextEnrichingTestProvingInterpreter
val pubkeyA = proverA.dlogSecrets.head.publicImage
val pubkeyB = proverB.dlogSecrets.head.publicImage
val verifier = new ErgoLikeTestInterpreter
@@ -42,17 +42,17 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons {
"height1" -> height1, "height2" -> height2,
"deadlineA" -> deadlineA, "deadlineB" -> deadlineB,
"pubkeyA" -> pubkeyA, "pubkeyB" -> pubkeyB, "hx" -> hx)
- val prop1 = compileWithCosting(env,
+ val prop1 = compile(env,
"""{
| anyOf(Coll(
| HEIGHT > height1 + deadlineA && pubkeyA,
| pubkeyB && blake2b256(getVar[Coll[Byte]](1).get) == hx
| ))
- |}""".stripMargin).asBoolValue
+ |}""".stripMargin).asSigmaProp
//chain1 script
val prop1Tree = SigmaOr(
- SigmaAnd(GT(Height, Plus(IntConstant(height1), IntConstant(deadlineA))).toSigmaProp, pubkeyA),
+ SigmaAnd(GT(Height, IntConstant(height1 + deadlineA)).toSigmaProp, pubkeyA),
SigmaAnd(pubkeyB, EQ(CalcBlake2b256(GetVarByteArray(1).get), hx).toSigmaProp)
)
prop1 shouldBe prop1Tree
@@ -69,14 +69,14 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons {
| ))
|}
""".stripMargin
- val prop2 = compileWithCosting(env, script2).asBoolValue
+ val prop2 = compile(env, script2).asSigmaProp
//chain2 script
val prop2Tree = BlockValue(
Vector(ValDef(1, GetVarByteArray(1).get)),
SigmaOr(
SigmaAnd(
- GT(Height, Plus(IntConstant(height2), IntConstant(deadlineB))).toSigmaProp,
+ GT(Height, IntConstant(height2 + deadlineB)).toSigmaProp,
pubkeyB),
SigmaAnd(
AND(
@@ -151,7 +151,7 @@ class AtomicSwapExampleSpecification extends SigmaTestingCommons {
val badProverA = proverA.withContextExtender(1, ByteArrayConstant(badX))
val badHx = ByteArrayConstant(Blake2b256(badX))
val badEnv = env + ("hx" -> badHx)
- val badProp2 = compileWithCosting(badEnv, script2).asBoolValue
+ val badProp2 = compile(badEnv, script2).asSigmaProp
badProverA.prove(badEnv, badProp2, ctx1, fakeMessage).isSuccess shouldBe false
}
diff --git a/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala b/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala
index ffb24c03e9..c5709a5644 100644
--- a/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala
@@ -1,27 +1,26 @@
package sigmastate.utxo.examples
-import org.ergoplatform.{ErgoLikeContext, Height, _}
+import org.ergoplatform._
import scorex.util.ScorexLogging
-import sigmastate.Values.{IntConstant, LongConstant, SValue}
-import sigmastate.Values.{ConcreteCollection, IntConstant, LongConstant}
-import sigmastate.eval.RuntimeIRContext
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.Values.IntConstant
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, SigmaTestingCommons}
import sigmastate.interpreter.ContextExtension
-import sigmastate.interpreter.Interpreter.{ScriptEnv, ScriptNameProp, emptyEnv}
+import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
import sigmastate.lang.Terms._
-import sigmastate.serialization.{ErgoTreeSerializer, OpCodes}
-import sigmastate.utxo.BlockchainSimulationSpecification.{Block, ValidationState}
+import sigmastate.utxo.blockchain.BlockchainSimulationTestingCommons._
import sigmastate.utxo._
-import sigmastate.{SLong, _}
+import sigmastate._
/**
- * Coin emission specification.
- * Instead of having implicit emission via coinbase transaction, we implement 1 output in a state with script,
- * that controls emission rules
+ * An example of currency emission contract.
+ * Instead of having implicit emission via coinbase transaction, we put 1 coin into genesis state with a script
+ * that controls emission.
+ * This script is corresponding to the whitepaper. Please note that Ergo has different contract
+ * defined in ErgoScriptPredef.
*/
class CoinEmissionSpecification extends SigmaTestingCommons with ScorexLogging {
// don't use TestingIRContext, this suite also serves the purpose of testing the RuntimeIRContext
- implicit lazy val IR = new TestingIRContext {
+ implicit lazy val IR: TestingIRContext = new TestingIRContext {
// override val okPrintEvaluatedEntries = true
}
@@ -30,7 +29,7 @@ class CoinEmissionSpecification extends SigmaTestingCommons with ScorexLogging {
private val coinsInOneErgo: Long = 100000000
private val blocksPerHour: Int = 30
- case class MonetarySettings(fixedRatePeriod: Long,
+ case class MonetarySettings(fixedRatePeriod: Int,
epochLength: Int,
fixedRate: Long,
oneEpochReduction: Long)
@@ -50,7 +49,7 @@ class CoinEmissionSpecification extends SigmaTestingCommons with ScorexLogging {
loop(0, 0)
}
- def emissionAtHeight(h: Long): Long = {
+ def emissionAtHeight(h: Int): Long = {
if (h < s.fixedRatePeriod) {
s.fixedRate
} else {
@@ -60,56 +59,49 @@ class CoinEmissionSpecification extends SigmaTestingCommons with ScorexLogging {
}.ensuring(_ >= 0, s"Negative at $h")
- ignore("emission specification") {
+ property("emission specification") {
val register = reg1
- val prover = new ErgoLikeTestProvingInterpreter()
+ val prover = new ContextEnrichingTestProvingInterpreter()
val rewardOut = ByIndex(Outputs, IntConstant(0))
- val minerOut = ByIndex(Outputs, IntConstant(1))
- val epoch = Plus(LongConstant(1), Divide(Minus(Height, LongConstant(s.fixedRatePeriod)), LongConstant(s.epochLength)))
- val coinsToIssue = If(LT(Height, LongConstant(s.fixedRatePeriod)),
+ val epoch =
+ Upcast(
+ Plus(IntConstant(1), Divide(Minus(Height, IntConstant(s.fixedRatePeriod)), IntConstant(s.epochLength))),
+ SLong)
+
+ val coinsToIssue = If(LT(Height, IntConstant(s.fixedRatePeriod)),
s.fixedRate,
Minus(s.fixedRate, Multiply(s.oneEpochReduction, epoch))
)
val sameScriptRule = EQ(ExtractScriptBytes(Self), ExtractScriptBytes(rewardOut))
- val heightCorrect = EQ(ExtractRegisterAs[SLong.type](rewardOut, register).get, Height)
- val heightIncreased = GT(Height, ExtractRegisterAs[SLong.type](Self, register).get)
+ val heightCorrect = EQ(ExtractRegisterAs[SInt.type](rewardOut, register).get, Height)
+ val heightIncreased = GT(Height, ExtractRegisterAs[SInt.type](Self, register).get)
val correctCoinsConsumed = EQ(coinsToIssue, Minus(ExtractAmount(Self), ExtractAmount(rewardOut)))
val lastCoins = LE(ExtractAmount(Self), s.oneEpochReduction)
- val outputsNum = EQ(SizeOf(Outputs), 2)
- val correctMinerProposition = EQ(
- ExtractScriptBytes(minerOut),
- ErgoTreeSerializer.DefaultSerializer.serializedPubkeyPropValue(MinerPubkey)
- )
- val prop = AND(
- heightIncreased,
- correctMinerProposition,
- BinOr(AND(outputsNum, sameScriptRule, correctCoinsConsumed, heightCorrect), lastCoins)
- )
+ val prop = BinOr(
+ AND(heightIncreased, sameScriptRule, correctCoinsConsumed, heightCorrect),
+ BinAnd(heightIncreased, lastCoins)
+ ).toSigmaProp
val env = Map("fixedRatePeriod" -> s.fixedRatePeriod,
"epochLength" -> s.epochLength,
"fixedRate" -> s.fixedRate,
"oneEpochReduction" -> s.oneEpochReduction)
- val prop1 = compile(env,
+ val prop1 = compileWithoutCosting(env,
"""{
| val epoch = 1 + ((HEIGHT - fixedRatePeriod) / epochLength)
| val out = OUTPUTS(0)
- | val minerOut = OUTPUTS(1)
| val coinsToIssue = if(HEIGHT < fixedRatePeriod) fixedRate else fixedRate - (oneEpochReduction * epoch)
| val correctCoinsConsumed = coinsToIssue == (SELF.value - out.value)
| val sameScriptRule = SELF.propositionBytes == out.propositionBytes
- | val heightIncreased = HEIGHT > SELF.R4[Long].get
- | val heightCorrect = out.R4[Long].get == HEIGHT
+ | val heightIncreased = HEIGHT > SELF.R4[Int].get
+ | val heightCorrect = out.R4[Int].get == HEIGHT
| val lastCoins = SELF.value <= oneEpochReduction
- | val outputsNum = OUTPUTS.size == 2
- | val correctMinerProposition = minerOut.propositionBytes ==
- | Coll[Byte](0.toByte, 1.toByte, 7.toByte) ++ MinerPubkey ++ Coll[Byte](-51.toByte, 115.toByte, 0.toByte)
- | allOf(Coll(heightIncreased, correctMinerProposition, allOf(Coll(outputsNum, sameScriptRule, correctCoinsConsumed, heightCorrect)) || lastCoins))
- |}""".stripMargin).asBoolValue
+ | allOf(Coll(heightIncreased, sameScriptRule, correctCoinsConsumed, heightCorrect)) || (heightIncreased && lastCoins)
+ |}""".stripMargin).asBoolValue.toSigmaProp
prop1 shouldEqual prop
@@ -117,20 +109,12 @@ class CoinEmissionSpecification extends SigmaTestingCommons with ScorexLogging {
val minerPubkey = minerImage.pkBytes
val minerProp = minerImage
- val initialBoxCandidate: ErgoBox = ErgoBox(coinsTotal, prop, 0, Seq(), Map(register -> LongConstant(-1)))
- val initBlock = BlockchainSimulationSpecification.Block(
- IndexedSeq(
- ErgoLikeTransaction(
- IndexedSeq(),
- IndexedSeq(initialBoxCandidate)
- )
- ),
- minerPubkey
- )
+ val initialBoxCandidate: ErgoBox = ErgoBox(coinsTotal / 4, prop, 0, Seq(), Map(register -> IntConstant(-1)))
+ val initBlock = FullBlock(IndexedSeq(createTransaction(initialBoxCandidate)), minerPubkey)
val genesisState = ValidationState.initialState(initBlock)
val fromState = genesisState.boxesReader.byId(genesisState.boxesReader.allIds.head).get
- val initialBox = ErgoBox(initialBoxCandidate.value, initialBoxCandidate.proposition, 0,
- initialBoxCandidate.additionalTokens, initialBoxCandidate.additionalRegisters, initBlock.txs.head.id, 0)
+ val initialBox = ErgoBox(initialBoxCandidate.value, initialBoxCandidate.ergoTree, 0,
+ initialBoxCandidate.additionalTokens, initialBoxCandidate.additionalRegisters, initBlock.txs.head.id)
initialBox shouldBe fromState
def genCoinbaseLikeTransaction(state: ValidationState,
@@ -140,15 +124,15 @@ class CoinEmissionSpecification extends SigmaTestingCommons with ScorexLogging {
val ut = if (emissionBox.value > s.oneEpochReduction) {
val minerBox = new ErgoBoxCandidate(emissionAtHeight(height), minerProp, height, Seq(), Map())
val newEmissionBox: ErgoBoxCandidate =
- new ErgoBoxCandidate(emissionBox.value - minerBox.value, prop, height, Seq(), Map(register -> LongConstant(height)))
+ new ErgoBoxCandidate(emissionBox.value - minerBox.value, prop, height, Seq(), Map(register -> IntConstant(height)))
UnsignedErgoLikeTransaction(
IndexedSeq(new UnsignedInput(emissionBox.id)),
IndexedSeq(newEmissionBox, minerBox)
)
} else {
- val minerBox1 = new ErgoBoxCandidate(emissionBox.value - 1, minerProp, height, Seq(), Map(register -> LongConstant(height)))
- val minerBox2 = new ErgoBoxCandidate(1, minerProp, height, Seq(), Map(register -> LongConstant(height)))
+ val minerBox1 = new ErgoBoxCandidate(emissionBox.value - 1, minerProp, height, Seq(), Map(register -> IntConstant(height)))
+ val minerBox2 = new ErgoBoxCandidate(1, minerProp, height, Seq(), Map(register -> IntConstant(height)))
UnsignedErgoLikeTransaction(
IndexedSeq(new UnsignedInput(emissionBox.id)),
IndexedSeq(minerBox1, minerBox2)
@@ -177,7 +161,7 @@ class CoinEmissionSpecification extends SigmaTestingCommons with ScorexLogging {
IR.resetContext()
}
val tx = genCoinbaseLikeTransaction(state, emissionBox, height)
- val block = Block(IndexedSeq(tx), minerPubkey)
+ val block = FullBlock(IndexedSeq(tx), minerPubkey)
val newState = state.applyBlock(block).get
if (tx.outputs.last.value > 1) {
val newEmissionBox = newState.boxesReader.byId(tx.outputs.head.id).get
diff --git a/src/test/scala/sigmastate/utxo/examples/ColdWalletContractExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/ColdWalletContractExampleSpecification.scala
new file mode 100644
index 0000000000..6866d61a61
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/ColdWalletContractExampleSpecification.scala
@@ -0,0 +1,61 @@
+package sigmastate.utxo.examples
+
+import org.ergoplatform._
+import sigmastate.Values.IntConstant
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.interpreter.Interpreter.ScriptNameProp
+import sigmastate.lang.Terms._
+
+
+class ColdWalletContractExampleSpecification extends SigmaTestingCommons {
+ private implicit lazy val IR: TestingIRContext = new TestingIRContext
+
+ import ErgoAddressEncoder._
+
+ implicit val ergoAddressEncoder: ErgoAddressEncoder = new ErgoAddressEncoder(TestnetNetworkPrefix)
+ property("Evaluation - ColdWallet Contract Example") {
+
+ val alice = new ContextEnrichingTestProvingInterpreter // private key controlling hot-wallet funds
+ val alicePubKey = alice.dlogSecrets.head.publicImage
+
+ val bob = new ContextEnrichingTestProvingInterpreter // private key controlling hot-wallet funds
+ val bobPubKey = bob.dlogSecrets.head.publicImage
+
+ val env = Map(
+ ScriptNameProp -> "env",
+ "alice" -> alicePubKey,
+ "bob" -> bobPubKey,
+ "blocksIn24h" -> IntConstant(500),
+ "percent" -> IntConstant(1),
+ "minSpend" -> IntConstant(100)
+ )
+
+ val script = compile(env,
+ """{
+ | val r4 = SELF.R4[Int].get // height at which period started
+ | val min = SELF.R5[Long].get // min Balance needed in this period
+ | val depth = HEIGHT - SELF.creationInfo._1
+ | val start = if (depth < r4) depth else r4
+ | val notExpired = HEIGHT - start <= blocksIn24h
+ |
+ | val newStart:Int = if (notExpired) start else HEIGHT
+ | val toKeep:Long = SELF.value - SELF.value * percent / 100
+ | val newMin:Long = if (notExpired) min else {if (toKeep > minSpend) toKeep else 0L}
+ |
+ | val isValid = {(out:Box) =>
+ | if (newMin == 0) true else {
+ | out.propositionBytes == SELF.propositionBytes &&
+ | out.value >= newMin &&
+ | out.R4[Int].get >= newStart &&
+ | out.R5[Long].get == newMin
+ | }
+ | }
+ | (alice && bob) || ((alice || bob) && OUTPUTS.exists(isValid))}""".stripMargin).asSigmaProp
+
+ val address = Pay2SHAddress(script)
+
+ val carol = new ContextEnrichingTestProvingInterpreter // private key controlling hot-wallet funds
+ val carolPubKey = carol.dlogSecrets.head.publicImage
+
+ }
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/CoopExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/CoopExampleSpecification.scala
index 37133195ec..0a5d9f77fd 100644
--- a/src/test/scala/sigmastate/utxo/examples/CoopExampleSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/CoopExampleSpecification.scala
@@ -1,21 +1,20 @@
package sigmastate.utxo.examples
-import org.ergoplatform.{ErgoBox, ErgoLikeContext, ErgoLikeTransaction}
+import org.ergoplatform.{ErgoBox, ErgoLikeContext, ErgoLikeTransaction, ErgoScriptPredef}
import org.scalatest.Assertion
import org.scalatest.TryValues._
import sigmastate.basics.DLogProtocol.ProveDlog
import scorex.crypto.hash.Blake2b256
-import sigmastate.Values.{ByteArrayConstant, Value}
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.Values.{ByteArrayConstant, SigmaPropValue, Value}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.lang.Terms._
-import sigmastate.utxo.ErgoLikeTestInterpreter
import sigmastate.{AvlTreeData, SBoolean}
class CoopExampleSpecification extends SigmaTestingCommons {
implicit lazy val IR = new TestingIRContext
def mkTxFromOutputs(ergoBox: ErgoBox*): ErgoLikeTransaction = {
- ErgoLikeTransaction(IndexedSeq(), ergoBox.toIndexedSeq)
+ createTransaction(ergoBox.toIndexedSeq)
}
def mkCtx(height: Int,
@@ -30,27 +29,27 @@ class CoopExampleSpecification extends SigmaTestingCommons {
self = self)
}
- def successProofTest(exp: Value[SBoolean.type],
+ def successProofTest(exp: SigmaPropValue,
ctx: ErgoLikeContext,
- prover: ErgoLikeTestProvingInterpreter,
+ prover: ContextEnrichingTestProvingInterpreter,
verifier: ErgoLikeTestInterpreter): Assertion = {
val proofResult = prover.prove(exp, ctx, fakeMessage)
proofResult should be a 'success
verifier.verify(exp, ctx, proofResult.success.value, fakeMessage) should be a 'success
}
- def failingProofTest(exp: Value[SBoolean.type],
+ def failingProofTest(exp: SigmaPropValue,
ctx: ErgoLikeContext,
- prover: ErgoLikeTestProvingInterpreter): Assertion = {
+ prover: ContextEnrichingTestProvingInterpreter): Assertion = {
prover.prove(exp, ctx, fakeMessage) should be a 'failure
}
property("commit to the threshold sig") {
- val coopA = new ErgoLikeTestProvingInterpreter
- val coopB = new ErgoLikeTestProvingInterpreter
- val coopC = new ErgoLikeTestProvingInterpreter
- val coopD = new ErgoLikeTestProvingInterpreter
+ val coopA = new ContextEnrichingTestProvingInterpreter
+ val coopB = new ContextEnrichingTestProvingInterpreter
+ val coopC = new ContextEnrichingTestProvingInterpreter
+ val coopD = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val totalValue = 10000L
@@ -67,10 +66,10 @@ class CoopExampleSpecification extends SigmaTestingCommons {
val pubkeyC = skC.publicImage
val pubkeyD = skD.publicImage
- val toolA = new ErgoLikeTestProvingInterpreter
- val toolB = new ErgoLikeTestProvingInterpreter
- val toolC = new ErgoLikeTestProvingInterpreter
- val toolD = new ErgoLikeTestProvingInterpreter
+ val toolA = new ContextEnrichingTestProvingInterpreter
+ val toolB = new ContextEnrichingTestProvingInterpreter
+ val toolC = new ContextEnrichingTestProvingInterpreter
+ val toolD = new ContextEnrichingTestProvingInterpreter
val toolRing = Seq(
@@ -79,16 +78,16 @@ class CoopExampleSpecification extends SigmaTestingCommons {
toolC.dlogSecrets.head.publicImage,
toolD.dlogSecrets.head.publicImage)
- val constrA = new ErgoLikeTestProvingInterpreter
- val constrB = new ErgoLikeTestProvingInterpreter
- val constrC = new ErgoLikeTestProvingInterpreter
+ val constrA = new ContextEnrichingTestProvingInterpreter
+ val constrB = new ContextEnrichingTestProvingInterpreter
+ val constrC = new ContextEnrichingTestProvingInterpreter
val constructionRing = Seq(
constrA.dlogSecrets.head.publicImage,
constrB.dlogSecrets.head.publicImage,
constrC.dlogSecrets.head.publicImage)
- val business = new ErgoLikeTestProvingInterpreter
+ val business = new ContextEnrichingTestProvingInterpreter
val businessKey = business.dlogSecrets.head.publicImage
def withdraw(minHeight: Long, totalValue: Long) = {
@@ -116,7 +115,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
"pubkeyConstr3" -> constructionRing(2)
)
- val spendingProp1 = compileWithCosting(spendingEnv,
+ val spendingProp1 = compile(spendingEnv,
s"""
|{
| val spendingSuccess = (pubkeyTool1 || pubkeyTool2 || pubkeyTool3 || pubkeyTool4) && businessKey
@@ -125,7 +124,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
|
| spendingSuccess || withdrawCondition
|}
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
{
val self = ErgoBox(totalValue, spendingProp1, 0)
@@ -153,7 +152,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
"pubkeyConstr3" -> constructionRing(2)
)
- val spendingProp2 = compileWithCosting(spendingEnv2,
+ val spendingProp2 = compile(spendingEnv2,
s"""
|{
| val spendingSuccess = (pubkeyTool1 || pubkeyTool2 || pubkeyTool3 || pubkeyTool4) && businessKey
@@ -162,7 +161,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
|
| spendingSuccess || withdrawCondition
|}
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
/**
* Withdraw successfully
@@ -205,7 +204,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
}
- val spendingProp3 = compileWithCosting(spendingEnv,
+ val spendingProp3 = compile(spendingEnv,
s"""
| {
|
@@ -215,7 +214,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
|
| spendingSuccess || withdrawCondition
| }
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
/**
* Will spend correctly if all the conditions are satisfied
@@ -246,7 +245,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
"pubkeyConstr3" -> SBoolean.mkConstant(false)
)
- val spendingProp4 = compileWithCosting(spendingEnv3,
+ val spendingProp4 = compile(spendingEnv3,
s"""
| {
|
@@ -256,7 +255,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
|
| spendingSuccess || withdrawCondition
| }
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
{
val self = ErgoBox(totalValue, spendingProp4, 0)
@@ -269,7 +268,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
successProofTest(spendingProp4, ctx, coopA, verifier)
}
- val spendingProp5 = compileWithCosting(spendingEnv, "businessKey").asBoolValue
+ val spendingProp5 = compile(spendingEnv, "businessKey").asSigmaProp
{
val self = ErgoBox(totalValue, spendingProp5, 0)
@@ -293,7 +292,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
)
// Basic compilation
- val thresholdProp = compileWithCosting(thresholdEnv,
+ val thresholdProp = compile(thresholdEnv,
s""" {
| val votingSuccess = atLeast(3, Coll(pubkeyA, pubkeyB, pubkeyC, pubkeyD))
| val properSpending = OUTPUTS(0).value >= ${toolValue}L &&
@@ -305,7 +304,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
|
| (votingSuccess && properSpending) || withdrawCondition
| }
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
/**
@@ -317,7 +316,7 @@ class CoopExampleSpecification extends SigmaTestingCommons {
val output2 = ErgoBox(constructionValue, spendingProp3, 0)
val output3 = ErgoBox(totalValue - toolValue - constructionValue, spendingProp5, 0)
//hack for avoiding None.get exception.
- val dummy = ErgoBox(0L, SBoolean.mkConstant(true), 0)
+ val dummy = ErgoBox(0L, ErgoScriptPredef.TrueProp, 0)
val tx = mkTxFromOutputs(output1, output2, output3, dummy)
val ctx = mkCtx(2000, tx, self)
@@ -362,10 +361,10 @@ class CoopExampleSpecification extends SigmaTestingCommons {
"pubkeyA" -> pubkeyA
)
- val inputProp = compileWithCosting(inputEnv,
+ val inputProp = compile(inputEnv,
s"""(OUTPUTS(0).value == $totalValue && blake2b256(OUTPUTS(0).propositionBytes) == thresholdProp) ||
| (HEIGHT > 1000 && pubkeyA)
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
/**
* height not higher, total value is equal
diff --git a/src/test/scala/sigmastate/utxo/examples/CrowdFunding.scala b/src/test/scala/sigmastate/utxo/examples/CrowdFunding.scala
new file mode 100644
index 0000000000..8a257ffd6a
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/CrowdFunding.scala
@@ -0,0 +1,73 @@
+package sigmastate.utxo.examples
+
+import special.sigma.{Context, Box}
+import org.ergoplatform.dsl.{SigmaContractSyntax, ContractSpec, StdContracts}
+
+/** @param backer The party, who wants to fund some amount of Ergs to the project.
+ * @param project The party, who wants to collect at least `minToRaise` Ergs before `deadline`.
+ * */
+case class CrowdFunding[Spec <: ContractSpec]
+ (deadline: Int, minToRaise: Long,
+ backer: Spec#ProvingParty,
+ project: Spec#ProvingParty)
+ (implicit val spec: Spec) extends SigmaContractSyntax with StdContracts
+{
+ def pkBacker = backer.pubKey
+ def pkProject = project.pubKey
+ import syntax._
+ lazy val contractEnv = Env("pkBacker" -> pkBacker, "pkProject" -> pkProject, "deadline" -> deadline, "minToRaise" -> minToRaise)
+
+ lazy val holderProp = proposition("holder", { ctx: Context =>
+ import ctx._
+ val fundraisingFailure = HEIGHT >= deadline && pkBacker
+ val enoughRaised = {(outBox: Box) =>
+ outBox.value >= minToRaise &&
+ outBox.propositionBytes == pkProject.propBytes
+ }
+ val fundraisingSuccess = HEIGHT < deadline &&
+ pkProject &&
+ OUTPUTS.exists(enoughRaised)
+
+ fundraisingFailure || fundraisingSuccess
+ },
+ """
+ |{
+ | val fundraisingFailure = HEIGHT >= deadline && pkBacker
+ | val enoughRaised = {(outBox: Box) =>
+ | outBox.value >= minToRaise &&
+ | outBox.propositionBytes == pkProject.propBytes
+ | }
+ | val fundraisingSuccess = HEIGHT < deadline &&
+ | pkProject &&
+ | OUTPUTS.exists(enoughRaised)
+ |
+ | fundraisingFailure || fundraisingSuccess
+ |}
+ """.stripMargin)
+
+ lazy val backerSignature = proposition("backerSignature", _ => pkBacker, "pkBacker")
+ lazy val projectSignature = proposition("projectSignature", _ => pkProject, "pkProject")
+
+ lazy val oldProp = proposition("old", { ctx: Context =>
+ import ctx._
+ val c1 = HEIGHT >= deadline && pkBacker
+ val c2 =
+ HEIGHT < deadline && pkProject &&
+ OUTPUTS.exists({ (out: Box) =>
+ out.value >= minToRaise && out.propositionBytes == pkProject.propBytes
+ })
+ c1 || c2
+ },
+ """
+ |{
+ | val c1 = HEIGHT >= deadline && pkBacker
+ | val c2 =
+ | HEIGHT < deadline && pkProject &&
+ | OUTPUTS.exists({ (out: Box) =>
+ | out.value >= minToRaise && out.propositionBytes == pkProject.propBytes
+ | })
+ | c1 || c2
+ |}
+ """.stripMargin)
+
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/CrowdFundingTests.scala b/src/test/scala/sigmastate/utxo/examples/CrowdFundingTests.scala
new file mode 100644
index 0000000000..1b3bc924e7
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/CrowdFundingTests.scala
@@ -0,0 +1,67 @@
+package sigmastate.utxo.examples
+
+import sigmastate.helpers.SigmaTestingCommons
+import org.ergoplatform.dsl.TestContractSpec
+
+class CrowdFundingTests extends SigmaTestingCommons { suite =>
+ lazy val spec = TestContractSpec(suite)(new TestingIRContext)
+ lazy val backer = spec.ProvingParty("Alice")
+ lazy val project = spec.ProvingParty("Bob")
+
+ property("Evaluation - Crowdfunding Example") {
+ val contract = CrowdFunding[spec.type](100, 1000, backer, project)(spec)
+ import contract.spec._
+
+ val holderBox = candidateBlock(0).newTransaction()
+ .outBox(10, contract.holderProp)
+
+ //First case: height < timeout, project is able to claim amount of tokens not less than required threshold
+ {
+ // normally this transaction would be invalid (ill-balanced), but we're not checking it in this test
+ val spendingTx = candidateBlock(contract.deadline - 1).newTransaction().spending(holderBox)
+ spendingTx.outBox(contract.minToRaise, contract.projectSignature)
+
+ // ASSERT
+ val input0 = spendingTx.inputs(0)
+ val res = input0.runDsl()
+ res shouldBe contract.pkProject
+
+ //project is generating a proof and it is passing verification
+ val buyerProof = contract.project.prove(input0).get
+ contract.verifier.verify(input0, buyerProof) shouldBe true
+
+ //backer can't generate a proof
+ contract.backer.prove(input0).isFailure shouldBe true
+ }
+
+ //Second case: height < timeout, project is NOT able to claim amount of tokens less than required threshold
+ {
+ val spendingTx = candidateBlock(contract.deadline - 1).newTransaction().spending(holderBox)
+ spendingTx.outBox(contract.minToRaise - 1, contract.projectSignature)
+ val input0 = spendingTx.inputs(0)
+
+ //project cant' generate a proof
+ val proofP2Try = contract.project.prove(input0)
+ proofP2Try.isSuccess shouldBe false
+
+ //backer can't generate a proof
+ val proofB2Try = contract.backer.prove(input0)
+ proofB2Try.isSuccess shouldBe false
+ }
+
+ //Third case: height >= timeout
+ {
+ val spendingTx = candidateBlock(contract.deadline).newTransaction().spending(holderBox)
+ spendingTx.outBox(contract.minToRaise + 1, contract.projectSignature)
+ val input0 = spendingTx.inputs(0)
+
+ //project cant' generate a proof
+ contract.project.prove(input0).isFailure shouldBe true
+
+ //backer is generating a proof and it is passing verification
+ val proofB = contract.backer.prove(input0).get
+ contract.verifier.verify(input0, proofB) shouldBe true
+ }
+ }
+
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/CrowdfundingExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/CrowdfundingExampleSpecification.scala
deleted file mode 100644
index fd6e6c2ec0..0000000000
--- a/src/test/scala/sigmastate/utxo/examples/CrowdfundingExampleSpecification.scala
+++ /dev/null
@@ -1,182 +0,0 @@
-package sigmastate.utxo.examples
-
-import org.ergoplatform._
-import sigmastate.Values.{BlockValue, ByteArrayConstant, ConcreteCollection, Constant, ConstantNode, FuncValue, GroupElementConstant, IntConstant, LongConstant, SigmaPropConstant, TaggedBox, ValDef, ValUse}
-import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
-import sigmastate.lang.Terms._
-import sigmastate.interpreter.Interpreter._
-import sigmastate.utxo._
-
-class CrowdfundingExampleSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
- /**
- * Crowdfunding example:
- * a project declares a need to raise "minToRaise" amount of tokens until some "timeout" height
- * a backer then creates an output which is spendable by with project's public key until timeout and only if a spending
- * transaction creates an output to project's public key with amount >= minToRaise
- * after the timeout output could be spent by backer only
- */
- property("Evaluation - Crowdfunding Example") {
-
- //a blockchain node verifying a block containing a spending transaction
- val verifier = new ErgoLikeTestInterpreter
-
- //backer's prover with his private key
- val backerProver = new ErgoLikeTestProvingInterpreter
-
- //project's prover with his private key
- val projectProver = new ErgoLikeTestProvingInterpreter
-
- val backerPubKey = backerProver.dlogSecrets.head.publicImage
- val projectPubKey = projectProver.dlogSecrets.head.publicImage
-
- val timeout = IntConstant(100)
- val minToRaise = LongConstant(1000)
-
- val env = Map(
- ScriptNameProp -> "CrowdFunding",
- "timeout" -> 100,
- "minToRaise" -> 1000,
- "backerPubKey" -> backerPubKey,
- "projectPubKey" -> projectPubKey
- )
- val compiledScript = compileWithCosting(env,
- """{
- | val c1 = HEIGHT >= timeout && backerPubKey
- | val c2 = allOf(Coll(
- | HEIGHT < timeout,
- | projectPubKey,
- | OUTPUTS.exists({ (out: Box) =>
- | out.value >= minToRaise && out.propositionBytes == projectPubKey.propBytes
- | })
- | ))
- | c1 || c2
- | }
- """.stripMargin).asBoolValue
-
- val expectedScript = BlockValue(
- Vector(
- ValDef(1, SigmaPropConstant(projectPubKey))),
- SigmaOr(List(
- SigmaAnd(List(
- BoolToSigmaProp(GE(Height, IntConstant(100))),
- SigmaPropConstant(backerPubKey))
- ),
- SigmaAnd(List(
- BoolToSigmaProp(AND(ConcreteCollection(Vector(
- LT(Height, IntConstant(100)),
- Exists(Outputs,
- FuncValue(Vector((2, SBox)),
- BinAnd(
- GE(ExtractAmount(ValUse(2, SBox)), LongConstant(1000)),
- EQ(ExtractScriptBytes(ValUse(2, SBox)), SigmaPropBytes(ValUse(1, SSigmaProp)))
- )
- )
- )
- ), SBoolean))),
- ValUse(1, SSigmaProp)))
- ))
- )
-
- compiledScript shouldBe expectedScript
-
- // Try a version of the script that matches the white paper -- should give the same result
- val altEnv = Map(
- "deadline" -> 100,
- "minToRaise" -> 1000,
- "backerPubKey" -> backerPubKey,
- "projectPubKey" -> projectPubKey
- )
-
- val altScript = compileWithCosting(altEnv,
- """
- | {
- | val fundraisingFailure = HEIGHT >= deadline && backerPubKey
- | val enoughRaised = {(outBox: Box) =>
- | outBox.value >= minToRaise &&
- | outBox.propositionBytes == projectPubKey.propBytes
- | }
- | val fundraisingSuccess = HEIGHT < deadline &&
- | projectPubKey &&
- | OUTPUTS.exists(enoughRaised)
- |
- | fundraisingFailure || fundraisingSuccess
- | }
- """.stripMargin).asBoolValue
-
-// altScript shouldBe compiledScript
-
- val outputToSpend = ErgoBox(10, compiledScript, 0)
-
- //First case: height < timeout, project is able to claim amount of tokens not less than required threshold
-
- val tx1Output1 = ErgoBox(minToRaise.value, projectPubKey, 0)
- val tx1Output2 = ErgoBox(1, projectPubKey, 0)
-
- //normally this transaction would invalid, but we're not checking it in this test
- val tx1 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(tx1Output1, tx1Output2))
-
- val ctx1 = ErgoLikeContext(
- currentHeight = timeout.value - 1,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(outputToSpend),
- spendingTransaction = tx1,
- self = outputToSpend)
-
- //project is generating a proof and it is passing verification
- val proofP = projectProver.prove(env, compiledScript, ctx1, fakeMessage).get.proof
- verifier.verify(env, compiledScript, ctx1, proofP, fakeMessage).get._1 shouldBe true
-
- //backer can't generate a proof
- backerProver.prove(compiledScript, ctx1, fakeMessage).isFailure shouldBe true
-
-
- //Second case: height < timeout, project is NOT able to claim amount of tokens not less than required threshold
-
- val tx2Output1 = ErgoBox(minToRaise.value - 1, projectPubKey, 0)
- val tx2Output2 = ErgoBox(1, projectPubKey, 0)
- val tx2 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(tx2Output1, tx2Output2))
-
- val ctx2 = ErgoLikeContext(
- currentHeight = timeout.value - 1,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(outputToSpend),
- spendingTransaction = tx2,
- self = outputToSpend)
-
- //project cant' generate a proof
- val proofP2Try = projectProver.prove(compiledScript, ctx2, fakeMessage)
- proofP2Try.isSuccess shouldBe false
-
- //backer can't generate a proof
- val proofB2Try = backerProver.prove(compiledScript, ctx2, fakeMessage)
- proofB2Try.isSuccess shouldBe false
-
- //Third case: height >= timeout
-
- //project raised enough money but too late...
- val tx3Output1 = ErgoBox(minToRaise.value + 1, projectPubKey, 0)
- val tx3Output2 = ErgoBox(1, projectPubKey, 0)
- val tx3 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(tx3Output1, tx3Output2))
-
- val ctx3 = ErgoLikeContext(
- currentHeight = timeout.value,
- lastBlockUtxoRoot = AvlTreeData.dummy,
- minerPubkey = ErgoLikeContext.dummyPubkey,
- boxesToSpend = IndexedSeq(outputToSpend),
- spendingTransaction = tx3,
- self = outputToSpend)
-
- //project cant' generate a proof
- projectProver.prove(compiledScript, ctx3, fakeMessage).isFailure shouldBe true
-
- //backer is generating a proof and it is passing verification
- val proofB = backerProver.prove(compiledScript, ctx3, fakeMessage).get.proof
- verifier.verify(env, compiledScript, ctx3, proofB, fakeMessage).get._1 shouldBe true
- }
-
-
-}
diff --git a/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala
new file mode 100644
index 0000000000..c98e97c777
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala
@@ -0,0 +1,115 @@
+
+package sigmastate.utxo.examples
+
+import java.math.BigInteger
+
+import org.ergoplatform.ErgoBox.{R4, R5}
+import org.ergoplatform.{ErgoBox, ErgoLikeContext, ErgoLikeTransaction}
+import sigmastate.AvlTreeData
+import sigmastate.Values.GroupElementConstant
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.basics.{DiffieHellmanTupleProverInput, ProveDHTuple}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
+import sigmastate.interpreter.CryptoConstants
+import sigmastate.interpreter.Interpreter._
+import sigmastate.lang.Terms._
+
+class DHTupleExampleSpecification extends SigmaTestingCommons {
+ private implicit lazy val IR = new TestingIRContext
+ /**
+ * let Alice's secret be x and Bob's be y
+ *
+ * Then
+ * (g, g^y, g^x, g^xy) forms a DH tuple for Alice and
+ * (g, g^x, g^y, g^xy) forms a DH tuple for Bob.
+ *
+ */
+ property("Evaluation - DH Example") {
+ import CryptoConstants.dlogGroup
+
+ val g = dlogGroup.generator
+
+ val alice = new ContextEnrichingTestProvingInterpreter
+ val alicePubKey:ProveDlog = alice.dlogSecrets.head.publicImage
+
+ val x:BigInteger = alice.dlogSecrets.head.w // x is Alice's private key
+
+ val g_x = alicePubKey.h // g_x is Alice's public key (g_x = g^x)
+
+ val env = Map(
+ ScriptNameProp -> "env",
+ "g" -> g,
+ "g_x" -> g_x
+ )
+
+ val script = compile(env,
+ """{
+ | val g_y = OUTPUTS(0).R4[GroupElement].get
+ | val g_xy = OUTPUTS(0).R5[GroupElement].get
+ |
+ | proveDHTuple(g, g_x, g_y, g_xy) || // for bob
+ | proveDHTuple(g, g_y, g_x, g_xy) // for alice
+ |}""".stripMargin
+ ).asSigmaProp
+
+ val inBox = ErgoBox(10, script, 50)
+
+ // a blockchain node verifying a block containing a spending transaction
+ val verifier = new ErgoLikeTestInterpreter
+
+ val bob = new ContextEnrichingTestProvingInterpreter
+
+ val y:BigInteger = bob.dlogSecrets.head.w // y is Bob's private key
+
+ val bobPubKey: ProveDlog = bob.dlogSecrets.head.publicImage
+ val g_y = GroupElementConstant(bobPubKey.h) // Bob's public key g^y
+
+ val g_xy = GroupElementConstant(dlogGroup.exponentiate(g_x, y)) // g^xy
+
+ val carol = new ContextEnrichingTestProvingInterpreter
+ val carolPubKey:ProveDlog = carol.dlogSecrets.head.publicImage
+
+ val outBox = ErgoBox(10, carolPubKey, 70, Nil,
+ Map(
+ R4 -> g_y,
+ R5 -> g_xy
+ )
+ )
+
+ val tx = createTransaction(IndexedSeq(outBox))
+
+ val context = ErgoLikeContext(
+ currentHeight = 70,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(inBox),
+ spendingTransaction = tx,
+ self = inBox
+ )
+ val dhtBob = DiffieHellmanTupleProverInput(y, ProveDHTuple(g, g_x, g_y, g_xy))
+
+ val proofBob = (new ContextEnrichingTestProvingInterpreter).withDHSecrets(
+ Seq(dhtBob)
+ ).prove(env, script, context, fakeMessage).get.proof
+
+ verifier.verify(env, script, context, proofBob, fakeMessage).get._1 shouldBe true
+
+ val dhtAlice = DiffieHellmanTupleProverInput(x, ProveDHTuple(g, g_y, g_x, g_xy))
+
+ val proofAlice = (new ContextEnrichingTestProvingInterpreter).withDHSecrets(
+ Seq(dhtAlice)
+ ).prove(env, script, context, fakeMessage).get.proof
+
+ verifier.verify(env, script, context, proofAlice, fakeMessage).get._1 shouldBe true
+
+ val dhtBad = DiffieHellmanTupleProverInput(BigInt(10).bigInteger, ProveDHTuple(g, g_y, g_x, g_xy))
+
+ val proofBad = (new ContextEnrichingTestProvingInterpreter).withDHSecrets(
+ Seq(dhtBad)
+ ).prove(env, script, context, fakeMessage).get.proof
+
+ verifier.verify(env, script, context, proofBad, fakeMessage).get._1 shouldBe false
+
+ }
+
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/DemurrageExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/DemurrageExampleSpecification.scala
index 2a82adc9cc..1e8bbf1c8d 100644
--- a/src/test/scala/sigmastate/utxo/examples/DemurrageExampleSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/DemurrageExampleSpecification.scala
@@ -1,15 +1,14 @@
package sigmastate.utxo.examples
-import sigmastate.Values.{LongConstant, TaggedBox, SigmaPropConstant}
+import sigmastate.Values.{LongConstant, SigmaPropConstant, TaggedBox}
import sigmastate._
import sigmastate.interpreter.Interpreter._
import org.ergoplatform._
import sigmastate.Values.ShortConstant
import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.interpreter.ContextExtension
import sigmastate.lang.Terms._
-import sigmastate.utxo.ErgoLikeTestInterpreter
class DemurrageExampleSpecification extends SigmaTestingCommons {
implicit lazy val IR = new TestingIRContext
@@ -42,9 +41,9 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
val verifier = new ErgoLikeTestInterpreter()
//backer's prover with his private key
- val userProver = new ErgoLikeTestProvingInterpreter().withContextExtender(outIdxVarId, ShortConstant(0))
+ val userProver = new ContextEnrichingTestProvingInterpreter().withContextExtender(outIdxVarId, ShortConstant(0))
- val minerProver = new ErgoLikeTestProvingInterpreter().withContextExtender(outIdxVarId, ShortConstant(0))
+ val minerProver = new ContextEnrichingTestProvingInterpreter().withContextExtender(outIdxVarId, ShortConstant(0))
val regScript = userProver.dlogSecrets.head.publicImage
@@ -56,7 +55,7 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
)
//todo: add condition on
- val prop = compileWithCosting(env,
+ val prop = compile(env,
"""{
| val outIdx = getVar[Short](127).get
| val out = OUTPUTS(outIdx)
@@ -75,7 +74,7 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
|
| anyOf(Coll(regScript, c1, c2))
| }
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
/*
todo: fix / uncomment
@@ -107,7 +106,7 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
//case 1: demurrage time hasn't come yet
val currentHeight1 = inHeight + demurragePeriod - 1
- val tx1 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(createBox(outValue, prop, currentHeight1)))
+ val tx1 = createTransaction(createBox(outValue, prop, currentHeight1))
val selfBox = createBox(inValue, prop, inHeight)
val ctx1 = ErgoLikeContext(
currentHeight1,
@@ -128,7 +127,7 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
//case 2: demurrage time has come
val currentHeight2 = inHeight + demurragePeriod
- val tx2 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(createBox(outValue, prop, currentHeight2)))
+ val tx2 = createTransaction(createBox(outValue, prop, currentHeight2))
val ctx2 = ErgoLikeContext(
currentHeight2,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -144,7 +143,7 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
//miner can spend "demurrageCoeff * demurragePeriod" tokens
val b = createBox(outValue, prop, currentHeight2)
- val tx3 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(b))
+ val tx3 = createTransaction(b)
val ctx3 = ErgoLikeContext(
currentHeight = currentHeight2,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -161,7 +160,7 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
//miner can't spend more
val b2 = createBox(outValue - 1, prop, currentHeight2)
- val tx4 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(b2))
+ val tx4 = createTransaction(b2)
val ctx4 = ErgoLikeContext(
currentHeight = currentHeight2,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -175,8 +174,7 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
verifier.verify(prop, ctx4, NoProof, fakeMessage).get._1 shouldBe false
//miner can spend less
- val tx5 = ErgoLikeTransaction(IndexedSeq(),
- IndexedSeq(createBox(outValue + 1, prop, currentHeight2)))
+ val tx5 = createTransaction(createBox(outValue + 1, prop, currentHeight2))
val ctx5 = ErgoLikeContext(
currentHeight = currentHeight2,
@@ -192,8 +190,8 @@ class DemurrageExampleSpecification extends SigmaTestingCommons {
//miner can destroy a box if it contains less than the storage fee
val iv = inValue - outValue
- val b3 = createBox(iv, Values.FalseLeaf, currentHeight2)
- val tx6 = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(b3))
+ val b3 = createBox(iv, ErgoScriptPredef.FalseProp, currentHeight2)
+ val tx6 = createTransaction(b3)
val selfBox6 = createBox(iv, prop, inHeight)
val ctx6 = ErgoLikeContext(
currentHeight = currentHeight2,
diff --git a/src/test/scala/sigmastate/utxo/examples/FsmExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/FsmExampleSpecification.scala
index 24b208a14e..f1fc217e7c 100644
--- a/src/test/scala/sigmastate/utxo/examples/FsmExampleSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/FsmExampleSpecification.scala
@@ -1,19 +1,22 @@
package sigmastate.utxo.examples
import org.ergoplatform._
-import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert, Lookup}
+import scorex.crypto.authds.avltree.batch.{Lookup, BatchAVLProver, Insert}
import scorex.crypto.authds.{ADKey, ADValue}
import scorex.crypto.hash
-import scorex.crypto.hash.{Blake2b256, Digest32}
+import scorex.crypto.hash.{Digest32, Blake2b256}
+import sigmastate.SCollection.SByteArray
import sigmastate.Values._
import sigmastate._
+import sigmastate.lang.Terms._
import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.serialization.ValueSerializer
import sigmastate.utxo._
class FsmExampleSpecification extends SigmaTestingCommons {
- implicit lazy val IR = new TestingIRContext
+ private implicit lazy val IR: TestingIRContext = new TestingIRContext
/**
* Similarly to the MAST-like example (in the MASTExampleSpecification class), we can do more complex contracts,
* e.g. ones with cycles. For example, we can do a contract described as a finite state machine.
@@ -39,12 +42,12 @@ class FsmExampleSpecification extends SigmaTestingCommons {
*/
property("simple FSM example") {
- val prover = new ErgoLikeTestProvingInterpreter
+ val prover = new ContextEnrichingTestProvingInterpreter
- val script1 = prover.dlogSecrets.head.publicImage.isProven
- val script2 = prover.dhSecrets.head.publicImage.isProven
- val script3 = AND(script1, script2)
- val script4 = prover.dlogSecrets.tail.head.publicImage .isProven //a script to leave FSM
+ val script1 = prover.dlogSecrets.head.publicImage.toSigmaProp
+ val script2 = prover.dhSecrets.head.publicImage.toSigmaProp
+ val script3 = SigmaAnd(script1, script2)
+ val script4 = prover.dlogSecrets.tail.head.publicImage.toSigmaProp //a script to leave FSM
val script1Hash = hash.Blake2b256(ValueSerializer.serialize(script1))
val script2Hash = hash.Blake2b256(ValueSerializer.serialize(script2))
@@ -71,7 +74,7 @@ class FsmExampleSpecification extends SigmaTestingCommons {
avlProver.generateProof()
val digest = avlProver.digest
- val treeData = new AvlTreeData(digest, 34, Some(0))
+ val treeData = new AvlTreeData(digest, AvlTreeFlags.ReadOnly, 34, Some(0))
val fsmDescRegister = ErgoBox.nonMandatoryRegisters.head
val currentStateRegister = ErgoBox.nonMandatoryRegisters(1)
@@ -79,15 +82,20 @@ class FsmExampleSpecification extends SigmaTestingCommons {
val scriptVarId = 2: Byte
val transitionProofId = 3: Byte
- val isMember = OptionIsDefined(TreeLookup(OptionGet(ExtractRegisterAs[SAvlTree.type](Self, fsmDescRegister)),
- Append(
+ val isMember = OptionIsDefined(
+ IR.builder.mkMethodCall(
+ OptionGet(ExtractRegisterAs[SAvlTree.type](Self, fsmDescRegister)),
+ SAvlTree.getMethod,
+ IndexedSeq(Append(
ConcreteCollection[SByte.type](
OptionGet(ExtractRegisterAs[SByte.type](Self, currentStateRegister)),
OptionGetOrElse(ExtractRegisterAs[SByte.type](ByIndex(Outputs, IntConstant.Zero),
currentStateRegister),ByteConstant(-1))),
CalcBlake2b256(GetVarByteArray(scriptVarId).get)
),
- GetVarByteArray(transitionProofId).get))
+ GetVarByteArray(transitionProofId).get)
+ ).asOption[SByteArray]
+ )
val scriptPreservation = EQ(ExtractScriptBytes(ByIndex(Outputs, IntConstant.Zero)), ExtractScriptBytes(Self))
@@ -116,9 +124,9 @@ class FsmExampleSpecification extends SigmaTestingCommons {
val finalScriptCorrect = TrueLeaf
- val fsmScript = OR(
- AND(isMember, DeserializeContext(scriptVarId, SBoolean), preservation), //going through FSM
- AND(finalStateCheck, finalScriptCorrect, DeserializeContext(scriptVarId, SBoolean)) //leaving FSM
+ val fsmScript = SigmaOr(
+ SigmaAnd(isMember, DeserializeContext(scriptVarId, SSigmaProp), preservation), //going through FSM
+ SigmaAnd(finalStateCheck, finalScriptCorrect, DeserializeContext(scriptVarId, SSigmaProp)) //leaving FSM
)
@@ -139,7 +147,7 @@ class FsmExampleSpecification extends SigmaTestingCommons {
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(fsmBox1),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(fsmBox2)),
+ createTransaction(fsmBox2),
self = fsmBox1)
val spendingProof = prover
@@ -159,7 +167,7 @@ class FsmExampleSpecification extends SigmaTestingCommons {
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(fsmBox2),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(fsmBox1)),
+ createTransaction(fsmBox1),
self = fsmBox2)
val spendingProof2 = prover
@@ -187,7 +195,7 @@ class FsmExampleSpecification extends SigmaTestingCommons {
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(fsmBox1),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(fsmBox3)),
+ createTransaction(fsmBox3),
self = fsmBox1)
//honest prover fails
@@ -214,7 +222,7 @@ class FsmExampleSpecification extends SigmaTestingCommons {
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(fsmBox2),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(fsmBox3)),
+ createTransaction(fsmBox3),
self = fsmBox2)
val spendingProof23 = prover
@@ -226,7 +234,7 @@ class FsmExampleSpecification extends SigmaTestingCommons {
//clearing FSM out of the box in the final state
- val freeBox = ErgoBox(100, TrueLeaf, 0)
+ val freeBox = ErgoBox(100, ErgoScriptPredef.TrueProp, 0)
avlProver.performOneOperation(Lookup(ADKey @@ (transition30 ++ script4Hash)))
val transition30Proof = avlProver.generateProof()
@@ -236,7 +244,7 @@ class FsmExampleSpecification extends SigmaTestingCommons {
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(fsmBox3),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(freeBox)),
+ createTransaction(freeBox),
self = fsmBox3)
val spendingProof30 = prover
@@ -252,7 +260,7 @@ class FsmExampleSpecification extends SigmaTestingCommons {
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(fsmBox2),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(freeBox)),
+ createTransaction(freeBox),
self = fsmBox2)
//honest prover fails
diff --git a/src/test/scala/sigmastate/utxo/examples/IcoExample.scala b/src/test/scala/sigmastate/utxo/examples/IcoExample.scala
new file mode 100644
index 0000000000..735f5906fb
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/IcoExample.scala
@@ -0,0 +1,135 @@
+package sigmastate.utxo.examples
+
+import com.google.common.primitives.Longs
+import org.ergoplatform.ErgoBox.{R4, R5}
+import org.ergoplatform.dsl.TestContractSpec
+import org.ergoplatform.{ErgoBox, ErgoLikeContext, ErgoLikeTransaction}
+import scorex.crypto.authds.{ADKey, ADValue}
+import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert}
+import scorex.crypto.hash.{Blake2b256, Digest32}
+import sigmastate.Values.{AvlTreeConstant, ByteArrayConstant, CollectionConstant}
+import sigmastate.{AvlTreeData, AvlTreeFlags, SByte}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.interpreter.Interpreter.ScriptNameProp
+import sigmastate.lang.Terms._
+
+class IcoExample extends SigmaTestingCommons {
+ suite =>
+ implicit lazy val IR: TestingIRContext = new TestingIRContext()
+ lazy val spec = TestContractSpec(suite)
+ lazy val backer = spec.ProvingParty("Alice")
+ lazy val project = spec.ProvingParty("Bob")
+
+ /**
+ * Simplest ICO example
+ */
+ property("simple ico example - fundraising stage only") {
+ val fundingEnv = Map(
+ ScriptNameProp -> "fundingScriptEnv"
+ )
+
+ val fundingScript = compile(fundingEnv,
+ """{
+ | val proof = getVar[Coll[Byte]](1).get
+ |
+ | // val funders: Coll[Box] = INPUTS.filter({(b: Box) => b.R5[Int].isEmpty})
+ |
+ | val toAdd: Coll[(Coll[Byte], Coll[Byte])] = INPUTS.map({ (b: Box) =>
+ | val pk = b.R4[Coll[Byte]].get
+ | val value = longToByteArray(b.value)
+ | (pk, value)
+ | })
+ |
+ | val modifiedTree = SELF.R5[AvlTree].get.insert(toAdd, proof).get
+ |
+ | val expectedTree = OUTPUTS(0).R5[AvlTree].get
+ |
+ | modifiedTree == expectedTree
+ |
+ |}""".stripMargin
+ ).asBoolValue.toSigmaProp
+
+ val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
+ val digest = avlProver.digest
+ val initTreeData = new AvlTreeData(digest, AvlTreeFlags.AllOperationsAllowed, 32, None)
+
+ val projectBoxBefore = ErgoBox(10, fundingScript, 0, Seq(),
+ Map(R4 -> ByteArrayConstant(Array.fill(16)(0: Byte) ++ Array.fill(16)(1: Byte)), R5 -> AvlTreeConstant(initTreeData)))
+
+ val inputBoxes = IndexedSeq(projectBoxBefore)
+
+ inputBoxes.foreach { b =>
+ val k = b.get(R4).get.asInstanceOf[CollectionConstant[SByte.type]].value
+ val v = Longs.toByteArray(b.value)
+ avlProver.performOneOperation(Insert(ADKey @@ k, ADValue @@ v))
+ }
+
+ val proof = avlProver.generateProof()
+ val endTree = new AvlTreeData(avlProver.digest, AvlTreeFlags.AllOperationsAllowed, 32, None)
+
+ val projectBoxAfter = ErgoBox(10, fundingScript, 0, Seq(),
+ Map(R4 -> ByteArrayConstant(Array.fill(32)(0: Byte)), R5 -> AvlTreeConstant(endTree)))
+
+ val fundingTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(projectBoxAfter))
+
+ val fundingContext = ErgoLikeContext(
+ currentHeight = 1000,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = inputBoxes,
+ spendingTransaction = fundingTx,
+ self = projectBoxBefore)
+
+ val projectProver = new ContextEnrichingTestProvingInterpreter()
+ .withContextExtender(1, ByteArrayConstant(proof))
+
+ projectProver.prove(fundingEnv + (ScriptNameProp -> "fundingScriptEnv"), fundingScript, fundingContext, fakeMessage).get
+ }
+
+ property("simple ico example - fixing stage") {
+
+ val fixingEnv = Map(
+ ScriptNameProp -> "fixingScriptEnv"
+ )
+
+ val fixingProp = compile(fixingEnv,
+ """{
+ | val openTree = SELF.R4[AvlTree].get
+ |
+ | val closedTree = OUTPUTS(0).R4[AvlTree].get
+ |
+ | val digestPreserved = openTree.digest == closedTree.digest
+ | val keyLengthPreserved = openTree.keyLength == closedTree.keyLength
+ | val valueLengthPreserved = openTree.valueLengthOpt == closedTree.valueLengthOpt
+ | val treeIsClosed = closedTree.enabledOperations == 0
+ |
+ | sigmaProp(digestPreserved && valueLengthPreserved && keyLengthPreserved && treeIsClosed)
+ |}""".stripMargin
+ ).asSigmaProp
+
+ val projectProver = new ErgoLikeTestProvingInterpreter
+ val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
+ val digest = avlProver.digest
+ val openTreeData = new AvlTreeData(digest, AvlTreeFlags.AllOperationsAllowed, 32, None)
+
+ val projectBoxBeforeClosing = ErgoBox(10, fixingProp, 0, Seq(),
+ Map(R4 -> AvlTreeConstant(openTreeData)))
+
+ val closedTreeData = new AvlTreeData(digest, AvlTreeFlags.ReadOnly, 32, None)
+
+ val projectBoxAfterClosing = ErgoBox(10, fixingProp, 0, Seq(),
+ Map(R4 -> AvlTreeConstant(closedTreeData)))
+
+ val fixingTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(projectBoxAfterClosing))
+
+ val fundingContext = ErgoLikeContext(
+ currentHeight = 1000,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(projectBoxBeforeClosing),
+ spendingTransaction = fixingTx,
+ self = projectBoxBeforeClosing)
+
+ projectProver.prove(fixingEnv, fixingProp, fundingContext, fakeMessage).get
+ }
+}
\ No newline at end of file
diff --git a/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala
index 41d5fd05dc..447eb2c626 100644
--- a/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala
@@ -1,12 +1,13 @@
package sigmastate.utxo.examples
import org.ergoplatform._
-import scorex.crypto.authds.avltree.batch.{Lookup, BatchAVLProver, Insert}
+import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert, Lookup}
import scorex.crypto.authds.{ADKey, ADValue}
import scorex.crypto.hash.{Digest32, Blake2b256}
+import sigmastate.SCollection.SByteArray
import sigmastate.Values._
import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.lang.Terms._
import sigmastate.interpreter.Interpreter._
import sigmastate.serialization.ValueSerializer
@@ -40,12 +41,12 @@ class MASTExampleSpecification extends SigmaTestingCommons {
val script1Hash = Blake2b256(script1Bytes)
val script2Hash = Blake2b256(ValueSerializer.serialize(GT(SizeOf(Inputs).upcastTo(SLong), LongConstant(1))))
- val prop = AND(scriptIsCorrect, If(EQ(SizeOf(Inputs), 1), EQ(scriptHash, script1Hash), EQ(scriptHash, script2Hash)))
+ val prop = AND(scriptIsCorrect, If(EQ(SizeOf(Inputs), 1), EQ(scriptHash, script1Hash), EQ(scriptHash, script2Hash))).toSigmaProp
val input1 = ErgoBox(20, prop, 0)
val tx = UnsignedErgoLikeTransaction(IndexedSeq(input1).map(i => new UnsignedInput(i.id)),
- IndexedSeq(ErgoBox(1, TrueLeaf, 0)))
+ IndexedSeq(ErgoBox(1, ErgoScriptPredef.TrueProp, 0)))
val ctx = ErgoLikeContext(
currentHeight = 50,
lastBlockUtxoRoot = AvlTreeData.dummy,
@@ -55,7 +56,7 @@ class MASTExampleSpecification extends SigmaTestingCommons {
self = input1)
- val prover = new ErgoLikeTestProvingInterpreter()
+ val prover = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(scriptId, ByteArrayConstant(script1Bytes))
val proveEnv = emptyEnv + (ScriptNameProp -> "simple_branching_prove")
@@ -85,28 +86,33 @@ class MASTExampleSpecification extends SigmaTestingCommons {
val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
treeElements.foreach(s => avlProver.performOneOperation(Insert(s._1, s._2)))
avlProver.generateProof()
- val treeData = new AvlTreeData(avlProver.digest, 32, None)
-
- val merklePathToScript = OptionIsDefined(TreeLookup(ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
- CalcBlake2b256(GetVarByteArray(scriptId).get),
- GetVarByteArray(proofId).get))
+ val treeData = new AvlTreeData(avlProver.digest, AvlTreeFlags.ReadOnly, 32, None)
+
+ val merklePathToScript = OptionIsDefined(
+ IR.builder.mkMethodCall(
+ ExtractRegisterAs[SAvlTree.type](Self, reg1).get,
+ SAvlTree.getMethod,
+ IndexedSeq(
+ CalcBlake2b256(GetVarByteArray(scriptId).get),
+ GetVarByteArray(proofId).get)).asOption[SByteArray]
+ )
val scriptIsCorrect = DeserializeContext(scriptId, SBoolean)
- val prop = AND(merklePathToScript, scriptIsCorrect)
+ val prop = AND(merklePathToScript, scriptIsCorrect).toSigmaProp
- val recipientProposition = new ErgoLikeTestProvingInterpreter().dlogSecrets.head.publicImage
- val selfBox = ErgoBox(20, TrueLeaf, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
+ val recipientProposition = new ContextEnrichingTestProvingInterpreter().dlogSecrets.head.publicImage
+ val selfBox = ErgoBox(20, ErgoScriptPredef.TrueProp, 0, Seq(), Map(reg1 -> AvlTreeConstant(treeData)))
val ctx = ErgoLikeContext(
currentHeight = 50,
lastBlockUtxoRoot = AvlTreeData.dummy,
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(selfBox),
- ErgoLikeTransaction(IndexedSeq(), IndexedSeq(ErgoBox(1, recipientProposition, 0))),
+ createTransaction(ErgoBox(1, recipientProposition, 0)),
self = selfBox)
avlProver.performOneOperation(Lookup(knownSecretTreeKey))
val knownSecretPathProof = avlProver.generateProof()
val usedBranch = scriptBranchesBytes.head
- val prover = new ErgoLikeTestProvingInterpreter()
+ val prover = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(secretId, knownSecret)
.withContextExtender(scriptId, ByteArrayConstant(usedBranch))
.withContextExtender(proofId, ByteArrayConstant(knownSecretPathProof))
diff --git a/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala
new file mode 100644
index 0000000000..4afba1f05e
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala
@@ -0,0 +1,252 @@
+
+package sigmastate.utxo.examples
+
+import java.math.BigInteger
+
+import org.ergoplatform.{ErgoBox, ErgoLikeContext, ErgoLikeTransaction}
+import org.ergoplatform.ErgoBox.{R4, R5, R6}
+import scorex.crypto.hash.Blake2b256
+import sigmastate.AvlTreeData
+import sigmastate.Values.{ByteConstant, GroupElementConstant, IntConstant, SigmaPropConstant}
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.basics.{DiffieHellmanTupleProverInput, ProveDHTuple}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
+import sigmastate.interpreter.CryptoConstants
+import sigmastate.interpreter.CryptoConstants.EcPointType
+import sigmastate.interpreter.Interpreter._
+import sigmastate.lang.Terms._
+
+class MixExampleSpecification extends SigmaTestingCommons {
+ private implicit lazy val IR = new TestingIRContext
+
+ property("Evaluation - Mix Example") {
+ import CryptoConstants.dlogGroup
+
+ val g = dlogGroup.generator
+
+ // Alice is first player, who initiates the mix
+ val alice = new ContextEnrichingTestProvingInterpreter
+ val alicePubKey:ProveDlog = alice.dlogSecrets.head.publicImage
+
+ val x:BigInteger = alice.dlogSecrets.head.w // x is Alice's private key
+
+ val g_x = alicePubKey.h // g_x is Alice's public key (g_x = g^x)
+ // Alternative 1:
+ // val g_x = alicePubKey.value
+ // Alternative 2:
+ // Generate x ourselves (e.g., val x = BigInt(randomBytes).bigInteger)
+ // To generate g_x from a BigInteger x, and to generate alicePubKey as ProveDlog type from g_x, use the following:
+ // val g_x:EcPointType = dlogGroup.exponentiate(g, x)
+ // val alicePubKey:ProveDlog = ProveDlog(g_x)
+
+ val fullMixEnv = Map(
+ ScriptNameProp -> "fullMixEnv",
+ "g" -> g,
+ "g_x" -> g_x
+ )
+
+ ProveDlog(g_x) shouldBe alicePubKey
+
+ // y is Bob's secret key and h = g^y is kind of like his "public key"
+ // The Diffie-Hellman solution is g_xy = g_y^x = g_x^y = g^xy.
+ val fullMixScript = compile(fullMixEnv,
+ """{
+ | val e = SELF.R4[GroupElement].get
+ | val f = SELF.R5[GroupElement].get
+ | proveDlog(f) || // either f is g^y
+ | proveDHTuple(g, e, g_x, f) // or f is u^y = g^xy
+ |}""".stripMargin
+ ).asSigmaProp
+
+ val halfMixEnv = Map(
+ ScriptNameProp -> "halfMixEnv",
+ "g" -> g,
+ "g_x" -> g_x,
+ "fullMixScriptHash" -> Blake2b256(fullMixScript.bytes)
+ )
+
+ // Note that below script allows Alice to spend the half-mix output anytime before Bob spends it.
+ // We could also consider a more restricted version of the game where Alice is unable to spend the half-mix output
+ // before some minimum height.
+
+ // The proveDHTuple instruction takes parameters (g, h, u, v) where g, h are generators (discrete log bases)
+ // with u = g^x and v = h^x. Note that y = log_g(h), where y is Bob's secret.
+
+ val halfMixScript = compile(halfMixEnv,
+ """{
+ | val c = OUTPUTS(0).R4[GroupElement].get
+ | val d = OUTPUTS(0).R5[GroupElement].get
+ |
+ | OUTPUTS.size == 2 &&
+ | OUTPUTS(0).value == SELF.value &&
+ | OUTPUTS(1).value == SELF.value &&
+ | blake2b256(OUTPUTS(0).propositionBytes) == fullMixScriptHash &&
+ | blake2b256(OUTPUTS(1).propositionBytes) == fullMixScriptHash &&
+ | OUTPUTS(1).R4[GroupElement].get == d &&
+ | OUTPUTS(1).R5[GroupElement].get == c && {
+ | proveDHTuple(g, g_x, c, d) ||
+ | proveDHTuple(g, g_x, d, c)
+ | }
+ |}""".stripMargin
+ ).asSigmaProp
+
+
+ /////////////////////////////////////////////////////////
+ //// Alice starts creating a Half-Mix box
+ /////////////////////////////////////////////////////////
+
+ // she creates a transaction that outputs a box with halfGame script.
+ // In the example, we don't create the transaction; we just create a box below
+
+ val halfMixCreationHeight = 70
+ val mixAmount = 10
+
+ val halfMixOutput = ErgoBox(mixAmount, halfMixScript, halfMixCreationHeight)
+ // above halMixOutput is a Half-Mix box created by Alice.
+
+ // a blockchain node verifying a block containing a spending transaction
+ val verifier = new ErgoLikeTestInterpreter
+
+ /////////////////////////////////////////////////////////
+ //// Bob picks Alice's Half-Mix box and creates a Full-Mix box
+ ///////////////////////////////////////////////////////////
+
+ // If Alice wants to abort the mix, she can take Bob's role and spend her Half-Mix output
+
+ val bob = new ContextEnrichingTestProvingInterpreter
+ val bobPubKey:ProveDlog = bob.dlogSecrets.head.publicImage
+
+ val y:BigInteger = bob.dlogSecrets.head.w // y is Bob's private key
+
+ val g_y = GroupElementConstant(bobPubKey.h) // g^y
+ val g_y_alt = GroupElementConstant(dlogGroup.exponentiate(g, y))
+
+ g_y shouldBe g_y_alt
+
+ // To Do: Extract below g_x from halfMixOutput
+ val g_xy = GroupElementConstant(dlogGroup.exponentiate(g_x, y))
+ val g_xy_alt = GroupElementConstant(dlogGroup.exponentiate(g_y, x))
+
+ g_xy shouldBe g_xy_alt
+
+ val randomBit = scala.util.Random.nextBoolean
+ // randomBit is interpreted as follows
+ // 0 is false
+ // 1 is true
+
+ val (c0, c1) = if (randomBit) (g_xy, g_y) else (g_y, g_xy)
+
+ val fullMixCreationHeight = 80
+
+ // if randomBit is 0 (i.e., false) below box is spendable by Alice, else by Bob
+ val fullMixOutput0 = ErgoBox(mixAmount, fullMixScript, fullMixCreationHeight, Nil,
+ Map(
+ R4 -> c0,
+ R5 -> c1
+ )
+ )
+
+ // if randomBit is 1 (i.e., true) below box is spendable by Alice, else by Bob
+ val fullMixOutput1 = ErgoBox(mixAmount, fullMixScript, fullMixCreationHeight, Nil,
+ Map(
+ R4 -> c1,
+ R5 -> c0
+ )
+ )
+
+ // normally this transaction would be invalid, but we're not checking it in this test
+ val fullMixTx = createTransaction(IndexedSeq(fullMixOutput0, fullMixOutput1))
+
+ val fullMixContext = ErgoLikeContext(
+ currentHeight = fullMixCreationHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(halfMixOutput),
+ spendingTransaction = fullMixTx,
+ self = halfMixOutput
+ )
+
+ // bob (2nd player) is generating a proof and it is passing verification
+ // To Do: Extract below g_x from halfMixOutput
+ val dhtBob = DiffieHellmanTupleProverInput(y, ProveDHTuple(g, g_x, g_y, g_xy))
+
+ val proofFullMix = (new ContextEnrichingTestProvingInterpreter).withDHSecrets(
+ Seq(dhtBob)
+ ).prove(halfMixEnv, halfMixScript, fullMixContext, fakeMessage).get.proof
+
+ verifier.verify(halfMixEnv, halfMixScript, fullMixContext, proofFullMix, fakeMessage).get._1 shouldBe true
+
+ //////////////////////////////////////////////
+ //// Setup for spending the above created outputs (fullMixOutput0, fullMixOutput1)
+ //////////////////////////////////////////////
+
+ // some 3rd person that will be paid
+ val carol = new ContextEnrichingTestProvingInterpreter
+ val carolPubKey:ProveDlog = carol.dlogSecrets.head.publicImage
+
+ val spendHeight = 90
+ val carolOutput = ErgoBox(mixAmount, carolPubKey, spendHeight)
+
+ // normally this transaction would be invalid, but we're not checking it in this test
+ val spendingTx = createTransaction(carolOutput)
+
+ //////////////////////////////////////////////
+ //// Alice spending her output
+ //////////////////////////////////////////////
+
+ val fullMixOutput0_R4 = fullMixOutput0.additionalRegisters(R4).v
+ val fullMixOutput0_R5 = fullMixOutput0.additionalRegisters(R5).v
+
+ fullMixOutput0_R4 shouldBe c0
+ fullMixOutput0_R5 shouldBe c1
+
+ val r4_x = dlogGroup.exponentiate(fullMixOutput0_R4.asInstanceOf[GroupElementConstant], x) // R4^x
+
+ // if R4^x == R5 then this fullMixOutput0 is Alice's output else its Bob's output.
+ val (aliceAnonBox, bobAnonBox) = if (r4_x == fullMixOutput0_R5.asInstanceOf[GroupElementConstant].value) {
+ println("First output is Alice's")
+ (fullMixOutput0, fullMixOutput1)
+ } else {
+ println("First output is Bob's")
+ dlogGroup.exponentiate(fullMixOutput0_R5.asInstanceOf[GroupElementConstant], x) shouldBe fullMixOutput0_R4.asInstanceOf[GroupElementConstant].value
+ (fullMixOutput1, fullMixOutput0)
+ }
+
+ val aliceSpendContext = ErgoLikeContext(
+ currentHeight = spendHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(aliceAnonBox),
+ spendingTransaction = spendingTx,
+ self = aliceAnonBox
+ )
+
+ // To Do: Extract below g_y, g_xy from fullMixOutputs registers
+ val dhtAlice = DiffieHellmanTupleProverInput(x, ProveDHTuple(g, g_y, g_x, g_xy))
+
+ val proofAliceSpend = (new ContextEnrichingTestProvingInterpreter).withDHSecrets(
+ Seq(dhtAlice)
+ ).prove(fullMixEnv, fullMixScript, aliceSpendContext, fakeMessage).get.proof
+
+ verifier.verify(fullMixEnv, fullMixScript, aliceSpendContext, proofAliceSpend, fakeMessage).get._1 shouldBe true
+
+ //////////////////////////////////////////////
+ //// Bob spending his output
+ //////////////////////////////////////////////
+
+ val bobSpendContext = ErgoLikeContext(
+ currentHeight = spendHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(bobAnonBox),
+ spendingTransaction = spendingTx,
+ self = bobAnonBox
+ )
+
+ val proofBobSpend = bob.prove(fullMixEnv, fullMixScript, bobSpendContext, fakeMessage).get.proof
+
+ verifier.verify(fullMixEnv, fullMixScript, bobSpendContext, proofBobSpend, fakeMessage).get._1 shouldBe true
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala b/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala
index 9de6ad6235..4d69d25d97 100644
--- a/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala
@@ -3,34 +3,37 @@ package sigmastate.utxo.examples
import java.security.SecureRandom
import com.google.common.primitives.Longs
-import org.ergoplatform.ErgoBox.RegisterId
-import org.ergoplatform._
+import org.ergoplatform.ErgoBox.{R4, RegisterId}
import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert, Lookup}
-import org.ergoplatform.ErgoBox.{RegisterId, R1, MandatoryRegisterId}
-import scorex.crypto.authds.avltree.batch.{Lookup, BatchAVLProver, Insert}
import scorex.crypto.authds.{ADKey, ADValue}
-import scorex.crypto.hash.{Digest32, Blake2b256}
+import scorex.crypto.hash.{Blake2b256, Digest32}
import sigmastate.SCollection.SByteArray
import sigmastate.Values._
import sigmastate._
+import sigmastate.lang.Terms._
import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.interpreter.CryptoConstants
import org.ergoplatform._
-import sigmastate.interpreter.Interpreter.{emptyEnv, ScriptNameProp}
+import org.ergoplatform.dsl.ContractSyntax.Token
+import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, StdContracts, TestContractSpec}
+import sigmastate.TrivialProp.TrueProp
+import sigmastate.eval.CSigmaProp
+import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv}
import sigmastate.utxo._
+import special.collection.Coll
+import special.sigma.Context
-class OracleExamplesSpecification extends SigmaTestingCommons {
+class OracleExamplesSpecification extends SigmaTestingCommons { suite =>
implicit lazy val IR = new TestingIRContext
- private val reg1 = ErgoBox.nonMandatoryRegisters.head
+ private val reg1 = ErgoBox.nonMandatoryRegisters(0)
private val reg2 = ErgoBox.nonMandatoryRegisters(1)
private val reg3 = ErgoBox.nonMandatoryRegisters(2)
private val reg4 = ErgoBox.nonMandatoryRegisters(3)
-
/**
- *
* An oracle example.
*
* A trusted weather station is publishing temperature data on blockchain.
@@ -71,18 +74,18 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
*
*/
property("oracle example") {
- val oracle = new ErgoLikeTestProvingInterpreter
- val aliceTemplate = new ErgoLikeTestProvingInterpreter
- val bob = new ErgoLikeTestProvingInterpreter
+ val oracle = new ContextEnrichingTestProvingInterpreter
+ val aliceTemplate = new ContextEnrichingTestProvingInterpreter
+ val bob = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val oraclePrivKey = oracle.dlogSecrets.head
val oraclePubImage = oraclePrivKey.publicImage
- val oraclePubKey = oraclePubImage.isProven
+ val oraclePubKey = oraclePubImage
- val alicePubKey = aliceTemplate.dlogSecrets.head.publicImage.isProven
- val bobPubKey = bob.dlogSecrets.head.publicImage.isProven
+ val alicePubKey = aliceTemplate.dlogSecrets.head.publicImage
+ val bobPubKey = bob.dlogSecrets.head.publicImage
val group = CryptoConstants.dlogGroup
@@ -108,7 +111,7 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
reg2 -> GroupElementConstant(a),
reg3 -> BigIntConstant(z),
reg4 -> LongConstant(ts)),
- boxId = 1
+ boxIndex = 1
)
val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
@@ -118,7 +121,7 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
val lastBlockUtxoDigest = avlProver.digest
- val treeData = new AvlTreeData(lastBlockUtxoDigest, 32, None)
+ val treeData = new AvlTreeData(lastBlockUtxoDigest, AvlTreeFlags.ReadOnly, 32, None)
def extract[T <: SType](Rn: RegisterId)(implicit tT: T) =
ExtractRegisterAs[T](GetVarBox(22: Byte).get, Rn)(tT).get
@@ -129,11 +132,14 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
OR(AND(GE(Height, IntConstant(sinceHeight)), LT(Height, IntConstant(timeoutHeight)), script),
AND(GE(Height, IntConstant(timeoutHeight)), fallback))
- val contractLogic = OR(AND(GT(extract[SLong.type](reg1), LongConstant(15)), alicePubKey),
- AND(LE(extract[SLong.type](reg1), LongConstant(15)), bobPubKey))
+ val contractLogic = OR(AND(GT(extract[SLong.type](reg1), LongConstant(15)), alicePubKey.isProven),
+ AND(LE(extract[SLong.type](reg1), LongConstant(15)), bobPubKey.isProven))
- val oracleProp = AND(OptionIsDefined(TreeLookup(LastBlockUtxoRootHash, ExtractId(GetVarBox(22: Byte).get), GetVarByteArray(23: Byte).get)),
- EQ(extract[SByteArray](ErgoBox.ScriptRegId), ByteArrayConstant(oraclePubKey.bytes)),
+ val oracleProp = AND(
+ OptionIsDefined(IR.builder.mkMethodCall(
+ LastBlockUtxoRootHash, SAvlTree.getMethod,
+ IndexedSeq(ExtractId(GetVarBox(22: Byte).get), GetVarByteArray(23: Byte).get)).asOption[SByteArray]),
+ EQ(extract[SByteArray](ErgoBox.ScriptRegId), ByteArrayConstant(ErgoTree.fromSigmaBoolean(oraclePubKey).bytes)),
EQ(Exponentiate(GroupGenerator, extract[SBigInt.type](reg3)),
MultiplyGroup(extract[SGroupElement.type](reg2),
Exponentiate(oraclePubImage.value,
@@ -152,23 +158,23 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
avlProver.performOneOperation(Lookup(ADKey @@ oracleBox.id))
val proof = avlProver.generateProof()
- val newBox1 = ErgoBox(20, alicePubKey, 0, boxId = 2)
+ val newBox1 = ErgoBox(20, alicePubKey, 0, boxIndex = 2)
val newBoxes = IndexedSeq(newBox1)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val sinceHeight = 40
val timeout = 60
- val propAlice = withinTimeframe(sinceHeight, timeout, alicePubKey)(oracleProp)
+ val propAlice = withinTimeframe(sinceHeight, timeout, alicePubKey.isProven)(oracleProp).toSigmaProp
- val sAlice = ErgoBox(10, propAlice, 0, Seq(), Map(), boxId = 3)
+ val sAlice = ErgoBox(10, propAlice, 0, Seq(), Map(), boxIndex = 3)
//"along with a brother" script
val propAlong = AND(
EQ(SizeOf(Inputs), IntConstant(2)),
EQ(ExtractId(ByIndex(Inputs, 0)), ByteArrayConstant(sAlice.id)))
- val propBob = withinTimeframe(sinceHeight, timeout, bobPubKey)(propAlong)
- val sBob = ErgoBox(10, propBob, 0, Seq(), Map(), boxId = 4)
+ val propBob = withinTimeframe(sinceHeight, timeout, bobPubKey.isProven)(propAlong).toSigmaProp
+ val sBob = ErgoBox(10, propBob, 0, Seq(), Map(), boxIndex = 4)
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -176,7 +182,7 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(sAlice, sBob),
spendingTransaction,
- self = null)
+ self = sAlice)
val alice = aliceTemplate
.withContextExtender(22: Byte, BoxConstant(oracleBox))
@@ -194,9 +200,10 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
}
+
/**
* In previous example, Alice and Bob can use the same box with temperature written into multiple times (possibly,
- * in on one block). Costs for a prover are high though.
+ * in one block). Costs for a prover are high though.
*
* In the example below we consider an alternative approach with one-time oracle box. An oracle creates a box with
* temperature written by request, and its only spendable by a transaction which is using Allce's and Bob's boxes.
@@ -204,20 +211,19 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
*
* As oracle is creating the box with the data on request, it can also participate in a spending transaction.
* Heavyweight authentication from the previous example is not needed then.
- *
*/
property("lightweight oracle example") {
- val oracle = new ErgoLikeTestProvingInterpreter
- val alice = new ErgoLikeTestProvingInterpreter
- val bob = new ErgoLikeTestProvingInterpreter
+ val oracle = new ContextEnrichingTestProvingInterpreter
+ val alice = new ContextEnrichingTestProvingInterpreter
+ val bob = new ContextEnrichingTestProvingInterpreter
val verifier = new ErgoLikeTestInterpreter
val oraclePrivKey = oracle.dlogSecrets.head
- val oraclePubKey = oraclePrivKey.publicImage.isProven
+ val oraclePubKey = oraclePrivKey.publicImage
- val alicePubKey = alice.dlogSecrets.head.publicImage.isProven
- val bobPubKey = bob.dlogSecrets.head.publicImage.isProven
+ val alicePubKey = alice.dlogSecrets.head.publicImage
+ val bobPubKey = bob.dlogSecrets.head.publicImage
val temperature: Long = 18
@@ -228,13 +234,16 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
additionalRegisters = Map(reg1 -> LongConstant(temperature))
)
- val contractLogic = OR(AND(GT(ExtractRegisterAs[SLong.type](ByIndex(Inputs, 0), reg1).get, LongConstant(15)), alicePubKey),
- AND(LE(ExtractRegisterAs[SLong.type](ByIndex(Inputs, 0), reg1).get, LongConstant(15)), bobPubKey))
+ val contractLogic = OR(
+ AND(GT(ExtractRegisterAs[SLong.type](ByIndex(Inputs, 0), reg1).get, LongConstant(15)), alicePubKey.isProven),
+ AND(LE(ExtractRegisterAs[SLong.type](ByIndex(Inputs, 0), reg1).get, LongConstant(15)), bobPubKey.isProven)
+ )
- val prop = AND(EQ(SizeOf(Inputs), IntConstant(3)),
- EQ(ExtractScriptBytes(ByIndex(Inputs, 0)), ByteArrayConstant(oraclePubKey.bytes)),
+ val prop = AND(
+ EQ(SizeOf(Inputs), IntConstant(3)),
+ EQ(ExtractScriptBytes(ByIndex(Inputs, 0)), ByteArrayConstant(ErgoTree.fromSigmaBoolean(oraclePubKey).bytes)),
contractLogic
- )
+ ).toSigmaProp
val sOracle = oracleBox
val sAlice = ErgoBox(10, prop, 0, Seq(), Map())
@@ -242,7 +251,7 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
val newBox1 = ErgoBox(20, alicePubKey, 0)
val newBoxes = IndexedSeq(newBox1)
- val spendingTransaction = ErgoLikeTransaction(IndexedSeq(), newBoxes)
+ val spendingTransaction = createTransaction(newBoxes)
val ctx = ErgoLikeContext(
currentHeight = 50,
@@ -250,9 +259,73 @@ class OracleExamplesSpecification extends SigmaTestingCommons {
minerPubkey = ErgoLikeContext.dummyPubkey,
boxesToSpend = IndexedSeq(sOracle, sAlice, sBob),
spendingTransaction,
- self = null)
+ self = sOracle)
val prA = alice.prove(emptyEnv + (ScriptNameProp -> "alice_prove"), prop, ctx, fakeMessage).get
verifier.verify(emptyEnv + (ScriptNameProp -> "verify"), prop, ctx, prA, fakeMessage).get._1 shouldBe true
}
+
+ case class OracleContract[Spec <: ContractSpec]
+ ( temperature: Long,
+ oracle: Spec#ProvingParty, alice: Spec#ProvingParty, bob: Spec#ProvingParty)
+ (implicit val spec: Spec) extends SigmaContractSyntax with StdContracts
+ {
+ import syntax._
+ def pkOracle = oracle.pubKey
+ def pkA = alice.pubKey
+ def pkB = bob.pubKey
+ def inRegId = reg1.asIndex
+
+ lazy val contractEnv = Env("pkA" -> pkA, "pkB" -> pkB, "pkOracle" -> pkOracle, "inRegId" -> inRegId)
+
+ lazy val prop = proposition("buyer", { ctx: Context =>
+ import ctx._
+ val okInputs = INPUTS.length == 3
+ val okInput0 = INPUTS(0).propositionBytes == pkOracle.propBytes
+ val inReg = INPUTS(0).R4[Long].get
+ val okContractLogic = (inReg > 15L && pkA) || (inReg <= 15L && pkB)
+ okInputs && okInput0 && okContractLogic
+ },
+ """{
+ | val okInputs = INPUTS.size == 3
+ | val okInput0 = INPUTS(0).propositionBytes == pkOracle.propBytes
+ | val inReg = INPUTS(0).R4[Long].get
+ | val okContractLogic = (inReg > 15L && pkA) || (inReg <= 15L && pkB)
+ | okInputs && okInput0 && okContractLogic
+ |}
+ """.stripMargin)
+
+ lazy val oracleSignature = proposition("oracleSignature", _ => pkOracle, "pkOracle")
+ lazy val aliceSignature = proposition("aliceSignature", _ => pkA, "pkA")
+ }
+
+ lazy val spec = TestContractSpec(suite)(new TestingIRContext)
+ lazy val oracle = spec.ProvingParty("Alice")
+ lazy val alice = spec.ProvingParty("Alice")
+ lazy val bob = spec.ProvingParty("Bob")
+
+ property("lightweight oracle example (ErgoDsl)") {
+ val temperature: Long = 18
+ val contract = OracleContract[spec.type](temperature, oracle, alice, bob)(spec)
+ import contract.spec._
+
+ // ARRANGE
+ // block, tx, and output boxes which we will spend
+ val mockTx = candidateBlock(0).newTransaction()
+ val sOracle = mockTx
+ .outBox(value = 1L, contract.oracleSignature)
+ .withRegs(reg1 -> temperature)
+
+ val sAlice = mockTx.outBox(10, contract.prop)
+ val sBob = mockTx.outBox(10, contract.prop)
+
+ val tx = candidateBlock(50).newTransaction().spending(sOracle, sAlice, sBob)
+ tx.outBox(20, contract.aliceSignature)
+ val in = tx.inputs(1)
+ val res = in.runDsl()
+ res shouldBe alice.pubKey
+
+ val pr = alice.prove(in).get
+ contract.verifier.verify(in, pr) shouldBe true
+ }
}
diff --git a/src/test/scala/sigmastate/utxo/examples/RPSGameExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/RPSGameExampleSpecification.scala
new file mode 100644
index 0000000000..3575813884
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/RPSGameExampleSpecification.scala
@@ -0,0 +1,307 @@
+
+package sigmastate.utxo.examples
+
+import org.ergoplatform.ErgoBox.{R4, R5, R6, R7}
+import org.ergoplatform._
+import scorex.crypto.hash.Blake2b256
+import scorex.utils.Random
+import sigmastate.Values.{ByteArrayConstant, ByteConstant, IntConstant, SigmaBoolean, SigmaPropConstant}
+import sigmastate._
+import sigmastate.basics.DLogProtocol.ProveDlog
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
+import sigmastate.interpreter.Interpreter._
+import sigmastate.lang.Terms._
+import sigmastate.utxo._
+
+class RPSGameExampleSpecification extends SigmaTestingCommons {
+ implicit lazy val IR = new TestingIRContext
+ /** RPS game:
+
+ Alice creates a RPS game of "playAmount" ergs by creating a Half-game UTXO called the "halfGameOutput" output below.
+ Another player (Bob) then sends a transaction spending Alice's UTXO and creating two outputs called "fullGameOutputs" ("Full game" UTXOs).
+ After Alice opens her commitment (see below), the fullGameOutputs can be spent by the winner.
+ The transactions encode the following protocol.
+
+ protocol:
+ Step 1: Alice commits to secret number a in {0, 1, 2} as follows:
+ Generate random s and compute h = Hash(s||a)
+ h is the commitment to a
+ Alice also selects the "play amount", the amount each player must spend to participate.
+ She generates a halfGameOutput encoding h and some spending condition given below by halfGameScript
+ Step 2: Bob chooses random number b from {0, 1, 2} (public) and creates a new tx spending Alice's UTXO along with
+ some others and creating two outputs that has the spending conditions given by fullGameScript.
+ (one of the conditions being that the amount of that output is >= twice the play amount.)
+ Step 3: Alice reveals (s, a) to open her commitment and winner is decided as per RPS rules.
+ If Alice fails to open her commitment before some deadline then Bob automatically wins.
+
+ For simplicity, we will use following bytes to designate choices
+ 0x00 = 0 = rock
+ 0x01 = 1 = paper
+ 0x02 = 2 = scissors
+
+ */
+ property("Evaluation - RpsGame Example") {
+
+ // Alice is first player, who initiates the game
+ val alice = new ContextEnrichingTestProvingInterpreter
+ val alicePubKey:ProveDlog = alice.dlogSecrets.head.publicImage
+
+ val a:Byte = (scala.util.Random.nextInt.abs % 3).toByte
+ val s:Array[Byte] = Random.randomBytes(31) // random padding
+ val h = Blake2b256(s :+ a) // Alice's commitment
+
+ val fullGameEnv = Map(
+ ScriptNameProp -> "fullGameScriptEnv",
+ "alice" -> alicePubKey,
+ "k" -> h
+ )
+
+ val fullGameScript = compile(fullGameEnv,
+ """{
+ | val s = getVar[Coll[Byte]](0).get // Alice's secret byte string s
+ | val a = getVar[Byte](1).get // Alice's secret choice a (represented as a byte)
+ | val b = SELF.R4[Byte].get // Bob's public choice b (represented as a byte)
+ | val bob = SELF.R5[SigmaProp].get
+ | val bobDeadline = SELF.R6[Int].get // after this height, Bob gets to spend unconditionally
+ | val drawPubKey = SELF.R7[SigmaProp].get
+ |
+ | (bob && HEIGHT > bobDeadline) || {
+ | val valid_a = (a == 0 || a == 1 || a == 2) && blake2b256(s ++ Coll(a)) == k
+ | valid_a && {
+ | val a_minus_b = a - b
+ | if (a_minus_b == 0) drawPubKey else {
+ | if ((a_minus_b) == 1 || (a_minus_b) == -2) alice else bob
+ | }
+ | }
+ | }
+ |}""".stripMargin
+ ).asSigmaProp
+
+ val halfGameEnv = Map(
+ ScriptNameProp -> "halfGameScript",
+ "alice" -> alicePubKey,
+ "fullGameScriptHash" -> Blake2b256(fullGameScript.bytes)
+ )
+
+ // Note that below script allows Alice to spend the half-game output anytime before Bob spends it.
+ // We could also consider a more restricted version of the game where Alice is unable to spend the half-game output
+ // before some minimum height.
+ val halfGameScript = compile(halfGameEnv,
+ """{
+ | OUTPUTS.forall{(out:Box) =>
+ | val b = out.R4[Byte].get
+ | val bobDeadline = out.R6[Int].get
+ | val validBobInput = b == 0 || b == 1 || b == 2
+ | // Bob needs to ensure that out.R5 contains bobPubKey
+ | bobDeadline >= HEIGHT+30 &&
+ | out.value >= SELF.value &&
+ | validBobInput &&
+ | blake2b256(out.propositionBytes) == fullGameScriptHash
+ | } && OUTPUTS.size == 2 &&
+ | OUTPUTS(0).R7[SigmaProp].get == alice // Alice does not care for Bob's draw case
+ | // Bob needs to ensure that OUTPUTS(1).R7 contains his public key
+ |}
+ """.stripMargin).asBoolValue.toSigmaProp
+
+ /////////////////////////////////////////////////////////
+ //// Alice starts creating a Half-Game
+ /////////////////////////////////////////////////////////
+
+ // she creates a transaction that outputs a box with halfGame script.
+ // In the example, we don't create the transaction; we just create a box below
+
+ val halfGameCreationHeight = 70
+ val playAmount = 10 // LongConstant(10)
+
+ val halfGameOutput = ErgoBox(playAmount, halfGameScript, halfGameCreationHeight)
+
+ /////////////////////////////////////////////////////////
+ //// above halfGameOutput is a Half-Game "box" created by Alice.
+ /////////////////////////////////////////////////////////
+
+ //a blockchain node verifying a block containing a spending transaction
+ val verifier = new ErgoLikeTestInterpreter
+
+ /////////////////////////////////////////////////////////
+ //// Bob will spend halfGameOutput and generate a full game
+ /////////////////////////////////////////////////////////
+
+ // a variable indicating height at which the tx spending halfGameTx is created
+ val fullGameCreationHeight = halfGameCreationHeight + 10
+
+ val bob = new ContextEnrichingTestProvingInterpreter
+ val bobPubKey:ProveDlog = bob.dlogSecrets.head.publicImage
+ val bobDeadline = 120 // height after which it become's Bob's money
+ val b:Byte = (scala.util.Random.nextInt.abs % 3).toByte
+
+ val fullGameOutput0 = ErgoBox(playAmount, fullGameScript, fullGameCreationHeight, Nil,
+ Map(
+ R4 -> ByteConstant(b),
+ R5 -> SigmaPropConstant(bobPubKey),
+ R6 -> IntConstant(bobDeadline),
+ R7 -> SigmaPropConstant(alicePubKey)
+ )
+ )
+
+ val fullGameOutput1 = ErgoBox(playAmount, fullGameScript, fullGameCreationHeight, Nil,
+ Map(
+ R4 -> ByteConstant(b),
+ R5 -> SigmaPropConstant(bobPubKey),
+ R6 -> IntConstant(bobDeadline),
+ R7 -> SigmaPropConstant(bobPubKey)
+ )
+ )
+
+ //normally this transaction would invalid (why?), but we're not checking it in this test
+ val fullGameTx = createTransaction(IndexedSeq(fullGameOutput0, fullGameOutput1))
+
+ val fullGameContext = ErgoLikeContext(
+ currentHeight = fullGameCreationHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(halfGameOutput),
+ spendingTransaction = fullGameTx,
+ self = halfGameOutput // what is the use of self?
+ )
+
+ // bob (2nd player) is generating a proof and it is passing verification
+ val proofFullGame = bob.prove(halfGameEnv, halfGameScript, fullGameContext, fakeMessage).get.proof
+
+ verifier.verify(halfGameEnv, halfGameScript, fullGameContext, proofFullGame, fakeMessage).get._1 shouldBe true
+
+ /////////////////////////////////////////////////////////
+ //// fullGameOutput represents the Full-Game "box" created by Bob.
+ /////////////////////////////////////////////////////////
+
+ /////////////////////////////////////////////////////////
+ // Possibility 1: Alice reveals secret
+ /////////////////////////////////////////////////////////
+
+ val gameOverHeight = fullGameCreationHeight + 10
+ // assume paying to Carol
+ val carol = new ContextEnrichingTestProvingInterpreter
+ val carolPubKey:ProveDlog = carol.dlogSecrets.head.publicImage
+
+ // note that playAmount below is not checked. It could be anything.
+ val gameOverOutput = ErgoBox(playAmount, carolPubKey, gameOverHeight)
+
+ // normally this transaction would be invalid, but we're not checking it in this test
+ val gameOverTx = createTransaction(gameOverOutput)
+
+ val aliceProver = alice.withContextExtender(0, ByteArrayConstant(s)).withContextExtender(1, ByteConstant(a))
+ val bobProver = bob.withContextExtender(0, ByteArrayConstant(s)).withContextExtender(1, ByteConstant(a))
+
+ val winContext0 = ErgoLikeContext(
+ currentHeight = gameOverHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(fullGameOutput0, fullGameOutput1),
+ spendingTransaction = gameOverTx,
+ self = fullGameOutput0
+ )
+
+ val winContext1 = ErgoLikeContext(
+ currentHeight = gameOverHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(fullGameOutput0, fullGameOutput1),
+ spendingTransaction = gameOverTx,
+ self = fullGameOutput1
+ )
+
+ a - b match {
+ case 0 => // draw
+ println("Draw")
+ /////////////////////////////////////////////////////////
+ // Possibility 1.1: draw
+ /////////////////////////////////////////////////////////
+
+ val drawContextAlice = ErgoLikeContext(
+ currentHeight = gameOverHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(fullGameOutput0),
+ spendingTransaction = gameOverTx,
+ self = fullGameOutput0
+ )
+
+ val proofAliceDraw = aliceProver.prove(fullGameEnv, fullGameScript, drawContextAlice, fakeMessage).get
+ verifier.verify(fullGameEnv, fullGameScript, drawContextAlice, proofAliceDraw, fakeMessage).get._1 shouldBe true
+
+ val drawContextBob = ErgoLikeContext(
+ currentHeight = gameOverHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(fullGameOutput1),
+ spendingTransaction = gameOverTx,
+ self = fullGameOutput1
+ )
+
+ val proofBobDraw = bobProver.prove(fullGameEnv, fullGameScript, drawContextBob, fakeMessage).get
+ verifier.verify(fullGameEnv, fullGameScript, drawContextBob, proofBobDraw, fakeMessage).get._1 shouldBe true
+
+ case 1 | -2 => // alice wins
+ println("Alice won")
+ /////////////////////////////////////////////////////////
+ // Possibility 1.2: Alice wins
+ /////////////////////////////////////////////////////////
+
+ val proofAliceWin0 = aliceProver.prove(fullGameEnv, fullGameScript, winContext0, fakeMessage).get
+ verifier.verify(fullGameEnv, fullGameScript, winContext0, proofAliceWin0, fakeMessage).get._1 shouldBe true
+
+ val proofAliceWin1 = aliceProver.prove(fullGameEnv, fullGameScript, winContext1, fakeMessage).get
+ verifier.verify(fullGameEnv, fullGameScript, winContext1, proofAliceWin1, fakeMessage).get._1 shouldBe true
+ case _ => // bob wins
+ println("Bob won")
+ /////////////////////////////////////////////////////////
+ // Possibility 1.3: Bob wins
+ /////////////////////////////////////////////////////////
+ val proofBobWin0 = bobProver.prove(fullGameEnv, fullGameScript, winContext0, fakeMessage).get
+ verifier.verify(fullGameEnv, fullGameScript, winContext0, proofBobWin0, fakeMessage).get._1 shouldBe true
+
+ val proofBobWin1 = bobProver.prove(fullGameEnv, fullGameScript, winContext1, fakeMessage).get
+ verifier.verify(fullGameEnv, fullGameScript, winContext1, proofBobWin1, fakeMessage).get._1 shouldBe true
+ }
+
+ /////////////////////////////////////////////////////////
+ // Possibility 2: (Bob wins and Alice does not reveal secret) OR (Alice wins and does not spend before bobDeadline)
+ // Bob can spend after bobDeadline.
+ /////////////////////////////////////////////////////////
+
+ val defaultWinHeight = bobDeadline + 1
+
+ // assume Bob is paying to Carol
+ // note that playAmount*2 below is not checked. It could be anything.
+ val defaultWinOutput = ErgoBox(playAmount*2, carolPubKey, defaultWinHeight)
+
+ //normally this transaction would invalid (why?), but we're not checking it in this test
+ val defaultWinTx = createTransaction(defaultWinOutput)
+
+ val defaultWinContext0 = ErgoLikeContext(
+ currentHeight = defaultWinHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(fullGameOutput0, fullGameOutput1),
+ spendingTransaction = defaultWinTx,
+ self = fullGameOutput0 // what is the use of self?
+ )
+ val defaultWinContext1 = ErgoLikeContext(
+ currentHeight = defaultWinHeight,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(fullGameOutput0, fullGameOutput1),
+ spendingTransaction = defaultWinTx,
+ self = fullGameOutput1 // what is the use of self?
+ )
+
+ val sDummy = Array[Byte]() // empty value for s; commitment cannot be opened but still Bob will be able to spend
+ val aDummy:Byte = 0
+ // below we need to specify a and s (even though they are not needed)
+ val proofDefaultWin0 = bobProver.prove(fullGameEnv, fullGameScript, defaultWinContext0, fakeMessage).get
+ verifier.verify(fullGameEnv, fullGameScript, defaultWinContext0, proofDefaultWin0, fakeMessage).get._1 shouldBe true
+
+ val proofDefaultWin1 = bobProver.prove(fullGameEnv, fullGameScript, defaultWinContext1, fakeMessage).get
+ verifier.verify(fullGameEnv, fullGameScript, defaultWinContext1, proofDefaultWin1, fakeMessage).get._1 shouldBe true
+ }
+
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/ReversibleTxExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/ReversibleTxExampleSpecification.scala
index 0dc8701f29..41995d02cd 100644
--- a/src/test/scala/sigmastate/utxo/examples/ReversibleTxExampleSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/ReversibleTxExampleSpecification.scala
@@ -1,12 +1,12 @@
package sigmastate.utxo.examples
-import sigmastate.interpreter.Interpreter.ScriptNameProp
import org.ergoplatform.ErgoBox.{R4, R5}
import org.ergoplatform._
import scorex.crypto.hash.Blake2b256
import sigmastate.Values.{IntConstant, SigmaPropConstant}
import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
+import sigmastate.interpreter.Interpreter.ScriptNameProp
import sigmastate.lang.Terms._
import sigmastate.utxo._
@@ -23,69 +23,88 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons {
* Often lack of reversible payments is considered a drawback in Bitcoin. ErgoScript allows us to easily design
* reversible payments.
*
- * assume Alice (alicePubKey) is the (hot) wallet of mining pool or an exchange.
+ * Use-case:
+ *
+ * Consider the hot-wallet of a mining pool or an exchange. Funds withdrawn by customers originate from this hot-wallet.
+ *
+ * Since its a hot-wallet, its private key can get compromised and unauthorized withdraws can occur.
+ *
+ * We want to ensure that in the event of such a compromise, we are able to "save" all funds stored in this wallet by
+ * moving them to a secure address, provided that the breach is discovered within 24 hours of the first unauthorized withdraw.
+ *
+ * In order to achieve this, we require that all coins sent via the hot-wallet (both legitimate and by the attacker)
+ * have a 24 hour cooling off period, during which the created UTXOs are "locked" and can only be spent by a trusted
+ * private key (which is different from the hot-wallet private key)
+ * Once this period is over, those coins become normal and can only be spent by the customer who withdrew.
+ *
+ * This is achieved by storing the hot-wallet funds in a Reversible Address, a special type of address.
*
- * Bob (bobPubKey) is an account holder with the pool or exchange. He may legitimately withdraw funds anytime.
- * The funds will be sent from a box controlled by alicePubKey. This is the normal scenario
+ * The reversible address is a P2SH address created using a script that encodes our spending condition.
+ * The script requires that any UTXO created by spending this box can only be spent by the trusted party during the
+ * locking period. Thus, all funds sent from such addresses have a temporary lock.
*
- * However, since alicePubKey is from a hot wallet, it could get compromised. Once compromised, any funds sent
- * from alicePubKey to some bobPubKey are not normal withdrawals and should be invalidated (aborted), provided
- * that the breach is discovered within a certain time (example 24 hours).
+ * Note that reversible addresses are designed for storing large amount of funds needed for automated withdraws
+ * (such as an exchange hot-wallet). They are NOT designed for storing funds for personal use (such as paying for a coffee).
*
- * In the abort scenario, we require that all withdraws are reversed and those funds are sent to a different
- * secure address (unrelated to alicePubKey).
+ * We use the following notation in the code:
*
- * The abort scenario would (and should) be performed by a key different from alicePubKey
- * Assume that abort can be done by Carol (carolPubKey) only.
+ * Alice is the hot-wallet with public key alicePubKey
*
- * The protocol is as follows:
- * Alice creates a script encoding the "reversible" logic. Lets call this the withdrawScript
+ * Bob with public key bobPubKey is a customer withdrawing from Alice. This is the normal scenario
*
- * She then creates a wallet address using a script called walletScript, which requires that the
- * spending condition generate a single box protected by withdrawScript
+ * Carol with public key carolPubKey is the trusted party who can spend during the locking period (i.e., she can reverse payments)
+ *
+ * Once alicePubKey is compromised (i.e., a transaction spending from this key is found to be unauthorized), an "abort procedure"
+ * is triggered. After this, all locked UTXOs sent from alicePubKey are suspect and should be aborted by Carol.
+ *
+ * A reversible address is created by Alice as follows:
+ *
+ * 1. Alice creates a script encoding the "reversible" logic. Lets call this the withdrawScript
+ * 2. She then creates a script called depositScript which requires that all created boxes be protected by withdrawScript.
+ * 3. She a deposit a P2SH address for topping up the hot-wallet using depositScript.
*
*/
property("Evaluation - Reversible Tx Example") {
- val alice = new ErgoLikeTestProvingInterpreter
+ val alice = new ContextEnrichingTestProvingInterpreter // private key controlling hot-wallet funds
val alicePubKey = alice.dlogSecrets.head.publicImage
- val bob = new ErgoLikeTestProvingInterpreter
+ val bob = new ContextEnrichingTestProvingInterpreter // private key of customer whose withdraws are sent from hot-wallet
val bobPubKey = bob.dlogSecrets.head.publicImage
- val carol = new ErgoLikeTestProvingInterpreter
+ val carol = new ContextEnrichingTestProvingInterpreter // private key of trusted party who can abort withdraws
val carolPubKey = carol.dlogSecrets.head.publicImage
val withdrawEnv = Map(
ScriptNameProp -> "withdrawEnv",
- "carolPubKey" -> carolPubKey // this pub key can reverse payments
+ "carol" -> carolPubKey // this pub key can reverse payments
)
- val withdrawScript = compileWithCosting(withdrawEnv,
+ val withdrawScript = compile(withdrawEnv,
"""{
- | val bobPubKey = SELF.R4[SigmaProp].get // Bob's key (or script) that Alice sent money to
+ | val bob = SELF.R4[SigmaProp].get // Bob's key (or script) that Alice sent money to
| val bobDeadline = SELF.R5[Int].get // after this height, Bob gets to spend unconditionally
|
- | (bobPubKey && HEIGHT > bobDeadline) ||
- | (carolPubKey && HEIGHT <= bobDeadline) // carolPubKey hardwired via withdrawEnv
- |}""".stripMargin).asBoolValue
+ | (bob && HEIGHT > bobDeadline) || (carol && HEIGHT <= bobDeadline)
+ |}""".stripMargin).asSigmaProp
- val walletEnv = Map(
- ScriptNameProp -> "walletEnv",
- "alicePubKey" -> alicePubKey,
+ val depositEnv = Map(
+ ScriptNameProp -> "depositEnv",
+ "alice" -> alicePubKey,
"withdrawScriptHash" -> Blake2b256(withdrawScript.bytes)
)
- val walletScript = compileWithCosting(walletEnv,
+ val depositScript = compile(depositEnv,
"""{
- | alicePubKey &&
- | OUTPUTS.size == 1 &&
- | blake2b256(OUTPUTS(0).propositionBytes) == withdrawScriptHash &&
- | OUTPUTS(0).R5[Int].get >= HEIGHT + 30 // bobDeadline stored in R5. after this height, Bob gets to spend unconditionally
+ | alice && OUTPUTS.forall({(out:Box) =>
+ | out.R5[Int].get >= HEIGHT + 30 &&
+ | blake2b256(out.propositionBytes) == withdrawScriptHash
+ | })
|}""".stripMargin
- ).asBoolValue
+ ).asSigmaProp
+ // Note: in above bobDeadline is stored in R5. After this height, Bob gets to spend unconditionally
- val walletAddress = Pay2SHAddress(walletScript)
+ val depositAddress = Pay2SHAddress(depositScript)
// The above is a "reversible wallet" address.
// Payments sent from this wallet are all reversible for a certain time
@@ -96,7 +115,7 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons {
// In the example, we don't create the transaction; we just create a box below
- val depositOutput = ErgoBox(depositAmount, walletAddress.script, depositHeight)
+ val depositOutput = ErgoBox(depositAmount, depositAddress.script, depositHeight)
// Now Alice wants to give Bob some amount from the wallet in a "reversible" way.
@@ -112,7 +131,7 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons {
)
//normally this transaction would be invalid (why?), but we're not checking it in this test
- val withdrawTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(reversibleWithdrawOutput))
+ val withdrawTx = createTransaction(reversibleWithdrawOutput)
val withdrawContext = ErgoLikeContext(
currentHeight = withdrawHeight,
@@ -123,16 +142,16 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons {
self = depositOutput
)
- val proofWithdraw = alice.prove(walletEnv, walletScript, withdrawContext, fakeMessage).get.proof
+ val proofWithdraw = alice.prove(depositEnv, depositScript, withdrawContext, fakeMessage).get.proof
val verifier = new ErgoLikeTestInterpreter
- verifier.verify(walletEnv, walletScript, withdrawContext, proofWithdraw, fakeMessage).get._1 shouldBe true
+ verifier.verify(depositEnv, depositScript, withdrawContext, proofWithdraw, fakeMessage).get._1 shouldBe true
// Possibility 1: Normal scenario
// Bob spends after bobDeadline. He sends to Dave
- val dave = new ErgoLikeTestProvingInterpreter
+ val dave = new ContextEnrichingTestProvingInterpreter
val davePubKey = dave.dlogSecrets.head.publicImage
val bobSpendAmount = 10
@@ -141,9 +160,7 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons {
val bobSpendOutput = ErgoBox(bobSpendAmount, davePubKey, bobSpendHeight)
//normally this transaction would be invalid (why?), but we're not checking it in this test
- val bobSpendTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(bobSpendOutput))
-
- // val fakeSelf: ErgoBox = createBox(0, TrueLeaf)
+ val bobSpendTx = createTransaction(bobSpendOutput)
val bobSpendContext = ErgoLikeContext(
currentHeight = bobSpendHeight,
@@ -168,9 +185,7 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons {
val carolSpendOutput = ErgoBox(carolSpendAmount, davePubKey, carolSpendHeight)
//normally this transaction would be invalid (why?), but we're not checking it in this test
- val carolSpendTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(carolSpendOutput))
-
- // val fakeSelf: ErgoBox = createBox(0, TrueLeaf)
+ val carolSpendTx = createTransaction(carolSpendOutput)
val carolSpendContext = ErgoLikeContext(
currentHeight = carolSpendHeight,
@@ -184,6 +199,6 @@ class ReversibleTxExampleSpecification extends SigmaTestingCommons {
val proofCarolSpend = carol.prove(withdrawEnv, withdrawScript, carolSpendContext, fakeMessage).get.proof
verifier.verify(withdrawEnv, withdrawScript, carolSpendContext, proofCarolSpend, fakeMessage).get._1 shouldBe true
- }
+ }
}
diff --git a/src/test/scala/sigmastate/utxo/examples/Rule110Specification.scala b/src/test/scala/sigmastate/utxo/examples/Rule110Specification.scala
index 488d46b075..54d68919eb 100644
--- a/src/test/scala/sigmastate/utxo/examples/Rule110Specification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/Rule110Specification.scala
@@ -3,20 +3,20 @@ package sigmastate.utxo.examples
import org.ergoplatform._
import scorex.crypto.hash.Blake2b256
import scorex.util._
-import sigmastate.Values.{BooleanConstant, ByteArrayConstant, ByteConstant, FalseLeaf, IntConstant, LongConstant, GetVarByteArray, TrueLeaf, Value}
+import sigmastate.Values.{BooleanConstant, ByteArrayConstant, ByteConstant, FalseLeaf, GetVarByteArray, IntConstant, LongConstant, TrueLeaf, Value}
import sigmastate._
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.interpreter.ContextExtension
import sigmastate.lang.Terms._
import sigmastate.serialization.ValueSerializer
import sigmastate.utxo._
+import sigmastate.utxo.blockchain.BlockchainSimulationTestingCommons._
/**
* Wolfram's Rule110 implementations
*
*/
class Rule110Specification extends SigmaTestingCommons {
- import BlockchainSimulationSpecification.{Block, ValidationState}
implicit lazy val IR = new TestingIRContext
private val reg1 = ErgoBox.nonMandatoryRegisters.head
private val reg2 = ErgoBox.nonMandatoryRegisters(1)
@@ -32,12 +32,12 @@ class Rule110Specification extends SigmaTestingCommons {
* - first output contains the same protecting script, allowing to calculate further layers
*/
property("rule110 - one layer in register") {
- val prover = new ErgoLikeTestProvingInterpreter {
+ val prover = new ContextEnrichingTestProvingInterpreter {
override val maxCost: Long = 2000000
}
val verifier = new ErgoLikeTestInterpreter
- val prop = compileWithCosting(Map(),
+ val prop = compile(Map(),
"""{
| val indices: Coll[Int] = Coll(0, 1, 2, 3, 4, 5)
| val inLayer: Coll[Byte] = SELF.R4[Coll[Byte]].get
@@ -49,7 +49,7 @@ class Rule110Specification extends SigmaTestingCommons {
| }
| (OUTPUTS(0).R4[Coll[Byte]].get == indices.map(procCell)) &&
| (OUTPUTS(0).propositionBytes == SELF.propositionBytes)
- }""".stripMargin).asBoolValue
+ }""".stripMargin).asBoolValue.toSigmaProp
val input = ErgoBox(1, prop, 0, Seq(), Map(reg1 -> ByteArrayConstant(Array(0, 1, 1, 0, 1, 0))))
val output = ErgoBox(1, prop, 0, Seq(), Map(reg1 -> ByteArrayConstant(Array(1, 1, 1, 1, 1, 0))))
@@ -203,7 +203,7 @@ class Rule110Specification extends SigmaTestingCommons {
val leftmostConditions = AND(EQ(SizeOf(Inputs), 1), EQ(in0X, in0Y), EQ(scriptHash, leftmostHash))
val scriptIsCorrect = DeserializeContext(scriptId, SBoolean)
- val prop = AND(scriptIsCorrect, OR(normalCaseConditions, rightmostConditions, nLeftmostConditions, leftmostConditions))
+ val prop = AND(scriptIsCorrect, OR(normalCaseConditions, rightmostConditions, nLeftmostConditions, leftmostConditions)).toSigmaProp
// test normal case
val nIn0 = ErgoBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-2), YReg -> ByteConstant(0), ValReg -> t))
@@ -214,7 +214,7 @@ class Rule110Specification extends SigmaTestingCommons {
val nOut2 = ErgoBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-1), YReg -> ByteConstant(-1), ValReg -> t))
val nTx = UnsignedErgoLikeTransaction(IndexedSeq(nIn0, nIn1, nIn2).map(i => new UnsignedInput(i.id)), IndexedSeq(nOut0, nOut1, nOut2))
- val nProver = new ErgoLikeTestProvingInterpreter()
+ val nProver = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(scriptId, ByteArrayConstant(normalCaseBytes))
val nCtx = ErgoLikeContext(
@@ -236,7 +236,7 @@ class Rule110Specification extends SigmaTestingCommons {
val rOut2 = ErgoBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(0), YReg -> ByteConstant(-1), ValReg -> t))
val rTx = UnsignedErgoLikeTransaction(IndexedSeq(rIn0, rIn1).map(i => new UnsignedInput(i.id)), IndexedSeq(rOut0, rOut1, rOut2))
- val rProver = new ErgoLikeTestProvingInterpreter()
+ val rProver = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(scriptId, ByteArrayConstant(rightmostBytes))
val rCtx = ErgoLikeContext(
@@ -258,7 +258,7 @@ class Rule110Specification extends SigmaTestingCommons {
val lnOut2 = ErgoBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-6), YReg -> ByteConstant(-7), ValReg -> t))
val lnTx = UnsignedErgoLikeTransaction(IndexedSeq(lnIn0, lnIn1).map(i => new UnsignedInput(i.id)), IndexedSeq(lnOut0, lnOut1, lnOut2))
- val lnProver = new ErgoLikeTestProvingInterpreter()
+ val lnProver = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(scriptId, ByteArrayConstant(nLeftmostBytes))
val lnCtx = ErgoLikeContext(
@@ -279,7 +279,7 @@ class Rule110Specification extends SigmaTestingCommons {
val lOut2 = ErgoBox(1, prop, 0, Seq(), Map(MidReg -> f, XReg -> ByteConstant(-7), YReg -> ByteConstant(-7), ValReg -> t))
val lTx = UnsignedErgoLikeTransaction(IndexedSeq(lIn0).map(i => new UnsignedInput(i.id)), IndexedSeq(lOut0, lOut1, lOut2))
- val lProver = new ErgoLikeTestProvingInterpreter()
+ val lProver = new ContextEnrichingTestProvingInterpreter()
.withContextExtender(scriptId, ByteArrayConstant(leftmostBytes))
val lCtx = ErgoLikeContext(
@@ -306,7 +306,7 @@ class Rule110Specification extends SigmaTestingCommons {
* new layer of rule 110
*/
property("rule110 - one bit per output (old version)") {
- val prover = new ErgoLikeTestProvingInterpreter()
+ val prover = new ContextEnrichingTestProvingInterpreter()
val RowReg = reg1
val ColumnReg = reg2
@@ -387,7 +387,7 @@ class Rule110Specification extends SigmaTestingCommons {
row1,
row2,
rule110
- ))
+ )).toSigmaProp
val hash = Blake2b256
@@ -403,8 +403,8 @@ class Rule110Specification extends SigmaTestingCommons {
ErgoBox(0L, prop, 0, Seq(), Map(row, column, value), txId.toModifierId, col.toShort)
}
- val initBlock = BlockchainSimulationSpecification.Block(
- IndexedSeq(ErgoLikeTransaction(IndexedSeq(), coins)),
+ val initBlock = FullBlock(
+ IndexedSeq(createTransaction(coins)),
ErgoLikeContext.dummyPubkey
)
@@ -417,13 +417,13 @@ class Rule110Specification extends SigmaTestingCommons {
require(row >= 1)
(0 until bitsInString).map { col =>
- val leftCol = if (col == 0) lastBitIndex else col - 1
- val centerCol = col
- val rightCol = if (col == lastBitIndex) 0 else col + 1
+ val leftColl = if (col == 0) lastBitIndex else col - 1
+ val centerColl = col
+ val rightColl = if (col == lastBitIndex) 0 else col + 1
- val left = byPos(state, row - 1, leftCol)
- val center = byPos(state, row - 1, centerCol)
- val right = byPos(state, row - 1, rightCol)
+ val left = byPos(state, row - 1, leftColl)
+ val center = byPos(state, row - 1, centerColl)
+ val right = byPos(state, row - 1, rightColl)
val lv = left.get(ValueReg).get.asInstanceOf[BooleanConstant].value
val cv = center.get(ValueReg).get.asInstanceOf[BooleanConstant].value
@@ -445,7 +445,7 @@ class Rule110Specification extends SigmaTestingCommons {
ut,
left,
ContextExtension.empty)
- val proverResultLeft = prover.prove(left.proposition, contextLeft, ut.messageToSign).get
+ val proverResultLeft = prover.prove(left.ergoTree, contextLeft, ut.messageToSign).get
val contextCenter = ErgoLikeContext(row,
state.state.lastBlockUtxoRoot,
@@ -454,7 +454,7 @@ class Rule110Specification extends SigmaTestingCommons {
ut,
center,
ContextExtension.empty)
- val proverResultCenter = prover.prove(center.proposition, contextCenter, ut.messageToSign).get
+ val proverResultCenter = prover.prove(center.ergoTree, contextCenter, ut.messageToSign).get
val contextRight = ErgoLikeContext(row,
state.state.lastBlockUtxoRoot,
@@ -463,12 +463,12 @@ class Rule110Specification extends SigmaTestingCommons {
ut,
right,
ContextExtension.empty)
- val proverResultRight = prover.prove(right.proposition, contextRight, ut.messageToSign).get
+ val proverResultRight = prover.prove(right.ergoTree, contextRight, ut.messageToSign).get
ut.toSigned(IndexedSeq(proverResultLeft, proverResultCenter, proverResultRight))
}
}
- val firstRowBlock = Block(generateTransactionsForRow(genesisState, 1), ErgoLikeContext.dummyPubkey)
+ val firstRowBlock = FullBlock(generateTransactionsForRow(genesisState, 1), ErgoLikeContext.dummyPubkey)
val t0 = System.currentTimeMillis()
val firstRowState = genesisState.applyBlock(firstRowBlock, 10000000).get
diff --git a/src/test/scala/sigmastate/utxo/examples/TimedPaymentExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/TimedPaymentExampleSpecification.scala
new file mode 100644
index 0000000000..3ceafee273
--- /dev/null
+++ b/src/test/scala/sigmastate/utxo/examples/TimedPaymentExampleSpecification.scala
@@ -0,0 +1,97 @@
+package sigmastate.utxo.examples
+
+import org.ergoplatform.ErgoBox.{R4, R5}
+import org.ergoplatform._
+import sigmastate.Values.{ByteArrayConstant, ByteConstant, IntConstant}
+import sigmastate._
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
+import sigmastate.interpreter.Interpreter.ScriptNameProp
+import sigmastate.lang.Terms._
+import sigmastate.lang.exceptions.InterpreterException
+import sigmastate.utxo._
+
+
+class TimedPaymentExampleSpecification extends SigmaTestingCommons {
+ private implicit lazy val IR: TestingIRContext = new TestingIRContext
+
+ import ErgoAddressEncoder._
+
+ implicit val ergoAddressEncoder: ErgoAddressEncoder = new ErgoAddressEncoder(TestnetNetworkPrefix)
+ property("Evaluation - Timed payment Tx Example") {
+
+ val alice = new ContextEnrichingTestProvingInterpreter // customer at coffee shop
+ val alicePubKey = alice.dlogSecrets.head.publicImage
+
+ val bob = new ContextEnrichingTestProvingInterpreter // owner of coffee shop (or payment address of coffee shop)
+ val bobPubKey = bob.dlogSecrets.head.publicImage
+
+ val env = Map(
+ ScriptNameProp -> "env",
+ "alice" -> alicePubKey
+ )
+
+ val script = compile(env,
+ """{ alice && HEIGHT <= getVar[Int](1).get }""".stripMargin
+ ).asSigmaProp
+
+ val address = Pay2SHAddress(script)
+ // The above is a "timed address".
+ // Payments sent from this wallet are must be confirmed within a certain height (given in the first output's R4)
+
+ val depositAmount = 10
+ val depositHeight = 50
+
+ // someone creates a transaction that outputs a box depositing money into the wallet.
+ // In the example, we don't create the transaction; we just create a box below
+
+
+ val depositOutput = ErgoBox(depositAmount, address.script, depositHeight)
+
+ // Now Alice wants to give Bob (coffee shop owner) some amount from the wallet in a "timed" way.
+
+ val withdrawAmount = 10
+ val withdrawHeight = 100
+ val confDeadline = 110
+
+ val timedWithdrawOutput = ErgoBox(withdrawAmount, bobPubKey, withdrawHeight)
+
+ //normally this transaction would be invalid, but we're not checking it in this test
+ val withdrawTx = createTransaction(IndexedSeq(timedWithdrawOutput))
+
+ val withdrawContext = ErgoLikeContext(
+ currentHeight = 109,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(depositOutput),
+ spendingTransaction = withdrawTx,
+ self = depositOutput
+ )
+
+ val proofWithdraw = alice.withContextExtender(
+ 1, IntConstant(confDeadline)
+ ).prove(env, script, withdrawContext, fakeMessage).get
+
+ val verifier = new ErgoLikeTestInterpreter
+
+ verifier.verify(env, script, withdrawContext, proofWithdraw, fakeMessage).get._1 shouldBe true
+
+ val withdrawContextBad = ErgoLikeContext(
+ currentHeight = 111,
+ lastBlockUtxoRoot = AvlTreeData.dummy,
+ minerPubkey = ErgoLikeContext.dummyPubkey,
+ boxesToSpend = IndexedSeq(depositOutput),
+ spendingTransaction = withdrawTx,
+ self = depositOutput
+ )
+ an [InterpreterException] should be thrownBy (alice.withContextExtender(
+ 1, IntConstant(confDeadline - 20)
+ ).prove(env, script, withdrawContext, fakeMessage).get.proof)
+
+ an [InterpreterException] should be thrownBy (alice.withContextExtender(
+ 1, IntConstant(confDeadline)
+ ).prove(env, script, withdrawContextBad, fakeMessage).get.proof)
+
+ // below gives error. Need to check if it is designed behavior or a bug
+ // verifier.verify(env, script, withdrawContextBad, proofWithdraw, fakeMessage).get._1 shouldBe false
+ }
+}
diff --git a/src/test/scala/sigmastate/utxo/examples/XorGameExampleSpecification.scala b/src/test/scala/sigmastate/utxo/examples/XorGameExampleSpecification.scala
index f228c89fd6..4cfab52b2f 100644
--- a/src/test/scala/sigmastate/utxo/examples/XorGameExampleSpecification.scala
+++ b/src/test/scala/sigmastate/utxo/examples/XorGameExampleSpecification.scala
@@ -8,41 +8,41 @@ import scorex.utils.Random
import sigmastate.Values.{ByteArrayConstant, ByteConstant, IntConstant, SigmaPropConstant}
import sigmastate._
import sigmastate.basics.DLogProtocol.ProveDlog
-import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons}
-import sigmastate.lang.Terms._
+import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeTestInterpreter, SigmaTestingCommons}
import sigmastate.interpreter.Interpreter._
+import sigmastate.lang.Terms._
import sigmastate.utxo._
class XorGameExampleSpecification extends SigmaTestingCommons {
private implicit lazy val IR: TestingIRContext = new TestingIRContext
+ /** XOR game:
- /** XOR game example:
-
- Alice creates a XOR game of "playAmount" amount of ergs until some "timeout" height, called aliceDeadline.
- Another player (Bob) then creates a transaction using this output that follows the game protocol
- given below. In the game, Alice will create "halfGameOutput" output (a "Half game" UTXO).
- Bob will spend Alice's output and create another output called "fullGameOutput" (a "Full game" UTXO).
- After Alice opens her commitment (see below), the fullGameOutput can be spent by the winner
+ Alice creates a XOR game of "playAmount" ergs by creating a Half-game UTXO called the "halfGameOutput" output below.
+ Another player (Bob) then sends a transaction spending Alice's UTXO and creating another output called "fullGameOutput" (a "Full game" UTXO).
+ After Alice opens her commitment (see below), the fullGameOutput can be spent by the winner.
+ The transactions encode the following protocol.
protocol:
Step 1: Alice commits to secret bit a as follows:
Generate random s and compute h = Hash(s||a)
h is the commitment to a
- Alice also selects the "play amount" which can be 0 (a "friendly" game)
+ Alice also selects the "play amount", the amount each player must spend to participate.
She generates a halfGameOutput encoding h and some spending condition given below by halfGameScript
Step 2: Bob chooses random bit b (public) and creates a new tx spending Alice's UTXO along with
- some others such that there is one output that has the spending conditions given by fullGameScript.
+ some others and creating one output that has the spending conditions given by fullGameScript.
(one of the conditions being that the amount of that output is >= twice the play amount.)
Step 3: Alice reveals (s, a) to open her commitment and wins if a == b. Otherwise Bob wins.
+ If Alice fails to open her commitment before some deadline then Bob automatically wins.
For simplicity, we will use following bytes to designate bits
0x00 = false
0x01 = true
+
*/
property("Evaluation - XorGame Example") {
// Alice is first player, who initiates the game
- val alice = new ErgoLikeTestProvingInterpreter
+ val alice = new ContextEnrichingTestProvingInterpreter
val alicePubKey = alice.dlogSecrets.head.publicImage
val a:Byte = if (scala.util.Random.nextBoolean) 0x01 else 0x00 // Alice's random choice
@@ -51,41 +51,43 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
val fullGameEnv = Map(
ScriptNameProp -> "fullGameScriptEnv",
- "alicePubKey" -> alicePubKey,
+ "alice" -> alicePubKey,
"h" -> h
)
- val fullGameScript = compileWithCosting(fullGameEnv,
+ val fullGameScript = compile(fullGameEnv,
"""{
| val s = getVar[Coll[Byte]](0).get // Alice's secret byte string s
| val a = getVar[Byte](1).get // Alice's secret bit a (represented as a byte)
| val b = SELF.R4[Byte].get // Bob's public bit b (represented as a byte)
- | val bobPubKey = SELF.R5[SigmaProp].get
+ | val bob = SELF.R5[SigmaProp].get // Bob's public key
| val bobDeadline = SELF.R6[Int].get // after this height, Bob gets to spend unconditionally
|
- | (bobPubKey && HEIGHT > bobDeadline) || {
+ | (bob && HEIGHT > bobDeadline) || {
| blake2b256(s ++ Coll(a)) == h && { // h is Alice's original commitment from the halfGameScript
- | alicePubKey && a == b || bobPubKey && a != b
+ | alice && a == b || bob && a != b
| }
| }
|}""".stripMargin
- ).asBoolValue
+ ).asSigmaProp
val halfGameEnv = Map(
ScriptNameProp -> "halfGameScript",
- "alicePubKey" -> alicePubKey,
+ "alice" -> alicePubKey,
"fullGameScriptHash" -> Blake2b256(fullGameScript.bytes)
)
- val halfGameScript = compileWithCosting(halfGameEnv,
+ // Note that below script allows Alice to spend the half-game output anytime before Bob spends it.
+ // We could also consider a more restricted version of the game where Alice is unable to spend the half-game output
+ // before some minimum height.
+ val halfGameScript = compile(halfGameEnv,
"""{
- | alicePubKey || {
+ | alice || {
| val out = OUTPUTS(0)
| val b = out.R4[Byte].get
- | val bobPubKey = out.R5[SigmaProp].get
| val bobDeadline = out.R6[Int].get
| val validBobInput = b == 0 || b == 1
- |
+ | // Bob needs to ensure that out.R5 contains his public key
| OUTPUTS.size == 1 &&
| bobDeadline >= HEIGHT+30 &&
| out.value >= SELF.value * 2 &&
@@ -93,7 +95,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
| blake2b256(out.propositionBytes) == fullGameScriptHash
| }
|}
- """.stripMargin).asBoolValue
+ """.stripMargin).asSigmaProp
/////////////////////////////////////////////////////////
//// Alice starts creating a Half-Game
@@ -119,7 +121,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
/////////////////////////////////////////////////////////
// Alice pays to Carol. Game ends here
- val carol = new ErgoLikeTestProvingInterpreter
+ val carol = new ContextEnrichingTestProvingInterpreter
val carolPubKey:ProveDlog = carol.dlogSecrets.head.publicImage
val abortHalfGameHeight = halfGameCreationHeight + 10 // can be anything
@@ -134,13 +136,13 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
val abortHalfGameOutput = ErgoBox(playAmount, carolPubKey, abortHalfGameHeight, Nil,
Map(
R4 -> ByteConstant(0), // dummy data. Has to be given, even though not needed as per halfGameScript
- R5 -> SigmaPropConstant((new ErgoLikeTestProvingInterpreter).dlogSecrets.head.publicImage), // dummy statement
+ R5 -> SigmaPropConstant((new ContextEnrichingTestProvingInterpreter).dlogSecrets.head.publicImage), // dummy statement
R6 -> IntConstant(0) // dummy data. Has to be given, even though not needed as per halfGameScript
)
)
//normally this transaction would invalid (why?), but we're not checking it in this test
- val abortHalfGameTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(abortHalfGameOutput))
+ val abortHalfGameTx = createTransaction(abortHalfGameOutput)
val abortHalfGameContext = ErgoLikeContext(
currentHeight = abortHalfGameHeight,
@@ -162,7 +164,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
//a variable indicating height at which the tx spending halfGameTx is created
val fullGameCreationHeight = halfGameCreationHeight + 10
- val bob = new ErgoLikeTestProvingInterpreter
+ val bob = new ContextEnrichingTestProvingInterpreter
val bobPubKey:ProveDlog = bob.dlogSecrets.head.publicImage
val bobDeadline = 120 // height after which it become's Bob's money
val b:Byte = if (scala.util.Random.nextBoolean) 0x01 else 0x00
@@ -176,7 +178,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
)
//normally this transaction would invalid (why?), but we're not checking it in this test
- val fullGameTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(fullGameOutput))
+ val fullGameTx = createTransaction(fullGameOutput)
val fullGameContext = ErgoLikeContext(
currentHeight = fullGameCreationHeight,
@@ -196,6 +198,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
//// fullGameOutput represents the Full-Game "box" created by Bob.
/////////////////////////////////////////////////////////
+
val winner = {
if (a != b) {
/////////////////////////////////////////////////////////
@@ -225,7 +228,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
val gameOverOutput = ErgoBox(playAmount*2, carolPubKey, gameOverHeight)
//normally this transaction would invalid (why?), but we're not checking it in this test
- val gameOverTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(gameOverOutput))
+ val gameOverTx = createTransaction(gameOverOutput)
val gameOverContext = ErgoLikeContext(
currentHeight = gameOverHeight,
@@ -252,7 +255,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
val defaultWinOutput = ErgoBox(playAmount*2, carolPubKey, defaultWinHeight)
//normally this transaction would invalid (why?), but we're not checking it in this test
- val defaultWinTx = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(defaultWinOutput))
+ val defaultWinTx = createTransaction(defaultWinOutput)
val defaultWinContext = ErgoLikeContext(
currentHeight = defaultWinHeight,
@@ -263,7 +266,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
self = fullGameOutput // what is the use of self?
)
- val sDummy = Array[Byte]()
+ val sDummy = Array[Byte]() // empty value for s; commitment cannot be opened but still Bob will be able to spend
val aDummy:Byte = 0
// below we need to specify a and s (even though they are not needed)
val proofDefaultWin = bob.withContextExtender(
@@ -273,6 +276,7 @@ class XorGameExampleSpecification extends SigmaTestingCommons {
).prove(fullGameEnv, fullGameScript, defaultWinContext, fakeMessage).get
verifier.verify(fullGameEnv, fullGameScript, defaultWinContext, proofDefaultWin, fakeMessage).get._1 shouldBe true
+
}
}
diff --git a/src/test/scala/special/sigma/ContractsTestkit.scala b/src/test/scala/special/sigma/ContractsTestkit.scala
new file mode 100644
index 0000000000..8ca4a0f4f7
--- /dev/null
+++ b/src/test/scala/special/sigma/ContractsTestkit.scala
@@ -0,0 +1,85 @@
+package special.sigma
+
+import scalan._
+import special.collection.{Coll, CollOverArrayBuilder}
+import scalan.RType
+import sigmastate.AvlTreeData
+import sigmastate.eval.{CAvlTree, CostingDataContext, CostingSigmaDslBuilder}
+import sigmastate.eval.Extensions._
+
+trait ContractsTestkit {
+ val R0 = 0.toByte;
+ val R1 = 1.toByte;
+ val R2 = 2.toByte;
+ val R3 = 3.toByte;
+ val R4 = 4.toByte;
+ val R5 = 5.toByte;
+ val R6 = 6.toByte;
+ val R7 = 7.toByte;
+ val R8 = 8.toByte;
+ val R9 = 9.toByte;
+
+
+ val Colls = new CollOverArrayBuilder
+ val SigmaDsl: SigmaDslBuilder = new TestSigmaDslBuilder
+ val noRegisters = collection[AnyValue]()
+ val noBytes = collection[Byte]()
+ val noInputs = Array[Box]()
+ val noOutputs = Array[Box]()
+ val dummyPubkey: Array[Byte] = Array.fill(32)(0: Byte)
+ val dummyADDigest: Coll[Byte] = Colls.fromArray(Array.fill(33)(0: Byte))
+ val emptyAvlTree = new CAvlTree(AvlTreeData.dummy)
+ val noHeaders = CostingSigmaDslBuilder.Colls.emptyColl[Header]
+ val dummyPreHeader: PreHeader = null
+
+ def collection[T:RType](items: T*) = Colls.fromArray(items.toArray)
+
+ def regs(m: Map[Byte, AnyValue]): Coll[AnyValue] = {
+ val res = new Array[AnyValue](10)
+ for ((id, v) <- m) {
+ assert(res(id) == null, s"register $id is defined more then once")
+ res(id) = v
+ }
+ Colls.fromArray(res)
+ }
+
+ def contextVars(m: Map[Byte, AnyValue]): Coll[AnyValue] = {
+ val maxKey = if (m.keys.isEmpty) 0 else m.keys.max
+ val res = new Array[AnyValue](maxKey)
+ for ((id, v) <- m) {
+ val i = id - 1
+ assert(res(i) == null, s"register $id is defined more then once")
+ res(i) = v
+ }
+ Colls.fromArray(res)
+ }
+
+ val AliceId = Array[Byte](1) // 0x0001
+ def newAliceBox(id: Byte, value: Long, registers: Map[Int, AnyValue] = Map()): Box = new TestBox(
+ Colls.fromArray(Array[Byte](0, id)), value,
+ Colls.fromArray(AliceId), noBytes, noBytes,
+ regs(registers.map { case (k, v) => (k.toByte, v) })
+ )
+
+ def testContext(inputs: Array[Box], outputs: Array[Box], height: Int, self: Box,
+ tree: AvlTree, minerPk: Array[Byte], vars: Array[AnyValue]) =
+ new CostingDataContext(
+ noInputs.toColl, noHeaders, dummyPreHeader,
+ inputs.toColl, outputs.toColl, height, self, tree, minerPk.toColl, vars.toColl, false)
+
+ def newContext(height: Int, self: Box, vars: AnyValue*): CostingDataContext = {
+ testContext(noInputs, noOutputs, height, self, emptyAvlTree, dummyPubkey, vars.toArray)
+ }
+
+ implicit class TestContextOps(ctx: CostingDataContext) {
+ def withInputs(inputs: Box*) = ctx.copy(inputs = inputs.toArray.toColl)
+ def withOutputs(outputs: Box*) = ctx.copy(outputs = outputs.toArray.toColl)
+ def withVariables(vars: Map[Int, AnyValue]) =
+ ctx.copy(vars = contextVars(vars.map { case (k, v) => (k.toByte, v) }))
+ }
+
+ case class NoEnvContract(condition: Context => Boolean) extends SigmaContract {
+ override def builder: SigmaDslBuilder = new TestSigmaDslBuilder
+ override def canOpen(ctx: Context): Boolean = condition(ctx)
+ }
+}
diff --git a/src/test/scala/special/sigma/SigmaDslCostedTests.scala b/src/test/scala/special/sigma/SigmaDslCostedTests.scala
new file mode 100644
index 0000000000..ea6026a9e6
--- /dev/null
+++ b/src/test/scala/special/sigma/SigmaDslCostedTests.scala
@@ -0,0 +1,22 @@
+package special.sigma
+
+import org.scalatest.{Matchers, FunSuite}
+import special.sigma.Extensions._
+
+class SigmaDslCostedTests extends FunSuite with ContractsTestkit with Matchers {
+ val boxA1 = newAliceBox(1, 100, Map(1 -> toAnyValue(20)))
+ val boxA2 = newAliceBox(2, 200)
+ val ctx = newContext(10, boxA1)
+ .withInputs(boxA2)
+ .withVariables(Map(1 -> toAnyValue(30), 2 -> toAnyValue(40)))
+ val p1: SigmaProp = new special.sigma.MockSigma(true)
+ val p2: SigmaProp = new special.sigma.MockSigma(false)
+ val dsl: SigmaDslBuilder = SigmaDsl
+
+// test("CostedContext") {
+// val ctxC = new CCostedContext(ctx)
+// ctx.cost shouldBe 4
+// ctxC.INPUTS.cost shouldBe 2
+// ctxC.OUTPUTS.cost shouldBe 1
+// }
+}
diff --git a/src/test/scala/special/sigma/SigmaDslStaginTests.scala b/src/test/scala/special/sigma/SigmaDslStaginTests.scala
new file mode 100644
index 0000000000..f3851b201e
--- /dev/null
+++ b/src/test/scala/special/sigma/SigmaDslStaginTests.scala
@@ -0,0 +1,56 @@
+package special.sigma
+
+import special.wrappers.WrappersTests
+
+import scala.language.reflectiveCalls
+import scalan.SigmaLibrary
+import special.sigma.Extensions._
+
+class SigmaDslStaginTests extends WrappersTests with ContractsTestkit {
+ class Ctx extends WrappersCtx with SigmaLibrary {
+ import TestSigmaDslBuilder._
+ val sigmaDslBuilder = RTestSigmaDslBuilder()
+ }
+
+ test("invokeUnlifted") {
+ val cake = new Ctx
+ import cake._
+ import Liftables._
+ import Context._
+ import Box._
+ import SigmaProp._
+ import SigmaDslBuilder._
+ import EnvRep._
+
+ val dsl: SSigmaDslBuilder = SigmaDsl
+ type RSigmaDslBuilder = cake.SigmaDslBuilder
+ type RContext = cake.Context
+ type RBox = cake.Box
+ type RSigmaProp = cake.SigmaProp
+ val boxA1 = newAliceBox(1, 100, Map(1 -> toAnyValue(20), 3 -> toAnyValue((10 -> SigmaDsl.Colls.fromArray(Array.emptyByteArray)))))
+ val boxA2 = newAliceBox(2, 200)
+ val ctx: SContext = newContext(10, boxA1)
+ .withInputs(boxA2)
+ .withVariables(Map(1 -> toAnyValue(30), 2 -> toAnyValue(40)))
+ val p1: SSigmaProp = new special.sigma.MockSigma(true)
+ val p2: SSigmaProp = new special.sigma.MockSigma(false)
+
+ check(dsl, { env: EnvRep[RSigmaDslBuilder] =>
+ for { dsl <- env; arg <- lifted(true) } yield dsl.sigmaProp(arg) }, dsl.sigmaProp(true))
+
+ check(ctx, { env: EnvRep[RContext] => for { obj <- env } yield obj.SELF }, ctx.SELF)
+ check(ctx, { env: EnvRep[RContext] =>
+ for { obj <- env; id <- lifted(1.toByte) } yield obj.getVar[Int](id) }, ctx.getVar[Int](1))
+
+ check(boxA1, { env: EnvRep[RBox] => for { obj <- env } yield obj.value }, boxA1.value)
+ check(boxA1, { env: EnvRep[RBox] => for { obj <- env } yield obj.creationInfo }, boxA1.creationInfo)
+ check(boxA1, { env: EnvRep[RBox] => for { obj <- env; arg <- lifted(1) } yield obj.getReg[Int](arg) }, boxA1.getReg[Int](1))
+ check(boxA1, { env: EnvRep[RBox] => for { obj <- env } yield obj.registers }, boxA1.registers)
+
+ check(p1, { env: EnvRep[RSigmaProp] => for { p1 <- env; arg <- lifted(true) } yield p1 && arg }, p1 && true)
+ check(p1, { env: EnvRep[RSigmaProp] => for { p1 <- env; arg <- lifted(p2) } yield p1 && arg }, p1 && p2)
+
+ val th = () => p2
+// check(p1, { env: EnvRep[RSigmaProp] => for { p1 <- env; thL <- lifted(th) } yield p1.lazyAnd(thL) }, p1.lazyAnd(th()))
+ }
+}
diff --git a/src/test/scala/special/sigma/SigmaDslTest.scala b/src/test/scala/special/sigma/SigmaDslTest.scala
new file mode 100644
index 0000000000..e4e9eec50f
--- /dev/null
+++ b/src/test/scala/special/sigma/SigmaDslTest.scala
@@ -0,0 +1,496 @@
+package special.sigma
+
+import java.math.BigInteger
+
+import org.ergoplatform.dsl.{SigmaContractSyntax, TestContractSpec}
+import org.ergoplatform.{ErgoLikeContext, ErgoLikeTransaction, ErgoBox}
+import org.scalacheck.Gen.containerOfN
+import org.scalacheck.{Arbitrary, Gen}
+import org.scalatest.prop.PropertyChecks
+import org.scalatest.{PropSpec, Matchers}
+import scalan.RType
+import scorex.crypto.authds.avltree.batch._
+import scorex.crypto.authds.{ADKey, ADValue}
+import scorex.crypto.hash.{Digest32, Blake2b256}
+import sigma.util.Extensions._
+import sigmastate.Values.{BooleanConstant, IntConstant}
+import sigmastate._
+import sigmastate.eval.Extensions._
+import sigmastate.eval._
+import sigmastate.helpers.SigmaTestingCommons
+import sigmastate.interpreter.ContextExtension
+import sigmastate.interpreter.Interpreter.ScriptEnv
+import special.collection.{Coll, Builder}
+
+
+/** This suite tests every method of every SigmaDsl type to be equivalent to
+ * the evaluation of the corresponding ErgoScript operation */
+class SigmaDslTest extends PropSpec
+ with PropertyChecks
+ with Matchers
+ with SigmaTestingCommons with SigmaContractSyntax
+ with SigmaTypeGens { suite =>
+
+ lazy val spec = TestContractSpec(suite)(new TestingIRContext)
+
+ override def contractEnv: ScriptEnv = Map()
+
+ implicit lazy val IR = new TestingIRContext {
+ override val okPrintEvaluatedEntries: Boolean = false
+ }
+
+ def checkEq[A,B](f: A => B)(g: A => B): A => Unit = { x: A =>
+ val b1 = f(x); val b2 = g(x)
+// assert(b1.getClass == b2.getClass)
+ assert(b1 == b2)
+ }
+
+ def checkEq2[A,B,R](f: (A, B) => R)(g: (A, B) => R): (A,B) => Unit = { (x: A, y: B) =>
+ val r1 = f(x, y); val r2 = g(x, y)
+ assert(r1.getClass == r2.getClass)
+ assert(r1 == r2)
+ }
+
+ case class EqualityChecker[T: RType](obj: T) {
+ def apply[R: RType](dslFunc: T => R)(script: String) =
+ checkEq(func[T, R](script))(dslFunc)(obj)
+ }
+
+ property("Boolean methods equivalence") {
+ lazy val toByte = checkEq(func[Boolean,Byte]("{ (x: Boolean) => x.toByte }"))(x => x.toByte)
+ forAll { x: Boolean =>
+ x.toByte
+ }
+ }
+
+ property("Byte methods equivalence") {
+ val toShort = checkEq(func[Byte,Short]("{ (x: Byte) => x.toShort }"))(x => x.toShort)
+ val toInt = checkEq(func[Byte,Int]("{ (x: Byte) => x.toInt }"))(x => x.toInt)
+ val toLong = checkEq(func[Byte,Long]("{ (x: Byte) => x.toLong }"))(x => x.toLong)
+ val toBigInt = checkEq(func[Byte,BigInt]("{ (x: Byte) => x.toBigInt }"))(x => x.toBigInt)
+ lazy val toBytes = checkEq(func[Byte,Coll[Byte]]("{ (x: Byte) => x.toBytes }"))(x => x.toBytes)
+ lazy val toBits = checkEq(func[Byte,Coll[Boolean]]("{ (x: Byte) => x.toBits }"))(x => x.toBits)
+ lazy val toAbs = checkEq(func[Byte,Byte]("{ (x: Byte) => x.toAbs }"))(x => x.toAbs)
+ lazy val compareTo = checkEq(func[(Byte, Byte), Int]("{ (x: (Byte, Byte)) => x._1.compareTo(x._2) }"))({ (x: (Byte, Byte)) => x._1.compareTo(x._2) })
+
+ forAll { x: Byte =>
+ Seq(toInt, toLong, toBigInt).foreach(_(x))
+//TODO toBytes, toBits, toAbs
+ }
+ forAll { x: (Byte, Byte) =>
+//TODO compareTo(x)
+ }
+ }
+
+
+ property("Int methods equivalence") {
+ val toByte = checkEq(func[Int,Byte]("{ (x: Int) => x.toByte }"))(x => x.toByte)
+ val toShort = checkEq(func[Int,Short]("{ (x: Int) => x.toShort }"))(x => x.toShort)
+ val toInt = checkEq(func[Int,Int]("{ (x: Int) => x.toInt }"))(x => x.toInt)
+ val toLong = checkEq(func[Int,Long]("{ (x: Int) => x.toLong }"))(x => x.toLong)
+ val toBigInt = checkEq(func[Int,BigInt]("{ (x: Int) => x.toBigInt }"))(x => x.toBigInt)
+ lazy val toBytes = checkEq(func[Int,Coll[Byte]]("{ (x: Int) => x.toBytes }"))(x => x.toBytes)
+ lazy val toBits = checkEq(func[Int,Coll[Boolean]]("{ (x: Int) => x.toBits }"))(x => x.toBits)
+ lazy val toAbs = checkEq(func[Int,Int]("{ (x: Int) => x.toAbs }"))(x => x.toAbs)
+ lazy val compareTo = checkEq(func[(Int, Int), Int]("{ (x: (Int, Int)) => x._1.compareTo(x._2) }"))(x => x._1.compareTo(x._2))
+
+ forAll { x: Int =>
+ whenever(Byte.MinValue <= x && x <= scala.Byte.MaxValue) {
+ toByte(x)
+ }
+ whenever(Short.MinValue <= x && x <= Short.MaxValue) {
+ toShort(x)
+ }
+ Seq(toInt, toLong, toBigInt).foreach(_(x))
+ //TODO toBytes, toBits, toAbs
+ }
+ forAll { x: (Int, Int) =>
+ //TODO compareTo(x)
+ }
+ }
+ // TODO add tests for Short, Long, BigInt operations
+
+ property("GroupElement operations equivalence") {
+ val ge = SigmaDsl.groupGenerator
+ val n = SigmaDsl.BigInt(BigInteger.TEN)
+ val g2 = ge.exp(n)
+
+ {
+ val eq = EqualityChecker(ge)
+// eq({ (x: GroupElement) => x.isIdentity })("{ (x: GroupElement) => x.isIdentity }")
+ eq({ (x: GroupElement) => x.getEncoded })("{ (x: GroupElement) => x.getEncoded }")
+ eq({ (x: GroupElement) => decodePoint(x.getEncoded) == x })("{ (x: GroupElement) => decodePoint(x.getEncoded) == x }")
+ eq({ (x: GroupElement) => x.negate })("{ (x: GroupElement) => x.negate }")
+ }
+
+ {
+ val eq = EqualityChecker((ge, n))
+ eq({ (x: (GroupElement, BigInt)) => x._1.exp(x._2) })("{ (x: (GroupElement, BigInt)) => x._1.exp(x._2) }")
+ }
+
+ {
+ val eq = EqualityChecker((ge, g2))
+ eq({ (x: (GroupElement, GroupElement)) => x._1.multiply(x._2) })("{ (x: (GroupElement, GroupElement)) => x._1.multiply(x._2) }")
+ }
+ }
+
+// property("sigma.types.Byte methods equivalence") {
+// import sigma.types._
+// val toInt = checkEq(func[Byte,Int]("{ (x: Byte) => x.toInt }"))(x => x.toInt)
+// forAll { x: Byte =>
+// Seq(toInt).foreach(_(x))
+// }
+// }
+//
+// property("sigma.types.Int methods equivalence") {
+// import sigma.types._
+// val toByte = checkEq(func[Int,Byte]("{ (x: Int) => x.toByte }"))(x => x.toByte)
+// lazy val compareTo = checkEq(func[(Int, Int), Int]("{ (x: (Int, Int)) => x._1.compareTo(x._2) }"))(x => x._1.compareTo(x._2))
+// forAll { in: scala.Int =>
+// whenever(scala.Byte.MinValue <= in && in <= scala.Byte.MaxValue) {
+// val x = CInt(in)
+// toByte(x)
+// }
+// }
+// }
+
+ val bytesGen: Gen[Array[Byte]] = containerOfN[Array, Byte](100, Arbitrary.arbByte.arbitrary)
+ val bytesCollGen = bytesGen.map(Colls.fromArray(_))
+ implicit val arbBytes = Arbitrary(bytesCollGen)
+ val keyCollGen = bytesCollGen.map(_.slice(0, 32))
+ import org.ergoplatform.dsl.AvlTreeHelpers._
+
+ private def sampleAvlProver = {
+ val key = keyCollGen.sample.get
+ val value = bytesCollGen.sample.get
+ val (_, avlProver) = createAvlTree(AvlTreeFlags.AllOperationsAllowed, ADKey @@ key.toArray -> ADValue @@ value.toArray)
+ (key, value, avlProver)
+ }
+
+ private def sampleAvlTree:CAvlTree = {
+ val (key, _, avlProver) = sampleAvlProver
+ val digest = avlProver.digest.toColl
+ val tree = SigmaDsl.avlTree(AvlTreeFlags.ReadOnly.serializeToByte, digest, 32, None)
+ tree
+ }
+
+ property("AvlTree properties equivalence") {
+ val doDigest = checkEq(func[AvlTree, Coll[Byte]]("{ (t: AvlTree) => t.digest }")) { (t: AvlTree) => t.digest }
+ val doEnabledOps = checkEq(func[AvlTree, Byte](
+ "{ (t: AvlTree) => t.enabledOperations }")) { (t: AvlTree) => t.enabledOperations }
+ val doKeyLength = checkEq(func[AvlTree, Int]("{ (t: AvlTree) => t.keyLength }")) { (t: AvlTree) => t.keyLength }
+ val doValueLength = checkEq(func[AvlTree, Option[Int]]("{ (t: AvlTree) => t.valueLengthOpt }")) { (t: AvlTree) => t.valueLengthOpt }
+ val insertAllowed = checkEq(func[AvlTree, Boolean]("{ (t: AvlTree) => t.isInsertAllowed }")) { (t: AvlTree) => t.isInsertAllowed }
+ val updateAllowed = checkEq(func[AvlTree, Boolean]("{ (t: AvlTree) => t.isUpdateAllowed }")) { (t: AvlTree) => t.isUpdateAllowed }
+ val removeAllowed = checkEq(func[AvlTree, Boolean]("{ (t: AvlTree) => t.isRemoveAllowed }")) { (t: AvlTree) => t.isRemoveAllowed }
+
+ val tree = sampleAvlTree
+
+ doDigest(tree)
+ doEnabledOps(tree)
+ doKeyLength(tree)
+ doValueLength(tree)
+ insertAllowed(tree)
+ updateAllowed(tree)
+ removeAllowed(tree)
+ }
+
+ property("AvlTree.{contains, get, getMany} equivalence") {
+ val doContains = checkEq(
+ func[(AvlTree, (Coll[Byte], Coll[Byte])), Boolean](
+ "{ (t: (AvlTree, (Coll[Byte], Coll[Byte]))) => t._1.contains(t._2._1, t._2._2) }"))
+ { (t: (AvlTree, (Coll[Byte], Coll[Byte]))) => t._1.contains(t._2._1, t._2._2) }
+ val doGet = checkEq(
+ func[(AvlTree, (Coll[Byte], Coll[Byte])), Option[Coll[Byte]]](
+ "{ (t: (AvlTree, (Coll[Byte], Coll[Byte]))) => t._1.get(t._2._1, t._2._2) }"))
+ { (t: (AvlTree, (Coll[Byte], Coll[Byte]))) => t._1.get(t._2._1, t._2._2) }
+ val doGetMany = checkEq(
+ func[(AvlTree, (Coll[Coll[Byte]], Coll[Byte])), Coll[Option[Coll[Byte]]]](
+ "{ (t: (AvlTree, (Coll[Coll[Byte]], Coll[Byte]))) => t._1.getMany(t._2._1, t._2._2) }"))
+ { (t: (AvlTree, (Coll[Coll[Byte]], Coll[Byte]))) => t._1.getMany(t._2._1, t._2._2) }
+
+ val (key, _, avlProver) = sampleAvlProver
+ avlProver.performOneOperation(Lookup(ADKey @@ key.toArray))
+ val digest = avlProver.digest.toColl
+ val proof = avlProver.generateProof().toColl
+ val tree = SigmaDsl.avlTree(AvlTreeFlags.ReadOnly.serializeToByte, digest, 32, None)
+ doContains((tree, (key, proof)))
+ doGet((tree, (key, proof)))
+ val keys = Colls.fromItems(key)
+ doGetMany((tree, (keys, proof)))
+ }
+
+ property("AvlTree.{insert, update, remove} equivalence") {
+ type KV = (Coll[Byte], Coll[Byte])
+ val doInsert = checkEq(
+ func[(AvlTree, (Coll[KV], Coll[Byte])), Option[AvlTree]](
+ "{ (t: (AvlTree, (Coll[(Coll[Byte], Coll[Byte])], Coll[Byte]))) => t._1.insert(t._2._1, t._2._2) }"))
+ { (t: (AvlTree, (Coll[KV], Coll[Byte]))) => t._1.insert(t._2._1, t._2._2) }
+ val doUpdate = checkEq(
+ func[(AvlTree, (Coll[KV], Coll[Byte])), Option[AvlTree]](
+ "{ (t: (AvlTree, (Coll[(Coll[Byte], Coll[Byte])], Coll[Byte]))) => t._1.update(t._2._1, t._2._2) }"))
+ { (t: (AvlTree, (Coll[KV], Coll[Byte]))) => t._1.update(t._2._1, t._2._2) }
+ val doRemove = checkEq(
+ func[(AvlTree, (Coll[Coll[Byte]], Coll[Byte])), Option[AvlTree]](
+ "{ (t: (AvlTree, (Coll[Coll[Byte]], Coll[Byte]))) => t._1.remove(t._2._1, t._2._2) }"))
+ { (t: (AvlTree, (Coll[Coll[Byte]], Coll[Byte]))) => t._1.remove(t._2._1, t._2._2) }
+
+ val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
+ val key = Array.fill(32)(1.toByte).toColl
+
+ {
+ val preInsertDigest = avlProver.digest.toColl
+ val value = bytesCollGen.sample.get
+ avlProver.performOneOperation(Insert(ADKey @@ key.toArray, ADValue @@ value.toArray))
+ val insertProof = avlProver.generateProof().toColl
+ val preInsertTree = SigmaDsl.avlTree(AvlTreeFlags(true, false, false).serializeToByte, preInsertDigest, 32, None)
+ val insertKvs = Colls.fromItems((key -> value))
+ doInsert((preInsertTree, (insertKvs, insertProof)))
+ }
+
+ {
+ val preUpdateDigest = avlProver.digest.toColl
+ val newValue = bytesCollGen.sample.get
+ avlProver.performOneOperation(Update(ADKey @@ key.toArray, ADValue @@ newValue.toArray))
+ val updateProof = avlProver.generateProof().toColl
+ val preUpdateTree = SigmaDsl.avlTree(AvlTreeFlags(false, true, false).serializeToByte, preUpdateDigest, 32, None)
+ val updateKvs = Colls.fromItems((key -> newValue))
+ doUpdate((preUpdateTree, (updateKvs, updateProof)))
+ }
+
+ {
+ val preRemoveDigest = avlProver.digest.toColl
+ avlProver.performOneOperation(Remove(ADKey @@ key.toArray))
+ val removeProof = avlProver.generateProof().toColl
+ val preRemoveTree = SigmaDsl.avlTree(AvlTreeFlags(false, false, true).serializeToByte, preRemoveDigest, 32, None)
+ val removeKeys = Colls.fromItems(key)
+ doRemove((preRemoveTree, (removeKeys, removeProof)))
+ }
+ }
+
+ property("longToByteArray equivalence") {
+ val eq = checkEq(func[Long, Coll[Byte]]("{ (x: Long) => longToByteArray(x) }")){ x =>
+ longToByteArray(x)
+ }
+ forAll { x: Long => eq(x) }
+ }
+
+ property("byteArrayToLong equivalence") {
+ val eq = checkEq(func[Coll[Byte],Long]("{ (x: Coll[Byte]) => byteArrayToLong(x) }")){ x =>
+ byteArrayToLong(x)
+ }
+ forAll { x: Array[Byte] =>
+ whenever(x.length >= 8) {
+ eq(Builder.DefaultCollBuilder.fromArray(x))
+ }
+ }
+ }
+
+ // TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/427
+ // TODO costing: expression t._1(t._2) cannot be costed because t is lambda argument
+ ignore("Func context variable") {
+// val doApply = checkEq(func[(Int => Int, Int), Int]("{ (t: (Int => Int, Int)) => t._1(t._2) }")) { (t: (Int => Int, Int)) => t._1(t._2) }
+// val code = compileWithCosting(emptyEnv, s"{ (x: Int) => x + 1 }")
+// val ctx = ErgoLikeContext.dummy(fakeSelf)
+// doApply((CFunc[Int, Int](ctx, code), 10))
+ }
+
+ val tokenId1: Digest32 = Blake2b256("id1")
+ val tokenId2: Digest32 = Blake2b256("id2")
+ val inBox = createBox(10, TrivialProp.TrueProp,
+ Seq(tokenId1 -> 10L, tokenId2 -> 20L),
+ Map(ErgoBox.R4 -> IntConstant(100), ErgoBox.R5 -> BooleanConstant(true)))
+
+ val dataBox = createBox(1000, TrivialProp.TrueProp,
+ Seq(tokenId1 -> 10L, tokenId2 -> 20L),
+ Map(ErgoBox.R4 -> IntConstant(100), ErgoBox.R5 -> BooleanConstant(true)))
+
+ val outBox = createBox(10, TrivialProp.TrueProp,
+ Seq(tokenId1 -> 10L, tokenId2 -> 20L),
+ Map(ErgoBox.R4 -> IntConstant(100), ErgoBox.R5 -> BooleanConstant(true)))
+
+ val header1: Header = CHeader(Blake2b256("Header.id").toColl,
+ 0,
+ Blake2b256("Header.parentId").toColl,
+ Blake2b256("ADProofsRoot").toColl,
+ sampleAvlTree,
+ Blake2b256("transactionsRoot").toColl,
+ timestamp = 0,
+ nBits = 0,
+ height = 0,
+ extensionRoot = Blake2b256("transactionsRoot").toColl,
+ minerPk = SigmaDsl.groupGenerator,
+ powOnetimePk = SigmaDsl.groupGenerator,
+ powNonce = Colls.fromArray(Array[Byte](0, 1, 2, 3, 4, 5, 6, 7)),
+ powDistance = SigmaDsl.BigInt(BigInt("1405498250268750867257727119510201256371618473728619086008183115260323").bigInteger),
+ votes = Colls.fromArray(Array[Byte](0, 1, 2))
+ )
+ val header2: Header = CHeader(Blake2b256("Header2.id").toColl,
+ 0,
+ header1.id,
+ Blake2b256("ADProofsRoot2").toColl,
+ sampleAvlTree,
+ Blake2b256("transactionsRoot2").toColl,
+ timestamp = 2,
+ nBits = 0,
+ height = 1,
+ extensionRoot = Blake2b256("transactionsRoot2").toColl,
+ minerPk = SigmaDsl.groupGenerator,
+ powOnetimePk = SigmaDsl.groupGenerator,
+ powNonce = Colls.fromArray(Array.fill(0.toByte)(8)),
+ powDistance = SigmaDsl.BigInt(BigInt("19306206489815517413186395405558417825367537880571815686937307203793939").bigInteger),
+ votes = Colls.fromArray(Array[Byte](0, 1, 0))
+ )
+ val headers = Colls.fromItems(header2, header1)
+ val preHeader: PreHeader = CPreHeader(0,
+ header2.id,
+ timestamp = 3,
+ nBits = 0,
+ height = 2,
+ minerPk = SigmaDsl.groupGenerator,
+ votes = Colls.emptyColl[Byte]
+ )
+ val ergoCtx = new ErgoLikeContext(
+ currentHeight = preHeader.height,
+ lastBlockUtxoRoot = header2.stateRoot.asInstanceOf[CAvlTree].treeData,
+ preHeader.minerPk.getEncoded.toArray,
+ boxesToSpend = IndexedSeq(inBox),
+ spendingTransaction = ErgoLikeTransaction(IndexedSeq(), IndexedSeq(outBox)),
+ self = inBox, headers = headers, preHeader = preHeader, dataBoxes = IndexedSeq(dataBox),
+ extension = ContextExtension(Map()))
+ lazy val ctx = ergoCtx.toSigmaContext(IR, false)
+
+ property("Box properties equivalence") {
+ val box = ctx.dataInputs(0)
+ val eq = EqualityChecker(box)
+ eq({ (x: Box) => x.id })("{ (x: Box) => x.id }")
+ eq({ (x: Box) => x.value })("{ (x: Box) => x.value }")
+ eq({ (x: Box) => x.propositionBytes })("{ (x: Box) => x.propositionBytes }")
+ eq({ (x: Box) => x.bytes })("{ (x: Box) => x.bytes }")
+ eq({ (x: Box) => x.bytesWithoutRef })("{ (x: Box) => x.bytesWithoutRef }")
+ eq({ (x: Box) => x.creationInfo })("{ (x: Box) => x.creationInfo }")
+ eq({ (x: Box) => x.tokens })("{ (x: Box) => x.tokens }")
+// TODO
+// checkEq(func[Box, Coll[(Coll[Byte], Long)]]("{ (x: Box) => x.registers }"))({ (x: Box) => x.registers })(box)
+ }
+
+
+ property("PreHeader properties equivalence") {
+ val h = ctx.preHeader
+ val eq = EqualityChecker(h)
+ eq({ (x: PreHeader) => x.version })("{ (x: PreHeader) => x.version }")
+ eq({ (x: PreHeader) => x.parentId })("{ (x: PreHeader) => x.parentId }")
+ eq({ (x: PreHeader) => x.timestamp })("{ (x: PreHeader) => x.timestamp }")
+ eq({ (x: PreHeader) => x.nBits })("{ (x: PreHeader) => x.nBits }")
+ eq({ (x: PreHeader) => x.height })("{ (x: PreHeader) => x.height }")
+ eq({ (x: PreHeader) => x.minerPk })("{ (x: PreHeader) => x.minerPk }")
+ eq({ (x: PreHeader) => x.votes })("{ (x: PreHeader) => x.votes }")
+ }
+
+ property("Header properties equivalence") {
+ val h = ctx.headers(0)
+ val eq = EqualityChecker(h)
+// TODO costing for eq({ (x: Header) => x.id })("{ (x: Header) => x.id }")
+ eq({ (x: Header) => x.version })("{ (x: Header) => x.version }")
+ eq({ (x: Header) => x.parentId })("{ (x: Header) => x.parentId }")
+ eq({ (x: Header) => x.ADProofsRoot})("{ (x: Header) => x.ADProofsRoot}")
+ eq({ (x: Header) => x.stateRoot })("{ (x: Header) => x.stateRoot }")
+ eq({ (x: Header) => x.transactionsRoot })("{ (x: Header) => x.transactionsRoot }")
+ eq({ (x: Header) => x.timestamp })("{ (x: Header) => x.timestamp }")
+ eq({ (x: Header) => x.nBits })("{ (x: Header) => x.nBits }")
+ eq({ (x: Header) => x.height })("{ (x: Header) => x.height }")
+ eq({ (x: Header) => x.extensionRoot })("{ (x: Header) => x.extensionRoot }")
+ eq({ (x: Header) => x.minerPk })("{ (x: Header) => x.minerPk }")
+ eq({ (x: Header) => x.powOnetimePk })("{ (x: Header) => x.powOnetimePk }")
+ eq({ (x: Header) => x.powNonce })("{ (x: Header) => x.powNonce }")
+ eq({ (x: Header) => x.powDistance })("{ (x: Header) => x.powDistance }")
+ eq({ (x: Header) => x.votes })("{ (x: Header) => x.votes }")
+ }
+
+ property("Context properties equivalence") {
+ val eq = EqualityChecker(ctx)
+ eq({ (x: Context) => x.dataInputs })("{ (x: Context) => x.dataInputs }")
+ eq({ (x: Context) => x.dataInputs(0) })("{ (x: Context) => x.dataInputs(0) }")
+ eq({ (x: Context) => x.dataInputs(0).id })("{ (x: Context) => x.dataInputs(0).id }")
+ eq({ (x: Context) => x.preHeader })("{ (x: Context) => x.preHeader }")
+ eq({ (x: Context) => x.headers })("{ (x: Context) => x.headers }")
+ eq({ (x: Context) => x.OUTPUTS })("{ (x: Context) => x.OUTPUTS }")
+ eq({ (x: Context) => x.INPUTS })("{ (x: Context) => x.INPUTS }")
+ eq({ (x: Context) => x.HEIGHT })("{ (x: Context) => x.HEIGHT }")
+ eq({ (x: Context) => x.SELF })("{ (x: Context) => x.SELF }")
+ eq({ (x: Context) => x.INPUTS.map { (b: Box) => b.value } })("{ (x: Context) => x.INPUTS.map { (b: Box) => b.value } }")
+ eq({ (x: Context) =>
+ x.INPUTS.map { (b: Box) => (b.value, b.value) }
+ })(
+ """{ (x: Context) =>
+ | x.INPUTS.map { (b: Box) => (b.value, b.value) }
+ |}""".stripMargin
+ )
+
+ eq({ (x: Context) =>
+ x.INPUTS.map { (b: Box) =>
+ val pk = b.R4[Int].get
+ val value = longToByteArray(b.value)
+ (pk, value)
+ }
+ })(
+ """{ (x: Context) =>
+ | x.INPUTS.map { (b: Box) =>
+ | val pk = b.R4[Int].get
+ | val value = longToByteArray(b.value)
+ | (pk, value)
+ | }
+ |}""".stripMargin)
+
+// TODO
+// checkEq(func[Context, Coll[Box]]("{ (x: Context) => INPUTS }"))({ (x: Context) => x.INPUTS })(ctx)
+ }
+
+ property("xorOf equivalence") {
+ val eq = checkEq(func[Coll[Boolean], Boolean]("{ (x: Coll[Boolean]) => xorOf(x) }")) { x =>
+ xorOf(x)
+ }
+ forAll { x: Array[Boolean] =>
+ eq(Builder.DefaultCollBuilder.fromArray(x))
+ }
+ }
+
+ property("LogicalNot equivalence") {
+ // TODO make a prefix method
+ val eq = checkEq(func[Boolean, Boolean]("{ (x: Boolean) => !x }")) { x => !x }
+ forAll { x: Boolean => eq(x) }
+ }
+
+ property("Negation equivalence") {
+ // TODO make a prefix method
+ val negByte = checkEq(func[Byte, Byte]("{ (x: Byte) => -x }")) { x => (-x).toByte }
+ forAll { x: Byte => negByte(x) }
+ val negShort = checkEq(func[Short, Short]("{ (x: Short) => -x }")) { x => (-x).toShort }
+ forAll { x: Short => negShort(x) }
+ val negInt = checkEq(func[Int, Int]("{ (x: Int) => -x }")) { x => -x }
+ forAll { x: Int => negInt(x) }
+ val negLong = checkEq(func[Long, Long]("{ (x: Long) => -x }")) { x => -x }
+ forAll { x: Long => negLong(x) }
+ }
+
+ property("special.sigma.BigInt Negation equivalence") {
+ // TODO make negate() into a prefix method
+ val negBigInteger = checkEq(func[BigInt, BigInt]("{ (x: BigInt) => -x }")) { x => x.negate() }
+ forAll { x: BigInt => negBigInteger(x) }
+ }
+
+ //TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/424
+ ignore("BinXor(logical XOR) equivalence") {
+ val eq = checkEq(func[(Boolean, Boolean), Boolean]("{ (x: (Boolean, Boolean)) => x._1 ^ x._2 }")) {
+ x => x._1 ^ x._2
+ }
+ forAll { x: (Boolean, Boolean) => eq(x) }
+ }
+
+ // TODO: related to https://github.com/ScorexFoundation/sigmastate-interpreter/issues/416
+ ignore("Box.getReg equivalence") {
+ // TODO implement in SigmaDsl (interpreter test passes in BasicOpsSpec.Box.getReg test)
+// val eq = checkEq(func[Box, Int]("{ (x: Box) => x.getReg[Int](1).get }")) { x => x.getReg(1).get }
+// forAll { x: Box => eq(x) }
+ }
+}
diff --git a/src/test/scala/special/sigma/SigmaExamplesTests.scala b/src/test/scala/special/sigma/SigmaExamplesTests.scala
new file mode 100644
index 0000000000..8e344e7730
--- /dev/null
+++ b/src/test/scala/special/sigma/SigmaExamplesTests.scala
@@ -0,0 +1,110 @@
+package special.sigma
+
+import org.scalatest.FunSuite
+import special.sigma.Extensions._
+
+class SigmaExamplesTests extends FunSuite with ContractsTestkit {
+
+ val backer = MockProveDlog(true, noBytes)
+ val project = MockProveDlog(true, noBytes)
+ val selfId = collection[Byte](0, 1)
+ val outId = collection[Byte](0, 2)
+
+ test("crowd funding") {
+ val timeout = 100
+ val minToRaise = 1000
+ val contract = new CrowdFundingContract(timeout, minToRaise, backer, project)
+ val bytes = Colls.fromArray(Array[Byte]())
+ val self = new TestBox(selfId, 10, noBytes, noBytes, noBytes, noRegisters)
+
+ { // when backer can open
+ val ctxForBacker = testContext(noInputs, noOutputs, height = 200, self, emptyAvlTree, dummyPubkey, Array())
+ val ok = contract.canOpen(ctxForBacker)
+ assert(ok)
+ }
+
+ { // then project can open
+ val out = new TestBox(outId, minToRaise, noBytes, noBytes, project.propBytes, noRegisters)
+ val ctxForProject = testContext(Array(), Array(out), height = 50, self, emptyAvlTree, dummyPubkey, Array())
+ val ok = contract.canOpen(ctxForProject)
+ assert(ok)
+ }
+ }
+
+ test("demurrage") {
+ val demurragePeriod = 100
+ val demurrageCost = 2
+ val userProof = new MockProveDlog(isValid = true, noBytes)
+ val contract = new DemurrageCurrencyContract(demurragePeriod, demurrageCost, userProof)
+
+ val prop = Colls.fromArray(Array[Byte](1, 2))
+ val outHeight = 100
+ val outValue = 10L
+ val curHeight = outHeight + demurragePeriod
+ val out = new TestBox(outId, outValue, noBytes, noBytes, prop, regs(Map(R4 -> toAnyValue(curHeight))))
+
+ { //case 1: demurrage time hasn't come yet
+ val ctxForProject = testContext(
+ inputs = Array(),
+ outputs = Array(out),
+ height = outHeight + demurragePeriod - 1,
+ self = new TestBox(
+ selfId, outValue,
+ noBytes, noBytes,
+ prop,
+ regs(Map(R4 -> toAnyValue(outHeight)))),
+ emptyAvlTree,
+ dummyPubkey,
+ vars = Array()
+ )
+ userProof.isValid = true
+ val userCan = contract.canOpen(ctxForProject)
+ assert(userCan)
+
+ userProof.isValid = false
+ val minerCan = contract.canOpen(ctxForProject)
+ assert(!minerCan)
+ }
+
+ { //case 2: demurrage time has come (user can spend all the money)
+ val ctxForProject = testContext(
+ inputs = Array(),
+ outputs = Array(out),
+ height = outHeight + demurragePeriod,
+ self = new TestBox(
+ selfId, outValue,
+ noBytes, noBytes,
+ prop,
+ regs(Map(R4 -> toAnyValue(outHeight)))),
+ emptyAvlTree,
+ dummyPubkey,
+ vars = Array()
+ )
+ userProof.isValid = true
+ val userCan = contract.canOpen(ctxForProject)
+ assert(userCan)
+ }
+
+ { //case 3: demurrage time has come (miner can spend "demurrageCost" tokens)
+ val minerOut = new TestBox(outId, outValue - demurrageCost,
+ noBytes, noBytes,
+ prop, regs(Map(R4 -> toAnyValue(curHeight))))
+ val ctxForMiner = testContext(
+ inputs = Array(),
+ outputs = Array(minerOut),
+ height = outHeight + demurragePeriod,
+ self = new TestBox(
+ selfId, outValue,
+ noBytes, noBytes,
+ prop,
+ regs(Map(R4 -> toAnyValue(outHeight)))),
+ emptyAvlTree,
+ dummyPubkey,
+ vars = Array()
+ )
+ userProof.isValid = false
+ val minerCan = contract.canOpen(ctxForMiner)
+ assert(minerCan)
+ }
+ }
+}
diff --git a/src/test/scala/special/sigma/SigmaTypeGens.scala b/src/test/scala/special/sigma/SigmaTypeGens.scala
new file mode 100644
index 0000000000..fbdd4955b9
--- /dev/null
+++ b/src/test/scala/special/sigma/SigmaTypeGens.scala
@@ -0,0 +1,22 @@
+package special.sigma
+
+import org.scalacheck.{Arbitrary, Gen}
+import sigmastate.eval.CBigInt
+import sigmastate.serialization.generators.ValueGenerators
+
+trait SigmaTypeGens extends ValueGenerators {
+ import Gen._; import Arbitrary._
+ import sigma.types._
+ val genBoolean = Arbitrary.arbBool.arbitrary.map(CBoolean(_): Boolean)
+ implicit val arbBoolean = Arbitrary(genBoolean)
+
+ val genByte = Arbitrary.arbByte.arbitrary.map(CByte(_): Byte)
+ implicit val arbByte = Arbitrary(genByte)
+
+ val genInt = Arbitrary.arbInt.arbitrary.map(CInt(_): Int)
+ implicit val arbInt = Arbitrary(genInt)
+
+ val genBigInt = arbBigInteger.arbitrary.map(CBigInt(_): BigInt)
+ implicit val arbBigInt = Arbitrary(genBigInt)
+}
+