# homomorphic encryption DGHV implementation in Rust. ## tests and build ### tests ```bash cargo test ``` ### build ```bash cargo build --release ``` ## commands The binary is `target/release/dghv` (or `cargo run --release -- `). Run `dghv --help` or `dghv --help` for the full option list. | command | description | |--------------------|----------------------------------------------------| | `keygen` | generate a secret key `p` (a random prime) | | `keygen-pair` | generate a key pair (`.privkey` + `.pubkey` files) | | `encrypt` | encrypt a single bit | | `decrypt` | decrypt a single bit | | `bootstrap-keygen` | generate a bootstrap key (`.bskey`) from a key pair| | `bootstrap` | refresh a ciphertext (same bit, fresh noise) | All keys and ciphertexts are hex-encoded. Messages are single bits (`0` or `1`). ### `keygen` Generates a secret key `p`, a random `size`-bit prime (found with the Fermat primality test), and prints it in hex. ```bash dghv keygen [-s ] ``` | option | default | description | |--------------------|---------|--------------------------------------| | `-s`, `--size` | `6400` | bit length of `p` (security parameter η) | ```bash $ dghv keygen -s 256 Secret key (p): 91aa598acb05314a2618fdd261b5f8fb0ca8fa03a560f2786bd3cb3b94397595 ``` > Prime generation is slow for large sizes: the default 6400 bits takes about 30 s. ### `keygen-pair` Generates a private/public key pair and writes it to `.privkey` and `.pubkey`. ```bash dghv keygen-pair -o [-s ] [-n ] [-t ] ``` | option | default | description | |-------------------|---------|----------------------------------------------------------| | `-o`, `--path` | required| output path prefix for the key files | | `-s`, `--size` | `6400` | bit length of the secret prime `p` (η) | | `-n`, `--noise` | `80` | noise parameter ρ (bit length of the noise) | | `-t`, `--theta` | `10` | number of public key elements (at least 2) | ```bash $ dghv keygen-pair -o alice -s 1024 -n 16 -t 10 keys written to alice.[privkey|pubkey] ``` File formats: - `.privkey`: the secret prime `p`, one hex line. - `.pubkey`: one hex line per public element `x_i`, largest first (`x_0`, which is an exact multiple of `p`, comes first). ### `encrypt` Encrypts one bit. Exactly one key source is required. ```bash dghv encrypt -b (--pubkey | --privkey | -k ) [-n ] [-o ] ``` | option | default | description | |--------------------|---------|---------------------------------------------------------------------| | `-b`, `--bit` | required| bit to encrypt (`0` or `1`) | | `--pubkey` | | public key file: asymmetric encryption | | `--privkey` | | private key file: symmetric encryption | | `-k`, `--key` | | secret key `p` as a hex string: symmetric encryption | | `-n`, `--noise` | `80` | noise parameter ρ | | `-o`, `--output` | stdout | write the hex ciphertext to a file instead of printing it | Use the same `--noise` value as the one used in `keygen-pair`. It must be small enough compared to the key size (the noise has to stay well below `p`). ```bash # asymmetric: only the public key is needed dghv encrypt -b 1 --pubkey alice.pubkey -n 16 -o ct.hex # symmetric: with the private key file, or with the key given directly as hex dghv encrypt -b 1 --privkey alice.privkey -n 16 dghv encrypt -b 0 -k "$(cat alice.privkey)" -n 16 ``` Without `-o`, the ciphertext is printed as `Encrypted bit (hex): `. ### `decrypt` Decrypts a ciphertext with the secret key. One ciphertext source and one key source are required. ```bash dghv decrypt (-c | -f ) (--privkey | -k ) ``` | option | description | |------------------------|------------------------------------------| | `-c`, `--ciphertext` | ciphertext as a hex string | | `-f`, `--file` | file containing the hex ciphertext | | `--privkey` | private key file | | `-k`, `--key` | secret key `p` as a hex string | ```bash $ dghv decrypt -f ct.hex --privkey alice.privkey Decrypted bit: 1 ``` ### `bootstrap-keygen` Generates the bootstrap key needed to refresh ciphertexts, and writes it to `.bskey`. It needs **both** keys of the pair: it hides the secret key `p` as a sparse subset sum (`weight` selected elements out of `hint-size`) and encrypts the selector bits under the public key. ```bash dghv bootstrap-keygen --pubkey --privkey -o [-n ] [-w ] [-m ] [--kappa ] ``` | option | default | description | |----------------------|--------------------|---------------------------------------------------------------| | `--pubkey` | required | public key file | | `--privkey` | required | private key file | | `-o`, `--path` | required | output path prefix (writes `.bskey`) | | `-n`, `--noise` | `80` | noise parameter ρ, use the one given to `keygen-pair` | | `-w`, `--weight` | `5` | Hamming weight θ of the secret subset | | `-m`, `--hint-size` | `20` | number of hint elements (at least `weight`) | | `--kappa` | bitlen(x₀) + 8 | precision of the hint (at least bitlen(x₀) + 4) | ```bash $ dghv bootstrap-keygen --pubkey alice.pubkey --privkey alice.privkey -o alice -n 16 bootstrap key written to alice.bskey (kappa=1048, weight=5, hint size=20), self-test passed ``` After generating the key, the command bootstraps a few test ciphertexts and checks that they still decrypt correctly. If they don't, nothing is written and the command fails: the noise of the bootstrapping circuit grows with `weight` and has to stay below the capacity of `p`. In that case use a larger `--size` for `keygen-pair`, or a smaller `--weight`. With the default key sizes (`-s 6400 -n 80`), weights up to 7 work; a larger `--hint-size` increases the cost, not the noise. `.bskey` is a text file: a first line `kappa weight hint-size`, then one `u_i enc_s_i` line (both hex) per hint element. It contains no secret in clear: the secret subset is only present as ciphertexts. ### `bootstrap` Refreshes a ciphertext: the output encrypts the same bit, but its noise no longer depends on the noise accumulated by the input. It only uses the public key and the bootstrap key, so it can be run by anyone. ```bash dghv bootstrap (-c | -f ) --pubkey --bskey [-o ] ``` | option | default | description | |------------------------|---------|---------------------------------------------------------| | `-c`, `--ciphertext` | | ciphertext as a hex string | | `-f`, `--file` | | file containing the hex ciphertext | | `--pubkey` | required| public key file | | `--bskey` | required| bootstrap key file (from `bootstrap-keygen`) | | `-o`, `--output` | stdout | write the new hex ciphertext to a file | ```bash dghv bootstrap -f ct.hex --pubkey alice.pubkey --bskey alice.bskey -o ct2.hex dghv decrypt -f ct2.hex --privkey alice.privkey # Decrypted bit: 1 ``` Without `-o`, the result is printed as `Bootstrapped bit (hex): `. The input must come from the same key pair as the bootstrap key, and its noise must still be below `p/4` (i.e. it must still decrypt correctly). > The command line only handles single ciphertexts, so it cannot chain homomorphic additions and multiplications. Use the library (`src/dghv.rs`, `src/dghv_asym.rs`, `src/bootstrapping.rs`) for that; `cargo test bootstrapping` has examples of multiplying ciphertexts and bootstrapping in between. ### full example ```bash # 1. generate a key pair (small parameters, fast) dghv keygen-pair -o alice -s 1024 -n 16 -t 10 # 2. anyone with the public key can encrypt dghv encrypt -b 1 --pubkey alice.pubkey -n 16 -o ct.hex # 3. only the owner of the private key can decrypt dghv decrypt -f ct.hex --privkey alice.privkey # Decrypted bit: 1 # 4. optionally, generate a bootstrap key (needs both keys) ... dghv bootstrap-keygen --pubkey alice.pubkey --privkey alice.privkey -o alice -n 16 # 5. ... then anyone can refresh a ciphertext with the public material only dghv bootstrap -f ct.hex --pubkey alice.pubkey --bskey alice.bskey -o ct2.hex dghv decrypt -f ct2.hex --privkey alice.privkey # Decrypted bit: 1 ```