mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-18 21:34:39 +01:00
Updated Bouncy Castle Schnorr implementation to most recent BIP 340 (#2025)
This commit is contained in:
parent
16599010c7
commit
613f6ba4b9
@ -1,6 +1,6 @@
|
||||
package org.bitcoins.core.util
|
||||
package org.bitcoins.crypto
|
||||
|
||||
import org.bitcoins.crypto.CryptoUtil
|
||||
import org.bitcoins.core.util.BytesUtil
|
||||
import org.bitcoins.testkit.core.gen.{CryptoGenerators, NumberGenerator}
|
||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||
import scodec.bits._
|
||||
@ -97,13 +97,13 @@ class CryptoUtilTest extends BitcoinSUnitTest {
|
||||
forAll(NumberGenerator.bytevector) { bytes =>
|
||||
assert(
|
||||
CryptoUtil.sha256SchnorrChallenge(bytes) == CryptoUtil
|
||||
.taggedSha256(bytes, "BIP340/challenge"))
|
||||
.taggedSha256(bytes, "BIP0340/challenge"))
|
||||
assert(
|
||||
CryptoUtil.sha256SchnorrNonce(bytes) == CryptoUtil
|
||||
.taggedSha256(bytes, "BIP340/nonce"))
|
||||
.taggedSha256(bytes, "BIP0340/nonce"))
|
||||
assert(
|
||||
CryptoUtil.sha256SchnorrAuxRand(bytes) == CryptoUtil
|
||||
.taggedSha256(bytes, "BIP340/aux"))
|
||||
.taggedSha256(bytes, "BIP0340/aux"))
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ object BouncyCastleUtil {
|
||||
val computedR = challengePoint.add(sigPoint)
|
||||
val yCoord = computedR.toPoint.getRawYCoord
|
||||
|
||||
yCoord != null && yCoord.sqrt() != null && computedR.schnorrNonce == rx
|
||||
yCoord != null && !yCoord.testBitZero() && computedR.schnorrNonce == rx
|
||||
case Failure(_) => false
|
||||
}
|
||||
}
|
||||
|
@ -43,11 +43,11 @@ trait CryptoUtil {
|
||||
sha256(tagBytes ++ bytes)
|
||||
}
|
||||
|
||||
// The tag "BIP340/challenge"
|
||||
// The tag "BIP0340/challenge"
|
||||
private val schnorrChallengeTagBytes = {
|
||||
ByteVector
|
||||
.fromValidHex(
|
||||
"07e00dcd3055c1b36ee93effe4d7f266024cdef4116982ff5dfdc1a97e77062907e00dcd3055c1b36ee93effe4d7f266024cdef4116982ff5dfdc1a97e770629"
|
||||
"7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c7bb52d7a9fef58323eb1bf7a407db382d2f3f2d81bb1224f49fe518f6d48d37c"
|
||||
)
|
||||
}
|
||||
|
||||
@ -55,11 +55,11 @@ trait CryptoUtil {
|
||||
sha256(schnorrChallengeTagBytes ++ bytes)
|
||||
}
|
||||
|
||||
// The tag "BIP340/nonce"
|
||||
// The tag "BIP0340/nonce"
|
||||
private val schnorrNonceTagBytes = {
|
||||
ByteVector
|
||||
.fromValidHex(
|
||||
"a2ba14a6b39c1c505260bf3aceb07febde3ab34c35c9259d25bd6972f15e6564a2ba14a6b39c1c505260bf3aceb07febde3ab34c35c9259d25bd6972f15e6564"
|
||||
"07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f07497734a79bcb355b9b8c7d034f121cf434d73ef72dda19870061fb52bfeb2f"
|
||||
)
|
||||
}
|
||||
|
||||
@ -67,11 +67,11 @@ trait CryptoUtil {
|
||||
sha256(schnorrNonceTagBytes ++ bytes)
|
||||
}
|
||||
|
||||
// The tag "BIP340/aux"
|
||||
// The tag "BIP0340/aux"
|
||||
private val schnorrAuxTagBytes = {
|
||||
ByteVector
|
||||
.fromValidHex(
|
||||
"4b07426ad8630dcdbadf8dee1e94f09ac2df4e7ee2629e5e6b27c8666c8cf31e4b07426ad8630dcdbadf8dee1e94f09ac2df4e7ee2629e5e6b27c8666c8cf31e"
|
||||
"f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90f1ef4e5ec063cada6d94cafa9d987ea069265839ecc11f972d77a52ed8c1cc90"
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2,35 +2,12 @@ package org.bitcoins.crypto
|
||||
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.Try
|
||||
|
||||
case class SchnorrNonce(bytes: ByteVector) extends NetworkElement {
|
||||
require(bytes.length == 32, s"Schnorr nonce must be 32 bytes, get $bytes")
|
||||
|
||||
private val evenKey: ECPublicKey = ECPublicKey(s"02$hex")
|
||||
private val oddKey: ECPublicKey = ECPublicKey(s"03$hex")
|
||||
private val schnorrPublicKey: SchnorrPublicKey = new SchnorrPublicKey(bytes)
|
||||
|
||||
private val yCoordEven: Boolean = {
|
||||
evenKey.toPoint.getRawYCoord.sqrt() != null
|
||||
}
|
||||
|
||||
/** Computes the public key associated with a SchnorrNonce as specified in bip-schnorr.
|
||||
* They y-coordinate is chosen to be a quadratic residue.
|
||||
*/
|
||||
val publicKey: ECPublicKey = {
|
||||
if (yCoordEven) {
|
||||
evenKey
|
||||
} else {
|
||||
oddKey
|
||||
}
|
||||
}
|
||||
|
||||
require(Try(publicKey).isSuccess,
|
||||
s"Schnorr nonce must be a valid x coordinate, got $bytes")
|
||||
require(
|
||||
publicKey.toPoint.getRawYCoord.sqrt != null,
|
||||
"Schnorr nonce must be an x coordinate for which a quadratic residue y coordinate exists")
|
||||
val publicKey: ECPublicKey = schnorrPublicKey.publicKey
|
||||
|
||||
def xCoord: FieldElement = {
|
||||
FieldElement(bytes)
|
||||
@ -39,21 +16,8 @@ case class SchnorrNonce(bytes: ByteVector) extends NetworkElement {
|
||||
|
||||
object SchnorrNonce extends Factory[SchnorrNonce] {
|
||||
|
||||
@tailrec
|
||||
def fromBytes(bytes: ByteVector): SchnorrNonce = {
|
||||
if (bytes.length == 32) {
|
||||
new SchnorrNonce(bytes)
|
||||
} else if (bytes.length < 32) {
|
||||
// means we need to pad the private key with 0 bytes so we have 32 bytes
|
||||
SchnorrNonce.fromBytes(bytes.padLeft(32))
|
||||
} else if (bytes.length == 33) {
|
||||
// this is for the case when java serialies a BigInteger to 33 bytes to hold the signed num representation
|
||||
SchnorrNonce.fromBytes(bytes.tail)
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Schnorr nonce cannot be greater than 33 bytes in size, got: " +
|
||||
CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size)
|
||||
}
|
||||
new SchnorrNonce(SchnorrPublicKey.fromBytes(bytes).bytes)
|
||||
}
|
||||
|
||||
def kFromBipSchnorr(
|
||||
|
Loading…
Reference in New Issue
Block a user