Skip to content

Commit

Permalink
Merge pull request #863 from ScorexFoundation/restructure-part2
Browse files Browse the repository at this point in the history
[v5.x] Abstract from Bouncycastle (restructure, part 2)
  • Loading branch information
aslesarenko authored Feb 22, 2023
2 parents 91d990b + 250922b commit 844aa38
Show file tree
Hide file tree
Showing 29 changed files with 526 additions and 349 deletions.
14 changes: 3 additions & 11 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ lazy val commonSettings = Seq(
scalaVersion := scala212,
scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports")
case Some((2, 12)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports")
case Some((2, 13)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports", "-release", "8")
case Some((2, 12)) => Seq("-Ywarn-unused:_,imports", "-Ywarn-unused:imports", "-release", "8")
case Some((2, 11)) => Seq()
case _ => sys.error("Unsupported scala version")
}
} ++ scalacReleaseOption,
},
javacOptions ++= javacReleaseOption,
resolvers += Resolver.sonatypeRepo("public"),
licenses := Seq("CC0" -> url("https://creativecommons.org/publicdomain/zero/1.0/legalcode")),
Expand Down Expand Up @@ -56,14 +56,6 @@ lazy val commonSettings = Seq(
),
)

def scalacReleaseOption = {
if (System.getProperty("java.version").startsWith("1."))
// java <9 "-release" is not supported
Seq()
else
Seq("-release", "8") // this is passed to javac as `javac -release 8`
}

