WIP: Implement bcrypto facades (#2743)

* Implement bcrypto facades

* signatures

* some more facades

* move JS test

* move JVM tests

* CryptoUtilTest

* CI config

* fix CI config

* add npm dependencies

* test over fullLinkJS-generated files
This commit is contained in:
rorp 2021-03-05 05:21:39 -08:00 committed by GitHub
parent d03bb2d22d
commit 5a2f95c38e
30 changed files with 485 additions and 55 deletions

View file

@ -0,0 +1,28 @@
name: Linux 2.13 Scala.js tests
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
on:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
if: "! contains(github.event.pull_request.labels.*.name, 'documentation')"
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Scala
uses: olafurpg/setup-scala@v10
with:
java-version: adopt@1.11
- name: Cache
uses: actions/cache@v2
with:
path: |
~/.ivy2/cache
~/.sbt
~/.bitcoin-s/binaries
key: ${{ runner.os }}-cache
- name: run tests
run: sbt ++2.13.5 cryptoTestJS/test 'set scalaJSStage in Global := FullOptStage' cryptoTestJS/test

View file

@ -55,13 +55,20 @@ lazy val crypto = crossProject(JVMPlatform, JSPlatform)
.jvmSettings(
libraryDependencies ++= Deps.cryptoJVM
)
.jsSettings(
npmDependencies in Compile ++= Seq(
"bcrypto" -> "5.4.0"
)
)
.jvmSettings(CommonSettings.jvmSettings: _*)
.jsSettings(commonJsSettings: _*)
.in(file("crypto"))
lazy val cryptoJS = crypto.js
.enablePlugins(ScalaJSBundlerPlugin)
lazy val cryptoJVM = crypto.jvm.dependsOn(secp256k1jni)
lazy val cryptoJVM = crypto.jvm
.dependsOn(secp256k1jni)
lazy val core = crossProject(JVMPlatform, JSPlatform)
.crossType(CrossType.Pure)
@ -363,6 +370,7 @@ lazy val cryptoTest = crossProject(JVMPlatform, JSPlatform)
lazy val cryptoTestJVM = cryptoTest.jvm
lazy val cryptoTestJS = cryptoTest.js
.enablePlugins(ScalaJSBundlerPlugin)
lazy val coreTest = crossProject(JVMPlatform, JSPlatform)
.crossType(CrossType.Pure)

View file

@ -0,0 +1,97 @@
package org.bitcoins.crypto
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers
import scodec.bits.ByteVector
class HashingTest extends AnyFlatSpec with Matchers {
private lazy val lines = Vector(
// rnd,sha1(rnd),sha256(rnd),ripeMd160(rnd),sha256Hash160(rnd),hmac(rnd,sha256)
"41dc440cf30c42cb17b935d3d8451b0c1e2a8ad9a529637228df5ca31a10c0a2,b600f58e73defdbb68650078f39760ba1bcfb391,4eb2b43a30cca0aebdefec2f6a30abb56a1f6d9b0462d252184dc5209c62d5d0,ddb6092b1103067c609b35bec4177abf5dfc9f5c,304d0d0762ec66b44764a11b0d02e234b1d75721,36d248dc8a9825ac48c32fe4ebf0b4dd8ee450c226f05dc8b8cfac62dbcc11a89bc00ab3942bc5ca74a7f189bff04fe9541b749a7670e9dcf36e3bdb37cd6e01",
"a361ef0fdc98778bd5c6f6c50a6300f560a88644029a623294091d2b3d0e22d7,7cb911a6852779261cc151410691bd408b23ba1d,d63c99b1abffc915ba9e35fdc5763304839d981dc25c106bdd90a8bdc4eb6f13,6003b2e364b11f2737c7fb4cb190fdd55783f76b,a4f38c39eab8afe5f2e63d1a89d0c365c96cc7a7,87c59c1c9535043a3c3ecdec25776613f198ae4707675c129a1ed8d217aac20f7d07ce4c84e6cfa833ee7d3e52b3673730b900e6ca7075185d1ecce473110447",
"35659ae4880ae74deda82a5d3b77ba8fc4adff84e1c46fa67955338bc7346977,e379fb92c9500d410818bd95796a87f662f1fd76,904a2128262e055f68896150e1b1da93849bda2054e5e6f6f8db11214a1b6855,a63e15d313afef12927f38924a97927ac3e61b8b,0c2109858080cad92ec93e883998b6048b671112,7bdd176479a379bb9447e5f7646cd0be210977b593d6a71fbdbe545a282b4fb9e22b6ec5d0afa62045fe96074b91544755f9c28ee0af368ae34165e5487d65d2",
"e3c54af8504a7f0d69f8f9c9b29c5d15fc861821547f285bb70d2850ce08efe9,a93c7e60aa08e08919c9085641ff1a7cd3400613,1325fb6c0029b128b0fdf37d014e3739aea56fc670756e335a2ce34fe08c2574,d5409d92add4c4f7fad2ae8eea100e19e2f1e66f,90dcb2f658418089a0d41abb7f012f2531f860a0,911a7b19f7f0f145921002ed3830d46045041e786cbea13c7f77066ed8a03d56ddaa2db987358f6a4c713fddd07570647fd80ea072da309a60758c305137d4a8",
"8283f8f51b5045ef414e462ebb5c9573950ec0162578df73d0f5490febac5a97,40ebb9af58651c51135641278884217f23f14993,540ed853ed97664d7ea82e663d2480076d1b81088a5ef405465871c8df3d1b9f,4c69787f663f188fbcee4b0d9a737083e018ac08,137b3fb7855dc321348e03c458ecc18daedf0f95,5172f81bbabd00b9c81654826dba9e527b5a1c553b9c2c92b7b59b420d5b8064c2fd3f9e8107ec3a07298f712de10a126d348d2bb6dac21aa397a665a1ee787d",
"6286477a8da8d7b6f2fc9080d5e7a4091b1d506ee2dc4f81740b0f54f438537d,aeded4ba719eb6fed787d34b8064402082db7a4d,3df54218915767977bdf2bcde8b45a711caa460c3baa2448f91bc13731e6ea3d,946d3624e583fef1b46bdb8c24155d62083c0b47,839cff76a9b045f49a0b7c44f34d8561dc442870,280245f199d155794032fb4ea90f22c38de688bfb4e43c66507994610d01676b0c05eb1d531fe4cb628fee5ff00b863feec037088e128c0d4e875816c9a4b6bd",
"47a8bb983cfc0387769dd6b80b8674c0531545c31cef0feff5c1113326003510,025c7f81895c1cd8e92c79a61a11b4b900eaf475,da19d198af8bcb060b07a8825f6898ac821b002b0e5da574cab2753bee430f8a,22292f488c729250acf0d2f7147fd6b2e6a808db,da91c4f8751060450782a9b023f6f5f4f2a0ee9f,aaebe082b58dce13087555d9ada0ec6c965acd39a014d47ad9f43700a8f36e466c5117165b4d585cc5bc5b295d9bbd6dcc8d27cce4a1c563ed1cfe1353186b79",
"8a329193ab14c37b397d749d1c254d9c5a962248cd2ad48460fb7cf659e89f52,ff4090d399bbb8e3220bc57ed13c6a0c44c79ea5,20460d4766c94a72ddef09c83f5eea9545af7826a446539c1a07291f6cdc5af4,eaf846e713cf63704cf1d80fd415265f4b5d6586,d45c9dc61b959c3548fe5c2de3781714d1dcf9f7,e5e62e56726480551da0b88de1657676979f3f5e6a028b3a0c91a186495060ebf5e4cab2c71675f36bd4b86c6ab8a1ee850eaffd93c28828504ae023783f6005",
"96c37689f01bd39b6f163fbf4b1025653ea196f0abdb8a5dcd8cbc76c78f8cf5,f7edf6a546b5c7023ae146ac1ef58256f0578b73,34957be30df1b91070c9b39e086b31906e295574d315eaf2e91c6b45a292bb84,84795b00f8405a6ca0fab024991f34187a1be0c1,2367689553879bbcea1ba7608eb1905fb8230565,98bc48d3da9fcb8723b5e37ae30a8aa54a411eede7a9e5220c9ae849cbd591577991922b8995ef34704618b23f1961770c9f31ebe346ca6089da391c96c6a11d",
"7eff84aeca24260baa06b61394bdec8b760a0c6558dd1748d91d6f492e0779b7,1c182efc13f2468d880372f4809d5a5e7011dfbf,13d1c9c1d3ac10cc78c43a2f0724a6a2e06adf5844a4ab45ff4779af1f15029d,8ce4f2abb9775f7e3cea0fa75238ab75cf6908e3,d3e2938a69fdce888260003f6f1702e9d3392ab0,4569f2282b016fee5b583390e709dd285eb09b7510bbe092f37e5fef581a78b42729eb9f46088d1d52a00f2f57d1ffd48ab64b5c0dfc38d01bf2c793c977fcfc",
"c7acfcf801519b59c4750b06d6d55b1915f3a0317859685dd2ae337a6065d4bb,384c59c208e92c46e4fb8bcea9e286181ee4f956,4853fbb9eafeb0bfe2d717ad34973ea979413874e97d92d7a85c16a8fb61626e,e45f80b6cd0533e8b6f9a974b17c20244812e0fe,d531970c5f1ca7d0772513b32e8b75fa837c27fd,fc7946c37e09c86ce48e704f162e96c06cd227df7813dcc910fb56793a8cd5b0f205207292f6c7d34aeddeae80d3a6243409f2d4bd11e0f4eba5e6711df77586",
"b53e7fb86d09133c5d1bfccae6a16652d26376784ec97995c9173f8d4d9151bc,69a8d04118b7f4e5c49a877ea2a1e6d9bdcc6dc5,33cb2e45fe278f822c9f8f0b0f6ca7c0aa84e588237a70e0870607756bdb18e0,f17ef3913819472407b45b9bf2bf454b4185bfe7,75cd9d71a818ccfc234c80cd89b6b52b898530bc,008892ec410fcc7197049a9967738edff5abeef1e29eb03a2b3f1939433f16ce284a9d3be887b3b1500161a38a617e8e467b4564bb6d030f617fc996d3a26dd2",
"7125adb44be6dc3bea98c348fc546b92371e99b4294d753c3a2c408447057a48,06fed168e3f0a8928d56c847364caeaf63c11f34,721e34ca27da076c1e18b51ffbf1f2921a431f55e83f85c4cbe679d5e081c120,023445e83064df92dcd60478cd68ea45f032d5c0,d0e99a8e4a7ba80bcc861b6dc81c29547dfd7dae,a485d3f5f22d70dae68176b76df8f8173adae876dcae8e93c5156277204a507484a50cc25b40e967ed75c4eaf29cda8e97ab8b05f72fa30a28e11ed9a30c6f7a",
"34ab9bc63b31a019e59af803cd9365500ed01e36e5d8e166d7fa22a3dd06a4b2,495804100e19df440a1026e016c3a55800064bed,203f617d00fada67c5d5f48736793d79d3b75633e8977d531a035b51df696853,4278ed1405c4d61d35bf2dbd8b0ad17cf8eb2de8,23656338b7894db5ca7c5804e91a128cf0d17acf,4ab854a2ce4f7a2ac71fb0b84b88f960cc0fd7467b9a6e298243b0117e8d38525876608fa403d43bceb2aee43abebac670db6e74a2f346cb1a254aa942cc1fbd",
"93dc29da56fac0a611c8c5014bc61a6c3861ae9def571818664c7e44b25a954d,ceb1b9394c434c5a1648112477c5f674ed4430ca,f3a1d0c012317a4802aa52ae17c03e6bb8f769d35c909af8c0dbab16fe238d79,31c690c105e778b5941492cdffa5a817adc14202,ac6975f571f6e961c3db6ac29cfc7e975b2aaa09,f2f758a0e28f40d2b13a590d57875295668f12725a1536b513b19f59b65f88f885229ef424f8b226ee5b53749097ca70aa8b6dbb3650779074775239c652b70c",
"f6372c5a3c6957b655d56167a4e723fc0eefdd3abf1857b2c7d797a0be0e4b0e,960b962cea70b57c7edc4f137261f94829957a3b,70eeaa3dc29f434da194e23bb5eb1001e9012bab15bec0fb9532c63f022c19a8,80f5a9119a99ef6bc04a1944f256fc8176216ad2,d535e38f334aa06538ea644849b80972a7fe6c6f,ac08b0031b5026157997b5c4a5f60df1c8afd39c5d7691033c72d65e4fa06312b48dd0cf46dd350188563c957ddabdb4b06ed2e9b4be2babcf640825358b555e"
)
private lazy val hashes = lines.map { line =>
val arr = line.split(",")
val data = ByteVector.fromValidHex(arr(0))
val sha1 = Sha1Digest.fromHex(arr(1))
val sha256 = Sha256Digest.fromHex(arr(2))
val ripeMd160 = RipeMd160Digest.fromHex(arr(3))
val sha256Hash160 = Sha256Hash160Digest.fromHex(arr(4))
val hmac = ByteVector.fromValidHex(arr(5))
(data, sha1, sha256, ripeMd160, sha256Hash160, hmac)
}
it must "compute sha1" in {
val expected = hashes.map(_._2)
val actual = hashes.map(_._1).map(BCryptoCryptoRuntime.sha1)
assert(actual == expected)
}
it must "compute sha256" in {
val expected = hashes.map(_._3)
val actual = hashes.map(_._1).map(BCryptoCryptoRuntime.sha256)
assert(actual == expected)
}
it must "compute ripemd160" in {
val expected = hashes.map(_._4)
val actual = hashes.map(_._1).map(BCryptoCryptoRuntime.ripeMd160)
assert(actual == expected)
}
it must "compute sha256hash160" in {
val expected = hashes.map(_._5)
val actual = hashes.map(_._1).map(BCryptoCryptoRuntime.sha256Hash160)
assert(actual == expected)
}
it must "compute hmac" in {
val expected = hashes.map(_._6)
val actual =
hashes
.map(x => (x._1, x._3.bytes))
.map(y => BCryptoCryptoRuntime.hmac512(y._1, y._2))
assert(actual == expected)
}
// From https://github.com/dgarage/NDLC/blob/d816c0c517611b336f09ceaa43d400ecb5ab909b/NDLC.Tests/Data/normalization_tests.json
it must "normalize and serialize strings correctly" in {
val singletons = Vector("\u00c5", "\u212b", "\u0041\u030a")
assert(
singletons
.map(BCryptoCryptoRuntime.normalize)
.forall(_ == "\u00c5")
)
val canonicalComposites = Vector("\u00f4", "\u006f\u0302")
assert(
canonicalComposites
.map(BCryptoCryptoRuntime.normalize)
.forall(_ == "\u00f4")
)
val multipleCombiningMarks = Vector("\u1e69", "\u0073\u0323\u0307")
assert(
multipleCombiningMarks
.map(BCryptoCryptoRuntime.normalize)
.forall(_ == "\u1e69")
)
}
}

View file

@ -0,0 +1,21 @@
package org.bitcoins.crypto
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers
class KeysTest extends AnyFlatSpec with Matchers {
it must "generate keys" in {
val privkey = ECPrivateKey.freshPrivateKey
assert(privkey != null)
assert(BCryptoCryptoRuntime.secKeyVerify(privkey.bytes))
val pubkey = privkey.publicKey
assert(pubkey != null)
assert(BCryptoCryptoRuntime.isValidPubKey(pubkey.bytes))
assert(!BCryptoCryptoRuntime.secKeyVerify(pubkey.bytes))
assert(!BCryptoCryptoRuntime.isValidPubKey(privkey.bytes))
}
}

View file

@ -0,0 +1,14 @@
package org.bitcoins.crypto
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers
class RandomTest extends AnyFlatSpec with Matchers {
it should "generate random bytes" in {
val rnd = 1.to(16).map(_ => BCryptoCryptoRuntime.randomBytes(32))
assert(rnd.size == 16)
assert(rnd.distinct.size == rnd.size)
}
}

View file

@ -1,11 +1,10 @@
package org.bitcoins.crypto
import org.bitcoins.testkitcore.gen.NumberGenerator
import scodec.bits.{ByteVector, HexStringSyntax}
import org.scalatest.compatible.Assertion
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.gen.{CryptoGenerators, NumberGenerator}
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
import org.scalacheck.Gen
import org.scalatest.compatible.Assertion
import scodec.bits.{ByteVector, HexStringSyntax}
class AesCryptTest extends BitcoinSUnitTest {
behavior of "AesEncrypt"

View file

@ -2,13 +2,18 @@ package org.bitcoins.crypto
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.testkitcore.gen.{CryptoGenerators, NumberGenerator}
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
import org.scalacheck.Gen
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import scodec.bits._
/** Created by chris on 1/26/16.
*/
class CryptoUtilTest extends BitcoinSUnitTest {
class CryptoUtilTest
extends AnyFlatSpec
with Matchers
with ScalaCheckPropertyChecks {
"CryptoUtil" must "perform a SHA-1 hash" in {
val hash = CryptoUtil.sha1(hex"")

View file

@ -2,14 +2,55 @@ package org.bitcoins.crypto
import scodec.bits.ByteVector
import scala.scalajs.js
import scala.scalajs.js.typedarray._
import scala.scalajs.js.JSStringOps._
import scala.scalajs.js.UnicodeNormalizationForm
/** This is an implementation of [[CryptoRuntime]] that defaults to
* Bcrypto (https://github.com/bcoin-org/bcrypto) when possible.
*/
trait BCryptoCryptoRuntime extends CryptoRuntime {
override val cryptoContext: CryptoContext = CryptoContext.BCrypto
/** Generates a 32 byte private key */
override def freshPrivateKey: ECPrivateKey = ???
implicit def bufferToByteVector(b: Buffer): ByteVector = toByteVector(b)
implicit def byteVectorToBuffer(b: ByteVector): Buffer = toNodeBuffer(b)
private lazy val hash160 = new Hash160
private lazy val ripeMd160 = new RipeMd160
private lazy val sha1 = new SHA1
private lazy val sha256 = SHA256Factory.create()
private lazy val hmac = SHA512.hmac.apply().asInstanceOf[HMAC]
private lazy val ecdsa = new ECDSA("SECP256K1", sha256, sha256, null)
private lazy val randomBytesFunc: Int => ByteVector =
try {
// try to call the native implementation
Random.randomBytes(1)
Random.randomBytes
} catch {
case _: Throwable =>
// the native implementation is not available,
// fall back to the JS implementation
RandomBrowser.randomBytes
}
def randomBytes(n: Int): ByteVector = randomBytesFunc(n)
override def ripeMd160(bytes: ByteVector): RipeMd160Digest = {
ripeMd160.init()
ripeMd160.update(bytes)
val hashBytes = ripeMd160.`final`()
RipeMd160Digest.fromBytes(hashBytes)
}
override def sha256Hash160(bytes: ByteVector): Sha256Hash160Digest = {
hash160.init()
hash160.update(bytes)
val hashBytes = hash160.`final`()
Sha256Hash160Digest.fromBytes(hashBytes)
}
/** Converts a private key -> public key
*
@ -18,19 +59,40 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
*/
override def toPublicKey(
privateKey: ECPrivateKey,
isCompressed: Boolean): ECPublicKey = ???
isCompressed: Boolean): ECPublicKey = {
val pubKeyBuffer =
ecdsa.publicKeyCreate(key = privateKey.bytes, compressed = isCompressed)
ECPublicKey.fromBytes(pubKeyBuffer)
}
override def ripeMd160(bytes: ByteVector): RipeMd160Digest = ???
override def sha256(bytes: ByteVector): Sha256Digest = {
sha256.init()
sha256.update(bytes)
val hashBytes = sha256.`final`()
Sha256Digest.fromBytes(hashBytes)
}
override def sha256Hash160(bytes: ByteVector): Sha256Hash160Digest = ???
/** Generates a 32 byte private key */
override def freshPrivateKey: ECPrivateKey = {
val keyBytes = ecdsa.privateKeyGenerate()
ECPrivateKey.fromBytes(keyBytes)
}
override def sha256(bytes: ByteVector): Sha256Digest = ???
override def sha1(bytes: ByteVector): Sha1Digest = {
sha1.init()
sha1.update(bytes)
val hashBytes = sha1.`final`()
Sha1Digest.fromBytes(hashBytes)
}
override def sha1(bytes: ByteVector): Sha1Digest = ???
override def hmac512(key: ByteVector, data: ByteVector): ByteVector = {
hmac.init(key)
hmac.update(data)
hmac.`final`()
}
override def hmac512(key: ByteVector, data: ByteVector): ByteVector = ???
override def normalize(str: String): String = ???
override def normalize(str: String): String =
str.normalize(UnicodeNormalizationForm.NFC)
/** Recover public keys from a signature and the message that was signed. This method will return 2 public keys, and the signature
* can be verified with both, but only one of them matches that private key that was used to generate the signature.
@ -42,25 +104,45 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
*/
override def recoverPublicKey(
signature: ECDigitalSignature,
message: ByteVector): (ECPublicKey, ECPublicKey) = ???
message: ByteVector): (ECPublicKey, ECPublicKey) = {
val keyBytes =
ecdsa.recover(message, signature.bytes, param = 0, compress = true)
val key = ECPublicKey.fromBytes(keyBytes)
override def publicKey(privateKey: ECPrivateKey): ECPublicKey = ???
val keyBytesWithSign =
ecdsa.recover(message, signature.bytes, param = 1, compress = true)
val keyWithSign = ECPublicKey.fromBytes(keyBytesWithSign)
(key, keyWithSign)
}
override def publicKey(privateKey: ECPrivateKey): ECPublicKey = {
val buffer =
ecdsa.publicKeyCreate(privateKey.bytes, privateKey.isCompressed)
ECPublicKey.fromBytes(buffer)
}
override def sign(
privateKey: ECPrivateKey,
dataToSign: ByteVector): ECDigitalSignature = ???
dataToSign: ByteVector): ECDigitalSignature = {
val buffer = ecdsa.sign(dataToSign, privateKey.bytes)
ECDigitalSignature.fromBytes(buffer)
}
override def signWithEntropy(
privateKey: ECPrivateKey,
bytes: ByteVector,
entropy: ByteVector): ECDigitalSignature = ???
override def secKeyVerify(privateKeybytes: ByteVector): Boolean = ???
override def secKeyVerify(privateKeybytes: ByteVector): Boolean =
ecdsa.privateKeyVerify(privateKeybytes)
override def verify(
publicKey: ECPublicKey,
data: ByteVector,
signature: ECDigitalSignature): Boolean = ???
signature: ECDigitalSignature): Boolean = {
ecdsa.verify(data, signature.bytes, publicKey.bytes)
}
override def decompressed(publicKey: ECPublicKey): ECPublicKey = ???
@ -78,14 +160,18 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
pubkey: ECPublicKey,
privkey: ECPrivateKey): ECPublicKey = ???
override def isValidPubKey(bytes: ByteVector): Boolean = ???
override def isValidPubKey(bytes: ByteVector): Boolean =
ecdsa.publicKeyVerify(bytes)
override def isFullyValidWithBouncyCastle(bytes: ByteVector): Boolean = ???
override def schnorrSign(
dataToSign: ByteVector,
privateKey: ECPrivateKey,
auxRand: ByteVector): SchnorrDigitalSignature = ???
auxRand: ByteVector): SchnorrDigitalSignature = {
val buffer = ecdsa.schnorrSign(dataToSign, privateKey.bytes) //, auxRand)
SchnorrDigitalSignature.fromBytes(buffer)
}
override def schnorrSignWithNonce(
dataToSign: ByteVector,
@ -95,7 +181,9 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
override def schnorrVerify(
data: ByteVector,
schnorrPubKey: SchnorrPublicKey,
signature: SchnorrDigitalSignature): Boolean = ???
signature: SchnorrDigitalSignature): Boolean = {
ecdsa.schnorrVerify(data, signature.bytes, schnorrPubKey.bytes)
}
override def schnorrComputeSigPoint(
data: ByteVector,
@ -123,15 +211,41 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
msg: ByteVector,
adaptorPoint: ECPublicKey): Boolean = ???
override def decodeSignature(
signature: ECDigitalSignature): (scala.BigInt, scala.BigInt) = ???
override def isValidSignatureEncoding(
signature: ECDigitalSignature): Boolean = ???
override def isDEREncoded(signature: ECDigitalSignature): Boolean = ???
override def sipHash(item: ByteVector, key: SipHashKey): Long = ???
private def toNodeBuffer(byteVector: ByteVector): Buffer = {
//the implicit used here is this
//https://github.com/scala-js/scala-js/blob/b5a93bb99a0b0b5044141d4b2871ea260ef17798/library/src/main/scala/scala/scalajs/js/typedarray/package.scala#L33
Buffer.from(byteVector.toArray.toTypedArray.buffer)
}
private def toByteVector(buffer: Buffer): ByteVector =
toByteVector(buffer, buffer.length)
private def toByteVector(buffer: Buffer, len: Int): ByteVector = {
//is this right?
val iter: js.Iterator[Int] = buffer.values()
val accum = new scala.collection.mutable.ArrayBuffer[Int](len)
var done = false
while (!done) {
val entry = iter.next()
if (entry.done) {
done = true
} else {
accum += entry.value
}
}
require(accum.length == len,
s"Need $len bytes for buffer -> bytevector conversion")
ByteVector(accum.map(_.toByte))
}
}
object BCryptoCryptoRuntime extends BCryptoCryptoRuntime

