masterseed

package module
v1.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

README

MasterSeed

MasterSeed 是 Keymaster Seed V1 的 Go 与 TypeScript SDK 项目。

源文件固定按 256 KiB(262144 字节)分块。每个数据块计算 SHA-256,所得 32 字节原始二进制摘要按块顺序直接拼接,形成种子文件:

seed_bytes = block_hash[0] || ... || block_hash[n-1]
seed_hash  = SHA256(seed_bytes)

种子文件不保存十六进制文本。Hex 仅用于 API、日志和传播时表示 seed_hash

项目文档

  • 需求文档:产品范围、功能需求和验收标准
  • 设计文档:V1 二进制格式、算法、SDK API 与错误模型
  • 施工单:Go、TypeScript、共享测试和发布任务
  • API 摘要:两个 SDK 的公开操作、类型和错误判断方式

实现包含:

  • 根目录 Go module:包名 masterseed
  • typescript/:运行时无关的核心 package;
  • masterseed/node:Node.js 文件路径适配层;
  • spec/seed-v1.mdtestdata/v1/vectors.json:公开格式和跨语言黄金向量。

Go 最小示例

种子文件保存的是原始二进制摘要;下面的 SeedHashHex 仅用于展示和传播。

package main

import (
    "context"
    "fmt"
    "github.com/bsv8/MasterSeed"
)

func main() {
    info, err := masterseed.CreateSeedFile(
        context.Background(), "source.bin", "source.seed",
        masterseed.CreateSeedFileOptions{},
    )
    if err != nil { panic(err) }
    fmt.Println(info.SeedHashHex)
}

完整源文件验证先取得可信的 seed_hash,再调用 VerifySourceFile

expected, err := masterseed.ParseDigestHex(seedHashHex)
if err != nil { panic(err) }
_, err = masterseed.VerifySourceFile(context.Background(), "source.bin", "source.seed", expected)

当上层协议还提供可信的源文件大小时,可以同时验证 Seed 的摘要数量,并执行 无索引的块成员查询或块内容验证:

info, err := masterseed.VerifySeedForSourceSize(ctx, bytes.NewReader(seedBytes), expected, sourceSize)
matches, err := masterseed.FindBlockHash(ctx, bytes.NewReader(seedBytes), expected, sourceSize, blockHash)
verified, err := masterseed.VerifyBlockInSeed(ctx, bytes.NewReader(seedBytes), expected, sourceSize, blockBytes)

这些流式操作都会读完并认证完整 Seed 后才返回成员结论;FindBlockHashMatchCount == 0 是正常查询结果。seed_hash 和源文件大小的可信来源仍由 调用方的签名、报价或其他上层协议负责。每次调用都会消费 Seed reader;执行 多个操作时必须重新打开文件或为每次调用创建独立的 bytes.NewReader(seedBytes)

TypeScript 最小示例

核心 API 接收任意 Uint8Array 异步 chunk;计数、大小和偏移使用 bigint

import { createSeed, Digest } from "masterseed";
import { createSeedFile, verifySourceFile } from "masterseed/node";

const info = await createSeed(
  (async function* () { yield new TextEncoder().encode("abc"); })(),
  { async write(bytes) { /* persist all 32 raw bytes */ } }
);
console.log(info.seedHashHex);

await createSeedFile("source.bin", "source.seed");
await verifySourceFile("source.bin", "source.seed", Digest.fromHex(info.seedHashHex));

TypeScript 核心入口也对等提供 verifySeedForSourceSizeexpectedBlockSizefindBlockHashverifyBlockInSeed;大小、计数和索引继续使用 bigint

默认路径生成禁止覆盖已有目标,并在同目录临时文件完成后才发布。失败或取消会清理临时文件。

检查命令

go test ./...
go vet ./...
cd typescript && npm ci && npm run check

V1 的 BLOCK_SIZE、SHA-256 和原始 32 字节摘要布局是协议常量;需要头部、元数据、其他块大小或其他算法时必须定义新版本,不能修改 V1 文件字节。

Documentation

Index

Constants

View Source
const (
	Format        = "keymaster-seed-v1"
	BlockSize     = 256 * 1024
	DigestSize    = 32
	HashAlgorithm = "SHA-256"
	// Upper-case aliases mirror the protocol notation used in the public spec.
	FORMAT         = Format
	BLOCK_SIZE     = BlockSize
	DIGEST_SIZE    = DigestSize
	HASH_ALGORITHM = HashAlgorithm
)

