Git Product home page Git Product logo

s0l0ist / node-seal Goto Github PK

View Code? Open in Web Editor NEW
186.0 5.0 22.0 83.19 MB

Homomorphic Encryption for TypeScript or JavaScript - Microsoft SEAL

Home Page: https://s0l0ist.github.io/node-seal/

License: MIT License

HTML 0.03% JavaScript 1.44% Shell 0.36% TypeScript 98.16%
encryption cryptography homomorphic-encryption webassembly emscripten seal microsoft homomorphic homomorphism cryptosystem

node-seal's People

Contributors

anish-yadav avatar dependabot[bot] avatar fossabot avatar s0l0ist avatar willclarktech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

node-seal's Issues

The example code with 1024 bit polymodulus seems to fail (incorrect output)

Hi,
Taking the example from here https://github.com/morfix-io/node-seal/blob/main/FULL-EXAMPLE.md

I have changed the code so that instead of specifying the parameters I do:

  let coeffModulus = seal.CoeffModulus.BFVDefault(polyModulusDegree)
  // Create a suitable set of CoeffModulus primes
  parms.setCoeffModulus(
      coeffModulus
  )

If I set the polyModulusDegree to 2048 I get

decodedArray Int32Array(2048) [
  2, 4, 6, 8, 10, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,
  ... 1948 more items
]

4096 I get

decodedArray Int32Array(4096) [
  2, 4, 6, 8, 10, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,
  ... 3996 more items
]

but adjusting it for 1024 bit and using the default function for coeff modulus seems to cause the output to fail:
1024

decodedArray Int32Array(1024) [
   105844, -318666,  353194,  308340,  -22466, -280593, -121865,
    93239,  161666,   56413, -429374,  274691,  214325,  150437,
  -262277, -435923,  175173,  180207, -250189, -183222, -302924,
   493734,  -39478,  507789, -123179,  -10467, -247445,  111902,
   446943, -463523,  490017,   45863, -455228,  -32028, -308374,
   161534, -216214,  -57172,  453304,    2499,  266728,  -17369,
   287119,   20179,  211342,  479885,  442275,   46353,   22520,
  -432398,  436056,  -26115, -103722,  264451,  256323,  308170,
   198784, -325548,  205138, -371934,   56778,  372592,  -79392,
    59866,  409560, -329666, -188138, -473686,  194220, -251112,
   199224,  227037,  117366, -311811, -249313,  -96853,  293575,
  -325482,  -27145, -389919,    1070, -414144,  486298, -375258,
  -436172, -100284,  -60636,  211476, -268699,  444525,   68176,
  -465590, -276743,   69281, -471714,  143503, -443269,  357831,
  -348976,   85036,
  ... 924 more items
]

Any ideas whats going on and how to fix it?
My use case is I want the smallest output size data I can get all the while using homomorphic encryption (I need to send the data over HTTP with the smallest payload).

Full code snippet:

;(async () => {
  // Using CommonJS for RunKit
  const SEAL = require('node-seal')
  const seal = await SEAL()
  const schemeType = seal.SchemeType.bfv
  const securityLevel = seal.SecurityLevel.tc128
  const polyModulusDegree = 1024    
  const bitSize = 20
  const parms = seal.EncryptionParameters(schemeType)
    // Set the PolyModulusDegree
  parms.setPolyModulusDegree(polyModulusDegree)
  let coeffModulus = seal.CoeffModulus.BFVDefault(polyModulusDegree)
  // Create a suitable set of CoeffModulus primes
  parms.setCoeffModulus(
      coeffModulus
  )

  // Set the PlainModulus to a prime of bitSize 20.
  parms.setPlainModulus(
    seal.PlainModulus.Batching(polyModulusDegree, bitSize)
  )
  const context = seal.Context(
    parms, // Encryption Parameters
    true, // ExpandModChain
    securityLevel // Enforce a security level
  )

  // Set the PolyModulusDegree
  parms.setPolyModulusDegree(polyModulusDegree)


  if (!context.parametersSet()) {
    throw new Error(
      'Could not set the parameters in the given context. Please try different encryption parameters.'
    )
  }

  const encoder = seal.BatchEncoder(context)
  const keyGenerator = seal.KeyGenerator(context)
  const publicKey = keyGenerator.createPublicKey()
  const secretKey = keyGenerator.secretKey()
  const encryptor = seal.Encryptor(context, publicKey)
  const decryptor = seal.Decryptor(context, secretKey)
  const evaluator = seal.Evaluator(context)

  // Create data to be encrypted
  const array = Int32Array.from([1, 2, 3, 4, 5])

  // Encode the Array
  const plainText = encoder.encode(array)

  // Encrypt the PlainText
  const cipherText = encryptor.encrypt(plainText)

  // Add the CipherText to itself and store it in the destination parameter (itself)
  evaluator.add(cipherText, cipherText, cipherText) // Op (A), Op (B), Op (Dest)

  // Or create return a new cipher with the result (omitting destination parameter)
  // const cipher2x = evaluator.add(cipherText, cipherText)

  // Decrypt the CipherText
  const decryptedPlainText = decryptor.decrypt(cipherText)

  // Decode the PlainText
  const decodedArray = encoder.decode(decryptedPlainText)

  console.log('decodedArray', decodedArray)
})()

