diff --git a/core/js/src/main/scala/sigma/crypto/Platform.scala b/core/js/src/main/scala/sigma/crypto/Platform.scala
index 88001ba140..777789ba24 100644
--- a/core/js/src/main/scala/sigma/crypto/Platform.scala
+++ b/core/js/src/main/scala/sigma/crypto/Platform.scala
@@ -253,6 +253,7 @@ object Platform {
case _: Boolean => tpe == SBoolean
case _: Byte | _: Short | _: Int | _: Long => tpe.isInstanceOf[SNumericType]
case _: BigInt => tpe == SBigInt
+ case _: UnsignedBigInt => tpe == SUnsignedBigInt
case _: String => tpe == SString
case _: GroupElement => tpe.isGroupElement
case _: SigmaProp => tpe.isSigmaProp
diff --git a/core/js/src/main/scala/sigma/js/Isos.scala b/core/js/src/main/scala/sigma/js/Isos.scala
index 767a358d62..bc88c46457 100644
--- a/core/js/src/main/scala/sigma/js/Isos.scala
+++ b/core/js/src/main/scala/sigma/js/Isos.scala
@@ -1,7 +1,7 @@
package sigma.js
import sigma.{Coll, Colls}
-import sigma.data.{CBigInt, Iso, RType}
+import sigma.data.{CBigInt, CUnsignedBigInt, Iso, RType}
import java.math.BigInteger
import scala.reflect.ClassTag
@@ -42,6 +42,18 @@ object Isos {
}
}
+ implicit val isoUnsignedBigInt: Iso[js.BigInt, sigma.UnsignedBigInt] = new Iso[js.BigInt, sigma.UnsignedBigInt] {
+ override def to(x: js.BigInt): sigma.UnsignedBigInt = {
+ CUnsignedBigInt(new BigInteger(x.toString(10)))
+ }
+
+ override def from(x: sigma.UnsignedBigInt): js.BigInt = {
+ val bi = x.asInstanceOf[CUnsignedBigInt].wrappedValue
+ val s = bi.toString(10)
+ js.BigInt(s)
+ }
+ }
+
implicit val isoBigIntToLong: Iso[js.BigInt, Long] = new Iso[js.BigInt, Long] {
override def to(x: js.BigInt): Long = java.lang.Long.parseLong(x.toString(10))
diff --git a/core/js/src/main/scala/sigma/js/Type.scala b/core/js/src/main/scala/sigma/js/Type.scala
index b323273a0c..ff391eba66 100644
--- a/core/js/src/main/scala/sigma/js/Type.scala
+++ b/core/js/src/main/scala/sigma/js/Type.scala
@@ -35,6 +35,9 @@ object Type extends js.Object {
/** Descriptor of ErgoScript type BigInt. */
val BigInt = new Type(sigma.BigIntRType)
+ /** Descriptor of ErgoScript type UnsignedBigInt. */
+ val UnsignedBigInt = new Type(sigma.UnsignedBigIntRType)
+
/** Descriptor of ErgoScript type GroupElement. */
val GroupElement = new Type(sigma.GroupElementRType)
diff --git a/core/jvm/src/main/scala/sigma/crypto/Platform.scala b/core/jvm/src/main/scala/sigma/crypto/Platform.scala
index b71694e81b..13c8d6515e 100644
--- a/core/jvm/src/main/scala/sigma/crypto/Platform.scala
+++ b/core/jvm/src/main/scala/sigma/crypto/Platform.scala
@@ -185,6 +185,7 @@ object Platform {
case _: Int => tpe == SInt
case _: Long => tpe == SLong
case _: BigInt => tpe == SBigInt
+ case _: UnsignedBigInt => tpe == SUnsignedBigInt
case _: String => tpe == SString // TODO v6.0: remove this case (see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/905)
case _: GroupElement => tpe.isGroupElement
case _: SigmaProp => tpe.isSigmaProp
diff --git a/core/shared/src/main/scala/sigma/Evaluation.scala b/core/shared/src/main/scala/sigma/Evaluation.scala
index d86b7c1650..c3ffcc8896 100644
--- a/core/shared/src/main/scala/sigma/Evaluation.scala
+++ b/core/shared/src/main/scala/sigma/Evaluation.scala
@@ -25,6 +25,7 @@ object Evaluation {
case SAny => AnyType
case SUnit => UnitType
case SBigInt => BigIntRType
+ case SUnsignedBigInt => UnsignedBigIntRType
case SBox => BoxRType
case SContext => ContextRType
case SGlobal => SigmaDslBuilderRType
@@ -67,6 +68,7 @@ object Evaluation {
case AnyType => SAny
case UnitType => SUnit
case BigIntRType => SBigInt
+ case UnsignedBigIntRType => SUnsignedBigInt
case GroupElementRType => SGroupElement
case AvlTreeRType => SAvlTree
case ot: OptionType[_] => SOption(rtypeToSType(ot.tA))
diff --git a/core/shared/src/main/scala/sigma/SigmaDsl.scala b/core/shared/src/main/scala/sigma/SigmaDsl.scala
index 58593d3619..e2870a3c8b 100644
--- a/core/shared/src/main/scala/sigma/SigmaDsl.scala
+++ b/core/shared/src/main/scala/sigma/SigmaDsl.scala
@@ -4,8 +4,8 @@ import java.math.BigInteger
import sigma.data._
/**
- * Functions defined for 256-bit signed integers
- * */
+ * Base class for signed 256-bits integers
+ */
trait BigInt {
/** Convert this BigInt value to Byte.
* @throws ArithmeticException if overflow happens.
@@ -167,8 +167,188 @@ trait BigInt {
* @return a 256-bit signed integer whose value is (this >> n). `n` should be in 0..255 range (inclusive).
*/
def shiftRight(n: Int): BigInt
+
+ /**
+ * @return unsigned representation of this BigInt, or exception if its value is negative
+ */
+ def toUnsigned: UnsignedBigInt
+
+ /**
+ * @return unsigned representation of this BigInt modulo `m`. Cryptographic mod operation is done, so result is
+ * always non-negative
+ */
+ def toUnsignedMod(m: UnsignedBigInt): UnsignedBigInt
+}
+
+/**
+ * Base class for unsigned 256-bits integers
+ */
+trait UnsignedBigInt {
+ /** Convert this BigInt value to Byte.
+ * @throws ArithmeticException if overflow happens.
+ */
+ def toByte: Byte
+
+ /** Convert this BigInt value to Short.
+ * @throws ArithmeticException if overflow happens.
+ */
+ def toShort: Short
+
+ /** Convert this BigInt value to Int.
+ * @throws ArithmeticException if overflow happens.
+ */
+ def toInt: Int
+
+ /** Convert this BigInt value to Int.
+ * @throws ArithmeticException if overflow happens.
+ */
+ def toLong: Long
+
+ /** Returns a big-endian representation of this BigInt in a collection of bytes.
+ * For example, the value {@code 0x1213141516171819} would yield the
+ * byte array {@code {0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19}}.
+ */
+ def toBytes: Coll[Byte]
+
+
+ /** Compares this numeric with that numeric for order. Returns a negative integer, zero, or a positive integer as the
+ * `this` is less than, equal to, or greater than `that`.
+ */
+ def compareTo(that: UnsignedBigInt): Int
+
+ /** Returns a BigInt whose value is {@code (this + that)}, or exception if result does not fit into 256 bits
+ * (consider using plusMod to avoid exception)
+ *
+ * @param that value to be added to this BigInt.
+ * @return { @code this + that}
+ */
+ def add(that: UnsignedBigInt): UnsignedBigInt
+ def +(that: UnsignedBigInt): UnsignedBigInt = add(that)
+
+ /** Returns a BigInt whose value is {@code (this - that)}, or exception if result is negative
+ * (consider using plusMod to avoid exception)
+ *
+ * @param that value to be subtracted from this BigInt.
+ * @return { @code this - that}
+ */
+ def subtract(that: UnsignedBigInt): UnsignedBigInt
+
+ def -(that: UnsignedBigInt): UnsignedBigInt = subtract(that)
+
+ /** Returns a BigInt whose value is {@code (this * that)} , or exception if result does not fit into 256 bits
+ * (consider using multiplyMod to avoid exception)
+ *
+ * @implNote An implementation may offer better algorithmic
+ * performance when { @code that == this}.
+ * @param that value to be multiplied by this BigInt.
+ * @return { @code this * that}
+ */
+ def multiply(that: UnsignedBigInt): UnsignedBigInt
+ def *(that: UnsignedBigInt): UnsignedBigInt = multiply(that)
+
+ /** Returns a BigInt whose value is {@code (this / that)}.
+ *
+ * @param that value by which this BigInt is to be divided.
+ * @return { @code this / that}
+ * @throws ArithmeticException if { @code that} is zero.
+ */
+ def divide(that: UnsignedBigInt): UnsignedBigInt
+ def /(that: UnsignedBigInt): UnsignedBigInt = divide(that)
+
+ /**
+ * Returns a BigInt whose value is {@code (this mod m}). This method
+ * differs from {@code remainder} in that it always returns a
+ * non-negative BigInteger.
+ *
+ * @param m the modulus.
+ * @return { @code this mod m}
+ * @throws ArithmeticException { @code m} ≤ 0
+ * @see #remainder
+ */
+ def mod(m: UnsignedBigInt): UnsignedBigInt
+ def %(m: UnsignedBigInt): UnsignedBigInt = mod(m)
+
+ /**
+ * Returns the minimum of this BigInteger and {@code val}.
+ *
+ * @param that value with which the minimum is to be computed.
+ * @return the BigInteger whose value is the lesser of this BigInteger and
+ * { @code val}. If they are equal, either may be returned.
+ */
+ def min(that: UnsignedBigInt): UnsignedBigInt
+
+ /**
+ * Returns the maximum of this BigInteger and {@code val}.
+ *
+ * @param that value with which the maximum is to be computed.
+ * @return the BigInteger whose value is the greater of this and
+ * { @code val}. If they are equal, either may be returned.
+ */
+ def max(that: UnsignedBigInt): UnsignedBigInt
+
+ /** Returns a BigInteger whose value is `(this & that)`.
+ * @param that value to be AND'ed with this BigInteger.
+ * @return `this & that`
+ */
+ def and(that: UnsignedBigInt): UnsignedBigInt
+ def &(that: UnsignedBigInt): UnsignedBigInt = and(that)
+
+ /** Returns a BigInteger whose value is `(this | that)`.
+ *
+ * @param that value to be OR'ed with this BigInteger.
+ * @return `this | that`
+ */
+ def or(that: UnsignedBigInt): UnsignedBigInt
+ def |(that: UnsignedBigInt): UnsignedBigInt = or(that)
+
+ def modInverse(m: UnsignedBigInt): UnsignedBigInt
+
+ /**
+ * @return this + that mod m , where mod is cryptographic mod operation
+ */
+ def plusMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt
+
+ /**
+ * @return this - that mod m , where mod is cryptographic mod operation, so result is always non-negative
+ */
+ def subtractMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt
+
+ /**
+ * @return this * that mod m , where mod is cryptographic mod operation
+ */
+ def multiplyMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt
+
+ /**
+ * @return an unsigned big integer whose value is `this xor that`
+ */
+ def xor(that: UnsignedBigInt): UnsignedBigInt
+
+ /**
+ * @return a 256-bit unsigned integer whose value is (this << n). The shift distance, n, may be negative,
+ * in which case this method performs a right shift. (Computes floor(this * 2n).)
+ */
+ def shiftLeft(n: Int): UnsignedBigInt
+
+ /**
+ * @return a 256-bit unsigned integer whose value is (this >> n). Sign extension is performed. The shift distance, n,
+ * may be negative, in which case this method performs a left shift. (Computes floor(this / 2n).)
+ */
+ def shiftRight(n: Int): UnsignedBigInt
+
+ /**
+ * @return an unsigned big integer value which is inverse of this (every bit is flipped)
+ */
+ def bitwiseInverse(): UnsignedBigInt
+
+ /**
+ * @return signed version of the same value, or exception if the value does not fit into signed type (since it is
+ * also about 256 bits, but one bit is encoding sign)
+ */
+ def toSigned(): BigInt
}
+
+
/** Base class for points on elliptic curves. */
trait GroupElement {
/** Checks if the provided element is an identity element. */
@@ -181,6 +361,12 @@ trait GroupElement {
*/
def exp(k: BigInt): GroupElement
+ /** Exponentiate this GroupElement
to the given unsigned 256 bit integer.
+ * @param k The power.
+ * @return this to the power of k
.
+ */
+ def expUnsigned(k: UnsignedBigInt): GroupElement
+
/** Group operation. */
def multiply(that: GroupElement): GroupElement
@@ -775,6 +961,9 @@ trait SigmaDslBuilder {
/** Create DSL big integer from existing `java.math.BigInteger`*/
def BigInt(n: BigInteger): BigInt
+ /** Create DSL unsigned big integer from existing `java.math.BigInteger`*/
+ def UnsignedBigInt(n: BigInteger): UnsignedBigInt
+
/** Extract `java.math.BigInteger` from DSL's `BigInt` type*/
def toBigInteger(n: BigInt): BigInteger
diff --git a/core/shared/src/main/scala/sigma/ast/SType.scala b/core/shared/src/main/scala/sigma/ast/SType.scala
index d289f4067a..3e915cf304 100644
--- a/core/shared/src/main/scala/sigma/ast/SType.scala
+++ b/core/shared/src/main/scala/sigma/ast/SType.scala
@@ -4,10 +4,10 @@ import sigma.Evaluation.stypeToRType
import sigma.ast.SCollection.SByteArray
import sigma.ast.SType.TypeCode
import sigma.data.OverloadHack.Overloaded1
-import sigma.data.{CBigInt, Nullable, SigmaConstants}
+import sigma.data.{CBigInt, CUnsignedBigInt, Nullable, SigmaConstants}
import sigma.reflection.{RClass, RMethod, ReflectionData}
import sigma.util.Extensions.{IntOps, LongOps, ShortOps}
-import sigma.{AvlTree, BigInt, Box, Coll, Context, Evaluation, GroupElement, Header, PreHeader, SigmaDslBuilder, SigmaProp, VersionContext}
+import sigma.{AvlTree, BigInt, Box, Coll, Context, Evaluation, GroupElement, Header, PreHeader, SigmaDslBuilder, SigmaProp, UnsignedBigInt, VersionContext}
import java.math.BigInteger
@@ -102,12 +102,24 @@ object SType {
/** Immutable empty IndexedSeq, can be used to avoid repeated allocations. */
val EmptySeq: IndexedSeq[SType] = EmptyArray
+ // <= V5 types, see `allPredefTypes` scaladoc below
+ private val v5PredefTypes = Array[SType](
+ SBoolean, SByte, SShort, SInt, SLong, SBigInt, SContext,
+ SGlobal, SHeader, SPreHeader, SAvlTree, SGroupElement, SSigmaProp, SString, SBox,
+ SUnit, SAny)
+
+ // V6 types, see `allPredefTypes` scaladoc below. Contains SUnsignedBigInt type in addition to v5 types.
+ private val v6PredefTypes = v5PredefTypes ++ Array(SUnsignedBigInt)
+
/** All pre-defined types should be listed here. Note, NoType is not listed.
* Should be in sync with sigmastate.lang.Types.predefTypes. */
- val allPredefTypes: Seq[SType] = Array[SType](
- SBoolean, SByte, SShort, SInt, SLong, SBigInt, SContext,
- SGlobal, SHeader, SPreHeader, SAvlTree, SGroupElement, SSigmaProp, SString, SBox,
- SUnit, SAny)
+ def allPredefTypes: Seq[SType] = {
+ if(VersionContext.current.isV6SoftForkActivated) {
+ v6PredefTypes
+ } else {
+ v5PredefTypes
+ }
+ }
/** A mapping of object types supporting MethodCall operations. For each serialized
* typeId this map contains a companion object which can be used to access the list of
@@ -136,6 +148,8 @@ object SType {
* (SByte, SShort, SInt, SLong, SBigInt) and the generic tNum type parameter is
* specialized accordingly.
*
+ * Also, SUnsignedBigInt type is added in v6.0.
+ *
* This difference in behaviour is tested by `property("MethodCall on numerics")`.
*
* The regression tests in `property("MethodCall Codes")` should pass.
@@ -144,7 +158,7 @@ object SType {
SBoolean, SString, STuple, SGroupElement, SSigmaProp, SContext, SGlobal, SHeader, SPreHeader,
SAvlTree, SBox, SOption, SCollection, SBigInt
)
- private val v6Types = v5Types ++ Seq(SByte, SShort, SInt, SLong)
+ private val v6Types = v5Types ++ Seq(SByte, SShort, SInt, SLong, SUnsignedBigInt)
private val v5TypesMap = v5Types.map { t => (t.typeId, t) }.toMap
@@ -177,6 +191,7 @@ object SType {
case SInt => x.isInstanceOf[Int]
case SLong => x.isInstanceOf[Long]
case SBigInt => x.isInstanceOf[BigInt]
+ case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated => x.isInstanceOf[UnsignedBigInt]
case SGroupElement => x.isInstanceOf[GroupElement]
case SSigmaProp => x.isInstanceOf[SigmaProp]
case SBox => x.isInstanceOf[Box]
@@ -240,7 +255,7 @@ trait STypeCompanion {
/** Special type to represent untyped values.
* Interpreter raises an error when encounter a Value with this type.
- * All Value nodes with this type should be elimitanted during typing.
+ * All Value nodes with this type should be eliminated during typing.
* If no specific type can be assigned statically during typing,
* then either error should be raised or type SAny should be assigned
* which is interpreted as dynamic typing. */
@@ -307,7 +322,7 @@ object SPrimType {
def unapply(t: SType): Option[SType] = SType.allPredefTypes.find(_ == t)
/** Type code of the last valid prim type so that (1 to LastPrimTypeCode) is a range of valid codes. */
- final val LastPrimTypeCode: Byte = 8: Byte
+ final val LastPrimTypeCode: Byte = 9: Byte
/** Upper limit of the interval of valid type codes for primitive types */
final val MaxPrimTypeCode: Byte = 11: Byte
@@ -359,8 +374,6 @@ trait SNumericType extends SProduct with STypeCompanion {
}
object SNumericType extends STypeCompanion {
- /** Array of all numeric types ordered by number of bytes in the representation. */
- final val allNumericTypes = Array(SByte, SShort, SInt, SLong, SBigInt)
// TODO v6.0: this typeId is now shadowed by SGlobal.typeId
// see https://github.com/ScorexFoundation/sigmastate-interpreter/issues/667
@@ -397,6 +410,7 @@ case object SByte extends SPrimType with SEmbeddable with SNumericType with SMon
case i: Int => i.toByteExact
case l: Long => l.toByteExact
case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toByte // toByteExact from int is called under the hood
+ case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toByte // toByteExact from int is called under the hood
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
@@ -419,6 +433,7 @@ case object SShort extends SPrimType with SEmbeddable with SNumericType with SMo
case i: Int => i.toShortExact
case l: Long => l.toShortExact
case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toShort // toShortExact from int is called under the hood
+ case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toShort // toShortExact from int is called under the hood
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
@@ -443,6 +458,7 @@ case object SInt extends SPrimType with SEmbeddable with SNumericType with SMono
case i: Int => i
case l: Long => l.toIntExact
case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toInt
+ case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toInt
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
@@ -469,17 +485,17 @@ case object SLong extends SPrimType with SEmbeddable with SNumericType with SMon
case i: Int => i.toLong
case l: Long => l
case bi: BigInt if VersionContext.current.isV6SoftForkActivated => bi.toLong
+ case ubi: UnsignedBigInt if VersionContext.current.isV6SoftForkActivated => ubi.toLong
case _ => sys.error(s"Cannot downcast value $v to the type $this")
}
}
-/** Type of 256 bit integer values. Implemented using [[java.math.BigInteger]]. */
+/** Type of 256-bit signed integer values. Implemented using [[java.math.BigInteger]]. */
case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SMonoType {
override type WrappedType = BigInt
override val typeCode: TypeCode = 6: Byte
override val reprClass: RClass[_] = RClass(classOf[BigInt])
override def typeId = typeCode
- implicit def typeBigInt: SBigInt.type = this
/** Type of Relation binary op like GE, LE, etc. */
val RelationOpType = SFunc(Array(SBigInt, SBigInt), SBoolean)
@@ -489,6 +505,7 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
override def numericTypeIndex: Int = 4
+ // no upcast to unsigned big int, use .toUnsigned / .toUnsignedMod instead
override def upcast(v: AnyVal): BigInt = {
v match {
case x: Byte => CBigInt(BigInteger.valueOf(x.toLong))
@@ -499,6 +516,8 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
case _ => sys.error(s"Cannot upcast value $v to the type $this")
}
}
+
+ // no downcast to unsigned big int, use .toUnsigned / .toUnsignedMod instead
override def downcast(v: AnyVal): BigInt = {
v match {
case x: Byte => CBigInt(BigInteger.valueOf(x.toLong))
@@ -511,6 +530,56 @@ case object SBigInt extends SPrimType with SEmbeddable with SNumericType with SM
}
}
+/** Type of 256-bit unsigned integer values. Implemented using [[java.math.BigInteger]]. */
+case object SUnsignedBigInt extends SPrimType with SEmbeddable with SNumericType with SMonoType {
+ override type WrappedType = UnsignedBigInt
+ override val typeCode: TypeCode = 9: Byte
+ override val reprClass: RClass[_] = RClass(classOf[UnsignedBigInt])
+ override def typeId = typeCode
+
+ /** Type of Relation binary op like GE, LE, etc. */
+ val RelationOpType = SFunc(Array(SUnsignedBigInt, SUnsignedBigInt), SBoolean)
+
+ /** The maximum size of BigInteger value in byte array representation. */
+ val MaxSizeInBytes: Long = SigmaConstants.MaxBigIntSizeInBytes.value // todo: 256 bits or more?
+
+ override def numericTypeIndex: Int = 5
+
+ // no upcast to signed big int, use .toSigned method
+ override def upcast(v: AnyVal): UnsignedBigInt = {
+ val bi = v match {
+ case x: Byte => BigInteger.valueOf(x.toLong)
+ case x: Short => BigInteger.valueOf(x.toLong)
+ case x: Int => BigInteger.valueOf(x.toLong)
+ case x: Long => BigInteger.valueOf(x)
+ case x: UnsignedBigInt => x.asInstanceOf[CUnsignedBigInt].wrappedValue
+ case _ => sys.error(s"Cannot upcast value $v to the type $this")
+ }
+ if(bi.compareTo(BigInteger.ZERO) >= 0) {
+ CUnsignedBigInt(bi)
+ } else {
+ sys.error(s"Cannot upcast negative value $v to the type $this")
+ }
+ }
+
+ // no downcast to signed big int, use .toSigned method
+ override def downcast(v: AnyVal): UnsignedBigInt = {
+ val bi = v match {
+ case x: Byte => BigInteger.valueOf(x.toLong)
+ case x: Short => BigInteger.valueOf(x.toLong)
+ case x: Int => BigInteger.valueOf(x.toLong)
+ case x: Long => BigInteger.valueOf(x)
+ case x: UnsignedBigInt => x.asInstanceOf[CUnsignedBigInt].wrappedValue
+ case _ => sys.error(s"Cannot downcast value $v to the type $this")
+ }
+ if (bi.compareTo(BigInteger.ZERO) >= 0) {
+ CUnsignedBigInt(bi)
+ } else {
+ sys.error(s"Cannot upcast negative value $v to the type $this")
+ }
+ }
+}
+
/** Descriptor of type `String` which is not used in ErgoTree, but used in ErgoScript.
* NOTE: this descriptor both type and type companion */
case object SString extends SProduct with SMonoType {
@@ -649,15 +718,16 @@ object SOption extends STypeCompanion {
override val reprClass: RClass[_] = RClass(classOf[Option[_]])
- type SBooleanOption = SOption[SBoolean.type]
- type SByteOption = SOption[SByte.type]
- type SShortOption = SOption[SShort.type]
- type SIntOption = SOption[SInt.type]
- type SLongOption = SOption[SLong.type]
- type SBigIntOption = SOption[SBigInt.type]
- type SGroupElementOption = SOption[SGroupElement.type]
- type SBoxOption = SOption[SBox.type]
- type SAvlTreeOption = SOption[SAvlTree.type]
+ type SBooleanOption = SOption[SBoolean.type]
+ type SByteOption = SOption[SByte.type]
+ type SShortOption = SOption[SShort.type]
+ type SIntOption = SOption[SInt.type]
+ type SLongOption = SOption[SLong.type]
+ type SBigIntOption = SOption[SBigInt.type]
+ type SUnsignedBigIntOption = SOption[SUnsignedBigInt.type]
+ type SGroupElementOption = SOption[SGroupElement.type]
+ type SBoxOption = SOption[SBox.type]
+ type SAvlTreeOption = SOption[SAvlTree.type]
/** This descriptors are instantiated once here and then reused. */
implicit val SByteOption = SOption(SByte)
@@ -666,6 +736,7 @@ object SOption extends STypeCompanion {
implicit val SIntOption = SOption(SInt)
implicit val SLongOption = SOption(SLong)
implicit val SBigIntOption = SOption(SBigInt)
+ implicit val SUnsignedBigIntOption = SOption(SUnsignedBigInt)
implicit val SBooleanOption = SOption(SBoolean)
implicit val SAvlTreeOption = SOption(SAvlTree)
implicit val SGroupElementOption = SOption(SGroupElement)
@@ -726,29 +797,31 @@ object SCollection extends STypeCompanion {
def apply[T <: SType](elemType: T): SCollection[T] = SCollectionType(elemType)
def apply[T <: SType](implicit elemType: T, ov: Overloaded1): SCollection[T] = SCollectionType(elemType)
- type SBooleanArray = SCollection[SBoolean.type]
- type SByteArray = SCollection[SByte.type]
- type SShortArray = SCollection[SShort.type]
- type SIntArray = SCollection[SInt.type]
- type SLongArray = SCollection[SLong.type]
- type SBigIntArray = SCollection[SBigInt.type]
- type SGroupElementArray = SCollection[SGroupElement.type]
- type SBoxArray = SCollection[SBox.type]
- type SAvlTreeArray = SCollection[SAvlTree.type]
+ type SBooleanArray = SCollection[SBoolean.type]
+ type SByteArray = SCollection[SByte.type]
+ type SShortArray = SCollection[SShort.type]
+ type SIntArray = SCollection[SInt.type]
+ type SLongArray = SCollection[SLong.type]
+ type SBigIntArray = SCollection[SBigInt.type]
+ type SUnsignedBigIntArray = SCollection[SUnsignedBigInt.type]
+ type SGroupElementArray = SCollection[SGroupElement.type]
+ type SBoxArray = SCollection[SBox.type]
+ type SAvlTreeArray = SCollection[SAvlTree.type]
/** This descriptors are instantiated once here and then reused. */
- val SBooleanArray = SCollection(SBoolean)
- val SByteArray = SCollection(SByte)
- val SByteArray2 = SCollection(SCollection(SByte))
- val SShortArray = SCollection(SShort)
- val SIntArray = SCollection(SInt)
- val SLongArray = SCollection(SLong)
- val SBigIntArray = SCollection(SBigInt)
- val SGroupElementArray = SCollection(SGroupElement)
- val SSigmaPropArray = SCollection(SSigmaProp)
- val SBoxArray = SCollection(SBox)
- val SAvlTreeArray = SCollection(SAvlTree)
- val SHeaderArray = SCollection(SHeader)
+ val SBooleanArray = SCollection(SBoolean)
+ val SByteArray = SCollection(SByte)
+ val SByteArray2 = SCollection(SCollection(SByte))
+ val SShortArray = SCollection(SShort)
+ val SIntArray = SCollection(SInt)
+ val SLongArray = SCollection(SLong)
+ val SBigIntArray = SCollection(SBigInt)
+ val SUnsignedBigIntArray = SCollection(SUnsignedBigInt)
+ val SGroupElementArray = SCollection(SGroupElement)
+ val SSigmaPropArray = SCollection(SSigmaProp)
+ val SBoxArray = SCollection(SBox)
+ val SAvlTreeArray = SCollection(SAvlTree)
+ val SHeaderArray = SCollection(SHeader)
}
/** Type descriptor of tuple type. */
diff --git a/data/shared/src/main/scala/sigma/crypto/BigIntegers.scala b/core/shared/src/main/scala/sigma/crypto/BigIntegers.scala
similarity index 92%
rename from data/shared/src/main/scala/sigma/crypto/BigIntegers.scala
rename to core/shared/src/main/scala/sigma/crypto/BigIntegers.scala
index 4465184580..c7c7b0721e 100644
--- a/data/shared/src/main/scala/sigma/crypto/BigIntegers.scala
+++ b/core/shared/src/main/scala/sigma/crypto/BigIntegers.scala
@@ -38,8 +38,8 @@ object BigIntegers {
* @return a positive BigInteger
*/
def createRandomBigInteger(
- bitLength: Int,
- random: SecureRandom): BigInteger = {
+ bitLength: Int,
+ random: SecureRandom): BigInteger = {
new BigInteger(1, createRandom(bitLength, random))
}
@@ -52,9 +52,9 @@ object BigIntegers {
* @return a random BigInteger value in the range [min,max]
*/
def createRandomInRange(
- min: BigInteger,
- max: BigInteger,
- random: SecureRandom): BigInteger = {
+ min: BigInteger,
+ max: BigInteger,
+ random: SecureRandom): BigInteger = {
val cmp = min.compareTo(max)
if (cmp >= 0) {
if (cmp > 0) throw new IllegalArgumentException("'min' may not be greater than 'max'")
@@ -64,7 +64,7 @@ object BigIntegers {
if (min.bitLength > max.bitLength / 2)
return createRandomInRange(ZERO, max.subtract(min), random).add(min)
- for ( _ <- 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
}
@@ -96,6 +96,7 @@ object BigIntegers {
/** Converts a byte array to a BigInteger, treating the array as bits of the unsigned
* integer.
+ *
* @param buf the byte array to convert
* @return the resulting positive BigInteger
*/
diff --git a/core/shared/src/main/scala/sigma/data/CBigInt.scala b/core/shared/src/main/scala/sigma/data/CBigInt.scala
index ea69174877..1fe1c2f503 100644
--- a/core/shared/src/main/scala/sigma/data/CBigInt.scala
+++ b/core/shared/src/main/scala/sigma/data/CBigInt.scala
@@ -1,7 +1,8 @@
package sigma.data
+import sigma.crypto.BigIntegers
import sigma.util.Extensions.BigIntegerOps
-import sigma.{BigInt, Coll, Colls}
+import sigma.{BigInt, Coll, Colls, UnsignedBigInt}
import java.math.BigInteger
@@ -28,11 +29,11 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr
override def signum: Int = wrappedValue.signum()
- override def add(that: BigInt): BigInt = CBigInt(wrappedValue.add(that.asInstanceOf[CBigInt].wrappedValue).to256BitValueExact)
+ override def add(that: BigInt): BigInt = CBigInt(wrappedValue.add(that.asInstanceOf[CBigInt].wrappedValue).toSignedBigIntValueExact)
- override def subtract(that: BigInt): BigInt = CBigInt(wrappedValue.subtract(that.asInstanceOf[CBigInt].wrappedValue).to256BitValueExact)
+ override def subtract(that: BigInt): BigInt = CBigInt(wrappedValue.subtract(that.asInstanceOf[CBigInt].wrappedValue).toSignedBigIntValueExact)
- override def multiply(that: BigInt): BigInt = CBigInt(wrappedValue.multiply(that.asInstanceOf[CBigInt].wrappedValue).to256BitValueExact)
+ override def multiply(that: BigInt): BigInt = CBigInt(wrappedValue.multiply(that.asInstanceOf[CBigInt].wrappedValue).toSignedBigIntValueExact)
override def divide(that: BigInt): BigInt = CBigInt(wrappedValue.divide(that.asInstanceOf[CBigInt].wrappedValue))
@@ -44,7 +45,7 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr
override def max(that: BigInt): BigInt = CBigInt(wrappedValue.max(that.asInstanceOf[CBigInt].wrappedValue))
- override def negate(): BigInt = CBigInt(wrappedValue.negate().to256BitValueExact)
+ override def negate(): BigInt = CBigInt(wrappedValue.negate().toSignedBigIntValueExact)
override def and(that: BigInt): BigInt = CBigInt(wrappedValue.and(that.asInstanceOf[CBigInt].wrappedValue))
@@ -52,7 +53,112 @@ case class CBigInt(override val wrappedValue: BigInteger) extends BigInt with Wr
override def xor(that: BigInt): BigInt = CBigInt(wrappedValue.xor(that.asInstanceOf[CBigInt].wrappedValue))
- override def shiftLeft(n: Int): BigInt = CBigInt(wrappedValue.shiftLeft(n).to256BitValueExact)
+ override def shiftLeft(n: Int): BigInt = CBigInt(wrappedValue.shiftLeft(n).toSignedBigIntValueExact)
+
+ override def shiftRight(n: Int): BigInt = CBigInt(wrappedValue.shiftRight(n).toSignedBigIntValueExact)
+
+ override def toUnsigned: UnsignedBigInt = {
+ if(this.wrappedValue.compareTo(BigInteger.ZERO) < 0){
+ throw new ArithmeticException("BigInteger argument for .toUnsigned is negative");
+ } else {
+ CUnsignedBigInt(this.wrappedValue)
+ }
+ }
+
+ override def toUnsignedMod(m: UnsignedBigInt): UnsignedBigInt = {
+ CUnsignedBigInt(this.wrappedValue.mod(m.asInstanceOf[CUnsignedBigInt].wrappedValue))
+ }
+
+}
+
+/** A default implementation of [[UnsignedBigInt]] interface.
+ *
+ * @see [[UnsignedBigInt]] for detailed descriptions
+ */
+case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends UnsignedBigInt with WrapperOf[BigInteger] {
+
+ if (wrappedValue.compareTo(BigInteger.ZERO) < 0) {
+ throw new IllegalArgumentException(s"Attempt to create unsigned value from negative big integer $wrappedValue")
+ }
+
+ if (wrappedValue.bitLength() > 256) {
+ throw new IllegalArgumentException(s"Too big unsigned big int value $wrappedValue")
+ }
+
+ override def toByte: Byte = wrappedValue.toByteExact
+
+ override def toShort: Short = wrappedValue.toShortExact
+
+ override def toInt: Int = wrappedValue.toIntExact
+
+ override def toLong: Long = wrappedValue.toLongExact
+
+ override def toBytes: Coll[Byte] = Colls.fromArray(BigIntegers.asUnsignedByteArray(wrappedValue))
+
+ override def compareTo(that: UnsignedBigInt): Int =
+ wrappedValue.compareTo(that.asInstanceOf[CUnsignedBigInt].wrappedValue)
+
+ override def add(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.add(that.asInstanceOf[CUnsignedBigInt].wrappedValue).toUnsignedBigIntValueExact)
+
+ override def subtract(that: UnsignedBigInt): UnsignedBigInt = {
+ CUnsignedBigInt(wrappedValue.subtract(that.asInstanceOf[CUnsignedBigInt].wrappedValue).toUnsignedBigIntValueExact)
+ }
+
+ override def multiply(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.multiply(that.asInstanceOf[CUnsignedBigInt].wrappedValue).toUnsignedBigIntValueExact)
+
+ override def divide(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.divide(that.asInstanceOf[CUnsignedBigInt].wrappedValue))
+
+ override def mod(m: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.mod(m.asInstanceOf[CUnsignedBigInt].wrappedValue))
+
+ override def min(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.min(that.asInstanceOf[CUnsignedBigInt].wrappedValue))
+
+ override def max(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.max(that.asInstanceOf[CUnsignedBigInt].wrappedValue))
+
+ override def and(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.and(that.asInstanceOf[CUnsignedBigInt].wrappedValue))
+
+ override def or(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.or(that.asInstanceOf[CUnsignedBigInt].wrappedValue))
+
+ override def modInverse(m: UnsignedBigInt): UnsignedBigInt = {
+ CUnsignedBigInt(wrappedValue.modInverse(m.asInstanceOf[CUnsignedBigInt].wrappedValue))
+ }
+
+ override def plusMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt = {
+ val thatBi = that.asInstanceOf[CUnsignedBigInt].wrappedValue
+ val mBi = m.asInstanceOf[CUnsignedBigInt].wrappedValue
+ CUnsignedBigInt(wrappedValue.add(thatBi).mod(mBi))
+ }
+
+ override def subtractMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt = {
+ val thatBi = that.asInstanceOf[CUnsignedBigInt].wrappedValue
+ val mBi = m.asInstanceOf[CUnsignedBigInt].wrappedValue
+ CUnsignedBigInt(wrappedValue.subtract(thatBi).mod(mBi))
+ }
+
+ override def multiplyMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt = {
+ val thatBi = that.asInstanceOf[CUnsignedBigInt].wrappedValue
+ val mBi = m.asInstanceOf[CUnsignedBigInt].wrappedValue
+ CUnsignedBigInt(wrappedValue.multiply(thatBi).mod(mBi))
+ }
+
+ /**
+ * @return a big integer whose value is `this xor that`
+ */
+ def xor(that: UnsignedBigInt): UnsignedBigInt = {
+ CUnsignedBigInt(wrappedValue.xor(that.asInstanceOf[CUnsignedBigInt].wrappedValue))
+ }
+
+ override def shiftLeft(n: Int): UnsignedBigInt = CUnsignedBigInt(wrappedValue.shiftLeft(n).toUnsignedBigIntValueExact)
+
+ override def shiftRight(n: Int): UnsignedBigInt = CUnsignedBigInt(wrappedValue.shiftRight(n).toUnsignedBigIntValueExact)
+
+ override def bitwiseInverse(): UnsignedBigInt = {
+ val bytes = BigIntegers.asUnsignedByteArray(32, wrappedValue)
+ val res: Array[Byte] = bytes.map(b => (~b & 0xff).toByte)
+ CUnsignedBigInt(BigIntegers.fromUnsignedByteArray(res))
+ }
+
+ override def toSigned(): BigInt = {
+ CBigInt(wrappedValue.toSignedBigIntValueExact)
+ }
- override def shiftRight(n: Int): BigInt = CBigInt(wrappedValue.shiftRight(n).to256BitValueExact)
}
diff --git a/core/shared/src/main/scala/sigma/data/CGroupElement.scala b/core/shared/src/main/scala/sigma/data/CGroupElement.scala
index ed4849f0d7..c5483797cf 100644
--- a/core/shared/src/main/scala/sigma/data/CGroupElement.scala
+++ b/core/shared/src/main/scala/sigma/data/CGroupElement.scala
@@ -3,7 +3,7 @@ package sigma.data
import sigma.crypto.{CryptoFacade, Ecp}
import sigma.serialization.GroupElementSerializer
import sigma.util.Extensions.EcpOps
-import sigma.{BigInt, Coll, Colls, GroupElement}
+import sigma.{BigInt, Coll, Colls, GroupElement, UnsignedBigInt}
/** A default implementation of [[GroupElement]] interface.
*
@@ -21,6 +21,9 @@ case class CGroupElement(override val wrappedValue: Ecp) extends GroupElement wi
override def exp(k: BigInt): GroupElement =
CGroupElement(CryptoFacade.exponentiatePoint(wrappedValue, k.asInstanceOf[CBigInt].wrappedValue))
+ override def expUnsigned(k: UnsignedBigInt): GroupElement =
+ CGroupElement(CryptoFacade.exponentiatePoint(wrappedValue, k.asInstanceOf[CUnsignedBigInt].wrappedValue))
+
override def multiply(that: GroupElement): GroupElement =
CGroupElement(CryptoFacade.multiplyPoints(wrappedValue, that.asInstanceOf[CGroupElement].wrappedValue))
diff --git a/core/shared/src/main/scala/sigma/data/package.scala b/core/shared/src/main/scala/sigma/data/package.scala
index c5a35f7b5f..58870c0888 100644
--- a/core/shared/src/main/scala/sigma/data/package.scala
+++ b/core/shared/src/main/scala/sigma/data/package.scala
@@ -14,6 +14,7 @@ package object data {
val StringClassTag = classTag[String]
val BigIntClassTag = classTag[BigInt]
+ val UnsignedBigIntClassTag = classTag[UnsignedBigInt]
val GroupElementClassTag = classTag[GroupElement]
val SigmaPropClassTag = classTag[SigmaProp]
val SigmaBooleanClassTag = classTag[SigmaBoolean]
diff --git a/core/shared/src/main/scala/sigma/package.scala b/core/shared/src/main/scala/sigma/package.scala
index 89b883f52d..41f90b33bb 100644
--- a/core/shared/src/main/scala/sigma/package.scala
+++ b/core/shared/src/main/scala/sigma/package.scala
@@ -26,6 +26,7 @@ package object sigma {
implicit val StringType : RType[String] = GeneralType(StringClassTag)
implicit val BigIntRType : RType[BigInt] = GeneralType(BigIntClassTag)
+ implicit val UnsignedBigIntRType : RType[UnsignedBigInt] = GeneralType(UnsignedBigIntClassTag)
implicit val GroupElementRType: RType[GroupElement] = GeneralType(GroupElementClassTag)
implicit val SigmaPropRType : RType[SigmaProp] = GeneralType(SigmaPropClassTag)
implicit val SigmaBooleanRType: RType[SigmaBoolean] = GeneralType(SigmaBooleanClassTag)
diff --git a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala
index 3a676ed81d..9765f8f58b 100644
--- a/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala
+++ b/core/shared/src/main/scala/sigma/reflection/ReflectionData.scala
@@ -101,29 +101,85 @@ object ReflectionData {
}
{
val clazz = classOf[sigma.BigInt]
- val paramTypes = Array[Class[_]](clazz)
+ val noParamTypes = Array[Class[_]]()
+ val oneParamTypes = Array[Class[_]](clazz)
registerClassEntry(clazz,
methods = Map(
- mkMethod(clazz, "add", paramTypes) { (obj, args) =>
+ mkMethod(clazz, "add", oneParamTypes) { (obj, args) =>
obj.asInstanceOf[BigInt].add(args(0).asInstanceOf[BigInt])
},
- mkMethod(clazz, "max", paramTypes) { (obj, args) =>
+ mkMethod(clazz, "max", oneParamTypes) { (obj, args) =>
obj.asInstanceOf[BigInt].max(args(0).asInstanceOf[BigInt])
},
- mkMethod(clazz, "min", paramTypes) { (obj, args) =>
+ mkMethod(clazz, "min", oneParamTypes) { (obj, args) =>
obj.asInstanceOf[BigInt].min(args(0).asInstanceOf[BigInt])
},
- mkMethod(clazz, "subtract", paramTypes) { (obj, args) =>
+ mkMethod(clazz, "subtract", oneParamTypes) { (obj, args) =>
obj.asInstanceOf[BigInt].subtract(args(0).asInstanceOf[BigInt])
},
- mkMethod(clazz, "multiply", paramTypes) { (obj, args) =>
+ mkMethod(clazz, "multiply", oneParamTypes) { (obj, args) =>
obj.asInstanceOf[BigInt].multiply(args(0).asInstanceOf[BigInt])
},
- mkMethod(clazz, "mod", paramTypes) { (obj, args) =>
+ mkMethod(clazz, "mod", oneParamTypes) { (obj, args) =>
obj.asInstanceOf[BigInt].mod(args(0).asInstanceOf[BigInt])
},
- mkMethod(clazz, "divide", paramTypes) { (obj, args) =>
+ mkMethod(clazz, "divide", oneParamTypes) { (obj, args) =>
obj.asInstanceOf[BigInt].divide(args(0).asInstanceOf[BigInt])
+ },
+ mkMethod(clazz, "toUnsigned", noParamTypes) { (obj, _) =>
+ obj.asInstanceOf[BigInt].toUnsigned
+ },
+ mkMethod(clazz, "toUnsignedMod", Array[Class[_]](classOf[sigma.UnsignedBigInt])) { (obj, args) =>
+ obj.asInstanceOf[BigInt].toUnsignedMod(args(0).asInstanceOf[UnsignedBigInt])
+ }
+ )
+ )
+ }
+ {
+ val clazz = classOf[sigma.UnsignedBigInt]
+ val noParamTypes = Array[Class[_]]()
+ val oneParamTypes = Array[Class[_]](clazz)
+ val twoParamTypes = Array[Class[_]](clazz, clazz)
+ registerClassEntry(clazz,
+ methods = Map(
+ mkMethod(clazz, "add", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].add(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "max", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].max(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "min", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].min(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "subtract", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].subtract(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "multiply", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].multiply(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "mod", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].mod(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "divide", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].divide(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "mod", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].mod(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "modInverse", oneParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].modInverse(args(0).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "plusMod", twoParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].plusMod(args(0).asInstanceOf[UnsignedBigInt], args(1).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "subtractMod", twoParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].subtractMod(args(0).asInstanceOf[UnsignedBigInt], args(1).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "multiplyMod", twoParamTypes) { (obj, args) =>
+ obj.asInstanceOf[UnsignedBigInt].multiplyMod(args(0).asInstanceOf[UnsignedBigInt], args(1).asInstanceOf[UnsignedBigInt])
+ },
+ mkMethod(clazz, "toSigned", noParamTypes) { (obj, _) =>
+ obj.asInstanceOf[UnsignedBigInt].toSigned()
}
)
)
@@ -304,6 +360,9 @@ object ReflectionData {
mkMethod(clazz, "exp", Array[Class[_]](classOf[BigInt])) { (obj, args) =>
obj.asInstanceOf[GroupElement].exp(args(0).asInstanceOf[BigInt])
},
+ mkMethod(clazz, "expUnsigned", Array[Class[_]](classOf[UnsignedBigInt])) { (obj, args) =>
+ obj.asInstanceOf[GroupElement].expUnsigned(args(0).asInstanceOf[UnsignedBigInt])
+ },
mkMethod(clazz, "multiply", Array[Class[_]](classOf[GroupElement])) { (obj, args) =>
obj.asInstanceOf[GroupElement].multiply(args(0).asInstanceOf[GroupElement])
},
diff --git a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala
index d33b340284..175e91fbcb 100644
--- a/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala
+++ b/core/shared/src/main/scala/sigma/serialization/CoreDataSerializer.scala
@@ -2,8 +2,9 @@ package sigma.serialization
import debox.cfor
import sigma.ast._
+import sigma.crypto.BigIntegers
import sigma.data._
-import sigma.util.Extensions.{CoreAvlTreeOps, BigIntOps, GroupElementOps, SigmaPropOps}
+import sigma.util.Extensions.{BigIntOps, CoreAvlTreeOps, GroupElementOps, SigmaPropOps}
import sigma.validation.ValidationRules.CheckSerializableTypeCode
import sigma.{Evaluation, _}
@@ -33,6 +34,10 @@ class CoreDataSerializer {
val data = v.asInstanceOf[BigInt].toBigInteger.toByteArray
w.putUShort(data.length)
w.putBytes(data)
+ case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated =>
+ val data = BigIntegers.asUnsignedByteArray(v.asInstanceOf[CUnsignedBigInt].wrappedValue)
+ w.putUShort(data.length)
+ w.putBytes(data)
case SGroupElement =>
GroupElementSerializer.serialize(v.asInstanceOf[GroupElement].toECPoint, w)
case SSigmaProp =>
@@ -108,6 +113,13 @@ class CoreDataSerializer {
}
val valueBytes = r.getBytes(size)
CBigInt(new BigInteger(valueBytes))
+ case SUnsignedBigInt if VersionContext.current.isV6SoftForkActivated =>
+ val size: Short = r.getUShort().toShort
+ if (size > SBigInt.MaxSizeInBytes) {
+ throw SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes: $size")
+ }
+ val valueBytes = r.getBytes(size)
+ CUnsignedBigInt(BigIntegers.fromUnsignedByteArray(valueBytes))
case SGroupElement =>
CGroupElement(GroupElementSerializer.parse(r))
case SSigmaProp =>
diff --git a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala
index 1936bbcd9a..aa5d43e229 100644
--- a/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala
+++ b/core/shared/src/main/scala/sigma/serialization/TypeSerializer.scala
@@ -242,6 +242,16 @@ class TypeSerializer {
object TypeSerializer extends TypeSerializer {
/** The list of embeddable types, i.e. types that can be combined with type constructor for optimized encoding.
* For each embeddable type `T`, and type constructor `C`, the type `C[T]` can be represented by single byte. */
- val embeddableIdToType = Array[SType](null, SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp)
+ def embeddableIdToType = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ embeddableV6
+ } else {
+ embeddableV5
+ }
+ }
+
+ private val embeddableV5 = Array[SType](null, SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp)
+
+ private val embeddableV6 = Array[SType](null, SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnsignedBigInt)
}
\ No newline at end of file
diff --git a/core/shared/src/main/scala/sigma/util/Extensions.scala b/core/shared/src/main/scala/sigma/util/Extensions.scala
index 624b3f5d6b..e97241ca3d 100644
--- a/core/shared/src/main/scala/sigma/util/Extensions.scala
+++ b/core/shared/src/main/scala/sigma/util/Extensions.scala
@@ -204,7 +204,7 @@ object Extensions {
* not exactly fit in a 256 bit range.
* @see BigInteger#longValueExact
*/
- @inline final def to256BitValueExact: BigInteger = {
+ @inline final def toSignedBigIntValueExact: BigInteger = {
// Comparing with 255 is correct because bitLength() method excludes the sign bit.
// For example, these are the boundary values:
// (new BigInteger("80" + "00" * 31, 16)).bitLength() = 256
@@ -217,8 +217,24 @@ object Extensions {
throw new ArithmeticException("BigInteger out of 256 bit range");
}
+ @inline final def toUnsignedBigIntValueExact: BigInteger = {
+ if (x.compareTo(BigInteger.ZERO) >= 0 && x.bitLength() <= 256) {
+ x
+ } else {
+ throw new ArithmeticException("Unsigned BigInteger out of 256 bit range or negative")
+ }
+ }
+
/** Converts `x` to [[sigma.BigInt]] */
def toBigInt: sigma.BigInt = CBigInt(x)
+
+ /** Converts `x` to [[sigma.UnsignedBigInt]] */
+ def toUnsignedBigInt: sigma.UnsignedBigInt = {
+ if(x.compareTo(BigInteger.ZERO) < 0){
+ throw new IllegalArgumentException("toUnsignedBigInt arg < 0")
+ }
+ CUnsignedBigInt(x)
+ }
}
implicit class BigIntOps(val x: sigma.BigInt) extends AnyVal {
diff --git a/core/shared/src/test/scala/sigma/VersionTesting.scala b/core/shared/src/test/scala/sigma/VersionTesting.scala
index 08053a6c48..a73452a838 100644
--- a/core/shared/src/test/scala/sigma/VersionTesting.scala
+++ b/core/shared/src/test/scala/sigma/VersionTesting.scala
@@ -72,8 +72,9 @@ trait VersionTesting {
protected def testFun_Run(testName: String, testFun: => Any): Unit = {
def msg = s"""property("$testName")(ActivatedVersion = $activatedVersionInTests; ErgoTree version = $ergoTreeVersionInTests)"""
if (printVersions) println(msg)
- try testFun
- catch {
+ try {
+ testFun
+ } catch {
case t: Throwable =>
if (!printVersions) {
// wasn't printed, print it now
diff --git a/data/js/src/main/scala/sigma/Platform.scala b/data/js/src/main/scala/sigma/Platform.scala
index 29c761c3f1..2fd4c937f0 100644
--- a/data/js/src/main/scala/sigma/Platform.scala
+++ b/data/js/src/main/scala/sigma/Platform.scala
@@ -28,6 +28,7 @@ object Platform {
case v: Long => Nullable(mkConstant[SLong.type](v, SLong))
case v: BigInteger => Nullable(mkConstant[SBigInt.type](CBigInt(v), SBigInt))
case n: sigma.BigInt => Nullable(mkConstant[SBigInt.type](n, SBigInt))
+ case n: sigma.UnsignedBigInt => Nullable(mkConstant[SUnsignedBigInt.type](n, SUnsignedBigInt))
case ge: GroupElement => Nullable(mkConstant[SGroupElement.type](ge, SGroupElement))
case b: Boolean => Nullable(if (b) TrueLeaf else FalseLeaf)
case v: String => Nullable(mkConstant[SString.type](v, SString))
diff --git a/data/js/src/main/scala/sigma/js/Value.scala b/data/js/src/main/scala/sigma/js/Value.scala
index a65156bd43..1fedb30250 100644
--- a/data/js/src/main/scala/sigma/js/Value.scala
+++ b/data/js/src/main/scala/sigma/js/Value.scala
@@ -81,6 +81,9 @@ object Value extends js.Object {
case sigma.BigIntRType =>
val v = data.asInstanceOf[js.BigInt]
CBigInt(new BigInteger(v.toString(16), 16))
+ case sigma.UnsignedBigIntRType =>
+ val v = data.asInstanceOf[js.BigInt]
+ CUnsignedBigInt(new BigInteger(v.toString(16), 16))
case sigma.GroupElementRType =>
val ge = data.asInstanceOf[GroupElement]
CGroupElement(ge.point)
@@ -121,6 +124,9 @@ object Value extends js.Object {
case sigma.BigIntRType =>
val hex = value.asInstanceOf[sigma.BigInt].toBigInteger.toString(10)
js.BigInt(hex)
+ case sigma.UnsignedBigIntRType =>
+ val hex = value.asInstanceOf[sigma.BigInt].toBigInteger.toString(10)
+ js.BigInt(hex)
case sigma.GroupElementRType =>
val point = value.asInstanceOf[CGroupElement].wrappedValue.asInstanceOf[Platform.Ecp]
new GroupElement(point)
@@ -158,6 +164,8 @@ object Value extends js.Object {
n
case sigma.BigIntRType =>
data.asInstanceOf[js.BigInt]
+ case sigma.UnsignedBigIntRType =>
+ data.asInstanceOf[js.BigInt]
case sigma.GroupElementRType =>
data.asInstanceOf[GroupElement]
case sigma.SigmaPropRType =>
diff --git a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala
index 5226d645ce..c88366d82b 100644
--- a/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala
+++ b/data/shared/src/main/scala/sigma/ast/SigmaPredef.scala
@@ -203,6 +203,22 @@ object SigmaPredef {
Seq(ArgInfo("", "")))
)
+ val UBigIntFromStringFunc = PredefinedFunc("unsignedBigInt",
+ Lambda(Array("input" -> SString), SUnsignedBigInt, None),
+ PredefFuncInfo(
+ { case (_, Seq(arg: EvaluatedValue[SString.type]@unchecked)) =>
+ val bi = new BigInteger(arg.value)
+ if (bi.compareTo(BigInteger.ZERO) >= 0) {
+ UnsignedBigIntConstant(bi)
+ } else {
+ throw new InvalidArguments(s"Negative argument for unsignedBigInt()")
+ }
+ }),
+ OperationInfo(Constant,
+ """Parsing string literal argument as a 256-bit unsigned big integer.""".stripMargin,
+ Seq(ArgInfo("", "")))
+ )
+
val FromBase16Func = PredefinedFunc("fromBase16",
Lambda(Array("input" -> SString), SByteArray, None),
PredefFuncInfo(
@@ -458,7 +474,7 @@ object SigmaPredef {
val resType = u.opType.tRange.asInstanceOf[SFunc].tRange
MethodCall(
Global,
- SGlobalMethods.fromBigEndianBytesMethod.withConcreteTypes(Map(tT -> resType)),
+ SGlobalMethods.FromBigEndianBytesMethod.withConcreteTypes(Map(tT -> resType)),
args.toIndexedSeq,
Map(tT -> resType)
)
@@ -483,6 +499,7 @@ object SigmaPredef {
GetVarFunc,
DeserializeFunc,
BigIntFromStringFunc,
+ UBigIntFromStringFunc,
FromBase16Func,
FromBase64Func,
FromBase58Func,
diff --git a/data/shared/src/main/scala/sigma/ast/methods.scala b/data/shared/src/main/scala/sigma/ast/methods.scala
index 65546c1888..a69654de7e 100644
--- a/data/shared/src/main/scala/sigma/ast/methods.scala
+++ b/data/shared/src/main/scala/sigma/ast/methods.scala
@@ -2,6 +2,7 @@ package sigma.ast
import org.ergoplatform._
import org.ergoplatform.validation._
+import sigma.{UnsignedBigInt, _}
import sigma.{Coll, VersionContext, _}
import sigma.Evaluation.stypeToRType
import sigma._
@@ -14,6 +15,8 @@ import sigma.ast.syntax.{SValue, ValueOps}
import sigma.data.ExactIntegral.{ByteIsExactIntegral, IntIsExactIntegral, LongIsExactIntegral, ShortIsExactIntegral}
import sigma.data.NumericOps.BigIntIsExactIntegral
import sigma.data.OverloadHack.Overloaded1
+import sigma.data.UnsignedBigIntNumericOps.UnsignedBigIntIsExactIntegral
+import sigma.data.{DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants}
import sigma.data.{CBigInt, DataValueComparer, KeyValueColl, Nullable, RType, SigmaConstants}
import sigma.eval.{CostDetails, ErgoTreeEvaluator, TracedCost}
import sigma.pow.Autolykos2PowValidation
@@ -99,7 +102,7 @@ sealed trait MethodsContainer {
}
object MethodsContainer {
- private val containers = new SparseArrayContainer[MethodsContainer](Array(
+ private val methodsV5 = Array(
SByteMethods,
SShortMethods,
SIntMethods,
@@ -120,11 +123,29 @@ object MethodsContainer {
STupleMethods,
SUnitMethods,
SAnyMethods
- ).map(m => (m.typeId, m)))
+ )
+
+ private val methodsV6 = methodsV5 ++ Seq(SUnsignedBigIntMethods)
+
+ private val containersV5 = new SparseArrayContainer[MethodsContainer](methodsV5.map(m => (m.typeId, m)))
+
+ private val containersV6 = new SparseArrayContainer[MethodsContainer](methodsV6.map(m => (m.typeId, m)))
- def contains(typeId: TypeCode): Boolean = containers.contains(typeId)
+ def contains(typeId: TypeCode): Boolean = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ containersV6.contains(typeId)
+ } else {
+ containersV5.contains(typeId)
+ }
+ }
- def apply(typeId: TypeCode): MethodsContainer = containers(typeId)
+ def apply(typeId: TypeCode): MethodsContainer = {
+ if (VersionContext.current.isV6SoftForkActivated) {
+ containersV6(typeId)
+ } else {
+ containersV5(typeId)
+ }
+ }
/** Finds the method of the give type.
*
@@ -136,7 +157,11 @@ object MethodsContainer {
case tup: STuple =>
STupleMethods.getTupleMethod(tup, methodName)
case _ =>
- containers.get(tpe.typeCode).flatMap(_.method(methodName))
+ if (VersionContext.current.isV6SoftForkActivated) {
+ containersV6.get(tpe.typeCode).flatMap(_.method(methodName))
+ } else {
+ containersV5.get(tpe.typeCode).flatMap(_.method(methodName))
+ }
}
}
@@ -252,6 +277,7 @@ object SNumericTypeMethods extends MethodsContainer {
case SIntMethods => IntIsExactIntegral.toBigEndianBytes(obj.asInstanceOf[Int])
case SLongMethods => LongIsExactIntegral.toBigEndianBytes(obj.asInstanceOf[Long])
case SBigIntMethods => obj.asInstanceOf[BigInt].toBytes
+ case SUnsignedBigIntMethods => obj.asInstanceOf[UnsignedBigInt].toBytes
}
})
.withInfo(PropertyCall,
@@ -274,6 +300,7 @@ object SNumericTypeMethods extends MethodsContainer {
case SIntMethods => IntIsExactIntegral.toBits(obj.asInstanceOf[Int])
case SLongMethods => LongIsExactIntegral.toBits(obj.asInstanceOf[Long])
case SBigIntMethods => BigIntIsExactIntegral.toBits(obj.asInstanceOf[BigInt])
+ case SUnsignedBigIntMethods => UnsignedBigIntIsExactIntegral.toBits(obj.asInstanceOf[UnsignedBigInt])
}
})
.withInfo(PropertyCall,
@@ -294,6 +321,7 @@ object SNumericTypeMethods extends MethodsContainer {
case SIntMethods => IntIsExactIntegral.bitwiseInverse(obj.asInstanceOf[Int])
case SLongMethods => LongIsExactIntegral.bitwiseInverse(obj.asInstanceOf[Long])
case SBigIntMethods => BigIntIsExactIntegral.bitwiseInverse(obj.asInstanceOf[BigInt])
+ case SUnsignedBigIntMethods => UnsignedBigIntIsExactIntegral.bitwiseInverse(obj.asInstanceOf[UnsignedBigInt])
}
})
.withInfo(PropertyCall, desc = "Returns bitwise inverse of this numeric. ")
@@ -308,6 +336,7 @@ object SNumericTypeMethods extends MethodsContainer {
case SIntMethods => IntIsExactIntegral.bitwiseOr(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
case SLongMethods => LongIsExactIntegral.bitwiseOr(obj.asInstanceOf[Long], other.head.asInstanceOf[Long])
case SBigIntMethods => BigIntIsExactIntegral.bitwiseOr(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt])
+ case SUnsignedBigIntMethods => UnsignedBigIntIsExactIntegral.bitwiseOr(obj.asInstanceOf[UnsignedBigInt], other.head.asInstanceOf[UnsignedBigInt])
}
})
.withInfo(MethodCall,
@@ -324,6 +353,7 @@ object SNumericTypeMethods extends MethodsContainer {
case SIntMethods => IntIsExactIntegral.bitwiseAnd(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
case SLongMethods => LongIsExactIntegral.bitwiseAnd(obj.asInstanceOf[Long], other.head.asInstanceOf[Long])
case SBigIntMethods => BigIntIsExactIntegral.bitwiseAnd(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt])
+ case SUnsignedBigIntMethods => UnsignedBigIntIsExactIntegral.bitwiseAnd(obj.asInstanceOf[UnsignedBigInt], other.head.asInstanceOf[UnsignedBigInt])
}
})
.withInfo(MethodCall,
@@ -340,6 +370,7 @@ object SNumericTypeMethods extends MethodsContainer {
case SIntMethods => IntIsExactIntegral.bitwiseXor(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
case SLongMethods => LongIsExactIntegral.bitwiseXor(obj.asInstanceOf[Long], other.head.asInstanceOf[Long])
case SBigIntMethods => BigIntIsExactIntegral.bitwiseXor(obj.asInstanceOf[BigInt], other.head.asInstanceOf[BigInt])
+ case SUnsignedBigIntMethods => UnsignedBigIntIsExactIntegral.bitwiseXor(obj.asInstanceOf[UnsignedBigInt], other.head.asInstanceOf[UnsignedBigInt])
}
})
.withInfo(MethodCall,
@@ -356,6 +387,7 @@ object SNumericTypeMethods extends MethodsContainer {
case SIntMethods => IntIsExactIntegral.shiftLeft(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
case SLongMethods => LongIsExactIntegral.shiftLeft(obj.asInstanceOf[Long], other.head.asInstanceOf[Int])
case SBigIntMethods => BigIntIsExactIntegral.shiftLeft(obj.asInstanceOf[BigInt], other.head.asInstanceOf[Int])
+ case SUnsignedBigIntMethods => UnsignedBigIntIsExactIntegral.shiftLeft(obj.asInstanceOf[UnsignedBigInt], other.head.asInstanceOf[Int])
}
})
.withInfo(MethodCall,
@@ -375,6 +407,7 @@ object SNumericTypeMethods extends MethodsContainer {
case SIntMethods => IntIsExactIntegral.shiftRight(obj.asInstanceOf[Int], other.head.asInstanceOf[Int])
case SLongMethods => LongIsExactIntegral.shiftRight(obj.asInstanceOf[Long], other.head.asInstanceOf[Int])
case SBigIntMethods => BigIntIsExactIntegral.shiftRight(obj.asInstanceOf[BigInt], other.head.asInstanceOf[Int])
+ case SUnsignedBigIntMethods => UnsignedBigIntIsExactIntegral.shiftRight(obj.asInstanceOf[UnsignedBigInt], other.head.asInstanceOf[Int])
}
})
.withInfo(MethodCall,
@@ -473,14 +506,25 @@ case object SBigIntMethods extends SNumericTypeMethods {
/** Type for which this container defines methods. */
override def ownerType: SMonoType = SBigInt
+ private val ToUnsignedCostKind = FixedCost(JitCost(5))
+
+ //id = 8 to make it after toBits
+ val ToUnsigned = SMethod(this, "toUnsigned", SFunc(this.ownerType, SUnsignedBigInt), 14, ToUnsignedCostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall,
+ "Converts non-negative big integer to unsigned type, throws exception on negative big integer.")
+
+ private val ToUnsignedModCostKind = FixedCost(JitCost(15))
+
+ val ToUnsignedMod = SMethod(this, "toUnsignedMod", SFunc(Array(this.ownerType, SUnsignedBigInt), SUnsignedBigInt), 15, ToUnsignedModCostKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall,
+ "Converts non-negative big integer to unsigned type using cryptographic mod operation.",
+ ArgInfo("m", "modulo value"))
+
protected override def getMethods(): Seq[SMethod] = {
if (VersionContext.current.isV6SoftForkActivated) {
- super.getMethods()
- // ModQMethod,
- // PlusModQMethod,
- // MinusModQMethod,
- // TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
- // MultModQMethod,
+ super.getMethods() ++ Seq(ToUnsigned, ToUnsignedMod)
} else {
super.getMethods()
}
@@ -488,6 +532,64 @@ case object SBigIntMethods extends SNumericTypeMethods {
}
+/** Methods of UnsignedBigInt type. Implemented using [[java.math.BigInteger]]. */
+case object SUnsignedBigIntMethods extends SNumericTypeMethods {
+ /** Type for which this container defines methods. */
+ override def ownerType: SMonoType = SUnsignedBigInt
+
+ final val ModInverseCostInfo = OperationCostInfo(FixedCost(JitCost(30)), NamedDesc("ModInverseMethodCall"))
+
+ val ModInverseMethod = SMethod(this, "modInverse", SFunc(Array(this.ownerType, this.ownerType), this.ownerType), 14, ModInverseCostInfo.costKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall,
+ "Computes modular inverse of a value. Modular inverse of A mod C is the B value that makes A * B mod C = 1.",
+ ArgInfo("m", "modulo value")
+ )
+
+ final val PlusModCostInfo = OperationCostInfo(FixedCost(JitCost(30)), NamedDesc("ModInverseMethodCall"))
+
+ val PlusModMethod = SMethod(this, "plusMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 15, PlusModCostInfo.costKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Modular addition", ArgInfo("that", "Addend") , ArgInfo("m", "modulo value"))
+
+ final val SubtractModCostInfo = OperationCostInfo(FixedCost(JitCost(30)), NamedDesc("SubtractModMethodCall"))
+
+ val SubtractModMethod = SMethod(this, "subtractMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 16, SubtractModCostInfo.costKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Modular subtraction", ArgInfo("that", "Subtrahend") , ArgInfo("m", "modulo value"))
+
+ final val MultiplyModCostInfo = OperationCostInfo(FixedCost(JitCost(40)), NamedDesc("MultiplyModMethodCall"))
+
+ val MultiplyModMethod = SMethod(this, "multiplyMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 17, MultiplyModCostInfo.costKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Modular multiplication", ArgInfo("that", "Multiplier") , ArgInfo("m", "modulo value"))
+
+ final val ModCostInfo = OperationCostInfo(FixedCost(JitCost(20)), NamedDesc("ModMethodCall"))
+
+ val ModMethod = SMethod(this, "mod", SFunc(Array(this.ownerType, this.ownerType), this.ownerType), 18, ModCostInfo.costKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Cryptographic modulo operation", ArgInfo("m", "Modulo value"))
+
+ final val ToSignedCostInfo = OperationCostInfo(FixedCost(JitCost(10)), NamedDesc("ToSignedMethodCall"))
+
+ val ToSignedMethod = SMethod(this, "toSigned", SFunc(Array(this.ownerType), SBigInt), 19, ToSignedCostInfo.costKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo(MethodCall, "Convert this unsigned big int to signed (with possible exception if leftmost bit is set to 1).")
+
+ // no 6.0 versioning here as it is done in method containers
+ protected override def getMethods(): Seq[SMethod] = {
+ super.getMethods() ++ Seq(
+ ModInverseMethod,
+ PlusModMethod,
+ SubtractModMethod,
+ MultiplyModMethod,
+ ModMethod,
+ ToSignedMethod
+ )
+ }
+
+}
+
/** Methods of type `String`. */
case object SStringMethods extends MonoTypeMethods {
/** Type for which this container defines methods. */
@@ -517,6 +619,12 @@ case object SGroupElementMethods extends MonoTypeMethods {
"Exponentiate this \\lst{GroupElement} to the given number. Returns this to the power of k",
ArgInfo("k", "The power"))
+ lazy val ExponentiateUnsignedMethod: SMethod = SMethod(
+ this, "expUnsigned", SFunc(Array(this.ownerType, SUnsignedBigInt), this.ownerType), 6, Exponentiate.costKind)
+ .withIRInfo(MethodCallIrBuilder)
+ .withInfo("Exponentiate this \\lst{GroupElement} to the given number. Returns this to the power of k",
+ ArgInfo("k", "The power"))
+
lazy val MultiplyMethod: SMethod = SMethod(
this, "multiply", SFunc(Array(this.ownerType, SGroupElement), this.ownerType), 4, MultiplyGroup.costKind)
.withIRInfo({ case (builder, obj, _, Seq(arg), _) =>
@@ -532,16 +640,24 @@ case object SGroupElementMethods extends MonoTypeMethods {
.withIRInfo(MethodCallIrBuilder)
.withInfo(PropertyCall, "Inverse element of the group.")
- protected override def getMethods(): Seq[SMethod] = super.getMethods() ++ Seq(
+ protected override def getMethods(): Seq[SMethod] = {
/* TODO soft-fork: https://github.com/ScorexFoundation/sigmastate-interpreter/issues/479
SMethod(this, "isIdentity", SFunc(this, SBoolean), 1)
.withInfo(PropertyCall, "Checks if this value is identity element of the eliptic curve group."),
*/
- GetEncodedMethod,
- ExponentiateMethod,
- MultiplyMethod,
- NegateMethod
- )
+ val v5Methods = Seq(
+ GetEncodedMethod,
+ ExponentiateMethod,
+ MultiplyMethod,
+ NegateMethod)
+
+ super.getMethods() ++ (if (VersionContext.current.isV6SoftForkActivated) {
+ v5Methods ++ Seq(ExponentiateUnsignedMethod)
+ } else {
+ v5Methods
+ })
+ }
+
}
/** Methods of type `SigmaProp` which represent sigma-protocol propositions. */
@@ -864,7 +980,7 @@ object SCollectionMethods extends MethodsContainer with MethodByNameUnapply {
| \lst{f} to each element of this collection and concatenating the results.
""".stripMargin, ArgInfo("f", "the function to apply to each element."))
- /** We assume all flatMap body patterns have similar executon cost. */
+ /** We assume all flatMap body patterns have similar execution cost. */
final val CheckFlatmapBody_Info = OperationCostInfo(
PerItemCost(baseCost = JitCost(20), perChunkCost = JitCost(20), chunkSize = 1),
NamedDesc("CheckFlatmapBody"))
@@ -1868,7 +1984,7 @@ case object SGlobalMethods extends MonoTypeMethods {
private val BigEndianBytesCostKind = FixedCost(JitCost(10))
// id = 4 is reserved for deserializeTo ()
- lazy val fromBigEndianBytesMethod = SMethod(
+ lazy val FromBigEndianBytesMethod = SMethod(
this, "fromBigEndianBytes", SFunc(Array(SGlobal, SByteArray), tT, Array(paramT)), 5, BigEndianBytesCostKind, Seq(tT))
.withIRInfo(MethodCallIrBuilder,
javaMethodOf[SigmaDslBuilder, Coll[Byte], RType[_]]("fromBigEndianBytes"),
@@ -1954,7 +2070,7 @@ case object SGlobalMethods extends MonoTypeMethods {
deserializeToMethod,
encodeNBitsMethod,
decodeNBitsMethod,
- fromBigEndianBytesMethod,
+ FromBigEndianBytesMethod,
someMethod,
noneMethod
)
diff --git a/data/shared/src/main/scala/sigma/ast/syntax.scala b/data/shared/src/main/scala/sigma/ast/syntax.scala
index 5a257481cb..a20c7dd274 100644
--- a/data/shared/src/main/scala/sigma/ast/syntax.scala
+++ b/data/shared/src/main/scala/sigma/ast/syntax.scala
@@ -40,6 +40,7 @@ object syntax {
type LongConstant = Constant[SLong.type]
type StringConstant = Constant[SString.type]
type BigIntConstant = Constant[SBigInt.type]
+ type UnsignedBigIntConstant = Constant[SUnsignedBigInt.type]
type BoxConstant = Constant[SBox.type]
type GroupElementConstant = Constant[SGroupElement.type]
type SigmaPropConstant = Constant[SSigmaProp.type]
diff --git a/data/shared/src/main/scala/sigma/ast/trees.scala b/data/shared/src/main/scala/sigma/ast/trees.scala
index fb9f84288e..4195ca1b2d 100644
--- a/data/shared/src/main/scala/sigma/ast/trees.scala
+++ b/data/shared/src/main/scala/sigma/ast/trees.scala
@@ -15,6 +15,7 @@ import sigma.serialization.CoreByteWriter.ArgInfo
import sigma.validation.SigmaValidationSettings
import sigma.{Coll, Colls, GroupElement, SigmaProp, VersionContext}
import NumericOps.{BigIntIsExactIntegral, BigIntIsExactOrdering}
+import sigma.data.UnsignedBigIntNumericOps.{UnsignedBigIntIsExactIntegral, UnsignedBigIntIsExactOrdering}
import sigma.eval.ErgoTreeEvaluator.DataEnv
import sigma.eval.Extensions.EvalCollOps
import sigma.eval.{ErgoTreeEvaluator, SigmaDsl}
@@ -640,7 +641,7 @@ case class SubstConstants[T <: SType](scriptBytes: Value[SByteArray], positions:
val (newBytes, nConstants) = SubstConstants.eval(
scriptBytes = scriptBytesV.toArray,
positions = positionsV.toArray,
- newVals = typedNewVals)(SigmaDsl.validationSettings)
+ newVals = typedNewVals)
res = Colls.fromArray(newBytes)
nConstants
@@ -671,7 +672,7 @@ object SubstConstants extends ValueCompanion {
*/
def eval(scriptBytes: Array[Byte],
positions: Array[Int],
- newVals: Array[Constant[SType]])(implicit vs: SigmaValidationSettings): (Array[Byte], Int) =
+ newVals: Array[Constant[SType]]): (Array[Byte], Int) =
ErgoTreeSerializer.DefaultSerializer.substituteConstants(scriptBytes, positions, newVals)
}
@@ -863,7 +864,8 @@ object ArithOp {
SShort -> new OperationImpl(ShortIsExactIntegral, ShortIsExactOrdering, SShort),
SInt -> new OperationImpl(IntIsExactIntegral, IntIsExactOrdering, SInt),
SLong -> new OperationImpl(LongIsExactIntegral, LongIsExactOrdering, SLong),
- SBigInt -> new OperationImpl(BigIntIsExactIntegral, BigIntIsExactOrdering, SBigInt)
+ SBigInt -> new OperationImpl(BigIntIsExactIntegral, BigIntIsExactOrdering, SBigInt),
+ SUnsignedBigInt -> new OperationImpl(UnsignedBigIntIsExactIntegral, UnsignedBigIntIsExactOrdering, SUnsignedBigInt)
).map { case (t, n) => (t.typeCode, n) })
/** Returns operation name for the given opCode. */
diff --git a/data/shared/src/main/scala/sigma/ast/values.scala b/data/shared/src/main/scala/sigma/ast/values.scala
index ff5da32ec7..b50bf70e18 100644
--- a/data/shared/src/main/scala/sigma/ast/values.scala
+++ b/data/shared/src/main/scala/sigma/ast/values.scala
@@ -8,7 +8,7 @@ import sigma.ast.TypeCodes.ConstantCode
import sigma.ast.syntax._
import sigma.crypto.{CryptoConstants, EcPointType}
import sigma.data.OverloadHack.Overloaded1
-import sigma.data.{CSigmaDslBuilder, CSigmaProp, Nullable, RType, SigmaBoolean}
+import sigma.data.{CSigmaDslBuilder, CSigmaProp, CUnsignedBigInt, Nullable, RType, SigmaBoolean}
import sigma.eval.ErgoTreeEvaluator.DataEnv
import sigma.eval.{ErgoTreeEvaluator, SigmaDsl}
import sigma.exceptions.InterpreterException
@@ -499,6 +499,20 @@ object BigIntConstant {
def apply(value: Long): Constant[SBigInt.type] = Constant[SBigInt.type](SigmaDsl.BigInt(BigInteger.valueOf(value)), SBigInt)
}
+object UnsignedBigIntConstant {
+ def apply(value: UnsignedBigInt): Constant[SUnsignedBigInt.type] = {
+ Constant[SUnsignedBigInt.type](value, SUnsignedBigInt)
+ }
+
+ def apply(value: BigInteger): Constant[SUnsignedBigInt.type] = {
+ Constant[SUnsignedBigInt.type](CUnsignedBigInt(value), SUnsignedBigInt)
+ }
+
+ def apply(value: Long): Constant[SUnsignedBigInt.type] = {
+ Constant[SUnsignedBigInt.type](CUnsignedBigInt(BigInteger.valueOf(value)), SUnsignedBigInt)
+ }
+}
+
object StringConstant {
def apply(value: String): Constant[SString.type] = Constant[SString.type](value, SString)
diff --git a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala
index 8d272439f4..d849479a17 100644
--- a/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala
+++ b/data/shared/src/main/scala/sigma/data/BigIntegerOps.scala
@@ -13,6 +13,11 @@ object OrderingOps {
def compare(x: BigInt, y: BigInt) = x.compareTo(y)
}
implicit object BigIntOrdering extends BigIntOrdering
+
+ trait UnsignedBigIntOrdering extends Ordering[UnsignedBigInt] {
+ def compare(x: UnsignedBigInt, y: UnsignedBigInt) = x.compareTo(y)
+ }
+ implicit object UnsignedBigIntOrdering extends UnsignedBigIntOrdering
}
object NumericOps {
diff --git a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala
index 6e1ef54616..6e599a3605 100644
--- a/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala
+++ b/data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala
@@ -6,11 +6,12 @@ import org.ergoplatform.validation.ValidationRules
import scorex.crypto.hash.{Blake2b256, Sha256}
import scorex.util.serialization.VLQByteBufferReader
import scorex.utils.{Ints, Longs}
-import sigma.ast.{AtLeast, SBigInt, SubstConstants}
+import sigma.ast.{AtLeast, SBigInt, SType, SUnsignedBigInt, SubstConstants}
import scorex.utils.Longs
import sigma.Evaluation.rtypeToSType
import sigma.ast.{AtLeast, SType, SubstConstants}
import sigma.crypto.{CryptoConstants, EcPointType, Ecp}
+import sigma.crypto.{BigIntegers, CryptoConstants, EcPointType, Ecp}
import sigma.eval.Extensions.EvalCollOps
import sigma.serialization.{ConstantStore, DataSerializer, GroupElementSerializer, SigmaByteReader, SigmaSerializer}
import sigma.serialization.{DataSerializer, GroupElementSerializer, SigmaSerializer}
@@ -20,6 +21,7 @@ import sigma.util.Extensions.BigIntegerOps
import sigma.util.NBitsUtils
import sigma.validation.SigmaValidationSettings
import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, Evaluation, GroupElement, SigmaDslBuilder, SigmaProp, VersionContext}
+import sigma.{AvlTree, BigInt, Box, Coll, CollBuilder, GroupElement, SigmaDslBuilder, SigmaProp, UnsignedBigInt, VersionContext}
import java.math.BigInteger
import java.nio.ByteBuffer
@@ -29,12 +31,13 @@ import java.nio.ByteBuffer
* @see [[SigmaDslBuilder]] for detailed descriptions
*/
class CSigmaDslBuilder extends SigmaDslBuilder { dsl =>
- implicit val validationSettings: SigmaValidationSettings = ValidationRules.currentSettings
override val Colls: CollBuilder = sigma.Colls
override def BigInt(n: BigInteger): BigInt = CBigInt(n)
+ override def UnsignedBigInt(n: BigInteger): UnsignedBigInt = CUnsignedBigInt(n)
+
override def toBigInteger(n: BigInt): BigInteger = n.asInstanceOf[CBigInt].wrappedValue
/** Wraps the given elliptic curve point into GroupElement type. */
@@ -158,7 +161,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl =>
}
override def byteArrayToBigInt(bytes: Coll[Byte]): BigInt = {
- val bi = new BigInteger(bytes.toArray).to256BitValueExact
+ val bi = new BigInteger(bytes.toArray).toSignedBigIntValueExact
this.BigInt(bi)
}
@@ -208,7 +211,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl =>
case e: Throwable =>
throw new RuntimeException(s"Cannot evaluate substConstants($scriptBytes, $positions, $newValues)", e)
}
- val (res, _) = SubstConstants.eval(scriptBytes.toArray, positions.toArray, constants)(validationSettings)
+ val (res, _) = SubstConstants.eval(scriptBytes.toArray, positions.toArray, constants)
Colls.fromArray(res)
}
@@ -246,8 +249,12 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl =>
if (bytes.length > SBigInt.MaxSizeInBytes) {
throw SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes in fromBigEndianBytes")
}
- CBigInt(new BigInteger(bytes.toArray).to256BitValueExact).asInstanceOf[T]
- // todo: UnsignedBitInt
+ CBigInt(new BigInteger(bytes.toArray).toSignedBigIntValueExact).asInstanceOf[T]
+ case sigma.UnsignedBigIntRType =>
+ if (bytes.length > SUnsignedBigInt.MaxSizeInBytes) {
+ throw SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes in fromBigEndianBytes")
+ }
+ CUnsignedBigInt(BigIntegers.fromUnsignedByteArray(bytes.toArray)).asInstanceOf[T]
case _ => throw new IllegalArgumentException("Unsupported type provided in fromBigEndianBytes")
}
}
diff --git a/data/shared/src/main/scala/sigma/data/DataValueComparer.scala b/data/shared/src/main/scala/sigma/data/DataValueComparer.scala
index 21ca85012f..d44f3f8d68 100644
--- a/data/shared/src/main/scala/sigma/data/DataValueComparer.scala
+++ b/data/shared/src/main/scala/sigma/data/DataValueComparer.scala
@@ -139,6 +139,7 @@ object DataValueComparer {
val descriptors: AVHashMap[RType[_], (OperationCostInfo[FixedCost], OperationCostInfo[PerItemCost])] =
AVHashMap.fromSeq(Array[(RType[_], (OperationCostInfo[FixedCost], OperationCostInfo[PerItemCost]))](
(BigIntRType, (EQ_BigInt, EQ_COA_BigInt)),
+ (UnsignedBigIntRType, (EQ_BigInt, EQ_COA_BigInt)),
(GroupElementRType, (EQ_GroupElement, EQ_COA_GroupElement)),
(AvlTreeRType, (EQ_AvlTree, EQ_COA_AvlTree)),
(BoxRType, (EQ_Box, EQ_COA_Box)),
@@ -344,6 +345,11 @@ object DataValueComparer {
okEqual = bi == r
}
+ case ubi: UnsignedBigInt => /** case 5 (see [[EQ_BigInt]]) */
+ E.addFixedCost(EQ_BigInt) {
+ okEqual = ubi == r
+ }
+
case sp1: SigmaProp =>
E.addCost(MatchType) // for second match below
okEqual = r match {
diff --git a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala
index 86a9bfffce..8adebc36d6 100644
--- a/data/shared/src/main/scala/sigma/data/ExactIntegral.scala
+++ b/data/shared/src/main/scala/sigma/data/ExactIntegral.scala
@@ -3,7 +3,7 @@ package sigma.data
import sigma.{Coll, Colls}
import sigma.util.Extensions.{ByteOps, ShortOps}
-/** Type-class which defines the operations on Integral types (Byte, Short, Int, Long, BigInt)
+/** Type-class which defines the operations on Integral types (Byte, Short, Int, Long, BigInt, UnsignedBigInt)
* with overflow checks.
*
* An exception is raised when an overflow is detected.
diff --git a/data/shared/src/main/scala/sigma/data/UnsignedBigIntegerOps.scala b/data/shared/src/main/scala/sigma/data/UnsignedBigIntegerOps.scala
new file mode 100644
index 0000000000..e628703deb
--- /dev/null
+++ b/data/shared/src/main/scala/sigma/data/UnsignedBigIntegerOps.scala
@@ -0,0 +1,156 @@
+package sigma.data
+
+import debox.cfor
+import scorex.util.encode.Base16
+import sigma._
+import sigma.crypto.BigIntegers
+import sigma.data.UnsignedBigIntOrderingOps.UnsignedBigIntOrdering
+import sigma.eval.Extensions.IntExt
+
+import scala.math.{Integral, Ordering}
+
+object UnsignedBigIntOrderingOps {
+ def apply[T](implicit ord: Ordering[T]) = ord
+
+ trait UnsignedBigIntOrdering extends Ordering[UnsignedBigInt] {
+ def compare(x: UnsignedBigInt, y: UnsignedBigInt) = x.compareTo(y)
+ }
+ implicit object UnsignedBigIntOrdering extends UnsignedBigIntOrdering
+}
+
+object UnsignedBigIntNumericOps {
+
+ /** Base implementation of Integral methods for UnsignedBigInt. */
+ trait UnsignedBigIntIsIntegral extends Integral[UnsignedBigInt] {
+ /** This method should not be used in v4.x */
+ def quot(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.divide(y)
+
+ /** This method is used in ErgoTreeEvaluator based interpreter, to implement
+ * '%' operation of ErgoTree (i.e. `%: (T, T) => T` operation) for all
+ * numeric types T including BigInt.
+ *
+ * In the v4.x interpreter, however, the `%` operation is implemented using
+ * [[CBigInt]].mod method , which delegates to [[java.math.BigInteger]].mod method.
+ *
+ * Even though this method is called `rem`, the semantics of ErgoTree
+ * language requires it to correspond to [[java.math.BigInteger]].mod
+ * method.
+ *
+ * For this reason we define implementation of this `rem` method using
+ * [[BigInt]].mod.
+ *
+ * NOTE: This method should not be used in v4.x
+ */
+ def rem(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.mod(y)
+
+ def plus(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.add(y)
+ def minus(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.subtract(y)
+ def times(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.multiply(y)
+ def negate(x: UnsignedBigInt): UnsignedBigInt = ???
+ def fromInt(x: Int): UnsignedBigInt = x.toUnsignedBigInt
+ def toInt(x: UnsignedBigInt): Int = x.toInt
+ def toLong(x: UnsignedBigInt): Long = x.toLong
+ def toFloat(x: UnsignedBigInt): Float = x.toFloat
+ def toDouble(x: UnsignedBigInt): Double = x.toDouble
+ }
+
+ /**
+ * The instance of Integral for UnsignedBigInt.
+ * Done similarly to BigIntIsIntegral.
+ */
+ object UnsignedBigIntIsIntegral extends UnsignedBigIntIsIntegral with UnsignedBigIntOrdering {
+ def parseString(str: String): Option[UnsignedBigInt] = ???
+ }
+
+ /** The instance of [[ExactIntegral]] typeclass for [[BigInt]]. */
+ implicit object UnsignedBigIntIsExactIntegral extends ExactIntegral[UnsignedBigInt] {
+ val n = UnsignedBigIntIsIntegral
+ override def plus(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = n.plus(x, y)
+ override def minus(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = n.minus(x, y)
+ override def times(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = n.times(x, y)
+
+ override def quot(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.divide(y)
+
+ /** This method is used in ErgoTreeEvaluator based interpreter, to implement
+ * '%' operation of ErgoTree (i.e. `%: (T, T) => T` operation) for all
+ * numeric types T including BigInt.
+ *
+ * In the v4.x interpreter, however, the `%` operation is implemented using
+ * [[CBigInt]].mod method, which delegates to [[java.math.BigInteger]].mod method.
+ *
+ * Even though this method is called `divisionRemainder`, the semantics of ErgoTree
+ * language requires it to correspond to [[java.math.BigInteger]].mod method.
+ *
+ * For this reason we define implementation of this method using [[BigInt]].mod.
+ *
+ * NOTE: This method should not be used in v4.x
+ */
+ override def divisionRemainder(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = x.mod(y)
+
+ /** Returns a big-endian representation of this value in a collection of bytes.
+ * For example, the `Int` value `0x12131415` would yield the
+ * collection of bytes [0x12, 0x13, 0x14, 0x15]
+ */
+ override def toBigEndianBytes(x: UnsignedBigInt): Coll[Byte] = x.toBytes
+
+ /**
+ * @return a numeric value which is inverse of `x` (every bit is flipped)
+ */
+ override def bitwiseInverse(x: UnsignedBigInt): UnsignedBigInt = x.bitwiseInverse()
+
+ /**
+ * @return a numeric value which is `this | that`
+ */
+ override def bitwiseOr(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = {
+ val vx = x.asInstanceOf[CUnsignedBigInt].wrappedValue
+ val vy = y.asInstanceOf[CUnsignedBigInt].wrappedValue
+ CUnsignedBigInt(vx.or(vy))
+ }
+
+ /**
+ * @return a numeric value which is `this && that`
+ */
+ override def bitwiseAnd(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = {
+ val vx = x.asInstanceOf[CUnsignedBigInt].wrappedValue
+ val vy = y.asInstanceOf[CUnsignedBigInt].wrappedValue
+ CUnsignedBigInt(vx.and(vy))
+ }
+
+ /**
+ * @return a numeric value which is `this xor that`
+ */
+ override def bitwiseXor(x: UnsignedBigInt, y: UnsignedBigInt): UnsignedBigInt = {
+ val vx = x.asInstanceOf[CUnsignedBigInt].wrappedValue
+ val vy = y.asInstanceOf[CUnsignedBigInt].wrappedValue
+ CUnsignedBigInt(vx.xor(vy))
+ }
+
+ /**
+ * @return a value which is (this << n). The shift distance, n, may be negative,
+ * in which case this method performs a right shift. (Computes floor(this * 2n).)
+ */
+ override def shiftLeft(x: UnsignedBigInt, bits: Int): UnsignedBigInt = {
+ if (bits < 0 || bits >= 256) {
+ throw new IllegalArgumentException(s"Wrong argument in UnsignedBigInt.shiftLeft: bits < 0 || bits >= 256 ($bits)")
+ } else {
+ x.shiftLeft(bits)
+ }
+ }
+
+ /**
+ * @return a value which is (this >> n). Sign extension is performed. The shift distance, n,
+ * may be negative, in which case this method performs a left shift. (Computes floor(this / 2n).)
+ */
+ override def shiftRight(x: UnsignedBigInt, bits: Int): UnsignedBigInt = {
+ if (bits < 0 || bits >= 256) {
+ throw new IllegalArgumentException(s"Wrong argument in UnsignedBigInt.shiftLeft: bits < 0 || bits >= 256 ($bits)")
+ } else {
+ x.shiftRight(bits)
+ }
+ }
+ }
+
+ /** The instance of [[scalan.ExactOrdering]] typeclass for [[BigInt]]. */
+ implicit object UnsignedBigIntIsExactOrdering extends ExactOrderingImpl[UnsignedBigInt](UnsignedBigIntIsIntegral)
+}
+
diff --git a/data/shared/src/main/scala/sigma/eval/Extensions.scala b/data/shared/src/main/scala/sigma/eval/Extensions.scala
index def9086e02..520d97377d 100644
--- a/data/shared/src/main/scala/sigma/eval/Extensions.scala
+++ b/data/shared/src/main/scala/sigma/eval/Extensions.scala
@@ -2,7 +2,7 @@ package sigma.eval
import sigma.ast.syntax.SigmaPropValue
import sigma.data.{CAnyValue, CSigmaDslBuilder, Nullable, RType, SigmaBoolean}
-import sigma.{BigInt, Coll, Colls, Evaluation, Platform}
+import sigma.{BigInt, Coll, Colls, Evaluation, Platform, UnsignedBigInt}
import sigma.ast.{Constant, ConstantNode, SBoolean, SCollection, SCollectionType, SType, SigmaPropConstant, SigmaPropIsProven, TransformingSigmaBuilder, Value}
import java.math.BigInteger
@@ -19,6 +19,7 @@ object Extensions {
implicit class IntExt(val x: Int) extends AnyVal {
/** Convert this value to BigInt. */
@inline def toBigInt: BigInt = CSigmaDslBuilder.BigInt(BigInteger.valueOf(x.toLong))
+ @inline def toUnsignedBigInt: UnsignedBigInt = CSigmaDslBuilder.UnsignedBigInt(BigInteger.valueOf(x.toLong))
}
implicit class LongExt(val x: Long) extends AnyVal {
diff --git a/data/shared/src/main/scala/sigma/serialization/OpCodes.scala b/data/shared/src/main/scala/sigma/serialization/OpCodes.scala
index 70050d00ba..c4647669fa 100644
--- a/data/shared/src/main/scala/sigma/serialization/OpCodes.scala
+++ b/data/shared/src/main/scala/sigma/serialization/OpCodes.scala
@@ -153,6 +153,7 @@ object OpCodes {
val OptionIsDefinedCode: OpCode = newOpCode(118)
// Modular arithmetic operations codes
+ // todo: remove?
val ModQCode : OpCode = newOpCode(119)
val PlusModQCode : OpCode = newOpCode(120)
val MinusModQCode: OpCode = newOpCode(121)
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/DataSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/DataSerializerSpecification.scala
index fe6f62dbe0..9201214e4f 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/DataSerializerSpecification.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/DataSerializerSpecification.scala
@@ -66,11 +66,12 @@ class DataSerializerSpecification extends SerializationSpecification {
implicit val tagT = tT.classTag
implicit val tAny = sigma.AnyType
- val withVersion = if (tpe == SHeader) {
- Some(VersionContext.V6SoftForkVersion)
+ val withVersion = if (tpe == SHeader || tpe == SUnsignedBigInt) {
+ None // Some(VersionContext.V6SoftForkVersion)
} else {
None
}
+
forAll { xs: Array[T#WrappedType] =>
roundtrip[SCollection[T]](xs.toColl, SCollection(tpe), withVersion)
roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)), withVersion)
@@ -148,6 +149,7 @@ class DataSerializerSpecification extends SerializationSpecification {
forAll { x: Long => roundtrip[SLong.type](x, SLong) }
forAll { x: String => roundtrip[SString.type](x, SString) }
forAll { x: BigInteger => roundtrip[SBigInt.type](x.toBigInt, SBigInt) }
+ forAll { x: BigInteger => roundtrip[SUnsignedBigInt.type](x.abs().toUnsignedBigInt, SUnsignedBigInt, Some(VersionContext.V6SoftForkVersion)) }
forAll { x: EcPointType => roundtrip[SGroupElement.type](x.toGroupElement, SGroupElement) }
forAll { x: SigmaBoolean => roundtrip[SSigmaProp.type](x.toSigmaProp, SSigmaProp) }
forAll { x: ErgoBox => roundtrip[SBox.type](x, SBox) }
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/SelectFieldSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/SelectFieldSerializerSpecification.scala
index fb3bbcd326..1c67806dbc 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/SelectFieldSerializerSpecification.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/SelectFieldSerializerSpecification.scala
@@ -4,8 +4,9 @@ import org.scalacheck.Gen
import sigma.ast.syntax.CollectionOps
import sigma.ast.{FalseLeaf, IntConstant, SelectField, Tuple}
import sigma.serialization.OpCodes.{SelectFieldCode, TupleCode}
+import sigmastate.CrossVersionProps
-class SelectFieldSerializerSpecification extends TableSerializationSpecification {
+class SelectFieldSerializerSpecification extends TableSerializationSpecification with CrossVersionProps {
property("SelectField: Serializer round trip ") {
forAll(tupleGen(2, 10)) { tuple: Tuple =>
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/TupleSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/TupleSerializerSpecification.scala
index e72890cbb7..04b4cffdc9 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/TupleSerializerSpecification.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/TupleSerializerSpecification.scala
@@ -1,8 +1,9 @@
package sigma.serialization
import sigma.ast.{FalseLeaf, IntConstant, Tuple}
+import sigmastate.CrossVersionProps
-class TupleSerializerSpecification extends TableSerializationSpecification {
+class TupleSerializerSpecification extends TableSerializationSpecification with CrossVersionProps {
property("Tuple: Serializer round trip ") {
forAll(tupleGen(1, 10)) { tuple: Tuple =>
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/TypeSerializerSpecification.scala b/interpreter/shared/src/test/scala/sigma/serialization/TypeSerializerSpecification.scala
index 6419faf364..ce28a712fd 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/TypeSerializerSpecification.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/TypeSerializerSpecification.scala
@@ -3,8 +3,9 @@ package sigma.serialization
import org.scalacheck.Arbitrary._
import org.scalatest.Assertion
import sigma.ast._
+import sigmastate.CrossVersionProps
-class TypeSerializerSpecification extends SerializationSpecification {
+class TypeSerializerSpecification extends SerializationSpecification with CrossVersionProps {
private def roundtrip[T <: SType](tpe: T, expected: Array[Byte]): Assertion = {
val w = SigmaSerializer.startWriter()
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala b/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala
index db6cd87330..1af51d4eee 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/generators/ObjectGenerators.scala
@@ -83,6 +83,7 @@ trait ObjectGenerators extends TypeGenerators
implicit lazy val arbRegisterIdentifier: Arbitrary[RegisterId] = Arbitrary(registerIdentifierGen)
implicit lazy val arbBigInteger: Arbitrary[BigInteger] = Arbitrary(Arbitrary.arbBigInt.arbitrary.map(_.bigInteger))
implicit lazy val arbBigInt: Arbitrary[BigInt] = Arbitrary(arbBigInteger.arbitrary.map(SigmaDsl.BigInt(_)))
+ implicit lazy val arbUnsignedBigInt: Arbitrary[UnsignedBigInt] = Arbitrary(arbBigInteger.arbitrary.map(_.abs()).map(SigmaDsl.UnsignedBigInt(_)))
implicit lazy val arbEcPointType: Arbitrary[dlogGroup.ElemType] = Arbitrary(Gen.const(()).flatMap(_ => CryptoConstants.dlogGroup.createRandomGenerator()))
implicit lazy val arbGroupElement: Arbitrary[GroupElement] = Arbitrary(arbEcPointType.arbitrary.map(SigmaDsl.GroupElement(_)))
implicit lazy val arbSigmaBoolean: Arbitrary[SigmaBoolean] = Arbitrary(Gen.oneOf(proveDHTGen, proveDHTGen))
@@ -142,6 +143,8 @@ trait ObjectGenerators extends TypeGenerators
arbString.arbitrary.map { v => mkConstant[SString.type](v, SString) }
lazy val bigIntConstGen: Gen[BigIntConstant] =
arbBigInt.arbitrary.map { v => mkConstant[SBigInt.type](v, SBigInt) }
+ lazy val unsignedBigIntConstGen: Gen[UnsignedBigIntConstant] =
+ arbUnsignedBigInt.arbitrary.map { v => mkConstant[SUnsignedBigInt.type](v, SUnsignedBigInt) }
lazy val byteArrayConstGen: Gen[CollectionConstant[SByte.type]] = for {
bytes <- arrayOfRange(1, 100, arbByte.arbitrary)
@@ -305,6 +308,7 @@ trait ObjectGenerators extends TypeGenerators
case SInt => arbInt
case SLong => arbLong
case SBigInt => arbBigInt
+ case SUnsignedBigInt => arbUnsignedBigInt
case SGroupElement => arbGroupElement
case SSigmaProp => arbSigmaProp
case SBox => arbBox
@@ -325,6 +329,11 @@ trait ObjectGenerators extends TypeGenerators
longConstGen,
booleanConstGen,
bigIntConstGen,
+ if(VersionContext.current.isV6SoftForkActivated) {
+ unsignedBigIntConstGen
+ } else {
+ bigIntConstGen
+ },
groupElementConstGen,
getVar[SInt.type],
getVar[SLong.type],
diff --git a/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala b/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala
index 70a215e831..c27053ebf2 100644
--- a/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala
+++ b/interpreter/shared/src/test/scala/sigma/serialization/generators/TypeGenerators.scala
@@ -2,6 +2,7 @@ package sigma.serialization.generators
import org.scalacheck.{Arbitrary, Gen}
import org.scalacheck.Arbitrary.arbString
+import sigma.VersionContext
import sigma.ast._
trait TypeGenerators {
@@ -11,6 +12,7 @@ trait TypeGenerators {
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 unsignedBigIntTypeGen: Gen[SUnsignedBigInt.type] = Gen.const(SUnsignedBigInt)
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)
@@ -19,10 +21,15 @@ trait TypeGenerators {
implicit val headerTypeGen: Gen[SHeader.type] = Gen.const(SHeader)
implicit val primTypeGen: Gen[SPrimType] =
- Gen.oneOf[SPrimType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit)
+ Gen.oneOf[SPrimType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt, SGroupElement, SSigmaProp, SUnit)
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, SHeader)
+ implicit val predefTypeGen: Gen[SPredefType] = {
+ if(VersionContext.current.isV6SoftForkActivated){
+ Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree, SHeader)
+ } else {
+ Gen.oneOf[SPredefType](SBoolean, SByte, SShort, SInt, SLong, SBigInt, SGroupElement, SSigmaProp, SUnit, SBox, SAvlTree)
+ }
+ }
implicit val arbPredefType: Arbitrary[SPredefType] = Arbitrary(predefTypeGen)
implicit def genToArbitrary[T: Gen]: Arbitrary[T] = Arbitrary(implicitly[Gen[T]])
@@ -34,7 +41,12 @@ trait TypeGenerators {
shortTypeGen,
intTypeGen,
longTypeGen,
- bigIntTypeGen
+ bigIntTypeGen,
+ if(VersionContext.current.isV6SoftForkActivated) {
+ unsignedBigIntTypeGen
+ } else {
+ bigIntTypeGen
+ }
))
} yield STuple(values.toIndexedSeq)
diff --git a/interpreter/shared/src/test/scala/sigmastate/crypto/BigIntSpecification.scala b/interpreter/shared/src/test/scala/sigmastate/crypto/BigIntSpecification.scala
new file mode 100644
index 0000000000..2662ff0a7a
--- /dev/null
+++ b/interpreter/shared/src/test/scala/sigmastate/crypto/BigIntSpecification.scala
@@ -0,0 +1,9 @@
+package sigmastate.crypto
+
+import org.scalatest.propspec.AnyPropSpec
+import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
+import sigmastate.TestsBase
+
+class BigIntSpecification extends AnyPropSpec with ScalaCheckPropertyChecks with TestsBase {
+
+}
diff --git a/parsers/shared/src/main/scala/sigmastate/lang/Types.scala b/parsers/shared/src/main/scala/sigmastate/lang/Types.scala
index 06683f6e96..4402eb949a 100644
--- a/parsers/shared/src/main/scala/sigmastate/lang/Types.scala
+++ b/parsers/shared/src/main/scala/sigmastate/lang/Types.scala
@@ -34,6 +34,7 @@ trait Types extends Core {
"Int" -> SInt,
"Long" -> SLong,
"BigInt" -> SBigInt,
+ "UnsignedBigInt" -> SUnsignedBigInt, // added in 6.0, but put in this map
"AvlTree" -> SAvlTree,
"Context" -> SContext,
"GroupElement" -> SGroupElement,
diff --git a/sc/shared/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala b/sc/shared/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala
index 11cbaff739..34598627db 100644
--- a/sc/shared/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala
+++ b/sc/shared/src/main/scala/org/ergoplatform/dsl/ContractSyntax.scala
@@ -55,6 +55,7 @@ trait ContractSyntax { contract: SigmaContract =>
case _: String => StringType
case _: Unit => UnitType
case _: sigma.BigInt => BigIntRType
+ case _: sigma.UnsignedBigInt => UnsignedBigIntRType
case _: GroupElement => GroupElementRType
case _: ErgoBox => syntax.ErgoBoxRType // TODO remove this RType
case _: Box => BoxRType
diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala
index 48ec9a45ba..f5235aba5e 100644
--- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala
@@ -16,10 +16,14 @@ import sigma.VersionContext
import sigma.data.ExactIntegral.{ByteIsExactIntegral, IntIsExactIntegral, LongIsExactIntegral, ShortIsExactIntegral}
import sigma.data.ExactOrdering.{ByteIsExactOrdering, IntIsExactOrdering, LongIsExactOrdering, ShortIsExactOrdering}
import sigma.data.{CSigmaDslBuilder, ExactIntegral, ExactNumeric, ExactOrdering, Lazy, Nullable}
-import sigma.exceptions.GraphBuildingException
-import sigma.serialization.OpCodes
import sigma.util.Extensions.ByteOps
import sigmastate.interpreter.Interpreter.ScriptEnv
+import sigma.ast.{Ident, Select, Val}
+import sigma.data.UnsignedBigIntNumericOps.{UnsignedBigIntIsExactIntegral, UnsignedBigIntIsExactOrdering}
+import sigma.exceptions.GraphBuildingException
+import sigma.serialization.OpCodes
+import sigma.{SigmaException, ast}
+import sigma.VersionContext
import scala.collection.mutable.ArrayBuffer
@@ -35,6 +39,7 @@ import scala.collection.mutable.ArrayBuffer
trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
import AvlTree._
import BigInt._
+ import UnsignedBigInt._
import Box._
import Coll._
import CollBuilder._
@@ -260,6 +265,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
case SString => StringElement
case SAny => AnyElement
case SBigInt => bigIntElement
+ case SUnsignedBigInt => unsignedBigIntElement
case SBox => boxElement
case SContext => contextElement
case SGlobal => sigmaDslBuilderElement
@@ -286,6 +292,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
case StringElement => SString
case AnyElement => SAny
case _: BigIntElem[_] => SBigInt
+ case _: UnsignedBigIntElem[_] => SUnsignedBigInt
case _: GroupElementElem[_] => SGroupElement
case _: AvlTreeElem[_] => SAvlTree
case oe: WOptionElem[_, _] => SOption(elemToSType(oe.eItem))
@@ -313,6 +320,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
case StringElement => StringIsLiftable
case UnitElement => UnitIsLiftable
case _: BigIntElem[_] => LiftableBigInt
+ case _: UnsignedBigIntElem[_] => LiftableUnsignedBigInt
case _: GroupElementElem[_] => LiftableGroupElement
case ce: CollElem[t,_] =>
implicit val lt = liftableFromElem[t](ce.eItem)
@@ -333,20 +341,24 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
(ShortElement, ShortIsExactIntegral),
(IntElement, IntIsExactIntegral),
(LongElement, LongIsExactIntegral),
- (bigIntElement, BigIntIsExactIntegral)
+ (bigIntElement, BigIntIsExactIntegral),
+ (unsignedBigIntElement, UnsignedBigIntIsExactIntegral)
)
private lazy val elemToExactIntegralMap = Map[Elem[_], ExactIntegral[_]](
(ByteElement, ByteIsExactIntegral),
(ShortElement, ShortIsExactIntegral),
(IntElement, IntIsExactIntegral),
- (LongElement, LongIsExactIntegral)
+ (LongElement, LongIsExactIntegral),
+ (bigIntElement, BigIntIsExactIntegral),
+ (unsignedBigIntElement, UnsignedBigIntIsExactIntegral)
)
protected lazy val elemToExactOrderingMap = Map[Elem[_], ExactOrdering[_]](
(ByteElement, ByteIsExactOrdering),
(ShortElement, ShortIsExactOrdering),
(IntElement, IntIsExactOrdering),
(LongElement, LongIsExactOrdering),
- (bigIntElement, BigIntIsExactOrdering)
+ (bigIntElement, BigIntIsExactOrdering),
+ (unsignedBigIntElement, UnsignedBigIntIsExactOrdering)
)
/** @return [[ExactNumeric]] instance for the given type */
@@ -456,6 +468,10 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
assert(tpe == SBigInt)
val resV = liftConst(bi)
resV
+ case ubi: SUnsignedBigInt =>
+ assert(tpe == SUnsignedBigInt)
+ val resV = liftConst(ubi)
+ resV
case p: SGroupElement =>
assert(tpe == SGroupElement)
val resV = liftConst(p)
@@ -1031,6 +1047,9 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
case SGroupElementMethods.ExponentiateMethod.name =>
val k = asRep[BigInt](argsV(0))
ge.exp(k)
+ case SGroupElementMethods.ExponentiateUnsignedMethod.name =>
+ val k = asRep[UnsignedBigInt](argsV(0))
+ ge.expUnsigned(k)
case _ => throwError()
}
case (box: Ref[Box]@unchecked, SBoxMethods) => method.name match {
@@ -1206,7 +1225,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
case SGlobalMethods.serializeMethod.name =>
val value = asRep[Any](argsV(0))
g.serialize(value)
- case SGlobalMethods.fromBigEndianBytesMethod.name =>
+ case SGlobalMethods.FromBigEndianBytesMethod.name =>
val bytes = asRep[Coll[Byte]](argsV(0))
val cT = stypeToElem(method.stype.tRange.withSubstTypes(typeSubst))
g.fromBigEndianBytes(bytes)(cT)
@@ -1219,7 +1238,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
g.none()(cT)
case _ => throwError()
}
- case (x: Ref[tNum], _: SNumericTypeMethods) => method.name match {
+ case (x: Ref[tNum], ms: SNumericTypeMethods) => method.name match {
case SNumericTypeMethods.ToBytesMethod.name =>
val op = NumericToBigEndianBytes(elemToExactNumeric(x.elem))
ApplyUnOp(op, x)
@@ -1249,6 +1268,40 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
val y = asRep[Int](argsV(0))
val op = NumericShiftRight(elemToExactNumeric(x.elem))(x.elem)
ApplyBinOpDiffArgs(op, x, y)
+ case SBigIntMethods.ToUnsigned.name => // only bigint has toUnsigned method
+ val bi = asRep[BigInt](x)
+ bi.toUnsigned()
+ case SBigIntMethods.ToUnsignedMod.name => // only bigint has toUnsignedMod method
+ val bi = asRep[BigInt](x)
+ val m = asRep[UnsignedBigInt](argsV(0))
+ bi.toUnsignedMod(m)
+
+ case SUnsignedBigIntMethods.ModMethod.name if ms.isInstanceOf[SUnsignedBigIntMethods.type] =>
+ val ubi = asRep[UnsignedBigInt](x)
+ val m = asRep[UnsignedBigInt](argsV(0))
+ ubi.mod(m)
+ case SUnsignedBigIntMethods.ModInverseMethod.name if ms.isInstanceOf[SUnsignedBigIntMethods.type] =>
+ val ubi = asRep[UnsignedBigInt](x)
+ val m = asRep[UnsignedBigInt](argsV(0))
+ ubi.modInverse(m)
+ case SUnsignedBigIntMethods.PlusModMethod.name if ms.isInstanceOf[SUnsignedBigIntMethods.type] =>
+ val ubi = asRep[UnsignedBigInt](x)
+ val that = asRep[UnsignedBigInt](argsV(0))
+ val m = asRep[UnsignedBigInt](argsV(1))
+ ubi.plusMod(that, m)
+ case SUnsignedBigIntMethods.SubtractModMethod.name if ms.isInstanceOf[SUnsignedBigIntMethods.type] =>
+ val ubi = asRep[UnsignedBigInt](x)
+ val that = asRep[UnsignedBigInt](argsV(0))
+ val m = asRep[UnsignedBigInt](argsV(1))
+ ubi.subtractMod(that, m)
+ case SUnsignedBigIntMethods.MultiplyModMethod.name if ms.isInstanceOf[SUnsignedBigIntMethods.type] =>
+ val ubi = asRep[UnsignedBigInt](x)
+ val that = asRep[UnsignedBigInt](argsV(0))
+ val m = asRep[UnsignedBigInt](argsV(1))
+ ubi.multiplyMod(that, m)
+ case SUnsignedBigIntMethods.ToSignedMethod.name if ms.isInstanceOf[SUnsignedBigIntMethods.type] =>
+ val ubi = asRep[UnsignedBigInt](x)
+ ubi.toSigned()
case _ => throwError()
}
case _ => throwError(s"Type ${stypeToRType(obj.tpe).name} doesn't have methods")
diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala b/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala
index 5fc26011a9..a49dbe53a6 100644
--- a/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/GraphIRReflection.scala
@@ -117,6 +117,59 @@ object GraphIRReflection {
},
mkMethod(clazz, "divide", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
obj.asInstanceOf[ctx.BigInt].divide(args(0).asInstanceOf[ctx.Ref[ctx.BigInt]])
+ },
+ mkMethod(clazz, "toUnsigned", Array[Class[_]]()) { (obj, _) =>
+ obj.asInstanceOf[ctx.BigInt].toUnsigned()
+ },
+ mkMethod(clazz, "toUnsignedMod", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.BigInt].toUnsignedMod(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ }
+ )
+ )
+ }
+
+ { val clazz = classOf[SigmaDsl#UnsignedBigInt]
+ val ctx = null.asInstanceOf[SigmaDsl] // ok! type level only
+ registerClassEntry(clazz,
+ methods = Map(
+ mkMethod(clazz, "add", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].add(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "max", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].max(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "min", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].min(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "subtract", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].subtract(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "multiply", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].multiply(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "mod", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].mod(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "divide", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].divide(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "plusMod", Array[Class[_]](classOf[Base#Ref[_]], classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].plusMod(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]], args(1).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "subtractMod", Array[Class[_]](classOf[Base#Ref[_]], classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].subtractMod(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]], args(1).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "multiplyMod", Array[Class[_]](classOf[Base#Ref[_]], classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].multiplyMod(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]], args(1).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "mod", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].mod(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "modInverse", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].modInverse(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
+ mkMethod(clazz, "toSigned", Array[Class[_]]()) { (obj, _) =>
+ obj.asInstanceOf[ctx.UnsignedBigInt].toSigned
}
)
)
@@ -368,6 +421,9 @@ object GraphIRReflection {
mkMethod(clazz, "exp", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
obj.asInstanceOf[ctx.GroupElement].exp(args(0).asInstanceOf[ctx.Ref[ctx.BigInt]])
},
+ mkMethod(clazz, "expUnsigned", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
+ obj.asInstanceOf[ctx.GroupElement].expUnsigned(args(0).asInstanceOf[ctx.Ref[ctx.UnsignedBigInt]])
+ },
mkMethod(clazz, "multiply", Array[Class[_]](classOf[Base#Ref[_]])) { (obj, args) =>
obj.asInstanceOf[ctx.GroupElement].multiply(args(0).asInstanceOf[ctx.Ref[ctx.GroupElement]])
},
diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala
index 9b7e3061c0..84c43f14dd 100644
--- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/SigmaDslUnit.scala
@@ -13,9 +13,26 @@ import scalan._
def mod(m: Ref[BigInt]): Ref[BigInt];
def min(that: Ref[BigInt]): Ref[BigInt];
def max(that: Ref[BigInt]): Ref[BigInt];
+ def toUnsigned(): Ref[UnsignedBigInt];
+ def toUnsignedMod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]
+ };
+ trait UnsignedBigInt extends Def[UnsignedBigInt] {
+ def add(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt];
+ def subtract(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt];
+ def multiply(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt];
+ def divide(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt];
+ def mod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt];
+ def min(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt];
+ def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt];
+ def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]
+ def plusMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]
+ def subtractMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]
+ def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt]
+ def toSigned(): Ref[BigInt]
};
trait GroupElement extends Def[GroupElement] {
def exp(k: Ref[BigInt]): Ref[GroupElement];
+ def expUnsigned(k: Ref[UnsignedBigInt]): Ref[GroupElement];
def multiply(that: Ref[GroupElement]): Ref[GroupElement];
def negate: Ref[GroupElement];
def getEncoded: Ref[Coll[Byte]]
diff --git a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala
index 97af672a27..695f503246 100644
--- a/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/ir/wrappers/sigma/impl/SigmaDslImpl.scala
@@ -99,6 +99,22 @@ object BigInt extends EntityObject("BigInt") {
Array[AnyRef](that),
true, false, element[BigInt]))
}
+
+ import UnsignedBigInt.unsignedBigIntElement
+
+ override def toUnsigned(): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ BigIntClass.getMethod("toUnsigned"),
+ Array[AnyRef](),
+ true, false, element[UnsignedBigInt](unsignedBigIntElement)))
+ }
+
+ override def toUnsignedMod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ BigIntClass.getMethod("toUnsignedMod", classOf[Sym]),
+ Array[AnyRef](m),
+ true, false, element[UnsignedBigInt](unsignedBigIntElement)))
+ }
}
implicit object LiftableBigInt
@@ -167,6 +183,22 @@ object BigInt extends EntityObject("BigInt") {
Array[AnyRef](that),
true, true, element[BigInt]))
}
+
+ import UnsignedBigInt.unsignedBigIntElement
+
+ def toUnsigned(): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ BigIntClass.getMethod("toUnsigned"),
+ Array[AnyRef](),
+ true, true, element[UnsignedBigInt](unsignedBigIntElement)))
+ }
+
+ def toUnsignedMod(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ BigIntClass.getMethod("toUnsignedMod", classOf[Sym]),
+ Array[AnyRef](that),
+ true, true, element[UnsignedBigInt](unsignedBigIntElement)))
+ }
}
// entityUnref: single unref method for each type family
@@ -184,7 +216,7 @@ object BigInt extends EntityObject("BigInt") {
override protected def collectMethods: Map[RMethod, MethodDesc] = {
super.collectMethods ++
Elem.declaredMethods(RClass(classOf[BigInt]), RClass(classOf[SBigInt]), Set(
- "add", "subtract", "multiply", "divide", "mod", "min", "max"
+ "add", "subtract", "multiply", "divide", "mod", "min", "max", "toUnsigned", "toUnsignedMod"
))
}
}
@@ -269,6 +301,236 @@ object BigInt extends EntityObject("BigInt") {
} // of object BigInt
registerEntityObject("BigInt", BigInt)
+object UnsignedBigInt extends EntityObject("UnsignedBigInt") {
+ import Liftables._
+
+ type SUnsignedBigInt = sigma.UnsignedBigInt
+ unsignedBigIntElement
+
+ case class UnsignedBigIntConst(constValue: SUnsignedBigInt)
+ extends LiftedConst[SUnsignedBigInt, UnsignedBigInt] with UnsignedBigInt
+ with Def[UnsignedBigInt] with UnsignedBigIntConstMethods {
+ val liftable: Liftable[SUnsignedBigInt, UnsignedBigInt] = LiftableUnsignedBigInt
+ val resultType: Elem[UnsignedBigInt] = liftable.eW
+ }
+
+ trait UnsignedBigIntConstMethods extends UnsignedBigInt { thisConst: Def[_] =>
+
+ private val UnsignedBigIntClass = RClass(classOf[UnsignedBigInt])
+
+ override def add(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("add", classOf[Sym]),
+ Array[AnyRef](that),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def subtract(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("subtract", classOf[Sym]),
+ Array[AnyRef](that),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def multiply(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("multiply", classOf[Sym]),
+ Array[AnyRef](that),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def divide(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("divide", classOf[Sym]),
+ Array[AnyRef](that),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def mod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("mod", classOf[Sym]),
+ Array[AnyRef](m),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def min(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("min", classOf[Sym]),
+ Array[AnyRef](that),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("max", classOf[Sym]),
+ Array[AnyRef](that),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("modInverse", classOf[Sym]),
+ Array[AnyRef](m),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def plusMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("plusMod", classOf[Sym], classOf[Sym]),
+ Array[AnyRef](that, m),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def subtractMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("subtractMod", classOf[Sym], classOf[Sym]),
+ Array[AnyRef](that, m),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("multiplyMod", classOf[Sym], classOf[Sym]),
+ Array[AnyRef](that, m),
+ true, false, element[UnsignedBigInt]))
+ }
+
+ override def toSigned(): Ref[BigInt] = {
+ asRep[BigInt](mkMethodCall(self,
+ UnsignedBigIntClass.getMethod("toSigned"),
+ Array[AnyRef](),
+ true, false, element[BigInt]))
+ }
+ }
+
+ implicit object LiftableUnsignedBigInt extends Liftable[SUnsignedBigInt, UnsignedBigInt] {
+ lazy val eW: Elem[UnsignedBigInt] = unsignedBigIntElement
+ lazy val sourceType: RType[SUnsignedBigInt] = {
+ RType[SUnsignedBigInt]
+ }
+
+ def lift(x: SUnsignedBigInt): Ref[UnsignedBigInt] = UnsignedBigIntConst(x)
+ }
+
+ private val UnsignedBigIntClass = RClass(classOf[UnsignedBigInt])
+
+ // entityAdapter for BigInt trait
+ case class UnsignedBigIntAdapter(source: Ref[UnsignedBigInt])
+ extends Node with UnsignedBigInt
+ with Def[UnsignedBigInt] {
+ val resultType: Elem[UnsignedBigInt] = element[UnsignedBigInt]
+
+ override def transform(t: Transformer) = UnsignedBigIntAdapter(t(source))
+
+ def add(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("add", classOf[Sym]),
+ Array[AnyRef](that),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def subtract(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("subtract", classOf[Sym]),
+ Array[AnyRef](that),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def multiply(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("multiply", classOf[Sym]),
+ Array[AnyRef](that),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def divide(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("divide", classOf[Sym]),
+ Array[AnyRef](that),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def mod(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("mod", classOf[Sym]),
+ Array[AnyRef](m),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def min(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("min", classOf[Sym]),
+ Array[AnyRef](that),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def max(that: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("max", classOf[Sym]),
+ Array[AnyRef](that),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def modInverse(m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("modInverse", classOf[Sym]),
+ Array[AnyRef](m),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def plusMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("plusMod", classOf[Sym], classOf[Sym]),
+ Array[AnyRef](that, m),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def subtractMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("subtractMod", classOf[Sym], classOf[Sym]),
+ Array[AnyRef](that, m),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def multiplyMod(that: Ref[UnsignedBigInt], m: Ref[UnsignedBigInt]): Ref[UnsignedBigInt] = {
+ asRep[UnsignedBigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("multiplyMod", classOf[Sym], classOf[Sym]),
+ Array[AnyRef](that, m),
+ true, true, element[UnsignedBigInt]))
+ }
+
+ def toSigned(): Ref[BigInt] = {
+ asRep[BigInt](mkMethodCall(source,
+ UnsignedBigIntClass.getMethod("toSigned"),
+ Array[AnyRef](),
+ true, true, element[BigInt]))
+ }
+ }
+
+ // entityUnref: single unref method for each type family
+ implicit final def unrefUnsignedBigInt(p: Ref[UnsignedBigInt]): UnsignedBigInt = {
+ if (p.node.isInstanceOf[UnsignedBigInt]) p.node.asInstanceOf[UnsignedBigInt]
+ else
+ UnsignedBigIntAdapter(p)
+ }
+
+ class UnsignedBigIntElem[To <: UnsignedBigInt]
+ extends EntityElem[To] {
+ override val liftable: Liftables.Liftable[_, To] = asLiftable[SUnsignedBigInt, To](LiftableUnsignedBigInt)
+
+ override protected def collectMethods: Map[RMethod, MethodDesc] = {
+ super.collectMethods ++
+ Elem.declaredMethods(RClass(classOf[UnsignedBigInt]), RClass(classOf[UnsignedBigInt]), Set(
+ "add", "subtract", "multiply", "divide", "mod", "modInverse",
+ "min", "max", "plusMod", "subtractMod", "multiplyMod", "toSigned"
+ ))
+ }
+ }
+
+ implicit lazy val unsignedBigIntElement: Elem[UnsignedBigInt] = new UnsignedBigIntElem[UnsignedBigInt]
+} // of object BigInt
+ registerEntityObject("UnsignedBigInt", UnsignedBigInt)
+
object GroupElement extends EntityObject("GroupElement") {
// entityConst: single const for each entity
import Liftables._
@@ -293,6 +555,13 @@ object GroupElement extends EntityObject("GroupElement") {
true, false, element[GroupElement]))
}
+ override def expUnsigned(k: Ref[UnsignedBigInt]): Ref[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(self,
+ GroupElementClass.getMethod("expUnsigned", classOf[Sym]),
+ Array[AnyRef](k),
+ true, false, element[GroupElement]))
+ }
+
override def multiply(that: Ref[GroupElement]): Ref[GroupElement] = {
asRep[GroupElement](mkMethodCall(self,
GroupElementClass.getMethod("multiply", classOf[Sym]),
@@ -340,6 +609,13 @@ object GroupElement extends EntityObject("GroupElement") {
true, true, element[GroupElement]))
}
+ def expUnsigned(k: Ref[UnsignedBigInt]): Ref[GroupElement] = {
+ asRep[GroupElement](mkMethodCall(source,
+ GroupElementClass.getMethod("expUnsigned", classOf[Sym]),
+ Array[AnyRef](k),
+ true, true, element[GroupElement]))
+ }
+
def multiply(that: Ref[GroupElement]): Ref[GroupElement] = {
asRep[GroupElement](mkMethodCall(source,
GroupElementClass.getMethod("multiply", classOf[Sym]),
diff --git a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala
index 1bbf1fc4f5..7d31b91c1e 100644
--- a/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala
+++ b/sc/shared/src/main/scala/sigma/compiler/phases/SigmaTyper.scala
@@ -178,9 +178,20 @@ class SigmaTyper(val builder: SigmaBuilder,
error(s"Cannot get field '$n' in in the object $newObj of non-product type ${newObj.tpe}", sel.sourceContext)
}
- case app @ Apply(sel @ Select(obj, n, _), args) =>
- val newSel = assignType(env, sel)
+ case app @ Apply(selOriginal @ Select(obj, nOriginal, resType), args) =>
val newArgs = args.map(assignType(env, _))
+
+ // hack to make possible to write g.exp(ubi) for both unsigned and signed big integers
+ // could be useful for other use cases where the same front-end code could be
+ // translated to different methods under the hood, based on argument types
+ // todo: consider better place for it
+ val (n, sel) = if (nOriginal == "exp" && newArgs(0).tpe.isInstanceOf[SUnsignedBigInt.type]) {
+ val newName = "expUnsigned"
+ (newName, Select(obj, newName, resType))
+ } else {
+ (nOriginal, selOriginal)
+ }
+ val newSel = assignType(env, sel)
newSel.tpe match {
case genFunTpe @ SFunc(argTypes, _, _) =>
// If it's a function then the application has type of that function's return type.
diff --git a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala
index abd89b6857..29b78d0e97 100644
--- a/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala
+++ b/sc/shared/src/test/scala/sigma/LanguageSpecificationV6.scala
@@ -14,6 +14,7 @@ import sigma.ast.syntax.TrueSigmaProp
import sigma.ast.{SInt, _}
import sigma.data.{AvlTreeData, AvlTreeFlags, CAnyValue, CAvlTree, CBigInt, CBox, CHeader, CSigmaProp, ExactNumeric, ProveDHTuple, RType}
import sigma.data.CSigmaDslBuilder
+import sigma.data.{AvlTreeData, AvlTreeFlags, CAnyValue, CAvlTree, CBigInt, CBox, CGroupElement, CHeader, CSigmaDslBuilder, CSigmaProp, CUnsignedBigInt, ExactNumeric, PairOfCols, ProveDHTuple, RType}
import sigma.crypto.SecP256K1Group
import sigma.data.{CBigInt, CBox, CGroupElement, CHeader, CSigmaDslBuilder, ExactNumeric, RType}
import sigma.data.{CBigInt, CBox, CHeader, CSigmaDslBuilder, ExactNumeric, PairOfCols, RType}
@@ -22,6 +23,9 @@ import sigma.serialization.ValueCodes.OpCode
import sigma.util.Extensions.{BooleanOps, IntOps}
import sigmastate.eval.{CContext, CPreHeader}
import sigma.util.Extensions.{BooleanOps, IntOps}
+import sigma.serialization.ValueCodes.OpCode
+import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps}
+import sigma.util.Extensions.{BooleanOps, IntOps}
import sigma.data.RType
import sigma.serialization.ValueCodes.OpCode
import sigma.util.Extensions.{BooleanOps, ByteOps, IntOps, LongOps}
@@ -30,6 +34,8 @@ import sigmastate.exceptions.MethodNotFound
import sigmastate.utils.Extensions.ByteOpsForSigma
import sigmastate.utils.Helpers
import sigma.Extensions.ArrayOps
+import sigma.Extensions.{ArrayOps, CollOps}
+import sigma.crypto.CryptoConstants
import sigma.interpreter.{ContextExtension, ProverResult}
import java.math.BigInteger
@@ -113,7 +119,6 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
verifyCases(cases, serializeShort, preGeneratedSamples = None)
}
-
property("Boolean.toByte") {
val toByte = newFeature((x: Boolean) => x.toByte, "{ (x: Boolean) => x.toByte }",
sinceVersion = V6SoftForkVersion
@@ -1828,6 +1833,7 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
newFeature(
{ (x: Context) => x.getVar[Boolean](11)},
"{ (x: Context) => CONTEXT.getVar[Boolean](11.toByte) }",
+ FuncValue(Array((1, SContext)), GetVar(11.toByte, SOption(SBoolean))),
sinceVersion = VersionContext.V6SoftForkVersion
)
}
@@ -1937,11 +1943,31 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
property("Global - fromBigEndianBytes") {
import sigma.data.OrderingOps.BigIntOrdering
+ import sigma.data.OrderingOps.UnsignedBigIntOrdering
def byteFromBigEndianBytes: Feature[Byte, Boolean] = {
newFeature(
{ (x: Byte) => CSigmaDslBuilder.fromBigEndianBytes[Byte](Colls.fromArray(Array(x))) == x},
"{ (x: Byte) => fromBigEndianBytes[Byte](x.toBytes) == x }",
+ FuncValue(
+ Array((1, SByte)),
+ EQ(
+ MethodCall.typed[Value[SByte.type]](
+ Global,
+ SGlobalMethods.FromBigEndianBytesMethod.withConcreteTypes(Map(STypeVar("T") -> SByte)),
+ Array(
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SByte),
+ SByteMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ Map(STypeVar("T") -> SByte)
+ ),
+ ValUse(1, SByte)
+ )
+ ),
sinceVersion = VersionContext.V6SoftForkVersion
)
}
@@ -1959,6 +1985,25 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
newFeature(
{ (x: Short) => CSigmaDslBuilder.fromBigEndianBytes[Short](Colls.fromArray(Shorts.toByteArray(x))) == x},
"{ (x: Short) => fromBigEndianBytes[Short](x.toBytes) == x }",
+ FuncValue(
+ Array((1, SShort)),
+ EQ(
+ MethodCall.typed[Value[SShort.type]](
+ Global,
+ SGlobalMethods.FromBigEndianBytesMethod.withConcreteTypes(Map(STypeVar("T") -> SShort)),
+ Array(
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SShort),
+ SShortMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ Map(STypeVar("T") -> SShort)
+ ),
+ ValUse(1, SShort)
+ )
+ ),
sinceVersion = VersionContext.V6SoftForkVersion
)
}
@@ -1976,6 +2021,25 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
newFeature(
{ (x: Int) => CSigmaDslBuilder.fromBigEndianBytes[Int](Colls.fromArray(Ints.toByteArray(x))) == x},
"{ (x: Int) => fromBigEndianBytes[Int](x.toBytes) == x }",
+ FuncValue(
+ Array((1, SInt)),
+ EQ(
+ MethodCall.typed[Value[SInt.type]](
+ Global,
+ SGlobalMethods.FromBigEndianBytesMethod.withConcreteTypes(Map(STypeVar("T") -> SInt)),
+ Array(
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SInt),
+ SIntMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ Map(STypeVar("T") -> SInt)
+ ),
+ ValUse(1, SInt)
+ )
+ ),
sinceVersion = VersionContext.V6SoftForkVersion
)
}
@@ -1992,6 +2056,25 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
newFeature(
{ (x: Long) => CSigmaDslBuilder.fromBigEndianBytes[Long](Colls.fromArray(Longs.toByteArray(x))) == x},
"{ (x: Long) => fromBigEndianBytes[Long](x.toBytes) == x }",
+ FuncValue(
+ Array((1, SLong)),
+ EQ(
+ MethodCall.typed[Value[SLong.type]](
+ Global,
+ SGlobalMethods.FromBigEndianBytesMethod.withConcreteTypes(Map(STypeVar("T") -> SLong)),
+ Array(
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SLong),
+ SLongMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ Map(STypeVar("T") -> SLong)
+ ),
+ ValUse(1, SLong)
+ )
+ ),
sinceVersion = VersionContext.V6SoftForkVersion
)
}
@@ -2008,6 +2091,25 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
newFeature(
{ (x: BigInt) => CSigmaDslBuilder.fromBigEndianBytes[BigInt](x.toBytes) == x},
"{ (x: BigInt) => Global.fromBigEndianBytes[BigInt](x.toBytes) == x }",
+ FuncValue(
+ Array((1, SBigInt)),
+ EQ(
+ MethodCall.typed[Value[SBigInt.type]](
+ Global,
+ SGlobalMethods.FromBigEndianBytesMethod.withConcreteTypes(Map(STypeVar("T") -> SBigInt)),
+ Array(
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SBigInt),
+ SBigIntMethods.getMethodByName("toBytes"),
+ IndexedSeq(),
+ Map()
+ )
+ ),
+ Map(STypeVar("T") -> SBigInt)
+ ),
+ ValUse(1, SBigInt)
+ )
+ ),
sinceVersion = VersionContext.V6SoftForkVersion
)
}
@@ -2021,12 +2123,57 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
bigIntFromBigEndianBytes
)
+ def unsignedBigIntFromBigEndianBytes: Feature[UnsignedBigInt, Boolean] = {
+ newFeature(
+ { (x: UnsignedBigInt) => CSigmaDslBuilder.fromBigEndianBytes[UnsignedBigInt](x.toBytes) == x},
+ "{ (x: UnsignedBigInt) => Global.fromBigEndianBytes[UnsignedBigInt](x.toBytes) == x }",
+ FuncValue(
+ Array((1, SUnsignedBigInt)),
+ EQ(
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ Global,
+ SGlobalMethods.FromBigEndianBytesMethod.withConcreteTypes(Map(STypeVar("T") -> SUnsignedBigInt)),
+ Array(
+ MethodCall.typed[Value[SCollection[SByte.type]]](
+ ValUse(1, SUnsignedBigInt),
+ SUnsignedBigIntMethods.getMethodByName("toBytes"),
+ IndexedSeq(),
+ Map()
+ )
+ ),
+ Map(STypeVar("T") -> SUnsignedBigInt)
+ ),
+ ValUse(1, SUnsignedBigInt)
+ )
+ ),
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+ }
+
+ verifyCases(
+ Seq(
+ CUnsignedBigInt(BigInteger.valueOf(50)) -> new Expected(ExpectedResult(Success(true), None)),
+ CUnsignedBigInt(sigma.crypto.CryptoConstants.groupOrder.divide(BigInteger.valueOf(2))) -> new Expected(ExpectedResult(Success(true), None)),
+ CUnsignedBigInt(sigma.crypto.CryptoConstants.groupOrder) -> new Expected(ExpectedResult(Success(true), None))
+ ),
+ unsignedBigIntFromBigEndianBytes
+ )
+
}
property("Coll.reverse") {
val f = newFeature[Coll[Int], Coll[Int]](
{ (xs: Coll[Int]) => xs.reverse },
"""{(xs: Coll[Int]) => xs.reverse }""".stripMargin,
+ FuncValue(
+ Array((1, SCollectionType(SInt))),
+ MethodCall.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SCollectionType(SInt)),
+ SCollectionMethods.ReverseMethod.withConcreteTypes(Map(STypeVar("IV") -> SInt)),
+ IndexedSeq(),
+ Map()
+ )
+ ),
sinceVersion = VersionContext.V6SoftForkVersion
)
@@ -2043,6 +2190,15 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
val f = newFeature[Coll[Int], Coll[Int]](
{ (xs: Coll[Int]) => xs.distinct },
"""{(xs: Coll[Int]) => xs.distinct }""".stripMargin,
+ FuncValue(
+ Array((1, SCollectionType(SInt))),
+ MethodCall.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SCollectionType(SInt)),
+ SCollectionMethods.DistinctMethod.withConcreteTypes(Map(STypeVar("IV") -> SInt)),
+ IndexedSeq(),
+ Map()
+ )
+ ),
sinceVersion = VersionContext.V6SoftForkVersion
)
@@ -2063,6 +2219,23 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
val f = newFeature[(Coll[Int], Coll[Int]), Boolean](
{ (xs: (Coll[Int], Coll[Int])) => xs._1.startsWith(xs._2) },
"""{(xs: (Coll[Int], Coll[Int])) => xs._1.startsWith(xs._2) }""".stripMargin,
+ FuncValue(
+ Array((1, SPair(SCollectionType(SInt), SCollectionType(SInt)))),
+ MethodCall.typed[Value[SBoolean.type]](
+ SelectField.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SPair(SCollectionType(SInt), SCollectionType(SInt))),
+ 1.toByte
+ ),
+ SCollectionMethods.StartsWithMethod.withConcreteTypes(Map(STypeVar("IV") -> SInt)),
+ Array(
+ SelectField.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SPair(SCollectionType(SInt), SCollectionType(SInt))),
+ 2.toByte
+ )
+ ),
+ Map()
+ )
+ ),
sinceVersion = VersionContext.V6SoftForkVersion
)
@@ -2083,7 +2256,24 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
val f = newFeature[(Coll[Int], Coll[Int]), Boolean](
{ (xs: (Coll[Int], Coll[Int])) => xs._1.endsWith(xs._2) },
"""{(xs: (Coll[Int], Coll[Int])) => xs._1.endsWith(xs._2) }""".stripMargin,
- sinceVersion = VersionContext.V6SoftForkVersion
+ FuncValue(
+ Array((1, SPair(SCollectionType(SInt), SCollectionType(SInt)))),
+ MethodCall.typed[Value[SBoolean.type]](
+ SelectField.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SPair(SCollectionType(SInt), SCollectionType(SInt))),
+ 1.toByte
+ ),
+ SCollectionMethods.EndsWithMethod.withConcreteTypes(Map(STypeVar("IV") -> SInt)),
+ Array(
+ SelectField.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SPair(SCollectionType(SInt), SCollectionType(SInt))),
+ 2.toByte
+ )
+ ),
+ Map()
+ )
+ ),
+ sinceVersion = VersionContext.V6SoftForkVersion
)
verifyCases(
@@ -2102,7 +2292,21 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
val f = newFeature[(Coll[Int], Int), Option[Int]](
{ (xs: (Coll[Int], Int)) => xs._1.get(xs._2) },
"""{(xs: (Coll[Int], Int)) => xs._1.get(xs._2) }""".stripMargin,
- sinceVersion = VersionContext.V6SoftForkVersion
+ FuncValue(
+ Array((1, SPair(SCollectionType(SInt), SInt))),
+ MethodCall.typed[Value[SOption[SInt.type]]](
+ SelectField.typed[Value[SCollection[SInt.type]]](
+ ValUse(1, SPair(SCollectionType(SInt), SInt)),
+ 1.toByte
+ ),
+ SCollectionMethods.GetMethod.withConcreteTypes(Map(STypeVar("IV") -> SInt)),
+ Array(
+ SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SCollectionType(SInt), SInt)), 2.toByte)
+ ),
+ Map()
+ )
+ ),
+ sinceVersion = VersionContext.V6SoftForkVersion
)
verifyCases(
@@ -2158,6 +2362,476 @@ class LanguageSpecificationV6 extends LanguageSpecificationBase { suite =>
)
}
+ property("BigInt.toUnsigned") {
+ import sigma.data.OrderingOps.BigIntOrdering
+
+ val f = newFeature[BigInt, UnsignedBigInt](
+ { (x: BigInt) => x.toUnsigned },
+ """{(x: BigInt) => x.toUnsigned }""".stripMargin,
+ FuncValue(
+ Array((1, SBigInt)),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SBigInt),
+ SBigIntMethods.ToUnsigned,
+ IndexedSeq(),
+ Map()
+ )
+ ),
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ CBigInt(new BigInteger("5")) -> Expected(ExpectedResult(Success(CUnsignedBigInt(new BigInteger("5"))), None)),
+ CBigInt(new BigInteger("-5")) -> Expected(ExpectedResult(Failure(new ArithmeticException("BigInteger argument for .toUnsigned is negative")), None)),
+ CBigInt(new BigInteger("0")) -> Expected(ExpectedResult(Success(CUnsignedBigInt(new BigInteger("0"))), None))
+ ),
+ f
+ )
+ }
+
+ property("BigInt.toUnsignedMod") {
+ import sigma.data.OrderingOps.BigIntOrdering
+ import sigma.data.OrderingOps.UnsignedBigIntOrdering
+
+ val f = newFeature[(BigInt, UnsignedBigInt), UnsignedBigInt](
+ { (xs: (BigInt, UnsignedBigInt)) => xs._1.toUnsignedMod(xs._2) },
+ """{ (xs: (BigInt, UnsignedBigInt)) => xs._1.toUnsignedMod(xs._2) }""".stripMargin,
+ FuncValue(
+ Array((1, SPair(SBigInt, SUnsignedBigInt))),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SBigInt.type]](ValUse(1, SPair(SBigInt, SUnsignedBigInt)), 1.toByte),
+ SBigIntMethods.ToUnsignedMod,
+ Array(
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SPair(SBigInt, SUnsignedBigInt)),
+ 2.toByte
+ )
+ ),
+ Map()
+ )
+ ),
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ (CBigInt(new BigInteger("50")), CUnsignedBigInt(new BigInteger("10"))) -> Expected(ExpectedResult(Success(CUnsignedBigInt(new BigInteger("0"))), None)),
+ (CBigInt(new BigInteger("50")), CUnsignedBigInt(new BigInteger("0"))) -> Expected(ExpectedResult(Failure(new ArithmeticException("BigInteger: modulus not positive")), None))
+ ),
+ f
+ )
+ }
+
+ property("GroupElement.expUnsigned") {
+ import sigma.data.OrderingOps.UnsignedBigIntOrdering
+
+ val f = newFeature[(GroupElement, UnsignedBigInt), GroupElement](
+ { (xs: (GroupElement, UnsignedBigInt)) => xs._1.expUnsigned(xs._2) },
+ """{ (xs: (GroupElement, UnsignedBigInt)) => xs._1.expUnsigned(xs._2) }""".stripMargin,
+ sinceVersion = VersionContext.V6SoftForkVersion
+ )
+
+ verifyCases(
+ Seq(
+ (CGroupElement(CryptoConstants.dlogGroup.generator), CUnsignedBigInt(new BigInteger("1"))) -> Expected(ExpectedResult(Success(CGroupElement(CryptoConstants.dlogGroup.generator)), None)),
+ (CGroupElement(CryptoConstants.dlogGroup.generator), CUnsignedBigInt(new BigInteger("0"))) -> Expected(ExpectedResult(Success(CGroupElement(CryptoConstants.dlogGroup.identity)), None)),
+ (CGroupElement(CryptoConstants.dlogGroup.generator), CUnsignedBigInt(CryptoConstants.dlogGroup.order)) -> Expected(ExpectedResult(Success(CGroupElement(CryptoConstants.dlogGroup.identity)), None))
+ ),
+ f
+ )
+ }
+
+ property("UnsignedBigInt methods") {
+ import sigma.data.OrderingOps.UnsignedBigIntOrdering
+
+ lazy val bitOr = newFeature[(UnsignedBigInt, UnsignedBigInt), UnsignedBigInt](
+ { (x: (UnsignedBigInt, UnsignedBigInt)) => (x._1 | x._2) },
+ "{ (x: (UnsignedBigInt, UnsignedBigInt)) => x._1.bitwiseOr(x._2) }",
+ if (VersionContext.current.isV6SoftForkActivated) {
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 1.toByte
+ ),
+ SUnsignedBigIntMethods.getMethodByName("bitwiseOr"),
+ Vector(
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 2.toByte
+ )
+ ),
+ Map()
+ )
+ )
+ } else {
+ null
+ },
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(BigInteger.valueOf(1)), CUnsignedBigInt(BigInteger.valueOf(2))) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(3))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(1001)), CUnsignedBigInt(BigInteger.valueOf(2002))) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(2043))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(100001)), CUnsignedBigInt(BigInteger.valueOf(20002))) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(118435))), None))
+ ),
+ bitOr
+ )
+
+ lazy val bitNot = newFeature[UnsignedBigInt, UnsignedBigInt](
+ { (x: UnsignedBigInt) => x.bitwiseInverse() },
+ "{ (x: UnsignedBigInt) => x.bitwiseInverse }",
+ if (VersionContext.current.isV6SoftForkActivated) {
+ FuncValue(
+ Array((1, SUnsignedBigInt)),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SUnsignedBigInt),
+ SUnsignedBigIntMethods.getMethodByName("bitwiseInverse"),
+ Vector(),
+ Map()
+ )
+ )
+ } else {
+ null
+ },
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ CUnsignedBigInt(BigInteger.valueOf(Byte.MaxValue)) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639808"))), None)),
+ CUnsignedBigInt(BigInteger.valueOf(0)) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(2).pow(256).subtract(BigInteger.ONE))), None)),
+ CUnsignedBigInt(BigInteger.valueOf(1)) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(2).pow(256).subtract(BigInteger.valueOf(2)))), None)),
+ CUnsignedBigInt(BigInteger.valueOf(2)) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(2).pow(256).subtract(BigInteger.valueOf(3)))), None)),
+ CUnsignedBigInt(BigInteger.valueOf(10001)) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(2).pow(256).subtract(BigInteger.valueOf(10002)))), None))
+ ),
+ bitNot
+ )
+
+
+ lazy val bitAnd = newFeature(
+ { (x: (UnsignedBigInt, UnsignedBigInt)) => x._1.asInstanceOf[CUnsignedBigInt].and(x._2.asInstanceOf[CUnsignedBigInt]) },
+ "{ (x: (UnsignedBigInt, UnsignedBigInt)) => x._1.bitwiseAnd(x._2) }",
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](ValUse(1, SPair(SUnsignedBigInt, SUnsignedBigInt)), 1.toByte),
+ SUnsignedBigIntMethods.v6Methods.find(_.name == "bitwiseAnd").get,
+ Vector(SelectField.typed[Value[SUnsignedBigInt.type]](ValUse(1, SPair(SUnsignedBigInt, SUnsignedBigInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(BigInteger.valueOf(3)), CUnsignedBigInt(BigInteger.valueOf(5))) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(1))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(10001)), CUnsignedBigInt(BigInteger.valueOf(2202))) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(16))), None))
+ ),
+ bitAnd
+ )
+
+ lazy val bitXor = newFeature(
+ { (x: (UnsignedBigInt, UnsignedBigInt)) => x._1.asInstanceOf[CUnsignedBigInt].xor(x._2.asInstanceOf[CUnsignedBigInt]) },
+ "{ (x: (UnsignedBigInt, UnsignedBigInt)) => x._1.bitwiseXor(x._2) }",
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](ValUse(1, SPair(SUnsignedBigInt, SUnsignedBigInt)), 1.toByte),
+ SUnsignedBigIntMethods.v6Methods.find(_.name == "bitwiseXor").get,
+ Vector(SelectField.typed[Value[SUnsignedBigInt.type]](ValUse(1, SPair(SUnsignedBigInt, SUnsignedBigInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(BigInteger.valueOf(3)), CUnsignedBigInt(BigInteger.valueOf(5))) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(6))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(10001)), CUnsignedBigInt(BigInteger.valueOf(2202))) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(12171))), None))
+ ),
+ bitXor
+ )
+
+ lazy val toBigEndianBytes = newFeature[UnsignedBigInt, Coll[Byte]](
+ { x: UnsignedBigInt => x.toBytes },
+ "{ (x: UnsignedBigInt) => x.toBytes }",
+ FuncValue(
+ Array((1, SUnsignedBigInt)),
+ MethodCall.typed[Value[SCollection[SUnsignedBigInt.type]]](
+ ValUse(1, SUnsignedBigInt),
+ SUnsignedBigIntMethods.getMethodByName("toBytes"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ CUnsignedBigInt(BigInteger.valueOf(127)) -> new Expected(ExpectedResult(Success(Coll(127.toByte)), None)),
+ CUnsignedBigInt(BigInteger.valueOf(Short.MaxValue)) -> new Expected(ExpectedResult(Success(Coll(127.toByte, (-1).toByte)), None)),
+ CUnsignedBigInt(BigInteger.valueOf(Int.MaxValue)) -> new Expected(ExpectedResult(Success(Coll(127.toByte, (-1).toByte, (-1).toByte, (-1).toByte)), None))
+ ),
+ toBigEndianBytes
+ )
+
+ def byte2Bools(b: Byte): Seq[Boolean] =
+ (0 to 7 map isBitSet(b)).reverse
+
+ def isBitSet(byte: Byte)(bit: Int): Boolean =
+ ((byte >> bit) & 1) == 1
+
+ lazy val toBits = newFeature[UnsignedBigInt, Coll[Boolean]](
+ { x: UnsignedBigInt => x.toBytes.flatMap(b => Colls.fromArray(byte2Bools(b).toArray)) },
+ "{ (x: UnsignedBigInt) => x.toBits }",
+ FuncValue(
+ Array((1, SUnsignedBigInt)),
+ MethodCall.typed[Value[SCollection[SUnsignedBigInt.type]]](
+ ValUse(1, SUnsignedBigInt),
+ SUnsignedBigIntMethods.getMethodByName("toBits"),
+ Vector(),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ CUnsignedBigInt(BigInteger.valueOf(83)) -> new Expected(ExpectedResult(Success(Coll(false, true, false, true, false, false, true, true)), None))
+ ),
+ toBits
+ )
+
+ lazy val shiftLeft = newFeature(
+ { (x: (UnsignedBigInt, Int)) => if (x._2 < 0 || x._2 >= 256) throw new IllegalArgumentException() else (x._1.asInstanceOf[UnsignedBigInt].shiftLeft(x._2)) },
+ "{ (x: (UnsignedBigInt, Int)) => x._1.shiftLeft(x._2) }",
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SInt))),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](ValUse(1, SPair(SUnsignedBigInt, SInt)), 1.toByte),
+ SUnsignedBigIntMethods.v6Methods.find(_.name == "shiftLeft").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SUnsignedBigInt, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(BigInteger.valueOf(3)), 3) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(24))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(3)), 8) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(768))), None))
+ ),
+ shiftLeft
+ )
+
+ lazy val shiftRight = newFeature(
+ { (x: (UnsignedBigInt, Int)) => if (x._2 < 0 || x._2 >= 256) throw new IllegalArgumentException() else (x._1.asInstanceOf[UnsignedBigInt].shiftRight(x._2)) },
+ "{ (x: (UnsignedBigInt, Int)) => x._1.shiftRight(x._2) }",
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SInt))),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](ValUse(1, SPair(SUnsignedBigInt, SInt)), 1.toByte),
+ SUnsignedBigIntMethods.v6Methods.find(_.name == "shiftRight").get,
+ Vector(SelectField.typed[Value[SInt.type]](ValUse(1, SPair(SUnsignedBigInt, SInt)), 2.toByte)),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(BigInteger.valueOf(24)), 3) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(3))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(1600)), 8) -> new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(6))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(24)), -1) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(24)), 256) -> new Expected(ExpectedResult(Failure(new IllegalArgumentException()), None))
+ ),
+ shiftRight
+ )
+
+ lazy val plusMod = newFeature(
+ { (x: (UnsignedBigInt, (UnsignedBigInt, UnsignedBigInt))) => x._1.asInstanceOf[UnsignedBigInt].plusMod(x._2._1, x._2._2) },
+ "{ (x: (UnsignedBigInt, (UnsignedBigInt, UnsignedBigInt))) => x._1.plusMod(x._2._1, x._2._2) }",
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt)))),
+ BlockValue(
+ Array(
+ ValDef(
+ 3,
+ List(),
+ SelectField.typed[Value[STuple]](
+ ValUse(1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ 2.toByte
+ )
+ )
+ ),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ 1.toByte
+ ),
+ SUnsignedBigIntMethods.getMethodByName("plusMod"),
+ Array(
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(3, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 1.toByte
+ ),
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(3, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 2.toByte
+ )
+ ),
+ Map()
+ )
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(BigInteger.valueOf(24)),
+ (CUnsignedBigInt(BigInteger.valueOf(24)), CUnsignedBigInt(BigInteger.valueOf(10)))) ->
+ new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(8))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(24)),
+ (CUnsignedBigInt(BigInteger.valueOf(24)), CUnsignedBigInt(BigInteger.valueOf(24)))) ->
+ new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(0))), None)),
+ (CUnsignedBigInt(CryptoConstants.groupOrder),
+ (CUnsignedBigInt(CryptoConstants.groupOrder), CUnsignedBigInt(CryptoConstants.groupOrder))) ->
+ new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(0))), None))
+ ),
+ plusMod
+ )
+
+ lazy val subtractMod = newFeature(
+ { (x: (UnsignedBigInt, (UnsignedBigInt, UnsignedBigInt))) => x._1.asInstanceOf[UnsignedBigInt].subtractMod(x._2._1, x._2._2) },
+ "{ (x: (UnsignedBigInt, (UnsignedBigInt, UnsignedBigInt))) => x._1.subtractMod(x._2._1, x._2._2) }",
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt)))),
+ BlockValue(
+ Array(
+ ValDef(
+ 3,
+ List(),
+ SelectField.typed[Value[STuple]](
+ ValUse(1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ 2.toByte
+ )
+ )
+ ),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ 1.toByte
+ ),
+ SUnsignedBigIntMethods.getMethodByName("subtractMod"),
+ Array(
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(3, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 1.toByte
+ ),
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(3, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 2.toByte
+ )
+ ),
+ Map()
+ )
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(BigInteger.valueOf(0)),
+ (CUnsignedBigInt(BigInteger.valueOf(24)), CUnsignedBigInt(BigInteger.valueOf(10)))) ->
+ new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(6))), None)),
+ (CUnsignedBigInt(BigInteger.valueOf(24)),
+ (CUnsignedBigInt(BigInteger.valueOf(24)), CUnsignedBigInt(BigInteger.valueOf(24)))) ->
+ new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(0))), None))
+ ),
+ subtractMod
+ )
+
+ lazy val multiplyMod = newFeature(
+ { (x: (UnsignedBigInt, (UnsignedBigInt, UnsignedBigInt))) => x._1.asInstanceOf[UnsignedBigInt].multiplyMod(x._2._1, x._2._2) },
+ "{ (x: (UnsignedBigInt, (UnsignedBigInt, UnsignedBigInt))) => x._1.multiplyMod(x._2._1, x._2._2) }",
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt)))),
+ BlockValue(
+ Array(
+ ValDef(
+ 3,
+ List(),
+ SelectField.typed[Value[STuple]](
+ ValUse(1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ 2.toByte
+ )
+ )
+ ),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SPair(SUnsignedBigInt, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ 1.toByte
+ ),
+ SUnsignedBigIntMethods.getMethodByName("multiplyMod"),
+ Array(
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(3, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 1.toByte
+ ),
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(3, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 2.toByte
+ )
+ ),
+ Map()
+ )
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(CryptoConstants.groupOrder),
+ (CUnsignedBigInt(CryptoConstants.groupOrder), CUnsignedBigInt(CryptoConstants.groupOrder))) ->
+ new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(0))), None))
+ ),
+ multiplyMod
+ )
+
+ lazy val modInverse = newFeature(
+ { (x: (UnsignedBigInt, UnsignedBigInt)) => x._1.asInstanceOf[UnsignedBigInt].modInverse(x._2) },
+ "{ (x: (UnsignedBigInt, UnsignedBigInt)) => x._1.modInverse(x._2) }",
+ FuncValue(
+ Array((1, SPair(SUnsignedBigInt, SUnsignedBigInt))),
+ MethodCall.typed[Value[SUnsignedBigInt.type]](
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 1.toByte
+ ),
+ SUnsignedBigIntMethods.getMethodByName("modInverse"),
+ Array(
+ SelectField.typed[Value[SUnsignedBigInt.type]](
+ ValUse(1, SPair(SUnsignedBigInt, SUnsignedBigInt)),
+ 2.toByte
+ )
+ ),
+ Map()
+ )
+ ),
+ sinceVersion = V6SoftForkVersion)
+
+ verifyCases(
+ Seq(
+ (CUnsignedBigInt(BigInteger.valueOf(12)), CUnsignedBigInt(BigInteger.valueOf(5))) ->
+ new Expected(ExpectedResult(Success(CUnsignedBigInt(BigInteger.valueOf(3))), None))
+ ),
+ modInverse
+ )
+
+ }
+
property("Global.some") {
lazy val some = newFeature(
{ (x: Byte) => CSigmaDslBuilder.some[Byte](x) },
diff --git a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
index de9e080862..7f3f28b791 100644
--- a/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
+++ b/sc/shared/src/test/scala/sigma/SigmaDslTesting.scala
@@ -1376,6 +1376,7 @@ class SigmaDslTesting extends AnyPropSpec
case IntType => arbInt
case LongType => arbLong
case BigIntRType => arbBigInt
+ case UnsignedBigIntRType => arbUnsignedBigInt
case GroupElementRType => arbGroupElement
case SigmaPropRType => arbSigmaProp
case BoxRType => arbBox
@@ -1404,7 +1405,7 @@ class SigmaDslTesting extends AnyPropSpec
*/
def updateArbitrary[A](t: RType[A], sampled: Sampled[A]) = {
t match {
- case BigIntRType | GroupElementRType | SigmaPropRType |
+ case BigIntRType | UnsignedBigIntRType | GroupElementRType | SigmaPropRType |
BoxRType | PreHeaderRType | HeaderRType | AvlTreeRType |
_: CollType[_] | _: PairType[_,_] | _: OptionType[_] =>
val newArb = Arbitrary(Gen.oneOf(sampled.samples))
diff --git a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala
index ce02bf8e08..0504a79c65 100644
--- a/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/ErgoTreeSpecification.scala
@@ -7,11 +7,13 @@ import sigma.ast.SCollection.SByteArray
import sigma.ast._
import sigma.ast.syntax.{SValue, SigmaPropValue, TrueSigmaProp}
import sigma.data.RType.asType
-import sigma.data.{CBox, Nullable, RType, TrivialProp}
+import sigma.data.{Nullable, RType, TrivialProp}
import sigma.validation.ValidationException
import sigma.validation.ValidationRules.CheckTypeCode
import ErgoTree.HeaderType
import SCollectionMethods.checkValidFlatmap
+import sigma.ast.SBigIntMethods.{ToUnsigned, ToUnsignedMod}
+import sigma.ast.SUnsignedBigIntMethods.{ModInverseMethod, ModMethod, MultiplyModMethod, PlusModMethod, SubtractModMethod, ToSignedMethod}
import sigmastate.eval.CProfiler
import sigmastate.helpers.{ErgoLikeContextTesting, SigmaPPrint}
import sigmastate.interpreter.Interpreter.ReductionResult
@@ -264,7 +266,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C
val typeCodes = Table(
("constant", "expectedValue"),
- (SPrimType.LastPrimTypeCode, 8),
+ (SPrimType.LastPrimTypeCode, 9),
(SPrimType.MaxPrimTypeCode, 11)
)
@@ -285,6 +287,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C
(SBigInt, 6, true, true, true),
(SGroupElement, 7, true, true, false),
(SSigmaProp, 8, true, true, false),
+ (SUnsignedBigInt, 9, true, true, true),
(SBox, 99, false, false, false),
(SAvlTree, 100, false, false, false),
(SContext, 101, false, false, false),
@@ -430,17 +433,55 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C
MInfo(10, BitwiseAndMethod, isResolvableFromIds = true),
MInfo(11, BitwiseXorMethod, isResolvableFromIds = true),
MInfo(12, ShiftLeftMethod, isResolvableFromIds = true),
- MInfo(13, ShiftRightMethod, isResolvableFromIds = true)
+ MInfo(13, ShiftRightMethod, isResolvableFromIds = true),
+ MInfo(14, ToUnsigned, isResolvableFromIds = true),
+ MInfo(15, ToUnsignedMod, isResolvableFromIds = true)
) else Seq.empty)
, true)
},
+ {
+ if (isV6Activated) {
+ // SUnsignedBigInt inherit methods from SNumericType.methods
+ // however they are not resolvable via SBigInt.typeId before v6.0
+ import SNumericTypeMethods._
+ (SUnsignedBigInt.typeId, Seq(
+ MInfo(methodId = 1, ToByteMethod, isResolvableFromIds = true),
+ MInfo(2, ToShortMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(3, ToIntMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(4, ToLongMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(5, ToBigIntMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(6, ToBytesMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(7, ToBitsMethod, isResolvableFromIds = if (isV6Activated) true else false),
+ MInfo(8, BitwiseInverseMethod, isResolvableFromIds = true),
+ MInfo(9, BitwiseOrMethod, isResolvableFromIds = true),
+ MInfo(10, BitwiseAndMethod, isResolvableFromIds = true),
+ MInfo(11, BitwiseXorMethod, isResolvableFromIds = true),
+ MInfo(12, ShiftLeftMethod, isResolvableFromIds = true),
+ MInfo(13, ShiftRightMethod, isResolvableFromIds = true),
+ MInfo(14, ModInverseMethod, true),
+ MInfo(15, PlusModMethod, true),
+ MInfo(16, SubtractModMethod, true),
+ MInfo(17, MultiplyModMethod, true),
+ MInfo(18, ModMethod, true),
+ MInfo(19, ToSignedMethod, true)
+ ), true)
+ } else {
+ (SUnsignedBigInt.typeId, Seq.empty, false)
+ }
+ },
{ import SGroupElementMethods._
(SGroupElement.typeId, Seq(
MInfo(2, GetEncodedMethod),
MInfo(3, ExponentiateMethod),
MInfo(4, MultiplyMethod),
MInfo(5, NegateMethod)
- ), true)
+ ) ++ {
+ if(VersionContext.current.isV6SoftForkActivated) {
+ Seq(MInfo(6, ExponentiateUnsignedMethod))
+ } else {
+ Seq.empty
+ }
+ }, true)
},
{ import SSigmaPropMethods._
(SSigmaProp.typeId, Seq(
@@ -519,7 +560,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C
(SGlobal.typeId, Seq(
MInfo(1, groupGeneratorMethod), MInfo(2, xorMethod)
) ++ (if (isV6Activated) {
- Seq(MInfo(3, serializeMethod), MInfo(4, deserializeToMethod), MInfo(5, fromBigEndianBytesMethod), MInfo(6, encodeNBitsMethod), MInfo(7, decodeNBitsMethod), MInfo(8, powHitMethod), MInfo(9, someMethod), MInfo(10, noneMethod)) // methods added in v6.0
+ Seq(MInfo(3, serializeMethod), MInfo(4, deserializeToMethod), MInfo(5, FromBigEndianBytesMethod), MInfo(6, encodeNBitsMethod), MInfo(7, decodeNBitsMethod), MInfo(8, powHitMethod), MInfo(9, someMethod), MInfo(10, noneMethod)) // methods added in v6.0
} else {
Seq.empty[MInfo]
}), true)
@@ -624,7 +665,7 @@ class ErgoTreeSpecification extends SigmaDslTesting with ContractsTestkit with C
}
property("MethodCall on numerics") {
- forAll(Table[STypeCompanion]("type", SByte, SShort, SInt, SLong, SBigInt)) { t =>
+ forAll(Table[STypeCompanion]("type", SByte, SShort, SInt, SLong, SBigInt, SUnsignedBigInt)) { t =>
// this methods are expected to fail resolution in before v6.0
if (!isV6Activated) {
(1 to 7).foreach { methodId =>
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
index 01473b47a1..2194414ab0 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/BasicOpsSpecification.scala
@@ -17,8 +17,13 @@ import sigma.{Colls, SigmaTestingData}
import sigma.Extensions.ArrayOps
import sigma.{SigmaTestingData, VersionContext}
import sigma.VersionContext.{V6SoftForkVersion, withVersions}
+import sigma.VersionContext.V6SoftForkVersion
+import sigma.VersionContext
+import sigma.GroupElement
+import sigma.VersionContext.V6SoftForkVersion
import sigma.ast.SCollection.SByteArray
import sigma.ast.SType.AnyOps
+import sigma.data.{AvlTreeData, CAnyValue, CBigInt, CGroupElement, CSigmaDslBuilder}
import sigma.data.{AvlTreeData, CAnyValue, CHeader, CSigmaDslBuilder}
import sigma.data.{AvlTreeData, AvlTreeFlags, CAND, CAnyValue, CHeader, CSigmaDslBuilder, CSigmaProp}
import sigma.util.StringUtil._
@@ -34,8 +39,9 @@ import sigmastate.interpreter.Interpreter._
import sigma.ast.Apply
import sigma.eval.EvalSettings
import sigma.exceptions.InvalidType
-import sigma.serialization.ErgoTreeSerializer
+import sigma.serialization.{ErgoTreeSerializer, SerializerException}
import sigma.interpreter.{ContextExtension, ProverResult}
+import sigma.validation.ValidationException
import sigma.util.NBitsUtils
import sigma.serialization.{DataSerializer, ErgoTreeSerializer, SigmaByteWriter}
import sigma.util.Extensions
@@ -45,6 +51,9 @@ import sigmastate.utils.Helpers._
import java.math.BigInteger
import scala.collection.compat.immutable.ArraySeq
+import java.security.SecureRandom
+import scala.annotation.tailrec
+import scala.util.Try
class BasicOpsSpecification extends CompilerTestingCommons
with CompilerCrossVersionProps {
@@ -173,7 +182,6 @@ class BasicOpsSpecification extends CompilerTestingCommons
flexVerifier.verify(verifyEnv, tree, ctxExt, pr.proof, fakeMessage).get._1 shouldBe true
}
-
property("getVarFromInput") {
def getVarTest(): Assertion = {
val customExt = Map(
@@ -231,6 +239,573 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+
+ property("group order deserialization") {
+ val b = SecP256K1Group.q
+
+ val customExt: Seq[(Byte, EvaluatedValue[_ <: SType])] = Map(
+ 0.toByte -> UnsignedBigIntConstant(b)
+ ).toSeq
+
+ def deserTest() = {test("restoring q", env, customExt,
+ s"""{
+ | val b1 = unsignedBigInt(\"${b.toString}\")
+ | val b2 = getVar[UnsignedBigInt](0).get
+ | b1 == b2
+ |}
+ | """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy deserTest()
+ } else {
+ deserTest()
+ }
+ }
+
+ property("signed -> unsigned bigint conversion - positive bigint") {
+ val b = new BigInteger("9280562930080889354892980449861222646750586663683904599823322027983929189860")
+ val ub = new BigInteger(1, b.toByteArray)
+
+ def conversionTest() = {test("conversion", env, ext,
+ s"""{
+ | val b = bigInt(\"${ub.toString}\")
+ | val ub = b.toUnsigned
+ | ub > 1
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ conversionTest()
+ }
+ }
+
+ property("signed -> unsigned bigint conversion - negative bigint") {
+ def conversionTest() = {test("conversion", env, ext,
+ s"""{
+ | val b = bigInt("-1")
+ | val ub = b.toUnsigned
+ | ub > 0
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ an[Exception] should be thrownBy conversionTest()
+ }
+ }
+
+ property("unsigned bigint - attempt to create from negative value") {
+ def conversionTest() = {test("conversion", env, ext,
+ s"""{
+ | val m = unsignedBigInt("-5")
+ | m >= 0
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ an[sigma.exceptions.InvalidArguments] should be thrownBy conversionTest()
+ }
+ }
+
+
+ property("signed -> unsigned bigint conversion - negative bigint - mod") {
+ def conversionTest() = {test("conversion", env, ext,
+ s"""{
+ | val b = bigInt("-1")
+ | val m = unsignedBigInt("5")
+ | val ub = b.toUnsignedMod(m)
+ | ub >= 0
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ conversionTest()
+ }
+ }
+
+ property("signed -> unsigned bigint conversion - negative bigint - mod - 2") {
+ def conversionTest() = {test("conversion", env, ext,
+ s"""{
+ | val t = (bigInt("-1"), bigInt("5"))
+ | val b = t._1
+ | val m = t._2
+ | val ub = b.toUnsignedMod(m.toUnsigned)
+ | ub >= 0
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ conversionTest()
+ }
+ }
+
+ property("unsigned bigint - add") {
+ def conversionTest() = {test("add", env, ext,
+ s"""{
+ | val a = unsignedBigInt("5")
+ | val b = unsignedBigInt("10")
+ | val res = a + b
+ | res == 15
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ conversionTest()
+ }
+ }
+
+ property("unsigned bigint - subtract with neg result") {
+ def conversionTest() = {test("subtract", env, ext,
+ s"""{
+ | val a = unsignedBigInt("5")
+ | val b = unsignedBigInt("10")
+ | val res = a - b
+ | res >= 0
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ an[Exception] should be thrownBy conversionTest()
+ }
+ }
+
+ property("unsigned -> signed bigint conversion") {
+ def conversionTest() = {test("conversion", env, ext,
+ s"""{
+ | val ub = unsignedBigInt("10")
+ | val b = ub.toSigned
+ | b - 11 == bigInt("-1")
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ conversionTest()
+ }
+ }
+
+ property("unsigned -> signed overflow") {
+ def conversionTest() = {test("conversion", env, ext,
+ s"""{
+ | val ub = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | ub.toSigned > 0
+ | } """.stripMargin,
+ null,
+ true
+ )}
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy conversionTest()
+ } else {
+ val t = Try(conversionTest())
+ // on JS exception is ArithmeticException directly, on JVM, ArithmeticException wrapped into InvocationTargetException
+ t.failed.get match {
+ case e: java.lang.ArithmeticException => e.getMessage.startsWith("BigInteger out of 256 bit range") shouldBe true
+ case e: Throwable => e.getCause.getMessage.startsWith("BigInteger out of 256 bit range") shouldBe true
+ }
+ }
+ }
+
+ property("schnorr sig check") {
+
+ val g = CGroupElement(SecP256K1Group.generator)
+
+ def randBigInt: BigInt = {
+ val random = new SecureRandom()
+ val values = new Array[Byte](32)
+ random.nextBytes(values)
+ BigInt(values).mod(SecP256K1Group.q)
+ }
+
+ @tailrec
+ def sign(msg: Array[Byte], secretKey: BigInt): (GroupElement, BigInt) = {
+ val r = randBigInt
+
+ val a: GroupElement = g.exp(CBigInt(r.bigInteger))
+ val z = (r + secretKey * BigInt(scorex.crypto.hash.Blake2b256(msg))).mod(CryptoConstants.groupOrder)
+
+ if(z.bitLength > 255) {
+ (a, z)
+ } else {
+ sign(msg,secretKey)
+ }
+ }
+
+ val holderSecret = randBigInt
+ val holderPk = g.exp(CBigInt(holderSecret.bigInteger))
+
+ val message = Array.fill(5)(1.toByte)
+
+ val (a, z) = sign(message, holderSecret)
+
+ val customExt: Seq[(Byte, EvaluatedValue[_ <: SType])] = Map(
+ 0.toByte -> GroupElementConstant(holderPk),
+ 1.toByte -> GroupElementConstant(a),
+ 2.toByte -> UnsignedBigIntConstant(z.bigInteger)
+ ).toSeq
+
+ def schnorrTest() = {
+ test("schnorr", env, customExt,
+ s"""{
+ |
+ | val g: GroupElement = groupGenerator
+ | val holder = getVar[GroupElement](0).get
+ |
+ | val message = fromBase16("${Base16.encode(message)}")
+ | val e: Coll[Byte] = blake2b256(message) // weak Fiat-Shamir
+ | val eInt = byteArrayToBigInt(e) // challenge as big integer
+ |
+ | // a of signature in (a, z)
+ | val a = getVar[GroupElement](1).get
+ | val aBytes = a.getEncoded
+ |
+ | // z of signature in (a, z)
+ | val z = getVar[UnsignedBigInt](2).get
+ |
+ | // Signature is valid if g^z = a * x^e
+ | val properSignature = g.exp(z) == a.multiply(holder.exp(eInt))
+ | sigmaProp(properSignature)
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy schnorrTest()
+ } else {
+ schnorrTest()
+ }
+ }
+
+ property("unsigned bigint - arith") {
+ def miTest() = {
+ test("modInverse", env, ext,
+ s"""{
+ | val bi1 = unsignedBigInt("248486720836984554860790790898080606")
+ | val bi2 = unsignedBigInt("2484867208369845548607907908980997780606")
+ | val m = (bi1 * bi1 + bi2 * bi1) / bi1 - bi2
+ | m > 0
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy miTest()
+ } else {
+ miTest()
+ }
+ }
+
+ property("mod") {
+ def miTest() = {
+ test("mod", env, ext,
+ s"""{
+ | val bi = unsignedBigInt("248486720836984554860790790898080606")
+ | val m = unsignedBigInt("575879797")
+ | bi.mod(m) < bi
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy miTest()
+ } else {
+ miTest()
+ }
+ }
+
+ property("modInverse") {
+ def miTest() = {
+ test("modInverse", env, ext,
+ s"""{
+ | val bi = unsignedBigInt("248486720836984554860790790898080606")
+ | val m = unsignedBigInt("575879797")
+ | bi.modInverse(m) > 0
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy miTest()
+ } else {
+ miTest()
+ }
+ }
+
+ property("mod ops - plus") {
+ def miTest() = {
+ test("modInverse", env, ext,
+ s"""{
+ | val bi1 = unsignedBigInt("248486720836984554860790790898080606")
+ | val bi2 = unsignedBigInt("2484867208369845548607907908980997780606")
+ | val m = unsignedBigInt("575879797")
+ | bi1.plusMod(bi2, m) > 0
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy miTest()
+ } else {
+ miTest()
+ }
+ }
+
+ property("mod ops - subtract") {
+ def miTest() = {
+ test("subtractMod", env, ext,
+ s"""{
+ | val bi1 = unsignedBigInt("2")
+ | val bi2 = unsignedBigInt("4")
+ | val m = unsignedBigInt("575879797")
+ | bi1.subtractMod(bi2, m) > 0
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy miTest()
+ } else {
+ miTest()
+ }
+ }
+
+ property("mod ops - multiply") {
+ def miTest() = {
+ test("modInverse", env, ext,
+ s"""{
+ | val bi1 = unsignedBigInt("248486720836984554860790790898080606")
+ | val bi2 = unsignedBigInt("2484867208369845548607907908980997780606")
+ | val m = unsignedBigInt("575879797")
+ | bi1.multiplyMod(bi2, m) > 0
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy miTest()
+ } else {
+ miTest()
+ }
+ }
+
+ // todo: finish the range proof verification script and test
+ ignore("Bulletproof verification for a range proof") {
+ /*
+ * Original range proof verifier code by Benedikt Bunz:
+ *
+ VectorBase vectorBase = params.getVectorBase();
+ PeddersenBase base = params.getBase();
+ int n = vectorBase.getGs().size();
+ T a = proof.getaI();
+ T s = proof.getS();
+
+ BigInteger q = params.getGroup().groupOrder();
+ BigInteger y = ProofUtils.computeChallenge(q, input, a, s);
+
+ FieldVector ys = FieldVector.from(VectorX.iterate(n, BigInteger.ONE, y::multiply), q);
+
+ BigInteger z = ProofUtils.challengeFromints(q, y);
+
+ BigInteger zSquared = z.pow(2).mod(q);
+ BigInteger zCubed = z.pow(3).mod(q);
+
+ FieldVector twos = FieldVector.from(VectorX.iterate(n, BigInteger.ONE, bi -> bi.shiftLeft(1)), q);
+ FieldVector twoTimesZSquared = twos.times(zSquared);
+ GeneratorVector tCommits = proof.gettCommits();
+
+ BigInteger x = ProofUtils.computeChallenge(q,z, tCommits);
+
+ BigInteger tauX = proof.getTauX();
+ BigInteger mu = proof.getMu();
+ BigInteger t = proof.getT();
+ BigInteger k = ys.sum().multiply(z.subtract(zSquared)).subtract(zCubed.shiftLeft(n).subtract(zCubed));
+ T lhs = base.commit(t.subtract(k), tauX);
+ T rhs = tCommits.commit(Arrays.asList(x, x.pow(2))).add(input.multiply(zSquared));
+ System.out.println("y " + y);
+ System.out.println("z " + z);
+
+ System.out.println("x " + x);pow
+ equal(lhs, rhs, "Polynomial identity check failed, LHS: %s, RHS %s");
+ BigInteger uChallenge = ProofUtils.challengeFromints(q, x, tauX, mu, t);
+ System.out.println("u " + uChallenge);
+ T u = base.g.multiply(uChallenge);
+ GeneratorVector hs = vectorBase.getHs();
+ GeneratorVector gs = vectorBase.getGs();
+ GeneratorVector hPrimes = hs.haddamard(ys.invert());
+ FieldVector hExp = ys.times(z).add(twoTimesZSquared);
+ T P = a.add(s.multiply(x)).add(gs.sum().multiply(z.negate())).add(hPrimes.commit(hExp)).subtract(base.h.multiply(mu)).add(u.multiply(t));
+ VectorBase primeBase = new VectorBase<>(gs, hPrimes, u);
+ // System.out.println("PVerify "+P.normalize());
+ // System.out.println("XVerify" +x);
+ // System.out.println("YVerify" +y);
+ // System.out.println("ZVerify" +z);
+ // System.out.println("uVerify" +u);
+
+ EfficientInnerProductVerifier verifier = new EfficientInnerProductVerifier<>();
+ verifier.verify(primeBase, P, proof.getProductProof(), uChallenge);
+ */
+
+ val g = CGroupElement(SecP256K1Group.generator)
+
+ def rangeTest() = {
+ test("range proof", env, ext,
+ s"""{
+ | // range proof input data
+ | val input: GroupElement = getVar[GroupElement](0).get
+ |
+ | // proof data
+ | val ai: GroupElement = getVar[GroupElement](1).get
+ | val s: GroupElement = getVar[GroupElement](2).get
+ | val tCommits: Coll[GroupElement] = getVar[Coll[GroupElement]](3).get
+ | val tauX: UnsignedBigInt = getVar[UnsignedBigInt](4).get
+ | val mu: UnsignedBigInt = getVar[UnsignedBigInt](5).get
+ | val t: UnsignedBigInt = getVar[UnsignedBigInt](6).get
+ |
+ | // inner product proof
+ | val L: Coll[GroupElement] = getVar[Coll[GroupElement]](7).get
+ | val R: Coll[GroupElement] = getVar[Coll[GroupElement]](8)).get
+ | val a: UnsignedBigInt = getVar[UnsignedBigInt](9).get
+ | val b: UnsignedBigInt = getVar[UnsignedBigInt](10).get
+ |
+ | // proof verification:
+ | val Q = lWeights.size
+ |
+ | val q // group order = getVar[UnsignedBigInt](11).get
+ |
+ | val yBytes = sha256(q.toBytes ++ input.getEncoded ++ aI.getEncoded ++ s.getEncoded)
+ |
+ | val y = byteArrayToBigInt(yBytes).toUnsignedMod(q)
+ |
+ | val ys =
+ |
+ | val z = byteArrayToBigInt(sha256(q.toBytes ++ yBytes)).toUnsignedMod(q)
+ | val zSquared = z.multiplyMod(z, q)
+ | val zCubed = zSquared.multiplyMod(z, q)
+ |
+ | // def times() : // todo: implement
+ |
+ | // ops needed: modInverse, mod ops
+ |
+ | sigmaProp(zCubed > 0)
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy rangeTest()
+ } else {
+ rangeTest()
+ }
+ }
+
+ // todo: complete
+ ignore("Bulletproof verification for a circuit proof") {
+
+ val g = CGroupElement(SecP256K1Group.generator)
+
+ def circuitTest() = {
+ test("schnorr", env, ext,
+ s"""{
+ | // circuit data - should be provided via data input likely
+ | val lWeights = Coll[UnsignedBigInt]
+ | val rWeights: Coll[UnsignedBigInt]
+ | val oWeights: Coll[UnsignedBigInt]
+ | val commitmentWeights: Coll[UnsignedBigInt]
+ |
+ | val cs: Coll[UnsignedBigInt]
+ | val commitments: Coll[GroupElement]
+ |
+ | // proof data
+ | val ai: GroupElement
+ | val ao: GroupElement
+ | val s: GroupElement
+ | val tCommits: Coll[GroupElement]
+ | val tauX: UnsignedBigInt
+ | val mu: UnsignedBigInt
+ | val t: UnsignedBigInt
+ |
+ | // inner product proof
+ | val L: Coll[GroupElement]
+ | val R: Coll[GroupElement]
+ | val a: UnsignedBigInt
+ | val b: UnsignedBigInt
+ |
+ | // proof verification:
+ | val Q = lWeights.size
+ |
+ | val q // group order
+ |
+ | val yBytes = sha256(q.toBytes ++ aI.getEncoded ++ aO.getEncoded ++ s.getEncoded)
+ |
+ | val y = byteArrayToBigInt(yBytes) // should be to unsigned bigint
+ |
+ | val z = byteArrayToBigInt(sha256(y ++ q.toBytes))
+ |
+ |
+ |
+ | sigmaProp(properSignature)
+ |}""".stripMargin,
+ null,
+ true
+ )
+ }
+
+ if (activatedVersionInTests < V6SoftForkVersion) {
+ an[Exception] should be thrownBy circuitTest()
+ } else {
+ circuitTest()
+ }
+ }
+
property("Byte.toBits") {
val customExt = Map(
1.toByte -> ByteConstant(1)
@@ -289,6 +864,42 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+
+ property("UnsignedBigInt.toBits") {
+ def toBitsTest() = test("UnsignedBigInt.toBits", env, ext,
+ s"""{
+ | val b = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | val ba = b.toBits
+ | ba.size == 256
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBitsTest()
+ } else {
+ an[ValidationException] shouldBe thrownBy(toBitsTest())
+ }
+ }
+
+ property("UnsignedBigInt.toBits - 2") {
+ def toBitsTest() = test("UnsignedBigInt.toBits", env, ext,
+ s"""{
+ | val b = unsignedBigInt("5")
+ | val ba = b.toBits
+ | ba.size == 8 && ba == Coll(false, false, false, false, false, true, false, true)
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBitsTest()
+ } else {
+ an[ValidationException] shouldBe thrownBy(toBitsTest())
+ }
+ }
+
+
property("BigInt.bitwiseInverse") {
def bitwiseInverseTest(): Assertion = test("BigInt.bitwiseInverse", env, ext,
s"""{
@@ -306,6 +917,23 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+ property("UnsignedBigInt.bitwiseInverse") {
+ def bitwiseInverseTest(): Assertion = test("UnsignedBigInt.bitwiseInverse", env, ext,
+ s"""{
+ | val b = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | val bi = b.bitwiseInverse
+ | bi.bitwiseInverse == b
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseInverseTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseInverseTest())
+ }
+ }
+
property("Byte.bitwiseInverse") {
def bitwiseInverseTest(): Assertion = test("Byte.bitwiseInverse", env, ext,
@@ -380,6 +1008,40 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+ property("UnsignedBigInt.bitwiseOr") {
+ def bitwiseOrTest(): Assertion = test("BigInt.bitwiseOr", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | x.bitwiseOr(x) == x
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseOrTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseOrTest())
+ }
+ }
+
+ property("UnsignedBigInt.bitwiseOr - 2") {
+ def bitwiseOrTest(): Assertion = test("BigInt.bitwiseOr", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | val y = unsignedBigInt("121")
+ | val z = unsignedBigInt("115792089237316195423570985008687907852837564279074904382605163141518161494393")
+ | x.bitwiseOr(y) == z && y.bitwiseOr(x) == z
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseOrTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseOrTest())
+ }
+ }
+
property("BigInt.bitwiseAnd") {
def bitwiseAndTest(): Assertion = test("BigInt.bitwiseAnd", env, ext,
s"""{
@@ -397,6 +1059,43 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+ property("UnsignedBigInt.bitwiseAnd") {
+ def bitwiseAndTest(): Assertion = test("UnsignedBigInt.bitwiseAnd", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | val y = 0.toBigInt.toUnsigned
+ | x.bitwiseAnd(y) == y
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseAndTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest())
+ }
+ }
+
+ property("UnsignedBigInt.bitwiseAnd - 2") {
+ def bitwiseAndTest(): Assertion = test("UnsignedBigInt.bitwiseAnd", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | val y = unsignedBigInt("1157920892373161954235709850086879078528375642790749043826051631415181614337")
+ | val z = unsignedBigInt("1157920892373161954235709850086879078522970439492889181512311797126516834561")
+ |
+ | // cross-checked with wolfram alpha
+ | x.bitwiseAnd(y) == z
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseAndTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest())
+ }
+ }
+
property("Short.bitwiseAnd") {
val customExt = Map(
1.toByte -> ShortConstant(32767)
@@ -437,6 +1136,26 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+ property("UnsignedBigInt.bitwiseXor") {
+ def bitwiseAndTest(): Assertion = test("UnsignedBigInt.bitwiseXor", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | val y = unsignedBigInt("1157920892373161954235709850086879078528375642790749043826051631415181614337")
+ | val z = unsignedBigInt("114634168344943033469335275158601028774319999042879875063406591178680309439552")
+ |
+ | // cross-checked with wolfram alpha
+ | x.bitwiseXor(y) == z
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ bitwiseAndTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(bitwiseAndTest())
+ }
+ }
+
property("Byte.shiftLeft") {
def shiftLeftTest(): Assertion = test("Byte.shiftLeft", env, ext,
s"""{
@@ -505,6 +1224,56 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+ property("UnsignedBigInt.shiftLeft") {
+ def shiftLeftTest(): Assertion = test("UnsignedBigInt.shiftLeft", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder.divide(new BigInteger("8"))}")
+ | val y = unsignedBigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | x.shiftLeft(2) == y
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftLeftTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest())
+ }
+ }
+
+ property("UnsignedBigInt.shiftLeft over limits") {
+ def shiftLeftTest(): Assertion = test("UnsignedBigInt.shiftLeft", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | x.shiftLeft(1) > x
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ an[ArithmeticException] shouldBe thrownBy(shiftLeftTest())
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest())
+ }
+ }
+
+
+ property("UnsignedBigInt.shiftLeft - neg shift") {
+ def shiftLeftTest(): Assertion = test("UnsignedBigInt.shiftLeft", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | x.shiftLeft(-1) > x
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ an[java.lang.IllegalArgumentException] shouldBe thrownBy(shiftLeftTest())
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftLeftTest())
+ }
+ }
+
property("BigInt.shiftLeft over limits") {
def shiftLeftTest(): Assertion = test("BigInt.shiftLeft", env, ext,
s"""{
@@ -643,6 +1412,42 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+ property("UnsignedBigInt.shiftRight") {
+ def shiftRightTest(): Assertion = test("UnsignedBigInt.shiftRight", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | val y = 3
+ | val z = unsignedBigInt("${CryptoConstants.groupOrder.divide(new BigInteger("8"))}")
+ | x.shiftRight(y) == z
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ shiftRightTest()
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
+ property("UnsignedBigInt.shiftRight - neg shift") {
+ def shiftRightTest(): Assertion = test("UnsignedBigInt.shiftRight", env, ext,
+ s"""{
+ | val x = unsignedBigInt("${CryptoConstants.groupOrder.divide(new BigInteger("2"))}")
+ | val y = -2
+ | val z = unsignedBigInt("${CryptoConstants.groupOrder.divide(new BigInteger("8"))}")
+ | z.shiftRight(y) == x
+ |}""".stripMargin,
+ null
+ )
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ an[java.lang.IllegalArgumentException] shouldBe thrownBy(shiftRightTest())
+ } else {
+ an[sigma.validation.ValidationException] shouldBe thrownBy(shiftRightTest())
+ }
+ }
+
property("getVarFromInput - invalid var") {
def getVarTest(): Assertion = {
val customExt = Map(
@@ -993,6 +1798,37 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}
+ property("UnsignedBigInt.toBytes") {
+ val script = s"""{
+ | val l = unsignedBigInt("${CryptoConstants.groupOrder}")
+ | l.toBytes.size == 32
+ | }""".stripMargin
+
+ def toBytesTest() = test("UnsignedBigInt.toBytes", env, ext, script, null)
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBytesTest()
+ } else {
+ an[ValidationException] shouldBe thrownBy(toBytesTest())
+ }
+ }
+
+ property("UnsignedBigInt.toBytes - 2") {
+ val script = s"""{
+ | val l = unsignedBigInt("5")
+ | val bs = l.toBytes
+ | bs.size == 1 && bs == Coll(5.toByte)
+ | }""".stripMargin
+
+ def toBytesTest() = test("UnsignedBigInt.toBytes", env, ext, script, null)
+
+ if (VersionContext.current.isV6SoftForkActivated) {
+ toBytesTest()
+ } else {
+ an[ValidationException] shouldBe thrownBy(toBytesTest())
+ }
+ }
+
property("serialize - byte array") {
def deserTest() = test("serialize", env, ext,
s"""{
diff --git a/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala b/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala
index 9d0ffc880b..8d3d09de74 100644
--- a/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala
+++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala
@@ -138,7 +138,7 @@ class OracleExamplesSpecification extends CompilerTestingCommons
LastBlockUtxoRootHash, SAvlTreeMethods.getMethod,
IndexedSeq(ExtractId(GetVarBox(22: Byte).get), GetVarByteArray(23: Byte).get)).asOption[SByteArray]),
EQ(extract[SByteArray](ErgoBox.ScriptRegId), ByteArrayConstant(ErgoTree.fromSigmaBoolean(oraclePubKey).bytes)),
- EQ(Exponentiate(GroupGenerator, extract[SBigInt.type](reg3)),
+ EQ(Exponentiate(GroupGenerator, extract[SBigInt.type](reg3)(SBigInt)),
MultiplyGroup(extract[SGroupElement.type](reg2),
Exponentiate(GroupElementConstant(oraclePubImage.value),
ByteArrayToBigInt(
diff --git a/sdk/shared/src/main/scala/org/ergoplatform/sdk/utils/Zero.scala b/sdk/shared/src/main/scala/org/ergoplatform/sdk/utils/Zero.scala
index 78dfe2dc94..a337ad44a8 100644
--- a/sdk/shared/src/main/scala/org/ergoplatform/sdk/utils/Zero.scala
+++ b/sdk/shared/src/main/scala/org/ergoplatform/sdk/utils/Zero.scala
@@ -1,7 +1,7 @@
package org.ergoplatform.sdk.utils
import org.ergoplatform.ErgoBox
-import sigma.data.{AvlTreeData, AvlTreeFlags, CAvlTree, CBigInt, CGroupElement, CSigmaProp, CollType, FuncType, OptionType, PairType, RType, TrivialProp, TupleType}
+import sigma.data.{AvlTreeData, AvlTreeFlags, CAvlTree, CBigInt, CGroupElement, CSigmaProp, CUnsignedBigInt, CollType, FuncType, OptionType, PairType, RType, TrivialProp, TupleType}
import sigma.data.RType._
import scorex.crypto.authds.avltree.batch.BatchAVLProver
import scorex.crypto.hash.{Blake2b256, Digest32}
@@ -11,6 +11,7 @@ import sigma._
import sigma.ast.ErgoTree
import ErgoTree.HeaderType
import sigma.crypto.CryptoConstants
+
import java.math.BigInteger
import scala.language.implicitConversions
@@ -48,6 +49,7 @@ object Zero extends ZeroLowPriority {
implicit val IntIsZero: Zero[Int] = CZero(0)
implicit val LongIsZero: Zero[Long] = CZero(0L)
implicit val BigIntIsZero: Zero[BigInt] = CZero(CBigInt(BigInteger.ZERO))
+ implicit val UnsignedBigIntIsZero: Zero[UnsignedBigInt] = CZero(CUnsignedBigInt(BigInteger.ZERO))
implicit val GroupElementIsZero: Zero[GroupElement] = CZero(CGroupElement(CryptoConstants.dlogGroup.identity))
implicit val AvlTreeIsZero: Zero[AvlTree] = CZero({
val avlProver = new BatchAVLProver[Digest32, Blake2b256.type](keyLength = 32, None)
@@ -88,6 +90,7 @@ object Zero extends ZeroLowPriority {
case LongType => Zero[Long]
case UnitType => Zero[Unit]
case BigIntRType => Zero[BigInt]
+ case UnsignedBigIntRType => Zero[UnsignedBigInt]
case BoxRType => Zero[Box]
case GroupElementRType => Zero[GroupElement]
case AvlTreeRType => Zero[AvlTree]
diff --git a/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala b/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala
index 5835f399cb..7e73b6c93d 100644
--- a/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala
+++ b/sdk/shared/src/test/scala/org/ergoplatform/sdk/DataJsonEncoderSpecification.scala
@@ -44,26 +44,20 @@ class DataJsonEncoderSpecification extends SerializationSpecification {
implicit val tT = Evaluation.stypeToRType(tpe)
implicit val tagT = tT.classTag
- val withVersion = if (tpe == SHeader) {
- Some(VersionContext.V6SoftForkVersion)
- } else {
- None
- }
forAll { xs: Array[T#WrappedType] =>
- roundtrip[SCollection[T]](xs.toColl, SCollection(tpe), withVersion)
- roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)), withVersion)
+ roundtrip[SCollection[T]](xs.toColl, SCollection(tpe))
+ roundtrip[SType](xs.toColl.map(x => (x, x)).asWrappedType, SCollection(STuple(tpe, tpe)))
val nested = xs.toColl.map(x => Colls.fromItems[T#WrappedType](x, x))
- roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe)), withVersion)
+ roundtrip[SCollection[SCollection[T]]](nested, SCollection(SCollection(tpe)))
roundtrip[SType](
xs.toColl.map { x =>
val arr = Colls.fromItems[T#WrappedType](x, x)
(arr, arr)
}.asWrappedType,
- SCollection(STuple(SCollection(tpe), SCollection(tpe))),
- withVersion
+ SCollection(STuple(SCollection(tpe), SCollection(tpe)))
)
}
}
@@ -74,17 +68,11 @@ class DataJsonEncoderSpecification extends SerializationSpecification {
@nowarn implicit val tag : ClassTag[T#WrappedType] = tT.classTag
@nowarn implicit val tAny : RType[Any] = sigma.AnyType
- val withVersion = if (tpe == SHeader) {
- Some(VersionContext.V6SoftForkVersion)
- } else {
- None
- }
-
forAll { in: (T#WrappedType, T#WrappedType) =>
val (x,y) = (in._1, in._2)
- roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe), withVersion)
- roundtrip[SType](((x, y), (x, y)).asWrappedType, STuple(STuple(tpe, tpe), STuple(tpe, tpe)), withVersion)
- roundtrip[SType](((x, y), ((x, y), (x, y))).asWrappedType, STuple(STuple(tpe, tpe), STuple(STuple(tpe, tpe), STuple(tpe, tpe))), withVersion)
+ roundtrip[SType]((x, y).asWrappedType, STuple(tpe, tpe))
+ roundtrip[SType](((x, y), (x, y)).asWrappedType, STuple(STuple(tpe, tpe), STuple(tpe, tpe)))
+ roundtrip[SType](((x, y), ((x, y), (x, y))).asWrappedType, STuple(STuple(tpe, tpe), STuple(STuple(tpe, tpe), STuple(tpe, tpe))))
}
}