Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
6eae6e7
scala-js: update dependencies
aslesarenko Sep 9, 2022
74d88c4
scala-js: added scorex.utils.Bytes, Ints, Longs
aslesarenko Sep 10, 2022
a16ff85
scala-js: added scorex.utils.Shorts, UnsignedBytes.scala
aslesarenko Sep 10, 2022
c4c0805
scala-js: removed org.whispersystems dependency and Curve25519
aslesarenko Sep 10, 2022
18736a6
scala-js: configure cross-platform sbt setup
aslesarenko Sep 11, 2022
b79798c
scala-js: update scorex-util dependency
aslesarenko Sep 26, 2022
89add8a
scala-js: remove unused declarations
aslesarenko Sep 26, 2022
c99a931
scala-js: remove scala-logging dependence
aslesarenko Sep 26, 2022
22b3dca
scala-js: move to JVM: Blake2b256Unsafe
aslesarenko Sep 26, 2022
4fe303b
scala-js: move to JVM: Blake2b512Specification
aslesarenko Sep 26, 2022
3b9ae72
scala-js: move to JVM: Blake2b512
aslesarenko Sep 26, 2022
2676e4b
scala-js: move to JVM: KeccakSpecification
aslesarenko Sep 26, 2022
e127667
scala-js: move to JVM: Keccak
aslesarenko Sep 26, 2022
054277f
scala-js: move to JVM: Whirlpool
aslesarenko Sep 26, 2022
0fbb8a8
scala-js: move to JVM: Stribog
aslesarenko Sep 26, 2022
cd4e049
scala-js: move to JVM: Skein + Sha256Unsafe
aslesarenko Sep 26, 2022
59eedd5
scala-js: move to JVM: CryptographicHash64 + ThreadUnsafeHash
aslesarenko Sep 26, 2022
6fa1d57
scala-js: reimplement Blake2b256 via Platform.scala
aslesarenko Sep 26, 2022
91b869f
scala-js: reimplement Sha256 via Platform.scala
aslesarenko Sep 26, 2022
727c7a8
scala-js: configure benchmarks project
aslesarenko Sep 26, 2022
dcd9953
scala-js: enable JSPlatform
aslesarenko Sep 26, 2022
e4a8d3e
scala-js: make code and tests compile
aslesarenko Sep 26, 2022
b9f974e
scala-js: Platform implemented for JS
aslesarenko Sep 27, 2022
546c402
scala-js: make all JS tests pass
aslesarenko Sep 27, 2022
dafca54
scala-js: setup ci.yml
aslesarenko Sep 27, 2022
27fb071
scala-js: ScalaJsSpec.scala added
aslesarenko Oct 9, 2022
e49a312
scala-js: more tests for ScalaJsSpec
aslesarenko Oct 20, 2022
e96eb00
scala-js: add Scala 2.12 to JS tests and publishing
aslesarenko Nov 16, 2022
95e9fa5
scala-js: replaced BouncycastleJs with @noble/hashes
aslesarenko Dec 30, 2022
a44a480
scala-js: release notes updated
aslesarenko Dec 30, 2022
b4526da
scala-js: ScalaDoc for BouncyCastleHash
aslesarenko Dec 30, 2022
5150edf
scala-js: add npmDependencies
aslesarenko Dec 30, 2022
8837261
scala-js: install npm CI action
aslesarenko Dec 31, 2022
cb2bee1
scala-js: fixes in release-notes.md
aslesarenko Jan 11, 2023
d54d1e1
scala-js: getting started guidelines in the Contributing section
aslesarenko Jan 11, 2023
0c84965
scala-js: addressed review comments
aslesarenko Jan 19, 2023
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
57 changes: 53 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ env:

jobs:
build:
name: Test and publish a snapshot
name: JVM - Test and publish a snapshot
env:
HAS_SECRETS: ${{ secrets.SONATYPE_PASSWORD != '' }}
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.12.10, 2.11.12, 2.13.1]
scala: [2.13.8, 2.12.15, 2.11.12]
java: [adopt@1.8]
runs-on: ${{ matrix.os }}
steps:
Expand All @@ -48,11 +48,60 @@ jobs:
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}

