UNPKG

@zkp2p/reclaim-witness-sdk

Version:

<div> <div> <img src="https://raw.githubusercontent.com/reclaimprotocol/.github/main/assets/banners/Attestor-Core.png" /> </div> </div>

348 lines 22.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.unixTimestampSeconds = void 0; exports.uint8ArrayToStr = uint8ArrayToStr; exports.getTranscriptString = getTranscriptString; exports.findIndexInUint8Array = findIndexInUint8Array; exports.uint8ArrayToBinaryStr = uint8ArrayToBinaryStr; exports.gunzipSync = gunzipSync; exports.getZkAlgorithmForCipherSuite = getZkAlgorithmForCipherSuite; exports.getPureCiphertext = getPureCiphertext; exports.getRecordIV = getRecordIV; exports.getProviderValue = getProviderValue; exports.generateRpcMessageId = generateRpcMessageId; exports.generateSessionId = generateSessionId; exports.generateTunnelId = generateTunnelId; exports.makeRpcEvent = makeRpcEvent; exports.getRpcTypeFromKey = getRpcTypeFromKey; exports.getRpcResponseType = getRpcResponseType; exports.getRpcRequestType = getRpcRequestType; exports.isApplicationData = isApplicationData; exports.extractArrayBufferFromWsData = extractArrayBufferFromWsData; exports.getRpcRequest = getRpcRequest; exports.extractApplicationDataFromTranscript = extractApplicationDataFromTranscript; exports.extractHandshakeFromTranscript = extractHandshakeFromTranscript; exports.decryptDirect = decryptDirect; exports.packRpcMessages = packRpcMessages; exports.ethersStructToPlainObject = ethersStructToPlainObject; const tls_1 = require("@reclaimprotocol/tls"); const zk_symmetric_crypto_1 = require("@reclaimprotocol/zk-symmetric-crypto"); const api_1 = require("../proto/api"); const DEFAULT_REDACTION_DATA = new Uint8Array(4) .fill(zk_symmetric_crypto_1.REDACTION_CHAR_CODE); function uint8ArrayToStr(arr) { return new TextDecoder().decode(arr); } function getTranscriptString(receipt) { var _a; const applMsgs = extractApplicationDataFromTranscript(receipt); const strList = []; for (const { message, sender } of applMsgs) { const content = uint8ArrayToStr(message); if ((_a = strList[strList.length - 1]) === null || _a === void 0 ? void 0 : _a.startsWith(sender)) { strList[strList.length - 1] += content; } else { strList.push(`${sender}: ${content}`); } } return strList.join('\n'); } const unixTimestampSeconds = () => Math.floor(Date.now() / 1000); exports.unixTimestampSeconds = unixTimestampSeconds; /** * Find index of needle in haystack */ function findIndexInUint8Array(haystack, needle) { for (let i = 0; i < haystack.length; i++) { if ((0, tls_1.areUint8ArraysEqual)(haystack.slice(i, i + needle.length), needle)) { return i; } } return -1; } /** * convert a Uint8Array to a binary encoded str * from: https://github.com/feross/buffer/blob/795bbb5bda1b39f1370ebd784bea6107b087e3a7/index.js#L1063 * @param buf * @returns */ function uint8ArrayToBinaryStr(buf) { let ret = ''; for (const v of buf) { (ret += String.fromCharCode(v)); } return ret; } function gunzipSync(buf) { const { gunzipSync } = require('zlib'); return gunzipSync(buf); } /** * Fetch the ZK algorithm for the specified cipher suite */ function getZkAlgorithmForCipherSuite(cipherSuite) { if (cipherSuite.includes('CHACHA20')) { return 'chacha20'; } if (cipherSuite.includes('AES_256_GCM')) { return 'aes-256-ctr'; } if (cipherSuite.includes('AES_128_GCM')) { return 'aes-128-ctr'; } throw new Error(`${cipherSuite} not supported for ZK ops`); } /** * Get the pure ciphertext without any MAC, * or authentication tag, * @param content content w/o header * @param cipherSuite */ function getPureCiphertext(content, cipherSuite) { // assert that the cipher suite is supported getZkAlgorithmForCipherSuite(cipherSuite); // 16 => auth tag length content = content.slice(0, -16); const { ivLength: fixedIvLength, } = tls_1.SUPPORTED_CIPHER_SUITE_MAP[cipherSuite]; // 12 => total IV length const recordIvLength = 12 - fixedIvLength; // record IV is prefixed to the ciphertext content = content.slice(recordIvLength); return content; } /** * Get the 8 byte IV part that's stored in the record for some cipher suites * @param content content w/o header * @param cipherSuite */ function getRecordIV(content, cipherSuite) { // assert that the cipher suite is supported getZkAlgorithmForCipherSuite(cipherSuite); const { ivLength: fixedIvLength, } = tls_1.SUPPORTED_CIPHER_SUITE_MAP[cipherSuite]; // 12 => total IV length const recordIvLength = 12 - fixedIvLength; return content.slice(0, recordIvLength); } function getProviderValue(params, fn, secretParams) { return typeof fn === 'function' // @ts-ignore ? fn(params, secretParams) : fn; } function generateRpcMessageId() { return (0, tls_1.uint8ArrayToDataView)(tls_1.crypto.randomBytes(8)).getUint32(0); } /** * Random session ID for a WebSocket client. */ function generateSessionId() { return generateRpcMessageId(); } /** * Random ID for a tunnel. */ function generateTunnelId() { return generateRpcMessageId(); } function makeRpcEvent(type, data) { const ev = new Event(type); ev.data = data; return ev; } /** * Get the RPC type from the key. * For eg. "claimTunnelRequest" -> * { type: 'claimTunnel', direction: 'request' } */ function getRpcTypeFromKey(key) { if (key.endsWith('Request')) { return { type: key.slice(0, -7), direction: 'request' }; } if (key.endsWith('Response')) { return { type: key.slice(0, -8), direction: 'response' }; } } /** * Get the RPC response type from the RPC type. * For eg. "claimTunnel" -> "claimTunnelResponse" */ function getRpcResponseType(type) { return `${type}Response`; } /** * Get the RPC request type from the RPC type. * For eg. "claimTunnel" -> "claimTunnelRequest" */ function getRpcRequestType(type) { return `${type}Request`; } function isApplicationData(packet, tlsVersion) { return packet.type === 'ciphertext' && (packet.contentType === 'APPLICATION_DATA' || (packet.data[0] === tls_1.PACKET_TYPE.WRAPPED_RECORD && tlsVersion === 'TLS1_2')); } /** * Convert the received data from a WS to a Uint8Array */ async function extractArrayBufferFromWsData(data) { if (data instanceof ArrayBuffer) { return new Uint8Array(data); } // uint8array/Buffer if (typeof data === 'object' && data && 'buffer' in data) { return data; } if (typeof data === 'string') { return (0, tls_1.strToUint8Array)(data); } if (data instanceof Blob) { return new Uint8Array(await data.arrayBuffer()); } throw new Error('unsupported data: ' + String(data)); } /** * Check if the RPC message is a request or a response. */ function getRpcRequest(msg) { if (msg.requestError) { return { direction: 'response', type: 'error' }; } for (const key in msg) { if (!msg[key]) { continue; } const rpcType = getRpcTypeFromKey(key); if (!rpcType) { continue; } return rpcType; } } /** * Finds all application data messages in a transcript * and returns them. Removes the "contentType" suffix from the message. * in TLS 1.3 */ function extractApplicationDataFromTranscript({ transcript, tlsVersion }) { const msgs = []; for (const m of transcript) { let message; // redacted msgs but with a valid packet header // can be considered application data messages if (m.redacted) { if (!m.plaintextLength) { message = DEFAULT_REDACTION_DATA; } else { const len = tlsVersion === 'TLS1_3' // remove content type suffix ? m.plaintextLength - 1 : m.plaintextLength; message = new Uint8Array(len) .fill(zk_symmetric_crypto_1.REDACTION_CHAR_CODE); } // otherwise, we need to check the content type } else if (tlsVersion === 'TLS1_3') { const contentType = m.message[m.message.length - 1]; if (contentType !== tls_1.CONTENT_TYPE_MAP['APPLICATION_DATA']) { continue; } message = m.message.slice(0, -1); } else if (m.recordHeader[0] === tls_1.PACKET_TYPE.WRAPPED_RECORD) { message = m.message; } else { continue; } msgs.push({ message, sender: m.sender }); } return msgs; } function extractHandshakeFromTranscript({ transcript, tlsVersion }) { const msgs = []; for (const [i, m] of transcript.entries()) { if (m.redacted) { break; // stop at first encrypted message } let message; if (m.recordHeader[0] === tls_1.PACKET_TYPE.HELLO) { message = m.message; } else if (m.recordHeader[0] === tls_1.PACKET_TYPE.WRAPPED_RECORD) { if (tlsVersion === 'TLS1_3') { const contentType = m.message[m.message.length - 1]; if (contentType !== tls_1.CONTENT_TYPE_MAP['HANDSHAKE']) { break; } message = m.message.slice(0, -1); } else { break; } } else { continue; } if (!message.length) { throw new Error('unsupported handshake message'); } msgs.push({ message, sender: m.sender, index: i }); } return msgs; } async function decryptDirect(directReveal, cipherSuite, recordHeader, serverTlsVersion, content) { const { key, iv, recordNumber } = directReveal; const { cipher } = tls_1.SUPPORTED_CIPHER_SUITE_MAP[cipherSuite]; const importedKey = await tls_1.crypto.importKey(cipher, key); return await (0, tls_1.decryptWrappedRecord)(content, { iv, key: importedKey, recordHeader, recordNumber, version: serverTlsVersion, cipherSuite, }); } function packRpcMessages(...msgs) { return api_1.RPCMessages.create({ messages: msgs.map(msg => (api_1.RPCMessage.create({ ...msg, id: msg.id || generateRpcMessageId() }))) }); } /** * Converts an Ethers struct (an array w named keys) to * a plain object. Recursively converts all structs inside. * Required to correctly JSON.stringify the struct. */ function ethersStructToPlainObject(struct) { if (!Array.isArray(struct)) { return struct; } const namedKeys = Object.keys(struct) .filter(key => isNaN(Number(key))); // seems to be an actual array if (!namedKeys.length) { return struct.map(ethersStructToPlainObject); } const obj = {}; for (const key of namedKeys) { obj[key] = ethersStructToPlainObject(struct[key]); } return obj; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJpY3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvZ2VuZXJpY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBMEJBLDBDQUVDO0FBRUQsa0RBYUM7QUFPRCxzREFXQztBQVFELHNEQVNDO0FBRUQsZ0NBR0M7QUFLRCxvRUFjQztBQVFELDhDQW1CQztBQVFELGtDQWFDO0FBRUQsNENBS0M7QUFFRCxvREFJQztBQUtELDhDQUVDO0FBS0QsNENBRUM7QUFFRCxvQ0FPQztBQU9ELDhDQWNDO0FBTUQsZ0RBRUM7QUFNRCw4Q0FFQztBQUVELDhDQVlDO0FBS0Qsb0VBcUJDO0FBS0Qsc0NBb0JDO0FBT0Qsb0ZBcUNDO0FBUUQsd0VBb0NDO0FBRUQsc0NBZUM7QUFFRCwwQ0FTQztBQU9ELDhEQWtCQztBQTdhRCw4Q0FTNkI7QUFDN0IsOEVBQTBFO0FBQzFFLHVDQUF1RDtBQVl2RCxNQUFNLHNCQUFzQixHQUFHLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQztLQUM5QyxJQUFJLENBQUMseUNBQW1CLENBQUMsQ0FBQTtBQUUzQixTQUFnQixlQUFlLENBQUMsR0FBZTtJQUM5QyxPQUFPLElBQUksV0FBVyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFBO0FBQ3JDLENBQUM7QUFFRCxTQUFnQixtQkFBbUIsQ0FBQyxPQUE2Qjs7SUFDaEUsTUFBTSxRQUFRLEdBQUcsb0NBQW9DLENBQUMsT0FBTyxDQUFDLENBQUE7SUFDOUQsTUFBTSxPQUFPLEdBQWEsRUFBRSxDQUFBO0lBQzVCLEtBQUksTUFBTSxFQUFFLE9BQU8sRUFBRSxNQUFNLEVBQUUsSUFBSSxRQUFRLEVBQUUsQ0FBQztRQUMzQyxNQUFNLE9BQU8sR0FBRyxlQUFlLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDeEMsSUFBRyxNQUFBLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQywwQ0FBRSxVQUFVLENBQUMsTUFBTSxDQUFD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