Skip to content

Commit

Permalink
unsigned encoding, .toBytes & .toBits tests passing
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti committed Nov 5, 2024
1 parent 1496770 commit ac4bbbc
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ object BigIntegers {
private val MAX_ITERATIONS = 1000

/** Create the given number of random bits.
*
* @param bitLength the number of random bits to create.
* @param random a source of randomness.
* @param random a source of randomness.
* @return a byte array containing random bits.
*/
@throws[IllegalArgumentException]
Expand All @@ -38,8 +39,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))
}

Expand All @@ -52,9 +53,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'")
Expand All @@ -64,7 +65,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
}
Expand Down Expand Up @@ -96,6 +97,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
*/
Expand Down
3 changes: 2 additions & 1 deletion core/shared/src/main/scala/sigma/data/CBigInt.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package sigma.data

import sigma.crypto.BigIntegers
import sigma.util.Extensions.BigIntegerOps
import sigma.{BigInt, Coll, Colls, UnsignedBigInt}

Expand Down Expand Up @@ -83,7 +84,7 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign

override def toLong: Long = wrappedValue.toLongExact

override def toBytes: Coll[Byte] = Colls.fromArray(wrappedValue.toByteArray)
override def toBytes: Coll[Byte] = Colls.fromArray(BigIntegers.asUnsignedByteArray(wrappedValue))

override def compareTo(that: UnsignedBigInt): Int =
wrappedValue.compareTo(that.asInstanceOf[CUnsignedBigInt].wrappedValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, _}

