Add OrderedSchnorrSignatures, use it in OracleAttestment (#4803)

* Add OrderedSchnorrSignatures, use it in OracleAttestment, propagate it threw the codebase

* Small cleanups

* Add SortedVecFactory

* Fix test case with out of order nonces
This commit is contained in:
Chris Stewart 2022-09-26 19:35:04 -05:00 committed by GitHub
parent a1fad6bcc4
commit 9c506b639f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 394 additions and 204 deletions

View file

@ -29,6 +29,7 @@ import org.bitcoins.core.protocol.{
import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature
import org.bitcoins.core.psbt.PSBT import org.bitcoins.core.psbt.PSBT
import org.bitcoins.core.util.FutureUtil import org.bitcoins.core.util.FutureUtil
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.core.wallet.fee.{FeeUnit, SatoshisPerVirtualByte} import org.bitcoins.core.wallet.fee.{FeeUnit, SatoshisPerVirtualByte}
import org.bitcoins.core.wallet.rescan.RescanState import org.bitcoins.core.wallet.rescan.RescanState
import org.bitcoins.core.wallet.utxo._ import org.bitcoins.core.wallet.utxo._
@ -935,7 +936,7 @@ class RoutesSpec extends AnyWordSpec with ScalatestRouteTest with MockFactory {
val dummyOracleAttestment = val dummyOracleAttestment =
OracleAttestmentV0TLV("eventId", OracleAttestmentV0TLV("eventId",
dummyPubKey.schnorrPublicKey, dummyPubKey.schnorrPublicKey,
Vector(dummyOracleSig), OrderedSchnorrSignatures(dummyOracleSig),
Vector("outcome")) Vector("outcome"))
lazy val winStr: String = "WIN" lazy val winStr: String = "WIN"

View file

@ -522,7 +522,7 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] {
val fields = Vector( val fields = Vector(
"tpe" -> Element(OracleEventV0TLV.tpe), "tpe" -> Element(OracleEventV0TLV.tpe),
"length" -> Element(tlv.length), "length" -> Element(tlv.length),
"oracleNonces" -> MultiElement(nonces.vec.map(Element(_))), "oracleNonces" -> MultiElement(nonces.toVector.map(Element(_))),
"eventMaturityEpoch" -> Element(eventMaturity), "eventMaturityEpoch" -> Element(eventMaturity),
"eventDescriptor" -> Element(descriptor), "eventDescriptor" -> Element(descriptor),
"event_uri" -> Element(CryptoUtil.serializeForHash(uri)) "event_uri" -> Element(CryptoUtil.serializeForHash(uri))
@ -545,7 +545,7 @@ object DLCParsingTestVector extends TestVectorParser[DLCParsingTestVector] {
"length" -> Element(tlv.length), "length" -> Element(tlv.length),
"eventId" -> Element(eventId), "eventId" -> Element(eventId),
"oraclePubKey" -> Element(pubkey), "oraclePubKey" -> Element(pubkey),
"signatures" -> MultiElement(sigs.map(Element(_))), "signatures" -> MultiElement(sigs.toVector.map(Element(_))),
"outcomes" -> MultiElement(outcomes.map(Element(_))) "outcomes" -> MultiElement(outcomes.map(Element(_)))
) )

View file

@ -7,7 +7,7 @@ import org.bitcoins.core.protocol.tlv.{
EnumOutcome, EnumOutcome,
OracleAnnouncementV0TLV OracleAnnouncementV0TLV
} }
import org.bitcoins.core.util.sorted.OrderedAnnouncements import org.bitcoins.core.util.sorted.{OrderedAnnouncements, OrderedNonces}
import org.bitcoins.crypto.ECPrivateKey import org.bitcoins.crypto.ECPrivateKey
import org.bitcoins.testkitcore.util.BitcoinSUnitTest import org.bitcoins.testkitcore.util.BitcoinSUnitTest
@ -67,10 +67,12 @@ class ContractOraclePairTest extends BitcoinSUnitTest {
) )
def numericOracleInfo(numDigits: Int): NumericSingleOracleInfo = { def numericOracleInfo(numDigits: Int): NumericSingleOracleInfo = {
val unsorted =
Vector.fill(numDigits)(ECPrivateKey.freshPrivateKey.schnorrNonce)
val sorted = OrderedNonces.fromUnsorted(unsorted)
NumericSingleOracleInfo( NumericSingleOracleInfo(
OracleAnnouncementV0TLV.dummyForKeys( OracleAnnouncementV0TLV.dummyForKeys(ECPrivateKey.freshPrivateKey,
ECPrivateKey.freshPrivateKey, sorted))
Vector.fill(numDigits)(ECPrivateKey.freshPrivateKey.schnorrNonce)))
} }
val oracleInfo1 = numericOracleInfo(1) val oracleInfo1 = numericOracleInfo(1)

View file

@ -0,0 +1,30 @@
package org.bitcoins.core.util
import org.bitcoins.core.util.sorted.OrderedNonces
import org.bitcoins.crypto.SchnorrNonce
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class OrderedNoncesTest extends BitcoinSUnitTest {
behavior of "OrderedNonces"
val unsorted = Vector(
SchnorrNonce(
"c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea"),
SchnorrNonce(
"92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc")
)
it must "throw an exception if you create an unordered nonces" in {
intercept[IllegalArgumentException] {
OrderedNonces(unsorted)
}
}
it must "sort nonces with OrderedNonces.fromUnsorted" in {
val sorted = OrderedNonces.fromUnsorted(unsorted)
assert(sorted.toVector != unsorted)
assert(sorted.toVector == Vector(unsorted(1), unsorted(0)))
}
}

View file

@ -0,0 +1,33 @@
package org.bitcoins.core.util
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.crypto.{FieldElement, SchnorrDigitalSignature, SchnorrNonce}
import org.bitcoins.testkitcore.util.BitcoinSUnitTest
class OrderedSchnorrSignaturesTest extends BitcoinSUnitTest {
behavior of "OrderedSchnorrSignatures"
val unsorted = Vector(
SchnorrDigitalSignature(
SchnorrNonce(
"c4b89873c8753de3f0a9e94c4a6190badaa983513a6624a3469eb4577904bfea"),
FieldElement.one),
SchnorrDigitalSignature(
SchnorrNonce(
"92efe81609c773d97da2b084eb691f48ef5e926acc6eecd629f80fb1184711bc"),
FieldElement.one)
)
it must "throw an exception if the signatures are out of order" in {
intercept[IllegalArgumentException] {
OrderedSchnorrSignatures(unsorted)
}
}
it must "sort the signatures" in {
val sorted = OrderedSchnorrSignatures.fromUnsorted(unsorted)
assert(sorted.toVector != unsorted)
assert(sorted.toVector == Vector(unsorted(1), unsorted(0)))
}
}

View file

@ -5,7 +5,7 @@ import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.dlc.compute.SigningVersion import org.bitcoins.core.protocol.dlc.compute.SigningVersion
import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.util.NumberUtil import org.bitcoins.core.util.NumberUtil
import org.bitcoins.core.util.sorted.OrderedNonces import org.bitcoins.core.util.sorted.{OrderedNonces, OrderedSchnorrSignatures}
import org.bitcoins.crypto._ import org.bitcoins.crypto._
import java.time.Instant import java.time.Instant
@ -60,10 +60,12 @@ sealed trait CompletedOracleEvent extends OracleEvent {
require(attestations.size == nonces.size, require(attestations.size == nonces.size,
"Must have a signature for every nonce") "Must have a signature for every nonce")
def signatures: Vector[SchnorrDigitalSignature] = def signatures: OrderedSchnorrSignatures = {
nonces.vec val unsorted = nonces.toVector
.zip(attestations) .zip(attestations)
.map(sigPieces => SchnorrDigitalSignature(sigPieces._1, sigPieces._2)) .map(sigPieces => SchnorrDigitalSignature(sigPieces._1, sigPieces._2))
OrderedSchnorrSignatures.fromUnsorted(unsorted)
}
def oracleAttestmentV0TLV: OracleAttestmentV0TLV = def oracleAttestmentV0TLV: OracleAttestmentV0TLV =
OracleAttestmentV0TLV(eventName, OracleAttestmentV0TLV(eventName,
@ -231,7 +233,7 @@ object OracleEvent {
CompletedDigitDecompositionV0OracleEvent( CompletedDigitDecompositionV0OracleEvent(
eventDb.pubkey, eventDb.pubkey,
OrderedNonces(sortedEventDbs.map(_.nonce)), OrderedNonces.fromUnsorted(sortedEventDbs.map(_.nonce)),
eventDb.eventName, eventDb.eventName,
eventDb.signingVersion, eventDb.signingVersion,
eventDb.maturationTime, eventDb.maturationTime,
@ -248,7 +250,7 @@ object OracleEvent {
PendingDigitDecompositionV0OracleEvent( PendingDigitDecompositionV0OracleEvent(
eventDb.pubkey, eventDb.pubkey,
OrderedNonces(sortedEventDbs.map(_.nonce)), OrderedNonces.fromUnsorted(sortedEventDbs.map(_.nonce)),
eventDb.eventName, eventDb.eventName,
eventDb.signingVersion, eventDb.signingVersion,
eventDb.maturationTime, eventDb.maturationTime,

View file

@ -5,10 +5,14 @@ import org.bitcoins.core.protocol.transaction.{
TransactionOutput TransactionOutput
} }
import org.bitcoins.core.wallet.fee.SatoshisPerKiloByte import org.bitcoins.core.wallet.fee.SatoshisPerKiloByte
import org.bitcoins.crypto.{
CryptoOrdering,
SchnorrDigitalSignature,
SchnorrNonce
}
import scodec.bits._ import scodec.bits._
import java.math.BigInteger import java.math.BigInteger
import scala.annotation.tailrec
import scala.math.Ordering import scala.math.Ordering
package object core { package object core {
@ -54,23 +58,7 @@ package object core {
} }
implicit val byteVectorOrdering: Ordering[ByteVector] = implicit val byteVectorOrdering: Ordering[ByteVector] =
new Ordering[ByteVector] { CryptoOrdering.byteVectorOrdering
@tailrec
override def compare(x: ByteVector, y: ByteVector): Int = {
if (x == y) {
0
} else if (x.isEmpty) {
-1
} else if (y.isEmpty) {
1
} else if (x.head != y.head) {
x.head.compare(y.head)
} else {
compare(x.tail, y.tail)
}
}
}
implicit val transactionInputOrder: Ordering[TransactionInput] = implicit val transactionInputOrder: Ordering[TransactionInput] =
new Ordering[TransactionInput] { new Ordering[TransactionInput] {
@ -87,4 +75,17 @@ package object core {
x.scriptPubKey.hex.compare(y.scriptPubKey.hex) x.scriptPubKey.hex.compare(y.scriptPubKey.hex)
} else x.value.compare(y.value) } else x.value.compare(y.value)
} }
implicit val nonceOrdering: Ordering[SchnorrNonce] =
CryptoOrdering.nonceOrdering
implicit val schnorrSignatureOrdering: Ordering[SchnorrDigitalSignature] = {
new Ordering[SchnorrDigitalSignature] {
override def compare(
x: SchnorrDigitalSignature,
y: SchnorrDigitalSignature): Int = {
nonceOrdering.compare(x.rx, y.rx)
}
}
}
} }

View file

@ -137,7 +137,7 @@ object DLCAdaptorPointComputer {
contractInfo.oracleInfo.singleOracleInfos.map { info => contractInfo.oracleInfo.singleOracleInfos.map { info =>
val announcement = info.announcement val announcement = info.announcement
val pubKey = announcement.publicKey val pubKey = announcement.publicKey
val nonces = announcement.eventTLV.nonces.vec.map(_.publicKey) val nonces = announcement.eventTLV.nonces.toVector.map(_.publicKey)
nonces.map { nonce => nonces.map { nonce =>
possibleOutcomes.map { outcome => possibleOutcomes.map { outcome =>

View file

@ -19,7 +19,7 @@ import org.bitcoins.core.protocol.tlv.{
OracleAttestmentTLV OracleAttestmentTLV
} }
import org.bitcoins.core.protocol.transaction.{Transaction, WitnessTransaction} import org.bitcoins.core.protocol.transaction.{Transaction, WitnessTransaction}
import org.bitcoins.core.util.sorted.OrderedAnnouncements import org.bitcoins.core.util.sorted.{OrderedAnnouncements, OrderedNonces}
import org.bitcoins.crypto._ import org.bitcoins.crypto._
import scodec.bits.ByteVector import scodec.bits.ByteVector
@ -263,11 +263,14 @@ object DLCUtil {
val announcementNonces: Vector[Vector[SchnorrNonce]] = { val announcementNonces: Vector[Vector[SchnorrNonce]] = {
announcements announcements
.map(_.eventTLV.nonces) .map(_.eventTLV.nonces)
.map(_.vec) .map(_.toVector)
} }
val resultOpt = oracleSignatures.find { case oracleSignature => val resultOpt = oracleSignatures.find { case oracleSignature =>
val oracleSigNonces: Vector[SchnorrNonce] = oracleSignature.sigs.map(_.rx) val oracleSigNonces: Vector[SchnorrNonce] = {
announcementNonces.contains(oracleSigNonces) val unsorted = oracleSignature.sigs.map(_.rx).toVector
OrderedNonces.fromUnsorted(unsorted).toVector
}
announcementNonces.exists(_ == oracleSigNonces)
} }
resultOpt resultOpt
} }

View file

@ -138,7 +138,9 @@ object DLCExecutor {
): ExecutedDLCOutcome = { ): ExecutedDLCOutcome = {
require( require(
DLCUtil.checkOracleSignaturesAgainstContract(contractInfo, oracleSigs), DLCUtil.checkOracleSignaturesAgainstContract(contractInfo, oracleSigs),
s"Incorrect oracle signatures and contract combination") s"Incorrect oracle signatures and contract combination, got=${oracleSigs} contractInfo.announcement=${contractInfo.oracleInfos
.map(_.singleOracleInfos.map(_.announcement.eventTLV.nonces))}"
)
val sigOracles = oracleSigs.map(_.oracle) val sigOracles = oracleSigs.map(_.oracle)
val oracleInfoOpt = contractInfo.oracleInfos.find { oracleInfo => val oracleInfoOpt = contractInfo.oracleInfos.find { oracleInfo =>

View file

@ -78,7 +78,7 @@ sealed trait SingleOracleInfo
* This point is used for adaptor signing. * This point is used for adaptor signing.
*/ */
def sigPoint(outcome: DLCOutcomeType): ECPublicKey = { def sigPoint(outcome: DLCOutcomeType): ECPublicKey = {
publicKey.computeSigPoint(outcome.serialized, nonces.vec) publicKey.computeSigPoint(outcome.serialized, nonces.toVector)
} }
/** Computes the sum of all nonces used in a given outcome */ /** Computes the sum of all nonces used in a given outcome */
@ -214,7 +214,7 @@ object NumericSingleOracleInfo {
def dummyForKeys( def dummyForKeys(
privKey: ECPrivateKey, privKey: ECPrivateKey,
nonces: Vector[SchnorrNonce]): NumericSingleOracleInfo = { nonces: OrderedNonces): NumericSingleOracleInfo = {
NumericSingleOracleInfo( NumericSingleOracleInfo(
OracleAnnouncementV0TLV.dummyForKeys(privKey, nonces)) OracleAnnouncementV0TLV.dummyForKeys(privKey, nonces))
} }

View file

@ -3,18 +3,19 @@ package org.bitcoins.core.protocol.dlc.models
import org.bitcoins.core.protocol.dlc.compute.CETCalculator import org.bitcoins.core.protocol.dlc.compute.CETCalculator
import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.util.SeqWrapper import org.bitcoins.core.util.SeqWrapper
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.crypto.{CryptoUtil, ECPrivateKey, SchnorrDigitalSignature} import org.bitcoins.crypto.{CryptoUtil, ECPrivateKey, SchnorrDigitalSignature}
/** Corresponds to a set of SchnorrDigitalSignatures given by a single oracle. */ /** Corresponds to a set of SchnorrDigitalSignatures given by a single oracle. */
sealed trait OracleSignatures extends SeqWrapper[SchnorrDigitalSignature] { sealed trait OracleSignatures extends SeqWrapper[SchnorrDigitalSignature] {
/** This oracle's signatures */ /** This oracle's signatures */
def sigs: Vector[SchnorrDigitalSignature] def sigs: OrderedSchnorrSignatures
/** The SingleOracleInfo for the oracle whose signatures are stored here. */ /** The SingleOracleInfo for the oracle whose signatures are stored here. */
def oracle: SingleOracleInfo def oracle: SingleOracleInfo
override def wrapped: Vector[SchnorrDigitalSignature] = sigs override def wrapped: Vector[SchnorrDigitalSignature] = sigs.toVector
/** Verifies the signatures against a given outcome. */ /** Verifies the signatures against a given outcome. */
def verifySignatures(outcome: DLCOutcomeType): Boolean = { def verifySignatures(outcome: DLCOutcomeType): Boolean = {
@ -38,7 +39,7 @@ object OracleSignatures {
def apply( def apply(
oracle: SingleOracleInfo, oracle: SingleOracleInfo,
sigs: Vector[SchnorrDigitalSignature]): OracleSignatures = { sigs: OrderedSchnorrSignatures): OracleSignatures = {
oracle match { oracle match {
case info: EnumSingleOracleInfo => case info: EnumSingleOracleInfo =>
require(sigs.length == 1, s"Expected one signature, got $sigs") require(sigs.length == 1, s"Expected one signature, got $sigs")
@ -76,7 +77,7 @@ case class EnumOracleSignature(
oracle: EnumSingleOracleInfo, oracle: EnumSingleOracleInfo,
sig: SchnorrDigitalSignature) sig: SchnorrDigitalSignature)
extends OracleSignatures { extends OracleSignatures {
override def sigs: Vector[SchnorrDigitalSignature] = Vector(sig) override def sigs: OrderedSchnorrSignatures = OrderedSchnorrSignatures(sig)
lazy val getOutcome: EnumOutcome = { lazy val getOutcome: EnumOutcome = {
// cast is safe, EnumSingleOracleInfo enforces this // cast is safe, EnumSingleOracleInfo enforces this
@ -105,7 +106,7 @@ case class EnumOracleSignature(
/** Wraps a set of oracle signatures of numeric digits. */ /** Wraps a set of oracle signatures of numeric digits. */
case class NumericOracleSignatures( case class NumericOracleSignatures(
oracle: NumericSingleOracleInfo, oracle: NumericSingleOracleInfo,
sigs: Vector[SchnorrDigitalSignature]) sigs: OrderedSchnorrSignatures)
extends OracleSignatures { extends OracleSignatures {
lazy val getOutcome: UnsignedNumericOutcome = { lazy val getOutcome: UnsignedNumericOutcome = {
@ -127,7 +128,7 @@ case class NumericOracleSignatures(
.getOrElse(throw new IllegalArgumentException( .getOrElse(throw new IllegalArgumentException(
s"Signature $sig does not match any digit 0-${base - 1}")) s"Signature $sig does not match any digit 0-${base - 1}"))
} }
UnsignedNumericOutcome(digits) UnsignedNumericOutcome(digits.toVector)
} }
/** Computes the NumericOutcome to which these signatures correspond. */ /** Computes the NumericOutcome to which these signatures correspond. */

View file

@ -21,7 +21,11 @@ import org.bitcoins.core.protocol.tlv.TLV.{
import org.bitcoins.core.protocol.transaction._ import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.protocol.{BigSizeUInt, BlockTimeStamp} import org.bitcoins.core.protocol.{BigSizeUInt, BlockTimeStamp}
import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature
import org.bitcoins.core.util.sorted.{OrderedAnnouncements, OrderedNonces} import org.bitcoins.core.util.sorted.{
OrderedAnnouncements,
OrderedNonces,
OrderedSchnorrSignatures
}
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
import org.bitcoins.crypto._ import org.bitcoins.crypto._
import scodec.bits.ByteVector import scodec.bits.ByteVector
@ -775,14 +779,14 @@ case class OracleEventV0TLV(
) extends OracleEventTLV { ) extends OracleEventTLV {
require( require(
eventDescriptor.noncesNeeded == nonces.vec.size, eventDescriptor.noncesNeeded == nonces.toVector.size,
s"Not enough nonces for this event descriptor, noncesNeeded=${eventDescriptor.noncesNeeded} nonces=${nonces.toVector.size}" s"Not enough nonces for this event descriptor, noncesNeeded=${eventDescriptor.noncesNeeded} nonces=${nonces.toVector.size}"
) )
override def tpe: BigSizeUInt = OracleEventV0TLV.tpe override def tpe: BigSizeUInt = OracleEventV0TLV.tpe
override val value: ByteVector = { override val value: ByteVector = {
u16PrefixedList(nonces.vec) ++ u16PrefixedList(nonces.toVector) ++
eventMaturityEpoch.bytes ++ eventMaturityEpoch.bytes ++
eventDescriptor.bytes ++ eventDescriptor.bytes ++
strBytes(eventId) strBytes(eventId)
@ -805,7 +809,7 @@ object OracleEventV0TLV extends TLVFactory[OracleEventV0TLV] {
val eventDescriptor = iter.take(EventDescriptorTLV) val eventDescriptor = iter.take(EventDescriptorTLV)
val eventId = iter.takeString() val eventId = iter.takeString()
OracleEventV0TLV(OrderedNonces(nonces), OracleEventV0TLV(OrderedNonces.fromUnsorted(nonces),
eventMaturity, eventMaturity,
eventDescriptor, eventDescriptor,
eventId) eventId)
@ -865,7 +869,7 @@ object OracleAnnouncementV0TLV extends TLVFactory[OracleAnnouncementV0TLV] {
val dummyPrivKey: ECPrivateKey = ECPrivateKey.fromHex( val dummyPrivKey: ECPrivateKey = ECPrivateKey.fromHex(
"f04671ab68f3fefbeaa344c49149748f722287a81b19cd956b2332d07b8f6853") "f04671ab68f3fefbeaa344c49149748f722287a81b19cd956b2332d07b8f6853")
val event = OracleEventV0TLV( val event = OracleEventV0TLV(
OrderedNonces(Vector(dummyPrivKey.schnorrNonce)), OrderedNonces.fromUnsorted(Vector(dummyPrivKey.schnorrNonce)),
UInt32.zero, UInt32.zero,
EnumEventDescriptorV0TLV.dummy, EnumEventDescriptorV0TLV.dummy,
"dummy") "dummy")
@ -881,7 +885,7 @@ object OracleAnnouncementV0TLV extends TLVFactory[OracleAnnouncementV0TLV] {
nonce: SchnorrNonce, nonce: SchnorrNonce,
events: Vector[EnumOutcome]): OracleAnnouncementTLV = { events: Vector[EnumOutcome]): OracleAnnouncementTLV = {
val event = OracleEventV0TLV( val event = OracleEventV0TLV(
OrderedNonces(Vector(nonce)), OrderedNonces.fromUnsorted(Vector(nonce)),
UInt32.zero, UInt32.zero,
EnumEventDescriptorV0TLV(events.map(outcome => outcome.outcome)), EnumEventDescriptorV0TLV(events.map(outcome => outcome.outcome)),
"dummy") "dummy")
@ -893,17 +897,14 @@ object OracleAnnouncementV0TLV extends TLVFactory[OracleAnnouncementV0TLV] {
def dummyForKeys( def dummyForKeys(
privKey: ECPrivateKey, privKey: ECPrivateKey,
nonces: Vector[SchnorrNonce]): OracleAnnouncementTLV = { nonces: OrderedNonces): OracleAnnouncementTLV = {
val eventDescriptor = DigitDecompositionEventDescriptorV0TLV(UInt16(2), val eventDescriptor = DigitDecompositionEventDescriptorV0TLV(UInt16(2),
isSigned = isSigned =
false, false,
nonces.length, nonces.length,
"dummy", "dummy",
Int32.zero) Int32.zero)
val event = OracleEventV0TLV(OrderedNonces(nonces), val event = OracleEventV0TLV(nonces, UInt32.zero, eventDescriptor, "dummy")
UInt32.zero,
eventDescriptor,
"dummy")
val sig = val sig =
privKey.schnorrSign(CryptoUtil.sha256DLCAnnouncement(event.bytes).bytes) privKey.schnorrSign(CryptoUtil.sha256DLCAnnouncement(event.bytes).bytes)
@ -916,7 +917,8 @@ object OracleAnnouncementV0TLV extends TLVFactory[OracleAnnouncementV0TLV] {
sealed trait OracleAttestmentTLV extends DLCOracleTLV { sealed trait OracleAttestmentTLV extends DLCOracleTLV {
def eventId: NormalizedString def eventId: NormalizedString
def publicKey: SchnorrPublicKey def publicKey: SchnorrPublicKey
def sigs: Vector[SchnorrDigitalSignature] def sigs: OrderedSchnorrSignatures
def outcomes: Vector[NormalizedString] def outcomes: Vector[NormalizedString]
} }
@ -931,7 +933,7 @@ object OracleAttestmentTLV extends TLVParentFactory[OracleAttestmentTLV] {
case class OracleAttestmentV0TLV( case class OracleAttestmentV0TLV(
eventId: NormalizedString, eventId: NormalizedString,
publicKey: SchnorrPublicKey, publicKey: SchnorrPublicKey,
sigs: Vector[SchnorrDigitalSignature], sigs: OrderedSchnorrSignatures,
outcomes: Vector[NormalizedString]) outcomes: Vector[NormalizedString])
extends OracleAttestmentTLV { extends OracleAttestmentTLV {
require(sigs.nonEmpty, "Cannot have 0 signatures") require(sigs.nonEmpty, "Cannot have 0 signatures")
@ -948,7 +950,7 @@ case class OracleAttestmentV0TLV(
strBytes(eventId) ++ strBytes(eventId) ++
publicKey.bytes ++ publicKey.bytes ++
u16PrefixedList(sigs) ++ u16PrefixedList(sigs.toVector) ++
outcomesBytes outcomesBytes
} }
} }
@ -967,7 +969,10 @@ object OracleAttestmentV0TLV extends TLVFactory[OracleAttestmentV0TLV] {
iter.takeString() iter.takeString()
} }
OracleAttestmentV0TLV(eventId, pubKey, sigs, outcomes) OracleAttestmentV0TLV(eventId,
pubKey,
OrderedSchnorrSignatures.fromUnsorted(sigs),
outcomes)
} }
lazy val dummy: OracleAttestmentV0TLV = { lazy val dummy: OracleAttestmentV0TLV = {
@ -978,7 +983,7 @@ object OracleAttestmentV0TLV extends TLVFactory[OracleAttestmentV0TLV] {
OracleAttestmentV0TLV(eventId, OracleAttestmentV0TLV(eventId,
key.schnorrPublicKey, key.schnorrPublicKey,
Vector(sig), OrderedSchnorrSignatures(sig),
Vector(outcome)) Vector(outcome))
} }

View file

@ -3,13 +3,19 @@ package org.bitcoins.core.util.sorted
import org.bitcoins.crypto.SchnorrNonce import org.bitcoins.crypto.SchnorrNonce
/** Represents an ordered set of SchnorrNonces */ /** Represents an ordered set of SchnorrNonces */
case class OrderedNonces(vec: Vector[SchnorrNonce]) case class OrderedNonces(private val vec: Vector[SchnorrNonce])
extends SortedVec[SchnorrNonce, SchnorrNonce](vec, extends SortedVec[SchnorrNonce, SchnorrNonce](
SortedVec.forOrdered(vec)) vec,
org.bitcoins.core.nonceOrdering)
object OrderedNonces { object OrderedNonces extends SortedVecFactory[SchnorrNonce, OrderedNonces] {
def apply(single: SchnorrNonce): OrderedNonces = { override def apply(single: SchnorrNonce): OrderedNonces = {
OrderedNonces(Vector(single)) OrderedNonces(Vector(single))
} }
override def fromUnsorted(vec: Vector[SchnorrNonce]): OrderedNonces = {
val sorted = vec.sorted(org.bitcoins.core.nonceOrdering)
OrderedNonces(sorted)
}
} }

View file

@ -0,0 +1,25 @@
package org.bitcoins.core.util.sorted
import org.bitcoins.crypto.SchnorrDigitalSignature
case class OrderedSchnorrSignatures(
private val vec: Vector[SchnorrDigitalSignature])
extends SortedVec[SchnorrDigitalSignature, SchnorrDigitalSignature](
vec,
org.bitcoins.core.schnorrSignatureOrdering)
object OrderedSchnorrSignatures
extends SortedVecFactory[
SchnorrDigitalSignature,
OrderedSchnorrSignatures] {
override def apply(sig: SchnorrDigitalSignature): OrderedSchnorrSignatures = {
OrderedSchnorrSignatures(Vector(sig))
}
def fromUnsorted(
vec: Vector[SchnorrDigitalSignature]): OrderedSchnorrSignatures = {
val sorted = vec.sorted(org.bitcoins.core.schnorrSignatureOrdering)
OrderedSchnorrSignatures(sorted)
}
}

View file

@ -38,3 +38,9 @@ object SortedVec {
SortedVecImpl(vec) SortedVecImpl(vec)
} }
} }
trait SortedVecFactory[U, T <: SortedVec[U, U]] {
def apply(t: U): T
def fromUnsorted(vec: Vector[U]): T
}

View file

@ -0,0 +1,35 @@
package org.bitcoins.crypto
import scodec.bits.ByteVector
import scala.annotation.tailrec
object CryptoOrdering {
val nonceOrdering: Ordering[SchnorrNonce] = {
new Ordering[SchnorrNonce] {
override def compare(x: SchnorrNonce, y: SchnorrNonce): Int = {
byteVectorOrdering.compare(x.bytes, y.bytes)
}
}
}
val byteVectorOrdering: Ordering[ByteVector] =
new Ordering[ByteVector] {
@tailrec
override def compare(x: ByteVector, y: ByteVector): Int = {
if (x == y) {
0
} else if (x.isEmpty) {
-1
} else if (y.isEmpty) {
1
} else if (x.head != y.head) {
x.head.compare(y.head)
} else {
compare(x.tail, y.tail)
}
}
}
}

View file

@ -277,6 +277,16 @@ object ECPrivateKey extends Factory[ECPrivateKey] {
/** Generates a fresh [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] that has not been used before. */ /** Generates a fresh [[org.bitcoins.crypto.ECPrivateKey ECPrivateKey]] that has not been used before. */
def freshPrivateKey: ECPrivateKey = CryptoUtil.freshPrivateKey def freshPrivateKey: ECPrivateKey = CryptoUtil.freshPrivateKey
/** Generates [[num]] private keys that are ordered by [[ECPrivateKey.schnorrNonce]] */
def generateNonceOrderedPrivKeys(num: Int): Vector[ECPrivateKey] = {
val privKeys = 0.to(num).map(_ => ECPrivateKey.freshPrivateKey).toVector
val sortByNonce = privKeys
.map(p => (p, p.schnorrNonce))
.sortBy(_._2)(CryptoOrdering.nonceOrdering)
sortByNonce.map(_._1)
}
} }
/** Created by chris on 2/16/16. /** Created by chris on 2/16/16.

View file

@ -6,6 +6,7 @@ import org.bitcoins.core.protocol.tlv.{
OracleAnnouncementV0TLV, OracleAnnouncementV0TLV,
OracleAttestmentV0TLV OracleAttestmentV0TLV
} }
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.crypto.FieldElement import org.bitcoins.crypto.FieldElement
import org.bitcoins.testkitcore.util.BitcoinSUnitTest import org.bitcoins.testkitcore.util.BitcoinSUnitTest
@ -22,9 +23,11 @@ class AttestationVerificationTest extends BitcoinSUnitTest {
val validEnumAttestation: OracleAttestmentV0TLV = OracleAttestmentV0TLV( val validEnumAttestation: OracleAttestmentV0TLV = OracleAttestmentV0TLV(
"fdd868690474657374545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a8500013168cb6d4c4e52aeb5bb75ce141cd9e1aa40e1d9123134d9aa390cffb338d51e323d991dadb52f32d0541027f973c363c0b746bb40dd1d42686f172d88ddef380161") "fdd868690474657374545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a8500013168cb6d4c4e52aeb5bb75ce141cd9e1aa40e1d9123134d9aa390cffb338d51e323d991dadb52f32d0541027f973c363c0b746bb40dd1d42686f172d88ddef380161")
val invalidEnumAttestation: OracleAttestmentV0TLV = val invalidEnumAttestation: OracleAttestmentV0TLV = {
val unsorted = validEnumAttestation.sigs.map(_.copy(sig = FieldElement.one))
validEnumAttestation.copy(sigs = validEnumAttestation.copy(sigs =
validEnumAttestation.sigs.map(_.copy(sig = FieldElement.one))) OrderedSchnorrSignatures.fromUnsorted(unsorted.toVector))
}
val unsignedDigitDecompAnnouncement: OracleAnnouncementV0TLV = val unsignedDigitDecompAnnouncement: OracleAnnouncementV0TLV =
OracleAnnouncementV0TLV( OracleAnnouncementV0TLV(
@ -35,10 +38,12 @@ class AttestationVerificationTest extends BitcoinSUnitTest {
"fdd868fd01b40564756d6d79545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a850006280b657b9c1cd8de3da2619194e2c71831598be3e60d39a242c232f580451c43050ce8ac95b549bb5fed9e3800cf3c040207071032a5c458485ad1817373c0b7bd61d1a6c395c99202058ddabf851e1c8220f12bd801bbb90efcf45d4a2d769cdaa4e883da6b59cac21fc8f18dae7893997d5d13ac63f33fdb7643bba4c4fc8d57ae1c605b9d36ff8477baa8c216abbfe6c3742236ecfad2415745a7cf7850c6cb6a147a2e2a8875133147055027ed130dec47c6a9f75983d532a5c5940a763546f4835c5b80ca64832a6b9e7526fd575db4913ce0a9686072c5f970f94c3a2e72d0655c541eac15e9caa5af059c1f3e433507f1782e8775c555f1c402509f0c87d4b2e93e52b2283c81185fb8ab14a757ff04b00b821d1aaac0a81e05d15da68e710b25a91bfdacf179d9da3b90dec98844d8ac1ed534922dfa362b9db86c134ca823f9aa4b18525521073096f73fd583205086c7db2b6ac243901e4f1898bc476a311fbcd5d2fb7a355a9032c67dead084fe66eed00f7e9646e6fa83902bc7013001300130013001300130") "fdd868fd01b40564756d6d79545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a850006280b657b9c1cd8de3da2619194e2c71831598be3e60d39a242c232f580451c43050ce8ac95b549bb5fed9e3800cf3c040207071032a5c458485ad1817373c0b7bd61d1a6c395c99202058ddabf851e1c8220f12bd801bbb90efcf45d4a2d769cdaa4e883da6b59cac21fc8f18dae7893997d5d13ac63f33fdb7643bba4c4fc8d57ae1c605b9d36ff8477baa8c216abbfe6c3742236ecfad2415745a7cf7850c6cb6a147a2e2a8875133147055027ed130dec47c6a9f75983d532a5c5940a763546f4835c5b80ca64832a6b9e7526fd575db4913ce0a9686072c5f970f94c3a2e72d0655c541eac15e9caa5af059c1f3e433507f1782e8775c555f1c402509f0c87d4b2e93e52b2283c81185fb8ab14a757ff04b00b821d1aaac0a81e05d15da68e710b25a91bfdacf179d9da3b90dec98844d8ac1ed534922dfa362b9db86c134ca823f9aa4b18525521073096f73fd583205086c7db2b6ac243901e4f1898bc476a311fbcd5d2fb7a355a9032c67dead084fe66eed00f7e9646e6fa83902bc7013001300130013001300130")
// this one was generated with the same public key // this one was generated with the same public key
val invalidUnsignedDigitDecompAttestation: OracleAttestmentV0TLV = val invalidUnsignedDigitDecompAttestation: OracleAttestmentV0TLV = {
validUnsignedDigitDecompAttestation.copy(sigs = val unsorted = validUnsignedDigitDecompAttestation.sigs.map(
validUnsignedDigitDecompAttestation.sigs.map( _.copy(sig = FieldElement.one))
_.copy(sig = FieldElement.one))) val sorted = OrderedSchnorrSignatures.fromUnsorted(unsorted.toVector)
validUnsignedDigitDecompAttestation.copy(sigs = sorted)
}
// this one was generated with a different public key // this one was generated with a different public key
val invalidUnsignedDigitDecompAttestation1: OracleAttestmentV0TLV = val invalidUnsignedDigitDecompAttestation1: OracleAttestmentV0TLV =
@ -47,16 +52,18 @@ class AttestationVerificationTest extends BitcoinSUnitTest {
val signedDigitDecompAnnouncement: OracleAnnouncementV0TLV = val signedDigitDecompAnnouncement: OracleAnnouncementV0TLV =
OracleAnnouncementV0TLV( OracleAnnouncementV0TLV(
"fdd824fd01661aabd9bbcae0207aff9510f05099295f32ff72290cf5c494d3869f582f8c4a6cf1b7d832562047f68ce607eb39dcd7ec8ce64432dc51a8853dc5a3acd96a8bc5545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a85fdd822fd010000070652285e89487dc8ce816a81234082394d9602263d35a7322b77299082257767b559c622def4bba15a2ad7fc336edd71ace9b4c366b9eaba22b73df00589e74b7ca5b6c7301ef7dc62aeae1823018107868d8956677421e11ffd8f125f2fedf4a527003355640ee9333cda6c37a92d4989c6ab96eddc9266f0ddce0e2a3ffb77aa9eefa1fe40eddd0fa63f501e9b368eed6ab0cc0d2e5e6da1baa570ed9e857134bbc8a15dd5949eb1203b1d15ae701fe4b04707a1ea54c10fef16308bf806f2aa0b17f8673fe785f6b9ff0718e55b621c8e9d92839759a98b88bd6590a0ff856011fe80fdd80a0f00020105756e697473000000000006067369676e6564") "fdd824fd010126487da78218c4fd04d85575595584c54bbec4f2ab3cb64f820bab24c14f9738f4284846c3780985f5c1189decc7680d9c0dbfa5e454b72ac6e292de0df0121ec22db0a9b26f825ccff38cd776103c952c5ede3fc5da3a69770d446011ac126ffdd8229d00049ef0f2b1e7befd3840b4ae6b9f690c6ed42ba9fcddbcde1a7ee91732d63b802ec1e88c69f414e1b47db730ccd4ec1f6e2049e5ce7d569b9dc42263503efb85ed60cbb1d5d42b28d571ef9cb37dba9927a65c819742267862d88acd50a276ad9a624b05aa3829dc181f785f31a0450299a972cc0eb44384529ef30a9a17c0f2aa63328350fdd80a0e00020004746573740000000000040474657374")
val validSignedDigitDecompAttestation: OracleAttestmentV0TLV = val validSignedDigitDecompAttestation: OracleAttestmentV0TLV =
OracleAttestmentV0TLV( OracleAttestmentV0TLV(
"fdd868fd01f7067369676e6564545aa0024da81c3fec63e56e07ee141cbefbd2c6e7d4dede124fe856ea453a8500070652285e89487dc8ce816a81234082394d9602263d35a7322b772990822577670ab288b31d99f56d18d4f34be875c0a4d73aae135c4f50349a1014b686d69841b559c622def4bba15a2ad7fc336edd71ace9b4c366b9eaba22b73df00589e74ba7b82eef2041bf6af1511016cadabe9d52e64d875caf5bfef85903dbc4fc00737ca5b6c7301ef7dc62aeae1823018107868d8956677421e11ffd8f125f2fedf469f40edbb7846274f46a973f5442ece91b5a6e450a8cdcef272058a27176dabba527003355640ee9333cda6c37a92d4989c6ab96eddc9266f0ddce0e2a3ffb7762f10e09f79273ab04d1549c1d60054738fe903575aa732760bd2668530459e9aa9eefa1fe40eddd0fa63f501e9b368eed6ab0cc0d2e5e6da1baa570ed9e857188bae5c59c9ac89bec3fa00c8e1b725789e1af15f7b256ae7f169edfe7f3ef8834bbc8a15dd5949eb1203b1d15ae701fe4b04707a1ea54c10fef16308bf806f2144d3e7aa63705924da607162f59bff757490469c2c8d4e62a1aa0bf27323bcdaa0b17f8673fe785f6b9ff0718e55b621c8e9d92839759a98b88bd6590a0ff85e072b65d258bbfdc653444b08714c2be395b7e645caa214567b22916ffb7ebeb012d013001310130013101300130") "fdd868fd012f0474657374c22db0a9b26f825ccff38cd776103c952c5ede3fc5da3a69770d446011ac126f00049ef0f2b1e7befd3840b4ae6b9f690c6ed42ba9fcddbcde1a7ee91732d63b802ec8230d8b4f0c926fa79dd4d24dcda5487c6e4957f4b208811baa11fde9849dddc1e88c69f414e1b47db730ccd4ec1f6e2049e5ce7d569b9dc42263503efb85ed08bfb84dab00ad7f1d1c07eb8e1559ba0c700e88f7387e936883fe77b406efb560cbb1d5d42b28d571ef9cb37dba9927a65c819742267862d88acd50a276ad9a1b25f23a7c49150f83f6b241a5b6b0f91951f285853452ae05ea5f7e8f3846a5624b05aa3829dc181f785f31a0450299a972cc0eb44384529ef30a9a17c0f2aa593b017b084ea40c7f364e5235c9a27f659dc2cfa689e0aa80f4a4cacd4d4de10131013101300130")
val invalidSignedDigitDecompAttestation: OracleAttestmentV0TLV = val invalidSignedDigitDecompAttestation: OracleAttestmentV0TLV = {
validSignedDigitDecompAttestation.copy(sigs = val unsorted =
validSignedDigitDecompAttestation.sigs.map( validSignedDigitDecompAttestation.sigs.map(_.copy(sig = FieldElement.one))
_.copy(sig = FieldElement.one))) val sorted = OrderedSchnorrSignatures.fromUnsorted(unsorted.toVector)
validSignedDigitDecompAttestation.copy(sigs = sorted)
}
val invalidSignedDigitDecompAttestation1: OracleAttestmentV0TLV = val invalidSignedDigitDecompAttestation1: OracleAttestmentV0TLV =
OracleAttestmentV0TLV( OracleAttestmentV0TLV(

View file

@ -248,7 +248,7 @@ case class DLCOracle()(implicit val conf: DLCOracleAppConfig)
nonces = rValueDbs.map(_.nonce) nonces = rValueDbs.map(_.nonce)
eventTLV = OracleEventV0TLV(OrderedNonces(nonces), eventTLV = OracleEventV0TLV(OrderedNonces.fromUnsorted(nonces),
epoch, epoch,
descriptor, descriptor,
eventName) eventName)

View file

@ -70,7 +70,7 @@ trait EventDbUtil {
eventName: String, eventName: String,
signingVersion: SigningVersion = SigningVersion.latest): Vector[ signingVersion: SigningVersion = SigningVersion.latest): Vector[
EventDb] = { EventDb] = {
val nonces = oracleAnnouncementV0TLV.eventTLV.nonces.vec val nonces = oracleAnnouncementV0TLV.eventTLV.nonces.toVector
nonces.zipWithIndex.map { case (nonce, index) => nonces.zipWithIndex.map { case (nonce, index) =>
EventDb( EventDb(
nonce = nonce, nonce = nonce,

View file

@ -437,43 +437,6 @@ class DLCExecutionTest extends BitcoinSDualWalletTest {
} yield succeed } yield succeed
} }
it must "throw an exception for a enum contract when do not have all the oracle signatures/outcomes" in {
wallets =>
val walletA = wallets._1.wallet
val resultF = for {
contractId <- getContractId(walletA)
status <- getDLCStatus(walletA)
(goodAttestment, _) = {
status.contractInfo match {
case single: SingleContractInfo =>
DLCWalletUtil.getSigs(single)
case disjoint: DisjointUnionContractInfo =>
sys.error(
s"Cannot retrieve sigs for disjoint union contract, got=$disjoint")
}
}
//purposefully drop these
//we cannot drop just a sig, or just an outcome because
//of invariants in OracleAttestmentV0TLV
badSigs = goodAttestment.sigs.dropRight(1)
badOutcomes = goodAttestment.outcomes.dropRight(1)
badAttestment = OracleAttestmentV0TLV(eventId = goodAttestment.eventId,
publicKey =
goodAttestment.publicKey,
sigs = badSigs,
outcomes = badOutcomes)
func = (wallet: DLCWallet) =>
wallet.executeDLC(contractId, badAttestment).map(_.get)
result <- dlcExecutionTest(wallets = wallets,
asInitiator = true,
func = func,
expectedOutputs = 1)
} yield assert(result)
recoverToSucceededIf[IllegalArgumentException](resultF)
}
it must "throw an exception when you try to execute a DLC in the SIGNED state" in { it must "throw an exception when you try to execute a DLC in the SIGNED state" in {
wallets => wallets =>
val walletA = wallets._1.wallet val walletA = wallets._1.wallet

View file

@ -4,7 +4,10 @@ import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.protocol.dlc.models.DLCStatus.{Claimed, RemoteClaimed} import org.bitcoins.core.protocol.dlc.models.DLCStatus.{Claimed, RemoteClaimed}
import org.bitcoins.core.protocol.dlc.models._ import org.bitcoins.core.protocol.dlc.models._
import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.util.sorted.OrderedAnnouncements import org.bitcoins.core.util.sorted.{
OrderedAnnouncements,
OrderedSchnorrSignatures
}
import org.bitcoins.crypto.{CryptoUtil, ECPrivateKey, SchnorrDigitalSignature} import org.bitcoins.crypto.{CryptoUtil, ECPrivateKey, SchnorrDigitalSignature}
import org.bitcoins.testkit.wallet.BitcoinSDualWalletTest import org.bitcoins.testkit.wallet.BitcoinSDualWalletTest
import org.bitcoins.testkit.wallet.DLCWalletUtil._ import org.bitcoins.testkit.wallet.DLCWalletUtil._
@ -77,7 +80,7 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest {
val initiatorWinSig = priv.schnorrSignWithNonce(hash, kValue) val initiatorWinSig = priv.schnorrSignWithNonce(hash, kValue)
OracleAttestmentV0TLV(eventId, OracleAttestmentV0TLV(eventId,
priv.schnorrPublicKey, priv.schnorrPublicKey,
Vector(initiatorWinSig), OrderedSchnorrSignatures(initiatorWinSig),
Vector(initiatorWinStr)) Vector(initiatorWinStr))
} }
@ -98,7 +101,7 @@ class DLCMultiOracleEnumExecutionTest extends BitcoinSDualWalletTest {
val recipientWinSig = priv.schnorrSignWithNonce(hash, kValue) val recipientWinSig = priv.schnorrSignWithNonce(hash, kValue)
OracleAttestmentV0TLV(eventId, OracleAttestmentV0TLV(eventId,
priv.schnorrPublicKey, priv.schnorrPublicKey,
Vector(recipientWinSig), OrderedSchnorrSignatures(recipientWinSig),
Vector(recipientWinStr)) Vector(recipientWinStr))
} }

View file

@ -4,7 +4,11 @@ import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.protocol.dlc.models.DLCStatus.{Claimed, RemoteClaimed} import org.bitcoins.core.protocol.dlc.models.DLCStatus.{Claimed, RemoteClaimed}
import org.bitcoins.core.protocol.dlc.models._ import org.bitcoins.core.protocol.dlc.models._
import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.util.sorted.OrderedAnnouncements import org.bitcoins.core.util.sorted.{
OrderedAnnouncements,
OrderedNonces,
OrderedSchnorrSignatures
}
import org.bitcoins.crypto._ import org.bitcoins.crypto._
import org.bitcoins.testkitcore.dlc.DLCTest.genNumericOracleOutcome import org.bitcoins.testkitcore.dlc.DLCTest.genNumericOracleOutcome
import org.bitcoins.testkit.wallet.DLCWalletUtil._ import org.bitcoins.testkit.wallet.DLCWalletUtil._
@ -18,19 +22,32 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest {
behavior of "DLCWallet" behavior of "DLCWallet"
val privateKeys: Vector[ECPrivateKey] = val privateKeys: Vector[ECPrivateKey] = {
0.until(5).map(_ => ECPrivateKey.freshPrivateKey).toVector val unsorted = 0.until(5).map(_ => ECPrivateKey.freshPrivateKey).toVector
val nonces = unsorted
.map(u => (u, u.schnorrNonce))
.sortBy(_._2)(org.bitcoins.core.nonceOrdering)
nonces.map(_._1)
}
val kValues: Vector[Vector[ECPrivateKey]] = val kValues: Vector[Vector[ECPrivateKey]] = {
privateKeys.map(_ => privateKeys.map { _ =>
0.until(numDigits).map(_ => ECPrivateKey.freshPrivateKey).toVector) val unsorted =
0.until(numDigits).map(_ => ECPrivateKey.freshPrivateKey).toVector
val sorted = unsorted
.map(u => (u, u.schnorrNonce))
.sortBy(_._2)(org.bitcoins.core.nonceOrdering)
sorted.map(_._1)
}
}
val contractDescriptor: NumericContractDescriptor = val contractDescriptor: NumericContractDescriptor =
DLCWalletUtil.multiNonceContractDescriptor DLCWalletUtil.multiNonceContractDescriptor
val announcements: Vector[OracleAnnouncementTLV] = val announcements: Vector[OracleAnnouncementTLV] =
privateKeys.zip(kValues).map { case (priv, ks) => privateKeys.zip(kValues).map { case (priv, ks) =>
OracleAnnouncementV0TLV.dummyForKeys(priv, ks.map(_.schnorrNonce)) val ordered = OrderedNonces.fromUnsorted(ks.map(_.schnorrNonce))
OracleAnnouncementV0TLV.dummyForKeys(priv, ordered)
} }
val threshold = 3 val threshold = 3
@ -228,7 +245,7 @@ class DLCMultiOracleExactNumericExecutionTest extends BitcoinSDualWalletTest {
s"kValues.length=${kValues.length} sigs.length=${sigs.length}") s"kValues.length=${kValues.length} sigs.length=${sigs.length}")
OracleAttestmentV0TLV(eventId, OracleAttestmentV0TLV(eventId,
priv.schnorrPublicKey, priv.schnorrPublicKey,
sigs, OrderedSchnorrSignatures.fromUnsorted(sigs),
digitsPadded.map(_.toString)) digitsPadded.map(_.toString))
} }
} }

View file

@ -4,7 +4,11 @@ import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.protocol.dlc.models.DLCStatus.{Claimed, RemoteClaimed} import org.bitcoins.core.protocol.dlc.models.DLCStatus.{Claimed, RemoteClaimed}
import org.bitcoins.core.protocol.dlc.models._ import org.bitcoins.core.protocol.dlc.models._
import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.util.sorted.OrderedAnnouncements import org.bitcoins.core.util.sorted.{
OrderedAnnouncements,
OrderedNonces,
OrderedSchnorrSignatures
}
import org.bitcoins.crypto._ import org.bitcoins.crypto._
import org.bitcoins.testkitcore.dlc.DLCTest import org.bitcoins.testkitcore.dlc.DLCTest
import org.bitcoins.testkit.wallet.DLCWalletUtil._ import org.bitcoins.testkit.wallet.DLCWalletUtil._
@ -20,19 +24,33 @@ class DLCMultiOracleNumericExecutionTest
behavior of "DLCWallet" behavior of "DLCWallet"
val privateKeys: Vector[ECPrivateKey] = val privateKeys: Vector[ECPrivateKey] = {
0.until(5).map(_ => ECPrivateKey.freshPrivateKey).toVector val unsorted = 0.until(5).map(_ => ECPrivateKey.freshPrivateKey).toVector
val nonces = unsorted
.map(u => (u, u.schnorrNonce))
.sortBy(_._2)(org.bitcoins.core.nonceOrdering)
nonces.map(_._1)
}
val kValues: Vector[Vector[ECPrivateKey]] = val kValues: Vector[Vector[ECPrivateKey]] = {
privateKeys.map(_ => privateKeys.map { _ =>
0.until(numDigits).map(_ => ECPrivateKey.freshPrivateKey).toVector) val unsorted =
0.until(numDigits).map(_ => ECPrivateKey.freshPrivateKey).toVector
val sorted = unsorted
.map(u => (u, u.schnorrNonce))
.sortBy(_._2)(org.bitcoins.core.nonceOrdering)
sorted.map(_._1)
}
}
val contractDescriptor: NumericContractDescriptor = val contractDescriptor: NumericContractDescriptor =
DLCWalletUtil.multiNonceContractDescriptor DLCWalletUtil.multiNonceContractDescriptor
val announcements: Vector[OracleAnnouncementTLV] = val announcements: Vector[OracleAnnouncementTLV] = {
privateKeys.zip(kValues).map { case (priv, ks) => privateKeys.zip(kValues).map { case (priv, ks) =>
OracleAnnouncementV0TLV.dummyForKeys(priv, ks.map(_.schnorrNonce)) val ordered = OrderedNonces.fromUnsorted(ks.map(_.schnorrNonce))
OracleAnnouncementV0TLV.dummyForKeys(priv, ordered)
}
} }
val threshold = 3 val threshold = 3
@ -237,7 +255,7 @@ class DLCMultiOracleNumericExecutionTest
s"kValues.length=${kValues.length} sigs.length=${sigs.length}") s"kValues.length=${kValues.length} sigs.length=${sigs.length}")
OracleAttestmentV0TLV(eventId, OracleAttestmentV0TLV(eventId,
priv.schnorrPublicKey, priv.schnorrPublicKey,
sigs, OrderedSchnorrSignatures.fromUnsorted(sigs),
digitsPadded.map(_.toString)) digitsPadded.map(_.toString))
} }
} }

View file

@ -4,6 +4,7 @@ import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.protocol.dlc.models.DLCStatus.{Claimed, RemoteClaimed} import org.bitcoins.core.protocol.dlc.models.DLCStatus.{Claimed, RemoteClaimed}
import org.bitcoins.core.protocol.dlc.models._ import org.bitcoins.core.protocol.dlc.models._
import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.crypto._ import org.bitcoins.crypto._
import org.bitcoins.testkit.wallet.DLCWalletUtil._ import org.bitcoins.testkit.wallet.DLCWalletUtil._
import org.bitcoins.testkit.wallet.{BitcoinSDualWalletTest, DLCWalletUtil} import org.bitcoins.testkit.wallet.{BitcoinSDualWalletTest, DLCWalletUtil}
@ -78,11 +79,11 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest {
(OracleAttestmentV0TLV(eventId, (OracleAttestmentV0TLV(eventId,
publicKey, publicKey,
initiatorWinSigs, OrderedSchnorrSignatures(initiatorWinSigs),
initiatorWinVec.map(_.toString)), initiatorWinVec.map(_.toString)),
OracleAttestmentV0TLV(eventId, OracleAttestmentV0TLV(eventId,
publicKey, publicKey,
recipientWinSigs, OrderedSchnorrSignatures(recipientWinSigs),
recipientWinVec.map(_.toString))) recipientWinVec.map(_.toString)))
} }
@ -175,7 +176,8 @@ class DLCNumericExecutionTest extends BitcoinSDualWalletTest {
//purposefully drop these //purposefully drop these
//we cannot drop just a sig, or just an outcome because //we cannot drop just a sig, or just an outcome because
//of invariants in OracleAttestmentV0TLV //of invariants in OracleAttestmentV0TLV
badSigs = goodAttestment.sigs.dropRight(1) badSigs = OrderedSchnorrSignatures.fromUnsorted(
goodAttestment.sigs.dropRight(1).toVector)
badOutcomes = goodAttestment.outcomes.dropRight(1) badOutcomes = goodAttestment.outcomes.dropRight(1)
badAttestment = OracleAttestmentV0TLV(eventId = goodAttestment.eventId, badAttestment = OracleAttestmentV0TLV(eventId = goodAttestment.eventId,
publicKey = publicKey =

View file

@ -7,6 +7,7 @@ import org.bitcoins.core.protocol.dlc.models.DLCMessage._
import org.bitcoins.core.protocol.dlc.models._ import org.bitcoins.core.protocol.dlc.models._
import org.bitcoins.core.protocol.script.P2WPKHWitnessV0 import org.bitcoins.core.protocol.script.P2WPKHWitnessV0
import org.bitcoins.core.protocol.tlv._ import org.bitcoins.core.protocol.tlv._
import org.bitcoins.core.util.sorted.OrderedSchnorrSignatures
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
import org.bitcoins.core.wallet.utxo.TxoState import org.bitcoins.core.wallet.utxo.TxoState
import org.bitcoins.crypto._ import org.bitcoins.crypto._
@ -763,7 +764,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
val oracleSig = SchnorrDigitalSignature( val oracleSig = SchnorrDigitalSignature(
"a6a09c7c83c50b34f9db560a2e14fef2eab5224c15b18c7114331756364bfce6c59736cdcfe1e0a89064f846d5dbde0902f82688dde34dc1833965a60240f287") "a6a09c7c83c50b34f9db560a2e14fef2eab5224c15b18c7114331756364bfce6c59736cdcfe1e0a89064f846d5dbde0902f82688dde34dc1833965a60240f287")
val sig = OracleSignatures(oracleInfo, Vector(oracleSig)) val sig =
OracleSignatures(oracleInfo, OrderedSchnorrSignatures(oracleSig))
for { for {
offer <- walletA.createDLCOffer( offer <- walletA.createDLCOffer(
@ -887,24 +889,8 @@ class WalletDLCSetupTest extends BitcoinSDualWalletTest {
} yield succeed } yield succeed
} }
//https://test.oracle.suredbits.com/contract/numeric/022428196c6a60673d1f2b90e7be14ac615986dce5571246e8bcc9d2d689d57b private val numericContractInfo =
private val numericContractInfo = ContractInfoV0TLV.fromHex( DLCWalletUtil.numericContractInfoV0
"""fdd82efd033f00000000000186a0fda720540012fda72648000501000000000000000000000001fd88b80000000000000000000001
|fdafc8000000000000c350000001fdd6d800000000000186a0000001fe0003ffff00000000000186a00000fda724020000fda712fd
|02d9fdd824fd02d391177fd623a72d56e7bc12e3903f8d6bce7f07a25226d54009cd7e670f5e7a7320b0704286580d8b6a7f31ab7b
|f71356a13c28aa609a021111b2e3d2b2db26bc120bd29248895b81f76b07d85a21b86021f22352d6376d19bbf5c93f918828f1fdd8
|22fd026d0012fad0cde50a2258efa25cbba60ef0b6677cd29654802937c112097edb64bd205beea02263d6461e60a9ca8e08209c8b
|d5552863156014d5418cad91ac590bbf13a847f105db9899d560e5040f9565c043c9e7fdf3782ad2708c5b99646c722b4118547472
|48fb52e6486cce3eca5ddf9d64ecbe0864501a446efd378863f9a4055fab50d2112320ff14d8747a72467589822103f197063b49e7
|7b90d82d3a8d49b63c3ceb9bd3328398a53989d4237216a24a1d12364efa2d2aec59cdc87909b115dca5b07106b70032ff78072f82
|ceeaf2e20db55086e9a2e5e5cac864992d747fd40f4b26bc3d7de958ee02460d1199ff81438c9b76b3934cbc4566d10f242563b95e
|7df79c28d52c9c46b617676a4ee84a549ee1f0f53865c9ef4d0ff825e2f438384c5f6238d0734beb570a1a49d035d9f86ee31c23f1
|e97bd34fba3f586c0fdf29997530e528b3200a0d7e34f865dc4ca7bfd722bf77c0478ddd25bfa2dc6a4ab973d0c1b7a9ff38283b7c
|19bbe02677a9b628f3ee3d5198d66c1623c9608293093c126d4124a445bb6412f720493b6ffa411db53923895fd50c9563d50a97a8
|6188084fe4c0f15ce50438ff0b00e1a9470185fd7c96296ae2be12056f61ceaeee7ced48314a3b6855bc9aa3b446b9dfad68553f53
|02c60670a95fb9bdc5e72db7f1e9d42e4f4baca1bcbb22612db6417b45cc3d78b1ef33fc362a68db56df00ab1ee0700bd900200f6a
|24882101e71de7e18a7fb0d7da27b340de52f97d96239f359cfe31afcaf69cc9ddfcbfbdb2267e673ad728a29dd22d31d1a1187162
|037480fdd80a100002000642544355534400000000001212446572696269742d4254432d394645423232""".stripMargin)
it must "fail accepting an offer twice simultaneously" in { wallets => it must "fail accepting an offer twice simultaneously" in { wallets =>
val walletA = wallets._1.wallet val walletA = wallets._1.wallet

View file

@ -110,7 +110,8 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit
.exists(_.used) .exists(_.used)
if (used) { if (used) {
val nonces = nonceDbs.sortBy(_.index).map(_.nonce) val nonces = nonceDbs.sortBy(_.index).map(_.nonce)
val eventTLV = OracleEventV0TLV(OrderedNonces(nonces), val eventTLV =
OracleEventV0TLV(OrderedNonces.fromUnsorted(nonces),
data.eventMaturity, data.eventMaturity,
data.eventDescriptor, data.eventDescriptor,
data.eventId) data.eventId)
@ -151,7 +152,7 @@ case class DLCDataManagement(dlcWalletDAOs: DLCWalletDAOs)(implicit
announcementData.find(_.id.contains(id)) match { announcementData.find(_.id.contains(id)) match {
case Some(data) => case Some(data) =>
val nonces = nonceDbs.sortBy(_.index).map(_.nonce) val nonces = nonceDbs.sortBy(_.index).map(_.nonce)
val eventTLV = OracleEventV0TLV(OrderedNonces(nonces), val eventTLV = OracleEventV0TLV(OrderedNonces.fromUnsorted(nonces),
data.eventMaturity, data.eventMaturity,
data.eventDescriptor, data.eventDescriptor,
data.eventId) data.eventId)

View file

@ -17,7 +17,7 @@ object OracleNonceDbHelper {
def fromAnnouncement( def fromAnnouncement(
id: Long, id: Long,
tlv: OracleAnnouncementTLV): Vector[OracleNonceDb] = { tlv: OracleAnnouncementTLV): Vector[OracleNonceDb] = {
tlv.eventTLV.nonces.vec.zipWithIndex.map { case (nonce, index) => tlv.eventTLV.nonces.toVector.zipWithIndex.map { case (nonce, index) =>
OracleNonceDb(id, index, SchnorrDigitalSignature.dummy, nonce, None, None) OracleNonceDb(id, index, SchnorrDigitalSignature.dummy, nonce, None, None)
} }
} }

View file

@ -141,7 +141,8 @@ val descriptor = NumericContractDescriptor(curve, numDigits = 15, roundTo100)
val announcements = 0.until(5).toVector.map { _ => val announcements = 0.until(5).toVector.map { _ =>
val oraclePrivKey = ECPrivateKey.freshPrivateKey val oraclePrivKey = ECPrivateKey.freshPrivateKey
val nonces = 0.until(15).toVector.map(_ => ECPrivateKey.freshPrivateKey.schnorrNonce) val nonces = 0.until(15).toVector.map(_ => ECPrivateKey.freshPrivateKey.schnorrNonce)
OracleAnnouncementV0TLV.dummyForKeys(oraclePrivKey, nonces) val orderedNonces = OrderedNonces.fromUnsorted(nonces)
OracleAnnouncementV0TLV.dummyForKeys(oraclePrivKey, orderedNonces)
} }
val oracleInfo = NumericMultiOracleInfo( val oracleInfo = NumericMultiOracleInfo(
threshold = 3, threshold = 3,

View file

@ -14,7 +14,11 @@ import org.bitcoins.core.protocol.script._
import org.bitcoins.core.protocol.tlv.{NumericDLCOutcomeType, _} import org.bitcoins.core.protocol.tlv.{NumericDLCOutcomeType, _}
import org.bitcoins.core.protocol.transaction._ import org.bitcoins.core.protocol.transaction._
import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature
import org.bitcoins.core.util.sorted.OrderedAnnouncements import org.bitcoins.core.util.sorted.{
OrderedAnnouncements,
OrderedNonces,
OrderedSchnorrSignatures
}
import org.bitcoins.core.util.{BitcoinScriptUtil, FutureUtil, NumberUtil} import org.bitcoins.core.util.{BitcoinScriptUtil, FutureUtil, NumberUtil}
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
import org.bitcoins.core.wallet.utxo._ import org.bitcoins.core.wallet.utxo._
@ -40,22 +44,27 @@ trait DLCTest {
} }
} }
val oraclePrivKeys: Vector[ECPrivateKey] = val oraclePrivKeys: Vector[ECPrivateKey] = {
(0 until 50).toVector.map(_ => ECPrivateKey.freshPrivateKey) ECPrivateKey.generateNonceOrderedPrivKeys(50)
}
val oraclePubKeys: Vector[SchnorrPublicKey] = val oraclePubKeys: Vector[SchnorrPublicKey] =
oraclePrivKeys.map(_.schnorrPublicKey) oraclePrivKeys.map(_.schnorrPublicKey)
val oraclePrivKey: ECPrivateKey = oraclePrivKeys.head val oraclePrivKey: ECPrivateKey = oraclePrivKeys.head
val oraclePubKey: SchnorrPublicKey = oraclePubKeys.head val oraclePubKey: SchnorrPublicKey = oraclePubKeys.head
val preCommittedKsPerOracle: Vector[Vector[ECPrivateKey]] = val preCommittedKsPerOracle: Vector[Vector[ECPrivateKey]] = {
oraclePrivKeys.map(_ => oraclePrivKeys.map { _ =>
(0 until 50).toVector.map(_ => ECPrivateKey.freshPrivateKey)) ECPrivateKey.generateNonceOrderedPrivKeys(50)
}
}
val preCommittedRsPerOracle: Vector[Vector[SchnorrNonce]] = val preCommittedRsPerOracle: Vector[OrderedNonces] =
preCommittedKsPerOracle.map(_.map(_.schnorrNonce)) preCommittedKsPerOracle.map { privKeys =>
OrderedNonces.fromUnsorted(privKeys.map(_.schnorrNonce))
}
val preCommittedKs: Vector[ECPrivateKey] = preCommittedKsPerOracle.head val preCommittedKs: Vector[ECPrivateKey] = preCommittedKsPerOracle.head
val preCommittedRs: Vector[SchnorrNonce] = preCommittedRsPerOracle.head val preCommittedRs: OrderedNonces = preCommittedRsPerOracle.head
val preCommittedK: ECPrivateKey = preCommittedKs.head val preCommittedK: ECPrivateKey = preCommittedKs.head
val preCommittedR: SchnorrNonce = preCommittedRs.head val preCommittedR: SchnorrNonce = preCommittedRs.head
@ -454,8 +463,9 @@ trait DLCTest {
.zip(preCommittedRsPerOracle .zip(preCommittedRsPerOracle
.slice(oracleShift, oracleShift + params.numOracles)) .slice(oracleShift, oracleShift + params.numOracles))
.map { case (privKey, rVals) => .map { case (privKey, rVals) =>
OracleAnnouncementV0TLV.dummyForKeys(privKey, val nonces =
rVals.take(params.numDigits)) OrderedNonces.fromUnsorted(rVals.take(params.numDigits).toVector)
OracleAnnouncementV0TLV.dummyForKeys(privKey, nonces)
} }
val oracleInfo = if (params.numOracles == 1) { val oracleInfo = if (params.numOracles == 1) {
NumericSingleOracleInfo(announcements.head) NumericSingleOracleInfo(announcements.head)
@ -779,14 +789,17 @@ trait DLCTest {
def computeNumericOracleSignatures( def computeNumericOracleSignatures(
digits: Vector[Int], digits: Vector[Int],
privKey: ECPrivateKey = oraclePrivKey, privKey: ECPrivateKey = oraclePrivKey,
kVals: Vector[ECPrivateKey] = preCommittedKs): Vector[ kVals: Vector[ECPrivateKey] =
SchnorrDigitalSignature] = { preCommittedKs): OrderedSchnorrSignatures = {
val unsorted =
digits.zip(kVals.take(digits.length)).map { case (digit, kValue) => digits.zip(kVals.take(digits.length)).map { case (digit, kValue) =>
privKey.schnorrSignWithNonce(CryptoUtil privKey.schnorrSignWithNonce(CryptoUtil
.sha256DLCAttestation(digit.toString) .sha256DLCAttestation(digit.toString)
.bytes, .bytes,
kValue) kValue)
} }
OrderedSchnorrSignatures.fromUnsorted(unsorted)
} }
/** Deterministically chooses an outcome from the middle third of the interesting possible outcomes. */ /** Deterministically chooses an outcome from the middle third of the interesting possible outcomes. */
@ -1059,13 +1072,15 @@ trait DLCTest {
case (dlcOffer, offerSetup, dlcAccept, acceptSetup, outcomes) => case (dlcOffer, offerSetup, dlcAccept, acceptSetup, outcomes) =>
val testFs = outcomeIndices.map { val testFs = outcomeIndices.map {
case (contractIndex, outcomeIndex) => case (contractIndex, outcomeIndex) =>
executeForOutcome(outcomeIndex, executeForOutcome(
dlcOffer, outcomeIndex = outcomeIndex,
offerSetup, dlcOffer = dlcOffer,
dlcAccept, offerSetup = offerSetup,
acceptSetup, dlcAccept = dlcAccept,
outcomes, acceptSetup = acceptSetup,
contractIndex) outcomes = outcomes,
contractIndex = contractIndex
)
} }
Future.sequence(testFs).map(_ => succeed) Future.sequence(testFs).map(_ => succeed)

View file

@ -134,7 +134,10 @@ trait TLVGen {
Gen Gen
.listOfN(desc.noncesNeeded, CryptoGenerators.schnorrNonce) .listOfN(desc.noncesNeeded, CryptoGenerators.schnorrNonce)
.map(_.toVector) .map(_.toVector)
} yield OracleEventV0TLV(OrderedNonces(nonces), maturity, desc, uri) } yield OracleEventV0TLV(OrderedNonces.fromUnsorted(nonces),
maturity,
desc,
uri)
} }
def oracleAnnouncementV0TLV: Gen[OracleAnnouncementV0TLV] = { def oracleAnnouncementV0TLV: Gen[OracleAnnouncementV0TLV] = {
@ -150,10 +153,11 @@ trait TLVGen {
eventId <- StringGenerators.genUTF8String eventId <- StringGenerators.genUTF8String
pubkey <- CryptoGenerators.schnorrPublicKey pubkey <- CryptoGenerators.schnorrPublicKey
numSigs <- Gen.choose(1, 10) numSigs <- Gen.choose(1, 10)
sigs <- unsorted <-
Gen Gen
.listOfN(numSigs, CryptoGenerators.schnorrDigitalSignature) .listOfN(numSigs, CryptoGenerators.schnorrDigitalSignature)
.map(_.toVector) .map(_.toVector)
sigs = OrderedSchnorrSignatures.fromUnsorted(unsorted)
outcomes <- outcomes <-
Gen Gen
.listOfN(numSigs, StringGenerators.genUTF8String) .listOfN(numSigs, StringGenerators.genUTF8String)
@ -237,10 +241,10 @@ trait TLVGen {
def oracleInfoV0TLV(numDigits: Int): Gen[OracleInfoV0TLV] = { def oracleInfoV0TLV(numDigits: Int): Gen[OracleInfoV0TLV] = {
for { for {
privKey <- CryptoGenerators.privateKey privKey <- CryptoGenerators.privateKey
rValues <- Gen.listOfN(numDigits, CryptoGenerators.schnorrNonce) unsorted <- Gen.listOfN(numDigits, CryptoGenerators.schnorrNonce)
rValues = OrderedNonces.fromUnsorted(unsorted.toVector)
} yield { } yield {
OracleInfoV0TLV( OracleInfoV0TLV(OracleAnnouncementV0TLV.dummyForKeys(privKey, rValues))
OracleAnnouncementV0TLV.dummyForKeys(privKey, rValues.toVector))
} }
} }

View file

@ -21,6 +21,7 @@ import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature
import org.bitcoins.core.script.PreExecutionScriptProgram import org.bitcoins.core.script.PreExecutionScriptProgram
import org.bitcoins.core.script.interpreter.ScriptInterpreter import org.bitcoins.core.script.interpreter.ScriptInterpreter
import org.bitcoins.core.script.util.PreviousOutputMap import org.bitcoins.core.script.util.PreviousOutputMap
import org.bitcoins.core.util.sorted.{OrderedNonces, OrderedSchnorrSignatures}
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
import org.bitcoins.crypto._ import org.bitcoins.crypto._
import org.bitcoins.dlc.wallet.DLCWallet import org.bitcoins.dlc.wallet.DLCWallet
@ -37,9 +38,14 @@ import scala.concurrent.{ExecutionContext, Future}
object DLCWalletUtil extends Logging { object DLCWalletUtil extends Logging {
lazy val oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey lazy val oraclePrivKey: ECPrivateKey = ECPrivateKey.freshPrivateKey
lazy val kValues: Vector[ECPrivateKey] = lazy val kValues: Vector[ECPrivateKey] = {
0.to(10).map(_ => ECPrivateKey.freshPrivateKey).toVector ECPrivateKey.generateNonceOrderedPrivKeys(10)
lazy val rValues: Vector[SchnorrNonce] = kValues.map(_.schnorrNonce) }
lazy val rValues: OrderedNonces = {
val nonces = kValues.map(_.schnorrNonce)
OrderedNonces.fromUnsorted(nonces)
}
lazy val kValue: ECPrivateKey = kValues.head lazy val kValue: ECPrivateKey = kValues.head
lazy val rValue: SchnorrNonce = rValues.head lazy val rValue: SchnorrNonce = rValues.head
@ -133,10 +139,12 @@ object DLCWalletUtil extends Logging {
lazy val multiNonceContractDescriptor: NumericContractDescriptor = lazy val multiNonceContractDescriptor: NumericContractDescriptor =
DLCTestUtil.genMultiDigitContractInfo(numDigits, total)._1 DLCTestUtil.genMultiDigitContractInfo(numDigits, total)._1
lazy val multiNonceOracleInfo: NumericSingleOracleInfo = lazy val multiNonceOracleInfo: NumericSingleOracleInfo = {
val unsorted = rValues.take(numDigits).toVector
val sorted = OrderedNonces.fromUnsorted(unsorted)
NumericSingleOracleInfo( NumericSingleOracleInfo(
OracleAnnouncementV0TLV.dummyForKeys(oraclePrivKey, OracleAnnouncementV0TLV.dummyForKeys(oraclePrivKey, sorted))
rValues.take(numDigits))) }
lazy val multiNonceContractOraclePair: ContractOraclePair.NumericPair = { lazy val multiNonceContractOraclePair: ContractOraclePair.NumericPair = {
ContractOraclePair.NumericPair(multiNonceContractDescriptor, ContractOraclePair.NumericPair(multiNonceContractDescriptor,
@ -146,6 +154,9 @@ object DLCWalletUtil extends Logging {
lazy val multiNonceContractInfo: ContractInfo = lazy val multiNonceContractInfo: ContractInfo =
SingleContractInfo(total, multiNonceContractOraclePair) SingleContractInfo(total, multiNonceContractOraclePair)
lazy val numericContractInfoV0 =
multiNonceContractInfo.toTLV.asInstanceOf[ContractInfoV0TLV]
lazy val dummyContractMaturity: BlockTimeStamp = BlockTimeStamp(0) lazy val dummyContractMaturity: BlockTimeStamp = BlockTimeStamp(0)
lazy val dummyContractTimeout: BlockTimeStamp = BlockTimeStamp(1) lazy val dummyContractTimeout: BlockTimeStamp = BlockTimeStamp(1)
@ -503,11 +514,11 @@ object DLCWalletUtil extends Logging {
(OracleAttestmentV0TLV(eventId, (OracleAttestmentV0TLV(eventId,
publicKey, publicKey,
Vector(initiatorWinSig), OrderedSchnorrSignatures(initiatorWinSig),
Vector(initiatorWinStr)), Vector(initiatorWinStr)),
OracleAttestmentV0TLV(eventId, OracleAttestmentV0TLV(eventId,
publicKey, publicKey,
Vector(recipientWinSig), OrderedSchnorrSignatures(recipientWinSig),
Vector(recipientWinStr))) Vector(recipientWinStr)))
} }