V1 constants are part of the wire format and must not change within V1.

Variables

This section is empty.

Functions

func BlockCountForSourceSize

func BlockCountForSourceSize(sourceSize uint64) uint64

BlockCountForSourceSize applies the V1 empty-file and aligned-file rules.

func ExpectedBlockSize added in v1.1.0

func ExpectedBlockSize(sourceSize, blockIndex uint64) (uint64, error)

ExpectedBlockSize returns the protocol length of a block for a source of sourceSize bytes. Empty sources have no valid block indices.

func IsCode

func IsCode(err error, code ErrorCode) bool

IsCode reports whether err or one of its causes has code.

func SeedOffset

func SeedOffset(blockIndex uint64) (uint64, error)

SeedOffset returns blockIndex*DIGEST_SIZE after checking overflow.

func SeedSizeForBlockCount

func SeedSizeForBlockCount(blockCount uint64) (uint64, error)

SeedSizeForBlockCount checks the block-count multiplication used by callers that work with untrusted metadata.

func SourceOffset

func SourceOffset(blockIndex uint64) (uint64, error)

SourceOffset returns blockIndex*BLOCK_SIZE after checking overflow.

Types

type BlockMatches added in v1.1.0

type BlockMatches struct {
	SeedInfo
	MatchCount uint64
	FirstIndex uint64
	LastIndex  uint64
}

BlockMatches describes all occurrences of a digest in a trusted seed.

func FindBlockHash added in v1.1.0

func FindBlockHash(ctx context.Context, seed io.Reader, expectedSeedHash Digest, sourceSize uint64, blockHash Digest) (BlockMatches, error)

FindBlockHash scans a trusted seed once and returns the first/last indices and total count of an exact 32-byte digest match.

type CreateSeedFileOptions

type CreateSeedFileOptions struct {
	Overwrite bool
	Sync      bool
}

CreateSeedFileOptions controls atomic path publishing.

type Digest

type Digest struct {
	// contains filtered or unexported fields
}

Digest is an immutable, fixed-size SHA-256 digest value.

func DigestFromBytes

func DigestFromBytes(value []byte) (Digest, error)

DigestFromBytes constructs a Digest only from exactly 32 bytes.

func DigestFromHex

func DigestFromHex(value string) (Digest, error)

DigestFromHex is an alias for ParseDigestHex.

func HashSeed

func HashSeed(ctx context.Context, seed io.Reader) (Digest, error)

HashSeed computes SHA-256 over any seed bytes without validating its length.

func NewDigest

func NewDigest(value []byte) (Digest, error)

NewDigest is an alias for DigestFromBytes for callers that prefer a constructor-style name.

func ParseDigestHex

func ParseDigestHex(value string) (Digest, error)

ParseDigestHex parses exactly 64 hexadecimal characters. Whitespace and 0x prefixes are intentionally not accepted.

func ReadBlockHash

func ReadBlockHash(ctx context.Context, seed io.ReaderAt, seedSize, blockIndex uint64) (Digest, error)

ReadBlockHash reads one raw digest from a random-access seed file.

func Sum256

func Sum256(value []byte) Digest

Sum256 returns the digest of value.

func VerifyBlock

func VerifyBlock(ctx context.Context, block []byte, expected Digest) (Digest, error)

VerifyBlock hashes one caller-provided block. A short block is accepted; an API caller needs source-length context to decide whether it is the last one.

func (Digest) Bytes

func (d Digest) Bytes() []byte

Bytes returns a copy of the raw 32-byte digest.

func (Digest) Equal

func (d Digest) Equal(other Digest) bool

Equal compares two digest values.

func (Digest) Hex

func (d Digest) Hex() string

Hex returns the canonical lower-case hexadecimal representation.

func (Digest) String

func (d Digest) String() string

String implements fmt.Stringer using the canonical hexadecimal form.

type Error

type Error struct {
	Code               ErrorCode
	Message            string
	Cause              error
	Operation          string
	Path               string
	BlockIndex         *uint64
	BlockCount         *uint64
	SourceOffset       *uint64
	SeedSize           *uint64
	ExpectedSeedSize   *uint64
	ExpectedBlockCount *uint64
	ActualBlockSize    *uint64
	Expected           *Digest
	Actual             *Digest
}

Error is the structured error returned by the SDK. Context fields are optional and are populated only when relevant to the failure.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type ErrorCode

type ErrorCode string

ErrorCode is stable across the Go and TypeScript SDKs.

