Revert "Schnorr sigs for Scala.js (#2784)" (#2802)

This reverts commit 8e7bde0ed9.
This commit is contained in:
Chris Stewart 2021-03-16 13:19:16 -05:00 committed by GitHub
parent 8e7bde0ed9
commit 78448b277c
43 changed files with 399 additions and 970 deletions

View File

@ -376,7 +376,10 @@ lazy val cryptoTest = crossProject(JVMPlatform, JSPlatform)
name := "bitcoin-s-crypto-test",
libraryDependencies ++= Deps.cryptoTest.value
)
.dependsOn(crypto)
.dependsOn(
crypto,
testkitCore
)
lazy val cryptoTestJVM = cryptoTest.jvm

View File

@ -1,19 +1,20 @@
package org.bitcoins.core.util
import java.math.BigInteger
import org.bitcoins.core.number._
import org.bitcoins.core.protocol.blockchain.BlockHeader
import org.bitcoins.core.protocol.blockchain.BlockHeader.TargetDifficultyHelper
import org.bitcoins.crypto.CryptoNumberUtil
import org.bitcoins.crypto.FieldElement
import scodec.bits.{BitVector, ByteVector}
import java.math.BigInteger
import scala.annotation.tailrec
import scala.math.BigInt
import scala.util.{Failure, Success, Try}
/** Created by chris on 2/8/16.
*/
sealed abstract class NumberUtil extends CryptoNumberUtil {
sealed abstract class NumberUtil extends BitcoinSLogger {
/** Takes 2^^num. */
def pow2(exponent: Int): BigInt = {
@ -23,6 +24,43 @@ sealed abstract class NumberUtil extends CryptoNumberUtil {
BigInt(1) << exponent
}
/** Converts a sequence of bytes to a **big endian** unsigned integer */
def toUnsignedInt(bytes: ByteVector): BigInt = {
toUnsignedInt(bytes.toArray)
}
def uintToFieldElement(bytes: ByteVector): FieldElement = {
FieldElement(toUnsignedInt(bytes))
}
/** Converts a sequence of bytes to a **big endian** unsigned integer */
def toUnsignedInt(bytes: Array[Byte]): BigInt = {
BigInt(new BigInteger(1, bytes))
}
/** Takes a hex string and parses it to a [[scala.math.BigInt BigInt]]. */
def toBigInt(hex: String): BigInt = toBigInt(BytesUtil.decodeHex(hex))
/** Converts a sequence of bytes to twos complement signed number. */
def toBigInt(bytes: ByteVector): BigInt = {
//BigInt interprets the number as an unsigned number then applies the given
//sign in front of that number, therefore if we have a negative number we need to invert it
//since twos complement is an inverted number representation for negative numbers
//see [[https://en.wikipedia.org/wiki/Two%27s_complement]]
if (bytes.isEmpty) BigInt(0)
//check if sign bit is set
else if ((0x80.toByte & bytes.head) != 0) {
val invertedBytes = bytes.tail.map(b => (b ^ 0xff.toByte).toByte)
val firstByteInverted = (bytes.head ^ 0xff.toByte).toByte
val num = firstByteInverted +: invertedBytes
BigInt(-1, num.toArray) - 1
} else {
val firstBitOff = (0x7f & bytes.head).toByte
val num = firstBitOff +: bytes.tail
BigInt(num.toArray)
}
}
/** Converts a sequence of [[scala.Byte Byte]] to a [[scala.Int Int]]. */
def toInt(bytes: ByteVector): Int = toBigInt(bytes).toInt

View File

@ -1,16 +0,0 @@
package org.bitcoins.crypto
class BCryptoECDigitalSignatureTest extends BitcoinSCryptoTest {
behavior of "BCryptoECDigitalSignatureTest"
it must "be able to generate valid signatures with bcrypto" in {
forAll(CryptoGenerators.privateKey, CryptoGenerators.sha256Digest) {
case (privKey: ECPrivateKey, hash: Sha256Digest) =>
val sig = BCryptoCryptoRuntime.sign(privKey, hash.bytes)
val pubKey = privKey.publicKey
assert(pubKey.verify(hash, sig))
}
}
}

View File

@ -1,8 +1,10 @@
package org.bitcoins.crypto
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers
import scodec.bits.ByteVector
class HashingTest extends BitcoinSCryptoTest {
class HashingTest extends AnyFlatSpec with Matchers {
private lazy val lines = Vector(
// rnd,sha1(rnd),sha256(rnd),ripeMd160(rnd),sha256Hash160(rnd),hmac(rnd,sha256)

View File

@ -1,8 +1,9 @@
package org.bitcoins.crypto
import scodec.bits.ByteVector
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers
class KeysTest extends BitcoinSCryptoTest {
class KeysTest extends AnyFlatSpec with Matchers {
it must "generate keys" in {
val privkey = ECPrivateKey.freshPrivateKey
@ -17,62 +18,4 @@ class KeysTest extends BitcoinSCryptoTest {
assert(!BCryptoCryptoRuntime.isValidPubKey(privkey.bytes))
}
it must "be able to compress/decompress public keys" in {
val privkey = ECPrivateKey.freshPrivateKey
assert(BCryptoCryptoRuntime.secKeyVerify(privkey.bytes))
assert(privkey.isCompressed)
val pubkey = BCryptoCryptoRuntime.toPublicKey(privkey, isCompressed = false)
assert(BCryptoCryptoRuntime.isValidPubKey(pubkey.bytes))
assert(!pubkey.isCompressed)
val compressed = privkey.publicKey
assert(BCryptoCryptoRuntime.isValidPubKey(compressed.bytes))
assert(compressed.isCompressed)
val converted = ECPublicKey.fromBytes(
BCryptoCryptoRuntime.publicKeyConvert(pubkey.bytes, compressed = true))
assert(BCryptoCryptoRuntime.isValidPubKey(converted.bytes))
assert(converted.isCompressed)
val decompressed = ECPublicKey.fromBytes(
BCryptoCryptoRuntime.publicKeyConvert(compressed.bytes,
compressed = false))
assert(BCryptoCryptoRuntime.isValidPubKey(decompressed.bytes))
assert(!decompressed.isCompressed)
assert(pubkey.bytes != converted.bytes)
assert(compressed.bytes == converted.bytes)
assert(compressed.bytes != decompressed.bytes)
assert(pubkey.bytes == decompressed.bytes)
}
private val inf = ECPublicKey.fromHex("00")
it must "be able to add infinity points" in {
val privkey = ECPrivateKey.freshPrivateKey
val pubkey1 = privkey.publicKey
val firstByte: Byte =
if (pubkey1.bytes.head == 0x02) 0x03
else if (pubkey1.bytes.head == 0x03) 0x02
else pubkey1.bytes.head
val pubkey2 =
ECPublicKey.fromBytes(ByteVector(firstByte) ++ pubkey1.bytes.tail)
val res1 = BCryptoCryptoRuntime.add(pubkey1, pubkey2)
assert(res1 == inf)
val decompressedPubkey1 = ECPublicKey.fromBytes(
BCryptoCryptoRuntime.publicKeyConvert(pubkey1.bytes, compressed = false))
val decompressedPubkey2 = ECPublicKey.fromBytes(
BCryptoCryptoRuntime.publicKeyConvert(pubkey2.bytes, compressed = false))
val res2 =
BCryptoCryptoRuntime.add(decompressedPubkey1, decompressedPubkey2)
assert(res2 == inf)
}
}

View File

@ -1,6 +1,9 @@
package org.bitcoins.crypto
class RandomTest extends BitcoinSCryptoTest {
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))

View File

@ -1,98 +0,0 @@
package org.bitcoins.crypto
import org.scalatest.Assertion
import scodec.bits.ByteVector
import scala.util.{Failure, Success, Try}
class SigningTest extends BitcoinSCryptoTest {
it must "be able to sign and verify signatures" in {
val privkey = ECPrivateKey.freshPrivateKey
val pubkey = privkey.publicKey
val msg = BCryptoCryptoRuntime.randomBytes(32)
val sig = privkey.sign(msg)
assert(pubkey.verify(msg, sig))
}
it must "be able to sign and verify Schnorr signatures" in {
val privkey = ECPrivateKey.freshPrivateKey
val pubkey = privkey.publicKey
val msg = BCryptoCryptoRuntime.randomBytes(32)
val sig = privkey.schnorrSign(msg)
assert(pubkey.schnorrVerify(msg, sig))
}
it must "pass the BIP 340 test-vectors with bcrypto" in {
BIP340TestVectors.vectors.foreach {
case (index, secKeyOpt, pubKey, auxRandOpt, msg, sig, result, comment) =>
test(index = index,
secKeyOpt = secKeyOpt,
pubKey = pubKey,
auxRandOpt = auxRandOpt,
msg = msg,
sig = sig,
result = result,
comment = comment)
}
}
def test(
index: Int,
secKeyOpt: Option[String],
pubKey: String,
auxRandOpt: Option[String],
msg: String,
sig: String,
result: Boolean,
comment: String): Assertion = {
val pkT = Try(SchnorrPublicKey(pubKey))
val msgBytes = ByteVector.fromHex(msg).get
val schnorrSigT = Try(SchnorrDigitalSignature(sig))
(pkT, schnorrSigT) match {
case (Success(pk), Success(schnorrSig)) =>
(secKeyOpt, auxRandOpt) match {
case (Some(secKeyStr), Some(auxRandStr)) =>
val secKey = ECPrivateKey(secKeyStr)
assert(secKey.schnorrPublicKey == pk)
val auxRand = ByteVector.fromHex(auxRandStr).get
testSign(index, secKey, auxRand, msgBytes, schnorrSig)
case _ => ()
}
testVerify(index, pk, msgBytes, schnorrSig, result, comment)
case (Failure(_), _) |
(_, Failure(_)) => // Must be verify only test resulting in false
assert(secKeyOpt.isEmpty)
assert(auxRandOpt.isEmpty)
assert(!result, s"Test $index failed to parse signature: $comment")
}
}
def testSign(
index: Int,
secKey: ECPrivateKey,
auxRand: ByteVector,
msg: ByteVector,
expectedSig: SchnorrDigitalSignature): Assertion = {
val bcryptoSig =
BCryptoCryptoRuntime.schnorrSign(msg, secKey, auxRand)
assert(bcryptoSig == expectedSig,
s"Test $index failed signing for Bouncy Castle")
}
def testVerify(
index: Int,
pubKey: SchnorrPublicKey,
msg: ByteVector,
sig: SchnorrDigitalSignature,
expectedResult: Boolean,
comment: String): Assertion = {
val bcryptoResult =
BCryptoCryptoRuntime.schnorrVerify(msg, pubKey, sig)
assert(bcryptoResult == expectedResult,
s"Test $index failed verification for Bouncy Castle: $comment")
}
}

View File

@ -1,10 +1,12 @@
package org.bitcoins.crypto
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 BitcoinSCryptoTest {
class AesCryptTest extends BitcoinSUnitTest {
behavior of "AesEncrypt"
val password = AesPassword.fromNonEmptyString("PASSWORD")

View File

@ -1,12 +1,13 @@
package org.bitcoins.crypto
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
import org.scalatest.Assertion
import scodec.bits.ByteVector
import scala.util.{Failure, Success, Try}
/** Tests from https://github.com/sipa/bips/blob/bip-taproot/bip-0340/test-vectors.csv */
class BouncyCastleBIP340Test extends BitcoinSCryptoTest {
class BouncyCastleBIP340Test extends BitcoinSUnitTest {
behavior of "Schnorr Signing"
def testSign(
@ -75,9 +76,35 @@ class BouncyCastleBIP340Test extends BitcoinSCryptoTest {
}
}
private def toOpt(str: String): Option[String] = {
if (str.isEmpty) {
None
} else {
Some(str)
}
}
it must "pass the BIP 340 test-vectors with both secp256k1 bindings and bouncy castle" in {
BIP340TestVectors.vectors.foreach {
case (index, secKeyOpt, pubKey, auxRandOpt, msg, sig, result, comment) =>
val bufferedSource =
io.Source.fromURL(getClass.getResource("/bip340-test-vectors.csv"))
try {
val lines = bufferedSource.getLines()
val _ = lines.next()
for (line <- bufferedSource.getLines()) {
val testVec = line.split(",").map(_.trim)
val index = testVec.head.toInt
val secKeyOpt = toOpt(testVec(1))
val pubKey = testVec(2)
val auxRandOpt = toOpt(testVec(3))
val msg = testVec(4)
val sig = testVec(5)
val result = testVec(6).toBoolean
val comment = if (testVec.length > 7) {
testVec(7)
} else {
""
}
test(index = index,
secKeyOpt = secKeyOpt,
pubKey = pubKey,
@ -86,6 +113,9 @@ class BouncyCastleBIP340Test extends BitcoinSCryptoTest {
sig = sig,
result = result,
comment = comment)
}
} finally {
bufferedSource.close()
}
}
}

View File

@ -1,6 +1,9 @@
package org.bitcoins.crypto
class BouncyCastleECDigitalSignatureTest extends BitcoinSCryptoTest {
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class BouncyCastleECDigitalSignatureTest extends BitcoinSUnitTest {
behavior of "BouncyCastleECDigitalSignatureTest"

View File

@ -1,9 +1,11 @@
package org.bitcoins.crypto
import org.bitcoins.testkitcore.gen.{CryptoGenerators, NumberGenerator}
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
import org.scalacheck.Gen
import org.scalatest.{Outcome, Succeeded}
class BouncyCastleSecp256k1Test extends BitcoinSCryptoTest {
class BouncyCastleSecp256k1Test extends BitcoinSUnitTest {
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
generatorDrivenConfigNewCode
@ -14,6 +16,7 @@ class BouncyCastleSecp256k1Test extends BitcoinSCryptoTest {
CryptoContext.default match {
case CryptoContext.LibSecp256k1 => super.withFixture(test)
case CryptoContext.BouncyCastle | CryptoContext.BCrypto =>
logger.warn(s"Test ${test.name} skipped as Secp256k1 is not available.")
Succeeded
}
}

View File

@ -1,12 +1,12 @@
package org.bitcoins.crypto
import org.bitcoins.core.util.NumberUtil
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
import scodec.bits.ByteVector
import scala.math.BigInt
/** Created by chris on 3/23/16.
*/
class DERSignatureUtilTest extends BitcoinSCryptoTest {
class DERSignatureUtilTest extends BitcoinSUnitTest {
val p2shSignature = ECDigitalSignature(
"304402205b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb02202e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf8001")
@ -37,30 +37,30 @@ class DERSignatureUtilTest extends BitcoinSCryptoTest {
it must "retrieve the (r,s) values for a p2sh signature in bitcoin" in {
val (r, s) = DERSignatureUtil.decodeSignature(p2shSignature)
r must be(
CryptoNumberUtil.toBigInt(
NumberUtil.toBigInt(
"5b7d2c2f177ae76cfbbf14d589c113b0b35db753d305d5562dd0b61cbf366cfb"))
s must be(
CryptoNumberUtil.toBigInt(
NumberUtil.toBigInt(
"2e56f93c4f08a27f986cd424ffc48a462c3202c4902104d4d0ff98ed28f4bf80"))
}
it must "retrieve the (r,s) values for a p2pkh signature in bitcoin" in {
val (r, s) = DERSignatureUtil.decodeSignature(p2pkhSignature)
r must be(
CryptoNumberUtil.toBigInt(
NumberUtil.toBigInt(
"16ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca03"))
s must be(
CryptoNumberUtil.toBigInt(
NumberUtil.toBigInt(
"119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac"))
}
it must "retrieve the (r,s) values from a p2pk signature in bitcoin" in {
val (r, s) = DERSignatureUtil.decodeSignature(p2pkSignature)
r must be(
CryptoNumberUtil.toBigInt(
NumberUtil.toBigInt(
"0a5c6163f07b8d3b013c4d1d6dba25e780b39658d79ba37af7057a3b7f15ffa1"))
s must be(
CryptoNumberUtil.toBigInt(
NumberUtil.toBigInt(
"1fd9b4eaa9943f734928b99a83592c2e7bf342ea2680f6a2bb705167966b7420"))
}

View File

@ -1,10 +1,12 @@
package org.bitcoins.crypto
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
import scodec.bits.ByteVector
/** Created by chris on 3/22/16.
*/
class ECDigitalSignatureTest extends BitcoinSCryptoTest {
class ECDigitalSignatureTest extends BitcoinSUnitTest {
implicit override val generatorDrivenConfig = generatorDrivenConfigNewCode

View File

@ -1,6 +1,15 @@
package org.bitcoins.crypto
class ECPrivateKeyTest extends BitcoinSCryptoTest {
import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3}
import org.bitcoins.core.crypto.ECPrivateKeyUtil
import org.bitcoins.testkitcore.gen.{
ChainParamsGenerator,
CryptoGenerators,
NumberGenerator
}
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class ECPrivateKeyTest extends BitcoinSUnitTest {
it must "create a private key from its hex representation" in {
val privateKeyHex =
"180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19"
@ -8,10 +17,70 @@ class ECPrivateKeyTest extends BitcoinSCryptoTest {
key.hex must be(privateKeyHex)
}
it must "determine if a private key corresponds to a compressed public key or not" in {
val compressedKey = "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi"
val uncompressedKey = "93DVKyFYwSN6wEo3E2fCrFPUp17FtrtNi2Lf7n4G3garFb16CRj"
ECPrivateKeyUtil.isCompressed(compressedKey) must be(true)
ECPrivateKeyUtil.isCompressed(uncompressedKey) must be(false)
}
it must "create a fresh private key" in {
ECPrivateKey() must not equal (ECPrivateKey())
}
it must "serialize a private key to WIF and then be able to deserialize it" in {
val hex = "2cecbfb72f8d5146d7fe7e5a3f80402c6dd688652c332dff2e44618d2d3372"
val privKey = ECPrivateKey(hex)
val wif = ECPrivateKeyUtil.toWIF(privKey, TestNet3)
val privKeyFromWIF = ECPrivateKeyUtil.fromWIFToPrivateKey(wif)
privKeyFromWIF must be(privKey)
val privKeyDecompressed = ECPrivateKey.fromHex(hex, isCompressed = false)
val wifDecompressed = ECPrivateKeyUtil.toWIF(privKeyDecompressed, TestNet3)
val privKeyDecompressedFromWIF =
ECPrivateKeyUtil.fromWIFToPrivateKey(wifDecompressed)
privKeyDecompressedFromWIF must be(privKeyDecompressed)
}
it must "serialize a private key to WIF when the private key is prefixed with 0 bytes" in {
val hex =
"00fc391adf4d6063a16a2e38b14d2be10133c4dacd4348b49d23ee0ce5ff4f1701"
val privKey = ECPrivateKey(hex)
val wif = ECPrivateKeyUtil.toWIF(privKey, TestNet3)
val privKeyFromWIF = ECPrivateKeyUtil.fromWIFToPrivateKey(wif)
privKeyFromWIF must be(privKey)
}
it must "correctly decode a private key from WIF" in {
val privateKey = ECPrivateKeyUtil.fromWIFToPrivateKey(
"cTPg4Zc5Jis2EZXy3NXShgbn487GWBTapbU63BerLDZM3w2hQSjC")
//derived hex on bitcore's playground
privateKey.hex must be(
"ad59fb6aadf617fb0f93469741fcd9a9f48700f1d1f465ddc0f26fa7f7bfa1ac")
}
it must "decode a WIF private key corresponding to uncompressed public key" in {
val wif = "5Kg1gnAjaLfKiwhhPpGS3QfRg2m6awQvaj98JCZBZQ5SuS2F15C"
val privKey = ECPrivateKeyUtil.fromWIFToPrivateKey(wif)
privKey.publicKey.hex must be(
"045b81f0017e2091e2edcd5eecf10d5bdd120a5514cb3ee65b8447ec18bfc4575c6d5bf415e54e03b1067934a0f0ba76b01c6b9ab227142ee1d543764b69d901e0")
}
it must "have serialization symmetry for WIF format" in {
forAll(CryptoGenerators.privateKey, ChainParamsGenerator.networkParams) {
(privKey, network) =>
val wif = ECPrivateKeyUtil.toWIF(privKey, network)
network match {
case MainNet =>
assert(ECPrivateKeyUtil.parseNetworkFromWIF(wif).get == network)
case TestNet3 | RegTest | SigNet =>
assert(ECPrivateKeyUtil.parseNetworkFromWIF(wif).get == TestNet3)
}
assert(ECPrivateKeyUtil.fromWIFToPrivateKey(wif) == privKey)
}
}
it must "have serialization symmetry" in {
forAll(CryptoGenerators.privateKey) { privKey =>
assert(ECPrivateKey(privKey.hex) == privKey)
@ -26,6 +95,16 @@ class ECPrivateKeyTest extends BitcoinSCryptoTest {
}
}
it must "fail to parse unknown WIF networks" in {
// Litecoin privkey
val wif = "6uSDaezGtedUbYk4F9CNVXbDWw9DuEuw7czU596t1CzmeAJ77P8"
assert(ECPrivateKeyUtil.parseNetworkFromWIF(wif).isFailure)
}
it must "fail to parse non-WIF strings" in {
assert(ECPrivateKeyUtil.parseNetworkFromWIF("hello there").isFailure)
}
it must "not serialize a ECPrivateKey toString" in {
ECPrivateKey().toString must be("Masked(ECPrivateKeyImpl)")
}

View File

@ -1,10 +1,12 @@
package org.bitcoins.crypto
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
import scodec.bits._
import scala.concurrent.ExecutionContext
class ECPublicKeyTest extends BitcoinSCryptoTest {
class ECPublicKeyTest extends BitcoinSUnitTest {
it must "be able to decompress keys" in {
val uncompressed =

View File

@ -1,6 +1,9 @@
package org.bitcoins.crypto
class FieldElementTest extends BitcoinSCryptoTest {
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class FieldElementTest extends BitcoinSUnitTest {
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
generatorDrivenConfigNewCode

View File

@ -1,8 +1,10 @@
package org.bitcoins.crypto
import org.bitcoins.testkitcore.gen.{CryptoGenerators, NumberGenerator}
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
import scodec.bits._
class HashDigestTest extends BitcoinSCryptoTest {
class HashDigestTest extends BitcoinSUnitTest {
behavior of "DoubleSha256Digest"
it must "be constructable from 32 bytes" in {

View File

@ -1,7 +1,10 @@
package org.bitcoins.crypto
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
/** Public key tests specific to the JVM */
class JvmECPublicKeyTest extends BitcoinSCryptoTest {
class JvmECPublicKeyTest extends BitcoinSUnitTest {
behavior of "JVMECPublicKeytest"

View File

@ -1,6 +1,10 @@
package org.bitcoins.crypto
class SchnorrDigitalSignatureTest extends BitcoinSCryptoTest {
import org.bitcoins.core.util.NumberUtil
import org.bitcoins.testkitcore.gen.{CryptoGenerators, NumberGenerator}
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class SchnorrDigitalSignatureTest extends BitcoinSUnitTest {
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
generatorDrivenConfigNewCode
@ -105,8 +109,8 @@ class SchnorrDigitalSignatureTest extends BitcoinSCryptoTest {
sig2.rx.bytes ++ privKey.schnorrPublicKey.bytes ++ message2
val e2Bytes = CryptoUtil.sha256SchnorrChallenge(bytesToHash2).bytes
val e1 = CryptoNumberUtil.uintToFieldElement(e1Bytes)
val e2 = CryptoNumberUtil.uintToFieldElement(e2Bytes)
val e1 = NumberUtil.uintToFieldElement(e1Bytes)
val e2 = NumberUtil.uintToFieldElement(e2Bytes)
val k = nonce.nonceKey.fieldElement
val x = privKey.schnorrKey.fieldElement

View File

@ -1,6 +1,9 @@
package org.bitcoins.crypto
class SchnorrNonceTest extends BitcoinSCryptoTest {
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class SchnorrNonceTest extends BitcoinSUnitTest {
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
generatorDrivenConfigNewCode

View File

@ -1,6 +1,9 @@
package org.bitcoins.crypto
class SchnorrPublicKeyTest extends BitcoinSCryptoTest {
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class SchnorrPublicKeyTest extends BitcoinSUnitTest {
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
generatorDrivenConfigNewCode

View File

@ -1,6 +1,9 @@
package org.bitcoins.crypto
class SignTest extends BitcoinSCryptoAsyncTest {
import org.bitcoins.testkitcore.gen.CryptoGenerators
import org.bitcoins.testkitcore.util.BitcoinSJvmTest
class SignTest extends BitcoinSJvmTest {
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
generatorDrivenConfigNewCode
@ -22,6 +25,17 @@ class SignTest extends BitcoinSCryptoAsyncTest {
}
}
it must "sign arbitrary pieces of data with arbitrary entropy correctly" in {
forAllAsync(CryptoGenerators.sha256Digest, CryptoGenerators.sha256Digest) {
case (hash, entropy) =>
val sigF = privKey.signWithEntropyFunction(hash.bytes, entropy.bytes)
sigF.map { sig =>
assert(pubKey.verify(hash.bytes, sig))
}
}
}
it must "sign arbitrary data correctly with low R values" in {
forAllAsync(CryptoGenerators.sha256Digest) { hash =>
val bytes = hash.bytes

View File

@ -1,26 +0,0 @@
package org.bitcoins.crypto
class SignWithEntropyTest extends BitcoinSCryptoAsyncTest {
implicit override val generatorDrivenConfig: PropertyCheckConfiguration =
generatorDrivenConfigNewCode
//ECPrivateKey implements the sign interface
//so just use it for testing purposes
val privKey: Sign = ECPrivateKey.freshPrivateKey
val pubKey: ECPublicKey = privKey.publicKey
behavior of "SignWithEntropy"
it must "sign arbitrary pieces of data with arbitrary entropy correctly" in {
forAllAsync(CryptoGenerators.sha256Digest, CryptoGenerators.sha256Digest) {
case (hash, entropy) =>
val sigF = privKey.signWithEntropyFunction(hash.bytes, entropy.bytes)
sigF.map { sig =>
assert(pubKey.verify(hash.bytes, sig))
}
}
}
}

View File

@ -1,56 +0,0 @@
package org.bitcoins.crypto
object BIP340TestVectors {
val vectors: Vector[
(
Int,
Option[String],
String,
Option[String],
String,
String,
Boolean,
String)] = Vector(
"index,secret key,public key,aux_rand,message,signature,verification result,comment",
"0,0000000000000000000000000000000000000000000000000000000000000003,F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9,0000000000000000000000000000000000000000000000000000000000000000,0000000000000000000000000000000000000000000000000000000000000000,E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0,TRUE,",
"1,B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,0000000000000000000000000000000000000000000000000000000000000001,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A,TRUE,",
"2,C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9,DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8,C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906,7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C,5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7,TRUE,",
"3,0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710,25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3,TRUE,test fails if msg is reduced modulo p or n",
"4,,D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9,,4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703,00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4,TRUE,",
"5,,EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,public key not on the curve",
"6,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2,FALSE,has_even_y(R) is false",
"7,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD,FALSE,negated message",
"8,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6,FALSE,negated s value",
"9,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051,FALSE,sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 0",
"10,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197,FALSE,sG - eP is infinite. Test fails in single verification if has_even_y(inf) is defined as true and x(inf) as 1",
"11,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,sig[0:32] is not an X coordinate on the curve",
"12,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,sig[0:32] is equal to field size",
"13,,DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141,FALSE,sig[32:64] is equal to curve order",
"14,,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30,,243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89,6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B,FALSE,public key is not a valid X coordinate because it exceeds the field size"
).tail.map { line =>
val testVec = line.split(",").map(_.trim)
val index = testVec.head.toInt
val secKeyOpt = toOpt(testVec(1))
val pubKey = testVec(2)
val auxRandOpt = toOpt(testVec(3))
val msg = testVec(4)
val sig = testVec(5)
val result = testVec(6).toBoolean
val comment = if (testVec.length > 7) {
testVec(7)
} else {
""
}
(index, secKeyOpt, pubKey, auxRandOpt, msg, sig, result, comment)
}
private def toOpt(str: String): Option[String] = {
if (str.isEmpty) {
None
} else {
Some(str)
}
}
}

View File

@ -1,118 +0,0 @@
package org.bitcoins.crypto
import org.scalacheck.Gen
import org.scalactic.anyvals.PosInt
import org.scalatest.flatspec.{AnyFlatSpec, AsyncFlatSpec}
import org.scalatest.matchers.must.Matchers
import org.scalatest.{Assertion, BeforeAndAfter, BeforeAndAfterAll, Succeeded}
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import scala.concurrent.{ExecutionContext, Future}
trait BitcoinSCryptoTest
extends AnyFlatSpec
with BeforeAndAfter
with BeforeAndAfterAll
with Matchers
with ScalaCheckPropertyChecks {
implicit def executionContext: ExecutionContext =
scala.concurrent.ExecutionContext.global
def generatorDrivenConfigNewCode: PropertyCheckConfiguration = {
customGenDrivenConfig(BitcoinSCryptoTest.NEW_CODE_EXECUTIONS)
}
/** Sets the generator driven tests to perform the given amount of execs */
def customGenDrivenConfig(executions: Int): PropertyCheckConfiguration = {
PropertyCheckConfiguration(
minSuccessful = PosInt.from(executions).get,
minSize = PosInt.from(executions).get,
workers = 1
)
}
}
trait BitcoinSCryptoAsyncTest
extends AsyncFlatSpec
with BeforeAndAfter
with BeforeAndAfterAll
with Matchers
with ScalaCheckPropertyChecks {
implicit override def executionContext =
scala.concurrent.ExecutionContext.Implicits.global
def generatorDrivenConfigNewCode: PropertyCheckConfiguration = {
customGenDrivenConfig(BitcoinSCryptoTest.NEW_CODE_EXECUTIONS)
}
/** Sets the generator driven tests to perform the given amount of execs */
def customGenDrivenConfig(executions: Int): PropertyCheckConfiguration = {
PropertyCheckConfiguration(
minSuccessful = PosInt.from(executions).get,
minSize = PosInt.from(executions).get,
workers = 1
)
}
def forAllAsync[A](gen: Gen[A])(
func: A => Future[Assertion]): Future[Assertion] = {
val samples = 1
.to(generatorDrivenConfig.minSize)
.map(_ => gen.sample)
.toVector
.flatten
val testRunsF = Future.sequence(samples.map(func))
checkRunResults(testRunsF)
}
def forAllAsync[A, B](genA: Gen[A], genB: Gen[B])(
func: (A, B) => Future[Assertion]): Future[Assertion] = {
val samples = 1
.to(generatorDrivenConfig.minSize)
.map(_ => (genA.sample, genB.sample))
.toVector
.collect { case (Some(a), Some(b)) =>
(a, b)
}
val testRunsF = Future.sequence(samples.map(x => func(x._1, x._2)))
checkRunResults(testRunsF)
}
private def checkRunResults(testRunsF: Future[Vector[Assertion]]) = {
for {
testRuns <- testRunsF
} yield {
val succeeded = testRuns.filter(_ == Succeeded)
val failed = testRuns.filterNot(_ == Succeeded)
if (succeeded.size < generatorDrivenConfig.minSuccessful) {
failed.headOption.getOrElse(fail())
} else {
succeed
}
}
}
}
object BitcoinSCryptoTest {
/** The number of times new code
* should be executed in a property based test
*/
val NEW_CODE_EXECUTIONS = 100
/** The number of times old code should be executed
* in a property based test
*/
val OLD_CODE_EXECUTIONS = 20
}

View File

@ -1,175 +0,0 @@
package org.bitcoins.crypto
import org.bitcoins.crypto
import org.scalacheck.Gen
import scodec.bits.ByteVector
/** Created by chris on 6/22/16.
*/
sealed abstract class CryptoGenerators {
def privateKey: Gen[ECPrivateKey] = Gen.delay(ECPrivateKey())
def fieldElement: Gen[FieldElement] = privateKey.map(_.fieldElement)
def smallFieldElement: Gen[FieldElement] =
NumberGenerator
.bytevector(30)
.map(bytes => FieldElement(ByteVector.fill(2)(0) ++ bytes))
def reallySmallFieldElement: Gen[FieldElement] =
NumberGenerator
.bytevector(15)
.map(bytes => FieldElement(ByteVector.fill(17)(0) ++ bytes))
def largeFieldElement: Gen[FieldElement] =
NumberGenerator
.bytevector(30)
.map(bytes => FieldElement(ByteVector.fill(2)(Byte.MinValue) ++ bytes))
def nonZeroFieldElement: Gen[FieldElement] =
nonZeroPrivKey.map(_.fieldElement)
/** Generates a random non-zero private key */
def nonZeroPrivKey: Gen[ECPrivateKey] =
privateKey.filter(_.bytes.toArray.exists(_ != 0.toByte))
def schnorrNonce: Gen[SchnorrNonce] =
nonZeroPrivKey.map(_.publicKey.bytes.tail).map(SchnorrNonce.fromBytes)
def schnorrPublicKey: Gen[SchnorrPublicKey] =
publicKey.map(_.schnorrPublicKey)
/** Generate a sequence of private keys
* @param num maximum number of keys to generate
* @return
*/
def privateKeySeq(num: Int): Gen[Seq[ECPrivateKey]] =
Gen.listOfN(num, privateKey)
/** Generates a sequence of private keys, and determines an amount of 'required' private keys
* that a transaction needs to be signed with
* @param num the maximum number of keys to generate
* @return
*/
def privateKeySeqWithRequiredSigs(num: Int): Gen[(Seq[ECPrivateKey], Int)] = {
if (num <= 0) {
Gen.const((Nil, 0))
} else {
val privateKeys = privateKeySeq(num)
for {
keys <- privateKeys
requiredSigs <- Gen.choose(0, keys.size - 1)
} yield (keys, requiredSigs)
}
}
/** Generates a random number of private keys less than 15.
* Also generates a random 'requiredSigs' number that a transaction needs to be signed with
*/
def privateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] =
for {
num <- Gen.choose(0, 15)
keysAndRequiredSigs <- privateKeySeqWithRequiredSigs(num)
} yield keysAndRequiredSigs
/** A generator with 7 or less private keys -- useful for creating smaller scripts */
def smallPrivateKeySeqWithRequiredSigs: Gen[(Seq[ECPrivateKey], Int)] =
for {
num <- Gen.choose(0, 7)
keysAndRequiredSigs <- privateKeySeqWithRequiredSigs(num)
} yield keysAndRequiredSigs
/** Generates a random public key */
def publicKey: Gen[ECPublicKey] =
for {
privKey <- privateKey
} yield privKey.publicKey
/** Generates a random digital signature */
def digitalSignature: Gen[ECDigitalSignature] =
for {
privKey <- privateKey
hash <- CryptoGenerators.doubleSha256Digest
} yield privKey.sign(hash)
def schnorrDigitalSignature: Gen[SchnorrDigitalSignature] = {
for {
privKey <- privateKey
hash <- CryptoGenerators.doubleSha256Digest
} yield privKey.schnorrSign(hash.bytes)
}
def adaptorSignature: Gen[ECAdaptorSignature] = {
for {
tweakedNonce <- publicKey
untweakedNonce <- publicKey
adaptedS <- fieldElement
proofS <- fieldElement
proofE <- fieldElement
} yield {
ECAdaptorSignature(tweakedNonce, adaptedS, untweakedNonce, proofS, proofE)
}
}
def sha256Digest: Gen[Sha256Digest] =
for {
bytes <- NumberGenerator.bytevector
digest = CryptoUtil.sha256(bytes)
} yield digest
def sha256DigestBE: Gen[Sha256DigestBE] = {
sha256Digest.map(_.flip)
}
/** Generates a random [[DoubleSha256Digest DoubleSha256Digest]] */
def doubleSha256Digest: Gen[DoubleSha256Digest] =
for {
key <- privateKey
digest = CryptoUtil.doubleSHA256(key.bytes)
} yield digest
def doubleSha256DigestBE: Gen[DoubleSha256DigestBE] = {
doubleSha256Digest.map(_.flip)
}
/** Generates a sequence of [[DoubleSha256Digest DoubleSha256Digest]]
* @param num the number of digets to generate
* @return
*/
def doubleSha256DigestSeq(num: Int): Gen[Seq[DoubleSha256Digest]] =
Gen.listOfN(num, doubleSha256Digest)
/** Generates a random [[Sha256Hash160Digest Sha256Hash160Digest]] */
def sha256Hash160Digest: Gen[Sha256Hash160Digest] =
for {
pubKey <- publicKey
hash = CryptoUtil.sha256Hash160(pubKey.bytes)
} yield hash
def aesKey128Bit: Gen[AesKey] = Gen.delay(AesKey.get128Bit())
def aesKey192Bit: Gen[AesKey] = Gen.delay(AesKey.get192Bit())
def aesKey256Bit: Gen[AesKey] = Gen.delay(AesKey.get256Bit())
def aesKey: Gen[AesKey] =
Gen.oneOf(aesKey128Bit, aesKey192Bit, aesKey256Bit)
def aesPassword: Gen[AesPassword] =
Gen.alphaStr.suchThat(_.nonEmpty).map(AesPassword.fromNonEmptyString(_))
def aesIV: Gen[AesIV] = Gen.delay(AesIV.random)
def aesEncryptedData: Gen[AesEncryptedData] =
for {
cipher <- NumberGenerator.bytevector.suchThat(_.nonEmpty)
iv <- aesIV
} yield crypto.AesEncryptedData(cipherText = cipher, iv)
def genKey: Gen[SipHashKey] =
Gen
.listOfN(16, NumberGenerator.byte)
.map(ByteVector(_))
.map(SipHashKey(_))
}
object CryptoGenerators extends CryptoGenerators

View File

@ -1,11 +1,19 @@
package org.bitcoins.crypto
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.testkitcore.gen.{CryptoGenerators, NumberGenerator}
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 BitcoinSCryptoTest {
class CryptoUtilTest
extends AnyFlatSpec
with Matchers
with ScalaCheckPropertyChecks {
"CryptoUtil" must "perform a SHA-1 hash" in {
val hash = CryptoUtil.sha1(hex"")
@ -41,7 +49,7 @@ class CryptoUtilTest extends BitcoinSCryptoTest {
it must "perform a single SHA256 hash on a bit vector" in {
val binary = bin"010001101110010001101110"
val strBytes = CryptoBytesUtil.decodeHex(binary.toHex)
val strBytes = BytesUtil.decodeHex(binary.toHex)
val shaStrBytes = CryptoUtil.sha256(strBytes)
val shaBinary = CryptoUtil.sha256(binary)

View File

@ -1,84 +0,0 @@
package org.bitcoins.crypto
import org.scalacheck.Arbitrary.arbitrary
import org.scalacheck.Gen
import scodec.bits.{BitVector, ByteVector}
/** Created by chris on 6/16/16.
*/
trait NumberGenerator {
def positiveShort: Gen[Short] = {
Gen.chooseNum[Short](0, Short.MaxValue)
}
/** Creates a generator that generates positive long numbers */
def positiveLongs: Gen[Long] = Gen.choose(0, Long.MaxValue)
/** Integers between 0 and Int.MaxValue
*/
val positiveInts: Gen[Int] = Gen.choose(0, Int.MaxValue)
/** Integers between Int.MinValue and -1
*/
val negativeInts: Gen[Int] = Gen.choose(Int.MinValue, -1)
/** Random integers
*/
val ints: Gen[Int] = Gen.choose(Int.MinValue, Int.MaxValue)
/** Creates a generator for positive longs without the number zero */
def positiveLongsNoZero: Gen[Long] = Gen.choose(1, Long.MaxValue)
/** Creates a number generator that generates negative long numbers */
def negativeLongs: Gen[Long] = Gen.choose(Long.MinValue, -1)
/** Chooses a BigInt in the ranges of 0 <= bigInt < 2^^64 */
def bigInts: Gen[BigInt] =
Gen
.chooseNum(Long.MinValue, Long.MaxValue)
.map(x => BigInt(x) + BigInt(2).pow(63))
def positiveBigInts: Gen[BigInt] = bigInts.filter(_ >= 0)
def bigIntsUInt64Range: Gen[BigInt] =
positiveBigInts.filter(_ < (BigInt(1) << 64))
/** Generates an arbitrary [[scala.Byte Byte]] in Scala */
def byte: Gen[Byte] = arbitrary[Byte]
/** Generates an arbitrary [[scodec.bits.ByteVector ByteVector]] */
def bytevector: Gen[ByteVector] = Gen.listOf(byte).map(ByteVector(_))
def bytevector(length: Int): Gen[ByteVector] =
Gen.listOfN(length, byte).map(ByteVector(_))
/** Generates a 100 byte sequence */
def bytes: Gen[List[Byte]] =
for {
num <- Gen.choose(0, 100)
b <- bytes(num)
} yield b
/** Generates the number of bytes specified by num
* @param num
* @return
*/
def bytes(num: Int): Gen[List[Byte]] = Gen.listOfN(num, byte)
/** Generates a random boolean */
def bool: Gen[Boolean] =
for {
num <- Gen.choose(0, 1)
} yield num == 1
/** Generates a bit vector */
def bitVector: Gen[BitVector] =
for {
n <- Gen.choose(0, 100)
vector <- Gen.listOfN(n, bool)
} yield BitVector.bits(vector)
}
object NumberGenerator extends NumberGenerator

View File

@ -4,9 +4,9 @@ import scodec.bits.ByteVector
import java.math.BigInteger
import scala.scalajs.js
import scala.scalajs.js.JSStringOps._
import scala.scalajs.js.typedarray._
import scala.scalajs.js.{JavaScriptException, UnicodeNormalizationForm}
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.
@ -23,9 +23,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
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, js.constructorOf[SHA256], null)
private lazy val ecdsa = new ECDSA("SECP256K1", sha256, sha256, null)
private lazy val randomBytesFunc: Int => ByteVector =
try {
@ -151,57 +149,49 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
override def tweakMultiply(
publicKey: ECPublicKey,
tweak: FieldElement): ECPublicKey = {
val keyBuffer = ecdsa.publicKeyTweakMul(publicKey.bytes, tweak.bytes, true)
ECPublicKey.fromBytes(keyBuffer)
}
tweak: FieldElement): ECPublicKey = ???
def publicKeyConvert(buffer: ByteVector, compressed: Boolean): ByteVector =
publicKeyConvert(toNodeBuffer(buffer), compressed)
override def add(pk1: ECPrivateKey, pk2: ECPrivateKey): ECPrivateKey = ???
def publicKeyConvert(buffer: Buffer, compressed: Boolean): Buffer =
ecdsa.publicKeyConvert(buffer, compressed)
override def add(bytes: ByteVector, pk2: ECPrivateKey): ByteVector = ???
override def add(pk1: ECPublicKey, pk2: ECPublicKey): ECPublicKey = {
try {
val keyBuffer =
ecdsa.publicKeyCombine(js.Array(pk1.bytes, pk2.bytes), true)
ECPublicKey.fromBytes(keyBuffer)
} catch {
case ex: JavaScriptException =>
// check for infinity
val k1: Buffer =
if (pk1.isCompressed) pk1.bytes
else publicKeyConvert(pk1.bytes, compressed = true)
val k2: Buffer =
if (pk2.isCompressed) pk2.bytes
else publicKeyConvert(pk2.bytes, compressed = true)
if (
((k1.head == 0x02 && k2.head == 0x03) ||
(k1.head == 0x03 && k2.head == 0x02)) &&
k1.tail == k2.tail
) {
ECPublicKey.fromHex("00")
} else {
throw ex
}
}
}
override def add(pk1: ECPublicKey, pk2: ECPublicKey): ECPublicKey = ???
override def pubKeyTweakAdd(
pubkey: ECPublicKey,
privkey: ECPrivateKey): ECPublicKey = {
val keyBuffer = ecdsa.publicKeyTweakAdd(pubkey.bytes, privkey.bytes, true)
ECPublicKey.fromBytes(keyBuffer)
}
privkey: ECPrivateKey): ECPublicKey = ???
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 = {
val buffer = ecdsa.schnorrSign(dataToSign, privateKey.bytes) //, auxRand)
SchnorrDigitalSignature.fromBytes(buffer)
}
override def schnorrSignWithNonce(
dataToSign: ByteVector,
privateKey: ECPrivateKey,
nonceKey: ECPrivateKey): SchnorrDigitalSignature = ???
override def schnorrVerify(
data: ByteVector,
schnorrPubKey: SchnorrPublicKey,
signature: SchnorrDigitalSignature): Boolean = {
ecdsa.schnorrVerify(data, signature.bytes, schnorrPubKey.bytes)
}
override def schnorrComputeSigPoint(
data: ByteVector,
nonce: SchnorrNonce,
pubKey: SchnorrPublicKey,
compressed: Boolean): ECPublicKey = ???
override def adaptorSign(
key: ECPrivateKey,
adaptorPoint: ECPublicKey,
@ -262,22 +252,6 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
s"Need $len bytes for buffer -> bytevector conversion")
ByteVector(accum.map(_.toByte))
}
override def decodePoint(bytes: ByteVector): ECPoint = {
if (bytes.size == 1 && bytes(0) == 0x00) {
ECPointInfinity
} else {
val decoded = ecdsa.curve
.applyDynamic("decodePoint")(toNodeBuffer(bytes))
.asInstanceOf[Point]
if (decoded.isInfinity())
ECPointInfinity
else
ECPoint(new BigInteger(decoded.getX().toString()),
new BigInteger(decoded.getY().toString()))
}
}
}
object BCryptoCryptoRuntime extends BCryptoCryptoRuntime

View File

@ -11,7 +11,7 @@ import scala.scalajs.js.annotation._
class ECDSA(
name: String = "SECP256K1",
hash: SHA256 = new SHA256,
xof: js.Dynamic = js.constructorOf[SHA256],
xof: SHA256 = new SHA256,
pre: String = null)
extends js.Object {
@ -19,24 +19,10 @@ class ECDSA(
def privateKeyVerify(key: Buffer): Boolean = js.native
def privateKeyTweakMul(key: Buffer, tweak: Buffer): Buffer =
js.native
def publicKeyCreate(key: Buffer, compressed: Boolean): Buffer = js.native
def publicKeyVerify(key: Buffer): Boolean = js.native
def publicKeyConvert(key: Buffer, compressed: Boolean): Buffer = js.native
def publicKeyTweakMul(key: Buffer, tweak: Buffer, compress: Boolean): Buffer =
js.native
def publicKeyTweakAdd(key: Buffer, tweak: Buffer, compress: Boolean): Buffer =
js.native
def publicKeyCombine(keys: js.Array[Buffer], compress: Boolean): Buffer =
js.native
def sign(msg: Buffer, key: Buffer): Buffer = js.native
def verify(msg: Buffer, sig: Buffer, key: Buffer): Boolean = js.native
@ -47,5 +33,10 @@ class ECDSA(
param: Byte,
compress: Boolean): Buffer = js.native
val curve: js.Dynamic = 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

@ -1,12 +0,0 @@
package org.bitcoins.crypto
import scala.scalajs.js
import scala.scalajs.js.annotation.JSImport
@js.native
@JSImport("bcrypto/lib/js/elliptic.js", JSImport.Default)
class Point extends js.Object {
def getX(): js.BigInt = js.native
def getY(): js.BigInt = js.native
def isInfinity(): Boolean = js.native
}

View File

@ -6,7 +6,7 @@ import org.bouncycastle.crypto.params.{
ECPublicKeyParameters
}
import org.bouncycastle.crypto.signers.{ECDSASigner, HMacDSAKCalculator}
import org.bouncycastle.math.ec.ECCurve
import org.bouncycastle.math.ec.{ECCurve, ECPoint}
import scodec.bits.ByteVector
import java.math.BigInteger
@ -15,7 +15,7 @@ import scala.util.Try
object BouncyCastleUtil {
private val curve: ECCurve = BouncyCastleCryptoParams.curve.getCurve
private val G = BouncyCastleCryptoParams.curve.getG
private val G: ECPoint = BouncyCastleCryptoParams.curve.getG
private def getBigInteger(bytes: ByteVector): BigInteger = {
new BigInteger(1, bytes.toArray)
@ -26,16 +26,16 @@ object BouncyCastleUtil {
decodePubKey(point, publicKey.isCompressed)
}
def decodePoint(bytes: ByteVector): org.bouncycastle.math.ec.ECPoint = {
def decodePoint(bytes: ByteVector): ECPoint = {
curve.decodePoint(bytes.toArray)
}
def decodePoint(pubKey: ECPublicKey): org.bouncycastle.math.ec.ECPoint = {
def decodePoint(pubKey: ECPublicKey): ECPoint = {
decodePoint(pubKey.bytes)
}
def decodePubKey(
point: org.bouncycastle.math.ec.ECPoint,
point: ECPoint,
isCompressed: Boolean = true): ECPublicKey = {
val bytes = point.getEncoded(isCompressed)
ECPublicKey.fromBytes(ByteVector(bytes))

View File

@ -1,6 +1,5 @@
package org.bitcoins.crypto
import org.bitcoins.crypto
import org.bouncycastle.crypto.AsymmetricCipherKeyPair
import org.bouncycastle.crypto.digests.{RIPEMD160Digest, SHA512Digest}
import org.bouncycastle.crypto.generators.ECKeyPairGenerator
@ -10,10 +9,12 @@ import org.bouncycastle.crypto.params.{
ECPrivateKeyParameters,
KeyParameter
}
import org.bouncycastle.math.ec.ECPoint
import scodec.bits.ByteVector
import java.math.BigInteger
import java.security.{MessageDigest, SecureRandom}
import scala.util.{Failure, Success, Try}
/** This is an implementation of [[CryptoRuntime]] that defaults to Bouncy Castle (https://bouncycastle.org/)
* and [[java.security]].
@ -41,9 +42,7 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
* @return a tuple (p1, p2) where p1 and p2 are points on the curve and p1.x = p2.x = x
* p1.y is even, p2.y is odd
*/
def recoverPoint(x: BigInteger): (
org.bouncycastle.math.ec.ECPoint,
org.bouncycastle.math.ec.ECPoint) = {
def recoverPoint(x: BigInteger): (ECPoint, ECPoint) = {
val bytes = ByteVector(x.toByteArray)
val bytes32 = if (bytes.length < 32) {
@ -151,6 +150,9 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
signature: ECDigitalSignature): Boolean =
BouncyCastleUtil.verifyDigitalSignature(data, publicKey, signature)
override def decompressed(publicKey: ECPublicKey): ECPublicKey =
BouncyCastleUtil.decompressPublicKey(publicKey)
override def publicKey(privateKey: ECPrivateKey): ECPublicKey =
BouncyCastleUtil.computePublicKey(privateKey)
@ -159,10 +161,18 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
tweak: FieldElement): ECPublicKey =
BouncyCastleUtil.pubKeyTweakMul(publicKey, tweak.bytes)
override def add(pk1: ECPrivateKey, pk2: ECPrivateKey): ECPrivateKey =
pk1.fieldElement.add(pk2.fieldElement).toPrivateKey
override def add(pk1: ByteVector, pk2: ECPrivateKey): ByteVector = {
val sum = pk2.fieldElement.add(FieldElement(pk1))
sum.bytes
}
override def add(pk1: ECPublicKey, pk2: ECPublicKey): ECPublicKey = {
val p1 = BouncyCastleUtil.decodePoint(pk1)
val p2 = BouncyCastleUtil.decodePoint(pk2)
val sumPoint = p1.add(p2)
val sumPoint =
BouncyCastleUtil.decodePoint(pk1).add(BouncyCastleUtil.decodePoint(pk2))
BouncyCastleUtil.decodePubKey(sumPoint)
}
@ -179,6 +189,77 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
override def isFullyValidWithBouncyCastle(bytes: ByteVector): Boolean =
bytes.nonEmpty && isValidPubKey(bytes)
override def schnorrSign(
dataToSign: ByteVector,
privateKey: ECPrivateKey,
auxRand: ByteVector): SchnorrDigitalSignature = {
val nonceKey =
SchnorrNonce.kFromBipSchnorr(privateKey, dataToSign, auxRand)
schnorrSignWithNonce(dataToSign, privateKey, nonceKey)
}
override def schnorrSignWithNonce(
dataToSign: ByteVector,
privateKey: ECPrivateKey,
nonceKey: ECPrivateKey): SchnorrDigitalSignature = {
val rx = nonceKey.schnorrNonce
val k = nonceKey.nonceKey.fieldElement
val x = privateKey.schnorrKey.fieldElement
val e = sha256SchnorrChallenge(
rx.bytes ++ privateKey.schnorrPublicKey.bytes ++ dataToSign).bytes
val challenge = x.multiply(FieldElement(e))
val sig = k.add(challenge)
SchnorrDigitalSignature(rx, sig)
}
override def schnorrVerify(
data: ByteVector,
schnorrPubKey: SchnorrPublicKey,
signature: SchnorrDigitalSignature): Boolean = {
val rx = signature.rx
val sT = Try(signature.sig.toPrivateKey)
sT match {
case Success(s) =>
val eBytes = sha256SchnorrChallenge(
rx.bytes ++ schnorrPubKey.bytes ++ data).bytes
val e = FieldElement(eBytes)
val negE = e.negate
val sigPoint = s.publicKey
val challengePoint = schnorrPubKey.publicKey.tweakMultiply(negE)
val computedR = challengePoint.add(sigPoint)
val yCoord = BouncyCastleUtil.decodePoint(computedR).getRawYCoord
yCoord != null && !yCoord.testBitZero() && computedR.schnorrNonce == rx
case Failure(_) => false
}
}
override def schnorrComputeSigPoint(
data: ByteVector,
nonce: SchnorrNonce,
pubKey: SchnorrPublicKey,
compressed: Boolean): ECPublicKey = {
val eBytes = sha256SchnorrChallenge(
nonce.bytes ++ pubKey.bytes ++ data).bytes
val e = FieldElement(eBytes)
val compressedSigPoint =
nonce.publicKey.add(pubKey.publicKey.tweakMultiply(e))
if (compressed) {
compressedSigPoint
} else {
compressedSigPoint.decompressed
}
}
override def adaptorSign(
key: ECPrivateKey,
adaptorPoint: ECPublicKey,
@ -230,15 +311,6 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
sh.doFinal()
}
override def decodePoint(bytes: ByteVector): crypto.ECPoint = {
val decoded = BouncyCastleUtil.decodePoint(bytes)
if (decoded.isInfinity)
crypto.ECPointInfinity
else
crypto.ECPoint(decoded.getRawXCoord.getEncoded,
decoded.getRawYCoord.getEncoded)
}
}
object BouncycastleCryptoRuntime extends BouncycastleCryptoRuntime

View File

@ -274,9 +274,6 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
override def sipHash(item: ByteVector, key: SipHashKey): Long =
BouncycastleCryptoRuntime.sipHash(item, key)
override def decodePoint(bytes: ByteVector): ECPoint =
BouncycastleCryptoRuntime.decodePoint(bytes)
}
object LibSecp256k1CryptoRuntime extends LibSecp256k1CryptoRuntime

View File

@ -1,49 +0,0 @@
package org.bitcoins.crypto
import scodec.bits.ByteVector
import java.math.BigInteger
import scala.math.BigInt
trait CryptoNumberUtil {
/** Converts a sequence of bytes to a **big endian** unsigned integer */
def toUnsignedInt(bytes: ByteVector): BigInt = {
toUnsignedInt(bytes.toArray)
}
/** Converts a sequence of bytes to a **big endian** unsigned integer */
def toUnsignedInt(bytes: Array[Byte]): BigInt = {
BigInt(new BigInteger(1, bytes))
}
def uintToFieldElement(bytes: ByteVector): FieldElement = {
FieldElement(toUnsignedInt(bytes))
}
/** Takes a hex string and parses it to a [[scala.math.BigInt BigInt]]. */
def toBigInt(hex: String): BigInt = toBigInt(CryptoBytesUtil.decodeHex(hex))
/** Converts a sequence of bytes to twos complement signed number. */
def toBigInt(bytes: ByteVector): BigInt = {
//BigInt interprets the number as an unsigned number then applies the given
//sign in front of that number, therefore if we have a negative number we need to invert it
//since twos complement is an inverted number representation for negative numbers
//see [[https://en.wikipedia.org/wiki/Two%27s_complement]]
if (bytes.isEmpty) BigInt(0)
//check if sign bit is set
else if ((0x80.toByte & bytes.head) != 0) {
val invertedBytes = bytes.tail.map(b => (b ^ 0xff.toByte).toByte)
val firstByteInverted = (bytes.head ^ 0xff.toByte).toByte
val num = firstByteInverted +: invertedBytes
BigInt(-1, num.toArray) - 1
} else {
val firstBitOff = (0x7f & bytes.head).toByte
val num = firstBitOff +: bytes.tail
BigInt(num.toArray)
}
}
}
object CryptoNumberUtil extends CryptoNumberUtil

View File

@ -2,8 +2,6 @@ package org.bitcoins.crypto
import scodec.bits.{BitVector, ByteVector}
import scala.util.{Failure, Success, Try}
/** Trait that should be extended by specific runtimes like javascript
* or the JVM to support crypto functions needed for bitcoin-s
*/
@ -148,29 +146,13 @@ trait CryptoRuntime {
data: ByteVector,
signature: ECDigitalSignature): Boolean
def decompressed(publicKey: ECPublicKey): ECPublicKey = {
if (publicKey.isCompressed) {
decodePoint(publicKey.bytes) match {
case ECPointInfinity => ECPublicKey.fromHex("00")
case point: ECPointImpl =>
val decompressedBytes =
ByteVector.fromHex("04").get ++
point.x.bytes ++
point.y.bytes
ECPublicKey(decompressedBytes)
}
} else publicKey
}
def decompressed(publicKey: ECPublicKey): ECPublicKey
def tweakMultiply(publicKey: ECPublicKey, tweak: FieldElement): ECPublicKey
def add(pk1: ECPrivateKey, pk2: ECPrivateKey): ECPrivateKey =
pk1.fieldElement.add(pk2.fieldElement).toPrivateKey
def add(pk1: ECPrivateKey, pk2: ECPrivateKey): ECPrivateKey
def add(pk1: ByteVector, pk2: ECPrivateKey): ByteVector = {
val sum = pk2.fieldElement.add(FieldElement(pk1))
sum.bytes
}
def add(bytes: ByteVector, pk2: ECPrivateKey): ByteVector
def add(pk1: ECPublicKey, pk2: ECPublicKey): ECPublicKey
@ -180,84 +162,26 @@ trait CryptoRuntime {
def isFullyValidWithBouncyCastle(bytes: ByteVector): Boolean
def decodePoint(bytes: ByteVector): ECPoint
def decodePoint(pubKey: ECPublicKey): ECPoint = {
decodePoint(pubKey.bytes)
}
def schnorrSign(
dataToSign: ByteVector,
privateKey: ECPrivateKey,
auxRand: ByteVector): SchnorrDigitalSignature = {
val nonceKey =
SchnorrNonce.kFromBipSchnorr(privateKey, dataToSign, auxRand)
schnorrSignWithNonce(dataToSign, privateKey, nonceKey)
}
auxRand: ByteVector): SchnorrDigitalSignature
def schnorrSignWithNonce(
dataToSign: ByteVector,
privateKey: ECPrivateKey,
nonceKey: ECPrivateKey): SchnorrDigitalSignature = {
val rx = nonceKey.schnorrNonce
val k = nonceKey.nonceKey.fieldElement
val x = privateKey.schnorrKey.fieldElement
val e = sha256SchnorrChallenge(
rx.bytes ++ privateKey.schnorrPublicKey.bytes ++ dataToSign).bytes
val challenge = x.multiply(FieldElement(e))
val sig = k.add(challenge)
SchnorrDigitalSignature(rx, sig)
}
nonceKey: ECPrivateKey): SchnorrDigitalSignature
def schnorrVerify(
data: ByteVector,
schnorrPubKey: SchnorrPublicKey,
signature: SchnorrDigitalSignature): Boolean = {
val rx = signature.rx
val sT = Try(signature.sig.toPrivateKey)
sT match {
case Success(s) =>
val eBytes = sha256SchnorrChallenge(
rx.bytes ++ schnorrPubKey.bytes ++ data).bytes
val e = FieldElement(eBytes)
val negE = e.negate
val sigPoint = s.publicKey
val challengePoint = schnorrPubKey.publicKey.tweakMultiply(negE)
val computedR = challengePoint.add(sigPoint)
decodePoint(computedR) match {
case ECPointInfinity => false
case ECPointImpl(_, yCoord) =>
!yCoord.toBigInteger.testBit(0) && computedR.schnorrNonce == rx
}
case Failure(_) => false
}
}
signature: SchnorrDigitalSignature): Boolean
def schnorrComputeSigPoint(
data: ByteVector,
nonce: SchnorrNonce,
pubKey: SchnorrPublicKey,
compressed: Boolean): ECPublicKey = {
val eBytes = sha256SchnorrChallenge(
nonce.bytes ++ pubKey.bytes ++ data).bytes
val e = FieldElement(eBytes)
val compressedSigPoint =
nonce.publicKey.add(pubKey.publicKey.tweakMultiply(e))
if (compressed) {
compressedSigPoint
} else {
compressedSigPoint.decompressed
}
}
compressed: Boolean): ECPublicKey
def adaptorSign(
key: ECPrivateKey,

View File

@ -195,9 +195,6 @@ trait CryptoUtil extends CryptoRuntime {
override def sipHash(item: ByteVector, key: SipHashKey): Long =
cryptoRuntime.sipHash(item, key)
override def decodePoint(bytes: ByteVector): ECPoint =
cryptoRuntime.decodePoint(bytes)
}
object CryptoUtil extends CryptoUtil

View File

@ -1,37 +0,0 @@
package org.bitcoins.crypto
import scodec.bits.ByteVector
import java.math.BigInteger
/** Represents a point on an elliptic curve.
*/
sealed trait ECPoint
/** The infinity point.
*/
case object ECPointInfinity extends ECPoint
/** A point on an elliptic curve.
* @param x
* @param y
*/
case class ECPointImpl(x: FieldElement, y: FieldElement) extends ECPoint
object ECPoint {
def apply(x: ByteVector, y: ByteVector): ECPoint =
ECPointImpl(FieldElement.fromBytes(x), FieldElement.fromBytes(y))
def apply(x: Array[Byte], y: Array[Byte]): ECPoint =
ECPointImpl(FieldElement.fromByteArray(x), FieldElement.fromByteArray(y))
def apply(x: BigInteger, y: BigInteger): ECPoint =
ECPointImpl(FieldElement(x), FieldElement(y))
def apply(x: BigInt, y: BigInt): ECPoint =
ECPointImpl(FieldElement(x), FieldElement(y))
def apply(x: String, y: String): ECPoint =
ECPointImpl(FieldElement.fromHex(x), FieldElement.fromHex(y))
}

View File

@ -1,4 +1,3 @@
import Deps.{Compile, Test}
import sbt._
import org.portablescala.sbtplatformdeps.PlatformDepsPlugin.autoImport._
@ -270,7 +269,8 @@ object Deps {
def crypto: Def.Initialize[Seq[ModuleID]] = {
Def.setting {
List(
Compile.scodec.value
Compile.scodec.value,
Test.scalaTest.value
)
}
}
@ -294,8 +294,7 @@ object Deps {
def cryptoTest = Def.setting {
List(
Test.scalaTest.value,
Test.scalacheck.value,
Compile.scalaTestPlus.value
Test.scalacheck.value
)
}

View File

@ -6,22 +6,22 @@ import org.bitcoins.core.protocol.blockchain.ChainParams
import org.bitcoins.core.util.BitcoinSLogger
import org.scalacheck.{Gen, Shrink}
import org.scalactic.anyvals.PosInt
import org.scalatest.concurrent.AsyncTimeLimitedTests
import org.scalatest.flatspec.AsyncFlatSpec
import org.scalatest.matchers.must.Matchers
import org.scalatest.time.Span
import org.scalatest.{
Assertion,
AsyncTestSuite,
BeforeAndAfter,
BeforeAndAfterAll
}
import org.scalatest.concurrent.AsyncTimeLimitedTests
import org.scalatest.flatspec.AsyncFlatSpec
import org.scalatest.matchers.must.Matchers
import org.scalatest.time.Span
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import scala.annotation.nowarn
import scala.collection.JavaConverters.iterableAsScalaIterableConverter
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration._
/** This is a base trait in bitcoin-s for async tests
*/
@ -30,7 +30,8 @@ trait BaseAsyncTest
with BeforeAndAfterAll
with Matchers
with ScalaCheckPropertyChecks
with AsyncTimeLimitedTests { this: AsyncTestSuite =>
with AsyncTimeLimitedTests
with BitcoinSLogger { this: AsyncTestSuite =>
implicit def np: NetworkParameters = RegTest
@ -290,10 +291,7 @@ trait BaseAsyncTest
* uses the default scala execution context to run
* the tests on
*/
trait BitcoinSJvmTest
extends AsyncFlatSpec
with BaseAsyncTest
with BitcoinSLogger {
trait BitcoinSJvmTest extends AsyncFlatSpec with BaseAsyncTest {
implicit override def executionContext: ExecutionContext =
scala.concurrent.ExecutionContext.global

View File

@ -14,7 +14,6 @@ import org.bitcoins.core.gcs.FilterHeader
import org.bitcoins.core.p2p.CompactFilterMessage
import org.bitcoins.core.protocol.blockchain.BlockHeader
import org.bitcoins.core.protocol.{BitcoinAddress, BlockStamp}
import org.bitcoins.core.util.BitcoinSLogger
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.db.AppConfig
import org.bitcoins.node._
@ -56,7 +55,7 @@ import org.scalatest.FutureOutcome
import scala.concurrent.duration._
import scala.concurrent.{ExecutionContext, Future}
trait NodeUnitTest extends BitcoinSFixture with EmbeddedPg with BitcoinSLogger {
trait NodeUnitTest extends BitcoinSFixture with EmbeddedPg {
override def beforeAll(): Unit = {
AppConfig.throwIfDefaultDatadir(getFreshConfig.nodeConf)

View File

@ -2,14 +2,13 @@ package org.bitcoins.testkit.util
import java.nio.file.Files
import org.bitcoins.core.config.NetworkParameters
import org.bitcoins.core.util.BitcoinSLogger
import org.bitcoins.rpc.client.common.BitcoindRpcClient
import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil
import scala.collection.mutable
import scala.concurrent.Future
abstract class BitcoindRpcTest extends BitcoinSAsyncTest with BitcoinSLogger {
abstract class BitcoindRpcTest extends BitcoinSAsyncTest {
private val dirExists =
Files.exists(BitcoindRpcTestClient.sbtBinaryDirectory)