def javacReleaseOption = {
if (System.getProperty("java.version").startsWith("1."))
// java <9 "--release" is not supported
Expand Down
4 changes: 2 additions & 2 deletions sigma-api/src/main/scala/special/sigma/SigmaDsl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package special.sigma

import java.math.BigInteger

import org.bouncycastle.math.ec.ECPoint
import special.collection._
import scalan._
import scorex.crypto.authds.{ADDigest, ADValue}
Expand Down Expand Up @@ -200,7 +199,8 @@ trait BigInt {
@scalan.Liftable
@WithMethodCallRecognizers
trait GroupElement {
def isInfinity: Boolean
/** Checks if the provided element is an identity element. */
def isIdentity: Boolean

/** Exponentiate this <code>GroupElement</code> to the given number.
* @param k The power.
Expand Down
2 changes: 0 additions & 2 deletions sigma-api/src/main/scala/special/sigma/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package special

import java.math.BigInteger

import org.bouncycastle.math.ec.ECPoint
import scalan.RType
import scalan.RType.GeneralType

Expand Down Expand Up @@ -30,5 +29,4 @@ package object sigma {
implicit val SigmaDslBuilderRType: RType[SigmaDslBuilder] = RType.fromClassTag(classTag[SigmaDslBuilder])

implicit val BigIntegerRType: RType[BigInteger] = GeneralType(classTag[BigInteger])
implicit val ECPointRType: RType[ECPoint] = GeneralType(classTag[ECPoint])
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ object P2PKAddress {

/** Constructs [[P2PKAddress]] instance using the public key of the given [[ProveDlog]]. */
def apply(pubkey: ProveDlog)(implicit encoder: ErgoAddressEncoder): P2PKAddress = {
val bs = GroupElementSerializer.toBytes(pubkey.h)
val bs = GroupElementSerializer.toBytes(pubkey.value)
new P2PKAddress(pubkey, bs)
}
}
Expand Down
2 changes: 1 addition & 1 deletion sigmastate/src/main/scala/sigmastate/SigSerializer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package sigmastate

import com.typesafe.scalalogging.LazyLogging
import gf2t.GF2_192_Poly
import org.bouncycastle.util.BigIntegers
import sigmastate.crypto.BigIntegers
import scorex.util.encode.Base16
import sigmastate.Values.SigmaBoolean
import sigmastate.basics.DLogProtocol.{ProveDlog, SecondDLogProverMessage}
Expand Down
207 changes: 35 additions & 172 deletions sigmastate/src/main/scala/sigmastate/basics/BcDlogGroup.scala
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
package sigmastate.basics

import java.math.BigInteger
import org.bouncycastle.asn1.x9.X9ECParameters
import org.bouncycastle.crypto.ec.CustomNamedCurves
import org.bouncycastle.math.ec.custom.sec.SecP256K1Point
import org.bouncycastle.math.ec.ECPoint
import org.bouncycastle.util.BigIntegers
import sigmastate.crypto.BigIntegers
import debox.cfor
import sigmastate.crypto.{CryptoContext, CryptoFacade}

import scala.collection.{Seq, mutable}
import scala.util.Try
import scala.collection.mutable

abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) extends DlogGroup[ElemType] {

lazy val curve = x9params.getCurve
/** Base class for EC-based groups where DLOG problem is hard (with bouncycastle-like interface).
* @param ctx context which abstracts basic operations with curve and elements.
*/
abstract class BcDlogGroup(val ctx: CryptoContext) extends DlogGroup {
/** Characteristic of the finite field of the underlying curve. */
lazy val p: BigInteger = ctx.fieldCharacteristic

//modulus of the field
lazy val p: BigInteger = curve.getField.getCharacteristic

//order of the group
lazy val q = x9params.getN
/** Order of the group as defined in ASN.1 def for Elliptic-Curve ECParameters structure.
* See X9.62, for further details.
* For reference implementation see `org.bouncycastle.asn1.x9.X9ECParameters.getN`.
*/
lazy val q: BigInteger = ctx.order

//Now that we have p, we can calculate k which is the maximum length in bytes
// of a string to be converted to a Group Element of this group.
/** Now that we have p, we can calculate k which is the maximum length in bytes
* of a string to be converted to a Group Element of this group.
*/
lazy val k = calcK(p)

/**
Expand All @@ -31,15 +32,15 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex
* It is composed of two main elements. The group element for which the optimized computations
* are built for, called the base and a vector of group elements that are the result of
* exponentiations of order 1,2,4,8,
*/
private class GroupElementsExponentiations(base: ElemType) //group element for which the optimized computations are built for
/**
*
* The constructor creates a map structure in memory.
* Then calculates the exponentiations of order 1,2,4,8 for the given base and save them in the map.
*
* @param base
* @param base group element for which the optimized computations are built for
* @throws IllegalArgumentException
*/ { // build new vector of exponentiations
*
*/
private class GroupElementsExponentiations(base: ElemType) {

private val exponentiations = new mutable.ListBuffer[ElemType]()

Expand Down Expand Up @@ -99,22 +100,11 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex
private val exponentiationsCache = mutable.Map[ElemType, GroupElementsExponentiations]()


//Create the generator
//Assume that (x,y) are the coordinates of a point that is indeed a generator but check that (x,y) are the coordinates of a point.
override lazy val generator: ElemType = x9params.getG.asInstanceOf[ElemType]

/**
* Checks if the given x and y represent a valid point on the given curve,
* i.e. if the point (x, y) is a solution of the curves equation.
*
* @param x coefficient of the point
* @param y coefficient of the point
* @return true if the given x and y represented a valid point on the given curve
/** Creates the generator.
* Assume that (x,y) are the coordinates of a point that is indeed a generator but
* check that (x,y) are the coordinates of a point.
*/
def checkCurveMembership(x: BigInteger, y: BigInteger): Boolean = {
Try(curve.validatePoint(x, y)).isSuccess
}

override lazy val generator: ElemType = ctx.generator

/**
* This function calculates k, the maximum length in bytes of a string to be converted to a Group Element of this group.
Expand All @@ -132,16 +122,14 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex
}

/**
*
* @return the order of this Dlog group
*/
override lazy val order: BigInteger = x9params.getN
override lazy val order: BigInteger = ctx.order

/**
*
* @return the identity of this Dlog group
*/
override lazy val identity: ElemType = curve.getInfinity.asInstanceOf[ElemType]
override lazy val identity: ElemType = ctx.infinity.asInstanceOf[ElemType]

/**
* Calculates the inverse of the given GroupElement.
Expand All @@ -151,7 +139,7 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex
* @throws IllegalArgumentException
**/
override def inverseOf(groupElement: ElemType): ElemType =
groupElement.negate().asInstanceOf[ElemType]
CryptoFacade.negatePoint(groupElement)

/**
* Raises the base GroupElement to the exponent. The result is another GroupElement.
Expand All @@ -163,16 +151,12 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex
*/
override def exponentiate(base: ElemType, exponent: BigInteger): ElemType = {
//infinity remains the same after any exponentiate
if (base.isInfinity) return base
if (CryptoFacade.isInfinityPoint(base)) return base

//If the exponent is negative, convert it to be the exponent modulus q.
val exp = if (exponent.compareTo(BigInteger.ZERO) < 0) exponent.mod(order) else exponent

/*
* BC treats EC as additive group while we treat that as multiplicative group.
* Therefore, exponentiate point is multiply.
*/
base.multiply(exp).asInstanceOf[ElemType]
CryptoFacade.exponentiatePoint(base, exp)
}


Expand All @@ -186,7 +170,7 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex
//However, if a specific Dlog Group has a more efficient implementation then is it advised to override this function in that concrete
//Dlog group. For example we do so in CryptoPpDlogZpSafePrime.
val one = BigInteger.ONE
val qMinusOne = x9params.getN.subtract(one)
val qMinusOne = ctx.order.subtract(one)
// choose a random number x in Zq*
val randNum = BigIntegers.createRandomInRange(one, qMinusOne, secureRandom)
// compute g^x to get a new element
Expand All @@ -213,22 +197,7 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex
* @throws IllegalArgumentException
*/
override def multiplyGroupElements(groupElement1: ElemType, groupElement2: ElemType): ElemType =
groupElement1.add(groupElement2).asInstanceOf[ElemType]


/**
* Computes the product of several exponentiations with distinct bases
* and distinct exponents.
* Instead of computing each part separately, an optimization is used to
* compute it simultaneously.
*
* @param groupElements
* @param exponentiations
* @return the exponentiation result
*/
override def simultaneousMultipleExponentiations(groupElements: Array[ElemType],
exponentiations: Array[BigInteger]): ElemType =
computeLL(groupElements, exponentiations)
CryptoFacade.multiplyPoints(groupElement1, groupElement2)

/**
* Computes the product of several exponentiations of the same base
Expand Down Expand Up @@ -273,113 +242,7 @@ abstract class BcDlogGroup[ElemType <: ECPoint](val x9params: X9ECParameters) ex
*/
override lazy val maxLengthOfByteArrayForEncoding: Int = k


/*
* Computes the simultaneousMultiplyExponentiate using a naive algorithm
*/
protected def computeNaive(groupElements: Array[ElemType], exponentiations: Array[BigInteger]): ElemType =
groupElements.zip(exponentiations)
.iterator
.map { case (base, exp) => exponentiate(base, exp) }
.foldLeft(identity) { case (r, elem) => multiplyGroupElements(elem, r) }


/*
* Compute the simultaneousMultiplyExponentiate by LL algorithm.
* The code is taken from the pseudo code of LL algorithm in http://dasan.sejong.ac.kr/~chlim/pub/multi_exp.ps.
*/
protected def computeLL(groupElements: Array[ElemType], exponentiations: Array[BigInteger]): ElemType = {
val n = groupElements.length
//get the biggest exponent
val bigExp = exponentiations.max
val t = bigExp.bitLength //num bits of the biggest exponent.
val w = getLLW(t) //window size, choose it according to the value of t

//h = n/w
val h = if ((n % w) == 0) n / w else (n / w) + 1

//create pre computation table
val preComp = createLLPreCompTable(groupElements, w, h)

//holds the computation result
var result: ElemType = computeLoop(exponentiations, w, h, preComp, identity, t - 1)
//computes the first loop of the algorithm. This loop returns in the next part of the algorithm with one single tiny change.

//computes the third part of the algorithm
(t - 2).to(0, -1).foreach { j =>
//Y = Y^2
result = exponentiate(result, new BigInteger("2"))
//computes the inner loop
result = computeLoop(exponentiations, w, h, preComp, result, j)
}
result
}

/*
* Computes the loop the repeats in the algorithm.
* for k=0 to h-1
* e=0
* for i=kw to kw+w-1
* if the bitIndex bit in ci is set:
* calculate e += 2^(i-kw)
* result = result *preComp[k][e]
*
*/
private def computeLoop(exponentiations: Array[BigInteger], w: Int, h: Int, preComp: Seq[Seq[ElemType]], result: ElemType, bitIndex: Int) = {
var res = result
cfor(0)(_ < h, _ + 1) { k =>
var e = 0
cfor(k * w)(_ < (k * w + w), _ + 1) { i =>
if (i < exponentiations.length) { //if the bit is set, change the e value
if (exponentiations(i).testBit(bitIndex)) {
val twoPow = Math.pow(2, i - k * w).toInt
e += twoPow
}
}
}
res = multiplyGroupElements(res, preComp(k)(e))
}
res
}

/*
* Creates the preComputation table.
*/
private def createLLPreCompTable(groupElements: Array[ElemType], w: Int, h: Int) = {
val twoPowW = Math.pow(2, w).toInt
//create the pre-computation table of size h*(2^(w))
val preComp: Seq[mutable.Seq[ElemType]] = Seq.fill(h)(mutable.Seq.fill(twoPowW)(identity))

cfor(0)(_ < h, _ + 1) { k =>
cfor(0)(_ < twoPowW, _ + 1) { e =>
cfor(0)(_ < w, _ + 1) { i =>
val baseIndex = k * w + i
if (baseIndex < groupElements.length) {
val base = groupElements(baseIndex)
//if bit i in e is set, change preComp[k][e]
if ((e & (1 << i)) != 0) { //bit i is set
preComp(k)(e) = multiplyGroupElements(preComp(k)(e), base)
}
}
}
}
}
preComp
}

/*
* returns the w value according to the given t
*/
private def getLLW(t: Int): Int = {
if (t <= 10) 2
else if (t <= 24) 3
else if (t <= 60) 4
else if (t <= 144) 5
else if (t <= 342) 6
else if (t <= 797) 7
else if (t <= 1828) 8
else 9
}
}

object SecP256K1 extends BcDlogGroup[SecP256K1Point](CustomNamedCurves.getByName("secp256k1"))
/** Implementation of [[BcDlogGroup]] using SecP256K1 curve. */
object SecP256K1Group extends BcDlogGroup(CryptoFacade.createCryptoContext())
Loading

0 comments on commit 844aa38

Please sign in to comment.