@@ -199,3 +199,120 @@ func BaoVerifyBuf(data, outboard []byte, group int, root [32]byte) bool {
199199 ok , _ := BaoDecode (io .Discard , d , or , group , root )
200200 return ok && d .Len () == 0 && o .Len () == 0 // check for trailing data
201201}
202+
203+ // BaoExtractSlice returns the slice encoding for the given offset and length.
204+ // When extracting from an outboard encoding, data should contain only the chunk
205+ // groups that will be present in the slice.
206+ func BaoExtractSlice (dst io.Writer , data , outboard io.Reader , group int , offset uint64 , length uint64 ) error {
207+ combinedEncoding := outboard == nil
208+ if combinedEncoding {
209+ outboard = data
210+ }
211+ groupSize := uint64 (chunkSize << group )
212+ buf := make ([]byte , groupSize )
213+ var err error
214+ read := func (r io.Reader , n uint64 , copy bool ) {
215+ if err == nil {
216+ _ , err = io .ReadFull (r , buf [:n ])
217+ if err == nil && copy {
218+ _ , err = dst .Write (buf [:n ])
219+ }
220+ }
221+ }
222+ var pos uint64
223+ var rec func (bufLen uint64 )
224+ rec = func (bufLen uint64 ) {
225+ inSlice := pos < (offset + length ) && offset < (pos + bufLen )
226+ if err != nil {
227+ return
228+ } else if bufLen <= groupSize {
229+ if combinedEncoding || inSlice {
230+ read (data , bufLen , inSlice )
231+ }
232+ pos += bufLen
233+ return
234+ }
235+ read (outboard , 64 , inSlice )
236+ mid := uint64 (1 ) << (bits .Len64 (bufLen - 1 ) - 1 )
237+ rec (mid )
238+ rec (bufLen - mid )
239+ }
240+ read (outboard , 8 , true )
241+ rec (binary .LittleEndian .Uint64 (buf [:8 ]))
242+ return err
243+ }
244+
245+ // BaoDecodeSlice reads from data, which must contain a slice encoding for the
246+ // given offset and length, and streams verified content to dst. It returns
247+ // false if verification fails.
248+ func BaoDecodeSlice (dst io.Writer , data io.Reader , group int , offset , length uint64 , root [32 ]byte ) (bool , error ) {
249+ groupSize := uint64 (chunkSize << group )
250+ buf := make ([]byte , groupSize )
251+ var err error
252+ read := func (n uint64 ) []byte {
253+ if err == nil {
254+ _ , err = io .ReadFull (data , buf [:n ])
255+ }
256+ return buf [:n ]
257+ }
258+ readParent := func () (l , r [8 ]uint32 ) {
259+ read (64 )
260+ return bytesToCV (buf [:32 ]), bytesToCV (buf [32 :])
261+ }
262+ write := func (p []byte ) {
263+ if err == nil {
264+ _ , err = dst .Write (p )
265+ }
266+ }
267+ var pos uint64
268+ var rec func (cv [8 ]uint32 , bufLen uint64 , flags uint32 ) bool
269+ rec = func (cv [8 ]uint32 , bufLen uint64 , flags uint32 ) bool {
270+ inSlice := pos < (offset + length ) && offset < (pos + bufLen )
271+ if err != nil {
272+ return false
273+ } else if bufLen <= groupSize {
274+ if ! inSlice {
275+ pos += bufLen
276+ return true
277+ }
278+ n := compressGroup (read (bufLen ), pos / chunkSize )
279+ n .flags |= flags
280+ valid := cv == chainingValue (n )
281+ if valid {
282+ // only write within range
283+ p := buf [:bufLen ]
284+ if pos + bufLen > offset + length {
285+ p = p [:offset + length - pos ]
286+ }
287+ if pos < offset {
288+ p = p [offset - pos :]
289+ }
290+ write (p )
291+ }
292+ pos += bufLen
293+ return valid
294+ }
295+ if ! inSlice {
296+ return true
297+ }
298+ l , r := readParent ()
299+ n := parentNode (l , r , iv , flags )
300+ mid := uint64 (1 ) << (bits .Len64 (bufLen - 1 ) - 1 )
301+ return chainingValue (n ) == cv && rec (l , mid , 0 ) && rec (r , bufLen - mid , 0 )
302+ }
303+
304+ dataLen := binary .LittleEndian .Uint64 (read (8 ))
305+ ok := rec (bytesToCV (root [:]), dataLen , flagRoot )
306+ return ok , err
307+ }
308+
309+ // BaoVerifySlice verifies the Bao slice encoding in data, returning the
310+ // verified bytes.
311+ func BaoVerifySlice (data []byte , group int , offset uint64 , length uint64 , root [32 ]byte ) ([]byte , bool ) {
312+ d := bytes .NewBuffer (data )
313+ var buf bytes.Buffer
314+ if ok , _ := BaoDecodeSlice (& buf , d , group , offset , length , root ); ! ok || d .Len () > 0 {
315+ return nil , false
316+ }
317+ return buf .Bytes (), true
318+ }
0 commit comments