- name: Runs tests
run: sbt ++${{ matrix.scala }} test
run: sbt ++${{ matrix.scala }} scryptoJVM/test

- name: Publish a snapshot ${{ github.ref }}
if: env.HAS_SECRETS == 'true'
run: sbt ++${{ matrix.scala }} publish
run: sbt ++${{ matrix.scala }} scryptoJVM/publish
env:
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}

buildJs:
name: JS - Test and publish a snapshot
env:
HAS_SECRETS: ${{ secrets.SONATYPE_PASSWORD != '' }}
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.13.8, 2.12.15]
java: [adopt@1.8]
node-version: [16.x]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2

- name: Setup NPM
uses: pnpm/action-setup@v2
with:
version: 7.21.0
node-version: ${{ matrix.node-version }}
cache: "pnpm"
- run: pnpm install

- name: Setup Java and Scala
uses: olafurpg/setup-scala@v10
with:
java-version: ${{ matrix.java }}

- name: Cache sbt
uses: actions/cache@v2
with:
path: |
~/.sbt
~/.ivy2/cache
~/.coursier/cache/v1
~/.cache/coursier/v1
~/AppData/Local/Coursier/Cache/v1
~/Library/Caches/Coursier/v1
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}

- name: Runs tests
run: sbt ++${{ matrix.scala }} scryptoJS/test

- name: Publish a snapshot ${{ github.ref }}
if: env.HAS_SECRETS == 'true'
run: sbt ++${{ matrix.scala }} scryptoJS/publish
env:
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }}
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ Here are code examples for generating proofs and checking them. In this example
* First, we create a prover and get an initial digest from it (in a real application, this value is a public constant because anyone, including verifiers, can compute it by using the same two lines of code)