const (
	InvalidSeedLength    ErrorCode = "INVALID_SEED_LENGTH"
	InvalidHashEncoding  ErrorCode = "INVALID_HASH_ENCODING"
	SeedHashMismatch     ErrorCode = "SEED_HASH_MISMATCH"
	BlockHashMismatch    ErrorCode = "BLOCK_HASH_MISMATCH"
	SourceTooShort       ErrorCode = "SOURCE_TOO_SHORT"
	SourceTooLong        ErrorCode = "SOURCE_TOO_LONG"
	BlockIndexOutOfRange ErrorCode = "BLOCK_INDEX_OUT_OF_RANGE"
	IntegerOverflow      ErrorCode = "INTEGER_OVERFLOW"
	TargetExists         ErrorCode = "TARGET_EXISTS"
	ReadFailed           ErrorCode = "READ_FAILED"
	WriteFailed          ErrorCode = "WRITE_FAILED"
	Aborted              ErrorCode = "ABORTED"
	InvalidArgument      ErrorCode = "INVALID_ARGUMENT"
	SeedSizeMismatch     ErrorCode = "SEED_SIZE_MISMATCH"
	BlockNotInSeed       ErrorCode = "BLOCK_NOT_IN_SEED"
	BlockSizeMismatch    ErrorCode = "BLOCK_SIZE_MISMATCH"
)

func CodeOf

func CodeOf(err error) ErrorCode

CodeOf extracts a stable SDK error code through wrapped errors.

type SeedInfo

type SeedInfo struct {
	Format          string
	BlockSize       uint64
	BlockCount      uint64
	SourceSize      uint64
	SourceSizeKnown bool
	SeedSize        uint64
	SeedHash        Digest
	SeedHashHex     string
}

SeedInfo describes a seed file. SourceSizeKnown is false for HashSeed and InspectSeed because a seed file does not encode source length.

func CreateSeed

func CreateSeed(ctx context.Context, source io.Reader, sink io.Writer) (SeedInfo, error)

CreateSeed hashes source in protocol-sized blocks and writes raw 32-byte digests to sink. It never writes hexadecimal text to the sink.

func CreateSeedFile

func CreateSeedFile(ctx context.Context, sourcePath, seedPath string, options CreateSeedFileOptions) (info SeedInfo, err error)

CreateSeedFile writes a seed beside the target, then publishes it. The default is no-overwrite; an incomplete seed is never left at seedPath.

func InspectSeed

func InspectSeed(ctx context.Context, seed io.Reader) (SeedInfo, error)

InspectSeed computes seed_hash and requires the seed length to be a multiple of the raw digest size.

func VerifySeed

func VerifySeed(ctx context.Context, seed io.Reader, expected Digest) (SeedInfo, error)

VerifySeed strictly inspects a seed and compares its raw-byte hash with the caller's expected digest using a constant-time comparison.

func VerifySeedForSourceSize added in v1.1.0

func VerifySeedForSourceSize(ctx context.Context, seed io.Reader, expectedSeedHash Digest, sourceSize uint64) (SeedInfo, error)

VerifySeedForSourceSize verifies seed structure, hash, and its digest count against a caller-provided source size in a single streaming pass.

type VerifiedBlock added in v1.1.0

type VerifiedBlock struct {
	SeedInfo
	BlockHash  Digest
	BlockIndex uint64
	BlockSize  uint64
}

VerifiedBlock identifies the first digest occurrence whose protocol block length agrees with the supplied block.

func VerifyBlockInSeed added in v1.1.0

func VerifyBlockInSeed(ctx context.Context, seed io.Reader, expectedSeedHash Digest, sourceSize uint64, block []byte) (VerifiedBlock, error)

VerifyBlockInSeed verifies membership and protocol block length in one seed pass. Seed integrity and source-size binding are checked before membership errors are returned.

type VerifyInfo

type VerifyInfo struct {
	SeedInfo
	BlocksVerified uint64
}

VerifyInfo describes a successful complete source verification.

func VerifySource

func VerifySource(ctx context.Context, source io.Reader, seed io.Reader) (VerifyInfo, error)

VerifySource validates every source block against the raw digests in seed, then checks that neither stream contains extra data.

func VerifySourceFile

func VerifySourceFile(ctx context.Context, sourcePath, seedPath string, expected Digest) (VerifyInfo, error)

VerifySourceFile verifies the seed hash before reopening the seed for the complete source pass, so untrusted seed contents are not used unchecked.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL