Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Secure random for JS #898

Merged
merged 4 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
Expand Down
17 changes: 13 additions & 4 deletions interpreter/js/src/main/scala/sigmastate/crypto/Platform.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand All @@ -120,7 +129,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
Expand Down Expand Up @@ -198,7 +207,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.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -109,6 +111,25 @@ 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
}

/** This class provides a cryptographically strong generator of byte arrays. */
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. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -89,7 +89,8 @@ class OracleExamplesSpecification extends CompilerTestingCommons

val temperature: Long = 18

val r = BigInt.apply(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()
Expand Down
Loading