Slide 25 of 74

Secrets

Kept, compared, never shown
type Login {
	user:     Str
	password: Secret
}

proc main(): void {
	typed := hide("hunter2")
	if typed is Result.Error(why) {
		echo "{why.reason}: {why.message}"
	} else if typed is Result.Ok(password) {
		echo reveal(password)                // hunter2
		echo password == bypass("hunter2")   // true
		echo Login("ada", password).user     // ada
		// echo password                      — a compile error
		// echo Login("ada", password)        — and so is this
	}
}

A Secret is text that must not leak — a password, a key, a token — and the type makes that a rule the compiler keeps:

  • echo, panic and interpolation refuse one, and so does anything holding one: a field, an element, a Result. So does writing one as JSON. reveal(secret) is the only way back to a Str.
  • What it holds lives in memory the operating system is told never to swap to disk, and is cleared once nothing holds it.
  • == compares what two hold in constant time, so how long it takes says nothing about where they differ. There is no order.

Locked memory is finite, so hide(text) answers a Result<Secret, SecretError>, whose reason is "LimitExceeded" when the limit is used up and "Unsupported" where the platform cannot lock memory at all. bypass(text) makes a Secret that cannot fail, kept in ordinary memory that may be swapped out — for text that was never really secret on the way in, like a literal, which the executable holds anyway.

A program that declares its own Secret still has the builtin as hive.Secret, and its error as hive.SecretError.