From b4a65a184556e43d2fe2273f8c53e505b074bc0b Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Tue, 1 Aug 2023 21:07:15 +0200 Subject: [PATCH 1/4] secure-random-js: upgrade sigmajsCryptoFacadeVersion = "0.0.7" and implement SecureRandom for js Platform --- build.sbt | 2 +- .../scala/sigmastate/crypto/Platform.scala | 4 ++-- .../crypto/SigmaJsCryptoFacade.scala | 20 +++++++++++++++++++ .../OracleExamplesSpecification.scala | 4 ++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/build.sbt b/build.sbt index 7053fd6555..371536017e 100644 --- a/build.sbt +++ b/build.sbt @@ -186,7 +186,7 @@ lazy val commonDependenies2 = libraryDependencies ++= Seq( "org.scala-lang.modules" %%% "scala-collection-compat" % "2.7.0" ) -val sigmajsCryptoFacadeVersion = "0.0.6" +val sigmajsCryptoFacadeVersion = "0.0.7" lazy val common = crossProject(JVMPlatform, JSPlatform) .in(file("common")) diff --git a/interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala b/interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala index 780b74f9a0..1b963331f2 100644 --- a/interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala +++ b/interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala @@ -120,7 +120,7 @@ object Platform { class Curve // TODO JS: Use JS library for secure source of randomness - type SecureRandom = Random + type SecureRandom = sigmastate.crypto.SecureRandomJS /** Opaque point type. */ @js.native @@ -198,7 +198,7 @@ object Platform { } /** Create JS specific source of secure randomness. */ - def createSecureRandom(): Random = new Random() + def createSecureRandom(): SecureRandom = new SecureRandomJS /** Computes HMAC-SHA512 hash of the given data using the specified key. * diff --git a/interpreter/js/src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala b/interpreter/js/src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala index 3b19095b6a..908d6ee166 100644 --- a/interpreter/js/src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala +++ b/interpreter/js/src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala @@ -1,5 +1,7 @@ package sigmastate.crypto +import debox.cfor + import scala.scalajs.js import scala.scalajs.js.annotation.JSImport import scala.scalajs.js.typedarray.Uint8Array @@ -109,6 +111,24 @@ object CryptoFacadeJs extends js.Object { def generatePbkdf2Key( normalizedMnemonic: String, normalizedPass: String): Uint8Array = js.native + + /** Creates a random array of bytes of the given length. */ + def getRandomBytes(length: Int): Uint8Array = js.native +} + +class SecureRandomJS { + /** + * Generates a user-specified number of random bytes. + * + * @param bytes the array to be filled in with random bytes. + */ + def nextBytes(bytes: Array[Byte]): Unit = { + val len = bytes.length + val arr = CryptoFacadeJs.getRandomBytes(len) + cfor(0)(_ < len, _ + 1) { i => + bytes(i) = arr(i).toByte + } + } } /** Represents imported Point class from `sigmajs-crypto-facade` JS libarary. */ 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 5dabe5114a..1e7d4b45b6 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala @@ -15,7 +15,7 @@ import sigmastate.helpers.TestingHelpers._ import org.ergoplatform._ import org.ergoplatform.dsl.{ContractSpec, SigmaContractSyntax, StdContracts, TestContractSpec} import sigmastate.basics.CryptoConstants -import sigmastate.crypto.CryptoFacade +import sigmastate.crypto.{BigIntegers, CryptoFacade} import sigmastate.eval.Extensions.ArrayOps import sigmastate.interpreter.Interpreter.{ScriptNameProp, emptyEnv} import sigmastate.utxo._ @@ -89,7 +89,7 @@ class OracleExamplesSpecification extends CompilerTestingCommons val temperature: Long = 18 - val r = BigInt.apply(128, CryptoFacade.createSecureRandom()) //128 bits random number + val r = BigInt(BigIntegers.createRandomBigInteger(128, CryptoFacade.createSecureRandom())) //128 bits random number val a = group.exponentiate(group.generator, r.bigInteger) val ts = System.currentTimeMillis() From 5b3581308354175f936bb5163d22bfce7d6056e7 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Fri, 4 Aug 2023 11:58:48 +0200 Subject: [PATCH 2/4] secure-random-js: add ScalaDoc --- .../src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala | 1 + 1 file changed, 1 insertion(+) diff --git a/interpreter/js/src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala b/interpreter/js/src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala index 908d6ee166..fa60015ed2 100644 --- a/interpreter/js/src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala +++ b/interpreter/js/src/main/scala/sigmastate/crypto/SigmaJsCryptoFacade.scala @@ -116,6 +116,7 @@ object CryptoFacadeJs extends js.Object { def getRandomBytes(length: Int): Uint8Array = js.native } +/** This class provides a cryptographically strong generator of byte arrays. */ class SecureRandomJS { /** * Generates a user-specified number of random bytes. From acffbef68edfca6517bd8fb91f41dc864c750086 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Fri, 4 Aug 2023 14:51:20 +0200 Subject: [PATCH 3/4] secure-random-js: fixed js Platform.exponentiatePoint --- .../src/main/scala/sigmastate/crypto/Platform.scala | 13 +++++++++++-- .../utxo/examples/OracleExamplesSpecification.scala | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala b/interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala index 1b963331f2..d23407e7d7 100644 --- a/interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala +++ b/interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala @@ -100,14 +100,23 @@ object Platform { def multiplyPoints(p1: Ecp, p2: Ecp): Ecp = new Ecp(CryptoFacadeJs.addPoint(p1.point, p2.point)) /** Exponentiate a point p. + * The implementation mimics the Java implementation of `AbstractECMultiplier.multiply` + * from BouncyCastle library. * * @param p point to exponentiate * @param n exponent * @return p to the power of n (`p^n`) i.e. `p + p + ... + p` (n times) */ def exponentiatePoint(p: Ecp, n: BigInteger): Ecp = { - val scalar = Convert.bigIntegerToBigInt(n) - new Ecp(CryptoFacadeJs.multiplyPoint(p.point, scalar)) + val sign = n.signum() + if (sign == 0 || isInfinityPoint(p)) { + val ctx = new CryptoContextJs() + return new Ecp(ctx.getInfinity()) + } + val scalar = Convert.bigIntegerToBigInt(n.abs()) + val positive = CryptoFacadeJs.multiplyPoint(p.point, scalar) + val result = if (sign > 0) positive else CryptoFacadeJs.negatePoint(positive) + new Ecp(result) } /** Check if a point is infinity. */ 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 1e7d4b45b6..384f0d4b63 100644 --- a/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala +++ b/sc/shared/src/test/scala/sigmastate/utxo/examples/OracleExamplesSpecification.scala @@ -89,7 +89,8 @@ class OracleExamplesSpecification extends CompilerTestingCommons val temperature: Long = 18 - val r = BigInt(BigIntegers.createRandomBigInteger(128, CryptoFacade.createSecureRandom())) //128 bits random number + //create 128 bits random number + val r = BigInt(BigIntegers.createRandomBigInteger(128, CryptoFacade.createSecureRandom())) val a = group.exponentiate(group.generator, r.bigInteger) val ts = System.currentTimeMillis() From 95950700b3dbedb687b5c4e2ed3104973043e9b9 Mon Sep 17 00:00:00 2001 From: Alexander Slesarenko Date: Fri, 4 Aug 2023 14:56:18 +0200 Subject: [PATCH 4/4] secure-random-js: ci.yml: run scJS/test --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5398146f45..db3427969c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - name: Runs tests and collect coverage - run: sbt -jvm-opts ci/ci.jvmopts ++${{ matrix.scala }} commonJS/test corelibJS/test interpreterJS/test graphirJS/test sdkJS/test + run: sbt -jvm-opts ci/ci.jvmopts ++${{ matrix.scala }} commonJS/test corelibJS/test interpreterJS/test graphirJS/test sdkJS/test scJS/test - name: Publish a JVM snapshot ${{ github.ref }} if: env.HAS_SECRETS == 'true'