aboutsummaryrefslogtreecommitdiff
path: root/format/pack/ingest/trailer.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-05 18:24:40 +0800
committerGravatar Runxi Yu2026-03-05 19:05:47 +0800
commit57f1818d547f2f1dca38033b4e29f62d89ef80f9 (patch)
tree88d55ac38e2427860bf380c8cce42fcb3bb1e9ee /format/pack/ingest/trailer.go
parentinternal/compress/zlib: Use flate's compression consumed counter (diff)
signatureNo signature
format/pack/ingest: Init
Diffstat (limited to 'format/pack/ingest/trailer.go')
-rw-r--r--format/pack/ingest/trailer.go65
1 files changed, 65 insertions, 0 deletions
diff --git a/format/pack/ingest/trailer.go b/format/pack/ingest/trailer.go
new file mode 100644
index 00000000..be8156d3
--- /dev/null
+++ b/format/pack/ingest/trailer.go
@@ -0,0 +1,65 @@
+package ingest
+
+import (
+ "bytes"
+ "fmt"
+ "hash"
+)
+
+// trailerVerifier incrementally verifies trailing hash bytes in a stream.
+type trailerVerifier struct {
+ hash hash.Hash
+ hashSize int
+ tail []byte
+ seen int64
+}
+
+// newTrailerVerifier creates a trailing hash verifier.
+func newTrailerVerifier(hash hash.Hash, hashSize int) *trailerVerifier {
+ return &trailerVerifier{
+ hash: hash,
+ hashSize: hashSize,
+ tail: make([]byte, 0, hashSize),
+ }
+}
+
+// write feeds one chunk of stream bytes into the verifier.
+func (verifier *trailerVerifier) write(src []byte) {
+ if len(src) == 0 {
+ return
+ }
+
+ verifier.seen += int64(len(src))
+ if len(verifier.tail) == 0 && len(src) <= verifier.hashSize {
+ verifier.tail = append(verifier.tail, src...)
+
+ return
+ }
+
+ tmp := make([]byte, 0, len(verifier.tail)+len(src))
+ tmp = append(tmp, verifier.tail...)
+ tmp = append(tmp, src...)
+ if len(tmp) <= verifier.hashSize {
+ verifier.tail = tmp
+
+ return
+ }
+
+ flushN := len(tmp) - verifier.hashSize
+ _, _ = verifier.hash.Write(tmp[:flushN])
+ verifier.tail = append(verifier.tail[:0], tmp[flushN:]...)
+}
+
+// verify finalizes verification against the stream trailer.
+func (verifier *trailerVerifier) verify() error {
+ if len(verifier.tail) != verifier.hashSize {
+ return fmt.Errorf("format/pack/ingest: stream too short for trailer hash")
+ }
+
+ computed := verifier.hash.Sum(nil)
+ if !bytes.Equal(computed, verifier.tail) {
+ return &ErrPackTrailerMismatch{}
+ }
+
+ return nil
+}