diff --git a/package.json b/package.json index 796613c..013fdb6 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,10 @@ "./web": { "import": "./lib/web.js", "require": "./lib/web.js" + }, + "./node": { + "import": "./lib/node.cjs", + "require": "./lib/node.cjs" } }, "scripts": { diff --git a/src/sdk/encrypt.test.ts b/src/sdk/encrypt.test.ts index 35b7d61..3abbeaa 100644 --- a/src/sdk/encrypt.test.ts +++ b/src/sdk/encrypt.test.ts @@ -10,6 +10,7 @@ import { CompactFheUint16List, CompactFheUint32List, CompactFheUint64List, + CompactFheUint160List, TfheCompactPublicKey, TfheClientKey, } from 'node-tfhe'; @@ -21,9 +22,10 @@ import { encrypt16, encrypt32, encrypt64, + encryptAddress, } from './encrypt'; -describe('encrypt8', () => { +describe('encrypt', () => { let clientKey: TfheClientKey; let publicKey: TfheCompactPublicKey; @@ -153,7 +155,7 @@ describe('encrypt8', () => { }); }); - it('encrypt/decrypt 64bits', async () => { + it('encrypt/decrypt bigint 64bits', async () => { const buffer = encrypt64(BigInt('18446744073709551615'), publicKey); const compactList = CompactFheUint64List.deserialize(buffer); let encryptedList = compactList.expand(); @@ -162,4 +164,31 @@ describe('encrypt8', () => { expect(decrypted.toString()).toBe('18446744073709551615'); }); }); + it('encrypt/decrypt 0x000... 160bits', async () => { + const buffer = encryptAddress( + '0x0000000000000000000000000000000000000000', + publicKey, + ); + const compactList = CompactFheUint160List.deserialize(buffer); + let encryptedList = compactList.expand(); + encryptedList.forEach((v: FheUint64) => { + const decrypted = v.decrypt(clientKey); + expect(decrypted.toString()).toBe('0'); + }); + }); + + it('encrypt/decrypt 160bits', async () => { + const buffer = encryptAddress( + '0x8ba1f109551bd432803012645ac136ddd64dba72', + publicKey, + ); + const compactList = CompactFheUint160List.deserialize(buffer); + let encryptedList = compactList.expand(); + encryptedList.forEach((v: FheUint64) => { + const decrypted = v.decrypt(clientKey); + expect(decrypted.toString()).toBe( + '797161134358056856230896843146392277790002887282', + ); + }); + }); }); diff --git a/src/sdk/encrypt.ts b/src/sdk/encrypt.ts index 4472f48..c78a214 100644 --- a/src/sdk/encrypt.ts +++ b/src/sdk/encrypt.ts @@ -6,7 +6,9 @@ import { CompactFheUint16List, CompactFheUint32List, CompactFheUint64List, + CompactFheUint160List, } from 'node-tfhe'; +import { fromHexString } from '../utils'; export const encrypt4 = ( value: number, @@ -78,3 +80,15 @@ export const encrypt64 = ( ); return encrypted.serialize(); }; + +export const encryptAddress = ( + value: string, + publicKey: TfheCompactPublicKey, +): Uint8Array => { + // value is something like 0x8ba1f109551bd432803012645ac136ddd64dba72 + const encrypted = CompactFheUint160List.encrypt_with_compact_public_key( + [BigInt(value)], + publicKey, + ); + return encrypted.serialize(); +}; diff --git a/src/sdk/index.test.ts b/src/sdk/index.test.ts index b5a7902..a86b070 100644 --- a/src/sdk/index.test.ts +++ b/src/sdk/index.test.ts @@ -118,6 +118,10 @@ describe('index', () => { expect(instance.encrypt32(BigInt(838392))).toBeTruthy(); expect(instance.encrypt64(BigInt(3433434343))).toBeTruthy(); + expect( + instance.encryptAddress('0x8ba1f109551bd432803012645ac136ddd64dba72'), + ).toBeTruthy(); + expect(() => instance.encryptBool(undefined as any)).toThrow( 'Missing value', ); @@ -145,6 +149,12 @@ describe('index', () => { expect(() => instance.encrypt64('wrong value' as any)).toThrow( 'Value must be a number or a bigint.', ); + expect(() => instance.encryptAddress('wrong value' as any)).toThrow( + 'Value must be a valid address.', + ); + expect(() => instance.encryptAddress(BigInt(32) as any)).toThrow( + 'Value must be a string.', + ); // Check limit expect(instance.encryptBool(1)).toBeTruthy(); diff --git a/src/sdk/index.ts b/src/sdk/index.ts index d097bb5..73fb6f7 100644 --- a/src/sdk/index.ts +++ b/src/sdk/index.ts @@ -6,6 +6,7 @@ import { encrypt16, encrypt32, encrypt64, + encryptAddress, encryptBool, } from './encrypt'; import { @@ -24,6 +25,7 @@ export type FhevmInstance = { encrypt16: (value: number | bigint) => Uint8Array; encrypt32: (value: number | bigint) => Uint8Array; encrypt64: (value: number | bigint) => Uint8Array; + encryptAddress: (value: string) => Uint8Array; generatePublicKey: ( options: GeneratePublicKeyParams & { force?: boolean; @@ -60,6 +62,11 @@ export type FhevmInstanceParams = { keypairs?: ExportedContractKeypairs; }; +export const getPublicKeyCallParams = () => ({ + to: '0x000000000000000000000000000000000000005d', + data: '0xd9d47bb001', +}); + export const createInstance = async ( params: FhevmInstanceParams, ): Promise => { @@ -180,6 +187,16 @@ export const createInstance = async ( return encrypt64(value, tfheCompactPublicKey); }, + encryptAddress(value) { + if (!tfheCompactPublicKey) + throw new Error( + 'Your instance has been created without the public blockchain key.', + ); + if (typeof value !== 'string') throw new Error('Value must be a string.'); + if (!isAddress(value)) throw new Error('Value must be a valid address.'); + return encryptAddress(value, tfheCompactPublicKey); + }, + // Reencryption generatePublicKey(options) { if (!options || !options.verifyingContract) diff --git a/src/utils.ts b/src/utils.ts index 1dfb41d..809d350 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -35,7 +35,7 @@ export const bytesToBigInt = function (byteArray: Uint8Array): bigint { }; export const isAddress = function (address: string) { - if (/^(0x)?[0-9a-f]{40}$/i.test(address.toLowerCase())) { + if (address.match(/^0x[0-9a-fA-F]{40}$/)) { // check if it has the basic requirements of an address return true; }