메인 콘텐츠로 건너뛰기

Consumer

Consumer 하위 클라이언트는 읽기 요청, 검증자로부터의 부분 복호화 수집, 그리고 최종 복호화를 처리합니다. walletClient가 필요합니다.
const consumer = client.consumer;
SDK는 또한 readVaultaccessCDR의 별칭으로, readFileVaultdownloadFile의 별칭으로 노출합니다.
부분 복호화는 (uuid, requesterPubKey)로 키가 지정된 DATA Foundation API REST 엔드포인트 (/dkg/cdr_partials)에서 수집됩니다. keeper는 ingress에서 각 검증자의 서명을 검증하므로, SDK는 로컬에서 서명을 다시 검증하지 않습니다. 심층 방어를 위해, attestationConfig를 전달하여 각 검증자의 부분 복호화를 수락하기 전에 SGX enclave를 검증하세요.

메서드

  • accessCDR
  • downloadFile
  • read
  • collectPartials
  • decryptDataKey
  • prefetchRegistry

accessCDR

읽기 요청을 제출하고, 검증자로부터 부분 복호화를 수집하며, 이를 결합하여 원본 데이터를 복구하는 고수준 메서드.
MethodType
accessCDR(params: AccessCDRParams) => Promise<AccessCDRResponse>
매개변수:
  • params.uuid: number - 볼트 UUID
  • params.accessAuxData: `0x${string}` - 읽기 조건에 전달되는 보조 데이터
  • params.requesterPubKey (선택): `0x${string}` - 압축되지 않은 secp256k1 공개 키 (65 bytes, 0x04 접두사). 생략하면 SDK가 일회용 키 쌍을 생성합니다.
  • params.recipientPrivKey (선택): Uint8Array - 32바이트 secp256k1 개인 키 (부분 복호화의 ECIES 복호화용). 생략하면 SDK가 일회용 키 쌍을 생성하고 사용 후 영점화합니다.
  • params.globalPubKey (선택): Uint8Array - DKG global public key (observer.getGlobalPubKey()에서 가져옴). 생략하면 SDK가 대신 쿼리합니다.
  • params.timeoutMs (선택): number - 부분 복호화 수집을 위한 타임아웃. 120_000이 좋은 시작점입니다.
  • params.feeOverride (선택): bigint - 명시적 읽기 수수료. readFee() 자동 쿼리를 건너뜁니다 (정확한 일치 의미, 다른 금액을 지불하는 방법이 아님).
  • params.onInvalidPartial (선택): (event, error) => void - 검증자의 부분 복호화가 attestationConfig 검사를 통과하지 못해 제외될 때 호출됩니다.
  • params.attestationConfig (선택): AttestationConfig - 부분 복호화를 수락하기 전에 각 검증자의 SGX enclave를 검증합니다.
Example
const { dataKey, txHash } = await client.consumer.accessCDR({
  uuid: 42,
  accessAuxData: "0x",
  timeoutMs: 120_000,
});

const secret = new TextDecoder().decode(dataKey);
console.log(`Read tx: ${txHash}`);
console.log(`Decrypted: ${secret}`);
가장 짧은 고수준 경로를 원한다면, requesterPubKey, recipientPrivKey, globalPubKey를 생략하고 accessCDR()이 채우도록 할 수 있습니다. 임계값은 부분 복호화 버킷의 DKG 라운드에서 자동으로 파생됩니다.
볼트에 한 번도 쓰여진 적이 없는 경우 동기적으로 EmptyVaultError를 던집니다. 이는 수수료가 발생하는 read() 트랜잭션이 제출되기 전에 사전 검사를 통해 발생하므로, 수수료가 소비되지 않습니다.
AccessCDRResponse
interface AccessCDRResponse {
  dataKey: Uint8Array; // the recovered plaintext
  txHash: `0x${string}`; // read request transaction hash
}

downloadFile

