Documentation
¶
Index ¶
- Constants
- Variables
- func ComputeBlockHash(encoded []byte) []byte
- func EncodeBlock(b *EncodedBlock) ([]byte, error)
- func GenerateKeyHex() (string, error)
- func HashCompressed(preEncryptionPayload []byte) []byte
- func HashLogical(encodedPlaintext []byte) []byte
- func HashPhysical(persistedPayload []byte) []byte
- func HashPlaintextEncodedBlock(encoded []byte) []byte
- func LoadEncryptionKey() ([]byte, error)
- func SliceChunkFromPayload(payload []byte, entry ChunkEntry) ([]byte, error)
- func VerifyBlockHash(encoded []byte, expected []byte) error
- type AESGCMTransformer
- type Block
- type BlockBuilder
- func (b *BlockBuilder) Add(chunk PendingChunk) error
- func (b *BlockBuilder) AddChunk(id uint64, data []byte) error
- func (b *BlockBuilder) Build() (*EncodedBlock, []byte, error)
- func (b *BlockBuilder) CanFit(size int64) bool
- func (b *BlockBuilder) Empty() bool
- func (b *BlockBuilder) Reset()
- func (b *BlockBuilder) ShouldFlushAtEnd() bool
- func (b *BlockBuilder) ShouldFlushBeforeAdd(nextSize int64) bool
- type BlockHashes
- type BlockHeader
- type BlockReader
- type BlockStore
- type ChunkEntry
- type ChunkLocator
- type ChunkResolver
- type ChunkSegment
- type Codec
- type DecodeInput
- type Descriptor
- type EncodeInput
- type EncodedBlock
- type EncodedPackedBlockV1
- type PackedBlockV1
- type PackedChunk
- type PendingChunk
- type PlainTransformer
- type Repository
- type StorageChunkResolver
- type TransformMetadata
- type TransformedBlock
- type Transformer
- type V17CompatResolver
Constants ¶
const ( // CKBL in ASCII. BlockMagicV1 uint32 = 0x434B424C BlockFormatVersionV1 uint16 = 1 BlockCodecNoneV1 uint16 = 0 // BlockHashAlgorithm is the current project hash algorithm used for // plaintext encoded block hashing. v1.8 policy hashes encoded plaintext // block bytes (not encrypted bytes). BlockHashAlgorithm = "sha256" )
Variables ¶
var ( ErrBlockFormatTooSmall = errors.New("block format: payload too small for header") ErrBlockFormatUnsupported = errors.New("block format: unsupported header values") ErrBlockFormatInvalidLayout = errors.New("block format: invalid table/payload layout") ErrBlockFormatInvalidCount = errors.New("block format: invalid chunk_count") ErrBlockFormatEmptyBlock = errors.New("block format: empty block is not allowed") ErrBlockHashMismatch = errors.New("block format: hash mismatch") ErrBlockHashExpectedNil = errors.New("block format: expected hash must not be nil or empty") ErrNilEncodedBlock = errors.New("block format: nil encoded block") )
var ErrBlockAlreadyExists = errors.New("block already exists for chunk")
var ErrBlockBuilderCannotFit = errors.New("block builder: chunk does not fit current block")
var ErrBlockBuilderChunkSizeMismatch = errors.New("block builder: chunk size does not match data length")
var ErrBlockBuilderInvalidTargetSize = errors.New("block builder: invalid target size")
var ErrBlockBuilderSizeOverflow = errors.New("block builder: size overflow")
var ErrBlockBuilderZeroChunkSize = errors.New("block builder: zero-size chunk is not allowed")
var V17ChunkSegmentMarker = &ChunkSegment{
ChunkID: 0,
BlockID: 0,
Offset: 0,
Size: 0,
}
V17ChunkSegmentMarker is a sentinel ChunkSegment indicating v1.7 direct chunk retrieval. BlockID == 0 and the other fields are zero-valued to signal legacy path.
Functions ¶
func ComputeBlockHash ¶ added in v1.8.0
ComputeBlockHash returns block hash over plaintext encoded block bytes.
IMPORTANT: hash target is encoded plaintext block bytes, before encryption. Delegates to HashLogical — the canonical hash helper for the logical layer.
func EncodeBlock ¶ added in v1.8.0
func EncodeBlock(b *EncodedBlock) ([]byte, error)
EncodeBlock serializes one in-memory encoded block using deterministic v1 binary layout with little-endian fields: | HEADER | CHUNK_TABLE | PAYLOAD |
func GenerateKeyHex ¶
func HashCompressed ¶ added in v1.9.0
HashCompressed returns the SHA-256 digest of the pre-encryption transform output (compressed bytes when compression is active, or encoded plaintext when compression is disabled).
When compression codec is "none": HashCompressed(x) == HashLogical(x).
func HashLogical ¶ added in v1.9.0
HashLogical returns the SHA-256 digest of the encoded plaintext block bytes. This is the canonical logical hash (block_hash) and is identical to the v1.8 block_hash contract. payload_hash is a deprecated lowercase-hex mirror retained for compatibility and observability only.
func HashPhysical ¶ added in v1.9.0
HashPhysical returns the SHA-256 digest of the exact persisted payload bytes (i.e. after all transforms including encryption).
When no encryption is applied: HashPhysical(x) == HashCompressed(x).
func HashPlaintextEncodedBlock ¶ added in v1.8.0
HashPlaintextEncodedBlock remains as compatibility alias.
func LoadEncryptionKey ¶
func SliceChunkFromPayload ¶ added in v1.8.0
func SliceChunkFromPayload(payload []byte, entry ChunkEntry) ([]byte, error)
SliceChunkFromPayload returns chunk bytes for one table entry.
func VerifyBlockHash ¶ added in v1.8.0
VerifyBlockHash verifies that the SHA-256 hash of encoded matches expected. Returns ErrBlockHashExpectedNil if expected is nil or empty. Returns ErrBlockHashMismatch (wrapping details) if hashes do not match.
Types ¶
type AESGCMTransformer ¶
type AESGCMTransformer struct {
Key []byte
}
func (*AESGCMTransformer) Decode ¶
func (t *AESGCMTransformer) Decode(_ context.Context, in DecodeInput) (data []byte, err error)
func (*AESGCMTransformer) Encode ¶
func (t *AESGCMTransformer) Encode(_ context.Context, in EncodeInput) (*TransformedBlock, error)
type Block ¶ added in v1.8.0
type Block struct {
ID int64
FormatVersion int
Codec string
Metadata storagemetadata.BlockStorageMetadata
ContainerID int64
ContainerOffset int64
}
Block represents a physical stored block unit for the v1.8 packed-block model. It captures the persisted block metadata shared by write, read, and verify paths.
type BlockBuilder ¶ added in v1.8.0
type BlockBuilder struct {
// contains filtered or unexported fields
}
BlockBuilder incrementally accumulates pending chunks for one packed block. Packing is deterministic: insertion order defines entry order.
func NewBlockBuilder ¶ added in v1.8.0
func NewBlockBuilder(targetSize int64) *BlockBuilder
NewBlockBuilder creates a builder with the given target block size.
func (*BlockBuilder) Add ¶ added in v1.8.0
func (b *BlockBuilder) Add(chunk PendingChunk) error
Add appends one pending chunk to the current block candidate.
func (*BlockBuilder) AddChunk ¶ added in v1.8.0
func (b *BlockBuilder) AddChunk(id uint64, data []byte) error
AddChunk appends one chunk and updates aggregate plaintext size. Compatibility helper while write path migrates to PendingChunk API.
func (*BlockBuilder) Build ¶ added in v1.8.0
func (b *BlockBuilder) Build() (*EncodedBlock, []byte, error)
Build constructs encoded block in-memory representation plus mandatory plaintext-encoded block hash.
func (*BlockBuilder) CanFit ¶ added in v1.8.0
func (b *BlockBuilder) CanFit(size int64) bool
CanFit reports whether a chunk of given size can be added without splitting. Oversized chunks are allowed only when the builder is empty so they can be emitted alone after a caller flushes any current block.
func (*BlockBuilder) Empty ¶ added in v1.8.0
func (b *BlockBuilder) Empty() bool
Empty reports whether there are no pending chunks.
func (*BlockBuilder) Reset ¶ added in v1.8.0
func (b *BlockBuilder) Reset()
Reset clears current pending chunks so the builder can start a new block.
func (*BlockBuilder) ShouldFlushAtEnd ¶ added in v1.8.0
func (b *BlockBuilder) ShouldFlushAtEnd() bool
ShouldFlushAtEnd applies deterministic end-of-operation flush rule: flush remaining pending chunks when operation ends.
func (*BlockBuilder) ShouldFlushBeforeAdd ¶ added in v1.8.0
func (b *BlockBuilder) ShouldFlushBeforeAdd(nextSize int64) bool
ShouldFlushBeforeAdd applies deterministic flush rule checks before adding the next chunk. It returns true only for size-based reasons:
- current_size + next_size > target_size
- oversized next chunk must be written alone (when current block is non-empty)
It does not consider timing, goroutine completion, or random ordering.
type BlockHashes ¶ added in v1.9.0
BlockHashes holds hash digests for the three semantic layers of a stored block.
Layer semantics:
LogicalHash = hash(encoded plaintext block bytes) — "what was written logically"
Identical to the legacy block_hash (v1.8 contract preserved).
CompressedHash = hash(pre-encryption transform output) — "what the encryptor received"
When compression is disabled, CompressedHash == LogicalHash.
PhysicalHash = hash(exact persisted payload bytes) — "what lives on disk / in the container"
When no encryption is applied, PhysicalHash == CompressedHash.
Phase 2 invariant (compression disabled, codec = "none"):
CompressedHash == LogicalHash
type BlockHeader ¶ added in v1.8.0
type BlockHeader struct {
Magic uint32
Version uint16
Codec uint16
ChunkCount uint32
PlaintextSize uint64
}
BlockHeader is the fixed-size binary block header for v1 format.
Layout (20 bytes): - magic uint32 - version uint16 - codec uint16 - chunk_count uint32 - plaintext_size uint64
type BlockReader ¶ added in v1.8.0
type BlockReader interface {
ReadBlock(ctx context.Context, blockID int64) (*EncodedBlock, error)
}
BlockReader provides context-aware read access to decoded blocks. It supports both legacy and packed repository read flows.
type BlockStore ¶ added in v1.8.0
BlockStore is the storage-block retrieval boundary for packed layouts. The interface intentionally remains minimal to keep storage access decoupled.
type ChunkEntry ¶ added in v1.8.0
ChunkEntry is one chunk segment entry in the v1 chunk table.
Layout (24 bytes): - chunk_id uint64 - offset uint64 - size uint64
type ChunkLocator ¶ added in v1.8.0
type ChunkLocator interface {
GetChunkSegment(chunkID int64) (*ChunkSegment, error)
}
ChunkLocator resolves chunk placement inside a physical block. It isolates lookup logic from restore and verification execution paths.
type ChunkResolver ¶ added in v1.8.0
type ChunkResolver interface {
ResolveChunk(ctx context.Context, chunkID int64) (*ChunkSegment, error)
}
ChunkResolver provides context-aware resolution of chunk placement inside blocks. It supports chunk lookup across legacy and packed layouts.
type ChunkSegment ¶ added in v1.8.0
ChunkSegment represents one chunk placement inside a physical block. Offset and Size are relative to decoded plaintext block bytes.
type Codec ¶
type Codec string
func LoadDefaultCodec ¶
LoadDefaultCodec resolves codec from env with a secure default. Precedence: env (COLDKEEP_CODEC) -> default (aes-gcm).
func ParseCodec ¶
type DecodeInput ¶
type DecodeInput struct {
ChunkHash string
Descriptor Descriptor
Payload []byte
}
type Descriptor ¶
type Descriptor struct {
ID int64
ChunkID int64
Codec Codec
FormatVersion int
PlaintextSize int64
StoredSize int64
Nonce []byte
ContainerID int64
BlockOffset int64
CreatedAt time.Time
UpdatedAt time.Time
}
Descriptor represents how a chunk is physically stored in the system. It links logical chunk identity to its encoded representation in a container.
type EncodeInput ¶
type EncodedBlock ¶
type EncodedBlock struct {
Header BlockHeader
Entries []ChunkEntry
Payload []byte
Metadata TransformMetadata
}
EncodedBlock is the in-memory representation of a decoded/constructed plaintext block format payload in v1 layout.
func DecodeBlock ¶ added in v1.8.0
func DecodeBlock(data []byte) (*EncodedBlock, error)
DecodeBlock parses and validates v1 encoded block bytes into in-memory representation.
func (*EncodedBlock) GetChunk ¶ added in v1.8.0
func (b *EncodedBlock) GetChunk(i int) []byte
GetChunk returns one chunk slice by table index from the payload. Invalid indexes or invalid entry bounds return nil.
type EncodedPackedBlockV1 ¶ added in v1.8.0
type EncodedPackedBlockV1 struct {
Bytes []byte
BlockHash []byte
Header BlockHeader
Entries []ChunkEntry
}
EncodedPackedBlockV1 is the result of encoding v1 block bytes. BlockHash is mandatory and computed from plaintext encoded block bytes.
func EncodePackedBlockV1 ¶ added in v1.8.0
func EncodePackedBlockV1(entries []ChunkEntry, payload []byte) (*EncodedPackedBlockV1, error)
EncodePackedBlockV1 encodes block bytes using deterministic v1 layout: | HEADER | CHUNK_TABLE | PAYLOAD |
func EncodePackedBlockV1FromChunks ¶ added in v1.8.0
func EncodePackedBlockV1FromChunks(chunks []PackedChunk) (*EncodedPackedBlockV1, error)
EncodePackedBlockV1FromChunks builds a v1 encoded block from an ordered chunk sequence, creating chunk table segmentation and payload deterministically.
type PackedBlockV1 ¶ added in v1.8.0
type PackedBlockV1 = EncodedBlock
PackedBlockV1 remains as a compatibility alias during Phase 2 rollout.
func DecodePackedBlockV1 ¶ added in v1.8.0
func DecodePackedBlockV1(encoded []byte) (*PackedBlockV1, error)
DecodePackedBlockV1 parses and validates encoded v1 block bytes.
type PackedChunk ¶ added in v1.8.0
PackedChunk is an encode helper input for building payload and chunk table deterministically from an ordered chunk sequence.
type PendingChunk ¶ added in v1.8.0
PendingChunk is one chunk candidate waiting to be packed into a block. Hash contains the chunk identity hash over plaintext bytes.
type PlainTransformer ¶
type PlainTransformer struct{}
PlainTransformer stores chunks as-is without any transformation.
func (*PlainTransformer) Decode ¶
func (t *PlainTransformer) Decode(_ context.Context, in DecodeInput) ([]byte, error)
No transformation needed for plain codec, just return the payload as-is. Phase 6 Step 8: Avoid unnecessary byte copies during restore - Decode returns payload directly without copying - Caller (restore.go) never mutates plaintext after verification - Direct return saves memory allocation and copy time per chunk
func (*PlainTransformer) Encode ¶
func (t *PlainTransformer) Encode(_ context.Context, in EncodeInput) (*TransformedBlock, error)
type Repository ¶
func (*Repository) GetByChunkHash ¶
func (r *Repository) GetByChunkHash(ctx context.Context, chunkHash string) (*Descriptor, error)
func (*Repository) GetByChunkID ¶
func (r *Repository) GetByChunkID(ctx context.Context, chunkID int64) (*Descriptor, error)
func (*Repository) Insert ¶
func (r *Repository) Insert(ctx context.Context, tx *sql.Tx, d *Descriptor) error
type StorageChunkResolver ¶ added in v1.8.0
type StorageChunkResolver struct {
// contains filtered or unexported fields
}
StorageChunkResolver implements ChunkResolver for v1.8 block-based layout. It resolves chunk locations by querying the chunk_block_refs and storage_blocks tables.
func NewStorageChunkResolver ¶ added in v1.8.0
func NewStorageChunkResolver(locator ChunkLocator) *StorageChunkResolver
NewStorageChunkResolver creates a chunk resolver backed by the given ChunkLocator.
func (*StorageChunkResolver) ResolveChunk ¶ added in v1.8.0
func (r *StorageChunkResolver) ResolveChunk(ctx context.Context, chunkID int64) (*ChunkSegment, error)
ResolveChunk looks up which block contains the chunk and returns the segment location.
type TransformMetadata ¶ added in v1.9.0
type TransformMetadata struct {
// PayloadHash is a compatibility/observability mirror of the logical block hash
// (lowercase-hex SHA256 of encoded plaintext block bytes before transforms).
// storage_blocks.block_hash remains the authoritative logical identity.
PayloadHash string
// CompressionCodec identifies the compression stage outcome persisted per block.
// v1.9 values are 'none' and 'zstd'. Store-if-smaller may keep 'none' even when
// zstd is configured for the repository.
CompressionCodec string
// CompressionRatio is compressed_payload_size / encoded_plaintext_size
// for the pre-encryption compression stage.
// 1.0 indicates no effective compression (including store-if-smaller fallback),
// values < 1.0 indicate successful size reduction.
CompressionRatio float64
}
TransformMetadata carries explicit transformation information through the persistence pipeline. It threads compression metadata, payload information, and hash data from encode stage through transform stage to final persistence for the current v1.9 write/read contract.
type TransformedBlock ¶ added in v1.8.0
type TransformedBlock struct {
Descriptor Descriptor
Payload []byte
}
type Transformer ¶
type Transformer interface {
Encode(ctx context.Context, in EncodeInput) (*TransformedBlock, error)
Decode(ctx context.Context, in DecodeInput) ([]byte, error)
}
Transformer defines how a chunk is transformed into a stored block and how a stored block is transformed back into plaintext.
func GetBlockTransformer ¶
func GetBlockTransformer(codec Codec) (Transformer, error)
get codec transformer from codec name
type V17CompatResolver ¶ added in v1.8.0
type V17CompatResolver struct{}
V17CompatResolver is a no-op resolver for v1.7 layouts. It signals that chunk resolution must fall back to legacy storage_chunks table logic. In the restore path, when ChunkResolver returns V17ChunkSegmentMarker, the system uses pre-v1.8 direct-chunk retrieval instead of block-based lookup.
func (*V17CompatResolver) ResolveChunk ¶ added in v1.8.0
func (r *V17CompatResolver) ResolveChunk(ctx context.Context, chunkID int64) (*ChunkSegment, error)
ResolveChunk returns the v1.7 marker, signaling direct chunk lookup without block read.