Make the round participants sign the vtxo tree (#271)

* [proto] add APIs to send and receive musig2 signing data

* [common] add serialization functions for nonces and signatures

* [application] implements tree signing

* fix: remove old debug logs

* [proto] cleaning

* [common] fix musig2.go

* [application] fixes and logs

* [interface] fix: stop forwarding 2 times the events

* [client] add musig2 support + sign the tree when joining a round

* [interface] add new APIs into permissions.go

* [application][proto] rework PingResponse (return all events type)

* [common] split SetKeys into 2 distinct methods

* [client] fixes according to musig2.go changes

* [sdk] support tree signing + new PingResponse

* [sdk] fixes

* [application] revert event channel type

* [application] use domain.RoundEvent as lastEvent type

* [application] remove IsCovenantLess

* comments

* [application] revert roundAborted changes

* [interface] remove bitcointree dependencie
This commit is contained in:
Louis Singer
2024-08-30 14:32:35 +02:00
committed by GitHub
parent 1b9660ec89
commit c183f99244
40 changed files with 4143 additions and 713 deletions

View File

@@ -262,7 +262,11 @@ func (a *covenantlessArkClient) Onboard(
return "", err
}
if err := signer.SetKeys(cosigners, aggregatedNonces); err != nil {
if err := signer.SetKeys(cosigners); err != nil {
return "", err
}
if err := signer.SetAggregatedNonces(aggregatedNonces); err != nil {
return "", err
}
@@ -608,7 +612,16 @@ func (a *covenantlessArkClient) CollaborativeRedeem(
})
}
paymentID, err := a.client.RegisterPayment(ctx, inputs)
roundEphemeralKey, err := secp256k1.GeneratePrivateKey()
if err != nil {
return "", err
}
paymentID, err := a.client.RegisterPayment(
ctx,
inputs,
hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
)
if err != nil {
return "", err
}
@@ -618,7 +631,7 @@ func (a *covenantlessArkClient) CollaborativeRedeem(
}
poolTxID, err := a.handleRoundStream(
ctx, paymentID, selectedCoins, receivers,
ctx, paymentID, selectedCoins, receivers, roundEphemeralKey,
)
if err != nil {
return "", err
@@ -990,8 +1003,13 @@ func (a *covenantlessArkClient) sendOffchain(
})
}
roundEphemeralKey, err := secp256k1.GeneratePrivateKey()
if err != nil {
return "", err
}
paymentID, err := a.client.RegisterPayment(
ctx, inputs,
ctx, inputs, hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
)
if err != nil {
return "", err
@@ -1006,7 +1024,7 @@ func (a *covenantlessArkClient) sendOffchain(
log.Infof("payment registered with id: %s", paymentID)
poolTxID, err := a.handleRoundStream(
ctx, paymentID, selectedCoins, receiversOutput,
ctx, paymentID, selectedCoins, receiversOutput, roundEphemeralKey,
)
if err != nil {
return "", err
@@ -1144,7 +1162,10 @@ func (a *covenantlessArkClient) addVtxoInput(
func (a *covenantlessArkClient) handleRoundStream(
ctx context.Context,
paymentID string, vtxosToSign []client.Vtxo, receivers []client.Output,
paymentID string,
vtxosToSign []client.Vtxo,
receivers []client.Output,
roundEphemeralKey *secp256k1.PrivateKey,
) (string, error) {
eventsCh, err := a.client.GetEventStream(ctx, paymentID)
if err != nil {
@@ -1158,6 +1179,8 @@ func (a *covenantlessArkClient) handleRoundStream(
defer pingStop()
var signerSession bitcointree.SignerSession
for {
select {
case <-ctx.Done():
@@ -1172,6 +1195,25 @@ func (a *covenantlessArkClient) handleRoundStream(
return event.(client.RoundFinalizedEvent).Txid, nil
case client.RoundFailedEvent:
return "", fmt.Errorf("round failed: %s", event.(client.RoundFailedEvent).Reason)
case client.RoundSigningStartedEvent:
pingStop()
log.Info("a round signing started")
signerSession, err = a.handleRoundSigningStarted(
ctx, roundEphemeralKey, event.(client.RoundSigningStartedEvent),
)
if err != nil {
return "", err
}
continue
case client.RoundSigningNoncesGeneratedEvent:
pingStop()
log.Info("round combined nonces generated")
if err := a.handleRoundSigningNoncesGenerated(
ctx, event.(client.RoundSigningNoncesGeneratedEvent), roundEphemeralKey, signerSession,
); err != nil {
return "", err
}
continue
case client.RoundFinalizationEvent:
pingStop()
log.Info("a round finalization started")
@@ -1200,6 +1242,73 @@ func (a *covenantlessArkClient) handleRoundStream(
}
}
func (a *covenantlessArkClient) handleRoundSigningStarted(
ctx context.Context, ephemeralKey *secp256k1.PrivateKey, event client.RoundSigningStartedEvent,
) (signerSession bitcointree.SignerSession, err error) {
sweepClosure := bitcointree.CSVSigClosure{
Pubkey: a.AspPubkey,
Seconds: uint(a.RoundLifetime),
}
sweepTapLeaf, err := sweepClosure.Leaf()
if err != nil {
return
}
sweepTapTree := txscript.AssembleTaprootScriptTree(*sweepTapLeaf)
root := sweepTapTree.RootNode.TapHash()
signerSession = bitcointree.NewTreeSignerSession(
ephemeralKey, event.UnsignedTree, int64(a.MinRelayFee), root.CloneBytes(),
)
if err = signerSession.SetKeys(event.CosignersPublicKeys); err != nil {
return
}
nonces, err := signerSession.GetNonces()
if err != nil {
return
}
myPubKey := hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed())
err = a.arkClient.client.SendTreeNonces(ctx, event.ID, myPubKey, nonces)
return
}
func (a *covenantlessArkClient) handleRoundSigningNoncesGenerated(
ctx context.Context,
event client.RoundSigningNoncesGeneratedEvent,
ephemeralKey *secp256k1.PrivateKey,
signerSession bitcointree.SignerSession,
) error {
if signerSession == nil {
return fmt.Errorf("tree signer session not set")
}
if err := signerSession.SetAggregatedNonces(event.Nonces); err != nil {
return err
}
sigs, err := signerSession.Sign()
if err != nil {
return err
}
if err := a.arkClient.client.SendTreeSignatures(
ctx,
event.ID,
hex.EncodeToString(ephemeralKey.PubKey().SerializeCompressed()),
sigs,
); err != nil {
return err
}
return nil
}
func (a *covenantlessArkClient) handleRoundFinalization(
ctx context.Context, event client.RoundFinalizationEvent,
vtxos []client.Vtxo, receivers []client.Output,
@@ -1619,7 +1728,16 @@ func (a *covenantlessArkClient) selfTransferAllPendingPayments(
outputs := []client.Output{myself}
paymentID, err := a.client.RegisterPayment(ctx, inputs)
roundEphemeralKey, err := secp256k1.GeneratePrivateKey()
if err != nil {
return "", err
}
paymentID, err := a.client.RegisterPayment(
ctx,
inputs,
hex.EncodeToString(roundEphemeralKey.PubKey().SerializeCompressed()),
)
if err != nil {
return "", err
}
@@ -1629,7 +1747,7 @@ func (a *covenantlessArkClient) selfTransferAllPendingPayments(
}
roundTxid, err := a.handleRoundStream(
ctx, paymentID, pendingVtxos, outputs,
ctx, paymentID, pendingVtxos, outputs, roundEphemeralKey,
)
if err != nil {
return "", err