UNPKG

@iden3/js-iden3-core

Version:

Low level API to create and manipulate iden3 Claims.

1,545 lines (1,535 loc) 55.7 kB
// src/schemaHash.ts import { Hex as Hex2 } from "@iden3/js-crypto"; // src/constants.ts var Constants = Object.freeze({ ERRORS: { // ErrDataOverflow means that given *big.Int value does not fit in Field Q // e.g. greater than Q constant: // Q constant: 21888242871839275222246405745257275088548364400416034343698204186575808495617 DATA_OVERFLOW: new Error("data does not fits SNARK size"), // ErrIncorrectIDPosition means that passed position is not one of predefined: // IDPositionIndex or IDPositionValue INCORRECT_ID_POSITION: new Error("incorrect ID position"), // throws when ID not found in the Claim. NO_ID: new Error("ID is not set"), // throws when subject position flags sets in invalid value. INVALID_SUBJECT_POSITION: new Error("invalid subject position"), // ErrIncorrectMerklizePosition means that passed position is not one of predefined: // MerklizePositionIndex or MerklizePositionValue INCORRECT_MERKLIZED_POSITION: new Error("incorrect Merklize position"), // ErrNoMerklizedRoot returns when Merklized Root is not found in the Claim. NO_MERKLIZED_ROOT: new Error("Merklized root is not set"), NETWORK_NOT_SUPPORTED_FOR_DID: new Error("network in not supported for did"), UNSUPPORTED_BLOCKCHAIN_FOR_DID: new Error("not supported blockchain for did"), UNSUPPORTED_DID_METHOD: new Error("not supported DID method"), UNKNOWN_DID_METHOD: new Error("unknown DID method"), INCORRECT_DID: new Error("incorrect DID"), UNSUPPORTED_ID: new Error("unsupported Id") }, SCHEMA: { HASH_LENGTH: 16 }, ETH_ADDRESS_LENGTH: 20, BYTES_LENGTH: 32, ELEM_BYTES_LENGTH: 4, NONCE_BYTES_LENGTH: 8, Q: BigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"), ID: { TYPE_DEFAULT: Uint8Array.from([0, 0]), TYPE_READONLY: Uint8Array.from([0, 1]), ID_LENGTH: 31 }, DID: { DID_SCHEMA: "did" }, GENESIS_LENGTH: 27 }); var Blockchain = { Ethereum: "eth", Polygon: "polygon", Privado: "privado", Billions: "billions", Linea: "linea", Unknown: "unknown", NoChain: "", ReadOnly: "readonly" }; var NetworkId = { Main: "main", Mumbai: "mumbai", Amoy: "amoy", Goerli: "goerli", Sepolia: "sepolia", Zkevm: "zkevm", Cardona: "cardona", Test: "test", Unknown: "unknown", NoNetwork: "" }; var DidMethod = { Iden3: "iden3", PolygonId: "polygonid", Other: "" }; var ChainIds = { [`${Blockchain.Ethereum}:${NetworkId.Main}`]: 1, [`${Blockchain.Ethereum}:${NetworkId.Goerli}`]: 5, [`${Blockchain.Ethereum}:${NetworkId.Sepolia}`]: 11155111, [`${Blockchain.Polygon}:${NetworkId.Main}`]: 137, [`${Blockchain.Polygon}:${NetworkId.Mumbai}`]: 80001, [`${Blockchain.Polygon}:${NetworkId.Amoy}`]: 80002, [`${Blockchain.Polygon}:${NetworkId.Zkevm}`]: 1101, [`${Blockchain.Polygon}:${NetworkId.Cardona}`]: 2442, [`${Blockchain.Privado}:${NetworkId.Main}`]: 21e3, [`${Blockchain.Privado}:${NetworkId.Test}`]: 21001, [`${Blockchain.Linea}:${NetworkId.Main}`]: 59144, [`${Blockchain.Linea}:${NetworkId.Sepolia}`]: 59141, [`${Blockchain.Billions}:${NetworkId.Main}`]: 45056, [`${Blockchain.Billions}:${NetworkId.Test}`]: 6913 }; var DidMethodByte = { [DidMethod.Iden3]: 1, [DidMethod.PolygonId]: 2, [DidMethod.Other]: 255 }; var blockchainNetworkMap = { [`${Blockchain.ReadOnly}:${NetworkId.NoNetwork}`]: 0, [`${Blockchain.Polygon}:${NetworkId.Main}`]: 16 | 1, [`${Blockchain.Polygon}:${NetworkId.Mumbai}`]: 16 | 2, [`${Blockchain.Polygon}:${NetworkId.Amoy}`]: 16 | 3, [`${Blockchain.Polygon}:${NetworkId.Zkevm}`]: 16 | 4, [`${Blockchain.Polygon}:${NetworkId.Cardona}`]: 16 | 5, [`${Blockchain.Ethereum}:${NetworkId.Main}`]: 32 | 1, [`${Blockchain.Ethereum}:${NetworkId.Goerli}`]: 32 | 2, [`${Blockchain.Ethereum}:${NetworkId.Sepolia}`]: 32 | 3, [`${Blockchain.Privado}:${NetworkId.Main}`]: 160 | 1, [`${Blockchain.Privado}:${NetworkId.Test}`]: 160 | 2, [`${Blockchain.Linea}:${NetworkId.Main}`]: 64 | 9, [`${Blockchain.Linea}:${NetworkId.Sepolia}`]: 64 | 8, [`${Blockchain.Billions}:${NetworkId.Main}`]: 176 | 1, [`${Blockchain.Billions}:${NetworkId.Test}`]: 176 | 2 }; var DidMethodNetwork = { [DidMethod.Iden3]: { ...blockchainNetworkMap }, [DidMethod.PolygonId]: { ...blockchainNetworkMap }, [DidMethod.Other]: { [`${Blockchain.Unknown}:${NetworkId.Unknown}`]: 255 } }; // src/utils.ts import { poseidon } from "@iden3/js-crypto"; var encoder = new TextEncoder(); function fromLittleEndian(bytes) { const n256 = BigInt(256); let result = BigInt(0); let base = BigInt(1); bytes.forEach((byte) => { result += base * BigInt(byte); base = base * n256; }); return result; } function fromBigEndian(bytes) { return fromLittleEndian(bytes.reverse()); } function toLittleEndian(bigNumber, len = 31) { const n256 = BigInt(256); const result = new Uint8Array(len); let i = 0; while (bigNumber > BigInt(0)) { result[i] = Number(bigNumber % n256); bigNumber = bigNumber / n256; i += 1; } return result; } function toBigEndian(bigNumber, len = 31) { return toLittleEndian(bigNumber, len).reverse(); } function putUint32(n) { const buf = new ArrayBuffer(4); const view = new DataView(buf); view.setUint32(0, n, true); return new Uint8Array(buf); } function getUint32(arr) { const buf = arr.buffer.slice(arr.byteOffset, arr.byteOffset + arr.byteLength); return new DataView(buf).getUint32(0, true); } function putUint64(n) { const buf = new ArrayBuffer(8); const view = new DataView(buf); view.setBigUint64(0, n, true); return new Uint8Array(buf); } function getUint64(arr) { const buf = arr.buffer.slice(arr.byteOffset, arr.byteOffset + arr.byteLength); return new DataView(buf).getBigUint64(0, true); } function getUnixTimestamp(d) { return Math.floor(d.getTime() / 1e3); } function getDateFromUnixTimestamp(n) { return new Date(n * 1e3); } function checkBigIntInField(a) { return a < Constants.Q; } function checkBigIntArrayInField(arr) { return arr.every((n) => checkBigIntInField(n)); } function idenState(clr, rer, ror) { return poseidon.hash([clr, rer, ror]); } var StringUtils = class _StringUtils { static isNotValidIDChar(char) { return _StringUtils.isNotAlpha(char) && _StringUtils.isNotDigit(char) && char !== "." && char !== "-"; } static isNotValidParamChar(char) { return _StringUtils.isNotAlpha(char) && _StringUtils.isNotDigit(char) && char !== "." && char !== "-" && char !== "_" && char !== ":"; } static isNotValidQueryOrFragmentChar(char) { return _StringUtils.isNotValidPathChar(char) && char !== "/" && char !== "?"; } static isNotValidPathChar(char) { return _StringUtils.isNotUnreservedOrSubdelim(char) && char !== ":" && char !== "@"; } static isNotUnreservedOrSubdelim(char) { switch (char) { case "-": case ".": case "_": case "~": case "!": case "$": case "&": case "'": case "(": case ")": case "*": case "+": case ",": case ";": case "=": return false; default: if (_StringUtils.isNotAlpha(char) && _StringUtils.isNotDigit(char)) { return true; } return false; } } static isNotHexDigit(char) { return _StringUtils.isNotDigit(char) && (char < "A" || char > "F") && (char < "a" || char > "f"); } static isNotDigit(char) { return char < "0" || char > "9"; } // StringUtils.isNotAlpha returns true if a byte is not a big letter between A-Z or small letter between a-z // https://tools.ietf.org/html/rfc5234#appendix-B.1 static isNotAlpha(char) { return _StringUtils.isNotSmallLetter(char) && _StringUtils.isNotBigLetter(char); } // isNotBigLetter returns true if a byte is not a big letter between A-Z // in US-ASCII http://www.columbia.edu/kermit/ascii.html // https://tools.ietf.org/html/rfc5234#appendix-B.1 static isNotBigLetter(char) { return char < "A" || char > "Z"; } // isNotSmallLetter returns true if a byte is not a small letter between a-z // in US-ASCII http://www.columbia.edu/kermit/ascii.html // https://tools.ietf.org/html/rfc5234#appendix-B.1 static isNotSmallLetter(char) { return char < "a" || char > "z"; } }; var genesisFromEthAddress = (addr) => { return Uint8Array.from([...new Uint8Array(7), ...addr]); }; // src/elemBytes.ts import { Hex, sha256 } from "@iden3/js-crypto"; var BytesHelper = class _BytesHelper { static intToBytes(int) { return _BytesHelper.intToNBytes(int, Constants.BYTES_LENGTH); } static intToNBytes(int, n) { return Uint8Array.from(toLittleEndian(int, n)); } static checkChecksum(bytes) { const { typ, genesis, checksum } = _BytesHelper.decomposeBytes(bytes); if (!checksum.length || JSON.stringify(Uint8Array.from([0, 0])) === JSON.stringify(checksum)) { return false; } const c = _BytesHelper.calculateChecksum(typ, genesis); return JSON.stringify(c) === JSON.stringify(checksum); } static decomposeBytes(b) { const offset = 2; const len = b.length - offset; return { typ: b.slice(0, offset), genesis: b.slice(offset, len), checksum: b.slice(-offset) }; } static calculateChecksum(typ, genesis) { const toChecksum = [...typ, ...genesis]; const s = toChecksum.reduce((acc, cur) => acc + cur, 0); const checksum = [s >> 8, s & 255]; return Uint8Array.from(checksum.reverse()); } static hashBytes(str) { const hash = sha256(encoder.encode(str)); return new Uint8Array(hash); } static hexToBytes(str) { return Hex.decodeString(str); } static bytesToHex(bytes) { const hex = []; for (let i = 0; i < bytes.length; i++) { const current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i]; hex.push((current >>> 4).toString(16)); hex.push((current & 15).toString(16)); } return hex.join(""); } static bytesToInt(bytes) { return fromLittleEndian(bytes); } }; var ElemBytes = class _ElemBytes { _bytes = new Uint8Array(Constants.BYTES_LENGTH); constructor(bytes) { if (bytes) { this._bytes = bytes; } if (this._bytes.length !== Constants.BYTES_LENGTH) { throw new Error("Invalid bytes length"); } } get bytes() { return this._bytes; } set bytes(value) { this._bytes = value; } toBigInt() { return BytesHelper.bytesToInt(this._bytes); } setBigInt(n) { if (!checkBigIntInField(n)) { throw Constants.ERRORS.DATA_OVERFLOW; } this._bytes = BytesHelper.intToBytes(n); return this; } slotFromHex(hex) { const bytes = Hex.decodeString(hex); if (bytes.length !== Constants.BYTES_LENGTH) { throw new Error("Invalid bytes length"); } this._bytes.set(bytes, 0); return this; } hex() { return Hex.encodeString(this._bytes); } // ElemBytesToInts converts slice of ElemBytes to slice of *big.Int static elemBytesToInts(elements) { const result = []; for (let i = 0; i < elements.length; i++) { const element = elements[i]; result.push(element.toBigInt()); } return result; } static fromInt(i) { if (!checkBigIntInField(i)) { throw Constants.ERRORS.DATA_OVERFLOW; } const bytes = BytesHelper.intToBytes(i); return new _ElemBytes(bytes); } }; // src/schemaHash.ts var SchemaHash = class _SchemaHash { // authSchemaHash predefined value of auth schema, used for auth claim during identity creation. // This schema is hardcoded in the identity circuits and used to verify user's auth claim. // Keccak256(https://schema.iden3.io/core/jsonld/auth.jsonld#AuthBJJCredential) last 16 bytes // Hex: cca3371a6cb1b715004407e325bd993c // BigInt: 80551937543569765027552589160822318028 static authSchemaHash = new _SchemaHash( Uint8Array.from([204, 163, 55, 26, 108, 177, 183, 21, 0, 68, 7, 227, 37, 189, 153, 60]) ); _bytes = new Uint8Array(Constants.SCHEMA.HASH_LENGTH); /** * Constructor * @param bytes */ constructor(bytes) { if (bytes) { this._bytes = bytes; } if (this.bytes.length !== Constants.SCHEMA.HASH_LENGTH) { throw new Error(`Schema hash must be ${Constants.SCHEMA.HASH_LENGTH} bytes long`); } } get bytes() { return this._bytes; } /** * MarshalText returns HEX representation of SchemaHash. * @returns {Uint8Array} 32 bytes// */ marshalTextBytes() { return Hex2.encode(this.bytes); } marshalText() { return Hex2.encodeString(this.bytes); } /** * NewSchemaHashFromHex creates new SchemaHash from hex string * @param s * @returns {SchemaHash} */ static newSchemaHashFromHex(s) { const schemaEncodedBytes = Hex2.decodeString(s); if (schemaEncodedBytes.length !== Constants.SCHEMA.HASH_LENGTH) { throw new Error(`invalid schema hash length: ${schemaEncodedBytes.length}`); } return new _SchemaHash(schemaEncodedBytes); } /** * NewSchemaHashFromInt creates new SchemaHash from big.Int * @param i * @returns */ static newSchemaHashFromInt(i) { const bytes = BytesHelper.intToNBytes(i, Constants.SCHEMA.HASH_LENGTH); const start = Constants.SCHEMA.HASH_LENGTH - bytes.length; return new _SchemaHash(BytesHelper.intToBytes(i).slice(start, Constants.SCHEMA.HASH_LENGTH)); } /** * Convert SchemaHash to big.Int * @returns {bigint} */ bigInt() { return BytesHelper.bytesToInt(this.bytes); } }; // src/id.ts import { poseidon as poseidon2, base58ToBytes, base58FromBytes } from "@iden3/js-crypto"; var Id = class _Id { _bytes; _checksum; constructor(typ, genesis) { this._checksum = BytesHelper.calculateChecksum(typ, genesis); this._bytes = Uint8Array.from([...typ, ...genesis, ...this._checksum]); } static getFromBytes(bytes) { const { typ, genesis } = BytesHelper.decomposeBytes(bytes); return new _Id(typ, genesis); } checksum() { return this._checksum; } string() { return base58FromBytes(this._bytes); } get bytes() { return this._bytes; } set bytes(b) { this._bytes = b; } type() { return this._bytes.slice(0, 2); } bigInt() { return fromLittleEndian(this._bytes); } equal(id) { return JSON.stringify(this._bytes) === JSON.stringify(id.bytes); } marshal() { return new TextEncoder().encode(this.string()); } static unMarshal(b) { return _Id.fromString(new TextDecoder().decode(b)); } static fromBytes(b) { const bytes = b ?? Uint8Array.from([]); if (bytes.length !== Constants.ID.ID_LENGTH) { throw new Error("fromBytes error: byte array incorrect length"); } if (bytes.every((i) => i === 0)) { throw new Error("fromBytes error: byte array empty"); } const id = _Id.getFromBytes(bytes); if (!BytesHelper.checkChecksum(bytes)) { throw new Error("fromBytes error: checksum error"); } return id; } static fromString(s) { const bytes = base58ToBytes(s); return _Id.fromBytes(bytes); } static fromBigInt(bigInt) { const b = BytesHelper.intToNBytes(bigInt, Constants.ID.ID_LENGTH); return _Id.fromBytes(b); } static profileId(id, nonce) { const bigIntHash = poseidon2.hash([id.bigInt(), nonce]); const { typ } = BytesHelper.decomposeBytes(id.bytes); const genesis = BytesHelper.intToNBytes(bigIntHash, 27); return new _Id(typ, genesis); } // IdGenesisFromIdenState calculates the genesis ID from an Identity State. static idGenesisFromIdenState(typ, state) { const idenStateData = ElemBytes.fromInt(state); const idGenesisBytes = idenStateData.bytes.slice(idenStateData.bytes.length - 27); return new _Id(typ, idGenesisBytes); } static ethAddressFromId(id) { const isZeros = id.bytes.slice(2, 2 + 7).every((i) => i === 0); if (!isZeros) { throw new Error("can't get Ethereum address: high bytes of genesis are not zero"); } return id.bytes.slice(2 + 7).slice(0, Constants.ETH_ADDRESS_LENGTH); } }; // src/claim.ts import { Hex as Hex3, poseidon as poseidon3 } from "@iden3/js-crypto"; var SlotName = /* @__PURE__ */ ((SlotName2) => { SlotName2["IndexA"] = "IndexA"; SlotName2["IndexB"] = "IndexB"; SlotName2["ValueA"] = "ValueA"; SlotName2["ValueB"] = "ValueB"; return SlotName2; })(SlotName || {}); var ErrSlotOverflow = class _ErrSlotOverflow extends Error { constructor(msg) { super(`Slot ${msg} not in field (too large)`); Object.setPrototypeOf(this, _ErrSlotOverflow.prototype); } }; var SubjectFlag = /* @__PURE__ */ ((SubjectFlag2) => { SubjectFlag2[SubjectFlag2["Self"] = 0] = "Self"; SubjectFlag2[SubjectFlag2["Invalid"] = 1] = "Invalid"; SubjectFlag2[SubjectFlag2["OtherIdenIndex"] = 2] = "OtherIdenIndex"; SubjectFlag2[SubjectFlag2["OtherIdenValue"] = 3] = "OtherIdenValue"; return SubjectFlag2; })(SubjectFlag || {}); var IdPosition = /* @__PURE__ */ ((IdPosition2) => { IdPosition2[IdPosition2["None"] = 0] = "None"; IdPosition2[IdPosition2["Index"] = 1] = "Index"; IdPosition2[IdPosition2["Value"] = 2] = "Value"; return IdPosition2; })(IdPosition || {}); var MerklizedFlag = /* @__PURE__ */ ((MerklizedFlag2) => { MerklizedFlag2[MerklizedFlag2["None"] = 0] = "None"; MerklizedFlag2[MerklizedFlag2["Index"] = 32] = "Index"; MerklizedFlag2[MerklizedFlag2["Value"] = 64] = "Value"; MerklizedFlag2[MerklizedFlag2["Invalid"] = 128] = "Invalid"; return MerklizedFlag2; })(MerklizedFlag || {}); var MerklizedRootPosition = /* @__PURE__ */ ((MerklizedRootPosition2) => { MerklizedRootPosition2[MerklizedRootPosition2["None"] = 0] = "None"; MerklizedRootPosition2[MerklizedRootPosition2["Index"] = 1] = "Index"; MerklizedRootPosition2[MerklizedRootPosition2["Value"] = 2] = "Value"; return MerklizedRootPosition2; })(MerklizedRootPosition || {}); var Flags = /* @__PURE__ */ ((Flags2) => { Flags2[Flags2["ByteIdx"] = 16] = "ByteIdx"; Flags2[Flags2["ExpirationBitIdx"] = 3] = "ExpirationBitIdx"; Flags2[Flags2["UpdatableBitIdx"] = 4] = "UpdatableBitIdx"; return Flags2; })(Flags || {}); var Claim = class _Claim { _index = []; _value = []; constructor() { for (let i = 0; i < Constants.ELEM_BYTES_LENGTH; i++) { this._index[i] = new ElemBytes(); this._value[i] = new ElemBytes(); } } // NewClaim creates new Claim with specified SchemaHash and any number of // options. Using options you can specify any field in claim. static newClaim(sh, ...args) { const c = new _Claim(); c.setSchemaHash(sh); for (let i = 0; i < args.length; i++) { const fn = args[i]; fn(c); } return c; } // GetSchemaHash return copy of claim's schema hash. getSchemaHash() { return new SchemaHash(this._index[0].bytes.slice(0, Constants.SCHEMA.HASH_LENGTH)); } get value() { return this._value; } set value(value) { this._value = value; } get index() { return this._index; } set index(value) { this._index = value; } // SetSchemaHash updates claim's schema hash. setSchemaHash(sh) { this._index[0] = new ElemBytes( Uint8Array.from([...sh.bytes, ...new Array(Constants.SCHEMA.HASH_LENGTH).fill(0)]) ); } setSubject(s) { this._index[0].bytes[16 /* ByteIdx */] &= 248; this._index[0].bytes[16 /* ByteIdx */] |= s; } getSubject() { let sbj = this._index[0].bytes[16 /* ByteIdx */]; sbj &= 7; return sbj; } setFlagExpiration(val) { if (val) { this._index[0].bytes[16 /* ByteIdx */] |= 1 << 3 /* ExpirationBitIdx */; } else { this._index[0].bytes[16 /* ByteIdx */] &= ~(1 << 3 /* ExpirationBitIdx */); } } getFlagExpiration() { const mask = 1 << 3 /* ExpirationBitIdx */; return (this._index[0].bytes[16 /* ByteIdx */] & mask) > 0; } // GetIDPosition returns the position at which the Id is stored. getIdPosition() { switch (this.getSubject()) { case 0 /* Self */: return 0 /* None */; case 2 /* OtherIdenIndex */: return 1 /* Index */; case 3 /* OtherIdenValue */: return 2 /* Value */; default: throw Constants.ERRORS.INVALID_SUBJECT_POSITION; } } // SetValueDataInts sets data to value slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. setValueDataInts(slotA, slotB) { this._value[2] = this.setSlotInt(slotA, "ValueA" /* ValueA */); this._value[3] = this.setSlotInt(slotB, "ValueB" /* ValueB */); } // SetValueDataBytes sets data to value slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. setValueDataBytes(slotA, slotB) { this._value[2] = this.setSlotBytes(slotA, "ValueA" /* ValueA */); this._value[3] = this.setSlotBytes(slotB, "ValueB" /* ValueB */); } // SetValueData sets data to value slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. setValueData(slotA, slotB) { const slotsAsInts = [slotA.toBigInt(), slotB.toBigInt()]; if (!checkBigIntArrayInField(slotsAsInts)) { throw Constants.ERRORS.DATA_OVERFLOW; } this._value[2] = slotA; this._value[3] = slotB; } // SetIndexDataInts sets data to index slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. setIndexDataInts(slotA, slotB) { this._index[2] = this.setSlotInt(slotA, "IndexA" /* IndexA */); this._index[3] = this.setSlotInt(slotB, "IndexB" /* IndexB */); } // SetIndexDataBytes sets data to index slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. setIndexDataBytes(slotA, slotB) { this._index[2] = this.setSlotBytes(slotA, "IndexA" /* IndexA */); this._index[3] = this.setSlotBytes(slotB, "IndexB" /* IndexB */); } setSlotBytes(value, slotName) { const slot = new ElemBytes(value); if (!checkBigIntInField(slot.toBigInt())) { throw new ErrSlotOverflow(slotName); } return slot; } setFlagMerklized(s) { let f; switch (s) { case 1 /* Index */: f = 32 /* Index */; break; case 2 /* Value */: f = 64 /* Value */; break; default: f = 0 /* None */; } this.index[0].bytes[16 /* ByteIdx */] &= 31; this.index[0].bytes[16 /* ByteIdx */] |= f; } getMerklized() { let mt = this.index[0].bytes[16 /* ByteIdx */]; mt &= 224; return mt; } // GetMerklizedPosition returns the position at which the Merklized flag is stored. getMerklizedPosition() { switch (this.getMerklized()) { case 0 /* None */: return 0 /* None */; case 32 /* Index */: return 1 /* Index */; case 64 /* Value */: return 2 /* Value */; default: throw Constants.ERRORS.INCORRECT_MERKLIZED_POSITION; } } setSlotInt(value, slotName) { if (!value) { value = BigInt(0); } if (!checkBigIntInField(value)) { throw new ErrSlotOverflow(slotName); } return new ElemBytes().setBigInt(value); } // SetIndexData sets data to index slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. setIndexData(slotA, slotB) { const slotsAsInts = [slotA.toBigInt(), slotB.toBigInt()]; if (!checkBigIntArrayInField(slotsAsInts)) { throw Constants.ERRORS.DATA_OVERFLOW; } this._index[2] = slotA; this._index[3] = slotB; } resetExpirationDate() { this.setFlagExpiration(false); const bytes = Array.from({ length: Constants.NONCE_BYTES_LENGTH }, () => 0); const arr = Array.from(this._value[0].bytes); arr.splice(Constants.NONCE_BYTES_LENGTH, Constants.NONCE_BYTES_LENGTH, ...bytes); this._value[0] = new ElemBytes(Uint8Array.from(arr)); } // GetExpirationDate returns expiration date and flag. Flag is true if // expiration date is present, false if null. getExpirationDate() { if (this.getFlagExpiration()) { const unixTimestamp = getUint64(this._value[0].bytes.slice(8, 16)); return getDateFromUnixTimestamp(Number(unixTimestamp)); } return null; } // SetExpirationDate sets expiration date to dt setExpirationDate(dt) { this.setFlagExpiration(true); const bytes = putUint64(BigInt(getUnixTimestamp(dt))); const arr = Array.from(this._value[0].bytes); arr.splice(Constants.NONCE_BYTES_LENGTH, Constants.NONCE_BYTES_LENGTH, ...bytes); this._value[0] = new ElemBytes(Uint8Array.from(arr)); } // GetRevocationNonce returns revocation nonce getRevocationNonce() { return getUint64(this._value[0].bytes.slice(0, 8)); } // SetRevocationNonce sets claim's revocation nonce setRevocationNonce(nonce) { const bytes = putUint64(nonce); if (bytes.length > Constants.NONCE_BYTES_LENGTH) { throw new Error("Nonce length is not valid"); } const arr = Array.from(this._value[0].bytes); arr.splice(0, Constants.NONCE_BYTES_LENGTH, ...bytes); this._value[0] = new ElemBytes(Uint8Array.from(arr)); } getValueId() { return Id.fromBytes(this._value[1].bytes.slice(0, -1)); } // SetValueId sets id to value. Removes id from index if any. setValueId(id) { this.resetIndexId(); this.setSubject(3 /* OtherIdenValue */); const arr = Array.from(this._index[1].bytes); arr.splice(0, id.bytes.length, ...id.bytes); this._value[1] = new ElemBytes(Uint8Array.from(arr)); } resetIndexId() { this._index[1] = new ElemBytes(new Uint8Array(Constants.BYTES_LENGTH).fill(0)); } resetValueId() { this._value[1] = new ElemBytes(new Uint8Array(Constants.BYTES_LENGTH).fill(0)); } getIndexId() { return Id.fromBytes(this._index[1].bytes.slice(0, -1)); } // SetIndexId sets id to index. Removes id from value if any. setIndexId(id) { this.resetValueId(); this.setSubject(2 /* OtherIdenIndex */); const arr = Array.from(this._index[1].bytes); arr.splice(0, id.bytes.length, ...id.bytes); this._index[1] = new ElemBytes(Uint8Array.from(arr)); } // SetVersion sets claim's version setVersion(ver) { const bytes = putUint32(ver); this._index[0].bytes[20] = bytes[0]; this._index[0].bytes[21] = bytes[1]; this._index[0].bytes[22] = bytes[2]; this._index[0].bytes[23] = bytes[3]; } // GetVersion returns claim's version getVersion() { return getUint32(this._index[0].bytes.slice(20, 24)); } // SetFlagUpdatable sets claim's flag `updatable` setFlagUpdatable(val) { if (val) { this._index[0].bytes[16 /* ByteIdx */] |= 1 << 4 /* UpdatableBitIdx */; } else { this._index[0].bytes[16 /* ByteIdx */] &= ~(1 << 4 /* UpdatableBitIdx */); } } // HIndex calculates the hash of the Index of the Claim hIndex() { return poseidon3.hash(ElemBytes.elemBytesToInts(this._index)); } // GetFlagUpdatable returns claim's flag `updatable` getFlagUpdatable() { const mask = 1 << 4 /* UpdatableBitIdx */; return (this._index[0].bytes[16 /* ByteIdx */] & mask) > 0; } // HValue calculates the hash of the Value of the Claim hValue() { return poseidon3.hash(ElemBytes.elemBytesToInts(this._value)); } // HiHv returns the HIndex and HValue of the Claim hiHv() { return { hi: this.hIndex(), hv: this.hValue() }; } // SetIndexMerklizedRoot sets merklized root to index. Removes root from value[2] if any. setIndexMerklizedRoot(r) { this.resetValueMerklizedRoot(); this.setFlagMerklized(1 /* Index */); this.index[2] = this.setSlotInt(r, "IndexA" /* IndexA */); } resetIndexMerklizedRoot() { this._index[2] = new ElemBytes(new Uint8Array(Constants.BYTES_LENGTH).fill(0)); } // SetValueMerklizedRoot sets merklized root to value. Removes root from index[2] if any. setValueMerklizedRoot(r) { this.resetIndexMerklizedRoot(); this.setFlagMerklized(2 /* Value */); this.value[2] = this.setSlotInt(r, "ValueA" /* ValueA */); } resetValueMerklizedRoot() { this._value[2] = new ElemBytes(new Uint8Array(Constants.BYTES_LENGTH).fill(0)); } // GetMerklizedRoot returns merklized root from claim's index of value. // Returns error ErrNoMerklizedRoot if MerklizedRoot is not set. getMerklizedRoot() { switch (this.getMerklized()) { case 32 /* Index */: return this.index[2].toBigInt(); case 64 /* Value */: return this.value[2].toBigInt(); default: throw Constants.ERRORS.NO_MERKLIZED_ROOT; } } // resetId deletes Id from index and from value. resetId() { this.resetIndexId(); this.resetValueId(); this.setSubject(0 /* Self */); } // GetId returns Id from claim's index of value. // Returns error ErrNoId if Id is not set. getId() { switch (this.getSubject()) { case 2 /* OtherIdenIndex */: return this.getIndexId(); case 3 /* OtherIdenValue */: return this.getValueId(); default: throw Constants.ERRORS.NO_ID; } } // RawSlots returns raw bytes of claim's index and value rawSlots() { return { index: this._index, value: this._value }; } // RawSlotsAsInts returns slots as []bigint rawSlotsAsInts() { return [...ElemBytes.elemBytesToInts(this._index), ...ElemBytes.elemBytesToInts(this._value)]; } clone() { return JSON.parse(JSON.stringify(this)); } marshalJson() { return this.rawSlotsAsInts().map((b) => b.toString()); } unMarshalJson(b) { const ints = JSON.parse(b).map((s) => BigInt(s)); if (ints.length !== this._index.length + this._value.length) { throw new Error("invalid number of claim's slots"); } this._index = []; this._value = []; for (let i = 0, j = Constants.ELEM_BYTES_LENGTH; i < ints.length / 2; i++, j++) { this._index[i] = new ElemBytes(); this._index[i].setBigInt(ints[i]); this._value[i] = new ElemBytes(); this._value[i].setBigInt(ints[j]); } return this; } marshalBinary() { const getBytes = (src) => src.reduce((acc, cur) => { return [...acc, ...cur.bytes]; }, []); return Uint8Array.from(getBytes(this._index).concat(getBytes(this._value))); } // Hex returns hex representation of binary claim hex() { const b = this.marshalBinary(); return Hex3.encodeString(b); } fromHex(hex) { const b = Hex3.decodeString(hex); this.unMarshalBinary(b); return this; } unMarshalBinary(data) { const wantLen = 2 * Constants.ELEM_BYTES_LENGTH * Constants.BYTES_LENGTH; if (data.length !== wantLen) { throw new Error("unexpected length of input data"); } this._index = []; this._value = []; for (let i = 0, j = Constants.ELEM_BYTES_LENGTH; i < Constants.ELEM_BYTES_LENGTH; i++, j++) { this._index[i] = new ElemBytes( data.slice(i * Constants.BYTES_LENGTH, (i + 1) * Constants.BYTES_LENGTH) ); this._value[i] = new ElemBytes( data.slice(j * Constants.BYTES_LENGTH, (j + 1) * Constants.BYTES_LENGTH) ); } } }; var ClaimOptions = class { // WithFlagUpdatable sets claim's flag `updatable` static withFlagUpdatable(val) { return (c) => c.setFlagUpdatable(val); } // WithVersion sets claim's version static withVersion(ver) { return (c) => c.setVersion(ver); } // WithIndexId sets Id to claim's index static withIndexId(id) { return (c) => c.setIndexId(id); } // WithValueId sets Id to claim's value static withValueId(id) { return (c) => c.setValueId(id); } // WithFlagMerklized sets claim's flag `merklized` static withFlagMerklized(p) { return (c) => c.setFlagMerklized(p); } // WithId sets Id to claim's index or value depending on `pos`. static withId(id, pos) { return (c) => { switch (pos) { case 1 /* Index */: c.setIndexId(id); break; case 2 /* Value */: c.setValueId(id); break; default: throw Constants.ERRORS.INCORRECT_ID_POSITION; } }; } // WithRevocationNonce sets claim's revocation nonce. static withRevocationNonce(nonce) { return (c) => c.setRevocationNonce(nonce); } // WithExpirationDate sets claim's expiration date to `dt`. static withExpirationDate(dt) { return (c) => c.setExpirationDate(dt); } // WithIndexData sets data to index slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. static withIndexData(slotA, slotB) { return (c) => c.setIndexData(slotA, slotB); } // WithIndexDataBytes sets data to index slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. static withIndexDataBytes(slotA, slotB) { return (c) => c.setIndexDataBytes(slotA, slotB); } // WithIndexDataInts sets data to index slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. static withIndexDataInts(slotA, slotB) { return (c) => c.setIndexDataInts(slotA, slotB); } // WithValueData sets data to value slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. static withValueData(slotA, slotB) { return (c) => c.setValueData(slotA, slotB); } // WithValueDataBytes sets data to value slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. static withValueDataBytes(slotA, slotB) { return (c) => c.setValueDataBytes(slotA, slotB); } // WithValueDataInts sets data to value slots A & B. // Returns ErrSlotOverflow if slotA or slotB value are too big. static withValueDataInts(slotA, slotB) { return (c) => c.setValueDataInts(slotA, slotB); } // WithIndexMerklizedRoot sets root to index i_2 // Returns ErrSlotOverflow if root value are too big. static withIndexMerklizedRoot(r) { return (c) => { c.setFlagMerklized(1 /* Index */); c.index[2] = c.setSlotInt(r, "IndexA" /* IndexA */); }; } // WithValueMerklizedRoot sets root to value v_2 // Returns ErrSlotOverflow if root value are too big. static withValueMerklizedRoot(r) { return (c) => { c.setFlagMerklized(2 /* Value */); c.value[2] = c.setSlotInt(r, "ValueA" /* ValueA */); }; } // WithMerklizedRoot sets root to value v_2 or index i_2 // Returns ErrSlotOverflow if root value are too big. static withMerklizedRoot(r, pos) { return (c) => { switch (pos) { case 1 /* Index */: c.setFlagMerklized(1 /* Index */); c.index[2] = c.setSlotInt(r, "IndexA" /* IndexA */); break; case 2 /* Value */: c.setFlagMerklized(2 /* Value */); c.value[2] = c.setSlotInt(r, "ValueA" /* ValueA */); break; default: throw Constants.ERRORS.INCORRECT_MERKLIZED_POSITION; } }; } }; // src/did/did-helper.ts var DIDNetworkFlag = class _DIDNetworkFlag { constructor(blockchain, networkId) { this.blockchain = blockchain; this.networkId = networkId; } toString() { return `${this.blockchain}:${this.networkId}`; } static fromString(s) { const [blockchain, networkId] = s.split(":"); return new _DIDNetworkFlag(blockchain.replace("_", ""), networkId.replace("_", "")); } }; function buildDIDType(method, blockchain, network) { const fb = DidMethodByte[method]; if (!fb) { throw Constants.ERRORS.UNSUPPORTED_DID_METHOD; } const methodFn = DidMethodNetwork[method]; if (!methodFn) { throw Constants.ERRORS.NETWORK_NOT_SUPPORTED_FOR_DID; } const sb = methodFn[new DIDNetworkFlag(blockchain, network).toString()]; if (typeof sb !== "number") { throw new Error( `blockchain ${blockchain.toString() ?? "-"} and network ${network.toString() ?? "-"} is not defined in core lib` ); } return Uint8Array.from([fb, sb]); } function findNetworkIDForDIDMethodByValue(method, byteNumber) { const methodMap = DidMethodNetwork[method]; if (!methodMap) { throw Constants.ERRORS.UNSUPPORTED_DID_METHOD; } for (const [key, value] of Object.entries(methodMap)) { if (value === byteNumber) { return DIDNetworkFlag.fromString(key).networkId; } } throw Constants.ERRORS.NETWORK_NOT_SUPPORTED_FOR_DID; } function findBlockchainForDIDMethodByValue(method, byteNumber) { const methodMap = DidMethodNetwork[method]; if (!methodMap) { throw new Error( `${Constants.ERRORS.NETWORK_NOT_SUPPORTED_FOR_DID}: did method ${method} is not defined in core lib` ); } for (const [key, value] of Object.entries(methodMap)) { if (value === byteNumber) { return DIDNetworkFlag.fromString(key).blockchain; } } throw Constants.ERRORS.UNSUPPORTED_BLOCKCHAIN_FOR_DID; } function findDIDMethodByValue(byteNumber) { for (const [key, value] of Object.entries(DidMethodByte)) { if (value === byteNumber) { return key; } } throw Constants.ERRORS.UNSUPPORTED_DID_METHOD; } // src/did/types.ts var Param = class { constructor(name, value) { this.name = name; this.value = value; } toString() { if (!this.name) { return ""; } if (!this.value) { return this.name; } return `${this.name}=${this.value}`; } }; var initDIDParams = Object.freeze({ method: "", id: "", idStrings: [], params: [], path: "", pathSegments: [], query: "", fragment: "" }); // src/did/did-parser.ts var Parser = class { // the output DID that the parser will assemble as it steps through its state machine // an error in the parser state machine constructor(input) { this.input = input; } currentIndex = 0; // index in the input which the parser is currently processing: out = { ...initDIDParams }; checkLength() { const inputLength = this.input.length; if (inputLength < 7) { throw new Error("input length is less than 7"); } return this.parseScheme.bind(this); } // parseScheme is a parserStep that validates that the input begins with 'did:' parseScheme() { const currentIndex = 3; if (this.input.slice(0, currentIndex + 1) !== "did:") { throw new Error("input does not begin with 'did:' prefix"); } this.currentIndex = currentIndex; return this.parseMethod.bind(this); } parseMethod() { const input = this.input; const inputLength = input.length; let currentIndex = this.currentIndex + 1; const startIndex = currentIndex; for (; ; ) { if (currentIndex === inputLength) { throw new Error("input does not have a second `:` marking end of method name"); } const char = input[currentIndex]; if (char === ":") { if (currentIndex === startIndex) { throw new Error(`method is empty, ${currentIndex}`); } break; } if (StringUtils.isNotDigit(char) && StringUtils.isNotSmallLetter(char)) { throw new Error(`"character is not a-z OR 0-9, ${currentIndex}`); } currentIndex = currentIndex + 1; } this.currentIndex = currentIndex; this.out.method = input.slice(startIndex, currentIndex); return this.parseId.bind(this); } parseId() { const input = this.input; const inputLength = input.length; let currentIndex = this.currentIndex + 1; const startIndex = currentIndex; let next = null; for (; ; ) { if (currentIndex === inputLength) { next = null; break; } const char = input[currentIndex]; if (char === ":") { next = this.parseId; break; } if (char === ";") { next = this.parseParamName; break; } if (char === "/") { next = this.parsePath; break; } if (char === "?") { next = this.parseQuery; break; } if (char === "#") { next = this.parseFragment; break; } if (StringUtils.isNotValidIDChar(char)) { throw new Error(`byte is not ALPHA OR DIGIT OR '.' OR '-', ${currentIndex}`); } currentIndex = currentIndex + 1; } if (currentIndex === startIndex) { throw new Error(`idstring must be at least one char long, ${currentIndex}`); } this.currentIndex = currentIndex; this.out.idStrings = [...this.out.idStrings, input.slice(startIndex, currentIndex)]; return next ? next.bind(this) : null; } parseParamName() { const input = this.input; const startIndex = this.currentIndex + 1; const next = this.paramTransition(); const currentIndex = this.currentIndex; if (currentIndex === startIndex) { throw new Error(`Param name must be at least one char long, ${currentIndex}`); } this.out.params = [...this.out.params, new Param(input.slice(startIndex, currentIndex), "")]; return next ? next.bind(this) : null; } parseParamValue() { const input = this.input; const startIndex = this.currentIndex + 1; const next = this.paramTransition(); const currentIndex = this.currentIndex; this.out.params[this.out.params.length - 1].value = input.slice(startIndex, currentIndex); return next ? next.bind(this) : null; } paramTransition() { const input = this.input; const inputLength = input.length; let currentIndex = this.currentIndex + 1; let indexIncrement; let next; let percentEncoded; for (; ; ) { if (currentIndex === inputLength) { next = null; break; } const char = input[currentIndex]; if (char === ";") { next = this.parseParamName; break; } if (char === "=") { next = this.parseParamValue; break; } if (char === "/") { next = this.parsePath; break; } if (char === "?") { next = this.parseQuery; break; } if (char == "#") { next = this.parseFragment; break; } if (char == "%") { if (currentIndex + 2 >= inputLength || StringUtils.isNotHexDigit(input[currentIndex + 1]) || StringUtils.isNotHexDigit(input[currentIndex + 2])) { throw new Error(`% is not followed by 2 hex digits', ${currentIndex}`); } percentEncoded = true; indexIncrement = 3; } else { percentEncoded = false; indexIncrement = 1; } if (!percentEncoded && StringUtils.isNotValidParamChar(char)) { throw new Error(`character is not allowed in param - ${char}', ${currentIndex}`); } currentIndex = currentIndex + indexIncrement; } this.currentIndex = currentIndex; return next ? next.bind(this) : null; } parsePath() { const input = this.input; const inputLength = input.length; let currentIndex = this.currentIndex + 1; const startIndex = currentIndex; let indexIncrement; let next; let percentEncoded; for (; ; ) { if (currentIndex === inputLength) { next = null; break; } const char = input[currentIndex]; if (char === "/") { next = this.parsePath; break; } if (char === "?") { next = this.parseQuery; break; } if (char === "%") { if (currentIndex + 2 >= inputLength || StringUtils.isNotHexDigit(input[currentIndex + 1]) || StringUtils.isNotHexDigit(input[currentIndex + 2])) { throw new Error(`% is not followed by 2 hex digits, ${currentIndex}`); } percentEncoded = true; indexIncrement = 3; } else { percentEncoded = false; indexIncrement = 1; } if (!percentEncoded && StringUtils.isNotValidPathChar(char)) { throw new Error(`character is not allowed in path, ${currentIndex}`); } currentIndex = currentIndex + indexIncrement; } if (currentIndex == startIndex && this.out.pathSegments.length === 0) { throw new Error(`first path segment must have at least one character, ${currentIndex}`); } this.currentIndex = currentIndex; this.out.pathSegments = [...this.out.pathSegments, input.slice(startIndex, currentIndex)]; return next ? next.bind(this) : null; } parseQuery() { const input = this.input; const inputLength = input.length; let currentIndex = this.currentIndex + 1; const startIndex = currentIndex; let indexIncrement; let next = null; let percentEncoded; for (; ; ) { if (currentIndex === inputLength) { break; } const char = input[currentIndex]; if (char === "#") { next = this.parseFragment; break; } if (char === "%") { if (currentIndex + 2 >= inputLength || StringUtils.isNotHexDigit(input[currentIndex + 1]) || StringUtils.isNotHexDigit(input[currentIndex + 2])) { throw new Error(`% is not followed by 2 hex digits, ${currentIndex}`); } percentEncoded = true; indexIncrement = 3; } else { percentEncoded = false; indexIncrement = 1; } if (!percentEncoded && StringUtils.isNotValidQueryOrFragmentChar(char)) { throw new Error(`character is not allowed in query - ${char}`); } currentIndex = currentIndex + indexIncrement; } this.currentIndex = currentIndex; this.out.query = input.slice(startIndex, currentIndex); return next ? next.bind(this) : null; } parseFragment() { const input = this.input; const inputLength = this.input.length; let currentIndex = this.currentIndex + 1; const startIndex = currentIndex; let indexIncrement; let percentEncoded; for (; ; ) { if (currentIndex === inputLength) { break; } const char = input[currentIndex]; if (char === "%") { if (currentIndex + 2 >= inputLength || StringUtils.isNotHexDigit(input[currentIndex + 1]) || StringUtils.isNotHexDigit(input[currentIndex + 2])) { throw new Error(`% is not followed by 2 hex digits, ${currentIndex}`); } percentEncoded = true; indexIncrement = 3; } else { percentEncoded = false; indexIncrement = 1; } if (!percentEncoded && StringUtils.isNotValidQueryOrFragmentChar(char)) { throw new Error(`character is not allowed in fragment - ${char}`); } currentIndex = currentIndex + indexIncrement; } this.currentIndex = currentIndex; this.out.fragment = input.slice(startIndex, currentIndex); return null; } }; // src/did/did.ts import { sha256 as sha2562 } from "@iden3/js-crypto"; var DID = class _DID { method = ""; id = ""; idStrings = []; params = []; path = ""; pathSegments = []; query = ""; fragment = ""; constructor(d) { if (d) { Object.assign(this, d); } } isUrl() { return this.params.length > 0 || !!this.path || this.pathSegments.length > 0 || !!this.query || !!this.fragment; } string() { const buff = ["did:"]; if (this.method) { buff.push(`${this.method}:`); } else { return ""; } if (this.id) { buff.push(this.id); } else if (this.idStrings.length) { buff.push(this.idStrings.join(":")); } else { return ""; } if (this.params.length) { for (const param of this.params) { const p = param.toString(); if (p) { buff.push(`;${p}`); } else { return ""; } } } if (this.path) { buff.push(`/${this.path}`); } else if (this.pathSegments.length) { buff.push(`/${this.pathSegments.join("/")}`); } if (this.query) { buff.push(`?${this.query}`); } if (this.fragment) { buff.push(`#${this.fragment}`); } return buff.join(""); } toJSON() { return this.string(); } static parse(s) { const parser = new Parser(s); let parserState = parser.checkLength(); while (parserState) { parserState = parserState(); } parser.out.id = parser.out.idStrings.join(":"); parser.out.path = parser.out.pathSegments.join("/"); return new _DID(parser.out); } static decodePartsFromId(id) { const method = findDIDMethodByValue(id.bytes[0]); const blockchain = findBlockchainForDIDMethodByValue(method, id.bytes[1]); const networkId = findNetworkIDForDIDMethodByValue(method, id.bytes[1]); return { method, blockchain, networkId }; } static networkIdFromId(id) { return _DID.throwIfDIDUnsupported(id).networkId; } static methodFromId(id) { return _DID.throwIfDIDUnsupported(id).method; } static blockchainFromId(id) { return _DID.throwIfDIDUnsupported(id).blockchain; } static throwIfDIDUnsupported(id) { const { method, blockchain, networkId } = _DID.decodePartsFromId(id); if (_DID.isUnsupported(method, blockchain, networkId)) { throw new Error(`${Constants.ERRORS.UNKNOWN_DID_METHOD.message}: unsupported DID`); } return { method, blockchain, networkId }; } // DIDGenesisFromIdenState calculates the genesis ID from an Identity State and returns it as DID static newFromIdenState(typ, state) { const id = Id.idGenesisFromIdenState(typ, state); return _DID.parseFromId(id); } // NewDID creates a new *w3c.DID from the type and the genesis static new(typ, genesis) { return _DID.parseFromId(new Id(typ, genesis)); } // ParseDIDFromID returns DID from ID static parseFromId(id) { if (!BytesHelper.checkChecksum(id.bytes)) { throw new Error(`${Constants.ERRORS.UNSUPPORTED_ID.message}: invalid checksum`); } const { method, blockchain, networkId } = _DID.throwIfDIDUnsupported(id); const didParts = [Constants.DID.DID_SCHEMA, method.toString(), blockchain.toString()]; if (networkId) { didParts.push(networkId.toString()); } didParts.push(id.string()); const didString = didParts.join(":"); const did = _DID.parse(didString); return did; } static idFromDID(did) { let id; try { id = _DID.getIdFromDID(did); } catch (error) { if (error.message === Constants.ERRORS.UNKNOWN_DID_METHOD.message) { return _DID.idFromUnsupport