Version: v1.1.2 Latest Latest

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

Go to latest
Published: Mar 8, 2020 License: Unlicense Imports: 24 Imported by: 2



Package hashchain implements a hash chain of signatures over a chain of code changes.

A hash chain is stored in a simple newline separated text file where each hash chain entry corresponds to a single line and has the following form:

hash-of-previous current-time type type-fields ...

Where hash-of-previous is the SHA256 hash of the previous line (without the trailing newline) in hex encoding. The fields are separated by single white spaces. The current-time is encoded as an ISO 8601 string in UTC (corresponds to time.RFC3339).

All hashes in a hash chain are SHA256 hashes encoded in hex notation. Hex encodings have to be lowercase. All public keys are Ed25519 keys and they and their signatures are encoded in base64 (URL encoding without padding). Comments are arbitrary UTF-8 sequences, but cannot contain newlines.

There are six different types of hash chain entries:


A hash chain must start with a cstart entry and that is the only line where this type must appear.

Type cstart

A cstart entry starts a new hash chain.

hash-of-previous current-time cstart pubkey nonce signature [comment]

The hash-of-previous for the cstart time is the hash of an empty source tree (see tree.EmptyHash). The signature by pubkey is over the pubkey, the nonce, and the optional comment. The comment should identify the owner of the pubkey, not the project. The nonce must be a 24 byte random number in base64 (URL encoding without padding). This makes pubkey the only valid signer for the hash chain and implicitly sets the signature threshold m to 1.

Type source

A source entry marks a new source tree state for publication from the developer owning the signing pubkey. The optional comment can be used to describe the change to the reviewers.

hash-of-previous current-time source tree-hash pubkey signature [comment]

The signature by pubkey is over the source tree hash and the optional comment. See the tree package for a detailed description of source tree hashes.

Type signtr

A signtr entry signs a previous hash chain entry and thereby approves all code changes and changes to the set of signature keys and m up to that point.

hash-of-previous current-time signtr hash-of-chain-entry pubkey signature

It does not necessarily sign the previous line and can therefore be done in a detached fashion by a reviewer and added later by the developer responsible for maintaining the hash chain. This avoids merge conflicts.

Type addkey

An addkey entry marks a signature pubkey for addition to the list of approved signature keys.

hash-of-previous current-time addkey w pubkey signature [comment]

The weight of the key towards the minimum number of necessary signatures m is denoted by w. The pubkey can be accompanied by an optional comment, but the signature must be over both. The comment is added last so it can contain white spaces without complicating the parsing, it should identify the owner of the pubkey.

Type remkey

A remkey entry marks a signature pubkey for removal from the list of approved signature keys.

hash-of-previous current-time remkey pubkey

Type sigctl

A sigctl entry denotes an update of m, the minimum number of necessary signatures to approve state changes (the threshold).

hash-of-previous current-time sigctl m


An example of a hash chain.

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 2018-05-19T00:07:02Z cstart KDKOGoY8ErjOnbDQb4k8SZFMvWdAIb-x6FGKKCRby70 sVnVenzHyCOV6nLUkCKg6ARllkYsTV-n 0UmUcDFZ2j3WWnqzEdxX-wzofWlhF3O0Rm1tT6qMUwLu8a1R5MwbK5zDongYZKccpA37Vp6Sp3m0xSreGskzCg Alice <alice@example.com>
40c7e5ca4be98e9cae6931afa4ac09e11ecb1ce20fa18d0faaabfac7e8fad071 2018-05-19T00:09:44Z addkey 1 91HOu2fvkjHd5S0LtAWTl6dYBk5cqB-NWiJqc0c_7Gc Xsr_L-1_5_B56vocve8s3Pb3vJoc-jpa2-tzIQhEjuoytYfcAiONu3er6RnVNMcsPuZFeqWCQKBwka-F-c13Ag Bob <bob@example.com>
34cd10effd93e67ba96fefb29ea751d013459a6de11cc117cf1deacd77d6b7be 2018-05-19T00:10:25Z sigctl 2
92d2fc6687b0d36d045adaf34a1615e513ef0e2dc60384cfe19863e9753567f8 2018-05-19T00:11:44Z source d844cbe6f6c2c29e97742b272096407e4d92e6ac7f167216b321c7aa55629716 KDKOGoY8ErjOnbDQb4k8SZFMvWdAIb-x6FGKKCRby70 r5aZCYGwWCFppaMDV7XSOHoyCl3qbUKGiSuYzjsTl4C0W9n0tCa0MXDy_fOwspV9f4_o0kMcb6XZS706ml3FAQ first release
d258ce20943beeed2d483096702a1449447f112dec7d907d50c285c649c17a24 2018-05-19T00:12:48Z signtr d258ce20943beeed2d483096702a1449447f112dec7d907d50c285c649c17a24 KDKOGoY8ErjOnbDQb4k8SZFMvWdAIb-x6FGKKCRby70 HKlLKnYSCVzc4b-erETK50EN5gKRKZQsT16grv7eFBklFqXBFoSXSmcY99HLWhAP9BJcA6c3Px1trNBns3KkDA
2e34e23ee293e8c0ed174639d325eb3e30f5337d5c5846380367724e93cb619e 2018-05-19T00:34:51Z signtr 2e34e23ee293e8c0ed174639d325eb3e30f5337d5c5846380367724e93cb619e 91HOu2fvkjHd5S0LtAWTl6dYBk5cqB-NWiJqc0c_7Gc xffZultos-MCbI4cNzAzAoccuDSnpL2nq_BsQanIruYM3RXoD9kdC6WiPEUkxrphKdG742IgBWlB3LwY0i1ZCw



