keyed

package
v0.6.4 Latest Latest
Warning

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

Go to latest
Published: Oct 2, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

Documentation

Overview

Package keyed holds the part of BRC-369 keyed content that every application keyed under a random scalar shares: the content key, its symmetric key and its commitment (BRC-369 sections 2.1 and 2.2), the check a holder runs on a key it has just unwrapped, and BRC-2's symmetric form, in which a key is wrapped and a certificate field is encrypted.

A content key is a random scalar, never derived from an identity or from anything else. The commitment is published; the key is released only to those meant to hold it. A holder that unwraps a key checks it against the commitment before anything uses it (CheckOpened), so that a wrong key names whoever wrapped it and not whoever encrypted under it.

What a key encrypts, who it is released to and how a release is framed are the application's. This package writes no record and names no protocol.

Index

Examples

Constants

View Source
const (
	DomainSymmetric  = "metanet keyed content symmetric v1"
	DomainCommitment = "metanet keyed content commitment v1"
)

BRC-369 section 2's domain strings.

View Source
const (
	IVLen = 32
	// TagLen is the length of the authentication tag.
	TagLen = 16
	// Overhead is what the form adds to a plaintext.
	Overhead = IVLen + TagLen
	// WrappedKeyLen is the length of a wrapped 32-byte key.
	WrappedKeyLen = 32 + Overhead
)

The sizes of BRC-2's symmetric form as go-sdk writes it: a 32-byte IV, the ciphertext, and a 16-byte tag.

Variables

View Source
var (
	// ErrScalar is a key that is not a scalar in [1, n-1].
	ErrScalar = errors.New("keyed: key is not a scalar in [1, n-1]")
	// ErrCommitment is a key that is not the committed one.
	ErrCommitment = errors.New("keyed: key does not match the commitment")
	// ErrUnwrap is a wrap that does not open, or opens to something that
	// is not 32 bytes.
	ErrUnwrap = errors.New("keyed: wrap does not open")
)

A holder's refusals (BRC-369 section 5.3), never a host's: a host cannot see a key.

Functions

func CheckOpened

func CheckOpened(plaintext []byte, commitment [32]byte) ([32]byte, error)

CheckOpened is the tail of every unwrap, in its order: the plaintext is exactly 32 bytes (ErrUnwrap), a scalar (ErrScalar), and the committed one (ErrCommitment). The key it returns with an error must not be used.

Example

A publisher draws a key, publishes its commitment, and wraps the key to each holder. A holder that opens a wrap checks the key against the commitment before anything uses it: a wrong key then names whoever wrapped it, not whoever encrypted under it.

package main

import (
	"errors"
	"fmt"

	"github.com/lightwebinc/bcommon/goldentest"
	"github.com/lightwebinc/bcommon/keyed"
)

func main() {
	// A fixed scalar so the example prints the same thing every time; a
	// publisher calls keyed.SampleKey(nil).
	k := goldentest.Fill(0x07)
	if err := keyed.CheckScalar(k); err != nil {
		fmt.Println(err)
		return
	}
	commitment := keyed.Commitment(k)
	symmetric := keyed.SymmetricKey(k)
	fmt.Println("the commitment says nothing about the key that encrypts:", commitment != symmetric)

	// The wrap: BRC-2's symmetric form under a key the two ends share. A
	// wallet's Encrypt writes the same form with an IV it draws itself.
	shared := goldentest.Fill(0x21)
	wrap, err := keyed.SymmetricSeal(shared[:], goldentest.Fill(0x80), k[:])
	fmt.Println("wrap:", len(wrap), "bytes", err)

	opened, err := keyed.SymmetricOpen(shared[:], wrap)
	if err != nil {
		fmt.Println(err)
		return
	}
	got, err := keyed.CheckOpened(opened, commitment)
	fmt.Println("the committed key:", got == k, err)

	// The same wrap against another commitment, and another key's wrap.
	other := goldentest.Fill(0x08)
	_, err = keyed.CheckOpened(opened, keyed.Commitment(other))
	fmt.Println("another commitment:", errors.Is(err, keyed.ErrCommitment))
	wrong := goldentest.Fill(0x22)
	_, err = keyed.SymmetricOpen(wrong[:], wrap)
	fmt.Println("another shared key opens it:", err == nil)
}
Output:
the commitment says nothing about the key that encrypts: true
wrap: 80 bytes <nil>
the committed key: true <nil>
another commitment: true
another shared key opens it: false

func CheckScalar

func CheckScalar(k [32]byte) error

CheckScalar refuses, as ErrScalar, a 32-byte big-endian value outside [1, n-1].

func Commitment

func Commitment(k [32]byte) [32]byte

Commitment is BRC-369 section 2.2's digest form: SHA-256 of the domain string and the scalar.

func SampleKey

func SampleKey(r io.Reader) ([32]byte, error)

SampleKey draws a key: a scalar uniform in [1, n-1] from r (crypto/rand.Reader when r is nil), never derived from anything (BRC-369 section 2.1 rule 1).

func SymmetricKey

func SymmetricKey(k [32]byte) [32]byte

SymmetricKey is BRC-369 section 2.1 rule 3: SHA-256 of the domain string and the scalar. It is never derived from the commitment.

func SymmetricOpen

func SymmetricOpen(key, sealed []byte) ([]byte, error)

SymmetricOpen reverses SymmetricSeal through go-sdk's own symmetric key, so it opens exactly what a wallet's Decrypt opens under the same key.

func SymmetricSeal

func SymmetricSeal(key []byte, iv [IVLen]byte, plaintext []byte) ([]byte, error)

SymmetricSeal is BRC-2's symmetric form as go-sdk writes it: AES-256-GCM under key with a 32-byte IV and no associated data, written IV || ciphertext || tag. It is what a wallet's Encrypt returns, with the IV chosen by the caller in place of a random one: an IV must never be used twice under one key, so only a caller that draws it from a CSPRNG, or a vector that fixes it to be reproducible, calls this.

Types

This section is empty.

Jump to

Keyboard shortcuts

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