View file

@ -15,5 +15,28 @@ class ECDSA(
pre: String = null)
extends js.Object {
def privateKeyGenerate(): Buffer = js.native
def privateKeyVerify(key: Buffer): Boolean = js.native
def publicKeyCreate(key: Buffer, compressed: Boolean): Buffer = js.native
def publicKeyVerify(key: Buffer): Boolean = js.native
def sign(msg: Buffer, key: Buffer): Buffer = js.native
def verify(msg: Buffer, sig: Buffer, key: Buffer): Boolean = js.native
def recover(
msg: Buffer,
sig: Buffer,
param: Byte,
compress: Boolean): Buffer = js.native
var schnorr: Schnorr = js.native
def schnorrSign(msg: Buffer, key: Buffer): Buffer = js.native
def schnorrVerify(msg: Buffer, sig: Buffer, key: Buffer): Boolean =
js.native
}

View file

@ -0,0 +1,14 @@
package org.bitcoins.crypto
import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport
@js.native
@JSImport("bcrypto/lib/internal/hmac.js", JSImport.Default)
class HMAC extends js.Object {
def init(key: Buffer): Unit = js.native
def update(bytes: Buffer): Unit = js.native
def `final`(): Buffer = js.native
}

View file

@ -7,8 +7,8 @@ import scala.scalajs.js.annotation._
* https://github.com/bcoin-org/bcrypto/blob/master/lib/js/hash160.js
*/
@js.native
@JSImport("bcrypto/lib/js/hash160.js", JSImport.Default)
class Hash160() extends Hasher {
@JSImport("bcrypto/lib/hash160.js", JSImport.Default)
class Hash160 extends Hasher {
override def init(): Unit = js.native
override def update(bytes: Buffer): Unit = js.native

View file

@ -5,8 +5,8 @@ import scala.scalajs.js.annotation._
//the annotation specifies that Foobaz is a native JS class defined in the module "bar.js", and exported under the name "Foo".
@js.native
@JSImport("bcrypto/lib/js/ripemd160.js", JSImport.Default)
class RipeMd160() extends Hasher {
@JSImport("bcrypto/lib/ripemd160.js", JSImport.Default)
class RipeMd160 extends Hasher {
override def init(): Unit = js.native

View file

@ -0,0 +1,14 @@
package org.bitcoins.crypto
import scala.scalajs.js
import scala.scalajs.js.annotation._
@js.native
@JSImport("bcrypto/lib/sha1.js", JSImport.Default)
class SHA1 extends Hasher {
override def init(): Unit = js.native
override def update(bytes: Buffer): Unit = js.native
override def `final`(): Buffer = js.native
}

View file

@ -7,11 +7,49 @@ import scala.scalajs.js.annotation._
* https://github.com/bcoin-org/bcrypto/blob/4db0feecde86bce71b0c33d31f7178fb14e7381f/lib/js/sha256.js#L54
*/
@js.native
@JSImport("bcrypto/lib/js/sha256.js", JSImport.Default)
class SHA256() extends Hasher {
@JSImport("bcrypto/lib/sha256.js", JSImport.Default)
class SHA256 extends Hasher {
var native: Int = js.native
var id: String = js.native
var size: Int = js.native
var bits: Int = js.native
var blockSize: Int = js.native
var zero: Buffer = js.native
var ctx: js.Dynamic = js.native
override def init(): Unit = js.native
override def update(bytes: Buffer): Unit = js.native
override def `final`(): Buffer = js.native
}
@js.native
@JSImport("bcrypto/lib/sha256.js", JSImport.Namespace)
object SHA256 extends js.Object {
val native: Int = js.native
val id: String = js.native
val size: Int = js.native
val bits: Int = js.native
val blockSize: Int = js.native
val zero: Buffer = js.native
val ctx: js.Dynamic = js.native
}
object SHA256Factory {
def create(): SHA256 = {
val hasher = new SHA256
// initialize static JS variables
hasher.native = SHA256.native
hasher.id = SHA256.id
hasher.size = SHA256.size
hasher.bits = SHA256.bits
hasher.blockSize = SHA256.blockSize
hasher.zero = SHA256.zero
hasher.ctx = SHA256.ctx
hasher
}
}

View file

@ -0,0 +1,57 @@
package org.bitcoins.crypto
import scala.scalajs.js
import scala.scalajs.js.annotation._
/** Scala wrapper for
* https://github.com/bcoin-org/bcrypto/blob/4db0feecde86bce71b0c33d31f7178fb14e7381f/lib/js/sha256.js#L54
*/
@js.native
@JSImport("bcrypto/lib/sha512.js", JSImport.Default)
class SHA512 extends Hasher {
var native: Int = js.native
var id: String = js.native
var size: Int = js.native
var bits: Int = js.native
var blockSize: Int = js.native
var zero: Buffer = js.native
var ctx: js.Dynamic = js.native
override def init(): Unit = js.native
override def update(bytes: Buffer): Unit = js.native
override def `final`(): Buffer = js.native
}
@js.native
@JSImport("bcrypto/lib/sha512.js", JSImport.Namespace)
object SHA512 extends js.Object {
val native: Int = js.native
val id: String = js.native
val size: Int = js.native
val bits: Int = js.native
val blockSize: Int = js.native
val zero: Buffer = js.native
val ctx: js.Dynamic = js.native
def hmac: js.Dynamic = js.native
}
object SHA512Factory {
def create(): SHA512 = {
val hasher = new SHA512
// initialize static JS variables
hasher.native = SHA512.native
hasher.id = SHA512.id
hasher.size = SHA512.size
hasher.bits = SHA512.bits
hasher.blockSize = SHA512.blockSize
hasher.zero = SHA512.zero
hasher.ctx = SHA512.ctx
hasher
}
}

View file

@ -287,10 +287,6 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
adaptorPoint: ECPublicKey): Boolean =
AdaptorStuff.adaptorVerify(adaptorSignature, key, msg, adaptorPoint)
override def decodeSignature(
signature: ECDigitalSignature): (BigInt, BigInt) =
DERSignatureUtil.decodeSignature(signature)
override def isValidSignatureEncoding(
signature: ECDigitalSignature): Boolean =
DERSignatureUtil.isValidSignatureEncoding(signature)

View file

@ -265,10 +265,6 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
adaptorPoint)
}
override def decodeSignature(
signature: ECDigitalSignature): (BigInt, BigInt) =
BouncycastleCryptoRuntime.decodeSignature(signature)
override def isValidSignatureEncoding(
signature: ECDigitalSignature): Boolean =
BouncycastleCryptoRuntime.isValidSignatureEncoding(signature)

View file

@ -203,7 +203,8 @@ trait CryptoRuntime {
msg: ByteVector,
adaptorPoint: ECPublicKey): Boolean
def decodeSignature(signature: ECDigitalSignature): (BigInt, BigInt)
def decodeSignature(signature: ECDigitalSignature): (BigInt, BigInt) =
DERSignatureUtil.decodeSignature(signature)
def isValidSignatureEncoding(signature: ECDigitalSignature): Boolean

View file

@ -177,7 +177,8 @@ object Deps {
"org.scala-lang.modules" %% "scala-collection-compat" % V.scalaCollectionCompatV
val scalacheck =
"org.scalacheck" %% "scalacheck" % V.scalacheck withSources () withJavadoc ()
Def.setting(
"org.scalacheck" %%% "scalacheck" % V.scalacheck withSources () withJavadoc ())
val scalaJsStubs =
"org.scala-js" %% "scalajs-stubs" % V.scalaJsStubsV % "provided"
@ -186,8 +187,8 @@ object Deps {
Def.setting(
"org.scalatest" %%% "scalatest" % V.scalaTest withSources () withJavadoc ())
val scalaTestPlus =
"org.scalatestplus" %% "scalacheck-1-14" % V.scalaTestPlus withSources () withJavadoc ()
val scalaTestPlus = Def.setting(
"org.scalatestplus" %%% "scalacheck-1-14" % V.scalaTestPlus withSources () withJavadoc ())
val pgEmbedded =
"com.opentable.components" % "otj-pg-embedded" % V.pgEmbeddedV withSources () withJavadoc ()
@ -205,7 +206,9 @@ object Deps {
"com.novocode" % "junit-interface" % V.junitV % "test" withSources () withJavadoc ()
val logback = Compile.logback % "test"
val grizzledSlf4j = Compile.grizzledSlf4j % "test"
val scalacheck = Compile.scalacheck % "test"
val scalacheck = Def.setting(
"org.scalacheck" %%% "scalacheck" % V.scalacheck % "test" withSources () withJavadoc ())
val scalaTest = Def.setting(
"org.scalatest" %%% "scalatest" % V.scalaTest % "test" withSources () withJavadoc ())
@ -290,7 +293,8 @@ object Deps {
def cryptoTest = Def.setting {
List(
Test.scalaTest.value
Test.scalaTest.value,
Test.scalacheck.value
)
}
@ -299,7 +303,7 @@ object Deps {
Compile.zeromq,
Compile.slf4j,
Test.logback,
Test.scalacheck,
Test.scalacheck.value,
Test.scalaTest.value
)
}
@ -316,7 +320,7 @@ object Deps {
Test.akkaStream,
Test.logback,
Test.scalaTest.value,
Test.scalacheck,
Test.scalacheck.value,
Test.newAsync,
Test.scalaCollectionCompat
)
@ -387,7 +391,7 @@ object Deps {
Test.akkaStream,
Test.logback,
Test.scalaTest.value,
Test.scalacheck
Test.scalacheck.value
)
}
@ -426,9 +430,9 @@ object Deps {
List(
Compile.newMicroPickle,
Compile.scalaCollectionCompat,
Compile.scalacheck,
Compile.scalacheck.value,
Compile.scalaTest.value,
Compile.scalaTestPlus,
Compile.scalaTestPlus.value,
Compile.slf4j
)
}
@ -436,9 +440,9 @@ object Deps {
def testkit = Def.setting {
List(
Compile.slf4j,
Compile.scalacheck,
Compile.scalacheck.value,
Compile.scalaTest.value,
Compile.scalaTestPlus,
Compile.scalaTestPlus.value,
Compile.pgEmbedded,
Test.akkaTestkit
)

View file

@ -39,5 +39,6 @@ addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.3.0")
// Scala.js
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.5.0")
addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.20.0")
addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.0.0")