mirror of
https://github.com/ACINQ/eclair.git
synced 2025-02-22 14:22:39 +01:00
implement revocation key derivation
This commit is contained in:
parent
1fe8b8feb2
commit
4e29d2b9fe
2 changed files with 76 additions and 0 deletions
|
@ -1,5 +1,7 @@
|
|||
package fr.acinq.protos
|
||||
|
||||
import java.math.BigInteger
|
||||
|
||||
import fr.acinq.bitcoin._
|
||||
import fr.acinq.eclair.channel.Scripts
|
||||
|
||||
|
@ -65,4 +67,56 @@ object Bolt3 {
|
|||
OP_CHECKSIG :: Nil
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
|
||||
def fixSize(data: BinaryData): BinaryData = data.length match {
|
||||
case 32 => data
|
||||
case length if length < 32 => Array.fill(32 - length)(0.toByte) ++ data
|
||||
}
|
||||
|
||||
case class Scalar(data: BinaryData) {
|
||||
require(data.length == 32)
|
||||
|
||||
def basePoint = BasePoint(Crypto.publicKeyFromPrivateKey(data :+ 1.toByte))
|
||||
|
||||
def add(scalar: Scalar): Scalar = {
|
||||
val buffer = new BigInteger(1, data).add(new BigInteger(1, scalar.data)).mod(Crypto.curve.getN).toByteArray
|
||||
val buffer1 = fixSize(buffer.dropWhile(_ == 0))
|
||||
Scalar(buffer1)
|
||||
}
|
||||
|
||||
def multiply(scalar: Scalar): Scalar = {
|
||||
val buffer = new BigInteger(1, data).multiply(new BigInteger(1, scalar.data)).mod(Crypto.curve.getN).toByteArray
|
||||
val buffer1 = fixSize(buffer.dropWhile(_ == 0))
|
||||
Scalar(buffer1)
|
||||
}
|
||||
}
|
||||
|
||||
case class BasePoint(data: BinaryData) {
|
||||
require(data.length == 33)
|
||||
|
||||
def add(point: BasePoint): BasePoint = {
|
||||
val local = Crypto.curve.getCurve.decodePoint(data)
|
||||
val rhs = Crypto.curve.getCurve.decodePoint(point.data)
|
||||
BasePoint(local.add(rhs).getEncoded(true))
|
||||
}
|
||||
|
||||
def multiply(scalar: Scalar): BasePoint = {
|
||||
val local = Crypto.curve.getCurve.decodePoint(data)
|
||||
val point = local.multiply(new BigInteger(1, scalar.data))
|
||||
BasePoint(point.getEncoded(true))
|
||||
}
|
||||
}
|
||||
|
||||
def revocationPubKey(revocationBasePoint: BasePoint, perCommitPoint: BasePoint): BasePoint = {
|
||||
val a = Scalar(Crypto.sha256(revocationBasePoint.data ++ perCommitPoint.data))
|
||||
val b = Scalar(Crypto.sha256(perCommitPoint.data ++ revocationBasePoint.data))
|
||||
revocationBasePoint.multiply(a).add(perCommitPoint.multiply(b))
|
||||
}
|
||||
|
||||
def revocationPrivKey(revocationSecret: Scalar, perCommitSecret: Scalar): Scalar = {
|
||||
val a = Scalar(Crypto.sha256(revocationSecret.basePoint.data ++ perCommitSecret.basePoint.data))
|
||||
val b = Scalar(Crypto.sha256(perCommitSecret.basePoint.data ++ revocationSecret.basePoint.data))
|
||||
revocationSecret.multiply(a).add(perCommitSecret.multiply(b))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import fr.acinq.bitcoin._
|
|||
import fr.acinq.eclair.blockchain.ExtendedBitcoinClient
|
||||
import fr.acinq.eclair.blockchain.rpc.BitcoinJsonRPCClient
|
||||
import fr.acinq.eclair.channel.Scripts
|
||||
import fr.acinq.protos.Bolt3.Scalar
|
||||
import org.junit.runner.RunWith
|
||||
import org.scalatest.FunSuite
|
||||
import org.scalatest.junit.JUnitRunner
|
||||
|
@ -309,4 +310,25 @@ class Bolt3Spec extends FunSuite {
|
|||
Transaction.correctlySpends(penaltyTx, htlcSuccessTx :: Nil, ScriptFlags.STANDARD_SCRIPT_VERIFY_FLAGS)
|
||||
println(s"penalty for out htlc success tx: ${hex(penaltyTx)}")
|
||||
}
|
||||
|
||||
test("derive revocation key") {
|
||||
object Local {
|
||||
val revocationSecret = Scalar(Crypto.sha256("local foo".getBytes()))
|
||||
val revocationBasePoint = revocationSecret.basePoint
|
||||
val perCommitSecret = Scalar(Crypto.sha256("local bar".getBytes()))
|
||||
}
|
||||
object Remote {
|
||||
val revocationSecret = Scalar(Crypto.sha256("remote foo".getBytes()))
|
||||
val perCommitSecret = Scalar(Crypto.sha256("remote bar".getBytes()))
|
||||
val perCommitBasePoint = perCommitSecret.basePoint
|
||||
}
|
||||
|
||||
// I can compute their revocation pubkey
|
||||
val theirRevocationPubKey = Bolt3.revocationPubKey(Local.revocationBasePoint, Remote.perCommitBasePoint)
|
||||
|
||||
// and if they give me their per-commit secret I can compute their revocation privkey
|
||||
val theirRevocationPrivKey = Bolt3.revocationPrivKey(Local.revocationSecret, Remote.perCommitSecret)
|
||||
|
||||
assert(theirRevocationPrivKey.basePoint == theirRevocationPubKey)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue