epir
Version:
EllipticPIR client library (Node.js / TypeScript bindings).
216 lines (179 loc) • 6.98 kB
text/typescript
import crypto from 'crypto';
import {
EpirCreateFunction,
DecryptionContextCreateFunction,
SCALAR_SIZE,
CIPHER_SIZE,
MG_DEFAULT_PATH
} from '../types';
import { createEpir, createDecryptionContext } from '../addon';
export let x: number;
export let y: number;
export let z: number;
export let w: number;
export const xorshift_init = (): void => {
x = 123456789;
y = 362436069;
z = 521288629;
w = 88675123;
};
export const shiftL = (n: number, cnt: number): number => {
return (n * (2 ** cnt)) & 0xffffffff;
};
export const xorshift = (): number => {
const t = x ^ (shiftL(x, 11));
x = y; y = z; z = w;
w = (w ^ (w >>> 19)) ^ (t ^ (t >>> 8));
return w;
};
export const sha256sum = (buf: ArrayBuffer): ArrayBuffer => {
const hash = crypto.createHash('sha256');
hash.update(new Uint8Array(buf));
return new Uint8Array(Buffer.from(hash.digest('hex'), 'hex'));
};
export const generateRandomScalars = (cnt: number): ArrayBuffer => {
const r = new Uint8Array(cnt * SCALAR_SIZE);
xorshift_init();
for(let i=0; i<cnt; i++) {
for(let j=0; j<SCALAR_SIZE; j++) {
r[i * SCALAR_SIZE + j] = xorshift() & 0xff;
}
r[(i + 1) * SCALAR_SIZE - 1] &= 0x1f;
}
return r.buffer;
};
export const privkey = new Uint8Array([
0x7e, 0xf6, 0xad, 0xd2, 0xbe, 0xd5, 0x9a, 0x79,
0xba, 0x6e, 0xdc, 0xfb, 0xa4, 0x8f, 0xde, 0x7a,
0x55, 0x31, 0x75, 0x4a, 0xf5, 0x93, 0x76, 0x34,
0x6c, 0x8b, 0x52, 0x84, 0xee, 0xf2, 0x52, 0x07
]);
export const pubkey = new Uint8Array([
0x9c, 0x76, 0x82, 0x3d, 0xbd, 0xb9, 0xbf, 0x04,
0x8f, 0xc5, 0xc2, 0xaf, 0x00, 0x0e, 0x28, 0xa1,
0x48, 0xee, 0x02, 0x19, 0x99, 0xfb, 0x7f, 0x21,
0xca, 0x1f, 0x84, 0xb8, 0xfe, 0x73, 0xd7, 0xe8
]);
export const msg = 0x12345678 & ((1 << 24) - 1);
export const r = new Uint8Array([
0x42, 0xff, 0x2d, 0x98, 0x4a, 0xe5, 0xa2, 0x8f,
0x7d, 0x02, 0x69, 0x87, 0xc7, 0x10, 0x9a, 0x7b,
0x3a, 0x1d, 0x36, 0x58, 0x82, 0x5a, 0x09, 0x17,
0xe1, 0x69, 0x3e, 0x83, 0xa5, 0x71, 0x5d, 0x09
]);
export const cipher = new Uint8Array([
0x11, 0xa9, 0x4e, 0xb7, 0x18, 0x53, 0x7e, 0x94,
0x7d, 0x0f, 0xf3, 0x0c, 0xdd, 0xae, 0x16, 0xae,
0xab, 0x42, 0x9e, 0xac, 0x09, 0x2b, 0x22, 0x00,
0x06, 0xb1, 0x9c, 0xcc, 0xb5, 0x26, 0xb4, 0x30,
0xeb, 0x76, 0x83, 0xc0, 0xdf, 0x90, 0x3a, 0x88,
0xf6, 0xf1, 0x09, 0x52, 0xbc, 0xa4, 0xd6, 0x45,
0x28, 0x4f, 0xf7, 0xed, 0x95, 0xc6, 0xa4, 0xe9,
0x67, 0xf5, 0xe7, 0xae, 0x22, 0xc9, 0x33, 0xcb
]);
export const mGHash = new Uint8Array([
0x1c, 0x09, 0xf4, 0x62, 0xf1, 0xb5, 0x8f, 0xc1,
0x40, 0xc9, 0x3c, 0xda, 0x6f, 0xec, 0x88, 0x85,
0x08, 0x44, 0xe3, 0xf0, 0x04, 0xb7, 0x24, 0x87,
0xb6, 0x53, 0x39, 0xbd, 0xc0, 0xe4, 0x17, 0x97
]);
export const index_counts = [1000, 1000, 1000];
export const ciphers_count = 3000;
export const elements_count = 1000 * 1000 * 1000;
export const idx = 12345678;
export const rows = [ Math.floor(idx / (1000 * 1000)), Math.floor((idx % (1000 * 1000)) / 1000), (idx % 1000) ];
export const selectorHash = new Uint8Array([
0xda, 0x20, 0x9d, 0x4f, 0x85, 0xad, 0x0d, 0xb2,
0x68, 0x45, 0x6f, 0x0d, 0x4e, 0x9e, 0x90, 0x7f,
0x8f, 0x87, 0x31, 0xa6, 0x69, 0x5d, 0xa5, 0x5f,
0x1f, 0x3d, 0x19, 0x2f, 0x59, 0xac, 0xe9, 0x0c
]);
export const runTests = (createEpir: EpirCreateFunction, createDecryptionContext: DecryptionContextCreateFunction): void => {
const epirPromise = createEpir();
const decCtxPromise = createDecryptionContext(MG_DEFAULT_PATH);
describe('ECElGamal', () => {
test('create private key', async () => {
const epir = await epirPromise;
const privkey = epir.createPrivkey();
expect(privkey.byteLength).toBe(SCALAR_SIZE);
});
test('create public key', async () => {
const epir = await epirPromise;
const pubkeyTest = epir.createPubkey(privkey.buffer);
expect(new Uint8Array(pubkeyTest)).toEqual(pubkey);
});
test('encrypt (normal)', async () => {
const epir = await epirPromise;
const cipherTest = epir.encrypt(pubkey.buffer, msg, r.buffer);
expect(new Uint8Array(cipherTest)).toEqual(cipher);
});
test('encrypt (fast)', async () => {
const epir = await epirPromise;
const cipherTest = epir.encryptFast(privkey.buffer, msg, r.buffer);
expect(new Uint8Array(cipherTest)).toEqual(cipher);
});
test('create DecryptionContext from ArrayBuffer', async () => {
const decCtx = await decCtxPromise;
const decCtx2 = await createDecryptionContext(decCtx.getMG());
const mG = decCtx2.getMG();
expect(sha256sum(mG)).toEqual(mGHash);
}, 30 * 1000);
//test('interpolation search of mG', async () => {
//});
test('decrypt (success)', async () => {
const decCtx = await decCtxPromise;
expect(decCtx.decryptCipher(privkey.buffer, cipher.buffer)).toBe(msg);
});
test('decrypt (fail)', async () => {
const decCtx = await decCtxPromise;
expect(() => decCtx.decryptCipher(pubkey.buffer, cipher.buffer)).toThrow(/^Failed to decrypt\.$/);
});
test('random encrypt (normal)', async () => {
const epir = await epirPromise;
const decCtx = await decCtxPromise;
const cipherTest = epir.encrypt(pubkey.buffer, msg);
expect(decCtx.decryptCipher(privkey.buffer, cipherTest)).toBe(msg);
});
test('random encrypt (fast)', async () => {
const epir = await epirPromise;
const decCtx = await decCtxPromise;
const cipherTest = epir.encryptFast(privkey.buffer, msg);
expect(decCtx.decryptCipher(privkey.buffer, cipherTest)).toBe(msg);
});
});
describe('Selector', () => {
test('ciphers count', async () => {
const epir = await epirPromise;
expect(epir.ciphersCount(index_counts)).toBe(ciphers_count);
});
test('elements count', async () => {
const epir = await epirPromise;
expect(epir.elementsCount(index_counts)).toBe(elements_count);
});
//test('create choice', async () => {
//});
test('create selector (deterministic, normal)', async () => {
const epir = await epirPromise;
const selector = await epir.createSelector(pubkey.buffer, index_counts, idx, generateRandomScalars(ciphers_count));
expect(sha256sum(selector)).toEqual(selectorHash);
}, 30 * 1000);
test('create selector (deterministic, fast)', async () => {
const epir = await epirPromise;
const selector = await epir.createSelectorFast(privkey.buffer, index_counts, idx, generateRandomScalars(ciphers_count));
expect(sha256sum(selector)).toEqual(selectorHash);
}, 30 * 1000);
test('create selector (random, normal)', async () => {
const epir = await epirPromise;
const selector = await epir.createSelector(pubkey.buffer, index_counts, idx);
expect(selector.byteLength).toBe(ciphers_count * CIPHER_SIZE);
}, 30 * 1000);
test('create selector (random, fast)', async () => {
const epir = await epirPromise;
const selector = await epir.createSelectorFast(privkey.buffer, index_counts, idx);
expect(selector.byteLength).toBe(ciphers_count * CIPHER_SIZE);
}, 30 * 1000);
});
};
if(require.main === null) {
runTests(createEpir, createDecryptionContext);
}