Advertisement
Guest User

paillier-bigint vs node-seal

a guest
Apr 6th, 2020
510
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const paillier = require('paillier-bigint')
  2. const { Seal } = require('node-seal')
  3. const { performance } = require('perf_hooks')
  4.  
  5. ;(async function () {
  6.   const benchmark = create()
  7.   await benchmark.performanceTest()
  8. })()
  9.  
  10. function create() {
  11.   let seal = null
  12.  
  13.   function randomIntInc(low, high) {
  14.     return Math.floor(Math.random() * (high - low + 1) + low)
  15.   }
  16.  
  17.   async function performanceTest() {
  18.     // Run paillier-bigint
  19.     await paillierPerformanceTest(paillier)
  20.  
  21.     // Run  node-seal
  22.     await sealPerformanceTest(seal)
  23.   }
  24.  
  25.   async function paillierPerformanceTest(paillier) {
  26.     let timeStart = 0
  27.     let timeEnd = 0
  28.  
  29.     process.stdout.write('Generating private/public keys: ')
  30.     timeStart = performance.now()
  31.     const { privateKey, publicKey } = await paillier.generateRandomKeys(3072)
  32.     timeEnd = performance.now()
  33.     process.stdout.write(
  34.       `Done [${Math.round((timeEnd - timeStart) * 1000)} microseconds]\r\n`
  35.     )
  36.  
  37.     let timeEncryptSum = 0
  38.     let timeDecryptSum = 0
  39.     let timeAddSum = 0
  40.     let timeMultiplyPlainSum = 0
  41.  
  42.     /*
  43.      How many times to run the test?
  44.      */
  45.     const count = 50
  46.  
  47.     /*
  48.      This number represents is the range ceiling for the values we will encrypt
  49.      */
  50.     const plainNumber = 786433
  51.  
  52.     process.stdout.write('Running tests ')
  53.     for (let i = 0; i < count; i++) {
  54.       const randomNumber = BigInt(
  55.         Math.floor(randomIntInc(0, plainNumber) % plainNumber)
  56.       )
  57.       /*
  58.        [Encryption]
  59.        */
  60.       timeStart = performance.now()
  61.       const cipher = publicKey.encrypt(randomNumber)
  62.       timeEnd = performance.now()
  63.       timeEncryptSum += timeEnd - timeStart
  64.  
  65.       /*
  66.        [Decryption]
  67.        */
  68.       timeStart = performance.now()
  69.       const plain = privateKey.decrypt(cipher)
  70.       timeEnd = performance.now()
  71.       timeDecryptSum += timeEnd - timeStart
  72.  
  73.       if (plain !== randomNumber) {
  74.         throw new Error('Decryption failed!')
  75.       }
  76.       /*
  77.        [Add]
  78.        */
  79.       timeStart = performance.now()
  80.       const sum = publicKey.addition(cipher, cipher)
  81.       timeEnd = performance.now()
  82.       timeAddSum += timeEnd - timeStart
  83.  
  84.       if (privateKey.decrypt(sum) !== randomNumber * 2n) {
  85.         throw new Error('Addition failed!')
  86.       }
  87.       /*
  88.        [Multiply Plain]
  89.        */
  90.       timeStart = performance.now()
  91.       const product = publicKey.multiply(cipher, randomNumber)
  92.       timeEnd = performance.now()
  93.       timeMultiplyPlainSum += timeEnd - timeStart
  94.       if (privateKey.decrypt(product) !== randomNumber * randomNumber) {
  95.         throw new Error('Addition failed!')
  96.       }
  97.       process.stdout.write('.')
  98.     }
  99.     process.stdout.write(' Done\r\n\r\n')
  100.  
  101.     const avgEncrypt = Math.round((timeEncryptSum * 1000) / count)
  102.     const avgDecrypt = Math.round((timeDecryptSum * 1000) / count)
  103.     const avgAdd = Math.round((timeAddSum * 1000) / count)
  104.     const avgMultiplyPlain = Math.round((timeMultiplyPlainSum * 1000) / count)
  105.  
  106.     console.log(`Average encrypt: ${avgEncrypt} microseconds`)
  107.     console.log(`Average decrypt: ${avgDecrypt} microseconds`)
  108.     console.log(`Average add: ${avgAdd} microseconds`)
  109.     console.log(`Average multiply plain: ${avgMultiplyPlain} microseconds`)
  110.     console.log('')
  111.   }
  112.   async function sealPerformanceTest() {
  113.     const seal = await Seal()
  114.     const parms = seal.EncryptionParameters(seal.SchemeType.BFV)
  115.     let polyModulusDegree = 4096
  116.     let smallModulus = seal.SmallModulus('786433')
  117.     let coeffModulus = seal.CoeffModulus.BFVDefault(polyModulusDegree)
  118.     parms.setPolyModulusDegree(polyModulusDegree)
  119.     parms.setCoeffModulus(coeffModulus)
  120.     parms.setPlainModulus(smallModulus)
  121.     let context = seal.Context(parms)
  122.  
  123.     let timeStart = 0
  124.     let timeEnd = 0
  125.  
  126.     console.log(context.toHuman())
  127.  
  128.     const plainModulus = parms.plainModulus
  129.  
  130.     process.stdout.write('Generating secret/public keys: ')
  131.     timeStart = performance.now()
  132.     const keyGenerator = seal.KeyGenerator(context)
  133.     timeEnd = performance.now()
  134.     process.stdout.write(
  135.       `Done [${Math.round((timeEnd - timeStart) * 1000)} microseconds]\r\n`
  136.     )
  137.     const secretKey = keyGenerator.getSecretKey()
  138.     const publicKey = keyGenerator.getPublicKey()
  139.  
  140.     const encryptor = seal.Encryptor(context, publicKey)
  141.     const decryptor = seal.Decryptor(context, secretKey)
  142.     const evaluator = seal.Evaluator(context)
  143.     const batchEncoder = seal.BatchEncoder(context)
  144.  
  145.     /*
  146.      These will hold the total times used by each operation.
  147.      */
  148.     let timeBatchSum = 0
  149.     let timeUnbatchSum = 0
  150.     let timeEncryptSum = 0
  151.     let timeDecryptSum = 0
  152.     let timeAddSum = 0
  153.     let timeMultiplySum = 0
  154.     let timeMultiplyPlainSum = 0
  155.  
  156.     /*
  157.      How many times to run the test?
  158.      */
  159.     const count = 50
  160.  
  161.     /*
  162.      Populate a vector of values to batch.
  163.      */
  164.     const slotCount = batchEncoder.slotCount
  165.     const array = new Uint32Array(slotCount)
  166.     const plainNumber = Number(plainModulus.value)
  167.     for (let i = 0; i < slotCount; i++) {
  168.       array[i] = Math.floor(randomIntInc(0, plainNumber) % plainNumber)
  169.     }
  170.  
  171.     process.stdout.write('Running tests ')
  172.     for (let i = 0; i < count; i++) {
  173.       /*
  174.        [Batching]
  175.        There is nothing unusual here. We batch our random plaintext matrix
  176.        into the polynomial. Note how the plaintext we create is of the exactly
  177.        right size so unnecessary reallocations are avoided.
  178.        */
  179.       const plain = seal.PlainText({
  180.         capacity: parms.polyModulusDegree,
  181.         coeffCount: 0
  182.       })
  183.       plain.reserve(polyModulusDegree)
  184.       timeStart = performance.now()
  185.       batchEncoder.encode(array, plain)
  186.       timeEnd = performance.now()
  187.       timeBatchSum += timeEnd - timeStart
  188.  
  189.       /*
  190.        [Unbatching]
  191.        We unbatch what we just batched.
  192.        */
  193.       timeStart = performance.now()
  194.       const unbatched = batchEncoder.decode(plain, false)
  195.       timeEnd = performance.now()
  196.       timeUnbatchSum += timeEnd - timeStart
  197.       if (JSON.stringify(unbatched) !== JSON.stringify(array)) {
  198.         throw new Error('Batch/unbatch failed. Something is wrong.')
  199.       }
  200.  
  201.       /*
  202.        [Encryption]
  203.        We make sure our ciphertext is already allocated and large enough
  204.        to hold the encryption with these encryption parameters. We encrypt
  205.        our random batched matrix here.
  206.        */
  207.       const encrypted = seal.CipherText({ context })
  208.       timeStart = performance.now()
  209.       encryptor.encrypt(plain, encrypted)
  210.       timeEnd = performance.now()
  211.       timeEncryptSum += timeEnd - timeStart
  212.  
  213.       /*
  214.        [Decryption]
  215.        We decrypt what we just encrypted.
  216.        */
  217.       const plain2 = seal.PlainText({
  218.         capacity: parms.polyModulusDegree,
  219.         coeffCount: 0
  220.       })
  221.       plain2.reserve(polyModulusDegree)
  222.       timeStart = performance.now()
  223.       decryptor.decrypt(encrypted, plain2)
  224.       timeEnd = performance.now()
  225.       timeDecryptSum += timeEnd - timeStart
  226.       if (plain2.toPolynomial() !== plain.toPolynomial()) {
  227.         throw new Error('Encrypt/decrypt failed. Something is wrong.')
  228.       }
  229.       /*
  230.        [Add]
  231.        We create two ciphertexts and perform a few additions with them.
  232.        */
  233.       const encrypted1 = seal.CipherText({ context })
  234.       const encrypted2 = seal.CipherText({ context })
  235.       const plain3 = batchEncoder.encode(Int32Array.from([i]))
  236.       const plain4 = batchEncoder.encode(Int32Array.from([i + 1]))
  237.       encryptor.encrypt(plain3, encrypted1)
  238.       encryptor.encrypt(plain4, encrypted2)
  239.       timeStart = performance.now()
  240.       evaluator.add(encrypted1, encrypted1, encrypted1)
  241.       evaluator.add(encrypted2, encrypted2, encrypted2)
  242.       evaluator.add(encrypted1, encrypted2, encrypted1)
  243.       timeEnd = performance.now()
  244.       timeAddSum += timeEnd - timeStart
  245.  
  246.       /*
  247.        [Multiply]
  248.        We multiply two ciphertexts. Since the size of the result will be 3,
  249.        and will overwrite the first argument, we reserve first enough memory
  250.        to avoid reallocating during multiplication.
  251.        */
  252.       encrypted1.reserve(context, 3)
  253.       timeStart = performance.now()
  254.       evaluator.multiply(encrypted1, encrypted2, encrypted1)
  255.       timeEnd = performance.now()
  256.       timeMultiplySum += timeEnd - timeStart
  257.  
  258.       /*
  259.        [Multiply Plain]
  260.        We multiply a ciphertext with a random plaintext. Recall that
  261.        multiplyPlain does not change the size of the ciphertext so we use
  262.        encrypted2 here.
  263.        */
  264.       timeStart = performance.now()
  265.       evaluator.multiplyPlain(encrypted2, plain, encrypted2)
  266.       timeEnd = performance.now()
  267.       timeMultiplyPlainSum += timeEnd - timeStart
  268.  
  269.       // Cleanup
  270.       plain.delete()
  271.       plain2.delete()
  272.       plain3.delete()
  273.       plain4.delete()
  274.       encrypted.delete()
  275.       encrypted1.delete()
  276.       encrypted2.delete()
  277.  
  278.       process.stdout.write('.')
  279.     }
  280.     process.stdout.write(' Done\r\n\r\n')
  281.  
  282.     const avgBatch = Math.round((timeBatchSum * 1000) / count)
  283.     const avgUnbatch = Math.round((timeUnbatchSum * 1000) / count)
  284.     const avgEncrypt = Math.round((timeEncryptSum * 1000) / count)
  285.     const avgDecrypt = Math.round((timeDecryptSum * 1000) / count)
  286.     const avgAdd = Math.round((timeAddSum * 1000) / (3 * count))
  287.     const avgMultiply = Math.round((timeMultiplySum * 1000) / count)
  288.     const avgMultiplyPlain = Math.round((timeMultiplyPlainSum * 1000) / count)
  289.  
  290.     console.log(`Average batch: ${avgBatch} microseconds`)
  291.     console.log(`Average unbatch: ${avgUnbatch} microseconds`)
  292.     console.log(`Average encrypt: ${avgEncrypt} microseconds`)
  293.     console.log(`Average decrypt: ${avgDecrypt} microseconds`)
  294.     console.log(`Average add: ${avgAdd} microseconds`)
  295.     console.log(`Average multiply: ${avgMultiply} microseconds`)
  296.     console.log(`Average multiply plain: ${avgMultiplyPlain} microseconds`)
  297.     console.log('')
  298.  
  299.     // Cleanup
  300.     parms.delete()
  301.     plainModulus.delete()
  302.     context.delete()
  303.     keyGenerator.delete()
  304.     secretKey.delete()
  305.     publicKey.delete()
  306.     evaluator.delete()
  307.     batchEncoder.delete()
  308.     encryptor.delete()
  309.     decryptor.delete()
  310.   }
  311.  
  312.   return {
  313.     performanceTest
  314.   }
  315. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement