diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24e1d94756..51761a5ecc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: - name: Upload coverage report to Codecov uses: codecov/codecov-action@v1 with: - fail_ci_if_error: true + fail_ci_if_error: false - name: Publish a snapshot ${{ github.ref }} if: env.HAS_SECRETS == 'true' diff --git a/build.sbt b/build.sbt index 5b7e3219ff..6c06c611fe 100644 --- a/build.sbt +++ b/build.sbt @@ -17,12 +17,12 @@ lazy val commonSettings = Seq( scalaVersion := scala212, scalacOptions ++= { CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, 13)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports") - case Some((2, 12)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports") + case Some((2, 13)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports", "-release", "8") + case Some((2, 12)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports", "-release", "8") case Some((2, 11)) => Seq() case _ => sys.error("Unsupported scala version") } - } ++ scalacReleaseOption, + }, javacOptions ++= javacReleaseOption, resolvers += Resolver.sonatypeRepo("public"), licenses := Seq("CC0" -> url("https://creativecommons.org/publicdomain/zero/1.0/legalcode")), @@ -56,14 +56,6 @@ lazy val commonSettings = Seq( ), ) -def scalacReleaseOption = { - if (System.getProperty("java.version").startsWith("1.")) - // java <9 "-release" is not supported - Seq() - else - Seq("-release", "8") // this is passed to javac as `javac -release 8` -} - def javacReleaseOption = { if (System.getProperty("java.version").startsWith("1.")) // java <9 "--release" is not supported @@ -77,25 +69,22 @@ dynverSonatypeSnapshots in ThisBuild := true // use "-" instead of default "+" dynverSeparator in ThisBuild := "-" -val bouncycastleBcprov = "org.bouncycastle" % "bcprov-jdk15on" % "1.64" -val scrypto = "org.scorexfoundation" %% "scrypto" % "2.1.10" -val scorexUtil = "org.scorexfoundation" %% "scorex-util" % "0.1.8" -val debox = "org.scorexfoundation" %% "debox" % "0.9.0" -val spireMacros = "org.typelevel" %% "spire-macros" % "0.17.0-M1" // The last version published for Scala 2.11-2.13 -val kiama = "org.bitbucket.inkytonik.kiama" %% "kiama" % "2.5.0" +val bouncycastleBcprov = "org.bouncycastle" % "bcprov-jdk15on" % "1.66" +val scrypto = "org.scorexfoundation" %% "scrypto" % "2.3.0-RC1" +val scorexUtil = "org.scorexfoundation" %% "scorex-util" % "0.2.0" +val debox = "org.scorexfoundation" %% "debox" % "0.10.0" +val spireMacros = "org.typelevel" %% "spire-macros" % "0.17.0-M1" val fastparse = "com.lihaoyi" %% "fastparse" % "2.3.3" -val commonsIo = "commons-io" % "commons-io" % "2.5" -val commonsMath3 = "org.apache.commons" % "commons-math3" % "3.2" val scalaCompat = "org.scala-lang.modules" %% "scala-collection-compat" % "2.7.0" val testingDependencies = Seq( - "org.scalatest" %% "scalatest" % "3.0.9" % Test, - "org.scalactic" %% "scalactic" % "3.0.9" % Test, - "org.scalacheck" %% "scalacheck" % "1.14.3" % Test, + "org.scalatest" %% "scalatest" % "3.2.14" % Test, + "org.scalactic" %% "scalactic" % "3.2.14" % Test, + "org.scalacheck" %% "scalacheck" % "1.15.2" % Test, // last supporting Scala 2.11 + "org.scalatestplus" %% "scalacheck-1-15" % "3.2.3.0" % Test, // last supporting Scala 2.11 "com.lihaoyi" %% "pprint" % "0.6.3" % Test, "com.storm-enroute" %% "scalameter" % "0.19" % Test, - "junit" % "junit" % "4.12" % Test, - "com.novocode" % "junit-interface" % "0.11" % Test + "junit" % "junit" % "4.12" % Test ) lazy val testSettings = Seq( @@ -111,8 +100,12 @@ libraryDependencies ++= Seq( scrypto, scorexUtil, "org.bouncycastle" % "bcprov-jdk15on" % "1.+", - kiama, fastparse, debox, spireMacros, scalaCompat -) ++ testingDependencies + fastparse, debox, spireMacros, scalaCompat +) ++ testingDependencies ++ + (if (scalaVersion.value == scala211) + Seq(circeCore211, circeGeneric211, circeParser211) + else + Seq(circeCore, circeGeneric, circeParser)) lazy val circeCore211 = "io.circe" %% "circe-core" % "0.10.0" lazy val circeGeneric211 = "io.circe" %% "circe-generic" % "0.10.0" @@ -122,12 +115,6 @@ lazy val circeCore = "io.circe" %% "circe-core" % "0.13.0" lazy val circeGeneric = "io.circe" %% "circe-generic" % "0.13.0" lazy val circeParser = "io.circe" %% "circe-parser" % "0.13.0" -libraryDependencies ++= Seq( - if (scalaVersion.value == scala211) circeCore211 else circeCore, - if (scalaVersion.value == scala211) circeGeneric211 else circeGeneric, - if (scalaVersion.value == scala211) circeParser211 else circeParser - ) - scalacOptions ++= Seq("-feature", "-deprecation") parallelExecution in Test := false @@ -158,10 +145,10 @@ usePgpKeyHex("C1FD62B4D44BDF702CDF2B726FF59DA944B150DD") def libraryDefSettings = commonSettings ++ testSettings lazy val common = Project("common", file("common")) - .settings(commonSettings ++ testSettings, + .settings(libraryDefSettings, libraryDependencies ++= Seq( "org.scala-lang" % "scala-reflect" % scalaVersion.value, - debox, commonsIo, scalaCompat + debox, scalaCompat )) .settings(publish / skip := true) @@ -179,14 +166,14 @@ lazy val libraryimpl = Project("library-impl", file("library-impl")) lazy val core = Project("core", file("core")) .dependsOn(common % allConfigDependency, libraryapi % allConfigDependency) - .settings(commonSettings, + .settings(libraryDefSettings, libraryDependencies ++= Seq( debox )) .settings(publish / skip := true) lazy val library = Project("library", file("library")) .dependsOn(common % allConfigDependency, core % allConfigDependency, libraryapi, libraryimpl) - .settings(//commonSettings, - libraryDefSettings ++ testSettings, + .settings( + libraryDefSettings, libraryDependencies ++= Seq( debox )) .settings(publish / skip := true) @@ -217,7 +204,7 @@ lazy val sigmastate = (project in file("sigmastate")) .dependsOn(sigmalibrary % allConfigDependency) .settings(libraryDefSettings) .settings(libraryDependencies ++= Seq( - scorexUtil, kiama, fastparse, commonsMath3, + scorexUtil, fastparse, if (scalaVersion.value == scala211) circeCore211 else circeCore, if (scalaVersion.value == scala211) circeGeneric211 else circeGeneric, if (scalaVersion.value == scala211) circeParser211 else circeParser @@ -245,94 +232,3 @@ lazy val rootSettings = Seq( mappings in (Test, packageBin) ++= (mappings in(Test, packageBin)).all(aggregateCompile).value.flatten, mappings in(Test, packageSrc) ++= (mappings in(Test, packageSrc)).all(aggregateCompile).value.flatten ) - -def runErgoTask(task: String, sigmastateVersion: String, log: Logger): Unit = { - val ergoBranch = "test-coverage" - val sbtEnvVars = Seq("BUILD_ENV" -> "test", "SIGMASTATE_VERSION" -> sigmastateVersion) - - log.info(s"Testing current build in Ergo (branch $ergoBranch):") - val cwd = new File("").absolutePath - val ergoPath = new File(cwd + "/ergo-tests/") - log.info(s"Cleaning $ergoPath") - s"rm -rf ${ergoPath.absolutePath}" ! - - log.info(s"Cloning Ergo branch $ergoBranch into ${ergoPath.absolutePath}") - s"git clone -b $ergoBranch --single-branch https://github.com/ergoplatform/ergo.git ${ergoPath.absolutePath}" ! - - - log.info(s"Updating Ergo in $ergoPath with Sigmastate version $sigmastateVersion") - Process(Seq("sbt", "unlock", "reload", "lock"), ergoPath, sbtEnvVars: _*) ! - - log.info("Updated Ergo lock.sbt:") - Process(Seq("git", "diff", "-U0", "lock.sbt"), ergoPath) ! - - log.info(s"Running Ergo tests in $ergoPath with Sigmastate version $sigmastateVersion") - val res = Process(Seq("sbt", task), ergoPath, sbtEnvVars: _*) ! - - if (res != 0) sys.error(s"Ergo $task failed!") -} - -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) -} - -commands += Command.command("ergoUnitTest") { state => - "clean" :: - "publishLocal" :: - "ergoUnitTestTask" :: - state -} - -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) -} - -commands += Command.command("ergoItTest") { state => - "clean" :: - "publishLocal" :: - "ergoItTestTask" :: - state -} - -def runSpamTestTask(task: String, sigmastateVersion: String, log: Logger): Unit = { - val spamBranch = "master" - val envVars = Seq("SIGMASTATE_VERSION" -> sigmastateVersion, - // SSH_SPAM_REPO_KEY should be set (see Jenkins Credentials Binding Plugin) - "GIT_SSH_COMMAND" -> "ssh -i $SSH_SPAM_REPO_KEY") - - log.info(s"Testing current build with spam tests (branch $spamBranch):") - val cwd = new File("") - val spamPath = new File(cwd.absolutePath + "/spam-tests/") - log.info(s"Cleaning $spamPath") - s"rm -rf ${spamPath.absolutePath}" ! - - log.info(s"Cloning spam tests branch $spamBranch into ${spamPath.absolutePath}") - Process(Seq("git", "clone", "-b", spamBranch, "--single-branch", "git@github.com:greenhat/sigma-spam.git", spamPath.absolutePath), - cwd.getAbsoluteFile, - envVars: _*) ! - - log.info(s"Running spam tests in $spamPath with Sigmastate version $sigmastateVersion") - val res = Process(Seq("sbt", task), spamPath, envVars: _*) ! - - if (res != 0) sys.error(s"Spam $task failed!") -} - -lazy val spamTestTask = TaskKey[Unit]("spamTestTask", "run spam tests with current version") -spamTestTask := { - val log = streams.value.log - val sigmastateVersion = version.value - runSpamTestTask("test", sigmastateVersion, log) -} - -commands += Command.command("spamTest") { state => - "clean" :: - "publishLocal" :: - "spamTestTask" :: - state -} diff --git a/common/src/main/java/java7/compat/Math.java b/common/src/main/java/java7/compat/Math.java deleted file mode 100644 index 72ed8d5de0..0000000000 --- a/common/src/main/java/java7/compat/Math.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java7.compat; - -/** - * Contains methods introduced since Java 1.8 which are not available in Java 1.7. - * Using this methods supports compatibility with Java 1.7 in non-JVM contexts like - * RoboVM. - * The implementations are copies from JDK 1.8 sources. - *

- * See - * this issue - */ -public final class Math { - /** - * Returns the sum of its arguments, - * throwing an exception if the result overflows an {@code int}. - * - * @param x the first value - * @param y the second value - * @return the result - * @throws ArithmeticException if the result overflows an int - * @since 1.8 - */ - public static int addExact(int x, int y) { - int r = x + y; - // HD 2-12 Overflow iff both arguments have the opposite sign of the result - if (((x ^ r) & (y ^ r)) < 0) { - throw new ArithmeticException("integer overflow"); - } - return r; - } - - /** - * Returns the sum of its arguments, - * throwing an exception if the result overflows a {@code long}. - * - * @param x the first value - * @param y the second value - * @return the result - * @throws ArithmeticException if the result overflows a long - * @since 1.8 - */ - public static long addExact(long x, long y) { - long r = x + y; - // HD 2-12 Overflow iff both arguments have the opposite sign of the result - if (((x ^ r) & (y ^ r)) < 0) { - throw new ArithmeticException("long overflow"); - } - return r; - } - - /** - * Returns the difference of the arguments, - * throwing an exception if the result overflows an {@code int}. - * - * @param x the first value - * @param y the second value to subtract from the first - * @return the result - * @throws ArithmeticException if the result overflows an int - * @since 1.8 - */ - public static int subtractExact(int x, int y) { - int r = x - y; - // HD 2-12 Overflow iff the arguments have different signs and - // the sign of the result is different than the sign of x - if (((x ^ y) & (x ^ r)) < 0) { - throw new ArithmeticException("integer overflow"); - } - return r; - } - - /** - * Returns the difference of the arguments, - * throwing an exception if the result overflows a {@code long}. - * - * @param x the first value - * @param y the second value to subtract from the first - * @return the result - * @throws ArithmeticException if the result overflows a long - * @since 1.8 - */ - public static long subtractExact(long x, long y) { - long r = x - y; - // HD 2-12 Overflow iff the arguments have different signs and - // the sign of the result is different than the sign of x - if (((x ^ y) & (x ^ r)) < 0) { - throw new ArithmeticException("long overflow"); - } - return r; - } - - /** - * Returns the product of the arguments, - * throwing an exception if the result overflows an {@code int}. - * - * @param x the first value - * @param y the second value - * @return the result - * @throws ArithmeticException if the result overflows an int - * @since 1.8 - */ - public static int multiplyExact(int x, int y) { - long r = (long)x * (long)y; - if ((int)r != r) { - throw new ArithmeticException("integer overflow"); - } - return (int)r; - } - - /** - * Returns the product of the arguments, - * throwing an exception if the result overflows a {@code long}. - * - * @param x the first value - * @param y the second value - * @return the result - * @throws ArithmeticException if the result overflows a long - * @since 1.8 - */ - public static long multiplyExact(long x, long y) { - long r = x * y; - long ax = java.lang.Math.abs(x); - long ay = java.lang.Math.abs(y); - if (((ax | ay) >>> 31 != 0)) { - // Some bits greater than 2^31 that might cause overflow - // Check the result using the divide operator - // and check for the special case of Long.MIN_VALUE * -1 - if (((y != 0) && (r / y != x)) || - (x == Long.MIN_VALUE && y == -1)) { - throw new ArithmeticException("long overflow"); - } - } - return r; - } -} diff --git a/common/src/main/java/scalan/Builtin.java b/common/src/main/java/scalan/Builtin.java deleted file mode 100644 index 83a1c37b84..0000000000 --- a/common/src/main/java/scalan/Builtin.java +++ /dev/null @@ -1,17 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - - -/** Relate annotated element with internal type or method given by `value` property. -* Applied to entities that should be replaced during virtualization by related type. -* The given related type is said to be pre-virtualized. -* The 'value' is a name of the class which can be resolved in a Scalan cake. E.g. IsoUR*/ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Builtin { - String value() default ""; // default value interpreted as "virtualized name is equal to annotated element name" -} diff --git a/common/src/main/java/scalan/Constructor.java b/common/src/main/java/scalan/Constructor.java deleted file mode 100644 index 0caecfe3d9..0000000000 --- a/common/src/main/java/scalan/Constructor.java +++ /dev/null @@ -1,14 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Used in generated wrappers. - * Annotates a wrapper method of the companion of a virtualized type wrapper, - * which (the method) corresponds to the constructor of wrapped type. */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Constructor { -} diff --git a/common/src/main/java/scalan/ContainerType.java b/common/src/main/java/scalan/ContainerType.java deleted file mode 100644 index c3768cda3c..0000000000 --- a/common/src/main/java/scalan/ContainerType.java +++ /dev/null @@ -1,14 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Annotates Special DSL types which implement the interface of containers. -* Each container is described using Cont[_] descriptors. -* Special supporting code is generated for annotated entities. */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.CLASS) -public @interface ContainerType { -} diff --git a/common/src/main/java/scalan/Convertible.java b/common/src/main/java/scalan/Convertible.java deleted file mode 100644 index 662f5f6ee3..0000000000 --- a/common/src/main/java/scalan/Convertible.java +++ /dev/null @@ -1,12 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Marks annotated type as having support for generic Converter generation. */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Convertible { -} diff --git a/common/src/main/java/scalan/External.java b/common/src/main/java/scalan/External.java deleted file mode 100644 index e8e2864c7c..0000000000 --- a/common/src/main/java/scalan/External.java +++ /dev/null @@ -1,15 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Relate annotated element with an external type or method given by `value` property. -* For example WOption related to Option is annotated as @External("Option") -* This annotation is used to separate wrapper Entity from user defined virtualized Entity. -* See WrapperEntity object. */ -@Target({ElementType.TYPE, ElementType.METHOD}) -public @interface External { - String value() default ""; // default value interpreted as "external name is equal to annotated element name" -} diff --git a/common/src/main/java/scalan/FunctorType.java b/common/src/main/java/scalan/FunctorType.java deleted file mode 100644 index 9832d78271..0000000000 --- a/common/src/main/java/scalan/FunctorType.java +++ /dev/null @@ -1,13 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Used to annotate container types (like Option, Coll), which have - * functor semantics. Special code is generated for such entities. */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.CLASS) -public @interface FunctorType { -} diff --git a/common/src/main/java/scalan/InlineAt.java b/common/src/main/java/scalan/InlineAt.java deleted file mode 100644 index 0590456be7..0000000000 --- a/common/src/main/java/scalan/InlineAt.java +++ /dev/null @@ -1,18 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Specifies the predicate when the annotated method should be inlined. -* The predicate is given by the parsable formula which can be used to -* create runtime predicate functions. -* Default empty string is interpreted as never invoke, in which case scalanizer -* don't perform virtualization of the method body and replace it with delayInvoke. */ -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface InlineAt { - String Never = ""; - String value() default Never; -} diff --git a/common/src/main/java/scalan/Internal.java b/common/src/main/java/scalan/Internal.java deleted file mode 100644 index 1555984ccc..0000000000 --- a/common/src/main/java/scalan/Internal.java +++ /dev/null @@ -1,14 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Used to annotate type and methods, which should not be virtualized. - * Everything marked @Internal are invisible for virtualization process. - */ -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Internal { -} diff --git a/common/src/main/java/scalan/Isospec.java b/common/src/main/java/scalan/Isospec.java deleted file mode 100644 index d5c2498537..0000000000 --- a/common/src/main/java/scalan/Isospec.java +++ /dev/null @@ -1,12 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Marks annotated type as having support for isomorphic specialization. */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Isospec { -} diff --git a/common/src/main/java/scalan/Liftable.java b/common/src/main/java/scalan/Liftable.java deleted file mode 100644 index 83dc56bc17..0000000000 --- a/common/src/main/java/scalan/Liftable.java +++ /dev/null @@ -1,12 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Marks annotated type as having support for lifting values to IR nodes. */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface Liftable { -} diff --git a/common/src/main/java/scalan/NeverInline.java b/common/src/main/java/scalan/NeverInline.java deleted file mode 100644 index 39b63e9a0c..0000000000 --- a/common/src/main/java/scalan/NeverInline.java +++ /dev/null @@ -1,12 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Equvalent to InlineAt(Never). */ -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface NeverInline { -} diff --git a/common/src/main/java/scalan/OverloadId.java b/common/src/main/java/scalan/OverloadId.java deleted file mode 100644 index c167013698..0000000000 --- a/common/src/main/java/scalan/OverloadId.java +++ /dev/null @@ -1,13 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Assigns an alternative name to the overloaded method. */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface OverloadId { - String value(); -} diff --git a/common/src/main/java/scalan/Reified.java b/common/src/main/java/scalan/Reified.java deleted file mode 100644 index 360340f678..0000000000 --- a/common/src/main/java/scalan/Reified.java +++ /dev/null @@ -1,19 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Type argument T should be reified in virtualized code type descriptor Elem[T] available -* in the scope where T is visible. This can be done either by explicitly passing additional -* parameter eT: Elem[T] or by proving that Elem[T] can be retrieved from the other arguments -* of the method or class. For example if x: Rep[T] then eT can be obtained by x.elem. -* The need for reified type arguments come from ClassTag[T], RType[T] context bounds or -* implicit parameters in the source code. -*/ -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Reified { - String value() default ""; -} diff --git a/common/src/main/java/scalan/WithMethodCallRecognizers.java b/common/src/main/java/scalan/WithMethodCallRecognizers.java deleted file mode 100644 index 37e229ed01..0000000000 --- a/common/src/main/java/scalan/WithMethodCallRecognizers.java +++ /dev/null @@ -1,17 +0,0 @@ -package scalan; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** Marks annotated method or trait/class as having support for pattern matching. - * Extractor methods will be generated by codegen for each method either annotated or - * belonging to the annotated type. - * Extractors can be used in rewriting rules to recognize IR nodes of MethodCall type, - * which represents the call of the annotated method. - */ -@Target({ElementType.METHOD,ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface WithMethodCallRecognizers { -} diff --git a/common/src/main/scala-2.11/sigmastate/kiama/util/Collections.scala b/common/src/main/scala-2.11/sigmastate/kiama/util/Collections.scala new file mode 100644 index 0000000000..347a996452 --- /dev/null +++ b/common/src/main/scala-2.11/sigmastate/kiama/util/Collections.scala @@ -0,0 +1,42 @@ +/* + * This file is part of Kiama. + * + * Copyright (C) 2013-2021 Anthony M Sloane, Macquarie University. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package sigmastate.kiama +package util + +object Collections { + + // Java to Scala conversions + + import scala.collection.JavaConverters._ + + def javaCollectionToVector[T](s : java.util.Collection[T]) : Vector[T] = + s.asScala.toVector + + def mapToJavaMap[T, U](v : Map[T, U]) : java.util.Map[T, U] = + v.asJava + + def seqToJavaList[T](v : Seq[T]) : java.util.List[T] = + v.asJava + + // Collection building + + import scala.collection.mutable.Builder + + type Factory[-B, +C] = scala.collection.generic.CanBuildFrom[_, B, C] + type CanBuildFrom[-A, -B, +C] = scala.collection.generic.CanBuildFrom[A, B, C] + + def newBuilder[B, C](cbf : Factory[B, C]) : Builder[B, C] = + cbf() + + def newBuilder[A, B, C](cbf : CanBuildFrom[A, B, C], from : A) : Builder[B, C] = + cbf(from) + +} diff --git a/common/src/main/scala-2.12/sigmastate/kiama/util/Collections.scala b/common/src/main/scala-2.12/sigmastate/kiama/util/Collections.scala new file mode 100644 index 0000000000..347a996452 --- /dev/null +++ b/common/src/main/scala-2.12/sigmastate/kiama/util/Collections.scala @@ -0,0 +1,42 @@ +/* + * This file is part of Kiama. + * + * Copyright (C) 2013-2021 Anthony M Sloane, Macquarie University. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package sigmastate.kiama +package util + +object Collections { + + // Java to Scala conversions + + import scala.collection.JavaConverters._ + + def javaCollectionToVector[T](s : java.util.Collection[T]) : Vector[T] = + s.asScala.toVector + + def mapToJavaMap[T, U](v : Map[T, U]) : java.util.Map[T, U] = + v.asJava + + def seqToJavaList[T](v : Seq[T]) : java.util.List[T] = + v.asJava + + // Collection building + + import scala.collection.mutable.Builder + + type Factory[-B, +C] = scala.collection.generic.CanBuildFrom[_, B, C] + type CanBuildFrom[-A, -B, +C] = scala.collection.generic.CanBuildFrom[A, B, C] + + def newBuilder[B, C](cbf : Factory[B, C]) : Builder[B, C] = + cbf() + + def newBuilder[A, B, C](cbf : CanBuildFrom[A, B, C], from : A) : Builder[B, C] = + cbf(from) + +} diff --git a/common/src/main/scala-2.13/sigmastate/kiama/util/Collections.scala b/common/src/main/scala-2.13/sigmastate/kiama/util/Collections.scala new file mode 100644 index 0000000000..14f3936af1 --- /dev/null +++ b/common/src/main/scala-2.13/sigmastate/kiama/util/Collections.scala @@ -0,0 +1,42 @@ +/* + * This file is part of Kiama. + * + * Copyright (C) 2013-2021 Anthony M Sloane, Macquarie University. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package sigmastate.kiama +package util + +object Collections { + + // Java to Scala conversions + + import scala.jdk.CollectionConverters._ + + def javaCollectionToVector[T](s : java.util.Collection[T]) : Vector[T] = + s.asScala.toVector + + def mapToJavaMap[T, U](v : Map[T, U]) : java.util.Map[T, U] = + v.asJava + + def seqToJavaList[T](v : Seq[T]) : java.util.List[T] = + v.asJava + + // Collection building + + import scala.collection.mutable.Builder + + type Factory[-B, +C] = scala.collection.Factory[B, C] + type CanBuildFrom[-A, -B, +C] = scala.collection.BuildFrom[A, B, C] + + def newBuilder[B, C](f : Factory[B, C]) : Builder[B, C] = + f.newBuilder + + def newBuilder[A, B, C](cbf : CanBuildFrom[A, B, C], from : A) : Builder[B, C] = + cbf.newBuilder(from) + +} diff --git a/common/src/main/scala/java7/compat/Math.scala b/common/src/main/scala/java7/compat/Math.scala new file mode 100644 index 0000000000..a1a7ce1296 --- /dev/null +++ b/common/src/main/scala/java7/compat/Math.scala @@ -0,0 +1,126 @@ +package java7.compat + +/** + * Contains methods introduced since Java 1.8 which are not available in Java 1.7. + * Using this methods supports compatibility with Java 1.7 in non-JVM contexts like + * RoboVM. + * The implementations are copies from JDK 1.8 sources. + *

+ * See + * this issue + */ +object Math { + /** + * Returns the sum of its arguments, + * throwing an exception if the result overflows an {@code int}. + * + * @param x the first value + * @param y the second value + * @return the result + * @throws ArithmeticException if the result overflows an int + */ + def addExact(x: Int, y: Int): Int = { + val r = x + y + // HD 2-12 Overflow iff both arguments have the opposite sign of the result + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("integer overflow") + } + r + } + + /** + * Returns the sum of its arguments, + * throwing an exception if the result overflows a {@code long}. + * + * @param x the first value + * @param y the second value + * @return the result + * @throws ArithmeticException if the result overflows a long + */ + def addExact(x: Long, y: Long): Long = { + val r = x + y + if (((x ^ r) & (y ^ r)) < 0) { + throw new ArithmeticException("long overflow") + } + r + } + + /** + * Returns the difference of the arguments, + * throwing an exception if the result overflows an {@code int}. + * + * @param x the first value + * @param y the second value to subtract from the first + * @return the result + * @throws ArithmeticException if the result overflows an int + */ + def subtractExact(x: Int, y: Int): Int = { + val r = x - y + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + if (((x ^ y) & (x ^ r)) < 0) { + throw new ArithmeticException("integer overflow") + } + r + } + + /** + * Returns the difference of the arguments, + * throwing an exception if the result overflows a {@code long}. + * + * @param x the first value + * @param y the second value to subtract from the first + * @return the result + * @throws ArithmeticException if the result overflows a long + */ + def subtractExact(x: Long, y: Long) = { + val r = x - y + // HD 2-12 Overflow iff the arguments have different signs and + // the sign of the result is different than the sign of x + if (((x ^ y) & (x ^ r)) < 0) { + throw new ArithmeticException("long overflow") + } + r + } + + /** + * Returns the product of the arguments, + * throwing an exception if the result overflows an {@code int}. + * + * @param x the first value + * @param y the second value + * @return the result + * @throws ArithmeticException if the result overflows an int + */ + def multiplyExact(x: Int, y: Int) = { + val r = x.toLong * y.toLong + if (r.toInt != r) { + throw new ArithmeticException("integer overflow") + } + r.toInt + } + + /** + * Returns the product of the arguments, + * throwing an exception if the result overflows a {@code long}. + * + * @param x the first value + * @param y the second value + * @return the result + * @throws ArithmeticException if the result overflows a long + */ + def multiplyExact(x: Long, y: Long) = { + val r = x * y + val ax = java.lang.Math.abs(x) + val ay = java.lang.Math.abs(y) + if ((ax | ay) >>> 31 != 0) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((y != 0) && (r / y != x)) || (x == Long.MinValue && y == -1)) { + throw new ArithmeticException("long overflow") + } + } + r + } +} diff --git a/common/src/main/scala/scalan/util/Extensions.scala b/common/src/main/scala/scalan/util/Extensions.scala index d144d6dc96..5b0c70987a 100644 --- a/common/src/main/scala/scalan/util/Extensions.scala +++ b/common/src/main/scala/scalan/util/Extensions.scala @@ -2,7 +2,6 @@ package scalan.util import java.math.BigInteger import java.nio.ByteBuffer - import scala.language.higherKinds object Extensions { @@ -216,4 +215,21 @@ object Extensions { None } } + + /** Syntactic sugar for postfix assertions and the value pass through + * Example: + * val positiveValue = x.ensuring(_ > 0, x => s"the value is not positive: $x") + */ + implicit final class Ensuring[A](private val self: A) extends AnyVal { + /** Ensures that the given predicate holds for this value. + * @param cond the predicate used to test this value. + * @param msg the error message to be used if the predicate does not hold. + * @return this value, if it satisfies the given predicate `p`. + * @throws AssertionError if the predicate does not hold. + */ + def ensuring(cond: A => Boolean, msg: A => Any): A = { + assert(cond(self), msg(self)) + self + } + } } diff --git a/common/src/main/scala/scalan/util/FileUtil.scala b/common/src/main/scala/scalan/util/FileUtil.scala index 56e138e85f..89a596ed28 100644 --- a/common/src/main/scala/scalan/util/FileUtil.scala +++ b/common/src/main/scala/scalan/util/FileUtil.scala @@ -2,19 +2,14 @@ package scalan.util import java.io._ import java.net.{JarURLConnection, URL} -import java.nio.charset.Charset import java.nio.file._ import java.nio.file.attribute.BasicFileAttributes -import java.util.jar.JarFile -import org.apache.commons.io.{FileUtils, IOUtils} import scala.Console import scala.collection.JavaConverters._ import scalan.util.StringUtil.StringUtilExtensions import scalan.util.CollectionUtil.AnyOps object FileUtil { - def read(file: File): String = FileUtils.readFileToString(file, Charset.defaultCharset()) - def withFile(file: File)(f: PrintWriter => Unit): Unit = { if (file.isDirectory && !file.delete()) { throw new RuntimeException(s"File $file is a non-empty directory") @@ -53,50 +48,6 @@ object FileUtil { out.toString } - def copy(source: File, target: File): Unit = - if (source.isFile) - FileUtils.copyFile(source, target, false) - else - FileUtils.copyDirectory(source, target, false) - - def copyFromClassPath(source: String, target: File, classLoader: ClassLoader = getClass.getClassLoader): Unit = { - target.getParentFile.mkdirs() - val urls = classLoader.getResources(source) - if (urls.hasMoreElements) { - if (source.endsWith("/")) { - urls.asScala.foreach { url => - url.getProtocol match { - case "file" => - FileUtils.copyDirectory(urlToFile(url), target, false) - case "jar" => - val jarFile = new JarFile(jarUrlToJarFile(url)) - jarFile.entries().asScala.foreach { entry => - val entryPath = entry.getName - if (entryPath.startsWith(source)) { - val entryTarget = new File(target, entryPath.stripPrefix(source)) - if (entry.isDirectory) - entryTarget.mkdirs() - else { - // copyInputStreamToFile closes stream - FileUtils.copyInputStreamToFile(jarFile.getInputStream(entry), entryTarget) - } - } - } - } - } - } else { - val url = urls.nextElement() - if (urls.hasMoreElements) { - throw new IllegalArgumentException(s"Multiple $source resources found on classpath") - } else { - // copyInputStreamToFile closes stream - FileUtils.copyInputStreamToFile(url.openStream(), target) - } - } - } else - throw new IllegalArgumentException(s"Resource $source not found on classpath") - } - def classPathLastModified(source: String, classLoader: ClassLoader = getClass.getClassLoader) = { def urlLastModified(url: URL): Long = { url.getProtocol match { @@ -139,23 +90,6 @@ object FileUtil { urlToFile(jarFileUrl) } - /** - * Copy file source to targetDir, keeping the original file name - */ - def copyToDir(source: File, targetDir: File): Unit = - copy(source, new File(targetDir, source.getName)) - - def move(source: File, target: File): Unit = - if (source.isFile) - FileUtils.moveFile(source, target) - else - FileUtils.moveDirectory(source, target) - - /** - * Add header into the file - */ - def addHeader(file: File, header: String): Unit = write(file, header + "\n" + read(file)) - /** * Like fileOrDirectory.delete() but works for non-empty directories * and throws exceptions instead of returning false on failure @@ -228,14 +162,6 @@ object FileUtil { for {d <- dirs; f <- listFiles(d)} yield f } - def readAndCloseStream(stream: InputStream) = { - try { - IOUtils.toString(stream, Charset.defaultCharset()) - } finally { - IOUtils.closeQuietly(stream) - } - } - def stripExtension(fileName: String) = fileName.lastIndexOf('.') match { case -1 => diff --git a/common/src/main/scala/scalan/util/ReflectionUtil.scala b/common/src/main/scala/scalan/util/ReflectionUtil.scala index c463e8a787..15c73b0548 100644 --- a/common/src/main/scala/scalan/util/ReflectionUtil.scala +++ b/common/src/main/scala/scalan/util/ReflectionUtil.scala @@ -1,33 +1,19 @@ package scalan.util -import java.lang.reflect.{Method, AnnotatedElement} import scala.language.existentials -import scala.reflect.{classTag, ClassTag} -import scalan.OverloadId object ReflectionUtil { - def jAnnotation[A <: java.lang.annotation.Annotation : ClassTag](element: AnnotatedElement) = - Option(element.getAnnotation(classTag[A].runtimeClass.asInstanceOf[Class[A]])) - - def overloadId(method: Method) = jAnnotation[OverloadId](method).map(_.value) - - /** Returns the superclass for an anonymous class produced by mixing in traits; the argument otherwise. */ - def namedSuperclass(clazz: Class[_]) = { - if (clazz.getSimpleName.contains("$anon$")) { - val superclass = clazz.getSuperclass - if (superclass == classOf[Object]) { - // clazz is composed of traits only, return the first one - clazz.getInterfaces.head - } else - superclass - } else - clazz - } implicit class ClassOps(val cl: Class[_]) extends AnyVal { + /** Special character in the name. */ private def isSpecialChar(c: Char): Boolean = { ('0' <= c && c <= '9') || c == '$' } + + /** Safe version of `getSimpleName` that works around a bug in Scala compilers 2.11, 2.12. + * This method is only used for debugging purposes. + * @see https://github.com/scala/bug/issues/5425 + */ def safeSimpleName: String = { if (cl.getEnclosingClass == null) return cl.getSimpleName val simpleName = cl.getName.substring(cl.getEnclosingClass.getName.length) diff --git a/common/src/main/scala/sigmastate/VersionContext.scala b/common/src/main/scala/sigmastate/VersionContext.scala index 04ac2da524..ef220d1109 100644 --- a/common/src/main/scala/sigmastate/VersionContext.scala +++ b/common/src/main/scala/sigmastate/VersionContext.scala @@ -21,10 +21,6 @@ case class VersionContext(activatedVersion: Byte, ergoTreeVersion: Byte) { /** @return true, if the activated script version of Ergo protocol on the network is * greater than v1. */ def isJitActivated: Boolean = activatedVersion >= JitActivationVersion - - /** @return true, if the version of ErgoTree being executed greater than v1. */ - def isErgoTreeVersionGreaterV1: Boolean = - ergoTreeVersion >= JitActivationVersion } object VersionContext { diff --git a/common/src/main/scala/sigmastate/kiama/kiama.scala b/common/src/main/scala/sigmastate/kiama/kiama.scala new file mode 100644 index 0000000000..df8518f88d --- /dev/null +++ b/common/src/main/scala/sigmastate/kiama/kiama.scala @@ -0,0 +1,29 @@ +package sigmastate + +/** + * Kiama is a Scala library for language processing. It is a project of the + * Programming Languages Research Group at Macquarie University. For full + * project details see the web site `http://github.com/inkytonik/kiama`. + * + * Kiama's main components address tree decoration via attribute grammars + * (package `attribution`), tree transformation via strategic term rewriting + * (package `rewriting`), dynamic semantics (package `machine`) and + * pretty-printing (package `output`). + * + * The `util` package contains support modules for parsing, input/output, + * read-eval-print loops (REPLs) and pattern matching. + * + * The `examples` package (available as part of the Kiama tests) contains + * many examples of using Kiama to solve small to medium language processing + * problems. + */ +package object kiama { + /** + * Convenient type constructor for partial functions. + */ + type ==>[T, U] = PartialFunction[T, U] + /** + * Another convenient type constructor for partial functions. + */ + type ===>[T] = PartialFunction[T, T] +} diff --git a/common/src/main/scala/sigmastate/kiama/rewriting/CallbackRewriter.scala b/common/src/main/scala/sigmastate/kiama/rewriting/CallbackRewriter.scala new file mode 100644 index 0000000000..157f6f172b --- /dev/null +++ b/common/src/main/scala/sigmastate/kiama/rewriting/CallbackRewriter.scala @@ -0,0 +1,71 @@ +/* + * This file is part of Kiama. + * + * Copyright (C) 2013-2021 Anthony M Sloane, Macquarie University. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package sigmastate.kiama +package rewriting + +/** + * Strategy-based term rewriting with callbacks. Clients can register + * functions that are called whenever a rewrite operation has happened. + * See the `Rewriter` class documentation for more detail on the methods + * defined here. + */ +trait CallbackRewriter extends Rewriter { + + /** + * The method to call when a rewrite operation has happened. It will + * be called under two circumstances. First, when a `rule` (or similar, such + * as `rulefs`, or `strategy`) is about to return a new term to replace an old + * term. (Note that if the rule creates sub-terms in the new term, the + * results of these operations are not notified, only the root of the + * new term.) Second, whenever a generic traversal (such as all or one) + * creates a new node to duplicate an old one. In both cases this method + * is called with both the old and the new terms. The return value should + * be a term that should go forward as the new term. + */ + def rewriting[T](oldTerm : T, newTerm : T) : T + + /** + * Produce a strategy that first runs the strategy s on the + * current term. If `s` fails, then fail. Otherwise, pass the original + * and new terms to the rewriting method and succeed with the term that + * it returns. + */ + def dispatch(s : Strategy) : Strategy = + new Strategy { + def apply(t : Any) = + s(t) match { + case None => None + case Some(u) => Some(rewriting(t, u)) + } + } + + override def rule[T](f : ===>[T]) : Strategy = + dispatch(super.rule[T](f)) + + override def rulef(f : Any => Any) : Strategy = + dispatch(super.rulef(f)) + + override def rulefs[T](f : T ==> Strategy) : Strategy = + dispatch(super.rulefs[T](f)) + + override def strategy[T](f : T ==> Option[T]) : Strategy = + dispatch(super.strategy(f)) + + override def strategyf(f : Any => Option[Any]) : Strategy = + dispatch(super.strategyf(f)) + + /** + * Product duplication with callback notification. + */ + override def dup[T <: Product](t : T, children : Array[AnyRef]) : T = + rewriting(t, super.dup(t, children)) + +} diff --git a/common/src/main/scala/sigmastate/kiama/rewriting/PlusStrategy.scala b/common/src/main/scala/sigmastate/kiama/rewriting/PlusStrategy.scala new file mode 100644 index 0000000000..26ac3ae2c5 --- /dev/null +++ b/common/src/main/scala/sigmastate/kiama/rewriting/PlusStrategy.scala @@ -0,0 +1,42 @@ +/* + * This file is part of Kiama. + * + * Copyright (C) 2008-2021 Anthony M Sloane, Macquarie University. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package sigmastate.kiama.rewriting + +/** + * Helper class to contain commonality of choice in non-deterministic + * choice operator and then-else part of a conditional choice. Only + * returned by the non-deterministic choice operator. `p` and `q` are + * evaluated at most once. + */ +class PlusStrategy(p : => Strategy, q : => Strategy) extends Strategy { + + /** + * The left alternative of the choice. + */ + lazy val left = p + + /** + * The right alternative of the choice. + */ + lazy val right = q + + /** + * The strategy itself (lazily computed). + */ + private lazy val s = left <+ right + + /** + * Implementation of this strategy. Just apply `s`. + */ + def apply(t : Any) = + s(t) + +} diff --git a/common/src/main/scala/sigmastate/kiama/rewriting/Rewriter.scala b/common/src/main/scala/sigmastate/kiama/rewriting/Rewriter.scala new file mode 100644 index 0000000000..6a2b8635c9 --- /dev/null +++ b/common/src/main/scala/sigmastate/kiama/rewriting/Rewriter.scala @@ -0,0 +1,987 @@ +/* + * This file is part of Kiama. + * + * Copyright (C) 2008-2021 Anthony M Sloane, Macquarie University. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package sigmastate.kiama +package rewriting + +import scala.collection.mutable + +/** + * Strategy-based term rewriting in the style of Stratego (http://strategoxt.org/). + * The implementation here is partially based on the semantics given in "Program + * Transformation with Scoped Dynamic Rewrite Rules", by Bravenboer, van Dam, Olmos + * and Visser, Fundamenta Informaticae, 69, 2005. The library strategies are mostly + * based on the Stratego library, but also on combinators found in the Scrap Your + * Boilerplate and Uniplate libraries for Haskell. + */ +trait Rewriter { + + import sigmastate.kiama.util.Comparison.same + import sigmastate.kiama.util.Collections.{CanBuildFrom, Factory, newBuilder} + + /** + * Rewrite a term. Apply the strategy `s` to a term returning the result term + * if `s` succeeds, otherwise return the original term. + */ + def rewrite[T](s : Strategy)(t : T) : T = { + s(t) match { + case Some(t1) => + t1.asInstanceOf[T] + case None => + t + } + } + + // Strategy creation + + /** + * Make a strategy with the body `f`. By default, make a basic strategy. + */ + def mkStrategy(f : Any => Option[Any]) : Strategy = + new Strategy { + def apply(t : Any) = + f(t) + } + + // Builder combinators. + + /** + * Construct a strategy that always succeeds, changing the subject term to + * the given term `t`. The term `t` is evaluated at most once. + */ + def build(t : Any) : Strategy = + rulef(_ => t) + + /** + * A strategy that always fails. + */ + val fail : Strategy = + mkStrategy(_ => None) + + /** + * A strategy that always succeeds. + */ + val id : Strategy = + mkStrategy(Some(_)) + + /** + * Perform a paramorphism over a value. This is a fold in which the + * recursive step may refer to the recursive component of the value + * and the results of folding over the children. When the function `f` + * is called, the first parameter is the value and the second is a + * sequence of the values that `f` has returned for the children. This + * will work on any value, but will only decompose values that are + * supported by the `Term` generic term deconstruction. This operation + * is similar to that used in the Uniplate library. + */ + def para[T](f : (Any, Seq[T]) => T) : Any => T = { + case Term(t, ts) => f(t, ts.map(para(f))) + } + + /** + * Define a term query by a partial function `f`. The query always succeeds + * with no effect on the subject term but applies the given partial function + * `f` to the subject term. In other words, the strategy runs `f` for its + * side-effects. If the subject term is not a `T` or the function is not + * defined at the subject term, the strategy fails. + * + * Due to the type erasure performed on Scala programs the type test + * will be imprecise for some types. E.g., it is not possible to tell + * the difference between `List[Int]` and `List[String]`. + */ + def query[T](f : T ==> Unit) : Strategy = { + val anyf = f.asInstanceOf[===>[Any]] + mkStrategy( + (t : Any) => { + val of = anyf andThen (_ => Some(t)) + try { + of.applyOrElse(t, (a : Any) => None) + } catch { + case _ : ClassCastException => + None + } + } + ) + } + + /** + * Define a rewrite rule using a partial function `f` defined on the type + * `T`. If the subject term is a `T` and the function is defined at the + * subject term, then the strategy succeeds with the return value of the + * function applied to the subject term. Otherwise, the strategy fails. + * + * Due to the type erasure performed on Scala programs the type test + * will be imprecise for some types. E.g., it is not possible to tell + * the difference between `List[Int]` and `List[String]`. + */ + def rule[T](f : ===>[T]) : Strategy = { + val anyf = f.asInstanceOf[===>[Any]] + val of = anyf andThen (Some(_)) + mkStrategy( + (t : Any) => + try { + of.applyOrElse(t, (a : Any) => None) + } catch { + case _ : ClassCastException => + None + } + ) + } + + /** + * Define a rewrite rule using a function `f` that returns a term. + * The rule always succeeds with the return value of the function. + */ + def rulef(f : Any => Any) : Strategy = + strategyf(t => Some(f(t))) + + /** + * Define a rewrite rule using a function `f` defined on type `T` that returns + * a strategy. If the subject term is a `T` and the function is defined at the + * subject term, the rule applies the function to the subject term to get a + * strategy which is then applied again to the subject term. In other words, + * the function is only used for effects such as pattern matching. The whole + * thing also fails if `f` is not defined at the term in the first place. + */ + def rulefs[T](f : T ==> Strategy) : Strategy = { + val anyf = f.asInstanceOf[Any ==> Strategy] + mkStrategy( + (t : Any) => { + val of = anyf andThen (_.apply(t)) + try { + of.applyOrElse(t, (a : Any) => None) + } catch { + case _ : ClassCastException => + None + } + } + ) + } + + /** + * Make a strategy from a partial function `f` defined on the type `T`. + * If the subject term is a `T` and the function is defined at the + * subject term, then the function return value when applied to the + * subject term determines whether the strategy succeeds or fails. + * If the subject term is not a `T` or the function is not defined at + * the subject term, the strategy fails. + * + * Due to the type erasure performed on Scala programs the type test + * will be imprecise for some types. E.g., it is not possible to tell + * the difference between `List[Int]` and `List[String]`. + */ + def strategy[T](f : T ==> Option[T]) : Strategy = { + val of = f.asInstanceOf[Any ==> Option[T]] + mkStrategy( + (t : Any) => + try { + of.applyOrElse(t, (a : Any) => None) + } catch { + case _ : ClassCastException => + None + } + ) + } + + /** + * Make a strategy from a function `f`. The function return value + * determines whether the strategy succeeds or fails. + */ + def strategyf(f : Any => Option[Any]) : Strategy = + mkStrategy(f) + + /** + * Construct a strategy that succeeds only if the subject term matches + * the given term `t`. + */ + def term[T](t : T) : Strategy = + rule[T]({ + case `t` => t + }) + + // Product duplication support + + /** + * General product duplication functionality. This object is a function + * that returns a product that applies the same constructor as the + * product `t`, but with the given children instead of `t`'s children. + * The function fails if a constructor cannot be found, there are the + * wrong number of new children, or if one of the new children is not + * of the appropriate type. + */ + object Duplicator { + + import java.lang.reflect.Constructor + + type Duper = (Any, Array[AnyRef]) => Any + + object MakeDuper extends (Class[_] => Duper) { + + def apply(clazz : Class[_]) : Duper = + try { + // See if this class has a MODULE$ field. This field is used by Scala + // to hold a singleton instance and is only present in singleton classes + // (e.g., ones arising from object declarations or case objects). If we + // are trying to duplicate one of these then we want to return the same + // singleton so we use an identity duper. + clazz.getField("MODULE$") + (t : Any, children : Array[AnyRef]) => + t + } catch { + // Otherwise, this is a normal class, so we try to make a + // duper that uses the first constructor. + case _ : NoSuchFieldException => + val ctors = clazz.getConstructors + if (ctors.length == 0) + sys.error(s"dup no constructors for ${clazz.getName}") + else + (t : Any, children : Array[AnyRef]) => + makeInstance(ctors(0), children) + } + + def makeInstance(ctor : Constructor[_], children : Array[AnyRef]) : Any = + try { + ctor.newInstance(unboxPrimitives(ctor, children) : _*) + } catch { + case e : IllegalArgumentException => + sys.error(s"""dup illegal arguments: $ctor got (${children.mkString(",")}) + |Common cause: term classes are nested in another class, move them to the top level""".stripMargin) + } + + def unboxPrimitives(ctor : Constructor[_], children : Array[AnyRef]) : Array[AnyRef] = { + val numChildren = ctor.getParameterTypes().length + val childrenTypes = ctor.getParameterTypes() + val newChildren = new Array[AnyRef](numChildren) + var i = 0 + while (i < numChildren) { + if (childrenTypes(i).isPrimitive()) + newChildren(i) = unboxAnyVal(children(i)) + else + newChildren(i) = children(i) + i = i + 1 + } + newChildren + } + + def unboxAnyVal(s : AnyRef) : AnyRef = + s match { + case p : Product if p.productArity == 1 => + p.productElement(0).asInstanceOf[AnyRef] + case _ => + s + } + + } + + private val cache = mutable.HashMap.empty[Class[_], Duper] + + /** Obtains a duper for the given class lazily. and memoize it in the `cache` map. + * This is the simplest solution, but not the most efficient for concurrent access. + */ + def getDuper(clazz: Class[_]): Duper = synchronized { // TODO optimize: avoid global sync + val duper = cache.get(clazz) match { + case Some(d) => d + case None => + val d = MakeDuper(clazz) + cache.put(clazz, d) + d + } + duper + } + + def apply[T <: Product](t : T, children : Array[AnyRef]) : T = { + val clazz = t.getClass + val duper = getDuper(clazz) + duper(t, children).asInstanceOf[T] + } + + } + + /** + * The duplicator used by the generic traversals. Needs to be defined + * as a method so we can override it in other rewriting modules. + */ + def dup[T <: Product](t : T, children : Array[AnyRef]) : T = + Duplicator(t, children) + + /** + * Copy a product node by creating a new node of the same class type + * using the same children. + */ + def copy[T <: Product](t : T) : T = + Duplicator(t, t.productIterator.map(makechild).toArray) + + /** + * Make an arbitrary value `c` into a term child, checking that it worked + * properly. Object references will be returned unchanged; other values + * will be boxed. + */ + protected def makechild(c : Any) : AnyRef = + c.asInstanceOf[AnyRef] + + // Generic traversals + + /** + * Traversal to a single child. Construct a strategy that applies `s` to + * the ''ith'' child of the subject term (counting from one). If `s` succeeds on + * the ''ith'' child producing `t`, then succeed, forming a new term that is the + * same as the original term except that the ''ith'' child is now `t`. If `s` fails + * on the ''ith'' child or the subject term does not have an ''ith'' child, then fail. + * `child(i, s)` is equivalent to Stratego's `i(s)` operator. If `s` succeeds on + * the ''ith'' child producing the same term (by `eq` for references and by `==` for + * other values), then the overall strategy returns the subject term. + * This operation works for instances of `Product` or finite `Seq` values. + * `s` is evaluated at most once. + */ + def child(i : Int, s : => Strategy) : Strategy = + mkStrategy({ + lazy val strat = s + t => + t match { + case p : Product => + childProduct(strat, i, p) + case t : Seq[_] => + childSeq(strat, i, t.asInstanceOf[Seq[Any]]) + case _ => + None + } + }) + + /** + * Implementation of `child` for `Product` values. + */ + def childProduct(s : Strategy, i : Int, p : Product) : Option[Any] = { + val numchildren = p.productArity + if ((i < 1) || (i > numchildren)) { + None + } else { + val ct = p.productElement(i - 1) + s(ct) match { + case Some(ti) if same(ct, ti) => + Some(p) + case Some(ti) => + val newchildren = p.productIterator.map(makechild).toArray + newchildren(i - 1) = makechild(ti) + Some(dup(p, newchildren)) + case None => + None + } + } + } + + /** + * Implementation of `child` for `Seq` values. + */ + def childSeq[CC[U] <: Seq[U]](s : Strategy, i : Int, t : CC[Any])(implicit cbf : CanBuildFrom[CC[Any], Any, CC[Any]]) : Option[CC[Any]] = { + val numchildren = t.size + if ((i < 1) || (i > numchildren)) { + None + } else { + val ct = t(i - 1) + s(ct) match { + case Some(ti) if same(ct, ti) => + Some(t) + case Some(ti) => + val b = newBuilder(cbf, t) + b.sizeHint(t.size) + t.foldLeft(0) { + case (j, ct) => + b += (if (j == i - 1) ti else ct) + j + 1 + } + Some(b.result()) + case None => + None + } + } + } + + /** + * Traversal to all children. Construct a strategy that applies `s` to all + * term children of the subject term. If `s` succeeds on all of the children, + * then succeed, forming a new term from the constructor + * of the original term and the result of `s` for each child. If `s` fails on any + * child, fail. If there are no children, succeed. If `s` succeeds on all + * children producing the same terms (by `eq` for references and by `==` for + * other values), then the overall strategy returns the subject term. + * This operation works on finite `Rewritable`, `Product`, `Map` and `Iterable` + * values, checked for in that order. + * Children of a `Rewritable` (resp. Product, collection) value are processed + * in the order returned by the value's deconstruct (resp. `productElement`, + * `foreach`) method. + * `s` is evaluated at most once. + */ + def all(s : => Strategy) : Strategy = + mkStrategy({ + lazy val strat = s + t => + t match { + case p : Product => + allProduct(strat, p) + case m : Map[_, _] => + allMap(strat, m.asInstanceOf[Map[Any, Any]]) + case t : Iterable[_] => + allIterable(strat, t.asInstanceOf[Iterable[Any]]) + case _ => + Some(t) + } + }) + + /** + * Implementation of `all` for `Product` values. + */ + def allProduct(s : Strategy, p : Product) : Option[Any] = { + val numchildren = p.productArity + if (numchildren == 0) + Some(p) + else { + val newchildren = Array.newBuilder[AnyRef] + val changed = + p.productIterator.foldLeft(false) { + case (changed, ct) => + s(ct) match { + case Some(ti) => + newchildren += makechild(ti) + changed || !same(ct, ti) + case None => + return None + } + } + if (changed) + Some(dup(p, newchildren.result())) + else + Some(p) + } + } + + /** + * Implementation of `all` for `Iterable` values. + */ + def allIterable[CC[U] <: Iterable[U]](s : Strategy, t : CC[Any])(implicit cbf : CanBuildFrom[CC[Any], Any, CC[Any]]) : Option[CC[Any]] = + if (t.size == 0) + Some(t) + else { + val b = newBuilder(cbf, t) + b.sizeHint(t.size) + val (changed, _) = + t.foldLeft((false, 0)) { + case ((changed, i), ct) => + s(ct) match { + case Some(ti) => + b += ti + (changed || !same(ct, ti), i + 1) + case None => + return None + } + } + if (changed) + Some(b.result()) + else + Some(t) + } + + /** + * Implementation of `all` for `Map` values. + */ + def allMap[CC[V, W] <: Map[V, W]](s : Strategy, t : CC[Any, Any])(implicit cbf : CanBuildFrom[CC[Any, Any], (Any, Any), CC[Any, Any]]) : Option[CC[Any, Any]] = + if (t.size == 0) + Some(t) + else { + val b = newBuilder(cbf, t) + b.sizeHint(t.size) + val (changed, _) = + t.foldLeft((false, 0)) { + case ((changed, i), ct) => + s(ct) match { + case Some(ti @ (tix, tiy)) => + b += ti + (changed || !same(ct, ti), i + 1) + case _ => + return None + } + } + if (changed) + Some(b.result()) + else + Some(t) + } + + /** + * Traversal to one child. Construct a strategy that applies `s` to the term + * children of the subject term. Assume that `c` is the + * first child on which s succeeds. Then stop applying `s` to the children and + * succeed, forming a new term from the constructor of the original term and + * the original children, except that `c` is replaced by the result of applying + * `s` to `c`. In the event that the strategy fails on all children, then fail. + * If there are no children, fail. If `s` succeeds on the one child producing + * the same term (by `eq` for references and by `==` for other values), then + * the overall strategy returns the subject term. + * This operation works on instances of finite `Rewritable`, `Product`, `Map` + * and `Iterable` values, checked for in that order. + * Children of a `Rewritable` (resp. `Product`, collection) value are processed + * in the order returned by the value's `deconstruct` (resp. `productElement`, + * `foreach`) method. + * `s` is evaluated at most once. + */ + def one(s : => Strategy) : Strategy = + mkStrategy({ + lazy val strat = s + t => + t match { + case p : Product => + oneProduct(strat, p) + case m : Map[_, _] => + oneMap(strat, m.asInstanceOf[Map[Any, Any]]) + case t : Iterable[_] => + oneIterable(strat, t.asInstanceOf[Iterable[Any]]) + case _ => + None + } + }) + + /** + * Implementation of `one` for `Product` values. + */ + def oneProduct(s : Strategy, p : Product) : Option[Any] = { + p.productIterator.foldLeft(0) { + case (i, ct) => + s(ct) match { + case Some(ti) if same(ct, ti) => + return Some(p) + case Some(ti) => + val newchildren = p.productIterator.toArray.map(makechild) + newchildren(i) = makechild(ti) + return Some(dup(p, newchildren)) + case None => + i + 1 + } + } + None + } + + /** + * Implementation of `one` for `Iterable` values. + */ + def oneIterable[CC[U] <: Iterable[U]](s : Strategy, t : CC[Any])(implicit cbf : CanBuildFrom[CC[Any], Any, CC[Any]]) : Option[CC[Any]] = { + val b = newBuilder(cbf, t) + b.sizeHint(t.size) + val add = + t.foldLeft(true) { + case (add, ct) => + if (add) + s(ct) match { + case Some(ti) if same(ct, ti) => + return Some(t) + case Some(ti) => + b += ti + false + case None => + b += ct + true + } + else { + b += ct + false + } + } + if (add) + None + else + Some(b.result()) + } + + /** + * Implementation of `one` for `Map` values. + */ + def oneMap[CC[V, W] <: Map[V, W]](s : Strategy, t : CC[Any, Any])(implicit cbf : CanBuildFrom[CC[Any, Any], (Any, Any), CC[Any, Any]]) : Option[CC[Any, Any]] = { + val b = newBuilder(cbf, t) + b.sizeHint(t.size) + val add = + t.foldLeft(true) { + case (add, ct) => + if (add) + s(ct) match { + case Some(ti @ (tix, tiy)) if same(ct, ti) => + return Some(t) + case Some(ti @ (tix, tiy)) => + b += ti + false + case Some(ti) => + sys.error(s"oneMap: got non-pair $ti") + case None => + b += ct + true + } + else { + b += ct + false + } + } + if (add) + None + else + Some(b.result()) + } + + /** + * Traversal to as many children as possible, but at least one. Construct a + * strategy that applies `s` to the term children of the subject term. + * If `s` succeeds on any of the children, then succeed, + * forming a new term from the constructor of the original term and the result + * of `s` for each succeeding child, with other children unchanged. In the event + * that `s` fails on all children, then fail. If there are no + * children, fail. If `s` succeeds on children producing the same terms (by `eq` + * for references and by `==` for other values), then the overall strategy + * returns the subject term. + * This operation works on instances of finite `Rewritable`, `Product`, `Map` and + * `Iterable` values, checked for in that order. + * Children of a `Rewritable` (resp. `Product`, collection) value are processed + * in the order returned by the value's `deconstruct` (resp. `productElement`, + * `foreach`) method. + * `s` is evaluated at most once. + */ + def some(s : => Strategy) : Strategy = + mkStrategy({ + lazy val strat = s + t => + t match { + case p : Product => + someProduct(strat, p) + case m : Map[_, _] => + someMap(strat, m.asInstanceOf[Map[Any, Any]]) + case t : Iterable[_] => + someIterable(strat, t.asInstanceOf[Iterable[Any]]) + case _ => + None + } + }) + + /** + * Implementation of `some` for `Product` values. + */ + def someProduct(s : Strategy, p : Product) : Option[Any] = { + val numchildren = p.productArity + if (numchildren == 0) + None + else { + val newchildren = Array.newBuilder[AnyRef] + val (success, changed) = + p.productIterator.foldLeft((false, false)) { + case ((success, changed), ct) => + s(ct) match { + case Some(ti) => + newchildren += makechild(ti) + (true, changed || !same(ct, ti)) + case None => + newchildren += makechild(ct) + (success, changed) + } + } + if (success) + if (changed) + Some(dup(p, newchildren.result())) + else + Some(p) + else + None + } + } + + /** + * Implementation of `some` for `Iterable` values. + */ + def someIterable[CC[U] <: Iterable[U]](s : Strategy, t : CC[Any])(implicit cbf : CanBuildFrom[CC[Any], Any, CC[Any]]) : Option[CC[Any]] = + if (t.size == 0) + None + else { + val b = newBuilder(cbf, t) + b.sizeHint(t.size) + val (success, changed) = + t.foldLeft((false, false)) { + case ((success, changed), ct) => + s(ct) match { + case Some(ti) => + b += ti + (true, changed || !same(ct, ti)) + case None => + b += ct + (success, changed) + } + } + if (success) + if (changed) + Some(b.result()) + else + Some(t) + else + None + } + + /** + * Implementation of `some` for `Map` values. + */ + def someMap[CC[V, W] <: Map[V, W]](s : Strategy, t : CC[Any, Any])(implicit cbf : CanBuildFrom[CC[Any, Any], (Any, Any), CC[Any, Any]]) : Option[CC[Any, Any]] = + if (t.size == 0) + None + else { + val b = newBuilder(cbf, t) + b.sizeHint(t.size) + val (success, changed) = + t.foldLeft((false, false)) { + case ((success, changed), ct) => + s(ct) match { + case Some(ti @ (tix, tiy)) => + b += ti + (true, changed || !same(ct, ti)) + case _ => + b += ct + (success, changed) + } + } + if (success) + if (changed) + Some(b.result()) + else + Some(t) + else + None + } + + // Extractors + + /** + * Generic term deconstruction. + */ + object Term { + + /** + * Generic term deconstruction. An extractor that decomposes `Product` + * `Rewritable` or `Seq` values into the value itself and a vector of + * its children. Terms that are not of these types are not decomposable + * (i.e., the children will be empty). + */ + def unapply(t : Any) : Some[(Any, Vector[Any])] = { + t match { + case p : Product => + Some((p, p.productIterator.toVector)) + case s : Seq[_] => + Some((s, s.toVector)) + case _ => + Some((t, Vector())) + } + } + + } + + // Library combinators + + /** + * `and(s1, s2)` applies `s1` and `s2` to the subject + * term and succeeds if both succeed. `s2` will always + * be applied, i.e., and is ''not'' a short-circuit + * operator. + */ + def and(s1 : Strategy, s2 : Strategy) : Strategy = + where(s1) < (test(s2) + (test(s2) <* fail)) + + /** + * Construct a strategy that applies `s`, yielding the result of `s` if it + * succeeds, otherwise leave the original subject term unchanged. In + * Stratego library this strategy is called `try`. + */ + def attempt(s : Strategy) : Strategy = + s <+ id + + /** + * Construct a strategy that applies `s` in a bottom-up, postfix fashion + * to the subject term. + */ + def bottomup(s : Strategy) : Strategy = + all(bottomup(s)) <* s + + /** + * A strategy that tests whether the two sub-terms of a pair of terms are equal. + */ + val eq : Strategy = + rule[(Any, Any)]({ + case t @ (x, y) if x == y => t + }) + + /** + * Construct a strategy that tests whether the two sub-terms of a + * pair of terms are equal. Synonym for `eq`. + */ + val equal : Strategy = + eq + + /** + * Same as `everywheretd`. + */ + def everywhere(s : Strategy) : Strategy = + everywheretd(s) + + /** + * Construct a strategy that applies `s` at all terms in a bottom-up fashion + * regardless of failure. Terms for which the strategy fails are left + * unchanged. + */ + def everywherebu(s : Strategy) : Strategy = + bottomup(attempt(s)) + + /** + * Construct a strategy that applies `s` at all terms in a top-down fashion + * regardless of failure. Terms for which the strategy fails are left + * unchanged. + */ + def everywheretd(s : Strategy) : Strategy = + topdown(attempt(s)) + + /** + * Construct a strategy that while `r` succeeds applies `s`. This operator + * is called `while` in the Stratego library. + */ + def loop(c : Strategy, s : Strategy) : Strategy = { + lazy val result : Strategy = attempt(c <* s <* result) + mkStrategy(result) + } + + /** + * Construct a strategy that applies `s(i)` for each integer `i` from `low` to + * `high` (inclusive). This operator is called `for` in the Stratego library. + */ + def loopiter(s : Int => Strategy, low : Int, high : Int) : Strategy = { + lazy val result = + if (low <= high) + s(low) <* loopiter(s, low + 1, high) + else + id + mkStrategy(result) + } + + /** + * Construct a strategy that applies `s` to each element of a finite + * sequence (type `Seq`) returning a new sequence of the results if + * all of the applications succeed, otherwise fail. If all of the + * applications succeed without change, return the input sequence. + */ + def map(s : Strategy) : Strategy = + strategy[Seq[_]]({ + case l : Seq[_] => + allIterable[Seq](s, l) + }) + + /** + * Construct a strategy that applies `s`, then fails if `s` succeeded or, if `s` + * failed, succeeds with the subject term unchanged, I.e., it tests if + * `s` applies, but has no effect on the subject term. + */ + def not(s : Strategy) : Strategy = + s < (fail + id) + + /** + * `or(s1, s2)` is similar to `ior(s1, s2)`, but the application + * of the strategies is only tested. + */ + def or(s1 : Strategy, s2 : Strategy) : Strategy = + where(s1) < (attempt(test(s2)) + test(s2)) + + /** + * Construct a strategy that applies `s` repeatedly to subterms + * until it fails on all of them. + */ + def reduce(s : Strategy) : Strategy = { + lazy val inner : Strategy = some(inner) + s + repeat(inner) + } + + /** + * Construct a strategy that applies `s` repeatedly until it fails. + */ + def repeat(s : Strategy) : Strategy = { + lazy val result : Strategy = attempt(s <* result) + mkStrategy(result) + } + + /** + * Construct a strategy that applies `s` repeatedly exactly `n` times. If + * `s` fails at some point during the n applications, the entire strategy + * fails. The result of the strategy is that of the ''nth'' application of + * `s`. + */ + def repeat(s : Strategy, n : Int) : Strategy = { + lazy val result = if (n == 0) id else s <* repeat(s, n - 1) + mkStrategy(result) + } + + /** + * Construct a strategy that tests whether strategy `s` succeeds, + * restoring the original term on success. A synonym for `where`. + */ + def test(s : Strategy) : Strategy = + where(s) + + /** + * Construct a strategy that applies `s` in a top-down, prefix fashion + * to the subject term. + */ + def topdown(s : Strategy) : Strategy = { + lazy val result : Strategy = s <* all(result) + mkStrategy(result) + } + + /** + * Construct a strategy that tests whether strategy `s` succeeds, + * restoring the original term on success. This is similar + * to Stratego's `where`, except that in this version any effects on + * bindings are not visible outside `s`. + */ + def where(s : Strategy) : Strategy = + strategyf(t => (s <* build(t))(t)) + + // Queries below here + + /** + * Collect query results in a Iterable collection. Run the function + * `f` as a top-down left-to-right query on the subject term. Each + * application of `f` returns a single value. All of these values are + * accumulated in the collection. + */ + def collect[CC[X] <: Iterable[X], U](f : Any ==> U)(implicit cbf : Factory[U, CC[U]]) : Any => CC[U] = + (t : Any) => { + val b = newBuilder(cbf) + val add = (u : U) => { b += u; () } + (everywhere(query(f andThen add)))(t) + b.result() + } + + /** + * Count function results. Run the function `f` as a top-down query on + * the subject term. Sum the integer values returned by `f` from all + * applications. + */ + def count(f : Any ==> Int) : Any => Int = + everything(0)(_ + _)(f) + + /** + * Apply the function at every term in `t` in a top-down, left-to-right order. + * Collect the resulting `T` values by accumulating them using `f` with initial + * left value `v`. Return the final value of the accumulation. + */ + def everything[T](v : T)(f : (T, T) => T)(g : Any ==> T)(t : Any) : T = { + val collector = collect[List, T](g) + collector(t).foldLeft(v)(f) + } + +} + +/** + * Strategy-based term rewriting for arbitrary terms. + */ +object Rewriter extends Rewriter diff --git a/common/src/main/scala/sigmastate/kiama/rewriting/Strategy.scala b/common/src/main/scala/sigmastate/kiama/rewriting/Strategy.scala new file mode 100644 index 0000000000..faf856e8d7 --- /dev/null +++ b/common/src/main/scala/sigmastate/kiama/rewriting/Strategy.scala @@ -0,0 +1,94 @@ +/* + * This file is part of Kiama. + * + * Copyright (C) 2008-2021 Anthony M Sloane, Macquarie University. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package sigmastate.kiama +package rewriting + +/** + * Any-rewriting strategies. A strategy is a function that takes a term + * of any type as input and either succeeds producing a new term (`Some`), + * or fails (`None`). + */ +abstract class Strategy extends (Any => Option[Any]) { + + /** + * Alias this strategy as `p` to make it easier to refer to in the + * combinator definitions. + */ + p => + + /** + * Make one of these strategies with the body `f`. + */ + def mkStrategy(f : Any => Option[Any]) : Strategy = + new Strategy { + def apply(t : Any) = + f(t) + } + + /** + * Sequential composition. Construct a strategy that first applies + * this strategy. If it succeeds, then apply `q` to the new subject + * term. Otherwise fail. `q` is evaluated at most once. + */ + def <*(q : => Strategy) : Strategy = + mkStrategy( + t1 => + p(t1) match { + case Some(t2) => q(t2) + case None => None + } + ) + + /** + * Deterministic choice. Construct a strategy that first applies + * this strategy. If it succeeds, succeed with the resulting term. + * Otherwise, apply `q` to the original subject term. `q` is + * evaluated at most once. + */ + def <+(q : => Strategy) : Strategy = + mkStrategy( + (t1 : Any) => + p(t1) match { + case Some(t2) => Some(t2) + case None => q(t1) + } + ) + + /** + * Non-deterministic choice. Normally, construct a strategy that + * first applies either this strategy or the given strategy. If it + * succeeds, succeed with the resulting term. Otherwise, apply `q`. + * Currently implemented as deterministic choice, but this behaviour + * should not be relied upon. + * When used as the argument to the `<` conditional choice + * combinator, `+` just serves to hold the two strategies that are + * chosen between by the conditional choice. + * `q` is evaluated at most once. + */ + def +(q : => Strategy) : PlusStrategy = + new PlusStrategy(p, q) + + /** + * Conditional choice: `c < l + r`. Construct a strategy that first + * applies this strategy (`c`). If `c` succeeds, the strategy applies + * `l` to the resulting term, otherwise it applies `r` to the original + * subject term. `lr` is evaluated at most once. + */ + def <(lr : => PlusStrategy) : Strategy = + mkStrategy( + t1 => + p(t1) match { + case Some(t2) => lr.left(t2) + case None => lr.right(t1) + } + ) + +} diff --git a/common/src/main/scala/sigmastate/kiama/util/Comparison.scala b/common/src/main/scala/sigmastate/kiama/util/Comparison.scala new file mode 100644 index 0000000000..91d302a76a --- /dev/null +++ b/common/src/main/scala/sigmastate/kiama/util/Comparison.scala @@ -0,0 +1,117 @@ +/* + * This file is part of Kiama. + * + * Copyright (C) 2014-2021 Anthony M Sloane, Macquarie University. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package sigmastate.kiama +package util + +/** + * Utility module for comparison routines. + */ +object Comparison { + + import scala.collection.mutable.TreeSet + + /** + * Compare two arbitrary values. If they are both references and not + * tuples, use reference equality. If they are tuples, use `same` to + * compare the components. Otherwise use value equality. + */ + def same(v1 : Any, v2 : Any) : Boolean = + if (v1 == null) + v2 == null + else if (v2 == null) + false + else + (v1, v2) match { + case (d1 : Double, d2 : Double) => + d1 == d2 + case (f1 : Float, f2 : Float) => + f1 == f2 + case (i1 : Int, i2 : Int) => + i1 == i2 + case (l1 : Long, l2 : Long) => + l1 == l2 + case ((l1, r1), (l2, r2)) => + same(l1, l2) && same(r1, r2) + case (r1 : AnyRef, r2 : AnyRef) => + r1 eq r2 + case _ => + sys.error(s"same: comparison of $v1 and $v2, should not be reached") + } + + /** + * An ordering that says two values are equal if `same` says they + * are, otherwise earlier elements are greater than later ones. + */ + class TOrdering[T] extends Ordering[T] { + def compare(a : T, b : T) : Int = + if (same(a, b)) 0 else 1 + } + + /** + * Compare two `Iterable` collections or options and tuples containing that kind of + * collection. Use `same` to compare the individual elements in the same order. + */ + def sameCollection(v1 : Any, v2 : Any) : Boolean = + if (v1 == null) + v2 == null + else if (v2 == null) + false + else + (v1, v2) match { + case (Some(s1), Some(s2)) => + sameCollection(s1, s2) + case ((t1, t2), (t3, t4)) => + sameCollection(t1, t3) && sameCollection(t2, t4) + case (t1 : Iterable[_], t2 : Iterable[_]) => + (t1.size == t2.size) && t1.zip(t2).forall(Function.tupled(sameCollection)) + case _ => + same(v1, v2) + } + + /** + * Compare two `Seq` collections or options and tuples containing that kind of + * collection. Use `same` to compare the individual elements in any order. + */ + def sameElements[T](t1 : Seq[_], t2 : Seq[_]) : Boolean = + (t1.size == t2.size) && (t1.forall(contains(t2, _))) + + /** + * Does the iterable `s` contain `t`? Equality is tested using `same`. + */ + def contains[T](s : Iterable[T], t : T) : Boolean = + s.exists(same(_, t)) + + /** + * Return a vector with only the distinct elements from the sequence `s`. + * "distinct" in this case means compare using `same`. + */ + def distinct[T](s : Seq[T]) : Vector[T] = { + val set = new TreeSet[T]()(new TOrdering[T]) + set ++= s + set.toVector + } + + /** + * Return the first zero-based index at which `elem` occurs in `s` using `same` + * to perform comparisons, or -1 if `elem` does not occur in `s`. + */ + def indexOf[T](s : Seq[T], elem : T) : Int = + s.indexWhere(same(_, elem)) + + /** + * Return the last zero-based index at which `elem` occurs in `s` using `same` + * to perform comparisons, or -1 if `elem` does not occur in `s`. + */ + def lastIndexOf[T](s : Seq[T], elem : T) : Int = + s.lastIndexWhere(same(_, elem)) + +} + diff --git a/common/src/test/scala/scalan/BaseTests.scala b/common/src/test/scala/scalan/BaseTests.scala index 905adda285..64a8c7f615 100644 --- a/common/src/test/scala/scalan/BaseTests.scala +++ b/common/src/test/scala/scalan/BaseTests.scala @@ -1,27 +1,30 @@ package scalan +import org.scalatest.flatspec.AnyFlatSpec +import org.scalatest.funspec.AnyFunSpec + import scala.language.implicitConversions -import org.scalatest.words.ResultOfStringPassedToVerb -import org.scalatest.{FlatSpec, _} +import org.scalatest.verbs.ResultOfStringPassedToVerb +import org.scalatest.funsuite.AnyFunSuite /** * Standard base class for most test suites. See BaseNestedTests and BaseShouldTests for alternatives * * See http://doc.scalatest.org/2.2.4/#org.scalatest.FunSuite. */ -abstract class BaseTests extends FunSuite with TestUtils +abstract class BaseTests extends AnyFunSuite with TestUtils /** * Standard base class for test suites with nested tests. * * See http://doc.scalatest.org/2.2.4/#org.scalatest.FunSpec. */ -abstract class BaseNestedTests extends FunSpec with TestUtils +abstract class BaseNestedTests extends AnyFunSpec with TestUtils /** * See http://doc.scalatest.org/2.2.4/#org.scalatest.FlatSpec. */ -abstract class BaseShouldTests extends FlatSpec with TestUtils { +abstract class BaseShouldTests extends AnyFlatSpec with TestUtils { protected final class InAndIgnoreMethods2(resultOfStringPassedToVerb: ResultOfStringPassedToVerb) { import resultOfStringPassedToVerb.rest diff --git a/common/src/test/scala/scalan/TestUtils.scala b/common/src/test/scala/scalan/TestUtils.scala index 0e1645f71d..a583f590af 100644 --- a/common/src/test/scala/scalan/TestUtils.scala +++ b/common/src/test/scala/scalan/TestUtils.scala @@ -2,7 +2,8 @@ package scalan import scalan.util.FileUtil import org.scalactic.TripleEquals -import org.scalatest.{Inside, Matchers, TestSuite} +import org.scalatest.matchers.should.Matchers +import org.scalatest.{Inside, TestSuite} import scalan.util.StringUtil.StringUtilExtensions /** diff --git a/common/src/test/scala/sigmastate/VersionTestingProperty.scala b/common/src/test/scala/sigmastate/VersionTestingProperty.scala index f6d8b6c400..bfa6cace28 100644 --- a/common/src/test/scala/sigmastate/VersionTestingProperty.scala +++ b/common/src/test/scala/sigmastate/VersionTestingProperty.scala @@ -1,13 +1,14 @@ package sigmastate import org.scalactic.source.Position -import org.scalatest.{PropSpec, Tag} +import org.scalatest.propspec.AnyPropSpec +import org.scalatest.Tag /** Decorator trait which allows to redefine `property` so that it is executed repeatedly for each valid * [[VersionContext]], which is properly initialized. * Thus, the properties can be versioned using `VersionContext.current`. */ -trait VersionTestingProperty extends PropSpec with VersionTesting { +trait VersionTestingProperty extends AnyPropSpec with VersionTesting { /** Redefine `property` so that testFun is executed repeatedly for each valid * [[VersionContext]] */ diff --git a/core/src/main/scala/scalan/TypeDescs.scala b/core/src/main/scala/scalan/TypeDescs.scala index fb3c276001..97689c169d 100644 --- a/core/src/main/scala/scalan/TypeDescs.scala +++ b/core/src/main/scala/scalan/TypeDescs.scala @@ -233,15 +233,6 @@ abstract class TypeDescs extends Base { self: Scalan => final def unapply[T, E <: Elem[T]](s: Ref[T]): Nullable[E] = Nullable(s.elem.asInstanceOf[E]) - /** Get unique method name suitable to be used as HashMap key. */ - def methodKey(m: Method) = { - val ann = m.getDeclaredAnnotation(classOf[OverloadId]) - if (ann != null) - s"${m.getName}_${ann.value}" - else - m.getName - } - /** Build a mapping between methods of staged class and the corresponding methods of source class. * The methods are related using names. * The computed mapping can be used to project MethodCalls IR nodes back to the corresponding @@ -255,7 +246,7 @@ abstract class TypeDescs extends Base { self: Scalan => def declaredMethods(cls: Class[_], srcCls: Class[_], methodNames: Set[String]): Seq[(Method, MethodDesc)] = { val rmethods = cls.getDeclaredMethods.filter(m => methodNames.contains(m.getName)) val smethods = srcCls.getDeclaredMethods.filter(m => methodNames.contains(m.getName)) - val mapping = CollectionUtil.joinSeqs(rmethods, smethods)(methodKey, methodKey) + val mapping = CollectionUtil.joinSeqs(rmethods, smethods)(_.getName, _.getName) mapping.map { case (rm, sm) => (rm, RMethodDesc(sm)) }.toSeq @@ -273,7 +264,7 @@ abstract class TypeDescs extends Base { self: Scalan => val specCls = wrapSpec.getClass val wMethods = wcls.getDeclaredMethods.filter(m => methodNames.contains(m.getName)) val specMethods = specCls.getDeclaredMethods.filter(m => methodNames.contains(m.getName)) - val mapping = CollectionUtil.joinSeqs(wMethods, specMethods)(methodKey, methodKey) + val mapping = CollectionUtil.joinSeqs(wMethods, specMethods)(_.getName, _.getName) mapping.map { case (wm, sm) => (wm, WMethodDesc(wrapSpec, sm)) }.toSeq diff --git a/core/src/main/scala/scalan/primitives/Thunks.scala b/core/src/main/scala/scalan/primitives/Thunks.scala index c6d7eb63e1..6f1dc80918 100644 --- a/core/src/main/scala/scalan/primitives/Thunks.scala +++ b/core/src/main/scala/scalan/primitives/Thunks.scala @@ -2,7 +2,7 @@ package scalan.primitives import scala.language.{existentials, implicitConversions} import scalan.compilation.{GraphVizConfig, GraphVizExport} -import scalan.{Liftable => _, _} +import scalan._ import debox.{Set => DSet, Buffer => DBuffer} import debox.cfor diff --git a/docs/LangSpec.md b/docs/LangSpec.md index b564744b8d..77f03e7023 100644 --- a/docs/LangSpec.md +++ b/docs/LangSpec.md @@ -56,7 +56,7 @@ The following sections describe ErgoScript and its operations. #### ErgoScript language features overview -- syntax borrowed from Scala and Kotlin +- syntax borrowed from Scala - standard syntax and semantics for well known constructs (operations, code blocks, if branches etc.) - high-order language with first-class lambdas which are used in collection operations - call-by-value (eager evaluation) @@ -105,11 +105,11 @@ Type Name | Description `Coll[T]` | a collection of arbitrary length with all values of type `T` `(T1,T2)` | a pair of values where T1, T2 can be different types -The type constructors `Coll`, `Option`, `(_,_)` can be used to construct complex +The type constructors `Coll`, `(_,_)` can be used to construct complex types as in the following example. ```scala { - val keyValues = OUTPUTS(0).R4[Coll[(Int, Option[Int])]].get + val keyValues = OUTPUTS(0).R4[Coll[(Int, (Byte, Long))]].get ... } ``` @@ -170,8 +170,8 @@ class Numeric { } ``` -All the predefined numeric types inherit Numeric class and its method. -Internally they are pre-defined like the following. +All the predefined numeric types inherit Numeric class and its methods. +They can be thought as being pre-defined like the following. ```scala class Byte extends Numeric @@ -208,7 +208,10 @@ class Context { /** Box whose proposition is being currently executing */ def SELF: Box - + + /** Zero based index in `inputs` of `selfBox` */ + def selfBoxIndex: Int + /** A collection of inputs of the current transaction, the transaction where * selfBox is one of the inputs. */ @@ -235,7 +238,13 @@ class Context { def headers: Coll[Header] /** Header fields that are known before the block is mined. */ - def preHeader: PreHeader + def preHeader: PreHeader + + /** Bytes of encoded miner's public key. + * Same as `preHeader.minerPk.getEncoded` + */ + def minerPubKey: Coll[Byte] + } /** Represents data of the block headers available in scripts. */ @@ -313,7 +322,7 @@ class PreHeader { /** Block height */ def height: Int - /** Miner public key. Should be used to collect block rewards. */ + /** Miner's public key. Should be used to collect block rewards. */ def minerPk: GroupElement /** Miner votes for changing system parameters. */ @@ -424,9 +433,16 @@ class Box { Besides properties, every box can have up to 10 numbered registers. The following syntax is supported to access registers on box objects: ``` -box.R3[Int].get // access R3 register, check that its value of type Int and return it -box.R3[Int].isDefined // check that value of R3 is defined and has type Int -box.R3[Int].getOrElse(d) // access R3 value if defined, otherwise return `d` +// access R3 register, check that its value of type Int and return it +box.R3[Int].get + +// check that value of R3 is defined and has type Int +box.R3[Int].isDefined + +// access R3 register, if it is defined and of type Int then return it, +// if not of type Int then throw exception, +// if not defined then return `d` +box.R3[Int].getOrElse(d) ``` #### GroupElement @@ -453,6 +469,40 @@ class GroupElement { } ``` +#### SigmaProp +```scala +/** Proposition which can be proven and verified by sigma protocol. */ +trait SigmaProp { + /** Serialized bytes of this sigma proposition. + * In order to have comparisons like `box.propositionBytes == prop.propBytes` + * this SigmaProp is converted to ErgoTree as: + * 1. prop converted to [[SigmaPropConstant]] + * 2. new ErgoTree created with with ErgoTree.DefaultHeader, EmptyConstant and SigmaPropConstant as the root + * + * Thus obtained ErgoTree is serialized using DefaultSerializer and compared with `box.propositionBytes`. + */ + def propBytes: Coll[Byte] + + /** Logical AND between this SigmaProp and the `other` SigmaProp. + * This constructs a new CAND node of a sigma tree with two children. */ + def &&(other: SigmaProp): SigmaProp + + /** Logical AND between this `SigmaProp` and the `Boolean` value on the right. + * The boolean value will be wrapped into `SigmaProp` using the `sigmaProp` function. + * This constructs a new CAND node of a sigma tree with two children. */ + def &&(other: Boolean): SigmaProp + + /** Logical OR between this SigmaProp and the other SigmaProp. + * This constructs a new COR node of sigma tree with two children. */ + def ||(other: SigmaProp): SigmaProp + + /** Logical OR between this `SigmaProp` and the `Boolean` value on the right. + * The boolean value will be wrapped into `SigmaProp` using the `sigmaProp` function. + * This constructs a new COR node of a sigma tree with two children. */ + def ||(other: Boolean): SigmaProp +} +``` + #### AvlTree ```scala @@ -818,23 +868,8 @@ def xorOf(conditions: Coll[Boolean]): Boolean */ def atLeast(k: Int, properties: Coll[SigmaProp]): SigmaProp -/** Special function to represent explicit Zero Knowledge Scope in ErgoScript code. - * Compiler checks Zero Knowledge properties and issue error message is case of violations. - * ZK-scoping is optional, it can be used when the user want to ensure Zero Knowledge of - * specific set of operations. - * Usually it will require simple restructuring of the code to make the scope body explicit. - * Invariants checked by the compiler: - * - single ZKProof in ErgoTree in a root position - * - no boolean operations in the body, because otherwise the result may be disclosed - * - all the operations are over SigmaProp values - * - * For motivation and details see - * https://github.com/ScorexFoundation/sigmastate-interpreter/issues/236 - */ -def ZKProof(block: SSigmaProp): Boolean - /** Embedding of Boolean values to SigmaProp values. As an example, this - * operation allows boolean experesions to be used as arguments of + * operation allows boolean expressions to be used as arguments of * `atLeast(..., sigmaProp(myCondition), ...)` operation. */ def sigmaProp(condition: Boolean): SigmaProp @@ -867,8 +902,7 @@ def decodePoint(bytes: Coll[Byte]): GroupElement * evaluate to a valid value of the `Option[Int]` type. * * For example `val x = getVar[Int](10)` expects the variable, if it is present, to have - * type `Int`. At runtime the corresponding type descriptor is passed as `cT` - * parameter. + * type `Int`. * * There are three cases: * 1) If the variable doesn't exist. @@ -894,13 +928,13 @@ def decodePoint(bytes: Coll[Byte]): GroupElement * val tag = tagOpt.get * if (tag == 1) { * val x = getVar[Int](id2).get - * // compute res using value x is of type Int + * // compute res when value x is of type Int * } else if (tag == 2) { * val x = getVar[GroupElement](id2).get - * // compute res using value x is of type GroupElement + * // compute res when value x is of type GroupElement * } else if (tag == 3) { * val x = getVar[ Array[Byte] ](id2).get - * // compute res using value x of type Array[Byte] + * // compute res when value x of type Array[Byte] * } else { * // compute `res` when `tag` is not 1, 2 or 3 * } diff --git a/docs/notes.md b/docs/notes.md index 059336de58..cc75f1065d 100644 --- a/docs/notes.md +++ b/docs/notes.md @@ -5,15 +5,7 @@ These dependencies can be removed with refactoring | Jar | Size, Kb | |---------------|---------------| -| kiama_2.12-2.1.0.jar | 652 | | - jline-2.14.3.jar | 268 | -| - scallop_2.12-2.1.1.jar | 348 | -| - dsprofile_2.12-0.4.0.jar | 49 | -| - dsprofile_2.12-0.4.0.jar | 49 | -| - dsinfo_2.12-0.4.0.jar | 15 | -| - jsr305-3.0.2.jar | 20 | -| com.typesafe.config:config-1.3.3.jar | 286 | -| commons-io-2.5.jar | 209 | | cats-core_2.12-1.4.0.jar | 4400 | | - cats-kernel_2.12-1.4.0.jar | 3200 | | - algebra_2.12-0.7.0.jar | 1100 | diff --git a/library-api/src/main/scala/special/SpecialPredef.scala b/library-api/src/main/scala/special/SpecialPredef.scala index 9c0bbdca99..9152f55d09 100644 --- a/library-api/src/main/scala/special/SpecialPredef.scala +++ b/library-api/src/main/scala/special/SpecialPredef.scala @@ -1,7 +1,7 @@ package special import scala.reflect.ClassTag -import scalan.{Reified, RType} +import scalan.RType object SpecialPredef { def loopUntil[A](s1: A, isMatch: A => Boolean, step: A => A): A = { @@ -15,7 +15,7 @@ object SpecialPredef { def some[A](x: A): Option[A] = Some(x) - @Reified("A") def none[A](implicit tA: RType[A]): Option[A] = Option.empty[A] + def none[A](implicit tA: RType[A]): Option[A] = Option.empty[A] def optionGetOrElse[A](opt: Option[A], default: A): A = opt.getOrElse(default) diff --git a/library-api/src/main/scala/special/collection/Colls.scala b/library-api/src/main/scala/special/collection/Colls.scala index a2b7630e9e..555be23415 100644 --- a/library-api/src/main/scala/special/collection/Colls.scala +++ b/library-api/src/main/scala/special/collection/Colls.scala @@ -322,7 +322,7 @@ trait CollBuilder { /** Construct a new collection from the given list of arguments. * The arguments should be of the same type for which there should be * an implicit type descriptor at the call site. */ - @Reified("T") def fromItems[T](items: T*)(implicit cT: RType[T]): Coll[T] + def fromItems[T](items: T*)(implicit cT: RType[T]): Coll[T] /** Deconstruct collection of (A,B) pairs into pair of collections. * If `xs` is represented as PairColl, then this is O(1) operation (no data is touched). */ diff --git a/library-api/src/main/scala/special/wrappers/WrappersSpec.scala b/library-api/src/main/scala/special/wrappers/WrappersSpec.scala index baefa6aa3e..0765ba3358 100644 --- a/library-api/src/main/scala/special/wrappers/WrappersSpec.scala +++ b/library-api/src/main/scala/special/wrappers/WrappersSpec.scala @@ -1,8 +1,6 @@ package special.wrappers -import scala.reflect.ClassTag -import special.SpecialPredef -import scalan.{NeverInline, RType, WrapSpec} +import scalan.{RType, WrapSpec} trait WrapSpecBase extends WrapSpec { } @@ -10,14 +8,14 @@ trait WrapSpecBase extends WrapSpec { /** Wrappers spec for Option */ trait OptionWrapSpec extends WrapSpecBase { def get[A](xs: Option[A]): A = xs.get - @NeverInline // TODO codegen: convertion to Thunk is required + // TODO codegen: convertion to Thunk is required def getOrElse[A](xs: Option[A], default: => A): A = xs.getOrElse(default) def map[A,B](xs: Option[A], f: A => B): Option[B] = xs.map(f) def flatMap[A,B](xs: Option[A], f: A => Option[B]): Option[B] = xs.flatMap(f) def filter[A](xs: Option[A], f: A => Boolean): Option[A] = xs.filter(f) def isDefined[A](xs: Option[A]): Boolean = xs.isDefined def isEmpty[A](xs: Option[A]): Boolean = xs.isEmpty - @NeverInline // TODO codegen: fold should have single section, and convertion to Thunk is required + // TODO codegen: fold should have single section, and convertion to Thunk is required def fold[A,B](xs: Option[A], ifEmpty: =>B, f: A => B): B = xs.fold(ifEmpty)(f) }; diff --git a/library-impl/src/main/scala/special/collection/CollsOverArrays.scala b/library-impl/src/main/scala/special/collection/CollsOverArrays.scala index 97ef53ed17..6f7c87695d 100644 --- a/library-impl/src/main/scala/special/collection/CollsOverArrays.scala +++ b/library-impl/src/main/scala/special/collection/CollsOverArrays.scala @@ -1,13 +1,9 @@ package special.collection import java.util -import java.util.Objects -import special.SpecialPredef - -import scala.reflect.ClassTag import scalan._ import scalan.util.CollectionUtil -import scalan.{RType, Reified} +import scalan.RType import Helpers._ import debox.Buffer import scalan.RType._ @@ -187,7 +183,6 @@ class CollOverArrayBuilder extends CollBuilder { builder => pairCollFromArrays(resA, resB)(tA, tB) } - @Reified("T") override def fromItems[T](items: T*)(implicit cT: RType[T]): Coll[T] = cT match { case pt: PairType[a,b] => val tA = pt.tFst diff --git a/library/src/main/scala/special/collection/CollsUnit.scala b/library/src/main/scala/special/collection/CollsUnit.scala index 5571d4b8f6..f43e31e689 100644 --- a/library/src/main/scala/special/collection/CollsUnit.scala +++ b/library/src/main/scala/special/collection/CollsUnit.scala @@ -6,7 +6,7 @@ package special.collection { import CollBuilder._; import PairColl._; import WOption._; - @ContainerType @FunctorType @Liftable @WithMethodCallRecognizers trait Coll[A] extends Def[Coll[A]] { + trait Coll[A] extends Def[Coll[A]] { implicit def eA: Elem[A]; def builder: Ref[CollBuilder]; def length: Ref[Int]; @@ -25,22 +25,22 @@ package special.collection { def indices: Ref[Coll[Int]]; def flatMap[B](f: Ref[scala.Function1[A, Coll[B]]]): Ref[Coll[B]]; def segmentLength(p: Ref[scala.Function1[A, Boolean]], from: Ref[Int]): Ref[Int]; - @NeverInline def find(p: Ref[scala.Function1[A, Boolean]]): Ref[WOption[A]] = delayInvoke; + def find(p: Ref[scala.Function1[A, Boolean]]): Ref[WOption[A]] = delayInvoke; def indexWhere(p: Ref[scala.Function1[A, Boolean]], from: Ref[Int]): Ref[Int]; - @NeverInline def indexOf(elem: Ref[A], from: Ref[Int]): Ref[Int] = delayInvoke; + def indexOf(elem: Ref[A], from: Ref[Int]): Ref[Int] = delayInvoke; def lastIndexWhere(p: Ref[scala.Function1[A, Boolean]], end: Ref[Int]): Ref[Int]; def take(n: Ref[Int]): Ref[Coll[A]]; def patch(from: Ref[Int], patch: Ref[Coll[A]], replaced: Ref[Int]): Ref[Coll[A]]; def updated(index: Ref[Int], elem: Ref[A]): Ref[Coll[A]]; def updateMany(indexes: Ref[Coll[Int]], values: Ref[Coll[A]]): Ref[Coll[A]]; def unionSet(that: Ref[Coll[A]]): Ref[Coll[A]]; - @NeverInline def diff(that: Ref[Coll[A]]): Ref[Coll[A]] = delayInvoke; - @NeverInline def intersect(that: Ref[Coll[A]]): Ref[Coll[A]] = delayInvoke; + def diff(that: Ref[Coll[A]]): Ref[Coll[A]] = delayInvoke; + def intersect(that: Ref[Coll[A]]): Ref[Coll[A]] = delayInvoke; def slice(from: Ref[Int], until: Ref[Int]): Ref[Coll[A]]; def append(other: Ref[Coll[A]]): Ref[Coll[A]]; def reverse: Ref[Coll[A]] }; - @WithMethodCallRecognizers trait PairColl[L, R] extends Coll[scala.Tuple2[L, R]] { + trait PairColl[L, R] extends Coll[scala.Tuple2[L, R]] { implicit def eL: Elem[L]; implicit def eR: Elem[R]; def ls: Ref[Coll[L]]; @@ -48,9 +48,9 @@ package special.collection { def mapFirst[T1](f: Ref[scala.Function1[L, T1]]): Ref[Coll[scala.Tuple2[T1, R]]]; def mapSecond[T1](f: Ref[scala.Function1[R, T1]]): Ref[Coll[scala.Tuple2[L, T1]]] }; - @Liftable @WithMethodCallRecognizers trait CollBuilder extends Def[CollBuilder] { + trait CollBuilder extends Def[CollBuilder] { def pairColl[A, B](as: Ref[Coll[A]], bs: Ref[Coll[B]]): Ref[PairColl[A, B]]; - @Reified(value = "T") def fromItems[T](items: Ref[T]*)(implicit cT: Elem[T]): Ref[Coll[T]]; + def fromItems[T](items: Ref[T]*)(implicit cT: Elem[T]): Ref[Coll[T]]; def unzip[A, B](xs: Ref[Coll[scala.Tuple2[A, B]]]): Ref[scala.Tuple2[Coll[A], Coll[B]]]; def xor(left: Ref[Coll[Byte]], right: Ref[Coll[Byte]]): Ref[Coll[Byte]]; def replicate[T](n: Ref[Int], v: Ref[T]): Ref[Coll[T]]; diff --git a/library/src/main/scala/wrappers/scala/WOptions.scala b/library/src/main/scala/wrappers/scala/WOptions.scala index 02b9082aa0..34c7a26035 100644 --- a/library/src/main/scala/wrappers/scala/WOptions.scala +++ b/library/src/main/scala/wrappers/scala/WOptions.scala @@ -4,16 +4,16 @@ package wrappers.scala { import special.wrappers.WrappersModule trait WOptions extends Base { self: WrappersModule => - @External("Option") @ContainerType @FunctorType @Liftable @WithMethodCallRecognizers trait WOption[A] extends Def[WOption[A]] { + trait WOption[A] extends Def[WOption[A]] { implicit def eA: Elem[A]; - @External def fold[B](ifEmpty: Ref[Thunk[B]], f: Ref[scala.Function1[A, B]]): Ref[B]; - @External def isEmpty: Ref[Boolean]; - @External def isDefined: Ref[Boolean]; - @External def filter(p: Ref[scala.Function1[A, Boolean]]): Ref[WOption[A]]; - @External def flatMap[B](f: Ref[scala.Function1[A, WOption[B]]]): Ref[WOption[B]]; - @External def map[B](f: Ref[scala.Function1[A, B]]): Ref[WOption[B]]; - @External def getOrElse[B](default: Ref[Thunk[B]]): Ref[B]; - @External def get: Ref[A] + def fold[B](ifEmpty: Ref[Thunk[B]], f: Ref[scala.Function1[A, B]]): Ref[B]; + def isEmpty: Ref[Boolean]; + def isDefined: Ref[Boolean]; + def filter(p: Ref[scala.Function1[A, Boolean]]): Ref[WOption[A]]; + def flatMap[B](f: Ref[scala.Function1[A, WOption[B]]]): Ref[WOption[B]]; + def map[B](f: Ref[scala.Function1[A, B]]): Ref[WOption[B]]; + def getOrElse[B](default: Ref[Thunk[B]]): Ref[B]; + def get: Ref[A] }; trait WOptionCompanion } diff --git a/library/src/main/scala/wrappers/scalan/WRTypes.scala b/library/src/main/scala/wrappers/scalan/WRTypes.scala index 26566be4a7..07795cdada 100644 --- a/library/src/main/scala/wrappers/scalan/WRTypes.scala +++ b/library/src/main/scala/wrappers/scalan/WRTypes.scala @@ -13,9 +13,9 @@ package wrappers.scalan { trait WRTypes extends Base { self: WrappersModule => import WRType._; - @External("RType") @Liftable @WithMethodCallRecognizers trait WRType[A] extends Def[WRType[A]] { + trait WRType[A] extends Def[WRType[A]] { implicit def eA: Elem[A]; - @External def name: Ref[String] + def name: Ref[String] }; trait WRTypeCompanion } diff --git a/library/src/main/scala/wrappers/special/WSpecialPredefs.scala b/library/src/main/scala/wrappers/special/WSpecialPredefs.scala index fc7f0c7401..6a5731fa06 100644 --- a/library/src/main/scala/wrappers/special/WSpecialPredefs.scala +++ b/library/src/main/scala/wrappers/special/WSpecialPredefs.scala @@ -6,13 +6,13 @@ package wrappers.special { trait WSpecialPredefs extends Base { self: WrappersModule => import WOption._; import WSpecialPredef._; - @External("SpecialPredef") @WithMethodCallRecognizers trait WSpecialPredef extends Def[WSpecialPredef]; + trait WSpecialPredef extends Def[WSpecialPredef]; trait WSpecialPredefCompanion { - @External def optionGetOrElse[A](opt: Ref[WOption[A]], default: Ref[A]): Ref[A]; - @External def none[@Reified A](implicit emA: Elem[A]): Ref[WOption[A]]; - @External def some[A](x: Ref[A]): Ref[WOption[A]]; - @External def cast[@Reified T](v: Ref[Any])(implicit emT: Elem[T]): Ref[WOption[T]]; - @External def loopUntil[A](s1: Ref[A], isMatch: Ref[scala.Function1[A, Boolean]], step: Ref[scala.Function1[A, A]]): Ref[A] + def optionGetOrElse[A](opt: Ref[WOption[A]], default: Ref[A]): Ref[A]; + def none[A](implicit emA: Elem[A]): Ref[WOption[A]]; + def some[A](x: Ref[A]): Ref[WOption[A]]; + def cast[T](v: Ref[Any])(implicit emT: Elem[T]): Ref[WOption[T]]; + def loopUntil[A](s1: Ref[A], isMatch: Ref[scala.Function1[A, Boolean]], step: Ref[scala.Function1[A, A]]): Ref[A] } } } \ No newline at end of file diff --git a/library/src/test/scala/special/collections/CollsTests.scala b/library/src/test/scala/special/collections/CollsTests.scala index b22822e2aa..b8a8339276 100644 --- a/library/src/test/scala/special/collections/CollsTests.scala +++ b/library/src/test/scala/special/collections/CollsTests.scala @@ -2,7 +2,8 @@ package special.collections import org.scalacheck.Gen import org.scalatest.exceptions.TestFailedException -import org.scalatest.{Matchers, PropSpec} +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import scalan._ import sigmastate.{VersionContext, VersionTestingProperty} @@ -10,7 +11,7 @@ import special.collection.{Coll, CollOverArray, PairOfCols} import scala.language.{existentials, implicitConversions} -class CollsTests extends PropSpec with ScalaCheckPropertyChecks with Matchers with CollGens with VersionTestingProperty { testSuite => +class CollsTests extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with CollGens with VersionTestingProperty { testSuite => import Gen._ import special.collection.ExtensionMethods._ diff --git a/sigma-api/src/main/scala/special/sigma/SigmaDsl.scala b/sigma-api/src/main/scala/special/sigma/SigmaDsl.scala index 8b265e3310..a6864a3302 100644 --- a/sigma-api/src/main/scala/special/sigma/SigmaDsl.scala +++ b/sigma-api/src/main/scala/special/sigma/SigmaDsl.scala @@ -2,7 +2,6 @@ package special.sigma import java.math.BigInteger -import org.bouncycastle.math.ec.ECPoint import special.collection._ import scalan._ import scorex.crypto.authds.{ADDigest, ADValue} @@ -15,8 +14,6 @@ import scala.util.Try * which is used for all cryptographic operations). * So it is globally and implicitly used in all methods. * */ -@scalan.Liftable -@WithMethodCallRecognizers trait BigInt { /** Convert this BigInt value to Byte. * @throws ArithmeticException if overflow happens. @@ -99,7 +96,7 @@ trait BigInt { * @return { @code this + that} */ def add(that: BigInt): BigInt - @Internal def +(that: BigInt): BigInt = add(that) + def +(that: BigInt): BigInt = add(that) /** Returns a BigInt whose value is {@code (this - that)}. * @@ -107,7 +104,7 @@ trait BigInt { * @return { @code this - that} */ def subtract(that: BigInt): BigInt - @Internal def -(that: BigInt): BigInt = subtract(that) + def -(that: BigInt): BigInt = subtract(that) /** Returns a BigInt whose value is {@code (this * that)}. * @@ -117,7 +114,7 @@ trait BigInt { * @return { @code this * that} */ def multiply(that: BigInt): BigInt - @Internal def *(that: BigInt): BigInt = multiply(that) + def *(that: BigInt): BigInt = multiply(that) /** Returns a BigInt whose value is {@code (this / that)}. * @@ -126,7 +123,7 @@ trait BigInt { * @throws ArithmeticException if { @code that} is zero. */ def divide(that: BigInt): BigInt - @Internal def /(that: BigInt): BigInt = divide(that) + def /(that: BigInt): BigInt = divide(that) /** * Returns a BigInt whose value is {@code (this mod m}). This method @@ -139,7 +136,7 @@ trait BigInt { * @see #remainder */ def mod(m: BigInt): BigInt - @Internal def %(m: BigInt): BigInt = mod(m) + def %(m: BigInt): BigInt = mod(m) /** * Returns a BigInt whose value is {@code (this % that)}. @@ -182,7 +179,7 @@ trait BigInt { * @return `this & that` */ def and(that: BigInt): BigInt - @Internal def &(that: BigInt): BigInt = and(that) + def &(that: BigInt): BigInt = and(that) /** Returns a BigInteger whose value is `(this | that)`. (This * method returns a negative BigInteger if and only if either `this` or `that`` is @@ -192,15 +189,14 @@ trait BigInt { * @return `this | that` */ def or(that: BigInt): BigInt - @Internal def |(that: BigInt): BigInt = or(that) + def |(that: BigInt): BigInt = or(that) } /** Base class for points on elliptic curves. */ -@scalan.Liftable -@WithMethodCallRecognizers trait GroupElement { - def isInfinity: Boolean + /** Checks if the provided element is an identity element. */ + def isIdentity: Boolean /** Exponentiate this GroupElement to the given number. * @param k The power. @@ -224,8 +220,6 @@ trait GroupElement { } /** Proposition which can be proven and verified by sigma protocol. */ -@scalan.Liftable -@WithMethodCallRecognizers trait SigmaProp { def isValid: Boolean /** Serialized bytes of this sigma proposition taken as ErgoTree and then serialized. */ @@ -233,26 +227,14 @@ trait SigmaProp { /** 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 + def &&(other: SigmaProp): 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 + def ||(other: SigmaProp): SigmaProp } /** Represents any value paired with type descriptor. */ -@scalan.Liftable -@WithMethodCallRecognizers trait AnyValue { /** The data value wrapped by this instance. */ def value: Any @@ -263,8 +245,6 @@ trait AnyValue { /** Runtime representation of Ergo boxes used during execution of ErgoTree operations. * @see [[org.ergoplatform.ErgoBox]] */ -@scalan.Liftable -@WithMethodCallRecognizers trait Box { /** Blake2b256 hash of this box's content, basically equals to `blake2b256(bytes)` */ def id: Coll[Byte] @@ -341,32 +321,32 @@ trait Box { * different from cT. * @since 2.0 */ - def getReg[@Reified T](i: Int)(implicit cT: RType[T]): Option[T] + def getReg[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) + def R0[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) + def R1[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) + def R2[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) + def R3[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) + def R4[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) + def R5[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) + def R6[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) + def R7[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) + def R8[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) + def R9[T](implicit cT:RType[T]): Option[T] = this.getReg[T](9) /** Secondary tokens */ def tokens: Coll[(Coll[Byte], Long)] @@ -384,9 +364,8 @@ trait Box { * @return result of the script execution in the current context * @since Mainnet */ - def executeFromRegister[@Reified T](regId: Byte)(implicit cT:RType[T]): T + def executeFromRegister[T](regId: Byte)(implicit cT:RType[T]): T - @Internal override def toString = s"Box(id=$id; value=$value; regs=$registers)" } @@ -399,7 +378,6 @@ trait Box { * * This interface is used as runtime representation of the AvlTree type of ErgoTree. */ -@scalan.Liftable trait AvlTree { /** Returns digest of the state represented by this tree. * Authenticated tree digest = root hash bytes ++ tree height @@ -554,7 +532,6 @@ trait AvlTreeVerifier { /** 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 @@ -582,7 +559,6 @@ trait PreHeader { // Testnet2 /** 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] @@ -636,8 +612,6 @@ trait Header { /** Runtime representation of Context ErgoTree type. * Represents data available in Sigma language using `CONTEXT` global variable. */ -@scalan.Liftable -@WithMethodCallRecognizers trait Context { def builder: SigmaDslBuilder @@ -656,22 +630,21 @@ trait Context { /** 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. */ + /** Zero based index in `inputs` of `selfBox`. */ def selfBoxIndex: Int /** Authenticated dynamic dictionary digest representing Utxo state before current state. */ def LastBlockUtxoRootHash: AvlTree - /** A fixed number of last block headers in descending order (first header is the newest one) - * @since 2.0 - */ + /** A fixed number of last block headers in descending order (first header is the newest one) */ def headers: Coll[Header] - /** - * @since 2.0 - */ + /** Fields of a new block header, that can be predicted by a miner before block's formation */ def preHeader: PreHeader + /** Bytes of encoded miner's public key. + * Same as `preHeader.minerPk.getEncoded` + */ def minerPubKey: Coll[Byte] /** Extracts Context variable by id and type. @@ -743,12 +716,9 @@ trait Context { def currentErgoTreeVersion: Byte } -@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 */ @@ -779,7 +749,6 @@ trait SigmaContract { def decodePoint(encoded: Coll[Byte]): GroupElement = this.builder.decodePoint(encoded) - @Reified("T") def substConstants[T](scriptBytes: Coll[Byte], positions: Coll[Int], newValues: Coll[T]): Coll[Byte] = this.builder.substConstants(scriptBytes, positions, newValues) @@ -795,8 +764,6 @@ trait SigmaContract { * * @see SGlobal.WrappedType, CostingSigmaDslBuilder */ -@scalan.Liftable -@WithMethodCallRecognizers trait SigmaDslBuilder { /** Access to collection operations. */ @@ -887,7 +854,6 @@ trait SigmaDslBuilder { * @param newValues new values to be injected into the corresponding positions in ErgoTree.constants array * @return original scriptBytes array where only specified constants are replaced and all other bytes remain exactly the same */ - @Reified("T") def substConstants[T](scriptBytes: Coll[Byte], positions: Coll[Int], newValues: Coll[T]): Coll[Byte] /** Decodes the given bytes to the corresponding GroupElement using default serialization. @@ -897,10 +863,10 @@ trait SigmaDslBuilder { def decodePoint(encoded: Coll[Byte]): GroupElement /** Create DSL big integer from existing `java.math.BigInteger`*/ - @Internal def BigInt(n: BigInteger): BigInt + def BigInt(n: BigInteger): BigInt /** Extract `java.math.BigInteger` from DSL's `BigInt` type*/ - @Internal def toBigInteger(n: BigInt): BigInteger + 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/package.scala b/sigma-api/src/main/scala/special/sigma/package.scala index b02b187ea5..dcbb71ef64 100644 --- a/sigma-api/src/main/scala/special/sigma/package.scala +++ b/sigma-api/src/main/scala/special/sigma/package.scala @@ -2,7 +2,6 @@ package special import java.math.BigInteger -import org.bouncycastle.math.ec.ECPoint import scalan.RType import scalan.RType.GeneralType @@ -30,5 +29,4 @@ package object sigma { implicit val SigmaDslBuilderRType: RType[SigmaDslBuilder] = RType.fromClassTag(classTag[SigmaDslBuilder]) implicit val BigIntegerRType: RType[BigInteger] = GeneralType(classTag[BigInteger]) - implicit val ECPointRType: RType[ECPoint] = GeneralType(classTag[ECPoint]) } \ No newline at end of file diff --git a/sigma-library/src/main/scala/special/sigma/SigmaDslUnit.scala b/sigma-library/src/main/scala/special/sigma/SigmaDslUnit.scala index 5634a05d6d..5bd2ad784b 100644 --- a/sigma-library/src/main/scala/special/sigma/SigmaDslUnit.scala +++ b/sigma-library/src/main/scala/special/sigma/SigmaDslUnit.scala @@ -3,7 +3,7 @@ package special.sigma { import scalan._ trait SigmaDsl extends Base { self: SigmaLibrary => - @Liftable @WithMethodCallRecognizers trait BigInt extends Def[BigInt] { + trait BigInt extends Def[BigInt] { def toByte: Ref[Byte]; def toShort: Ref[Short]; def toInt: Ref[Int]; @@ -28,28 +28,24 @@ package special.sigma { def max(that: Ref[BigInt]): Ref[BigInt]; def negate: Ref[BigInt] }; - @Liftable @WithMethodCallRecognizers trait GroupElement extends Def[GroupElement] { + trait GroupElement extends Def[GroupElement] { def isInfinity: Ref[Boolean]; def exp(k: Ref[BigInt]): Ref[GroupElement]; def multiply(that: Ref[GroupElement]): Ref[GroupElement]; def negate: Ref[GroupElement]; def getEncoded: Ref[Coll[Byte]] }; - @Liftable @WithMethodCallRecognizers trait SigmaProp extends Def[SigmaProp] { + trait SigmaProp extends Def[SigmaProp] { def isValid: Ref[Boolean]; def propBytes: Ref[Coll[Byte]]; - @OverloadId(value = "and_sigma") def &&(other: Ref[SigmaProp]): Ref[SigmaProp]; - // manual fix - @OverloadId(value = "and_bool") def &&(other: Ref[Boolean])(implicit o: Overloaded1): Ref[SigmaProp]; - @OverloadId(value = "or_sigma") def ||(other: Ref[SigmaProp]): Ref[SigmaProp]; - // manual fix - @OverloadId(value = "or_bool") def ||(other: Ref[Boolean])(implicit o: Overloaded1): Ref[SigmaProp]; + def &&(other: Ref[SigmaProp]): Ref[SigmaProp]; + def ||(other: Ref[SigmaProp]): Ref[SigmaProp]; }; - @Liftable @WithMethodCallRecognizers trait AnyValue extends Def[AnyValue] { + trait AnyValue extends Def[AnyValue] { def value: Ref[Any]; def tVal: Ref[WRType[Any]] }; - @Liftable @WithMethodCallRecognizers trait Box extends Def[Box] { + trait Box extends Def[Box] { def id: Ref[Coll[Byte]]; def value: Ref[Long]; def propositionBytes: Ref[Coll[Byte]]; @@ -71,7 +67,7 @@ package special.sigma { def creationInfo: Ref[scala.Tuple2[Int, Coll[Byte]]]; def executeFromRegister[T](regId: Ref[Byte])(implicit cT: Elem[T]): Ref[T] }; - @Liftable trait AvlTree extends Def[AvlTree] { + trait AvlTree extends Def[AvlTree] { def digest: Ref[Coll[Byte]]; def enabledOperations: Ref[Byte]; def keyLength: Ref[Int]; @@ -88,7 +84,7 @@ package special.sigma { def update(operations: Ref[Coll[scala.Tuple2[Coll[Byte], Coll[Byte]]]], proof: Ref[Coll[Byte]]): Ref[WOption[AvlTree]]; def remove(operations: Ref[Coll[Coll[Byte]]], proof: Ref[Coll[Byte]]): Ref[WOption[AvlTree]] }; - @Liftable trait PreHeader extends Def[PreHeader] { + trait PreHeader extends Def[PreHeader] { def version: Ref[Byte]; def parentId: Ref[Coll[Byte]]; def timestamp: Ref[Long]; @@ -97,7 +93,7 @@ package special.sigma { def minerPk: Ref[GroupElement]; def votes: Ref[Coll[Byte]] }; - @Liftable trait Header extends Def[Header] { + trait Header extends Def[Header] { def id: Ref[Coll[Byte]]; def version: Ref[Byte]; def parentId: Ref[Coll[Byte]]; @@ -114,7 +110,7 @@ package special.sigma { def powDistance: Ref[BigInt]; def votes: Ref[Coll[Byte]] }; - @Liftable @WithMethodCallRecognizers trait Context extends Def[Context] { + trait Context extends Def[Context] { def builder: Ref[SigmaDslBuilder]; def OUTPUTS: Ref[Coll[Box]]; def INPUTS: Ref[Coll[Box]]; @@ -129,7 +125,7 @@ package special.sigma { def getVar[T](id: Ref[Byte])(implicit cT: Elem[T]): Ref[WOption[T]]; def vars: Ref[Coll[AnyValue]] }; - @Liftable @WithMethodCallRecognizers trait SigmaDslBuilder extends Def[SigmaDslBuilder] { + trait SigmaDslBuilder extends Def[SigmaDslBuilder] { def Colls: Ref[CollBuilder]; def verifyZK(cond: Ref[Thunk[SigmaProp]]): Ref[Boolean]; def atLeast(bound: Ref[Int], props: Ref[Coll[SigmaProp]]): Ref[SigmaProp]; @@ -147,7 +143,7 @@ package special.sigma { def proveDlog(g: Ref[GroupElement]): Ref[SigmaProp]; def proveDHTuple(g: Ref[GroupElement], h: Ref[GroupElement], u: Ref[GroupElement], v: Ref[GroupElement]): Ref[SigmaProp]; def groupGenerator: Ref[GroupElement]; - @Reified(value = "T") def substConstants[T](scriptBytes: Ref[Coll[Byte]], positions: Ref[Coll[Int]], newValues: Ref[Coll[T]]): Ref[Coll[Byte]]; + def substConstants[T](scriptBytes: Ref[Coll[Byte]], positions: Ref[Coll[Int]], newValues: Ref[Coll[T]]): Ref[Coll[Byte]]; def decodePoint(encoded: Ref[Coll[Byte]]): Ref[GroupElement]; def avlTree(operationFlags: Ref[Byte], digest: Ref[Coll[Byte]], keyLength: Ref[Int], valueLengthOpt: Ref[WOption[Int]]): Ref[AvlTree]; def xor(l: Ref[Coll[Byte]], r: Ref[Coll[Byte]]): Ref[Coll[Byte]] diff --git a/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala index efdbd3fc23..8195aed696 100644 --- a/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala +++ b/sigma-library/src/main/scala/special/sigma/impl/SigmaDslImpl.scala @@ -908,14 +908,6 @@ object SigmaProp extends EntityObject("SigmaProp") { true, false, element[SigmaProp])) } - // manual fix && - override def &&(other: Ref[Boolean])(implicit o: Overloaded1): Ref[SigmaProp] = { - asRep[SigmaProp](mkMethodCall(self, - SigmaPropClass.getMethod("$amp$amp", classOf[Sym], classOf[Overloaded1]), - Array[AnyRef](other, o), - true, false, element[SigmaProp])) - } - // manual fix || override def ||(other: Ref[SigmaProp]): Ref[SigmaProp] = { asRep[SigmaProp](mkMethodCall(self, @@ -923,14 +915,6 @@ object SigmaProp extends EntityObject("SigmaProp") { Array[AnyRef](other), true, false, element[SigmaProp])) } - - // manual fix || - override def ||(other: Ref[Boolean])(implicit o: Overloaded1): Ref[SigmaProp] = { - asRep[SigmaProp](mkMethodCall(self, - SigmaPropClass.getMethod("$bar$bar", classOf[Sym], classOf[Overloaded1]), - Array[AnyRef](other, o), - true, false, element[SigmaProp])) - } } implicit object LiftableSigmaProp @@ -978,14 +962,6 @@ object SigmaProp extends EntityObject("SigmaProp") { true, true, element[SigmaProp])) } - // manual fix && - def &&(other: Ref[Boolean])(implicit o: Overloaded1): Ref[SigmaProp] = { - asRep[SigmaProp](mkMethodCall(source, - SigmaPropClass.getMethod("$amp$amp", classOf[Sym], classOf[Overloaded1]), - Array[AnyRef](other, o), - true, true, element[SigmaProp])) - } - // manual fix || def ||(other: Ref[SigmaProp]): Ref[SigmaProp] = { asRep[SigmaProp](mkMethodCall(source, @@ -994,28 +970,6 @@ object SigmaProp extends EntityObject("SigmaProp") { true, true, element[SigmaProp])) } - // manual fix || - def ||(other: Ref[Boolean])(implicit o: Overloaded1): Ref[SigmaProp] = { - asRep[SigmaProp](mkMethodCall(source, - SigmaPropClass.getMethod("$bar$bar", classOf[Sym], classOf[Overloaded1]), - Array[AnyRef](other, o), - true, true, element[SigmaProp])) - } - - def lazyAnd(other: Ref[Thunk[SigmaProp]]): Ref[SigmaProp] = { - asRep[SigmaProp](mkMethodCall(source, - SigmaPropClass.getMethod("lazyAnd", classOf[Sym]), - Array[AnyRef](other), - true, true, element[SigmaProp])) - } - - def lazyOr(other: Ref[Thunk[SigmaProp]]): Ref[SigmaProp] = { - asRep[SigmaProp](mkMethodCall(source, - SigmaPropClass.getMethod("lazyOr", classOf[Sym]), - Array[AnyRef](other), - true, true, element[SigmaProp])) - } - // manual fix def builder: Ref[SigmaDslBuilder] = { asRep[SigmaDslBuilder](mkMethodCall(source, @@ -1040,7 +994,7 @@ object SigmaProp extends EntityObject("SigmaProp") { 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" + "isValid", "propBytes", "$amp$amp", "$bar$bar" )) } } @@ -1084,7 +1038,7 @@ object SigmaProp extends EntityObject("SigmaProp") { object and_sigma_&& { def unapply(d: Def[_]): Nullable[(Ref[SigmaProp], Ref[SigmaProp])] = d match { - case MethodCall(receiver, method, args, _) if method.getName == "$amp$amp" && receiver.elem.isInstanceOf[SigmaPropElem[_]] && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "and_sigma" } => + case MethodCall(receiver, method, args, _) if method.getName == "$amp$amp" && receiver.elem.isInstanceOf[SigmaPropElem[_]] => val res = (receiver, args(0)) Nullable(res).asInstanceOf[Nullable[(Ref[SigmaProp], Ref[SigmaProp])]] case _ => Nullable.None @@ -1092,35 +1046,15 @@ object SigmaProp extends EntityObject("SigmaProp") { def unapply(exp: Sym): Nullable[(Ref[SigmaProp], Ref[SigmaProp])] = unapply(exp.node) } - object and_bool_&& { - def unapply(d: Def[_]): Nullable[(Ref[SigmaProp], Ref[Boolean])] = d match { - case MethodCall(receiver, method, args, _) if method.getName == "$amp$amp" && receiver.elem.isInstanceOf[SigmaPropElem[_]] && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "and_bool" } => - val res = (receiver, args(0)) - Nullable(res).asInstanceOf[Nullable[(Ref[SigmaProp], Ref[Boolean])]] - case _ => Nullable.None - } - def unapply(exp: Sym): Nullable[(Ref[SigmaProp], Ref[Boolean])] = unapply(exp.node) - } - object or_sigma_|| { def unapply(d: Def[_]): Nullable[(Ref[SigmaProp], Ref[SigmaProp])] = d match { - case MethodCall(receiver, method, args, _) if method.getName == "$bar$bar" && receiver.elem.isInstanceOf[SigmaPropElem[_]] && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "or_sigma" } => + case MethodCall(receiver, method, args, _) if method.getName == "$bar$bar" && receiver.elem.isInstanceOf[SigmaPropElem[_]] => val res = (receiver, args(0)) Nullable(res).asInstanceOf[Nullable[(Ref[SigmaProp], Ref[SigmaProp])]] case _ => Nullable.None } def unapply(exp: Sym): Nullable[(Ref[SigmaProp], Ref[SigmaProp])] = unapply(exp.node) } - - object or_bool_|| { - def unapply(d: Def[_]): Nullable[(Ref[SigmaProp], Ref[Boolean])] = d match { - case MethodCall(receiver, method, args, _) if method.getName == "$bar$bar" && receiver.elem.isInstanceOf[SigmaPropElem[_]] && { val ann = method.getAnnotation(classOf[scalan.OverloadId]); ann != null && ann.value == "or_bool" } => - val res = (receiver, args(0)) - Nullable(res).asInstanceOf[Nullable[(Ref[SigmaProp], Ref[Boolean])]] - case _ => Nullable.None - } - def unapply(exp: Sym): Nullable[(Ref[SigmaProp], Ref[Boolean])] = unapply(exp.node) - } } object SigmaPropCompanionMethods { diff --git a/sigmastate/src/main/java/gf2t/GF2_192.java b/sigmastate/src/main/java/gf2t/GF2_192.java deleted file mode 100644 index dc0c166bcf..0000000000 --- a/sigmastate/src/main/java/gf2t/GF2_192.java +++ /dev/null @@ -1,580 +0,0 @@ -/* - By Leonid Reyzin - - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to - */ -package gf2t; - -import java.util.Arrays; - -public class GF2_192 { - private final long [] word = new long[3]; - - /** - * - * @param obj the field element with which to compare - * @return true if and only if this and that represent the same field element - */ - @Override - public boolean equals(Object obj) { - if (this == obj) return true; // equal references - if (obj instanceof GF2_192) { - GF2_192 that = (GF2_192)obj; - return this.word[0]==that.word[0] && this.word[1]==that.word[1] && this.word[2]==that.word[2]; - } - return false; // different types - } - - @Override - public int hashCode() { - return Arrays.hashCode(word); - } - - // using irreducible polynomial x^192+x^7+x^2+x+1 - // We need only the last word - static private final long irredPentanomial = (1L<<7) | (1L<<2) | (1L<<1) | 1L; - - // irredPentanomial times 0, 1, x, x+1, x^2, x^2+1, x^2+x, x^2+x+1, x^3, x^3+1, x^3+x, x^3+x+1, x^3+x^2, x^3+x^2+1, x^3+x^2+x, x^3+x^2x+1, - // Need only the last word, because the leading two words are 0 - static private final long [] irredMuls = {0L, irredPentanomial, irredPentanomial<<1, (irredPentanomial<<1)^irredPentanomial, - irredPentanomial<<2, (irredPentanomial<<2)^irredPentanomial, (irredPentanomial<<2)^(irredPentanomial<<1), (irredPentanomial<<2)^(irredPentanomial<<1)^irredPentanomial, - irredPentanomial<<3, (irredPentanomial<<3)^irredPentanomial, (irredPentanomial<<3)^(irredPentanomial<<1), (irredPentanomial<<3)^(irredPentanomial<<1)^irredPentanomial, - (irredPentanomial<<3)^(irredPentanomial<<2), (irredPentanomial<<3)^(irredPentanomial<<2)^irredPentanomial, (irredPentanomial<<3)^(irredPentanomial<<2)^(irredPentanomial<<1), (irredPentanomial<<3)^(irredPentanomial<<2)^(irredPentanomial<<1)^irredPentanomial - - }; - - /** - * returns the 0 field element - */ - public GF2_192() { - } - - /** - * returns a copy of the field element - * @param that element to copy - */ - public GF2_192(GF2_192 that) { - this.word[0] = that.word[0]; - this.word[1] = that.word[1]; - this.word[2] = that.word[2]; - } - - /** - * returns the field element whose 32 least significant bits are bits of that and rest are 0 - * @param that lower 32 bits - */ - public GF2_192(int that) { - this.word[0] = ((long) that) & 0xFFFFFFFFL; - } - - /** - * returns the field element whose bits are given by the long array - * @param that must be length 3 - */ - public GF2_192(long [] that) { - assert (that.length == 3); - this.word[0] = that[0]; - this.word[1] = that[1]; - this.word[2] = that[2]; - } - - /** - * returns the field element whose bits are given by the byte array that - * @param that must be length 24 - */ - public GF2_192(byte [] that) { - this(that, 0); - } - - /** - * returns the field element whose bits are given by the byte array that[pos]...that[pos+23] - * @param that must be length at least pos+24 - */ - public GF2_192(byte [] that, int pos) { - assert (that.length >= pos+24); - for (int i = 0; i<8; i++) { - word[0] |= (((long)that[i+pos] & 0xFF))<<(i<<3); - } - for (int i = 0; i<8; i++) { - word[1] |= (((long)that[i+pos+8] & 0xFF))<<(i<<3); - } - for (int i = 0; i<8; i++) { - word[2] |= (((long)that[i+pos+16] & 0xFF))<<(i<<3); - } - } - - /** - * - * @return long array of length 3 containing the three words of the field element - */ - public long [] toLongArray() { - long [] ret = new long[3]; - ret[0] = word[0]; - ret[1] = word[1]; - ret[2] = word[2]; - return ret; - } - - /** - * - * @return byte array of length 24 containing the two words of the field element - */ - public byte[] toByteArray() { - byte [] ret = new byte[24]; - toByteArray(ret, 0); - return ret; - } - - /** - * @param ret bytes of the field element will go into ret[pos]...ret[pos+23] - */ - public void toByteArray(byte[] ret, int pos) { - assert(ret.length>=pos+24); - for (int j = 0; j<3; j++) { - for (int i = 0; i < 8; i++) { - ret[pos+i+8*j] = (byte) ((word[j] >> (i << 3)) & 0xFF); - } - } - } - - - - /** - * - * @return true if this == 0, false otherwise - */ - public boolean isZero () { - return word[0]==0L && word[1]==0L && word[2]==0L; - } - - /** - * - * @return true if this == 1, false otherwise - */ - public boolean isOne () { - return word[0]==1L && word[1]==0L && word[2]==0L; - } - - /** - * Computes a plus b and puts the result into res. - * @param res output; must be not null; may be equal to a and/or b - * @param a multiplicand; may be equal to res, in which case will get overwritten - * @param b multiplier; may be equal to res, in which case will get overwritten - */ - - public static void add (GF2_192 res, GF2_192 a, GF2_192 b) { - res.word[0] = a.word[0]^b.word[0]; - res.word[1] = a.word[1]^b.word[1]; - res.word[2] = a.word[2]^b.word[2]; - } - - - - /** - * Computes a times b and puts the result into res. - * Uses table lookups, which may not preserve - * the secrecy of the inputs in case of side-channel attacks. - * - * @param res output; must be not null; may be equal to a and/or b - * @param a multiplicand; may be equal to res, in which case will get overwritten - * @param b multiplier; may be equal to res, in which case will get overwritten - */ - public static void mul (GF2_192 res, GF2_192 a, GF2_192 b) { - - // Implements a sort of times-x-and-add algorithm, except instead of multiplying by x - // we multiply by x^4 and then add one of possible 16 precomputed values - - // contains a*0, a*1, a*x, a*(x+1), a*x^2, a*(x^2+1), a*(x^2+x), a*(x^2+x+1) - // a*x^3, a*(x^3+1), a*(x^3+x), a*(x^3+x+1), a*(x^3+x^2), a*(x^3+x^2+1), a*(x^3+x^2+x), a*(x^3+x^2+x+1), all mod reduced - // First word of each is in a0 muls, second word of each is in a1muls, third word of each is in a2muls - long [] a0muls = new long[16]; - long [] a1muls = new long[16]; - long [] a2muls = new long[16]; - - // a0muls[0], a1muls[0] and a2muls[0] are already correctly initialized to 0 - - a0muls[1] = a.word[0]; - a1muls[1] = a.word[1]; - a2muls[1] = a.word[2]; - - // a*x, a*x^2, a*x^3 - for (int i = 2; i<=8; i*=2) { - // multiply a*x^{log_2 i/2} by x to get a*x^{log_2 i} - int prev = i / 2; - a0muls[i] = a0muls[prev] << 1; - a1muls[i] = (a1muls[prev] << 1) | (a0muls[prev] >>> 63); - a2muls[i] = (a2muls[prev] << 1) | (a1muls[prev] >>> 63); - // mod reduce - a0muls[i] ^= irredMuls[(int) (a2muls[prev] >>> 63)]; - } - - // a*(x+1) - a0muls[3] = a0muls[1] ^ a0muls[2]; - a1muls[3] = a1muls[1] ^ a1muls[2]; - a2muls[3] = a2muls[1] ^ a2muls[2]; - - - // a*(x^2+1), a*(x^2+x), a*(x^2+x+1) - for (int i = 1; i<4; i++) { - a0muls[4|i] = a0muls[4]^a0muls[i]; - a1muls[4|i] = a1muls[4]^a1muls[i]; - a2muls[4|i] = a2muls[4]^a2muls[i]; - } - - // a*(x^3+1), a*(x^3+x), a*(x^3+x+1), a*(x^3+x^2), a*(x^3+x^2+1), a*(x^3+x^2+x), a*(x^3+x^2+x+1) - for (int i = 1; i<8; i++) { - a0muls[8|i] = a0muls[8]^a0muls[i]; - a1muls[8|i] = a1muls[8]^a1muls[i]; - a2muls[8|i] = a2muls[8]^a2muls[i]; - } - - long w0 = 0, w1 = 0, w2 = 0; - for (int j = 2; j>=0; j--) { - long multiplier = b.word[j]; - for (int i = 60; i >= 0; i -= 4) { - // Multiply by x^4 - int modReduceIndex = (int) (w2 >>> 60); - w2 = (w2 << 4) | (w1 >>> 60); - w1 = (w1 << 4) | (w0 >>> 60); - // MOD REDUCE ACCORDING TO modReduceIndex by XORing the right value - w0 = (w0 << 4) ^ irredMuls[modReduceIndex]; - //w0 = (w0<<4)^(irredPentanomial*(modReduceIndex&8))^(irredPentanomial*(modReduceIndex&4))^(irredPentanomial*(modReduceIndex&2))^(irredPentanomial*(modReduceIndex&1)); - - // Add the correct multiple of a - int index = (int) ((multiplier >>> i) & 15); - w0 ^= a0muls[index]; - w1 ^= a1muls[index]; - w2 ^= a2muls[index]; - } - } - res.word[0] = w0; - res.word[1] = w1; - res.word[2] = w2; - } - - /** - * Computes a times b and puts the result into res. More efficient than mul(res, a, new GF2_192(b)) - * @param res output; must be not null; may be equal to a and/or b - * @param a multiplicand; may be equal to res, in which case will get overwritten - * @param b multiplier; may be equal to res, in which case will get overwritten - */ - public static void mul (GF2_192 res, GF2_192 a, byte b) { - - long w0 = 0, w1 = 0, w2 = 0, w3=0; - - for (int i = 7; i >= 0; i--) { - w3 = w2 >>> 63; - w2 = (w2 << 1) | (w1 >>> 63); - w1 = (w1 << 1) | (w0 >>> 63); - w0 <<= 1; - long t = (b >>> i) & 1; - w2 ^= a.word[2] * t; - w1 ^= a.word[1] * t; - w0 ^= (a.word[0] * t) ^ (irredPentanomial * w3); // mod reduce - } - res.word[0] = w0; - res.word[1] = w1; - res.word[2] = w2; - } - - - public static void invert (GF2_192 res, GF2_192 z) { - // Computes z^{2^192-2} = z^{exponent written in binary as 191 ones followed by a single zero} - // (by Fermat's little theorem, this is the correct inverse) - - // contains z raised to the power whose binary representation is 2^k ones - GF2_192 zTo2ToK1s = new GF2_192(z); - - // Square res to get its exponent to be 10 in binary - mul(res, z, z); - - // contains z raised to the power whose binary representation is 2^k ones followed by 2^k zeros - GF2_192 zTo2ToK1s2ToK0s = new GF2_192(res); - - - // Loop invariant - // res contains z raised to the power whose binary representation is 2^{k+1}-1 ones followed by a single zero - // zTo2ToK1s contains z raised to the power whose binary representation is 2^k ones - // zTo2ToK1s2ToK0s contains z raised to the power whose binary representation is 2^k ones followed by 2^k zeros - int k = 0; - while (k<6) { - k++; - // Fill in the zeros in the exponent of zTo2ToK1s2ToK0s with ones - mul(zTo2ToK1s, zTo2ToK1s2ToK0s, zTo2ToK1s); - // zTo2ToK1s2ToK0s = power2To2ToK with 2^k zeros appended to the exponent - power2To2ToK(zTo2ToK1s2ToK0s, zTo2ToK1s, k); - // prepend 2^k ones to res - mul(res, res, zTo2ToK1s2ToK0s); - } - // Prepened another 64 ones to res - power2To2ToK(zTo2ToK1s2ToK0s, zTo2ToK1s2ToK0s, k); - mul(res, res, zTo2ToK1s2ToK0s); - } - - - - // These tables are used in power2To2ToK and sqr -- see explanation in power2To2ToK. They take up about about 14KB. - - private static final long [][] powTable0 = { - {1L,4L,16L,64L,256L,1024L,4096L,16384L,65536L,262144L,1048576L,4194304L,16777216L,67108864L,268435456L,1073741824L,4294967296L,17179869184L,68719476736L,274877906944L,1099511627776L,4398046511104L,17592186044416L,70368744177664L,281474976710656L,1125899906842624L,4503599627370496L,18014398509481984L,72057594037927936L,288230376151711744L,1152921504606846976L,4611686018427387904L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,135L,540L,2160L,8640L,34560L,138240L,552960L,2211840L,8847360L,35389440L,141557760L,566231040L,2264924160L,9059696640L,36238786560L,144955146240L,579820584960L,2319282339840L,9277129359360L,37108517437440L,148434069749760L,593736278999040L,2374945115996160L,9499780463984640L,37999121855938560L,151996487423754240L,607985949695016960L,2431943798780067840L,-8718968878589280256L,2017612633061982208L,8070450532247928832L,-4611686018427387904L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,270L,1080L,4199L,}, - {1L,16L,256L,4096L,65536L,1048576L,16777216L,268435456L,4294967296L,68719476736L,1099511627776L,17592186044416L,281474976710656L,4503599627370496L,72057594037927936L,1152921504606846976L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,135L,2160L,34560L,552960L,8847360L,141557760L,2264924160L,36238786560L,579820584960L,9277129359360L,148434069749760L,2374945115996160L,37999121855938560L,607985949695016960L,-8718968878589280256L,8070450532247928832L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,1080L,16405L,262480L,4199680L,67194880L,1075118080L,17201889280L,275230228480L,4403683655680L,70458938490880L,1127343015854080L,18037488253665280L,288599812058644480L,4617596992938311680L,94575592174780416L,1513209474796486656L,5764607523034234880L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,540L,8640L,138375L,2214635L,35434160L,566946560L,9071144960L,145138319360L,2322213109760L,37155409756160L,594486556098560L,9511784897576960L,152188558361231360L,2435016933779701760L,2066782793056124928L,-3824963458521104384L,-5859183115209015296L,-1513209474796486656L,-5764607523034234880L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,270L,4199L,65620L,1048694L,16777290L,}, - {1L,65536L,4294967296L,281474976710656L,0L,0L,0L,0L,0L,0L,0L,0L,135L,8847360L,579820584960L,37999121855938560L,0L,0L,0L,0L,0L,0L,0L,0L,16405L,1075118080L,70458938490880L,4617596992938311680L,0L,0L,0L,0L,0L,0L,0L,0L,2214635L,145138319360L,9511784897576960L,-3824963458521104384L,0L,0L,0L,0L,0L,0L,0L,4199L,268435729L,17592203935744L,1152922677132918784L,76842668642009088L,0L,0L,0L,0L,0L,0L,0L,552960L,36238823415L,2374947531325440L,8070608823267622912L,-8072983807038324736L,0L,0L,0L,0L,0L,0L,1080L,67194880L,4403688133701L,288600105530228736L,5783840476780036096L,6072259672578981888L,0L,0L,0L,0L,0L,0L,138375L,9071137756L,594486085783387L,2066751970480947200L,-7784595809881817088L,-8116893903405187072L,0L,0L,0L,0L,0L,270L,16777290L,1099511627845L,72057594037993729L,4311810048L,282578783305728L,72339069014638592L,0L,0L,0L,0L,0L,34560L,2264924160L,148434069749895L,-8718968878580398201L,582094356480L,38148135746273280L,-8680969756733341696L,0L,0L,0L,0L,0L,4199680L,275230228480L,18037488253681685L,1513209475875820821L,70735243837440L,4635704940130467840L,6130806467734798336L,0L,0L,0L,0L,8640L,566946560L,37155409756160L,2435016933781924651L,-1513209329119911445L,9547060033028096L,-1513172181595455488L,2444047222778626048L,0L,0L,0L,0L,1048694L,68719546624L,4503604207554663L,300166943871232L,1224996759836561425L,1157443864920915968L,1229500363472633856L,1157706579210928128L,0L,0L,0L,2160L,141557895L,9277138794240L,607986568019867760L,40522537422618480L,-646134085450172169L,8680969174647242752L,-38147594580393984L,8716435603798884352L,0L,0L,0L,262480L,17201906733L,1127344162226488L,94650720833590632L,4923631783780892776L,4685244537110860101L,6130877201840930816L,4635630379498209280L,1244400872037810176L,0L,0L,540L,35434160L,2322211272620L,152188437960410523L,-5867073703402003989L,-608753751841641685L,5021550739930207323L,2435017087666290688L,-1503124363304501248L,-3144919914788159488L,0L,0L,65620L,4294967417L,281474976710691L,16L,118L,65641L,}, - {1L,0L,0L,268435729L,0L,0L,72057594037993729L,0L,8640L,1224996759836561425L,0L,2322211272620L,4295032833L,0L,-3824963458521104384L,1152940269605290257L,67194880L,-8116893903405048697L,72340168543043841L,18037488253681685L,2444084377648024256L,1152940269335812193L,4923631783780892776L,8706684044243276764L,575525617665L,0L,2214635L,6917686146403139857L,0L,594486068876182L,109923151000961281L,0L,-1508668585977835444L,-42651198216466415L,17201907249L,-1503124363304500630L,37718226699878401L,4617597137004134400L,-3834029160147512970L,-79200059939786479L,5542457468742751288L,72653179618366162L,-8718686828065942650L,6157755589565773013L,-427524231241125731L,-7636548200255303383L,2349380831670242920L,-1503122247285515780L,1L,16405L,36240966940L,268435729L,4403688133701L,-8718374392512378660L,72057594037993729L,1513209475874772323L,2019996756866529500L,1224996759976022166L,4684963044965832011L,5021552416478667632L,37999126150971393L,4684939972385783829L,-4989366934530337413L,-6920043528899271987L,72339069031416121L,-8680822410973408226L,-6391613922127811155L,1153203052884328721L,5891559298491384716L,-7528422813418094127L,35172261L,-608824726141909180L,575525617798L,9441498026213649L,3487211355411353591L,6917686182105090782L,-4416945885376472588L,6063073012436278090L,-8753160638328035514L,-5605497289716500368L,-5610075583180945114L,90149276037394458L,339026464814167628L,369965729453364929L,-3860411569319034860L,-7219661873698413202L,-7217141859998432150L,1806743557951716919L,-8790878027314019100L,-8686366285709925551L,-9018771827274447141L,-3500033589960484657L,-6239661070421212278L,-7022774006793486301L,-5486222289147287496L,6557835543537224962L,1L,4403688117328L,268435729L,268435729L,1513213877407514960L,72057594037993729L,72057594179551622L,6054338822752200080L,1224996759836570065L,1262995881831960726L,4685176399308498684L,2326506170314L,-8110982924599230463L,-7012597109688626096L,-2672024288427437773L,1760926221464557073L,-8193431732091728425L,-8188932805459047229L,-702248183304599069L,2358520128326754357L,3596724480578929564L,2653562374675748729L,7558329885135416404L,8706684602589025248L,611764439881L,-4354323463508992325L,6917686146405354490L,-1801282968903807655L,9071577101557338822L,109381790017557217L,8696092877002101742L,-4668327226503048164L,1475308329743286364L,128146801688724317L,-8390330629760215797L,-1531869438861569413L,-4617320090730090391L,5541920254930687988L,3761689569789112577L,-2327319826622658605L,-6182158405047794621L,-41970731974321979L,-4950437438052009930L,-3752274221890333889L,1476151931308439890L,5613176216134850767L,289726897646273736L,-1503122247017080678L,594453066058452L,4437244711257L,72057630278829085L,7782810071065752468L,-7925740857026315255L,-7637528022863553386L,-3839220191352824283L,6705067445074182019L,6637312287860931618L,-2154173082950753382L,-8117068327749574457L,4645236792527042077L,3567261728918198996L,-1570715894964224286L,3851762367547029496L,-1282481202581286367L,604372413954671920L,7336273916715742398L,8984291365106642911L,-3520346153016046579L,-3001672072993760708L,5487223282412062341L,3220238017403266817L,-7526201328351032492L,-6651737113209978849L,-876842992662428725L,2730222910065286284L,4666291884953713058L,27885208784216435L,-3464689086048100177L,9074463908856611112L,6089525621414736771L,-344374184071824754L,-4138339726157814851L,90460192285484837L,7003316425532605053L,2325362866034789830L,6377579351440235774L,-5484290407194710110L,3204252260295655770L,4952583157325034207L,-8782555314696362611L,-2316049681279009322L,-1127600795797440159L,7751601582170687883L,-6463181785702448409L,7121056025054547704L,6485777949499231279L,}, - {1L,-3006172399682371634L,2600966637154804214L,8641L,8525113116679455864L,-2145144163292000430L,2019996756799457565L,-1850476282776554867L,-4889822090580977265L,909561413152654253L,-25001132819151504L,7726439241120171362L,7303489125464870298L,4332131768403656981L,2962048663402138678L,-2892279489278463047L,-4733651509025142792L,1063143929388429494L,-1197895461363724390L,3525840681984842667L,-4695277565342099683L,5146529997701558317L,7435951619486932058L,-2724786844429777139L,40504930336318985L,876946985023164340L,5608484252067120944L,-6816077621382648259L,-4033654809715777901L,-4081572395912436435L,-8636364450456842826L,7120123665156854152L,-2739360841521830815L,4179210361336297309L,-5035580621240300693L,5024856697532411216L,-5583726119146644383L,1447126495187071743L,-2586987284404803098L,8837846401203718243L,6684981609574125625L,1540466829568951558L,-4848578993616133096L,531411902399629160L,-8097992882751386397L,5836923291160128631L,2657822116024759531L,5082038816076700909L,7237486007293790522L,5252165852497928096L,-6943891580396708852L,-2358876157997055033L,2004344792661408502L,6922719691033397220L,-6115771057843578790L,-882977230851385180L,4445218069992821756L,5905786485590667688L,-8952895028275913749L,6335857422495481096L,-1336747599306330073L,-295017526585807725L,6427842712075527612L,6136969228259728187L,8790718804228268581L,-7649524091336109629L,-5994405249073919640L,4313678309655720149L,1583534994170157977L,5606445082714174951L,6853837681080604556L,-8485637026077231303L,7790525872849806729L,5940658092022763209L,8602473577714766584L,2936249914771413453L,-5521212179187796747L,4711968172455986094L,-4922856425548406499L,130141881968551392L,3536227681426168034L,1538274929948045556L,2319096648797621624L,-390137264770768181L,8029329512101034001L,-7020589058068074770L,3265911137432880136L,8114665243288440240L,1727024161912275448L,7211866768629281013L,-3130723513389854793L,-7216856759928143716L,3533195878158403511L,3984449705890310687L,-8379049565896909567L,-8388101802220698225L,-1001505570555522767L,-2621811112096768870L,603025228237669646L,-4855786637640829169L,-8861801597506211630L,5171117103964917160L,-6016899467464669218L,574486107801798403L,1346751909104125183L,6265319601178024276L,3065092470199993307L,-3544361000120591516L,-6311655751958887780L,5850322626671860616L,-2175699856332693179L,2849507709866937883L,-5020421862032512214L,-4568858551591370457L,-2431265188066595845L,-8732538833975482925L,49029378622487761L,948188484528056399L,685766231005340987L,-6108229294291709748L,-6619503736528295873L,2499319692519687998L,-8241104250166498648L,-6283823462790380478L,-1799922584861092054L,-6240401189323759144L,5497064944286443280L,6723566846653152186L,-7200823809060633542L,-8991399666593498102L,3696845228942259783L,5525150667579715560L,949595271893899961L,4431634865357028469L,-7719973862985677490L,-6034475957088628470L,-4268733492881789978L,6756633516157056278L,-1957554544632307580L,7121101677918762223L,-2926994538817486764L,5070148293018691908L,-3164346027824263021L,-8065527601021753218L,-7393579279100902671L,1578925030408104064L,-5470498100570909442L,-9059484745764947078L,8728828886428453065L,876414647339389056L,-4691346483920214801L,271068101201614328L,-1328948676306083414L,-601927494426833593L,-1580410200329916588L,-4326051892200391110L,5551955200782384943L,214408676534699021L,892732170117421280L,-6779792031755998944L,8533716818059729780L,873315600166044946L,8844237596764485904L,4304845159865160138L,5606488036825769410L,425090181770096226L,-1135909175464444990L,-4725116773226449403L,5897643684611700155L,1650595387261410562L,-7317473568888247260L,-8317376280642525522L,524782793988048123L,-6713202495631135192L,-4939556292506913402L,-5609869695293186861L,-4230589026387944683L,-724065909912518572L,-2110301323783658314L,1029673643630214818L,-5297873999180537788L,-8928073349900829853L,7277641038077141425L,6527157727335254212L,-3946003823558145331L,8063768130289328687L,4522053259152859193L,675627983587702560L,-1137165482193899852L,8414663288495567717L,-8436820189876267996L,7876837133135388570L,}, - {1L,-5169860002514781635L,-2589809952505784534L,8777364680166470481L,-8830656417429304044L,3176782973934494582L,109797415759816827L,1076956885061792565L,7914398690249482831L,8011904680480159185L,8410793115243855507L,6266439534501642392L,-336875557465114730L,4038138302048025623L,-8101148793053570270L,1124933003446523927L,8391412732637477197L,2199881538445059432L,719775327569887587L,-4825086212853447750L,-7314323185577824224L,4891665885256984545L,7598126349271893834L,-3239373303059569532L,-659203789875424936L,7692138112394859210L,-193023354580355438L,1661409395237152970L,-867709405024660660L,-4774852438416084051L,1013518333030173816L,3485843496410831696L,188315317670329959L,-7626348485928744434L,4785373727715537048L,-2557360640145528783L,815573462730278215L,2725495643400585416L,763815832452911292L,-1234416280134845253L,3031628907175299520L,6164952807644926203L,-6906157987463386683L,8750285495619286011L,-2944268397760272112L,-8571087382226582932L,7349937386463951048L,7786267339579184516L,337223540666190292L,1366638621193514276L,5979097440737272663L,-8229072190234731287L,-7464767416008336370L,2196188713781264658L,-6606956754260663431L,8497668204436713713L,7806277383834821447L,591641631205476095L,6045490875774248095L,456224709346991991L,-7218871130131209394L,580163022797824109L,-3693397793970743538L,-1855672627986562453L,1785325366189117080L,-5612555377205332105L,-294341367983285122L,2445160339032774813L,7132278192002140706L,878326058396851309L,3921174184439993950L,5853022697017928950L,-2825405099755624515L,-7030859599219471492L,-8473806211642996024L,-8498195465917087535L,-4182645819142121229L,726866375401350017L,-4123860299531460321L,67135272333132065L,238539200704091067L,9069168069279185101L,-8554967853203633945L,-1798135605252717890L,-359730572749547446L,4493519132539194015L,4958647882027071589L,-911149761898967393L,-5156659928190548061L,1295304005530223213L,-6977343558102121156L,6922621878872799870L,6666583055979266042L,7292171483456095852L,-1969457853973942746L,-6898392144047603629L,5756338153240882170L,6504592230467093280L,169954543499997878L,8244762795686741102L,-7702335274149853320L,170612181012260678L,-1167924627447415726L,6330133554527618692L,-670458599026908667L,-5475429905606927886L,-4407322762187867157L,-8580599370684241560L,3285212811372363965L,7894963086517678484L,8569304869073834915L,-6544807253825008820L,-5996237358893605511L,-3042468804887085356L,2374190430796422836L,3894653610967932827L,3898642019578338045L,-5362019755573200863L,4402246476084717913L,3291977739464152007L,3674469931224113236L,-44278192132845207L,-146130534644405364L,5382065438553845456L,6785308159791913441L,4538149016807450869L,8422045206362267535L,-751406355315423454L,8999771730341663411L,-990169186945997877L,1777800203227879507L,-4856230533325857618L,6591273902673649307L,4756065680746518619L,-8504746896788247085L,4474109455375415963L,7512977545114097664L,-4994667515641620176L,-4624712674055432963L,-7581435093848090518L,-3374583368016299959L,-6772163028506140599L,-4597352927609652442L,7074576231879668500L,8699761606660221174L,-1460827062303528567L,8015141181709918285L,-1169566320418753181L,-4781112204804977330L,1888326456844245676L,8052564071464611668L,8677658026519325509L,8196795344534159240L,-6189127939919551760L,-756836619992549632L,3275904360037766197L,8063439441889441129L,-7331287930982412507L,5909316323417099098L,7555764543220595192L,5975647989155847506L,3542169932787954825L,3572787110578921974L,-4910033269362933281L,4127048709984103372L,-8249546761957136187L,2136513283148217767L,6914147571605817471L,-1401967832836965144L,8407424200159619086L,3198875950909199105L,2570623872214327259L,6598776223519113019L,-8548723600459949403L,1542874467657402904L,5132064706814079464L,-8697292868739094825L,7457266453233910833L,-1093418532865160497L,3247028061820159553L,-1424542897552112257L,5068257691790424406L,5880873780866162489L,-3102632713002543235L,1263997674554416274L,5364397535996490566L,-6980107079961147736L,-3471995143361337385L,6641708940048027257L,1135429108619021836L,5387343206428796059L,-6804247660018484977L,}, - {1L,1073223059898794450L,-2038813369256918412L,5304323081406240818L,3303538589997961255L,-8242543733483560526L,-3361776038394087875L,-7966401800695747134L,3661948208390050674L,6880986284844289330L,2763308461018415133L,1781656665212037754L,6138182394991053453L,-7512225217435664149L,-2696439080506022889L,-2583065046819908147L,-3131915636955022563L,-2889357217172249387L,-5802605454962117101L,-2436895282174351119L,-1766568650463350318L,-377122117525974673L,1776581853777064707L,-308611149542073169L,-540314814780534625L,8467843478952328360L,3468583091456007095L,505744836808219017L,-5428914123150493339L,-7776987036728855764L,-6102268671949303457L,3494341367960380577L,2418782979535889063L,4679473505413000143L,-6441695285033044392L,6265164336385959504L,-7246211974952246812L,-531598530841805554L,7617543382550044362L,7304030873573479981L,-32281324903020730L,5445701030230371763L,252311267739668938L,7731413305529340107L,4792829355971906114L,3012742833337443711L,7376323673068462242L,2937445380659696069L,9159469984575429466L,4180661836353763848L,9102205873245014544L,-9157654341755851144L,-5917184808139238532L,-913012161319772394L,3520965615244733154L,1105108204046932414L,3640346287517683383L,2610854371735641718L,3369140582718399805L,-167503450741461836L,7612537899180910062L,4647612969614095840L,3109561378106990004L,8745335350416839074L,-298291418130746473L,-2193685336892597509L,-3205646479549694138L,-6912700853529572321L,-5285985482282474664L,-8011420405948338685L,-20608671900365787L,2461277845240147045L,-8794182113545320389L,-4143692325726628162L,-5206060059250865124L,-7341828269574673748L,5997074990730119543L,-6983875851493091721L,5190016632970933241L,-1133665158084916157L,-7711757776416462528L,958657918611969015L,2998347888694802671L,-176777484057504605L,5157771292309956459L,-8999461217390585327L,4257577863211723393L,-3385462713578387432L,5581805654425926531L,-6981668768611461067L,6619449109488021267L,8273870493873208839L,6305391702152098821L,-7738026482851978733L,-7424370079506352431L,1130290113791392248L,5736936187682728875L,-1889540322116193194L,6918453404219483036L,-258362754443186269L,1740351069027290592L,2990762037699987674L,2598835903464008375L,-6081928830422087295L,5388584501900900268L,-3101635458397415306L,5560630914118636896L,5540181403154305832L,-5050504706493546867L,2482421493273885212L,8345872426056290435L,-114929197746482490L,-1411535166620560130L,1955447843789378400L,-4415727728018118178L,174849678320512726L,-5578523943478722759L,5785969583518444021L,-2232487152186233036L,3347165569852915762L,8597084251364200641L,-8637378221001354125L,1905787365039574668L,-5764297333239831537L,-6887855556896782846L,-7466419285184801288L,3561228892785125799L,-6025847770670435502L,7880903838892214728L,4831723645980851507L,-8700410925103051535L,5167047152144011193L,-5589950774695842572L,-6975863374495850197L,8636325743490381438L,-5393462740365964783L,758109935525139289L,8449824526047483324L,2882040775719318333L,8722862970638278922L,652288902771973384L,-5889783177719394690L,-3211436433657712007L,1362735929528070085L,8025013999877916656L,8057121196213509424L,-597152196419816458L,-3731606026680532941L,-6814641654656904693L,-2513538531416010165L,-1449817420573805572L,7983703381157839238L,4136435098211692276L,-1331213617861613522L,-289183771021882356L,-3100859045837937046L,536889653442631647L,1933334157013614393L,-3378838522188481907L,59059052034778512L,-9070778615901588520L,-8561634908355121490L,8646082716902511799L,-7190394898230747028L,2223190096772479452L,-625200368095748196L,-7695499964415613072L,-2925720374223602748L,7859320007538329711L,-8590024973885119823L,8447867896928955011L,-8341487853447061366L,1319006032904755853L,5631657808401138749L,2597687022492864406L,7575706244535104411L,-5270921382190007475L,3486972365953290955L,67197056587467249L,-542829327793657434L,-8188837871581890476L,-3908705513843534551L,-8566981112648480966L,-6798624665298914527L,9174760941175519307L,-5792872140589943835L,-2219700069287782459L,-6440926725540882731L,687123600828336407L,6695459205124198333L,5752186679888935902L,3823361293471306013L,}, - }; - private static final long [][] powTable1 = { - {0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,1L,4L,16L,64L,256L,1024L,4096L,16384L,65536L,262144L,1048576L,4194304L,16777216L,67108864L,268435456L,1073741824L,4294967296L,17179869184L,68719476736L,274877906944L,1099511627776L,4398046511104L,17592186044416L,70368744177664L,281474976710656L,1125899906842624L,4503599627370496L,18014398509481984L,72057594037927936L,288230376151711744L,1152921504606846976L,4611686018427387904L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,2L,8L,33L,135L,540L,2160L,8640L,34560L,138240L,552960L,2211840L,8847360L,35389440L,141557760L,566231040L,2264924160L,9059696640L,36238786560L,144955146240L,579820584960L,2319282339840L,9277129359360L,37108517437440L,148434069749760L,593736278999040L,2374945115996160L,9499780463984640L,37999121855938560L,151996487423754240L,607985949695016960L,2431943798780067840L,-8718968878589280256L,2017612633061982208L,8070450532247928832L,-4611686018427387904L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,}, - {0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,1L,16L,256L,4096L,65536L,1048576L,16777216L,268435456L,4294967296L,68719476736L,1099511627776L,17592186044416L,281474976710656L,4503599627370496L,72057594037927936L,1152921504606846976L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,8L,135L,2160L,34560L,552960L,8847360L,141557760L,2264924160L,36238786560L,579820584960L,9277129359360L,148434069749760L,2374945115996160L,37999121855938560L,607985949695016960L,-8718968878589280256L,8070450532247928832L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,4L,64L,1025L,16405L,262480L,4199680L,67194880L,1075118080L,17201889280L,275230228480L,4403683655680L,70458938490880L,1127343015854080L,18037488253665280L,288599812058644480L,4617596992938311680L,94575592174780416L,1513209474796486656L,5764607523034234880L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,2L,33L,540L,8650L,138414L,2214635L,35434160L,566946560L,9071144960L,145138319360L,2322213109760L,37155409756160L,594486556098560L,9511784897576960L,152188558361231360L,2435016933779701760L,2066782793056124928L,-3824963458521104384L,-5859183115209015296L,-1513209474796486656L,-5764607523034234880L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,}, - {0L,0L,0L,0L,1L,65536L,4294967296L,281474976710656L,0L,0L,0L,0L,0L,0L,0L,0L,135L,8847360L,579820584960L,37999121855938560L,0L,0L,0L,0L,0L,0L,0L,0L,16405L,1075118080L,70458938490880L,4617596992938311680L,0L,0L,0L,0L,0L,0L,0L,33L,2214635L,145138319360L,9511784897576960L,-3824963458521104384L,0L,0L,0L,0L,0L,0L,0L,4096L,268435729L,17592203935744L,1152922677132918784L,76842668642009088L,0L,0L,0L,0L,0L,0L,8L,552960L,36238823415L,2374947531325440L,8070608823267622912L,-8072983807038324736L,0L,0L,0L,0L,0L,0L,1025L,67194948L,4403688133701L,288600105530228736L,5783840476780036096L,6072259672578981888L,0L,0L,0L,0L,0L,2L,138414L,9071137783L,594486085783387L,2066751970480947200L,-7784595809881817088L,-8116893903405187072L,0L,0L,0L,0L,0L,256L,16777216L,1099511627777L,72057594037993729L,4311810048L,282578783305728L,72339069014638592L,0L,0L,0L,0L,0L,34560L,2264924160L,148434069749895L,-8718968878580398201L,582094356480L,38148135746273280L,-8680969756733341696L,0L,0L,0L,0L,64L,4199680L,275230228480L,18037488253681749L,1513209475875820821L,70735243837440L,4635704940130467840L,6130806467734798336L,0L,0L,0L,0L,8650L,566946560L,37155409756193L,2435016933781924608L,-1513209329119911445L,9547060033028096L,-1513172181595455488L,2444047222778626048L,0L,0L,0L,16L,1048577L,68719546624L,4503604207554576L,300166943871248L,1224996759836561425L,1157443864920915968L,1229500363472633856L,1157706579210928128L,0L,0L,0L,2160L,141557903L,9277138794248L,607986568019867768L,40522537422618488L,-646134085450172169L,8680969174647242752L,-38147594580393984L,8716435603798884352L,0L,0L,4L,262480L,17201906772L,1127344162226437L,94650720833590549L,4923631783780892757L,4685244537110860101L,6130877201840930816L,4635630379498209280L,1244400872037810176L,0L,0L,540L,35434131L,2322211272589L,152188437960410544L,-5867073703402004022L,-608753751841641693L,5021550739930207323L,2435017087666290688L,-1503124363304501248L,-3144919914788159488L,0L,1L,65536L,4294967296L,}, - {0L,135L,0L,0L,36238823415L,0L,0L,-8718968878580398201L,0L,1048577L,-646134085450172169L,0L,281474976710656L,579829432455L,33L,76842668642009088L,8072983807037771767L,9071137783L,72339069031416064L,-8680821320398633081L,2435016933781924608L,1153203052884328721L,8072983770657683879L,-608753751841642177L,1L,70995809403015L,0L,268435737L,2325224901419503607L,0L,72057596286140673L,-4047941590536714361L,8650L,1828479723647826040L,5198580908436257015L,2322211206545L,281479271743623L,4652851823974482055L,-3824945721178980319L,1229782974218235903L,-8359203940994719823L,-7785153702193098917L,-8790878036300495359L,1551279595255904722L,1157478821306368048L,-1231840126630824042L,-2244067483645952701L,-5867073703402004022L,16404L,135L,2214635L,4403419698516L,36238823415L,594486085783387L,1441151881837827092L,-8718968878580398137L,-1513209329246797650L,5766090787059466581L,-646134068292338525L,4987494515535258582L,351930695303188L,4617597572767748231L,4989366934530869954L,4995636651726742868L,2616027333969501107L,-8680969754468382976L,6148982769688008083L,-3255113792571260030L,8108459549707964399L,6110225865917094366L,2616023978973555122L,4330401300L,9440922232176661L,70995809419410L,1162434420959906814L,-6650882093460728755L,2325229302423405341L,1510550969824680745L,-4696143385879816939L,-3255272293030243662L,299538383934670116L,899585657599261095L,-6421298510395728011L,4987212465024951234L,-8439804607159910222L,4722974330230397517L,2604241862179011578L,2945765058557585494L,-4172586336866215245L,-7908298668497926605L,3292917456527349333L,-1778416807812019587L,-2687845494699988046L,-1568533776661182301L,-7153308993320401295L,-751561123640744348L,135L,135L,594486083601840L,36238823415L,36238823351L,-1512615122307666256L,-8718968878580398201L,-8718968861378493549L,-5859145822004578895L,-646134085451220746L,-5251909112208802653L,5012764771064815280L,282054806696071L,1463670458724844711L,-8184224933876447855L,8149678041610583920L,8167559115579133249L,-8179721325835109289L,-8788221579835704968L,-2069077196422502013L,-4705347465926991951L,6955256496823371726L,-7524108394299359031L,7563110548872886158L,70995809403014L,75399497649272L,-8947147165825350487L,2325224901151067886L,3838472271485441641L,-8942843533514592335L,-4119999182185003507L,4329109129124827895L,-6421336103236948990L,5891272723926220804L,-1804055540449515934L,8460564669008640934L,-3753081440134336504L,-3860138431806531030L,-7856653449343714193L,-7595651990768072831L,-4052283364874674317L,5532806268997719779L,5288704387223848300L,-8744239686539652327L,-8855053725810232034L,6006015969448097578L,1347435800541178025L,2211897868760481646L,36238839779L,72061997459758636L,590093403544079L,-8718964475161218279L,360860506022940844L,-72057449430616578L,-2087283856937846165L,2955844742563665725L,1563985813813261386L,-7320240988429897084L,-6688021649094603968L,123717882122878262L,-370210050093239481L,6069896046897945042L,-8123643723470492874L,3483026182173742943L,-7835963269163963083L,629692079040326967L,-2397767918274165203L,2307919561648830965L,-44914365399010368L,599544380208996432L,-597294467434364901L,-6964430688229133911L,2334920026170350992L,-5605342300067343405L,3551021258077608539L,609035323518161084L,-6721022405297278944L,3504310508963389432L,-7283152471191799613L,-8722198899053206729L,-1250874794737731711L,9074608179003201540L,1810628635239662178L,-6451776899373758723L,-4615694538393549295L,-4362275103790198702L,-3792222432303245256L,-1559692666614209616L,-98431217577796539L,-9029920801466639058L,-7109365235188542407L,-946677770089042793L,-182592247182753593L,-2637452241563314774L,6124864149863968072L,5021550739898464339L,}, - {0L,-675700754464725196L,-7400245184483749183L,2325224865180680192L,4308854149351096230L,4087632387066765743L,-7275283868590567591L,998815193966931967L,-2143796421407463834L,6056625504733376525L,-4045721824789864836L,-858530229944418774L,94575875809256316L,-7495074221927422752L,-3628564631334774117L,-6872602957773652666L,-8837670072557268635L,2150855273413160557L,5842706246122142201L,-8874354114744897075L,-7498620451270880714L,8345255364170114647L,8675725534108615393L,-628718379448202296L,7213058728673621187L,8697600085574001635L,569941992076422209L,2101729217045010600L,-869272563270581351L,6349834165615373008L,-8278423197265695468L,-289667629372155284L,-4996188247313713002L,-4193590892988300734L,-7808747067947116470L,5740222723455656079L,-1004293179227928657L,-7378027571087326870L,1850676172401126584L,4102071215454560899L,7259757191991660866L,-3263750637324313573L,-7101095927535849009L,2960944838505603741L,7960409200978162151L,-1380919195139420544L,-7265787777315546970L,8696134004788876257L,4459615944721376107L,357711267766598467L,-6591463393386029767L,6213350576813261001L,2844246054154448404L,-3029083139417290328L,2245638225067189479L,8617601719125400457L,2128220270181946136L,3470499785866555218L,132066871132521002L,5517882414738609434L,-2003374013673959323L,3739836398962945633L,4448468942318558050L,5616161409774106646L,-1642714353533004129L,3432917397076393183L,-7631234578304800051L,1381553953950798900L,4023962110129311253L,8644710097507238632L,-1197417248055046378L,-9214470001404003712L,1609372195130461718L,-1978500250962778826L,-4911048255582930948L,6141651141653126100L,-2210543824408560838L,-6093993786564968581L,-2331300188278471014L,301965068498387180L,-4793576488484320667L,-5125824936144379883L,-5544211551818536164L,4552272197317892247L,-7837278238339183834L,-8761637332466461638L,147364084060044539L,-6064825681333790105L,-9198755709530655411L,-1778124120876162064L,-1861492150822659393L,4745713929342438769L,6861768606120208380L,5182389685193931296L,-8534340902764341615L,-3590390582013687815L,30073544289745672L,5662918870480130927L,8401074218837039520L,-3162537045663256753L,-3696184205999945570L,-4122514099598642296L,-7789756672013896695L,-287966903401783401L,-6507490048846866302L,-4916032157138151070L,-5141347076922627105L,-5155040494742911856L,7430428299516436592L,7568914190360801521L,8976947262451327251L,-823811253246772689L,3192421721340291099L,-2321904427011346487L,-7001545068850142391L,-8141745164608837714L,-8484695803346689573L,-5018197261793538831L,-4680980064014602375L,-3442898850200611643L,-5222684558521265456L,7664587417491999280L,-1184664264514778096L,-6690427770995712658L,-4105408088494675476L,-4179651232527412888L,4672902529451387521L,-4929725195951149496L,1568605474300434685L,9132692739037808736L,1067330377231330106L,6234823338025250317L,5513535159769997480L,-6296592138893575335L,1857768573899923229L,-7795052510154389180L,-7305898577268848196L,-4018600913292308304L,5464682203804131280L,4913993492957390835L,7057555747515730451L,-4522471330477326797L,4668369156558985260L,4477286195984166923L,7381389311118714077L,-7376279152378820185L,2001470970870984953L,-6267077529255448638L,2308580872094892292L,-3732951464203912308L,6769597213437287237L,7233920586946777352L,2580562194308495651L,-5163189941835227305L,6315713421482690203L,4098234801449939167L,-209812842733548776L,-7894469765614518540L,-2554059219807878625L,1903444257061664607L,9182030862387586589L,-3109633788736425272L,6389430618268296347L,2129494461042385878L,6329472897410366361L,-91499458815143634L,1221682685580272771L,9196639794739742553L,3102002862952173801L,-2224431388243524627L,346567882230063653L,-5437991707734288744L,-2709888611820883348L,-2920666756321254869L,4930390194078211174L,-6753455264900793669L,8186033625824413668L,2517429022687892375L,-591051196767852614L,-4262657608111575498L,-3159880638279040943L,-5917782714799358545L,-2681282764713948442L,-2318918853231809968L,-6811170076728669460L,3266419467001559315L,-515756142318178599L,-3869312023589911625L,1976731212099439882L,-8842932614801981568L,3225246888378129325L,8664993276476894618L,}, - {0L,6888918647020560317L,6616704076946383887L,72307319579008765L,5019028484594594082L,-3189487582568884878L,2134511505384836107L,-8664850887478530773L,4653976163382426028L,-7552953056849816027L,6722895949646321714L,-6956540475216209151L,-5858062716999869069L,-6264590843552634074L,5887677734908074113L,2474629020427595354L,-7967281225152887102L,185220160216387872L,-5760623994813845340L,-2535719245014115912L,5111362823887419820L,8505227612259241925L,9012934128161153438L,-3454844884687058304L,2688606500979393393L,257493182509576689L,3669454563593192799L,-5918660207704940910L,989805058886100772L,-7949845614554438917L,-8650932953258294805L,3719293863967856435L,5524498832277079871L,-8204898049315048076L,7429706311125713887L,-3392350091536387004L,8803967679232678927L,-6709573047928675008L,3993787092655773756L,-3869147372389115171L,-5407630961212543773L,-3635696971192372537L,-4123255486571580111L,7821261793194743720L,-8259701755427194463L,8778804536940933206L,-2390355563131639991L,-6022268794344148517L,-7704290986577360513L,-5411054657730165929L,6563199634835578546L,-6179985290346013130L,-1779710405126312658L,3860946749005281310L,2894361089265489575L,3315776251307050326L,6320628998837644363L,-4720130451255879792L,-7396858832460579381L,4947792566457792928L,-771597949057082277L,-6283874120936860908L,7751617974029105049L,-3171781932687118992L,-4986583824628389869L,7554891199116256466L,440872917012743287L,8832529013462318719L,6930378999847853276L,-6172476313572563251L,6597889588190964693L,-3923014422236362697L,4997044127822541429L,-7107806937807475144L,-6289965583375946716L,-3044570048596622809L,-582961432760897161L,-5961388502855958672L,-7194944488185970118L,-2808201162094710660L,2825505208148432617L,-7328788671423443242L,-981277169914054735L,5488327868523545998L,8289151770336172410L,4907413581236102050L,-5687370805778312995L,59381471987291070L,-6444452561966471140L,8634477550854188789L,6207648744164223412L,-101963300189371393L,7848638498504197321L,3498348962566120926L,-5579914395407433825L,-2545139183283670919L,5130648017855629422L,563110260262788563L,2135475898455702366L,7684314690515735551L,-7002326702731443230L,3880977581557303704L,-8637342854207977051L,8496120004406519552L,8560768772188447329L,2594230810807943255L,4337654442994597095L,-4585888647597749639L,-7892855638664835779L,1565051773613738620L,-1693518853642867805L,5567975317132003788L,2962765293309317965L,-3913616984206243549L,-5558808830930587106L,-8050075131445890472L,-8457438218982837752L,-2386212332821275776L,6035074888470767028L,-7849778513431525815L,3298946049141257047L,7780989528292148686L,7259205837724911376L,4482330118862142166L,-6537500962732474747L,-3022706756077921906L,7148848233164372316L,5077131755656950340L,7912726786975152439L,4848423276587831069L,-3830309290120570642L,4508033649949774926L,6846300513888811901L,6242882741110337747L,4170945278743029343L,-8127216801805486969L,-7852480183891607774L,3990619336327845960L,-5983515027675199463L,-5175175724494917100L,-1281849133123778903L,6285841989812053065L,-6067528458241089448L,7576477052240298304L,-36164364831076984L,-60994174189450074L,-8529533350870615239L,-4817148324041097753L,-4640927619693149134L,1872208642623965689L,5240297214938900007L,1572132602803588846L,-650696111471122406L,-6683156123433455837L,4545617032206292763L,-5495059938487344780L,6556517553578965713L,-2511396774410513113L,-2176872386175367579L,-8143603626268702413L,-8219576026727867109L,5228455090572155705L,-8048532819979278350L,-2942421454182291603L,-7739452100314543781L,5339545143011211455L,431828781909893989L,6504224558731934448L,1325434730767337764L,9044277964768096581L,-2012199912615250454L,2239476923138147060L,5446470907191488828L,-8988608972356041587L,318526050097438911L,4497994325831131702L,2421970446587647365L,8944762431294272394L,-1575644653468915716L,-7480808359693534377L,-8386442038249850993L,-4826695226202864144L,-2040524201209064254L,1185655104167734601L,9208155472300323928L,5181480307949496453L,7213432351073135570L,3512466954668360697L,-4638794086271207228L,-5040741222494255775L,2246055029297786978L,-2407449019420128263L,}, - {0L,4331831946986922092L,5039137575310318944L,6572365103720100214L,-3372926667923484384L,-804959452957560038L,5319341503317224386L,6670307960034794050L,9122331677505366914L,8132210050240438928L,1856212684185378577L,-2418012329048383413L,2221935190602818642L,-686940626615845117L,1911412200771311721L,-8073430757900621106L,3214975954359082910L,-4390346519891573401L,-3501449563817128233L,2931745286610574473L,6196837566508069630L,-7985185842868269260L,-242763400354519042L,-4762972334960522653L,-1128709856992935914L,-3133210263897755440L,-6300878854527293186L,7341789762184517091L,-742546840681255590L,-7168808549419220445L,-4984050358805078354L,5072732112695304142L,2078982868474422173L,-6351627917229293982L,-5889560863851129253L,-6131615849942787808L,6542639951406636963L,8480740463682186660L,183168288556720330L,-336660061516138115L,-1410356938699911649L,926150233093626212L,-2881764498566629282L,-1145487279366622181L,2351884447002867207L,-5662126631020168770L,-2882202962071256822L,6804440515561204260L,-7645812423207814611L,4621144061789925334L,-2353433576646516057L,-664832534192041661L,-554535101160684318L,-2377767015672774851L,2162245627601598447L,7482066041309690120L,8259346317988151315L,-3846765727327599638L,1731326869372517225L,-1980000664251113326L,800694689332165758L,2515205999128895054L,-1997432734072953419L,4672602758053323554L,6952202226827626829L,1161365306867490106L,-8384523961905918605L,-733116767785239559L,5682995397931390212L,-3325241677131986932L,-7594435646578169790L,1216932035765251873L,7076597346109630370L,4335245905675328559L,-8507624828826261297L,-6137869528790051691L,-2990757269081501860L,8207981314338567695L,-211809688264439807L,-3940005235808670096L,1182929724269347747L,4877641380646887291L,-7648008948030491945L,6628446266965226465L,-2970852163554202170L,-4670164336893474473L,-153630879029846201L,-3309814009518565346L,1753932513542224524L,-5251791855420722187L,-6759963098607779538L,-8872083893346595943L,-3120155793324540715L,5978602003840494141L,7512687430188190283L,562835420304739569L,4904579120205325277L,-3683422392650008109L,7042500995660740987L,-1972180833418385981L,6346437281268254654L,-2243185610911458224L,9026737040177775190L,4993647529943791743L,288019624394432352L,-4353118648656339247L,-5420873398923132591L,1549704053713244983L,3614498467424513972L,-9027385653029153084L,1629718615812967730L,-2759637422881662616L,8432531436503595927L,611355542547437884L,-3281181767178975456L,-6653389075112192169L,-6767829238387607677L,-18377277181334064L,3726999606378779346L,8982897182547291075L,-7270818405218871784L,7385860370779663565L,8974928614734018492L,291006976587948877L,5300536609199764342L,-5751424882775853301L,4349796007363489739L,-6969537113022603028L,6155372982161835515L,2778638126408133418L,-5347543214912549170L,-9027306700095574549L,30249368683249826L,7438665593684814940L,2922690888626912628L,-8180978412153428577L,-7237995582212279627L,416623024707852752L,-6898030889740364442L,7422011222211524550L,-1171936184535606480L,-6766055360615975733L,1731128074959168128L,-4607795217355720589L,-3213029979791539367L,-5255952104659057192L,-2314414383739670603L,4396632171704966086L,3006711910774356251L,5778933548260329613L,4157127632653091975L,7318697691457423286L,569409338780015498L,4153168956437659929L,-1756599119278225307L,-3314455936932684387L,342118048129659290L,-7569984731692337361L,7663926015038805676L,-7070277473562255822L,289945662752184113L,7974238619106446240L,738352690694983924L,831937267866542901L,-7662231404878724479L,-6989417225990538386L,4271423021483837384L,-4850149730195086768L,3731768127773306728L,7364897548779496026L,-2756767884644196684L,-1753950093378288022L,7143078809577818863L,4597090775987743317L,7848087705354908100L,1905884943523277834L,-6153674769862497703L,7016308115898147045L,-1899771811690011877L,7221196628836046154L,-4199539233852873704L,-8773468848938902681L,3961256666769655818L,-3407671319284954837L,3336711503507566638L,1628300123613068774L,-6944467362566050167L,5759866442005474216L,-2680310850292804557L,-8904643492625661829L,6625111154478727695L,-8756613211059540532L,}, - }; - private static final long [][] powTable2 = { - {0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,1L,4L,16L,64L,256L,1024L,4096L,16384L,65536L,262144L,1048576L,4194304L,16777216L,67108864L,268435456L,1073741824L,4294967296L,17179869184L,68719476736L,274877906944L,1099511627776L,4398046511104L,17592186044416L,70368744177664L,281474976710656L,1125899906842624L,4503599627370496L,18014398509481984L,72057594037927936L,288230376151711744L,1152921504606846976L,4611686018427387904L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,2L,8L,33L,135L,540L,2160L,8640L,34560L,138240L,552960L,2211840L,8847360L,35389440L,141557760L,566231040L,2264924160L,9059696640L,36238786560L,144955146240L,579820584960L,2319282339840L,9277129359360L,37108517437440L,148434069749760L,593736278999040L,2374945115996160L,9499780463984640L,37999121855938560L,151996487423754240L,607985949695016960L,2431943798780067840L,-8718968878589280256L,2017612633061982208L,8070450532247928832L,-4611686018427387904L,}, - {0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,1L,16L,256L,4096L,65536L,1048576L,16777216L,268435456L,4294967296L,68719476736L,1099511627776L,17592186044416L,281474976710656L,4503599627370496L,72057594037927936L,1152921504606846976L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,8L,135L,2160L,34560L,552960L,8847360L,141557760L,2264924160L,36238786560L,579820584960L,9277129359360L,148434069749760L,2374945115996160L,37999121855938560L,607985949695016960L,-8718968878589280256L,8070450532247928832L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,4L,64L,1025L,16405L,262480L,4199680L,67194880L,1075118080L,17201889280L,275230228480L,4403683655680L,70458938490880L,1127343015854080L,18037488253665280L,288599812058644480L,4617596992938311680L,94575592174780416L,1513209474796486656L,5764607523034234880L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,2L,33L,540L,8650L,138414L,2214635L,35434160L,566946560L,9071144960L,145138319360L,2322213109760L,37155409756160L,594486556098560L,9511784897576960L,152188558361231360L,2435016933779701760L,2066782793056124928L,-3824963458521104384L,-5859183115209015296L,-1513209474796486656L,-5764607523034234880L,}, - {0L,0L,0L,0L,0L,0L,0L,0L,1L,65536L,4294967296L,281474976710656L,0L,0L,0L,0L,0L,0L,0L,0L,135L,8847360L,579820584960L,37999121855938560L,0L,0L,0L,0L,0L,0L,0L,0L,16405L,1075118080L,70458938490880L,4617596992938311680L,0L,0L,0L,0L,0L,0L,0L,33L,2214635L,145138319360L,9511784897576960L,-3824963458521104384L,0L,0L,0L,0L,0L,0L,0L,4096L,268435729L,17592203935744L,1152922677132918784L,76842668642009088L,0L,0L,0L,0L,0L,0L,8L,552960L,36238823415L,2374947531325440L,8070608823267622912L,-8072983807038324736L,0L,0L,0L,0L,0L,0L,1025L,67194948L,4403688133701L,288600105530228736L,5783840476780036096L,6072259672578981888L,0L,0L,0L,0L,0L,2L,138414L,9071137783L,594486085783387L,2066751970480947200L,-7784595809881817088L,-8116893903405187072L,0L,0L,0L,0L,0L,256L,16777216L,1099511627777L,72057594037993729L,4311810048L,282578783305728L,72339069014638592L,0L,0L,0L,0L,0L,34560L,2264924160L,148434069749895L,-8718968878580398201L,582094356480L,38148135746273280L,-8680969756733341696L,0L,0L,0L,0L,64L,4199680L,275230228480L,18037488253681749L,1513209475875820821L,70735243837440L,4635704940130467840L,6130806467734798336L,0L,0L,0L,0L,8650L,566946560L,37155409756193L,2435016933781924608L,-1513209329119911445L,9547060033028096L,-1513172181595455488L,2444047222778626048L,0L,0L,0L,16L,1048577L,68719546624L,4503604207554576L,300166943871248L,1224996759836561425L,1157443864920915968L,1229500363472633856L,1157706579210928128L,0L,0L,0L,2160L,141557903L,9277138794248L,607986568019867768L,40522537422618488L,-646134085450172169L,8680969174647242752L,-38147594580393984L,8716435603798884352L,0L,0L,4L,262480L,17201906772L,1127344162226437L,94650720833590549L,4923631783780892757L,4685244537110860101L,6130877201840930816L,4635630379498209280L,1244400872037810176L,0L,0L,540L,35434131L,2322211272589L,152188437960410544L,-5867073703402004022L,-608753751841641693L,5021550739930207323L,2435017087666290688L,-1503124363304501248L,-3144919914788159488L,}, - {0L,0L,16405L,0L,0L,4403688133701L,0L,0L,1513209475875820821L,0L,141557903L,4685244537110860101L,0L,37999121855938560L,70460013625365L,4096L,-8072983807038324728L,6072259672646177861L,1099511627777L,-8680969754468382976L,6148844231222908181L,300166943871248L,8108459549707964415L,6072264093493673942L,0L,135L,9441497757794325L,0L,36238822398L,-4344883889898761147L,0L,-8718968601253017721L,-4731747198132988651L,1048577L,-132789517139225323L,-1552739068514332347L,281474985492480L,37999701685387285L,-8439804064927760332L,79200023969402880L,-4437309755392L,5541920255199135408L,72340746325590273L,-7908297577503485241L,-6110106313622404075L,8676465578921629935L,-326184747196674646L,-3477858389994040487L,1L,2214508L,16405L,268435729L,594453068185772L,4403688133701L,72057594037993793L,7782220301781673580L,1513209475875828959L,1224996777003865156L,-5568602317731943389L,4685246687521203912L,4617315522256633857L,46947281589357164L,-3824892998506958796L,4995636651659171088L,8116893894401741024L,-2657538287028282471L,6130806742969226560L,27400700751995177L,6195590254004767622L,1157782445580441636L,-3782275202737413550L,-2658220304921737954L,575525634069L,1162363457633372907L,9441497759976190L,6917681753729944802L,-5498814577540363438L,-4345476997192759376L,1551110792602277236L,5891520892378292651L,6144410812500239428L,634601418098493862L,1774375360755843061L,132652009187043017L,4653133841193683532L,-2595690203251959175L,72110664981553453L,-1230337829717287256L,-6188909812282035538L,6456071231484419289L,-2320958359203443879L,1835508870757419369L,2040370669282281878L,6661217468141030217L,-8423640389371565403L,-8499405260925408371L,268435728L,16405L,16405L,72057594306428944L,4403688133701L,4403688142223L,1152939165798699280L,1513209475875820821L,1513211798084813650L,1224996764271055007L,4685244537241932234L,-8363651757808097592L,1190939387166195984L,38069581936595025L,5021584044531862713L,-6992383705976074216L,-2597990945295154084L,-363348139508661757L,-7600368554163986847L,-7582301154678812143L,894948077087235353L,6955255921298015887L,6959836035952832632L,3211452494295328458L,6917685570877522327L,9441497757794450L,10016896989796619L,7027313512938572782L,-4344883925063770117L,2927870116789082016L,8786239407365985943L,4131336578943587486L,-4726948581212862695L,127865309502915844L,6074982671291646492L,-3775267067956559256L,-79200059939802875L,-8744009164630305692L,4615764723498800113L,-8718682424587484521L,-6158288432344557974L,-5261638342178675313L,-9059672762503245484L,5519878846588365914L,-4436464087703865944L,1518927025456563280L,1468085383922929905L,2639105496201891805L,270650237L,4403690315305L,-8718374425263534908L,72652047106048429L,1513803926786430456L,-7346953228811164402L,9007217061455705778L,3243811299122139894L,6753230224894884636L,-5602660768557635367L,-883519440648577041L,-116177230604955516L,-2323053257641285469L,-8482307462680691891L,-5549874877820869559L,958020971772365464L,-4991544269364360344L,6363309982556444943L,7331190440433981494L,5015726139678737532L,-2043388114386413778L,5482647037605624617L,1206745860518513047L,2086309373276999127L,8079745281175912599L,-3273465508891764574L,315336160138416834L,3834475922849262099L,38021128702995733L,3474027448873074912L,-4358775760477723763L,-5618657038833202186L,-1545654340300590546L,-2631227852331219336L,-8776825519658677635L,-2327823662365475282L,5194557473419685442L,-4092526298777937177L,-916312845293823853L,-2363175478922554126L,-4978193684293897722L,-6320440829497657480L,-2670705166203992950L,8762236708630736962L,-5599128477180867553L,5323899568776667617L,-5564129564103000826L,-3382740581917399352L,}, - {0L,2716622788963031847L,40846672993527025L,1513209509967159019L,4621053680045158388L,-2903996173352235569L,-8072983807038316094L,-7575455417369363805L,8071326617522633051L,-7258922398541384564L,8704697640774031947L,-6681570071551204221L,-1562641326068657855L,-883532926705604284L,956268130454475388L,1215539162648774541L,-426414134220978363L,5270683299884762747L,2330181287926686005L,6134726476362434106L,-2325959145524659347L,4329716150192313480L,-8392881078967907522L,-1802165835817182982L,-8100388729951545868L,1867951006267200589L,7919618595933494384L,-8980269885778783131L,4071040395359672573L,-312862961573357955L,-2941873227506952960L,-8115294874401740510L,5303426865933611246L,2958139355704065308L,1463694019776869652L,-8976074711962363925L,5268644657139266566L,6964861625476310538L,-1517608123673286513L,-2915846685277558710L,5550751346972347727L,2112780311210561748L,-1828007150056065159L,6384500303152980510L,-906389597981947895L,4410709334475405688L,-6483486400246371702L,-8147255517704438781L,-6120938892653523797L,3199011783477797964L,-6761726043452623010L,-7047017470580974912L,1462717182584096488L,-7023268205675315115L,-2989303706422286108L,3180460850976781138L,-298416058831618501L,-7266836423948921205L,6663350365655515731L,-8359063233001334572L,9056022989288353575L,7798619345308693609L,-44616847615569961L,3192155203687896874L,1239389723220221729L,-4986248400106757818L,4108171716624422170L,-4173733134437352158L,-8125352421416488169L,-1185374074307245661L,-2966673101544610810L,2704683786991607858L,1515177657563554330L,5601341054180475457L,2983614494542029933L,3582348994995344418L,-7227381997475091214L,375800204207924206L,2993383011336056468L,-8189001996079290037L,682068580983257903L,948844863510518846L,-5027244184536956601L,1827155836971693192L,-1870457681157527590L,1442861833621761616L,-7501553589451368346L,7570278778816122784L,2996106664946480472L,-8781991581739643752L,-1791985321944155905L,-867682135916918265L,-3280503815586869540L,323928290362912952L,-5799577295755596577L,7265376777009662712L,-5900142203173808917L,-1517427944723435699L,8119832848073844820L,-3536200579017813566L,-3797880052796029066L,2953127755774818207L,7848593138406357335L,-3561467074012037304L,-7337175485261886469L,5807093610353856481L,4150266656318619307L,5586315349794142210L,3173004702088493577L,-4041319562043822090L,3864667468337058586L,3273021938862095623L,1830503478934844635L,3749676212788847170L,3555683139611306856L,2307286949526856026L,-6923475262585040711L,-701796416470938392L,-1858770742650766417L,5567697607330176830L,-7615393280240676601L,8367577308384162142L,1289903960876064367L,2964316419676655924L,103719735714153803L,115707662404946645L,7038009716978659739L,6993618381930301556L,-4413073683489083550L,-5009032023647056184L,8984906013653963103L,4426963583202880421L,-6178068367693439722L,3477129417051532148L,-6090672487045910366L,-6135241880902941518L,-1212340631615108657L,-3815125365865109228L,-9071677335252123805L,-1160367325517043426L,2955609817225945308L,-1003634050197601548L,5820534109579904411L,-2426268040301780073L,-8146151533873453013L,606046764860835901L,6365109532573370147L,-6149510524360813181L,8739343454238347465L,-2972886873342710445L,-8078313491105835340L,-8453826761140217942L,2610148900125924178L,4094047797743140623L,1798485114169935380L,4998884408623716905L,8950537777569088369L,1259580490436590913L,-315040158391152316L,4404501065226543846L,8146418735010981422L,-3207553747699863543L,8675392909711600921L,2405040524590938945L,3011427288135051459L,-7505026985532373362L,-717246331947472893L,-1249163693485939994L,-5296945757900320134L,4406943265523691209L,-7262817264707461431L,4641142375242104030L,974365924473300426L,5883429614278840526L,1752533021582360374L,4682777309199078800L,3204063093503561410L,-363155732334907633L,-2346835733169282527L,-8137667428439140060L,-5206973815505988715L,-6974909107915889500L,8764043288183918255L,-4092038371708175209L,3554060350791641111L,8798581772638267674L,683285472572572424L,7214985925390295205L,-2157639133813705666L,-1448249137206045231L,3845284593116750432L,-491254275194118919L,}, - {0L,-9067886894117383031L,-8765631554449913793L,-351960140370164101L,-3809828891435867380L,709347176573105019L,6367995667762707277L,-2306580641000201140L,-3294298272065609853L,4371465194278568200L,2607306921379681548L,-417323118857018121L,-7881922716238547623L,1742624878807396150L,6417633233153038438L,7245011226171800446L,8165326897970180555L,-3243122380933127165L,-6714040292093312106L,5299517670423801760L,1162621650998540887L,-2644879706039864385L,5228558976169295831L,-4391072266260069004L,5007015542307306646L,4682900706152011413L,-2123901141179325738L,-1563119241267841448L,-7901984116490304069L,3479726911851668567L,2328631765004444895L,4163098372279135427L,-1162220268661065413L,7829988552306176969L,3774955113097750561L,-2924095674636243058L,-3804005518905654993L,4738269630527809961L,5850935874683467236L,8655960374699796185L,-9059189580654183421L,4147746414725146890L,24509238664879977L,-7300123086118785535L,4751556328478914134L,1176138900156266839L,-2121425120505405076L,7247247000762229134L,9000592214487314811L,-889874608502765498L,7236795550799772071L,4974622482278556577L,-420560834611630453L,-3768646734241421044L,-6934105751774839201L,2969065130293732380L,1157896836976407312L,-1559291870109505818L,-2713062981234471322L,-7531022569765588290L,885491871452046438L,8154994685434777085L,-6183517998680799133L,-1006560964259624252L,-3294584533985251232L,8399396859432285260L,4941554285858435526L,-6156845871586263088L,-3284695794597124922L,1532126679216399071L,8710324980140137084L,-5829657872686309788L,-8769115779063538072L,6935866645975431778L,3597238061932133376L,2900308539208720779L,-2048705180801093564L,7055281952541030950L,-7002220757486340324L,964568490678066690L,-8767317763140366030L,-7051357021415343791L,-4942724421035409788L,-3480567531822663066L,97030438992350687L,6148848201715609829L,8190673576143502363L,-582873467951437833L,2647318604324937637L,-6741961242409679499L,-3005976745528477871L,6997691635910859134L,-1554393429201478263L,5312146010243409080L,8436439012567294277L,-6630723209210577509L,-8673971494977105192L,3562527997978101964L,3222754741725930251L,-5514361182259644100L,8086871624387515496L,-1467927774684365475L,8787210120862734018L,3868688879557973489L,6456800047903216186L,2070752891678043017L,-2941591783186713651L,-8183443290798012978L,8647945886161088410L,-1841819063379755142L,7860120982846312859L,-8493947801835772681L,-8772774970693045973L,-5241215312398964897L,-2611583395517621586L,-6102100345907364588L,1496816916737236359L,-7037938107874011031L,1848097601417926664L,-3280842067707319343L,9059361377927179923L,3282174138875773780L,-4916481664416226618L,3886169231649272478L,-1162360497370278599L,637220995047853939L,2885978966316747573L,6728781912350490111L,2328479630147269651L,5554304721491051724L,-6390247834560005501L,678119673988273692L,8651416760092589714L,3253782092936323383L,-1172981379019092788L,-2681934234447846106L,2685869215896638688L,3821621354052583845L,-2684383087845706054L,8084097633656028849L,-8363538709557862805L,-4959083379007699006L,-636423994845221856L,-6174337185251636501L,-8181624222422079238L,5775773648593308303L,2958061024555050145L,-5902970918704504061L,-2311021221920430097L,-1163971532460119016L,7608815371737216021L,-2151017459333583787L,-4990542649899559495L,-7513884523432741003L,4393693670759726766L,-6124974036012512535L,4359543309307998296L,-7037830908455507891L,9041027053538546397L,-4965851250845680310L,-2710962042488783523L,-8360351447962823382L,8718758072633673592L,6091137861253238579L,3170648231776465081L,7255519673286422939L,-7053661224901986133L,-915340883967460252L,58498294164417086L,-3484407801438382424L,-5784099705119286635L,4125777477825819372L,-6146926288831583310L,-3273005006573409355L,3494948349508696583L,-5006780570108823652L,1464644271341482461L,8662100360049866867L,-8213718696027725861L,6111700097284965138L,8732551933992222890L,-2625466519519768621L,7604239518435423389L,-7828716348124971154L,-7235290890666697460L,5948056974595294574L,1526856277675902747L,6112243656016507212L,-5496701154568696152L,-3510748376081434273L,-8169496792421316254L,-8879479780209390885L,}, - {0L,3140177619151565L,1460417631189212726L,2353554947493303907L,-8202113219766144441L,-6445610874707668273L,608805251577783707L,5576331011745724676L,-4616645954249110408L,-8150056064724481814L,-4375043884813768089L,61489915732671441L,2417003783109232201L,-5797177228338315992L,2030419241542275643L,3535467551177747619L,8160953148558434627L,3783933582983994877L,-395558155134838237L,-9037492967799507046L,-5583543374553761415L,-3766787778222337249L,83690989555392614L,586532773118624438L,6753062925187026745L,-8948265279136309565L,-6410106965476177336L,4682508874368457020L,-295508894803101770L,8755364544425811426L,-6946865691886399246L,-4998699326132353090L,-4913666944514812110L,6656002279105587104L,-4102330896140732563L,4073773542208959172L,1868016903708504679L,5519576265667760424L,-4364728854253647198L,-4053216048524447777L,6663500710558038858L,6972529717731021777L,-3207571042298769577L,-3888399221174842362L,420006135991670627L,8470075279405824658L,7027685758317034910L,2040544246752732537L,-3800680914792011602L,2040759759708548109L,-9015248103296315503L,652011287933867814L,-7782739132326567829L,-2317801922460293066L,2611886844620986012L,-8984631646102328554L,891896526125902634L,-367951637747449086L,-3497113700860363823L,5236614907167581294L,4114633954038032258L,-7512497826449542169L,3242179150310062402L,5331743182358224881L,7796816641120626796L,-2424392677330210781L,-8144516314316042367L,675811259852555579L,-4634618573840023378L,4925946102011935067L,-4976229192152584784L,-3306578665043743720L,-6377989030567179047L,3293903018441646805L,618512784046332063L,53396408973512940L,-972771490037569515L,-6449609039165015841L,-4713122490770203220L,5807317894024892376L,-2670957669784138572L,3253385083202136062L,4051471174117632380L,-6471306451500783400L,6958488026378472944L,-5240312948719888335L,-8730122111509150856L,-391530967442739522L,5304728157073167586L,-8727565006975506202L,-2051755253763667777L,-3562176666377319713L,7612155015414030601L,1518046426766570808L,-307960163954445386L,-4612626700850755125L,-7636305212757699943L,697133298319656099L,-4630649231468148194L,5297521963269776703L,-9050284098059359704L,-9005170998800333392L,2690681881609407239L,-6345572204046605232L,5811140775354848418L,-7583858705664828398L,883333908996047580L,-3023430280093746546L,1253866782730544252L,-2652541341293732240L,-3271892520967689019L,-3752005443895063020L,4447917552968482513L,-3824236721243846818L,5600139313482945383L,-999779136651389228L,-8469897042294769427L,7796143214715526711L,406420894930862997L,-2962130523947052332L,-1278282830806339692L,-8447450042751963291L,634287000685320862L,-4988625188634368073L,7264114668740343559L,604237143730786090L,1470443674382315935L,7627286917302141493L,6193255306513896806L,-88995703250039083L,5251413380424095294L,-896519829376623449L,-1255840563362049523L,-6375440828517507443L,2331875313404929916L,8954805250915502220L,7208472503953793396L,-4921350084320109520L,8682056056407108854L,-588986527289762379L,9058761110104874970L,5619968217006612529L,3556136729690226244L,2636161296644079035L,-8961930654928536483L,-5855381532408164884L,8378124878485911957L,-2362426267959965117L,2730324786590578227L,-7828512552827125787L,6135910401929572633L,7539770217393522009L,2966065950377957666L,-2096713473244396849L,-7604673598994665387L,-7219768014399086113L,2704497122794833704L,-2967228398298959366L,-6762901644464291495L,-1553630643759993924L,1564603397139288648L,6116811891197961186L,3562368697804772802L,-3199395829836276360L,-1165308188865718640L,-2427793488252231210L,-8760734042314058841L,-7857272506160709120L,3203259669013418168L,-946026787142432929L,4945843407304527756L,-3777254025118911417L,-8496811611764847693L,6997957085954944184L,6393220067418700989L,1296680119038768392L,5852192073241482937L,-4072182146803896176L,-6966297004098237683L,-5487642568473235337L,-1519244559474694756L,3811374754853013692L,-2605325301426890003L,-2885808776371324742L,6661350203815069651L,1327657210385814471L,-3825923588202089762L,-7915987217397706762L,6735184013381996252L,1519213888176055875L,8382345159179417209L,1911513965813618260L,}, - }; - - //The tables above were generated by the code below. The code is no longer needed. - - /* ******************************************************************************************* - - - static long [][] powTable0 = new long [7] []; - static long [][] powTable1 = new long [7] []; - static long [][] powTable2 = new long [7] []; - - public static void genPowTable() { - GF2_192 z = new GF2_192(); - int i; - - powTable0[0] = new long [192]; - powTable1[0] = new long [192]; - powTable2[0] = new long [192]; - i = 0; - for (; i<64; i++) { - z.word[0] = 1L<=7) { - // By Fermat's little theorem, z^{2^{2^k}} = z^{2^{2^k} mod (2^{192}-1)} - // If k>=7, then 2^{2^k} mod (2^{192}-1) = 2^64 when k is even and 2^128 when k is odd (proof below), - // so that's what we compute. - // Note that we have no precomputed table for k=7 (i.e., 2^128), because we don't expect - // this to be needed -- only up to k=6 is used in inversion. - // Here's the proof: let m = 64. 2^{2^k} mod (2^{192}-1) = 2^{mn} mod (2^{3m}-1) for n = 2^{k-6}. - // Let d = n div 3 and r = n mod 3. - // Then 2^{mn} = (2^{3m}-1) (2^{m(n-3}}+2^{m(n-6)}+...+2^{m-nd})+2^{nr} - // So the remainder is 2^{nr}. r is 2 when k is odd and 1 when k is even. - - power2To2ToK (res, z, 6); - if (k%2 == 1) { - power2To2ToK(res, res, 6); - } - } - else { - // powTable0[k][i] contains the result of raising x^i to the power 2^k for i = 0...63 - // powTable0[k][i-64] contains the result of raising x^i to the power 2^k for i = 64...127 - // powTable0[k][i-128] contains the result of raising x^i to the power 2^k for i = 128...191 - // Because raising to the power 2^k is linear over any field of characteristic 2, - // we just need to XOR the values in these tables at indices i where z is 1. - // This selection is done via multiplication by 0 or 1, to avoid having an input-dependent path - // through the code, thus reducing the chance of side-channel attacks. - // - // Note that more efficient tables can be precomputed -- for example, the result of raising - // every one of 16 possible 4-bit nibbles at every one of 32 possible nibble positions. - // But indexing into these tables will be input-dependent, which may make side-channel attacks easier. - - long t0 = 0; - long t1 = 0; - long t2 = 0; - int maxIndex = 0, i = 0; - for (long w : z.word) { - maxIndex += 64; - for (; i < maxIndex; i++) { - long multiplier = (w & 1); - // No "if w&1 == 0" here, to avoid a data-dependent path through the code, - // thus reducing the chance of side channel attacks - t0 ^= powTable0[k][i] * multiplier; - t1 ^= powTable1[k][i] * multiplier; - t2 ^= powTable2[k][i] * multiplier; - w >>>= 1; - } - } - res.word[0] = t0; - res.word[1] = t1; - res.word[2] = t2; - } - } - - - /** - * - * @return bits of this in hexadecimal notation, most significant on the left - */ - public String toString() { - return String.format("%016X", word[2])+String.format("%016X", word[1])+String.format("%016X", word[0]); - } - - -} diff --git a/sigmastate/src/main/java/gf2t/GF2_192_Poly.java b/sigmastate/src/main/java/gf2t/GF2_192_Poly.java deleted file mode 100644 index d3ccd61fc3..0000000000 --- a/sigmastate/src/main/java/gf2t/GF2_192_Poly.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - By Leonid Reyzin - - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to - */ - -package gf2t; - -import java.util.Arrays; - -public class GF2_192_Poly { - private final GF2_192 [] c; // must be not null and of length at least 1 - - private int deg; // must be >=0. actual degree is <= deg. c[deg+1]...c[c.length-1] must be 0 or null - // deg of the 0 polynomial is 0 - - /** - * Constructs the polynomial given the byte array representation of the coefficients. - * Coefficient of degree zero is given separately. Each coefficient should be given - * as a 24-byte representation of a GF2_192 value. Coefficient of degree 1 should - * start at moreCoeffs[0]. - * @param coeff0 byte array representing lowest coefficient (24 bytes) - * @param moreCoeffs byte array with concatenation of byte-converted coefficients - * (24 bytes each) from degree 1 to the highest - */ - public GF2_192_Poly (byte[] coeff0, byte[] moreCoeffs) { - deg = moreCoeffs.length/24; - c = new GF2_192[deg+1]; - c[0] = new GF2_192(coeff0); - for (int i = 1; i<=deg; i++) { - c[i] = new GF2_192(moreCoeffs, (i-1)*24); - } - } - - /** - * Factory constructor -- same as GF2_192_Poly(coeff0, moreCoeffs) - * @param coeff0 byte array representing lowest coefficient (24 bytes) - * @param moreCoeffs byte array with concatenation of byte-converted coefficients - * (24 bytes each) from degree 1 to the highest - * @return new polynomial with the given coefficients - */ - public static GF2_192_Poly fromByteArray(byte[] coeff0, byte[] moreCoeffs) { - return new GF2_192_Poly(coeff0, moreCoeffs); - } - - - /** - * Interpolates the polynomial at given points (and at point 0, if valueAt0!=null). - * If points are not all distinct, or if 0 is in the points array and valueAt0!=null, behavior is undefined. - * valueAt0 is separated only for efficiency reason; the caller can treat 0 like any other point instead - * (i.e., the points array can include 0 if valueAt0==null, but computation will be slightly less efficient). - * If points is null, or values is null, or if lengths of points and values arrays differ, - * or if the arrays are 0 length and valueAt0 is null, returns null. - * - * @param points the set of distinct inputs to the returned polynomial - * (last byte of the field element only; all other bits are assumed to be 0) - * @param values values[i] will be the result evaluating the returned polynomial at points[i]. values[i] must not be null. - * @param valueAt0 if not null, then valueAt0 will be the result of evaluating the returned polynomial at 0 - * @return the unique lowest-degree polynomial p such that for every i, p(points[i]) = values[i] and p(0)=valueAt0 - * (if valueAt0!=null) - */ - public static GF2_192_Poly interpolate (byte[] points, GF2_192 [] values, GF2_192 valueAt0) { - if (points == null || values == null || (values.length == 0 && valueAt0 == null) || values.length!=points.length) return null; - - int resultDegree = values.length-1; - if (valueAt0!=null) { - resultDegree++; - } - - GF2_192_Poly result = new GF2_192_Poly(resultDegree, 0); - GF2_192_Poly vanishingPoly = new GF2_192_Poly(resultDegree, 1); - - for (int i = 0; i < points.length; i++) { - GF2_192 t = result.evaluate(points[i]); - GF2_192 s = vanishingPoly.evaluate(points[i]); - - // need to find r such that currentValue+r*valueOfVanishingPoly = values[i] - GF2_192.add(t, t, values[i]); - GF2_192.invert(s, s); - GF2_192.mul(t, t, s); - - result.addMonicTimesConstantTo(vanishingPoly, t); - - if (i < points.length - 1 || valueAt0!=null) { - vanishingPoly.monicTimesMonomial(points[i]); - } - } - - if (valueAt0!=null) { // the last point is 0 - GF2_192 t = new GF2_192(result.c[0]); // evaluating at 0 is easy - GF2_192 s = new GF2_192(vanishingPoly.c[0]); // evaluating at 0 is easy - - // need to find r such that currentValue+r*valueOfVanishingPoly = valueAt0] - GF2_192.add(t, t, valueAt0); - GF2_192.invert(s, s); - GF2_192.mul(t, t, s); - result.addMonicTimesConstantTo(vanishingPoly, t); - } - return result; - } - - /** - * Evaluates the polynomial at a given point - * @param x the last byte of a field element (all other bits are assumed to be 0) - * @return the value of this polynomial evaluated at the field element - */ - public GF2_192 evaluate (byte x) { - GF2_192 res = new GF2_192(c[deg]); - for (int d = deg-1; d>=0; d--) { - GF2_192.mul(res, res, x); - GF2_192.add(res, res, c[d]); - } - return res; - } - - /** - * adds r*p to this; assumes p is monic, c.length>p.deg, and (p.deg == this.deg+1, or this==0 and p==1) - * @param p the monic polynomial being added to this - * @param r the constant by which p is multiplied before being added - */ - private void addMonicTimesConstantTo (GF2_192_Poly p, GF2_192 r) { - GF2_192 t = new GF2_192(); - for (int i = 0; i 0; i--) { - // c[i] = c[i-1]+r*c[i] - GF2_192.mul(c[i], c[i], r); - GF2_192.add(c[i], c[i], c[i - 1]); - } - GF2_192.mul(c[0], c[0], r); - } - - - /** - * Constructs a constant polynomial - * - * @param maxDeg the maximum degree this polynomial could possibly have (to allocate space) - * @param constantTerm the polynomial is initially created with degree 0 and given constantTerm - */ - private GF2_192_Poly (int maxDeg, int constantTerm) { - c = new GF2_192[maxDeg+1]; - c[0] = new GF2_192(constantTerm); - deg = 0; - } - - /** - * - * @return this represented in usual polynomial notation (but possibly leading 0s), with X as the free variable - */ - public String toString() { - String ret = ""; - if (deg>=2) { - ret+= c[deg].toString() + "*X^"+deg; - int i; - for (i = deg - 1; i >= 2; i--) { - ret += " + " + c[i]+"*X^"+i; - } - ret+= " + "; - } - if (deg>=1) { - ret += c[1] + "*X" + " + "; - } - ret+=c[0]; - return ret; - } - - - /** - * Returns a byte array that contains the concatenation of all the coefficients - * (except possibly the degree-0 coefficient, which is omitted if coeff0 is false). - * Lowest-degree coefficient (0 or 1 depending on coeff0) starts at index 0 of the returned array. - * Each coefficient takes 24 bytes, for a total of degree*24 bytes if coeff0 is false, - * or (degree+1)*24 bytes if coeff0 is true - * @param coeff0 whether to include coeff0 - * @return array of all coefficients (except possibly 0th depending on coeff0) - */ - public byte[] toByteArray(Boolean coeff0) { - int c0; - if (coeff0) c0 = 0; - else c0=1; - byte [] ret = new byte[(deg+1-c0)*24]; - for (int i=c0; i<=deg; i++) { - c[i].toByteArray(ret, (i-c0)*24); - - } - return ret; - } - - /** - * @return The degree-0 coefficient, converted to an array of 24 bytes - */ - public byte[] coeff0Bytes() { - return c[0].toByteArray(); - } - - @Override - public int hashCode() { - return 31 * Arrays.deepHashCode(c) + deg; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj instanceof GF2_192_Poly) { - GF2_192_Poly that = (GF2_192_Poly)obj; - return Arrays.deepEquals(c, that.c) && deg == that.deg; - } - return false; - } -} diff --git a/sigmastate/src/main/scala/org/ergoplatform/ErgoAddress.scala b/sigmastate/src/main/scala/org/ergoplatform/ErgoAddress.scala index 0a9fdfb49c..251df04e1f 100644 --- a/sigmastate/src/main/scala/org/ergoplatform/ErgoAddress.scala +++ b/sigmastate/src/main/scala/org/ergoplatform/ErgoAddress.scala @@ -1,6 +1,8 @@ package org.ergoplatform -import com.google.common.primitives.Ints +import java.util + +import scorex.utils.Ints import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix import scorex.crypto.hash.{Digest32, Blake2b256} import scorex.util.encode.Base58 @@ -123,7 +125,7 @@ object P2PKAddress { /** Constructs [[P2PKAddress]] instance using the public key of the given [[ProveDlog]]. */ def apply(pubkey: ProveDlog)(implicit encoder: ErgoAddressEncoder): P2PKAddress = { - val bs = GroupElementSerializer.toBytes(pubkey.h) + val bs = GroupElementSerializer.toBytes(pubkey.value) new P2PKAddress(pubkey, bs) } } diff --git a/sigmastate/src/main/scala/org/ergoplatform/ErgoBox.scala b/sigmastate/src/main/scala/org/ergoplatform/ErgoBox.scala index e097a6302f..256f643d93 100644 --- a/sigmastate/src/main/scala/org/ergoplatform/ErgoBox.scala +++ b/sigmastate/src/main/scala/org/ergoplatform/ErgoBox.scala @@ -1,6 +1,6 @@ package org.ergoplatform -import com.google.common.primitives.{Ints, Shorts} +import scorex.utils.{Ints, Shorts} import org.ergoplatform.ErgoBox.{NonMandatoryRegisterId, TokenId} import org.ergoplatform.settings.ErgoAlgos import scorex.crypto.authds.ADKey @@ -61,7 +61,7 @@ class ErgoBox( import ErgoBox._ /** Blake2b256 hash of the serialized `bytes`. */ - lazy val id: BoxId = ADKey @@ Blake2b256.hash(bytes) + lazy val id: BoxId = ADKey @@@ Blake2b256.hash(bytes) override def get(identifier: RegisterId): Option[Value[SType]] = { identifier match { diff --git a/sigmastate/src/main/scala/sigmastate/SigSerializer.scala b/sigmastate/src/main/scala/sigmastate/SigSerializer.scala index d7f3875337..92c18463dc 100644 --- a/sigmastate/src/main/scala/sigmastate/SigSerializer.scala +++ b/sigmastate/src/main/scala/sigmastate/SigSerializer.scala @@ -1,8 +1,7 @@ package sigmastate import com.typesafe.scalalogging.LazyLogging -import gf2t.GF2_192_Poly -import org.bouncycastle.util.BigIntegers +import sigmastate.crypto.{BigIntegers, GF2_192_Poly} import scorex.util.encode.Base16 import sigmastate.Values.SigmaBoolean import sigmastate.basics.DLogProtocol.{ProveDlog, SecondDLogProverMessage} @@ -11,7 +10,7 @@ import sigmastate.basics.{ProveDHTuple, SecondDiffieHellmanTupleProverMessage} import sigmastate.interpreter.ErgoTreeEvaluator.{fixedCostOp, perItemCostOp} import sigmastate.interpreter.{CryptoConstants, ErgoTreeEvaluator, NamedDesc, OperationCostInfo} import sigmastate.lang.exceptions.SerializerException -import sigmastate.serialization.{SigmaSerializer} +import sigmastate.serialization.SigmaSerializer import sigmastate.util.safeNewArray import sigmastate.utils.{Helpers, SigmaByteReader, SigmaByteWriter} import debox.cfor diff --git a/sigmastate/src/main/scala/sigmastate/UncheckedTree.scala b/sigmastate/src/main/scala/sigmastate/UncheckedTree.scala index f932f7d77f..365a1f85a7 100644 --- a/sigmastate/src/main/scala/sigmastate/UncheckedTree.scala +++ b/sigmastate/src/main/scala/sigmastate/UncheckedTree.scala @@ -4,8 +4,8 @@ import java.util.Arrays import sigmastate.basics.DLogProtocol.{FirstDLogProverMessage, ProveDlog, SecondDLogProverMessage} import sigmastate.basics.VerifierMessage.Challenge import sigmastate.Values.SigmaBoolean -import gf2t.GF2_192_Poly import sigmastate.basics.{FirstDiffieHellmanTupleProverMessage, ProveDHTuple, SecondDiffieHellmanTupleProverMessage} +import sigmastate.crypto.GF2_192_Poly sealed trait UncheckedTree extends ProofTree diff --git a/sigmastate/src/main/scala/sigmastate/UnprovenTree.scala b/sigmastate/src/main/scala/sigmastate/UnprovenTree.scala index 8d4dc83f6d..6e600b927b 100644 --- a/sigmastate/src/main/scala/sigmastate/UnprovenTree.scala +++ b/sigmastate/src/main/scala/sigmastate/UnprovenTree.scala @@ -1,8 +1,6 @@ package sigmastate import java.math.BigInteger - -import gf2t.GF2_192_Poly import sigmastate.Values.{ErgoTree, SigmaBoolean, SigmaPropConstant} import sigmastate.basics.DLogProtocol.{FirstDLogProverMessage, ProveDlog} import sigmastate.basics.VerifierMessage.Challenge @@ -13,7 +11,7 @@ import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer import sigmastate.serialization.SigmaSerializer import sigmastate.utils.SigmaByteWriter import debox.cfor - +import sigmastate.crypto.GF2_192_Poly import scala.language.existentials object ConjectureType extends Enumeration { diff --git a/sigmastate/src/main/scala/sigmastate/Values.scala b/sigmastate/src/main/scala/sigmastate/Values.scala index 7544107216..0a70c43783 100644 --- a/sigmastate/src/main/scala/sigmastate/Values.scala +++ b/sigmastate/src/main/scala/sigmastate/Values.scala @@ -2,7 +2,7 @@ package sigmastate import java.math.BigInteger import java.util.{Arrays, Objects} -import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{count, everywherebu, strategy} +import sigmastate.kiama.rewriting.Rewriter.{count, everywherebu, strategy} import org.ergoplatform.settings.ErgoAlgos import org.ergoplatform.validation.ValidationException import scalan.{Nullable, RType} diff --git a/sigmastate/src/main/scala/sigmastate/basics/BcDlogGroup.scala b/sigmastate/src/main/scala/sigmastate/basics/BcDlogGroup.scala index 2fb7583a67..f4b9b4c8f3 100644 --- a/sigmastate/src/main/scala/sigmastate/basics/BcDlogGroup.scala +++ b/sigmastate/src/main/scala/sigmastate/basics/BcDlogGroup.scala @@ -1,28 +1,29 @@ package sigmastate.basics import java.math.BigInteger -import org.bouncycastle.asn1.x9.X9ECParameters -import org.bouncycastle.crypto.ec.CustomNamedCurves -import org.bouncycastle.math.ec.custom.sec.SecP256K1Point -import org.bouncycastle.math.ec.ECPoint -import org.bouncycastle.util.BigIntegers +import sigmastate.crypto.BigIntegers import debox.cfor +import sigmastate.crypto.{CryptoContext, CryptoFacade} -import scala.collection.{Seq, mutable} -import scala.util.Try +import scala.collection.mutable -abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) extends DlogGroup[ElemType] { - lazy val curve = x9params.getCurve +/** Base class for EC-based groups where DLOG problem is hard (with bouncycastle-like interface). + * @param ctx context which abstracts basic operations with curve and elements. + */ +abstract class BcDlogGroup(val ctx: CryptoContext) extends DlogGroup { + /** Characteristic of the finite field of the underlying curve. */ + lazy val p: BigInteger = ctx.fieldCharacteristic - //modulus of the field - lazy val p: BigInteger = curve.getField.getCharacteristic - - //order of the group - lazy val q = x9params.getN + /** Order of the group as defined in ASN.1 def for Elliptic-Curve ECParameters structure. + * See X9.62, for further details. + * For reference implementation see `org.bouncycastle.asn1.x9.X9ECParameters.getN`. + */ + lazy val q: BigInteger = ctx.order - //Now that we have p, we can calculate k which is the maximum length in bytes - // of a string to be converted to a Group Element of this group. + /** Now that we have p, we can calculate k which is the maximum length in bytes + * of a string to be converted to a Group Element of this group. + */ lazy val k = calcK(p) /** @@ -31,15 +32,15 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex * It is composed of two main elements. The group element for which the optimized computations * are built for, called the base and a vector of group elements that are the result of * exponentiations of order 1,2,4,8, - */ - private class GroupElementsExponentiations(base: ElemType) //group element for which the optimized computations are built for - /** + * * The constructor creates a map structure in memory. * Then calculates the exponentiations of order 1,2,4,8 for the given base and save them in the map. * - * @param base + * @param base group element for which the optimized computations are built for * @throws IllegalArgumentException - */ { // build new vector of exponentiations + * + */ + private class GroupElementsExponentiations(base: ElemType) { private val exponentiations = new mutable.ListBuffer[ElemType]() @@ -99,22 +100,11 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex private val exponentiationsCache = mutable.Map[ElemType, GroupElementsExponentiations]() - //Create the generator - //Assume that (x,y) are the coordinates of a point that is indeed a generator but check that (x,y) are the coordinates of a point. - override lazy val generator: ElemType = x9params.getG.asInstanceOf[ElemType] - - /** - * Checks if the given x and y represent a valid point on the given curve, - * i.e. if the point (x, y) is a solution of the curves equation. - * - * @param x coefficient of the point - * @param y coefficient of the point - * @return true if the given x and y represented a valid point on the given curve + /** Creates the generator. + * Assume that (x,y) are the coordinates of a point that is indeed a generator but + * check that (x,y) are the coordinates of a point. */ - def checkCurveMembership(x: BigInteger, y: BigInteger): Boolean = { - Try(curve.validatePoint(x, y)).isSuccess - } - + override lazy val generator: ElemType = ctx.generator /** * This function calculates k, the maximum length in bytes of a string to be converted to a Group Element of this group. @@ -132,16 +122,14 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex } /** - * * @return the order of this Dlog group */ - override lazy val order: BigInteger = x9params.getN + override lazy val order: BigInteger = ctx.order /** - * * @return the identity of this Dlog group */ - override lazy val identity: ElemType = curve.getInfinity.asInstanceOf[ElemType] + override lazy val identity: ElemType = ctx.infinity.asInstanceOf[ElemType] /** * Calculates the inverse of the given GroupElement. @@ -151,7 +139,7 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex * @throws IllegalArgumentException **/ override def inverseOf(groupElement: ElemType): ElemType = - groupElement.negate().asInstanceOf[ElemType] + CryptoFacade.negatePoint(groupElement) /** * Raises the base GroupElement to the exponent. The result is another GroupElement. @@ -163,16 +151,12 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex */ override def exponentiate(base: ElemType, exponent: BigInteger): ElemType = { //infinity remains the same after any exponentiate - if (base.isInfinity) return base + if (CryptoFacade.isInfinityPoint(base)) return base //If the exponent is negative, convert it to be the exponent modulus q. val exp = if (exponent.compareTo(BigInteger.ZERO) < 0) exponent.mod(order) else exponent - /* - * BC treats EC as additive group while we treat that as multiplicative group. - * Therefore, exponentiate point is multiply. - */ - base.multiply(exp).asInstanceOf[ElemType] + CryptoFacade.exponentiatePoint(base, exp) } @@ -186,7 +170,7 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex //However, if a specific Dlog Group has a more efficient implementation then is it advised to override this function in that concrete //Dlog group. For example we do so in CryptoPpDlogZpSafePrime. val one = BigInteger.ONE - val qMinusOne = x9params.getN.subtract(one) + val qMinusOne = ctx.order.subtract(one) // choose a random number x in Zq* val randNum = BigIntegers.createRandomInRange(one, qMinusOne, secureRandom) // compute g^x to get a new element @@ -213,22 +197,7 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex * @throws IllegalArgumentException */ override def multiplyGroupElements(groupElement1: ElemType, groupElement2: ElemType): ElemType = - groupElement1.add(groupElement2).asInstanceOf[ElemType] - - - /** - * Computes the product of several exponentiations with distinct bases - * and distinct exponents. - * Instead of computing each part separately, an optimization is used to - * compute it simultaneously. - * - * @param groupElements - * @param exponentiations - * @return the exponentiation result - */ - override def simultaneousMultipleExponentiations(groupElements: Array[ElemType], - exponentiations: Array[BigInteger]): ElemType = - computeLL(groupElements, exponentiations) + CryptoFacade.multiplyPoints(groupElement1, groupElement2) /** * Computes the product of several exponentiations of the same base @@ -273,113 +242,7 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex */ override lazy val maxLengthOfByteArrayForEncoding: Int = k - - /* - * Computes the simultaneousMultiplyExponentiate using a naive algorithm - */ - protected def computeNaive(groupElements: Array[ElemType], exponentiations: Array[BigInteger]): ElemType = - groupElements.zip(exponentiations) - .iterator - .map { case (base, exp) => exponentiate(base, exp) } - .foldLeft(identity) { case (r, elem) => multiplyGroupElements(elem, r) } - - - /* - * Compute the simultaneousMultiplyExponentiate by LL algorithm. - * The code is taken from the pseudo code of LL algorithm in http://dasan.sejong.ac.kr/~chlim/pub/multi_exp.ps. - */ - protected def computeLL(groupElements: Array[ElemType], exponentiations: Array[BigInteger]): ElemType = { - val n = groupElements.length - //get the biggest exponent - val bigExp = exponentiations.max - val t = bigExp.bitLength //num bits of the biggest exponent. - val w = getLLW(t) //window size, choose it according to the value of t - - //h = n/w - val h = if ((n % w) == 0) n / w else (n / w) + 1 - - //create pre computation table - val preComp = createLLPreCompTable(groupElements, w, h) - - //holds the computation result - var result: ElemType = computeLoop(exponentiations, w, h, preComp, identity, t - 1) - //computes the first loop of the algorithm. This loop returns in the next part of the algorithm with one single tiny change. - - //computes the third part of the algorithm - (t - 2).to(0, -1).foreach { j => - //Y = Y^2 - result = exponentiate(result, new BigInteger("2")) - //computes the inner loop - result = computeLoop(exponentiations, w, h, preComp, result, j) - } - result - } - - /* - * Computes the loop the repeats in the algorithm. - * for k=0 to h-1 - * e=0 - * for i=kw to kw+w-1 - * if the bitIndex bit in ci is set: - * calculate e += 2^(i-kw) - * result = result *preComp[k][e] - * - */ - private def computeLoop(exponentiations: Array[BigInteger], w: Int, h: Int, preComp: Seq[Seq[ElemType]], result: ElemType, bitIndex: Int) = { - var res = result - cfor(0)(_ < h, _ + 1) { k => - var e = 0 - cfor(k * w)(_ < (k * w + w), _ + 1) { i => - if (i < exponentiations.length) { //if the bit is set, change the e value - if (exponentiations(i).testBit(bitIndex)) { - val twoPow = Math.pow(2, i - k * w).toInt - e += twoPow - } - } - } - res = multiplyGroupElements(res, preComp(k)(e)) - } - res - } - - /* - * Creates the preComputation table. - */ - private def createLLPreCompTable(groupElements: Array[ElemType], w: Int, h: Int) = { - val twoPowW = Math.pow(2, w).toInt - //create the pre-computation table of size h*(2^(w)) - val preComp: Seq[mutable.Seq[ElemType]] = Seq.fill(h)(mutable.Seq.fill(twoPowW)(identity)) - - cfor(0)(_ < h, _ + 1) { k => - cfor(0)(_ < twoPowW, _ + 1) { e => - cfor(0)(_ < w, _ + 1) { i => - val baseIndex = k * w + i - if (baseIndex < groupElements.length) { - val base = groupElements(baseIndex) - //if bit i in e is set, change preComp[k][e] - if ((e & (1 << i)) != 0) { //bit i is set - preComp(k)(e) = multiplyGroupElements(preComp(k)(e), base) - } - } - } - } - } - preComp - } - - /* - * returns the w value according to the given t - */ - private def getLLW(t: Int): Int = { - if (t <= 10) 2 - else if (t <= 24) 3 - else if (t <= 60) 4 - else if (t <= 144) 5 - else if (t <= 342) 6 - else if (t <= 797) 7 - else if (t <= 1828) 8 - else 9 - } } -object SecP256K1 extends BcDlogGroup[SecP256K1Point](CustomNamedCurves.getByName("secp256k1")) \ No newline at end of file +/** Implementation of [[BcDlogGroup]] using SecP256K1 curve. */ +object SecP256K1Group extends BcDlogGroup(CryptoFacade.createCryptoContext()) \ No newline at end of file diff --git a/sigmastate/src/main/scala/sigmastate/basics/DLogProtocol.scala b/sigmastate/src/main/scala/sigmastate/basics/DLogProtocol.scala index 75db9c69d2..38cfe1d8cb 100644 --- a/sigmastate/src/main/scala/sigmastate/basics/DLogProtocol.scala +++ b/sigmastate/src/main/scala/sigmastate/basics/DLogProtocol.scala @@ -2,7 +2,7 @@ package sigmastate.basics import java.math.BigInteger -import org.bouncycastle.util.BigIntegers +import sigmastate.crypto.BigIntegers import sigmastate.Values._ import Value.PropositionCode import scorex.util.encode.Base16 @@ -27,8 +27,8 @@ object DLogProtocol { extends SigmaProofOfKnowledgeLeaf[DLogSigmaProtocol, DLogProverInput] { override def size: Int = 1 override val opCode: OpCode = OpCodes.ProveDlogCode - lazy val h: EcPointType = value - lazy val pkBytes: Array[Byte] = GroupElementSerializer.toBytes(h) + /** Serialized bytes of the elliptic curve point (using GroupElementSerializer). */ + lazy val pkBytes: Array[Byte] = GroupElementSerializer.toBytes(value) } object ProveDlog { @@ -102,6 +102,7 @@ object DLogProtocol { SecondDLogProverMessage(z) } + /** Simulation of sigma protocol. */ def simulate(publicInput: ProveDlog, challenge: Challenge): (FirstDLogProverMessage, SecondDLogProverMessage) = { val qMinusOne = dlogGroup.order.subtract(BigInteger.ONE) @@ -111,7 +112,7 @@ object DLogProtocol { //COMPUTE a = g^z*h^(-e) (where -e here means -e mod q) val e: BigInteger = new BigInteger(1, challenge) val minusE = dlogGroup.order.subtract(e) - val hToE = dlogGroup.exponentiate(publicInput.h, minusE) + val hToE = dlogGroup.exponentiate(publicInput.value, minusE) val gToZ = dlogGroup.exponentiate(dlogGroup.generator, z) val a = dlogGroup.multiplyGroupElements(gToZ, hToE) FirstDLogProverMessage(a) -> SecondDLogProverMessage(z) @@ -133,7 +134,7 @@ object DLogProtocol { challenge: Challenge, secondMessage: SecondDLogProverMessage): EcPointType = { val g = dlogGroup.generator - val h = proposition.h + val h = proposition.value dlogGroup.multiplyGroupElements( dlogGroup.exponentiate(g, secondMessage.z.underlying()), diff --git a/sigmastate/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala b/sigmastate/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala index 5316bc70c9..9122cc78cd 100644 --- a/sigmastate/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala +++ b/sigmastate/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala @@ -2,7 +2,7 @@ package sigmastate.basics import java.math.BigInteger -import org.bouncycastle.util.BigIntegers +import sigmastate.crypto.BigIntegers import sigmastate.Values.Value.PropositionCode import sigmastate._ import sigmastate.basics.VerifierMessage.Challenge diff --git a/sigmastate/src/main/scala/sigmastate/basics/DlogGroup.scala b/sigmastate/src/main/scala/sigmastate/basics/DlogGroup.scala index 8df0f87e00..f7df1c8e3c 100644 --- a/sigmastate/src/main/scala/sigmastate/basics/DlogGroup.scala +++ b/sigmastate/src/main/scala/sigmastate/basics/DlogGroup.scala @@ -2,7 +2,7 @@ package sigmastate.basics import java.math.BigInteger import java.security.SecureRandom -import org.bouncycastle.math.ec.ECPoint +import sigmastate.crypto.{CryptoFacade, Ecp} /** @@ -19,7 +19,9 @@ import org.bouncycastle.math.ec.ECPoint * * @tparam ElemType is concrete type */ -trait DlogGroup[ElemType <: ECPoint] { +trait DlogGroup { + /** The type of the elements of this Dlog group */ + type ElemType = Ecp val secureRandom = new SecureRandom() @@ -95,23 +97,12 @@ trait DlogGroup[ElemType <: ECPoint] { // if the given element is the identity, get a new random element while ( { - randGen.isInfinity + CryptoFacade.isInfinityPoint(randGen) }) randGen = createRandomElement() randGen } - /** - * Computes the product of several exponentiations with distinct bases - * and distinct exponents. - * Instead of computing each part separately, an optimization is used to - * compute it simultaneously. - * @param groupElements - * @param exponentiations - * @return the exponentiation result - */ - def simultaneousMultipleExponentiations(groupElements: Array[ElemType], exponentiations: Array[BigInteger]): ElemType - /** * Computes the product of several exponentiations of the same base * and distinct exponents. diff --git a/sigmastate/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala b/sigmastate/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala index 199cdd1bf8..3327d94ebf 100644 --- a/sigmastate/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala +++ b/sigmastate/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala @@ -1,15 +1,7 @@ package sigmastate.basics -import java.security.SecureRandom - -import sigmastate.basics.VerifierMessage.Challenge -import sigmastate.interpreter.CryptoConstants -import sigmastate.{SigmaProofOfKnowledgeLeaf, UncheckedTree} import supertagged.TaggedType -import scala.concurrent.Future - - /* Abstracting Sigma protocols Functionality to get: @@ -59,93 +51,10 @@ trait SigmaProtocol[SP <: SigmaProtocol[SP]] { trait SigmaProtocolCommonInput[SP <: SigmaProtocol[SP]] { - val soundness: Int = CryptoConstants.soundnessBits } trait SigmaProtocolPrivateInput[SP <: SigmaProtocol[SP], CI <: SigmaProtocolCommonInput[SP]] { def publicImage: CI } -/** - * common interface for both Prover and Verifier - */ -trait Party[SP <: SigmaProtocol[SP], CI <: SigmaProtocolCommonInput[SP]] { - val publicInput: CI -} - -//implement it as a FSM-DSL waitfor - then - action - then - waitfor - etc -trait InteractiveParty - -trait Prover[SP <: SigmaProtocol[SP], -CI <: SigmaProtocolCommonInput[SP], -PI <: SigmaProtocolPrivateInput[SP, CI]] extends Party[SP, CI] { - val privateInputOpt: Option[PI] -} - - -trait InteractiveProver[SP <: SigmaProtocol[SP], CI <: SigmaProtocolCommonInput[SP], PI <: SigmaProtocolPrivateInput[SP, CI]] - extends Prover[SP, CI, PI] with InteractiveParty { - - def firstMessage: SP#A - def secondMessage(challenge: Challenge): SP#Z - - def simulate(challenge: Challenge): (SP#A, SP#Z) -} - -trait SimulatingProver[SP <: SigmaProtocol[SP], CI <: SigmaProtocolCommonInput[SP]] { - val challenge: Challenge -} - - -trait ZeroKnowledgeProofOfKnowledge[SP <: SigmaProtocol[SP]] - -trait NonInteractiveProver[SP <: SigmaProtocol[SP], - PI <: SigmaProtocolPrivateInput[SP, CI], - CI <: SigmaProofOfKnowledgeLeaf[SP, PI], - P <: UncheckedTree] - extends Prover[SP, CI, PI] { - - def prove(challenge: Array[Byte]): P -} - -trait Verifier[SP <: SigmaProtocol[SP], CI <: SigmaProtocolCommonInput[SP]] extends Party[SP, CI] { - type P <: Prover[SP, CI, _] - type ST <: SigmaProtocolTranscript[SP, CI] - - lazy val challenge = Challenge({ - val ch = new Array[Byte](publicInput.soundness / 8) - new SecureRandom().nextBytes(ch) //modifies ch - ch - }) - - val publicInput: CI - - def prover: P - - def transcript: Future[Option[ST]] -} - -/** - * Sigma Protocol transcript enough for verification - * - * @tparam SP - * @tparam CI - */ -trait SigmaProtocolTranscript[SP <: SigmaProtocol[SP], CI <: SigmaProtocolCommonInput[SP]] { - - /** Common input known to both prover and verifier. */ - val x: CI - - /** First prover message */ - val a: SP#A - - /** Challenge created by verifier and sent to prover */ - val e: Challenge - - /** Second prover message - response to the challenge */ - val z: SP#Z - - /** Returns true if the verifier has accepted the prover's reponse to the challenge. */ - def accepted: Boolean -} diff --git a/sigmastate/src/main/scala/sigmastate/crypto/BigIntegers.scala b/sigmastate/src/main/scala/sigmastate/crypto/BigIntegers.scala new file mode 100644 index 0000000000..0e55f12532 --- /dev/null +++ b/sigmastate/src/main/scala/sigmastate/crypto/BigIntegers.scala @@ -0,0 +1,104 @@ +package sigmastate.crypto + +import java.math.BigInteger +import java.security.SecureRandom + +/** Re-implementation in Scala of select set of utility methods from + * org.bouncycastle.util.BigIntegers. + */ +object BigIntegers { + + /** The value 0 as a BigInteger. */ + val ZERO: BigInteger = BigInteger.valueOf(0) + + private val MAX_ITERATIONS = 1000 + + /** Create the given number of random bits. + * @param bitLength the number of random bits to create. + * @param random a source of randomness. + * @return a byte array containing random bits. + */ + @throws[IllegalArgumentException] + def createRandom(bitLength: Int, random: SecureRandom): Array[Byte] = { + if (bitLength < 1) throw new IllegalArgumentException("bitLength must be at least 1") + val nBytes = (bitLength + 7) / 8 + val rv = new Array[Byte](nBytes) + random.nextBytes(rv) + + // strip off any excess bits in the MSB + val xBits = 8 * nBytes - bitLength + rv(0) = (rv(0) & 255 >>> xBits).toByte + rv + } + + /** + * Return a positive BigInteger in the range of 0 to 2**bitLength - 1. + * + * @param bitLength maximum bit length for the generated BigInteger. + * @param random a source of randomness. + * @return a positive BigInteger + */ + def createRandomBigInteger( + bitLength: Int, + random: SecureRandom): BigInteger = { + new BigInteger(1, createRandom(bitLength, random)) + } + + /** + * Return a random BigInteger not less than 'min' and not greater than 'max' + * + * @param min the least value that may be generated + * @param max the greatest value that may be generated + * @param random the source of randomness + * @return a random BigInteger value in the range [min,max] + */ + def createRandomInRange( + min: BigInteger, + max: BigInteger, + random: SecureRandom): BigInteger = { + val cmp = min.compareTo(max) + if (cmp >= 0) { + if (cmp > 0) throw new IllegalArgumentException("'min' may not be greater than 'max'") + return min + } + + if (min.bitLength > max.bitLength / 2) + return createRandomInRange(ZERO, max.subtract(min), random).add(min) + + for ( i <- 0 until MAX_ITERATIONS ) { + val x = createRandomBigInteger(max.bitLength, random) + if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) return x + } + // fall back to a faster (restricted) method + createRandomBigInteger(max.subtract(min).bitLength - 1, random).add(min) + } + + /** + * Return the passed in value as an unsigned byte array of the specified length, padded with + * leading zeros as necessary.. + * + * @param length the fixed length of the result + * @param value the value to be converted. + * @return a byte array padded to a fixed length with leading zeros. + */ + def asUnsignedByteArray(length: Int, value: BigInteger): Array[Byte] = { + val bytes = value.toByteArray + if (bytes.length == length) return bytes + val start = if (bytes(0) == 0) 1 else 0 + + val count = bytes.length - start + if (count > length) + throw new IllegalArgumentException("standard length exceeded for value") + + val tmp = new Array[Byte](length) + System.arraycopy(bytes, start, tmp, tmp.length - count, count) + tmp + } + + /** Converts a byte array to a BigInteger, treating the array as bits of the unsigned + * integer. + * @param buf the byte array to convert + * @return the resulting positive BigInteger + */ + def fromUnsignedByteArray(buf: Array[Byte]) = new BigInteger(1, buf) +} diff --git a/sigmastate/src/main/scala/sigmastate/crypto/CryptoContext.scala b/sigmastate/src/main/scala/sigmastate/crypto/CryptoContext.scala new file mode 100644 index 0000000000..b5aceec849 --- /dev/null +++ b/sigmastate/src/main/scala/sigmastate/crypto/CryptoContext.scala @@ -0,0 +1,30 @@ +package sigmastate.crypto + +import java.math.BigInteger + +/** A context for cryptographic operations. */ +abstract class CryptoContext { + /** The characteristics of the underlying finite field. */ + def fieldCharacteristic: BigInteger + + /** The order of the underlying group. */ + def order: BigInteger + + /** Validates a point. + * @param x the x-coordinate of the point + * @param y the y-coordinate of the point + * @return the point if it is valid + * @throws IllegalArgumentException if the coordinates do not represent a valid point + */ + def validatePoint(x: BigInteger, y: BigInteger): Ecp + + /** The point at infinity. */ + def infinity(): Ecp + + /** Decodes a point from its byte representation. */ + def decodePoint(encoded: Array[Byte]): Ecp + + /** The generator of the underlying group. */ + def generator: Ecp +} + diff --git a/sigmastate/src/main/scala/sigmastate/crypto/CryptoContextJvm.scala b/sigmastate/src/main/scala/sigmastate/crypto/CryptoContextJvm.scala new file mode 100644 index 0000000000..6a3420242f --- /dev/null +++ b/sigmastate/src/main/scala/sigmastate/crypto/CryptoContextJvm.scala @@ -0,0 +1,30 @@ +package sigmastate.crypto + +import org.bouncycastle.asn1.x9.X9ECParameters + +import java.math.BigInteger + +/** JVM implementation of context for cryptographic operations using Bouncycastle. */ +class CryptoContextJvm(x9params: X9ECParameters) extends CryptoContext { + private lazy val curve = x9params.getCurve + + override def fieldCharacteristic: BigInteger = curve.getField.getCharacteristic + + override def order: BigInteger = x9params.getN + + override def generator: Ecp = { + Platform.Ecp(x9params.getG) + } + + override def validatePoint(x: BigInteger, y: BigInteger): Ecp = { + Platform.Ecp(curve.validatePoint(x, y)) + } + + override def infinity(): Ecp = { + Platform.Ecp(curve.getInfinity) + } + + override def decodePoint(encoded: Array[Byte]): Ecp = { + Platform.Ecp(curve.decodePoint(encoded)) + } +} diff --git a/sigmastate/src/main/scala/sigmastate/crypto/CryptoFacade.scala b/sigmastate/src/main/scala/sigmastate/crypto/CryptoFacade.scala new file mode 100644 index 0000000000..54ec07940c --- /dev/null +++ b/sigmastate/src/main/scala/sigmastate/crypto/CryptoFacade.scala @@ -0,0 +1,86 @@ +package sigmastate.crypto + +import java.math.BigInteger + +/** A facade for cryptographic operations. The concrete implementation is delegated to the + * Platform object, which is resolved by the compiler to either JVM or JS implementation. + * Cross-platform code should use this facade instead of the Platform object directly. + */ +object CryptoFacade { + /** Create a new context for cryptographic operations. */ + def createCryptoContext(): CryptoContext = Platform.createContext() + + /** * Normalization ensures that any projective coordinate is 1, and therefore that the x, y + * coordinates reflect those of the equivalent point in an affine coordinate system. + * + * @return a new ECPoint instance representing the same point, but with normalized coordinates + */ + def normalizePoint(p: Ecp): Ecp = Platform.normalizePoint(p) + + /** Negate a point. */ + def negatePoint(p: Ecp): Ecp = Platform.negatePoint(p) + + /** Check if a point is infinity. */ + def isInfinityPoint(p: Ecp): Boolean = Platform.isInfinityPoint(p) + + /** Exponentiate a point. + * + * @param p point to exponentiate + * @param n exponent + * @return p to the power of n (`p^n`) + */ + def exponentiatePoint(p: Ecp, n: BigInteger): Ecp = Platform.exponentiatePoint(p, n) + + /** Multiply two points. + * + * @param p1 first point + * @param p2 second point + * @return group multiplication (p1 * p2) + */ + def multiplyPoints(p1: Ecp, p2: Ecp): Ecp = Platform.multiplyPoints(p1, p2) + + /** Return simplified string representation of the point (used only for debugging) */ + def showPoint(p: Ecp): String = Platform.showPoint(p) + + /** Returns the sign of the field element. */ + def signOf(p: ECFieldElem): Boolean = Platform.signOf(p) + + /** Returns byte representation of the given field element. */ + def encodeFieldElem(p: ECFieldElem): Array[Byte] = Platform.encodeFieldElem(p) + + /** Returns the x-coordinate. + * + * Caution: depending on the curve's coordinate system, this may not be the same value as in an + * affine coordinate system; use normalize() to get a point where the coordinates have their + * affine values, or use getAffineXCoord() if you expect the point to already have been + * normalized. + * + * @return the x-coordinate of this point + */ + def getXCoord(p: Ecp): ECFieldElem = Platform.getXCoord(p) + + /** Returns the y-coordinate. + * + * Caution: depending on the curve's coordinate system, this may not be the same value as in an + * affine coordinate system; use normalize() to get a point where the coordinates have their + * affine values, or use getAffineYCoord() if you expect the point to already have been + * normalized. + * + * @return the y-coordinate of this point + */ + def getYCoord(p: Ecp): ECFieldElem = Platform.getYCoord(p) + + /** Returns the affine x-coordinate after checking that this point is normalized. + * + * @return The affine x-coordinate of this point + * @throws IllegalStateException if the point is not normalized + */ + def getAffineXCoord(p: Ecp): ECFieldElem = Platform.getAffineXCoord(p) + + /** Returns the affine y-coordinate after checking that this point is normalized + * + * @return The affine y-coordinate of this point + * @throws IllegalStateException if the point is not normalized + */ + def getAffineYCoord(p: Ecp): ECFieldElem = Platform.getAffineYCoord(p) +} diff --git a/sigmastate/src/main/scala/sigmastate/crypto/GF2_192.scala b/sigmastate/src/main/scala/sigmastate/crypto/GF2_192.scala new file mode 100644 index 0000000000..36e8343e2b --- /dev/null +++ b/sigmastate/src/main/scala/sigmastate/crypto/GF2_192.scala @@ -0,0 +1,577 @@ +/* + By Leonid Reyzin + + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to + */ +package sigmastate.crypto + +import debox.cfor + +import java.util + +class GF2_192 extends AnyRef { + private[crypto] val word: Array[Long] = new Array[Long](3) + + /** + * returns a copy of the field element + * + * @param that element to copy + */ + def this(that: GF2_192) { + this() + this.word(0) = that.word(0) + this.word(1) = that.word(1) + this.word(2) = that.word(2) + } + + /** + * returns the field element whose 32 least significant bits are bits of that and rest are 0 + * + * @param that lower 32 bits + */ + def this(that: Int) { + this() + this.word(0) = that.toLong & 0xFFFFFFFFL + } + + /** + * returns the field element whose bits are given by the long array + * + * @param that must be length 3 + */ + def this(that: Array[Long]) { + this() + require(that.length == 3) + this.word(0) = that(0) + this.word(1) = that(1) + this.word(2) = that(2) + } + + /** + * returns the field element whose bits are given by the byte array that[pos]...that[pos+23] + * + * @param that must be length at least pos+24 + */ + def this(that: Array[Byte], pos: Int) { + this() + assert(that.length >= pos + 24) + cfor(0)(_ < 8, _ + 1) { i => + word(0) |= (that(i + pos).toLong & 0xFF) << (i << 3) + } + cfor(0)(_ < 8, _ + 1) { i => + word(1) |= (that(i + pos + 8).toLong & 0xFF) << (i << 3) + } + cfor(0)(_ < 8, _ + 1) { i => + word(2) |= (that(i + pos + 16).toLong & 0xFF) << (i << 3) + } + } + + /** + * returns the field element whose bits are given by the byte array that + * + * @param that must be length 24 + */ + def this(that: Array[Byte]) { + this(that, 0) + } + + + /** + * + * @param obj the field element with which to compare + * @return true if and only if this and that represent the same field element + */ + override def equals(obj: Any): Boolean = { + if (this eq obj.asInstanceOf[AnyRef]) return true // equal references + obj match { + case that: GF2_192 => + this.word(0) == that.word(0) && this.word(1) == that.word(1) && this.word(2) == that.word(2) + case _ => false + } + } + + override def hashCode = util.Arrays.hashCode(word) + + /** + * + * @return long array of length 3 containing the three words of the field element + */ + def toLongArray: Array[Long] = { + val ret = new Array[Long](3) + ret(0) = word(0) + ret(1) = word(1) + ret(2) = word(2) + ret + } + + /** + * + * @return byte array of length 24 containing the two words of the field element + */ + def toByteArray: Array[Byte] = { + val ret = new Array[Byte](24) + toByteArray(ret, 0) + ret + } + + /** + * @param ret bytes of the field element will go into ret[pos]...ret[pos+23] + */ + def toByteArray(ret: Array[Byte], pos: Int): Unit = { + assert(ret.length >= pos + 24) + cfor (0)(_ < 3, _ + 1) { j => + cfor(0)(_ < 8, _ + 1) { i => + ret(pos + i + 8 * j) = ((word(j) >> (i << 3)) & 0xFF).toByte + } + } + } + + /** + * + * @return true if this == 0, false otherwise + */ + def isZero: Boolean = word(0) == 0L && word(1) == 0L && word(2) == 0L + + /** + * + * @return true if this == 1, false otherwise + */ + def isOne: Boolean = word(0) == 1L && word(1) == 0L && word(2) == 0L + + //The tables above were generated by the code below. The code is no longer needed. + /* ******************************************************************************************* + + + static long [][] powTable0 = new long [7] []; + static long [][] powTable1 = new long [7] []; + static long [][] powTable2 = new long [7] []; + + public static void genPowTable() { + GF2_192 z = new GF2_192(); + int i; + + powTable0[0] = new long [192]; + powTable1[0] = new long [192]; + powTable2[0] = new long [192]; + i = 0; + for (; i<64; i++) { + z.word[0] = 1L<= 0, _ - 1) { i => + w3 = w2 >>> 63 + w2 = (w2 << 1) | (w1 >>> 63) + w1 = (w1 << 1) | (w0 >>> 63) + w0 <<= 1 + val t: Long = (b >>> i) & 1 + w2 ^= a.word(2) * t + w1 ^= a.word(1) * t + w0 ^= (a.word(0) * t) ^ (irredPentanomial * w3) // mod reduce + } + res.word(0) = w0 + res.word(1) = w1 + res.word(2) = w2 + } + + /** + * Computes a plus b and puts the result into res. + * + * @param res output; must be not null; may be equal to a and/or b + * @param a multiplicand; may be equal to res, in which case will get overwritten + * @param b multiplier; may be equal to res, in which case will get overwritten + */ + def add(res: GF2_192, a: GF2_192, b: GF2_192): Unit = { + res.word(0) = a.word(0) ^ b.word(0) + res.word(1) = a.word(1) ^ b.word(1) + res.word(2) = a.word(2) ^ b.word(2) + } + + /** + * Computes a times b and puts the result into res. + * Uses table lookups, which may not preserve + * the secrecy of the inputs in case of side-channel attacks. + * + * @param res output; must be not null; may be equal to a and/or b + * @param a multiplicand; may be equal to res, in which case will get overwritten + * @param b multiplier; may be equal to res, in which case will get overwritten + */ + def mul(res: GF2_192, + a: GF2_192, + b: GF2_192): Unit = { + // Implements a sort of times-x-and-add algorithm, except instead of multiplying by x + // we multiply by x^4 and then add one of possible 16 precomputed values + // contains a*0, a*1, a*x, a*(x+1), a*x^2, a*(x^2+1), a*(x^2+x), a*(x^2+x+1) + // a*x^3, a*(x^3+1), a*(x^3+x), a*(x^3+x+1), a*(x^3+x^2), a*(x^3+x^2+1), a*(x^3+x^2+x), a*(x^3+x^2+x+1), all mod reduced + // First word of each is in a0 muls, second word of each is in a1muls, third word of each is in a2muls + val a0muls = new Array[Long](16) + val a1muls = new Array[Long](16) + val a2muls = new Array[Long](16) + + // a0muls[0], a1muls[0] and a2muls[0] are already correctly initialized to 0 + a0muls(1) = a.word(0) + a1muls(1) = a.word(1) + a2muls(1) = a.word(2) + // a*x, a*x^2, a*x^3 + var i = 2 + while (i <= 8) { + // multiply a*x^{log_2 i/2} by x to get a*x^{log_2 i} + val prev = i / 2 + a0muls(i) = a0muls(prev) << 1 + a1muls(i) = (a1muls(prev) << 1) | (a0muls(prev) >>> 63) + a2muls(i) = (a2muls(prev) << 1) | (a1muls(prev) >>> 63) + // mod reduce + a0muls(i) ^= irredMuls((a2muls(prev) >>> 63).toInt) + i *= 2 + } + + // a*(x+1) + a0muls(3) = a0muls(1) ^ a0muls(2) + a1muls(3) = a1muls(1) ^ a1muls(2) + a2muls(3) = a2muls(1) ^ a2muls(2) + + // a*(x^2+1), a*(x^2+x), a*(x^2+x+1) + cfor(1)(_ < 4, _ + 1) { i => + a0muls(4 | i) = a0muls(4) ^ a0muls(i) + a1muls(4 | i) = a1muls(4) ^ a1muls(i) + a2muls(4 | i) = a2muls(4) ^ a2muls(i) + } + + // a*(x^3+1), a*(x^3+x), a*(x^3+x+1), a*(x^3+x^2), a*(x^3+x^2+1), a*(x^3+x^2+x), a*(x^3+x^2+x+1) + cfor(1)(_ < 8, _ + 1) { i => + a0muls(8 | i) = a0muls(8) ^ a0muls(i) + a1muls(8 | i) = a1muls(8) ^ a1muls(i) + a2muls(8 | i) = a2muls(8) ^ a2muls(i) + } + var w0: Long = 0 + var w1: Long = 0 + var w2: Long = 0 + cfor(2)(_ >= 0, _ - 1) { j => + val multiplier = b.word(j) + var i = 60 + while (i >= 0) { + // Multiply by x^4 + val modReduceIndex = (w2 >>> 60).toInt + w2 = (w2 << 4) | (w1 >>> 60) + w1 = (w1 << 4) | (w0 >>> 60) + // MOD REDUCE ACCORDING TO modReduceIndex by XORing the right value + w0 = (w0 << 4) ^ irredMuls(modReduceIndex) + //w0 = (w0<<4)^(irredPentanomial*(modReduceIndex&8))^(irredPentanomial*(modReduceIndex&4))^(irredPentanomial*(modReduceIndex&2))^(irredPentanomial*(modReduceIndex&1)); + // Add the correct multiple of a + val index = ((multiplier >>> i) & 15).toInt + w0 ^= a0muls(index) + w1 ^= a1muls(index) + w2 ^= a2muls(index) + i -= 4 + } + } + res.word(0) = w0 + res.word(1) = w1 + res.word(2) = w2 + } + + def invert(res: GF2_192, + z: GF2_192): Unit = { + // Computes z^{2^192-2} = z^{exponent written in binary as 191 ones followed by a single zero} + // (by Fermat's little theorem, this is the correct inverse) + // contains z raised to the power whose binary representation is 2^k ones + val zTo2ToK1s = new GF2_192(z) + + // Square res to get its exponent to be 10 in binary + mul(res, z, z) + // contains z raised to the power whose binary representation is 2^k ones followed by 2^k zeros + val zTo2ToK1s2ToK0s = new GF2_192(res) + // Loop invariant + // res contains z raised to the power whose binary representation is 2^{k+1}-1 ones followed by a single zero + // zTo2ToK1s contains z raised to the power whose binary representation is 2^k ones + // zTo2ToK1s2ToK0s contains z raised to the power whose binary representation is 2^k ones followed by 2^k zeros + var k = 0 + while (k < 6) { + k += 1 + // Fill in the zeros in the exponent of zTo2ToK1s2ToK0s with ones + mul(zTo2ToK1s, zTo2ToK1s2ToK0s, zTo2ToK1s) + // zTo2ToK1s2ToK0s = power2To2ToK with 2^k zeros appended to the exponent + power2To2ToK(zTo2ToK1s2ToK0s, zTo2ToK1s, k) + // prepend 2^k ones to res + mul(res, res, zTo2ToK1s2ToK0s) + } + // Prepened another 64 ones to res + power2To2ToK(zTo2ToK1s2ToK0s, zTo2ToK1s2ToK0s, k) + mul(res, res, zTo2ToK1s2ToK0s) + } + + /** + * Squares z and puts the result into res. Same as power2To2ToK(res, z, 0). + * About same efficiency as mul(res, z, z) (more efficient implementations are possible, + * but not provided here because of risk of side-channel attacks) + * + * @param res output; must be not null; may be equal to z + * @param z input to be squared; may be equal to res, in which case will get overwritten + */ + def sqr(res: GF2_192, + z: GF2_192): Unit = { + // It is possible to precompute the square of every byte value in every byte position + // (only bytes a few byte positions are needed -- squares of bytes in other positions + // can be figured out by shifting squares of bytes in positions 0 and 16). This will result in a slightly + // bigger table and several times more efficient squaring. However, because table lookups will + // be input-dependent, this gives a higher risk of side-channel attacks that reveal z. + // Hence, it's not implemented. + // + power2To2ToK(res, z, 0) + } + + /** + * Raises z to the power 2^{2^k} and puts the result into res. Same sqr(z, z) 2^k times. + * Takes only about as much time as mul(res, z, z) (even more efficient implementations are possible, + * but not provided here because of risk of side-channel attacks) + * @param res output; must be not null; may be equal to z + * @param z input to be squared; may be equal to res, in which case will get overwritten + */ + def power2To2ToK(res: GF2_192, z: GF2_192, k: Int): Unit = { + if (k >= 7) { + // By Fermat's little theorem, z^{2^{2^k}} = z^{2^{2^k} mod (2^{192}-1)} + // If k>=7, then 2^{2^k} mod (2^{192}-1) = 2^64 when k is even and 2^128 when k is odd (proof below), + // so that's what we compute. + // Note that we have no precomputed table for k=7 (i.e., 2^128), because we don't expect + // this to be needed -- only up to k=6 is used in inversion. + // Here's the proof: let m = 64. 2^{2^k} mod (2^{192}-1) = 2^{mn} mod (2^{3m}-1) for n = 2^{k-6}. + // Let d = n div 3 and r = n mod 3. + // Then 2^{mn} = (2^{3m}-1) (2^{m(n-3}}+2^{m(n-6)}+...+2^{m-nd})+2^{nr} + // So the remainder is 2^{nr}. r is 2 when k is odd and 1 when k is even. + power2To2ToK(res, z, 6) + if (k % 2 == 1) { + power2To2ToK(res, res, 6) + } + } else { + // powTable0[k][i] contains the result of raising x^i to the power 2^k for i = 0...63 + // powTable0[k][i-64] contains the result of raising x^i to the power 2^k for i = 64...127 + // powTable0[k][i-128] contains the result of raising x^i to the power 2^k for i = 128...191 + // Because raising to the power 2^k is linear over any field of characteristic 2, + // we just need to XOR the values in these tables at indices i where z is 1. + // This selection is done via multiplication by 0 or 1, to avoid having an input-dependent path + // through the code, thus reducing the chance of side-channel attacks. + // + // Note that more efficient tables can be precomputed -- for example, the result of raising + // every one of 16 possible 4-bit nibbles at every one of 32 possible nibble positions. + // But indexing into these tables will be input-dependent, which may make side-channel attacks easier. + var t0: Long = 0 + var t1: Long = 0 + var t2: Long = 0 + var maxIndex = 0 + var i = 0 + cfor(0)(_ < z.word.length, _ + 1) { iW => + var w = z.word(iW) + maxIndex += 64 + while (i < maxIndex) { + val multiplier: Long = w & 1 + // No "if w&1 == 0" here, to avoid a data-dependent path through the code, + // thus reducing the chance of side channel attacks + t0 ^= powTable0(k)(i) * multiplier + t1 ^= powTable1(k)(i) * multiplier + t2 ^= powTable2(k)(i) * multiplier + w >>>= 1 + i += 1 + } + } + res.word(0) = t0 + res.word(1) = t1 + res.word(2) = t2 + } + } +} diff --git a/sigmastate/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala b/sigmastate/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala new file mode 100644 index 0000000000..dc0617ea29 --- /dev/null +++ b/sigmastate/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala @@ -0,0 +1,257 @@ +/* + By Leonid Reyzin + + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to + */ + +package sigmastate.crypto + +import debox.cfor + +import java.util +import java.util.Arrays + +class GF2_192_Poly { + final private var c: Array[GF2_192] = null // must be not null and of length at least 1 + + private var deg: Int = 0 // must be >=0. actual degree is <= deg. c[deg+1]...c[c.length-1] must be 0 or null + // deg of the 0 polynomial is 0 + + /** + * Constructs the polynomial given the byte array representation of the coefficients. + * Coefficient of degree zero is given separately. Each coefficient should be given + * as a 24-byte representation of a GF2_192 value. Coefficient of degree 1 should + * start at moreCoeffs[0]. + * + * @param coeff0 byte array representing lowest coefficient (24 bytes) + * @param moreCoeffs byte array with concatenation of byte-converted coefficients + * (24 bytes each) from degree 1 to the highest + */ + def this(coeff0: Array[Byte], moreCoeffs: Array[Byte]) { + this() + deg = moreCoeffs.length / 24 + c = new Array[GF2_192](deg + 1) + c(0) = new GF2_192(coeff0) + cfor(1)(_ <= deg, _ + 1) { i => + c(i) = new GF2_192(moreCoeffs, (i - 1) * 24) + } + } + + /** + * Evaluates the polynomial at a given point + * + * @param x the last byte of a field element (all other bits are assumed to be 0) + * @return the value of this polynomial evaluated at the field element + */ + def evaluate(x: Byte): GF2_192 = { + val res = new GF2_192(c(deg)) + cfor(deg - 1)(_ >= 0, _ - 1) { d => + GF2_192.mul(res, res, x) + GF2_192.add(res, res, c(d)) + } + res + } + + /** + * adds r*p to this; assumes p is monic, c.length>p.deg, and (p.deg == this.deg+1, or this==0 and p==1) + * + * @param p the monic polynomial being added to this + * @param r the constant by which p is multiplied before being added + */ + private def addMonicTimesConstantTo(p: GF2_192_Poly, r: GF2_192): Unit = { + val t: GF2_192 = new GF2_192 + cfor(0)(_ < p.deg, _ + 1) { i => + GF2_192.mul(t, p.c(i), r) + GF2_192.add(c(i), c(i), t) + } + deg = p.deg + c(deg) = new GF2_192(r) + } + + /** + * multiplies this by (x+r), assuming this is monic of degree deg (i.e. assumed c[deg]==1) + * + * @param r the constant term of the monomial + */ + private def monicTimesMonomial(r: Byte): Unit = { + deg += 1 + c(deg) = new GF2_192(1) + cfor(deg - 1)(_ > 0, _ - 1) { i => + // c[i] = c[i-1]+r*c[i] + GF2_192.mul(c(i), c(i), r) + GF2_192.add(c(i), c(i), c(i - 1)) + } + GF2_192.mul(c(0), c(0), r) + } + + /** + * Constructs a constant polynomial + * + * @param maxDeg the maximum degree this polynomial could possibly have (to allocate space) + * @param constantTerm the polynomial is initially created with degree 0 and given constantTerm + */ + def this(maxDeg: Int, constantTerm: Int) { + this() + c = new Array[GF2_192](maxDeg + 1) + c(0) = new GF2_192(constantTerm) + deg = 0 + } + + /** + * + * @return this represented in usual polynomial notation (but possibly leading 0s), with X as the free variable + */ + override def toString: String = { + var ret: String = "" + if (deg >= 2) { + ret += c(deg).toString + "*X^" + deg + cfor(deg - 1)(_ >= 2, _ - 1) { i => + ret += " + " + c(i) + "*X^" + i + } + ret += " + " + } + if (deg >= 1) { + ret += c(1) + "*X" + " + " + } + ret += c(0) + ret + } + + /** + * Returns a byte array that contains the concatenation of all the coefficients + * (except possibly the degree-0 coefficient, which is omitted if coeff0 is false). + * Lowest-degree coefficient (0 or 1 depending on coeff0) starts at index 0 of the returned array. + * Each coefficient takes 24 bytes, for a total of degree*24 bytes if coeff0 is false, + * or (degree+1)*24 bytes if coeff0 is true + * + * @param coeff0 whether to include coeff0 + * @return array of all coefficients (except possibly 0th depending on coeff0) + */ + def toByteArray(coeff0: Boolean): Array[Byte] = { + val c0 = if (coeff0) 0 else 1 + val ret: Array[Byte] = new Array[Byte]((deg + 1 - c0) * 24) + cfor(c0)(_ <= deg, _ + 1) { i => + c(i).toByteArray(ret, (i - c0) * 24) + } + ret + } + + /** + * @return The degree-0 coefficient, converted to an array of 24 bytes + */ + def coeff0Bytes: Array[Byte] = c(0).toByteArray + + override def hashCode: Int = { + 31 * util.Arrays.deepHashCode(c.asInstanceOf[Array[AnyRef]]) + deg + } + + override def equals(obj: Any): Boolean = { + if (this eq obj.asInstanceOf[AnyRef]) return true + obj match { + case that: GF2_192_Poly => + util.Arrays.deepEquals(c.asInstanceOf[Array[AnyRef]], that.c.asInstanceOf[Array[AnyRef]]) && + deg == that.deg + case _ => false + } + } +} + +object GF2_192_Poly { + /** + * Factory constructor -- same as GF2_192_Poly(coeff0, moreCoeffs) + * + * @param coeff0 byte array representing lowest coefficient (24 bytes) + * @param moreCoeffs byte array with concatenation of byte-converted coefficients + * (24 bytes each) from degree 1 to the highest + * @return new polynomial with the given coefficients + */ + // deg of the 0 polynomial is 0 + def fromByteArray(coeff0: Array[Byte], moreCoeffs: Array[Byte]): GF2_192_Poly = { + val res = new GF2_192_Poly(coeff0, moreCoeffs) + res + } + + /** + * Interpolates the polynomial at given points (and at point 0, if valueAt0!=null). + * If points are not all distinct, or if 0 is in the points array and valueAt0!=null, behavior is undefined. + * valueAt0 is separated only for efficiency reason; the caller can treat 0 like any other point instead + * (i.e., the points array can include 0 if valueAt0==null, but computation will be slightly less efficient). + * If points is null, or values is null, or if lengths of points and values arrays differ, + * or if the arrays are 0 length and valueAt0 is null, returns null. + * + * @param points the set of distinct inputs to the returned polynomial + * (last byte of the field element only; all other bits are assumed to be 0) + * @param values values[i] will be the result evaluating the returned polynomial at points[i]. values[i] must not be null. + * @param valueAt0 if not null, then valueAt0 will be the result of evaluating the returned polynomial at 0 + * @return the unique lowest-degree polynomial p such that for every i, p(points[i]) = values[i] and p(0)=valueAt0 + * (if valueAt0!=null) + */ + def interpolate(points: Array[Byte], + values: Array[GF2_192], + valueAt0: GF2_192): GF2_192_Poly = { + if (points == null || values == null || + (values.length == 0 && valueAt0 == null) || + values.length != points.length) return null + + var resultDegree = values.length - 1 + if (valueAt0 != null) resultDegree += 1 + + val result = new GF2_192_Poly(resultDegree, 0) + val vanishingPoly = new GF2_192_Poly(resultDegree, 1) + + cfor (0)(_ < points.length, _ + 1) { i => + val t = result.evaluate(points(i)) + val s = vanishingPoly.evaluate(points(i)) + + // need to find r such that currentValue+r*valueOfVanishingPoly = values[i] + GF2_192.add(t, t, values(i)) + GF2_192.invert(s, s) + GF2_192.mul(t, t, s) + + result.addMonicTimesConstantTo(vanishingPoly, t) + + if (i < points.length - 1 || valueAt0 != null) { + vanishingPoly.monicTimesMonomial(points(i)) + } + } + + if (valueAt0 != null) { + // the last point is 0 + val t = new GF2_192(result.c(0)) // evaluating at 0 is easy + val s = new GF2_192(vanishingPoly.c(0)) + + // need to find r such that currentValue+r*valueOfVanishingPoly = valueAt0] + GF2_192.add(t, t, valueAt0) + GF2_192.invert(s, s) + GF2_192.mul(t, t, s) + result.addMonicTimesConstantTo(vanishingPoly, t) + } + + result + } + +} + diff --git a/sigmastate/src/main/scala/sigmastate/crypto/Platform.scala b/sigmastate/src/main/scala/sigmastate/crypto/Platform.scala new file mode 100644 index 0000000000..5cb4a9f345 --- /dev/null +++ b/sigmastate/src/main/scala/sigmastate/crypto/Platform.scala @@ -0,0 +1,106 @@ +package sigmastate.crypto + +import org.bouncycastle.crypto.ec.CustomNamedCurves +import org.bouncycastle.math.ec.{ECFieldElement, ECPoint} + +import java.math.BigInteger + +/** JVM specific implementation of crypto methods*/ +object Platform { + /** Returns the x-coordinate. + * + * Caution: depending on the curve's coordinate system, this may not be the same value as in an + * affine coordinate system; use normalize() to get a point where the coordinates have their + * affine values, or use getAffineXCoord() if you expect the point to already have been + * normalized. + * + * @return the x-coordinate of this point + */ + def getXCoord(p: Ecp): ECFieldElem = ECFieldElem(p.value.getXCoord) + + /** Returns the y-coordinate. + * + * Caution: depending on the curve's coordinate system, this may not be the same value as in an + * affine coordinate system; use normalize() to get a point where the coordinates have their + * affine values, or use getAffineYCoord() if you expect the point to already have been + * normalized. + * + * @return the y-coordinate of this point + */ + def getYCoord(p: Ecp): ECFieldElem = ECFieldElem(p.value.getYCoord) + + /** Returns the affine x-coordinate after checking that this point is normalized. + * + * @return The affine x-coordinate of this point + * @throws IllegalStateException if the point is not normalized + */ + def getAffineXCoord(p: Ecp): ECFieldElem = ECFieldElem(p.value.getAffineXCoord) + + /** Returns the affine y-coordinate after checking that this point is normalized + * + * @return The affine y-coordinate of this point + * @throws IllegalStateException if the point is not normalized + */ + def getAffineYCoord(p: Ecp): ECFieldElem = ECFieldElem(p.value.getAffineYCoord) + + /** Returns byte representation of the given field element. */ + def encodeFieldElem(p: ECFieldElem): Array[Byte] = p.value.getEncoded + + /** Returns the value of bit 0 in BigInteger representation of this point. */ + def signOf(p: ECFieldElem): Boolean = p.value.testBitZero() + + /** * Normalization ensures that any projective coordinate is 1, and therefore that the x, y + * coordinates reflect those of the equivalent point in an affine coordinate system. + * + * @return a new ECPoint instance representing the same point, but with normalized coordinates + */ + def normalizePoint(p: Ecp): Ecp = Ecp(p.value.normalize()) + + /** Return simplified string representation of the point (used only for debugging) */ + def showPoint(p: Ecp): String = { + val rawX = p.value.getRawXCoord.toString.substring(0, 6) + val rawY = p.value.getRawYCoord.toString.substring(0, 6) + s"ECPoint($rawX,$rawY,...)" + } + + /** Multiply two points. + * @param p1 first point + * @param p2 second point + * @return group multiplication (p1 * p2) + */ + def multiplyPoints(p1: Ecp, p2: Ecp): Ecp = { + /* + * BC treats EC as additive group while we treat that as multiplicative group. + */ + Ecp(p1.value.add(p2.value)) + } + + /** Exponentiate a point. + * @param p point to exponentiate + * @param n exponent + * @return p to the power of n (p^n) + */ + def exponentiatePoint(p: Ecp, n: BigInteger): Ecp = { + /* + * BC treats EC as additive group while we treat that as multiplicative group. + * Therefore, exponentiate point is multiply. + */ + Ecp(p.value.multiply(n)) + } + + /** Check if a point is infinity. */ + def isInfinityPoint(p: Ecp): Boolean = p.value.isInfinity + + /** Negate a point. */ + def negatePoint(p: Ecp): Ecp = Ecp(p.value.negate()) + + /** Wrapper for point type. */ + case class Ecp(private[crypto] val value: ECPoint) + + /** Wrapper for field element type. */ + case class ECFieldElem(value: ECFieldElement) + + /** Create a new context for cryptographic operations. */ + def createContext(): CryptoContext = new CryptoContextJvm(CustomNamedCurves.getByName("secp256k1")) + +} diff --git a/sigmastate/src/main/scala/sigmastate/crypto/package.scala b/sigmastate/src/main/scala/sigmastate/crypto/package.scala new file mode 100644 index 0000000000..24d797be6f --- /dev/null +++ b/sigmastate/src/main/scala/sigmastate/crypto/package.scala @@ -0,0 +1,8 @@ +package sigmastate + +package object crypto { + /** Instance of Elliptic Curve point. */ + type Ecp = Platform.Ecp + /** Instance of Elliptic Curve field element. */ + type ECFieldElem = Platform.ECFieldElem +} diff --git a/sigmastate/src/main/scala/sigmastate/eval/CostingDataContext.scala b/sigmastate/src/main/scala/sigmastate/eval/CostingDataContext.scala index c152cb1716..76bafd2fa2 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/CostingDataContext.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/CostingDataContext.scala @@ -1,10 +1,9 @@ package sigmastate.eval -import com.google.common.primitives.{Ints, Longs} +import scorex.utils.{Ints, Longs} import java.math.BigInteger import java.util.Arrays -import org.bouncycastle.math.ec.ECPoint import org.ergoplatform.{ErgoBox, SigmaConstants} import org.ergoplatform.validation.ValidationRules import scalan.OverloadHack.Overloaded1 @@ -27,6 +26,7 @@ import scorex.crypto.hash.{Blake2b256, Digest32, Sha256} import sigmastate.Values.ErgoTree.EmptyConstants import sigmastate.basics.DLogProtocol.ProveDlog import sigmastate.basics.ProveDHTuple +import sigmastate.crypto.{CryptoFacade, Ecp} import sigmastate.lang.TransformingSigmaBuilder import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer import sigmastate.serialization.{GroupElementSerializer, SigmaSerializer} @@ -96,7 +96,7 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr /** A default implementation of [[GroupElement]] interface. * @see [[GroupElement]] for detailed descriptions */ -case class CGroupElement(override val wrappedValue: EcPointType) extends GroupElement with WrapperOf[ECPoint] { +case class CGroupElement(override val wrappedValue: Ecp) extends GroupElement with WrapperOf[Ecp] { val dsl = CostingSigmaDslBuilder override def toString: String = s"GroupElement(${Extensions.showECPoint(wrappedValue)})" @@ -104,16 +104,16 @@ case class CGroupElement(override val wrappedValue: EcPointType) extends GroupEl override def getEncoded: Coll[Byte] = dsl.Colls.fromArray(GroupElementSerializer.toBytes(wrappedValue)) - override def isInfinity: Boolean = wrappedValue.isInfinity + override def isIdentity: Boolean = CryptoFacade.isInfinityPoint(wrappedValue) override def exp(k: BigInt): GroupElement = - dsl.GroupElement(wrappedValue.multiply(k.asInstanceOf[CBigInt].wrappedValue)) + dsl.GroupElement(CryptoFacade.exponentiatePoint(wrappedValue, k.asInstanceOf[CBigInt].wrappedValue)) override def multiply(that: GroupElement): GroupElement = - dsl.GroupElement(wrappedValue.add(that.asInstanceOf[CGroupElement].wrappedValue)) + dsl.GroupElement(CryptoFacade.multiplyPoints(wrappedValue, that.asInstanceOf[CGroupElement].wrappedValue)) override def negate: GroupElement = - dsl.GroupElement(wrappedValue.negate()) + dsl.GroupElement(CryptoFacade.negatePoint(wrappedValue)) } /** A default implementation of [[SigmaProp]] interface. @@ -131,6 +131,7 @@ case class CSigmaProp(sigmaTree: SigmaBoolean) extends SigmaProp with WrapperOf[ 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 + // TODO v6.0: add `pk.propBytes(version)` val root = sigmaTree.toSigmaProp val ergoTree = new ErgoTree(ErgoTree.DefaultHeader, EmptyConstants, Right(root), 0, null, None) val bytes = DefaultSerializer.serializeErgoTree(ergoTree) @@ -142,19 +143,11 @@ case class CSigmaProp(sigmaTree: SigmaBoolean) extends SigmaProp with WrapperOf[ CSigmaProp(CAND.normalized(Array(sigmaTree, other.sigmaTree))) } - // TODO refactor: remove this (it shouldn't be used in interpreter) - override def &&(other: Boolean): SigmaProp = - CSigmaProp(CAND.normalized(Array(sigmaTree, TrivialProp(other)))) - override def ||(other: SigmaProp): SigmaProp = other match { case other: CSigmaProp => CSigmaProp(COR.normalized(Array(sigmaTree, other.sigmaTree))) } - // TODO refactor: remove this (it shouldn't be used in interpreter) - override def ||(other: Boolean): SigmaProp = - CSigmaProp(COR.normalized(Array(sigmaTree, TrivialProp(other)))) - override def toString: String = s"SigmaProp(${wrappedValue.showToString})" } @@ -509,7 +502,8 @@ class CostingSigmaDslBuilder extends SigmaDslBuilder { dsl => override def toBigInteger(n: BigInt): BigInteger = n.asInstanceOf[CBigInt].wrappedValue - def GroupElement(p: ECPoint): GroupElement = p match { + /** Wraps the given elliptic curve point into GroupElement type. */ + def GroupElement(p: Ecp): GroupElement = p match { case ept: EcPointType => CGroupElement(ept) case m => sys.error(s"Point of type ${m.getClass} is not supported") } @@ -523,9 +517,12 @@ class CostingSigmaDslBuilder extends SigmaDslBuilder { dsl => /** Extract `sigmastate.AvlTreeData` from DSL's `AvlTree` type. */ def toAvlTreeData(p: AvlTree): AvlTreeData = p.asInstanceOf[CAvlTree].treeData - /** Extract `org.bouncycastle.math.ec.ECPoint` from DSL's `GroupElement` type. */ - def toECPoint(ge: GroupElement): ECPoint = ge.asInstanceOf[CGroupElement].wrappedValue + /** Extract `sigmastate.crypto.Ecp` from DSL's `GroupElement` type. */ + def toECPoint(ge: GroupElement): Ecp = ge.asInstanceOf[CGroupElement].wrappedValue + /** Creates a new AvlTree instance with the given parameters. + * @see AvlTreeData for details + */ 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) diff --git a/sigmastate/src/main/scala/sigmastate/eval/Evaluation.scala b/sigmastate/src/main/scala/sigmastate/eval/Evaluation.scala index 830d6817d8..d54c2e8f7a 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/Evaluation.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/Evaluation.scala @@ -1,6 +1,5 @@ package sigmastate.eval -import org.bouncycastle.math.ec.ECPoint import org.ergoplatform._ import scalan.RType import scalan.RType._ @@ -99,7 +98,6 @@ object Evaluation { case BigIntegerRType => SBigInt case BigIntRType => SBigInt - case ECPointRType => SGroupElement case GroupElementRType => SGroupElement case AvlTreeRType => SAvlTree @@ -147,7 +145,6 @@ object Evaluation { case _: BigInteger => BigIntegerRType case _: special.sigma.BigInt => BigIntRType - case _: ECPoint => ECPointRType case _: GroupElement => GroupElementRType case _: ErgoBox => ErgoBoxRType diff --git a/sigmastate/src/main/scala/sigmastate/eval/Extensions.scala b/sigmastate/src/main/scala/sigmastate/eval/Extensions.scala index bf982e3269..a5d93ba25c 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/Extensions.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/Extensions.scala @@ -1,7 +1,5 @@ package sigmastate.eval -import org.bouncycastle.math.ec.ECPoint - import java.math.BigInteger import scalan.RType import sigmastate.{SCollection, SCollectionType, SType} @@ -13,6 +11,7 @@ import sigmastate.SType.AnyOps import org.ergoplatform.ErgoBox import debox.{Buffer => DBuffer} import debox.cfor +import sigmastate.crypto.{CryptoFacade, Ecp} object Extensions { private val Colls = CostingSigmaDslBuilder.Colls @@ -89,14 +88,12 @@ object Extensions { } /** Shortened String representation of `source` GroupElement. */ - def showECPoint(p: ECPoint): String = { - if (p.isInfinity) { - "INF" + def showECPoint(p: Ecp): String = { + if (p.isIdentity) { + "IDENTITY" } else { - val rawX = p.getRawXCoord.toString.substring(0, 6) - val rawY = p.getRawYCoord.toString.substring(0, 6) - s"ECPoint($rawX,$rawY,...)" + CryptoFacade.showPoint(p) } } diff --git a/sigmastate/src/main/scala/sigmastate/eval/Profiler.scala b/sigmastate/src/main/scala/sigmastate/eval/Profiler.scala index b3fad46020..2f0e7f3e0c 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/Profiler.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/Profiler.scala @@ -7,7 +7,6 @@ import sigmastate.serialization.OpCodes.OpCode import sigmastate.serialization.ValueSerializer.getSerializer import scalan.util.Extensions.ByteOps import debox.{Buffer => DBuffer, Map => DMap} -import org.apache.commons.math3.util.Precision import debox.sp import sigmastate.eval.Extensions.DBufferOps import sigmastate.interpreter.{CostItem, FixedCostItem, SeqCostItem, TypeBasedCostItem} @@ -335,7 +334,7 @@ class Profiler { .map { case (opName, error, cost, time, count) => val key = s"$opName".padTo(30, ' ') val warn = if (cost < time) "!!!" else "" - val err = Precision.round(error, 4) + val err = f"$error%4.4f" s"$key -> ($err, $cost$warn, $time), // count = $count " } .mkString("\n") diff --git a/sigmastate/src/main/scala/sigmastate/eval/TreeBuilding.scala b/sigmastate/src/main/scala/sigmastate/eval/TreeBuilding.scala index 4f8501606f..25f909e8bc 100644 --- a/sigmastate/src/main/scala/sigmastate/eval/TreeBuilding.scala +++ b/sigmastate/src/main/scala/sigmastate/eval/TreeBuilding.scala @@ -319,10 +319,6 @@ trait TreeBuilding extends SigmaLibrary { IR: IRContext => case OM.isDefined(In(optionSym)) => mkOptionIsDefined(optionSym.asValue[SOption[SType]]) - case SigmaM.and_bool_&&(In(prop), In(cond)) => // TODO refactor: remove or cover by tests: it is never executed - SigmaAnd(Seq(prop.asSigmaProp, mkBoolToSigmaProp(cond.asBoolValue))) - case SigmaM.or_bool_||(In(prop), In(cond)) => // TODO refactor: remove or cover by tests: it is never executed - 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)) => diff --git a/sigmastate/src/main/scala/sigmastate/interpreter/CryptoConstants.scala b/sigmastate/src/main/scala/sigmastate/interpreter/CryptoConstants.scala index 1da6c8c27e..1d4a3a2d28 100644 --- a/sigmastate/src/main/scala/sigmastate/interpreter/CryptoConstants.scala +++ b/sigmastate/src/main/scala/sigmastate/interpreter/CryptoConstants.scala @@ -2,17 +2,21 @@ package sigmastate.interpreter import java.math.BigInteger import java.security.SecureRandom +import sigmastate.basics.{BcDlogGroup, SecP256K1Group} +import sigmastate.crypto.Ecp -import org.bouncycastle.math.ec.custom.sec.SecP256K1Point -import sigmastate.basics.{BcDlogGroup, SecP256K1} - +/** Constants used in crypto operations implementation. */ object CryptoConstants { - type EcPointType = SecP256K1Point + /** Type of group elements used in the signature scheme. */ + type EcPointType = Ecp + /** Length of encoded group element in bytes. */ val EncodedGroupElementLength: Byte = 33 - val dlogGroup: BcDlogGroup[EcPointType] = SecP256K1 + /** Group used in the signature scheme. */ + val dlogGroup: BcDlogGroup = SecP256K1Group + /** Secure random generator used in the signature scheme. */ val secureRandom: SecureRandom = dlogGroup.secureRandom /** Size of the binary representation of any group element (2 ^ groupSizeBits == ) */ @@ -27,6 +31,7 @@ object CryptoConstants { /** Length of hash function used in the signature scheme. Blake2b hash function is used. */ val hashLengthBits = 256 + /** Length of hash in bytes. */ val hashLength: Int = hashLengthBits / 8 /** A size of challenge in Sigma protocols, in bits. @@ -37,6 +42,10 @@ object CryptoConstants { */ implicit val soundnessBits: Int = 192.ensuring(_ < groupSizeBits, "2^t < q condition is broken!") + /** Generates random bytes using secure random generator. + * @param howMany number of bytes to generate + * @return generated bytes in a new array + */ def secureRandomBytes(howMany: Int): Array[Byte] = { val bytes = new Array[Byte](howMany) secureRandom.nextBytes(bytes) diff --git a/sigmastate/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala b/sigmastate/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala index d28ec31c3f..bdd59eb850 100644 --- a/sigmastate/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala +++ b/sigmastate/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala @@ -6,7 +6,7 @@ import sigmastate.{PerItemCost, VersionContext, TypeBasedCost, FixedCost, SType, import sigmastate.Values._ import sigmastate.eval.Profiler import sigmastate.interpreter.ErgoTreeEvaluator.DataEnv -import sigmastate.interpreter.Interpreter.JitReductionResult +import sigmastate.interpreter.Interpreter.ReductionResult import special.sigma.{Context, SigmaProp} import scalan.util.Extensions._ import sigmastate.interpreter.EvalSettings._ @@ -460,7 +460,7 @@ object ErgoTreeEvaluator { * @param evalSettings evaluation settings * @return a sigma protocol proposition (as [[SigmaBoolean]]) and accumulated JIT cost estimation. */ - def evalToCrypto(context: ErgoLikeContext, ergoTree: ErgoTree, evalSettings: EvalSettings): JitReductionResult = { + def evalToCrypto(context: ErgoLikeContext, ergoTree: ErgoTree, evalSettings: EvalSettings): ReductionResult = { val (res, cost) = eval(context, ergoTree.constants, ergoTree.toProposition(replaceConstants = false), evalSettings) val sb = res match { case sp: SigmaProp => @@ -468,7 +468,7 @@ object ErgoTreeEvaluator { case sb: SigmaBoolean => sb case _ => error(s"Expected SigmaBoolean but was: $res") } - JitReductionResult(sb, cost) + ReductionResult(sb, cost) } /** Evaluate the given expression in the given Ergo context using the given settings. diff --git a/sigmastate/src/main/scala/sigmastate/interpreter/Interpreter.scala b/sigmastate/src/main/scala/sigmastate/interpreter/Interpreter.scala index 4f9ba46e05..1276849e60 100644 --- a/sigmastate/src/main/scala/sigmastate/interpreter/Interpreter.scala +++ b/sigmastate/src/main/scala/sigmastate/interpreter/Interpreter.scala @@ -1,12 +1,12 @@ package sigmastate.interpreter import java.util -import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{everywherebu, rule, strategy} -import org.bitbucket.inkytonik.kiama.rewriting.Strategy +import sigmastate.kiama.rewriting.Rewriter.{everywherebu, rule, strategy} +import sigmastate.kiama.rewriting.Strategy import org.ergoplatform.ErgoLikeContext import org.ergoplatform.validation.SigmaValidationSettings import org.ergoplatform.validation.ValidationRules._ -import scorex.util.ScorexLogging +import sigmastate.basics.DLogProtocol.ProveDlog import sigmastate.SCollection.SByteArray import sigmastate.Values._ import sigmastate.basics.DLogProtocol.{ProveDlog, DLogInteractiveProver, FirstDLogProverMessage} @@ -46,7 +46,7 @@ import scala.util.{Try, Success} * The interpreter has evaluationMode which defines how it should execute scripts. * @see verify, fullReduction */ -trait Interpreter extends ScorexLogging { +trait Interpreter { type CTX <: InterpreterContext @@ -63,6 +63,11 @@ trait Interpreter extends ScorexLogging { println(msg) } + protected def logMessage(msg: String, t: Throwable) = { + println(msg) + t.printStackTrace(System.out) + } + /** The cost of Value[T] deserialization is O(n), where n is the length of its bytes * array. To evaluate [[DeserializeContext]] and * [[sigmastate.utxo.DeserializeRegister]] we add the following cost of deserialization @@ -159,9 +164,9 @@ trait Interpreter extends ScorexLogging { * @return result of script reduction * @see `ReductionResult` */ - protected def reduceToCryptoJITC(context: CTX, env: ScriptEnv, exp: SigmaPropValue): Try[JitReductionResult] = Try { + protected def reduceToCryptoJITC(context: CTX, env: ScriptEnv, exp: SigmaPropValue): Try[ReductionResult] = Try { implicit val vs = context.validationSettings - trySoftForkable[JitReductionResult](whenSoftFork = WhenSoftForkJitReductionResult(context.initCost)) { + trySoftForkable[ReductionResult](whenSoftFork = WhenSoftForkReductionResult(context.initCost)) { val (resProp, cost) = { val ctx = context.asInstanceOf[ErgoLikeContext] @@ -172,7 +177,7 @@ trait Interpreter extends ScorexLogging { } } - JitReductionResult(SigmaDsl.toSigmaBoolean(resProp), cost.toLong) + ReductionResult(SigmaDsl.toSigmaBoolean(resProp), cost.toLong) } } @@ -193,7 +198,7 @@ trait Interpreter extends ScorexLogging { */ def fullReduction(ergoTree: ErgoTree, ctx: CTX, - env: ScriptEnv): FullReductionResult = { + env: ScriptEnv): ReductionResult = { implicit val vs: SigmaValidationSettings = ctx.validationSettings val context = ctx.withErgoTreeVersion(ergoTree.version).asInstanceOf[CTX] VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) { @@ -206,14 +211,13 @@ trait Interpreter extends ScorexLogging { // NOTE, evaluator cost unit needs to be scaled to the cost unit of context val evalCost = Eval_SigmaPropConstant.costKind.cost.toBlockCost val resCost = Evaluation.addCostChecked(context.initCost, evalCost, context.costLimit) - val jitRes = JitReductionResult(sb, resCost) - FullReductionResult(jitRes) + ReductionResult(sb, resCost) case _ if !ergoTree.hasDeserialize => val ctx = context.asInstanceOf[ErgoLikeContext] - val jitRes = VersionContext.withVersions(ctx.activatedScriptVersion, ergoTree.version) { + val res = VersionContext.withVersions(ctx.activatedScriptVersion, ergoTree.version) { ErgoTreeEvaluator.evalToCrypto(ctx, ergoTree, evalSettings) } - FullReductionResult(jitRes) + res case _ => reductionWithDeserialize(ergoTree, prop, context, env) } @@ -225,7 +229,7 @@ trait Interpreter extends ScorexLogging { * which encodes either a sigma-protocol proposition or a boolean (true or false) value. * See other overload for details. */ - def fullReduction(ergoTree: ErgoTree, ctx: CTX): FullReductionResult = { + def fullReduction(ergoTree: ErgoTree, ctx: CTX): ReductionResult = { fullReduction(ergoTree, ctx, Interpreter.emptyEnv) } @@ -233,9 +237,9 @@ trait Interpreter extends ScorexLogging { private def reductionWithDeserialize(ergoTree: ErgoTree, prop: SigmaPropValue, context: CTX, - env: ScriptEnv): FullReductionResult = { + env: ScriptEnv): ReductionResult = { implicit val vs: SigmaValidationSettings = context.validationSettings - val jitRes = VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) { + val res = VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) { val deserializeSubstitutionCost = java7.compat.Math.multiplyExact(ergoTree.bytes.length, CostPerTreeByte) val currCost = Evaluation.addCostChecked(context.initCost, deserializeSubstitutionCost, context.costLimit) val context1 = context.withInitCost(currCost).asInstanceOf[CTX] @@ -248,7 +252,7 @@ trait Interpreter extends ScorexLogging { reduceToCryptoJITC(context2, env, propTree).getOrThrow } - FullReductionResult(jitRes) + res } /** Adds the cost to verify sigma protocol proposition. @@ -259,7 +263,7 @@ trait Interpreter extends ScorexLogging { * @param costLimit total cost limit to check and raise exception if exceeded * @return computed jitRes.cost + crypto verification cost */ - protected def addCryptoCost(jitRes: JitReductionResult, costLimit: Long) = { + protected def addCryptoCost(jitRes: ReductionResult, costLimit: Long) = { val cryptoCost = estimateCryptoVerifyCost(jitRes.value).toBlockCost // scale JitCost to tx cost // Note, jitRes.cost is already scaled in fullReduction @@ -352,7 +356,7 @@ trait Interpreter extends ScorexLogging { case TrivialProp.TrueProp => (true, reduced.cost) case TrivialProp.FalseProp => (false, reduced.cost) case _ => - val fullJitCost = addCryptoCost(reduced.jitRes, context.costLimit) + val fullCost = addCryptoCost(reduced, context.costLimit) val ok = if (evalSettings.isMeasureOperationTime) { val E = ErgoTreeEvaluator.forProfiling(verifySignatureProfiler, evalSettings) @@ -360,7 +364,7 @@ trait Interpreter extends ScorexLogging { } else { verifySignature(reduced.value, message, proof)(null) } - (ok, fullJitCost) + (ok, fullCost) } } } @@ -459,7 +463,7 @@ trait Interpreter extends ScorexLogging { // NOTE, property("handle improper signature") doesn't lead to exception // because the current implementation of parseAndComputeChallenges doesn't throw // an exception - log.warn("Improper signature: ", t); + logMessage("Improper signature: ", t); false } } @@ -473,34 +477,14 @@ object Interpreter { * The second component is the estimated cost of contract execution. */ type VerificationResult = (Boolean, Long) - /** Result of ErgoTree reduction procedure (see `fullReduction`) */ - abstract class ReductionResult { - /** The value of SigmaProp type which represents a logical statement verifiable via - * sigma protocol. - */ - def value: SigmaBoolean - - /** Estimated cost of the contract execution.*/ - def cost: Long - } - - /** Result of ErgoTree reduction procedure by JIT-based interpreter (see + /** Result of ErgoTree reduction procedure by JIT-based interpreter (see `fullReduction`, * `reduceToCrypto` and friends). * * @param value the value of SigmaProp type which represents a logical statement * verifiable via sigma protocol. * @param cost the estimated cost of the contract execution (in block's scale). */ - case class JitReductionResult(value: SigmaBoolean, cost: Long) extends ReductionResult - - /** Result of fullReduction to sigma tree with costing. */ - case class FullReductionResult( - private[sigmastate] val jitRes: JitReductionResult - ) extends ReductionResult { - require(jitRes != null, s"JIT result must be defined: $this") - override def value: SigmaBoolean = jitRes.value - override def cost: Long = jitRes.cost - } + case class ReductionResult(value: SigmaBoolean, cost: Long) /** Represents properties of interpreter invocation. */ type ScriptEnv = Map[String, Any] @@ -514,7 +498,7 @@ object Interpreter { /** The result of script reduction when soft-fork condition is detected by the old node, * in which case the script is reduced to the trivial true proposition and takes up 0 cost. */ - def WhenSoftForkJitReductionResult(cost: Long): JitReductionResult = JitReductionResult(TrivialProp.TrueProp, cost) + def WhenSoftForkReductionResult(cost: Long): ReductionResult = ReductionResult(TrivialProp.TrueProp, cost) /** Represents the cost of computing DLogInteractiveProver.computeCommitment. */ final val ComputeCommitments_Schnorr = OperationCostInfo( diff --git a/sigmastate/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala b/sigmastate/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala index 00d4bf5cc3..d49cba76f3 100644 --- a/sigmastate/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala +++ b/sigmastate/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala @@ -1,9 +1,7 @@ package sigmastate.interpreter -import gf2t.{GF2_192, GF2_192_Poly} -import org.bitbucket.inkytonik.kiama.attribution.UncachedAttribution.attr -import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{everywherebu, everywheretd, rule} -import org.bitbucket.inkytonik.kiama.rewriting.Strategy +import sigmastate.kiama.rewriting.Rewriter.{everywherebu, everywheretd, rule} +import sigmastate.kiama.rewriting.Strategy import scalan.util.CollectionUtil._ import sigmastate.TrivialProp.{FalseProp, TrueProp} import sigmastate.Values._ @@ -12,6 +10,7 @@ import sigmastate._ import sigmastate.basics.DLogProtocol._ import sigmastate.basics.VerifierMessage.Challenge import sigmastate.basics._ +import sigmastate.crypto.{GF2_192, GF2_192_Poly} import sigmastate.lang.exceptions.InterpreterException import sigmastate.utils.Helpers @@ -129,7 +128,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { VersionContext.withVersions(context.activatedScriptVersion, ergoTree.version) { val (resValue, resCost) = { val reduced = fullReduction(ergoTree, context, env) - val fullCost = addCryptoCost(reduced.jitRes, context.costLimit) + val fullCost = addCryptoCost(reduced, context.costLimit) (reduced.value, fullCost) } @@ -470,7 +469,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { val newChildren = t.children.foldLeft(Seq[ProofTree](), 1) { case ((s, count), child) => val newChild = child match { - case r: UnprovenTree if r.real => r.withChallenge(Challenge @@ q.evaluate(count.toByte).toByteArray()) + case r: UnprovenTree if r.real => r.withChallenge(Challenge @@ q.evaluate(count.toByte).toByteArray) case p: ProofTree => p } (s :+ newChild, count + 1) @@ -556,7 +555,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { case ut: UnprovenTree => ut case t: ProofTree => - log.warn("Wrong input in prove(): ", t); + logMessage(s"Wrong input in prove(): $t"); ??? }) @@ -578,7 +577,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { } //converts ProofTree => UncheckedSigmaTree - val convertToUnchecked: ProofTree => UncheckedSigmaTree = attr { + def convertToUnchecked(proofTree: ProofTree): UncheckedSigmaTree = proofTree match { case and: CAndUnproven => CAndUncheckedNode(and.challengeOpt.get, and.children.map(convertToUnchecked)) case or: COrUnproven => diff --git a/sigmastate/src/main/scala/sigmastate/lang/SigmaBinder.scala b/sigmastate/src/main/scala/sigmastate/lang/SigmaBinder.scala index 214a4abb01..eac3794eda 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/SigmaBinder.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/SigmaBinder.scala @@ -2,7 +2,7 @@ package sigmastate.lang import java.lang.reflect.InvocationTargetException -import org.bitbucket.inkytonik.kiama.rewriting.CallbackRewriter +import sigmastate.kiama.rewriting.CallbackRewriter import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix import org.ergoplatform._ import scalan.Nullable diff --git a/sigmastate/src/main/scala/sigmastate/lang/SigmaCompiler.scala b/sigmastate/src/main/scala/sigmastate/lang/SigmaCompiler.scala index b51163fb00..ebe3118fb0 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/SigmaCompiler.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/SigmaCompiler.scala @@ -2,7 +2,7 @@ package sigmastate.lang import fastparse.Parsed import fastparse.Parsed.Success -import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{everywherebu, rewrite, rule} +import sigmastate.kiama.rewriting.Rewriter.{everywherebu, rewrite, rule} import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix import org.ergoplatform.Global import sigmastate.Values.{SValue, Value} @@ -82,13 +82,6 @@ class SigmaCompiler(settings: CompilerSettings) { typecheck(env, parsed) } - private[sigmastate] def compileWithoutCosting(env: ScriptEnv, code: String): Value[SType] = { - val typed = typecheck(env, code) - val spec = new SigmaSpecializer(builder) - val ir = spec.specialize(typed) - ir - } - /** Compiles the given ErgoScript source code. */ def compile(env: ScriptEnv, code: String)(implicit IR: IRContext): CompilerResult[IR.type] = { val typed = typecheck(env, code) diff --git a/sigmastate/src/main/scala/sigmastate/lang/SigmaPrinter.scala b/sigmastate/src/main/scala/sigmastate/lang/SigmaPrinter.scala deleted file mode 100644 index 456878b981..0000000000 --- a/sigmastate/src/main/scala/sigmastate/lang/SigmaPrinter.scala +++ /dev/null @@ -1,92 +0,0 @@ -package sigmastate.lang - -import sigmastate._ -import sigmastate.Values._ -import sigmastate.lang.Terms._ -import scala.collection.immutable.{Seq => ImmSeq} - -/** Sigma pretty printing. */ -class SigmaPrinter extends org.bitbucket.inkytonik.kiama.output.PrettyPrinter { - - import org.bitbucket.inkytonik.kiama.output.PrettyPrinterTypes.Document - - /** Format a lambda expression. */ - def format(t : SValue) : Document = - pretty(toDoc(t)) - - /** The layout from formatting a lambda expression. */ - def formattedLayout(t : SValue) : String = - format(t).layout - - /** Format a type. */ - def format(t : SType) : Document = - pretty(typeToDoc(t)) - - /** The layout from formatting a type. */ - def formattedLayout(t : SType) : String = - format(t).layout - - /** - * Convert an expression node to a pretty-printing document in - * fully-parenthesised style. - */ - def toDoc(t : SValue) : Doc = - t match { - case LongConstant(d) => value(d) - case Ident(i,_) => i - case Lambda(_, args, tLam, Some(e)) => - parens('\\' <> parens(lsep( - ImmSeq(args.map { case (n, targ) => n <+> ": " <+> typedeclToDoc(targ) }:_*), - comma)) <> - typedeclToDoc(tLam) <+> '.' <+> - group(nest(toDoc(e)))) - case Apply(e, args) => - parens(toDoc(e) <+> parens(lsep(ImmSeq(args.map(toDoc):_*), comma))) - -// case Opn(l, AddOp(), r) => binToDoc(l, "+", r) -// case Opn(l, SubOp(), r) => binToDoc(l, "-", r) - -// case Val(i, t, e1, e2) => -// parens("let" <+> i <> typedeclToDoc(t) <+> '=' <> -// nest(line <> toDoc(e1)) <+> "in" <> -// nest(line <> toDoc(e2))) -// case Valp(bs, e) => -// parens("letp" <> -// nest(line <> vsep(bs.map(b => b.i <+> '=' <+> toDoc(b.e)))) <+> -// "in" <> -// nest(line <> toDoc(e))) - } - - /** - * Return a pretty-printing document for an instance of a type declaration. - */ - def typedeclToDoc(t : SType) : Doc = - if (t == NoType) - emptyDoc - else - space <> ':' <+> typeToDoc(t) - - /** - * Return a pretty-printing document for an instance of a type. - */ - def typeToDoc(t : SType) : Doc = - t match { - case SLong => "Int" - case SFunc(dom, t2, _) => - parens(lsep(ImmSeq(dom.map(typeToDoc):_*), comma)) <+> "->" <+> typeToDoc(t2) - case NoType => "NoType" // Not used - case _ => s"" - } - - /** - * Return a pretty-printing document for an instance of a binary expression. - */ - def binToDoc(l : SValue, op : String, r : SValue) : Doc = - parens(toDoc(l) <+> op <+> toDoc(r)) - -} - -/** - * Lambda calculus pretty printing. - */ -object SigmaPrinter extends SigmaPrinter diff --git a/sigmastate/src/main/scala/sigmastate/lang/SigmaSpecializer.scala b/sigmastate/src/main/scala/sigmastate/lang/SigmaSpecializer.scala deleted file mode 100644 index 22e6ce5a2b..0000000000 --- a/sigmastate/src/main/scala/sigmastate/lang/SigmaSpecializer.scala +++ /dev/null @@ -1,169 +0,0 @@ -package sigmastate.lang - -import org.bitbucket.inkytonik.kiama.rewriting.Rewriter.{reduce, rewrite, strategy} -import org.ergoplatform._ -import sigmastate.SCollection._ -import sigmastate.Values.Value.Typed -import sigmastate.Values._ -import sigmastate._ -import sigmastate.lang.SigmaPredef._ -import sigmastate.lang.Terms.{Apply, Block, Ident, Lambda, Select, Val, ValueOps} -import sigmastate.lang.exceptions.SpecializerException -import sigmastate.utxo._ - -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) - tagged - } - - /** Rewriting of AST with respect to environment to resolve all references - * to let bound and lambda bound names. */ - private def eval(env: Map[String, SValue], e: SValue): SValue = rewrite(reduce(strategy[Any]({ - case Ident(n, _) => env.get(n) - - case _ @ Block(binds, res) => - var curEnv = env - 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) - - case Upcast(Constant(value, _), toTpe: SNumericType) => - Some(mkConstant(toTpe.upcast(value.asInstanceOf[AnyVal]), toTpe)) - - case Downcast(Constant(value, _), toTpe: SNumericType) => - Some(mkConstant(toTpe.downcast(value.asInstanceOf[AnyVal]), toTpe)) - - // Rule: numeric.to* casts - case Select(obj, method, Some(tRes: SNumericType)) - if obj.tpe.isNumType && obj.asNumValue.tpe.isCastMethod(method) => - val numValue = obj.asNumValue - if (numValue.tpe == tRes) - Some(numValue) - else if ((numValue.tpe max tRes) == numValue.tpe) - Some(mkDowncast(numValue, tRes)) - else - Some(mkUpcast(numValue, tRes)) - - // Rule: col.size --> SizeOf(col) - case Select(obj, SizeMethod.name, _) => - if (obj.tpe.isCollectionLike) - Some(mkSizeOf(obj.asValue[SCollection[SType]])) - else - error(s"The type of $obj is expected to be Collection to select 'size' property") - - // Rule: proof.isProven --> IsValid(proof) - case Select(p, SSigmaProp.IsProven, _) if p.tpe == SSigmaProp => - Some(SigmaPropIsProven(p.asSigmaProp)) - - // Rule: proof.propBytes --> ProofBytes(proof) - case Select(p, SSigmaProp.PropBytes, _) if p.tpe == SSigmaProp => - Some(SigmaPropBytes(p.asSigmaProp)) - - 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")) - Some(mkExtractRegisterAs(box.asBox, reg, SOption(valType)).asValue[SOption[valType.type]]) - - case Select(nrv: NotReadyValue[SOption[SType]]@unchecked, SOption.Get, _) => - Some(mkOptionGet(nrv)) - - case Apply(Select(nrv: NotReadyValue[SOption[SType]]@unchecked, SOption.GetOrElse, _), Seq(arg)) => - Some(mkOptionGetOrElse(nrv, arg)) - - case Select(nrv: NotReadyValue[SOption[SType]]@unchecked, SOption.IsDefined, _) => - Some(mkOptionIsDefined(nrv)) - - 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.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 Select(tuple, fn, _) if tuple.tpe.isTuple && fn.startsWith("_") => - val index = fn.substring(1).toByte - Some(mkSelectField(tuple.asTuple, index)) - - case Apply(Select(col, SliceMethod.name, _), Seq(from, until)) => - Some(mkSlice(col.asValue[SCollection[SType]], from.asIntValue, until.asIntValue)) - - case Apply(Select(col, FilterMethod.name, _), Seq(l @ Lambda(_, _, _, _))) => - Some(mkFilter(col.asValue[SCollection[SType]], l)) - - case Apply(Select(col, ExistsMethod.name, _), Seq(l @ Lambda(_, _, _, _))) => - Some(mkExists(col.asValue[SCollection[SType]], l)) - - case Apply(Select(col, ForallMethod.name, _), Seq(l @ Lambda(_, _, _, _))) => - Some(mkForAll(col.asValue[SCollection[SType]], l)) - - case Apply(Select(col, MapMethod.name, _), Seq(l @ Lambda(_, _, _, _))) => - Some(mkMapCollection(col.asValue[SCollection[SType]], l)) - - case Apply(Select(col, FoldMethod.name, _), Seq(zero, l @ Lambda(_, _, _, _))) => - Some(mkFold(col.asValue[SCollection[SType]], zero, l)) - - case Apply(col, Seq(index)) if col.tpe.isCollection => - Some(ByIndex(col.asCollection[SType], index.asValue[SInt.type])) - - case opt: OptionValue[_] => - error(s"Option constructors are not supported: $opt") - - case AND(ConcreteCollection(items, SBoolean)) if items.exists(_.isInstanceOf[AND]) => - Some(mkAND( - mkConcreteCollection( - items.flatMap { - case AND(ConcreteCollection(innerItems, SBoolean)) => innerItems - case v => IndexedSeq(v) - }, SBoolean))) - - case OR(ConcreteCollection(items, SBoolean)) if items.exists(_.isInstanceOf[OR]) => - Some(mkOR( - mkConcreteCollection( - items.flatMap { - case OR(ConcreteCollection(innerItems, SBoolean)) => innerItems - case v => IndexedSeq(v) - }, SBoolean))) - - case PredefinedFuncApply(irNode) => - Some(irNode) - - })))(e) - - def specialize(typed: SValue): SValue = { - specialize(Map(), typed) - } - - def specialize(env: Map[String, SValue], typed: SValue): SValue = { - val res = eval(env, typed) - res - } -} - -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/sigmastate/src/main/scala/sigmastate/lang/SigmaTyper.scala b/sigmastate/src/main/scala/sigmastate/lang/SigmaTyper.scala index 60ac7c04f0..06928adb28 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/SigmaTyper.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/SigmaTyper.scala @@ -1,19 +1,19 @@ package sigmastate.lang -import org.bitbucket.inkytonik.kiama.rewriting.Rewriter._ +import sigmastate.kiama.rewriting.Rewriter._ import org.ergoplatform._ import sigmastate.SCollection._ import sigmastate.Values._ import sigmastate._ import SCollection.SBooleanArray import scalan.Nullable +import scalan.util.Extensions.Ensuring import sigmastate.lang.Terms._ import sigmastate.lang.exceptions._ import sigmastate.lang.SigmaPredef._ import sigmastate.serialization.OpCodes import sigmastate.utxo._ -import scala.collection.compat.immutable.ArraySeq import scala.collection.mutable.ArrayBuffer /** @@ -521,7 +521,9 @@ class SigmaTyper(val builder: SigmaBuilder, case v @ Select(_, _, Some(_)) => v case v => error(s"Don't know how to assignType($v)", v.sourceContext) - }).withEnsuredSrcCtx(bound.sourceContext) + }).ensuring(v => v.tpe != NoType, + v => s"Errors found while assigning types to expression $bound: $v assigned NoType") + .withEnsuredSrcCtx(bound.sourceContext) def assignConcreteCollection(cc: ConcreteCollection[SType], newItems: Seq[Value[SType]]) = { val types = newItems.map(_.tpe).distinct @@ -609,17 +611,6 @@ class SigmaTyper(val builder: SigmaBuilder, 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 - rewrite(everywherebu(rule[Any]{ - case v: SValue => - if (v.tpe == NoType) untyped = v - v - }))(assigned) - - if (untyped != null) - error(s"Errors found in $bound while assigning types to expression: $untyped assigned NoType", untyped.sourceContext) - assigned } } diff --git a/sigmastate/src/main/scala/sigmastate/lang/Terms.scala b/sigmastate/src/main/scala/sigmastate/lang/Terms.scala index 75cd14d251..9b90d62577 100644 --- a/sigmastate/src/main/scala/sigmastate/lang/Terms.scala +++ b/sigmastate/src/main/scala/sigmastate/lang/Terms.scala @@ -1,6 +1,6 @@ package sigmastate.lang -import org.bitbucket.inkytonik.kiama.rewriting.Rewriter._ +import sigmastate.kiama.rewriting.Rewriter._ import scalan.Nullable import sigmastate.SCollection.{SIntArray, SByteArray} import sigmastate.Values._ diff --git a/sigmastate/src/main/scala/sigmastate/serialization/GroupElementSerializer.scala b/sigmastate/src/main/scala/sigmastate/serialization/GroupElementSerializer.scala index d004d42566..b8523cb430 100644 --- a/sigmastate/src/main/scala/sigmastate/serialization/GroupElementSerializer.scala +++ b/sigmastate/src/main/scala/sigmastate/serialization/GroupElementSerializer.scala @@ -1,5 +1,6 @@ package sigmastate.serialization +import sigmastate.crypto.CryptoFacade import sigmastate.interpreter.CryptoConstants import sigmastate.interpreter.CryptoConstants.EcPointType import sigmastate.util.safeNewArray @@ -21,12 +22,12 @@ object GroupElementSerializer extends SigmaSerializer[EcPointType, EcPointType] private lazy val identityPointEncoding = Array.fill(encodingSize)(0: Byte) override def serialize(point: EcPointType, w: SigmaByteWriter): Unit = { - val bytes = if (point.isInfinity) { + val bytes = if (CryptoFacade.isInfinityPoint(point)) { identityPointEncoding } else { - val normed = point.normalize() - val ySign = normed.getAffineYCoord.testBitZero() - val X = normed.getXCoord.getEncoded + val normed = CryptoFacade.normalizePoint(point) + val ySign = CryptoFacade.signOf(CryptoFacade.getAffineYCoord(normed)) + val X = CryptoFacade.encodeFieldElem(CryptoFacade.getXCoord(normed)) val PO = safeNewArray[Byte](X.length + 1) PO(0) = (if (ySign) 0x03 else 0x02).toByte System.arraycopy(X, 0, PO, 1, X.length) @@ -38,7 +39,7 @@ object GroupElementSerializer extends SigmaSerializer[EcPointType, EcPointType] override def parse(r: SigmaByteReader): EcPointType = { val encoded = r.getBytes(encodingSize) if (encoded(0) != 0) { - curve.curve.decodePoint(encoded).asInstanceOf[EcPointType] + curve.ctx.decodePoint(encoded) } else { curve.identity } diff --git a/sigmastate/src/main/scala/sigmastate/utils/Extensions.scala b/sigmastate/src/main/scala/sigmastate/utils/Extensions.scala index 8d8d8d9927..24ee381108 100644 --- a/sigmastate/src/main/scala/sigmastate/utils/Extensions.scala +++ b/sigmastate/src/main/scala/sigmastate/utils/Extensions.scala @@ -1,6 +1,6 @@ package sigmastate.utils -import com.google.common.primitives.{Ints, Longs, Shorts} +import scorex.utils.{Ints, Longs, Shorts} import sigmastate.eval.SigmaDsl import special.collection.Coll diff --git a/sigmastate/src/test/java/gf2t/GF2_192Test.java b/sigmastate/src/test/java/gf2t/GF2_192Test.java deleted file mode 100644 index 46a4110b82..0000000000 --- a/sigmastate/src/test/java/gf2t/GF2_192Test.java +++ /dev/null @@ -1,711 +0,0 @@ -/* - By Leonid Reyzin - - This is free and unencumbered software released into the public domain. - - Anyone is free to copy, modify, publish, use, compile, sell, or - distribute this software, either in source code form or as a compiled - binary, for any purpose, commercial or non-commercial, and by any - means. - - In jurisdictions that recognize copyright laws, the author or authors - of this software dedicate any and all copyright interest in the - software to the public domain. We make this dedication for the benefit - of the public at large and to the detriment of our heirs and - successors. We intend this dedication to be an overt act of - relinquishment in perpetuity of all present and future rights to this - software under copyright law. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - - For more information, please refer to - */ -package gf2t; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.Random; -import java.util.Arrays; - -import static org.junit.Assert.assertFalse; - -@RunWith(ReadableTest.class) -public class GF2_192Test { - - private static class GF2t_slow { - - private long[] x; - - public boolean isOne() { - if (x[0] != 1l) return false; - for (int i = 1; i < x.length; i++) { - if (x[i] != 0l) return false; - } - return true; - } - - public boolean equals(long[] that) { - int i; - for (i = 0; i < Math.min(x.length, that.length); i++) { - if (x[i] != that[i]) - return false; - } - for (; i < x.length; i++) { - if (x[i] != 0) { - return false; - } - } - for (; i < that.length; i++) { - if (that[i] != 0) { - return false; - } - } - return true; - } - - - public static void mulBits(GF2t_slow ret, long[] a, long[] b) { - long[] c = new long[a.length + b.length]; - - - for (int i = 0; i < a.length; i++) { - for (int i1 = 0; i1 < 64; i1++) { - for (int j = 0; j < b.length; j++) { - for (int j1 = 0; j1 < 64; j1++) { - if ((a[i] & (1l << i1)) != 0 && (b[j] & (1l << j1)) != 0) { - int cPosition = i * 64 + i1 + j * 64 + j1; - c[cPosition / 64] ^= 1l << (cPosition % 64); - } - } - } - } - } - ret.x = c; - } - - private static void modReduce(GF2t_slow poly, Modulus mod) { - for (int i = poly.x.length * 64 - 1; i >= mod.degree; i--) { - if ((poly.x[i >> 6] & (1l << (i & 63))) != 0) { - for (int j = 0; j < mod.offset.length; j++) { - int k = i - mod.offset[j]; - poly.x[k >> 6] ^= (1l << (k & 63)); - } - } - } - } - - public String toString() { - String ret = ""; - for (int i = x.length - 1; i >= 0; i--) { - ret += x[i]; - } - return ret; - } - - public static class Modulus { - // represented as an array of bit positions - // where coefficient = 1, counting from degree down - private final int[] offset; - private final int degree; - - Modulus(int[] sparseModulus) { - degree = sparseModulus[0]; - offset = new int[sparseModulus.length]; - offset[0] = 0; - for (int i = 1; i < sparseModulus.length; i++) { - offset[i] = degree - sparseModulus[i]; - } - } - } - } - - private static long[][] testValues = null; - private static GF2_192 zero = new GF2_192(0); - private static GF2_192 one = new GF2_192(1); - private static int[] pentanomial = {192, 7, 2, 1, 0}; - private static GF2t_slow.Modulus m = new GF2t_slow.Modulus(pentanomial); - static {genTestValues();} - private static void genTestValues() { - if (testValues == null) { - testValues = new long[250][]; - - for (int i = 0; i < testValues.length; i++) { - testValues[i] = new long[3]; - } - - - // Test single 1s in every bit position but last - // (1s in last bit position -- i.e., just the value of 1 -- will be tested separately) - int j = 0; - for (int i = 1; i < 64; i++, j++) { - testValues[j][0] = 1L << i; - testValues[j][1] = 0; - testValues[j][2] = 0; - } - for (int i = 0; i < 64; i++, j++) { - testValues[j][0] = 0; - testValues[j][1] = 1L << i; - testValues[j][2] = 0; - } - for (int i = 0; i < 64; i++, j++) { - testValues[j][0] = 0; - testValues[j][1] = 0; - testValues[j][2] = 1L << i; - } - - // Test first word zero, last two words random, - // and first word random, last two words 0 - // and first word random, second word 1, last word 0 - // and last word random, first two words 0 - - Random rand = new Random(); - - for (int i = 0; i < 5; i++, j++) { - testValues[j][0] = 0; - testValues[j][1] = rand.nextLong(); - testValues[j][2] = rand.nextLong(); - } - - for (int i = 0; i < 5; i++, j++) { - testValues[j][0] = rand.nextLong(); - testValues[j][1] = 0; - testValues[j][2] = 0; - } - - - for (int i = 0; i < 5; i++, j++) { - testValues[j][0] = rand.nextLong(); - testValues[j][1] = 1; - testValues[j][2] = 0; - } - - for (int i = 0; i < 5; i++, j++) { - testValues[j][0] = 0; - testValues[j][1] = 1; - testValues[j][2] = rand.nextLong(); - } - - // Test all three words random - while (j < testValues.length) { - testValues[j][0] = rand.nextLong(); - testValues[j][1] = rand.nextLong(); - testValues[j++][2] = rand.nextLong(); - } - } - } - - @Test - public void constructorAndEqualityTest() { - GF2_192 t = new GF2_192(); - long[] r = t.toLongArray(); - assertFalse("Fail: empty constructor.", !t.isZero() || r.length != 3 || r[0] != 0L || r[1] != 0L || r[2] != 0L); - - t = new GF2_192(0); - r = t.toLongArray(); - assertFalse("Fail: constructor on 0 int",!t.isZero() || r.length != 3 || r[0] != 0L || r[1] != 0L || r[2] != 0L); - - t = new GF2_192(1); - r = t.toLongArray(); - assertFalse("Fail: constructor on 1 int", !t.isOne() || r.length != 3 || r[0] != 1L || r[1] != 0L || r[2] != 0L); - - t = new GF2_192(-1); - r = t.toLongArray(); - assertFalse("Fail: constructor on 0xFFFFFFFF int " + t, r[0] != 0xFFFFFFFFL || r[1] != 0L || r[2]!=0L); - - long[] s = new long[3]; - - s[0] = 123345L; - s[1] = 123567891234567L; - s[2] = 487237823242367L; - - t = new GF2_192(s); - - GF2_192 t1 = new GF2_192(t); - - r = t.toLongArray(); - assertFalse("Fail: constructor on long array", r[0] != s[0] || r[1] != s[1] || r[2] != s[2]); - - - r = t1.toLongArray(); - assertFalse ("Fail: copy constructor",r[0] != s[0] || r[1] != s[1] || r[2] != s[2]) ; - - byte[] b = new byte[24]; - for (int i = 0; i < 8; i++) { - b[i] = (byte) (r[0] >>> (i * 8)); - } - - for (int i = 0; i < 8; i++) { - b[i + 8] = (byte) (r[1] >>> (i * 8)); - } - - for (int i = 0; i < 8; i++) { - b[i + 16] = (byte) (r[2] >>> (i * 8)); - } - t = new GF2_192(b); - s = t.toLongArray(); - - assertFalse("Fail: constructor on byte array",r[0] != s[0] || r[1] != s[1] || r[2] != s[2]); - byte [] c = t.toByteArray(); - assertFalse("Fail: toByteArray", !Arrays.equals(b, c)); - - byte [] b2 = new byte[30]; - for (int i=0; i<24; i++) { - b2[i+6]=b[i]; - } - t = new GF2_192(b2, 6); - s = t.toLongArray(); - assertFalse("Fail: constructor on byte array with offset", r[0] != s[0] || r[1] != s[1] || r[2]!=s[2]); - - byte [] b1 = t.toByteArray(); - assertFalse("Fail: toByteArray", !Arrays.equals(b, b1)); - - - byte [] b3 = new byte [40]; - t.toByteArray(b3, 10); - for (int i = 0; i>> (i * 8)); - } - - for (int i = 0; i < 8; i++) { - b[i + 8] = (byte) (r[1] >>> (i * 8)); - } - for (int i = 0; i < 8; i++) { - b[i + 16] = (byte) (r[2] >>> (i * 8)); - } - - - t = new GF2_192(b); - s = t.toLongArray(); - assertFalse("Fail: constructor on byte array of all 1s", r[0] != s[0] || r[1] != s[1] || r[2]!=s[2]); - - b1 = t.toByteArray(); - assertFalse("Fail: toByteArray all 1s", !Arrays.equals(b, b1)); - - b2 = new byte[30]; - for (int i=0; i<24; i++) { - b2[i+6]=b[i]; - } - t = new GF2_192(b2, 6); - s = t.toLongArray(); - assertFalse("Fail: constructor on byte array with offset of all 1s", r[0] != s[0] || r[1] != s[1] || r[2]!=s[2]); - - b1 = t.toByteArray(); - assertFalse("Fail: toByteArray all 1s", !Arrays.equals(b, b1)); - - b3 = new byte [40]; - t.toByteArray(b3, 10); - for (int i = 0; i klass) throws InitializationError { - super(klass); - } - - public static LinkedList splitCamelCaseString(String s) { - LinkedList result = new LinkedList(); - for (String w : s.split("(? ProveDlog( - CryptoConstants.dlogGroup.curve.decodePoint(point).asInstanceOf[CryptoConstants.EcPointType] + CryptoConstants.dlogGroup.ctx.decodePoint(point).asInstanceOf[CryptoConstants.EcPointType] ) }.get val regs = Map( diff --git a/sigmastate/src/test/scala/sigmastate/CrossVersionProps.scala b/sigmastate/src/test/scala/sigmastate/CrossVersionProps.scala index 183dc971a5..3b46ba4371 100644 --- a/sigmastate/src/test/scala/sigmastate/CrossVersionProps.scala +++ b/sigmastate/src/test/scala/sigmastate/CrossVersionProps.scala @@ -1,13 +1,14 @@ package sigmastate -import org.scalatest.{PropSpecLike, Tag} +import org.scalatest.Tag import org.scalactic.source.Position import sigmastate.eval.Profiler import debox.cfor +import org.scalatest.propspec.AnyPropSpecLike import scala.util.DynamicVariable -trait CrossVersionProps extends PropSpecLike with TestsBase { +trait CrossVersionProps extends AnyPropSpecLike with TestsBase { /** Number of times each test property is warmed up (i.e. executed before final execution). */ def perTestWarmUpIters: Int = 0 diff --git a/sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala index f3b45766c5..38e89b1212 100644 --- a/sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/ErgoTreeSpecification.scala @@ -1,8 +1,8 @@ package sigmastate import org.ergoplatform.settings.ErgoAlgos -import org.ergoplatform.validation.{ValidationRules, ValidationException} -import org.ergoplatform.{ErgoAddressEncoder, ErgoBox, Self, ErgoLikeContext} +import org.ergoplatform.validation.{ValidationException, ValidationRules} +import org.ergoplatform.{ErgoAddressEncoder, ErgoBox, ErgoLikeContext, Self} import scalan.RType.asType import scalan.{Nullable, RType} import sigmastate.SCollection.{SByteArray, checkValidFlatmap} @@ -11,10 +11,10 @@ import sigmastate.VersionContext._ import sigmastate.eval.{CostingBox, Evaluation, Profiler} import sigmastate.helpers.{ErgoLikeContextTesting, SigmaPPrint} import sigmastate.interpreter.ErgoTreeEvaluator -import sigmastate.interpreter.Interpreter.JitReductionResult +import sigmastate.interpreter.Interpreter.ReductionResult import sigmastate.lang.SourceContext import sigmastate.lang.Terms._ -import sigmastate.lang.exceptions.{InterpreterException, CostLimitException} +import sigmastate.lang.exceptions.{CostLimitException, InterpreterException} import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer import sigmastate.utils.Helpers.TryOps import sigmastate.utxo._ @@ -685,7 +685,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit { VersionContext.withVersions(activatedVersion = 1, tree.version) { // v4.x behavior val res = ErgoTreeEvaluator.evalToCrypto(createCtx, tree, evalSettings) - res shouldBe JitReductionResult(TrivialProp(true), 3) + res shouldBe ReductionResult(TrivialProp(true), 3) } VersionContext.withVersions(activatedVersion = 2, tree.version) { diff --git a/sigmastate/src/test/scala/sigmastate/SigmaProtocolSpecification.scala b/sigmastate/src/test/scala/sigmastate/SigmaProtocolSpecification.scala index b5381c2780..96931f5e84 100644 --- a/sigmastate/src/test/scala/sigmastate/SigmaProtocolSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/SigmaProtocolSpecification.scala @@ -1,7 +1,7 @@ package sigmastate -import gf2t.{GF2_192_Poly, GF2_192} import sigmastate.basics.VerifierMessage.Challenge +import sigmastate.crypto.{GF2_192, GF2_192_Poly} import special.sigma.SigmaTestingData class SigmaProtocolSpecification extends SigmaTestingData { diff --git a/sigmastate/src/test/scala/sigmastate/TestsBase.scala b/sigmastate/src/test/scala/sigmastate/TestsBase.scala index e2e952855b..8e7425cd1f 100644 --- a/sigmastate/src/test/scala/sigmastate/TestsBase.scala +++ b/sigmastate/src/test/scala/sigmastate/TestsBase.scala @@ -2,7 +2,7 @@ package sigmastate import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix import org.ergoplatform.ErgoScriptPredef -import org.scalatest.Matchers +import org.scalatest.matchers.should.Matchers import sigmastate.Values.{ErgoTree, SValue, SigmaBoolean, SigmaPropValue, Value} import sigmastate.eval.IRContext import sigmastate.helpers.SigmaPPrint @@ -65,9 +65,6 @@ trait TestsBase extends Matchers with VersionTesting { } } - def compileWithoutCosting(env: ScriptEnv, code: String): Value[SType] = - compiler.compileWithoutCosting(env, code) - /** Compile the given code to ErgoTree expression. */ def compile(env: ScriptEnv, code: String)(implicit IR: IRContext): Value[SType] = { val res = compiler.compile(env, code) diff --git a/sigmastate/src/test/scala/sigmastate/crypto/GF2_192_Specification.scala b/sigmastate/src/test/scala/sigmastate/crypto/GF2_192_Specification.scala new file mode 100644 index 0000000000..b415fc99bd --- /dev/null +++ b/sigmastate/src/test/scala/sigmastate/crypto/GF2_192_Specification.scala @@ -0,0 +1,693 @@ +package sigmastate.crypto + +import org.junit.Assert.assertFalse +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks + +import java.util +import java.util.{Arrays, Random} + +class GF2_192_Specification extends AnyPropSpec + with ScalaCheckDrivenPropertyChecks + with Matchers { + + private object GF2t_slow { + def mulBits(ret: GF2t_slow, a: Array[Long], b: Array[Long]): Unit = { + val c = new Array[Long](a.length + b.length) + + for ( i <- 0 until a.length ) { + for ( i1 <- 0 until 64 ) { + for ( j <- 0 until b.length ) { + for ( j1 <- 0 until 64 ) { + if ((a(i) & (1l << i1)) != 0 && (b(j) & (1l << j1)) != 0) { + val cPosition = i * 64 + i1 + j * 64 + j1 + c(cPosition / 64) ^= 1l << (cPosition % 64) + } + } + } + } + } + ret.x = c + } + + def modReduce(poly: GF2t_slow, mod: GF2t_slow.Modulus): Unit = { + for (i <- poly.x.length * 64 - 1 to mod.degree by -1) { + if ((poly.x(i >> 6) & (1l << (i & 63))) != 0) { + for ( j <- 0 until mod.offset.length ) { + val k = i - mod.offset(j) + poly.x(k >> 6) ^= (1l << (k & 63)) + } + } + } + } + + class Modulus private[crypto](val sparseModulus: Array[Int]) { + // represented as an array of bit positions + // where coefficient = 1, counting from degree down + final private[crypto] var offset: Array[Int] = new Array[Int](sparseModulus.length) + final private[crypto] var degree: Int = sparseModulus(0) + + offset(0) = 0 + for ( i <- 1 until sparseModulus.length ) { + offset(i) = degree - sparseModulus(i) + } + } + } + + private class GF2t_slow { + var x: Array[Long] = null + + def isOne: Boolean = { + if (x(0) != 1l) return false + for ( i <- 1 until x.length ) { + if (x(i) != 0l) return false + } + true + } + + def equals(that: Array[Long]): Boolean = { + var i = 0 + while ( i < Math.min(x.length, that.length) ) { + if (x(i) != that(i)) return false + i += 1 + } + while ( i < x.length ) { + if (x(i) != 0) return false + i += 1 + } + while ( i < that.length ) { + if (that(i) != 0) return false + i += 1 + } + true + } + + override def toString: String = { + var ret = "" + for ( i <- x.length - 1 to 0 by -1 ) { + ret += x(i) + } + ret + } + } + + private var testValues: Array[Array[Long]] = null + private val zero = new GF2_192(0) + private val one = new GF2_192(1) + private val pentanomial = Array(192, 7, 2, 1, 0) + private val m = new GF2t_slow.Modulus(pentanomial) + genTestValues() + + private def genTestValues(): Unit = { + if (testValues == null) { + testValues = new Array[Array[Long]](250) + for ( i <- 0 until testValues.length ) { + testValues(i) = new Array[Long](3) + } + + // Test single 1s in every bit position but last + // (1s in last bit position -- i.e., just the value of 1 -- will be tested separately) + + var j = 0 + var i = 1 + while ( i < 64 ) { + testValues(j)(0) = 1L << i + testValues(j)(1) = 0 + testValues(j)(2) = 0 + i += 1 + j += 1 + } + i = 0 + while ( i < 64 ) { + testValues(j)(0) = 0 + testValues(j)(1) = 1L << i + testValues(j)(2) = 0 + i += 1 + j += 1 + } + i = 0 + while ( i < 64 ) { + testValues(j)(0) = 0 + testValues(j)(1) = 0 + testValues(j)(2) = 1L << i + i += 1 + j += 1 + } + + // Test first word zero, last two words random, + // and first word random, last two words 0 + // and first word random, second word 1, last word 0 + // and last word random, first two words 0 + val rand = new Random + + i = 0 + while ( i < 5 ) { + testValues(j)(0) = 0 + testValues(j)(1) = rand.nextLong + testValues(j)(2) = rand.nextLong + i += 1 + j += 1 + } + i = 0 + while ( i < 5 ) { + testValues(j)(0) = rand.nextLong + testValues(j)(1) = 0 + testValues(j)(2) = 0 + i += 1 + j += 1 + } + i = 0 + while ( i < 5 ) { + testValues(j)(0) = rand.nextLong + testValues(j)(1) = 1 + testValues(j)(2) = 0 + i += 1 + j += 1 + } + + i = 0 + while ( i < 5 ) { + testValues(j)(0) = 0 + testValues(j)(1) = 1 + testValues(j)(2) = rand.nextLong + i += 1 + j += 1 + } + // Test all three words random + while ( j < testValues.length ) { + testValues(j)(0) = rand.nextLong + testValues(j)(1) = rand.nextLong + testValues(j)(2) = rand.nextLong + j += 1 + } + } + } + + property("constructorAndEqualityTest") { + var t = new GF2_192 + var r = t.toLongArray + assertFalse("Fail: empty constructor.", !t.isZero || r.length != 3 || r(0) != 0L || r(1) != 0L || r(2) != 0L) + + t = new GF2_192(0) + r = t.toLongArray + assertFalse("Fail: constructor on 0 int", !t.isZero || r.length != 3 || r(0) != 0L || r(1) != 0L || r(2) != 0L) + + t = new GF2_192(1) + r = t.toLongArray + assertFalse("Fail: constructor on 1 int", !t.isOne || r.length != 3 || r(0) != 1L || r(1) != 0L || r(2) != 0L) + + t = new GF2_192(-1) + r = t.toLongArray + assertFalse("Fail: constructor on 0xFFFFFFFF int " + t, r(0) != 0xFFFFFFFFL || r(1) != 0L || r(2) != 0L) + + var s = new Array[Long](3) + + s(0) = 123345L + s(1) = 123567891234567L + s(2) = 487237823242367L + + t = new GF2_192(s) + var t1 = new GF2_192(t) + + r = t.toLongArray + assertFalse("Fail: constructor on long array", r(0) != s(0) || r(1) != s(1) || r(2) != s(2)) + + r = t1.toLongArray + assertFalse("Fail: copy constructor", r(0) != s(0) || r(1) != s(1) || r(2) != s(2)) + + val b = new Array[Byte](24) + for ( i <- 0 until 8 ) { + b(i) = (r(0) >>> (i * 8)).toByte + } + for ( i <- 0 until 8 ) { + b(i + 8) = (r(1) >>> (i * 8)).toByte + } + for ( i <- 0 until 8 ) { + b(i + 16) = (r(2) >>> (i * 8)).toByte + } + + t = new GF2_192(b) + s = t.toLongArray + assertFalse("Fail: constructor on byte array", + r(0) != s(0) || r(1) != s(1) || r(2) != s(2)) + + val c = t.toByteArray + assertFalse("Fail: toByteArray", !Arrays.equals(b, c)) + + var b2 = new Array[Byte](30) + for ( i <- 0 until 24 ) { + b2(i + 6) = b(i) + } + + t = new GF2_192(b2, 6) + s = t.toLongArray + assertFalse("Fail: constructor on byte array with offset", + r(0) != s(0) || r(1) != s(1) || r(2) != s(2)) + + var b1 = t.toByteArray + assertFalse("Fail: toByteArray", !Arrays.equals(b, b1)) + + var b3 = new Array[Byte](40) + t.toByteArray(b3, 10) + for ( i <- 0 until b.length ) { + assertFalse("Fail: toByteArray with offset", + b3(i + 10) != b(i)) + } + + s(0) = 0xFFFFFFFFFFFFFFFFL + s(1) = 0xFFFFFFFFFFFFFFFFL + s(2) = 0xFFFFFFFFFFFFFFFFL + t = new GF2_192(s) + t1 = new GF2_192(t) + + r = t.toLongArray + assertFalse("Fail: constructor on long array of all 1s", + r(0) != s(0) || r(1) != s(1) || r(2) != s(2)) + + r = t1.toLongArray + assertFalse("Fail: copy constructor", + r(0) != s(0) || r(1) != s(1) || r(2) != s(2)) + + for ( i <- 0 until 8 ) { + b(i) = (r(0) >>> (i * 8)).toByte + } + + for ( i <- 0 until 8 ) { + b(i + 8) = (r(1) >>> (i * 8)).toByte + } + + for ( i <- 0 until 8 ) { + b(i + 16) = (r(2) >>> (i * 8)).toByte + } + + t = new GF2_192(b) + s = t.toLongArray + assertFalse("Fail: constructor on byte array of all 1s", + r(0) != s(0) || r(1) != s(1) || r(2) != s(2)) + + b1 = t.toByteArray + assertFalse("Fail: toByteArray all 1s", !Arrays.equals(b, b1)) + + b2 = new Array[Byte](30) + for ( i <- 0 until 24 ) { + b2(i + 6) = b(i) + } + t = new GF2_192(b2, 6) + s = t.toLongArray + assertFalse("Fail: constructor on byte array with offset of all 1s", + r(0) != s(0) || r(1) != s(1) || r(2) != s(2)) + + b1 = t.toByteArray + assertFalse("Fail: toByteArray all 1s", !Arrays.equals(b, b1)) + + b3 = new Array[Byte](40) + t.toByteArray(b3, 10) + for ( i <- 0 until b.length ) { + assertFalse("Fail: toByteArray all 1s with offset", b3(i + 10) != b(i)) + } + } + + property("pow2To2ToKTest") { + // includes squaring test + val res = new GF2_192 + var z: GF2_192 = null + val maxK = 15 + for ( k <- 0 until maxK ) { + GF2_192.power2To2ToK(res, zero, k) + assertFalse("Fail: power2To2ToK of 0 for k=" + k, !res.isZero) + + z = new GF2_192(zero) + GF2_192.power2To2ToK(z, z, k) + assertFalse("Fail: power2To2ToK of 0 in place for k=" + k, !z.isZero) + + GF2_192.power2To2ToK(res, one, k) + assertFalse("Fail: power2To2ToK of 1 for k=" + k, !res.isOne) + + z = new GF2_192(one) + GF2_192.power2To2ToK(z, z, k) + assertFalse("Fail: power2To2ToK of 1 in place for k=" + k, !z.isOne) + } + + GF2_192.sqr(res, zero) + assertFalse("Fail: sqr of 0", !res.isZero) + + z = new GF2_192(zero) + GF2_192.sqr(z, z) + assertFalse("Fail: sqr of 0 in place", !z.isZero) + + GF2_192.sqr(res, one) + assertFalse("Fail: sqr of 1", !res.isOne) + + z = new GF2_192(one) + GF2_192.sqr(z, z) + assertFalse("Fail: sqr of 1 in place", !z.isOne) + + val res1 = new GF2_192 + val res2 = new GF2_192 + for ( p <- testValues ) { + for ( k <- 0 until maxK ) { + z = new GF2_192(p) + GF2_192.power2To2ToK(res, z, k) + if (k == 0) { + // Ground truth for squaring: self-multiply + GF2_192.mul(res1, z, z) // sqr should equal power2To2ToK with k = 0 + assertFalse("Fail: power2To2To1 " + z, !(res == res1)) + GF2_192.sqr(res2, z) // sqr should equal self-multiply with k = 0 + assertFalse("Fail: sqr for k = " + k + " value = " + z, !(res == res2)) + } + else { + // res1 is the ground truth, computed using smaller values of k than is currently being tested + GF2_192.power2To2ToK(res1, res1, k - 1) + assertFalse("Fail: power2To2ToK for k = " + k + " value = " + z, !(res == res1)) + } + + // Input location = output location tests + GF2_192.power2To2ToK(z, z, k) // power2To2ToK into same location + assertFalse("Fail: power2To2ToK in place for k = " + k + " value = " + new GF2_192(p), !(res == z)) + if (k == 0) { + z = new GF2_192(p) + GF2_192.sqr(z, z) // sqr into same location + assertFalse("Fail: sqr in place " + new GF2_192(p), !(res == z)) + } + } + } + } + + property("specialMultTest") { + val res = new GF2_192 + val res1 = new GF2t_slow + + // Run everything times 0 and 0 times everything + // and everything times 1 and 1 times everything + // where 0 and 1 are GF2_192 + + for ( p <- testValues ) { + var p1 = new GF2_192(p) + GF2_192.mul(res, p1, zero) + assertFalse("Fail: " + p1 + " * 0", !res.isZero) + GF2_192.mul(p1, p1, zero) + assertFalse("Fail: " + p1 + " * 0" + " in place ", !p1.isZero) + p1 = new GF2_192(p) + GF2_192.mul(res, zero, p1) + assertFalse("Fail: 0 * " + p1, !res.isZero) + GF2_192.mul(p1, zero, p1) + assertFalse("Fail: 0 * " + p1 + " in place ", !p1.isZero) + p1 = new GF2_192(p) + GF2_192.mul(res, p1, one) + assertFalse("Fail: " + p1 + " * 1", !(res == p1)) + GF2_192.mul(p1, p1, one) + assertFalse("Fail: " + p1 + " * 1 in place", !(res == p1)) + GF2_192.mul(res, one, p1) + assertFalse("Fail: 1 * " + p1, !(res == p1)) + GF2_192.mul(p1, one, p1) + assertFalse("Fail: 1 * " + p1 + " in place", !(res == p1)) + } + + // Run everything times 0 + // and everything times 1 + // where 0 and 1 are bytes + for ( p <- testValues ) { + val p1 = new GF2_192(p) + GF2_192.mul(res, p1, 1.toByte) + assertFalse("Fail: " + p1 + " * 1 byte ", !(res == p1)) + GF2_192.mul(p1, p1, 1.toByte) + assertFalse("Fail: " + p1 + " * 1 byte in place", !(res == p1)) + GF2_192.mul(res, p1, 0.toByte) + assertFalse("Fail: " + p1 + " * 0 byte", !res.isZero) + GF2_192.mul(p1, p1, 0.toByte) + assertFalse("Fail: " + p1 + " * 0 byte in place", !p1.isZero) + } + + // Run everything times every byte + val temp = new Array[Long](1) + for ( p <- testValues ) { + for ( i <- 2 until 256 ) { + val p1 = new GF2_192(p) + temp(0) = i + GF2_192.mul(res, p1, i.toByte) + GF2t_slow.mulBits(res1, p, temp) + GF2t_slow.modReduce(res1, m) + assertFalse("Fail: " + p1 + " * " + i + " byte", !res1.equals(res.toLongArray)) + GF2_192.mul(p1, p1, i.toByte) + assertFalse("Fail: " + p1 + " * " + i + " byte in place", !(res == p1)) + } + } + } + + property("specialAddTest") { + val res = new GF2_192 + + // Run everything plus 0 and 0 plus everything + // where 0 is GF2_192 + for ( p <- testValues ) { + val p1 = new GF2_192(p) + GF2_192.add(res, p1, zero) + assertFalse(s"Fail: $p1 + 0", !(res == p1)) + GF2_192.add(p1, p1, zero) + assertFalse(s"Fail: $p1 + 0 in place", !(res == p1)) + GF2_192.add(res, zero, p1) + assertFalse(s"Fail: 0 + $p1", !(res == p1)) + GF2_192.add(p1, zero, p1) + assertFalse(s"Fail: $p1 + 0 in place", !(res == p1)) + } + } + + property("generalAddTest") { + val res = new GF2_192 + val res1 = new GF2t_slow + res1.x = new Array[Long](3) + + // Try everything plus everything in the test array + for ( p <- testValues ) { + var p1 = new GF2_192(p) + for ( q <- testValues ) { + val q1 = new GF2_192(q) + GF2_192.add(res, p1, q1) + res1.x(0) = p(0) ^ q(0) + res1.x(1) = p(1) ^ q(1) + res1.x(2) = p(2) ^ q(2) + assertFalse(s"Fail: $p1 + $q1 = $res not $res1", + !res1.equals(res.toLongArray)) + + GF2_192.add(p1, p1, q1) + assertFalse(s"Fail: $p1 + $q1 in place 1 ", !(res == p1)) + + p1 = new GF2_192(p) + GF2_192.add(q1, p1, q1) + assertFalse(s"Fail: $p1 + $q1 in place 2 ", !(res == q1)) + } + } + + // Try everything plus self in the test array, both in place and not, and make sure you get zeros + for ( p <- testValues ) { + val p1 = new GF2_192(p) + GF2_192.add(res, p1, p1) + assertFalse(s"Fail: $p1 + self", !res.isZero) + + GF2_192.add(p1, p1, p1) + assertFalse(s"Fail: $p1 self in place", !p1.isZero) + } + } + + property("generalMultTest") { + val res = new GF2_192 + val res1 = new GF2t_slow + + // Now run everything times everything in the test array + // TODO: speed this up + for ( p <- testValues ) { + var p1 = new GF2_192(p) + for ( q <- testValues ) { + val q1 = new GF2_192(q) + GF2_192.mul(res, p1, q1) + GF2t_slow.mulBits(res1, p, q) + GF2t_slow.modReduce(res1, m) + assertFalse(s"Fail: $p1 * $q1", !res1.equals(res.toLongArray)) + + GF2_192.mul(p1, p1, q1) + assertFalse(s"Fail: $p1 * $q1 in place 1 ", !(res == p1)) + + p1 = new GF2_192(p) + GF2_192.mul(q1, p1, q1) + assertFalse(s"Fail: $p1 * $q1 in place 2 ", !(res == q1)) + } + } + + // Try everything times self in the test array, in place + for ( p <- testValues ) { + val p1 = new GF2_192(p) + GF2_192.sqr(res, p1) + GF2_192.mul(p1, p1, p1) + assertFalse(s"Fail: $p1 * self in place", !(res == p1)) + } + } + + property("inversionTest") { + val res = new GF2_192 + val res2 = new GF2_192 + val res1 = new GF2t_slow + + // Test inversion of 1 + GF2_192.invert(res, one) + assertFalse("Fail: inversion of 1", !res.isOne) + + // Test inversion of everything + for ( p <- testValues ) { + val p1 = new GF2_192(p) + if (!p1.isZero) { + GF2_192.invert(res, p1) + GF2_192.mul(res2, p1, res) + assertFalse(s"Fail: inversion of $p1 self-test ", !res2.isOne) + + GF2t_slow.mulBits(res1, res.toLongArray, p) + GF2t_slow.modReduce(res1, m) + assertFalse(s"Fail: inversion of $p1 GF2t_slow-test", !res1.isOne) + + GF2_192.invert(p1, p1) + assertFalse(s"Fail: inversion of $p1 in place ", !(p1 == res)) + } + } + } + + property("interpolateTest") { + // Test for null inputs, arrays of unequal length, etc. + val optArray: Array[GF2_192] = new Array[GF2_192](2) + optArray(0) = null + optArray(1) = new GF2_192(17) + + var res: GF2_192_Poly = null + val rand: Random = new Random + + // Try with arrays of length 0 + var p = GF2_192_Poly.interpolate( + new Array[Byte](0), new Array[GF2_192](0), new GF2_192(0)) + assertFalse("Zero polynomial should be 0 at 0", !p.evaluate(0.toByte).isZero) + assertFalse("Zero polynomial should be 0 at 5", !p.evaluate(5.toByte).isZero) + + val val17 = new GF2_192(17) + p = GF2_192_Poly.interpolate(new Array[Byte](0), new Array[GF2_192](0), val17) + assertFalse("Constant 17 polynomial should be 17 at 0", !(p.evaluate(0.toByte) == val17)) + assertFalse("Constant 17 polynomial should be 17 at 5", !(p.evaluate(5.toByte) == val17)) + + for ( len <- 1 until 100 ) { + val points = new Array[Byte](len) + val values = new Array[GF2_192](len) + val temp = new Array[Byte](24) + for ( i <- 0 until len ) { + // generate a byte that is not equal to anything in the array nor 0 + var doLoop = true + while (doLoop) { + var b: Byte = 0 + do b = rand.nextInt.toByte while ( b == 0.toByte ) + var j: Int = 0 + var doBreak = false + while (!doBreak && j < i) { + if (b == points(j)) { // detected equality with something in the array + doBreak = true + } else { + j += 1 + } + } + if (j == i) { // did not detect equality with anything in the array + points(i) = b + doLoop = false + } + } + } + for ( i <- 0 until len ) { + rand.nextBytes(temp) + values(i) = new GF2_192(temp) + } + + res = GF2_192_Poly.interpolate(points, values, null) + for ( i <- 0 until len ) { + val t = res.evaluate(points(i)) + assertFalse(s"Interpolation error on length = $len at input point number $i", !(t == values(i))) + } + rand.nextBytes(temp) + val valueAt0 = new GF2_192(temp) + res = GF2_192_Poly.interpolate(points, values, valueAt0) + for ( i <- 0 until len ) { + val t = res.evaluate(points(i)) + assertFalse(s"Interpolation error on length = $len at input point number $i(with optional 0)", !(t == values(i))) + } + val t = res.evaluate(0.toByte) + assertFalse(s"Interpolation error on length = $len at input optional 0", !(t == valueAt0)) + + val b = res.toByteArray(false) + val t1 = GF2_192_Poly.fromByteArray(valueAt0.toByteArray, b) + val b1 = t1.toByteArray(false) + assertFalse( + s"To byte array round trip error ${util.Arrays.toString(b)} ${util.Arrays.toString(b1)}", + !Arrays.equals(b, b1)) + + val b2 = t1.toByteArray(true) + assertFalse("To byte array round trip error at coeff0", + !Arrays.equals(valueAt0.toByteArray, Arrays.copyOfRange(b2, 0, 24))) + assertFalse("To byte array round trip error with coeff0 at later coeff", + !Arrays.equals(b1, Arrays.copyOfRange(b2, 24, b2.length))) + + val b3 = t1.coeff0Bytes + assertFalse("To byte array round trip error on coeff0", + !Arrays.equals(b3, valueAt0.toByteArray)) + } + + for ( len <- 1 until 100 ) { + val points = new Array[Byte](len) + val values = new Array[GF2_192](len) + val temp = new Array[Byte](24) + + for ( i <- 0 until len ) { + // generate a byte that is not equal to anything in the array (but may be 0) + var okLoop = true + while (okLoop) { + val b = rand.nextInt.toByte + var j = 0 + j = 0 + var doBreak = false + while (!doBreak && j < i) { + if (b == points(j)) { + doBreak = true + } else { + j += 1 + } + } + if (j == i) { + points(i) = b + okLoop = false + } + } + } + for ( i <- 0 until len ) { + rand.nextBytes(temp) + values(i) = new GF2_192(temp) + } + + res = GF2_192_Poly.interpolate(points, values, null) + for ( i <- 0 until len ) { + val t = res.evaluate(points(i)) + assertFalse(s"Interpolation error on length = $len $i(with 0 allowed but not additional)", !(t == values(i))) + } + + for ( opt <- optArray ) { + res = GF2_192_Poly.interpolate(null, values, opt) + assertFalse("Fail: interpolate should output null on points = null", res != null) + res = GF2_192_Poly.interpolate(points, null, opt) + assertFalse("Fail: interpolate should output null on values = null", res != null) + res = GF2_192_Poly.interpolate(points, new Array[GF2_192](0), opt) + assertFalse("Fail: interpolate should output null on values of length 0", res != null) + res = GF2_192_Poly.interpolate(new Array[Byte](0), values, opt) + assertFalse("Fail: interpolate should output null on points of length 0", res != null) + res = GF2_192_Poly.interpolate(new Array[Byte](len - 1), values, opt) + assertFalse("Fail: interpolate should output null on not enough points", res != null) + res = GF2_192_Poly.interpolate(new Array[Byte](len + 1), values, opt) + assertFalse("Fail: interpolate should output null on too many points", res != null) + } + } + for ( opt <- optArray ) { + res = GF2_192_Poly.interpolate(null, null, opt) + assertFalse("Fail: interpolate should output null on both points and values = null", res != null) + } + } +} diff --git a/sigmastate/src/test/scala/sigmastate/crypto/GroupLawsSpecification.scala b/sigmastate/src/test/scala/sigmastate/crypto/GroupLawsSpecification.scala index b77d3c5b0a..b5b0b8b33b 100644 --- a/sigmastate/src/test/scala/sigmastate/crypto/GroupLawsSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/crypto/GroupLawsSpecification.scala @@ -1,11 +1,11 @@ package sigmastate.crypto import java.math.BigInteger - import org.scalacheck.Gen -import sigmastate.helpers.SigmaTestingCommons +import sigmastate.helpers.{SigmaPPrint, SigmaTestingCommons} import sigmastate.interpreter.CryptoConstants import sigmastate.interpreter.CryptoConstants.EcPointType +import sigmastate.utils.Helpers import scala.util.Random @@ -54,4 +54,52 @@ class GroupLawsSpecification extends SigmaTestingCommons { } } + private def printPoints(points: Seq[(String, Any)]) = { + points.foreach { case (name, p) => + println(s"val $name = ${SigmaPPrint.apply(p).plainText}") + } + } + +// uncommment to generate new test vectors +// +// property("generate initial points") { +// printPoints(Seq( +// "identity" -> group.identity, +// "order" -> group.order, +// "p1" -> group.createRandomElement(), +// "p2" -> group.createRandomElement(), +// "p3" -> group.createRandomElement() +// )) +// } + + val p1: Ecp = Helpers.decodeECPoint("0381c5275b1d50c39a0c36c4561c3a37bff1d87e37a9ad69eab029e426c0b1a8ac") + val p2 = Helpers.decodeECPoint("02198064ec24024bb8b300e20dd18e33cc1fccb0fea73940bd9a1d3d9d6c3ddd8f") + val p3 = Helpers.decodeECPoint("02e135f5f905fb843698d48959c6c792b2c6f9605b90be2280d53b4b69ef23e8a9") + +// uncommment to generate new test vectors + property("generate op results") { + printPoints(Seq( + "p1" -> p1, + "p2" -> p2, + "p3" -> p3, + "p1.add(p2)" -> CryptoFacade.multiplyPoints(p1, p2), + "p1.multiply(order)" -> CryptoFacade.exponentiatePoint(p1, group.order), + "p1.multiply(order + 1)" -> CryptoFacade.exponentiatePoint(p1, group.order.add(BigInteger.ONE)), + "p1.inverse" -> CryptoFacade.negatePoint(p1) + )) + } + + property("check test vectors") { + CryptoFacade.multiplyPoints(p1, p2) shouldBe + Helpers.decodeECPoint("03de5e9c2806c05cd45a57d18c469743f42a0d2c84370b6662eb39d8a2990abed8") + + CryptoFacade.exponentiatePoint(p1, group.order) shouldBe + Helpers.decodeECPoint("000000000000000000000000000000000000000000000000000000000000000000") + + CryptoFacade.exponentiatePoint(p1, group.order.add(BigInteger.ONE)) shouldBe + Helpers.decodeECPoint("0381c5275b1d50c39a0c36c4561c3a37bff1d87e37a9ad69eab029e426c0b1a8ac") + + CryptoFacade.negatePoint(p1) shouldBe + Helpers.decodeECPoint("0281c5275b1d50c39a0c36c4561c3a37bff1d87e37a9ad69eab029e426c0b1a8ac") + } } diff --git a/sigmastate/src/test/scala/sigmastate/eval/BasicOpsTests.scala b/sigmastate/src/test/scala/sigmastate/eval/BasicOpsTests.scala index 4d024fc33d..d4f05a4050 100644 --- a/sigmastate/src/test/scala/sigmastate/eval/BasicOpsTests.scala +++ b/sigmastate/src/test/scala/sigmastate/eval/BasicOpsTests.scala @@ -1,14 +1,16 @@ package sigmastate.eval +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.should.Matchers + import java.math.BigInteger -import org.bouncycastle.crypto.ec.CustomNamedCurves -import org.scalatest.{FunSuite, Matchers} import sigmastate.TrivialProp +import sigmastate.basics.SecP256K1Group import special.sigma.{ContractsTestkit, SigmaDslBuilder, SigmaProp} import scala.language.implicitConversions -class BasicOpsTests extends FunSuite with ContractsTestkit with Matchers { +class BasicOpsTests extends AnyFunSuite with ContractsTestkit with Matchers { override val SigmaDsl: SigmaDslBuilder = CostingSigmaDslBuilder implicit def boolToSigma(b: Boolean): SigmaProp = TrivialProp(b) @@ -33,7 +35,7 @@ class BasicOpsTests extends FunSuite with ContractsTestkit with Matchers { // TODO this is valid for BigIntModQ type (https://github.com/ScorexFoundation/sigmastate-interpreter/issues/554) ignore("ByteArrayToBigInt should always produce big int less than dlog group order") { - val groupOrder = CustomNamedCurves.getByName("secp256k1").getN + val groupOrder = SecP256K1Group.ctx.order SigmaDsl.byteArrayToBigInt( Colls.fromArray(groupOrder.subtract(BigInteger.ONE).toByteArray) diff --git a/sigmastate/src/test/scala/sigmastate/helpers/NegativeTesting.scala b/sigmastate/src/test/scala/sigmastate/helpers/NegativeTesting.scala index 798def6b18..25d7a9e384 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/NegativeTesting.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/NegativeTesting.scala @@ -1,10 +1,11 @@ package sigmastate.helpers -import org.scalatest.Matchers import scala.annotation.tailrec import scala.util.{Failure, Success, Try} import debox.cfor +import org.scalatest.matchers.should.Matchers + import scala.reflect.ClassTag trait NegativeTesting extends Matchers { diff --git a/sigmastate/src/test/scala/sigmastate/helpers/SigmaPPrint.scala b/sigmastate/src/test/scala/sigmastate/helpers/SigmaPPrint.scala index f9a5e64885..3122e2f5f0 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/SigmaPPrint.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/SigmaPPrint.scala @@ -1,7 +1,6 @@ package sigmastate.helpers import java.math.BigInteger -import gf2t.GF2_192_Poly import org.ergoplatform.ErgoBox import org.ergoplatform.ErgoBox.RegisterId import org.ergoplatform.settings.ErgoAlgos @@ -11,6 +10,7 @@ import scalan.RType.PrimitiveType import sigmastate.SCollection._ import sigmastate.Values.{ConstantNode, ErgoTree, FuncValue, ValueCompanion} import sigmastate._ +import sigmastate.crypto.GF2_192_Poly import sigmastate.interpreter.CryptoConstants.EcPointType import sigmastate.lang.SigmaTyper import sigmastate.lang.Terms.MethodCall @@ -111,7 +111,7 @@ object SigmaPPrint extends PPrinter { Tree.Apply("BigInt", treeifyMany(v.toString(16), 16)) case poly: GF2_192_Poly => - val c0 = poly.coeff0Bytes() + val c0 = poly.coeff0Bytes val others = poly.toByteArray(false) // don't output Tree.Apply("GF2_192_Poly.fromByteArray", treeifyMany(c0, others)) diff --git a/sigmastate/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala b/sigmastate/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala index b9fa6ffaba..69ed1a9c78 100644 --- a/sigmastate/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala +++ b/sigmastate/src/test/scala/sigmastate/helpers/SigmaTestingCommons.scala @@ -6,8 +6,10 @@ import org.ergoplatform.validation.ValidationRules.CheckSerializableTypeCode import org.ergoplatform.validation.{ValidationException, ValidationSpecification} import org.scalacheck.Arbitrary.arbByte import org.scalacheck.Gen -import org.scalatest.prop.{GeneratorDrivenPropertyChecks, PropertyChecks} -import org.scalatest.{Assertion, Matchers, PropSpec} +import org.scalatest.Assertion +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.{ScalaCheckDrivenPropertyChecks, ScalaCheckPropertyChecks} import scalan.util.BenchmarkUtil import scalan.{RType, TestContexts, TestUtils} import scorex.crypto.hash.Blake2b256 @@ -27,9 +29,9 @@ import scala.language.implicitConversions import scala.reflect.ClassTag import scala.util.DynamicVariable -trait SigmaTestingCommons extends PropSpec - with PropertyChecks - with GeneratorDrivenPropertyChecks +trait SigmaTestingCommons extends AnyPropSpec + with ScalaCheckPropertyChecks + with ScalaCheckDrivenPropertyChecks with Matchers with TestUtils with TestContexts with ValidationSpecification with NegativeTesting with TestsBase { diff --git a/sigmastate/src/test/scala/sigmastate/lang/LangTests.scala b/sigmastate/src/test/scala/sigmastate/lang/LangTests.scala index 634bb8f103..a512b25de9 100644 --- a/sigmastate/src/test/scala/sigmastate/lang/LangTests.scala +++ b/sigmastate/src/test/scala/sigmastate/lang/LangTests.scala @@ -1,12 +1,11 @@ package sigmastate.lang -import sigmastate.lang.Terms.{MethodCallLike, Ident} -import sigmastate.Values.{LongConstant, SValue, Value, SigmaBoolean, ConcreteCollection} +import org.scalatest.matchers.should.Matchers +import sigmastate.lang.Terms.{Ident, MethodCallLike} +import sigmastate.Values.{ConcreteCollection, LongConstant, SValue, SigmaBoolean, Value} import sigmastate._ -import java.math.BigInteger -import org.bouncycastle.math.ec.ECPoint -import org.scalatest.Matchers +import java.math.BigInteger import sigmastate.basics.DLogProtocol.ProveDlog import sigmastate.SCollection.SByteArray import sigmastate.basics.ProveDHTuple @@ -39,10 +38,10 @@ trait LangTests extends Matchers with NegativeTesting { 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]) + val g1 = CostingSigmaDslBuilder.GroupElement(ecp1) + val g2 = CostingSigmaDslBuilder.GroupElement(ecp2) + val g3 = CostingSigmaDslBuilder.GroupElement(ecp3) + val g4 = CostingSigmaDslBuilder.GroupElement(ecp4) protected val n1: BigInt = BigInt(10).underlying() protected val n2: BigInt = BigInt(20).underlying() @@ -75,7 +74,7 @@ trait LangTests extends Matchers with NegativeTesting { def ty(s: String): SType = SigmaParser.parseType(s) def assertSrcCtxForAllNodes(tree: SValue): Unit = { - import org.bitbucket.inkytonik.kiama.rewriting.Rewriter._ + import sigmastate.kiama.rewriting.Rewriter._ rewrite(everywherebu(rule[Any] { case node: SValue => withClue(s"Missing sourceContext for $node") { node.sourceContext.isDefined shouldBe true } diff --git a/sigmastate/src/test/scala/sigmastate/lang/SigmaBinderTest.scala b/sigmastate/src/test/scala/sigmastate/lang/SigmaBinderTest.scala index ad8db1ef17..a9404048ed 100644 --- a/sigmastate/src/test/scala/sigmastate/lang/SigmaBinderTest.scala +++ b/sigmastate/src/test/scala/sigmastate/lang/SigmaBinderTest.scala @@ -2,8 +2,9 @@ package sigmastate.lang import org.ergoplatform.{Height, Inputs, Outputs, Self} import org.ergoplatform.ErgoAddressEncoder._ -import org.scalatest.prop.PropertyChecks -import org.scalatest.{Matchers, PropSpec} +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import sigmastate.Values._ import sigmastate._ import sigmastate.interpreter.Interpreter.ScriptEnv @@ -12,7 +13,7 @@ import sigmastate.lang.Terms._ import sigmastate.lang.exceptions.BinderException import sigmastate.eval._ -class SigmaBinderTest extends PropSpec with PropertyChecks with Matchers with LangTests { +class SigmaBinderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with LangTests { import StdSigmaBuilder._ def bind(env: ScriptEnv, x: String): SValue = { diff --git a/sigmastate/src/test/scala/sigmastate/lang/SigmaBuilderTest.scala b/sigmastate/src/test/scala/sigmastate/lang/SigmaBuilderTest.scala index 07061743c4..3e25700816 100644 --- a/sigmastate/src/test/scala/sigmastate/lang/SigmaBuilderTest.scala +++ b/sigmastate/src/test/scala/sigmastate/lang/SigmaBuilderTest.scala @@ -1,13 +1,14 @@ package sigmastate.lang -import org.scalatest.prop.PropertyChecks -import org.scalatest.{Matchers, PropSpec} +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import sigmastate.Values._ import sigmastate._ import sigmastate.lang.exceptions.ConstraintFailed import sigmastate.serialization.OpCodes -class SigmaBuilderTest extends PropSpec with PropertyChecks with Matchers with LangTests { +class SigmaBuilderTest extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with LangTests { property("StdSigmaBuilder construct nodes") { import StdSigmaBuilder._ diff --git a/sigmastate/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala b/sigmastate/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala index 2d16830bb0..605082437f 100644 --- a/sigmastate/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala +++ b/sigmastate/src/test/scala/sigmastate/lang/SigmaCompilerTest.scala @@ -21,20 +21,12 @@ class SigmaCompilerTest extends SigmaTestingCommons with LangTests with ObjectGe 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) } diff --git a/sigmastate/src/test/scala/sigmastate/lang/SigmaParserTest.scala b/sigmastate/src/test/scala/sigmastate/lang/SigmaParserTest.scala index 7807a546a0..4b5680af0a 100644 --- a/sigmastate/src/test/scala/sigmastate/lang/SigmaParserTest.scala +++ b/sigmastate/src/test/scala/sigmastate/lang/SigmaParserTest.scala @@ -2,8 +2,9 @@ package sigmastate.lang import fastparse.Parsed import org.ergoplatform.{ErgoAddressEncoder, ErgoBox} -import org.scalatest.prop.PropertyChecks -import org.scalatest.{PropSpec, Matchers} +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import sigmastate.SCollection._ import sigmastate.Values._ import sigmastate._ @@ -12,7 +13,7 @@ import sigmastate.lang.Terms._ import sigmastate.lang.syntax.ParserException import sigmastate.serialization.OpCodes -class SigmaParserTest extends PropSpec with PropertyChecks with Matchers with LangTests { +class SigmaParserTest extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with LangTests { import StdSigmaBuilder._ private val predefFuncRegistry = new PredefinedFuncRegistry(StdSigmaBuilder) diff --git a/sigmastate/src/test/scala/sigmastate/lang/SigmaSpecializerTest.scala b/sigmastate/src/test/scala/sigmastate/lang/SigmaSpecializerTest.scala deleted file mode 100644 index b661ae5924..0000000000 --- a/sigmastate/src/test/scala/sigmastate/lang/SigmaSpecializerTest.scala +++ /dev/null @@ -1,229 +0,0 @@ -package sigmastate.lang - -import org.ergoplatform.ErgoAddressEncoder.{NetworkPrefix, TestnetNetworkPrefix} -import org.ergoplatform.ErgoBox.R4 -import org.ergoplatform._ -import org.scalatest.prop.PropertyChecks -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.{ConcreteCollectionGenerators, TransformerGenerators, ObjectGenerators} -import sigmastate.utxo._ -import sigmastate.lang.Terms._ - -class SigmaSpecializerTest extends PropSpec - with PropertyChecks - with Matchers - with LangTests - with ObjectGenerators - with ConcreteCollectionGenerators - with TransformerGenerators { - - private def countANDORInputNodes(root: Transformer[SCollection[SBoolean.type], SBoolean.type]): Int = - root.input.items.foldLeft(0) { (sum, item) => - item match { - case r@AND(_) => sum + countANDORInputNodes(r) - case r@OR(_) => sum + countANDORInputNodes(r) - case _ => sum + 1 - } - } - - def typed(env: Map[String, SValue], x: String): SValue = { - 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 typer = new SigmaTyper(builder, predefinedFuncRegistry, lowerMethodCalls = true) - val typed = typer.typecheck(bound) - typed - } - def spec(env: Map[String, SValue], typed: SValue, networkPrefix: NetworkPrefix = TestnetNetworkPrefix): SValue = { - val spec = new SigmaSpecializer(TransformingSigmaBuilder) - spec.specialize(env, typed) - } - def spec(code: String): SValue = { - spec(Map(), typed(Map(), code)) - } - def fail(env: Map[String, SValue], code: String, messageSubstr: String = ""): Unit = { - try { - spec(env, typed(env, code)) - assert(false, s"Should fail: $code") - } catch { - case e: SpecializerException => - if (messageSubstr.nonEmpty) - if (!e.getMessage.contains(messageSubstr)) { - throw new AssertionError(s"Error message '${e.getMessage}' doesn't contain '$messageSubstr'.", e) - } - } - } - - property("resolve let-bound names and substitute") { - spec(Map("X" -> LongConstant(10)), - Ident("X", SLong)) shouldBe LongConstant(10) - spec(Map("X" -> LongConstant(10)), - Plus(Ident("X", SLong).asValue[SLong.type], LongConstant(1))) shouldBe Plus(10L, 1L) - } - - property("substitute all val expressions in block result") { - spec("{ val X = 10; X }") shouldBe IntConstant(10) - spec("{ val X = 10; val Y = 20; X + Y }") shouldBe Plus(10, 20) - spec("{ val X = 10; val Y = 20; X + Y + X }") shouldBe Plus(Plus(10, 20), 10) - spec("{ val X = 10 + 1; X + X}") shouldBe Plus(Plus(10, 1), Plus(10, 1)) - spec("{ val X = 10; val Y = X; Y}") shouldBe IntConstant(10) - spec("{ val X = 10; val Y = X; val Z = Y; Z }") shouldBe IntConstant(10) - spec("{ val X = 10; val Y = X + 1; val Z = Y + X; Z + Y + X }") shouldBe - Plus(Plus(/*Z=*/Plus(/*Y=*/Plus(10, 1), 10), /*Y=*/Plus(10, 1)), 10) - } - - property("Tuple operations") { - spec("(1, 2L)._1") shouldBe SelectField(Tuple(IntConstant(1), LongConstant(2L)), 1) - spec("(1, 2L)._2") shouldBe SelectField(Tuple(IntConstant(1), LongConstant(2L)), 2) - spec("(1, 2L, 3)._3") shouldBe SelectField(Tuple(IntConstant(1), LongConstant(2L), IntConstant(3)), 3) - - // tuple as collection - spec("(1, 2L).size") shouldBe SizeOf(Tuple(IntConstant(1), LongConstant(2L))) -// spec(env, "(1, 2L)(0)") shouldBe SInt -// spec(env, "(1, 2L)(1)") shouldBe SLong -// spec(env, "(1, 2L).getOrElse(2, 3)") shouldBe SAny -// spec(env, "(1, 2L).slice(0, 2)") shouldBe SCollection(SAny) -// spec(env, "fun (a: Int) = (1, 2L)(a)") shouldBe SFunc(IndexedSeq(SInt), SAny) - } - - property("Option constructors") { - fail(Map(), "None", "Option constructors are not supported") - fail(Map(), "Some(10)", "Option constructors are not supported") - } - - property("generic methods of arrays") { - spec("OUTPUTS.map({ (out: Box) => out.value >= 10 })") shouldBe - MapCollection(Outputs, Lambda(Vector(("out", SBox)), SBoolean, GE(ExtractAmount(Ident("out", SBox).asBox), LongConstant(10)))) - spec("OUTPUTS.exists({ (out: Box) => out.value >= 10 })") shouldBe - Exists(Outputs, Lambda(Vector(("out", SBox)), SBoolean, GE(ExtractAmount(Ident("out", SBox).asBox), LongConstant(10)))) - spec("OUTPUTS.forall({ (out: Box) => out.value >= 10 })") shouldBe - ForAll(Outputs, Lambda(Vector(("out", SBox)), SBoolean, GE(ExtractAmount(Ident("out", SBox).asBox), LongConstant(10)))) - spec("{ val arr = Coll(1,2); arr.fold(0, { (n1: Int, n2: Int) => n1 + n2 })}") shouldBe - Fold(ConcreteCollection.fromItems(IntConstant(1), IntConstant(2)), - IntConstant(0), - Lambda(Vector(("n1", SInt), ("n2", SInt)), SInt, Plus(Ident("n1", SInt).asNumValue, Ident("n2", SInt).asNumValue))) - spec("{ val arr = Coll(1,2); arr.fold(true, {(n1: Boolean, n2: Int) => n1 && (n2 > 1)})}") shouldBe - Fold(ConcreteCollection.fromItems(IntConstant(1), IntConstant(2)), - TrueLeaf, - Lambda(Vector(("n1", SBoolean), ("n2", SInt)), SBoolean, - BinAnd(Ident("n1", SBoolean).asBoolValue, GT(Ident("n2", SInt), IntConstant(1)))) - ) - spec("OUTPUTS.slice(0, 10)") shouldBe - Slice(Outputs, IntConstant(0), IntConstant(10)) - spec("OUTPUTS.filter({ (out: Box) => out.value >= 10 })") shouldBe - Filter(Outputs, Lambda(Vector(("out", SBox)), SBoolean, GE(ExtractAmount(Ident("out", SBox).asBox), LongConstant(10)))) - } - - property("AND flattening predefined") { - spec("true && true") shouldBe BinAnd(TrueLeaf, TrueLeaf) - spec("true && false") shouldBe BinAnd(TrueLeaf, FalseLeaf) - spec("true && (true && 10 == 10)") shouldBe - BinAnd(TrueLeaf, BinAnd(TrueLeaf, EQ(IntConstant(10), IntConstant(10)))) - spec("true && true && true") shouldBe BinAnd(BinAnd(TrueLeaf, TrueLeaf), TrueLeaf) - spec("true && (true && (true && true)) && true") shouldBe - BinAnd(BinAnd(TrueLeaf, BinAnd(TrueLeaf, BinAnd(TrueLeaf, TrueLeaf))), TrueLeaf) - } - - property("AND flattening, CAND/COR untouched") { - val sigmaBooleans1 = AND(Array(TrueLeaf, CAND(Array(proveDlogGen.sample.get, proveDHTGen.sample.get)).toSigmaProp.isProven)) - spec(Map(), sigmaBooleans1) shouldBe sigmaBooleans1 - val sigmaBooleans2 = AND(Array(TrueLeaf, COR(Array(proveDlogGen.sample.get, proveDHTGen.sample.get)).toSigmaProp.isProven)) - spec(Map(), sigmaBooleans2) shouldBe sigmaBooleans2 - } - - property("AND flattening") { - forAll(logicalExprTreeNodeGen(Seq(AND.apply))) { tree => - val out = spec(Map(), tree).asInstanceOf[AND] - out.input.items.forall(!_.isInstanceOf[AND]) shouldBe true - countANDORInputNodes(tree) shouldBe out.input.items.length - } - } - - property("OR flattening predefined") { - spec("true || true || true") shouldBe BinOr(BinOr(TrueLeaf, TrueLeaf), TrueLeaf) - spec("true || (true || true) || true") shouldBe - BinOr(BinOr(TrueLeaf, BinOr(TrueLeaf, TrueLeaf)), TrueLeaf) - } - - property("XOR flattening predefined") { - spec("true ^ true ^ true") shouldBe BinXor(BinXor(TrueLeaf, TrueLeaf), TrueLeaf) - spec("true ^ (true ^ true) ^ true") shouldBe - BinXor(BinXor(TrueLeaf, BinXor(TrueLeaf, TrueLeaf)), TrueLeaf) - } - - property("OR flattening, CAND/COR untouched") { - val sigmaBooleans1 = OR(Array(TrueLeaf, CAND(Array(proveDlogGen.sample.get, proveDHTGen.sample.get)).toSigmaProp.isProven)) - spec(Map(), sigmaBooleans1) shouldBe sigmaBooleans1 - val sigmaBooleans2 = OR(Array(TrueLeaf, COR(Array(proveDlogGen.sample.get, proveDHTGen.sample.get)).toSigmaProp.isProven)) - spec(Map(), sigmaBooleans2) shouldBe sigmaBooleans2 - } - - property("OR flattening") { - forAll(logicalExprTreeNodeGen(Seq(OR.apply))) { tree => - val out = spec(Map(), tree).asInstanceOf[OR] - out.input.items.forall(!_.isInstanceOf[OR]) shouldBe true - countANDORInputNodes(tree) shouldBe out.input.items.length - } - } - - property("numeric casts") { - spec("1.toByte") shouldBe ByteConstant(1) - spec("1.toLong") shouldBe LongConstant(1) - spec("1.toBigInt") shouldBe BigIntConstant(1) - spec("HEIGHT.toLong") shouldBe Upcast(Height, SLong) - spec("HEIGHT.toByte") shouldBe Downcast(Height, SByte) - spec("INPUTS.size.toLong") shouldBe Upcast(SizeOf(Inputs), SLong) - spec("INPUTS.size.toBigInt") shouldBe Upcast(SizeOf(Inputs), SBigInt) - } - - property("failed numeric casts for constants") { - an[ArithmeticException] should be thrownBy spec("999.toByte") - an[ArithmeticException] should be thrownBy spec("999.toShort.toByte") - an[ArithmeticException] should be thrownBy spec(s"${Int.MaxValue}.toShort") - an[ArithmeticException] should be thrownBy spec(s"${Long.MaxValue}L.toInt") - } - - property("ExtractRegisterAs") { - spec("SELF.R4[Int]") shouldBe ExtractRegisterAs[SInt.type](Self, R4) - } - - property("OptionIsDefined") { - spec("SELF.R4[Int].isDefined") shouldBe ExtractRegisterAs[SInt.type](Self, R4).isDefined - spec("getVar[Int](1).isDefined") shouldBe GetVarInt(1).isDefined - } - - property("OptionGet") { - spec("SELF.R4[Int].get") shouldBe ExtractRegisterAs[SInt.type](Self, R4).get - spec("getVar[Int](1).get") shouldBe GetVarInt(1).get - } - - property("OptionGetOrElse") { - spec("SELF.R4[Int].getOrElse(0)") shouldBe ExtractRegisterAs[SInt.type](Self, R4).getOrElse(IntConstant(0)) - spec("getVar[Int](1).getOrElse(0)") shouldBe GetVarInt(1).getOrElse(IntConstant(0)) - } - - property("string concat") { - spec(""" "a" + "b" """) shouldBe StringConstant("ab") - } - - property("ExtractCreationInfo") { - spec("SELF.creationInfo") shouldBe ExtractCreationInfo(Self) - spec("SELF.creationInfo._1") shouldBe SelectField(ExtractCreationInfo(Self), 1) - spec("SELF.creationInfo._2") shouldBe SelectField(ExtractCreationInfo(Self), 2) - } - - property("sigmaProp") { - spec("sigmaProp(HEIGHT > 1000)") shouldBe BoolToSigmaProp(GT(Height, IntConstant(1000))) - } - - property("ZKProof") { - spec("ZKProof { sigmaProp(HEIGHT > 1000) }") shouldBe ZKProofBlock(BoolToSigmaProp(GT(Height, IntConstant(1000)))) - } -} diff --git a/sigmastate/src/test/scala/sigmastate/lang/SigmaTyperTest.scala b/sigmastate/src/test/scala/sigmastate/lang/SigmaTyperTest.scala index fc680bfcf9..3153344bbe 100644 --- a/sigmastate/src/test/scala/sigmastate/lang/SigmaTyperTest.scala +++ b/sigmastate/src/test/scala/sigmastate/lang/SigmaTyperTest.scala @@ -2,8 +2,9 @@ package sigmastate.lang import org.ergoplatform.ErgoAddressEncoder.TestnetNetworkPrefix import org.ergoplatform._ -import org.scalatest.prop.PropertyChecks -import org.scalatest.{Matchers, PropSpec} +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import sigmastate.SCollection._ import sigmastate.Values._ import sigmastate._ @@ -19,7 +20,8 @@ import sigmastate.serialization.ErgoTreeSerializer import sigmastate.serialization.generators.ObjectGenerators import sigmastate.utxo.{Append, ExtractCreationInfo} -class SigmaTyperTest extends PropSpec with PropertyChecks with Matchers with LangTests with ObjectGenerators { +class SigmaTyperTest extends AnyPropSpec + with ScalaCheckPropertyChecks with Matchers with LangTests with ObjectGenerators { private val predefFuncRegistry = new PredefinedFuncRegistry(StdSigmaBuilder) import predefFuncRegistry._ diff --git a/sigmastate/src/test/scala/sigmastate/serialization/AvlTreeSpecification.scala b/sigmastate/src/test/scala/sigmastate/serialization/AvlTreeSpecification.scala index 3c09275a1b..ed3382fa10 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/AvlTreeSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/AvlTreeSpecification.scala @@ -45,7 +45,7 @@ class AvlTreeSpecification extends SerializationSpecification { val k = Blake2b256.hash("1") val v = k - avlProver.performOneOperation(Insert(ADKey @@ k, ADValue @@ v)) + avlProver.performOneOperation(Insert(ADKey @@@ k, ADValue @@@ v)) val proof = avlProver.generateProof() val resTree = tree.insert(Array(k.toColl -> v.toColl).toColl, proof.toColl).get diff --git a/sigmastate/src/test/scala/sigmastate/serialization/DeserializationResilience.scala b/sigmastate/src/test/scala/sigmastate/serialization/DeserializationResilience.scala index d8733d89a9..22be862da2 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/DeserializationResilience.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/DeserializationResilience.scala @@ -403,10 +403,10 @@ class DeserializationResilience extends SerializationSpecification val tree = SigmaDsl.avlTree(treeData) val k = Blake2b256.hash("1") val v = k - avlProver.performOneOperation(Insert(ADKey @@ k, ADValue @@ v)) + avlProver.performOneOperation(Insert(ADKey @@@ k, ADValue @@@ v)) val proof = avlProver.generateProof() val verifier = tree.createVerifier(Colls.fromArray(proof)) - verifier.performOneOperation(Insert(ADKey @@ k, ADValue @@ v)).isFailure shouldBe true + verifier.performOneOperation(Insert(ADKey @@@ k, ADValue @@@ v)).isFailure shouldBe true // NOTE, even though performOneOperation fails, some AvlTree$ methods used in Interpreter // (remove_eval, update_eval, contains_eval) won't throw, while others will. } diff --git a/sigmastate/src/test/scala/sigmastate/serialization/GroupElementSerializerSpecification.scala b/sigmastate/src/test/scala/sigmastate/serialization/GroupElementSerializerSpecification.scala index dd17ce069f..5be6cc5ff9 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/GroupElementSerializerSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/GroupElementSerializerSpecification.scala @@ -1,5 +1,6 @@ package sigmastate.serialization +import sigmastate.crypto.CryptoFacade import sigmastate.interpreter.CryptoConstants import sigmastate.eval._ @@ -12,7 +13,7 @@ class GroupElementSerializerSpecification extends SerializationSpecification { val bytes = GroupElementSerializer.toBytes(identity) bytes.length shouldBe CryptoConstants.EncodedGroupElementLength bytes.forall(_ == 0) shouldBe true - GroupElementSerializer.parse(SigmaSerializer.startReader(bytes, 0)).isInfinity shouldBe true + GroupElementSerializer.parse(SigmaSerializer.startReader(bytes, 0)).isIdentity shouldBe true } property("point roundtrip") { @@ -20,8 +21,10 @@ class GroupElementSerializerSpecification extends SerializationSpecification { 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 + CryptoFacade.getAffineXCoord(CryptoFacade.normalizePoint(restored)) shouldBe + CryptoFacade.getAffineXCoord(CryptoFacade.normalizePoint(ge.value)) + CryptoFacade.getAffineYCoord(CryptoFacade.normalizePoint(restored)) shouldBe + CryptoFacade.getAffineYCoord(CryptoFacade.normalizePoint(ge.value)) } } } diff --git a/sigmastate/src/test/scala/sigmastate/serialization/SerializationSpecification.scala b/sigmastate/src/test/scala/sigmastate/serialization/SerializationSpecification.scala index 5ffc800191..03b8801459 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/SerializationSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/SerializationSpecification.scala @@ -2,17 +2,20 @@ package sigmastate.serialization import org.ergoplatform.validation.ValidationSpecification import org.scalacheck.Gen -import org.scalatest.prop.{PropertyChecks, TableDrivenPropertyChecks, GeneratorDrivenPropertyChecks} -import org.scalatest.{PropSpec, Assertion, Matchers} +import org.scalatest.prop.TableDrivenPropertyChecks +import org.scalatest.Assertion import org.scalacheck.Arbitrary._ +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.{ScalaCheckDrivenPropertyChecks, ScalaCheckPropertyChecks} import sigmastate.Values._ import sigmastate.SType import sigmastate.helpers.NegativeTesting import sigmastate.serialization.generators._ -trait SerializationSpecification extends PropSpec - with PropertyChecks - with GeneratorDrivenPropertyChecks +trait SerializationSpecification extends AnyPropSpec + with ScalaCheckPropertyChecks + with ScalaCheckDrivenPropertyChecks with TableDrivenPropertyChecks with Matchers with ObjectGenerators diff --git a/sigmastate/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala b/sigmastate/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala index 57a578174a..dbaa64f57e 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala @@ -2,8 +2,6 @@ package sigmastate.serialization import java.math.BigInteger import java.util - -import gf2t.GF2_192_Poly import org.ergoplatform.settings.ErgoAlgos import org.scalacheck.{Arbitrary, Gen} import org.scalatest.Assertion @@ -12,6 +10,7 @@ import sigmastate._ import sigmastate.basics.DLogProtocol.{ProveDlog, SecondDLogProverMessage} import sigmastate.basics.VerifierMessage.Challenge import sigmastate.basics.{ProveDHTuple, SecondDiffieHellmanTupleProverMessage} +import sigmastate.crypto.GF2_192_Poly import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTransactionTesting, SigmaTestingCommons} import sigmastate.interpreter.Interpreter import sigmastate.serialization.generators.ObjectGenerators diff --git a/sigmastate/src/test/scala/sigmastate/serialization/generators/ObjectGenerators.scala b/sigmastate/src/test/scala/sigmastate/serialization/generators/ObjectGenerators.scala index 537c616b05..b776bd8682 100644 --- a/sigmastate/src/test/scala/sigmastate/serialization/generators/ObjectGenerators.scala +++ b/sigmastate/src/test/scala/sigmastate/serialization/generators/ObjectGenerators.scala @@ -188,7 +188,7 @@ trait ObjectGenerators extends TypeGenerators def additionalTokensGen(cnt: Int): Seq[Gen[(Digest32, Long)]] = (0 until cnt).map { _ => for { - id <- Digest32 @@ boxIdGen + id <- Digest32 @@@ boxIdGen amt <- Gen.oneOf(1, 500, 20000, 10000000, Long.MaxValue) } yield id -> amt } @@ -202,8 +202,8 @@ trait ObjectGenerators extends TypeGenerators val unsignedShortGen: Gen[Short] = Gen.chooseNum(0, Short.MaxValue).map(_.toShort) val contextExtensionGen: Gen[ContextExtension] = for { - values <- Gen.sequence(contextExtensionValuesGen(0, 5)) - } yield ContextExtension(values.asScala.toMap) + values <- Gen.sequence(contextExtensionValuesGen(0, 5))(Buildable.buildableSeq) + } yield ContextExtension(values.toMap) val serializedProverResultGen: Gen[ProverResult] = for { length <- Gen.chooseNum(1, 100) @@ -252,7 +252,7 @@ trait ObjectGenerators extends TypeGenerators flags <- avlTreeFlagsGen keyLength <- unsignedIntGen vl <- arbOption[Int](Arbitrary(unsignedIntGen)).arbitrary - } yield AvlTreeData(ADDigest @@ digest, flags, keyLength, vl) + } yield AvlTreeData(ADDigest @@@ digest, flags, keyLength, vl) def avlTreeGen: Gen[AvlTree] = avlTreeDataGen.map(SigmaDsl.avlTree) @@ -315,14 +315,14 @@ trait ObjectGenerators extends TypeGenerators tId <- modifierIdGen boxId <- unsignedShortGen tokensCount <- Gen.chooseNum[Int](0, MaxTokens) - tokens <- Gen.sequence(additionalTokensGen(tokensCount)).map(_.asScala.map(_._1)) + tokens <- Gen.sequence(additionalTokensGen(tokensCount))(Buildable.buildableSeq).map(_.map(_._1)) candidate <- ergoBoxCandidateGen(tokens.toSeq) } yield candidate.toBox(tId, boxId) val additionalRegistersGen: Gen[Map[NonMandatoryRegisterId, EvaluatedValue[SType]]] = for { regNum <- Gen.chooseNum[Byte](0, ErgoBox.nonMandatoryRegistersCount) - regs <- Gen.sequence(additionalRegistersGen(regNum)) - } yield regs.asScala.toMap + regs <- Gen.sequence(additionalRegistersGen(regNum))(Buildable.buildableSeq) + } yield regs.toMap def arrayOfN[T](n: Int, g: Gen[T])(implicit evb: Buildable[T,Array[T]]): Gen[Array[T]] = { Gen.containerOfN[Array, T](n, g) diff --git a/sigmastate/src/test/scala/sigmastate/utils/HelpersTests.scala b/sigmastate/src/test/scala/sigmastate/utils/HelpersTests.scala index 3ce1f60473..2578553c9f 100644 --- a/sigmastate/src/test/scala/sigmastate/utils/HelpersTests.scala +++ b/sigmastate/src/test/scala/sigmastate/utils/HelpersTests.scala @@ -1,11 +1,12 @@ package sigmastate.utils -import org.scalatest.prop.PropertyChecks -import org.scalatest.{PropSpec, Matchers} import sigmastate.serialization.generators.ObjectGenerators import Helpers._ +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks -class HelpersTests extends PropSpec with PropertyChecks with Matchers with ObjectGenerators { +class HelpersTests extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with ObjectGenerators { property("xorU") { forAll(arrayGen[Byte]) { arr => diff --git a/sigmastate/src/test/scala/sigmastate/utils/SparseArrayContainerSpecification.scala b/sigmastate/src/test/scala/sigmastate/utils/SparseArrayContainerSpecification.scala index b1f6a5705f..0f6b69b78f 100644 --- a/sigmastate/src/test/scala/sigmastate/utils/SparseArrayContainerSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utils/SparseArrayContainerSpecification.scala @@ -1,13 +1,14 @@ package sigmastate.utils import org.scalacheck.{Arbitrary, Gen} -import org.scalatest.prop.PropertyChecks -import org.scalatest.{Matchers, PropSpec} +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import sigmastate.serialization.generators.ObjectGenerators -class SparseArrayContainerSpecification extends PropSpec +class SparseArrayContainerSpecification extends AnyPropSpec with ObjectGenerators - with PropertyChecks + with ScalaCheckPropertyChecks with Matchers { private val distinctCodeValuePairsGen: Gen[Seq[(Byte, Long)]] = for { diff --git a/sigmastate/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala index e7abf54a0a..8d4ac696be 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/AVLTreeScriptsSpecification.scala @@ -1,6 +1,6 @@ package sigmastate.utxo -import com.google.common.primitives.Longs +import scorex.utils.Longs import org.ergoplatform._ import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, TestContractSpec} import scorex.crypto.authds.avltree.batch._ @@ -31,8 +31,8 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons 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) + def genKey(str: String): ADKey = ADKey @@@ Blake2b256("key: " + str) + def genValue(str: String): ADValue = ADValue @@@ Blake2b256("val: " + str) val inKey = genKey("init key") val inValue = genValue("init value") @@ -231,7 +231,7 @@ class AVLTreeScriptsSpecification extends SigmaTestingCommons 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 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() diff --git a/sigmastate/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala index 11ba35d60c..d9b3453777 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/ErgoLikeInterpreterSpecification.scala @@ -1,6 +1,6 @@ package sigmastate.utxo -import com.google.common.primitives.Bytes +import scorex.utils.Bytes import org.ergoplatform.ErgoBox.R4 import org.ergoplatform._ import org.ergoplatform.validation.ValidationException diff --git a/sigmastate/src/test/scala/sigmastate/utxo/ProverSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/ProverSpecification.scala index d5f76503b4..88b29bac4f 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/ProverSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/ProverSpecification.scala @@ -5,7 +5,7 @@ import scorex.crypto.hash.Blake2b256 import sigmastate.Values.SigmaBoolean import sigmastate._ import sigmastate.basics.DLogProtocol.FirstDLogProverMessage -import sigmastate.basics.{FirstDiffieHellmanTupleProverMessage, SecP256K1} +import sigmastate.basics.{FirstDiffieHellmanTupleProverMessage, SecP256K1Group} import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, SigmaTestingCommons} import sigmastate.interpreter.{HintsBag, ProverInterpreter} import sigmastate.lang.exceptions.InterpreterException @@ -38,7 +38,7 @@ class ProverSpecification extends SigmaTestingCommons { val r = h.ownCommitments.head.secretRandomness // g^r == a - SecP256K1.exponentiate(SecP256K1.generator, r) shouldBe a.ecData + SecP256K1Group.exponentiate(SecP256K1Group.generator, r) shouldBe a.ecData val h2 = prover.generateCommitmentsFor(pk3, Seq(pk)) h2.hints.size shouldBe 2 diff --git a/sigmastate/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala b/sigmastate/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala index 5165517071..3bf3f0cf08 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/SerializationRoundTripSpec.scala @@ -1,17 +1,18 @@ package sigmastate.utxo import org.ergoplatform._ -import org.scalatest.prop.GeneratorDrivenPropertyChecks -import org.scalatest.{PropSpec, Matchers} import scalan.util.BenchmarkUtil import sigmastate.helpers.SigmaTestingCommons -import sigmastate.interpreter.{ProverResult, ContextExtension} +import sigmastate.interpreter.{ContextExtension, ProverResult} import sigmastate.serialization.generators.ObjectGenerators import debox.{Buffer => DBuffer} +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks import sigmastate.util.{MaxArrayLength, safeNewArray} -class SerializationRoundTripSpec extends PropSpec - with GeneratorDrivenPropertyChecks +class SerializationRoundTripSpec extends AnyPropSpec + with ScalaCheckDrivenPropertyChecks with Matchers with ObjectGenerators with SigmaTestingCommons { diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchange.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchange.scala index ecf843efe1..17de1cd96f 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchange.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsAtomicExchange.scala @@ -26,7 +26,7 @@ case class AssetsAtomicExchange[Spec <: ContractSpec] lazy val buyerProp = proposition("buyer", { ctx: Context => import ctx._ - (HEIGHT > deadline && pkA) || { + (HEIGHT > deadline && pkA) || sigmaProp({ val tokenData = OUTPUTS(0).R2[Coll[(Coll[Byte], Long)]].get(0) val knownId = OUTPUTS(0).R4[Coll[Byte]].get == SELF.id allOf(Coll( @@ -35,7 +35,7 @@ case class AssetsAtomicExchange[Spec <: ContractSpec] OUTPUTS(0).propositionBytes == pkA.propBytes, knownId )) - } + }) }, """{ | (HEIGHT > deadline && pkA) || { @@ -52,14 +52,14 @@ case class AssetsAtomicExchange[Spec <: ContractSpec] lazy val sellerProp = proposition("seller", {ctx: Context => import ctx._ - (HEIGHT > deadline && pkB) || { + (HEIGHT > deadline && pkB) || sigmaProp({ val knownBoxId = OUTPUTS(1).R4[Coll[Byte]].get == SELF.id allOf(Coll( OUTPUTS(1).value >= 100L, knownBoxId, OUTPUTS(1).propositionBytes == pkB.propBytes )) - } + }) }, """{ | (HEIGHT > deadline && pkB) || diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala index 5724ac2fe4..448f9e4801 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/AssetsPartialFilling.scala @@ -21,7 +21,7 @@ case class AssetsPartialFilling[Spec <: ContractSpec] lazy val buyerProp = proposition("buyer", { ctx: Context => import ctx._ - (HEIGHT > deadline && pkA) || { + (HEIGHT > deadline && pkA) || sigmaProp({ val outIdx = getVar[Short](127).get val out = OUTPUTS(outIdx) @@ -38,7 +38,7 @@ case class AssetsPartialFilling[Spec <: ContractSpec] out.propositionBytes == pkA.propBytes, out.R4[Coll[Byte]].get == SELF.id )) - } + }) }, """(HEIGHT > deadline && pkA) || { | @@ -62,7 +62,7 @@ case class AssetsPartialFilling[Spec <: ContractSpec] lazy val sellerProp = proposition("seller", {ctx: Context => import ctx._ - (HEIGHT > deadline && pkB) || { + (HEIGHT > deadline && pkB) || sigmaProp({ val outIdx = getVar[Short](127).get val out = OUTPUTS(outIdx) @@ -88,7 +88,7 @@ case class AssetsPartialFilling[Spec <: ContractSpec] outR4 == SELF.id, out.propositionBytes == pkB.propBytes )) - } + }) }, """ (HEIGHT > deadline && pkB) || { | val outIdx = getVar[Short](127).get diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala index cba2d96e96..9b585a823b 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/CoinEmissionSpecification.scala @@ -2,9 +2,8 @@ package sigmastate.utxo.examples import org.ergoplatform._ import org.ergoplatform.settings.ErgoAlgos -import scorex.util.ScorexLogging -import sigmastate.Values.{ErgoTree, IntConstant} -import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, SigmaTestingCommons} +import sigmastate.Values.{BlockValue, ErgoTree, IntConstant, LongConstant, ValDef, ValUse} +import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, SigmaPPrint, SigmaTestingCommons} import sigmastate.helpers.TestingHelpers._ import sigmastate.interpreter.ContextExtension import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv} @@ -22,7 +21,7 @@ import sigmastate.eval._ * defined in ErgoScriptPredef. */ class CoinEmissionSpecification extends SigmaTestingCommons - with ScorexLogging with CrossVersionProps { + with CrossVersionProps { // don't use TestingIRContext, this suite also serves the purpose of testing the RuntimeIRContext implicit lazy val IR: TestingIRContext = new TestingIRContext { // uncomment if you want to log script evaluation @@ -30,6 +29,10 @@ class CoinEmissionSpecification extends SigmaTestingCommons saveGraphsInFile = false } + protected def logMessage(msg: String) = { + println(msg) + } + private val reg1 = ErgoBox.nonMandatoryRegisters.head private val coinsInOneErgo: Long = 100000000 @@ -90,7 +93,7 @@ block 1600 in 1622 ms, 30000000000 coins remain, defs: 61661 val register = reg1 val prover = new ContextEnrichingTestProvingInterpreter() - val rewardOut = ByIndex(Outputs, IntConstant(0)) + val rewardOut = ValUse(1, SBox) val epoch = Upcast( @@ -103,14 +106,24 @@ block 1600 in 1622 ms, 30000000000 coins remain, defs: 61661 ) val sameScriptRule = EQ(ExtractScriptBytes(Self), ExtractScriptBytes(rewardOut)) 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 prop = BinOr( - AND(heightCorrect, heightIncreased, sameScriptRule, correctCoinsConsumed), - BinAnd(heightIncreased, lastCoins) - ).toSigmaProp + val correctCoinsConsumed = EQ( + coinsToIssue, + Minus(ValUse(3, SLong), ExtractAmount(rewardOut)) + ) + + val prop = BlockValue( + Array( + ValDef(1, List(), ByIndex(Outputs, IntConstant(0), None)), + ValDef(2, List(), GT(Height, OptionGet(ExtractRegisterAs(Self, ErgoBox.R4, SOption(SInt))))), + ValDef(3, List(), ExtractAmount(Self)) + ), + BoolToSigmaProp(BinOr( + AND(heightCorrect, ValUse(2, SBoolean), sameScriptRule, correctCoinsConsumed), + BinAnd( + ValUse(2, SBoolean), + LE(ValUse(3, SLong), LongConstant(s.oneEpochReduction))) + )) + ).asSigmaProp val tree = mkTestErgoTree(prop) val env = Map("fixedRatePeriod" -> s.fixedRatePeriod, @@ -118,7 +131,7 @@ block 1600 in 1622 ms, 30000000000 coins remain, defs: 61661 "fixedRate" -> s.fixedRate, "oneEpochReduction" -> s.oneEpochReduction) - val prop1 = compileWithoutCosting(env, + val prop1 = compile(env, """{ | val epoch = 1 + ((HEIGHT - fixedRatePeriod) / epochLength) | val out = OUTPUTS(0) @@ -208,7 +221,7 @@ block 1600 in 1622 ms, 30000000000 coins remain, defs: 61661 val newEmissionBox = newState.boxesReader.byId(tx.outputs.head.id).get chainGen(newState, newEmissionBox, height + 1, hLimit) } else { - log.debug(s"Emission box is consumed at height $height") + logMessage(s"Emission box is consumed at height $height") } } diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/CrowdFunding.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/CrowdFunding.scala index 8e3e015d7d..ebbf021fb8 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/CrowdFunding.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/CrowdFunding.scala @@ -25,7 +25,7 @@ case class CrowdFunding[Spec <: ContractSpec] } val fundraisingSuccess = HEIGHT < deadline && pkProject && - OUTPUTS.exists(enoughRaised) + sigmaProp(OUTPUTS.exists(enoughRaised)) fundraisingFailure || fundraisingSuccess }, @@ -52,9 +52,9 @@ case class CrowdFunding[Spec <: ContractSpec] val c1 = HEIGHT >= deadline && pkBacker val c2 = HEIGHT < deadline && pkProject && - OUTPUTS.exists({ (out: Box) => + sigmaProp(OUTPUTS.exists({ (out: Box) => out.value >= minToRaise && out.propositionBytes == pkProject.propBytes - }) + })) c1 || c2 }, """ diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala index 8cd017d6e9..657beb98ab 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/DHTupleExampleSpecification.scala @@ -35,7 +35,7 @@ class DHTupleExampleSpecification extends SigmaTestingCommons 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 g_x = alicePubKey.value // g_x is Alice's public key (g_x = g^x) val env = Map( ScriptNameProp -> "env", @@ -63,7 +63,7 @@ class DHTupleExampleSpecification extends SigmaTestingCommons 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_y = GroupElementConstant(bobPubKey.value) // Bob's public key g^y val g_xy = GroupElementConstant(dlogGroup.exponentiate(g_x, y)) // g^xy diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/DummyExamplesSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/DummyExamplesSpecification.scala index 2a2f2b2f7b..8e1cf9936a 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/DummyExamplesSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/DummyExamplesSpecification.scala @@ -31,7 +31,7 @@ class DummyExamplesSpecification extends SigmaTestingCommons { suite => } def getRoot(item: Coll[Byte]):Coll[Byte] = path.foldLeft(item, xor) - pkA && getRoot(oldItem) == oldRoot && getRoot(newItem) == newRoot + pkA && sigmaProp(getRoot(oldItem) == oldRoot) && sigmaProp(getRoot(newItem) == newRoot) val dummy = Coll[Byte]() val isValid = {(b:Box) => b.propositionBytes == dummy} diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/IcoExample.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/IcoExample.scala index 790cf69afc..5b47961119 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/IcoExample.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/IcoExample.scala @@ -1,6 +1,6 @@ package sigmastate.utxo.examples -import com.google.common.primitives.Longs +import scorex.utils.Longs import org.ergoplatform.ErgoBox.{R4, R5} import org.ergoplatform._ import org.ergoplatform.dsl.TestContractSpec @@ -440,7 +440,7 @@ class IcoExample extends SigmaTestingCommons val projectBoxBeforeClosing = testBox(10, issuanceTree, 0, Seq(), Map(R4 -> ByteArrayConstant(Array.emptyByteArray), R5 -> AvlTreeConstant(openTreeData))) - val tokenId = Digest32 @@ projectBoxBeforeClosing.id + val tokenId = Digest32 @@@ projectBoxBeforeClosing.id val closedTreeData = SigmaDsl.avlTree(new AvlTreeData(digest, AvlTreeFlags.RemoveOnly, 32, None)) val projectBoxAfterClosing = testBox(1, withdrawalTree, 0, @@ -481,7 +481,7 @@ class IcoExample extends SigmaTestingCommons } funderKvs.foreach { case (k, v) => - avlProver.performOneOperation(Insert(ADKey @@ k, ADValue @@ v)) + avlProver.performOneOperation(Insert(ADKey @@@ k, ADValue @@ v)) } val digest = avlProver.digest val fundersTree = new AvlTreeData(digest, AvlTreeFlags.RemoveOnly, 32, None) @@ -492,12 +492,12 @@ class IcoExample extends SigmaTestingCommons avlProver.generateProof() withdrawals.foreach { case (k, _) => - avlProver.performOneOperation(Lookup(ADKey @@ k)) + avlProver.performOneOperation(Lookup(ADKey @@@ k)) } val lookupProof = avlProver.generateProof() withdrawals.foreach { case (k, _) => - avlProver.performOneOperation(Remove(ADKey @@ k)) + avlProver.performOneOperation(Remove(ADKey @@@ k)) } val removalProof = avlProver.generateProof() diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala index 2639522f64..63182e2a1a 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/LetsSpecification.scala @@ -291,9 +291,9 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui R4 -> AvlTreeConstant(SigmaDsl.avlTree(initTreeData)), R5 -> SigmaPropConstant(TrivialProp.TrueProp))) - val userTokenId = Digest32 @@ projectBoxBefore.id + val userTokenId = Digest32 @@@ projectBoxBefore.id - avlProver.performOneOperation(Insert(ADKey @@ userTokenId, ADValue @@ Array.emptyByteArray)) + avlProver.performOneOperation(Insert(ADKey @@@ userTokenId, ADValue @@ Array.emptyByteArray)) val proof = avlProver.generateProof() val endTree = new AvlTreeData(avlProver.digest, AvlTreeFlags.InsertOnly, 32, None) @@ -330,14 +330,14 @@ class LetsSpecification extends SigmaTestingCommons with CrossVersionProps { sui val userTokenId1 = Digest32 @@ Array.fill(32)(Random.nextInt(100).toByte) val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None) - avlProver.performOneOperation(Insert(ADKey @@ userTokenId0, ADValue @@ Array.emptyByteArray)) - avlProver.performOneOperation(Insert(ADKey @@ userTokenId1, ADValue @@ Array.emptyByteArray)) + avlProver.performOneOperation(Insert(ADKey @@@ userTokenId0, ADValue @@ Array.emptyByteArray)) + avlProver.performOneOperation(Insert(ADKey @@@ userTokenId1, ADValue @@ Array.emptyByteArray)) val digest = avlProver.digest avlProver.generateProof() val initTreeData = new AvlTreeData(digest, AvlTreeFlags.InsertOnly, 32, None) - avlProver.performOneOperation(Lookup(ADKey @@ userTokenId0)) - avlProver.performOneOperation(Lookup(ADKey @@ userTokenId1)) + avlProver.performOneOperation(Lookup(ADKey @@@ userTokenId0)) + avlProver.performOneOperation(Lookup(ADKey @@@ userTokenId1)) val proof = avlProver.generateProof() val managementTree = mkTestErgoTree(managementScript) diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala index 3a5d28b45c..2de3395431 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/MASTExampleSpecification.scala @@ -83,7 +83,7 @@ class MASTExampleSpecification extends SigmaTestingCommons val allSecrets = (0 until 5).map(_ => Random.nextString(32).getBytes("UTF-8")) val scriptBranches = allSecrets.map(s => EQ(ByteArrayConstant(s), GetVarByteArray(secretId).get)) val scriptBranchesBytes = scriptBranches.map(b => ValueSerializer.serialize(b)) - val treeElements: Seq[(ADKey, ADValue)] = scriptBranchesBytes.map(s => (ADKey @@ Blake2b256(s), ADValue @@ s)) + val treeElements: Seq[(ADKey, ADValue)] = scriptBranchesBytes.map(s => (ADKey @@@ Blake2b256(s), ADValue @@ s)) val knownSecretTreeKey = treeElements.head._1 val knownSecret = ByteArrayConstant(allSecrets.head) diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala index b626751312..99806ca35b 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/MixExampleSpecification.scala @@ -30,7 +30,7 @@ class MixExampleSpecification extends SigmaTestingCommons val x: BigInteger = alice.dlogSecrets.head.w // x is Alice's private key - val gX = alicePubKey.h // g_x is Alice's public key (g_x = g^x) + val gX = alicePubKey.value // g_x is Alice's public key (g_x = g^x) // Alternative 1: // val g_x = alicePubKey.value // Alternative 2: @@ -118,7 +118,7 @@ class MixExampleSpecification extends SigmaTestingCommons val y: BigInteger = bob.dlogSecrets.head.w // y is Bob's private key - val gY = GroupElementConstant(bobPubKey.h) // g^y + val gY = GroupElementConstant(bobPubKey.value) // g^y val gY_alt = GroupElementConstant(dlogGroup.exponentiate(g, y)) gY shouldBe gY_alt diff --git a/sigmastate/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala b/sigmastate/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala index 3774e5ddc2..5ec589587f 100644 --- a/sigmastate/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala +++ b/sigmastate/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala @@ -2,7 +2,7 @@ package sigmastate.utxo.examples import java.security.SecureRandom -import com.google.common.primitives.Longs +import scorex.utils.Longs import org.ergoplatform.ErgoBox.RegisterId import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert, Lookup} import scorex.crypto.authds.{ADKey, ADValue} @@ -114,7 +114,7 @@ class OracleExamplesSpecification extends SigmaTestingCommons val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None) - avlProver.performOneOperation(Insert(ADKey @@ oracleBox.id, ADValue @@ oracleBox.bytes)) + avlProver.performOneOperation(Insert(ADKey @@@ oracleBox.id, ADValue @@ oracleBox.bytes)) avlProver.generateProof() val lastBlockUtxoDigest = avlProver.digest @@ -153,7 +153,7 @@ class OracleExamplesSpecification extends SigmaTestingCommons ), contractLogic) - avlProver.performOneOperation(Lookup(ADKey @@ oracleBox.id)) + avlProver.performOneOperation(Lookup(ADKey @@@ oracleBox.id)) val proof = avlProver.generateProof() val newBox1 = testBox(20, alicePubKey, 0, boxIndex = 2) diff --git a/sigmastate/src/test/scala/special/sigma/SigmaDslSpecification.scala b/sigmastate/src/test/scala/special/sigma/SigmaDslSpecification.scala index 5b6b29b665..0e0b50dacd 100644 --- a/sigmastate/src/test/scala/special/sigma/SigmaDslSpecification.scala +++ b/sigmastate/src/test/scala/special/sigma/SigmaDslSpecification.scala @@ -3949,15 +3949,6 @@ class SigmaDslSpecification extends SigmaDslTesting FuncValue(Vector((1, SByteArray)), ByteArrayToLong(ValUse(1, SByteArray))))) } - // TODO soft-fork: 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)) - // } - property("Box properties equivalence") { verifyCases( { diff --git a/sigmastate/src/test/scala/special/sigma/SigmaDslStaginTests.scala b/sigmastate/src/test/scala/special/sigma/SigmaDslStaginTests.scala index 9a25237682..1b93729e93 100644 --- a/sigmastate/src/test/scala/special/sigma/SigmaDslStaginTests.scala +++ b/sigmastate/src/test/scala/special/sigma/SigmaDslStaginTests.scala @@ -48,7 +48,8 @@ class SigmaDslStaginTests extends BaseCtxTests with ErgoScriptTestkit with BaseL cake.check(boxA1, { env: EnvRep[RBox] => for { obj <- env; arg <- lifted(1) } yield obj.getReg[Coll[Byte]](arg) }, boxA1.getReg[special.collection.Coll[Byte]](1)) cake.check(boxA1, { env: EnvRep[RBox] => for { obj <- env } yield obj.registers }, boxA1.registers) - cake.check(p1, { env: EnvRep[RSigmaProp] => for { p1 <- env; arg <- lifted(true) } yield p1 && arg }, p1 && true) - cake.check(p1, { env: EnvRep[RSigmaProp] => for { p1 <- env; arg <- lifted(p2) } yield p1 && arg }, p1 && p2) + cake.check(p1, { env: EnvRep[RSigmaProp] => + for { p1 <- env; arg <- lifted(p2) } yield p1 && arg + }, p1 && p2) } } diff --git a/sigmastate/src/test/scala/special/sigma/SigmaDslTesting.scala b/sigmastate/src/test/scala/special/sigma/SigmaDslTesting.scala index 664f3ec64a..281355ccd2 100644 --- a/sigmastate/src/test/scala/special/sigma/SigmaDslTesting.scala +++ b/sigmastate/src/test/scala/special/sigma/SigmaDslTesting.scala @@ -9,8 +9,6 @@ import org.scalacheck.Arbitrary._ import org.scalacheck.Gen.frequency import org.scalacheck.{Arbitrary, Gen} import org.scalatest.exceptions.TestFailedException -import org.scalatest.prop.PropertyChecks -import org.scalatest.{Matchers, PropSpec} import scalan.RType import scalan.RType._ import scalan.util.BenchmarkUtil @@ -35,14 +33,17 @@ import sigmastate.utxo.{DeserializeContext, DeserializeRegister, GetVar, OptionG import sigmastate.{SOption, SSigmaProp, SType, VersionContext, eval} import special.collection.{Coll, CollType} import debox.cfor +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks import java.util import scala.collection.mutable import scala.reflect.ClassTag import scala.util.{Failure, Success, Try} -class SigmaDslTesting extends PropSpec - with PropertyChecks +class SigmaDslTesting extends AnyPropSpec + with ScalaCheckPropertyChecks with Matchers with SigmaTestingData with SigmaContractSyntax with ObjectGenerators { suite =>