Skip to content

Commit

Permalink
Merge pull request #7 from NillionNetwork/feat/hkdf
Browse files Browse the repository at this point in the history
feat: replace `_seeds` with HKDF
  • Loading branch information
lapets authored Feb 16, 2025
2 parents d8c6c32 + 654f00c commit 8fd115b
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 37 deletions.
41 changes: 14 additions & 27 deletions src/nilql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* TypeScript library for working with encrypted data within nilDB queries
* and replies.
*/
import { hkdf } from "node:crypto";
import * as bcu from "bigint-crypto-utils";
import sodium from "libsodium-wrappers-sumo";
import * as paillierBigint from "paillier-bigint";
Expand Down Expand Up @@ -72,37 +73,24 @@ async function _sha512(bytes: Uint8Array): Promise<Uint8Array> {
return new Uint8Array(buffer);
}

/**
* Return entries in an indexed sequence of seeds derived from a base seed.
*/
async function _seeds(seed: Uint8Array, index: bigint): Promise<Uint8Array> {
if (index < 0 || index >= 2n ** 64n) {
throw new RangeError("index must be a 64-bit unsigned integer value");
}

const buffer = Buffer.alloc(8);
buffer.writeBigInt64LE(index, 0);
return await _sha512(_concat(seed, new Uint8Array(buffer)));
}

/**
* Return a random byte sequence of the specified length (using the seed if one
* is supplied).
*/
async function _randomBytes(
length: number,
seed: Uint8Array | null = null,
salt: Uint8Array | null = null,
): Promise<Uint8Array> {
await sodium.ready;

if (seed !== null) {
let bytes = new Uint8Array();
const iterations: number =
Math.floor(length / 64) + (length % 64 > 0 ? 1 : 0);
for (let i = 0n; i < iterations; i++) {
bytes = _concat(bytes, await _seeds(seed, i));
}
return bytes.subarray(0, length);
return new Promise<Uint8Array>((resolve, reject) => {
hkdf("sha512", seed, salt ?? "", "", length, (err, derivedKey) => {
if (err) reject(err);
else resolve(new Uint8Array(derivedKey));
});
});
}

return sodium.randombytes_buf(length);
Expand Down Expand Up @@ -131,10 +119,9 @@ async function _randomInteger(
let integer = null;
let index = 0n;
while (integer === null || integer > range) {
const uint8Array = await _randomBytes(
8,
seed !== null ? await _seeds(seed, index) : null,
);
const index_bytes = Buffer.alloc(8);
index_bytes.writeBigInt64LE(index, 0);
const uint8Array = await _randomBytes(8, seed, index_bytes);
index++;

uint8Array[4] &= 0b00000001;
Expand Down Expand Up @@ -303,14 +290,14 @@ class SecretKey {
// Distinct multiplicative mask for each additive share.
secretKey.material = [];
for (let i = 0n; i < secretKey.cluster.nodes.length; i++) {
const seedIteration =
seedBytes === null ? null : await _seeds(seedBytes, i);
const indexBytes = Buffer.alloc(8);
indexBytes.writeBigInt64LE(i, 0);
(secretKey.material as Array<number>).push(
Number(
await _randomInteger(
1n,
_SECRET_SHARED_SIGNED_INTEGER_MODULUS - 1n,
seedIteration,
await _randomBytes(64, seedBytes, indexBytes),
),
),
);
Expand Down
20 changes: 10 additions & 10 deletions tests/nilql.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,14 @@ describe("methods of cryptographic key classes", () => {
);
expect(
await toHashBase64(secretKeyFromSeed.material as Uint8Array),
).toStrictEqual("TVFhJJ32+eh+yaYL1Dhcw7Z+ykY4N1cKDJXDxdS92vI=");
).toStrictEqual("2bW6BLeeCTqsCqrijSkBBPGjDb/gzjtGnFZt0nsZP8w=");

const secretKey = await nilql.SecretKey.generate(
{ nodes: [{}] },
{ store: true },
);
expect(await toHashBase64(secretKey.material as Uint8Array)).not.toEqual(
"TVFhJJ32+eh+yaYL1Dhcw7Z+ykY4N1cKDJXDxdS92vI=",
"2bW6BLeeCTqsCqrijSkBBPGjDb/gzjtGnFZt0nsZP8w=",
);
});

Expand All @@ -208,14 +208,14 @@ describe("methods of cryptographic key classes", () => {
);
expect(
await toHashBase64(secretKeyFromSeed.material as Uint8Array),
).toStrictEqual("TVFhJJ32+eh+yaYL1Dhcw7Z+ykY4N1cKDJXDxdS92vI=");
).toStrictEqual("2bW6BLeeCTqsCqrijSkBBPGjDb/gzjtGnFZt0nsZP8w=");

const secretKey = await nilql.SecretKey.generate(
{ nodes: [{}, {}, {}] },
{ store: true },
);
expect(await toHashBase64(secretKey.material as Uint8Array)).not.toEqual(
"TVFhJJ32+eh+yaYL1Dhcw7Z+ykY4N1cKDJXDxdS92vI=",
"2bW6BLeeCTqsCqrijSkBBPGjDb/gzjtGnFZt0nsZP8w=",
);
});

Expand All @@ -227,14 +227,14 @@ describe("methods of cryptographic key classes", () => {
);
expect(
await toHashBase64(secretKeyFromSeed.material as Uint8Array),
).toStrictEqual("M4qqWosTwaBvPMEvUDWKg/RJA3+18+mv/X5Zlj21NhY=");
).toStrictEqual("qbcFGTOGTPo+vs3EChnVUWk5lnn6L6Cr/DIq8li4H+4=");

const secretKey = await nilql.SecretKey.generate(
{ nodes: [{}] },
{ match: true },
);
expect(await toHashBase64(secretKey.material as Uint8Array)).not.toEqual(
"M4qqWosTwaBvPMEvUDWKg/RJA3+18+mv/X5Zlj21NhY=",
"qbcFGTOGTPo+vs3EChnVUWk5lnn6L6Cr/DIq8li4H+4=",
);
});