PlainText seem not working

Hi,

I have tried using both plaintext.load (commented below) and encoder.encode to construct a PlainText object that I would be using for encryption. However, it seems that the code isnt executing as when I do a console.log("here2") after said lines, it doesn't go there. Please advise... Btw, init() is used by my other function generateKey (which generates both public and privatekey) and it works fine.

Thanks,
Benjie

async function encrypt(file, keyfromDB) {
  await init();
  
  //encode plaintext to be encrypted
  let buff = fs.readFileSync("uploads/" + file);
  const plaintext = seal.PlainText();

  /* let base64data = buff.toString('base64');
  console.log(base64data);
  plaintext.load(context, base64data);
  console.log("here2");*/

  const encoder = seal.BatchEncoder(context);
  const uint32array = new Uint32Array(buff);
  console.log(uint32array);
  plaintext = encoder.encode(uint32array);
  console.log("here2");`

using smaller key sizes and adjusting the calculation (continued)

Apologies - couldnt' work out if I can re-open a ticket that has been closed. (#133)

So continuing the conversation there, basically I have data that is larger than i can store in a a single array (each array can't be bigger than the PolyModulusDegree)

So to start, assuming the parameters are:

const heConfig = {
    keySize: 4096,
    bitSize: 20
}

then in each array of data to process I can store 4096 bits of data.
With regards to my algorithm then:

    for (let i = 0, l = arraysToSend.length; i < l; i++) {
      const image3232Chunk = seal.CipherText()
      image3232Chunk.load(context, arraysToSend[i]) //load the current image chunk
      const encryptedFillArray = seal.CipherText()
      encryptedFillArray.load(context, savedFillArray) //encrypted load of zeros to store the result
      for (let j = 0, end = kernels.length; j < end; j++) {
          const tmp = evaluator.multiplyPlain(image3232Chunk, kernels[j])
          evaluator.add(encryptedFillArray, tmp, encryptedFillArray)
      }
      const send = encryptedFillArray.save()
      convEncArray.push(send)
    }
  • I am loading in the first 4096 bits of data here image3232Chunk.load(context, arraysToSend[i])
  • I create a "place" to store the answer, encryptedFillArray.load(context, savedFillArray) (sendFillArray is an encrypted set of zeros that I am cloning into encryptedFillArray)
  • then I have a array of plain texts (kernels) each is nine 1s and the rest zeros, each entry in the array is shifted nine along from the last:
[0]: 1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1, 0, 0, 0, 0, 0, 0, 0, 0, 0...... (to 4096 in total)
[1]: 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1...... (to 4096 in total)

etc, until all 4096 places have been a 1 in an entry.
Reason being, I want to multiply the each set of 9 values of image3232Chunk by the kernel value (which in practice won't be 1's, thats just for testing) - then its stored in tmp. Then tmp is added to encryptedFillArray - the reason for the zeros will then mean the other values in encryptedFillArray are not affected during the addition here: evaluator.add(encryptedFillArray, tmp, encryptedFillArray)

I.e adding

0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 ,1 ,1 ,1 ,1 ,1 ,1 ,1......
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 ....

will not affect the first nine 2s so I can keep adding them and only affecting the correct nine slots.

Then i save that result in convEncArray and do it again for the next arrayToSend.

This works nicely except that I can't use a smaller keySize than 4096 because evaluator.add corrupts the data with smaller key sizes however using 4096 to encrypt the data means I have about half a MB of data to send over HTTP, whereas with 1024 key size, I have about 25kb to send over HTTP.

However I reckon either, I can use a relin key on evaluator.add(encryptedFillArray, tmp, encryptedFillArray) with a smaller keySize, or a more efficient algorithm to do the addition.

So....

My question then is, is there a "neat" way to add all the tmps I have together in one go so not to corrupt encrytpedFilleArray with smaller keys (1024, 2048), or can I relin after every loop round (or somehow work out when to relin so not to do it every time around the loop) and will relin key that I have to send with the request over HTTP just make it as big and therefore be pointless?

Hopefully that makes some more sense?

Thank you!

Evaluator.add() result

Hey. I'm trying to add two 'vectors' :

const v1 = [0, 0, 1]
const v2 = [1, 0, 0]

which in ciphertext are ciphertext1 and ciphertext1, respectively.

This is the code use to add them:

const evaluator = Morfix.Evaluator({
    context: context
  })

  const cipherTextResult = Morfix.CipherText()
  evaluator.add({
    a: cipherText1,
    b: cipherText2,
    destination: cipherTextResult
  })

  // Create a new plainText variable to store the decrypted cipherText
  const decryptedPlainText = Morfix.PlainText()
  decryptor.decrypt({
    cipherText: cipherTextResult,
    plainText: decryptedPlainText
  })

  // Create a c++ vector to store the decoded result
  const decodeVector = Morfix.Vector({array: new Int32Array(3) })

  // Decode the plaintext to the c++ vector
  encoder.decodeVectorInt32({
    plainText: decryptedPlainText,
    vector: decodeVector
  })

  console.log('decodeVector.size', decodeVector.size)

  // Convert the vector to a JS array
  const decryptedArray = decodeVector.toArray()
  console.log('decryptedArray', decryptedArray)

which outputs:

decodeVector.size 4099
decryptedArray Int32Array [
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0,
  ... 3999 more items
]

However, i require the result in the form [1, 0, 1]. How do I get that ?

Rescaling in CKKS for substraction

The issue:

I am trying to substract rB from rA, but I'm having an issue with the scales.
The cipherTextSxy was previously relinearized and rescaled in other steps of the code.
I have already tried to set rA's scale to rB's scale but then we'd lose the real value of rA and the substraction, even though it would not fail, would not be realistic. I have also tried to turn N's plaintext to a ciphertext and work with the evaluator.multiply() function, but there is also an scale issue with that approach.

Screenshot of the scales' values:
Scales of cipherTextSxy and NPlainText:

image

Scales of rA and rB:

image

My code:
    // Turn N into a PlainText
    const NPlaintext = seal.PlainText();
    const NArray = Float64Array.from([N]);
    encoder.encode(NArray, scale, NPlaintext);

    // Compute rA = N*Sxy
    let rA = seal.CipherText();
    evaluator.multiplyPlain(cipherTextSxy, NPlaintext, rA);
    evaluator.relinearize(rA, relinKey);
    evaluator.rescaleToNext(rA);

    // Compute rB = Sx*Sy
    let rB = seal.CipherText();
    evaluator.multiply(cipherTextSx, cipherTextSy, rB);
    evaluator.relinearize(rB, relinKey);
    evaluator.rescaleToNext(rB);

    // Compute rAB = rA - rB
    let rAB = seal.CipherText();
    //rA.setScale(rB.scale);
    console.log(`Scale A: ${rA.scale}`);
    console.log(`Scale B: ${rB.scale}`);
    console.log(`Scale AB: ${rAB.scale}`);
    evaluator.sub(rA, rB, rAB);
Encryption parameters:
    /**************************************************
     * SCHEME PARAMETERS
     **************************************************/
    const schemeType = seal.SchemeType.ckks;
    const securityLevel = seal.SecurityLevel.tc128;
    const polyModulusDegree = 8192;
    const bitSizes = [60, 40, 40, 60];
    const bitSize = 40;
    
    const parms = seal.EncryptionParameters(schemeType);
    
    /**************************************************
     * POLY MODULUS DEGREE
     **************************************************/
    parms.setPolyModulusDegree(polyModulusDegree);
    
    /**************************************************
     * COEFF MODULUS PRIMES
     **************************************************/
    parms.setCoeffModulus(
        seal.CoeffModulus.Create(polyModulusDegree, Int32Array.from(bitSizes))
    );
    
    /**************************************************
     * CREATE CONTEXT
     **************************************************/
    const context = seal.Context(
        parms, // Encryption Parameters
        true, // ExpandModChain
        securityLevel // Enforce a security level
    );

Parameters for multiplication operations for polyModulusDegree = 1024

Hi, I am new in using SEAL, when i use following parameters
const polyModulusDegree = 4096
const bitSizes = [36,36,37]
const bitSize = 20, the response output size is around 180kb,
I need an output less than or equal to 128 kb, is there any way to compress the encrypted result?

Evaluator switch_key_inplace

Hey ๐Ÿ‘‹

First off. Thanks for a great package. It has really made it easy and fairly trivial to get started using FHE in my application.

According to this conversation, the reference implemention has a switch_key_inplace method.

I was wondering if you have implemented this in any capacity in this implementation?

Best,

How can i use global context (different seal)

Here is my init code:

async function contextInit() {
    const SEAL = require('node-seal')
    const seal = await SEAL()
    
    const schemeType = seal.SchemeType.bfv
    const securityLevel = seal.SecurityLevel.tc128
    const polyModulusDegree = 4096
    const bitSizes = [36, 36, 37]
    const bitSize = 20
    
    const encParms = seal.EncryptionParameters(schemeType)
    encParms.setPolyModulusDegree(polyModulusDegree)
    encParms.setCoeffModulus(seal.CoeffModulus.Create(polyModulusDegree, Int32Array.from(bitSizes)))
    encParms.setPlainModulus(seal.PlainModulus.Batching(polyModulusDegree, bitSize))
    
    const context = seal.Context(encParms, true, securityLevel)
    
    if (!context.parametersSet()) {
        throw new Error('Could not set the parameters in the given context. Please try different encryption parameters.')
    }
    return context
}
module.exports.context = contextInit()

And call context like this:

(async () => {
    const SEAL = require('node-seal')
    const seal = await SEAL()
    const context = await require('./main').context

    const key = seal.KeyGenerator(context)

})()

But i'm got an blind error

BindingError: Expected null or instance of SEALContext, got an instance of SEALContext

It's can use context(create from another seal) with another seal ?

Access Public key and Secret Key

Is it possible to store the Public key and secret key in a vault. I cant do that as it is returning a complete object as below

secret key {
instance: [Getter],
inject: [Function: inject],
delete: [Function: delete],
save: [Function: save],
saveArray: [Function: saveArray],
load: [Function: load],
loadArray: [Function: loadArray],
copy: [Function: copy],
clone: [Function: clone],
move: [Function: move]
}

encrypted1 is not valid for encryption parameters

I'm trying to play around with the hosted sandbox, but no matter what I do, I always get the error encrypted1 is not valid for encryption parameters. Before running anything, I generated all the necessary parts. Maybe I am doing something wrong - is there some guide how to use the sandbox?

Benchmarks not working

When running on MacOS Big Sur the command npm run seal:build:bench it generates the following error:

> [email protected] seal:build:bench 
> export BUILD_BENCH=ON && export THROW_ON_TRANSPARENT=ON && npm run seal:cmake && npm run seal:make


> [email protected] seal:cmake 
> bash scripts/seal-cmake.sh

scripts/seal-cmake.sh: line 4: ./emsdk_env.sh: No such file or directory
scripts/seal-cmake.sh: line 18: emcmake: command not found

It seems like the script file emsdk_env.sh is missing from the repository.

polymodulus, bitsize, bitsizes

I am using the security level SecurityLevel.tc128 and want to use polyModulusDegree=1024
what combinations of bitSizes [-,-,-] can i have and what should be the bitsize?

How can i call "CipherText.setScale"

I need to change scale of CipherText

And CipherText.scale of node-seal is read-only property.

But MS-SEAL has setScale Function.

I wonder if you could help me by support CipherText.setScale in this great library?

Thank you!

Is anyone using any KMS to store LWE keys?

Currently, I don't see any KMS support LWE Keys. How does it currently manage to store and retrieve keys?

  • Store and retrieve from AWS S3
  • Store in Secret manager (but has limitation in size)
  • may be vaulted as secrets.

Is there any other better way to handle key management? including Rotations?

Cannot import from Javascript(browser)

Describe the bug
Cannot import node-seal from browser (not node-js)

To Reproduce
Trying import node-seal from browser, my Javascript can not import node-seal.

(Based on Full example so other lines are same. And works perfectly in Node.js)

main.html
....<script type="module" src="/main.js" ></script>....

main.js
(async () => { import SEAL from 'node-seal'; ......

And I got an error like: Uncaught SyntaxError: Unexpected identifier (at main.js:12:12)

So I tried other methods to import node-seal but could not solve it.

tried: const SEAL = require('node-seal');
error: Uncaught (in promise) ReferenceError: require is not defined

tried: import SEAL from 'node-seal/throws_wasm_web_umd'
error: Failed to resolve module specifier "node-seal/throws_wasm_web_umd". Relative references must start with either "/", "./", or "../".

tried: import {SEAL} from './node_modules/node-seal/throws_wasm_node_umd.js'
error: The requested module './node_modules/node-seal/throws_wasm_node_umd.js' does not provide an export named 'SEAL' (at main.js:1:9)

Is there something I missed??

thanks.

Environment

  • browser: Chrome
  • nodejs version [e.g. v16.13.0]: 14.18.12
  • node-seal version [e.g. 4.6.2]: v5.0.0

SecurityLevel 192

The issue:

I have a linear regression system working with basic security level tc128. I am trying to switch to tc192 to explore how latency will be affected. To briefly explain what the system does, as the titles are in spanish, in the first div you introduce X and Y axis values and by the Least Squares Method you should get the equation parameters. With the second div, you can compute the prediction.
With tc128 it works perfectly fine but, with tc192, the decrypted data is wrong. I am not sure if the bit sizes I have introduced are not correct or what the issue is here. I have already tried changing the bit sizes, and also swithing to polymodulus degree 16384 and changing the bit sizes accordingly and nothing seems to work. The sum of the bit sizes with tc192 and polymodulus of 8192 is 145, bellow the enforced limit.

The code with bit sizes:

image

The program working with tc128:

image

The program not working with tc192:

image

load() in public-key.js

Hey. I'm trying to load a previously saved public key (created using keyGenerator.getPublicKey() ) from a .csr file. I'm using the load(context, encoded) function from the public-key.js, but i am running into trouble.

When using the associated save() method, i just used it as publicKey.save() on my previously defined public key. But what exactly do i call the load method on ? I tried using the documentation to solve my dilemma but i'm still stuck. Any guidance would be appreciated.

how can i use SEAL instance in different environment

I want to use an instance like context, publicKey, secretKey and etc. with another device that has own SEAL. but when I export instance to another device and use it with SEAL in each device it not work

have a specific method to share instance like context to other device or other environment that instance still work with other environment ?

this diagram would help to explain this system.
Untitled Diagram drawio

description:
device1: config context, publicKey, secretKey
device2: use context and publicKey from device1 to create Encryptor and encrypt plainText to cipherText
device3: use context from device1 with Evaluator to process with cipherText
device4: use context and secretKey from device1 with Decrypter cipherText to plainText
ps. all device use own SEAL ==> [from require ('node-seal')]

Comparing two chipertext in CKKS

Hello,

I am using CKKS and I would like to compare two chipertext to see if the first one is greater than a certain threshold.
I have integer values as a message.

For example, I have Enc(832) and I would check if it is greater than Enc(850).

How could I accomplish this?

Thank you.

using smaller key sizes and adjusting the calculation

hey so I am very close to something that now works fully which I'm really pleased with. To be honest, most of the work has been converting 2D arrays to 1D arrays.
The one last thing I'm experiencing is:

    console.log("kernels length", kernels.length)
    for (let i = 0, l = arraysToSend.length; i < l; i++) {
      const image3232Chunk = seal.CipherText()
      image3232Chunk.load(context, arraysToSend[i]) //load the current image chunk
      const encryptedFillArray = seal.CipherText()
      encryptedFillArray.load(context, savedFillArray) //encrypted load of zeros to store the result
      for (let j = 0, end = kernels.length; j < end; j++) {
          const tmp = evaluator.multiplyPlain(image3232Chunk, kernels[j])
          evaluator.add(encryptedFillArray, tmp, encryptedFillArray)
      }
      const send = encryptedFillArray.save()
      convEncArray.push(send)
    }

In this case the first line prints: kernels length 114
If I use

const heConfig = {
    keySize: 4096,
    bitSize: 20
}

then I get the correct value after I decrypt. However 2048 or 1024 gives me garbage out. My thinking is my multiplyPlain and add are resulting in too much entropy in the data and its causing garbage when I decrypt. My initial thinking is I am applying too many calculations to the encryptedFillArray (my final resulting array for each iteration) and its becoming a load of mess when the keySize is too small - I think tmp will not be the problem here.
What options do I have to allow myself to use smaller key sizes?
my first guess is relinearize but I think the galois keys are very big and I'd rather not send one over the wire, so then I thought could I create an array of encryptFillArray[...]s and then add them back together afterwards or something, rather than apply the maths on the same one again and again?

The reason I want to use smaller key sizes is because I want to send the base64 exported cipher texts (.save()) over HTTP and smaller key sizes means smaller amounts of data to send.

also...

UJNRELATED:
Final and unrelated question, I'm actually trying to calculate the average - I need to end up with the multiplication of each value, then sum them and divide by the number of values in kernels[x], but I am not sure how to do that in a 1D array - i.e choosing the correct elements (only a subset of the values in the cipherText array) and secondly I am not sure if I can do division at all (even multiply by inverse....?) so that I end up with 1 value rather than kernels[j].length values (i'm doing gaussian blur on the data which is an average. I may have to do this part after decryption I suspect...?

Thanks!

Seal header is invalid

I have been using the library to build an application and everything seemed to be working fine, until I encountered an error as Error:loaded SEALHeader is invalid. Are any recent changes commited to the library causing this?
Getting the above error when I am doing the following
cipherText.load(context,encryptedSum) cipherText is an instance of Morfix.CipherText()

Usage question: how to check if an operation result is negative or positive?

I'm wondering about the typical example of taking someone's salary, and checking if it's below a certain amount. This should be quite easy doing r = salary - threshold, where if r < 0, it doesn't meet the threshold, but how do I express this? I can construct the necessary machinery no problem for everything but the comparison.

Key.load() with key generate by an api

Hello,
I try to use the Microsoft Seal librairie and your librairie to build an application.
In my situtation, the api generate the key and the front need to load the public key to send the ciphertext to the api. But when I want to load the string in the key, I have an error : "Error: ciphertext data is invalid"
My api is in C# witth the Microsoft nuget (https://www.nuget.org/packages/Microsoft.Research.SEALNet) version 3.6.4
And my front use angular with your package.

When I export the public key from the api, I use the save function and convert the UTF16 string in UTF8 string (I read that could be a source of issue) :

                // Transform public Key in a UTF16 string
                MemoryStream stream = new MemoryStream();
                publicKey.Save(stream, ComprModeType.ZSTD);
                stream.Seek(0, SeekOrigin.Begin);
                string utf16String = Convert.ToBase64String(stream.ToArray());
                // Get UTF16 bytes and convert UTF16 bytes to UTF8 bytes
                byte[] utf16Bytes = Encoding.Unicode.GetBytes(utf16String);
                byte[] utf8Bytes = Encoding.Convert(Encoding.Unicode, Encoding.UTF8, utf16Bytes);
                // Fill UTF8 bytes inside UTF8 string
                for (int i = 0; i < utf8Bytes.Length; i++)
                {
                    // Because char always saves 2 bytes, fill char with 0
                    byte[] utf8Container = new byte[2] { utf8Bytes[i], 0 };
                    result += BitConverter.ToChar(utf8Container, 0);
                } 

Next I imagine build the context with the same parameter :

      const securityLevel = seal.SecurityLevel.tc128
      const bitSizes = [36, 36, 37]
      const bitSize = 20
      const schemeType = seal.SchemeType.bfv;
      const parms = seal.EncryptionParameters(schemeType)
      // Set the PolyModulusDegree
      parms.setPolyModulusDegree(polyModulusDegree)
      // Create a suitable set of CoeffModulus primes
      parms.setCoeffModulus(
        seal.CoeffModulus.Create(polyModulusDegree, Int32Array.from(bitSizes))
      )
      // Set the PlainModulus to a prime of bitSize 20.
      parms.setPlainModulus(
        seal.PlainModulus.Batching(polyModulusDegree, bitSize)
      )
      const context = seal.Context(
        parms, // Encryption Parameters
        true, // ExpandModChain
        securityLevel // Enforce a security level
      )

And when it's the time to load the key with this :

     var publicKey: PublicKey = seal.PublicKey()
     publicKey.load( context, publicKeystring)
     "Error: ciphertext data is invalid"

I read you are supporting Microsoft Seal 3.6.4, so I would like some advises to understand what is the problem.

How to export ciphertext and apply addition outside node-seal

Hi guys, I need some help.

I'm using this repository to perform great BVF operations, it's amazing!

When I use the entire lib to perform all operations works fine, but is possible to perform addition operations outside the lib? How can I export 2 ciphertexts in a way that I can perform a external addition (I should execute this into another programming language and restricted hardware)?

My SEAL config:

const schemeType = seal.SchemeType.bfv
const polyModulusDegree = 4096
const bitSize = 20

let parms = seal.EncryptionParameters(schemeType)
parms.setPolyModulusDegree(polyModulusDegree)
parms.setCoeffModulus(seal.CoeffModulus.BFVDefault(polyModulusDegree));
parms.setPlainModulus(seal.PlainModulus.Batching(polyModulusDegree, bitSize));

The result of ciphertext.saveArray():

Uint8Array(88518) [
   94, 161,  16,   4,   1,   2,   0,   0, 198,  89,   1,  0,
    0,   0,   0,   0,  40, 181,  47, 253, 160,  97,   0,  2,
    0, 156, 202,  10, 204, 150,  13,  52, 119, 156, 167, 65,
   60, 254,  25,   4,  42,   4,  70,  70,  88, 164, 155, 79,
  189, 172, 170, 221, 139,  98,  47,  74, 154, 185, 225, 42,
  183, 135,   2,   0,   2,   0,  16,   0, 240,  63,   1,  0,
   94, 161,  16,   4,  24,  64, 181,  55,  39,  69,   8,  0,
    0,   0,  24,  50, 145,  30,  11,   0,   0,   0, 121, 37,
  162,   6,  13,   0,
  ... 88418 more items
]

Sorry if this is a primary question, I'm not a cipher expert

Thanks!

[React Native] ReferenceError: Can't find variable: WebAssembly

After I've created fresh project with
npx react-native init project-name --template react-native-template-typescript
and installing react-native-get-random-values + adding
global.document = {}
into the code, I'm constantly getting this error: Possible Unhandled Promise Rejection (id: 0):
ReferenceError: Can't find variable: WebAssembly

I'm currently developing on Windows; I've tried to install react-native-wasm, which doesnt work also (complains about not finding react-native-wasm/src/index.js, which exists)

package.json:

{
  "name": "project-name",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
  },
  "dependencies": {
    "node-seal": "^4.5.5",
    "react": "17.0.1",
    "react-native": "0.64.0",
    "react-native-get-random-values": "^1.7.0",
    "react-native-wasm": "^0.1.3"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/runtime": "^7.12.5",
    "@react-native-community/eslint-config": "^2.0.0",
    "@types/jest": "^26.0.20",
    "@types/react-native": "^0.64.0",
    "@types/react-test-renderer": "^16.9.2",
    "babel-jest": "^26.6.3",
    "eslint": "^7.14.0",
    "jest": "^26.6.3",
    "metro-react-native-babel-preset": "^0.64.0",
    "react-test-renderer": "17.0.1",
    "typescript": "^3.8.3"
  },
  "resolutions": {
    "@types/react": "^17"
  },
  "jest": {
    "preset": "react-native",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js",
      "jsx",
      "json",
      "node"
    ]
  }
}

Maybe Windows is the main issue, but I'm not sure.
How to fix this? Any ideas?

UPD: also there is a warning no native wasm support detected that appears before promise gets rejected

CipherText.save() generating different values

When trying to run add two numbers twice with same public key and private key, I am getting different strings when computing cipherText.saev() as shown below.

evaluator.add(cipherText, cipherText1, cipherText)
console.log('cipherText----->',cipherText.save())

CKKS code from documentation doesn't run successfully

Hi,

I found your blogs and decided to give your code a go. Pretty cool stuff. Got BFV working, and I wanted to have a go at CKSS.

One issue, I'm not sure you are aware of, or whether it was intentional within the sandbox, is if you just press all the create buttons (which my guess was that would create a successful default setup, fails with an error of Encrypted1 is not valid for encryption parameters - maybe this is not a bug but from the blogs it seems that it should work as a default setup and as it doesn't makes it quite tricky as the generated code examples don't then work.... Anyway....

Using the documentation, I put together the following for CKKS

(async () => {
    const SEAL = require('node-seal')
    const seal = await SEAL()

    const schemeType = seal.SchemeType.ckks
    // const schemeType = seal.SchemeType.bfv
    const securityLevel = seal.SecurityLevel.tc128
    const polyModulusDegree = 4096
    // const bitSizes = [36, 36, 37]
    const bitSizes = [46,16,46]
    const bitSize = 20

    const encParms = seal.EncryptionParameters(schemeType)

// Set the PolyModulusDegree
    encParms.setPolyModulusDegree(polyModulusDegree)

// Create a suitable set of CoeffModulus primes
    encParms.setCoeffModulus(
        seal.CoeffModulus.Create(polyModulusDegree, Int32Array.from(bitSizes))
    )

// Create a new Context
    const context = seal.Context(
        encParms, // Encryption Parameters
        true, // ExpandModChain
        securityLevel // Enforce a security level
    )

    if (!context.parametersSet()) {
        throw new Error(
            'Could not set the parameters in the given context. Please try different encryption parameters.'
        )
    }

// Create a new KeyGenerator (creates a new keypair internally)
    const keyGenerator = seal.KeyGenerator(context)

    const secretKey = keyGenerator.secretKey()
    const publicKey = keyGenerator.createPublicKey()
    const relinKey = keyGenerator.createRelinKeys()
// Generating Galois keys takes a while compared to the others
    const galoisKey = keyGenerator.createGaloisKeys()

    // Creating PlainText(s)
    const plainA = seal.PlainText()
    const plainB = seal.PlainText()

// Creating CipherText(s)
    const cipherA = seal.CipherText()
    const cipherB = seal.CipherText()

// Create an Evaluator which will allow HE functions to execute
    const evaluator = seal.Evaluator(context)

// Or a CKKSEncoder (only CKKS SchemeType)
    const encoder = seal.CKKSEncoder(context)

// Create an Encryptor to encrypt PlainTexts
    const encryptor = seal.Encryptor(context, publicKey)

// Create a Decryptor to decrypt CipherTexts
    const decryptor = seal.Decryptor(context, secretKey)

    const plainTextA = encoder.encode(Float64Array.from([1.0, 2.0, 3.0]),1.0) //what is the scale factor here?

    const result = encoder.decode(plainTextA) //why is plainTextA void here?
    console.log('test result', result)

    // Encrypt a PlainText
    const cipherTextA = encryptor.encrypt(plainTextA)

// Add CipherText B to CipherText A and store the sum in a destination CipherText
    const cipherTextD = seal.CipherText()

    evaluator.add(cipherTextA, cipherTextA, cipherTextD)

    // Decrypt a CipherText
    const plainTextD = decryptor.decrypt(cipherTextD)

    const decoded = encoder.decode(
        plainTextD,
        true // Can be omitted since this defaults to true.
    )
    console.log("len decoded", decoded.length)
    console.log('decoded', decoded)
})()

This almost wrks, however I think I am doing something wrong at the line const plainTextA = encoder.encode...... but i am struggling to work out what. It maybe that I am setting the scale on the encoding incorrectly, I saw in the docs you have Math.pow(2, 20) so perhaps I have completely missed what its for, but I have not managed to get the above to add the cipher to itself, which worked fine with BFV.

For context, I am trying to create a calculation that I can visually see it takes a long time compared to the decrypted similar calculation and then check the match. My thinking is lots of multiplications - but I am wondering if the batchEncoder will actually make it too efficient to see visually a slow down when encrypting and then doing the maths?

I am aware that CKKS is an approximation so not sure if i will actually be able to compare the results of the plain and cipher'd calculations, but perhaps with some rounding I will be able to.

Anyway, thanks for this project, very cool!

RangeError: WebAssemblyMemory()

When I am trying to test the load on my application which hits the service number of times, I get the following error
RangeError: WebAssemblyMemory(): could not allocate memory.
Is there any way I can fix this memory allocation ?

Can't encode integer

Here is my code:

(async () => {
    // ES6 or CommonJS
    // import { Seal } from 'node-seal'
    // const { Seal } = require('node-seal')
  
    // Using CommonJS for RunKit
    const { Seal } = require('node-seal')
  
    const Morfix = await Seal
  
    const parms = Morfix.EncryptionParameters({
      schemeType: Morfix.SchemeType.BFV
    })
  
    parms.setPolyModulusDegree({
      polyModulusDegree: 8192
    })
  
    // Create a suitable vector of CoeffModulus primes
    parms.setCoeffModulus({
      coeffModulus: Morfix.CoeffModulus.Create({
        polyModulusDegree: 8192,
        bitSizes: Morfix.Vector({array: new Int32Array([36,36,37]) }),
        //securityLevel: Morfix.SecurityLevel.tc128
      })
    })
  

    // Set the PlainModulus to a prime of bitSize 20.
    parms.setPlainModulus({
      plainModulus: Morfix.PlainModulus.Batching({
        polyModulusDegree: 8192,
        bitSize: 20
      })
    })
  
    const context = Morfix.Context({
      encryptionParams: parms,
      expandModChain: true,
      securityLevel: Morfix.SecurityLevel.tc128
    })
  
    if (!context.parametersSet) {
      throw new Error('Could not set the parameters in the given context. Please try different encryption parameters.')
    }
  
    const encoder = Morfix.IntegerEncoder({context})
  
    const keyGenerator = Morfix.KeyGenerator({
      context: context
    })
  
    const publicKey = keyGenerator.getPublicKey()
    const secretKey = keyGenerator.getSecretKey()
    const encryptor = Morfix.Encryptor({
      context: context,
      publicKey: publicKey
    })
    const decryptor = Morfix.Decryptor({
      context: context,
      secretKey: secretKey
    })
  

    // Create a plainText variable and encode the vector to it
    const plainText = Morfix.PlainText()
    encoder.encodeInt32({value: 6, destination: plainText})
  })()

The error message is

'function IntegerEncoder.encodeInt32 called with 2 arguments, expected 1 args!'

Not quite sure how to encode an integer. I didn't find any instructions to encode and decode integer, so I followed the API doc and gave it 1 argument.

Saving context when creating multiple private keys.

Hello, I'm not sure if this is the right place to ask this but I've been using your package for a small university project where i'm generating individual private keys for new users who are joining our system. For some unknown reason i'm generating the same private key but the public key does vary. Is there something that i'm missing? Would really appreciate your help. Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.