UNPKG

epir

Version:

EllipticPIR client library (Node.js / TypeScript bindings).

113 lines (96 loc) 3.3 kB
import { SCALAR_SIZE } from './types'; export const time = (): number => Date.now(); export const runMeasurement = async <T>(func: () => (Promise<T> | T)): Promise<{ execTime: number, ret: T }> => { const begin = time(); const ret = func(); if(ret instanceof Promise) { const ret2 = await ret; const end = time(); return { execTime: end - begin, ret: ret2 }; } else { const end = time(); return { execTime: end - begin, ret: ret }; } }; export const printMeasurement = async <T>( func: () => (Promise<T> | T), prefix: string, postfix = 'ms.'): Promise<T> => { const { execTime, ret } = await runMeasurement<T>(func); console.log(`\u001b[32m${prefix} ${execTime.toLocaleString()} ${postfix}\u001b[0m`); return ret; } export const arrayBufferConcat = (arr: ArrayBuffer[]): ArrayBuffer => { const len = arr.reduce((acc, v) => acc + v.byteLength, 0); const ret = new Uint8Array(len); for(let i=0, offset=0; i<arr.length; i++) { ret.set(new Uint8Array(arr[i]), offset); offset += arr[i].byteLength; } return ret.buffer; } export const arrayBufferCompare = ( a: ArrayBuffer, aOffset: number, b: ArrayBuffer, bOffset: number, len: number): number => { const aa = new Uint8Array(a, aOffset, len); const bb = new Uint8Array(b, bOffset, len); for(let i=0; i<len; i++) { if(aa[i] == bb[i]) continue; return aa[i] - bb[i]; } return 0; } export const arrayBufferToHex = (buf: ArrayBuffer): string => { const arr = new Uint8Array(buf); let ret = ''; for(const n of arr) { ret += Number(n).toString(16).padStart(2, '0'); } return ret; }; export const hexToArrayBuffer = (hex: string): ArrayBuffer => { const split = hex.match(/.{2}/g); if(!split) return new ArrayBuffer(0); return new Uint8Array(split.map((h) => parseInt(h, 16))).buffer; }; export const checkIsHex = (hex: string, expectedSize = -1): boolean => { const pattern = /^[0-9a-fA-F]+$/; if(expectedSize >= 0) { return ((hex.length === 2 * expectedSize) && (hex.match(pattern) !== null)); } else { return ((hex.length % 2 === 0) && (hex.match(pattern) !== null)); } }; export const getRandomBytes = (len: number): ArrayBuffer => { const MAX_ENTROPY = 65536; const ret = new Uint8Array(len); for(let offset=0; offset<len; offset+=MAX_ENTROPY) { window.crypto.getRandomValues(ret.subarray(offset, Math.min(len, offset + MAX_ENTROPY))); } return ret.buffer; }; export const isCanonical = (buf: ArrayBuffer): boolean => { const bufView = new Uint8Array(buf); let c = (bufView[31] & 0x7f) ^ 0x7f; for(let i=30; i>0; i--) { c |= bufView[i] ^ 0xff; } const d = (0xed - 1 - bufView[0]) >> 8; return !((c == 0) && d) }; export const isZero = (buf: ArrayBuffer): boolean => { return new Uint8Array(buf).reduce<boolean>((acc, v) => acc && (v == 0), true); }; export const getRandomScalar = (): ArrayBuffer => { for(;;) { const scalar = getRandomBytes(SCALAR_SIZE); new Uint8Array(scalar)[31] &= 0x1f; if(!isCanonical(scalar) || isZero(scalar)) continue; return scalar; } }; export const getRandomScalars = (cnt: number): ArrayBuffer[] => { const ret: ArrayBuffer[] = []; for(let i=0; i<cnt; i++) ret.push(getRandomScalar()); return ret; } export const getRandomScalarsConcat = (cnt: number): ArrayBuffer => { return arrayBufferConcat(getRandomScalars(cnt)); }