9.3 KiB
homomorphic encryption
DGHV implementation in Rust.
tests and build
tests
cargo test
build
cargo build --release
commands
The binary is target/release/dghv (or cargo run --release -- <command>). Run dghv --help or dghv <command> --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.
dghv keygen [-s <SIZE>]
| option | default | description |
|---|---|---|
-s, --size |
6400 |
bit length of p (security parameter η) |
$ 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 <path>.privkey and <path>.pubkey.
dghv keygen-pair -o <PATH> [-s <SIZE>] [-n <NOISE>] [-t <THETA>]
| 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) |
$ dghv keygen-pair -o alice -s 1024 -n 16 -t 10
keys written to alice.[privkey|pubkey]
File formats:
<path>.privkey: the secret primep, one hex line.<path>.pubkey: one hex line per public elementx_i, largest first (x_0, which is an exact multiple ofp, comes first).
encrypt
Encrypts one bit. Exactly one key source is required.
dghv encrypt -b <BIT> (--pubkey <FILE> | --privkey <FILE> | -k <HEX>) [-n <NOISE>] [-o <FILE>]
| 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).
# 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): <ciphertext>.
decrypt
Decrypts a ciphertext with the secret key. One ciphertext source and one key source are required.
dghv decrypt (-c <HEX> | -f <FILE>) (--privkey <FILE> | -k <HEX>)
| 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 |
$ 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 <path>.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.
dghv bootstrap-keygen --pubkey <FILE> --privkey <FILE> -o <PATH> [-n <NOISE>] [-w <WEIGHT>] [-m <HINT_SIZE>] [--kappa <KAPPA>]
| option | default | description |
|---|---|---|
--pubkey |
required | public key file |
--privkey |
required | private key file |
-o, --path |
required | output path prefix (writes <path>.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) |
$ 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.
<path>.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.
dghv bootstrap (-c <HEX> | -f <FILE>) --pubkey <FILE> --bskey <FILE> [-o <FILE>]
| 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 |
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): <ciphertext>. 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 bootstrappinghas examples of multiplying ciphertexts and bootstrapping in between.
full example
# 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