Synchronous cryptography; convenient `mint` overload for producing a ref and a bind at once

This commit is contained in:
Tony Garnock-Jones 2024-03-21 21:27:23 +01:00
parent de2a163dee
commit 291ec1805b
2 changed files with 41 additions and 14 deletions

View File

@ -18,6 +18,6 @@ export const newKey: () => Promise<Bytes> =
const HMAC_BLAKE2s = makeHMAC(BLAKE2s);
export async function mac(secretKey: Bytes, data: Bytes): Promise<Bytes> {
export function mac(secretKey: Bytes, data: Bytes): Bytes {
return Bytes.from(HMAC_BLAKE2s(underlying(secretKey), underlying(data)));
}

View File

@ -10,8 +10,9 @@
// California: Internet Society, 2014.
import { mac } from './cryptography.js';
import { Bytes, decode, encode, is, neverEmbeddedType, Value } from '@preserves/core';
import { Bytes, decode, encode, is, neverEmbeddedType, Value, fromJS } from '@preserves/core';
import * as S from '../gen/sturdy.js';
import * as G from '../gen/gatekeeper.js';
export * from '../gen/sturdy.js';
export type SturdyValue = Value<S._embedded>;
@ -37,16 +38,42 @@ export function sturdyDecode(bs: Bytes): SturdyValue {
});
}
export async function mint(oid: SturdyValue, secretKey: Bytes): Promise<S.SturdyRef> {
return S.SturdyRef(S.Parameters({
oid,
sig: await mac(secretKey, sturdyEncode(oid)),
caveats: S.CaveatsField.absent(),
}));
export function sturdyBind(
oid: SturdyValue,
secretKey: Bytes,
target: S._embedded,
observer?: S._embedded,
): G.Bind {
return G.Bind({
description: G.Description({
stepType: fromJS(S.SturdyStepType()) as symbol,
detail: fromJS(S.SturdyDescriptionDetail({ oid, key: secretKey })),
}),
target,
observer: (observer === void 0) ? G.BindObserver.absent() : G.BindObserver.present(observer),
});
}
async function chainMac(key: Bytes | Promise<Bytes>, caveats: S.Caveat[]): Promise<Bytes> {
return caveats.reduce(async (key, c) => mac(await key, sturdyEncode(S.fromCaveat(c))), key);
type RefAndBind = { ref: S.SturdyRef, bind: G.Bind };
export function mint(oid: SturdyValue, secretKey: Bytes): S.SturdyRef;
export function mint(oid: SturdyValue, secretKey: Bytes, target: S._embedded, observer?: S._embedded): RefAndBind;
export function mint(
oid: SturdyValue,
secretKey: Bytes,
target?: S._embedded,
observer?: S._embedded,
): S.SturdyRef | RefAndBind {
const ref = S.SturdyRef(S.Parameters({
oid,
sig: mac(secretKey, sturdyEncode(oid)),
caveats: S.CaveatsField.absent(),
}));
if (target === void 0) return ref;
return { ref, bind: sturdyBind(oid, secretKey, target, observer) };
}
function chainMac(key: Bytes, caveats: S.Caveat[]): Bytes {
return caveats.reduce((key, c) => mac(key, sturdyEncode(S.fromCaveat(c))), key);
}
export function caveatChain(r: S.SturdyRef): S.Caveat[] {
@ -57,16 +84,16 @@ export function caveatChain(r: S.SturdyRef): S.Caveat[] {
}
}
export async function attenuate(r: S.SturdyRef, ... a: S.Caveat[]): Promise<S.SturdyRef> {
export function attenuate(r: S.SturdyRef, ... a: S.Caveat[]): S.SturdyRef {
if (a.length === 0) return r;
return S.SturdyRef(S.Parameters({
oid: r.parameters.oid,
caveats: S.CaveatsField.present([... caveatChain(r), ... a]),
sig: await chainMac(r.parameters.sig, a),
sig: chainMac(r.parameters.sig, a),
}));
}
export async function validate(r: S.SturdyRef, secretKey: Bytes): Promise<boolean> {
const sig = await chainMac(await mac(secretKey, sturdyEncode(r.parameters.oid)), caveatChain(r));
export function validate(r: S.SturdyRef, secretKey: Bytes): boolean {
const sig = chainMac(mac(secretKey, sturdyEncode(r.parameters.oid)), caveatChain(r));
return is(sig, r.parameters.sig);
}