CDR을 통해 암호화된 파일 키를 읽고, StorageProvider에서 암호화된 blob을 다운로드한 다음, 복호화된 파일 바이트를 반환하는 고수준 메서드. 매개변수:
  • params.uuid: number - 볼트 UUID
  • params.accessAuxData: `0x${string}` - 읽기 조건에 전달되는 보조 데이터
  • params.storageProvider: StorageProvider - 암호화된 콘텐츠를 가져오는 데 사용되는 백엔드
  • params.requesterPubKey (선택): `0x${string}` - 읽기 흐름을 위한 명시적 요청자 공개 키
  • params.recipientPrivKey (선택): Uint8Array - 읽기 흐름을 위한 명시적 수신자 개인 키
  • params.globalPubKey (선택): Uint8Array - DKG global public key. 생략하면 자동 쿼리됩니다.
  • params.timeoutMs (선택): number - 검증자 부분 복호화 수집을 위한 타임아웃
  • params.feeOverride (선택): bigint - 명시적 읽기 수수료. readFee() 자동 쿼리를 건너뜁니다.
  • params.onInvalidPartial (선택): (event, error) => void - 검증자의 부분 복호화가 attestationConfig 검사를 통과하지 못해 제외될 때 호출됩니다.
  • params.attestationConfig (선택): AttestationConfig - 부분 복호화를 수락하기 전에 각 검증자의 SGX enclave를 검증합니다.
  • params.skipCidVerification (선택): boolean - 다운로드한 암호화된 파일의 CID 무결성 검증 건너뛰기 (기본값: false)
Example
import { writeFile } from "node:fs/promises";

const { content } = await client.consumer.downloadFile({
  uuid: 42,
  accessAuxData: "0x",
  storageProvider,
  timeoutMs: 120_000,
});

await writeFile("./example.decrypted.pdf", Buffer.from(content));
console.log("Saved ./example.decrypted.pdf");
DATA Foundation 라이선스 게이팅 읽기의 경우, accessAuxData는 호출자의 라이선스 토큰 ID를 abi.encode(uint256[] licenseTokenIds)로 인코딩해야 합니다.
downloadFile()accessCDR()과 동일한 선택적 키 자동 관리 동작을 상속하며, content와 함께 cidtxHash를 반환합니다.
content는 원시 복호화된 파일 바이트입니다. 원본 파일이 텍스트 기반인 경우에만 텍스트로 디코딩하세요.

read

온체인에서 읽기 요청을 제출합니다. 호출자는 볼트의 읽기 조건을 충족해야 합니다. 이는 검증자들이 암호화된 부분 복호화를 제출하도록 유도합니다.
MethodType
read(params: ReadParams) => Promise<ReadResponse>
매개변수:
  • params.uuid: number - 볼트 UUID
  • params.accessAuxData: `0x${string}` - 읽기 조건에 전달되는 보조 데이터
  • params.requesterPubKey: `0x${string}` - 일회용의 압축되지 않은 secp256k1 공개 키. 부분 복호화는 이 값에 의해 인덱싱됩니다.
  • params.feeOverride (선택): bigint - 명시적 읽기 수수료. readFee() 자동 쿼리를 건너뜁니다.
Example
const { txHash } = await client.consumer.read({
  uuid: 42,
  accessAuxData: "0x",
  requesterPubKey,
});
ReadResponse
interface ReadResponse {
  txHash: `0x${string}`;
}

collectPartials

지정된 (uuid, requesterPubKey)에 대해 적어도 임계값만큼의 부분 복호화 제출이 표면화될 때까지 DATA Foundation API REST 엔드포인트 (/dkg/cdr_partials)를 폴링합니다.
MethodType
collectPartials(params: CollectPartialsParams) => Promise<PartialDecryptionEvent[]>
매개변수:
  • params.uuid: number - 볼트 UUID
  • params.requesterPubKey: `0x${string}` - 일치하는 read() 요청에 사용된 압축되지 않은 secp256k1 공개 키
  • params.timeoutMs (선택): number - 밀리초 단위 타임아웃. 120_000이 좋은 시작점입니다.
  • params.pollIntervalMs (선택): number - 밀리초 단위의 폴링 간격
  • params.onInvalidPartial (선택): (event, error) => void - 검증자의 부분 복호화가 attestationConfig 검사를 통과하지 못해 제외될 때 호출됩니다.
  • params.attestationConfig (선택): AttestationConfig - 각 검증자의 SGX enclave를 검증하고 신뢰할 수 없는 검증자의 부분 복호화를 제외합니다