Expand All @@ -246,14 +246,14 @@ describe("methods of cryptographic key classes", () => {
);
expect(
await toHashBase64(secretKeyFromSeed.material as Uint8Array),
).toStrictEqual("M4qqWosTwaBvPMEvUDWKg/RJA3+18+mv/X5Zlj21NhY=");
).toStrictEqual("qbcFGTOGTPo+vs3EChnVUWk5lnn6L6Cr/DIq8li4H+4=");

const secretKey = await nilql.SecretKey.generate(
{ nodes: [{}, {}, {}] },
{ match: true },
);
expect(await toHashBase64(secretKey.material as Uint8Array)).not.toEqual(
"M4qqWosTwaBvPMEvUDWKg/RJA3+18+mv/X5Zlj21NhY=",
"qbcFGTOGTPo+vs3EChnVUWk5lnn6L6Cr/DIq8li4H+4=",
);
});

Expand All @@ -265,14 +265,14 @@ describe("methods of cryptographic key classes", () => {
);
expect(
await toHashBase64(secretKeyFromSeed.material as number[]),
).toStrictEqual("uh5uhif06rquRHY4kbrL/31JY7SV1uj6nXSqSUfvLLg=");
).toStrictEqual("L8RiHNq2EUgt/fDOoUw9QK2NISeUkAkhxHHIPoHPZ84=");

const secretKey = await nilql.SecretKey.generate(
{ nodes: [{}, {}, {}] },
{ sum: true },
);
expect(await toHashBase64(secretKey.material as number[])).not.toEqual(
"uh5uhif06rquRHY4kbrL/31JY7SV1uj6nXSqSUfvLLg=",
"L8RiHNq2EUgt/fDOoUw9QK2NISeUkAkhxHHIPoHPZ84=",
);
});
});
Expand Down

0 comments on commit 8fd115b

Please sign in to comment.