4. Epoch key proof
Before generating an epoch key proof, we should generate a current user state to know the current global state trees and the attestation histories.
DB
We should initialize a storage to save the state.
import { DB, SQLiteConnector } from 'anondb/node'
import { schema } from '@unirep/core'
// construct a memory db
const db = await SQLiteConnector.create(schema, ':memory:')
// or construct a SQLite db
// const db = await SQLiteConnector.create(schema, 'test.sqlite')
Prover
Also we have to initialize a prover to generate proofs and verify proofs. Or a defaultProver
can be used in the @unirep/circuits
package.
import { defaultProver as prover } from '@unirep/circuits/provers/defaultProver'
See: @unirep/circuits
Identity
Also, the ZkIdentity
can be unserialized with a serialized identity, for example:
import { ZkIdentity, Strategy } from '@unirep/crypto'
const identity = new ZkIdentity(
Strategy.SERIALIZED,
`{"identityNullifier":"27d1ae5c98aab64b851a9c668a7eec0d835867a17d4b9454a8bf9824836271d6","identityTrapdoor":"2596ecc2a1e1f6a8f279e097464e6edc3b18b946d934398dfe52a34c4e414e67","secret":["27d1ae5c98aab64b851a9c668a7eec0d835867a17d4b9454a8bf9824836271d6","2596ecc2a1e1f6a8f279e097464e6edc3b18b946d934398dfe52a34c4e414e67"]}`
)
Generate current user state
And then we can use a genUserState
to perform synchronization.
import { UserState } from '@unirep/core'
const genUserState = async (
provider: ethers.providers.Provider,
address: string,
identity: ZkIdentity,
db: DB
) => {
const contract = getUnirepContract(address, provider)
const userState = new UserState(
db,
prover,
contract,
identity
)
await userState.start()
await userState.waitForSync()
return userState
}
const userState = await genUserState(
provider,
UNIREP_CONTRACT_ADDRESS,
identity,
db
)
Generate epoch key proof
Use the user state to generate epoch key proof.
// genearte epoch key proof
const epochKeyNonce = 0
const proof = await userState.genVerifyEpochKeyProof(epochKeyNonce)
Verify epoch key proof
Verify the proof with UniRep smart contract
const isValid = await contract.verifyEpochKeyValidity(
proof.publicSignals,
proof.proof
)
console.log(isValid)
Verify the proof with local prover
const isValid = await proof.verify()
console.log(isValid)
Verify UniRep state
Check if the global state tree exists in the current UniRep state.
It can be verified by either a Synchronizer
or a UserState
object. But the Synchronizer
doesn't take ZkIdentity
as an input. For example
import { Synchronizer } from '@unirep/core'
const genUnirepState = async (
provider: ethers.providers.Provider,
address: string,
db: DB
) => {
const contract = getUnirepContract(address, provider)
const unirepState = new Synchronizer(
db,
prover,
contract,
)
await unirepState.start()
await unirepState.waitForSync()
return unirepState
}
const unirepState = await genUnirepState(
provider,
UNIREP_CONTRACT_ADDRESS,
db
)
Then we can use the identity-free object to verify the global state tree root.
const isGSTRootExisted = await unirepState.GSTRootExists(
proof.globalStateTree as string,
proof.epoch as number
)
console.log(isGSTRootExisted) // false then the proof will be invalid