@iden3/js-iden3-core
Version:
Low level API to create and manipulate iden3 Claims.
89 lines (88 loc) • 3.14 kB
JavaScript
import { Constants } from './constants';
import { fromLittleEndian } from './utils';
import { BytesHelper, ElemBytes } from './elemBytes';
import { poseidon, base58ToBytes, base58FromBytes } from '@iden3/js-crypto';
// ID is a byte array with
// [ type | root_genesis | checksum ]
// [2 bytes | 27 bytes | 2 bytes ]
// where the root_genesis are the first 28 bytes from the hash root_genesis
export class Id {
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 = poseidon.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, //nolint:revive
state) {
const idenStateData = ElemBytes.fromInt(state);
// we take last 27 bytes, because of swapped endianness
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);
}
}