From 62819c478323bd591fa2b173d1a9ece75eed0fc1 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Fri, 28 Jul 2023 17:09:54 +0200 Subject: [PATCH 1/7] refactoring: simplify sigma protocol abstractions --- .../src/main/scala/sigmastate/basics/DLogProtocol.scala | 4 ++-- .../scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala | 4 ++-- .../main/scala/sigmastate/basics/SigmaProtocolFunctions.scala | 4 ++-- .../main/scala/sigmastate/interpreter/ProverInterpreter.scala | 4 ++-- .../src/main/scala/sigmastate/interpreter/ProverUtils.scala | 2 +- interpreter/shared/src/main/scala/sigmastate/trees.scala | 4 ++-- .../sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala | 2 +- sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala | 2 +- .../scala/org/ergoplatform/sdk/AppkitProvingInterpreter.scala | 2 +- .../scala/org/ergoplatform/sdk/wallet/secrets/SecretKey.scala | 4 ++-- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala b/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala index 492b054b0e..bc61d3bdd3 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala @@ -23,7 +23,7 @@ object DLogProtocol { /** Construct a new SigmaBoolean value representing public key of discrete logarithm signature protocol. */ case class ProveDlog(value: EcPointType) - extends SigmaProofOfKnowledgeLeaf[DLogSigmaProtocol, DLogProverInput] { + extends SigmaProofOfKnowledgeLeaf[DLogProverInput] { override def size: Int = 1 override val opCode: OpCode = OpCodes.ProveDlogCode /** Serialized bytes of the elliptic curve point (using GroupElementSerializer). */ @@ -43,7 +43,7 @@ object DLogProtocol { } case class DLogProverInput(w: BigInteger) - extends SigmaProtocolPrivateInput[DLogSigmaProtocol, ProveDlog] { + extends SigmaProtocolPrivateInput[ProveDlog] { import CryptoConstants.dlogGroup diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala b/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala index 08e9dd2ab7..70add355b8 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala @@ -19,7 +19,7 @@ trait DiffieHellmanTupleProtocol extends SigmaProtocol[DiffieHellmanTupleProtoco } case class DiffieHellmanTupleProverInput(w: BigInteger, commonInput: ProveDHTuple) - extends SigmaProtocolPrivateInput[DiffieHellmanTupleProtocol, ProveDHTuple] { + extends SigmaProtocolPrivateInput[ProveDHTuple] { override lazy val publicImage: ProveDHTuple = commonInput } @@ -62,7 +62,7 @@ case class SecondDiffieHellmanTupleProverMessage(z: BigInteger) extends SecondPr /** Construct a new SigmaProp value representing public key of Diffie Hellman signature protocol. * Common input: (g,h,u,v) */ case class ProveDHTuple(gv: EcPointType, hv: EcPointType, uv: EcPointType, vv: EcPointType) - extends SigmaProofOfKnowledgeLeaf[DiffieHellmanTupleProtocol, DiffieHellmanTupleProverInput] { + extends SigmaProofOfKnowledgeLeaf[DiffieHellmanTupleProverInput] { override val opCode: OpCode = OpCodes.ProveDiffieHellmanTupleCode override def size: Int = 4 // one node for each EcPoint lazy val g = gv diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala b/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala index 3327d94ebf..3676829576 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala @@ -50,10 +50,10 @@ trait SigmaProtocol[SP <: SigmaProtocol[SP]] { } -trait SigmaProtocolCommonInput[SP <: SigmaProtocol[SP]] { +trait SigmaProtocolCommonInput { } -trait SigmaProtocolPrivateInput[SP <: SigmaProtocol[SP], CI <: SigmaProtocolCommonInput[SP]] { +trait SigmaProtocolPrivateInput[CI <: SigmaProtocolCommonInput] { def publicImage: CI } diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala index ff91db6285..6d4cdb8e3f 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala @@ -29,7 +29,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { override type ProofT = UncheckedTree /** All secrets available for this prover. */ - def secrets: Seq[SigmaProtocolPrivateInput[_, _]] + def secrets: Seq[SigmaProtocolPrivateInput[_]] /** * Public keys of prover's secrets. This operation can be costly if there are many @@ -181,7 +181,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { // is known to an external participant in multi-signing; // else mark it "simulated" val isReal = hintsBag.realImages.contains(ul.proposition) || secrets.exists { - case in: SigmaProtocolPrivateInput[_, _] => in.publicImage == ul.proposition + case in: SigmaProtocolPrivateInput[_] => in.publicImage == ul.proposition } ul.withSimulated(!isReal) case t: UnprovenTree => diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala index 7a3ce291db..aaadb1aa03 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala @@ -41,7 +41,7 @@ trait ProverUtils extends Interpreter { sc.children.zipWithIndex.foldLeft(bag) { case (b, (child, idx)) => traverseNode(child, b, position.child(idx)) } - case leaf: SigmaProofOfKnowledgeLeaf[_, _] => + case leaf: SigmaProofOfKnowledgeLeaf[_] => if (generateFor.contains(leaf)) { val (r, a) = leaf match { case _: ProveDlog => diff --git a/interpreter/shared/src/main/scala/sigmastate/trees.scala b/interpreter/shared/src/main/scala/sigmastate/trees.scala index 0d60fa1b74..5469abdec1 100644 --- a/interpreter/shared/src/main/scala/sigmastate/trees.scala +++ b/interpreter/shared/src/main/scala/sigmastate/trees.scala @@ -40,8 +40,8 @@ trait SigmaConjecture extends SigmaBoolean { /** * Basic trait for leafs of crypto-trees, such as ProveDlog and ProveDiffieHellman instances */ -trait SigmaProofOfKnowledgeLeaf[SP <: SigmaProtocol[SP], S <: SigmaProtocolPrivateInput[SP, _]] - extends SigmaBoolean with SigmaProtocolCommonInput[SP] +trait SigmaProofOfKnowledgeLeaf[S <: SigmaProtocolPrivateInput[_]] + extends SigmaBoolean with SigmaProtocolCommonInput /** diff --git a/interpreter/shared/src/test/scala/sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala b/interpreter/shared/src/test/scala/sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala index aec7d4a723..2a3609a3fc 100644 --- a/interpreter/shared/src/test/scala/sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala +++ b/interpreter/shared/src/test/scala/sigmastate/helpers/ErgoLikeTestProvingInterpreter.scala @@ -8,7 +8,7 @@ import sigmastate.interpreter.ProverInterpreter class ErgoLikeTestProvingInterpreter extends ErgoLikeTestInterpreter with ProverInterpreter { - override lazy val secrets: Seq[SigmaProtocolPrivateInput[_, _]] = { + override lazy val secrets: Seq[SigmaProtocolPrivateInput[_]] = { (1 to 4).map(_ => DLogProverInput.random()) ++ (1 to 4).map(_ => DiffieHellmanTupleProverInput.random()) } diff --git a/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala index e7781a289c..c6b4ced7d9 100644 --- a/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala @@ -85,7 +85,7 @@ class SigmaDslTesting extends AnyPropSpec val sk2: DLogProverInput = decodeSecretInput("34648336872573478681093104997365775365807654884817677358848426648354905397359") val sk3: DLogProverInput = decodeSecretInput("50415569076448343263191022044468203756975150511337537963383000142821297891310") - val secrets: Seq[SigmaProtocolPrivateInput[_ <: SigmaProtocol[_], _ <: SigmaProtocolCommonInput[_]]] = { + val secrets: Seq[SigmaProtocolPrivateInput[_ <: SigmaProtocolCommonInput]] = { // Note, not all secrets are used, which is required by checkVerify // This is to make AtLeast to be unproved and thus the verify is successfull // because of the other condition in SigmaOr (see checkVerify) diff --git a/sdk/shared/src/main/scala/org/ergoplatform/sdk/AppkitProvingInterpreter.scala b/sdk/shared/src/main/scala/org/ergoplatform/sdk/AppkitProvingInterpreter.scala index 91e684d9ac..000b0a7347 100644 --- a/sdk/shared/src/main/scala/org/ergoplatform/sdk/AppkitProvingInterpreter.scala +++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/AppkitProvingInterpreter.scala @@ -44,7 +44,7 @@ class AppkitProvingInterpreter( /** All secrets available to this interpreter including [[ExtendedSecretKey]], dlog and * dht secrets. */ - override val secrets: Seq[SigmaProtocolPrivateInput[_, _]] = { + override val secrets: Seq[SigmaProtocolPrivateInput[_]] = { val dlogs: IndexedSeq[DLogProverInput] = secretKeys.map(_.privateInput) dlogs ++ dLogInputs ++ dhtInputs } diff --git a/sdk/shared/src/main/scala/org/ergoplatform/sdk/wallet/secrets/SecretKey.scala b/sdk/shared/src/main/scala/org/ergoplatform/sdk/wallet/secrets/SecretKey.scala index 0d6d54d719..73ce7d39ea 100644 --- a/sdk/shared/src/main/scala/org/ergoplatform/sdk/wallet/secrets/SecretKey.scala +++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/wallet/secrets/SecretKey.scala @@ -10,7 +10,7 @@ trait SecretKey { /** * Private (secret) input of a sigma protocol */ - def privateInput: SigmaProtocolPrivateInput[_, _] + def privateInput: SigmaProtocolPrivateInput[_] } /** @@ -19,7 +19,7 @@ trait SecretKey { sealed trait PrimitiveSecretKey extends SecretKey object PrimitiveSecretKey { - def apply(sigmaPrivateInput: SigmaProtocolPrivateInput[_, _]): PrimitiveSecretKey = sigmaPrivateInput match { + def apply(sigmaPrivateInput: SigmaProtocolPrivateInput[_]): PrimitiveSecretKey = sigmaPrivateInput match { case dls: DLogProverInput => DlogSecretKey(dls) case dhts: DiffieHellmanTupleProverInput => DhtSecretKey(dhts) } From b853091042d620c5b8bbb4d825678a6ddcade2e7 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Fri, 28 Jul 2023 18:36:52 +0200 Subject: [PATCH 2/7] refactoring: simplified and renamed SigmaProofOfKnowledgeLeaf => SigmaLeaf --- .../sigmastate/basics/DLogProtocol.scala | 3 +-- .../basics/DiffieHellmanTupleProtocol.scala | 2 +- .../basics/SigmaProtocolFunctions.scala | 6 ++--- .../sigmastate/interpreter/ProverUtils.scala | 2 +- .../src/main/scala/sigmastate/trees.scala | 22 ++++++++----------- .../scala/special/sigma/SigmaDslTesting.scala | 16 +++++++------- 6 files changed, 22 insertions(+), 29 deletions(-) diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala b/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala index bc61d3bdd3..5d378a5b1f 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala @@ -22,8 +22,7 @@ object DLogProtocol { } /** Construct a new SigmaBoolean value representing public key of discrete logarithm signature protocol. */ - case class ProveDlog(value: EcPointType) - extends SigmaProofOfKnowledgeLeaf[DLogProverInput] { + case class ProveDlog(value: EcPointType) extends SigmaLeaf { override def size: Int = 1 override val opCode: OpCode = OpCodes.ProveDlogCode /** Serialized bytes of the elliptic curve point (using GroupElementSerializer). */ diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala b/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala index 70add355b8..e3579db2ed 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala @@ -62,7 +62,7 @@ case class SecondDiffieHellmanTupleProverMessage(z: BigInteger) extends SecondPr /** Construct a new SigmaProp value representing public key of Diffie Hellman signature protocol. * Common input: (g,h,u,v) */ case class ProveDHTuple(gv: EcPointType, hv: EcPointType, uv: EcPointType, vv: EcPointType) - extends SigmaProofOfKnowledgeLeaf[DiffieHellmanTupleProverInput] { + extends SigmaLeaf { override val opCode: OpCode = OpCodes.ProveDiffieHellmanTupleCode override def size: Int = 4 // one node for each EcPoint lazy val g = gv diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala b/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala index 3676829576..c080a761c8 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala @@ -1,5 +1,6 @@ package sigmastate.basics +import sigmastate.SigmaLeaf import supertagged.TaggedType /* @@ -50,10 +51,7 @@ trait SigmaProtocol[SP <: SigmaProtocol[SP]] { } -trait SigmaProtocolCommonInput { -} - -trait SigmaProtocolPrivateInput[CI <: SigmaProtocolCommonInput] { +trait SigmaProtocolPrivateInput[CI <: SigmaLeaf] { def publicImage: CI } diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala index aaadb1aa03..dd416d1447 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala @@ -41,7 +41,7 @@ trait ProverUtils extends Interpreter { sc.children.zipWithIndex.foldLeft(bag) { case (b, (child, idx)) => traverseNode(child, b, position.child(idx)) } - case leaf: SigmaProofOfKnowledgeLeaf[_] => + case leaf: SigmaLeaf => if (generateFor.contains(leaf)) { val (r, a) = leaf match { case _: ProveDlog => diff --git a/interpreter/shared/src/main/scala/sigmastate/trees.scala b/interpreter/shared/src/main/scala/sigmastate/trees.scala index 5469abdec1..e745a88c91 100644 --- a/interpreter/shared/src/main/scala/sigmastate/trees.scala +++ b/interpreter/shared/src/main/scala/sigmastate/trees.scala @@ -1,34 +1,31 @@ package sigmastate +import debox.{cfor, Map => DMap} import org.ergoplatform.SigmaConstants import org.ergoplatform.validation.SigmaValidationSettings -import scalan.{ExactIntegral, ExactNumeric, ExactOrdering, Nullable} +import scalan.ExactIntegral._ +import scalan.ExactOrdering._ import scalan.OverloadHack.Overloaded1 +import scalan.{ExactIntegral, ExactOrdering} import scorex.crypto.hash.{Blake2b256, CryptographicHash32, Sha256} +import sigmastate.ArithOp.OperationImpl import sigmastate.Operations._ import sigmastate.SCollection.{SByteArray, SIntArray} import sigmastate.SOption.SIntOption import sigmastate.Values._ -import sigmastate.basics.{SigmaProtocol, SigmaProtocolCommonInput, SigmaProtocolPrivateInput} +import sigmastate.eval.Extensions.EvalCollOps +import sigmastate.eval.NumericOps.{BigIntIsExactIntegral, BigIntIsExactOrdering} +import sigmastate.eval.{Colls, SigmaDsl} import sigmastate.interpreter.ErgoTreeEvaluator import sigmastate.interpreter.ErgoTreeEvaluator.DataEnv import sigmastate.serialization.OpCodes._ import sigmastate.serialization._ import sigmastate.utxo.{SimpleTransformerCompanion, Transformer} -import debox.{Map => DMap} -import scalan.ExactIntegral._ -import scalan.ExactOrdering._ -import sigmastate.ArithOp.OperationImpl -import sigmastate.eval.NumericOps.{BigIntIsExactIntegral, BigIntIsExactOrdering} -import sigmastate.eval.{Colls, SigmaDsl} -import sigmastate.lang.TransformingSigmaBuilder import special.collection.Coll import special.sigma.{GroupElement, SigmaProp} import scala.collection.mutable import scala.collection.mutable.ArrayBuffer -import debox.cfor -import sigmastate.eval.Extensions.EvalCollOps /** * Basic trait for inner nodes of crypto-trees, so AND/OR/THRESHOLD sigma-protocol connectives @@ -40,8 +37,7 @@ trait SigmaConjecture extends SigmaBoolean { /** * Basic trait for leafs of crypto-trees, such as ProveDlog and ProveDiffieHellman instances */ -trait SigmaProofOfKnowledgeLeaf[S <: SigmaProtocolPrivateInput[_]] - extends SigmaBoolean with SigmaProtocolCommonInput +trait SigmaLeaf extends SigmaBoolean /** diff --git a/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala index c6b4ced7d9..53c4cdddac 100644 --- a/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala @@ -1,5 +1,6 @@ package special.sigma +import debox.cfor import org.ergoplatform.SigmaConstants.ScriptCostLimit import org.ergoplatform._ import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, TestContractSpec} @@ -9,6 +10,10 @@ import org.scalacheck.Arbitrary._ import org.scalacheck.Gen.frequency import org.scalacheck.{Arbitrary, Gen} import org.scalatest.exceptions.TestFailedException +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import scalan.Platform.threadSleepOrNoOp import scalan.RType import scalan.RType._ import scalan.util.BenchmarkUtil @@ -18,7 +23,7 @@ import scalan.util.StringUtil.StringUtilExtensions import sigmastate.SType.AnyOps import sigmastate.Values.{ByteArrayConstant, Constant, ConstantNode, ErgoTree, IntConstant, SValue} import sigmastate.basics.DLogProtocol.{DLogProverInput, ProveDlog} -import sigmastate.basics.{SigmaProtocol, SigmaProtocolCommonInput, SigmaProtocolPrivateInput} +import sigmastate.basics.SigmaProtocolPrivateInput import sigmastate.eval.Extensions._ import sigmastate.eval.{CompiletimeIRContext, CostingBox, CostingDataContext, Evaluation, IRContext, SigmaDsl} import sigmastate.helpers.TestingHelpers._ @@ -30,13 +35,8 @@ import sigmastate.serialization.ValueSerializer import sigmastate.serialization.generators.ObjectGenerators import sigmastate.utils.Helpers._ import sigmastate.utxo.{DeserializeContext, DeserializeRegister, GetVar, OptionGet} -import sigmastate.{SOption, SSigmaProp, SType, VersionContext, eval} +import sigmastate.{SOption, SSigmaProp, SType, SigmaLeaf, 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 scalan.Platform.threadSleepOrNoOp import java.util import scala.collection.mutable @@ -85,7 +85,7 @@ class SigmaDslTesting extends AnyPropSpec val sk2: DLogProverInput = decodeSecretInput("34648336872573478681093104997365775365807654884817677358848426648354905397359") val sk3: DLogProverInput = decodeSecretInput("50415569076448343263191022044468203756975150511337537963383000142821297891310") - val secrets: Seq[SigmaProtocolPrivateInput[_ <: SigmaProtocolCommonInput]] = { + val secrets: Seq[SigmaProtocolPrivateInput[_ <: SigmaLeaf]] = { // Note, not all secrets are used, which is required by checkVerify // This is to make AtLeast to be unproved and thus the verify is successfull // because of the other condition in SigmaOr (see checkVerify) From fbac23a25e41ccbecc3ad511ecf630dc9343ac3e Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sun, 30 Jul 2023 15:24:14 +0200 Subject: [PATCH 3/7] multisig: challenge to become Coll[Byte] which fixes equality of case classes --- .../wrappers/scala/impl/WOptionsImpl.scala | 2 +- .../wrappers/scalan/impl/WRTypesImpl.scala | 2 +- .../main/scala/sigmastate/SigSerializer.scala | 17 +-- .../main/scala/sigmastate/UncheckedTree.scala | 117 ++++-------------- .../main/scala/sigmastate/UnprovenTree.scala | 2 +- .../sigmastate/basics/DLogProtocol.scala | 9 +- .../basics/DiffieHellmanTupleProtocol.scala | 8 +- .../basics/SigmaProtocolFunctions.scala | 7 +- .../scala/sigmastate/crypto/BigIntegers.scala | 2 +- .../sigmastate/crypto/GF2_192_Poly.scala | 1 - .../main/scala/sigmastate/eval/Profiler.scala | 6 - .../sigmastate/interpreter/Interpreter.scala | 2 +- .../interpreter/ProverInterpreter.scala | 24 ++-- .../sigmastate/interpreter/ProverUtils.scala | 4 +- .../main/scala/sigmastate/utils/Helpers.scala | 13 ++ .../SigmaProtocolSpecification.scala | 4 +- .../sigmastate/helpers/NegativeTesting.scala | 2 +- .../sigmastate/helpers/TestingHelpers.scala | 13 +- .../SigSerializerSpecification.scala | 62 +++++----- .../generators/TypeGenerators.scala | 26 ++-- .../scala/sigmastate/utils/HelpersTests.scala | 10 ++ .../scala/org/ergoplatform/sdk/js/Isos.scala | 18 +-- 22 files changed, 155 insertions(+), 196 deletions(-) diff --git a/graph-ir/shared/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala b/graph-ir/shared/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala index 4b69cfe957..e5e7f333e6 100644 --- a/graph-ir/shared/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala +++ b/graph-ir/shared/src/main/scala/wrappers/scala/impl/WOptionsImpl.scala @@ -90,7 +90,7 @@ class WOptionCls extends EntityObject("WOption") { case class WOptionAdapter[A](source: Ref[WOption[A]]) extends Node with WOption[A] with Def[WOption[A]] { - implicit lazy val eA = source.elem.typeArgs("A")._1.asInstanceOf[Elem[A]] + implicit lazy val eA: Elem[A] = source.elem.typeArgs("A")._1.asInstanceOf[Elem[A]] val resultType: Elem[WOption[A]] = element[WOption[A]] override def transform(t: Transformer) = WOptionAdapter[A](t(source)) diff --git a/graph-ir/shared/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala b/graph-ir/shared/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala index dfbd0f3111..66bbf9ed81 100644 --- a/graph-ir/shared/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala +++ b/graph-ir/shared/src/main/scala/wrappers/scalan/impl/WRTypesImpl.scala @@ -67,7 +67,7 @@ class WRTypeCls extends EntityObject("WRType") { case class WRTypeAdapter[A](source: Ref[WRType[A]]) extends Node with WRType[A] with Def[WRType[A]] { - implicit lazy val eA = source.elem.typeArgs("A")._1.asInstanceOf[Elem[A]] + implicit lazy val eA: Elem[A] = source.elem.typeArgs("A")._1.asInstanceOf[Elem[A]] val resultType: Elem[WRType[A]] = element[WRType[A]] override def transform(t: Transformer) = WRTypeAdapter[A](t(source)) diff --git a/interpreter/shared/src/main/scala/sigmastate/SigSerializer.scala b/interpreter/shared/src/main/scala/sigmastate/SigSerializer.scala index 07ff33c5bc..033d7f7b62 100644 --- a/interpreter/shared/src/main/scala/sigmastate/SigSerializer.scala +++ b/interpreter/shared/src/main/scala/sigmastate/SigSerializer.scala @@ -5,13 +5,14 @@ import scorex.util.encode.Base16 import sigmastate.Values.SigmaBoolean import sigmastate.basics.DLogProtocol.{ProveDlog, SecondDLogProverMessage} import sigmastate.basics.VerifierMessage.Challenge -import sigmastate.basics.{SecondDiffieHellmanTupleProverMessage, ProveDHTuple, CryptoConstants} +import sigmastate.basics.{CryptoConstants, ProveDHTuple, SecondDiffieHellmanTupleProverMessage} import sigmastate.interpreter.ErgoTreeEvaluator.{fixedCostOp, perItemCostOp} import sigmastate.interpreter.{ErgoTreeEvaluator, NamedDesc, OperationCostInfo} import sigmastate.serialization.SigmaSerializer import sigmastate.util.safeNewArray import sigmastate.utils.{Helpers, SigmaByteReader, SigmaByteWriter} import debox.cfor +import sigmastate.eval.Extensions.ArrayOps import sigmastate.exceptions.SerializerException /** Contains implementation of signature (aka proof) serialization. @@ -61,7 +62,7 @@ class SigSerializer { w: SigmaByteWriter, writeChallenge: Boolean): Unit = { if (writeChallenge) { - w.putBytes(node.challenge) + w.putBytes(node.challenge.toArray) } node match { case dl: UncheckedSchnorr => @@ -184,7 +185,7 @@ class SigSerializer { // Verifier Step 2: Let e_0 be the challenge in the node here (e_0 is called "challenge" in the code) val challenge = if (challengeOpt == null) { Challenge @@ readBytesChecked(r, hashSize, - hex => warn(s"Invalid challenge in: $hex")) + hex => warn(s"Invalid challenge in: $hex")).toColl } else { challengeOpt } @@ -223,18 +224,18 @@ class SigSerializer { // Read all the children but the last and compute the XOR of all the challenges including e_0 val nChildren = or.children.length val children = safeNewArray[UncheckedSigmaTree](nChildren) - val xorBuf = challenge.clone() + val xorBuf = challenge.toArray.clone() val iLastChild = nChildren - 1 cfor(0)(_ < iLastChild, _ + 1) { i => val parsedChild = parseAndComputeChallenges(or.children(i), r, null) children(i) = parsedChild - Helpers.xorU(xorBuf, parsedChild.challenge) // xor it into buffer + Helpers.xorU(xorBuf, parsedChild.challenge.toArray) // xor it into buffer } val lastChild = or.children(iLastChild) // use the computed XOR for last child's challenge children(iLastChild) = parseAndComputeChallenges( - lastChild, r, challengeOpt = Challenge @@ xorBuf) + lastChild, r, challengeOpt = Challenge @@ xorBuf.toColl) COrUncheckedNode(challenge, children) @@ -248,13 +249,13 @@ class SigSerializer { val polynomial = perItemCostOp(ParsePolynomial, nCoefs) { () => val coeffBytes = readBytesChecked(r, hashSize * nCoefs, hex => warn(s"Invalid coeffBytes for $th: $hex")) - GF2_192_Poly.fromByteArray(challenge, coeffBytes) + GF2_192_Poly.fromByteArray(challenge.toArray, coeffBytes) } val children = safeNewArray[UncheckedSigmaTree](nChildren) cfor(0)(_ < nChildren, _ + 1) { i => val c = perItemCostOp(EvaluatePolynomial, nCoefs) { () => - Challenge @@ polynomial.evaluate((i + 1).toByte).toByteArray + Challenge @@ polynomial.evaluate((i + 1).toByte).toByteArray.toColl } children(i) = parseAndComputeChallenges(th.children(i), r, c) } diff --git a/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala b/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala index 365a1f85a7..2f4f78fdca 100644 --- a/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala +++ b/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala @@ -1,6 +1,5 @@ package sigmastate -import java.util.Arrays import sigmastate.basics.DLogProtocol.{FirstDLogProverMessage, ProveDlog, SecondDLogProverMessage} import sigmastate.basics.VerifierMessage.Challenge import sigmastate.Values.SigmaBoolean @@ -12,114 +11,48 @@ sealed trait UncheckedTree extends ProofTree case object NoProof extends UncheckedTree sealed trait UncheckedSigmaTree extends UncheckedTree { - val challenge: Array[Byte] + val challenge: Challenge } -trait UncheckedConjecture extends UncheckedSigmaTree with ProofTreeConjecture { - - override def equals(obj: Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj match { - case x: UncheckedConjecture => - Arrays.equals(challenge, x.challenge) && children == x.children - case _ => false - }) - - override def hashCode(): Int = - 31 * Arrays.hashCode(challenge) + children.hashCode() -} +trait UncheckedConjecture extends UncheckedSigmaTree with ProofTreeConjecture trait UncheckedLeaf[SP <: SigmaBoolean] extends UncheckedSigmaTree with ProofTreeLeaf { val proposition: SigmaBoolean } -case class UncheckedSchnorr(override val proposition: ProveDlog, - override val commitmentOpt: Option[FirstDLogProverMessage], - override val challenge: Challenge, - secondMessage: SecondDLogProverMessage) - extends UncheckedLeaf[ProveDlog] { +case class UncheckedSchnorr( + override val proposition: ProveDlog, + override val commitmentOpt: Option[FirstDLogProverMessage], + override val challenge: Challenge, + secondMessage: SecondDLogProverMessage +) extends UncheckedLeaf[ProveDlog] - override def equals(obj: Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj match { - case x: UncheckedSchnorr => - // NOTE, proposition is not compared because it is included into challenge - // like `challenge = hash(prop ++ msg)` - commitmentOpt == x.commitmentOpt && - Arrays.equals(challenge, x.challenge) && - secondMessage == x.secondMessage - case _ => false - }) - - override def hashCode(): Int = { - var h = commitmentOpt.hashCode() - h = 31 * h + Arrays.hashCode(challenge) - h = 31 * h + secondMessage.hashCode() - h - } -} - - -case class UncheckedDiffieHellmanTuple(override val proposition: ProveDHTuple, - override val commitmentOpt: Option[FirstDiffieHellmanTupleProverMessage], - override val challenge: Challenge, - secondMessage: SecondDiffieHellmanTupleProverMessage) - extends UncheckedLeaf[ProveDHTuple] { - - override def equals(obj: Any): Boolean = (this eq obj.asInstanceOf[AnyRef]) || (obj match { - case x: UncheckedDiffieHellmanTuple => - // NOTE, proposition is not compared because it is included into challenge - // like `challenge = hash(prop ++ msg)` - commitmentOpt == x.commitmentOpt && - Arrays.equals(challenge, x.challenge) && - secondMessage == x.secondMessage - case _ => false - }) - - override def hashCode(): Int = { - var h = commitmentOpt.hashCode() - h = 31 * h + Arrays.hashCode(challenge) - h = 31 * h + secondMessage.hashCode() - h - } -} - -case class CAndUncheckedNode(override val challenge: Challenge, - override val children: Seq[UncheckedSigmaTree]) - extends UncheckedConjecture { +case class UncheckedDiffieHellmanTuple( + override val proposition: ProveDHTuple, + override val commitmentOpt: Option[FirstDiffieHellmanTupleProverMessage], + override val challenge: Challenge, + secondMessage: SecondDiffieHellmanTupleProverMessage +) extends UncheckedLeaf[ProveDHTuple] +case class CAndUncheckedNode( + override val challenge: Challenge, + override val children: Seq[UncheckedSigmaTree]) extends UncheckedConjecture { override val conjectureType = ConjectureType.AndConjecture } - -case class COrUncheckedNode(override val challenge: Challenge, - override val children: Seq[UncheckedSigmaTree]) extends UncheckedConjecture { - +case class COrUncheckedNode( + override val challenge: Challenge, + override val children: Seq[UncheckedSigmaTree]) extends UncheckedConjecture { override val conjectureType = ConjectureType.OrConjecture - } -case class CThresholdUncheckedNode(override val challenge: Challenge, - override val children: Seq[UncheckedSigmaTree], - k: Integer, - polynomialOpt: Option[GF2_192_Poly]) extends UncheckedConjecture { +case class CThresholdUncheckedNode( + override val challenge: Challenge, + override val children: Seq[UncheckedSigmaTree], + k: Integer, + polynomialOpt: Option[GF2_192_Poly]) extends UncheckedConjecture { require(children.length <= 255) // Our polynomial arithmetic can take only byte inputs require(k >= 0 && k <= children.length) override val conjectureType = ConjectureType.ThresholdConjecture - - override def canEqual(other: Any) = other.isInstanceOf[CThresholdUncheckedNode] - - override def equals(other: Any) = (this eq other.asInstanceOf[AnyRef]) || (other match { - case other: CThresholdUncheckedNode => - Arrays.equals(challenge, other.challenge) && - children == other.children && - k == other.k && - polynomialOpt == other.polynomialOpt - case _ => false - }) - - override def hashCode(): Int = { - var h = Arrays.hashCode(challenge) - h = 31 * h + children.hashCode - h = 31 * h + k.hashCode() - h = 31 * h + polynomialOpt.hashCode() - h - } } diff --git a/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala b/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala index 6e600b927b..fff252c3b9 100644 --- a/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala +++ b/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala @@ -102,7 +102,7 @@ sealed trait UnprovenTree extends ProofTree { /** * Challenge used by the prover. */ - val challengeOpt: Option[Array[Byte]] + val challengeOpt: Option[Challenge] def withChallenge(challenge: Challenge): UnprovenTree diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala b/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala index 5d378a5b1f..d286c2dda3 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala @@ -78,7 +78,7 @@ object DLogProtocol { } - object DLogInteractiveProver { + object DLogInteractiveProver extends SigmaProtocolProver { import CryptoConstants.secureRandom def firstMessage(): (BigInteger, FirstDLogProverMessage) = { @@ -93,8 +93,9 @@ object DLogProtocol { def secondMessage(privateInput: DLogProverInput, rnd: BigInteger, challenge: Challenge): SecondDLogProverMessage = { import CryptoConstants.dlogGroup + // TODO: get rid of duplicate code val q: BigInteger = dlogGroup.order - val e: BigInteger = new BigInteger(1, challenge) + val e: BigInteger = new BigInteger(1, challenge.toArray) val ew: BigInteger = e.multiply(privateInput.w).mod(q) val z: BigInteger = rnd.add(ew).mod(q) SecondDLogProverMessage(z) @@ -108,7 +109,7 @@ object DLogProtocol { val z = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, secureRandom) //COMPUTE a = g^z*h^(-e) (where -e here means -e mod q) - val e: BigInteger = new BigInteger(1, challenge) + val e: BigInteger = new BigInteger(1, challenge.toArray) val minusE = dlogGroup.order.subtract(e) val hToE = dlogGroup.exponentiate(publicInput.value, minusE) val gToZ = dlogGroup.exponentiate(dlogGroup.generator, z) @@ -136,7 +137,7 @@ object DLogProtocol { dlogGroup.multiplyGroupElements( dlogGroup.exponentiate(g, secondMessage.z.underlying()), - dlogGroup.inverseOf(dlogGroup.exponentiate(h, new BigInteger(1, challenge)))) + dlogGroup.inverseOf(dlogGroup.exponentiate(h, new BigInteger(1, challenge.toArray)))) } } diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala b/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala index e3579db2ed..62174dc5da 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala @@ -83,7 +83,7 @@ object ProveDHTupleProp { } } -object DiffieHellmanTupleInteractiveProver { +object DiffieHellmanTupleInteractiveProver extends SigmaProtocolProver { import CryptoConstants.dlogGroup @@ -99,7 +99,7 @@ object DiffieHellmanTupleInteractiveProver { rnd: BigInteger, challenge: Challenge): SecondDiffieHellmanTupleProverMessage = { val q: BigInteger = dlogGroup.order - val e: BigInteger = new BigInteger(1, challenge) + val e: BigInteger = new BigInteger(1, challenge.toArray) val ew: BigInteger = e.multiply(privateInput.w).mod(q) val z: BigInteger = rnd.add(ew).mod(q) SecondDiffieHellmanTupleProverMessage(z) @@ -114,7 +114,7 @@ object DiffieHellmanTupleInteractiveProver { val z = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, dlogGroup.secureRandom) // COMPUTE a = g^z*u^(-e) and b = h^z*v^{-e} (where -e here means -e mod q) - val e: BigInteger = new BigInteger(1, challenge) + val e: BigInteger = new BigInteger(1, challenge.toArray) val minusE = dlogGroup.order.subtract(e) val hToZ = dlogGroup.exponentiate(publicInput.h, z) val gToZ = dlogGroup.exponentiate(publicInput.g, z) @@ -149,7 +149,7 @@ object DiffieHellmanTupleInteractiveProver { val z = secondMessage.z - val e = new BigInteger(1, challenge) + val e = new BigInteger(1, challenge.toArray) val gToZ = dlogGroup.exponentiate(g, z) val hToZ = dlogGroup.exponentiate(h, z) diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala b/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala index c080a761c8..5b35fcad3a 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala @@ -1,6 +1,7 @@ package sigmastate.basics import sigmastate.SigmaLeaf +import special.collection.Coll import supertagged.TaggedType /* @@ -26,7 +27,7 @@ trait VerifierMessage extends TranscriptMessage object VerifierMessage { /** A challenge from the verifier (message `e` of `SigmaProtocol`)*/ - object Challenge extends TaggedType[Array[Byte]] + object Challenge extends TaggedType[Coll[Byte]] type Challenge = Challenge.Type } @@ -55,4 +56,8 @@ trait SigmaProtocolPrivateInput[CI <: SigmaLeaf] { def publicImage: CI } +trait SigmaProtocolProver { + +} + diff --git a/interpreter/shared/src/main/scala/sigmastate/crypto/BigIntegers.scala b/interpreter/shared/src/main/scala/sigmastate/crypto/BigIntegers.scala index 7bab41df79..43bded8e09 100644 --- a/interpreter/shared/src/main/scala/sigmastate/crypto/BigIntegers.scala +++ b/interpreter/shared/src/main/scala/sigmastate/crypto/BigIntegers.scala @@ -65,7 +65,7 @@ object BigIntegers { if (min.bitLength > max.bitLength / 2) return createRandomInRange(ZERO, max.subtract(min), random).add(min) - for ( i <- 0 until MAX_ITERATIONS ) { + for ( _ <- 0 until MAX_ITERATIONS ) { val x = createRandomBigInteger(max.bitLength, random) if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) return x } diff --git a/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala b/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala index dc0617ea29..344305a157 100644 --- a/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala +++ b/interpreter/shared/src/main/scala/sigmastate/crypto/GF2_192_Poly.scala @@ -32,7 +32,6 @@ 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 diff --git a/interpreter/shared/src/main/scala/sigmastate/eval/Profiler.scala b/interpreter/shared/src/main/scala/sigmastate/eval/Profiler.scala index 2f0e7f3e0c..74e187b809 100644 --- a/interpreter/shared/src/main/scala/sigmastate/eval/Profiler.scala +++ b/interpreter/shared/src/main/scala/sigmastate/eval/Profiler.scala @@ -169,12 +169,6 @@ class Profiler { /** Timings of method calls */ private val mcStat = new StatCollection[Int, Long]() - /** Update time measurement stats for a given method. */ - @inline private final def addMcTime(typeId: Byte, methodId: Byte, time: Long) = { - val key = typeId << 8 | methodId - mcStat.addPoint(key, time) - } - /** Wrapper class which implements special equality between CostItem instances, * suitable for collecting of the statistics. */ class CostItemKey(val costItem: CostItem) { diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala index 1559fcc775..c927dff826 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala @@ -383,7 +383,7 @@ trait Interpreter { * (and, if applicable, the associated data). Reject otherwise. */ val expectedChallenge = CryptoFunctions.hashFn(bytes) - util.Arrays.equals(newRoot.challenge, expectedChallenge) + util.Arrays.equals(newRoot.challenge.toArray, expectedChallenge) } /** diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala index 6d4cdb8e3f..794fd737ce 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala @@ -11,8 +11,10 @@ import sigmastate.basics.DLogProtocol._ import sigmastate.basics.VerifierMessage.Challenge import sigmastate.basics._ import sigmastate.crypto.{GF2_192, GF2_192_Poly} +import sigmastate.eval.Extensions.ArrayOps import sigmastate.exceptions.InterpreterException import sigmastate.utils.Helpers +import special.collection.Coll import java.math.BigInteger import scala.util.Try @@ -91,7 +93,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { // Prover Step 8: compute the challenge for the root of the tree as the Fiat-Shamir hash of propBytes // and the message being signed. - val rootChallenge = Challenge @@ CryptoFunctions.hashFn(Helpers.concatArrays(propBytes, message)) + val rootChallenge = Challenge @@ CryptoFunctions.hashFn(Helpers.concatArrays(propBytes, message)).toColl val step8 = step6.withChallenge(rootChallenge) // Prover Step 9: complete the proof by computing challenges at real nodes and additionally responses at real leaves @@ -287,7 +289,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { // take challenge from previously done proof stored in the hints bag, // or generate random challenge for simulated child val newChallenge = hintsBag.proofs.find(_.position == c.position).map(_.challenge).getOrElse( - Challenge @@ secureRandomBytes(CryptoFunctions.soundnessBytes) + Challenge @@ secureRandomBytes(CryptoFunctions.soundnessBytes).toColl ) c.withChallenge(newChallenge) } @@ -314,8 +316,10 @@ trait ProverInterpreter extends Interpreter with ProverUtils { // the other children and e_0. assert(or.challengeOpt.isDefined) val unprovenChildren = or.children.cast[UnprovenTree] - val t = unprovenChildren.tail.map(_.withChallenge(Challenge @@ secureRandomBytes(CryptoFunctions.soundnessBytes))) - val toXor: Seq[Array[Byte]] = or.challengeOpt.get +: t.map(_.challengeOpt.get) + val t = unprovenChildren.tail.map( + _.withChallenge(Challenge @@ secureRandomBytes(CryptoFunctions.soundnessBytes).toColl) + ) + val toXor: Seq[Coll[Byte]] = or.challengeOpt.get +: t.map(_.challengeOpt.get) val xoredChallenge = Challenge @@ Helpers.xor(toXor: _*) val h = unprovenChildren.head.withChallenge(xoredChallenge) or.copy(children = h +: t) @@ -329,11 +333,11 @@ trait ProverInterpreter extends Interpreter with ProverUtils { assert(t.challengeOpt.isDefined) val n = t.children.length val unprovenChildren = t.children.cast[UnprovenTree] - val q = GF2_192_Poly.fromByteArray(t.challengeOpt.get, secureRandomBytes(CryptoFunctions.soundnessBytes * (n - t.k))) + val q = GF2_192_Poly.fromByteArray(t.challengeOpt.get.toArray, secureRandomBytes(CryptoFunctions.soundnessBytes * (n - t.k))) val newChildren = unprovenChildren.foldLeft((Seq[UnprovenTree](), 1)) { case ((childSeq, childIndex), child) => - (childSeq :+ child.withChallenge(Challenge @@ q.evaluate(childIndex.toByte).toByteArray), childIndex + 1) + (childSeq :+ child.withChallenge(Challenge @@ q.evaluate(childIndex.toByte).toByteArray.toColl), childIndex + 1) }._1 t.withPolynomial(q).copy(children = newChildren) @@ -412,7 +416,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { case t: ProofTree => error(s"Don't know how to challengeSimulated($t)") }) - private def extractChallenge(pt: ProofTree): Option[Array[Byte]] = pt match { + private def extractChallenge(pt: ProofTree): Option[Challenge] = pt match { case upt: UnprovenTree => upt.challengeOpt case sn: UncheckedSchnorr => Some(sn.challenge) case dh: UncheckedDiffieHellmanTuple => Some(dh.challenge) @@ -461,16 +465,16 @@ trait ProverInterpreter extends Interpreter with ProverUtils { // has a challenge. Other ways are more of a pain because the children can be of different types val challengeOpt = extractChallenge(child) if (challengeOpt.isEmpty) (p, v) - else (p :+ count.toByte, v :+ new GF2_192(challengeOpt.get)) + else (p :+ count.toByte, v :+ new GF2_192(challengeOpt.get.toArray)) } (newPoints, newValues, count + 1) } - val q = GF2_192_Poly.interpolate(points, values, new GF2_192(t.challengeOpt.get)) + val q = GF2_192_Poly.interpolate(points, values, new GF2_192(t.challengeOpt.get.toArray)) 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.toColl) case p: ProofTree => p } (s :+ newChild, count + 1) diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala index dd416d1447..46138ca9d7 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala @@ -122,12 +122,12 @@ trait ProverUtils extends Interpreter { val hints = if (realFound) { Seq( RealCommitment(leaf.proposition, leaf.commitmentOpt.get, position), - RealSecretProof(leaf.proposition, Challenge @@ leaf.challenge, leaf, position) + RealSecretProof(leaf.proposition, leaf.challenge, leaf, position) ) } else { Seq( SimulatedCommitment(leaf.proposition, leaf.commitmentOpt.get, position), - SimulatedSecretProof(leaf.proposition, Challenge @@ leaf.challenge, leaf, position) + SimulatedSecretProof(leaf.proposition, leaf.challenge, leaf, position) ) } hintsBag.addHints(hints: _*) diff --git a/interpreter/shared/src/main/scala/sigmastate/utils/Helpers.scala b/interpreter/shared/src/main/scala/sigmastate/utils/Helpers.scala index df775cbecf..1b16ef05f9 100644 --- a/interpreter/shared/src/main/scala/sigmastate/utils/Helpers.scala +++ b/interpreter/shared/src/main/scala/sigmastate/utils/Helpers.scala @@ -1,5 +1,6 @@ package sigmastate.utils +import debox.cfor import io.circe.Decoder import org.ergoplatform.settings.ErgoAlgos import scalan.{OverloadHack, RType} @@ -37,6 +38,18 @@ object Helpers { def xor(bas: Array[Byte]*): Array[Byte] = bas.reduce({case (ba, ba1) => xor(ba, ba1)}: ((Array[Byte], Array[Byte]) => Array[Byte])) + def xor(bas: Coll[Byte]*): Coll[Byte] = { + require(bas.nonEmpty, "at least one argument is required") + if (bas.length == 1) bas(0) + else { + val res = bas(0).toArray.clone() + cfor(1)(_ < bas.length, _ + 1) { i => + xorU(res, bas(i).toArray) + } + Colls.fromArray(res) + } + } + /** Same as `xor` but makes in-place update of the first argument (hence suffix `U`) * This is boxing-free version. * @return reference to the updated first argument to easy chaining of calls. */ diff --git a/interpreter/shared/src/test/scala/sigmastate/SigmaProtocolSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/SigmaProtocolSpecification.scala index 96931f5e84..669cb09da5 100644 --- a/interpreter/shared/src/test/scala/sigmastate/SigmaProtocolSpecification.scala +++ b/interpreter/shared/src/test/scala/sigmastate/SigmaProtocolSpecification.scala @@ -7,8 +7,8 @@ import special.sigma.SigmaTestingData class SigmaProtocolSpecification extends SigmaTestingData { property("CThresholdUncheckedNode equality") { - val c1 = Challenge @@ Array[Byte](1) - val c2 = Challenge @@ Array[Byte](2) + val c1 = Challenge @@ Coll[Byte](1) + val c2 = Challenge @@ Coll[Byte](2) val n0 = CThresholdUncheckedNode(c1, Seq(), 0, None) val n1 = CThresholdUncheckedNode(c1, Seq(), 0, None) val n2 = CThresholdUncheckedNode(c2, Seq(), 0, None) diff --git a/interpreter/shared/src/test/scala/sigmastate/helpers/NegativeTesting.scala b/interpreter/shared/src/test/scala/sigmastate/helpers/NegativeTesting.scala index 158dc2b1bf..fb004c2302 100644 --- a/interpreter/shared/src/test/scala/sigmastate/helpers/NegativeTesting.scala +++ b/interpreter/shared/src/test/scala/sigmastate/helpers/NegativeTesting.scala @@ -114,7 +114,7 @@ trait NegativeTesting extends Matchers { def repeatAndReturnLast[A](nIters: Int)(block: => A): A = { require(nIters > 0) var res = block - cfor(1)(_ < nIters, _ + 1) { i => + cfor(1)(_ < nIters, _ + 1) { _ => res = block } res diff --git a/interpreter/shared/src/test/scala/sigmastate/helpers/TestingHelpers.scala b/interpreter/shared/src/test/scala/sigmastate/helpers/TestingHelpers.scala index 0ebac010ae..fa1b9f163c 100644 --- a/interpreter/shared/src/test/scala/sigmastate/helpers/TestingHelpers.scala +++ b/interpreter/shared/src/test/scala/sigmastate/helpers/TestingHelpers.scala @@ -1,20 +1,17 @@ package sigmastate.helpers -import scorex.crypto.hash.Digest32 -import special.collection.{Coll, CollOverArray, PairOfCols} -import scorex.util.ModifierId -import org.ergoplatform.{DataInput, ErgoBox, ErgoBoxCandidate, ErgoLikeContext, ErgoLikeTransaction, ErgoLikeTransactionTemplate, Input, UnsignedInput} -import sigmastate.Values.ErgoTree import org.ergoplatform.ErgoBox.{AdditionalRegisters, Token, allZerosModifierId} import org.ergoplatform.validation.SigmaValidationSettings +import org.ergoplatform._ +import scorex.util.ModifierId import sigmastate.AvlTreeData -import sigmastate.eval.CostingSigmaDslBuilder -import sigmastate.eval._ +import sigmastate.Values.ErgoTree +import sigmastate.eval.{CostingSigmaDslBuilder, _} import sigmastate.interpreter.ContextExtension +import special.collection.{Coll, CollOverArray, PairOfCols} import special.sigma.{Header, PreHeader} import scala.collection.compat.immutable.ArraySeq -import scala.collection.mutable.WrappedArray // TODO refactor: unification is required between two hierarchies of tests // and as part of it, more methods can be moved to TestingHelpers diff --git a/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala index 6df3cc89d0..f34e2c784a 100644 --- a/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala @@ -1,17 +1,17 @@ package sigmastate.serialization import java.math.BigInteger -import java.util import org.ergoplatform.settings.ErgoAlgos -import org.scalacheck.{Gen, Arbitrary} +import org.scalacheck.{Arbitrary, Gen} import org.scalatest.Assertion import sigmastate.Values.SigmaBoolean import sigmastate._ import sigmastate.basics.DLogProtocol.{ProveDlog, SecondDLogProverMessage} import sigmastate.basics.VerifierMessage.Challenge -import sigmastate.basics.{SecondDiffieHellmanTupleProverMessage, ProveDHTuple} +import sigmastate.basics.{ProveDHTuple, SecondDiffieHellmanTupleProverMessage} import sigmastate.crypto.GF2_192_Poly -import sigmastate.helpers.{ErgoLikeTransactionTesting, ErgoLikeContextTesting, ContextEnrichingTestProvingInterpreter, TestingCommons} +import sigmastate.eval.Extensions.ArrayOps +import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTransactionTesting, TestingCommons} import sigmastate.interpreter.Interpreter import sigmastate.serialization.generators.ObjectGenerators import sigmastate.utils.Helpers @@ -54,7 +54,7 @@ class SigSerializerSpecification extends TestingCommons // `firstMessageOpt` is not serialized sch1.copy(commitmentOpt = None) == sch2 case (conj1: UncheckedConjecture, conj2: UncheckedConjecture) => - util.Arrays.equals(conj1.challenge, conj2.challenge) && + conj1.challenge == conj2.challenge && conj1.children.zip(conj2.children).forall(t => isEquivalent(t._1, t._2)) case _ => false } @@ -147,7 +147,7 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("02e8e77123e300f8324e7b5c4cbe0f7ac616e0b78fc45f28f54fa6696231fc8ec3") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("c6429b70f4926a3ba1454f1aec116075f9e9fbe8a8f72114"), + Challenge @@ ErgoAlgos.decodeUnsafe("c6429b70f4926a3ba1454f1aec116075f9e9fbe8a8f72114").toColl, SecondDLogProverMessage( BigInt("b277b8462a8b9098f5d4c934ab2876eb1b5707f3119e209bdbbad831e7cc4a41", 16) ) @@ -172,7 +172,7 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("034132d4c7eb387f12ef40ba3ec03723bda0ee5707f7471185aafc316167e85137") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("9ec740b57353cb2f6035bb1a481b0066b2fdc0406a6fa67e"), + Challenge @@ ErgoAlgos.decodeUnsafe("9ec740b57353cb2f6035bb1a481b0066b2fdc0406a6fa67e").toColl, SecondDiffieHellmanTupleProverMessage( new BigInteger("bb2e6f44a38052b3f564fafcd477c4eb8cda1a8a553a4a5f38f1e1084d6a69f0", 16) ) @@ -194,7 +194,7 @@ class SigSerializerSpecification extends TestingCommons "a00b476899e583aefc18b237a7a70e73baace72aa533271a561d3432c347dcaec8975fdefb36389abe21656aadcfda0a0259681ce17bc47c9539ae1e7068292bb9646a9ffe4e11653495bd67588cfd6454d82cc455036e5b" ), CAndUncheckedNode( - Challenge @@ ErgoAlgos.decodeUnsafe("a00b476899e583aefc18b237a7a70e73baace72aa533271a"), + Challenge @@ ErgoAlgos.decodeUnsafe("a00b476899e583aefc18b237a7a70e73baace72aa533271a").toColl, List( UncheckedSchnorr( ProveDlog( @@ -203,7 +203,7 @@ class SigSerializerSpecification extends TestingCommons ) ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("a00b476899e583aefc18b237a7a70e73baace72aa533271a"), + Challenge @@ ErgoAlgos.decodeUnsafe("a00b476899e583aefc18b237a7a70e73baace72aa533271a").toColl, SecondDLogProverMessage( BigInt("561d3432c347dcaec8975fdefb36389abe21656aadcfda0a0259681ce17bc47c", 16) ) @@ -215,7 +215,7 @@ class SigSerializerSpecification extends TestingCommons ) ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("a00b476899e583aefc18b237a7a70e73baace72aa533271a"), + Challenge @@ ErgoAlgos.decodeUnsafe("a00b476899e583aefc18b237a7a70e73baace72aa533271a").toColl, SecondDLogProverMessage( BigInt("9539ae1e7068292bb9646a9ffe4e11653495bd67588cfd6454d82cc455036e5b", 16) ) @@ -239,7 +239,7 @@ class SigSerializerSpecification extends TestingCommons "c617e65a2ca62ac97bc33a33b76cb669622129ba0e094ad96287d97c2c6d6c8e48790d7c44961f7d958d59222ab4d7c814808a466a3e66e6f98e02d421757baa2842288b8d02787b5111db2e8924623790175e5bf27a2e4513e8eb196c22c8cf26a9d7b51cd7e386508db9c12b070d84" ), COrUncheckedNode( - Challenge @@ ErgoAlgos.decodeUnsafe("c617e65a2ca62ac97bc33a33b76cb669622129ba0e094ad9"), + Challenge @@ ErgoAlgos.decodeUnsafe("c617e65a2ca62ac97bc33a33b76cb669622129ba0e094ad9").toColl, List( UncheckedSchnorr( ProveDlog( @@ -248,7 +248,7 @@ class SigSerializerSpecification extends TestingCommons ) ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("6287d97c2c6d6c8e48790d7c44961f7d958d59222ab4d7c8"), + Challenge @@ ErgoAlgos.decodeUnsafe("6287d97c2c6d6c8e48790d7c44961f7d958d59222ab4d7c8").toColl, SecondDLogProverMessage( BigInt("14808a466a3e66e6f98e02d421757baa2842288b8d02787b5111db2e89246237", 16) ) @@ -260,7 +260,7 @@ class SigSerializerSpecification extends TestingCommons ) ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("a4903f2600cb464733ba374ff3faa914f7ac709824bd9d11"), + Challenge @@ ErgoAlgos.decodeUnsafe("a4903f2600cb464733ba374ff3faa914f7ac709824bd9d11").toColl, SecondDLogProverMessage( BigInt("90175e5bf27a2e4513e8eb196c22c8cf26a9d7b51cd7e386508db9c12b070d84", 16) ) @@ -295,7 +295,7 @@ class SigSerializerSpecification extends TestingCommons "96addfddcc197bdbacf5c0142fb16c39384b3699fa47da7dffd3149193b042fda134c0e208fefcb791379959ac6fc731adf47e32000fc75e2923dba482c843c7f6b684cbf2ceec5bfdf5fe6d13cabe5d15f8295ca4e8094fba3c4716bfdfc3c462417a79a61fcc487d6997a42739d533eebffa3b420a6e2e44616a1341e5baa1165c6c22e91a81addd97c3bd2fe40ecdbbda6f43bf71240da8dac878c044c16d42a4b34c536bbb1b" ), COrUncheckedNode( - Challenge @@ ErgoAlgos.decodeUnsafe("96addfddcc197bdbacf5c0142fb16c39384b3699fa47da7d"), + Challenge @@ ErgoAlgos.decodeUnsafe("96addfddcc197bdbacf5c0142fb16c39384b3699fa47da7d").toColl, List( UncheckedDiffieHellmanTuple( ProveDHTuple( @@ -305,16 +305,16 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("03f17cefec3911966dc9952090325267a5cf7f9b0be76b02623021989d7f0007a2") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("ffd3149193b042fda134c0e208fefcb791379959ac6fc731"), + Challenge @@ ErgoAlgos.decodeUnsafe("ffd3149193b042fda134c0e208fefcb791379959ac6fc731").toColl, SecondDiffieHellmanTupleProverMessage(new BigInteger("adf47e32000fc75e2923dba482c843c7f6b684cbf2ceec5bfdf5fe6d13cabe5d", 16)) ), COrUncheckedNode( - Challenge @@ ErgoAlgos.decodeUnsafe("697ecb4c5fa939260dc100f6274f908ea97cafc056281d4c"), + Challenge @@ ErgoAlgos.decodeUnsafe("697ecb4c5fa939260dc100f6274f908ea97cafc056281d4c").toColl, List( UncheckedSchnorr( ProveDlog(Helpers.decodeECPoint("03f997167c03aa234732e3a68126b371dffa1e409f62ca8fa18cea6acd1dbe54d5")), None, - Challenge @@ ErgoAlgos.decodeUnsafe("15f8295ca4e8094fba3c4716bfdfc3c462417a79a61fcc48"), + Challenge @@ ErgoAlgos.decodeUnsafe("15f8295ca4e8094fba3c4716bfdfc3c462417a79a61fcc48").toColl, SecondDLogProverMessage(BigInt("7d6997a42739d533eebffa3b420a6e2e44616a1341e5baa1165c6c22e91a81ad", 16)) ), UncheckedDiffieHellmanTuple( @@ -325,7 +325,7 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("02fc58b939b105231da101540c87e56f5703460c179935aaee47137f3c367904f1") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("7c86e210fb413069b7fd47e09890534acb3dd5b9f037d104"), + Challenge @@ ErgoAlgos.decodeUnsafe("7c86e210fb413069b7fd47e09890534acb3dd5b9f037d104").toColl, SecondDiffieHellmanTupleProverMessage(new BigInteger("dd97c3bd2fe40ecdbbda6f43bf71240da8dac878c044c16d42a4b34c536bbb1b", 16)) ) ) @@ -370,15 +370,15 @@ class SigSerializerSpecification extends TestingCommons "4fdc76711fd844de0831d8e90ebaf9c622117a062b2f8b63ff8b9c2a4eed345a11c697f6850cf3a38763d738539ad2d2e0a3e44384f23eee260931d88e1f5241a2600a7c98545ada675fd5e627e8e84f140fc95e28775cde52e71bb4d7b5ee2564553fac5b52202530fcbcdf205b7cca145202fb2a5bb181a890eb15536b08b747ea163f6b5d32a116fa9e1eb6b348fd82d3ebc11c125e5bc3f09c499aa0a8db14dc1780b4181f9bae5ed0f743f71b82b18784380814507d810cbef61ebc0b30e7f324083e2d3d08" ), COrUncheckedNode( - Challenge @@ ErgoAlgos.decodeUnsafe("4fdc76711fd844de0831d8e90ebaf9c622117a062b2f8b63"), + Challenge @@ ErgoAlgos.decodeUnsafe("4fdc76711fd844de0831d8e90ebaf9c622117a062b2f8b63").toColl, List( CAndUncheckedNode( - Challenge @@ ErgoAlgos.decodeUnsafe("ff8b9c2a4eed345a11c697f6850cf3a38763d738539ad2d2"), + Challenge @@ ErgoAlgos.decodeUnsafe("ff8b9c2a4eed345a11c697f6850cf3a38763d738539ad2d2").toColl, List( UncheckedSchnorr( ProveDlog(Helpers.decodeECPoint("0368c0d88d9eb2972bbfc23c961de6307f6a944352cbfe316f262401feabdaa87d")), None, - Challenge @@ ErgoAlgos.decodeUnsafe("ff8b9c2a4eed345a11c697f6850cf3a38763d738539ad2d2"), + Challenge @@ ErgoAlgos.decodeUnsafe("ff8b9c2a4eed345a11c697f6850cf3a38763d738539ad2d2").toColl, SecondDLogProverMessage(BigInt("e0a3e44384f23eee260931d88e1f5241a2600a7c98545ada675fd5e627e8e84f", 16)) ), UncheckedDiffieHellmanTuple( @@ -389,13 +389,13 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("029d4ec275379f9212a53e15994aef203dcec43a177c0b1f40afcf592e5753ce67") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("ff8b9c2a4eed345a11c697f6850cf3a38763d738539ad2d2"), + Challenge @@ ErgoAlgos.decodeUnsafe("ff8b9c2a4eed345a11c697f6850cf3a38763d738539ad2d2").toColl, SecondDiffieHellmanTupleProverMessage(new BigInteger("140fc95e28775cde52e71bb4d7b5ee2564553fac5b52202530fcbcdf205b7cca", 16)) ) ) ), COrUncheckedNode( - Challenge @@ ErgoAlgos.decodeUnsafe("b057ea5b5135708419f74f1f8bb60a65a572ad3e78b559b1"), + Challenge @@ ErgoAlgos.decodeUnsafe("b057ea5b5135708419f74f1f8bb60a65a572ad3e78b559b1").toColl, List( UncheckedDiffieHellmanTuple( ProveDHTuple( @@ -405,7 +405,7 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("0315d84dba1b29074f766e57bb11843687da899180cf2487ccecd0a3ec5f05365a") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("145202fb2a5bb181a890eb15536b08b747ea163f6b5d32a1"), + Challenge @@ ErgoAlgos.decodeUnsafe("145202fb2a5bb181a890eb15536b08b747ea163f6b5d32a1").toColl, SecondDiffieHellmanTupleProverMessage(new BigInteger("16fa9e1eb6b348fd82d3ebc11c125e5bc3f09c499aa0a8db14dc1780b4181f9b", 16)) ), UncheckedDiffieHellmanTuple( @@ -416,7 +416,7 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("0315d84dba1b29074f766e57bb11843687da899180cf2487ccecd0a3ec5f05365a") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("a405e8a07b6ec105b167a40ad8dd02d2e298bb0113e86b10"), + Challenge @@ ErgoAlgos.decodeUnsafe("a405e8a07b6ec105b167a40ad8dd02d2e298bb0113e86b10").toColl, SecondDiffieHellmanTupleProverMessage(new BigInteger("ae5ed0f743f71b82b18784380814507d810cbef61ebc0b30e7f324083e2d3d08", 16)) ) ) @@ -448,12 +448,12 @@ class SigSerializerSpecification extends TestingCommons "c94696c3e3089d9fd1174c18e6dd22f1be8003bbea08011fcf39310e7c9049c1c9966198b8d63a2f19e98843b81b74399f662dba4e764cd548406dd180453dd1bc0e24562f0184d189ca25a41ca8b54ada857dd649d3228a8c359ac499d430ecada3f92d5206cddeffb16248068c1003477d717e04afbf206c87a59ce5263ee7cc4020b5772d91b1df00bd72b15347fd" ), CThresholdUncheckedNode( - Challenge @@ ErgoAlgos.decodeUnsafe("c94696c3e3089d9fd1174c18e6dd22f1be8003bbea08011f"), + Challenge @@ ErgoAlgos.decodeUnsafe("c94696c3e3089d9fd1174c18e6dd22f1be8003bbea08011f").toColl, List( UncheckedSchnorr( ProveDlog(Helpers.decodeECPoint("03a5a5234701fff48be4ed1b3e1fab446657eeddb52e2573c52b9c4021f2403866")), None, - Challenge @@ ErgoAlgos.decodeUnsafe("067fa7cd9f98d45e18812d805e0b18dea7698bf852137526"), + Challenge @@ ErgoAlgos.decodeUnsafe("067fa7cd9f98d45e18812d805e0b18dea7698bf852137526").toColl, SecondDLogProverMessage(BigInt("9f662dba4e764cd548406dd180453dd1bc0e24562f0184d189ca25a41ca8b54a", 16)) ), UncheckedDiffieHellmanTuple( @@ -464,7 +464,7 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("02730455ebb8c01a89dced09c5253c9bfa4b1471d1068ba30ab226104a6551c461") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("5735f4df1b280e1d423a8f28977057af8c52123c9a3fe96d"), + Challenge @@ ErgoAlgos.decodeUnsafe("5735f4df1b280e1d423a8f28977057af8c52123c9a3fe96d").toColl, SecondDiffieHellmanTupleProverMessage(new BigInteger("da857dd649d3228a8c359ac499d430ecada3f92d5206cddeffb16248068c1003", 16)) ), UncheckedDiffieHellmanTuple( @@ -475,7 +475,7 @@ class SigSerializerSpecification extends TestingCommons Helpers.decodeECPoint("03cefefa1511430ca2a873759107085f269f6fbcd4e836db7760749f52b7f7923a") ), None, - Challenge @@ ErgoAlgos.decodeUnsafe("980cc5d167b847dc8baceeb02fa66d8095bb9a7f22249d54"), + Challenge @@ ErgoAlgos.decodeUnsafe("980cc5d167b847dc8baceeb02fa66d8095bb9a7f22249d54").toColl, SecondDiffieHellmanTupleProverMessage(new BigInteger("477d717e04afbf206c87a59ce5263ee7cc4020b5772d91b1df00bd72b15347fd", 16)) ) ), @@ -525,7 +525,9 @@ class SigSerializerSpecification extends TestingCommons r.position = 0 var reported = false - val res = SigSerializer.readBytesChecked(r, nRequested, msg => reported = true) + val res = SigSerializer.readBytesChecked(r, + numRequestedBytes = nRequested, + onError = _ => reported = true) res shouldBe bytes reported shouldBe true } diff --git a/interpreter/shared/src/test/scala/sigmastate/serialization/generators/TypeGenerators.scala b/interpreter/shared/src/test/scala/sigmastate/serialization/generators/TypeGenerators.scala index c4c964cc74..2582d1305c 100644 --- a/interpreter/shared/src/test/scala/sigmastate/serialization/generators/TypeGenerators.scala +++ b/interpreter/shared/src/test/scala/sigmastate/serialization/generators/TypeGenerators.scala @@ -5,24 +5,24 @@ import org.scalacheck.Arbitrary.arbString import sigmastate._ trait TypeGenerators { - implicit val booleanTypeGen = Gen.const(SBoolean) - implicit val byteTypeGen = Gen.const(SByte) - implicit val shortTypeGen = Gen.const(SShort) - implicit val intTypeGen = Gen.const(SInt) - implicit val longTypeGen = Gen.const(SLong) - implicit val bigIntTypeGen = Gen.const(SBigInt) - implicit val groupElementTypeGen = Gen.const(SGroupElement) - implicit val sigmaPropTypeGen = Gen.const(SSigmaProp) - implicit val boxTypeGen = Gen.const(SBox) - implicit val avlTreeTypeGen = Gen.const(SAvlTree) - implicit val optionSigmaPropTypeGen = Gen.const(SOption(SSigmaProp)) + implicit val booleanTypeGen: Gen[SBoolean.type] = Gen.const(SBoolean) + implicit val byteTypeGen: Gen[SByte.type] = Gen.const(SByte) + implicit val shortTypeGen: Gen[SShort.type] = Gen.const(SShort) + implicit val intTypeGen: Gen[SInt.type] = Gen.const(SInt) + implicit val longTypeGen: Gen[SLong.type] = Gen.const(SLong) + implicit val bigIntTypeGen: Gen[SBigInt.type] = Gen.const(SBigInt) + implicit val groupElementTypeGen: Gen[SGroupElement.type] = Gen.const(SGroupElement) + implicit val sigmaPropTypeGen: Gen[SSigmaProp.type] = Gen.const(SSigmaProp) + implicit val boxTypeGen: Gen[SBox.type] = Gen.const(SBox) + implicit val avlTreeTypeGen: Gen[SAvlTree.type] = Gen.const(SAvlTree) + implicit val optionSigmaPropTypeGen: Gen[SOption[SSigmaProp.type]] = Gen.const(SOption(SSigmaProp)) implicit val primTypeGen: Gen[SPrimType] = Gen.oneOf[SPrimType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit) - implicit val arbPrimType = Arbitrary(primTypeGen) + implicit val arbPrimType: Arbitrary[SPrimType] = Arbitrary(primTypeGen) implicit val predefTypeGen: Gen[SPredefType] = Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree) - implicit val arbPredefType = Arbitrary(predefTypeGen) + implicit val arbPredefType: Arbitrary[SPredefType] = Arbitrary(predefTypeGen) implicit def genToArbitrary[T: Gen]: Arbitrary[T] = Arbitrary(implicitly[Gen[T]]) diff --git a/interpreter/shared/src/test/scala/sigmastate/utils/HelpersTests.scala b/interpreter/shared/src/test/scala/sigmastate/utils/HelpersTests.scala index c1accad043..3325035bbd 100644 --- a/interpreter/shared/src/test/scala/sigmastate/utils/HelpersTests.scala +++ b/interpreter/shared/src/test/scala/sigmastate/utils/HelpersTests.scala @@ -5,12 +5,16 @@ import Helpers._ import org.scalatest.matchers.should.Matchers import org.scalatest.propspec.AnyPropSpec import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks +import sigmastate.eval.Extensions.ArrayOps class HelpersTests extends AnyPropSpec with ScalaCheckPropertyChecks with Matchers with ObjectGenerators { property("xorU") { forAll(arrayGen[Byte]) { arr => val x = xor(arr, arr) + val xColl = xor(arr.toColl, arr.toColl) + x shouldBe xColl.toArray + val cloned = arr.clone() xorU(cloned, arr) cloned shouldBe x @@ -18,7 +22,13 @@ class HelpersTests extends AnyPropSpec with ScalaCheckPropertyChecks with Matche val arr1 = x val arr2 = cloned val arr3 = xor(arr1, arr2) + val arr3Coll = xor(arr1.toColl, arr2.toColl) + arr3 shouldBe arr3Coll.toArray + val res1 = xor(cloned, arr1, arr2, arr3) + val res1Coll = xor(cloned.toColl, arr1.toColl, arr2.toColl, arr3.toColl) + res1 shouldBe res1Coll.toArray + val res2 = cloned xorU(res2, Seq(arr1, arr2, arr3)) diff --git a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Isos.scala b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Isos.scala index c00f72bdff..e045294eab 100644 --- a/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Isos.scala +++ b/sdk/js/src/main/scala/org/ergoplatform/sdk/js/Isos.scala @@ -1,30 +1,30 @@ package org.ergoplatform.sdk.js import org.ergoplatform.ErgoBox._ -import org.ergoplatform.{DataInput, ErgoBox, ErgoBoxCandidate, UnsignedErgoLikeTransaction, UnsignedInput} -import org.ergoplatform.sdk.{ExtendedInputBox, Iso} import org.ergoplatform.sdk.JavaHelpers.UniversalConverter import org.ergoplatform.sdk.wallet.protocol.context.{CErgoLikeStateContext, ErgoLikeStateContext} +import org.ergoplatform.sdk.{ExtendedInputBox, Iso} +import org.ergoplatform._ import scalan.RType -import scorex.crypto.authds.{ADDigest, ADKey} +import scorex.crypto.authds.ADKey import scorex.util.ModifierId import scorex.util.encode.Base16 -import sigmastate.{AvlTreeData, AvlTreeFlags, SType} import sigmastate.Values.{Constant, GroupElementConstant} import sigmastate.eval.Extensions.ArrayOps import sigmastate.eval.{CAvlTree, CBigInt, CHeader, CPreHeader, Colls, Digest32Coll, Evaluation} +import sigmastate.fleetSdkCommon.distEsmTypesBoxesMod.Box +import sigmastate.fleetSdkCommon.distEsmTypesCommonMod.HexString +import sigmastate.fleetSdkCommon.distEsmTypesRegistersMod.NonMandatoryRegisters +import sigmastate.fleetSdkCommon.distEsmTypesTokenMod.TokenAmount +import sigmastate.fleetSdkCommon.distEsmTypesTransactionsMod.UnsignedTransaction import sigmastate.fleetSdkCommon.{distEsmTypesBoxesMod => boxesMod, distEsmTypesCommonMod => commonMod, distEsmTypesContextExtensionMod => contextExtensionMod, distEsmTypesInputsMod => inputsMod, distEsmTypesRegistersMod => registersMod, distEsmTypesTokenMod => tokenMod} import sigmastate.interpreter.ContextExtension import sigmastate.serialization.{ErgoTreeSerializer, ValueSerializer} +import sigmastate.{AvlTreeData, AvlTreeFlags, SType} import special.collection.Coll import special.collection.Extensions.CollBytesOps import special.sigma import special.sigma.GroupElement -import sigmastate.fleetSdkCommon.distEsmTypesBoxesMod.Box -import sigmastate.fleetSdkCommon.distEsmTypesCommonMod.HexString -import sigmastate.fleetSdkCommon.distEsmTypesRegistersMod.NonMandatoryRegisters -import sigmastate.fleetSdkCommon.distEsmTypesTokenMod.TokenAmount -import sigmastate.fleetSdkCommon.distEsmTypesTransactionsMod.UnsignedTransaction import java.math.BigInteger import scala.collection.immutable.ListMap From 49d1255978d3d0edad2ddf7bfe31e481937b94c0 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sun, 30 Jul 2023 16:25:57 +0200 Subject: [PATCH 4/7] refactoring: avoided duplicated code in computing response to challenge --- .../main/scala/sigmastate/SigSerializer.scala | 4 +- .../main/scala/sigmastate/UncheckedTree.scala | 6 +- .../main/scala/sigmastate/UnprovenTree.scala | 4 +- .../sigmastate/basics/DLogProtocol.scala | 8 +-- .../basics/DiffieHellmanTupleProtocol.scala | 65 ++++++++++++------- .../basics/SigmaProtocolFunctions.scala | 30 ++++++++- .../sigmastate/interpreter/Interpreter.scala | 2 +- .../interpreter/ProverInterpreter.scala | 4 +- .../src/main/scala/sigmastate/trees.scala | 2 +- .../SigSerializerSpecification.scala | 18 ++--- .../sigmastate/utxo/ProverSpecification.scala | 4 +- 11 files changed, 93 insertions(+), 54 deletions(-) diff --git a/interpreter/shared/src/main/scala/sigmastate/SigSerializer.scala b/interpreter/shared/src/main/scala/sigmastate/SigSerializer.scala index 033d7f7b62..f003586d85 100644 --- a/interpreter/shared/src/main/scala/sigmastate/SigSerializer.scala +++ b/interpreter/shared/src/main/scala/sigmastate/SigSerializer.scala @@ -5,7 +5,7 @@ import scorex.util.encode.Base16 import sigmastate.Values.SigmaBoolean import sigmastate.basics.DLogProtocol.{ProveDlog, SecondDLogProverMessage} import sigmastate.basics.VerifierMessage.Challenge -import sigmastate.basics.{CryptoConstants, ProveDHTuple, SecondDiffieHellmanTupleProverMessage} +import sigmastate.basics.{CryptoConstants, ProveDHTuple, SecondDHTupleProverMessage} import sigmastate.interpreter.ErgoTreeEvaluator.{fixedCostOp, perItemCostOp} import sigmastate.interpreter.{ErgoTreeEvaluator, NamedDesc, OperationCostInfo} import sigmastate.serialization.SigmaSerializer @@ -204,7 +204,7 @@ class SigSerializer { fixedCostOp(ParseChallenge_ProveDHT) { val z_bytes = readBytesChecked(r, order, hex => warn(s"Invalid z bytes for $dh: $hex")) val z = BigIntegers.fromUnsignedByteArray(z_bytes) - UncheckedDiffieHellmanTuple(dh, None, challenge, SecondDiffieHellmanTupleProverMessage(z)) + UncheckedDiffieHellmanTuple(dh, None, challenge, SecondDHTupleProverMessage(z)) } case and: CAND => diff --git a/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala b/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala index 2f4f78fdca..99e26be99e 100644 --- a/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala +++ b/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala @@ -3,7 +3,7 @@ package sigmastate import sigmastate.basics.DLogProtocol.{FirstDLogProverMessage, ProveDlog, SecondDLogProverMessage} import sigmastate.basics.VerifierMessage.Challenge import sigmastate.Values.SigmaBoolean -import sigmastate.basics.{FirstDiffieHellmanTupleProverMessage, ProveDHTuple, SecondDiffieHellmanTupleProverMessage} +import sigmastate.basics.{FirstDHTupleProverMessage, ProveDHTuple, SecondDHTupleProverMessage} import sigmastate.crypto.GF2_192_Poly sealed trait UncheckedTree extends ProofTree @@ -29,9 +29,9 @@ case class UncheckedSchnorr( case class UncheckedDiffieHellmanTuple( override val proposition: ProveDHTuple, - override val commitmentOpt: Option[FirstDiffieHellmanTupleProverMessage], + override val commitmentOpt: Option[FirstDHTupleProverMessage], override val challenge: Challenge, - secondMessage: SecondDiffieHellmanTupleProverMessage + secondMessage: SecondDHTupleProverMessage ) extends UncheckedLeaf[ProveDHTuple] case class CAndUncheckedNode( diff --git a/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala b/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala index fff252c3b9..db5aed3a37 100644 --- a/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala +++ b/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala @@ -4,7 +4,7 @@ import java.math.BigInteger import sigmastate.Values.{ErgoTree, SigmaBoolean, SigmaPropConstant} import sigmastate.basics.DLogProtocol.{FirstDLogProverMessage, ProveDlog} import sigmastate.basics.VerifierMessage.Challenge -import sigmastate.basics.{FirstDiffieHellmanTupleProverMessage, FirstProverMessage, ProveDHTuple} +import sigmastate.basics.{FirstDHTupleProverMessage, FirstProverMessage, ProveDHTuple} import sigmastate.interpreter.{ErgoTreeEvaluator, NamedDesc, OperationCostInfo} import sigmastate.interpreter.ErgoTreeEvaluator.fixedCostOp import sigmastate.serialization.ErgoTreeSerializer.DefaultSerializer @@ -187,7 +187,7 @@ case class UnprovenSchnorr(override val proposition: ProveDlog, } case class UnprovenDiffieHellmanTuple(override val proposition: ProveDHTuple, - override val commitmentOpt: Option[FirstDiffieHellmanTupleProverMessage], + override val commitmentOpt: Option[FirstDHTupleProverMessage], randomnessOpt: Option[BigInteger], override val challengeOpt: Option[Challenge] = None, override val simulated: Boolean, diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala b/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala index d286c2dda3..9b801d7ad1 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/DLogProtocol.scala @@ -91,13 +91,7 @@ object DLogProtocol { } def secondMessage(privateInput: DLogProverInput, rnd: BigInteger, challenge: Challenge): SecondDLogProverMessage = { - import CryptoConstants.dlogGroup - - // TODO: get rid of duplicate code - val q: BigInteger = dlogGroup.order - val e: BigInteger = new BigInteger(1, challenge.toArray) - val ew: BigInteger = e.multiply(privateInput.w).mod(q) - val z: BigInteger = rnd.add(ew).mod(q) + val z = responseToChallenge(privateInput, rnd, challenge) SecondDLogProverMessage(z) } diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala b/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala index 62174dc5da..e39508bf4f 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/DiffieHellmanTupleProtocol.scala @@ -14,8 +14,8 @@ import special.sigma.SigmaProp trait DiffieHellmanTupleProtocol extends SigmaProtocol[DiffieHellmanTupleProtocol] { - override type A = FirstDiffieHellmanTupleProverMessage - override type Z = SecondDiffieHellmanTupleProverMessage + override type A = FirstDHTupleProverMessage + override type Z = SecondDHTupleProverMessage } case class DiffieHellmanTupleProverInput(w: BigInteger, commonInput: ProveDHTuple) @@ -41,8 +41,12 @@ object DiffieHellmanTupleProverInput { } } -//a = g^r, b = h^r -case class FirstDiffieHellmanTupleProverMessage(a: CryptoConstants.EcPointType, b: CryptoConstants.EcPointType) +/** First message of Diffie Hellman tuple sigma protocol. + * @param a commitment to secret randomness `a = g^r`, where `g` is default generator of the group + * @param b commitment to secret randomness `b = h^r`, where `h` is another random generator of the group + * @see createRandomGenerator in [[sigmastate.basics.CryptoConstants.dlogGroup]] + */ +case class FirstDHTupleProverMessage(a: EcPointType, b: EcPointType) extends FirstProverMessage { override type SP = DiffieHellmanTupleProtocol @@ -52,11 +56,15 @@ case class FirstDiffieHellmanTupleProverMessage(a: CryptoConstants.EcPointType, } } -//z = r + ew mod q -case class SecondDiffieHellmanTupleProverMessage(z: BigInteger) extends SecondProverMessage { - +/** Represents a response for challenge in Diffie Hellman tuple sigma protocol. + * @param z responce to the challenge computed as `(r + ew) mod q`, where + * `r` is the prover's randomness, + * `e` challenge from the verifier (also computed by the prover in non-interactive case), + * `w` is the prover's secret. + * `q` is the group order + */ +case class SecondDHTupleProverMessage(z: BigInteger) extends SecondProverMessage { override type SP = DiffieHellmanTupleProtocol - } /** Construct a new SigmaProp value representing public key of Diffie Hellman signature protocol. @@ -87,33 +95,42 @@ object DiffieHellmanTupleInteractiveProver extends SigmaProtocolProver { import CryptoConstants.dlogGroup - def firstMessage(publicInput: ProveDHTuple): (BigInteger, FirstDiffieHellmanTupleProverMessage) = { + /** Create a commitment to randomness r and a first message of sigma protocol. */ + def firstMessage(publicInput: ProveDHTuple): (BigInteger, FirstDHTupleProverMessage) = { val qMinusOne = dlogGroup.order.subtract(BigInteger.ONE) val r = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, dlogGroup.secureRandom) val a = dlogGroup.exponentiate(publicInput.g, r) val b = dlogGroup.exponentiate(publicInput.h, r) - r -> FirstDiffieHellmanTupleProverMessage(a, b) + r -> FirstDHTupleProverMessage(a, b) } + /** Creates second message of sigma protocol, which is a response for the challenge from the verifier. + * + * @param privateInput private input of the prover (secret) + * @param rnd random number generated by the prover (secret random number used to + * compute commitment) + * @param challenge challenge from the verifier (also computed by the prover in non-interactive case) + * @return second message from the prover + */ def secondMessage(privateInput: DiffieHellmanTupleProverInput, rnd: BigInteger, - challenge: Challenge): SecondDiffieHellmanTupleProverMessage = { - val q: BigInteger = dlogGroup.order - val e: BigInteger = new BigInteger(1, challenge.toArray) - val ew: BigInteger = e.multiply(privateInput.w).mod(q) - val z: BigInteger = rnd.add(ew).mod(q) - SecondDiffieHellmanTupleProverMessage(z) + challenge: Challenge): SecondDHTupleProverMessage = { + val z = responseToChallenge(privateInput, rnd, challenge) + SecondDHTupleProverMessage(z) } - def simulate(publicInput: ProveDHTuple, challenge: Challenge): - (FirstDiffieHellmanTupleProverMessage, SecondDiffieHellmanTupleProverMessage) = { + /** Simulates messages of the sigma protocol which are indistinquishable from generated + * by the real prover. */ + def simulate(publicInput: ProveDHTuple, challenge: Challenge): (FirstDHTupleProverMessage, SecondDHTupleProverMessage) = { val qMinusOne = dlogGroup.order.subtract(BigInteger.ONE) - //SAMPLE a random z <- Zq + //SAMPLE a random z <- Zq, this will be the simulated response to the challenge val z = BigIntegers.createRandomInRange(BigInteger.ZERO, qMinusOne, dlogGroup.secureRandom) // COMPUTE a = g^z*u^(-e) and b = h^z*v^{-e} (where -e here means -e mod q) + // in real prover we compute commitments from random number and them compute response to the challenge, + // but here we do in opposite direction, use random response and compute commitments from it val e: BigInteger = new BigInteger(1, challenge.toArray) val minusE = dlogGroup.order.subtract(e) val hToZ = dlogGroup.exponentiate(publicInput.h, z) @@ -122,7 +139,7 @@ object DiffieHellmanTupleInteractiveProver extends SigmaProtocolProver { val vToMinusE = dlogGroup.exponentiate(publicInput.v, minusE) val a = dlogGroup.multiplyGroupElements(gToZ, uToMinusE) val b = dlogGroup.multiplyGroupElements(hToZ, vToMinusE) - FirstDiffieHellmanTupleProverMessage(a, b) -> SecondDiffieHellmanTupleProverMessage(z) + FirstDHTupleProverMessage(a, b) -> SecondDHTupleProverMessage(z) } /** @@ -133,14 +150,14 @@ object DiffieHellmanTupleInteractiveProver extends SigmaProtocolProver { * * g^z = a*u^e, h^z = b*v^e => a = g^z/u^e, b = h^z/v^e * - * @param proposition - * @param challenge - * @param secondMessage + * @param proposition proposition "I know DH tuple" + * @param challenge challenge from verifier + * @param secondMessage prover's response to the challenge * @return */ def computeCommitment(proposition: ProveDHTuple, challenge: Challenge, - secondMessage: SecondDiffieHellmanTupleProverMessage): (EcPointType, EcPointType) = { + secondMessage: SecondDHTupleProverMessage): (EcPointType, EcPointType) = { val g = proposition.g val h = proposition.h diff --git a/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala b/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala index 5b35fcad3a..2350c3f1d2 100644 --- a/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala +++ b/interpreter/shared/src/main/scala/sigmastate/basics/SigmaProtocolFunctions.scala @@ -1,9 +1,14 @@ package sigmastate.basics import sigmastate.SigmaLeaf +import sigmastate.basics.CryptoConstants.dlogGroup +import sigmastate.basics.DLogProtocol.{DLogProverInput, ProveDlog} +import sigmastate.basics.VerifierMessage.Challenge import special.collection.Coll import supertagged.TaggedType +import java.math.BigInteger + /* Abstracting Sigma protocols Functionality to get: @@ -53,11 +58,34 @@ trait SigmaProtocol[SP <: SigmaProtocol[SP]] { trait SigmaProtocolPrivateInput[CI <: SigmaLeaf] { + /** Public image generated from the secret. + * Represents proof of knowledge proposition. + */ def publicImage: CI + + /** Secret random number known to the prover. */ + def w: BigInteger } trait SigmaProtocolProver { - + /** Computes response for the challenge in non-interactive sigma protocol. + * + * @param privateInput private input of the prover (secret) + * @param rnd random number generated by the prover (secret random number used to + * compute commitment) + * @param challenge challenge from the verifier (also computed by the prover in non-interactive case) + * @return response computed by the prover + */ + protected def responseToChallenge( + privateInput: SigmaProtocolPrivateInput[_ <: SigmaLeaf], + rnd: BigInteger, + challenge: Challenge): BigInteger = { + val q: BigInteger = dlogGroup.order + val e: BigInteger = new BigInteger(1, challenge.toArray) + val ew: BigInteger = e.multiply(privateInput.w).mod(q) + val z: BigInteger = rnd.add(ew).mod(q) + z + } } diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala index c927dff826..d30a862f98 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala @@ -405,7 +405,7 @@ trait Interpreter { implicit val E = ErgoTreeEvaluator.getCurrentEvaluator fixedCostOp(ComputeCommitments_DHT) { val (a, b) = DiffieHellmanTupleInteractiveProver.computeCommitment(dh.proposition, dh.challenge, dh.secondMessage) - dh.copy(commitmentOpt = Some(FirstDiffieHellmanTupleProverMessage(a, b))) + dh.copy(commitmentOpt = Some(FirstDHTupleProverMessage(a, b))) } case _: UncheckedSigmaTree => ??? diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala index 794fd737ce..e9dfa6b052 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverInterpreter.scala @@ -399,7 +399,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { // Step 6 (real leaf -- compute the commitment a or take it from the hints bag) hintsBag.commitments.find(_.position == dhu.position).map { cmtHint => - dhu.copy(commitmentOpt = Some(cmtHint.commitment.asInstanceOf[FirstDiffieHellmanTupleProverMessage])) + dhu.copy(commitmentOpt = Some(cmtHint.commitment.asInstanceOf[FirstDHTupleProverMessage])) }.getOrElse { if (dhu.simulated) { // Step 5 (simulated leaf -- complete the simulation) @@ -542,7 +542,7 @@ trait ProverInterpreter extends Interpreter with ProverUtils { provenSchnorr.secondMessage }.getOrElse { val bs = secureRandomBytes(32) - SecondDiffieHellmanTupleProverMessage(new BigInteger(1, bs).mod(CryptoConstants.groupOrder)) + SecondDHTupleProverMessage(new BigInteger(1, bs).mod(CryptoConstants.groupOrder)) } } UncheckedDiffieHellmanTuple(dhu.proposition, None, dhu.challengeOpt.get, z) diff --git a/interpreter/shared/src/main/scala/sigmastate/trees.scala b/interpreter/shared/src/main/scala/sigmastate/trees.scala index e745a88c91..533229f652 100644 --- a/interpreter/shared/src/main/scala/sigmastate/trees.scala +++ b/interpreter/shared/src/main/scala/sigmastate/trees.scala @@ -35,7 +35,7 @@ trait SigmaConjecture extends SigmaBoolean { } /** - * Basic trait for leafs of crypto-trees, such as ProveDlog and ProveDiffieHellman instances + * Basic trait for leafs of crypto-trees, such as [[sigmastate.basics.DLogProtocol.ProveDlog]] and [[sigmastate.basics.ProveDHTuple]] instances */ trait SigmaLeaf extends SigmaBoolean diff --git a/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala index f34e2c784a..884b8d7150 100644 --- a/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala @@ -8,7 +8,7 @@ import sigmastate.Values.SigmaBoolean import sigmastate._ import sigmastate.basics.DLogProtocol.{ProveDlog, SecondDLogProverMessage} import sigmastate.basics.VerifierMessage.Challenge -import sigmastate.basics.{ProveDHTuple, SecondDiffieHellmanTupleProverMessage} +import sigmastate.basics.{ProveDHTuple, SecondDHTupleProverMessage} import sigmastate.crypto.GF2_192_Poly import sigmastate.eval.Extensions.ArrayOps import sigmastate.helpers.{ContextEnrichingTestProvingInterpreter, ErgoLikeContextTesting, ErgoLikeTransactionTesting, TestingCommons} @@ -173,7 +173,7 @@ class SigSerializerSpecification extends TestingCommons ), None, Challenge @@ ErgoAlgos.decodeUnsafe("9ec740b57353cb2f6035bb1a481b0066b2fdc0406a6fa67e").toColl, - SecondDiffieHellmanTupleProverMessage( + SecondDHTupleProverMessage( new BigInteger("bb2e6f44a38052b3f564fafcd477c4eb8cda1a8a553a4a5f38f1e1084d6a69f0", 16) ) ), @@ -306,7 +306,7 @@ class SigSerializerSpecification extends TestingCommons ), None, Challenge @@ ErgoAlgos.decodeUnsafe("ffd3149193b042fda134c0e208fefcb791379959ac6fc731").toColl, - SecondDiffieHellmanTupleProverMessage(new BigInteger("adf47e32000fc75e2923dba482c843c7f6b684cbf2ceec5bfdf5fe6d13cabe5d", 16)) + SecondDHTupleProverMessage(new BigInteger("adf47e32000fc75e2923dba482c843c7f6b684cbf2ceec5bfdf5fe6d13cabe5d", 16)) ), COrUncheckedNode( Challenge @@ ErgoAlgos.decodeUnsafe("697ecb4c5fa939260dc100f6274f908ea97cafc056281d4c").toColl, @@ -326,7 +326,7 @@ class SigSerializerSpecification extends TestingCommons ), None, Challenge @@ ErgoAlgos.decodeUnsafe("7c86e210fb413069b7fd47e09890534acb3dd5b9f037d104").toColl, - SecondDiffieHellmanTupleProverMessage(new BigInteger("dd97c3bd2fe40ecdbbda6f43bf71240da8dac878c044c16d42a4b34c536bbb1b", 16)) + SecondDHTupleProverMessage(new BigInteger("dd97c3bd2fe40ecdbbda6f43bf71240da8dac878c044c16d42a4b34c536bbb1b", 16)) ) ) ) @@ -390,7 +390,7 @@ class SigSerializerSpecification extends TestingCommons ), None, Challenge @@ ErgoAlgos.decodeUnsafe("ff8b9c2a4eed345a11c697f6850cf3a38763d738539ad2d2").toColl, - SecondDiffieHellmanTupleProverMessage(new BigInteger("140fc95e28775cde52e71bb4d7b5ee2564553fac5b52202530fcbcdf205b7cca", 16)) + SecondDHTupleProverMessage(new BigInteger("140fc95e28775cde52e71bb4d7b5ee2564553fac5b52202530fcbcdf205b7cca", 16)) ) ) ), @@ -406,7 +406,7 @@ class SigSerializerSpecification extends TestingCommons ), None, Challenge @@ ErgoAlgos.decodeUnsafe("145202fb2a5bb181a890eb15536b08b747ea163f6b5d32a1").toColl, - SecondDiffieHellmanTupleProverMessage(new BigInteger("16fa9e1eb6b348fd82d3ebc11c125e5bc3f09c499aa0a8db14dc1780b4181f9b", 16)) + SecondDHTupleProverMessage(new BigInteger("16fa9e1eb6b348fd82d3ebc11c125e5bc3f09c499aa0a8db14dc1780b4181f9b", 16)) ), UncheckedDiffieHellmanTuple( ProveDHTuple( @@ -417,7 +417,7 @@ class SigSerializerSpecification extends TestingCommons ), None, Challenge @@ ErgoAlgos.decodeUnsafe("a405e8a07b6ec105b167a40ad8dd02d2e298bb0113e86b10").toColl, - SecondDiffieHellmanTupleProverMessage(new BigInteger("ae5ed0f743f71b82b18784380814507d810cbef61ebc0b30e7f324083e2d3d08", 16)) + SecondDHTupleProverMessage(new BigInteger("ae5ed0f743f71b82b18784380814507d810cbef61ebc0b30e7f324083e2d3d08", 16)) ) ) ) @@ -465,7 +465,7 @@ class SigSerializerSpecification extends TestingCommons ), None, Challenge @@ ErgoAlgos.decodeUnsafe("5735f4df1b280e1d423a8f28977057af8c52123c9a3fe96d").toColl, - SecondDiffieHellmanTupleProverMessage(new BigInteger("da857dd649d3228a8c359ac499d430ecada3f92d5206cddeffb16248068c1003", 16)) + SecondDHTupleProverMessage(new BigInteger("da857dd649d3228a8c359ac499d430ecada3f92d5206cddeffb16248068c1003", 16)) ), UncheckedDiffieHellmanTuple( ProveDHTuple( @@ -476,7 +476,7 @@ class SigSerializerSpecification extends TestingCommons ), None, Challenge @@ ErgoAlgos.decodeUnsafe("980cc5d167b847dc8baceeb02fa66d8095bb9a7f22249d54").toColl, - SecondDiffieHellmanTupleProverMessage(new BigInteger("477d717e04afbf206c87a59ce5263ee7cc4020b5772d91b1df00bd72b15347fd", 16)) + SecondDHTupleProverMessage(new BigInteger("477d717e04afbf206c87a59ce5263ee7cc4020b5772d91b1df00bd72b15347fd", 16)) ) ), 2, diff --git a/interpreter/shared/src/test/scala/sigmastate/utxo/ProverSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/utxo/ProverSpecification.scala index 1ca5bb96a2..360754db6f 100644 --- a/interpreter/shared/src/test/scala/sigmastate/utxo/ProverSpecification.scala +++ b/interpreter/shared/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, SecP256K1Group} +import sigmastate.basics.{FirstDHTupleProverMessage, SecP256K1Group} import sigmastate.exceptions.InterpreterException import sigmastate.helpers.{ErgoLikeTestProvingInterpreter, TestingCommons} import sigmastate.interpreter.{HintsBag, ProverInterpreter} @@ -52,7 +52,7 @@ class ProverSpecification extends TestingCommons { h3.realCommitments.head.commitment shouldBe h3.ownCommitments.head.commitment - h3.realCommitments.head.commitment.isInstanceOf[FirstDiffieHellmanTupleProverMessage] shouldBe true + h3.realCommitments.head.commitment.isInstanceOf[FirstDHTupleProverMessage] shouldBe true } property("setPositions - and") { From 8988532d4fd1ce883e9361a64ae77c5ddba987e7 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Sun, 30 Jul 2023 19:49:54 +0200 Subject: [PATCH 5/7] refactoring: more precise types for ProofTreeLeaf + Hint.image --- .../src/test/scala/scalan/BaseTests.scala | 3 ++- .../main/scala/sigmastate/UncheckedTree.scala | 8 +++--- .../main/scala/sigmastate/UnprovenTree.scala | 2 +- .../scala/sigmastate/interpreter/Hint.scala | 27 +++++++++---------- .../sigmastate/interpreter/ProverUtils.scala | 2 +- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/common/shared/src/test/scala/scalan/BaseTests.scala b/common/shared/src/test/scala/scalan/BaseTests.scala index 64a8c7f615..e015ff948e 100644 --- a/common/shared/src/test/scala/scalan/BaseTests.scala +++ b/common/shared/src/test/scala/scalan/BaseTests.scala @@ -34,7 +34,8 @@ abstract class BaseShouldTests extends AnyFlatSpec with TestUtils { } } - protected implicit def convertToInAndIgnoreMethods2(resultOfStringPassedToVerb: ResultOfStringPassedToVerb) = + protected implicit def convertToInAndIgnoreMethods2( + resultOfStringPassedToVerb: ResultOfStringPassedToVerb): InAndIgnoreMethods2 = new InAndIgnoreMethods2(resultOfStringPassedToVerb) } diff --git a/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala b/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala index 99e26be99e..4b4b28fa0d 100644 --- a/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala +++ b/interpreter/shared/src/main/scala/sigmastate/UncheckedTree.scala @@ -16,23 +16,21 @@ sealed trait UncheckedSigmaTree extends UncheckedTree { trait UncheckedConjecture extends UncheckedSigmaTree with ProofTreeConjecture -trait UncheckedLeaf[SP <: SigmaBoolean] extends UncheckedSigmaTree with ProofTreeLeaf { - val proposition: SigmaBoolean -} +trait UncheckedLeaf extends UncheckedSigmaTree with ProofTreeLeaf case class UncheckedSchnorr( override val proposition: ProveDlog, override val commitmentOpt: Option[FirstDLogProverMessage], override val challenge: Challenge, secondMessage: SecondDLogProverMessage -) extends UncheckedLeaf[ProveDlog] +) extends UncheckedLeaf case class UncheckedDiffieHellmanTuple( override val proposition: ProveDHTuple, override val commitmentOpt: Option[FirstDHTupleProverMessage], override val challenge: Challenge, secondMessage: SecondDHTupleProverMessage -) extends UncheckedLeaf[ProveDHTuple] +) extends UncheckedLeaf case class CAndUncheckedNode( override val challenge: Challenge, diff --git a/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala b/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala index db5aed3a37..a01c937a1f 100644 --- a/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala +++ b/interpreter/shared/src/main/scala/sigmastate/UnprovenTree.scala @@ -25,7 +25,7 @@ object ConjectureType extends Enumeration { trait ProofTree extends Product trait ProofTreeLeaf extends ProofTree { - val proposition: SigmaBoolean + val proposition: SigmaLeaf val commitmentOpt: Option[FirstProverMessage] } diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/Hint.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/Hint.scala index 13570e846c..ab2530f653 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/Hint.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/Hint.scala @@ -1,8 +1,7 @@ package sigmastate.interpreter import java.math.BigInteger - -import sigmastate.{NodePosition, UncheckedTree} +import sigmastate.{NodePosition, SigmaLeaf, UncheckedTree} import sigmastate.Values.SigmaBoolean import sigmastate.basics.FirstProverMessage import sigmastate.basics.VerifierMessage.Challenge @@ -13,6 +12,10 @@ import sigmastate.basics.VerifierMessage.Challenge * prover knows that pk2 is known to another party, the prover may prove the statement (with an empty proof for "pk2"). */ trait Hint { + /** + * Public image of a secret + */ + def image: SigmaLeaf /** * A hint is related to a subtree (or a leaf) of a tree. This field encodes a position in the tree. @@ -25,12 +28,6 @@ trait Hint { * A hint which is indicating that a secret associated with its public image "image" is already proven. */ abstract class SecretProven extends Hint { - - /** - * Public image of a secret which is proven - */ - def image: SigmaBoolean - /** * Challenge used for a proof */ @@ -46,16 +43,16 @@ abstract class SecretProven extends Hint { * A hint which contains a proof-of-knowledge for a secret associated with its public image "image", * with also the mark that the proof is real. */ -case class RealSecretProof(image: SigmaBoolean, +case class RealSecretProof(image: SigmaLeaf, challenge: Challenge, uncheckedTree: UncheckedTree, override val position: NodePosition) extends SecretProven /** * A hint which contains a proof-of-knowledge for a secret associated with its public image "image", - * with also the mark that the proof is real. + * with also the mark that the proof is simulated (not real). */ -case class SimulatedSecretProof(image: SigmaBoolean, +case class SimulatedSecretProof(image: SigmaLeaf, challenge: Challenge, uncheckedTree: UncheckedTree, override val position: NodePosition) extends SecretProven @@ -66,7 +63,7 @@ case class SimulatedSecretProof(image: SigmaBoolean, * to randomness ("a" in a sigma protocol). */ abstract class CommitmentHint extends Hint { - def image: SigmaBoolean + /** Commitment to randomness (first message in a sigma protocol) */ def commitment: FirstProverMessage } @@ -78,7 +75,7 @@ abstract class CommitmentHint extends Hint { * @param secretRandomness - randomness * @param commitment - commitment to randomness used while proving knowledge of the secret */ -case class OwnCommitment(override val image: SigmaBoolean, +case class OwnCommitment(override val image: SigmaLeaf, secretRandomness: BigInteger, commitment: FirstProverMessage, override val position: NodePosition) extends CommitmentHint @@ -89,7 +86,7 @@ case class OwnCommitment(override val image: SigmaBoolean, * @param image - image of a secret * @param commitment - commitment to randomness used while proving knowledge of the secret */ -case class RealCommitment(override val image: SigmaBoolean, +case class RealCommitment(override val image: SigmaLeaf, commitment: FirstProverMessage, override val position: NodePosition) extends CommitmentHint @@ -99,7 +96,7 @@ case class RealCommitment(override val image: SigmaBoolean, * @param image - image of a secret * @param commitment - commitment to randomness used while proving knowledge of the secret */ -case class SimulatedCommitment(override val image: SigmaBoolean, +case class SimulatedCommitment(override val image: SigmaLeaf, commitment: FirstProverMessage, override val position: NodePosition) extends CommitmentHint diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala index 46138ca9d7..e2b0fe8f5a 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ProverUtils.scala @@ -115,7 +115,7 @@ trait ProverUtils extends Interpreter { inner.children.zipWithIndex.foldLeft(hintsBag) { case (hb, (c, idx)) => traverseNode(c, realPropositions, simulatedPropositions, hb, position.child(idx)) } - case leaf: UncheckedLeaf[_] => + case leaf: UncheckedLeaf => val realFound = realPropositions.contains(leaf.proposition) val simulatedFound = simulatedPropositions.contains(leaf.proposition) if (realFound || simulatedFound) { From cf8e3a39200fb61f60f64512a650c60d68a636a1 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Wed, 9 Aug 2023 17:09:56 +0200 Subject: [PATCH 6/7] refactoring: removed ScriptCostLimit constant --- .../scala/org/ergoplatform/SigmaConstants.scala | 5 ----- .../interpreter/ErgoTreeEvaluator.scala | 12 ++++++++---- .../src/test/scala/sigmastate/TestsBase.scala | 3 +++ .../helpers/ErgoLikeContextTesting.scala | 13 +++++++------ .../ConstantSerializerSpecification.scala | 9 +++++---- .../DataSerializerSpecification.scala | 15 ++++++++------- .../SigSerializerSpecification.scala | 2 +- .../scala/special/sigma/ContractsTestkit.scala | 6 ++++-- .../scala/special/sigma/SigmaTestingData.scala | 12 ++++++------ .../src/main/scala/sigmastate/lang/Types.scala | 1 - .../ergoplatform/ErgoAddressSpecification.scala | 3 +-- .../org/ergoplatform/ErgoTreePredefSpec.scala | 2 +- .../helpers/CompilerTestingCommons.scala | 3 +-- .../sigma/DataValueComparerSpecification.scala | 6 +++--- .../scala/special/sigma/SigmaDslTesting.scala | 3 +-- 15 files changed, 49 insertions(+), 46 deletions(-) diff --git a/interpreter/shared/src/main/scala/org/ergoplatform/SigmaConstants.scala b/interpreter/shared/src/main/scala/org/ergoplatform/SigmaConstants.scala index ff1251ae10..be745d8d7d 100644 --- a/interpreter/shared/src/main/scala/org/ergoplatform/SigmaConstants.scala +++ b/interpreter/shared/src/main/scala/org/ergoplatform/SigmaConstants.scala @@ -66,10 +66,6 @@ object SigmaConstants { "Max children count should not be greater than provided value") { } - object ScriptCostLimit extends SizeConstant[Int](1000000, 12, - "Maximum execution cost of a script") { - } - object MaxLoopLevelInCostFunction extends SizeConstant[Int](1, 13, "Maximum allowed loop level in a cost function") { } @@ -96,7 +92,6 @@ object SigmaConstants { MaxTupleLength, MaxHeaders, MaxChildrenCountForAtLeastOp, - ScriptCostLimit, MaxLoopLevelInCostFunction, VotesArraySize, AutolykosPowSolutionNonceArraySize diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala index bdd59eb850..e118665533 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala @@ -1,7 +1,6 @@ package sigmastate.interpreter import org.ergoplatform.ErgoLikeContext -import org.ergoplatform.SigmaConstants.ScriptCostLimit import sigmastate.{PerItemCost, VersionContext, TypeBasedCost, FixedCost, SType, JitCost} import sigmastate.Values._ import sigmastate.eval.Profiler @@ -42,7 +41,12 @@ case class EvalSettings( * The default value is None, which means the version is defined by ErgoTree.version * and Context.activatedScriptVersion. */ - evaluationMode: Option[EvaluationMode] = None) + evaluationMode: Option[EvaluationMode] = None, + /** Maximum execution cost of a script used by profiler. + * @see ErgoTreeEvaluator + */ + scriptCostLimitInEvaluator: Int = 1000000, +) object EvalSettings { /** Enumeration type of evaluation modes of [[Interpreter]]. @@ -123,7 +127,7 @@ class ErgoTreeEvaluator( protected val coster: CostAccumulator, val profiler: Profiler, val settings: EvalSettings) { - + /** Evaluates the given expression in the given data environment. */ def eval(env: DataEnv, exp: SValue): Any = { VersionContext.checkVersions(context.activatedScriptVersion, context.currentErgoTreeVersion) @@ -392,7 +396,7 @@ object ErgoTreeEvaluator { def forProfiling(profiler: Profiler, evalSettings: EvalSettings): ErgoTreeEvaluator = { val acc = new CostAccumulator( initialCost = JitCost(0), - costLimit = Some(JitCost.fromBlockCost(ScriptCostLimit.value))) + costLimit = Some(JitCost.fromBlockCost(evalSettings.scriptCostLimitInEvaluator))) new ErgoTreeEvaluator( context = null, constants = ArraySeq.empty, diff --git a/interpreter/shared/src/test/scala/sigmastate/TestsBase.scala b/interpreter/shared/src/test/scala/sigmastate/TestsBase.scala index 2ac254da5b..4e40d91c23 100644 --- a/interpreter/shared/src/test/scala/sigmastate/TestsBase.scala +++ b/interpreter/shared/src/test/scala/sigmastate/TestsBase.scala @@ -31,4 +31,7 @@ trait TestsBase extends Matchers with VersionTesting { /** Transform sigma proposition into [[ErgoTree]] using current ergoTreeHeaderInTests. */ def mkTestErgoTree(prop: SigmaBoolean): ErgoTree = ErgoTree.fromSigmaBoolean(ergoTreeHeaderInTests, prop) + + /** Max cost of script execution in tests. */ + val scriptCostLimitInTests: Int = 1000000 } diff --git a/interpreter/shared/src/test/scala/sigmastate/helpers/ErgoLikeContextTesting.scala b/interpreter/shared/src/test/scala/sigmastate/helpers/ErgoLikeContextTesting.scala index 2945192700..702d890147 100644 --- a/interpreter/shared/src/test/scala/sigmastate/helpers/ErgoLikeContextTesting.scala +++ b/interpreter/shared/src/test/scala/sigmastate/helpers/ErgoLikeContextTesting.scala @@ -1,16 +1,16 @@ package sigmastate.helpers -import org.ergoplatform.SigmaConstants.ScriptCostLimit import org.ergoplatform.ErgoLikeContext.Height import org.ergoplatform._ -import org.ergoplatform.validation.{ValidationRules, SigmaValidationSettings} +import org.ergoplatform.validation.{SigmaValidationSettings, ValidationRules} import sigmastate.AvlTreeData import sigmastate.basics.CryptoConstants import sigmastate.eval._ import sigmastate.interpreter.ContextExtension -import sigmastate.serialization.{SigmaSerializer, GroupElementSerializer} +import sigmastate.interpreter.ErgoTreeEvaluator.DefaultEvalSettings +import sigmastate.serialization.{GroupElementSerializer, SigmaSerializer} import special.collection.Coll -import special.sigma.{Box, PreHeader, Header} +import special.sigma.{Box, Header, PreHeader} object ErgoLikeContextTesting { /* NO HF PROOF: @@ -46,7 +46,8 @@ object ErgoLikeContextTesting { new ErgoLikeContext( lastBlockUtxoRoot, noHeaders, dummyPreHeader(currentHeight, minerPubkey), noBoxes, boxesToSpend, spendingTransaction, boxesToSpend.indexOf(self), extension, vs, - ScriptCostLimit.value, initCost = 0L, activatedVersion) + DefaultEvalSettings.scriptCostLimitInEvaluator, + initCost = 0L, activatedVersion) def apply(currentHeight: Height, lastBlockUtxoRoot: AvlTreeData, @@ -59,7 +60,7 @@ object ErgoLikeContextTesting { new ErgoLikeContext( lastBlockUtxoRoot, noHeaders, dummyPreHeader(currentHeight, minerPubkey), dataBoxes, boxesToSpend, spendingTransaction, selfIndex, ContextExtension.empty, - ValidationRules.currentSettings, ScriptCostLimit.value, + ValidationRules.currentSettings, DefaultEvalSettings.scriptCostLimitInEvaluator, initCost = 0L, activatedVersion) diff --git a/interpreter/shared/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala index 8b261df880..42df295d53 100644 --- a/interpreter/shared/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigmastate/serialization/ConstantSerializerSpecification.scala @@ -1,12 +1,11 @@ package sigmastate.serialization import java.math.BigInteger - import org.ergoplatform._ import org.scalacheck.Arbitrary._ import scalan.RType import sigmastate.SCollection.SByteArray -import sigmastate.Values.{LongConstant, FalseLeaf, Constant, SValue, TrueLeaf, BigIntConstant, GroupGenerator, ByteArrayConstant} +import sigmastate.Values.{BigIntConstant, ByteArrayConstant, Constant, FalseLeaf, GroupGenerator, LongConstant, SValue, TrueLeaf} import sigmastate.basics.CryptoConstants.EcPointType import sigmastate._ import sigmastate.eval._ @@ -19,6 +18,8 @@ import scorex.util.encode.Base16 import sigmastate.exceptions.SerializerException import sigmastate.lang.DeserializationSigmaBuilder +import scala.annotation.nowarn + class ConstantSerializerSpecification extends TableSerializationSpecification { private def testCollection[T <: SType](tpe: T) = { @@ -47,8 +48,8 @@ class ConstantSerializerSpecification extends TableSerializationSpecification { def testTuples[T <: SType](tpe: T) = { implicit val wWrapped = wrappedTypeGen(tpe) implicit val tT = Evaluation.stypeToRType(tpe) - implicit val tag = tT.classTag - implicit val tAny = RType.AnyType + @nowarn implicit val tag = tT.classTag + implicit val tAny: RType[Any] = RType.AnyType forAll { in: (T#WrappedType, T#WrappedType) => val (x,y) = (in._1, in._2) roundTripTest(Constant[SType]((x, y).asWrappedType, STuple(tpe, tpe))) diff --git a/interpreter/shared/src/test/scala/sigmastate/serialization/DataSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/serialization/DataSerializerSpecification.scala index 61f6fc85e3..d50f943d7a 100644 --- a/interpreter/shared/src/test/scala/sigmastate/serialization/DataSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigmastate/serialization/DataSerializerSpecification.scala @@ -1,12 +1,11 @@ package sigmastate.serialization import java.math.BigInteger - import org.ergoplatform.ErgoBox import org.scalacheck.Arbitrary._ import scalan.RType import sigmastate.SCollection.SByteArray -import sigmastate.Values.{SigmaBoolean, ErgoTree} +import sigmastate.Values.{ErgoTree, SigmaBoolean} import sigmastate._ import sigmastate.eval.Evaluation import sigmastate.eval._ @@ -14,12 +13,13 @@ import sigmastate.eval.Extensions._ import sigmastate.basics.CryptoConstants.EcPointType import special.sigma.AvlTree import SType.AnyOps -import org.ergoplatform.SigmaConstants.ScriptCostLimit import sigmastate.exceptions.SerializerException import sigmastate.interpreter.{CostAccumulator, ErgoTreeEvaluator} import sigmastate.interpreter.ErgoTreeEvaluator.DefaultProfiler import sigmastate.utils.Helpers +import scala.annotation.nowarn + class DataSerializerSpecification extends SerializationSpecification { def roundtrip[T <: SType](obj: T#WrappedType, tpe: T) = { @@ -30,13 +30,14 @@ class DataSerializerSpecification extends SerializationSpecification { val res = DataSerializer.deserialize(tpe, r) res shouldBe obj + val es = ErgoTreeEvaluator.DefaultEvalSettings val accumulator = new CostAccumulator( initialCost = JitCost(0), - costLimit = Some(JitCost.fromBlockCost(ScriptCostLimit.value))) + costLimit = Some(JitCost.fromBlockCost(es.scriptCostLimitInEvaluator))) val evaluator = new ErgoTreeEvaluator( context = null, constants = ErgoTree.EmptyConstants, - coster = accumulator, DefaultProfiler, ErgoTreeEvaluator.DefaultEvalSettings) + coster = accumulator, DefaultProfiler, es) val ok = DataValueComparer.equalDataValues(res, obj)(evaluator) ok shouldBe true @@ -76,8 +77,8 @@ class DataSerializerSpecification extends SerializationSpecification { def testTuples[T <: SType](tpe: T) = { implicit val wWrapped = wrappedTypeGen(tpe) - implicit val tag = tpe.classTag[T#WrappedType] - implicit val tAny = RType.AnyType + @nowarn implicit val tag = tpe.classTag[T#WrappedType] + implicit val tAny: RType[Any] = RType.AnyType forAll { in: (T#WrappedType, T#WrappedType) => val (x,y) = (in._1, in._2) roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe)) diff --git a/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala index 884b8d7150..a66c56f2f2 100644 --- a/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala +++ b/interpreter/shared/src/test/scala/sigmastate/serialization/SigSerializerSpecification.scala @@ -491,7 +491,7 @@ class SigSerializerSpecification extends TestingCommons ) ) - cases.zipWithIndex.foreach { case (c, iCase) => + cases.zipWithIndex.foreach { case (c, _) => val sigBytes = SigSerializer.toProofBytes(c.uncheckedTree) sigBytes shouldBe c.proof val uncheckedTree = SigSerializer.parseAndComputeChallenges(c.prop, c.proof)(null) diff --git a/interpreter/shared/src/test/scala/special/sigma/ContractsTestkit.scala b/interpreter/shared/src/test/scala/special/sigma/ContractsTestkit.scala index 4c073d3dc9..a544361d98 100644 --- a/interpreter/shared/src/test/scala/special/sigma/ContractsTestkit.scala +++ b/interpreter/shared/src/test/scala/special/sigma/ContractsTestkit.scala @@ -7,7 +7,9 @@ import sigmastate.{AvlTreeData, Values} import sigmastate.eval._ import sigmastate.eval.Extensions._ import sigmastate.helpers.TestingHelpers._ -import scalan._ // imports implicit ClassTag +import scalan._ + +import scala.annotation.nowarn // imports implicit ClassTag trait ContractsTestkit { val R0 = 0.toByte; @@ -59,7 +61,7 @@ trait ContractsTestkit { val AliceId = Array[Byte](1) // 0x0001 - def newAliceBox(id: Byte, value: Long): Box = { + def newAliceBox(@nowarn id: Byte, value: Long): Box = { val ergoBox = testBox(value, ErgoTree.fromProposition(Values.TrueSigmaProp), creationHeight = 0, additionalTokens = Seq(), additionalRegisters = Map()) diff --git a/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala b/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala index 3838ac87d2..db2f8501c5 100644 --- a/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala +++ b/interpreter/shared/src/test/scala/special/sigma/SigmaTestingData.scala @@ -7,7 +7,7 @@ import org.scalacheck.Gen.containerOfN import org.scalacheck.util.Buildable import org.scalacheck.{Arbitrary, Gen} import scalan.RType -import scorex.crypto.authds.{ADDigest, ADKey, ADValue} +import scorex.crypto.authds.{ADKey, ADValue} import scorex.crypto.hash.{Blake2b256, Digest32} import scorex.util.ModifierId import sigmastate.Values.{ByteArrayConstant, ConcreteCollection, ConstantPlaceholder, ErgoTree, FalseLeaf, IntConstant, LongConstant, SigmaPropConstant, TrueLeaf} @@ -43,11 +43,11 @@ trait SigmaTestingData extends TestingCommons with ObjectGenerators { len <- Gen.choose(0, 100) arr <- containerOfN[Array, Byte](len, Arbitrary.arbByte.arbitrary) } yield arr - val bytesCollGen = bytesGen.map(Colls.fromArray(_)) - val intsCollGen = arrayGen[Int].map(Colls.fromArray(_)) - implicit val arbBytes = Arbitrary(bytesCollGen) - implicit val arbInts = Arbitrary(intsCollGen) - val keyCollGen = collOfN[Byte](32, arbitrary[Byte]) + val bytesCollGen: Gen[Coll[Byte]] = bytesGen.map(Colls.fromArray(_)) + val intsCollGen: Gen[Coll[Int]] = arrayGen[Int].map(Colls.fromArray(_)) + implicit val arbBytes: Arbitrary[Coll[Byte]] = Arbitrary(bytesCollGen) + implicit val arbInts: Arbitrary[Coll[Int]] = Arbitrary(intsCollGen) + val keyCollGen: Gen[Coll[Byte]] = collOfN[Byte](32, arbitrary[Byte]) import org.ergoplatform.dsl.AvlTreeHelpers._ def createAvlTreeAndProver(entries: (Coll[Byte], Coll[Byte])*) = { diff --git a/parsers/shared/src/main/scala/sigmastate/lang/Types.scala b/parsers/shared/src/main/scala/sigmastate/lang/Types.scala index 8a45d4d66b..e4869e4190 100644 --- a/parsers/shared/src/main/scala/sigmastate/lang/Types.scala +++ b/parsers/shared/src/main/scala/sigmastate/lang/Types.scala @@ -3,7 +3,6 @@ package sigmastate.lang import fastparse._ import ScalaWhitespace._ import sigmastate._ -import sigmastate.SCollection.SByteArray import Values._ import sigmastate.lang.Terms.Ident import sigmastate.lang.syntax.Core diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala index 6b3c219aaa..22359c1606 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala @@ -1,7 +1,6 @@ package org.ergoplatform import org.ergoplatform.ErgoAddressEncoder.{MainnetNetworkPrefix, TestnetNetworkPrefix, hash256} -import org.ergoplatform.SigmaConstants.ScriptCostLimit import org.ergoplatform.validation.{ValidationException, ValidationRules} import org.scalatest.{Assertion, TryValues} import scorex.crypto.hash.Blake2b256 @@ -260,7 +259,7 @@ class ErgoAddressSpecification extends SigmaDslTesting property("negative cases: deserialized script + costing exceptions") { implicit lazy val IR = new TestingIRContext - def testPay2SHAddress(address: Pay2SHAddress, script: VarBinding, costLimit: Int = ScriptCostLimit.value): CostedProverResult = { + def testPay2SHAddress(address: Pay2SHAddress, script: VarBinding, costLimit: Int = scriptCostLimitInTests): CostedProverResult = { val boxToSpend = testBox(10, address.script, creationHeight = 5) val ctx = copyContext(ErgoLikeContextTesting.dummy(boxToSpend, activatedVersionInTests) .withExtension(ContextExtension(Seq( diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoTreePredefSpec.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoTreePredefSpec.scala index 36c5e78067..89247a968a 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/ErgoTreePredefSpec.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoTreePredefSpec.scala @@ -226,7 +226,7 @@ class ErgoTreePredefSpec extends CompilerTestingCommons with CompilerCrossVersio boxesToSpend = inputBoxes, spendingTransaction, self = inputBoxes.head, - activatedVersionInTests).withCostLimit(SigmaConstants.ScriptCostLimit.value * 10) + activatedVersionInTests).withCostLimit(scriptCostLimitInTests * 10) val pr = prover.prove(emptyEnv + (ScriptNameProp -> "tokenThresholdScript_prove"), prop, ctx, fakeMessage).getOrThrow verifier.verify(emptyEnv + (ScriptNameProp -> "tokenThresholdScript_verify"), prop, ctx, pr, fakeMessage).getOrThrow._1 shouldBe true diff --git a/sc/shared/src/test/scala/sigmastate/helpers/CompilerTestingCommons.scala b/sc/shared/src/test/scala/sigmastate/helpers/CompilerTestingCommons.scala index 8981ace5df..b2b497e423 100644 --- a/sc/shared/src/test/scala/sigmastate/helpers/CompilerTestingCommons.scala +++ b/sc/shared/src/test/scala/sigmastate/helpers/CompilerTestingCommons.scala @@ -1,6 +1,5 @@ package sigmastate.helpers -import org.ergoplatform.SigmaConstants.ScriptCostLimit import org.ergoplatform._ import org.ergoplatform.validation.ValidationRules.CheckSerializableTypeCode import org.ergoplatform.validation.{ValidationException, ValidationSpecification} @@ -137,7 +136,7 @@ trait CompilerTestingCommons extends TestingCommons val sigmaCtx = createContexts(in, bindings) val accumulator = new CostAccumulator( initialCost = JitCost(0), - costLimit = Some(JitCost.fromBlockCost(ScriptCostLimit.value))) + costLimit = Some(JitCost.fromBlockCost(evalSettings.scriptCostLimitInEvaluator))) val evaluator = new ErgoTreeEvaluator( context = sigmaCtx, constants = ErgoTree.EmptyConstants, diff --git a/sc/shared/src/test/scala/special/sigma/DataValueComparerSpecification.scala b/sc/shared/src/test/scala/special/sigma/DataValueComparerSpecification.scala index b264d52144..eaca756182 100644 --- a/sc/shared/src/test/scala/special/sigma/DataValueComparerSpecification.scala +++ b/sc/shared/src/test/scala/special/sigma/DataValueComparerSpecification.scala @@ -1,6 +1,5 @@ package special.sigma -import org.ergoplatform.SigmaConstants.ScriptCostLimit import org.scalatest.BeforeAndAfterAll import scalan.RType import scalan.util.BenchmarkUtil @@ -23,7 +22,8 @@ class DataValueComparerSpecification extends SigmaDslTesting isMeasureOperationTime = true, isMeasureScriptTime = true, isLogEnabled = false, // don't commit the `true` value (CI log is too high) - costTracingEnabled = true // should always be enabled in tests (and false by default) + costTracingEnabled = true, // should always be enabled in tests (and false by default) + scriptCostLimitInEvaluator = scriptCostLimitInTests ) override val nBenchmarkIters = 10 @@ -36,7 +36,7 @@ class DataValueComparerSpecification extends SigmaDslTesting def createEvaluator(settings: EvalSettings, profiler: Profiler): ErgoTreeEvaluator = { val accumulator = new CostAccumulator( initialCost = JitCost(0), - costLimit = Some(JitCost.fromBlockCost(ScriptCostLimit.value))) + costLimit = Some(JitCost.fromBlockCost(settings.scriptCostLimitInEvaluator))) val evaluator = new ErgoTreeEvaluator( context = null, constants = ErgoTree.EmptyConstants, diff --git a/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala index 53c4cdddac..884e257ab4 100644 --- a/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala +++ b/sc/shared/src/test/scala/special/sigma/SigmaDslTesting.scala @@ -1,7 +1,6 @@ package special.sigma import debox.cfor -import org.ergoplatform.SigmaConstants.ScriptCostLimit import org.ergoplatform._ import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, TestContractSpec} import org.ergoplatform.validation.ValidationRules.CheckSerializableTypeCode @@ -366,7 +365,7 @@ class SigmaDslTesting extends AnyPropSpec createErgoLikeContext( newCtx, ValidationRules.currentSettings, - ScriptCostLimit.value, + evalSettings.scriptCostLimitInEvaluator, initCost = initialCostInTests.value ) From 39e793b03ac9bafca588852f384add6292f8c851 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Wed, 9 Aug 2023 18:10:58 +0200 Subject: [PATCH 7/7] refactoring: cleanup and updates in docs directory --- docs/Costing.md | 446 ------------------ docs/ergoscript-compiler.md | 56 +++ docs/notes.md | 14 +- docs/releasenotes.md | 21 - docs/sigma-dsl.md | 8 +- docs/sigma-front-end.md | 55 --- docs/soft-fork-log.md | 38 -- .../interpreter/ErgoTreeEvaluator.scala | 2 +- 8 files changed, 67 insertions(+), 573 deletions(-) delete mode 100644 docs/Costing.md create mode 100644 docs/ergoscript-compiler.md delete mode 100644 docs/releasenotes.md delete mode 100644 docs/sigma-front-end.md delete mode 100644 docs/soft-fork-log.md diff --git a/docs/Costing.md b/docs/Costing.md deleted file mode 100644 index a48b6d9b84..0000000000 --- a/docs/Costing.md +++ /dev/null @@ -1,446 +0,0 @@ - -## Estimation of ErgoTree computational complexity - -### Background - -To prevent DDoS attacks every script in a blockchain have to be checked for complexity limits. -This estimation happens during block/transaction validation for every guarding script of every input box. -Script can be executed iff its estimated complexity in a given `Context` is less than a `limit` value. - -### Contract execution context - -Transaction `tx` is validated as part of the block. -Every input box `ib` in `tx` contains a property `propBytes` with serialized ErgoTree of the contract. -During validation `propBytes` property is deserialized to ErgoTree `tree` which is executed. -The box `ib` itself is accessed via `SELF` property of the `Context` data structure. -Besides `Context` execution of a contract depends on votable `ProtocolParameters` data, which contains -global parameters which can be set up by miners following a voting protocol. - -### Costing Rules - -The following constants are used in cost and size calculations. - -Constant Name | Description ---------------|------------ -GroupSize | Number of bytes to represent any group element as byte array - -The following table shows the rules for calculating cost and size for a result of each operation -based on costs and sizes of the operations arguments. -The operations names are given by the node classes of ErgoTree. - - -Operation | Cost in time units, Size in bytes ----------------------|----------------------------------- -`ProveDLog` | CT("ProveDlogEval"), GroupSize -`ProveDHTuple` | CT("ProveDHTupleEval"), GroupSize * 4 -x,y: BigInt; x op y where op in ("+", "-") | cost(x) + cost(y) + CT("op"), MaxSizeInBytes - - -### Asymptotic complexity of the costing algorithm - -For a given input box `ib` the algorithm consists of the following steps (details of each -step are given in later sections): - -`#` | Step | Complexity -----|-------------------------------------------------------------------|----------- -1 | Check that `val len = propBytes.length; len < MaxPropBytesSize` | `O(1)` -2 | Deserialize `propBytes` to ErgoTree `tree` with `N` nodes | `O(len) and N = O(len)` -3 | Recursively traverse `tree` and build costed graph `graphC` with `M <= N` nodes | `O(N)` -4 | Split `graphC` into calculation function `calcF` and cost estimation function `costF` | `O(M)` -5 | Topologically sort nodes of `costF` for execution (Tarjan algorithm) | `O(M)` -6 | Iterate over sorted nodes of `costF` and execute primitive ops | `O(M)` - -#### Overview of Costing Process - - -Deserialized ErgoTree have to be translated into two related functions: -1) `calcF: Context => SigmaBoolean` - script calculation function, which produces Sigma tree for -further proof generation (when new `tx` is created) or proof verification (when `tx` is verified) -2) `costF: Context => Int` - cost estimation function, which by construction is closely connected -with `calcF` and allows to compute execution complexity of `calcF` in a given context. - -_Costing Process_ or simply _costing_ is the process of obtaining two functions `calcF` and `costF` -for a given deserialized ErgoTree. - -The key feature of the costing algorithm is that in many cases the functions `calcF` and `costF` can be -constructed for a given ErgoTree once and for all Context. This is statically verifiable property -which can be ensured by the compiler of ErgoTree. - -If context independent costing is not possible, the corresponding bit should be setup in script header. -In this case _context-dependent costing_ should be performed for the script during transaction validation. -Context-dependent costing can use data in the `Context` to construct `calcF` and `costF` functions. -This is necessary to achieve better cost approximations in complex scripts. - -Costing process is divided into two steps: -1) Building of _Costed Graph_ `graphC` (see [below](#BuildingCostedGraph)) -2) Splitting of the `graphC` into `calcF` and `costF` functions (see [below](#SplittingCostedGraph)) - -### Deserialization (Steps 1, 2 of costing algorithm) - -Deserializer should check that serialized byte array is of limited size, otherwise -out-of-memory attack is possible. `MaxPropBytesSize` is a protocol parameter (see `ProtocolParameters`). -During deserialization another parameter `MaxTreeDepth` is checked to limit depth of ErgoTree and thus -avoid stack-overflow attack. - -### Building Costed Graph (Step 3) - - -Costed Graph is a graph-based intermediate representatin (IR) which is created from the deserialized -ErgoTree. Implementation of Costed Graph is based on Scalan/Special framework. -See [Scalan idioms](https://github.com/scalan/scalan.github.io/blob/master/idioms.md) for details. - -#### Costed Values - - -The nodes of the costed graph `graphC` are _costed values_ of type `Costed[T]`. -```scala -trait Costed[Val] { - def value: Val // the value which is costed - def cost: Int // the cost estimation to obtain value - def dataSize: Long // the size estimation of the value in bytes -} -``` -Every costed value `valC: Costed[T]` is a container of the value along with additional data to -represent cost and size (costing information, costing properties). - -Note, that `cost` and `dataSize` are independent parameters because some _costed_ values may have -very small `dataSize`, but at the same time very high `cost`, e.g. result of contract may be `true` -boolean value whose `dataSize` is 1 byte, but its `cost` is the cost of executing the whole contract. -The opposite is also possible. For example a context variable of `Coll[Byte]` type have `cost` equal 0, -but may have very big `dataSize`. - -From this perspective Costed Graph `graphC` is a data flow graph between costed values. -Costed graph represents both execution of values and simultaneous execution of `cost` and `dataSize` -estimations for all intermediate values. - -The `cost` and `dataSize` computations depend on operations in the contract. -Consider the following contract fragment where we multiply two big integers: -``` -val x: BigInt = ... -val y: BigInt = ... -val z = x * y -``` -In the costed graph it corresponds to the following fragment: - -```scala -val xC: Costed[BigInt] = ... -val yC: Costed[BigInt]= ... -val zC = new Costed { - val value = xC.value * yC.value - val dataSize = xC.dataSize + yC.dataSize + 1L - val cost = xC.cost + yC.cost + costOf("*_per_item") * this.dataSize -} -``` -For the example above note the following properties: -1) both `cost` and `dataSize` depend on costing information from arguments -2) resulting `zC.cost` depend on `dataSize` of arguments -3) neigher `cost` nor `dataSize` depend on argument values, i.e. costing properties of result -can be approximated using costing properties of arguments along. - -The property 3) turns out to be very important, because many operations have this property -which leads to the possibility to do context-independent costing. - -Depending on type `T` costed values have specialized representations, given by descendants of -the type `Costed[T]`. The following subsections describe possible specialization in detail. - -##### Costed Values of Primitive Type - -The simplest case is when `T` is primitive. -In this case cost information is represented by class `CCostedPrim[T]` derived from trait `CostedPrim[T]`. -Separation into class and closely related trait is technical implementation detail, we will omit traits -in the following sections for brevity. The trait always have the same public methods as class. -```scala -trait CostedPrim[Val] extends Costed[Val] -class CCostedPrim[Val](val value: Val, val cost: Int, val dataSize: Long) extends CostedPrim[Val] -``` -This representation of costs is used for intermediate values of type `Boolean`, `Byte`, `Short`, `Int`, -`Long`, `BigInt`, `GroupElement` and `SigmaProp` types. -These types represent atomic values of constant or limited size. -The following table summarizes this - -Type | Data Size, bytes ----------------|----------------- -`Boolean` | == 1 -`Byte` | == 1 -`Short` | == 2 -`Int` | == 4 -`Long` | == 8 -`BigInt` | <= 32 -`GroupElement` | <= 32 -`SigmaProp` | <= 32 - -Constants, context variables and registers of primitive types are represented in costed graph `graphC` -using `CCostedPrim` class. For these cases costed properties as computed from actual data values. -For example having Int literal in the contract - -`val x: Int = 10` - -costing algorithm constructs the following graph - -`val xC: Costed[Int] = CCostedPrim(10, costOf("Const:() => Int"), sizeOf[Int])` - -Here `costOf("Const:() => Int")` is an operation which requests `CostModel` for the cost of using -a constant value in a script. - -##### Costed Values of Tuple type - -If `L` and `R` types, then costed value of type `(L,R)` is represented by the following -specializations of `Costed[(L,R)]` type -```scala -class CCostedPair[L,R](val l: Costed[L], val r: Costed[R]) extends CostedPair[L,R] { - def value: (L,R) = (l.value, r.value) - def cost: Int = l.cost + r.cost + ConstructTupleCost - def dataSize: Long = l.dataSize + r.dataSize -} -``` -Thus, for every intermediate value of type `(L,R)` we assume it has two components -which are both costed values and accessible via properties `l` and `r` of -`CostedPair` trait. - -For each constant, context variable and register access the corresponding `CCostedPair` -is computed from actual data values by recursively deconstructing them down to primitive -types. -For example for the constant `(10, (10L, true))` the following costed value will be created -in costed graph -```scala -CCostedPair( - CCostedPrim(10, costOf("Const:() => Int"), sizeOf[Int]), - CCostedPair( - CCostedPrim(10L, costOf("Const:() => Long"), sizeOf[Long]), - CCostedPrim(true, costOf("Const:() => Boolean"), sizeOf[Boolean]))) -``` - -##### Costed Values of Coll Type - -If `Item` is a type of array element, then costed value of type `Coll[Item]` is -represented by the following specializations of `Costed[Coll[Item]]` type -```scala -class CCostedColl[Item]( - val values: Coll[Item], val costs: Coll[Int], - val sizes: Coll[Long], val valuesCost: Int) extends CostedColl[Item] { - def value: Coll[Item] = values - def cost: Int = valuesCost + costs.sum - def dataSize: Long = sizes.sum - def mapCosted[Res](f: Costed[Item] => Costed[Res]): CostedColl[Res] = rewritableMethod - def foldCosted[B](zero: Costed[B], op: Costed[(B, Item)] => Costed[B]): Costed[B] = rewritableMethod -} -``` -For constant, context variables and registers values of `Coll` type the costing information -of `CCostedColl` is computed from actual data. - -Note methods `mapCosted` and `foldCosted`, these methods represent costed version of original -collection methods. Note the methods are defined as rewritable, meaning their implementation -require special rewriting rule. See section [Rewrite Rules](#RewriteRules) - -#### Building Costed Graph - -Given an environment `envVals` and ErgoTree `tree` a Costed Graph can be obtained as -[reified lambda](https://github.com/scalan/scalan.github.io/blob/master/idioms.md#Idiom4) of type -`Ref[Context => Costed[T#WrappedType]]` -This transformation is implemented as shown in the following `buildCostedGraph` method, which can -be found in `RuntimeCosting.scala` file. -```scala -def buildCostedGraph[T <: SType](envVals: Map[Any, SValue], tree: Value[T]): Ref[Context => Costed[T#WrappedType]] = - fun { ctx: Ref[Context] => // here ctx represents data context - val ctxC = RCCostedContext(ctx) // data context is wrapped into Costed value container - val env = envVals.mapValues(v => evalNode(ctxC, Map(), v)) // do costing of environment - val res = evalNode(ctxC, env, tree) // traverse tree recursively applying costing rules - res - } -``` -Note that function `evalNode` applies the [costing rules](#CostingRules) recursively for tree nodes -(of `sigmastate.Values.Value[T]` type). Those rules are executed in the `fun` block and -as result all the created graph nodes belong to the resulting costed graph - -#### Costing Rules - - -In order to build costed graph, the algorithm have to recursively traverse ErgoTree. -For each node of ErgoTree, separate _costing rule_ is applied using `evalNode` method -whose structure is show below. -```scala -type RCosted[A] = Ref[Costed[A]] -type CostingEnv = Map[Any, RCosted[_]] -def evalNode[T <: SType](ctx: Ref[CostedContext], env: CostingEnv, node: Value[T]): RCosted[T#WrappedType] = { - def eval[T <: SType](node: Value[T]) = evalNode(ctx, env, node) - object In { def unapply(v: SValue): Nullable[RCosted[Any]] = Nullable(evalNode(ctx, env, v)) } - ... - node match { - case Node1(In(arg1),...,In(argK)) => rhs1(arg1,...,argK) - ... - case NodeN(In(arg1),...,In(argK)) => rhsN(arg1,...,argK) - } -} -``` -Here `In` is a helper extractor which recursively apply `evalNode` for each argument so that variables -`arg1,...,argK` represent results of costing of the corresponding subtree. -The right hand side of each rule (`rhs1,...rhsN`) contains operations with -[Ref types](https://github.com/scalan/scalan.github.io/blob/master/idioms.md#Idiom3), the effect of their -execution is creation of new graph nodes which become part of resulting costed graph. - -Following is an example of a simple costing rule to introduce basic concepts -(it can be found in RuntimeCosting.scala file). -```scala - case sigmastate.MultiplyGroup(In(_l), In(_r)) => - val l = asRep[Costed[GroupElement]](_l) // type cast to an expected Ref type - val r = asRep[Costed[GroupElement]](_r) - val value = l.value.add(r.value) // value sub-rule - val cost = l.cost + r.cost + costOf(node) // cost sub-rule - val size = CryptoConstants.groupSize.toLong // size sub-rule - RCCostedPrim(value, cost, size) -``` -The rule first recognizes specific ErgoTree node, then recursively each argument is costed -so that the result is bound with variables `_l` and `_r`. -Right hand side starts with typecasting costed subgraphs to expected types. This operation is safe -because input ErgoTree is type checked. These typecasts also make the rest of the rules typesafe, -which is ensured by Scala compiler checking correctness of the operations. -Using costed arguments `l` and `r` the rule contains three sub-rules. -_Value rule_ implements calculation of the resulting value and essentially translates -MultiplyGroup operation into operation in the costed graph. -_Cost rule_ defines formula of the cost for `MultiplyGroup` operation (by adding to the costed graph). -_Size rule_ defines formula of the size for `MultiplyGroup` operation -And finally `value`, `cost` and `size` are packed into costed value which represent current tree node -in the costed graph. - -The rule above has the simples form and applicable to most simple operations. However some operations -require rules which don't fall into this default patterns. -Following is an example rule for `MapCollection` tree node, which makes recursive costing of arguments -explicit by using `eval` helper and also employ other idioms of staged evaluation. -```scala - case MapCollection(input, id, mapper) => - val eIn = stypeToElem(input.tpe.elemType) // translate sigma type to Special type descriptor - val xs = asRep[CostedColl[Any]](eval(input)) // recursively build subgraph for input argument - implicit val eAny = xs.elem.asInstanceOf[CostedElem[Coll[Any],_]].eVal.eA - assert(eIn == eAny, s"Types should be equal: but $eIn != $eAny") - val mapperC = fun { x: Ref[Costed[Any]] => // x argument is already costed - evalNode(ctx, env + (id -> x), mapper) // associate id in the tree with x node of the graph - } - val res = xs.mapCosted(mapperC) // call costed method of costed collection - res -``` -Observe that this rule basically translates mapping operation over collection into invocation of -the method `mapCosted` on costed collection value `xs` with appropriately prepared argument `mapperC`. -Because `xs` has [Ref type](https://github.com/scalan/scalan.github.io/blob/master/idioms.md#Idiom3) -this invocation has an effect of adding new `MethodCall(xs, "mapCosted", Seq(mapperC))` node to the graph. -This new node is immediately catched by the rewriting rule (see [Rewrite Rules](#RewriteRules) section) which further transforms it into final -nodes of resulting costed graph. Such separation makes the whole algorithm more modular. - -### Spliting Costed Graph (Step 4) - - -Costed Graph represents simultaneous calculation of original contract and cost information along contract's data flow. -However in order to perform cost estimation before contract calculation we need to separate contract calculation -operations of the Costed Graph from cost and data size computing operations. - -After building a Costed Graph -```scala -val graphC: Ref[Context => SType#WrappedValue] = buildCostedGraph(env, tree) -``` -we can perform _splitting_ by using the function `split` to obtain `calcF` and `costF` functions -```scala -val Pair(calcF: Ref[Context => SType#WrappedValue], costF: Ref[Context => Int]) = split(graphC) -``` -Both `calcF` and `costF` take `Context` as its argument and both represented as -[reified lambdas](https://github.com/scalan/scalan.github.io/blob/master/idioms.md#Idiom4) of -Scalan/Special IR. - -This _splitting_ function is generic and defined as shown below -```scala - def split[T,R](f: Ref[T => Costed[R]]): Ref[(T => R, T => Int)] = { - val calc = fun { x: Ref[T] => val y = f(x); val res = y.value; res } - val cost = fun { x: Ref[T] => f(x).cost } - Pair(calc, cost) - } -``` -In order to understand how this function works first observe, that this function is from -reified lambda to a pair of reified lambdas, thus it performs transformation of one graph to a pair of -new graphs. -Second, consider the `fun` block in the definition of `calc` and the application `f(x)` inside the block. -Because `f` is a reified lambda then according to staged evaluation semantics its application to `x` -has an effect of inlining, i.e. unfolding the graph of `f` with `x` substituted for `f`'s argument into -the block of `fun`. -Third, remember that Costed Graph have nodes of types derived from `Costed` depending of the type of value, -e.g. for primitive type `CCostedPrim(v, c, s)` node is added to the graph. -This is described in [Costed Values](#CostedValues) section. -And forth, recall that typical costing rule have the following formulas for calculation of costed values. -```scala - val value = l.value.add(r.value) // value sub-rule - val cost = l.cost + r.cost + costOf(node) // cost sub-rule - val size = CryptoConstants.groupSize.toLong // size sub-rule - RCCostedPrim(value, cost, size) -``` -Combined with third point and assuming -```scala - l = new CCostedPrim(v1, c1, s1) - r = new CCostedPrim(v2, c2, s2) -``` -we can conclude that `l.value.add(r.value)` will evaluate to `v1.add(v2)` and similarly -`l.cost + r.cost + costOf(node)` will evaluate to `c1 + c2 + costOf(node)`. - -```scala - val value = v1.add(v2) // value sub-rule - val cost = c1 + c2 + costOf(node) // cost sub-rule - val size = CryptoConstants.groupSize.toLong // size sub-rule - RCCostedPrim(value, cost, size) -``` -In other words, resuting node of the cosing rule doesn't depend on intermediate costed nodes. -Such intermediate nodes (like `CCostedPrim` above) become dead and are not used in values calculation. -This is the key insight in the implementation of function `split`. - -Now, keeping above in mind, after the graph of `f` is unfolded `y` represents resulting node. -Thus, `value` property is called on the costed node `y` which has type `Costed`. -The resulting symbol obtained by execution of `y.value` becomes a resulting node of the -`calc` graph. After the block of `fun` operator is executed, dead-code-elimination is performed by `fun` -using simple collection of reachable nodes of the graph starting from resulting node `res`. - -Thus, by construction, the body of `calc` contains only operations necessary to execute contract, and have no -vestiges of costing and sizing operations. - -### Real World Complications - -Here we discuss some complications in the algorithm caused by the diversity of real world examples. -The main motivation here is to keep main algorithm generic and simple, and encapsulate all complexity -of the specific cases into reusable modules. - - -#### Rewrite Rules - -[Rewrite rules](https://github.com/scalan/scalan.github.io/blob/master/idioms.md#Idiom6) is the mechanism -to hook into graph building process and perform on the fly substitution of -specific sub-graphs with equivalent but different sub-graphs. -The following rule uses auto-generated extractor `mapCosted` which recognizes invocations of method -`CostedColl.mapCosted` (Remember, this method was used in costing rule for `MapCollection` tree node). - -```scala -override def rewriteDef[T](d: Def[T]): Ref[_] = { - val CCM = CostedCollMethods - d match { - case CCM.mapCosted(xs: RCostedColl[a], _f: RCostedFunc[_, b]) => - val f = asRep[Costed[a] => Costed[b]](_f) - val (calcF, costF, sizeF) = splitCostedFunc[a, b](f) - val vals = xs.values.map(calcF) - val mRes = AllMarking(element[Int]) - val mCostF = sliceAnalyzer.analyzeFunc(costF, mRes) - implicit val eA = xs.elem.eItem - implicit val eB = f.elem.eRange.eVal - - val costs = mCostF.mDom match { - case PairMarking(markA,_) if markA.isEmpty => - val slicedCostF = fun { in: Ref[(Int, Long)] => costF(Pair(variable[a], in)) } - xs.costs.zip(xs.sizes).map(slicedCostF) - case _ => - xs.values.zip(xs.costs.zip(xs.sizes)).map(costF) - } - val tpeB = elemToSType(eB) - val sizes = if (tpeB.isConstantSize) { - colBuilder.replicate(xs.sizes.length, typeSize(tpeB)) - } else - xs.sizes.map(sizeF) - RCCostedColl(vals, costs, sizes, xs.valuesCost) - case _ => super.rewriteDef(d) - } -} -``` -Method `rewriteDef` is defined in `Scalan` cake trait and can be overridden following _stackable overrides_ -pattern (calling super.rewriteDef for the default case). This specific rule is defined in `RuntimeCosting` -trait. diff --git a/docs/ergoscript-compiler.md b/docs/ergoscript-compiler.md new file mode 100644 index 0000000000..e50f7d6a00 --- /dev/null +++ b/docs/ergoscript-compiler.md @@ -0,0 +1,56 @@ + +# ErgoScript Compiler + +Sigma frontend implements the following pipeline: + +`SourceCode` --> `parse` --> `bind` -> `typecheck` -> `buildGraph` -> `buildTree` -> `ErgoTree` + +Here: +- `SourceCode` - a string of unicode characters +- `parse` - method `SigmaCompiler.parse` +- `bind` - method `SigmaBinder.bind` +- `typecheck` - method `SigmaTyper.typecheck` +- `buildGraph` - method `IRContext.buildGraph` +- `buildTree` - method `IRContext.buildTree` +- `ErgoTree` - an intermediate representation which can be processed by Sigma [Interpreter](https://github.com/ScorexFoundation/sigmastate-interpreter/blob/master/interpreter/shared/src/main/scala/sigmastate/interpreter/Interpreter.scala#L46) + +## Parser +`parse` takes a string and produces abstract syntax tree, AST, of a Sigma expression represented by `Value` type in Scala. + +In case of any errors it throws `ParserException` + +## Binder +`SigmaBinder` takes an AST of successfully parsed Sigma expression and resolves +global variables and predefined functions that are looked up in the provided environment. +Binder transforms environment values of predefined Scala types (such as Int, Boolean, Box, etc.) +into constant nodes (IntConstant, BoxConstant, etc) of the corresponding type. (See also `Constant` class) + +In case of any error it throws `BinderException` + +## Typer +`SigmaTyper` takes an AST from the output of `SigmaBinder` and assigns types +to all tree nodes. Since AST is immutable data structure the typer produces a new tree. + +Type assignment is performed by `assignType` tree transformation which assign correct types for all +tree nodes. + +In case of any error it throws `TyperException` + +## Graph Building + +`IRContext.buildGraph` takes an AST from the output of `SigmaTyper` and builds a graph where nodes are operations and edges are dependencies between operations. +During graph building the following optimizations are performed: +- constant propagation +- common subexpression elimination +- dead code elimination + +## Tree Building + +`IRContext.buildTree` takes a graph from the output of `IRContext.buildGraph` and builds the resulting ErgoTree. + +## IR contexts + +- `IRContext` - the main interface of graph IR which mixes in both GraphBuilding and TreeBuilding traits. + Since v5.0 it is not used by Interpreter and thus not part of consensus. + +- `CompiletimeIRContext` - the main implementation of IRContext diff --git a/docs/notes.md b/docs/notes.md index cc75f1065d..7bea09d887 100644 --- a/docs/notes.md +++ b/docs/notes.md @@ -3,13 +3,13 @@ These dependencies can be removed with refactoring -| Jar | Size, Kb | -|---------------|---------------| -| - jline-2.14.3.jar | 268 | -| 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 | -| - spire-macros_2.12-0.14.1.jar | 73 | +| Jar | Size, Kb | +|--------------------------------|----------| +| - jline-3.10.0.jar | 715 | +| cats-core_2.12-2.1.0.jar | 4900 | +| - cats-kernel_2.12-1.4.0.jar | 3500 | +| - algebra_2.12-2.0.0-M2.jar | 1400 | +| - spire-macros_2.12-0.14.1.jar | 79 | diff --git a/docs/releasenotes.md b/docs/releasenotes.md deleted file mode 100644 index e34cfa8562..0000000000 --- a/docs/releasenotes.md +++ /dev/null @@ -1,21 +0,0 @@ -# v2.2 - -- soft-forkability for cost estimation (#503) -- optimization of cost estimation rules (#523) -- new Context parameters (initCost, costLimit) -- implemented fast complexity measure of box propositions - (to fail-fast on too complex scripts #537) -- implemented test cases to check fast script rejections of - of either oversized of too costly scripts - -# v2.1 -- soft-forkability for language evolution (add types, operations) #500 -- ErgoTree language specification (abstract syntax, typing rules, semantics, serialization format) #495 -- ErgoTree IR extended with metadata to generate specification appendixes. -- more operations implemented (zip #498, element-wise xor for collections #494, flatMap #493, - plusModQ, minusModQ #488, logical xor #478, filter #471, Option.map #469, groupGenerator #440) -- security improvements (like limiting ErgoTree depth during deserialization #459 #482) -- ICO and LETS examples #450 -- final version of ErgoScript white paper (#410) -- improvements in scorex-util serialization -- various fixes code cleanup and better test coverage (#504, #508, #515) \ No newline at end of file diff --git a/docs/sigma-dsl.md b/docs/sigma-dsl.md index ee9691186b..e9ca0ba0ff 100644 --- a/docs/sigma-dsl.md +++ b/docs/sigma-dsl.md @@ -6,10 +6,8 @@ code directly in Scala IDE (e.g. IntelliJ IDEA) and copy-paste code snippets between SigmaDsl and SigmaScript. Special Scala macros can also be used to automatically translate SigmaDsl to - Sigma byte code. - -SigmaDsl is implemented as Scala library using [Special](https://github.com/scalan/special) -framework. + Sigma byte code. Some prototype has been implemented [here](https://github.com/ergoplatform/ergo-scala-compiler) ## See also -[Special](https://github.com/scalan/special) + +[ergo-scala-compiler](https://github.com/ergoplatform/ergo-scala-compiler) diff --git a/docs/sigma-front-end.md b/docs/sigma-front-end.md deleted file mode 100644 index 693ca98089..0000000000 --- a/docs/sigma-front-end.md +++ /dev/null @@ -1,55 +0,0 @@ - -# Sigma language front-end - -Sigma frontend implements the following pipeline: - -SourceCode --> `Parser` --> `Binder` -> `Typer` -> `CompiletimeCosting` -> `TreeBuilding` -> ErgoTree - -Here: -- SourceCode is a string of unicode characters -- ErgoTree is an intermediate representation which can be processed by Sigma [Interpreter](https://github.com/ScorexFoundation/sigmastate-interpreter/blob/master/src/main/scala/sigmastate/interpreter/Interpreter.scala) - -## Parser -`SigmaParser` takes a string and produces abstract syntax tree, AST, of a Sigma expression represented by `Value` type in Scala. - -In case of any errors it throws `ParserException` - -## Binder -`SigmaBinder` takes an AST of successfully parsed Sigma expression and resolves -global variables and predefined functions that are looked up in the provided environment.. -Binder transforms environment values of predefined Scala types (such as Int, Boolean, Box, etc.) -into constant nodes (IntConstant, BoxConstant, etc) of the corresponding type. (See also `Constant` class) - -In case of any error it throws `BinderException` - -## Typer -`SigmaTyper` takes an AST from the output of `SigmaBinder` and assigns types -to all tree nodes. Since AST is immutable data structure the typer produces a new tree. - -Type assignment is performed by `assignType` tree transformation which assign correct types for all -tree nodes. - -In case of any error it throws `TyperException` - -## Costing - -See Costing.md for detailed description of costing process. - -## TreeBuilding - - -## IR contexts -There are following IR contexts. - -Context class | Description -----------------------|------------ - IRContext | Generic context which includes extends Evaluation, RuntimeCosting and TreeBuilding - RuntimeIRContext | context which should be used during transaction validation - CompiletimeIRContext | context which should be used during ErgoScript compilation - -The reason to have different contexts is to limit RuntimeIRContext to support only those nodes which can be serialized as part of ErgoTree. -This doesn't include all ErgoScript nodes which CompiletimeIRContext can handle. -For example, compileWithCosting should use IR context with CompiletimeCosting mixed in. -However, Interpreter takes as input compiled or deserialized ErgoTree, so it can work without CompiletimeCosting mixed in into IR context. - - diff --git a/docs/soft-fork-log.md b/docs/soft-fork-log.md deleted file mode 100644 index 072e177827..0000000000 --- a/docs/soft-fork-log.md +++ /dev/null @@ -1,38 +0,0 @@ - -## A log of changes leading to soft-fork - -This list should be updated every time something soft-forkable is added. - -### Changes in v2.1 - - - new type (SGlobal.typeCode = 106) - - new method (SGlobal.groupGenerator.methodId = 1) - - new method (SAvlTree.updateDigest.methodId = 15) - - removed GroupElement.nonce (changed codes of getEncoded, exp, multiply, negate) - - change in Coll.filter serialization format (removed tagged variable id, changed condition type) - -### Changes in v2.2 - -#### Changes in ErgoConstants - MaxTokens 4 -> 255 - MaxPropositionBytes 64K -> 4K - SizeBoxBytesWithoutRefsMax 64K -> 4K - MaxSigmaPropSizeInBytes 1K (added because SigmaProp.isConstantSize == true) - MaxLoopLevelInCostFunction 1 (added and checked) - -#### ComplexityTable added - -#### Changes in CostTable - -MinimalCost = 10 (1) -interpreterInitCost = 10000 (added) -perGraphNodeCost = 200 (added) -val costFactor: Double = 2d (added) -constCost = 10 (1) -lambdaCost = 10 (1) -plusMinus = 10 (2) -comparisonCost = 10 (3) -lambdaInvoke = 30 (added) -concreteCollectionItemCost = 10 (added) // since each item is a separate graph node -logicCost = 10 (2) -castOp = 10 (5) \ No newline at end of file diff --git a/interpreter/shared/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala b/interpreter/shared/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala index e118665533..de6ad39789 100644 --- a/interpreter/shared/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala +++ b/interpreter/shared/src/main/scala/sigmastate/interpreter/ErgoTreeEvaluator.scala @@ -45,7 +45,7 @@ case class EvalSettings( /** Maximum execution cost of a script used by profiler. * @see ErgoTreeEvaluator */ - scriptCostLimitInEvaluator: Int = 1000000, + scriptCostLimitInEvaluator: Int = 1000000 ) object EvalSettings {