mirror of
https://github.com/vacp2p/rln-interep-contract.git
synced 2025-02-28 22:20:42 +00:00
127 lines
3.5 KiB
TypeScript
127 lines
3.5 KiB
TypeScript
import { Signer, utils } from "ethers";
|
|
import createIdentity from "@interep/identity";
|
|
import { Group, Member } from "@semaphore-protocol/group";
|
|
import { generateProof, packToSolidityProof } from "@semaphore-protocol/proof";
|
|
import type { Identity } from "@semaphore-protocol/identity";
|
|
// import createProof from '@interep/proof'
|
|
import type { SnarkArtifacts } from "@interep/proof/dist/types/types";
|
|
|
|
export const sToBytes32 = (str: string): string => {
|
|
return utils.formatBytes32String(str);
|
|
};
|
|
|
|
// zerokit can only use 15, 19, and 20 depth
|
|
export const merkleTreeDepth = 20;
|
|
|
|
export const SNARK_SCALAR_FIELD = BigInt(
|
|
"21888242871839275222246405745257275088548364400416034343698204186575808495617"
|
|
);
|
|
|
|
export const createGroupId = (provider: string, name: string): bigint => {
|
|
const providerBytes = sToBytes32(provider);
|
|
const nameBytes = sToBytes32(name);
|
|
return (
|
|
BigInt(
|
|
utils.solidityKeccak256(
|
|
["bytes32", "bytes32"],
|
|
[providerBytes, nameBytes]
|
|
)
|
|
) % SNARK_SCALAR_FIELD
|
|
);
|
|
};
|
|
|
|
const providers = ["github", "twitter", "reddit"];
|
|
const tiers = ["bronze", "silver", "gold", "unrated"];
|
|
|
|
// from goerli.interep.link
|
|
const validGroups: {
|
|
[key: string]: string[];
|
|
} = {
|
|
github: ["gold", "bronze", "unrated"],
|
|
reddit: ["unrated"],
|
|
};
|
|
|
|
export const getGroups = () => {
|
|
return providers.flatMap((provider) =>
|
|
tiers.map((tier) => {
|
|
return {
|
|
provider: sToBytes32(provider),
|
|
name: sToBytes32(tier),
|
|
root: 1,
|
|
depth: merkleTreeDepth,
|
|
};
|
|
})
|
|
);
|
|
};
|
|
|
|
export const getValidGroups = () => {
|
|
const returnArr = [];
|
|
for (const provider of Object.keys(validGroups)) {
|
|
for (const tier of validGroups[provider]) {
|
|
returnArr.push({
|
|
provider: sToBytes32(provider),
|
|
name: sToBytes32(tier),
|
|
root: 1,
|
|
depth: merkleTreeDepth,
|
|
});
|
|
}
|
|
}
|
|
return returnArr;
|
|
};
|
|
|
|
export const createInterepIdentity = (signer: Signer, provider: string) => {
|
|
if (!providers.includes(provider))
|
|
throw new Error(`Invalid provider: ${provider}`);
|
|
|
|
const sign = (message: string) => signer.signMessage(message);
|
|
return createIdentity(sign, provider);
|
|
};
|
|
|
|
interface ProofCreationArgs {
|
|
identity: Identity;
|
|
members: Member[];
|
|
groupProvider: typeof providers[0];
|
|
groupTier: typeof tiers[0];
|
|
externalNullifier: number;
|
|
signal: string;
|
|
snarkArtifacts: SnarkArtifacts;
|
|
}
|
|
|
|
// Similar to https://github.com/interep-project/interep.js/blob/ae7d19f560a63fef08b71ecba7a926729538011c/packages/proof/src/createProof.ts#L21,
|
|
// but without the api interactions
|
|
// Note: An aribitrary set of members is passed in, without validation
|
|
// when this function is called, ensure that the membership set passed in is a valid representation of onchain membership
|
|
export const createInterepProof = async (args: ProofCreationArgs) => {
|
|
const group = new Group(merkleTreeDepth);
|
|
|
|
const idCommitment = args.identity.getCommitment();
|
|
|
|
group.addMembers(args.members);
|
|
|
|
const memberIndex = group.indexOf(idCommitment);
|
|
if (memberIndex === -1) {
|
|
throw new Error("The semaphore identity is not yet verifiable onchain");
|
|
}
|
|
|
|
const merkleProof = group.generateProofOfMembership(memberIndex);
|
|
|
|
const { publicSignals, proof } = await generateProof(
|
|
args.identity,
|
|
merkleProof,
|
|
BigInt(args.externalNullifier),
|
|
args.signal,
|
|
args.snarkArtifacts
|
|
);
|
|
|
|
const solidityProof = packToSolidityProof(proof);
|
|
const groupId = createGroupId(args.groupProvider, args.groupTier).toString();
|
|
|
|
return {
|
|
groupId,
|
|
signal: args.signal,
|
|
publicSignals,
|
|
proof,
|
|
solidityProof,
|
|
};
|
|
};
|