필요한 임계값은 부분 복호화 버킷 자체의 DKG 라운드(observer.getThresholdAt(round))에서 파생되므로, 폴링 중간에 DKG 롤오버가 발생해도 버킷이 잘못된 라운드와 비교되지 않습니다. 볼트 ciphertext는 호출 시작 시 한 번 읽혀지고 나머지 폴링 루프 동안 고정됩니다.
충분한 부분 복호화가 수집되기 전에 타임아웃에 도달하면 PartialCollectionTimeoutError를 던집니다. 볼트에 한 번도 쓰여진 적이 없는 경우 EmptyVaultError를 던집니다.
Example
const partials = await client.consumer.collectPartials({
  uuid: 42,
  requesterPubKey,
  timeoutMs: 120_000,
});

console.log(`Collected ${partials.length} partials`);
PartialDecryptionEvent
interface PartialDecryptionEvent {
  validator: `0x${string}`;
  round: number;
  pid: number;                      // 1-based participant index
  encryptedPartial: `0x${string}`;  // AES-GCM encrypted
  ephemeralPubKey: `0x${string}`;   // 65 bytes, uncompressed secp256k1
  pubShare: `0x${string}`;          // 34 bytes, Ed25519 with curve-code prefix
  uuid: number;
  ciphertext: `0x${string}`;        // TDH2 ciphertext this partial decrypts
}
성공적인 collectPartials 호출에서 반환되는 모든 이벤트는 동일한 roundciphertext를 공유합니다: 결과는 볼트의 현재 ciphertext와 일치하는 버킷으로 필터링됩니다.

decryptDataKey

수집된 부분 복호화를 ECIES를 사용하여 복호화한 다음, TDH2를 통해 결합하여 원본 평문을 복구합니다.
MethodType
decryptDataKey(params: DecryptParams) => Promise<Uint8Array>
매개변수:
  • params.ciphertext: TDH2Ciphertext - 암호화된 데이터 ({ raw, label })
  • params.partials: PartialDecryptionEvent[] - 수집된 부분 복호화
  • params.recipientPrivKey: Uint8Array - 일회용 secp256k1 개인 키 (32 bytes)
  • params.globalPubKey: Uint8Array - DKG global public key
  • params.label: Uint8Array - 32바이트 label (uuidToLabel(uuid)에서)
TDH2 combine 임계값은 암묵적으로 partials.length로 사용되며, collectPartials는 이미 재구성에 필요한 정확한 임계값 수를 반환합니다. 결합하려는 부분 복호화를 정확히 전달하세요.
ciphertext가 요구하는 것보다 적은 부분 복호화가 전달되면 InsufficientPartialsError를 던집니다. ciphertext가 비어 있거나 형식이 잘못된 경우 InvalidCiphertextError를 던집니다.
Example
import { uuidToLabel } from "@piplabs/cdr-sdk";

const label = uuidToLabel(uuid);
const dataKey = await client.consumer.decryptDataKey({
  ciphertext: { raw: ciphertextBytes, label },
  partials,
  recipientPrivKey,
  globalPubKey,
  label,
});

const secret = new TextDecoder().decode(dataKey);

prefetchRegistry

활성 DKG 라운드에 대한 검증자 commPubKey + attestation 캐시를 미리 준비합니다. 구성 후 첫 번째 accessCDR() / downloadFile() 호출은 그렇지 않으면 이 가져오기에서 지연될 수 있습니다. 읽기가 임박한 것을 알고 있는 프론트엔드(예: 지갑 연결 직후)는 이를 백그라운드에서 호출할 수 있습니다.
MethodType
prefetchRegistry() => Promise<void>
Example
// Best-effort warm-up, safe to call repeatedly
client.consumer.prefetchRegistry().catch(() => {});