```scala
import com.google.common.primitives.Longs
import scorex.utils.Longs
import scorex.crypto.authds.{ADKey, ADValue}
import scorex.crypto.authds.avltree.batch._
import scorex.crypto.hash.{Blake2b256, Digest32}
Expand Down Expand Up @@ -190,4 +190,30 @@ The code is under Public Domain CC0 license means you can do anything with it. F

# Contributing

Your contributions are always welcome! Please submit a pull request or create an issue to add a new cryptographic primitives or better implementations.
Clone the repository
```
$git clone <repository> scrypto
$cd scrypto
```

The code uses [Scalablytyped](https://scalablytyped.org/docs/readme) to generate Scala.js bindings
for `@noble/hashes`. This [video](https://youtu.be/hWUAVrNj65c?t=1341) explains how the
environment for ScalablyTyped is configured in this repository.

Before compiling the library with SBT, you need to install JS dependencies for ScalablyTyped.
The configuration is in `package.json`.
```
$npm install
added 285 packages, and audited 286 packages in 20s
found 0 vulnerabilities
```

Then you can compile the library with SBT and run tests.
```
$sbt
sbt:scrypto> compile
sbt:scrypto> test
```

Your contributions are always welcome!
Please submit a pull request or create an issue to add a new cryptographic primitives or better implementations.
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ object Base16Benchmark {
.view
.map(_ => Random.nextString(200).getBytes("UTF-8"))
.map(Base16.encode)
.force
.force.toSeq

val xab: Seq[Array[Byte]] = (1 to 1000)
.view
.map(_ => Random.nextString(200).getBytes("UTF-8"))
.force
.force.toSeq
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package scorex.benchmarks

import java.util.concurrent.TimeUnit

import com.google.common.primitives.Shorts
import scorex.utils.Shorts
import org.openjdk.jmh.annotations._
import org.openjdk.jmh.infra.Blackhole
import scorex.utils.ByteArray
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/src/main/scala/scorex.benchmarks/Helpers.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package scorex.benchmarks

import com.google.common.primitives.Longs
import scorex.utils.Longs
import scorex.crypto.authds.{ADKey, ADValue}
import scorex.crypto.authds.avltree.batch.{BatchAVLProver, Insert, Operation, Remove}
import scorex.crypto.hash.{Blake2b256, Digest32}
Expand Down
85 changes: 54 additions & 31 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ import sbt.Keys.{homepage, scalaVersion}
name := "scrypto"
description := "Cryptographic primitives for Scala"

lazy val scala213 = "2.13.8"
lazy val scala212 = "2.12.15"
lazy val scala211 = "2.11.12"
lazy val scala213 = "2.13.7"

crossScalaVersions := Seq(scala212, scala211, scala213)
scalaVersion := scala212

javacOptions ++=
"-source" :: "1.8" ::
Expand All @@ -34,48 +31,74 @@ lazy val commonSettings = Seq(
"scm:git@github.com:input-output-hk/scrypto.git"
)
),
libraryDependencies ++= Seq(
"org.rudogma" %%% "supertagged" % "2.0-RC2",
"org.scorexfoundation" %%% "scorex-util" % "0.1.8-20-565873cd-SNAPSHOT",
"org.scalatest" %%% "scalatest" % "3.3.0-SNAP3" % Test,
"org.scalatest" %%% "scalatest-propspec" % "3.3.0-SNAP3" % Test,
"org.scalatest" %%% "scalatest-shouldmatchers" % "3.3.0-SNAP3" % Test,
"org.scalatestplus" %%% "scalacheck-1-15" % "3.3.0.0-SNAP3" % Test,
"org.scalacheck" %%% "scalacheck" % "1.15.2" % Test
),
publishMavenStyle := true,
publishTo := sonatypePublishToBundle.value
)

libraryDependencies ++= Seq(
"org.rudogma" %% "supertagged" % "1.5",
"com.google.guava" % "guava" % "23.0",
"com.typesafe.scala-logging" %% "scala-logging" % "3.9.2",
"org.whispersystems" % "curve25519-java" % "0.5.0",
"org.bouncycastle" % "bcprov-jdk15to18" % "1.66",
"org.scorexfoundation" %% "scorex-util" % "0.1.8"
)

libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % "3.1.+" % Test,
"org.scalacheck" %% "scalacheck" % "1.14.+" % Test,
// https://mvnrepository.com/artifact/org.scalatestplus/scalatestplus-scalacheck
"org.scalatestplus" %% "scalatestplus-scalacheck" % "3.1.0.0-RC2" % Test
)

publishMavenStyle := true

publishArtifact in Test := false
Test / publishArtifact := false

publishTo := sonatypePublishToBundle.value

pomIncludeRepository := { _ => false }

lazy val scrypto = (project in file(".")).settings(commonSettings: _*)

lazy val benchmarks = (project in file("benchmarks"))
.settings(commonSettings, name := "scrypto-benchmarks")
.dependsOn(scrypto)
.enablePlugins(JmhPlugin)
lazy val scrypto = crossProject(JVMPlatform, JSPlatform)
.in(file("."))
.settings(commonSettings: _*)
.jvmSettings(
libraryDependencies ++= Seq(
"org.bouncycastle" % "bcprov-jdk15to18" % "1.66"
),
scalaVersion := scala213,
crossScalaVersions := Seq(scala211, scala212, scala213)
)

lazy val scryptoJS = scrypto.js
.enablePlugins(ScalaJSBundlerPlugin)
.enablePlugins(ScalablyTypedConverterExternalNpmPlugin)
.settings(
scalaVersion := scala213,
crossScalaVersions := Seq(scala212, scala213),
libraryDependencies ++= Seq(
"org.scala-js" %%% "scala-js-macrotask-executor" % "1.0.0",
("org.scala-js" %%% "scalajs-java-securerandom" % "1.0.0").cross(CrossVersion.for3Use2_13)
),
Test / parallelExecution := false,
// how to setup ScalablyTyped https://youtu.be/hWUAVrNj65c?t=1341
externalNpm := { file(s"${baseDirectory.value}/..") },
Compile / npmDependencies ++= Seq(
"@noble/hashes" -> "^1.1.4"
),
useYarn := true
)

lazy val benchmarks = project
.in(file("benchmarks"))
.dependsOn(scrypto.jvm)
.settings(
moduleName := "scrypto-benchmarks",
crossScalaVersions := Seq(scala211, scala212, scala213),
scalaVersion := scala213,
)
.enablePlugins(JmhPlugin)

credentials ++= (for {
username <- Option(System.getenv().get("SONATYPE_USERNAME"))
password <- Option(System.getenv().get("SONATYPE_PASSWORD"))
} yield Credentials("Sonatype Nexus Repository Manager", "oss.sonatype.org", username, password)).toSeq

// prefix version with "-SNAPSHOT" for builds without a git tag
dynverSonatypeSnapshots in ThisBuild := true
ThisBuild / dynverSonatypeSnapshots := true
// use "-" instead of default "+"
dynverSeparator in ThisBuild := "-"
ThisBuild / dynverSeparator := "-"

// PGP key for signing a release build published to sonatype
// signing is done by sbt-pgp plugin
Expand Down
84 changes: 84 additions & 0 deletions js/src/main/scala/scorex/crypto/hash/Platform.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package scorex.crypto.hash

import typings.nobleHashes.blake2Mod.BlakeOpts
import typings.nobleHashes.mod.blake2b
import typings.nobleHashes.sha256Mod.sha256
import typings.nobleHashes.utilsMod

import scala.scalajs.js.typedarray.Uint8Array

/** JS platform specific implementation of methods.
* When shared code is compiled to JS, this implementation is used.
*
* The JS implementation is based on type wrappers generated by ScalablyTyped for the
* @noble/hashes library. (See configuration in build.sbt.)
*
* @see jvm/src/main/scala/scorex/crypto/hash/Platform.scala for JVM implementation
*/
object Platform {

/** Represents abstract digest from @noble.
* See createBlake2bDigest, createSha256Digest methods.
*/
type Digest = utilsMod.Hash[_]

private def bytesToShorts(xs: Array[Byte]): Array[Short] =
xs.map(x => (x & 0xFF).toShort)

private def uint8ArrayToBytes(jsShorts: Uint8Array): Array[Byte] = {
jsShorts.toArray[Short].map(x => x.toByte)
}

/** Creates an implementation of the cryptographic hash function Blakbe2b.
*
* @param bitSize the bit size of the digest
* @return the digest implementation
*/
def createBlake2bDigest(bitSize: Int): Digest = {
val opts = BlakeOpts().setDkLen(bitSize / 8)
blake2b.create(opts)
}

/** Creates an implementation of the cryptographic hash function SHA-256.
*
* @return the digest implementation
*/
def createSha256Digest(): Digest = {
sha256.create()
}

/** Update the message digest with a single byte.
*
* @param digest the digest to be updated
* @param b the input byte to be entered.
*/
def updateDigest(digest: Digest, b: Byte): Unit = {
digest.update(Uint8Array.of((b & 0xFF).toShort))
}

/** Update the message digest with a block of bytes.
*
* @param digest the digest to be updated
* @param bytes the byte array containing the data.
* @param inOff the offset into the byte array where the data starts.
* @param inLen the length of the data.
*/
def updateDigest(digest: Digest,
bytes: Array[Byte],
inOff: Int,
inLen: Int): Unit = {
val in = Uint8Array.of(bytesToShorts(bytes.slice(inOff, inOff + inLen)): _*)
digest.update(in)
}

/** Close the digest, producing the final digest value. The doFinal
* call leaves the digest reset.
* A new array is created to store the result.
*
* @param digest the digest to be finalized
*/
def doFinalDigest(digest: Digest): Array[Byte] = {
val res = digest.digest()
uint8ArrayToBytes(res)
}
}
Loading