Skip to content

Commit

Permalink
Merge pull request #488 from lightninglabs/proof-magic-bytes
Browse files Browse the repository at this point in the history
proof: add magic bytes to individual proofs and proof files
  • Loading branch information
guggero authored Sep 8, 2023
2 parents 9628583 + d89392d commit c5bdbfe
Show file tree
Hide file tree
Showing 20 changed files with 707 additions and 527 deletions.
4 changes: 2 additions & 2 deletions cmd/tapcli/proofs.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func verifyProof(ctx *cli.Context) error {
defer cleanUp()

resp, err := client.VerifyProof(ctxc, &taprpc.ProofFile{
RawProof: rawFile,
RawProofFile: rawFile,
})
if err != nil {
return fmt.Errorf("unable to verify proof file: %w", err)
Expand Down Expand Up @@ -273,7 +273,7 @@ func exportProof(ctx *cli.Context) error {
// JSON format.
if ctx.String(proofPathName) != "" {
filePath := lncfg.CleanAndExpandPath(ctx.String(proofPathName))
return writeToFile(filePath, resp.RawProof)
return writeToFile(filePath, resp.RawProofFile)
}

printRespJSON(resp)
Expand Down
4 changes: 2 additions & 2 deletions itest/addrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,10 @@ func sendProof(t *harnessTest, src, dst *tapdHarness, scriptKey []byte,
}, defaultWaitTimeout)
require.NoError(t.t, waitErr)

t.Logf("Importing proof %x", proofResp.RawProof)
t.Logf("Importing proof %x", proofResp.RawProofFile)

importResp, err := dst.ImportProof(ctxb, &tapdevrpc.ImportProofRequest{
ProofFile: proofResp.RawProof,
ProofFile: proofResp.RawProofFile,
GenesisPoint: genInfo.GenesisPoint,
})
require.NoError(t.t, err)
Expand Down
12 changes: 6 additions & 6 deletions itest/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func WaitForProofUpdate(t *testing.T, client taprpc.TaprootAssetsClient,

f := &proof.File{}
require.NoError(
t, f.Decode(bytes.NewReader(exportResp.RawProof)),
t, f.Decode(bytes.NewReader(exportResp.RawProofFile)),
)
lastProof, err := f.LastProof()
require.NoError(t, err)
Expand Down Expand Up @@ -255,7 +255,7 @@ func AssertAssetProofs(t *testing.T, tapClient taprpc.TaprootAssetsClient,
require.NoError(t, err)

file, snapshot := verifyProofBlob(
t, tapClient, chainClient, a, exportResp.RawProof,
t, tapClient, chainClient, a, exportResp.RawProofFile,
)

assetJSON, err := formatProtoJSON(a)
Expand All @@ -268,7 +268,7 @@ func AssertAssetProofs(t *testing.T, tapClient taprpc.TaprootAssetsClient,
t, CommitmentKey(t, a), snapshot.Asset.AssetCommitmentKey(),
)

return exportResp.RawProof
return exportResp.RawProofFile
}

// assertAssetProofsInvalid makes sure the proofs for the given asset can be
Expand All @@ -289,11 +289,11 @@ func assertAssetProofsInvalid(t *testing.T, tapd *tapdHarness,
require.NoError(t, err)

f := &proof.File{}
require.NoError(t, f.Decode(bytes.NewReader(exportResp.RawProof)))
require.NoError(t, f.Decode(bytes.NewReader(exportResp.RawProofFile)))

// Also make sure that the RPC can verify the proof as well.
verifyResp, err := tapd.VerifyProof(ctxt, &taprpc.ProofFile{
RawProof: exportResp.RawProof,
RawProofFile: exportResp.RawProofFile,
})
require.NoError(t, err)
require.False(t, verifyResp.Valid)
Expand All @@ -314,7 +314,7 @@ func verifyProofBlob(t *testing.T, tapClient taprpc.TaprootAssetsClient,

// Also make sure that the RPC can verify the proof as well.
verifyResp, err := tapClient.VerifyProof(ctxt, &taprpc.ProofFile{
RawProof: blob,
RawProofFile: blob,
})
require.NoError(t, err)
require.True(t, verifyResp.Valid)
Expand Down
4 changes: 2 additions & 2 deletions itest/send_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -861,11 +861,11 @@ func addProofTestVectorFromFile(t *testing.T, testName string,
require.NoError(t, waitErr)

if binaryFileName != "" {
test.WriteTestFileHex(t, binaryFileName, proofResp.RawProof)
test.WriteTestFileHex(t, binaryFileName, proofResp.RawProofFile)
}

var f proof.File
err := f.Decode(bytes.NewReader(proofResp.RawProof))
err := f.Decode(bytes.NewReader(proofResp.RawProofFile))
require.NoError(t, err)

if f.NumProofs() <= fileIndex {
Expand Down
25 changes: 24 additions & 1 deletion proof/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,15 @@ func NewFile(v Version, proofs ...Proof) (*File, error) {

// Encode encodes the proof file into `w` including its checksum.
func (f *File) Encode(w io.Writer) error {
err := binary.Write(w, binary.BigEndian, uint32(f.Version))
num, err := w.Write(FilePrefixMagicBytes[:])
if err != nil {
return err
}
if num != PrefixMagicBytesLength {
return errors.New("failed to write prefix magic bytes")
}

err = binary.Write(w, binary.BigEndian, uint32(f.Version))
if err != nil {
return err
}
Expand Down Expand Up @@ -137,6 +145,21 @@ func (f *File) Encode(w io.Writer) error {

// Decode decodes a proof file from `r`.
func (f *File) Decode(r io.Reader) error {
var prefixMagicBytes [PrefixMagicBytesLength]byte
num, err := r.Read(prefixMagicBytes[:])
if err != nil {
return err
}
if num != PrefixMagicBytesLength {
return errors.New("failed to read prefix magic bytes")
}

if prefixMagicBytes != FilePrefixMagicBytes {
return fmt.Errorf("invalid prefix magic bytes, expected %s, "+
"got %s", string(FilePrefixMagicBytes[:]),
string(prefixMagicBytes[:]))
}

var version uint32
if err := binary.Read(r, binary.BigEndian, &version); err != nil {
return err
Expand Down
67 changes: 67 additions & 0 deletions proof/proof.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package proof

import (
"bytes"
"errors"
"fmt"
"io"

"github.com/btcsuite/btcd/wire"
Expand Down Expand Up @@ -58,6 +60,48 @@ var (
RegtestOwnershipProofName = "ownership-proof.hex"
)

const (
// PrefixMagicBytesLength is the length of the magic bytes that are
// prefixed to individual proofs or proof files.
PrefixMagicBytesLength = 4
)

var (
// PrefixMagicBytes are the magic bytes that are prefixed to an
// individual transition or mint proof when encoding it. This is the
// ASCII encoding of the string "TAPP" (Taproot Assets Protocol Proof)
// in hex.
PrefixMagicBytes = [PrefixMagicBytesLength]byte{0x54, 0x41, 0x50, 0x50}

// FilePrefixMagicBytes are the magic bytes that are prefixed to a proof
// file when encoding it. This is the ASCII encoding of the string
// "TAPF" (Taproot Assets Protocol File) in hex.
FilePrefixMagicBytes = [PrefixMagicBytesLength]byte{
0x54, 0x41, 0x50, 0x46,
}
)

// IsSingleProof returns true if the given blob is an encoded individual
// mint/transition proof.
func IsSingleProof(blob Blob) bool {
if len(blob) < PrefixMagicBytesLength {
return false
}

return bytes.Equal(blob[:PrefixMagicBytesLength], PrefixMagicBytes[:])
}

// IsProofFile returns true if the given blob is an encoded proof file.
func IsProofFile(blob Blob) bool {
if len(blob) < PrefixMagicBytesLength {
return false
}

return bytes.Equal(
blob[:PrefixMagicBytesLength], FilePrefixMagicBytes[:],
)
}

// UpdateCallback is a callback that is called when proofs are updated because
// of a re-org.
type UpdateCallback func([]*Proof) error
Expand Down Expand Up @@ -212,6 +256,14 @@ func (p *Proof) DecodeRecords() []tlv.Record {

// Encode encodes a Proof into `w`.
func (p *Proof) Encode(w io.Writer) error {
num, err := w.Write(PrefixMagicBytes[:])
if err != nil {
return err
}
if num != PrefixMagicBytesLength {
return errors.New("failed to write prefix magic bytes")
}

stream, err := tlv.NewStream(p.EncodeRecords()...)
if err != nil {
return err
Expand All @@ -221,6 +273,21 @@ func (p *Proof) Encode(w io.Writer) error {

// Decode decodes a Proof from `r`.
func (p *Proof) Decode(r io.Reader) error {
var prefixMagicBytes [PrefixMagicBytesLength]byte
num, err := r.Read(prefixMagicBytes[:])
if err != nil {
return err
}
if num != PrefixMagicBytesLength {
return errors.New("failed to read prefix magic bytes")
}

if prefixMagicBytes != PrefixMagicBytes {
return fmt.Errorf("invalid prefix magic bytes, expected %s, "+
"got %s", string(PrefixMagicBytes[:]),
string(prefixMagicBytes[:]))
}

stream, err := tlv.NewStream(p.DecodeRecords()...)
if err != nil {
return err
Expand Down
32 changes: 29 additions & 3 deletions proof/proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,12 +246,38 @@ func TestProofEncoding(t *testing.T) {
require.NoError(t, err)
proof.AdditionalInputs = []File{*file, *file}

var buf bytes.Buffer
require.NoError(t, proof.Encode(&buf))
var proofBuf bytes.Buffer
require.NoError(t, proof.Encode(&proofBuf))
proofBytes := proofBuf.Bytes()

var decodedProof Proof
require.NoError(t, decodedProof.Decode(&buf))
require.NoError(t, decodedProof.Decode(bytes.NewReader(proofBytes)))

assertEqualProof(t, &proof, &decodedProof)

// Make sure the proof and proof file prefixes are checked correctly.
var fileBuf bytes.Buffer
require.NoError(t, file.Encode(&fileBuf))
fileBytes := fileBuf.Bytes()

p := &Proof{}
err = p.Decode(bytes.NewReader(fileBytes))
require.ErrorContains(
t, err, "invalid prefix magic bytes, expected TAPP",
)

f := &File{}
err = f.Decode(bytes.NewReader(proofBytes))
require.ErrorContains(
t, err, "invalid prefix magic bytes, expected TAPF",
)

require.True(t, IsSingleProof(proofBytes))
require.True(t, IsProofFile(fileBytes))
require.False(t, IsProofFile(proofBytes))
require.False(t, IsSingleProof(fileBytes))
require.False(t, IsProofFile(nil))
require.False(t, IsSingleProof(nil))
}

func genRandomGenesisWithProof(t testing.TB, assetType asset.Type,
Expand Down
2 changes: 1 addition & 1 deletion proof/testdata/ownership-proof.hex
Original file line number Diff line number Diff line change
@@ -1 +1 @@
00240eebbbf4b53b1759d7cac14c6414b85815bf4df5f91f9ab7db3af230d787c1e000000001015000004020881098b292c1342c3880f14b416a641c21c2f312ce0127bb121f27d5a15496433da16a1b841ed6743acdae8eab606ab9a0820aecb5e57da538573d1e879f4178577cf064ffff7f200200000002fd018c0200000000010200f7627d2a9f7186d9e3e18009a81dc39d7d5c527b4ecb4049d02f3d4d07e5940000000000ffffffff0eebbbf4b53b1759d7cac14c6414b85815bf4df5f91f9ab7db3af230d787c1e001000000000000000003e8030000000000002251201ddfbf3832ad0061453e6533e2b98bb6b344ef9addb3222cb56a9f37fadee2bbe8030000000000002251205a7c661fd2b45837e8b1096cac64dff973b8afa3deb3c269c95af12a5ee348884aa9f505000000002251200c011e5c0cf6fe653634b835845f835b95a07818336e45d0fa51bf8eacba085f0247304402206a96d02679d947906572e8083569aa2c2ce4a582f4c0f75aa9c313bee9daf7d8022052af856a8f8b8e69d689ac3c9b3ef348ea38728942750b913771abfe3f08e07c01210246e7a2190cfa4cfd80ef894cc0e3752e682a8cb334710c01fc11f5ead08a910c0140ec31f6ed956aee5b5bf5d6a0040c5c0de9727537db72e6bf8b5a37a531225ccf63591131043b1c4e6cc9d58238df2c402fa404118d52f65123d103916c1970300000000003220163b1e755ba02747c67db8fe1fa693dcf9e66f9333f58bffb4f06ce8501c207fb0004fd02b400010001590075dc43685274cde4fe26577ae1bc945cedd6d2421ea22bde862ea9d5c7278c000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd025806fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a000151a8d993f84dbcbd37fa9e637701df24adcd8ecb9f3673d52c4e2ee2ead56e5c0000000000000258ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffd016600010001590075dc43685274cde4fe26577ae1bc945cedd6d2421ea22bde862ea9d5c7278c000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd025806ad01ab00650eebbbf4b53b1759d7cac14c6414b85815bf4df5f91f9ab7db3af230d787c1e000000001af46688108d6b3a8a7133502b742290df126c9f0649e26754225ea45935fdfd402c3239dc920d64be74c8ed1dfccaa26550e5c8cee2d6d12881ab0d3183c60d6ad01420140afa7bdc77debb61cbf36aa9cb601534d52aa49a1079cf64a1d44586e651bfa0fa02deea716e6e4f8fe8eae052b5950a54b1fc0b2eaf522c0b467a86b4de2546f07281b4bd820fed5f617faf7f481a8d076dd8be8e7fe5ca5e3163282c9105818d54900000000000004b0080200000921026fbf5bf92953f9bcf93603befd44dc83fcfd813a5a4adb40be42427378e8b5b508020000092102777d47bfc5e62bdd5199995fb6c485069239b92b083d9d6723917b75176d70ac059f000400000001012102bb464af24d0d8a24611c821e08f3fd57054ccac7b5875905bc6e045060f79503027400490001000120af46688108d6b3a8a7133502b742290df126c9f0649e26754225ea45935fdfd402220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06f802c700040000000001210315e5b3b06d61b3ad951f51d1daf4a3b8ec224224ea4025e72dda731d590497c9029c00710001000120af46688108d6b3a8a7133502b742290df126c9f0649e26754225ea45935fdfd4024a0001c4207b6354ab04e407d260e4e01f8a0626639071b556a0961da00fbfe7c7964f0000000000000258ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e000400000002012102c7df030275b2ea0de67f7158d8cc1bd28fe98881d1fdac0db674ad62d04b02ce0303020101079f00040000000001210315e5b3b06d61b3ad951f51d1daf4a3b8ec224224ea4025e72dda731d590497c9027400490001000120af46688108d6b3a8a7133502b742290df126c9f0649e26754225ea45935fdfd402220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a420140f840a182fba1a6eae0c1bcd7d9e4bc257c711480e2d7f93dd421134f23c63ebccf327a6930ce0bcbd17bd388659db0d59e272d9877fcc1fef68e9a901bf9efa10b04000001bc
5441505000248f6f371662879ba4db9cce742e4e79703f772a51dfbc65a00bf5dd6964e3ff190000000101500000402017b41c426f6e0ea2318a0272c0e5166355a97e0b45e014ae265b055cf15e4a09cac22e8351343ddf97acbf38f547709654cc4cdb49bdfb77c3b195e44e1345cd697ef864ffff7f200000000002fd018c02000000000102000b9c5425fd4186521743f78203b73a0cc85fffeeb48026f11bb6eed16a1f290000000000ffffffff8f6f371662879ba4db9cce742e4e79703f772a51dfbc65a00bf5dd6964e3ff1901000000000000000003e8030000000000002251206be9cc2c4d68ec4e9827bff12067bca0770a92fd10e346c9587eb674e534b2d4e8030000000000002251209556a078749c7a768ccbb97124296639ffa4785b59c82c4c135121e0217a96a44aa9f50500000000225120a152904d7685c3e24c348784140064f68ea252af71560c9c400574e696f375f502473044022069b2a86cf0a1e9f3f23bd38cab06c99a3ed326b4a2bdf932c744e8a662fe9cf302206911494f403f7e0aff12d53a3ec8dff3b8792bbcb6769499ae84e0423e39486c012102e641075343b4dae91de76437617f51a4c251395600c763595a8128f296dcb02901404986e85a6e29e02504b22b313bff0de240164a5b2d1309d2ffe1b841742c72042c40b70609c0206a6660d97dd812911eb054f2548d847989937b7e06459753460000000003220162a6107a3639a2d6d21ea74f905bbdd2cd760247197c19250125cce69ad617150004fd02b400010001590476d8a24114bbe8346622da3422784ed07c069deb8f1bc388664b31156379bc000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd025806fd022301fd021f0065000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fd01b44a0001cac8adc6fbff43b96418da0830e41cc24e687198fae443bbe64d13df6630dc830000000000000258ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffd016600010001590476d8a24114bbe8346622da3422784ed07c069deb8f1bc388664b31156379bc000000000f66697273742d697465737462757878dedfcaf730cec72f6dbea97c64d4a4f3489edc3c2ff8413ad169e9717a3b058d00000000000201000303fd025806ad01ab00658f6f371662879ba4db9cce742e4e79703f772a51dfbc65a00bf5dd6964e3ff19000000010fb088e12cab13f6f2f0a9cb1a48132477f9bf81625c8d513071ce841ef39b960232cad83de89c46e89e5522cf298fa8082ff0724bc4b9d9f8f577984e21ebb2bb014201408d602ec4a118925c23597faa896bccb675025b95f6827e29d6aa4a109eeea5ff64abdef145caa91bcba5f89d5dc79186620b1ce71db2780417fc1cefe584d7d607287a1d9a8372ee98c20893e1ab4d8028f1d3661c5fee83dbcfc528bfa738e5b07100000000000004b008020000092102efd8980ab3cacc9183c45bbbdded673416dba20a21486343d2dbbc5c37a0659b080200000921021cd140129b6140352dbf4469c8f2fbe4b3567479925f0619f59e8dfad0e0ea02059f000400000001012103a5d14787afdd48b27852302d8e6044adc80b2b09a84e405bd15df0a58372cb090274004900010001200fb088e12cab13f6f2f0a9cb1a48132477f9bf81625c8d513071ce841ef39b9602220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff06f802c7000400000000012103a2989befc0beca8bd322df75b77adbffcd472231e4f0f6709ba355c2590bafdb029c007100010001200fb088e12cab13f6f2f0a9cb1a48132477f9bf81625c8d513071ce841ef39b96024a000113e93b60b459b01018e7d1c419a0c085dc2a8022272f096228640e957005277a0000000000000258ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e000400000002012102fe7cd697bcc60a44dfd209ed970e6cd14d6094506a47a2a6a5b0cfa6f63dd0d60303020101079f000400000000012103a2989befc0beca8bd322df75b77adbffcd472231e4f0f6709ba355c2590bafdb0274004900010001200fb088e12cab13f6f2f0a9cb1a48132477f9bf81625c8d513071ce841ef39b9602220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff012700010001220000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a420140e960b17b2a7553e40958ee541c99c31b1143fb6ff70c363d04a761111ec634e4526d969945031d185f32df5f20bc2a2e6b4617e58db851fe559bf91f8e9ea4b70b04000001bc
Loading

0 comments on commit c5bdbfe

Please sign in to comment.