Skip to content

Commit

Permalink
Merge pull request #56 from zama-ai/feat/allow-more-types
Browse files Browse the repository at this point in the history
feat: allow bigint and number for all encrypt methods
  • Loading branch information
immortal-tofu authored Mar 1, 2024
2 parents e0df4fd + 0c94ced commit 207c8d7
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 47 deletions.
58 changes: 44 additions & 14 deletions src/sdk/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,20 @@ describe('index', () => {
publicKey: tfhePublicKey,
});
expect(instance.encryptBool(true)).toBeTruthy();

expect(instance.encryptBool(1)).toBeTruthy();
expect(instance.encrypt4(2)).toBeTruthy();
expect(instance.encrypt8(34)).toBeTruthy();
expect(instance.encrypt16(344)).toBeTruthy();
expect(instance.encrypt32(3422)).toBeTruthy();
expect(instance.encrypt64(BigInt(34))).toBeTruthy();
expect(instance.encrypt64(34)).toBeTruthy();

expect(instance.encryptBool(BigInt(0))).toBeTruthy();
expect(instance.encrypt4(BigInt(2))).toBeTruthy();
expect(instance.encrypt8(BigInt(233))).toBeTruthy();
expect(instance.encrypt16(BigInt(3342))).toBeTruthy();
expect(instance.encrypt32(BigInt(838392))).toBeTruthy();
expect(instance.encrypt64(BigInt(3433434343))).toBeTruthy();

