gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/trustlessstreamer_test.go (about) 1 package renter 2 3 import ( 4 "bytes" 5 "testing" 6 7 "gitlab.com/NebulousLabs/fastrand" 8 "gitlab.com/SkynetLabs/skyd/skymodules" 9 "go.sia.tech/siad/crypto" 10 "go.sia.tech/siad/modules" 11 ) 12 13 // TestBuildSubSectionProof is a unit test for BuildSubSectionProof which builds 14 // a proof for every possible segment of a section. 15 func TestBuildSubSectionProof(t *testing.T) { 16 ec, err := skymodules.NewRSSubCode(2, 3, crypto.SegmentSize) 17 if err != nil { 18 t.Fatal(err) 19 } 20 21 // Create the encoded chunk. 22 pieceSize := modules.SectorSize //uint64(2 << 14) // 16 kib 23 chunkSize := pieceSize * uint64(ec.MinPieces()) 24 chunk0 := fastrand.Bytes(int(chunkSize)) 25 chunk1 := fastrand.Bytes(int(chunkSize)) 26 logicalChunkData0, err := ec.Encode(append([]byte{}, chunk0...)) // deep-copy to not modify 'chunk' 27 if err != nil { 28 t.Fatal(err) 29 } 30 logicalChunkData1, err := ec.Encode(append([]byte{}, chunk1...)) // deep-copy to not modify 'chunk' 31 if err != nil { 32 t.Fatal(err) 33 } 34 chunks := [][]byte{chunk0, chunk1} 35 logicalChunkDatas := [][][]byte{logicalChunkData0, logicalChunkData1} 36 37 // Get number of sections per chunk. 38 requestSize := SkylinkDataSourceRequestSize 39 numSections := chunkSize / requestSize 40 if chunkSize%requestSize != 0 { 41 t.Fatal("chunkSize should be cleanly divided by request size") 42 } 43 44 // Run the test for every potential section of the chunks. 45 for chunkIndex, chunk := range chunks { 46 logicalChunkData := logicalChunkDatas[chunkIndex] 47 48 for sectionIndex := uint64(0); sectionIndex < numSections; sectionIndex++ { 49 // Compute the offset and length of the section within the 50 // chunk. 51 offsetInChunk := requestSize * sectionIndex 52 lengthInChunk := requestSize 53 54 // Trim the logical chunk data to only contain the parts of the 55 // pieces relevant to the section. 56 lcd := make([][]byte, len(logicalChunkData)) 57 pieceOff, pieceLen := GetPieceOffsetAndLen(ec, offsetInChunk, lengthInChunk) 58 for pieceIndex := range lcd { 59 lcd[pieceIndex] = logicalChunkData[pieceIndex][pieceOff : pieceOff+pieceLen] 60 } 61 62 // Create the proofs for each piece. That is the proof that the 63 // section is part of the sector. 64 sectionProofStart := int(pieceOff) / crypto.SegmentSize 65 sectionProofEnd := int(pieceOff+pieceLen) / crypto.SegmentSize 66 var proofs [][]crypto.Hash 67 for _, piece := range logicalChunkData { 68 proof := crypto.MerkleRangeProof(piece, sectionProofStart, sectionProofEnd) 69 proofs = append(proofs, proof) 70 } 71 72 // The proofs should be valid. 73 for pieceIndex, piece := range lcd { 74 merkleRoot := crypto.MerkleRoot(logicalChunkData[pieceIndex]) 75 valid := crypto.VerifyRangeProof(piece, proofs[pieceIndex], int(pieceOff)/crypto.SegmentSize, int(pieceOff+pieceLen)/crypto.SegmentSize, merkleRoot) 76 if !valid { 77 t.Fatal("invalid merkle proof") 78 } 79 } 80 81 // Build the download response. 82 dr := newDownloadResponse(offsetInChunk, lengthInChunk, ec, lcd, proofs, nil) 83 84 // The download response should be able to recover the right 85 // data. 86 section, err := dr.externDownloadedData.Recover() 87 if err != nil { 88 t.Fatal(err) 89 } 90 if !bytes.Equal(section, chunk[offsetInChunk:offsetInChunk+lengthInChunk]) { 91 t.Fatal("mismatch", len(section), lengthInChunk) 92 } 93 94 // For every segment of every logical piece within the downloaded data, create a 95 // proof that proves this segment is contained within a section 96 // by combining the section proof and segment proof using 97 // ComputeSectionProof. 98 for pieceIndex := range dr.externDownloadedData.Proofs { 99 // Compute the merkle root of the logical piece. 100 merkleRoot := crypto.MerkleRoot(logicalChunkData[pieceIndex]) 101 102 // Grab the section proof. This proves that the section 103 // is part of a sector. 104 sectionProof := dr.externDownloadedData.Proofs[pieceIndex] 105 106 // Build one proof for every segment of the section. 107 for startSegment := 0; startSegment < len(lcd[pieceIndex])/crypto.SegmentSize; startSegment++ { 108 // Create the subSectionProof. This proves that 109 // the downloaded data is part of the section. 110 subSectionProof := crypto.MerkleRangeProof(lcd[pieceIndex], startSegment, startSegment+1) 111 112 // Build the combined proof of section and 113 // sub-section proof. This proves that the 114 // downloaded data is part of a sector. 115 combinedProof := BuildSubSectionProof(sectionIndex, subSectionProof, sectionProof) 116 117 // Verify the proof. 118 segmentProofStart := sectionProofStart + startSegment 119 segmentProofEnd := segmentProofStart + 1 120 logicalPiece := lcd[pieceIndex] 121 valid := crypto.VerifyRangeProof(logicalPiece[startSegment*crypto.SegmentSize:][:crypto.SegmentSize], combinedProof, segmentProofStart, segmentProofEnd, merkleRoot) 122 if !valid { 123 t.Fatal("invalid merkle proof") 124 } 125 } 126 } 127 } 128 } 129 }