mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2025-01-19 05:43:51 +01:00
Brought down ecdsa adaptor signatures implemented in scala from the dlc-crypto branch (#2034)
This commit is contained in:
parent
09dfd5eb73
commit
e71b664e1a
@ -3,7 +3,12 @@ package org.bitcoins.core.crypto
|
|||||||
import org.bitcoins.core.protocol.transaction.Transaction
|
import org.bitcoins.core.protocol.transaction.Transaction
|
||||||
import org.bitcoins.core.script.crypto.HashType
|
import org.bitcoins.core.script.crypto.HashType
|
||||||
import org.bitcoins.core.wallet.utxo.{InputInfo, InputSigningInfo}
|
import org.bitcoins.core.wallet.utxo.{InputInfo, InputSigningInfo}
|
||||||
import org.bitcoins.crypto.{DERSignatureUtil, ECDigitalSignature, ECPrivateKey}
|
import org.bitcoins.crypto.{
|
||||||
|
DERSignatureUtil,
|
||||||
|
ECAdaptorSignature,
|
||||||
|
ECDigitalSignature,
|
||||||
|
ECPrivateKey
|
||||||
|
}
|
||||||
import scodec.bits.ByteVector
|
import scodec.bits.ByteVector
|
||||||
|
|
||||||
import scala.concurrent.{ExecutionContext, Future}
|
import scala.concurrent.{ExecutionContext, Future}
|
||||||
@ -145,6 +150,15 @@ sealed abstract class TransactionSignatureCreator {
|
|||||||
s
|
s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def createSig(
|
||||||
|
component: TxSigComponent,
|
||||||
|
adaptorSign: ByteVector => ECAdaptorSignature,
|
||||||
|
hashType: HashType): ECAdaptorSignature = {
|
||||||
|
val hash =
|
||||||
|
TransactionSignatureSerializer.hashForSignature(component, hashType)
|
||||||
|
adaptorSign(hash.bytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object TransactionSignatureCreator extends TransactionSignatureCreator
|
object TransactionSignatureCreator extends TransactionSignatureCreator
|
||||||
|
@ -2,7 +2,11 @@ package org.bitcoins.crypto
|
|||||||
|
|
||||||
import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3}
|
import org.bitcoins.core.config.{MainNet, RegTest, SigNet, TestNet3}
|
||||||
import org.bitcoins.core.crypto.ECPrivateKeyUtil
|
import org.bitcoins.core.crypto.ECPrivateKeyUtil
|
||||||
import org.bitcoins.testkit.core.gen.{ChainParamsGenerator, CryptoGenerators}
|
import org.bitcoins.testkit.core.gen.{
|
||||||
|
ChainParamsGenerator,
|
||||||
|
CryptoGenerators,
|
||||||
|
NumberGenerator
|
||||||
|
}
|
||||||
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
import org.bitcoins.testkit.util.BitcoinSUnitTest
|
||||||
|
|
||||||
class ECPrivateKeyTest extends BitcoinSUnitTest {
|
class ECPrivateKeyTest extends BitcoinSUnitTest {
|
||||||
@ -117,4 +121,20 @@ class ECPrivateKeyTest extends BitcoinSUnitTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it must "correctly execute the ecdsa single signer adaptor signature protocol" in {
|
||||||
|
forAll(CryptoGenerators.privateKey,
|
||||||
|
CryptoGenerators.privateKey,
|
||||||
|
NumberGenerator.bytevector(32)) {
|
||||||
|
case (privKey, adaptorSecret, msg) =>
|
||||||
|
val adaptorSig = privKey.adaptorSign(adaptorSecret.publicKey, msg)
|
||||||
|
assert(
|
||||||
|
privKey.publicKey
|
||||||
|
.adaptorVerify(msg, adaptorSecret.publicKey, adaptorSig))
|
||||||
|
val sig = adaptorSecret.completeAdaptorSignature(adaptorSig)
|
||||||
|
val secret =
|
||||||
|
adaptorSecret.publicKey.extractAdaptorSecret(adaptorSig, sig)
|
||||||
|
assert(secret == adaptorSecret)
|
||||||
|
assert(privKey.publicKey.verify(msg, sig))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,11 @@ object BouncyCastleUtil {
|
|||||||
.getOrElse(false)
|
.getOrElse(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def pubKeyTweakMul(pubKey: ECPublicKey, tweak: FieldElement): ECPublicKey = {
|
||||||
|
val tweakedPoint = pubKey.toPoint.multiply(tweak.toBigInteger)
|
||||||
|
ECPublicKey.fromPoint(tweakedPoint, pubKey.isCompressed)
|
||||||
|
}
|
||||||
|
|
||||||
def decompressPublicKey(publicKey: ECPublicKey): ECPublicKey = {
|
def decompressPublicKey(publicKey: ECPublicKey): ECPublicKey = {
|
||||||
if (publicKey.isCompressed) {
|
if (publicKey.isCompressed) {
|
||||||
val point = decodePoint(publicKey.bytes)
|
val point = decodePoint(publicKey.bytes)
|
||||||
@ -215,3 +220,224 @@ object BouncyCastleUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object AdaptorStuff {
|
||||||
|
import ECAdaptorSignature.{deserializePoint, serializePoint}
|
||||||
|
|
||||||
|
// Compute s' = k^-1 * (dataToSign + rx*privateKey)
|
||||||
|
private def adaptorSignHelper(
|
||||||
|
dataToSign: ByteVector,
|
||||||
|
k: FieldElement,
|
||||||
|
r: ECPublicKey,
|
||||||
|
privateKey: ECPrivateKey): FieldElement = {
|
||||||
|
val rx = FieldElement(r.toPoint.getXCoord.toBigInteger)
|
||||||
|
val x = privateKey.fieldElement
|
||||||
|
val m = FieldElement(dataToSign)
|
||||||
|
val kInv = k.inverse
|
||||||
|
|
||||||
|
rx.multiply(x).add(m).multiply(kInv)
|
||||||
|
}
|
||||||
|
|
||||||
|
def adaptorSign(
|
||||||
|
privateKey: ECPrivateKey,
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
dataToSign: ByteVector): ECAdaptorSignature = {
|
||||||
|
// Include dataToSign and adaptor in nonce derivation
|
||||||
|
val hash = CryptoUtil.sha256(dataToSign ++ serializePoint(adaptorPoint))
|
||||||
|
val k = DLEQStuff.dleqNonceFunc(hash.bytes,
|
||||||
|
privateKey.fieldElement,
|
||||||
|
"ECDSAAdaptorNon")
|
||||||
|
|
||||||
|
if (k.isZero) {
|
||||||
|
throw new RuntimeException("Nonce cannot be zero.")
|
||||||
|
}
|
||||||
|
|
||||||
|
val untweakedNonce = k.getPublicKey // k*G
|
||||||
|
val tweakedNonce = adaptorPoint.tweakMultiply(k) // k*Y
|
||||||
|
|
||||||
|
// DLEQ_prove((G,R'),(Y, R))
|
||||||
|
val (proofS, proofE) =
|
||||||
|
DLEQStuff.dleqProve(k, adaptorPoint, "ECDSAAdaptorSig")
|
||||||
|
|
||||||
|
// s' = k^-1*(m + rx*x)
|
||||||
|
val adaptedSig = adaptorSignHelper(dataToSign, k, tweakedNonce, privateKey)
|
||||||
|
|
||||||
|
ECAdaptorSignature(tweakedNonce, adaptedSig, untweakedNonce, proofS, proofE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute R'x = s^-1 * (msg*G + rx*pubKey) = s^-1 * (msg + rx*privKey) * G
|
||||||
|
private def adaptorVerifyHelper(
|
||||||
|
rx: FieldElement,
|
||||||
|
s: FieldElement,
|
||||||
|
pubKey: ECPublicKey,
|
||||||
|
msg: ByteVector): FieldElement = {
|
||||||
|
val m = FieldElement(msg)
|
||||||
|
val untweakedPoint =
|
||||||
|
m.getPublicKey.add(pubKey.tweakMultiply(rx)).tweakMultiply(s.inverse)
|
||||||
|
|
||||||
|
FieldElement(untweakedPoint.bytes.tail)
|
||||||
|
}
|
||||||
|
|
||||||
|
def adaptorVerify(
|
||||||
|
adaptorSig: ECAdaptorSignature,
|
||||||
|
pubKey: ECPublicKey,
|
||||||
|
data: ByteVector,
|
||||||
|
adaptor: ECPublicKey): Boolean = {
|
||||||
|
val untweakedNonce = deserializePoint(adaptorSig.dleqProof.take(33))
|
||||||
|
val proofS = FieldElement(adaptorSig.dleqProof.drop(33).take(32))
|
||||||
|
val proofR = FieldElement(adaptorSig.dleqProof.drop(65))
|
||||||
|
|
||||||
|
val tweakedNonce = deserializePoint(adaptorSig.adaptedSig.take(33))
|
||||||
|
val adaptedSig = FieldElement(adaptorSig.adaptedSig.drop(33))
|
||||||
|
|
||||||
|
val validProof = DLEQStuff.dleqVerify(
|
||||||
|
"ECDSAAdaptorSig",
|
||||||
|
proofS,
|
||||||
|
proofR,
|
||||||
|
untweakedNonce,
|
||||||
|
adaptor,
|
||||||
|
tweakedNonce
|
||||||
|
)
|
||||||
|
|
||||||
|
if (validProof) {
|
||||||
|
val tweakedNoncex = FieldElement(tweakedNonce.bytes.tail)
|
||||||
|
val untweakedNoncex = FieldElement(untweakedNonce.bytes.tail)
|
||||||
|
|
||||||
|
if (tweakedNoncex.isZero || untweakedNoncex.isZero) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
|
||||||
|
val untweakedRx =
|
||||||
|
adaptorVerifyHelper(tweakedNoncex, adaptedSig, pubKey, data)
|
||||||
|
|
||||||
|
untweakedRx == untweakedNoncex
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def adaptorComplete(
|
||||||
|
adaptorSecret: ECPrivateKey,
|
||||||
|
adaptedSig: ByteVector): ECDigitalSignature = {
|
||||||
|
val tweakedNonce: ECPublicKey =
|
||||||
|
ECAdaptorSignature.deserializePoint(adaptedSig.take(33))
|
||||||
|
val rx = FieldElement(tweakedNonce.bytes.tail)
|
||||||
|
val adaptedS: FieldElement = FieldElement(adaptedSig.drop(33))
|
||||||
|
val correctedS = adaptedS.multInv(adaptorSecret.fieldElement)
|
||||||
|
|
||||||
|
val sig = ECDigitalSignature.fromRS(BigInt(rx.toBigInteger),
|
||||||
|
BigInt(correctedS.toBigInteger))
|
||||||
|
DERSignatureUtil.lowS(sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
def extractAdaptorSecret(
|
||||||
|
sig: ECDigitalSignature,
|
||||||
|
adaptorSig: ECAdaptorSignature,
|
||||||
|
adaptor: ECPublicKey): ECPrivateKey = {
|
||||||
|
val secretOrNeg = adaptorSig.adaptedS.multInv(FieldElement(sig.s))
|
||||||
|
if (secretOrNeg.getPublicKey == adaptor) {
|
||||||
|
secretOrNeg.toPrivateKey
|
||||||
|
} else {
|
||||||
|
secretOrNeg.negate.toPrivateKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object DLEQStuff {
|
||||||
|
import ECAdaptorSignature.serializePoint
|
||||||
|
|
||||||
|
def dleqPair(
|
||||||
|
fe: FieldElement,
|
||||||
|
adaptorPoint: ECPublicKey): (ECPublicKey, ECPublicKey) = {
|
||||||
|
val point = fe.getPublicKey
|
||||||
|
val tweakedPoint = adaptorPoint.tweakMultiply(fe)
|
||||||
|
|
||||||
|
(point, tweakedPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
def dleqNonceFunc(
|
||||||
|
hash: ByteVector,
|
||||||
|
fe: FieldElement,
|
||||||
|
algoName: String): FieldElement = {
|
||||||
|
val kBytes =
|
||||||
|
CryptoUtil.taggedSha256(fe.bytes ++ hash, algoName).bytes
|
||||||
|
FieldElement(kBytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
def dleqChallengeHash(
|
||||||
|
algoName: String,
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
r1: ECPublicKey,
|
||||||
|
r2: ECPublicKey,
|
||||||
|
p1: ECPublicKey,
|
||||||
|
p2: ECPublicKey): ByteVector = {
|
||||||
|
CryptoUtil
|
||||||
|
.taggedSha256(
|
||||||
|
serializePoint(adaptorPoint) ++ serializePoint(r1) ++ serializePoint(
|
||||||
|
r2) ++ serializePoint(p1) ++ serializePoint(p2),
|
||||||
|
algoName)
|
||||||
|
.bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Proves that the DLOG_G(R') = DLOG_Y(R) (= fe)
|
||||||
|
* For a full description, see https://cs.nyu.edu/courses/spring07/G22.3220-001/lec3.pdf
|
||||||
|
*/
|
||||||
|
def dleqProve(
|
||||||
|
fe: FieldElement,
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
algoName: String): (FieldElement, FieldElement) = {
|
||||||
|
// (fe*G, fe*Y)
|
||||||
|
val (p1, p2) = dleqPair(fe, adaptorPoint)
|
||||||
|
|
||||||
|
// hash(Y || fe*G || fe*Y)
|
||||||
|
val hash =
|
||||||
|
CryptoUtil
|
||||||
|
.sha256(
|
||||||
|
serializePoint(adaptorPoint) ++ serializePoint(p1) ++ serializePoint(
|
||||||
|
p2))
|
||||||
|
.bytes
|
||||||
|
val k = dleqNonceFunc(hash, fe, algoName)
|
||||||
|
|
||||||
|
if (k.isZero) {
|
||||||
|
throw new RuntimeException("Nonce cannot be zero.")
|
||||||
|
}
|
||||||
|
|
||||||
|
val r1 = k.getPublicKey
|
||||||
|
val r2 = adaptorPoint.tweakMultiply(k)
|
||||||
|
|
||||||
|
// Hash all components to get a challenge (this is the trick that turns
|
||||||
|
// interactive ZKPs into non-interactive ZKPs, using hash assumptions)
|
||||||
|
//
|
||||||
|
// In short, rather than having the verifier present challenges, hash
|
||||||
|
// all shared information (so that both parties can compute) and use
|
||||||
|
// this hash as the challenge to the prover as loosely speaking this
|
||||||
|
// should only be game-able if the prover can reverse hash functions.
|
||||||
|
val challengeHash =
|
||||||
|
dleqChallengeHash(algoName, adaptorPoint, r1, r2, p1, p2)
|
||||||
|
val e = FieldElement(challengeHash)
|
||||||
|
|
||||||
|
// s = k + fe*challenge. This proof works because then k = fe*challenge - s
|
||||||
|
// so that R' = k*G =?= p1*challenge - s and R = k*Y =?= p2*challenge - s
|
||||||
|
// can both be verified given s and challenge and will be true if and only
|
||||||
|
// if R = y*R' which is what we are trying to prove.
|
||||||
|
val s = fe.multiply(e).add(k)
|
||||||
|
|
||||||
|
(s, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Verifies a proof that the DLOG_G of P1 equals the DLOG_adaptor of P2 */
|
||||||
|
def dleqVerify(
|
||||||
|
algoName: String,
|
||||||
|
s: FieldElement,
|
||||||
|
e: FieldElement,
|
||||||
|
p1: ECPublicKey,
|
||||||
|
adaptor: ECPublicKey,
|
||||||
|
p2: ECPublicKey): Boolean = {
|
||||||
|
val r1 = p1.tweakMultiply(e.negate).add(s.getPublicKey)
|
||||||
|
val r2 = p2.tweakMultiply(e.negate).add(adaptor.tweakMultiply(s))
|
||||||
|
val challengeHash = dleqChallengeHash(algoName, adaptor, r1, r2, p1, p2)
|
||||||
|
|
||||||
|
challengeHash == e.bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
package org.bitcoins.crypto
|
||||||
|
|
||||||
|
import scodec.bits.ByteVector
|
||||||
|
|
||||||
|
case class ECAdaptorSignature(bytes: ByteVector) extends NetworkElement {
|
||||||
|
require(
|
||||||
|
bytes.length == 162,
|
||||||
|
s"Adaptor signature must have 65 byte sig and 97 byte dleq proof, got $bytes")
|
||||||
|
|
||||||
|
val (adaptedSig: ByteVector, dleqProof: ByteVector) = bytes.splitAt(65)
|
||||||
|
|
||||||
|
val tweakedNonce: ECPublicKey =
|
||||||
|
ECAdaptorSignature.deserializePoint(adaptedSig.take(33))
|
||||||
|
val adaptedS: FieldElement = FieldElement(adaptedSig.drop(33))
|
||||||
|
|
||||||
|
require(!adaptedS.isZero, "Adapted signature cannot be zero.")
|
||||||
|
|
||||||
|
val untweakedNonce: ECPublicKey =
|
||||||
|
ECAdaptorSignature.deserializePoint(dleqProof.take(33))
|
||||||
|
val dleqProofS: FieldElement = FieldElement(dleqProof.drop(33).take(32))
|
||||||
|
val dleqProofE: FieldElement = FieldElement(dleqProof.drop(65))
|
||||||
|
|
||||||
|
require(ECPublicKey.isFullyValidWithBouncyCastle(tweakedNonce.bytes),
|
||||||
|
s"Tweaked nonce (R) must be a valid public key: $tweakedNonce")
|
||||||
|
require(ECPublicKey.isFullyValidWithBouncyCastle(untweakedNonce.bytes),
|
||||||
|
s"Untweaked nonce (R') must be a valid public key: $untweakedNonce")
|
||||||
|
}
|
||||||
|
|
||||||
|
object ECAdaptorSignature extends Factory[ECAdaptorSignature] {
|
||||||
|
|
||||||
|
def fromBytes(bytes: ByteVector): ECAdaptorSignature = {
|
||||||
|
new ECAdaptorSignature(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
def apply(
|
||||||
|
tweakedNonce: ECPublicKey,
|
||||||
|
adaptedS: FieldElement,
|
||||||
|
untweakedNonce: ECPublicKey,
|
||||||
|
dleqProofS: FieldElement,
|
||||||
|
dleqProofE: FieldElement): ECAdaptorSignature = {
|
||||||
|
fromBytes(
|
||||||
|
serializePoint(tweakedNonce) ++ adaptedS.bytes ++ serializePoint(
|
||||||
|
untweakedNonce) ++ dleqProofS.bytes ++ dleqProofE.bytes
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
def empty(): ECAdaptorSignature =
|
||||||
|
fromBytes(ByteVector.fill(162)(0.toByte))
|
||||||
|
|
||||||
|
def serializePoint(point: ECPublicKey): ByteVector = {
|
||||||
|
val (sign, xCoor) = point.bytes.splitAt(1)
|
||||||
|
sign.map(b => (b & 0x01).toByte) ++ xCoor
|
||||||
|
}
|
||||||
|
|
||||||
|
def deserializePoint(point: ByteVector): ECPublicKey = {
|
||||||
|
val (sign, xCoor) = point.splitAt(1)
|
||||||
|
ECPublicKey(sign.map(b => (b | 0x02).toByte) ++ xCoor)
|
||||||
|
}
|
||||||
|
}
|
@ -167,6 +167,58 @@ sealed abstract class ECPrivateKey
|
|||||||
BouncyCastleUtil.schnorrSignWithNonce(dataToSign, this, nonce)
|
BouncyCastleUtil.schnorrSignWithNonce(dataToSign, this, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: match on CryptoContext once secp version is added
|
||||||
|
def adaptorSign(
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
msg: ByteVector): ECAdaptorSignature = {
|
||||||
|
adaptorSignWithBouncyCastle(adaptorPoint, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
def adaptorSignWithSecp(
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
msg: ByteVector): ECAdaptorSignature = {
|
||||||
|
val sigWithProof = NativeSecp256k1.adaptorSign(bytes.toArray,
|
||||||
|
adaptorPoint.bytes.toArray,
|
||||||
|
msg.toArray)
|
||||||
|
ECAdaptorSignature(ByteVector(sigWithProof))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
def adaptorSignWithBouncyCastle(
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
msg: ByteVector): ECAdaptorSignature = {
|
||||||
|
AdaptorStuff.adaptorSign(this, adaptorPoint, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: match on CryptoContext once secp version is added
|
||||||
|
def completeAdaptorSignature(
|
||||||
|
adaptorSignature: ECAdaptorSignature): ECDigitalSignature = {
|
||||||
|
completeAdaptorSignatureWithBouncyCastle(adaptorSignature)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
def completeAdaptorSignatureWithSecp(
|
||||||
|
adaptorSignature: ECAdaptorSignature): ECDigitalSignature = {
|
||||||
|
val sigBytes = NativeSecp256k1.adaptorAdapt(
|
||||||
|
bytes.toArray,
|
||||||
|
adaptorSignature.adaptedSig.toArray)
|
||||||
|
ECDigitalSignature.fromBytes(ByteVector(sigBytes))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
def completeAdaptorSignatureWithBouncyCastle(
|
||||||
|
adaptorSignature: ECAdaptorSignature): ECDigitalSignature = {
|
||||||
|
AdaptorStuff.adaptorComplete(this, adaptorSignature.adaptedSig)
|
||||||
|
}
|
||||||
|
|
||||||
|
def completeAdaptorSignature(
|
||||||
|
adaptorSignature: ECAdaptorSignature,
|
||||||
|
hashTypeByte: Byte): ECDigitalSignature = {
|
||||||
|
val completedSig = completeAdaptorSignature(adaptorSignature)
|
||||||
|
ECDigitalSignature(completedSig.bytes ++ ByteVector.fromByte(hashTypeByte))
|
||||||
|
}
|
||||||
|
|
||||||
def nonceKey: ECPrivateKey = {
|
def nonceKey: ECPrivateKey = {
|
||||||
if (schnorrNonce.publicKey == publicKey) {
|
if (schnorrNonce.publicKey == publicKey) {
|
||||||
this
|
this
|
||||||
@ -394,6 +446,60 @@ sealed abstract class ECPublicKey extends BaseECKey {
|
|||||||
|
|
||||||
def schnorrNonce: SchnorrNonce = SchnorrNonce(bytes)
|
def schnorrNonce: SchnorrNonce = SchnorrNonce(bytes)
|
||||||
|
|
||||||
|
// TODO: match on CryptoContext once secp version is added
|
||||||
|
def adaptorVerify(
|
||||||
|
msg: ByteVector,
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
adaptorSignature: ECAdaptorSignature): Boolean = {
|
||||||
|
adaptorVerifyWithBouncyCastle(msg, adaptorPoint, adaptorSignature)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
def adaptorVerifyWithSecp(
|
||||||
|
msg: ByteVector,
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
adaptorSignature: ECAdaptorSignature): Boolean = {
|
||||||
|
NativeSecp256k1.adaptorVerify(adaptorSignature.adaptedSig.toArray,
|
||||||
|
bytes.toArray,
|
||||||
|
msg.toArray,
|
||||||
|
adaptorPoint.bytes.toArray,
|
||||||
|
adaptorSignature.dleqProof.toArray)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
def adaptorVerifyWithBouncyCastle(
|
||||||
|
msg: ByteVector,
|
||||||
|
adaptorPoint: ECPublicKey,
|
||||||
|
adaptorSignature: ECAdaptorSignature): Boolean = {
|
||||||
|
AdaptorStuff.adaptorVerify(adaptorSignature, this, msg, adaptorPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: match on CryptoContext once secp version is added
|
||||||
|
def extractAdaptorSecret(
|
||||||
|
adaptorSignature: ECAdaptorSignature,
|
||||||
|
signature: ECDigitalSignature): ECPrivateKey = {
|
||||||
|
extractAdaptorSecretWithBouncyCastle(adaptorSignature, signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
def extractAdaptorSecretWithSecp(
|
||||||
|
adaptorSignature: ECAdaptorSignature,
|
||||||
|
signature: ECDigitalSignature): ECPrivateKey = {
|
||||||
|
val secretBytes = NativeSecp256k1.adaptorExtractSecret(
|
||||||
|
signature.bytes.toArray,
|
||||||
|
adaptorSignature.adaptedSig.toArray,
|
||||||
|
bytes.toArray)
|
||||||
|
|
||||||
|
ECPrivateKey(ByteVector(secretBytes))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
def extractAdaptorSecretWithBouncyCastle(
|
||||||
|
adaptorSignature: ECAdaptorSignature,
|
||||||
|
signature: ECDigitalSignature): ECPrivateKey = {
|
||||||
|
AdaptorStuff.extractAdaptorSecret(signature, adaptorSignature, this)
|
||||||
|
}
|
||||||
|
|
||||||
override def toString: String = "ECPublicKey(" + hex + ")"
|
override def toString: String = "ECPublicKey(" + hex + ")"
|
||||||
|
|
||||||
/** Checks if the [[org.bitcoins.crypto.ECPublicKey ECPublicKey]] is compressed */
|
/** Checks if the [[org.bitcoins.crypto.ECPublicKey ECPublicKey]] is compressed */
|
||||||
|
@ -12,6 +12,7 @@ import org.bitcoins.crypto.{
|
|||||||
AesPassword,
|
AesPassword,
|
||||||
CryptoUtil,
|
CryptoUtil,
|
||||||
DoubleSha256Digest,
|
DoubleSha256Digest,
|
||||||
|
ECAdaptorSignature,
|
||||||
ECDigitalSignature,
|
ECDigitalSignature,
|
||||||
ECPrivateKey,
|
ECPrivateKey,
|
||||||
ECPublicKey,
|
ECPublicKey,
|
||||||
@ -228,6 +229,18 @@ sealed abstract class CryptoGenerators {
|
|||||||
} yield privKey.schnorrSign(hash.bytes)
|
} yield privKey.schnorrSign(hash.bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def adaptorSignature: Gen[ECAdaptorSignature] = {
|
||||||
|
for {
|
||||||
|
tweakedNonce <- publicKey
|
||||||
|
untweakedNonce <- publicKey
|
||||||
|
adaptedS <- fieldElement
|
||||||
|
proofS <- fieldElement
|
||||||
|
proofE <- fieldElement
|
||||||
|
} yield {
|
||||||
|
ECAdaptorSignature(tweakedNonce, adaptedS, untweakedNonce, proofS, proofE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def sha256Digest: Gen[Sha256Digest] =
|
def sha256Digest: Gen[Sha256Digest] =
|
||||||
for {
|
for {
|
||||||
bytes <- NumberGenerator.bytevector
|
bytes <- NumberGenerator.bytevector
|
||||||
|
Loading…
Reference in New Issue
Block a user