Rawsexprs: module
{
	PATH:	con "rawsexprs.dis";

	Sexp: adt {
		pick {
		String =>
			s: string;
			hint:	string;
		Binary =>
			data:	array of byte;
			hint: string;
		List =>
			l:	cyclic list of ref Sexp;
		}

		unpack:	fn(a: array of byte): (ref Sexp, array of byte, string);
		text:	fn(e: self ref Sexp): string;
		packedsize:	fn(e: self ref Sexp): int;
		pack:	fn(e: self ref Sexp): array of byte;
	};

	init:	fn();
};

SPKI: module
{
	PATH: con "/dis/lib/spki/spki.dis";

	Hash: adt {
		alg:	string;
		hash:	array of byte;

		sexp:	fn(h: self ref Hash): ref Sexprs->Sexp;
		text:	fn(h: self ref Hash): string;
		eq:	fn(h1: self ref Hash, h2: ref Hash): int;
	};

	Key: adt {
		pk:	ref Keyring->PK;	# either pk/sk or hash might be nil
		sk:	ref Keyring->SK;
		nbits:	int;
		halg:	string;	# basic signature hash algorithm
		henc:	string;	# pre-signature encoding
		hash:	list of ref Hash;

		hashed:	fn(k: self ref Key, alg: string): array of byte;
		hashexp:	fn(k: self ref Key, alg: string): ref Hash;
		ishash:	fn(k: self ref Key): int;
		public:	fn(k: self ref Key): ref Key;
		sigalg:	fn(k: self ref Key): string;
		text:	fn(k: self ref Key): string;
		sexp:	fn(k: self ref Key): ref Sexprs->Sexp;
		eq:	fn(k1: self ref Key, k2: ref Key): int;
	};

	Name: adt {
		principal:	ref Key;
		names:	list of string;

		isprincipal:	fn(n: self ref Name): int;
		local:	fn(n: self ref Name): ref Name;
		islocal:	fn(n: self ref Name): int;
		isprefix:	fn(n1: self ref Name, n2: ref Name): int;
		text:	fn(n: self ref Name): string;
		sexp:	fn(n: self ref Name): ref Sexprs->Sexp;
		eq:	fn(n1: self ref Name, n2: ref Name): int;
	};

	Cert: adt {
		e:	ref Sexprs->Sexp;	# S-expression, if originally parsed
		issuer:	ref Name;
		subject:	ref Subject;
		valid:	ref Valid;
		pick {
		A or KH or O =>	# auth, keyholder or object
			delegate:	int;
			tag:	ref Sexprs->Sexp;
		N =>	# name
		}

		text:	fn(c: self ref Cert): string;
		sexp:	fn(c: self ref Cert): ref Sexprs->Sexp;
	};

	# the pick might move to a more general `Principal' structure,
	# allowing compound and quoting principals
	Subject: adt {
		pick{
		P =>
			key:	ref Key;
		N =>
			name:	ref Name;
		O =>
			hash:	ref Hash;
		KH =>
			holder:	ref Name;
		T =>
			k, n:	int;
			subs:	cyclic list of ref Subject;
		}

		eq:	fn(s1: self ref Subject, s2: ref Subject): int;
		principal:	fn(s: self ref Subject): ref Key;
		text:	fn(s: self ref Subject): string;
		sexp:	fn(s: self ref Subject): ref Sexprs->Sexp;
	};

	Principal: adt[T] {
		pick{
		N =>
			name:	ref Name;
		Q =>
			quoter:	T;
			quotes:	cyclic ref Principal;
		}
	};

	Signature: adt {
		hash:	ref Hash;
		key:	ref Key;	# find by hash if necessary
		sa:	string;	# alg[-[encoding-]hash]
		sig:	list of (string, array of byte);

		algs:	fn(s: self ref Signature): (string, string, string);
		sexp:	fn(s: self ref Signature): ref Sexprs->Sexp;
		text:	fn(s: self ref Signature): string;
	};

	Seqel: adt {
		pick{
		C =>
			c: ref Cert;
		K =>
			k: ref Key;
		O =>
			op: string;
			args: list of ref Sexprs->Sexp;
		S =>
			sig: ref Signature;
		RV =>	# <reval>
			ok:	list of (string, string);
			onetime:	array of byte;
			valid:	ref Valid;
		CRL =>
			bad:	list of (string, string);
			valid:	ref Valid;
		Delta =>
			hash:	string;
			bad:	list of (string, string);
			valid:	ref Valid;
		E =>
			exp:	ref Sexprs->Sexp;
		}

		sexp:	fn(se: self ref Seqel): ref Sexprs->Sexp;
		text:	fn(se: self ref Seqel): string;
	};

	Valid: adt {
		notbefore:	string;
		notafter:	string;

		intersect:	fn(a: self Valid, b: Valid): (int, Valid);
		text:	fn(a: self Valid): string;
		sexp:	fn(a: self Valid): ref Sexprs->Sexp;
	};

	Toplev: adt {
		pick {
		C =>
			v:	ref Cert;
		Sig =>
			v:	ref Signature;
		K =>
			v:	ref Key;
		Seq =>
			v:	list of ref Seqel;
		}

		sexp:	fn(t: self ref Toplev): ref Sexprs->Sexp;
		text:	fn(t: self ref Toplev): string;
	};

	init:	fn();

	# parse structures
	parse:	fn(s: ref Sexprs->Sexp): (ref Toplev, string);
	parseseq:	fn(s: ref Sexprs->Sexp): list of ref Seqel;
	parsecert:	fn(s: ref Sexprs->Sexp): ref Cert;
	parsesig:	fn(s: ref Sexprs->Sexp): ref Signature;
	parsename:	fn(s: ref Sexprs->Sexp): ref Name;
	parsekey:	fn(s: ref Sexprs->Sexp): ref Key;
	parsehash:	fn(s: ref Sexprs->Sexp): ref Hash;
	parsecompound:	fn(s: ref Sexprs->Sexp): ref Name;
	parsevalid:	fn(s: ref Sexprs->Sexp): ref Valid;

	# signature checking
	checksig:	fn(c: ref Cert, sig: ref Signature): string;
	sig2icert:	fn(sig: ref Signature, signer: string, exp: int): ref Keyring->Certificate;

	# signature making
	signcert:	fn(c: ref Cert, sigalg: string, key: ref Key): (ref Signature, string);
	signbytes:	fn(a: array of byte, sigalg: string, key: ref Key): (ref Signature, string);

	# tags
	maketag:	fn(e: ref Sexprs->Sexp): ref Sexprs->Sexp;
	tagintersect:	fn(t1: ref Sexprs->Sexp, t2: ref Sexprs->Sexp): ref Sexprs->Sexp;
	tagimplies:	fn(t1: ref Sexprs->Sexp, t2: ref Sexprs->Sexp): int;

	# hash canonical s-expression
	hashbytes:	fn(a: array of byte, alg: string): array of byte;
	hashexp:	fn(e: ref Sexprs->Sexp, alg: string): array of byte;

	# convert between date and time strings and Inferno form
	date2epoch:	fn(s: string): int;	# YYYY-MM-DD_HH:MM:SS
	epoch2date:	fn(t: int): string;
	time2secs:	fn(s: string): int;	# HH:MM:SS
	secs2time:	fn(t: int): string;

	# misc
	sigalgs:	fn(algs: string): (string, string, string);

	# debugging
	dump:	fn(s: string, a: array of byte);
};

Proofs: module
{
	Proof: adt {
		n:	int;

		parse:	fn(s: string): ref Proof;
		sexp:	fn(p: self ref Proof): ref Sexprs->Sexp;
		text:	fn(p: self ref Proof): string;
	};

	init:	fn(): string;
};

Verifier: module
{
	PATH:	con "/dis/lib/spki/verifier.dis";

	Speaksfor: adt {
		subject:	ref SPKI->Subject;
		name:	ref SPKI->Name;
		regarding:	ref Sexprs->Sexp;
		valid:	ref SPKI->Valid;
	};

	init:	fn();
	verify:	fn(seq: list of ref SPKI->Seqel): (ref Speaksfor, list of ref SPKI->Seqel, string);
};
