Skip to content

Commit

Permalink
mod, toSigned, subtractMod
Browse files Browse the repository at this point in the history
  • Loading branch information
kushti committed Jun 17, 2024
1 parent 72db85b commit fc6d856
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 31 deletions.
13 changes: 3 additions & 10 deletions core/shared/src/main/scala/sigma/SigmaDsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,6 @@ trait UnsignedBigInt {
def mod(m: UnsignedBigInt): UnsignedBigInt
def %(m: UnsignedBigInt): UnsignedBigInt = mod(m)

/**
* Returns a BigInt whose value is {@code (this % that)}.
*
* @param that value by which this BigInt is to be divided, and the
* remainder computed.
* @return { @code this % that}
* @throws ArithmeticException if { @code that} is zero.
*/
def remainder(that: UnsignedBigInt): UnsignedBigInt

/**
* Returns the minimum of this BigInteger and {@code val}.
*
Expand Down Expand Up @@ -287,7 +277,10 @@ trait UnsignedBigInt {

def modInverse(m: UnsignedBigInt): UnsignedBigInt
def plusMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt
def subtractMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt
def multiplyMod(that: UnsignedBigInt, m: UnsignedBigInt): UnsignedBigInt

def toSigned(): BigInt
}


Expand Down
12 changes: 10 additions & 2 deletions core/shared/src/main/scala/sigma/data/CBigInt.scala
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,6 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign

override def mod(m: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.mod(m.asInstanceOf[CUnsignedBigInt].wrappedValue))

override def remainder(that: UnsignedBigInt): UnsignedBigInt = CUnsignedBigInt(wrappedValue.remainder(that.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))
Expand All @@ -113,9 +111,19 @@ case class CUnsignedBigInt(override val wrappedValue: BigInteger) extends Unsign
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))
}

override def toSigned(): BigInt = {
CBigInt(wrappedValue.to256BitValueExact)
}
}
37 changes: 35 additions & 2 deletions data/shared/src/main/scala/sigma/ast/methods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,17 @@ case object SUnsignedBigIntMethods extends SNumericTypeMethods {
bi.plusMod(bi2, m)
}

val MultiplyModMethod = SMethod(this, "multiplyMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 11, ModInverseCostInfo.costKind)
val SubtractModMethod = SMethod(this, "subtractMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 11, ModInverseCostInfo.costKind)
.withIRInfo(MethodCallIrBuilder)
.withInfo(MethodCall, "")

def subtractMod_eval(mc: MethodCall, bi: UnsignedBigInt, bi2: UnsignedBigInt, m: UnsignedBigInt)
(implicit E: ErgoTreeEvaluator): UnsignedBigInt = {
E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) // todo: costing
bi.subtractMod(bi2, m)
}

val MultiplyModMethod = SMethod(this, "multiplyMod", SFunc(Array(this.ownerType, this.ownerType, this.ownerType), this.ownerType), 12, ModInverseCostInfo.costKind)
.withIRInfo(MethodCallIrBuilder)
.withInfo(MethodCall, "")

Expand All @@ -431,12 +441,35 @@ case object SUnsignedBigIntMethods extends SNumericTypeMethods {
bi.multiplyMod(bi2, m)
}

val ModMethod = SMethod(this, "mod", SFunc(Array(this.ownerType, this.ownerType), this.ownerType), 13, ModInverseCostInfo.costKind)
.withIRInfo(MethodCallIrBuilder)
.withInfo(MethodCall, "")

def mod_eval(mc: MethodCall, bi: UnsignedBigInt, m: UnsignedBigInt)
(implicit E: ErgoTreeEvaluator): UnsignedBigInt = {
E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) // todo: costing
bi.mod(m)
}

val ToSignedMethod = SMethod(this, "toSigned", SFunc(Array(this.ownerType), SBigInt), 14, ModInverseCostInfo.costKind)
.withIRInfo(MethodCallIrBuilder)
.withInfo(MethodCall, "")

def toSigned_eval(mc: MethodCall, bi: UnsignedBigInt)
(implicit E: ErgoTreeEvaluator): BigInt = {
E.addCost(ModInverseCostInfo.costKind, mc.method.opDesc) // todo: costing
bi.toSigned()
}

// no 6.0 versioning here as it is done in method containers
protected override def getMethods(): Seq[SMethod] = {
super.getMethods() ++ Seq(
ModInverseMethod,
PlusModMethod,
MultiplyModMethod
SubtractModMethod,
MultiplyModMethod,
ModMethod,
ToSignedMethod
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1021,17 +1021,26 @@ trait GraphBuilding extends Base with DefRewriting { IR: IRContext =>
bi.toUnsignedMod(m)
}
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 =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ import scalan._
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];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,12 +379,26 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") {
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]))
}
}


Expand Down Expand Up @@ -470,12 +484,26 @@ object UnsignedBigInt extends EntityObject("UnsignedBigInt") {
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class BasicOpsSpecification extends CompilerTestingCommons
val b = new BigInteger("9280562930080889354892980449861222646750586663683904599823322027983929189860")
val ub = new BigInteger(1, b.toByteArray)

def conversionTest() = {test("restoring", env, ext,
def conversionTest() = {test("conversion", env, ext,
s"""{
| val b = bigInt(\"${ub.toString}\")
| val ub = b.toUnsigned
Expand All @@ -184,7 +184,7 @@ class BasicOpsSpecification extends CompilerTestingCommons
}

property("signed -> unsigned bigint conversion - negative bigint") {
def conversionTest() = {test("restoring", env, ext,
def conversionTest() = {test("conversion", env, ext,
s"""{
| val b = bigInt("-1")
| val ub = b.toUnsigned
Expand All @@ -202,7 +202,7 @@ class BasicOpsSpecification extends CompilerTestingCommons
}

property("signed -> unsigned bigint conversion - negative bigint - mod") {
def conversionTest() = {test("restoring", env, ext,
def conversionTest() = {test("conversion", env, ext,
s"""{
| val b = bigInt("-1")
| val m = unsignedBigInt("5")
Expand All @@ -220,6 +220,24 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}

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("schnorr sig check") {

val g = CGroupElement(SecP256K1Group.generator)
Expand Down Expand Up @@ -292,6 +310,26 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}

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,
Expand Down Expand Up @@ -333,6 +371,27 @@ class BasicOpsSpecification extends CompilerTestingCommons
}
}

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,
Expand Down Expand Up @@ -365,17 +424,11 @@ class BasicOpsSpecification extends CompilerTestingCommons
T s = proof.getS();
BigInteger q = params.getGroup().groupOrder();
BigInteger y;
if (salt.isPresent()) {
y = ProofUtils.computeChallenge(q, salt.get(), input, a, s);
} else {
y = ProofUtils.computeChallenge(q, input, a, s);
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 z = ProofUtils.challengeFromints(q, y);
BigInteger zSquared = z.pow(2).mod(q);
BigInteger zCubed = z.pow(3).mod(q);
Expand Down Expand Up @@ -445,18 +498,19 @@ class BasicOpsSpecification extends CompilerTestingCommons
|
| val yBytes = sha256(q.toBytes ++ input.getEncoded ++ aI.getEncoded ++ s.getEncoded)
|
| val y = byteArrayToBigInt(yBytes) mod q // should be to unsigned bigint
| val y = byteArrayToBigInt(yBytes).toUnsignedMod(q)
|
| val z = byteArrayToBigInt(sha256(q.toBytes ++ yBytes)) mod q
| val ys =
|
| val zSquared = z * z mod q
| val zCubed = zSquared * z mod q
| 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
| // def times() : // todo: implement
|
| // ops needed: modInverse, mod ops
|
| sigmaProp(properSignature)
| sigmaProp(zCubed > 0)
|}""".stripMargin,
null,
true
Expand Down

0 comments on commit fc6d856

Please sign in to comment.