From edb5d854df227669dd78ce9faee0111e67793172 Mon Sep 17 00:00:00 2001 From: ffranr Date: Tue, 10 Dec 2024 17:53:03 +0000 Subject: [PATCH] asset+proof: update GroupKeyRevealDecoder to handle multiple versions Enhance the GroupKeyRevealDecoder to first attempt decoding as GroupKeyRevealV0. If this fails with a specific expected error, fallback to decoding as GroupKeyRevealV1. --- asset/asset.go | 9 ++++++++- proof/encoding.go | 49 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/asset/asset.go b/asset/asset.go index 93c7d2ed3..c963e7fab 100644 --- a/asset/asset.go +++ b/asset/asset.go @@ -918,6 +918,13 @@ type GroupVirtualTx struct { TweakedKey btcec.PublicKey } +var ( + // ErrGroupKeyRevealDecodeVersion is returned when the group key reveal + // version does not + ErrGroupKeyRevealDecodeVersion = errors.New("invalid decode version " + + "for group key reveal") +) + // GroupKeyReveal represents the data used to derive the adjusted key that // uniquely identifies an asset group. type GroupKeyReveal interface { @@ -1244,7 +1251,7 @@ func (g *GroupKeyRevealV0) Decode(r io.Reader, buf *[8]byte, l uint64) error { // is essential to prevent misinterpreting V1 and later group key // reveals as V0. if l > btcec.PubKeyBytesLenCompressed+sha256.Size { - return tlv.ErrRecordTooLarge + return ErrGroupKeyRevealDecodeVersion } if l < btcec.PubKeyBytesLenCompressed { diff --git a/proof/encoding.go b/proof/encoding.go index b5de89a8b..bec11db6a 100644 --- a/proof/encoding.go +++ b/proof/encoding.go @@ -2,6 +2,7 @@ package proof import ( "bytes" + "errors" "fmt" "io" "math" @@ -483,14 +484,52 @@ func GroupKeyRevealDecoder(r io.Reader, val any, buf *[8]byte, l uint64) error { return tlv.NewTypeForEncodingErr(val, "GroupKeyReveal") } + // Use a TeeReader to capture the read bytes, enabling the construction + // of a new reader for subsequent decoding attempts. + var readBuf bytes.Buffer + teeReader := io.TeeReader(r, &readBuf) + // Attempt decoding with GroupKeyRevealV0. - var gkrV0 asset.GroupKeyRevealV0 - err := gkrV0.Decode(r, buf, l) + var ( + gkrV0 asset.GroupKeyRevealV0 + scratchBufV0 [8]byte + ) + + err := gkrV0.Decode(teeReader, &scratchBufV0, l) + if err != nil { + // If the error is not related to versioning, return the error. + errIsVersionRelated := errors.Is( + err, asset.ErrGroupKeyRevealDecodeVersion, + ) + if !errIsVersionRelated { + return fmt.Errorf("group key reveal V0 decode "+ + "error: %w", err) + } + } + + // If the decoding was successful, set the value, the scratch buffer, + // and return. + if err == nil { + *typ = &gkrV0 + *buf = scratchBufV0 + return nil + } + + // Attempt decoding with GroupKeyRevealV1. + var ( + gkrV1 asset.GroupKeyRevealV1 + scratchBufV1 [8]byte + newReader = bytes.NewReader(readBuf.Bytes()) + ) + + err = gkrV1.Decode(newReader, &scratchBufV1, l) if err != nil { - return fmt.Errorf("group key reveal V0 decode error: %w", err) + return fmt.Errorf("group key reveal V1 decode error: %w", err) } - // If the decoding was successful, set the value and return. - *typ = &gkrV0 + // If the decoding was successful, set the value, the scratch buffer, + // and return. + *typ = &gkrV1 + *buf = scratchBufV1 return nil }