expect(() => instance.encryptBool(undefined as any)).toThrow(
'Missing value',
Expand All @@ -122,32 +131,53 @@ describe('index', () => {
'Value must be a boolean',
);
expect(() => instance.encrypt4('wrong value' as any)).toThrow(
'Value must be a number',
'Value must be a number or a bigint.',
);
expect(() => instance.encrypt8('wrong value' as any)).toThrow(
'Value must be a number',
'Value must be a number or a bigint.',
);
expect(() => instance.encrypt16('wrong value' as any)).toThrow(
'Value must be a number',
'Value must be a number or a bigint.',
);
expect(() => instance.encrypt32('wrong value' as any)).toThrow(
'Value must be a number',
'Value must be a number or a bigint.',
);
expect(() => instance.encrypt64('wrong value' as any)).toThrow(
'Value must be a number',
'Value must be a number or a bigint.',
);

expect(() => instance.encrypt4(BigInt(34) as any)).toThrow(
'Value must be a number',
// Check limit
expect(instance.encryptBool(1)).toBeTruthy();
expect(() => instance.encryptBool(34)).toThrow('Value must be 1 or 0.');
expect(() => instance.encryptBool(BigInt(34))).toThrow(
'Value must be 1 or 0.',
);
expect(() => instance.encrypt8(BigInt(34) as any)).toThrow(
'Value must be a number',

expect(instance.encrypt4(Math.pow(2, 4) - 1)).toBeTruthy();
expect(() => instance.encrypt4(BigInt(34))).toThrow(
'The value exceeds the limit for 4bits integer (15).',
);
expect(() => instance.encrypt16(BigInt(34) as any)).toThrow(
'Value must be a number',

expect(instance.encrypt8(Math.pow(2, 8) - 1)).toBeTruthy();
expect(() => instance.encrypt8(BigInt(256))).toThrow(
'The value exceeds the limit for 8bits integer (255).',
);
expect(() => instance.encrypt32(BigInt(34) as any)).toThrow(
'Value must be a number',

expect(instance.encrypt16(Math.pow(2, 16) - 1)).toBeTruthy();
expect(() => instance.encrypt16(BigInt(70000))).toThrow(
'The value exceeds the limit for 16bits integer (65535).',
);

expect(instance.encrypt32(Math.pow(2, 32) - 1)).toBeTruthy();
expect(() => instance.encrypt32(BigInt(Math.pow(2, 32)) as any)).toThrow(
'The value exceeds the limit for 32bits integer (4294967295).',
);

expect(
instance.encrypt64(BigInt(Math.pow(2, 64)) - BigInt(1)),
).toBeTruthy();
expect(() => instance.encrypt64(BigInt(Math.pow(2, 64)) as any)).toThrow(
'The value exceeds the limit for 64bits integer (18446744073709551615).',
);
});

Expand Down
83 changes: 50 additions & 33 deletions src/sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ import { fromHexString, isAddress, toHexString } from '../utils';
import { ContractKeypairs } from './types';

export type FhevmInstance = {
encryptBool: (value: boolean) => Uint8Array;
encrypt4: (value: number) => Uint8Array;
encrypt8: (value: number) => Uint8Array;
encrypt16: (value: number) => Uint8Array;
encrypt32: (value: number) => Uint8Array;
encryptBool: (value: boolean | number | bigint) => Uint8Array;
encrypt4: (value: number | bigint) => Uint8Array;
encrypt8: (value: number | bigint) => Uint8Array;
encrypt16: (value: number | bigint) => Uint8Array;
encrypt32: (value: number | bigint) => Uint8Array;
encrypt64: (value: number | bigint) => Uint8Array;
generatePublicKey: (
options: GeneratePublicKeyParams & {
Expand Down Expand Up @@ -102,64 +102,81 @@ export const createInstance = async (
);
};

const checkEncryptedValue = (value: number | bigint, bits: number) => {
if (value == null) throw new Error('Missing value');
const limit = BigInt(Math.pow(2, bits));
if (typeof value !== 'number' && typeof value !== 'bigint')
throw new Error('Value must be a number or a bigint.');
if (value >= limit) {
throw new Error(
`The value exceeds the limit for ${bits}bits integer (${(
limit - BigInt(1)
).toString()}).`,
);
}
};

return {
// Parameters
encryptBool(value) {
if (value == null) throw new Error('Missing value');
if (typeof value !== 'boolean')
throw new Error('Value must be a boolean');
if (!tfheCompactPublicKey)
throw new Error(
'Your instance has been created without the public blockchain key',
'Your instance has been created without the public blockchain key.',
);
return encryptBool(value, tfheCompactPublicKey);
if (value == null) throw new Error('Missing value');
if (
typeof value !== 'boolean' &&
typeof value !== 'number' &&
typeof value !== 'bigint'
)
throw new Error('Value must be a boolean, a number or a bigint.');
if (
(typeof value !== 'bigint' || typeof value !== 'number') &&
Number(value) > 1
)
throw new Error('Value must be 1 or 0.');
return encryptBool(Boolean(value), tfheCompactPublicKey);
},
encrypt4(value) {
if (value == null) throw new Error('Missing value');
if (typeof value !== 'number') throw new Error('Value must be a number');
if (!tfheCompactPublicKey)
throw new Error(
'Your instance has been created without the public blockchain key',
'Your instance has been created without the public blockchain key.',
);
return encrypt4(value, tfheCompactPublicKey);
checkEncryptedValue(value, 4);
return encrypt4(Number(value), tfheCompactPublicKey);
},
encrypt8(value) {
if (value == null) throw new Error('Missing value');
if (typeof value !== 'number') throw new Error('Value must be a number');
if (!tfheCompactPublicKey)
throw new Error(
'Your instance has been created without the public blockchain key',
'Your instance has been created without the public blockchain key.',
);
return encrypt8(value, tfheCompactPublicKey);
checkEncryptedValue(value, 8);
return encrypt8(Number(value), tfheCompactPublicKey);
},
encrypt16(value) {
if (value == null) throw new Error('Missing value');
if (typeof value !== 'number') throw new Error('Value must be a number');
if (!tfheCompactPublicKey)
throw new Error(
'Your instance has been created without the public blockchain key',
'Your instance has been created without the public blockchain key.',
);
return encrypt16(value, tfheCompactPublicKey);
checkEncryptedValue(value, 16);
return encrypt16(Number(value), tfheCompactPublicKey);
},

encrypt32(value) {
if (value == null) throw new Error('Missing value');
if (typeof value !== 'number') throw new Error('Value must be a number');
if (!tfheCompactPublicKey)
throw new Error(
'Your instance has been created without the public blockchain key',
'Your instance has been created without the public blockchain key.',
);
return encrypt32(value, tfheCompactPublicKey);
checkEncryptedValue(value, 32);
return encrypt32(Number(value), tfheCompactPublicKey);
},

encrypt64(value) {
if (value == null) throw new Error('Missing value');
if (typeof value !== 'number' && typeof value !== 'bigint')
throw new Error('Value must be a number or a bigint');
if (!tfheCompactPublicKey)
throw new Error(
'Your instance has been created without the public blockchain key',
'Your instance has been created without the public blockchain key.',
);
checkEncryptedValue(value, 64);
return encrypt64(value, tfheCompactPublicKey);
},

Expand Down Expand Up @@ -210,10 +227,10 @@ export const createInstance = async (
hasKeypair,

decrypt(contractAddress, ciphertext) {
if (!ciphertext) throw new Error('Missing ciphertext');
if (!contractAddress) throw new Error('Missing contract address');
if (!ciphertext) throw new Error('Missing ciphertext.');
if (!contractAddress) throw new Error('Missing contract address.');
const kp = contractKeypairs[contractAddress];
if (!kp) throw new Error(`Missing keypair for ${contractAddress}`);
if (!kp) throw new Error(`Missing keypair for ${contractAddress}.`);
return decrypt(kp, ciphertext);
},

Expand Down

0 comments on commit 207c8d7

Please sign in to comment.