2023-05-04 08:18:15 +00:00
|
|
|
package bao
|
|
|
|
|
|
|
|
import (
|
2023-05-17 13:52:25 +00:00
|
|
|
"bufio"
|
2023-05-04 08:18:15 +00:00
|
|
|
_ "embed"
|
|
|
|
"io"
|
2023-05-17 13:52:25 +00:00
|
|
|
"lukechampine.com/blake3"
|
2023-05-04 08:18:15 +00:00
|
|
|
)
|
|
|
|
|
2023-05-17 13:52:25 +00:00
|
|
|
const (
|
|
|
|
chunkSize = 1024
|
|
|
|
)
|
2023-05-15 16:34:55 +00:00
|
|
|
|
2023-05-17 13:52:25 +00:00
|
|
|
func ComputeTree(reader io.Reader, size int64) ([]byte, [32]byte, error) {
|
|
|
|
bufSize := baoOutboardSize(int(size))
|
|
|
|
buf := bufferAt{buf: make([]byte, bufSize)}
|
2023-05-15 16:34:55 +00:00
|
|
|
|
2023-05-17 13:52:25 +00:00
|
|
|
hash, err := blake3.BaoEncode(&buf, bufio.NewReader(reader), size, true)
|
2023-05-04 08:18:15 +00:00
|
|
|
if err != nil {
|
2023-05-17 13:52:25 +00:00
|
|
|
return nil, [32]byte{}, err
|
2023-05-04 08:18:15 +00:00
|
|
|
}
|
|
|
|
|
2023-05-17 13:52:25 +00:00
|
|
|
return buf.buf, hash, nil
|
2023-05-04 08:18:15 +00:00
|
|
|
}
|
|
|
|
|
2023-05-17 13:52:25 +00:00
|
|
|
func baoOutboardSize(dataLen int) int {
|
|
|
|
if dataLen == 0 {
|
|
|
|
return 8
|
2023-05-15 19:45:05 +00:00
|
|
|
}
|
2023-05-17 13:52:25 +00:00
|
|
|
chunks := (dataLen + chunkSize - 1) / chunkSize
|
|
|
|
cvs := 2*chunks - 2 // no I will not elaborate
|
|
|
|
return 8 + cvs*32
|
2023-05-15 19:45:05 +00:00
|
|
|
}
|
|
|
|
|
2023-05-17 13:52:25 +00:00
|
|
|
type bufferAt struct {
|
|
|
|
buf []byte
|
2023-05-04 08:18:15 +00:00
|
|
|
}
|
|
|
|
|
2023-05-17 13:52:25 +00:00
|
|
|
func (b *bufferAt) WriteAt(p []byte, off int64) (int, error) {
|
|
|
|
if copy(b.buf[off:], p) != len(p) {
|
|
|
|
panic("bad buffer size")
|
2023-05-04 08:18:15 +00:00
|
|
|
}
|
2023-05-17 13:52:25 +00:00
|
|
|
return len(p), nil
|
2023-05-04 08:18:15 +00:00
|
|
|
}
|