@reclaimprotocol/zk-symmetric-crypto
Version:
JS Wrappers for Various ZK Snark Circuits
227 lines (226 loc) • 6.82 kB
TypeScript
export type EncryptionAlgorithm = 'aes-256-ctr' | 'aes-128-ctr' | 'chacha20';
export type ZKEngine = 'snarkjs' | 'gnark' | 'stwo';
export type UintArray = Uint32Array;
export type Proof = {
algorithm: EncryptionAlgorithm;
/** serialised proof */
proofData: ZKProof;
/**
* the plaintext obtained as an output
* of the ZK circuit
* Will be `undefined` if proving with TOPRF
*/
plaintext: Uint8Array | undefined;
};
export type FileFetch = {
fetch(engine: ZKEngine, filename: string, logger?: Logger): Promise<Uint8Array>;
};
export type MakeZKOperatorOpts<T> = {
algorithm: EncryptionAlgorithm;
fetcher: FileFetch;
options?: T;
};
export type MakeZKOperator<T> = (opts: MakeZKOperatorOpts<T>) => ZKOperator;
export type MakeOPRFOperator<T> = (opts: MakeZKOperatorOpts<T>) => OPRFOperator;
/**
* provide Uint8array for file data loaded into memory
* or string, that is the path to load said file
* */
type ZKInput = Uint8Array | string;
export type VerificationKey = {
/** binary data for .zkey file */
data: ZKInput;
json?: unknown;
};
export type CircuitWasm = Uint8Array | string;
export type GenerateWitnessOpts = {
/**
* the algorithm to use for the encryption
* circuit. Used to correctly slice the
* IV, counters etc.
*/
algorithm: EncryptionAlgorithm;
/**
* private input to the circuit (i.e. key)
*/
privateInput: PrivateInput;
/**
* public input to the circuit,
* i.e. the ciphertext to decrypt
*/
publicInput: PublicInput;
} & ({
mask: ZKInputItem;
toprf: ZKTOPRFPublicSignals;
} | {});
export type GenerateProofOpts = GenerateWitnessOpts & {
/**
* Operator to use for proving the circuit
*/
operator: ZKOperator | OPRFOperator;
logger?: Logger;
};
export type GetPublicSignalsOpts = {
algorithm: EncryptionAlgorithm;
publicInput: PublicInput;
} & ({
plaintext: Uint8Array | undefined;
} | {
key: Uint8Array;
});
export type VerifyProofOpts = {
proof: Proof;
publicInput: PublicInput;
} & ({
operator: ZKOperator;
logger?: Logger;
} | {
operator: OPRFOperator;
logger?: Logger;
toprf: ZKTOPRFPublicSignals;
});
export type AlgorithmConfig = {
index: number;
/**
* Chunk size in words (of the algorithm)
* eg. chacha20 has 32-bit words, aes-256-ctr has 8-bit words
*/
chunkSize: number;
bitsPerWord: number;
keySizeBytes: number;
ivSizeBytes: number;
startCounter: number;
blocksPerChunk: number;
isLittleEndian: boolean;
uint8ArrayToBits: (arr: Uint8Array) => number[];
bitsToUint8Array: (bits: number[]) => Uint8Array;
/**
* Encrypt some ciphertext with the given key and IV
*/
encrypt(opts: {
key: Uint8Array;
iv: Uint8Array;
in: Uint8Array;
}): Promise<Uint8Array> | Uint8Array;
};
type ZKProof = string | Uint8Array;
type ZKProofOutput = {
proof: ZKProof;
};
type ZKInputItem = Uint8Array;
export type ZKTOPRFResponsePublicSignals = {
publicKeyShare: ZKInputItem;
evaluated: ZKInputItem;
c: ZKInputItem;
r: ZKInputItem;
};
type TOPRFLocation = {
pos: number;
len: number;
};
export type ZKTOPRFPublicSignals = {
locations: TOPRFLocation[];
domainSeparator: string;
output: ZKInputItem;
responses: ZKTOPRFResponsePublicSignals[];
};
export type BlockInfo = {
nonce: ZKInputItem;
counter: number;
boundary: number | undefined;
};
export type ZKProofPublicSignals = {
noncesAndCounters: BlockInfo[];
in: ZKInputItem;
out: ZKInputItem;
};
export type ZKProofPublicSignalsOPRF = ZKProofPublicSignals & {
toprf: ZKTOPRFPublicSignals;
};
export type ZKProofInput = {
key: ZKInputItem;
} & ZKProofPublicSignals;
export type ZKProofInputOPRF = {
key: ZKInputItem;
mask: ZKInputItem;
} & ZKProofPublicSignalsOPRF;
export type OPRFRequestData = {
mask: Uint8Array;
maskedData: Uint8Array;
secretElements: Uint8Array[];
};
type OPRFResponse = {
evaluated: Uint8Array;
c: Uint8Array;
r: Uint8Array;
};
export type OPRFResponseData = OPRFResponse & {
publicKeyShare: Uint8Array;
};
export type KeyShare = {
index: number;
publicKey: Uint8Array;
privateKey: Uint8Array;
};
export type KeygenResult = {
publicKey: Uint8Array;
privateKey: Uint8Array;
shares: KeyShare[];
};
/**
* the operator to use for proving and verifying the groth16
* proof of the ChaCha20 circuit
*
* this generic interface is allow
* for different implementations
*/
export type ZKOperator = {
generateWitness(input: ZKProofInput, logger?: Logger): Promise<Uint8Array> | Uint8Array;
groth16Prove(witness: Uint8Array, logger?: Logger): Promise<ZKProofOutput>;
groth16Verify(publicSignals: ZKProofPublicSignals, proof: ZKProof, logger?: Logger): Promise<boolean>;
/**
* Release any used resources. The operator
* should still be usable after this call.
*
* This is useful for releasing any resources
* in case ZK operations are not going to be
* used for a while.
*/
release?(): void;
};
export type OPRFOperator = {
generateWitness(input: ZKProofInputOPRF, logger?: Logger): Promise<Uint8Array>;
groth16Prove(witness: Uint8Array, logger?: Logger): Promise<ZKProofOutput>;
groth16Verify(publicSignals: ZKProofPublicSignalsOPRF, proof: ZKProof, logger?: Logger): Promise<boolean>;
generateThresholdKeys(total: number, threshold: number, logger?: Logger): Promise<KeygenResult>;
generateOPRFRequestData(data: Uint8Array, domainSeparator: string, logger?: Logger): Promise<OPRFRequestData>;
finaliseOPRF(serverPublicKey: Uint8Array, request: OPRFRequestData, responses: OPRFResponseData[], logger?: Logger): Promise<Uint8Array>;
evaluateOPRF(serverPrivateKey: Uint8Array, request: Uint8Array, logger?: Logger): Promise<OPRFResponse>;
/**
* Release any used resources. The operator
* should still be usable after this call.
*
* This is useful for releasing any resources
* in case ZK operations are not going to be
* used for a while.
*/
release?(): void;
};
export type PrivateInput = {
/** 256 bit ChaCha20 key to decrypt ciphertext */
key: Uint8Array;
};
export type RawPublicInput = {
/** the ciphertext to decrypt */
ciphertext: Uint8Array;
/** 192 bit IV for the ciphertext decryption */
iv: Uint8Array;
/**
* If the passed ciphertext is a slice of the original ciphertext,
* what offset (in bytes) does this slice start from?
* */
offsetBytes?: number;
};
export type PublicInput = RawPublicInput | RawPublicInput[];
export type Logger = Pick<typeof console, 'info' | 'trace' | 'debug' | 'error' | 'warn'>;
export {};