@unirep/core
Version:
Client library for protocol related functions which are used in UniRep protocol.
316 lines (315 loc) • 14.2 kB
TypeScript
import { ethers } from 'ethers';
import { DB } from 'anondb';
import { Identity } from '@semaphore-protocol/identity';
import { Prover, ReputationProof, EpochKeyProof, SignupProof, UserStateTransitionProof, EpochKeyLiteProof } from '@unirep/circuits';
import { Synchronizer } from './Synchronizer';
/**
* The user state object is used to manage user state for an attester.
* The state is backed by an [anondb](https://github.com/vimwitch/anondb) instance.
* @example
* ```ts
* import { UserState } from '@unirep/core'
* import { defaultProver } from '@unirep/circuits/provers/defaultProver'
* import { Identity } from '@semaphore-protocol/identity'
*
* const id = new Identity()
* const state = new UserState({
* prover: defaultProver, // a circuit prover
* unirepAddress: '0xaabbccaabbccaabbccaabbccaabbccaabbccaaaa',
* provider, // an ethers.js provider
* id,
* })
*
* // or, initialize with an existing synchronizer object
* const state = new UserState({
* synchronizer,
* id,
* prover: defaultProver, // a circuit prover
* })
*
* // start the synchoronizer deamon
* await state.start()
* await state.waitForSync()
*
* // stop the synchronizer deamon
* state.stop()
* ```
*/
export default class UserState {
private _prover;
private _id;
private _sync;
private _chainId;
private _db;
/**
* The [Semaphore](https://semaphore.pse.dev/) identity commitment of the user.
*/
get commitment(): bigint;
/**
* The [Semaphore](https://semaphore.pse.dev/) identity of the user.
*/
get id(): Identity;
/**
* The underlying synchronizer object.
*/
get sync(): Synchronizer;
/**
* The prover object.
*/
get prover(): Prover;
/**
* The current chain ID of UniRep contract.
*/
get chainId(): number;
/**
* Read the database object.
*/
get db(): DB;
constructor(config: {
synchronizer?: Synchronizer;
db?: DB;
attesterId?: bigint | bigint[];
unirepAddress?: string;
provider?: ethers.providers.Provider;
id: Identity;
prover: Prover;
});
/**
* Start the synchronizer daemon.
* Start polling the blockchain for new events. If we're behind the HEAD block we'll poll many times quickly
*/
start(): Promise<void>;
/**
* Wait for the synchronizer to sync up to a certain block.
* By default this will wait until the current latest known block (according to the provider).
* @param blockNumber The block number to be synced to.
*/
waitForSync(blockNumber?: number): Promise<void>;
/**
* Stop synchronizing with Unirep contract.
*/
stop(): void;
/**
* Query the current database if the [Semaphore](https://semaphore.pse.dev/) identity commitment is stored.
* @param attesterId The attester to be queried. Default: `this.attesterId`.
* @returns True if user has signed up in unirep contract, false otherwise.
*/
hasSignedUp(attesterId?: bigint | string): Promise<boolean>;
/**
* Query the current database for a user's signup event or latest user state transition [nullifier](https://developer.unirep.io/docs/protocol/nullifiers).
* @param attesterId The attester to be queried. Default: `this.attesterId`
* @returns The latest epoch where a user performed a user state transition.
*/
latestTransitionedEpoch(attesterId?: bigint | string): Promise<number>;
/**
* Get the latest global state tree leaf index for an epoch.
* @param epoch Get the global state tree leaf index of the given epoch. Default: current epoch.
* @param attesterId The attester to be queried. Default: `this.attesterId`
* @returns The the latest state tree leaf index for an epoch.
*/
latestStateTreeLeafIndex(epoch?: number, attesterId?: bigint | string): Promise<number>;
/**
* Get epoch keys for the current user, for an epoch.
* If a `nonce` value is supplied the return value will be a single epoch key.
* Otherwise an array of all epoch keys will be returned.
*
* If no `epoch` is supplied the current epoch will be used (as determined by `synchronizer.calcCurrentEpoch`).
* @param epoch The epoch to be queried. Default: current epoch.
* @param nonce The specified epoch key nonce. Default: `0`.
* @param attesterId The attester to be queried. Default: `this.attesterId`
* @returns An epoch key or an array of epoch keys.
*/
getEpochKeys(epoch?: bigint | number, nonce?: number, attesterId?: bigint | string): bigint | bigint[];
/**
* This function is used to parse replacement data field to be `index` and `data`. See [replacement data field](https://developer.unirep.io/docs/protocol/data#replacement-field).
* @param replData The raw data which is processed on-chain.
* @returns The parsed data and the data index (nonce).
*/
parseReplData(replData: bigint): {
data: bigint;
nonce: bigint;
};
/**
* @private
* Update user state data.
* @param data The latest transitioned data.
* @param latestTransitionedEpoch The latest found transitioned epoch.
* @param attesterId The attester ID.
*/
private _updateData;
/**
* Get the data for a user up to and including the provided epoch.
* By default data up to and including the current epoch is returned.
*
* :::tip
* If you want to make a proof of data make sure to use `getProvableData`.
* Data can only be proven once it has been included in a state tree leaf.
* Learn more about reputation proofs [here](https://developer.unirep.io/docs/circuits-api/classes/src.ReputationProof.md).
* :::
* @param toEpoch The latest epoch that the reputation is accumulated. Default: current epoch.
* @param attesterId The attester to be queried. Default: `this.sync.attesterId`
* @param fromEpoch The epoch to start querying from. Default: `0`.
* @returns The data object
*/
getData: (toEpoch?: number, attesterId?: bigint | string) => Promise<bigint[]>;
/**
* Get the data that can be proven by the user using a state tree leaf.
* This is the data up to, but not including, the epoch the user has transitioned into.
* @param attesterId The attester to be queried. Default: `this.attesterId`
* @returns The data object
*/
getProvableData(attesterId?: bigint | string): Promise<bigint[]>;
/**
* Get the pending changes to the data owned by an epoch key.
* @param epochKey The epoch key to be queried.
* @param epoch The epoch of the epoch key to be queried.
* @param attesterId The attester to be queried. Default: `this.attesterId`
* @returns The data object.
*/
getDataByEpochKey: (epochKey: bigint | string, epoch: number, attesterId?: bigint | string) => Promise<any[]>;
/**
* @private
* Check if epoch key nonce is valid. Throws an error if the epoch key nonce is invalid.
* @param epochKeyNonce The input epoch key nonce to be checked.
*/
private _checkEpkNonce;
/**
* @private
* Check if a synchronizer is set. Throws an error if a synchronizer is not set.
*/
private _checkSync;
/**
* @private
* Check if a chain ID is set. If a chain ID is not set, it queries the provider and sets chain ID.
*/
private _checkChainId;
/**
* @private
* Check if the input exceeds the maximum bit
* @param input The input value
* @param bit The bit number
*/
private _checkBit;
/**
* Get the index of epoch key among all attestations.
* @param epoch The epoch of the epoch key to be queried.
* @param epochKey The epoch key to be queried.
* @param attesterId The attester to be queried.
* @returns The index of the epoch key.
*/
getEpochKeyIndex: (epoch: number, epochKey: bigint | string, attesterId: bigint | string) => Promise<number>;
/**
* Generate a user state transition proof. Returns a [`UserStateTransitionProof`](https://developer.unirep.io/docs/circuits-api/classes/src.UserStateTransitionProof.md).
* @param options.toEpoch `toEpoch` is used to indicate in which epoch the proof will be used. Default: current epoch.
* @param options.attesterId `attesterId` is used to generate proof for certain attester. Default: `this.attesterId`.
* @returns The `UserStateTransitionProof` object.
* @example
* ```ts
* const { publicSignals, proof } = await userState.genUserStateTransitionProof()
* ```
*/
genUserStateTransitionProof: (options?: {
toEpoch?: number;
attesterId?: bigint | string;
}) => Promise<UserStateTransitionProof>;
/**
* Generate a proof of reputation. Returns a [`ReputationProof`](https://developer.unirep.io/docs/circuits-api/classes/src.ReputationProof.md).
* :::danger
* **Please avoid assigning the `minRep = data[0] - data[1]` or `maxRep = data[1] - data[0]`.**<br/>
* The proof could allow a user to accidentally publish their overall reputation (i.e. `data[0]-data[1]`).
* Depending on the circumstances (such as the length of the attestation history) this could reveal a user’s epoch key(s) as well.
* :::
* @param options.epkNonce The nonce determines the output of the epoch key. Default: `0`.
* @param options.minRep The amount of reputation that user wants to prove. It should satisfy: `posRep - negRep >= minRep`. Default: `0`
* @param options.maxRep The amount of reputation that user wants to prove. It should satisfy: `negRep - posRep >= maxRep`. Default: `0`
* @param options.graffiti The graffiti that user wants to prove. It should satisfy: `graffiti == (data[SUM_FIELD_COUNT] / (2 ** REPL_NONCE_BITS))`. Default: `0`.
* @param options.proveZeroRep Indicates if user wants to prove `posRep - negRep == 0`. Default: `0`.
* @param options.revealNonce Indicates if user wants to reveal epoch key nonce. Default: `false`.
* @param options.data Indicates if user wants to endorse a 253-bits data. Default: `0`.
* @param options.attesterId `attesterId` is used to generate proof for certain attester. Default: `this.attesterId`
* @returns The reputation proof of type `ReputationProof`.
* @example
* ```ts
* const {publicSignals, proof} = await userState.genProveReputationProof({
* minRep: 3,
* graffiti: '1234',
* })
* ```
*/
genProveReputationProof: (options: {
epkNonce?: number;
minRep?: number | bigint | string;
maxRep?: number | bigint | string;
graffiti?: bigint | string;
proveZeroRep?: boolean;
revealNonce?: boolean;
data?: bigint | string;
attesterId?: bigint | string;
}) => Promise<ReputationProof>;
/**
* Generate a proof that can be used to signup. Returns a [`SignupProof`](https://developer.unirep.io/docs/circuits-api/classes/src.SignupProof.md)
* @param options.epoch Indicates in which epoch the proof will be used. Default: current epoch.
* @param options.attesterId Indicates for which attester the proof will be used. Default: `this.attesterId`
* @returns The sign up proof of type `SignUpProof`.
* @example
* ```ts
* const { publicSignals, proof } = await userState.genUserSignUpProof()
* ```
*/
genUserSignUpProof: (options?: {
epoch?: number;
attesterId?: bigint | string;
}) => Promise<SignupProof>;
/**
* Generate a proof that a user controls an epoch key in a certain epoch.
* Optionally provide a data value to sign.
* Returns an [`EpochKeyProof`](https://developer.unirep.io/docs/circuits-api/classes/src.EpochKeyProof.md).
* @param options.nonce The specified epoch key nonce. Default: `0`.
* @param options.epoch The specified epoch. Default: current epoch.
* @param options.data Indicates if user wants to endorse a 253-bits data. Default: `0`
* @param options.revealNonce Indicates if user wants to reveal epoch key nonce. Default: `false`.
* @param options.attesterId Indicates for which attester the proof will be used. Default: `this.attesterId`
* @returns The epoch key proof of type `EpochKeyProof`.
* @example
* ```ts
* const { publicSignals, proof } = await userState.genEpochKeyProof({
* nonce: 1
* })
* ```
*/
genEpochKeyProof: (options?: {
nonce?: number;
epoch?: number;
data?: bigint;
revealNonce?: boolean;
attesterId?: bigint | string;
}) => Promise<EpochKeyProof>;
/**
* Generate a proof that a user controls an epoch key in a certain epoch.
* Optionally provide a data value to sign.
* Returns an [`EpochKeyLiteProof`](https://developer.unirep.io/docs/circuits-api/classes/src.EpochKeyLiteProof.md).
*
* This proof **will not include a merkle tree proof** which makes the proof size smaller than an [`EpochKeyProof`](https://developer.unirep.io/docs/circuits-api/classes/src.EpochKeyProof.md).
* It can be used to prove a seen and valid epoch key.
* @param options.nonce The specified epoch key nonce. Default: `0`.
* @param options.epoch The specified epoch. Default: current epoch.
* @param options.data Indicates if user wants to endorse a 253-bits data. Default: `0`.
* @param options.revealNonce Indicates if user wants to reveal epoch key nonce. Default: `false`.
* @param options.attesterId Indicates for which attester the proof will be used. Default: `this.attesterId`
* @returns The epoch key lite proof of type `EpochKeyLiteProof`.
* @example
* ```ts
* const { publicSignals, proof } = await userState.genEpochKeyLiteProof({
* nonce: 1
* })
* ```
*/
genEpochKeyLiteProof: (options?: {
nonce?: number;
epoch?: number;
data?: bigint;
revealNonce?: boolean;
attesterId?: bigint | string;
}) => Promise<EpochKeyLiteProof>;
}
export { UserState };