/
pad.go
72 lines (59 loc) · 1.62 KB
/
pad.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Copyright 2019 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
package kbfscrypto
import (
"encoding/binary"
"io"
"github.com/pkg/errors"
)
const (
padPrefixSize = 4
minBlockSize = 256
)
// powerOfTwoEqualOrGreater returns smallest power of 2 greater than or equal
// to the input n.
// https://en.wikipedia.org/wiki/Power_of_two#Algorithm_to_round_up_to_power_of_two
func powerOfTwoEqualOrGreater(n int) int {
if n <= minBlockSize {
return minBlockSize
}
if n&(n-1) == 0 {
// if n is already power of 2, return it
return n
}
n--
n |= (n >> 1)
n |= (n >> 2)
n |= (n >> 4)
n |= (n >> 8)
n |= (n >> 16)
n |= (n >> 16 >> 16) // make it work with 64 bit int; no effect on 32bit.
n++
return n
}
// PadBlock adds zero padding to an encoded block.
func PadBlock(block []byte) ([]byte, error) {
totalLen := powerOfTwoEqualOrGreater(len(block))
buf := make([]byte, padPrefixSize+totalLen)
binary.LittleEndian.PutUint32(buf, uint32(len(block)))
copy(buf[padPrefixSize:], block)
return buf, nil
}
// DepadBlock extracts the actual block data from a padded block.
func DepadBlock(paddedBlock []byte) ([]byte, error) {
totalLen := len(paddedBlock)
if totalLen < padPrefixSize {
return nil, errors.WithStack(io.ErrUnexpectedEOF)
}
blockLen := binary.LittleEndian.Uint32(paddedBlock)
blockEndPos := int(blockLen + padPrefixSize)
if totalLen < blockEndPos {
return nil, errors.WithStack(
PaddedBlockReadError{
ActualLen: totalLen,
ExpectedLen: blockEndPos,
})
}
return paddedBlock[padPrefixSize:blockEndPos], nil
}