mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 01:40:55 +01:00
Pull over scala3 compatible code for crypto/
project (#5575)
* Pull over scala3 compatible code for crypto/ project from https://github.com/bitcoin-s/bitcoin-s/pull/3497 * Add -Xsource:3 flag to crypto/ * Remove tests for constructors
This commit is contained in:
parent
f707db0a0e
commit
3af204e74d
@ -36,6 +36,7 @@ lazy val commonJsSettings = {
|
||||
|
||||
lazy val crypto = crossProject(JVMPlatform, JSPlatform)
|
||||
.crossType(CrossType.Pure)
|
||||
.settings(scalacOptions += "-Xsource:3")
|
||||
.settings(
|
||||
name := "bitcoin-s-crypto",
|
||||
libraryDependencies ++= Deps.crypto.value
|
||||
|
@ -354,10 +354,6 @@ class AesCryptTest extends BitcoinSCryptoTest {
|
||||
assertDoesNotCompile("""val k = AesKey(hex"1234")""")
|
||||
}
|
||||
|
||||
it must "not have a constructor" in {
|
||||
assertDoesNotCompile("""val k = new AesKey(hex"1234")""")
|
||||
}
|
||||
|
||||
it must "not be constructable from bad byte lenghts" in {
|
||||
val bytevectorGens: Seq[Gen[ByteVector]] =
|
||||
(0 until 100)
|
||||
@ -383,11 +379,6 @@ class AesCryptTest extends BitcoinSCryptoTest {
|
||||
assertDoesNotCompile("""val iv = AesIV(hex"1234")""")
|
||||
}
|
||||
|
||||
it must "not have a constructor" in {
|
||||
assertDoesNotCompile("""val iv = new AesIV(hex"1234")""")
|
||||
|
||||
}
|
||||
|
||||
it must "not be constructable from invalid length bytes" in {
|
||||
val bytes = hex"12345"
|
||||
intercept[IllegalArgumentException] {
|
||||
@ -401,10 +392,6 @@ class AesCryptTest extends BitcoinSCryptoTest {
|
||||
assertDoesNotCompile("""val p = AesPassword("hi there")""")
|
||||
}
|
||||
|
||||
it must "not have a constructor" in {
|
||||
assertDoesNotCompile("""val p = new AesPassword("hi there")""")
|
||||
}
|
||||
|
||||
it must "fail to create an empty AES password" in {
|
||||
assert(AesPassword.fromStringOpt("").isEmpty)
|
||||
intercept[IllegalArgumentException] {
|
||||
|
@ -67,10 +67,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
override def toPublicKey(privateKey: ECPrivateKeyBytes): ECPublicKey = {
|
||||
val buffer = CryptoJsUtil.toNodeBuffer(privateKey.bytes)
|
||||
val pubKeyBuffer =
|
||||
SECP256k1.publicKeyCreate(
|
||||
key = buffer,
|
||||
compressed = privateKey.isCompressed
|
||||
)
|
||||
SECP256k1.publicKeyCreate(key = buffer,
|
||||
compressed = privateKey.isCompressed)
|
||||
val privKeyByteVec = CryptoJsUtil.toByteVector(pubKeyBuffer)
|
||||
ECPublicKey.fromBytes(privKeyByteVec)
|
||||
}
|
||||
@ -155,8 +153,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
*/
|
||||
override def recoverPublicKey(
|
||||
signature: ECDigitalSignature,
|
||||
message: ByteVector
|
||||
): (ECPublicKey, ECPublicKey) = {
|
||||
message: ByteVector): (ECPublicKey, ECPublicKey) = {
|
||||
val msgBuffer = CryptoJsUtil.toNodeBuffer(message)
|
||||
val sigBuffer = CryptoJsUtil.toNodeBuffer(signature.bytes)
|
||||
val keyBytes =
|
||||
@ -190,8 +187,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def sign(
|
||||
privateKey: ECPrivateKey,
|
||||
dataToSign: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
dataToSign: ByteVector): ECDigitalSignature = {
|
||||
val privBuffer = CryptoJsUtil.toNodeBuffer(privateKey.bytes)
|
||||
val dataBuffer = CryptoJsUtil.toNodeBuffer(dataToSign)
|
||||
val buffer = SECP256k1.signDER(dataBuffer, privBuffer)
|
||||
@ -202,8 +198,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
override def signWithEntropy(
|
||||
privateKey: ECPrivateKey,
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature = ???
|
||||
entropy: ByteVector): ECDigitalSignature = ???
|
||||
|
||||
override def secKeyVerify(privateKeybytes: ByteVector): Boolean = {
|
||||
val buffer = CryptoJsUtil.toNodeBuffer(privateKeybytes)
|
||||
@ -213,8 +208,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
override def verify(
|
||||
publicKey: ECPublicKeyApi,
|
||||
data: ByteVector,
|
||||
signature: ECDigitalSignature
|
||||
): Boolean = {
|
||||
signature: ECDigitalSignature): Boolean = {
|
||||
val dataBuffer = CryptoJsUtil.toNodeBuffer(data)
|
||||
val sigBuffer = CryptoJsUtil.toNodeBuffer(signature.bytes)
|
||||
val pubKeyBuffer = CryptoJsUtil.toNodeBuffer(publicKey.bytes)
|
||||
@ -223,8 +217,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def tweakMultiply(
|
||||
publicKey: ECPublicKey,
|
||||
tweak: FieldElement
|
||||
): ECPublicKey = {
|
||||
tweak: FieldElement): ECPublicKey = {
|
||||
val pubKeyBuffer = CryptoJsUtil.toNodeBuffer(publicKey.decompressedBytes)
|
||||
val tweakBuffer = CryptoJsUtil.toNodeBuffer(tweak.bytes)
|
||||
val keyBuffer =
|
||||
@ -238,10 +231,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
val pk2Buffer = CryptoJsUtil.toNodeBuffer(pk2.decompressedBytes)
|
||||
try {
|
||||
val keyBuffer =
|
||||
SECP256k1.publicKeyCombine(
|
||||
js.Array(pk1Buffer, pk2Buffer),
|
||||
compress = true
|
||||
)
|
||||
SECP256k1.publicKeyCombine(js.Array(pk1Buffer, pk2Buffer),
|
||||
compress = true)
|
||||
val keyBytes = CryptoJsUtil.toByteVector(keyBuffer)
|
||||
ECPublicKey.fromBytes(keyBytes)
|
||||
} catch {
|
||||
@ -252,8 +243,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
// check for infinity
|
||||
if ((k1.head ^ k2.head) == 0x01 && k1.tail == k2.tail) {
|
||||
throw new IllegalArgumentException(
|
||||
s"Invalid public key sum, got 0x00 = $pk1 + $pk2"
|
||||
)
|
||||
s"Invalid public key sum, got 0x00 = $pk1 + $pk2")
|
||||
} else {
|
||||
throw ex
|
||||
}
|
||||
@ -262,8 +252,7 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def pubKeyTweakAdd(
|
||||
pubkey: ECPublicKey,
|
||||
privkey: ECPrivateKey
|
||||
): ECPublicKey = {
|
||||
privkey: ECPrivateKey): ECPublicKey = {
|
||||
val pubKeyBuffer = CryptoJsUtil.toNodeBuffer(pubkey.decompressedBytes)
|
||||
val privKeyBuffer = CryptoJsUtil.toNodeBuffer(privkey.bytes)
|
||||
val keyBuffer =
|
||||
@ -297,10 +286,8 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
if (decoded.isInfinity())
|
||||
SecpPointInfinity
|
||||
else
|
||||
SecpPoint(
|
||||
new BigInteger(decoded.getX().toString()),
|
||||
new BigInteger(decoded.getY().toString())
|
||||
)
|
||||
SecpPoint(new BigInteger(decoded.getX().toString()),
|
||||
new BigInteger(decoded.getY().toString()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,20 +295,17 @@ trait BCryptoCryptoRuntime extends CryptoRuntime {
|
||||
pass: ByteVector,
|
||||
salt: ByteVector,
|
||||
iterationCount: Int,
|
||||
derivedKeyLength: Int
|
||||
): ByteVector = {
|
||||
derivedKeyLength: Int): ByteVector = {
|
||||
|
||||
// bcrypto uses bytes instead of bits for length, so divide by 8
|
||||
val keyLengthBytes = derivedKeyLength / 8
|
||||
|
||||
val buffer =
|
||||
PBKDF2.derive(
|
||||
sha512,
|
||||
CryptoJsUtil.toNodeBuffer(pass),
|
||||
CryptoJsUtil.toNodeBuffer(salt),
|
||||
iterationCount,
|
||||
keyLengthBytes
|
||||
)
|
||||
PBKDF2.derive(sha512,
|
||||
CryptoJsUtil.toNodeBuffer(pass),
|
||||
CryptoJsUtil.toNodeBuffer(salt),
|
||||
iterationCount,
|
||||
keyLengthBytes)
|
||||
CryptoJsUtil.toByteVector(buffer)
|
||||
}
|
||||
}
|
||||
|
@ -26,10 +26,8 @@ object CryptoJsUtil {
|
||||
accum += entry.value
|
||||
}
|
||||
}
|
||||
require(
|
||||
accum.length == len,
|
||||
s"Need $len bytes for buffer -> bytevector conversion"
|
||||
)
|
||||
require(accum.length == len,
|
||||
s"Need $len bytes for buffer -> bytevector conversion")
|
||||
ByteVector(accum.map(_.toByte))
|
||||
}
|
||||
|
||||
|
@ -67,30 +67,24 @@ class Buffer() extends js.Object {
|
||||
* {{{new Buffer(arrayBuffer[, byteOffset[, length]])}}}
|
||||
*/
|
||||
@inline
|
||||
@deprecated(
|
||||
"Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.",
|
||||
since = "6.0.0"
|
||||
)
|
||||
@deprecated("Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.",
|
||||
since = "6.0.0")
|
||||
def this(arrayBuffer: ArrayBuffer, byteOffset: Int, length: Int) = this()
|
||||
|
||||
/** @example
|
||||
* {{{new Buffer(arrayBuffer[, byteOffset[, length]])}}}
|
||||
*/
|
||||
@inline
|
||||
@deprecated(
|
||||
"Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.",
|
||||
since = "6.0.0"
|
||||
)
|
||||
@deprecated("Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.",
|
||||
since = "6.0.0")
|
||||
def this(arrayBuffer: ArrayBuffer, byteOffset: Int) = this()
|
||||
|
||||
/** @example
|
||||
* {{{new Buffer(arrayBuffer[, byteOffset[, length]])}}}
|
||||
*/
|
||||
@inline
|
||||
@deprecated(
|
||||
"Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.",
|
||||
since = "6.0.0"
|
||||
)
|
||||
@deprecated("Use Buffer.from(arrayBuffer[, byteOffset [, length]]) instead.",
|
||||
since = "6.0.0")
|
||||
def this(arrayBuffer: ArrayBuffer) = this()
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@ -149,8 +143,7 @@ class Buffer() extends js.Object {
|
||||
targetStart: Int = js.native,
|
||||
targetEnd: Int = js.native,
|
||||
sourceStart: Int = js.native,
|
||||
sourceEnd: Int = js.native
|
||||
): Int = js.native
|
||||
sourceEnd: Int = js.native): Int = js.native
|
||||
|
||||
/** Copies data from a region of buf to a region in target even if the target
|
||||
* memory region overlaps with buf.
|
||||
@ -173,8 +166,7 @@ class Buffer() extends js.Object {
|
||||
target: Buffer,
|
||||
targetStart: Int = js.native,
|
||||
sourceStart: Int = js.native,
|
||||
sourceEnd: Int = js.native
|
||||
): Int = js.native
|
||||
sourceEnd: Int = js.native): Int = js.native
|
||||
|
||||
/** Creates and returns an iterator of [index, byte] pairs from the Buffer
|
||||
* contents.
|
||||
@ -215,8 +207,7 @@ class Buffer() extends js.Object {
|
||||
value: Buffer | Int | String,
|
||||
offset: Int = js.native,
|
||||
end: Int = js.native,
|
||||
encoding: String = js.native
|
||||
): this.type = js.native
|
||||
encoding: String = js.native): this.type = js.native
|
||||
|
||||
/** Returns the index of the first occurrence of value in buf or -1 if buf
|
||||
* does not contain value
|
||||
@ -235,8 +226,7 @@ class Buffer() extends js.Object {
|
||||
def indexOf(
|
||||
value: Buffer | Int | String,
|
||||
byteOffset: Int = js.native,
|
||||
encoding: String = js.native
|
||||
): Int = js.native
|
||||
encoding: String = js.native): Int = js.native
|
||||
|
||||
/** Equivalent to buf.indexOf() !== -1.
|
||||
* @param value
|
||||
@ -253,8 +243,7 @@ class Buffer() extends js.Object {
|
||||
def includes(
|
||||
value: Buffer | Int | String,
|
||||
byteOffset: Int = js.native,
|
||||
encoding: String = js.native
|
||||
): Boolean =
|
||||
encoding: String = js.native): Boolean =
|
||||
js.native
|
||||
|
||||
/** Creates and returns an iterator of buf keys (indices).
|
||||
@ -292,8 +281,7 @@ class Buffer() extends js.Object {
|
||||
def lastIndexOf(
|
||||
value: Buffer | Int | String,
|
||||
byteOffset: Int = js.native,
|
||||
encoding: String = js.native
|
||||
): Int =
|
||||
encoding: String = js.native): Int =
|
||||
js.native
|
||||
|
||||
/** Returns the amount of memory allocated for buf in bytes. Note that this
|
||||
@ -496,8 +484,7 @@ class Buffer() extends js.Object {
|
||||
def readIntBE(
|
||||
offset: Int,
|
||||
byteLength: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Reads byteLength number of bytes from buf at the specified offset and
|
||||
* interprets the result as a two's complement signed value. Supports up to
|
||||
@ -520,8 +507,7 @@ class Buffer() extends js.Object {
|
||||
def readIntLE(
|
||||
offset: Int,
|
||||
byteLength: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Reads an unsigned 8-bit integer from buf at the specified offset. Setting
|
||||
* noAssert to true allows offset to be beyond the end of buf, but the result
|
||||
@ -624,8 +610,7 @@ class Buffer() extends js.Object {
|
||||
def readUIntBE(
|
||||
offset: Int,
|
||||
byteLength: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Reads byteLength number of bytes from buf at the specified offset and
|
||||
* interprets the result as an unsigned integer. Supports up to 48 bits of
|
||||
@ -648,8 +633,7 @@ class Buffer() extends js.Object {
|
||||
def readUIntLE(
|
||||
offset: Int,
|
||||
byteLength: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Returns a new Buffer that references the same memory as the original, but
|
||||
* offset and cropped by the start and end indices.
|
||||
@ -722,8 +706,7 @@ class Buffer() extends js.Object {
|
||||
def toString(
|
||||
encoding: String = js.native,
|
||||
start: Int = js.native,
|
||||
end: Int = js.native
|
||||
): String = js.native
|
||||
end: Int = js.native): String = js.native
|
||||
|
||||
/** Re-encodes the given Buffer instance from one character encoding to
|
||||
* another. Returns a new Buffer instance. Throws if the fromEnc or toEnc
|
||||
@ -772,8 +755,7 @@ class Buffer() extends js.Object {
|
||||
string: String,
|
||||
offset: Int = js.native,
|
||||
length: Int = js.native,
|
||||
encoding: String = js.native
|
||||
): Int =
|
||||
encoding: String = js.native): Int =
|
||||
js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
@ -797,8 +779,7 @@ class Buffer() extends js.Object {
|
||||
def writeDoubleBE(
|
||||
value: Double,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeDoubleBE() writes big endian, writeDoubleLE() writes little endian).
|
||||
@ -821,8 +802,7 @@ class Buffer() extends js.Object {
|
||||
def writeDoubleLE(
|
||||
value: Double,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeFloatBE() writes big endian, writeFloatLE() writes little endian).
|
||||
@ -845,8 +825,7 @@ class Buffer() extends js.Object {
|
||||
def writeFloatBE(
|
||||
value: Float,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeFloatBE() writes big endian, writeFloatLE() writes little endian).
|
||||
@ -869,8 +848,7 @@ class Buffer() extends js.Object {
|
||||
def writeFloatLE(
|
||||
value: Float,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset. value should be a valid
|
||||
* signed 8-bit integer. Behavior is undefined when value is anything other
|
||||
@ -917,8 +895,7 @@ class Buffer() extends js.Object {
|
||||
def writeInt16BE(
|
||||
value: Int,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeInt16BE() writes big endian, writeInt16LE() writes little endian).
|
||||
@ -943,8 +920,7 @@ class Buffer() extends js.Object {
|
||||
def writeInt16LE(
|
||||
value: Int,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeInt32BE() writes big endian, writeInt32LE() writes little endian).
|
||||
@ -969,8 +945,7 @@ class Buffer() extends js.Object {
|
||||
def writeInt32BE(
|
||||
value: Int,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeInt32BE() writes big endian, writeInt32LE() writes little endian).
|
||||
@ -995,8 +970,7 @@ class Buffer() extends js.Object {
|
||||
def writeInt32LE(
|
||||
value: Int,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes byteLength bytes of value to buf at the specified offset. Supports
|
||||
* up to 48 bits of accuracy. Behavior is undefined when value is anything
|
||||
@ -1022,8 +996,7 @@ class Buffer() extends js.Object {
|
||||
value: Int,
|
||||
offset: Int,
|
||||
byteLength: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes byteLength bytes of value to buf at the specified offset. Supports
|
||||
* up to 48 bits of accuracy. Behavior is undefined when value is anything
|
||||
@ -1049,8 +1022,7 @@ class Buffer() extends js.Object {
|
||||
value: Int,
|
||||
offset: Int,
|
||||
byteLength: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset. value should be a valid
|
||||
* unsigned 8-bit integer. Behavior is undefined when value is anything other
|
||||
@ -1093,8 +1065,7 @@ class Buffer() extends js.Object {
|
||||
def writeUInt16BE(
|
||||
value: Int,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeUInt16BE() writes big endian, writeUInt16LE() writes little endian).
|
||||
@ -1117,8 +1088,7 @@ class Buffer() extends js.Object {
|
||||
def writeUInt16LE(
|
||||
value: Int,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeUInt32BE() writes big endian, writeUInt32LE() writes little endian).
|
||||
@ -1141,8 +1111,7 @@ class Buffer() extends js.Object {
|
||||
def writeUInt32BE(
|
||||
value: Int,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes value to buf at the specified offset with specified endian format
|
||||
* (writeUInt32BE() writes big endian, writeUInt32LE() writes little endian).
|
||||
@ -1165,8 +1134,7 @@ class Buffer() extends js.Object {
|
||||
def writeUInt32LE(
|
||||
value: Int,
|
||||
offset: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes byteLength bytes of value to buf at the specified offset. Supports
|
||||
* up to 48 bits of accuracy. Behavior is undefined when value is anything
|
||||
@ -1192,8 +1160,7 @@ class Buffer() extends js.Object {
|
||||
value: Int,
|
||||
offset: Int,
|
||||
byteLength: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
/** Writes byteLength bytes of value to buf at the specified offset. Supports
|
||||
* up to 48 bits of accuracy. Behavior is undefined when value is anything
|
||||
@ -1219,8 +1186,7 @@ class Buffer() extends js.Object {
|
||||
value: Int,
|
||||
offset: Int,
|
||||
byteLength: Int,
|
||||
noAssert: Boolean = js.native
|
||||
): Int = js.native
|
||||
noAssert: Boolean = js.native): Int = js.native
|
||||
|
||||
}
|
||||
|
||||
@ -1273,8 +1239,7 @@ object Buffer extends js.Object {
|
||||
def alloc(
|
||||
size: Int,
|
||||
fill: Buffer | Int | String = js.native,
|
||||
encoding: String = js.native
|
||||
): Buffer = js.native
|
||||
encoding: String = js.native): Buffer = js.native
|
||||
|
||||
/** Calling Buffer.alloc(size) can be significantly slower than the
|
||||
* alternative Buffer.allocUnsafe(size) but ensures that the newly created
|
||||
|
@ -17,6 +17,5 @@ object PBKDF2 extends js.Object {
|
||||
pass: Buffer,
|
||||
salt: Buffer,
|
||||
iter: Int,
|
||||
len: Int
|
||||
): Buffer = js.native
|
||||
len: Int): Buffer = js.native
|
||||
}
|
||||
|
@ -44,15 +44,13 @@ object SECP256k1 extends js.Object {
|
||||
msg: Buffer,
|
||||
sig: Buffer,
|
||||
param: Byte,
|
||||
compress: Boolean
|
||||
): Buffer = js.native
|
||||
compress: Boolean): Buffer = js.native
|
||||
|
||||
def recoverDER(
|
||||
msg: Buffer,
|
||||
sig: Buffer,
|
||||
param: Byte,
|
||||
compress: Boolean
|
||||
): Buffer = js.native
|
||||
compress: Boolean): Buffer = js.native
|
||||
|
||||
val curve: js.Dynamic = js.native
|
||||
}
|
||||
|
@ -9,10 +9,8 @@ object BouncyCastleCryptoParams {
|
||||
|
||||
/** The curve that bitcoin uses. */
|
||||
val curve =
|
||||
new ECDomainParameters(
|
||||
params.getCurve,
|
||||
params.getG,
|
||||
params.getN,
|
||||
params.getH
|
||||
)
|
||||
new ECDomainParameters(params.getCurve,
|
||||
params.getG,
|
||||
params.getN,
|
||||
params.getH)
|
||||
}
|
||||
|
@ -36,8 +36,7 @@ object BouncyCastleUtil {
|
||||
|
||||
private[crypto] def decodePubKey(
|
||||
point: ECPoint,
|
||||
isCompressed: Boolean = true
|
||||
): ECPublicKey = {
|
||||
isCompressed: Boolean = true): ECPublicKey = {
|
||||
val bytes = point.getEncoded(isCompressed)
|
||||
ECPublicKey.fromBytes(ByteVector(bytes))
|
||||
}
|
||||
@ -77,16 +76,12 @@ object BouncyCastleUtil {
|
||||
|
||||
def sign(
|
||||
dataToSign: ByteVector,
|
||||
privateKey: ECPrivateKey
|
||||
): ECDigitalSignature = {
|
||||
privateKey: ECPrivateKey): ECDigitalSignature = {
|
||||
val signer: ECDSASigner = new ECDSASigner(
|
||||
new HMacDSAKCalculator(new SHA256Digest())
|
||||
)
|
||||
new HMacDSAKCalculator(new SHA256Digest()))
|
||||
val privKey: ECPrivateKeyParameters =
|
||||
new ECPrivateKeyParameters(
|
||||
getBigInteger(privateKey.bytes),
|
||||
BouncyCastleCryptoParams.curve
|
||||
)
|
||||
new ECPrivateKeyParameters(getBigInteger(privateKey.bytes),
|
||||
BouncyCastleCryptoParams.curve)
|
||||
signer.init(true, privKey)
|
||||
val components: Array[BigInteger] =
|
||||
signer.generateSignature(dataToSign.toArray)
|
||||
@ -99,8 +94,7 @@ object BouncyCastleUtil {
|
||||
val signatureLowS = DERSignatureUtil.lowS(signature)
|
||||
require(
|
||||
signatureLowS.isDEREncoded,
|
||||
"We must create DER encoded signatures when signing a piece of data, got: " + signatureLowS
|
||||
)
|
||||
"We must create DER encoded signatures when signing a piece of data, got: " + signatureLowS)
|
||||
signatureLowS
|
||||
}
|
||||
|
||||
@ -117,16 +111,12 @@ object BouncyCastleUtil {
|
||||
def signWithEntropy(
|
||||
dataToSign: ByteVector,
|
||||
privateKey: ECPrivateKey,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
entropy: ByteVector): ECDigitalSignature = {
|
||||
val signer: ECDSASigner = new ECDSASigner(
|
||||
new HMacDSAKCalculatorWithEntropy(new SHA256Digest(), entropy)
|
||||
)
|
||||
new HMacDSAKCalculatorWithEntropy(new SHA256Digest(), entropy))
|
||||
val privKey: ECPrivateKeyParameters =
|
||||
new ECPrivateKeyParameters(
|
||||
getBigInteger(privateKey.bytes),
|
||||
BouncyCastleCryptoParams.curve
|
||||
)
|
||||
new ECPrivateKeyParameters(getBigInteger(privateKey.bytes),
|
||||
BouncyCastleCryptoParams.curve)
|
||||
signer.init(true, privKey)
|
||||
val components: Array[BigInteger] =
|
||||
signer.generateSignature(dataToSign.toArray)
|
||||
@ -139,32 +129,26 @@ object BouncyCastleUtil {
|
||||
val signatureLowS = DERSignatureUtil.lowS(signature)
|
||||
require(
|
||||
signatureLowS.isDEREncoded,
|
||||
"We must create DER encoded signatures when signing a piece of data, got: " + signatureLowS
|
||||
)
|
||||
"We must create DER encoded signatures when signing a piece of data, got: " + signatureLowS)
|
||||
signatureLowS
|
||||
}
|
||||
|
||||
def verifyDigitalSignature(
|
||||
data: ByteVector,
|
||||
publicKey: ECPublicKeyApi,
|
||||
signature: ECDigitalSignature
|
||||
): Boolean = {
|
||||
signature: ECDigitalSignature): Boolean = {
|
||||
val resultTry = Try {
|
||||
val publicKeyParams =
|
||||
new ECPublicKeyParameters(
|
||||
decodePoint(publicKey.bytes),
|
||||
BouncyCastleCryptoParams.curve
|
||||
)
|
||||
new ECPublicKeyParameters(decodePoint(publicKey.bytes),
|
||||
BouncyCastleCryptoParams.curve)
|
||||
|
||||
val signer = new ECDSASigner
|
||||
signer.init(false, publicKeyParams)
|
||||
signature match {
|
||||
case EmptyDigitalSignature =>
|
||||
signer.verifySignature(
|
||||
data.toArray,
|
||||
java.math.BigInteger.valueOf(0),
|
||||
java.math.BigInteger.valueOf(0)
|
||||
)
|
||||
signer.verifySignature(data.toArray,
|
||||
java.math.BigInteger.valueOf(0),
|
||||
java.math.BigInteger.valueOf(0))
|
||||
case _: ECDigitalSignature =>
|
||||
val (r, s) = signature.decodeSignature
|
||||
signer.verifySignature(data.toArray, r.bigInteger, s.bigInteger)
|
||||
|
@ -18,7 +18,7 @@ import java.security.{MessageDigest, SecureRandom}
|
||||
* Castle (https://bouncycastle.org/) and [[java.security]].
|
||||
*/
|
||||
trait BouncycastleCryptoRuntime extends CryptoRuntime {
|
||||
private[this] lazy val secureRandom = new SecureRandom()
|
||||
private lazy val secureRandom = new SecureRandom()
|
||||
|
||||
override val cryptoContext: CryptoContext = CryptoContext.BouncyCastle
|
||||
|
||||
@ -65,20 +65,16 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
|
||||
bytes.tail
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
s"Field element cannot have more than 32 bytes, got $bytes from $x"
|
||||
)
|
||||
s"Field element cannot have more than 32 bytes, got $bytes from $x")
|
||||
}
|
||||
|
||||
(
|
||||
BouncyCastleUtil.decodePoint(ECPublicKey(0x02.toByte +: bytes32)),
|
||||
BouncyCastleUtil.decodePoint(ECPublicKey(0x03.toByte +: bytes32))
|
||||
)
|
||||
(BouncyCastleUtil.decodePoint(ECPublicKey(0x02.toByte +: bytes32)),
|
||||
BouncyCastleUtil.decodePoint(ECPublicKey(0x03.toByte +: bytes32)))
|
||||
}
|
||||
|
||||
override def recoverPublicKey(
|
||||
signature: ECDigitalSignature,
|
||||
message: ByteVector
|
||||
): (ECPublicKey, ECPublicKey) = {
|
||||
message: ByteVector): (ECPublicKey, ECPublicKey) = {
|
||||
|
||||
val curve = BouncyCastleCryptoParams.curve
|
||||
val (r, s) = (signature.r.bigInteger, signature.s.bigInteger)
|
||||
@ -159,16 +155,14 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def sign(
|
||||
privateKey: ECPrivateKey,
|
||||
dataToSign: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
dataToSign: ByteVector): ECDigitalSignature = {
|
||||
BouncyCastleUtil.sign(dataToSign, privateKey)
|
||||
}
|
||||
|
||||
override def signWithEntropy(
|
||||
privateKey: ECPrivateKey,
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature =
|
||||
entropy: ByteVector): ECDigitalSignature =
|
||||
BouncyCastleUtil.signWithEntropy(bytes, privateKey, entropy)
|
||||
|
||||
override def secKeyVerify(privateKeyBytes: ByteVector): Boolean = {
|
||||
@ -182,8 +176,7 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
|
||||
override def verify(
|
||||
publicKey: ECPublicKeyApi,
|
||||
data: ByteVector,
|
||||
signature: ECDigitalSignature
|
||||
): Boolean =
|
||||
signature: ECDigitalSignature): Boolean =
|
||||
BouncyCastleUtil.verifyDigitalSignature(data, publicKey, signature)
|
||||
|
||||
override def publicKey(privateKey: ECPrivateKeyBytes): ECPublicKey =
|
||||
@ -191,8 +184,7 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def tweakMultiply(
|
||||
publicKey: ECPublicKey,
|
||||
tweak: FieldElement
|
||||
): ECPublicKey =
|
||||
tweak: FieldElement): ECPublicKey =
|
||||
BouncyCastleUtil.pubKeyTweakMul(publicKey, tweak.bytes)
|
||||
|
||||
override def add(pk1: ECPublicKey, pk2: ECPublicKey): ECPublicKey = {
|
||||
@ -204,8 +196,7 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
|
||||
|
||||
def pubKeyTweakAdd(
|
||||
pubkey: ECPublicKey,
|
||||
privkey: ECPrivateKey
|
||||
): ECPublicKey = {
|
||||
privkey: ECPrivateKey): ECPublicKey = {
|
||||
val tweak = privkey.publicKey
|
||||
pubkey.add(tweak)
|
||||
}
|
||||
@ -233,18 +224,15 @@ trait BouncycastleCryptoRuntime extends CryptoRuntime {
|
||||
if (decoded.isInfinity)
|
||||
SecpPointInfinity
|
||||
else
|
||||
SecpPoint(
|
||||
decoded.getRawXCoord.getEncoded,
|
||||
decoded.getRawYCoord.getEncoded
|
||||
)
|
||||
SecpPoint(decoded.getRawXCoord.getEncoded,
|
||||
decoded.getRawYCoord.getEncoded)
|
||||
}
|
||||
|
||||
override def pbkdf2WithSha512(
|
||||
pass: ByteVector,
|
||||
salt: ByteVector,
|
||||
iterationCount: Int,
|
||||
derivedKeyLength: Int
|
||||
): ByteVector = {
|
||||
derivedKeyLength: Int): ByteVector = {
|
||||
val bytes =
|
||||
PBKDF2.withSha512(pass, salt, iterationCount, derivedKeyLength).getEncoded
|
||||
ByteVector(bytes)
|
||||
|
@ -42,8 +42,7 @@ class HMacDSAKCalculatorWithEntropy(digest: Digest, entropy: ByteVector)
|
||||
override def init(
|
||||
n: BigInteger,
|
||||
d: BigInteger,
|
||||
message: Array[Byte]
|
||||
): Unit = {
|
||||
message: Array[Byte]): Unit = {
|
||||
this.n = n
|
||||
|
||||
Arrays.fill(V, 0x01.toByte)
|
||||
|
@ -16,8 +16,7 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def recoverPublicKey(
|
||||
signature: ECDigitalSignature,
|
||||
message: ByteVector
|
||||
): (ECPublicKey, ECPublicKey) =
|
||||
message: ByteVector): (ECPublicKey, ECPublicKey) =
|
||||
BouncycastleCryptoRuntime.recoverPublicKey(signature, message)
|
||||
|
||||
override def hmac512(key: ByteVector, data: ByteVector): ByteVector =
|
||||
@ -52,18 +51,15 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def toPublicKey(privateKey: ECPrivateKeyBytes): ECPublicKey = {
|
||||
val pubKeyBytes: Array[Byte] =
|
||||
NativeSecp256k1.computePubkey(
|
||||
privateKey.bytes.toArray,
|
||||
privateKey.isCompressed
|
||||
)
|
||||
NativeSecp256k1.computePubkey(privateKey.bytes.toArray,
|
||||
privateKey.isCompressed)
|
||||
val pubBytes = ByteVector(pubKeyBytes)
|
||||
ECPublicKey(pubBytes)
|
||||
}
|
||||
|
||||
override def sign(
|
||||
privateKey: ECPrivateKey,
|
||||
dataToSign: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
dataToSign: ByteVector): ECDigitalSignature = {
|
||||
val signature =
|
||||
NativeSecp256k1.sign(dataToSign.toArray, privateKey.bytes.toArray)
|
||||
ECDigitalSignature(ByteVector(signature))
|
||||
@ -72,13 +68,10 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
override def signWithEntropy(
|
||||
privateKey: ECPrivateKey,
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
val sigBytes = NativeSecp256k1.signWithEntropy(
|
||||
bytes.toArray,
|
||||
privateKey.bytes.toArray,
|
||||
entropy.toArray
|
||||
)
|
||||
entropy: ByteVector): ECDigitalSignature = {
|
||||
val sigBytes = NativeSecp256k1.signWithEntropy(bytes.toArray,
|
||||
privateKey.bytes.toArray,
|
||||
entropy.toArray)
|
||||
|
||||
ECDigitalSignature(ByteVector(sigBytes))
|
||||
}
|
||||
@ -89,14 +82,11 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
override def verify(
|
||||
publicKey: ECPublicKeyApi,
|
||||
data: ByteVector,
|
||||
signature: ECDigitalSignature
|
||||
): Boolean = {
|
||||
signature: ECDigitalSignature): Boolean = {
|
||||
val result =
|
||||
NativeSecp256k1.verify(
|
||||
data.toArray,
|
||||
signature.bytes.toArray,
|
||||
publicKey.bytes.toArray
|
||||
)
|
||||
NativeSecp256k1.verify(data.toArray,
|
||||
signature.bytes.toArray,
|
||||
publicKey.bytes.toArray)
|
||||
|
||||
if (!result) {
|
||||
// if signature verification fails with libsecp256k1 we need to use our old
|
||||
@ -116,23 +106,18 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def publicKey(privateKey: ECPrivateKeyBytes): ECPublicKey = {
|
||||
val pubKeyBytes: Array[Byte] =
|
||||
NativeSecp256k1.computePubkey(
|
||||
privateKey.bytes.toArray,
|
||||
privateKey.isCompressed
|
||||
)
|
||||
NativeSecp256k1.computePubkey(privateKey.bytes.toArray,
|
||||
privateKey.isCompressed)
|
||||
val pubBytes = ByteVector(pubKeyBytes)
|
||||
ECPublicKey(pubBytes)
|
||||
}
|
||||
|
||||
override def tweakMultiply(
|
||||
publicKey: ECPublicKey,
|
||||
tweak: FieldElement
|
||||
): ECPublicKey = {
|
||||
val mulBytes = NativeSecp256k1.pubKeyTweakMul(
|
||||
publicKey.bytes.toArray,
|
||||
tweak.bytes.toArray,
|
||||
true
|
||||
)
|
||||
tweak: FieldElement): ECPublicKey = {
|
||||
val mulBytes = NativeSecp256k1.pubKeyTweakMul(publicKey.bytes.toArray,
|
||||
tweak.bytes.toArray,
|
||||
true)
|
||||
ECPublicKey(ByteVector(mulBytes))
|
||||
}
|
||||
|
||||
@ -158,8 +143,7 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def combinePubKeys(
|
||||
pubKeys: Vector[ECPublicKey],
|
||||
isCompressed: Boolean = true
|
||||
): ECPublicKey = {
|
||||
isCompressed: Boolean = true): ECPublicKey = {
|
||||
val summands = pubKeys.map(_.decompressedBytes.toArray).toArray
|
||||
val sumKey = NativeSecp256k1.pubKeyCombine(summands, isCompressed)
|
||||
|
||||
@ -168,54 +152,43 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
|
||||
override def pubKeyTweakAdd(
|
||||
pubkey: ECPublicKey,
|
||||
privkey: ECPrivateKey
|
||||
): ECPublicKey = {
|
||||
privkey: ECPrivateKey): ECPublicKey = {
|
||||
val tweaked = NativeSecp256k1.pubKeyTweakAdd(
|
||||
pubkey.decompressedBytes.toArray,
|
||||
privkey.bytes.toArray,
|
||||
true
|
||||
)
|
||||
true)
|
||||
ECPublicKey(ByteVector(tweaked))
|
||||
}
|
||||
|
||||
override def schnorrSign(
|
||||
dataToSign: ByteVector,
|
||||
privateKey: ECPrivateKey,
|
||||
auxRand: ByteVector
|
||||
): SchnorrDigitalSignature = {
|
||||
auxRand: ByteVector): SchnorrDigitalSignature = {
|
||||
val sigBytes =
|
||||
NativeSecp256k1.schnorrSign(
|
||||
dataToSign.toArray,
|
||||
privateKey.bytes.toArray,
|
||||
auxRand.toArray
|
||||
)
|
||||
NativeSecp256k1.schnorrSign(dataToSign.toArray,
|
||||
privateKey.bytes.toArray,
|
||||
auxRand.toArray)
|
||||
SchnorrDigitalSignature(ByteVector(sigBytes))
|
||||
}
|
||||
|
||||
override def schnorrSignWithNonce(
|
||||
dataToSign: ByteVector,
|
||||
privateKey: ECPrivateKey,
|
||||
nonceKey: ECPrivateKey
|
||||
): SchnorrDigitalSignature = {
|
||||
nonceKey: ECPrivateKey): SchnorrDigitalSignature = {
|
||||
val sigBytes =
|
||||
NativeSecp256k1.schnorrSignWithNonce(
|
||||
dataToSign.toArray,
|
||||
privateKey.bytes.toArray,
|
||||
nonceKey.bytes.toArray
|
||||
)
|
||||
NativeSecp256k1.schnorrSignWithNonce(dataToSign.toArray,
|
||||
privateKey.bytes.toArray,
|
||||
nonceKey.bytes.toArray)
|
||||
SchnorrDigitalSignature(ByteVector(sigBytes))
|
||||
}
|
||||
|
||||
override def schnorrVerify(
|
||||
data: ByteVector,
|
||||
schnorrPubKey: SchnorrPublicKey,
|
||||
signature: SchnorrDigitalSignature
|
||||
): Boolean = {
|
||||
NativeSecp256k1.schnorrVerify(
|
||||
signature.bytes.toArray,
|
||||
data.toArray,
|
||||
schnorrPubKey.bytes.toArray
|
||||
)
|
||||
signature: SchnorrDigitalSignature): Boolean = {
|
||||
NativeSecp256k1.schnorrVerify(signature.bytes.toArray,
|
||||
data.toArray,
|
||||
schnorrPubKey.bytes.toArray)
|
||||
}
|
||||
|
||||
// TODO: add a native implementation
|
||||
@ -223,53 +196,43 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
data: ByteVector,
|
||||
nonce: SchnorrNonce,
|
||||
pubKey: SchnorrPublicKey,
|
||||
compressed: Boolean
|
||||
): ECPublicKey = {
|
||||
BouncycastleCryptoRuntime.schnorrComputeSigPoint(
|
||||
data,
|
||||
nonce,
|
||||
pubKey,
|
||||
compressed
|
||||
)
|
||||
compressed: Boolean): ECPublicKey = {
|
||||
BouncycastleCryptoRuntime.schnorrComputeSigPoint(data,
|
||||
nonce,
|
||||
pubKey,
|
||||
compressed)
|
||||
}
|
||||
|
||||
override def adaptorSign(
|
||||
key: ECPrivateKey,
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): ECAdaptorSignature = {
|
||||
auxRand: ByteVector): ECAdaptorSignature = {
|
||||
val sig = NativeSecp256k1.adaptorSign(
|
||||
key.bytes.toArray,
|
||||
adaptorPoint.decompressedBytes.toArray,
|
||||
msg.toArray,
|
||||
auxRand.toArray
|
||||
)
|
||||
auxRand.toArray)
|
||||
ECAdaptorSignature(ByteVector(sig))
|
||||
}
|
||||
|
||||
override def adaptorComplete(
|
||||
key: ECPrivateKey,
|
||||
adaptorSignature: ECAdaptorSignature
|
||||
): ECDigitalSignature = {
|
||||
adaptorSignature: ECAdaptorSignature): ECDigitalSignature = {
|
||||
val sigBytes =
|
||||
NativeSecp256k1.adaptorAdapt(
|
||||
key.bytes.toArray,
|
||||
adaptorSignature.bytes.toArray
|
||||
)
|
||||
NativeSecp256k1.adaptorAdapt(key.bytes.toArray,
|
||||
adaptorSignature.bytes.toArray)
|
||||
ECDigitalSignature.fromBytes(ByteVector(sigBytes))
|
||||
}
|
||||
|
||||
override def extractAdaptorSecret(
|
||||
signature: ECDigitalSignature,
|
||||
adaptorSignature: ECAdaptorSignature,
|
||||
key: ECPublicKey
|
||||
): ECPrivateKey = {
|
||||
key: ECPublicKey): ECPrivateKey = {
|
||||
val secretBytes = NativeSecp256k1.adaptorExtractSecret(
|
||||
signature.bytes.toArray,
|
||||
adaptorSignature.bytes.toArray,
|
||||
key.decompressedBytes.toArray
|
||||
)
|
||||
key.decompressedBytes.toArray)
|
||||
|
||||
ECPrivateKey(ByteVector(secretBytes))
|
||||
}
|
||||
@ -278,19 +241,15 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
adaptorSignature: ECAdaptorSignature,
|
||||
key: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
adaptorPoint: ECPublicKey
|
||||
): Boolean = {
|
||||
NativeSecp256k1.adaptorVerify(
|
||||
adaptorSignature.bytes.toArray,
|
||||
key.decompressedBytes.toArray,
|
||||
msg.toArray,
|
||||
adaptorPoint.decompressedBytes.toArray
|
||||
)
|
||||
adaptorPoint: ECPublicKey): Boolean = {
|
||||
NativeSecp256k1.adaptorVerify(adaptorSignature.bytes.toArray,
|
||||
key.decompressedBytes.toArray,
|
||||
msg.toArray,
|
||||
adaptorPoint.decompressedBytes.toArray)
|
||||
}
|
||||
|
||||
override def isValidSignatureEncoding(
|
||||
signature: ECDigitalSignature
|
||||
): Boolean =
|
||||
signature: ECDigitalSignature): Boolean =
|
||||
BouncycastleCryptoRuntime.isValidSignatureEncoding(signature)
|
||||
|
||||
override def isDEREncoded(signature: ECDigitalSignature): Boolean =
|
||||
@ -320,14 +279,11 @@ trait LibSecp256k1CryptoRuntime extends CryptoRuntime {
|
||||
pass: ByteVector,
|
||||
salt: ByteVector,
|
||||
iterationCount: Int,
|
||||
derivedKeyLength: Int
|
||||
): ByteVector = {
|
||||
BouncycastleCryptoRuntime.pbkdf2WithSha512(
|
||||
pass,
|
||||
salt,
|
||||
iterationCount,
|
||||
derivedKeyLength
|
||||
)
|
||||
derivedKeyLength: Int): ByteVector = {
|
||||
BouncycastleCryptoRuntime.pbkdf2WithSha512(pass,
|
||||
salt,
|
||||
iterationCount,
|
||||
derivedKeyLength)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,7 @@ object PBKDF2 {
|
||||
bytes: ByteVector,
|
||||
salt: ByteVector,
|
||||
iterationCount: Int,
|
||||
derivedKeyLength: Int
|
||||
): SecretKey = {
|
||||
derivedKeyLength: Int): SecretKey = {
|
||||
|
||||
val keySpec = new PBEKeySpec(
|
||||
bytes.toArray.map(_.toChar),
|
||||
|
@ -26,8 +26,7 @@ object AdaptorUtil {
|
||||
privKey: ECPrivateKey,
|
||||
adaptorPoint: ECPublicKey,
|
||||
algoName: String,
|
||||
auxRand: ByteVector
|
||||
): FieldElement = {
|
||||
auxRand: ByteVector): FieldElement = {
|
||||
val randHash = CryptoUtil.sha256ECDSAAdaptorAux(auxRand).bytes
|
||||
val maskedKey = randHash.xor(privKey.bytes)
|
||||
|
||||
@ -49,13 +48,11 @@ object AdaptorUtil {
|
||||
dataToSign: ByteVector,
|
||||
k: FieldElement,
|
||||
r: ECPublicKey,
|
||||
privateKey: ECPrivateKey
|
||||
): FieldElement = {
|
||||
privateKey: ECPrivateKey): FieldElement = {
|
||||
CryptoUtil.decodePoint(r) match {
|
||||
case SecpPointInfinity =>
|
||||
throw new IllegalArgumentException(
|
||||
s"Invalid point, got=$SecpPointInfinity"
|
||||
)
|
||||
s"Invalid point, got=$SecpPointInfinity")
|
||||
case point: SecpPointFinite =>
|
||||
val rx = FieldElement(point.x.toBigInteger)
|
||||
val x = privateKey.fieldElement
|
||||
@ -73,15 +70,12 @@ object AdaptorUtil {
|
||||
privateKey: ECPrivateKey,
|
||||
adaptorPoint: ECPublicKey,
|
||||
dataToSign: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): ECAdaptorSignature = {
|
||||
val k = adaptorNonce(
|
||||
dataToSign,
|
||||
privateKey,
|
||||
adaptorPoint,
|
||||
"ECDSAadaptor/non",
|
||||
auxRand
|
||||
)
|
||||
auxRand: ByteVector): ECAdaptorSignature = {
|
||||
val k = adaptorNonce(dataToSign,
|
||||
privateKey,
|
||||
adaptorPoint,
|
||||
"ECDSAadaptor/non",
|
||||
auxRand)
|
||||
|
||||
if (k.isZero) {
|
||||
throw new RuntimeException("Nonce cannot be zero.")
|
||||
@ -106,8 +100,7 @@ object AdaptorUtil {
|
||||
rx: FieldElement,
|
||||
s: FieldElement,
|
||||
pubKey: ECPublicKey,
|
||||
msg: ByteVector
|
||||
): FieldElement = {
|
||||
msg: ByteVector): FieldElement = {
|
||||
val m = FieldElement(msg)
|
||||
val untweakedPoint =
|
||||
m.getPublicKey.add(pubKey.multiply(rx)).multiply(s.inverse)
|
||||
@ -121,8 +114,7 @@ object AdaptorUtil {
|
||||
adaptorSig: ECAdaptorSignature,
|
||||
pubKey: ECPublicKey,
|
||||
data: ByteVector,
|
||||
adaptor: ECPublicKey
|
||||
): Boolean = {
|
||||
adaptor: ECPublicKey): Boolean = {
|
||||
val validProof = DLEQUtil.dleqVerify(
|
||||
adaptorSig.dleqProofS,
|
||||
adaptorSig.dleqProofE,
|
||||
@ -133,8 +125,7 @@ object AdaptorUtil {
|
||||
|
||||
if (validProof) {
|
||||
val tweakedNoncex = FieldElement(
|
||||
CurveCoordinate(adaptorSig.tweakedNonce.bytes.tail).toBigInteger
|
||||
)
|
||||
CurveCoordinate(adaptorSig.tweakedNonce.bytes.tail).toBigInteger)
|
||||
val untweakedNoncex = FieldElement(adaptorSig.untweakedNonce.bytes.tail)
|
||||
|
||||
if (tweakedNoncex.isZero || untweakedNoncex.isZero) {
|
||||
@ -156,15 +147,12 @@ object AdaptorUtil {
|
||||
*/
|
||||
def adaptorComplete(
|
||||
adaptorSecret: ECPrivateKey,
|
||||
adaptorSig: ECAdaptorSignature
|
||||
): ECDigitalSignature = {
|
||||
adaptorSig: ECAdaptorSignature): ECDigitalSignature = {
|
||||
val rx = FieldElement(adaptorSig.tweakedNonce.bytes.tail)
|
||||
val correctedS = adaptorSig.adaptedS.multInv(adaptorSecret.fieldElement)
|
||||
|
||||
val sig = ECDigitalSignature.fromRS(
|
||||
BigInt(rx.toBigInteger),
|
||||
BigInt(correctedS.toBigInteger)
|
||||
)
|
||||
val sig = ECDigitalSignature.fromRS(BigInt(rx.toBigInteger),
|
||||
BigInt(correctedS.toBigInteger))
|
||||
DERSignatureUtil.lowS(sig)
|
||||
}
|
||||
|
||||
@ -174,19 +162,14 @@ object AdaptorUtil {
|
||||
def extractAdaptorSecret(
|
||||
sig: ECDigitalSignature,
|
||||
adaptorSig: ECAdaptorSignature,
|
||||
adaptor: ECPublicKey
|
||||
): ECPrivateKey = {
|
||||
require(
|
||||
adaptorSig.tweakedNonce.bytes.tail == sig.rBytes,
|
||||
"Adaptor signature must be related to signature"
|
||||
)
|
||||
adaptor: ECPublicKey): ECPrivateKey = {
|
||||
require(adaptorSig.tweakedNonce.bytes.tail == sig.rBytes,
|
||||
"Adaptor signature must be related to signature")
|
||||
|
||||
val secretOrNeg = adaptorSig.adaptedS.multInv(FieldElement(sig.s))
|
||||
|
||||
require(
|
||||
secretOrNeg.getPublicKey.bytes.tail == adaptor.bytes.tail,
|
||||
s"Invalid inputs: $sig, $adaptorSig, and $adaptor"
|
||||
)
|
||||
require(secretOrNeg.getPublicKey.bytes.tail == adaptor.bytes.tail,
|
||||
s"Invalid inputs: $sig, $adaptorSig, and $adaptor")
|
||||
|
||||
if (secretOrNeg.getPublicKey == adaptor) {
|
||||
secretOrNeg.toPrivateKey
|
||||
|
@ -10,7 +10,7 @@ import scala.util.{Failure, Success, Try}
|
||||
* vector (IV). Both the cipher text and the IV is needed to decrypt the cipher
|
||||
* text.
|
||||
*/
|
||||
final case class AesEncryptedData(cipherText: ByteVector, iv: AesIV)
|
||||
case class AesEncryptedData(cipherText: ByteVector, iv: AesIV)
|
||||
extends NetworkElement {
|
||||
|
||||
/** We serialize IV and ciphertext by prepending the IV to the ciphertext, and
|
||||
@ -59,8 +59,7 @@ object AesEncryptedData extends Factory[AesEncryptedData] {
|
||||
override def fromBytes(bytes: ByteVector): AesEncryptedData = {
|
||||
require(
|
||||
bytes.length > AesIV.length,
|
||||
s"AesEncryptedData must be longer than ${AesIV.length} bytes, got $bytes"
|
||||
)
|
||||
s"AesEncryptedData must be longer than ${AesIV.length} bytes, got $bytes")
|
||||
val (ivBytes, cipherText) = bytes.splitAt(AesIV.length)
|
||||
val iv = AesIV.fromValidBytes(ivBytes)
|
||||
AesEncryptedData(cipherText, iv)
|
||||
@ -69,9 +68,7 @@ object AesEncryptedData extends Factory[AesEncryptedData] {
|
||||
|
||||
/** Represents a salt used to derive a AES key from a human-readable passphrase.
|
||||
*/
|
||||
final case class AesSalt(
|
||||
bytes: ByteVector
|
||||
) extends AnyVal
|
||||
case class AesSalt(bytes: ByteVector) extends AnyVal
|
||||
|
||||
object AesSalt extends Factory[AesSalt] {
|
||||
|
||||
@ -87,8 +84,7 @@ object AesSalt extends Factory[AesSalt] {
|
||||
|
||||
// we enforce the non-empty password length in the companion object
|
||||
// to be able to make this extend AnyVal, and not be boxed at runtime
|
||||
final case class AesPassword private (private val value: String)
|
||||
extends MaskedToString {
|
||||
case class AesPassword(private val value: String) extends MaskedToString {
|
||||
|
||||
/** Converts this password into an AES key
|
||||
*
|
||||
@ -116,8 +112,7 @@ final case class AesPassword private (private val value: String)
|
||||
passwordBytes,
|
||||
salt.bytes,
|
||||
iterationCount = AesPassword.ITERATIONS,
|
||||
derivedKeyLength = AesPassword.KEY_SIZE
|
||||
)
|
||||
derivedKeyLength = AesPassword.KEY_SIZE)
|
||||
|
||||
AesKey.fromValidBytes(secretKey)
|
||||
}
|
||||
@ -145,8 +140,7 @@ object AesPassword extends StringFactory[AesPassword] {
|
||||
case Some(password) => password
|
||||
case None =>
|
||||
sys.error(
|
||||
s"Could not construct AesPassword from given string, not logging in case it's sensitive"
|
||||
)
|
||||
s"Could not construct AesPassword from given string, not logging in case it's sensitive")
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,15 +150,13 @@ object AesPassword extends StringFactory[AesPassword] {
|
||||
def fromNonEmptyString(string: String): AesPassword =
|
||||
fromStringOpt(string).getOrElse(
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot construct empty AES passwords!"
|
||||
)
|
||||
)
|
||||
"Cannot construct empty AES passwords!"))
|
||||
}
|
||||
|
||||
/** Represents a encryption/decryption key. AES keys can be converted to
|
||||
* [[javax.crypto.SecretKey SecretKey]]s, and have certain length requirements.
|
||||
*/
|
||||
final case class AesKey private (bytes: ByteVector)
|
||||
case class AesKey(bytes: ByteVector)
|
||||
extends MaskedToString
|
||||
with NetworkElement {
|
||||
|
||||
@ -206,9 +198,7 @@ object AesKey {
|
||||
def fromValidBytes(bytes: ByteVector): AesKey = {
|
||||
fromBytes(bytes).getOrElse(
|
||||
throw new IllegalArgumentException(
|
||||
s"Given bytes (${bytes.toHex}) had bad length"
|
||||
)
|
||||
)
|
||||
s"Given bytes (${bytes.toHex}) had bad length"))
|
||||
}
|
||||
|
||||
/** Allowed AES key lengths, bytes */
|
||||
@ -231,9 +221,7 @@ object AesKey {
|
||||
|
||||
/** Represents an initialization vector (IV) used in AES encryption.
|
||||
*/
|
||||
final case class AesIV private (bytes: ByteVector)
|
||||
extends AnyVal
|
||||
with NetworkElement
|
||||
case class AesIV(bytes: ByteVector) extends AnyVal with NetworkElement
|
||||
|
||||
object AesIV {
|
||||
|
||||
@ -256,9 +244,7 @@ object AesIV {
|
||||
def fromValidBytes(bytes: ByteVector): AesIV =
|
||||
fromBytes(bytes).getOrElse(
|
||||
throw new IllegalArgumentException(
|
||||
s"Given bytes must be of length 16! Got: ${bytes.length}"
|
||||
)
|
||||
)
|
||||
s"Given bytes must be of length 16! Got: ${bytes.length}"))
|
||||
|
||||
/** Generates a random IV */
|
||||
def random: AesIV = {
|
||||
@ -282,14 +268,11 @@ object AesCrypt {
|
||||
|
||||
private def decryptionCipher(
|
||||
secret: AesKey,
|
||||
initializationVector: AesIV
|
||||
): Cipher = {
|
||||
initializationVector: AesIV): Cipher = {
|
||||
val cipher = getCipher
|
||||
cipher.init(
|
||||
Cipher.DECRYPT_MODE,
|
||||
secret.toSecretKey,
|
||||
new IvParameterSpec(initializationVector.bytes.toArray)
|
||||
)
|
||||
cipher.init(Cipher.DECRYPT_MODE,
|
||||
secret.toSecretKey,
|
||||
new IvParameterSpec(initializationVector.bytes.toArray))
|
||||
cipher
|
||||
}
|
||||
|
||||
@ -297,8 +280,7 @@ object AesCrypt {
|
||||
*/
|
||||
def decrypt(
|
||||
encrypted: AesEncryptedData,
|
||||
key: AesKey
|
||||
): Either[AesDecryptionException, ByteVector] = {
|
||||
key: AesKey): Either[AesDecryptionException, ByteVector] = {
|
||||
val cipher = decryptionCipher(key, encrypted.iv)
|
||||
|
||||
val decryptionAttempt = Try {
|
||||
@ -319,11 +301,9 @@ object AesCrypt {
|
||||
|
||||
private def encryptionCipher(secret: AesKey, iv: AesIV): Cipher = {
|
||||
val cipher = getCipher
|
||||
cipher.init(
|
||||
Cipher.ENCRYPT_MODE,
|
||||
secret.toSecretKey,
|
||||
new IvParameterSpec(iv.bytes.toArray)
|
||||
)
|
||||
cipher.init(Cipher.ENCRYPT_MODE,
|
||||
secret.toSecretKey,
|
||||
new IvParameterSpec(iv.bytes.toArray))
|
||||
cipher
|
||||
}
|
||||
|
||||
@ -335,8 +315,7 @@ object AesCrypt {
|
||||
private[crypto] def encryptWithIV(
|
||||
plainText: ByteVector,
|
||||
iv: AesIV,
|
||||
key: AesKey
|
||||
): AesEncryptedData = {
|
||||
key: AesKey): AesEncryptedData = {
|
||||
val cipher = encryptionCipher(key, iv)
|
||||
|
||||
val cipherText = cipher.doFinal(plainText.toArray)
|
||||
|
@ -9,7 +9,7 @@ import scala.util.{Failure, Success, Try}
|
||||
*/
|
||||
trait CryptoRuntime {
|
||||
|
||||
val cryptoContext: CryptoContext
|
||||
def cryptoContext: CryptoContext
|
||||
|
||||
/** Generates a 32 byte private key */
|
||||
def freshPrivateKey: ECPrivateKey
|
||||
@ -166,8 +166,7 @@ trait CryptoRuntime {
|
||||
*/
|
||||
def recoverPublicKey(
|
||||
signature: ECDigitalSignature,
|
||||
message: ByteVector
|
||||
): (ECPublicKey, ECPublicKey)
|
||||
message: ByteVector): (ECPublicKey, ECPublicKey)
|
||||
|
||||
// The tag "BIP0340/aux"
|
||||
private val schnorrAuxTagBytes = {
|
||||
@ -200,16 +199,14 @@ trait CryptoRuntime {
|
||||
def signWithEntropy(
|
||||
privateKey: ECPrivateKey,
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature
|
||||
entropy: ByteVector): ECDigitalSignature
|
||||
|
||||
def secKeyVerify(privateKeybytes: ByteVector): Boolean
|
||||
|
||||
def verify(
|
||||
publicKey: ECPublicKeyApi,
|
||||
data: ByteVector,
|
||||
signature: ECDigitalSignature
|
||||
): Boolean
|
||||
signature: ECDigitalSignature): Boolean
|
||||
|
||||
def decompressed(pubKeyBytes: ByteVector): ByteVector = {
|
||||
decodePoint(pubKeyBytes) match {
|
||||
@ -223,8 +220,7 @@ trait CryptoRuntime {
|
||||
|
||||
def decompressed[PK <: ECPublicKeyApi](
|
||||
pubKeyBytes: ByteVector,
|
||||
fromBytes: ByteVector => PK
|
||||
): PK = {
|
||||
fromBytes: ByteVector => PK): PK = {
|
||||
fromBytes(decompressed(pubKeyBytes))
|
||||
}
|
||||
|
||||
@ -294,15 +290,13 @@ trait CryptoRuntime {
|
||||
*/
|
||||
def combinePubKeys(
|
||||
pubKeys: Vector[ECPublicKey],
|
||||
isCompressed: Boolean = true
|
||||
): ECPublicKey = {
|
||||
isCompressed: Boolean = true): ECPublicKey = {
|
||||
val summandPoints = pubKeys.map(_.toPoint)
|
||||
val sumPoint = summandPoints.reduce[SecpPoint](add(_, _))
|
||||
sumPoint match {
|
||||
case SecpPointInfinity =>
|
||||
throw new IllegalArgumentException(
|
||||
"Sum result was 0x00, an invalid public key."
|
||||
)
|
||||
"Sum result was 0x00, an invalid public key.")
|
||||
case p: SecpPointFinite =>
|
||||
if (isCompressed) p.toPublicKey.compressed
|
||||
else p.toPublicKey.decompressed
|
||||
@ -325,8 +319,7 @@ trait CryptoRuntime {
|
||||
def schnorrSign(
|
||||
dataToSign: ByteVector,
|
||||
privateKey: ECPrivateKey,
|
||||
auxRand: ByteVector
|
||||
): SchnorrDigitalSignature = {
|
||||
auxRand: ByteVector): SchnorrDigitalSignature = {
|
||||
val nonceKey =
|
||||
SchnorrNonce.kFromBipSchnorr(privateKey, dataToSign, auxRand)
|
||||
|
||||
@ -336,14 +329,12 @@ trait CryptoRuntime {
|
||||
def schnorrSignWithNonce(
|
||||
dataToSign: ByteVector,
|
||||
privateKey: ECPrivateKey,
|
||||
nonceKey: ECPrivateKey
|
||||
): SchnorrDigitalSignature = {
|
||||
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
|
||||
rx.bytes ++ privateKey.schnorrPublicKey.bytes ++ dataToSign).bytes
|
||||
|
||||
val challenge = x.multiply(FieldElement(e))
|
||||
val sig = k.add(challenge)
|
||||
@ -354,16 +345,14 @@ trait CryptoRuntime {
|
||||
def schnorrVerify(
|
||||
data: ByteVector,
|
||||
schnorrPubKey: SchnorrPublicKey,
|
||||
signature: SchnorrDigitalSignature
|
||||
): Boolean = {
|
||||
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
|
||||
rx.bytes ++ schnorrPubKey.bytes ++ data).bytes
|
||||
|
||||
val e = FieldElement(eBytes)
|
||||
val negE = e.negate
|
||||
@ -384,11 +373,9 @@ trait CryptoRuntime {
|
||||
data: ByteVector,
|
||||
nonce: SchnorrNonce,
|
||||
pubKey: SchnorrPublicKey,
|
||||
compressed: Boolean
|
||||
): ECPublicKey = {
|
||||
compressed: Boolean): ECPublicKey = {
|
||||
val eBytes = sha256SchnorrChallenge(
|
||||
nonce.bytes ++ pubKey.bytes ++ data
|
||||
).bytes
|
||||
nonce.bytes ++ pubKey.bytes ++ data).bytes
|
||||
|
||||
val e = FieldElement(eBytes)
|
||||
|
||||
@ -406,23 +393,20 @@ trait CryptoRuntime {
|
||||
key: ECPrivateKey,
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): ECAdaptorSignature = {
|
||||
auxRand: ByteVector): ECAdaptorSignature = {
|
||||
AdaptorUtil.adaptorSign(key, adaptorPoint, msg, auxRand)
|
||||
}
|
||||
|
||||
def adaptorComplete(
|
||||
key: ECPrivateKey,
|
||||
adaptorSignature: ECAdaptorSignature
|
||||
): ECDigitalSignature = {
|
||||
adaptorSignature: ECAdaptorSignature): ECDigitalSignature = {
|
||||
AdaptorUtil.adaptorComplete(key, adaptorSignature)
|
||||
}
|
||||
|
||||
def extractAdaptorSecret(
|
||||
signature: ECDigitalSignature,
|
||||
adaptorSignature: ECAdaptorSignature,
|
||||
key: ECPublicKey
|
||||
): ECPrivateKey = {
|
||||
key: ECPublicKey): ECPrivateKey = {
|
||||
AdaptorUtil.extractAdaptorSecret(signature, adaptorSignature, key)
|
||||
}
|
||||
|
||||
@ -430,8 +414,7 @@ trait CryptoRuntime {
|
||||
adaptorSignature: ECAdaptorSignature,
|
||||
key: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
adaptorPoint: ECPublicKey
|
||||
): Boolean =
|
||||
adaptorPoint: ECPublicKey): Boolean =
|
||||
AdaptorUtil.adaptorVerify(adaptorSignature, key, msg, adaptorPoint)
|
||||
|
||||
def decodeSignature(signature: ECDigitalSignature): (BigInt, BigInt) =
|
||||
@ -451,22 +434,18 @@ trait CryptoRuntime {
|
||||
pass: String,
|
||||
salt: String,
|
||||
iterationCount: Int,
|
||||
derivedKeyLength: Int
|
||||
): ByteVector = {
|
||||
pbkdf2WithSha512(
|
||||
ByteVector(pass.getBytes),
|
||||
ByteVector(salt.getBytes),
|
||||
iterationCount,
|
||||
derivedKeyLength
|
||||
)
|
||||
derivedKeyLength: Int): ByteVector = {
|
||||
pbkdf2WithSha512(ByteVector(pass.getBytes),
|
||||
ByteVector(salt.getBytes),
|
||||
iterationCount,
|
||||
derivedKeyLength)
|
||||
}
|
||||
|
||||
def pbkdf2WithSha512(
|
||||
pass: ByteVector,
|
||||
salt: ByteVector,
|
||||
iterationCount: Int,
|
||||
derivedKeyLength: Int
|
||||
): ByteVector
|
||||
derivedKeyLength: Int): ByteVector
|
||||
|
||||
def randomBytes(n: Int): ByteVector
|
||||
|
||||
|
@ -84,8 +84,7 @@ trait CryptoUtil extends CryptoRuntime {
|
||||
|
||||
override def recoverPublicKey(
|
||||
signature: ECDigitalSignature,
|
||||
message: ByteVector
|
||||
): (ECPublicKey, ECPublicKey) = {
|
||||
message: ByteVector): (ECPublicKey, ECPublicKey) = {
|
||||
cryptoRuntime.recoverPublicKey(signature, message)
|
||||
}
|
||||
|
||||
@ -94,26 +93,22 @@ trait CryptoUtil extends CryptoRuntime {
|
||||
|
||||
override def sign(
|
||||
privateKey: ECPrivateKey,
|
||||
dataToSign: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
dataToSign: ByteVector): ECDigitalSignature = {
|
||||
val sig = cryptoRuntime.sign(privateKey, dataToSign)
|
||||
assert(
|
||||
verify(privateKey.publicKey, dataToSign, sig),
|
||||
"Something has gone wrong, a generated signature may have been corrupted"
|
||||
)
|
||||
"Something has gone wrong, a generated signature may have been corrupted")
|
||||
sig
|
||||
}
|
||||
|
||||
override def signWithEntropy(
|
||||
privateKey: ECPrivateKey,
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
entropy: ByteVector): ECDigitalSignature = {
|
||||
val sig = cryptoRuntime.signWithEntropy(privateKey, bytes, entropy)
|
||||
assert(
|
||||
verify(privateKey.publicKey, bytes, sig),
|
||||
"Something has gone wrong, a generated signature may have been corrupted"
|
||||
)
|
||||
"Something has gone wrong, a generated signature may have been corrupted")
|
||||
sig
|
||||
}
|
||||
|
||||
@ -123,22 +118,19 @@ trait CryptoUtil extends CryptoRuntime {
|
||||
override def verify(
|
||||
publicKey: ECPublicKeyApi,
|
||||
data: ByteVector,
|
||||
signature: ECDigitalSignature
|
||||
): Boolean =
|
||||
signature: ECDigitalSignature): Boolean =
|
||||
cryptoRuntime.verify(publicKey, data, signature)
|
||||
|
||||
override def decompressed(pubKeyBytes: ByteVector): ByteVector =
|
||||
cryptoRuntime.decompressed(pubKeyBytes)
|
||||
|
||||
override def decompressed[PK <: ECPublicKeyApi](
|
||||
publicKey: PK
|
||||
): publicKey.type =
|
||||
publicKey: PK): publicKey.type =
|
||||
cryptoRuntime.decompressed(publicKey)
|
||||
|
||||
override def tweakMultiply(
|
||||
publicKey: ECPublicKey,
|
||||
tweak: FieldElement
|
||||
): ECPublicKey =
|
||||
tweak: FieldElement): ECPublicKey =
|
||||
cryptoRuntime.tweakMultiply(publicKey, tweak)
|
||||
|
||||
override def add(pk1: ECPrivateKey, pk2: ECPrivateKey): ECPrivateKey =
|
||||
@ -155,14 +147,12 @@ trait CryptoUtil extends CryptoRuntime {
|
||||
|
||||
override def combinePubKeys(
|
||||
pubKeys: Vector[ECPublicKey],
|
||||
isCompressed: Boolean = true
|
||||
): ECPublicKey =
|
||||
isCompressed: Boolean = true): ECPublicKey =
|
||||
cryptoRuntime.combinePubKeys(pubKeys, isCompressed)
|
||||
|
||||
override def pubKeyTweakAdd(
|
||||
pubkey: ECPublicKey,
|
||||
privkey: ECPrivateKey
|
||||
): ECPublicKey =
|
||||
privkey: ECPrivateKey): ECPublicKey =
|
||||
cryptoRuntime.pubKeyTweakAdd(pubkey, privkey)
|
||||
|
||||
override def isValidPubKey(pubKey: ECPublicKeyApi): Boolean =
|
||||
@ -171,82 +161,70 @@ trait CryptoUtil extends CryptoRuntime {
|
||||
override def schnorrSign(
|
||||
dataToSign: ByteVector,
|
||||
privateKey: ECPrivateKey,
|
||||
auxRand: ByteVector
|
||||
): SchnorrDigitalSignature = {
|
||||
auxRand: ByteVector): SchnorrDigitalSignature = {
|
||||
val sig = cryptoRuntime.schnorrSign(dataToSign, privateKey, auxRand)
|
||||
assert(
|
||||
schnorrVerify(dataToSign, privateKey.schnorrPublicKey, sig),
|
||||
"Something has gone wrong, a generated signature may have been corrupted"
|
||||
)
|
||||
"Something has gone wrong, a generated signature may have been corrupted")
|
||||
sig
|
||||
}
|
||||
|
||||
override def schnorrSignWithNonce(
|
||||
dataToSign: ByteVector,
|
||||
privateKey: ECPrivateKey,
|
||||
nonceKey: ECPrivateKey
|
||||
): SchnorrDigitalSignature = {
|
||||
nonceKey: ECPrivateKey): SchnorrDigitalSignature = {
|
||||
val sig =
|
||||
cryptoRuntime.schnorrSignWithNonce(dataToSign, privateKey, nonceKey)
|
||||
assert(
|
||||
schnorrVerify(dataToSign, privateKey.schnorrPublicKey, sig),
|
||||
"Something has gone wrong, a generated signature may have been corrupted"
|
||||
)
|
||||
"Something has gone wrong, a generated signature may have been corrupted")
|
||||
sig
|
||||
}
|
||||
|
||||
override def schnorrVerify(
|
||||
data: ByteVector,
|
||||
schnorrPubKey: SchnorrPublicKey,
|
||||
signature: SchnorrDigitalSignature
|
||||
): Boolean =
|
||||
signature: SchnorrDigitalSignature): Boolean =
|
||||
cryptoRuntime.schnorrVerify(data, schnorrPubKey, signature)
|
||||
|
||||
override def schnorrComputeSigPoint(
|
||||
data: ByteVector,
|
||||
nonce: SchnorrNonce,
|
||||
pubKey: SchnorrPublicKey,
|
||||
compressed: Boolean
|
||||
): ECPublicKey =
|
||||
compressed: Boolean): ECPublicKey =
|
||||
cryptoRuntime.schnorrComputeSigPoint(data, nonce, pubKey, compressed)
|
||||
|
||||
override def adaptorSign(
|
||||
key: ECPrivateKey,
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): ECAdaptorSignature =
|
||||
auxRand: ByteVector): ECAdaptorSignature =
|
||||
cryptoRuntime.adaptorSign(key, adaptorPoint, msg, auxRand)
|
||||
|
||||
override def adaptorComplete(
|
||||
key: ECPrivateKey,
|
||||
adaptorSignature: ECAdaptorSignature
|
||||
): ECDigitalSignature =
|
||||
adaptorSignature: ECAdaptorSignature): ECDigitalSignature =
|
||||
cryptoRuntime.adaptorComplete(key, adaptorSignature)
|
||||
|
||||
override def extractAdaptorSecret(
|
||||
signature: ECDigitalSignature,
|
||||
adaptorSignature: ECAdaptorSignature,
|
||||
key: ECPublicKey
|
||||
): ECPrivateKey =
|
||||
key: ECPublicKey): ECPrivateKey =
|
||||
cryptoRuntime.extractAdaptorSecret(signature, adaptorSignature, key)
|
||||
|
||||
override def adaptorVerify(
|
||||
adaptorSignature: ECAdaptorSignature,
|
||||
key: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
adaptorPoint: ECPublicKey
|
||||
): Boolean =
|
||||
adaptorPoint: ECPublicKey): Boolean =
|
||||
cryptoRuntime.adaptorVerify(adaptorSignature, key, msg, adaptorPoint)
|
||||
|
||||
override def decodeSignature(
|
||||
signature: ECDigitalSignature
|
||||
): (BigInt, BigInt) =
|
||||
signature: ECDigitalSignature): (BigInt, BigInt) =
|
||||
cryptoRuntime.decodeSignature(signature)
|
||||
|
||||
override def isValidSignatureEncoding(
|
||||
signature: ECDigitalSignature
|
||||
): Boolean =
|
||||
signature: ECDigitalSignature): Boolean =
|
||||
cryptoRuntime.isValidSignatureEncoding(signature)
|
||||
|
||||
override def isDEREncoded(signature: ECDigitalSignature): Boolean =
|
||||
@ -264,8 +242,7 @@ trait CryptoUtil extends CryptoRuntime {
|
||||
pass: ByteVector,
|
||||
salt: ByteVector,
|
||||
iterationCount: Int,
|
||||
derivedKeyLength: Int
|
||||
): ByteVector =
|
||||
derivedKeyLength: Int): ByteVector =
|
||||
cryptoRuntime.pbkdf2WithSha512(pass, salt, iterationCount, derivedKeyLength)
|
||||
}
|
||||
|
||||
|
@ -217,10 +217,8 @@ sealed abstract class DERSignatureUtil {
|
||||
val sigLowS =
|
||||
if (isLowS(signature)) signature
|
||||
else
|
||||
ECDigitalSignature(
|
||||
signature.r,
|
||||
CryptoParams.getN.subtract(signature.s.bigInteger)
|
||||
)
|
||||
ECDigitalSignature(signature.r,
|
||||
CryptoParams.getN.subtract(signature.s.bigInteger))
|
||||
require(DERSignatureUtil.isLowS(sigLowS))
|
||||
sigLowS
|
||||
}
|
||||
|
@ -19,8 +19,7 @@ object DLEQUtil {
|
||||
|
||||
def dleqPair(
|
||||
fe: FieldElement,
|
||||
adaptorPoint: ECPublicKey
|
||||
): (ECPublicKey, ECPublicKey) = {
|
||||
adaptorPoint: ECPublicKey): (ECPublicKey, ECPublicKey) = {
|
||||
val point = fe.getPublicKey
|
||||
val tweakedPoint = adaptorPoint.multiply(fe)
|
||||
|
||||
@ -35,19 +34,16 @@ object DLEQUtil {
|
||||
adaptorPoint: ECPublicKey,
|
||||
point: ECPublicKey,
|
||||
tweakedPoint: ECPublicKey,
|
||||
auxRand: ByteVector
|
||||
): FieldElement = {
|
||||
auxRand: ByteVector): FieldElement = {
|
||||
val hash = CryptoUtil
|
||||
.sha256(point.bytes ++ tweakedPoint.bytes)
|
||||
.bytes
|
||||
|
||||
AdaptorUtil.adaptorNonce(
|
||||
hash,
|
||||
fe.toPrivateKey,
|
||||
adaptorPoint,
|
||||
"DLEQ",
|
||||
auxRand
|
||||
)
|
||||
AdaptorUtil.adaptorNonce(hash,
|
||||
fe.toPrivateKey,
|
||||
adaptorPoint,
|
||||
"DLEQ",
|
||||
auxRand)
|
||||
}
|
||||
|
||||
/** Computes the challenge hash value for dleqProve as specified in
|
||||
@ -58,13 +54,11 @@ object DLEQUtil {
|
||||
r1: ECPublicKey,
|
||||
r2: ECPublicKey,
|
||||
p1: ECPublicKey,
|
||||
p2: ECPublicKey
|
||||
): ByteVector = {
|
||||
p2: ECPublicKey): ByteVector = {
|
||||
CryptoUtil
|
||||
.sha256DLEQ(
|
||||
p1.bytes ++ adaptorPoint.bytes ++
|
||||
p2.bytes ++ r1.bytes ++ r2.bytes
|
||||
)
|
||||
p2.bytes ++ r1.bytes ++ r2.bytes)
|
||||
.bytes
|
||||
}
|
||||
|
||||
@ -76,8 +70,7 @@ object DLEQUtil {
|
||||
def dleqProve(
|
||||
fe: FieldElement,
|
||||
adaptorPoint: ECPublicKey,
|
||||
auxRand: ByteVector
|
||||
): (FieldElement, FieldElement) = {
|
||||
auxRand: ByteVector): (FieldElement, FieldElement) = {
|
||||
require(!fe.isZero, "Input field element cannot be zero.")
|
||||
|
||||
// (fe*G, fe*Y)
|
||||
@ -120,8 +113,7 @@ object DLEQUtil {
|
||||
e: FieldElement,
|
||||
p1: ECPublicKey,
|
||||
adaptor: ECPublicKey,
|
||||
p2: ECPublicKey
|
||||
): Boolean = {
|
||||
p2: ECPublicKey): Boolean = {
|
||||
val r1 = p1.multiply(e.negate).add(s.getPublicKey)
|
||||
val r2 = p2.multiply(e.negate).add(adaptor.multiply(s))
|
||||
val challengeHash = dleqChallengeHash(adaptor, r1, r2, p1, p2)
|
||||
|
@ -3,10 +3,8 @@ package org.bitcoins.crypto
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
case class ECAdaptorSignature(bytes: ByteVector) extends NetworkElement {
|
||||
require(
|
||||
bytes.length == 162,
|
||||
s"Adaptor signature must be 162 bytes, got $bytes"
|
||||
)
|
||||
require(bytes.length == 162,
|
||||
s"Adaptor signature must be 162 bytes, got $bytes")
|
||||
|
||||
val (adaptedSig: ByteVector, dleqProof: ByteVector) = bytes.splitAt(98)
|
||||
|
||||
@ -31,8 +29,7 @@ object ECAdaptorSignature extends Factory[ECAdaptorSignature] {
|
||||
untweakedNonce: ECPublicKey,
|
||||
adaptedS: FieldElement,
|
||||
dleqProofE: FieldElement,
|
||||
dleqProofS: FieldElement
|
||||
): ECAdaptorSignature = {
|
||||
dleqProofS: FieldElement): ECAdaptorSignature = {
|
||||
fromBytes(
|
||||
tweakedNonce.bytes ++ untweakedNonce.bytes ++
|
||||
adaptedS.bytes ++ dleqProofE.bytes ++ dleqProofS.bytes
|
||||
|
@ -87,10 +87,8 @@ sealed abstract class ECDigitalSignature extends NetworkElement {
|
||||
}
|
||||
|
||||
def appendHashType(hashType: HashType): ECDigitalSignature = {
|
||||
require(
|
||||
this.hashTypeOpt.isEmpty,
|
||||
"Cannot append HashType to signature which already has HashType"
|
||||
)
|
||||
require(this.hashTypeOpt.isEmpty,
|
||||
"Cannot append HashType to signature which already has HashType")
|
||||
|
||||
val bytesWithHashType = bytes.:+(hashType.byte)
|
||||
ECDigitalSignature.fromBytes(bytesWithHashType)
|
||||
@ -156,10 +154,8 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] {
|
||||
val sigWithExtra = fromBytes(bytes)
|
||||
val sig = fromRS(sigWithExtra.r, sigWithExtra.s)
|
||||
|
||||
require(
|
||||
bytes.startsWith(sig.bytes),
|
||||
s"Received weirdly encoded signature at beginning of $bytes"
|
||||
)
|
||||
require(bytes.startsWith(sig.bytes),
|
||||
s"Received weirdly encoded signature at beginning of $bytes")
|
||||
|
||||
sig
|
||||
}
|
||||
@ -170,8 +166,7 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] {
|
||||
def fromFrontOfBytesWithSigHash(bytes: ByteVector): ECDigitalSignature = {
|
||||
val sigWithoutSigHash = fromFrontOfBytes(bytes)
|
||||
ECDigitalSignature(
|
||||
sigWithoutSigHash.bytes :+ bytes.drop(sigWithoutSigHash.byteSize).head
|
||||
)
|
||||
sigWithoutSigHash.bytes :+ bytes.drop(sigWithoutSigHash.byteSize).head)
|
||||
}
|
||||
|
||||
def apply(r: BigInt, s: BigInt): ECDigitalSignature = fromRS(r, s)
|
||||
@ -195,13 +190,10 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] {
|
||||
val totalSize = 4 + rsSize
|
||||
val bytes: ByteVector = {
|
||||
ByteVector(
|
||||
Array(
|
||||
0x30.toByte,
|
||||
totalSize.toByte,
|
||||
0x2.toByte,
|
||||
r.toByteArray.length.toByte
|
||||
)
|
||||
)
|
||||
Array(0x30.toByte,
|
||||
totalSize.toByte,
|
||||
0x2.toByte,
|
||||
r.toByteArray.length.toByte))
|
||||
.++(ByteVector(r.toByteArray))
|
||||
.++(ByteVector(Array(0x2.toByte, s.toByteArray.length.toByte)))
|
||||
.++(ByteVector(s.toByteArray))
|
||||
@ -233,8 +225,7 @@ object ECDigitalSignature extends Factory[ECDigitalSignature] {
|
||||
def fromRS(byteVector: ByteVector): ECDigitalSignature = {
|
||||
require(
|
||||
byteVector.length == 64,
|
||||
s"Incorrect size for reading a ECDigital signature from a bytevec, got ${byteVector.length}"
|
||||
)
|
||||
s"Incorrect size for reading a ECDigital signature from a bytevec, got ${byteVector.length}")
|
||||
val r = BigInt(1, byteVector.take(32).toArray)
|
||||
val s = BigInt(1, byteVector.takeRight(32).toArray)
|
||||
fromRS(r, s)
|
||||
|
@ -172,8 +172,7 @@ case class ECPrivateKey(bytes: ByteVector)
|
||||
|
||||
override def signWithEntropy(
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
entropy: ByteVector): ECDigitalSignature = {
|
||||
CryptoUtil.signWithEntropy(this, bytes, entropy)
|
||||
}
|
||||
|
||||
@ -184,36 +183,31 @@ case class ECPrivateKey(bytes: ByteVector)
|
||||
|
||||
def schnorrSign(
|
||||
dataToSign: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): SchnorrDigitalSignature = {
|
||||
auxRand: ByteVector): SchnorrDigitalSignature = {
|
||||
CryptoUtil.schnorrSign(dataToSign, this, auxRand)
|
||||
}
|
||||
|
||||
def schnorrSignWithNonce(
|
||||
dataToSign: ByteVector,
|
||||
nonce: ECPrivateKey
|
||||
): SchnorrDigitalSignature = {
|
||||
nonce: ECPrivateKey): SchnorrDigitalSignature = {
|
||||
CryptoUtil.schnorrSignWithNonce(dataToSign, this, nonce)
|
||||
}
|
||||
|
||||
override def adaptorSign(
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): ECAdaptorSignature = {
|
||||
auxRand: ByteVector): ECAdaptorSignature = {
|
||||
CryptoUtil.adaptorSign(this, adaptorPoint, msg, auxRand)
|
||||
}
|
||||
|
||||
def completeAdaptorSignature(
|
||||
adaptorSignature: ECAdaptorSignature
|
||||
): ECDigitalSignature = {
|
||||
adaptorSignature: ECAdaptorSignature): ECDigitalSignature = {
|
||||
CryptoUtil.adaptorComplete(this, adaptorSignature)
|
||||
}
|
||||
|
||||
def completeAdaptorSignature(
|
||||
adaptorSignature: ECAdaptorSignature,
|
||||
hashTypeByte: Byte
|
||||
): ECDigitalSignature = {
|
||||
hashTypeByte: Byte): ECDigitalSignature = {
|
||||
val completedSig = completeAdaptorSignature(adaptorSignature)
|
||||
ECDigitalSignature(completedSig.bytes ++ ByteVector.fromByte(hashTypeByte))
|
||||
}
|
||||
@ -236,8 +230,7 @@ case class ECPrivateKey(bytes: ByteVector)
|
||||
|
||||
// CryptoParams.curve.getN
|
||||
private val N: BigInteger = new BigInteger(
|
||||
"115792089237316195423570985008687907852837564279074904382605163141518161494337"
|
||||
)
|
||||
"115792089237316195423570985008687907852837564279074904382605163141518161494337")
|
||||
|
||||
def negate: ECPrivateKey = {
|
||||
val negPrivKeyNum = N.subtract(new BigInteger(1, bytes.toArray))
|
||||
@ -281,8 +274,7 @@ object ECPrivateKey extends Factory[ECPrivateKey] {
|
||||
} else
|
||||
throw new IllegalArgumentException(
|
||||
"Private keys must be 32 in size, got: " +
|
||||
CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size
|
||||
)
|
||||
CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size)
|
||||
}
|
||||
|
||||
def fromFieldElement(fieldElement: FieldElement): ECPrivateKey = {
|
||||
@ -341,15 +333,13 @@ case class ECPublicKey(bytes: ByteVector)
|
||||
|
||||
def schnorrVerify(
|
||||
data: ByteVector,
|
||||
signature: SchnorrDigitalSignature
|
||||
): Boolean = {
|
||||
signature: SchnorrDigitalSignature): Boolean = {
|
||||
schnorrPublicKey.verify(data, signature)
|
||||
}
|
||||
|
||||
def schnorrComputePoint(
|
||||
data: ByteVector,
|
||||
nonce: SchnorrNonce
|
||||
): ECPublicKey = {
|
||||
nonce: SchnorrNonce): ECPublicKey = {
|
||||
schnorrPublicKey.computeSigPoint(data, nonce)
|
||||
}
|
||||
|
||||
@ -360,15 +350,13 @@ case class ECPublicKey(bytes: ByteVector)
|
||||
def adaptorVerify(
|
||||
msg: ByteVector,
|
||||
adaptorPoint: ECPublicKey,
|
||||
adaptorSignature: ECAdaptorSignature
|
||||
): Boolean = {
|
||||
adaptorSignature: ECAdaptorSignature): Boolean = {
|
||||
CryptoUtil.adaptorVerify(adaptorSignature, this, msg, adaptorPoint)
|
||||
}
|
||||
|
||||
def extractAdaptorSecret(
|
||||
adaptorSignature: ECAdaptorSignature,
|
||||
signature: ECDigitalSignature
|
||||
): ECPrivateKey = {
|
||||
signature: ECDigitalSignature): ECPrivateKey = {
|
||||
CryptoUtil.extractAdaptorSecret(signature, adaptorSignature, this)
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,7 @@ case class FieldElement(bytes: ByteVector)
|
||||
|
||||
require(
|
||||
privKeyT.isSuccess || isZero,
|
||||
s"$bytes is not a valid field element: ${privKeyT.failed.get.getMessage}"
|
||||
)
|
||||
s"$bytes is not a valid field element: ${privKeyT.failed.get.getMessage}")
|
||||
|
||||
def toPrivateKey: ECPrivateKey =
|
||||
if (!isZero) {
|
||||
|
@ -6,16 +6,13 @@ import java.math.BigInteger
|
||||
|
||||
abstract class FiniteFieldMember[F <: FiniteFieldMember[F]](
|
||||
fieldOrder: BigInteger,
|
||||
byteSize: Int
|
||||
) extends NetworkElement {
|
||||
require(
|
||||
bytes.length == byteSize,
|
||||
s"Finite field member must have $byteSize bytes, got $bytes"
|
||||
)
|
||||
byteSize: Int)
|
||||
extends NetworkElement {
|
||||
require(bytes.length == byteSize,
|
||||
s"Finite field member must have $byteSize bytes, got $bytes")
|
||||
require(
|
||||
toBigInteger.compareTo(fieldOrder) < 0,
|
||||
s"$bytes is not a valid field member (was not less than $fieldOrder)."
|
||||
)
|
||||
s"$bytes is not a valid field member (was not less than $fieldOrder).")
|
||||
|
||||
def isZero: Boolean = bytes.toArray.forall(_ == 0.toByte)
|
||||
|
||||
@ -56,8 +53,8 @@ abstract class FiniteFieldMember[F <: FiniteFieldMember[F]](
|
||||
|
||||
abstract class FiniteFieldObject[F <: FiniteFieldMember[F]](
|
||||
fieldOrder: BigInteger,
|
||||
byteSize: Int
|
||||
) extends Factory[F] {
|
||||
byteSize: Int)
|
||||
extends Factory[F] {
|
||||
|
||||
def fieldMemberConstructor(bytes: ByteVector): F
|
||||
|
||||
@ -70,8 +67,7 @@ abstract class FiniteFieldObject[F <: FiniteFieldMember[F]](
|
||||
fieldMemberConstructor(bytes.tail)
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
s"Field element cannot have more than 32 bytes, got $bytes"
|
||||
)
|
||||
s"Field element cannot have more than 32 bytes, got $bytes")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,11 +68,9 @@ object Sha256Digest extends Factory[Sha256Digest] {
|
||||
}
|
||||
|
||||
override def fromBytes(bytes: ByteVector): Sha256Digest = {
|
||||
require(
|
||||
bytes.length == 32,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha256Digest must be 32 bytes in size, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 32,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha256Digest must be 32 bytes in size, got: " + bytes.length)
|
||||
Sha256DigestImpl(bytes)
|
||||
}
|
||||
|
||||
@ -98,11 +96,9 @@ object Sha256DigestBE extends Factory[Sha256DigestBE] {
|
||||
}
|
||||
|
||||
override def fromBytes(bytes: ByteVector): Sha256DigestBE = {
|
||||
require(
|
||||
bytes.length == 32,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha256Digest must be 32 bytes in size, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 32,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha256Digest must be 32 bytes in size, got: " + bytes.length)
|
||||
Sha256DigestBEImpl(bytes)
|
||||
}
|
||||
|
||||
@ -112,10 +108,8 @@ object Sha256DigestBE extends Factory[Sha256DigestBE] {
|
||||
/** Represents the result of SHA256(SHA256())
|
||||
*/
|
||||
case class DoubleSha256Digest(bytes: ByteVector) extends HashDigest {
|
||||
require(
|
||||
bytes.length == 32,
|
||||
"DoubleSha256Digest must always be 32 bytes, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 32,
|
||||
"DoubleSha256Digest must always be 32 bytes, got: " + bytes.length)
|
||||
|
||||
lazy val flip: DoubleSha256DigestBE = DoubleSha256DigestBE(bytes.reverse)
|
||||
|
||||
@ -139,10 +133,8 @@ object DoubleSha256Digest extends Factory[DoubleSha256Digest] {
|
||||
|
||||
/** The big endian version of [[DoubleSha256Digest DoubleSha256Digest]] */
|
||||
case class DoubleSha256DigestBE(bytes: ByteVector) extends HashDigest {
|
||||
require(
|
||||
bytes.length == 32,
|
||||
"DoubleSha256Digest must always be 32 bytes, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 32,
|
||||
"DoubleSha256Digest must always be 32 bytes, got: " + bytes.length)
|
||||
|
||||
def flip: DoubleSha256Digest =
|
||||
DoubleSha256Digest.fromBytes(bytes.reverse)
|
||||
@ -177,11 +169,9 @@ object RipeMd160Digest extends Factory[RipeMd160Digest] {
|
||||
}
|
||||
|
||||
override def fromBytes(bytes: ByteVector): RipeMd160Digest = {
|
||||
require(
|
||||
bytes.length == 20,
|
||||
// $COVERAGE-OFF$
|
||||
"RIPEMD160Digest must always be 20 bytes, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 20,
|
||||
// $COVERAGE-OFF$
|
||||
"RIPEMD160Digest must always be 20 bytes, got: " + bytes.length)
|
||||
RipeMd160DigestImpl(bytes)
|
||||
}
|
||||
}
|
||||
@ -202,11 +192,9 @@ object RipeMd160DigestBE extends Factory[RipeMd160DigestBE] {
|
||||
}
|
||||
|
||||
override def fromBytes(bytes: ByteVector): RipeMd160DigestBE = {
|
||||
require(
|
||||
bytes.length == 20,
|
||||
// $COVERAGE-OFF$
|
||||
"RIPEMD160Digest must always be 20 bytes, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 20,
|
||||
// $COVERAGE-OFF$
|
||||
"RIPEMD160Digest must always be 20 bytes, got: " + bytes.length)
|
||||
RipeMd160DigestBEImpl(bytes)
|
||||
}
|
||||
}
|
||||
@ -229,11 +217,9 @@ object Sha256Hash160Digest extends Factory[Sha256Hash160Digest] {
|
||||
}
|
||||
|
||||
override def fromBytes(bytes: ByteVector): Sha256Hash160Digest = {
|
||||
require(
|
||||
bytes.length == 20,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 20,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length)
|
||||
Sha256Hash160DigestImpl(bytes)
|
||||
}
|
||||
}
|
||||
@ -254,11 +240,9 @@ object Sha256Hash160DigestBE extends Factory[Sha256Hash160DigestBE] {
|
||||
}
|
||||
|
||||
override def fromBytes(bytes: ByteVector): Sha256Hash160DigestBE = {
|
||||
require(
|
||||
bytes.length == 20,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 20,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha256Hash160Digest must always be 20 bytes, got: " + bytes.length)
|
||||
Sha256Hash160DigestBEImpl(bytes)
|
||||
}
|
||||
}
|
||||
@ -279,11 +263,9 @@ object Sha3_256Digest extends Factory[Sha3_256Digest] {
|
||||
}
|
||||
|
||||
override def fromBytes(bytes: ByteVector): Sha3_256Digest = {
|
||||
require(
|
||||
bytes.length == 32,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha3-256Digest must be 32 bytes in size, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 32,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha3-256Digest must be 32 bytes in size, got: " + bytes.length)
|
||||
Sha3_256DigestImpl(bytes)
|
||||
}
|
||||
|
||||
@ -309,11 +291,9 @@ object Sha3_256DigestBE extends Factory[Sha3_256DigestBE] {
|
||||
}
|
||||
|
||||
override def fromBytes(bytes: ByteVector): Sha3_256DigestBE = {
|
||||
require(
|
||||
bytes.length == 32,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha3-256Digest must be 32 bytes in size, got: " + bytes.length
|
||||
)
|
||||
require(bytes.length == 32,
|
||||
// $COVERAGE-OFF$
|
||||
"Sha3-256Digest must be 32 bytes in size, got: " + bytes.length)
|
||||
Sha3_256DigestBEImpl(bytes)
|
||||
}
|
||||
|
||||
|
@ -107,16 +107,14 @@ object HashType extends Factory[HashType] {
|
||||
false
|
||||
}
|
||||
|
||||
lazy val hashTypes = Seq(
|
||||
sigHashAll,
|
||||
sigHashNone,
|
||||
sigHashSingle,
|
||||
sigHashAnyoneCanPay,
|
||||
sigHashNoneAnyoneCanPay,
|
||||
sigHashAllAnyoneCanPay,
|
||||
sigHashSingleAnyoneCanPay,
|
||||
sigHashDefault
|
||||
)
|
||||
lazy val hashTypes = Seq(sigHashAll,
|
||||
sigHashNone,
|
||||
sigHashSingle,
|
||||
sigHashAnyoneCanPay,
|
||||
sigHashNoneAnyoneCanPay,
|
||||
sigHashAllAnyoneCanPay,
|
||||
sigHashSingleAnyoneCanPay,
|
||||
sigHashDefault)
|
||||
|
||||
lazy val hashTypeBytes: Vector[Byte] = Vector(
|
||||
sigHashDefaultByte,
|
||||
@ -157,8 +155,7 @@ object HashType extends Factory[HashType] {
|
||||
val sigHashAnyoneCanPayByte = 0x80.toByte
|
||||
|
||||
val sigHashAnyoneCanPay: SIGHASH_ANYONECANPAY = SIGHASH_ANYONECANPAY(
|
||||
sigHashAnyoneCanPayNum
|
||||
)
|
||||
sigHashAnyoneCanPayNum)
|
||||
|
||||
/** The default byte for [[SIGHASH_NONE]] */
|
||||
val sigHashNoneByte: Byte = 2.toByte
|
||||
@ -176,8 +173,7 @@ object HashType extends Factory[HashType] {
|
||||
val sigHashAllAnyoneCanPayNum = sigHashAllByte.toInt | sigHashAnyoneCanPayNum
|
||||
|
||||
val sigHashAllAnyoneCanPay = SIGHASH_ALL_ANYONECANPAY(
|
||||
sigHashAllAnyoneCanPayNum
|
||||
)
|
||||
sigHashAllAnyoneCanPayNum)
|
||||
|
||||
val sigHashNoneAnyoneCanPayByte =
|
||||
(HashType.sigHashNoneByte | HashType.sigHashAnyoneCanPayByte).toByte
|
||||
@ -186,8 +182,7 @@ object HashType extends Factory[HashType] {
|
||||
sigHashNoneByte.toInt | sigHashAnyoneCanPayNum
|
||||
|
||||
val sigHashNoneAnyoneCanPay = SIGHASH_NONE_ANYONECANPAY(
|
||||
sigHashNoneAnyoneCanPayNum
|
||||
)
|
||||
sigHashNoneAnyoneCanPayNum)
|
||||
|
||||
val sigHashSingleAnyoneCanPayByte =
|
||||
(HashType.sigHashSingleByte | HashType.sigHashAnyoneCanPayByte).toByte
|
||||
@ -196,8 +191,7 @@ object HashType extends Factory[HashType] {
|
||||
sigHashSingleByte.toInt | sigHashAnyoneCanPayNum
|
||||
|
||||
val sigHashSingleAnyoneCanPay = SIGHASH_SINGLE_ANYONECANPAY(
|
||||
sigHashSingleAnyoneCanPayNum
|
||||
)
|
||||
sigHashSingleAnyoneCanPayNum)
|
||||
|
||||
/** Checks if the given digital signature has a valid hash type Mimics this
|
||||
* functionality inside of Bitcoin Core
|
||||
@ -220,8 +214,7 @@ case class SIGHASH_ALL(override val num: Int) extends HashType {
|
||||
HashType.isSigHashAll(num),
|
||||
"SIGHASH_ALL acts as a 'catch-all' for undefined hashtypes, and has a default " +
|
||||
"value of one. Your input was: " + num + ", which is of hashType: " + HashType(
|
||||
num
|
||||
)
|
||||
num)
|
||||
)
|
||||
}
|
||||
|
||||
@ -230,43 +223,32 @@ object SIGHASH_ALL {
|
||||
}
|
||||
|
||||
case class SIGHASH_NONE(override val num: Int) extends HashType {
|
||||
require(
|
||||
HashType.isSigHashNone(num),
|
||||
"The given number is not a SIGHASH_NONE number: " + num
|
||||
)
|
||||
require(HashType.isSigHashNone(num),
|
||||
"The given number is not a SIGHASH_NONE number: " + num)
|
||||
}
|
||||
|
||||
case class SIGHASH_SINGLE(override val num: Int) extends HashType {
|
||||
require(
|
||||
HashType.isSigHashSingle(num),
|
||||
"The given number is not a SIGHASH_SINGLE number: " + num
|
||||
)
|
||||
require(HashType.isSigHashSingle(num),
|
||||
"The given number is not a SIGHASH_SINGLE number: " + num)
|
||||
}
|
||||
|
||||
case class SIGHASH_ANYONECANPAY(override val num: Int) extends HashType {
|
||||
require(
|
||||
HashType.isSigHashAnyoneCanPay(num),
|
||||
"The given number was not a SIGHASH_ANYONECANPAY number: " + num
|
||||
)
|
||||
require(HashType.isSigHashAnyoneCanPay(num),
|
||||
"The given number was not a SIGHASH_ANYONECANPAY number: " + num)
|
||||
}
|
||||
|
||||
case class SIGHASH_ALL_ANYONECANPAY(override val num: Int) extends HashType {
|
||||
require(
|
||||
HashType.isSigHashAllAnyoneCanPay(num),
|
||||
"The given number was not a SIGHASH_ALL_ANYONECANPAY number: " + num
|
||||
)
|
||||
require(HashType.isSigHashAllAnyoneCanPay(num),
|
||||
"The given number was not a SIGHASH_ALL_ANYONECANPAY number: " + num)
|
||||
}
|
||||
|
||||
case class SIGHASH_NONE_ANYONECANPAY(override val num: Int) extends HashType {
|
||||
require(
|
||||
HashType.isSigHashNoneAnyoneCanPay(num),
|
||||
"The given number was not a SIGHASH_NONE_ANYONECANPAY number: " + num
|
||||
)
|
||||
require(HashType.isSigHashNoneAnyoneCanPay(num),
|
||||
"The given number was not a SIGHASH_NONE_ANYONECANPAY number: " + num)
|
||||
}
|
||||
|
||||
case class SIGHASH_SINGLE_ANYONECANPAY(override val num: Int) extends HashType {
|
||||
require(
|
||||
HashType.isSigHashSingleAnyoneCanPay(num),
|
||||
"The given number was not a SIGHASH_SINGLE_ANYONECANPAY number: " + num
|
||||
)
|
||||
"The given number was not a SIGHASH_SINGLE_ANYONECANPAY number: " + num)
|
||||
}
|
||||
|
@ -12,19 +12,13 @@ object SchnorrDigitalSignature extends Factory[SchnorrDigitalSignature] {
|
||||
// If the sig is 65 bytes long, return sig[64] ≠ 0x00[20] and
|
||||
// Verify(q, hashTapSighash(0x00 || SigMsg(sig[64], 0)), sig[0:64]).
|
||||
override def fromBytes(bytes: ByteVector): SchnorrDigitalSignature = {
|
||||
require(
|
||||
bytes.length == 64,
|
||||
s"SchnorrDigitalSignature must be exactly 64 bytes, got $bytes"
|
||||
)
|
||||
SchnorrDigitalSignature(
|
||||
SchnorrNonce(bytes.take(32)),
|
||||
FieldElement(bytes.drop(32))
|
||||
)
|
||||
require(bytes.length == 64,
|
||||
s"SchnorrDigitalSignature must be exactly 64 bytes, got $bytes")
|
||||
SchnorrDigitalSignature(SchnorrNonce(bytes.take(32)),
|
||||
FieldElement(bytes.drop(32)))
|
||||
}
|
||||
|
||||
lazy val dummy: SchnorrDigitalSignature =
|
||||
SchnorrDigitalSignature(
|
||||
FieldElement.one.getPublicKey.schnorrNonce,
|
||||
FieldElement.one
|
||||
)
|
||||
SchnorrDigitalSignature(FieldElement.one.getPublicKey.schnorrNonce,
|
||||
FieldElement.one)
|
||||
}
|
||||
|
@ -25,8 +25,7 @@ object SchnorrNonce extends Factory[SchnorrNonce] {
|
||||
def kFromBipSchnorr(
|
||||
privKey: ECPrivateKey,
|
||||
message: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): ECPrivateKey = {
|
||||
auxRand: ByteVector): ECPrivateKey = {
|
||||
val privKeyForUse = privKey.schnorrKey
|
||||
|
||||
val randHash =
|
||||
@ -34,8 +33,7 @@ object SchnorrNonce extends Factory[SchnorrNonce] {
|
||||
val maskedKey = randHash.xor(privKeyForUse.bytes)
|
||||
|
||||
val nonceHash = CryptoUtil.sha256SchnorrNonce(
|
||||
maskedKey ++ privKey.schnorrPublicKey.bytes ++ message
|
||||
)
|
||||
maskedKey ++ privKey.schnorrPublicKey.bytes ++ message)
|
||||
|
||||
ECPrivateKey(nonceHash.bytes).nonceKey
|
||||
}
|
||||
@ -46,8 +44,7 @@ object SchnorrNonce extends Factory[SchnorrNonce] {
|
||||
def fromBipSchnorr(
|
||||
privKey: ECPrivateKey,
|
||||
message: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): SchnorrNonce = {
|
||||
auxRand: ByteVector): SchnorrNonce = {
|
||||
val k = kFromBipSchnorr(privKey, message, auxRand)
|
||||
k.publicKey.schnorrNonce
|
||||
}
|
||||
|
@ -6,14 +6,10 @@ import scala.annotation.tailrec
|
||||
import scala.util.Try
|
||||
|
||||
case class SchnorrPublicKey(bytes: ByteVector) extends PublicKey {
|
||||
require(
|
||||
bytes.length == 32,
|
||||
s"Schnorr public keys must be 32 bytes, got $bytes"
|
||||
)
|
||||
require(
|
||||
Try(publicKey).isSuccess,
|
||||
s"Schnorr public key must be a valid x coordinate, got $bytes"
|
||||
)
|
||||
require(bytes.length == 32,
|
||||
s"Schnorr public keys must be 32 bytes, got $bytes")
|
||||
require(Try(publicKey).isSuccess,
|
||||
s"Schnorr public key must be a valid x coordinate, got $bytes")
|
||||
|
||||
def verify(data: ByteVector, signature: SchnorrDigitalSignature): Boolean = {
|
||||
CryptoUtil.schnorrVerify(data, this, signature)
|
||||
@ -33,8 +29,7 @@ case class SchnorrPublicKey(bytes: ByteVector) extends PublicKey {
|
||||
|
||||
def computeSigPoint(
|
||||
bytesToHash: Vector[ByteVector],
|
||||
nonces: Vector[SchnorrNonce]
|
||||
): ECPublicKey = {
|
||||
nonces: Vector[SchnorrNonce]): ECPublicKey = {
|
||||
// TODO: when combine function is ported from secp, use that instead for nonces
|
||||
val bytesAndNonces = bytesToHash.zip(nonces)
|
||||
|
||||
@ -43,8 +38,7 @@ case class SchnorrPublicKey(bytes: ByteVector) extends PublicKey {
|
||||
.sha256SchnorrChallenge(
|
||||
nonce.bytes ++ this.bytes ++ CryptoUtil
|
||||
.sha256DLCAttestation(bytes)
|
||||
.bytes
|
||||
)
|
||||
.bytes)
|
||||
.bytes
|
||||
val e = ECPrivateKey(eBytes)
|
||||
(e, nonce.publicKey)
|
||||
@ -62,8 +56,7 @@ case class SchnorrPublicKey(bytes: ByteVector) extends PublicKey {
|
||||
def computeSigPoint(
|
||||
data: ByteVector,
|
||||
nonce: SchnorrNonce,
|
||||
compressed: Boolean
|
||||
): ECPublicKey = {
|
||||
compressed: Boolean): ECPublicKey = {
|
||||
CryptoUtil.schnorrComputeSigPoint(data, nonce, this, compressed)
|
||||
}
|
||||
|
||||
@ -84,10 +77,8 @@ object SchnorrPublicKey extends Factory[SchnorrPublicKey] {
|
||||
|
||||
@tailrec
|
||||
def fromBytes(bytes: ByteVector): SchnorrPublicKey = {
|
||||
require(
|
||||
bytes.length <= 33,
|
||||
s"XOnlyPublicKey must be less than 33 bytes, got $bytes"
|
||||
)
|
||||
require(bytes.length <= 33,
|
||||
s"XOnlyPublicKey must be less than 33 bytes, got $bytes")
|
||||
if (bytes.length == 32)
|
||||
new SchnorrPublicKey(bytes)
|
||||
else if (bytes.length < 32) {
|
||||
@ -99,8 +90,7 @@ object SchnorrPublicKey extends Factory[SchnorrPublicKey] {
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"XOnlyPublicKey cannot be greater than 33 bytes in size, got: " +
|
||||
CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size
|
||||
)
|
||||
CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,10 +51,8 @@ case class SecpPointFinite(x: CurveCoordinate, y: CurveCoordinate)
|
||||
|
||||
def schnorrNonce: SchnorrNonce = {
|
||||
val pub = toPublicKey
|
||||
require(
|
||||
pub.isCompressed,
|
||||
s"SchnorrNonce can only be created from compressed public keys"
|
||||
)
|
||||
require(pub.isCompressed,
|
||||
s"SchnorrNonce can only be created from compressed public keys")
|
||||
pub.schnorrNonce
|
||||
}
|
||||
}
|
||||
@ -70,10 +68,8 @@ object SecpPoint {
|
||||
SecpPointFinite(CurveCoordinate.fromBytes(x), CurveCoordinate.fromBytes(y))
|
||||
|
||||
def apply(x: Array[Byte], y: Array[Byte]): SecpPointFinite =
|
||||
SecpPointFinite(
|
||||
CurveCoordinate.fromByteArray(x),
|
||||
CurveCoordinate.fromByteArray(y)
|
||||
)
|
||||
SecpPointFinite(CurveCoordinate.fromByteArray(x),
|
||||
CurveCoordinate.fromByteArray(y))
|
||||
|
||||
def apply(x: BigInteger, y: BigInteger): SecpPointFinite =
|
||||
SecpPointFinite(CurveCoordinate(x), CurveCoordinate(y))
|
||||
|
@ -36,12 +36,10 @@ trait AsyncSign {
|
||||
*/
|
||||
def asyncSignWithEntropy(
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): Future[ECDigitalSignature]
|
||||
entropy: ByteVector): Future[ECDigitalSignature]
|
||||
|
||||
private def asyncSignLowR(bytes: ByteVector, startAt: Long)(implicit
|
||||
ec: ExecutionContext
|
||||
): Future[ECDigitalSignature] = {
|
||||
ec: ExecutionContext): Future[ECDigitalSignature] = {
|
||||
val sigF = if (startAt == 0) { // On first try, use normal signing
|
||||
asyncSign(bytes)
|
||||
} else { // Subsequently, use additional entropy
|
||||
@ -58,9 +56,8 @@ trait AsyncSign {
|
||||
}
|
||||
}
|
||||
|
||||
def asyncSignLowR(
|
||||
bytes: ByteVector
|
||||
)(implicit ec: ExecutionContext): Future[ECDigitalSignature] = {
|
||||
def asyncSignLowR(bytes: ByteVector)(implicit
|
||||
ec: ExecutionContext): Future[ECDigitalSignature] = {
|
||||
asyncSignLowR(bytes, startAt = 0)
|
||||
}
|
||||
|
||||
@ -73,10 +70,9 @@ object AsyncSign {
|
||||
asyncSignFunction: ByteVector => Future[ECDigitalSignature],
|
||||
asyncSignWithEntropyFunction: (
|
||||
ByteVector,
|
||||
ByteVector
|
||||
) => Future[ECDigitalSignature],
|
||||
override val publicKey: ECPublicKey
|
||||
) extends AsyncSign {
|
||||
ByteVector) => Future[ECDigitalSignature],
|
||||
override val publicKey: ECPublicKey)
|
||||
extends AsyncSign {
|
||||
|
||||
override def asyncSign(bytes: ByteVector): Future[ECDigitalSignature] = {
|
||||
asyncSignFunction(bytes)
|
||||
@ -84,8 +80,7 @@ object AsyncSign {
|
||||
|
||||
override def asyncSignWithEntropy(
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): Future[ECDigitalSignature] = {
|
||||
entropy: ByteVector): Future[ECDigitalSignature] = {
|
||||
asyncSignWithEntropyFunction(bytes, entropy)
|
||||
}
|
||||
}
|
||||
@ -94,19 +89,15 @@ object AsyncSign {
|
||||
asyncSign: ByteVector => Future[ECDigitalSignature],
|
||||
asyncSignWithEntropy: (
|
||||
ByteVector,
|
||||
ByteVector
|
||||
) => Future[ECDigitalSignature],
|
||||
pubKey: ECPublicKey
|
||||
): AsyncSign = {
|
||||
ByteVector) => Future[ECDigitalSignature],
|
||||
pubKey: ECPublicKey): AsyncSign = {
|
||||
AsyncSignImpl(asyncSign, asyncSignWithEntropy, pubKey)
|
||||
}
|
||||
|
||||
def constant(sig: ECDigitalSignature, pubKey: ECPublicKey): AsyncSign = {
|
||||
AsyncSignImpl(
|
||||
_ => Future.successful(sig),
|
||||
(_, _) => Future.successful(sig),
|
||||
pubKey
|
||||
)
|
||||
AsyncSignImpl(_ => Future.successful(sig),
|
||||
(_, _) => Future.successful(sig),
|
||||
pubKey)
|
||||
}
|
||||
|
||||
/** This dummySign function is useful for the case where we do not have the
|
||||
@ -127,13 +118,11 @@ trait AsyncAdaptorSign extends AsyncSign {
|
||||
def asyncAdaptorSign(
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): Future[ECAdaptorSignature]
|
||||
auxRand: ByteVector): Future[ECAdaptorSignature]
|
||||
|
||||
def asyncAdaptorSign(
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector
|
||||
): Future[ECAdaptorSignature] = {
|
||||
msg: ByteVector): Future[ECAdaptorSignature] = {
|
||||
val auxRand = ECPrivateKey.freshPrivateKey.bytes
|
||||
asyncAdaptorSign(adaptorPoint, msg, auxRand)
|
||||
}
|
||||
@ -158,13 +147,11 @@ trait Sign extends AsyncSign {
|
||||
*/
|
||||
def signWithEntropy(
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature
|
||||
entropy: ByteVector): ECDigitalSignature
|
||||
|
||||
override def asyncSignWithEntropy(
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): Future[ECDigitalSignature] = {
|
||||
entropy: ByteVector): Future[ECDigitalSignature] = {
|
||||
Future.successful(signWithEntropy(bytes, entropy))
|
||||
}
|
||||
|
||||
@ -193,9 +180,8 @@ trait Sign extends AsyncSign {
|
||||
signLowR(bytes, startAt = 0)
|
||||
}
|
||||
|
||||
override def asyncSignLowR(
|
||||
bytes: ByteVector
|
||||
)(implicit ec: ExecutionContext): Future[ECDigitalSignature] = {
|
||||
override def asyncSignLowR(bytes: ByteVector)(implicit
|
||||
ec: ExecutionContext): Future[ECDigitalSignature] = {
|
||||
Future.successful(signLowR(bytes))
|
||||
}
|
||||
}
|
||||
@ -205,8 +191,8 @@ object Sign {
|
||||
private case class SignImpl(
|
||||
signFunction: ByteVector => ECDigitalSignature,
|
||||
signWithEntropyFunction: (ByteVector, ByteVector) => ECDigitalSignature,
|
||||
override val publicKey: ECPublicKey
|
||||
) extends Sign {
|
||||
override val publicKey: ECPublicKey)
|
||||
extends Sign {
|
||||
|
||||
override def sign(bytes: ByteVector): ECDigitalSignature = {
|
||||
signFunction(bytes)
|
||||
@ -214,8 +200,7 @@ object Sign {
|
||||
|
||||
override def signWithEntropy(
|
||||
bytes: ByteVector,
|
||||
entropy: ByteVector
|
||||
): ECDigitalSignature = {
|
||||
entropy: ByteVector): ECDigitalSignature = {
|
||||
signWithEntropyFunction(bytes, entropy)
|
||||
}
|
||||
}
|
||||
@ -223,8 +208,7 @@ object Sign {
|
||||
def apply(
|
||||
sign: ByteVector => ECDigitalSignature,
|
||||
signWithEntropy: (ByteVector, ByteVector) => ECDigitalSignature,
|
||||
pubKey: ECPublicKey
|
||||
): Sign = {
|
||||
pubKey: ECPublicKey): Sign = {
|
||||
SignImpl(sign, signWithEntropy, pubKey)
|
||||
}
|
||||
|
||||
@ -242,13 +226,11 @@ trait AdaptorSign extends Sign with AsyncAdaptorSign {
|
||||
def adaptorSign(
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): ECAdaptorSignature
|
||||
auxRand: ByteVector): ECAdaptorSignature
|
||||
|
||||
def adaptorSign(
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector
|
||||
): ECAdaptorSignature = {
|
||||
msg: ByteVector): ECAdaptorSignature = {
|
||||
val auxRand = ECPrivateKey.freshPrivateKey.bytes
|
||||
adaptorSign(adaptorPoint, msg, auxRand)
|
||||
}
|
||||
@ -256,8 +238,7 @@ trait AdaptorSign extends Sign with AsyncAdaptorSign {
|
||||
override def asyncAdaptorSign(
|
||||
adaptorPoint: ECPublicKey,
|
||||
msg: ByteVector,
|
||||
auxRand: ByteVector
|
||||
): Future[ECAdaptorSignature] = {
|
||||
auxRand: ByteVector): Future[ECAdaptorSignature] = {
|
||||
Future.successful(adaptorSign(adaptorPoint, msg, auxRand))
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,6 @@ package org.bitcoins.crypto
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
case class SipHashKey(bytes: ByteVector) extends NetworkElement {
|
||||
require(
|
||||
bytes.size == 16,
|
||||
"Can only use a key length of 16 bytes, got: " + bytes.size
|
||||
)
|
||||
require(bytes.size == 16,
|
||||
"Can only use a key length of 16 bytes, got: " + bytes.size)
|
||||
}
|
||||
|
@ -9,14 +9,10 @@ import scala.util.Try
|
||||
* y-coordinate parity
|
||||
*/
|
||||
case class XOnlyPubKey(bytes: ByteVector) extends PublicKey {
|
||||
require(
|
||||
bytes.length == 32,
|
||||
s"x-only public keys must be 32 bytes, got $bytes"
|
||||
)
|
||||
require(
|
||||
Try(publicKey(EvenParity)).isSuccess,
|
||||
s"x-only public key must be a valid x coordinate, got $bytes"
|
||||
)
|
||||
require(bytes.length == 32,
|
||||
s"x-only public keys must be 32 bytes, got $bytes")
|
||||
require(Try(publicKey(EvenParity)).isSuccess,
|
||||
s"x-only public key must be a valid x coordinate, got $bytes")
|
||||
|
||||
def publicKey(parity: KeyParity): ECPublicKey = {
|
||||
val pubKeyBytes = parity.bytes ++ bytes
|
||||
@ -48,8 +44,7 @@ case class XOnlyPubKey(bytes: ByteVector) extends PublicKey {
|
||||
def checkTapTweak(
|
||||
internal: XOnlyPubKey,
|
||||
merkleRootOpt: Option[Sha256Digest],
|
||||
parity: Boolean
|
||||
): Boolean = {
|
||||
parity: Boolean): Boolean = {
|
||||
// Q = point_add(lift_x(pubkey), point_mul(G, t))
|
||||
val tweaked = internal.computeTapTweakHash(merkleRootOpt)
|
||||
val fe = FieldElement.fromBytes(tweaked.bytes)
|
||||
@ -84,8 +79,7 @@ case class XOnlyPubKey(bytes: ByteVector) extends PublicKey {
|
||||
* @return
|
||||
*/
|
||||
def createTapTweak(
|
||||
merkleRootOpt: Option[Sha256Digest]
|
||||
): (KeyParity, XOnlyPubKey) = {
|
||||
merkleRootOpt: Option[Sha256Digest]): (KeyParity, XOnlyPubKey) = {
|
||||
val taggedHash = computeTapTweakHash(merkleRootOpt)
|
||||
val result = CryptoParams.getG
|
||||
.multiply(FieldElement(taggedHash.bytes))
|
||||
@ -102,10 +96,8 @@ object XOnlyPubKey extends Factory[XOnlyPubKey] {
|
||||
|
||||
@tailrec
|
||||
def fromBytes(bytes: ByteVector): XOnlyPubKey = {
|
||||
require(
|
||||
bytes.length <= 33,
|
||||
s"XOnlyPublicKey must be less than 33 bytes, got $bytes"
|
||||
)
|
||||
require(bytes.length <= 33,
|
||||
s"XOnlyPublicKey must be less than 33 bytes, got $bytes")
|
||||
|
||||
if (bytes.length == 32)
|
||||
new XOnlyPubKey(bytes)
|
||||
@ -118,8 +110,7 @@ object XOnlyPubKey extends Factory[XOnlyPubKey] {
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"XOnlyPublicKey cannot be greater than 33 bytes in size, got: " +
|
||||
CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size
|
||||
)
|
||||
CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -89,8 +89,7 @@ object KeySet {
|
||||
|
||||
def apply(
|
||||
keys: Vector[SchnorrPublicKey],
|
||||
tweaks: Vector[MuSigTweak]
|
||||
): LexicographicKeySet = {
|
||||
tweaks: Vector[MuSigTweak]): LexicographicKeySet = {
|
||||
val sortedKeys = keys.sorted(NetworkElement.lexicographicalOrdering)
|
||||
LexicographicKeySet(sortedKeys, tweaks)
|
||||
}
|
||||
@ -99,13 +98,11 @@ object KeySet {
|
||||
/** The default way of ordering a KeySet is lexicographically */
|
||||
case class LexicographicKeySet(
|
||||
override val keys: Vector[SchnorrPublicKey],
|
||||
override val tweaks: Vector[MuSigTweak] = Vector.empty
|
||||
) extends KeySet {
|
||||
override val tweaks: Vector[MuSigTweak] = Vector.empty)
|
||||
extends KeySet {
|
||||
keys.init.zip(keys.tail).foreach { case (key1, key2) =>
|
||||
require(
|
||||
key1.hex.compareTo(key2.hex) <= 0,
|
||||
"Keys must be sorted lexicographically"
|
||||
)
|
||||
require(key1.hex.compareTo(key2.hex) <= 0,
|
||||
"Keys must be sorted lexicographically")
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,5 +111,5 @@ case class LexicographicKeySet(
|
||||
*/
|
||||
case class UnsortedKeySet(
|
||||
override val keys: Vector[SchnorrPublicKey],
|
||||
override val tweaks: Vector[MuSigTweak] = Vector.empty
|
||||
) extends KeySet
|
||||
override val tweaks: Vector[MuSigTweak] = Vector.empty)
|
||||
extends KeySet
|
||||
|
@ -6,10 +6,8 @@ import scodec.bits.ByteVector
|
||||
/** Wraps the ephemeral private keys making up a MuSig2 nonce */
|
||||
case class MuSigNoncePriv(privNonces: Vector[ECPrivateKey])
|
||||
extends NetworkElement {
|
||||
require(
|
||||
privNonces.length == MuSigUtil.nonceNum,
|
||||
s"Exactly ${MuSigUtil.nonceNum} keys are expected, found $privNonces"
|
||||
)
|
||||
require(privNonces.length == MuSigUtil.nonceNum,
|
||||
s"Exactly ${MuSigUtil.nonceNum} keys are expected, found $privNonces")
|
||||
|
||||
def toPublicNonces: MuSigNoncePub = {
|
||||
MuSigNoncePub(privNonces.map(_.publicKey.toPoint))
|
||||
@ -31,13 +29,11 @@ case class MuSigNoncePriv(privNonces: Vector[ECPrivateKey])
|
||||
|
||||
/** Collapses this into a single ephemeral private key */
|
||||
def sumToKey(b: FieldElement): FieldElement = {
|
||||
MuSigUtil.nonceSum[FieldElement](
|
||||
toFieldElements,
|
||||
b,
|
||||
_.add(_),
|
||||
_.multiply(_),
|
||||
FieldElement.zero
|
||||
)
|
||||
MuSigUtil.nonceSum[FieldElement](toFieldElements,
|
||||
b,
|
||||
_.add(_),
|
||||
_.multiply(_),
|
||||
FieldElement.zero)
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,25 +57,18 @@ object MuSigNoncePriv extends Factory[MuSigNoncePriv] {
|
||||
privKeyOpt: Option[ECPrivateKey] = None,
|
||||
aggPubKeyOpt: Option[SchnorrPublicKey] = None,
|
||||
msgOpt: Option[ByteVector] = None,
|
||||
extraInOpt: Option[ByteVector] = None
|
||||
): MuSigNoncePriv = {
|
||||
require(
|
||||
preRand.length == 32,
|
||||
s"32 bytes of entropy must be provided, found $preRand"
|
||||
)
|
||||
require(
|
||||
msgOpt.forall(msg => msg.length == 32),
|
||||
s"The message to be signed must be 32 bytes, found $msgOpt"
|
||||
)
|
||||
extraInOpt: Option[ByteVector] = None): MuSigNoncePriv = {
|
||||
require(preRand.length == 32,
|
||||
s"32 bytes of entropy must be provided, found $preRand")
|
||||
require(msgOpt.forall(msg => msg.length == 32),
|
||||
s"The message to be signed must be 32 bytes, found $msgOpt")
|
||||
require(
|
||||
extraInOpt.forall(_.length <= 4294967295L),
|
||||
"extraIn too long, its length must be represented by at most four bytes"
|
||||
)
|
||||
"extraIn too long, its length must be represented by at most four bytes")
|
||||
|
||||
def serializeWithLen(
|
||||
bytesOpt: Option[ByteVector],
|
||||
lengthSize: Int = 1
|
||||
): ByteVector = {
|
||||
lengthSize: Int = 1): ByteVector = {
|
||||
bytesOpt match {
|
||||
case Some(bytes) =>
|
||||
ByteVector.fromLong(bytes.length, lengthSize) ++ bytes
|
||||
@ -115,8 +104,7 @@ object MuSigNoncePriv extends Factory[MuSigNoncePriv] {
|
||||
privKeyOpt: Option[ECPrivateKey] = None,
|
||||
aggPubKeyOpt: Option[SchnorrPublicKey] = None,
|
||||
msgOpt: Option[ByteVector] = None,
|
||||
extraInOpt: Option[ByteVector] = None
|
||||
): MuSigNoncePriv = {
|
||||
extraInOpt: Option[ByteVector] = None): MuSigNoncePriv = {
|
||||
val preRand = CryptoUtil.randomBytes(32)
|
||||
|
||||
genInternal(preRand, privKeyOpt, aggPubKeyOpt, msgOpt, extraInOpt)
|
||||
|
@ -5,10 +5,8 @@ import scodec.bits.ByteVector
|
||||
|
||||
/** Wraps the ephemeral points making up a MuSig2 nonce */
|
||||
case class MuSigNoncePub(pubNonces: Vector[SecpPoint]) extends NetworkElement {
|
||||
require(
|
||||
pubNonces.length == MuSigUtil.nonceNum,
|
||||
s"Exactly ${MuSigUtil.nonceNum} keys are expected, found $pubNonces"
|
||||
)
|
||||
require(pubNonces.length == MuSigUtil.nonceNum,
|
||||
s"Exactly ${MuSigUtil.nonceNum} keys are expected, found $pubNonces")
|
||||
|
||||
def apply(i: Int): SecpPoint = {
|
||||
pubNonces(i)
|
||||
@ -27,13 +25,11 @@ case class MuSigNoncePub(pubNonces: Vector[SecpPoint]) extends NetworkElement {
|
||||
|
||||
/** Collapses this into a single ephemeral public key */
|
||||
def sumToKey(b: FieldElement): ECPublicKey = {
|
||||
MuSigUtil.nonceSum[SecpPoint](
|
||||
pubNonces,
|
||||
b,
|
||||
_.add(_),
|
||||
_.multiply(_),
|
||||
SecpPointInfinity
|
||||
) match {
|
||||
MuSigUtil.nonceSum[SecpPoint](pubNonces,
|
||||
b,
|
||||
_.add(_),
|
||||
_.multiply(_),
|
||||
SecpPointInfinity) match {
|
||||
case SecpPointInfinity => CryptoParams.getG
|
||||
case p: SecpPointFinite => p.toPublicKey
|
||||
}
|
||||
|
@ -7,14 +7,12 @@ import org.bitcoins.crypto.{ECPublicKey, FieldElement, OddParity}
|
||||
*/
|
||||
case class MuSigTweakContext(
|
||||
parityAcc: ParityMultiplier,
|
||||
tweakAcc: FieldElement
|
||||
) {
|
||||
tweakAcc: FieldElement) {
|
||||
|
||||
/** Adds tweak to tweakAcc and aggPubKey changing parityAcc if necessary */
|
||||
def applyTweak(
|
||||
tweak: MuSigTweak,
|
||||
aggPubKey: ECPublicKey
|
||||
): (ECPublicKey, MuSigTweakContext) = {
|
||||
aggPubKey: ECPublicKey): (ECPublicKey, MuSigTweakContext) = {
|
||||
val parityMult =
|
||||
if (tweak.isXOnlyT && aggPubKey.parity == OddParity) Neg
|
||||
else Pos
|
||||
|
@ -7,8 +7,7 @@ import org.bitcoins.crypto.{EvenParity, FieldElement, KeyParity, OddParity}
|
||||
case class MuSigTweakData(
|
||||
context: MuSigTweakContext,
|
||||
aggPubKeyParity: KeyParity,
|
||||
e: FieldElement
|
||||
) {
|
||||
e: FieldElement) {
|
||||
|
||||
def additiveTweak: FieldElement = {
|
||||
val g = aggPubKeyParity match {
|
||||
|
@ -37,8 +37,7 @@ object MuSigUtil {
|
||||
b: FieldElement,
|
||||
add: (T, T) => T,
|
||||
multiply: (T, FieldElement) => T,
|
||||
identity: T
|
||||
): T = {
|
||||
identity: T): T = {
|
||||
nonces
|
||||
.foldLeft((FieldElement.one, identity)) { case ((pow, sumSoFar), nonce) =>
|
||||
val prod = multiply(nonce, pow)
|
||||
@ -55,8 +54,7 @@ object MuSigUtil {
|
||||
aggNoncePub: MuSigNoncePub,
|
||||
privKey: ECPrivateKey,
|
||||
message: ByteVector,
|
||||
keySet: KeySet
|
||||
): (ECPublicKey, FieldElement) = {
|
||||
keySet: KeySet): (ECPublicKey, FieldElement) = {
|
||||
val pubKey = privKey.publicKey
|
||||
val coef = keySet.keyAggCoef(pubKey.schnorrPublicKey)
|
||||
val SigningSession(b, aggNonce, e) =
|
||||
@ -80,18 +78,14 @@ object MuSigUtil {
|
||||
|
||||
val s = adjustedPrivKey.multiply(e).multiply(coef).add(privNonceSum)
|
||||
|
||||
require(
|
||||
partialSigVerify(
|
||||
s,
|
||||
noncePriv.toPublicNonces,
|
||||
pubKey.schnorrPublicKey,
|
||||
keySet,
|
||||
b,
|
||||
aggNonce,
|
||||
e
|
||||
),
|
||||
"Failed verification when generating signature."
|
||||
)
|
||||
require(partialSigVerify(s,
|
||||
noncePriv.toPublicNonces,
|
||||
pubKey.schnorrPublicKey,
|
||||
keySet,
|
||||
b,
|
||||
aggNonce,
|
||||
e),
|
||||
"Failed verification when generating signature.")
|
||||
|
||||
(aggNonce, s)
|
||||
}
|
||||
@ -101,21 +95,16 @@ object MuSigUtil {
|
||||
pubNonces: Vector[MuSigNoncePub],
|
||||
keySet: KeySet,
|
||||
message: ByteVector,
|
||||
signerIndex: Int
|
||||
): Boolean = {
|
||||
require(
|
||||
signerIndex >= 0 && signerIndex < keySet.length,
|
||||
s"Invalid signer index $signerIndex for ${keySet.length} signers"
|
||||
)
|
||||
signerIndex: Int): Boolean = {
|
||||
require(signerIndex >= 0 && signerIndex < keySet.length,
|
||||
s"Invalid signer index $signerIndex for ${keySet.length} signers")
|
||||
|
||||
partialSigVerify(
|
||||
partialSig,
|
||||
pubNonces(signerIndex),
|
||||
MuSigNoncePub.aggregate(pubNonces),
|
||||
keySet(signerIndex),
|
||||
keySet,
|
||||
message
|
||||
)
|
||||
partialSigVerify(partialSig,
|
||||
pubNonces(signerIndex),
|
||||
MuSigNoncePub.aggregate(pubNonces),
|
||||
keySet(signerIndex),
|
||||
keySet,
|
||||
message)
|
||||
}
|
||||
|
||||
def partialSigVerify(
|
||||
@ -124,8 +113,7 @@ object MuSigUtil {
|
||||
aggNoncePub: MuSigNoncePub,
|
||||
pubKey: SchnorrPublicKey,
|
||||
keySet: KeySet,
|
||||
message: ByteVector
|
||||
): Boolean = {
|
||||
message: ByteVector): Boolean = {
|
||||
val SigningSession(b, aggNonce, e) =
|
||||
SigningSession(aggNoncePub, keySet, message)
|
||||
|
||||
@ -139,8 +127,7 @@ object MuSigUtil {
|
||||
keySet: KeySet,
|
||||
b: FieldElement,
|
||||
aggNonce: ECPublicKey,
|
||||
e: FieldElement
|
||||
): Boolean = {
|
||||
e: FieldElement): Boolean = {
|
||||
val nonceSum = noncePub.sumToKey(b)
|
||||
val nonceSumAdjusted = aggNonce.parity match {
|
||||
case EvenParity => nonceSum
|
||||
@ -153,8 +140,7 @@ object MuSigUtil {
|
||||
val aggKey = pubKey.toXOnly.publicKey(aggKeyParity)
|
||||
val a = keySet.keyAggCoef(pubKey)
|
||||
partialSig.getPublicKey == nonceSumAdjusted.add(
|
||||
aggKey.multiply(e.multiply(a))
|
||||
)
|
||||
aggKey.multiply(e.multiply(a)))
|
||||
}
|
||||
|
||||
/** Aggregates MuSig partial signatures into a BIP340 SchnorrDigitalSignature
|
||||
@ -163,8 +149,7 @@ object MuSigUtil {
|
||||
sVals: Vector[FieldElement],
|
||||
aggNoncePub: MuSigNoncePub,
|
||||
keySet: KeySet,
|
||||
message: ByteVector
|
||||
): SchnorrDigitalSignature = {
|
||||
message: ByteVector): SchnorrDigitalSignature = {
|
||||
val SigningSession(_, aggNonce, e) =
|
||||
SigningSession(aggNoncePub, keySet, message)
|
||||
val tweakData =
|
||||
@ -178,8 +163,7 @@ object MuSigUtil {
|
||||
def signAgg(
|
||||
sVals: Vector[FieldElement],
|
||||
aggPubNonce: ECPublicKey,
|
||||
tweakDataOpt: Option[MuSigTweakData] = None
|
||||
): SchnorrDigitalSignature = {
|
||||
tweakDataOpt: Option[MuSigTweakData] = None): SchnorrDigitalSignature = {
|
||||
val sSum = sVals.reduce(_.add(_))
|
||||
val s = tweakDataOpt match {
|
||||
case Some(tweakData) => sSum.add(tweakData.additiveTweak)
|
||||
|
@ -12,16 +12,14 @@ import scodec.bits.ByteVector
|
||||
case class SigningSession(
|
||||
b: FieldElement,
|
||||
aggNonce: ECPublicKey,
|
||||
e: FieldElement
|
||||
)
|
||||
e: FieldElement)
|
||||
|
||||
object SigningSession {
|
||||
|
||||
def computeB(
|
||||
aggNoncePub: MuSigNoncePub,
|
||||
keySet: KeySet,
|
||||
message: ByteVector
|
||||
): FieldElement = {
|
||||
message: ByteVector): FieldElement = {
|
||||
val aggPubKey = keySet.aggPubKey.schnorrPublicKey
|
||||
|
||||
val bHash =
|
||||
@ -33,12 +31,10 @@ object SigningSession {
|
||||
def computeE(
|
||||
aggPubKey: SchnorrPublicKey,
|
||||
aggNonce: ECPublicKey,
|
||||
message: ByteVector
|
||||
): FieldElement = {
|
||||
message: ByteVector): FieldElement = {
|
||||
val eBytes = CryptoUtil
|
||||
.sha256SchnorrChallenge(
|
||||
aggNonce.schnorrNonce.bytes ++ aggPubKey.bytes ++ message
|
||||
)
|
||||
aggNonce.schnorrNonce.bytes ++ aggPubKey.bytes ++ message)
|
||||
.bytes
|
||||
|
||||
FieldElement(new java.math.BigInteger(1, eBytes.toArray))
|
||||
@ -47,8 +43,7 @@ object SigningSession {
|
||||
def getSessionValues(
|
||||
aggNoncePub: MuSigNoncePub,
|
||||
keySet: KeySet,
|
||||
message: ByteVector
|
||||
): SigningSession = {
|
||||
message: ByteVector): SigningSession = {
|
||||
val aggPubKey = keySet.aggPubKey.schnorrPublicKey
|
||||
val b = computeB(aggNoncePub, keySet, message)
|
||||
val aggNonce = aggNoncePub.sumToKey(b)
|
||||
@ -60,8 +55,7 @@ object SigningSession {
|
||||
def apply(
|
||||
aggNoncePub: MuSigNoncePub,
|
||||
keySet: KeySet,
|
||||
message: ByteVector
|
||||
): SigningSession = {
|
||||
message: ByteVector): SigningSession = {
|
||||
getSessionValues(aggNoncePub, keySet, message)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user