Expand Down Expand Up @@ -34,7 +35,7 @@ class CoreDataSerializer {
w.putUShort(data.length)
w.putBytes(data)
case SUnsignedBigInt => // todo: versioning
val data = v.asInstanceOf[CUnsignedBigInt].wrappedValue.toByteArray
val data = BigIntegers.asUnsignedByteArray(v.asInstanceOf[CUnsignedBigInt].wrappedValue)
w.putUShort(data.length)
w.putBytes(data)
case SGroupElement =>
Expand Down Expand Up @@ -114,11 +115,11 @@ class CoreDataSerializer {
CBigInt(new BigInteger(valueBytes))
case SUnsignedBigInt => // todo: versioning
val size: Short = r.getUShort().toShort
if (size > SBigInt.MaxSizeInBytes + 1) { //todo: use encoding with no sign bit
if (size > SBigInt.MaxSizeInBytes) {
throw new SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes: $size")
}
val valueBytes = r.getBytes(size)
CUnsignedBigInt(new BigInteger(valueBytes))
CUnsignedBigInt(BigIntegers.fromUnsignedByteArray(valueBytes))
case SGroupElement =>
CGroupElement(GroupElementSerializer.parse(r))
case SSigmaProp =>
Expand Down
4 changes: 2 additions & 2 deletions data/shared/src/main/scala/sigma/data/CSigmaDslBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import scorex.crypto.hash.{Blake2b256, Sha256}
import scorex.utils.{Ints, Longs}
import sigma.ast.{AtLeast, SBigInt, SType, SUnsignedBigInt, SubstConstants}
import scorex.utils.Longs
import sigma.crypto.{CryptoConstants, EcPointType, Ecp}
import sigma.crypto.{BigIntegers, CryptoConstants, EcPointType, Ecp}
import sigma.eval.Extensions.EvalCollOps
import sigma.serialization.{DataSerializer, GroupElementSerializer, SigmaSerializer}
import sigma.serialization.{GroupElementSerializer, SerializerException, SigmaSerializer}
Expand Down Expand Up @@ -238,7 +238,7 @@ class CSigmaDslBuilder extends SigmaDslBuilder { dsl =>
if (bytes.length > SUnsignedBigInt.MaxSizeInBytes) {
throw SerializerException(s"BigInt value doesn't not fit into ${SBigInt.MaxSizeInBytes} bytes in fromBigEndianBytes")
}
CUnsignedBigInt(new BigInteger(bytes.toArray).toSignedBigIntValueExact).asInstanceOf[T]
CUnsignedBigInt(BigIntegers.fromUnsignedByteArray(bytes.toArray)).asInstanceOf[T]
case _ => throw new IllegalArgumentException("Unsupported type provided in fromBigEndianBytes")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ object UnsignedBigIntNumericOps {
* For example, the `Int` value `0x12131415` would yield the
* collection of bytes [0x12, 0x13, 0x14, 0x15]
*/
override def toBigEndianBytes(x: UnsignedBigInt): Coll[Byte] = ???
override def toBigEndianBytes(x: UnsignedBigInt): Coll[Byte] = x.toBytes

/**
* @return a numeric value which is inverse of `x` (every bit, including sign, is flipped)
Expand Down
51 changes: 28 additions & 23 deletions sc/shared/src/main/scala/sigma/compiler/ir/GraphBuilding.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1032,28 +1032,6 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
opt.filter(asRep[t => Boolean](argsV(0)))
case _ => throwError()
}
case (ubi: Ref[UnsignedBigInt]@unchecked, SUnsignedBigIntMethods) => method.name match {
case SUnsignedBigIntMethods.ModMethod.name =>
val m = asRep[UnsignedBigInt](argsV(0))
ubi.mod(m)
case SUnsignedBigIntMethods.ModInverseMethod.name =>
val m = asRep[UnsignedBigInt](argsV(0))
ubi.modInverse(m)
case SUnsignedBigIntMethods.PlusModMethod.name =>
val that = asRep[UnsignedBigInt](argsV(0))
val m = asRep[UnsignedBigInt](argsV(1))
ubi.plusMod(that, m)
case SUnsignedBigIntMethods.SubtractModMethod.name =>
val that = asRep[UnsignedBigInt](argsV(0))
val m = asRep[UnsignedBigInt](argsV(1))
ubi.subtractMod(that, m)
case SUnsignedBigIntMethods.MultiplyModMethod.name =>
val that = asRep[UnsignedBigInt](argsV(0))
val m = asRep[UnsignedBigInt](argsV(1))
ubi.multiplyMod(that, m)
case SUnsignedBigIntMethods.ToSignedMethod.name =>
ubi.toSigned
}
case (ge: Ref[GroupElement]@unchecked, SGroupElementMethods) => method.name match {
case SGroupElementMethods.GetEncodedMethod.name =>
ge.getEncoded
Expand Down Expand Up @@ -1226,7 +1204,7 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
g.fromBigEndianBytes(bytes)(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)
Expand Down Expand Up @@ -1263,6 +1241,33 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import sigma.eval.EvalSettings
import sigma.exceptions.InvalidType
import sigma.serialization.{ErgoTreeSerializer, SerializerException}
import sigma.interpreter.{ContextExtension, ProverResult}
import sigma.validation.ValidationException
import sigmastate.utils.Helpers
import sigmastate.utils.Helpers._

Expand Down Expand Up @@ -797,7 +798,7 @@ class BasicOpsSpecification extends CompilerTestingCommons
property("UnsignedBigInt.toBits") {
def toBitsTest() = test("UnsignedBigInt.toBits", env, ext,
s"""{
| val b = bigInt("${CryptoConstants.groupOrder}")
| val b = unsignedBigInt("${CryptoConstants.groupOrder}")
| val ba = b.toBits
| ba.size == 256
|}""".stripMargin,
Expand All @@ -807,7 +808,7 @@ class BasicOpsSpecification extends CompilerTestingCommons
if (VersionContext.current.isV6SoftForkActivated) {
toBitsTest()
} else {
an[SerializerException] shouldBe thrownBy(toBitsTest())
an[ValidationException] shouldBe thrownBy(toBitsTest())
}
}

Expand Down Expand Up @@ -1516,18 +1517,17 @@ class BasicOpsSpecification extends CompilerTestingCommons
}

property("UnsignedBigInt.toBytes") {
def toBytesTest() = test("UnsignedBigInt.toBytes", env, ext,
s"""{
| val l = bigInt("${CryptoConstants.groupOrder}")
| l.toBytes.size == 32
| }""".stripMargin,
null
)
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[SerializerException] shouldBe thrownBy(toBytesTest())
an[ValidationException] shouldBe thrownBy(toBytesTest())
}
}

Expand Down

0 comments on commit ac4bbbc

Please sign in to comment.