+
+ This PCD represents that a particular Semphore Identity owns an Ethereum
+ Address that is part of a merkle group of Ethereum public keys or
+ addresses.
+
+
+
+
+ Commitment
+
+
+
+ Merkle Root
+
+ {pcd.claim.publicInput.circuitPubInput.merkleRoot.toString(16)}
+
+
+ );
+}
+
+const Container = styled.div`
+ padding: 16px;
+ overflow: hidden;
+ width: 100%;
+`;
diff --git a/packages/ethereum-group-pcd/src/EthereumGroupPCD.ts b/packages/ethereum-group-pcd/src/EthereumGroupPCD.ts
new file mode 100644
index 0000000000..e5c5e5dbf7
--- /dev/null
+++ b/packages/ethereum-group-pcd/src/EthereumGroupPCD.ts
@@ -0,0 +1,336 @@
+import {
+ ArgumentTypeName,
+ DisplayOptions,
+ PCD,
+ PCDArgument,
+ PCDPackage,
+ SerializedPCD,
+ StringArgument,
+} from "@pcd/pcd-types";
+import {
+ SemaphoreIdentityPCD,
+ SemaphoreIdentityPCDPackage,
+ SemaphoreIdentityPCDTypeName,
+} from "@pcd/semaphore-identity-pcd";
+import {
+ SemaphoreSignaturePCD,
+ SemaphoreSignaturePCDPackage,
+} from "@pcd/semaphore-signature-pcd";
+import {
+ CircuitPubInput,
+ MembershipProver,
+ MembershipVerifier,
+ ProverConfig,
+ PublicInput,
+} from "@personaelabs/spartan-ecdsa";
+import { ethers } from "ethers";
+import JSONBig from "json-bigint";
+import { v4 as uuid } from "uuid";
+import { EthereumGroupCardBody } from "./CardBody";
+
+export const EthereumGroupPCDTypeName = "ethereum-group-pcd";
+
+export interface EthereumGroupPCDInitArgs {
+ // TODO: how do we distribute these in-package, so that consumers
+ // of the package don't have to copy-paste these artifacts?
+ // TODO: how do we account for different versions of the same type
+ // of artifact? eg. this one is parameterized by group size. Should
+ // we pre-generate a bunch of artifacts per possible group size?
+ // Should we do code-gen?
+ zkeyFilePath: string;
+ wasmFilePath: string;
+
+ addrMembershipConfig?: ProverConfig;
+ pubkeyMembershipConfig?: ProverConfig;
+}
+
+export interface EthereumGroupPCDArgs {
+ identity: PCDArgument