This section is empty.


View Source
var ErrCannotMerge = errors.New("hashchain: cannot merge")

ErrCannotMerge is returned if two hash chains cannot be merged.

View Source
var ErrDescendingTime = errors.New("hashchain: time is going backwards")

ErrDescendingTime is returned when the time in the hash chain is not ascending.

View Source
var ErrEmpty = errors.New("hashchain: is empty")

ErrEmpty is returned when the hash chain is empty.

View Source
var ErrHeadNotFound = errors.New("hashchain: head not found")

ErrHeadNotFound is returned if the head could not be found in hash chain.

View Source
var ErrIllegalCStart = errors.New("hashchain: cstart is only allowed on start")

ErrIllegalCStart is returned when a cstart entry appears in a different row than row 1.

View Source
var ErrLinkBroken = errors.New("hashchain: link broken")

ErrLinkBroken is returned when a link in the hash chain is broken.

View Source
var ErrMLargerThanN = errors.New("hashchain: signature threshold m is larger than total weight of signers n")

ErrMLargerThanN is returned when m > n.

View Source
var ErrMustStartWithCStart = errors.New("hashchain: must start with cstart")

ErrMustStartWithCStart is returned when the hash chain doess not start with a cstart entry.

View Source
var ErrNothingToMerge = errors.New("hashchain: nothing to merge")

ErrNothingToMerge is returned if there is nothing to merge.

View Source
var ErrSignatureThresholdNonPositive = errors.New("hashchain: signature threshold m must be positive")

ErrSignatureThresholdNonPositive is returned when the signature threshold is non-positive.

View Source
var ErrUnknownLinkType = errors.New("hashchain: unknown link type")

ErrUnknownLinkType is returned when the link type is unknown.

View Source
var ErrWrongSigAddKey = errors.New("hashchain: addkey signature doesn't validate")

ErrWrongSigAddKey is returned when the signature of an addkey entry doesn't validate.

View Source
var ErrWrongSigCStart = errors.New("hashchain: cstart signature doesn't validate")

ErrWrongSigCStart is returned when the signature of a cstart entry doesn't validate.

View Source
var ErrWrongSigSignature = errors.New("hashchain: signature signature doesn't validate")

ErrWrongSigSignature is returned when the signature of a signature entry doesn't validate.

View Source
var ErrWrongSigSource = errors.New("hashchain: source signature doesn't validate")

ErrWrongSigSource is returned when the signature of a source entry doesn't validate.

View Source
var ErrWrongTypeFields = errors.New("hashchain: entry has wrong number of type fields")

ErrWrongTypeFields is returned when a hash chain entry has the wrong number of type fields.


This section is empty.


type HashChain

