signify-ts
Version:
Signing at the edge for KERI, ACDC, and KERIA
194 lines (193 loc) • 5.85 kB
JavaScript
import { BexDex, Matter, NumDex } from "./matter.js";
import { CesrNumber } from "./number.js";
import { format, sum, fraction } from 'mathjs';
export class Tholder {
// private _bexter: any
constructor(kargs) {
this._weighted = false;
this._thold = undefined;
this._size = 0;
this._number = undefined;
this._satisfy = undefined;
if (kargs.thold !== undefined) {
this._processThold(kargs.thold);
}
else if (kargs.limen != undefined) {
this._processLimen(kargs.limen);
}
else if (kargs.sith !== undefined) {
this._processSith(kargs.sith);
}
else {
throw new Error('Missing threshold expression');
}
}
get weighted() {
return this._weighted;
}
get thold() {
return this._thold;
}
get size() {
return this._size;
}
get limen() {
var _a;
return (_a = this._number) === null || _a === void 0 ? void 0 : _a.qb64b;
}
get sith() {
if (this.weighted) {
let sith = this.thold.map((clause) => {
return clause.map((c) => {
if (0 < Number(c) && Number(c) < 1) {
return format(c, { fraction: 'ratio' });
}
else {
return format(c, { fraction: 'decimal' });
}
});
});
if (sith.length == 1) {
sith = sith[0];
}
return sith;
}
else {
return this.thold.toString(16);
}
}
get json() {
return JSON.stringify(this.sith);
}
get num() {
return this._weighted ? undefined : this._thold;
}
_processThold(thold) {
if (typeof thold === 'number') {
this._processUnweighted(thold);
}
else {
this._processWeighted(thold);
}
}
_processLimen(limen) {
const matter = new Matter({ qb64: limen });
if (NumDex.has(matter.code)) {
const number = new CesrNumber({
raw: matter.raw,
code: matter.code,
});
this._processUnweighted(number.num);
}
else if (BexDex.has(matter.code)) {
// TODO: Implement Bexter
}
else {
throw new Error('Invalid code for limen=' + matter.code);
}
}
_processSith(sith) {
if (typeof sith == 'number') {
this._processUnweighted(sith);
}
else if (typeof sith == 'string' && sith.indexOf('[') == -1) {
this._processUnweighted(parseInt(sith, 16));
}
else {
let _sith = sith;
if (typeof sith == 'string') {
_sith = JSON.parse(sith);
}
if (_sith.length == 0) {
throw new Error('Empty weight list');
}
const mask = _sith.map((x) => {
return typeof x !== 'string';
});
if (mask.length > 0 && !mask.every((x) => x)) {
_sith = [_sith];
}
for (const c of _sith) {
const mask = c.map((x) => {
return typeof x === 'string';
});
if (mask.length > 0 && !mask.every((x) => x)) {
throw new Error('Invalid sith, some weights in clause ' +
mask +
' are non string');
}
}
const thold = this._processClauses(_sith);
this._processWeighted(thold);
}
}
_processClauses(sith) {
const thold = new Array();
sith.forEach((clause) => {
thold.push(clause.map((w) => {
return this.weight(w);
}));
});
return thold;
}
_processUnweighted(thold) {
if (thold < 0) {
throw new Error('Non-positive int threshold = {thold}.');
}
this._thold = thold;
this._weighted = false;
this._size = this._thold; // used to verify that keys list size is at least size
this._satisfy = this._satisfy_numeric;
this._number = new CesrNumber({}, thold);
// this._bexter = undefined
}
_processWeighted(thold) {
for (const clause of thold) {
if (Number(sum(clause)) < 1) {
throw new Error('Invalid sith clause: ' +
thold +
'all clause weight sums must be >= 1');
}
}
this._thold = thold;
this._weighted = true;
this._size = thold.reduce((acc, currentValue) => {
return acc + currentValue.length;
}, 0);
this._satisfy = this._satisfy_weighted;
//TODO: created Bexter if needed
}
weight(w) {
return fraction(w);
}
_satisfy_numeric(indices) {
return this.thold > 0 && indices.length >= this.thold; // at least one
}
_satisfy_weighted(indices) {
if (indices.length === 0) {
return false;
}
const indexes = new Set(indices.sort());
const sats = new Array(indices.length).fill(false);
for (const idx of indexes) {
sats[idx] = true;
}
let wio = 0;
for (const clause of this.thold) {
let cw = 0;
for (const w of clause) {
if (sats[wio]) {
cw += Number(w);
}
wio += 1;
}
if (cw < 1) {
return false;
}
}
return true;
}
satisfy(indices) {
return this._satisfy(indices);
}
}