Give oracle ability to sign messages with private key (#3070)

This commit is contained in:
benthecarman 2021-05-12 10:09:34 -05:00 committed by GitHub
parent aff2374f45
commit 2b8ac08cdc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 95 additions and 1 deletions

View file

@ -1313,6 +1313,20 @@ object ConsoleCli {
case other => other
}))
),
cmd("signmessage")
.action((_, conf) => conf.copy(command = SignMessage("")))
.text("Signs the SHA256 hash of the given string using the oracle's signing key")
.children(
arg[String]("message")
.text("Message to hash and sign")
.required()
.action((msg, conf) =>
conf.copy(command = conf.command match {
case signMessage: SignMessage =>
signMessage.copy(message = msg)
case other => other
}))
),
note(sys.props("line.separator") + "=== Util ==="),
cmd("createmultisig")
.action((_, conf) =>
@ -1628,6 +1642,9 @@ object ConsoleCli {
case GetSignatures(eventName) =>
RequestParam("getsignatures", Seq(up.writeJs(eventName)))
case SignMessage(message) =>
RequestParam("signmessage", Seq(up.writeJs(message)))
case CreateMultisig(requiredKeys, keys, addressType) =>
RequestParam("createmultisig",
Seq(up.writeJs(requiredKeys),
@ -1997,4 +2014,6 @@ object CliCommand {
extends OracleServerCliCommand
case class GetSignatures(eventName: String) extends OracleServerCliCommand
case class SignMessage(message: String) extends OracleServerCliCommand
}

View file

@ -319,5 +319,22 @@ class OracleRoutesSpec
String] == s"""{"result":"${dummyAttestmentTLV.hex}","error":null}""")
}
}
"sign message" in {
(mockOracleApi
.signMessage(_: String))
.expects("message")
.returning(sig)
val route =
oracleRoutes.handleCommand(
ServerCommand("signmessage", Arr(Str("message"))))
Post() ~> route ~> check {
assert(contentType == `application/json`)
assert(
responseAs[String] == s"""{"result":"${sig.hex}","error":null}""")
}
}
}
}

View file

@ -232,6 +232,17 @@ case class OracleRoutes(oracle: DLCOracleApi)(implicit
}
}
case ServerCommand("signmessage", arr) =>
SignMessage.fromJsArr(arr) match {
case Failure(exception) =>
reject(ValidationRejection("failure", Some(exception)))
case Success(SignMessage(message)) =>
complete {
val signature = oracle.signMessage(message)
Server.httpSuccess(signature.hex)
}
}
case ServerCommand("keymanagerpassphrasechange", arr) =>
KeyManagerPassphraseChange.fromJsArr(arr) match {
case Failure(err) =>

View file

@ -13,6 +13,28 @@ import java.time.Instant
import scala.util.control.NonFatal
import scala.util.{Failure, Try}
case class SignMessage(message: String)
object SignMessage extends ServerJsonModels {
def fromJsArr(jsArr: ujson.Arr): Try[SignMessage] = {
jsArr.arr.toList match {
case strJs :: Nil =>
Try {
val message = strJs.str
SignMessage(message)
}
case Nil =>
Failure(new IllegalArgumentException("Missing message argument"))
case other =>
Failure(
new IllegalArgumentException(
s"Bad number of arguments: ${other.length}. Expected: 1"))
}
}
}
case class CreateEvent(
label: String,
maturationTime: Instant,

View file

@ -6,7 +6,8 @@ import org.bitcoins.core.number._
import org.bitcoins.core.protocol.Bech32Address
import org.bitcoins.core.protocol.dlc.SigningVersion
import org.bitcoins.core.protocol.tlv._
import org.bitcoins.crypto.{SchnorrNonce, SchnorrPublicKey}
import org.bitcoins.crypto._
import scodec.bits.ByteVector
import java.time.Instant
import scala.concurrent.Future
@ -76,4 +77,12 @@ trait DLCOracleApi {
* the oracle private key will be revealed.
*/
def deleteAttestations(oracleEventTLV: OracleEventTLV): Future[OracleEvent]
/** Signs the SHA256 hash of the given string using the oracle's signing key */
def signMessage(message: String): SchnorrDigitalSignature = {
signMessage(CryptoUtil.serializeForHash(message))
}
/** Signs the SHA256 hash of the given bytes using the oracle's signing key */
def signMessage(message: ByteVector): SchnorrDigitalSignature
}

View file

@ -60,6 +60,13 @@ class DLCOracleTest extends DLCOracleFixture {
}
}
it must "correctly sign a message" in { dlcOracle: DLCOracle =>
val message = "hello world"
val signature = dlcOracle.signMessage(message)
assert(
dlcOracle.publicKey.verify(CryptoUtil.sha256(message).bytes, signature))
}
it must "get the correctly sorted nonces in an announcement " in {
dlcOracle: DLCOracle =>
val eventName = "test"

View file

@ -18,6 +18,7 @@ import org.bitcoins.dlc.oracle.config.DLCOracleAppConfig
import org.bitcoins.dlc.oracle.storage._
import org.bitcoins.dlc.oracle.util.EventDbUtil
import org.bitcoins.keymanager.{DecryptedMnemonic, WalletStorage}
import scodec.bits.ByteVector
import java.time.Instant
import scala.concurrent.{ExecutionContext, Future}
@ -373,6 +374,12 @@ class DLCOracle(private[this] val extPrivateKey: ExtPrivateKeyHardened)(implicit
} yield OracleEvent.fromEventDbs(signSig ++ digitSigs)
}
/** @inheritdoc */
def signMessage(message: ByteVector): SchnorrDigitalSignature = {
val hash = CryptoUtil.sha256(message)
signingKey.schnorrSign(hash.bytes)
}
/** Deletes attestations for the given event
*
* WARNING: if previous signatures have been made public

View file

@ -44,6 +44,8 @@ checkout [this page](build-oracle-server.md).
- `outcome` - Number to sign for this event
- `getsignatures` `event` - Get the signatures from a signed event
- `eventName` - The event's name
- `signmessage` `message` - Signs the SHA256 hash of the given string using the oracle's signing key
- `message` - Message to hash and sign
### Create Event Example