type HashChain struct {
	// contains filtered or unexported fields

HashChain of threshold signatures over a chain of code changes.

func Read

func Read(r io.Reader) (*HashChain, error)

Read hash chain from r and verify it.

func ReadFile

func ReadFile(filename string) (*HashChain, error)

ReadFile reads hash chain from filename and verifies it.

func Start

func Start(filename string, secKey [64]byte, comment []byte) (*HashChain, string, error)

Start returns a new hash chain with signature control list m.

func (*HashChain) AddKey

func (c *HashChain) AddKey(weight int, pubKey [32]byte, signature [64]byte, comment []byte) (string, error)

AddKey adds pubkey with signature and optional comment to hash chain.

func (*HashChain) Apply

func (c *HashChain) Apply(head *[32]byte, patchDir string) error

Apply to current working directory and check head if not nil.

func (*HashChain) CheckHead

func (c *HashChain) CheckHead(head [32]byte) error

CheckHead checks wether the hash chain contains the given head as entry.

func (*HashChain) Close

func (c *HashChain) Close() error

Close the underlying file pointer of hash chain and release lock.

func (*HashChain) DeepVerify

func (c *HashChain) DeepVerify(treeDir, patchDir string, excludePaths []string) error

DeepVerify hash chain. Use directory treeDir to apply patches from patchDir one after another and verify that they reflect the treehashes recorded in the hash chain.

func (*HashChain) DetachedSignature

func (c *HashChain) DetachedSignature(linkHash, pubKey, signature string) (string, error)

DetachedSignature adds a detached signature entry for linkHash signed by pubKey to the hash chain.

func (*HashChain) Fprint

func (c *HashChain) Fprint(w io.Writer) error

Fprint hash chain to w.

func (*HashChain) Head

func (c *HashChain) Head() [32]byte

Head returns the hash of the last entry.

func (*HashChain) LastSignedTreeHash

func (c *HashChain) LastSignedTreeHash() (string, int)

LastSignedTreeHash returns the last signed tree hash and its index. The first signed tree hash is tree.EmptyHash with index 0.

func (*HashChain) LastTreeHash

func (c *HashChain) LastTreeHash() string

LastTreeHash returns the most current tree hash (can be unsigned).

func (*HashChain) LinkHash

func (c *HashChain) LinkHash(treeHash string) [32]byte

LinkHash returns the link hash corresponding to given treeHash.

func (*HashChain) M

func (c *HashChain) M() int

M returns the signature threshold.

func (*HashChain) Merge

func (c *HashChain) Merge(src *HashChain) error

Merge hashchain src into c.

func (*HashChain) N

func (c *HashChain) N() int

N returns the total weight of all signers.

func (*HashChain) Print

func (c *HashChain) Print()

Print colorized hash chain on stdout.

func (*HashChain) RemoveKey

func (c *HashChain) RemoveKey(pubKey [32]byte) (string, error)

RemoveKey adds a pubkey remove entry to hash chain.

func (*HashChain) Signature

func (c *HashChain) Signature(linkHash [32]byte, secKey [64]byte, detached bool) (string, error)

Signature adds a signature entry for linkHash signed by secKey to the hash chain. If detached it just returns the signature without adding it.

func (*HashChain) SignatureControl

func (c *HashChain) SignatureControl(m int) (string, error)

SignatureControl adds a signature control entry to the hash chain.

func (*HashChain) Signer

func (c *HashChain) Signer() map[string]bool

Signer returns a map containing all active signers for hash chain.

func (*HashChain) SignerBarrier

func (c *HashChain) SignerBarrier(pubKey string) int

SignerBarrier returns the signer barrier for pubKey.

func (*HashChain) SignerComment

func (c *HashChain) SignerComment(pubKey string) string

SignerComment returns the signer comment for given pubKey.

func (*HashChain) SignerInfo

func (c *HashChain) SignerInfo(treeHash string) (string, string)

SignerInfo returns signer pubKey and comment for patch with given treeHash.

func (*HashChain) SignerWeight

func (c *HashChain) SignerWeight(pubKey string) int

SignerWeight returns the signer weight for given pubKey.

func (*HashChain) Source

func (c *HashChain) Source(treeHash [32]byte, secKey [64]byte, comment []byte) (string, error)

Source adds a source entry for treeHash and optional comment signed by secKey to the hash chain.

func (*HashChain) SourceLine

func (c *HashChain) SourceLine(treeHash string) int

SourceLine returns the line number where the given tree hash was signed.

func (*HashChain) TreeComments

func (c *HashChain) TreeComments() []string

TreeComments returns a list of all tree comments in order (starting from tree.EmptyHash).

func (*HashChain) TreeHashes

func (c *HashChain) TreeHashes() []string

TreeHashes returns a list of all tree hashes in order (starting from tree.EmptyHash).

func (*HashChain) UnsignedInfo

func (c *HashChain) UnsignedInfo(pubkey, treeHash string, omitSource bool) ([]string, error)

UnsignedInfo returns a string slice with information about all unsigned entries suitable for printing. If TreeHash is defined it returns info until that treeHash. If omitSource is true source lines are omitted


Path Synopsis
Package state implements the state of a hashchain.
Package state implements the state of a hashchain.
Package linktype defines the different link types of a hash chain.
Package linktype defines the different link types of a hash chain.

Jump to

Keyboard shortcuts

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