Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
F
fhew-rs
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Sai Tarun Inaganti
fhew-rs
Commits
34bf4f87
Commit
34bf4f87
authored
Nov 23, 2020
by
Sai Tarun Inaganti
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
No commit message
No commit message
parent
dc9c56c1
Changes
5
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
557 additions
and
302 deletions
+557
-302
Cargo.toml
Cargo.toml
+2
-1
src/bin/test.rs
src/bin/test.rs
+60
-35
src/fhew.rs
src/fhew.rs
+336
-151
src/lib.rs
src/lib.rs
+60
-41
src/lwe.rs
src/lwe.rs
+99
-74
No files found.
Cargo.toml
View file @
34bf4f87
...
...
@@ -7,7 +7,8 @@ edition = "2018"
[dependencies]
fftw
=
{
version
=
"*"
}
ndarray
=
{
version
=
"*"
}
ndarray
=
{
version
=
"*"
,
features
=
["rayon"]
}
num
=
{
version
=
"*"
}
rand
=
{
version
=
"*"
}
rayon
=
{
version
=
"*"
}
strum
=
{
version
=
"*"
}
\ No newline at end of file
src/bin/test.rs
View file @
34bf4f87
use
std
::
fs
::
File
;
use
std
::
process
::
exit
;
use
fftw
::
types
::
*
;
//
use fftw::types::*;
use
::
fhew
::{
*
,
BinGate
::
*
,
...
...
@@ -9,8 +10,8 @@ use ::fhew::{
use
rand
::
Rng
;
fn
help
(
cmd
:
&
String
)
{
eprintln!
(
"
\n
usage: {}
n
\n
"
,
cmd
);
eprintln!
(
" Generate a secret key sk and evaluation key ek, and repeat the following test
n
times:"
);
eprintln!
(
"
\n
usage: {}
<count>
\n
"
,
cmd
);
eprintln!
(
" Generate a secret key sk and evaluation key ek, and repeat the following test
<count>
times:"
);
eprintln!
(
" - generate random bits b1,b2,b3,b4"
);
eprintln!
(
" - compute ciphertexts c1, c2, c3 and c4 encrypting b1, b2, b3 and b4 under sk"
);
eprintln!
(
" - homomorphically compute the encrypted (c1 NAND c2) NAND (c3 NAND c4)"
);
...
...
@@ -28,19 +29,19 @@ fn cleartext_gate(v1: bool, v2: bool, gate: BinGate) -> bool {
}
fn
eprint_gate
(
gate
:
BinGate
)
{
match
gate
{
OR
=>
eprint!
(
"
OR
\t
"
),
AND
=>
eprint!
(
"
AND
\t
"
),
NOR
=>
eprint!
(
"
NOT
\t
"
),
NAND
=>
eprint!
(
"
NAND
\t
"
)
OR
=>
eprint!
(
"
OR
"
),
AND
=>
eprint!
(
"
AND
"
),
NOR
=>
eprint!
(
"
NOR
"
),
NAND
=>
eprint!
(
"
NAND
"
)
}
}
fn
main
()
{
// assert_eq!(q, 512);
let
mut
rng
=
rand
::
thread_rng
();
//
let mut rng = rand::thread_rng();
let
mut
ffto
:
FFT
=
Default
::
default
();
// fftSetup(&mut ffto);
let
mut
t
TestMSB
:
RingFFT
=
Default
::
default
();
let
mut
t
_test_msb
:
RingFFT
=
RingFFT
();
let
args
:
Vec
<
String
>
=
std
::
env
::
args
()
.collect
();
if
args
.len
()
!=
2
{
...
...
@@ -48,14 +49,19 @@ fn main() {
}
let
count
:
i32
=
args
[
1
]
.parse
()
.unwrap
();
eprintln!
(
"Setting up FHEW"
);
fhew
::
setup
(
&
mut
ffto
,
&
mut
t
TestMSB
);
fhew
::
setup
(
&
mut
ffto
,
&
mut
t
_test_msb
);
eprint!
(
"Generating secret key ... "
);
let
mut
lwe_sk
:
lwe
::
SecretKey
=
Default
::
default
();
lwe
::
keyGen
(
&
mut
lwe_sk
,
&
mut
rng
);
let
mut
lwe_sk
:
lwe
::
SecretKey
=
SecretKey
();
lwe
::
key_gen
(
&
mut
lwe_sk
);
// dbg!(&lwe_sk);
eprintln!
(
"Done.
\n
"
);
eprintln!
(
"Generating evaluation key ... this may take a while ... "
);
let
mut
ek
:
EvalKey
=
Default
::
default
();
fhew
::
keyGen
(
&
mut
ek
,
&
lwe_sk
,
&
mut
rng
,
&
mut
ffto
);
fhew
::
key_gen
(
&
mut
ek
,
&
lwe_sk
,
&
mut
ffto
);
// let mut f = File::create("key.txt").unwrap();
// fwrite_ek(&ek, &mut f);
eprintln!
(
"Done.
\n
"
);
eprintln!
(
"Testing depth-2 homomorphic circuits {} times."
,
count
);
eprintln!
(
"Circuit shape : (a GATE NOT(b)) GATE (c GATE d)
\n
"
);
...
...
@@ -65,48 +71,67 @@ fn main() {
let
(
mut
se1
,
mut
se2
,
mut
e1
,
mut
e2
,
mut
e12
):
(
CipherText
,
CipherText
,
CipherText
,
CipherText
,
CipherText
)
=
Default
::
default
();
for
i
in
1
..
(
3
*
count
)
{
if
i
%
3
!=
0
{
v1
=
rng
.gen
::
<
i32
>
()
%
2
;
v2
=
rng
.gen
::
<
i32
>
()
%
2
;
lwe
::
encrypt
(
&
mut
e1
,
&
lwe_sk
,
v1
,
&
mut
rng
);
lwe
::
encrypt
(
&
mut
e2
,
&
lwe_sk
,
v2
,
&
mut
rng
);
if
i
%
3
==
1
{
eprint!
(
" NOT
\t
Enc({}) = "
,
v2
);
for
i
in
1
..
(
3
*
count
+
1
)
{
// if i != 1 {break;}
if
i
%
3
!=
0
{
// 1,2
v1
=
(
rand
::
thread_rng
()
.gen
::
<
u32
>
()
%
2
)
as
i32
;
v2
=
(
rand
::
thread_rng
()
.gen
::
<
u32
>
()
%
2
)
as
i32
;
// v1 = 0;
// v2 = 0;
lwe
::
encrypt
(
&
mut
e1
,
&
lwe_sk
,
v1
);
lwe
::
encrypt
(
&
mut
e2
,
&
lwe_sk
,
v2
);
// for t in 0..n {
// println!("t = {}, lwe_sk[t] = {}, e1.a[t] = {}, e2.a[t] = {}", t, lwe_sk[t], e1.a[t], e2.a[t]);
// }
if
i
%
3
==
1
{
// 1
eprint!
(
"
\t
NOT
\t
Enc({}) = "
,
v2
);
let
e2_temp
=
e2
.clone
();
fhew
::
hom_not
(
&
mut
e2
,
&
e2_temp
);
let
notv2
=
lwe
::
decrypt
(
&
lwe_sk
,
&
e2
);
eprintln!
(
"Enc({})"
,
v2
);
if
!
(
notv2
==
!
v2
)
{
eprintln!
(
"Enc({})"
,
notv2
);
// dbg!(v2,notv2,!v2,!notv2);
if
!
(
notv2
!=
v2
&&
notv2
*
v2
==
0
)
{
eprintln!
(
"ERROR: incorrect NOT Homomorphic computation at iteration {}"
,
i
+
1
);
exit
(
1
);
}
v2
=
!
v2
;
v2
=
if
v2
==
0
{
1
}
else
{
0
}
;
}
}
else
{
}
else
{
// 3
v1
=
sv1
;
v2
=
sv2
;
e1
=
se1
.clone
();
e2
=
se2
.clone
();
}
let
gate
:
BinGate
=
match
rng
.gen
::
<
usize
>
()
%
4
{
// let gate: BinGate = BinGate::NAND;
let
gate
:
BinGate
=
match
rand
::
thread_rng
()
.gen
::
<
usize
>
()
%
4
{
0
=>
BinGate
::
OR
,
1
=>
BinGate
::
AND
,
2
=>
BinGate
::
NOR
,
3
=>
BinGate
::
NAND
,
_
=>
BinGate
::
OR
};
eprint!
(
"Enc({})"
,
v1
);
lwe
::
encrypt
(
&
mut
e1
,
&
lwe_sk
,
v1
);
lwe
::
encrypt
(
&
mut
e2
,
&
lwe_sk
,
v2
);
fhew
::
hom_gate
(
&
mut
e12
,
gate
,
&
ek
,
&
e1
,
&
e2
,
&
mut
ffto
,
&
t_test_msb
);
let
v12
:
i32
=
lwe
::
decrypt
(
&
lwe_sk
,
&
e12
);
eprint!
(
"Enc({})
\t
"
,
v1
);
eprint_gate
(
gate
);
eprint!
(
"Enc({}) = "
,
v2
);
eprint!
(
"
\t
Enc({}) = "
,
v2
);
fhew
::
hom_gate
(
&
mut
e12
,
gate
,
&
ek
,
&
e1
,
&
e2
,
&
mut
ffto
,
&
tTestMSB
,
&
mut
rng
);
let
v12
:
i32
=
lwe
::
decrypt
(
&
lwe_sk
,
&
e12
);
eprint!
(
"Enc({})"
,
v12
);
eprintln!
(
""
);
eprintln!
(
"Enc({})"
,
v12
);
// for j in 0..n {
// println!("i = {}, j = {}, e1.a[j] = {}, e2.a[j] = {}, e12.a[j] = {}", i, j, e1.a[j], e2.a[j], e12.a[j]);
// }
// println!("i = {}\ne1.a = {:?}\ne2.a = {:?}\ne12.a = {:?}", i, e1.a, e2.a, e12.a);
// println!("e1.b = {}, e2.b = {}, e12.b = {}", e1.b, e2.b, e12.b);
match
i
%
3
{
0
=>
eprintln!
(
""
),
1
=>
{
sv1
=
v12
;
se1
=
e12
.clone
();
...
...
@@ -114,10 +139,10 @@ fn main() {
2
=>
{
sv2
=
v12
;
se2
=
e12
.clone
();
}
_
=>
(
)
}
,
_
=>
eprintln!
(
""
)
}
// println!("i = {}, v1 = {}, v2 = {}, v12 = {}", i, v1, v2, v12);
if
cleartext_gate
(
v1
!=
0
,
v2
!=
0
,
gate
)
!=
(
v12
!=
0
)
{
eprintln!
(
"
\n
ERROR: incorrect Homomorphic Gate computation at iteration {}"
,
i
+
1
);
exit
(
1
);
...
...
src/fhew.rs
View file @
34bf4f87
This diff is collapsed.
Click to expand it.
src/lib.rs
View file @
34bf4f87
...
...
@@ -9,26 +9,26 @@ use ndarray::*;
use
rand
::
Rng
;
use
std
::
num
::
Wrapping
;
pub
const
n
:
usize
=
50
0
;
pub
const
n
:
usize
=
1
0
;
pub
const
N
:
usize
=
1024
;
pub
const
N2
:
usize
=
N
/
2
;
pub
const
N2
:
usize
=
N
/
2
+
1
;
pub
const
K
:
usize
=
3
;
pub
const
K
:
usize
=
3
;
// K
pub
const
K2
:
usize
=
6
;
pub
const
Q
:
usize
=
1
<<
32
;
pub
const
Q
:
usize
=
1
<<
32
;
// Q
pub
const
q
:
usize
=
512
;
pub
const
q2
:
usize
=
256
;
pub
const
q2
:
usize
=
q
/
2
;
type
ZmodQ
=
Wrapping
<
i32
>
;
pub
type
ZmodQ
=
Wrapping
<
i32
>
;
type
UZmodQ
=
Wrapping
<
u32
>
;
const
v
:
ZmodQ
=
Wrapping
((
1
<<
29
)
+
1
);
const
v_inverse
:
ZmodQ
=
Wrapping
(
-
536870911
);
// 3758096385;
const
V
:
ZmodQ
=
Wrapping
((
1
<<
29
)
+
1
);
const
V_INVERSE
:
ZmodQ
=
Wrapping
(
-
536870911
);
// 3758096385; 1/V mod Q
const
vgprime
:
[
ZmodQ
;
3
]
=
[
Wrapping
(
536870913
),
Wrapping
(
2048
),
Wrapping
(
4194304
)];
// [v, v<<11, v
<<22];
const
g_bits
:
[
isize
;
3
]
=
[
11
,
11
,
10
];
const
g_bits
_32
:
[
isize
;
3
]
=
[
21
,
21
,
22
];
const
VGPRIME
:
[
ZmodQ
;
3
]
=
[
Wrapping
(
V
.
0
),
Wrapping
(
V
.
0
<<
11
),
Wrapping
(
V
.
0
<<
22
)];
// [V, V<<11, V
<<22];
const
G_BITS
:
[
isize
;
3
]
=
[
11
,
11
,
10
];
const
G_BITS
_32
:
[
isize
;
3
]
=
[
21
,
21
,
22
];
pub
const
KS_BASE
:
usize
=
25
;
pub
const
KS_EXP
:
usize
=
7
;
...
...
@@ -46,22 +46,30 @@ pub const BS_BASE: usize = 23;
pub
const
BS_EXP
:
usize
=
2
;
pub
const
BS_TABLE
:
[
usize
;
2
]
=
[
1
,
23
];
#[derive(Clone)]
pub
struct
RingModQ
(
pub
Array1
<
ZmodQ
>
);
// [ZmodQ; N];
impl
Default
for
RingModQ
{
fn
default
()
->
RingModQ
{
RingModQ
(
Array
::
default
(
N
))
}
// #[derive(Clone,Debug)]
// pub struct RingModQ(pub Array1<ZmodQ>); // [ZmodQ; N];
// impl Default for RingModQ {
// fn default() -> RingModQ {
// RingModQ(Array::default(N))
// }
// }
pub
type
RingModQ
=
Array
<
ZmodQ
,
Ix1
>
;
pub
fn
RingModQ
()
->
RingModQ
{
Array
::
default
(
N
)
}
#[derive(Clone)]
pub
struct
RingFFT
(
pub
Array1
<
c64
>
);
// [c64; N2];
impl
Default
for
RingFFT
{
fn
default
()
->
RingFFT
{
RingFFT
(
Array
::
default
(
N2
))
}
// #[derive(Clone,Debug)]
// pub struct RingFFT(pub Array1<c64>); // [c64; N2];
// impl Default for RingFFT {
// fn default() -> RingFFT {
// RingFFT(Array::default(N2))
// }
// }
pub
type
RingFFT
=
Array
<
c64
,
Ix1
>
;
pub
fn
RingFFT
()
->
RingFFT
{
Array
::
default
(
N2
)
}
#[derive(Copy,Clone)]
#[derive(Copy,Clone
,Debug
)]
pub
enum
BinGate
{
OR
,
AND
,
NOR
,
NAND
}
const
GATE_CONST
:
[
usize
;
4
]
=
[
15
*
q
/
8
,
9
*
q
/
8
,
11
*
q
/
8
,
13
*
q
/
8
];
...
...
@@ -75,11 +83,11 @@ struct Distrib {
table
:
&
'static
[
f64
]
}
fn
sample
(
chi
:
&
Distrib
,
rng
:
&
mut
rand
::
rngs
::
ThreadRng
)
->
i32
{
fn
sample
(
chi
:
&
Distrib
)
->
i32
{
// dbg!(chi.std_dev);
if
chi
.max
!=
0
{
if
chi
.max
!=
0
{
// CHI1, CHI_BINARY
// println!("path 1");
let
r
:
f64
=
r
ng
.gen
();
let
r
:
f64
=
r
and
::
thread_rng
()
.gen
();
for
i
in
0
..
chi
.max
{
if
r
<=
chi
.table
[
i
as
usize
]
{
return
i
-
chi
.offset
;
...
...
@@ -89,24 +97,24 @@ fn sample(chi: &Distrib, rng: &mut rand::rngs::ThreadRng) -> i32 {
}
let
mut
r
:
f64
;
let
s
=
chi
.std_dev
;
if
s
<
500.0
{
if
s
<
500.0
{
// CHI3
// println!("path 2");
let
mut
x
:
i32
;
let
maxx
=
(
s
*
8.0
)
.ceil
()
as
i32
;
loop
{
x
=
r
ng
.gen
::
<
i32
>
()
%
(
2
*
maxx
+
1
)
-
maxx
;
r
=
r
ng
.gen
();
x
=
r
and
::
thread_rng
()
.gen
::
<
i32
>
()
%
(
2
*
maxx
+
1
)
-
maxx
;
r
=
r
and
::
thread_rng
()
.gen
();
// println!("x = {}, y = {}, z = {}", r, x, s);
if
r
<
(
-
(
x
*
x
)
as
f64
/
(
2.0
*
s
*
s
))
.exp
()
{
return
x
;
}
}
}
else
{
}
else
{
// CHI2
// println!("path 3");
let
mut
x
:
f64
;
loop
{
x
=
16.0
*
r
ng
.gen
::
<
f64
>
()
-
8.0
;
r
=
r
ng
.gen
();
x
=
16.0
*
r
and
::
thread_rng
()
.gen
::
<
f64
>
()
-
8.0
;
r
=
r
and
::
thread_rng
()
.gen
();
// println!("r = {}\tx = {}\ts = {}", r, x, s);
if
r
<
(
-
x
*
x
/
2.0
)
.exp
()
{
return
(
0.5
+
x
*
s
)
.floor
()
as
i32
;
...
...
@@ -174,30 +182,41 @@ impl Default for FFT {
in_
:
AlignedVec
::
new
(
N
*
2
),
out
:
AlignedVec
::
new
(
N
+
1
),
plan_fft_forw
:
R2CPlan64
::
aligned
(
&
[
N
*
2
],
Flag
::
PATIENT
)
.unwrap
(),
plan_fft_back
:
C2RPlan64
::
aligned
(
&
[
N
*
2
],
Flag
::
PATIENT
)
.unwrap
()
plan_fft_back
:
C2RPlan64
::
aligned
(
&
[
N
*
2
],
Flag
::
PATIENT
|
Flag
::
PRESERVEINPUT
)
.unwrap
()
}
}
}
pub
fn
fft_setup
(
ffto
:
&
mut
FFT
)
{
*
ffto
=
Default
::
default
();
}
pub
fn
fft_forward
(
ffto
:
&
mut
FFT
,
val
:
&
RingModQ
,
res
:
&
mut
RingFFT
)
{
pub
fn
fft_forward
<
'a
,
'b
>
(
ffto
:
&
mut
FFT
,
val
:
ArrayView
<
'a
,
ZmodQ
,
Ix1
>
,
mut
res
:
ArrayViewMut
<
'b
,
c64
,
Ix1
>
)
{
for
k
in
0
..
N
{
ffto
.in_
[
k
]
=
val
.
0
[
k
]
.
0
as
f64
;
ffto
.in_
[
k
]
=
val
[
k
]
.
0
as
f64
;
ffto
.in_
[
k
+
N
]
=
0.0
;
}
ffto
.plan_fft_forw
.r2c
(
&
mut
ffto
.in_
,
&
mut
ffto
.out
)
.unwrap
();
for
k
in
0
..
N2
{
res
.
0
[
k
]
=
ffto
.out
[
2
*
k
+
1
];
for
k
in
0
..
(
N2
-
1
)
{
res
[
k
]
=
ffto
.out
[
2
*
k
+
1
];
// res[k] = ffto.out[k];
}
}
pub
fn
fft_backward
(
ffto
:
&
mut
FFT
,
val
:
&
RingFFT
,
res
:
&
mut
RingModQ
)
{
pub
fn
fft_backward
<
'a
,
'b
>
(
ffto
:
&
mut
FFT
,
val
:
ArrayView
<
'a
,
c64
,
Ix1
>
,
mut
res
:
ArrayViewMut
<
'b
,
ZmodQ
,
Ix1
>
)
{
for
k
in
0
..
N2
{
ffto
.out
[
2
*
k
+
1
]
=
val
.
0
[
k
]
/
c64
::
new
(
N
as
f64
,
0.0
);
ffto
.out
[
2
*
k
]
=
c64
::
new
(
0.0
,
0.0
);
if
k
<
N2
-
1
{
ffto
.out
[
2
*
k
+
1
]
=
val
[
k
]
/
c64
::
new
(
N
as
f64
,
0.0
);
}
// ffto.out[k] = val[k]; // /c64::new(N as f64,0.0);
}
ffto
.plan_fft_back
.c2r
(
&
mut
ffto
.out
,
&
mut
ffto
.in_
)
.unwrap
();
for
k
in
0
..
N
{
res
.
0
[
k
]
=
Wrapping
(
ffto
.in_
[
k
]
.round
()
as
i32
);
// let max: i64 = i32::MAX as i64;
// let min: i64 = i32::MIN as i64;
// let div: i64 = max - min + 1;
// let mut t = ffto.in_[k].round() as i64 % div;
// t = if t > max { t - div } else if t < min { t + div } else { t };
// res[k] = Wrapping(t as i32);
res
[
k
]
=
Wrapping
(
ffto
.in_
[
k
]
.round
()
.rem_euclid
(
2f64
.powi
(
32
))
as
u32
as
i32
);
}
}
src/lwe.rs
View file @
34bf4f87
use
rand
::
Rng
;
use
crate
::
*
;
use
ndarray
::
parallel
::
prelude
::
*
;
use
ndarray
::
linalg
::
*
;
use
rayon
::
prelude
::
*
;
#[derive(Clone)]
#[derive(Clone
,Debug
)]
pub
struct
CipherText
{
pub
a
:
Array1
<
i32
>
,
// [isize; n],
pub
b
:
i32
...
...
@@ -14,7 +17,7 @@ impl Default for CipherText {
}
}
}
#[derive(Clone)]
#[derive(Clone
,Debug
)]
pub
struct
CipherTextQ
{
pub
a
:
Array1
<
ZmodQ
>
,
// [ZmodQ; n],
pub
b
:
ZmodQ
...
...
@@ -27,7 +30,7 @@ impl Default for CipherTextQ {
}
}
}
#[derive(Clone)]
#[derive(Clone
,Debug
)]
pub
struct
CipherTextQN
{
pub
a
:
Array1
<
ZmodQ
>
,
// [ZmodQ; n],
pub
b
:
ZmodQ
...
...
@@ -35,123 +38,145 @@ pub struct CipherTextQN {
impl
Default
for
CipherTextQN
{
fn
default
()
->
Self
{
CipherTextQN
{
a
:
Array
::
default
(
n
),
a
:
Array
::
default
(
N
),
b
:
Default
::
default
()
}
}
}
#[derive(Clone)]
pub
struct
SecretKey
(
pub
Array1
<
i32
>
);
// [isize; n];
impl
Default
for
SecretKey
{
fn
default
()
->
Self
{
SecretKey
(
Array
::
default
(
n
))
}
// #[derive(Clone,Debug)]
// pub struct SecretKey(pub Array1<i32>); // [isize; n];
// impl Default for SecretKey {
// fn default() -> Self {
// SecretKey(Array::default(n))
// }
// }
pub
type
SecretKey
=
Array
<
i32
,
Ix1
>
;
pub
fn
SecretKey
()
->
SecretKey
{
Array
::
default
(
n
)
}
// #[derive(Clone,Debug)]
// pub struct SecretKeyN(pub Array1<i32>); // [isize; N];
// impl Default for SecretKeyN {
// fn default() -> Self {
// SecretKeyN(Array::default(N))
// }
// }
pub
type
SecretKeyN
=
Array
<
i32
,
Ix1
>
;
pub
fn
SecretKeyN
()
->
SecretKeyN
{
Array
::
default
(
N
)
}
#[derive(Clone)]
pub
struct
SecretKeyN
(
pub
Array1
<
i32
>
);
// [isize; N];
impl
Default
for
SecretKeyN
{
fn
default
()
->
Self
{
SecretKeyN
(
Array
::
default
(
N
))
}
// #[derive(Clone,Debug)]
// pub struct SwitchingKey(pub Array3<CipherTextQ>); // [[[CipherTextQ; KS_EXP]; KS_BASE]; N];
// impl Default for SwitchingKey {
// fn default() -> Self {
// SwitchingKey(Array::default((N,KS_BASE,KS_EXP)))
// }
// }
pub
type
SwitchingKey
=
Array
<
CipherTextQ
,
Ix3
>
;
pub
fn
SwitchingKey
()
->
SwitchingKey
{
let
k
=
Array
::
default
((
N
,
KS_BASE
,
KS_EXP
));
eprintln!
(
"evaluation key 2 -> switching key zeroing complete"
);
k
}
const
qi
:
i32
=
q
as
i32
;
pub
fn
key
Gen
(
sk
:
&
mut
SecretKey
,
rng
:
&
mut
rand
::
rngs
::
ThreadRng
)
{
loop
{
pub
fn
key
_gen
(
sk
:
&
mut
SecretKey
)
{
//
loop {
let
mut
s
=
0
;
let
mut
ss
=
0
;
for
i
in
0
..
n
{
sk
.
0
[
i
]
=
sample
(
&
CHI_BINARY
,
rng
);
s
+=
sk
.
0
[
i
];
ss
+=
(
sk
.
0
[
i
])
.abs
();
// sk[i] = sample(&CHI_BINARY);
sk
[
i
]
=
BINARY_TABLE
[
i
%
3
]
.floor
()
as
i32
;
s
+=
sk
[
i
];
ss
+=
(
sk
[
i
])
.abs
();
}
if
s
.abs
()
>
5
||
(
ss
-
(
n
as
i32
)
/
2
)
.abs
()
>
5
{
continue
;
}
else
{
break
;
}
}
}
pub
fn
key
GenN
(
sk
:
&
mut
SecretKeyN
,
rng
:
&
mut
rand
::
rngs
::
ThreadRng
)
{
//
if s.abs() > 5 || (ss - (n as i32) / 2).abs() > 5 {
//
continue;
//
} else {
//
break;
//
}
//
}
}
pub
fn
key
_gen_N
(
sk
:
&
mut
SecretKeyN
)
{
for
i
in
0
..
N
{
sk
.
0
[
i
]
=
sample
(
&
CHI1
,
rng
);
// sk[i] = sample(&CHI1);
sk
[
i
]
=
(
i
as
i32
)
%
2
;
}
}
pub
fn
encrypt
(
ct
:
&
mut
CipherText
,
sk
:
&
SecretKey
,
m
:
i32
,
rng
:
&
mut
rand
::
rngs
::
ThreadRng
)
{
ct
.b
=
(
m
%
4
)
*
qi
/
4
+
sample
(
&
CHI3
,
rng
);
pub
fn
encrypt
(
ct
:
&
mut
CipherText
,
sk
:
&
SecretKey
,
m
:
i32
)
{
ct
.b
=
(
m
%
4
)
*
qi
/
4
;
// + sample(&CHI3
);
for
i
in
0
..
n
{
ct
.a
[
i
]
=
rng
.gen
::
<
i32
>
()
%
qi
;
ct
.b
=
(
ct
.b
+
ct
.a
[
i
]
*
sk
.
0
[
i
])
%
qi
;
// ct.a[i] = rand::thread_rng().gen::<i32>() % qi;
ct
.a
[
i
]
=
(
i
as
i32
)
%
qi
;
ct
.b
=
(
ct
.b
+
ct
.a
[
i
]
*
sk
[
i
])
%
qi
;
// println!("i = {}, ct.b = {}", i, ct.b);
}
// println!("m = {}, ct.b = {}, ct->a = {:?}", m, ct.b, ct.a);
}
pub
fn
decrypt
(
sk
:
&
SecretKey
,
ct
:
&
CipherText
)
->
i32
{
let
mut
r
=
ct
.b
;
// dbg!(r);
for
i
in
0
..
n
{
r
-=
ct
.a
[
i
]
*
sk
.
0
[
i
];
r
-=
ct
.a
[
i
]
*
sk
[
i
];
// dbg!(r);
}
r
=
((
r
%
qi
)
+
qi
+
qi
/
8
)
%
qi
;
// dbg!(r,qi);
// dbg!(r, qi, 4*r/qi);
4
*
r
/
qi
}
#[derive(Clone)]
pub
struct
SwitchingKey
(
pub
Array3
<
CipherTextQ
>
);
// [[[CipherTextQ; KS_EXP]; KS_BASE]; N];
impl
Default
for
SwitchingKey
{
fn
default
()
->
Self
{
SwitchingKey
(
Array
::
default
((
N
,
KS_BASE
,
KS_EXP
)))
}
}
pub
fn
switchingKeyGen
(
res
:
&
mut
SwitchingKey
,
new_sk
:
&
SecretKey
,
old_sk
:
&
SecretKeyN
,
rng
:
&
mut
rand
::
rngs
::
ThreadRng
)
{
pub
fn
switching_key_gen
<
'b
,
'c
>
(
res
:
&
mut
SwitchingKey
,
new_sk
:
ArrayView
<
'b
,
i32
,
Ix1
>
,
old_sk
:
ArrayView
<
'c
,
i32
,
Ix1
>
)
{
// dbg!(&res[[0,0,0]]);
for
i
in
0
..
N
{
for
j
in
0
..
KS_BASE
{
for
k
in
0
..
KS_EXP
{
// dbg!("switching key",i,j,k);
let
mut
ct
:
CipherTextQ
=
Default
::
default
();
ct
.b
=
-
Wrapping
(
old_sk
.
0
[
i
])
*
Wrapping
(
j
as
i32
)
*
Wrapping
(
KS_TABLE
[
k
])
+
Wrapping
(
sample
(
&
CHI2
,
rng
));
for
l
in
0
..
n
{
ct
.a
[
l
]
=
rng
.gen
();
let
addend
=
ct
.a
[
l
]
*
Wrapping
(
new_sk
.
0
[
l
]);
// dbg!(ct.b, addend, isize::MAX, isize::MIN);
// let upper = addend <= isize::MAX - ct.b;
// let lower = addend >= isize::MIN - ct.b;
// ct.b = if upper && lower {
// ct.b + addend
// } else if !upper && lower {
// isize::MIN + (addend - (isize::MAX - ct.b)) - 1
// } else {
// isize::MAX - (- addend - (ct.b - isize::MIN)) + 1
// };
ct
.b
=
ct
.b
+
addend
;
// dbg!(ct.b);
}
res
.
0
[[
i
,
j
,
k
]]
=
ct
;
// ct.a.par_map_inplace(|x| *x = rand::thread_rng().gen());
ct
.a
.par_map_inplace
(|
x
|
*
x
=
Wrapping
(
i
as
i32
)
*
Wrapping
(
j
as
i32
)
*
Wrapping
(
k
as
i32
));
ct
.b
=
// Wrapping(sample(&CHI2))
-
Wrapping
(
old_sk
[
i
])
*
Wrapping
(
j
as
i32
)
*
Wrapping
(
KS_TABLE
[
k
])
+
ct
.a.dot
::
<
Array
<
Wrapping
<
i32
>
,
Ix1
>>
(
&
new_sk
.mapv
(
Wrapping
));
// + Zip::from(&ct.a).and(new_sk).fold(Wrapping(0), |acc, &x, &y| acc + x * Wrapping(y));
// + ct.a.par_iter().zip(new_sk.par_iter()).map(|(x,y)| x*Wrapping(y)).sum();
res
[[
i
,
j
,
k
]]
=
ct
;
}
}
}
// dbg!(&res[[0,0,0]]);
eprintln!
(
"evaluation key 3 -> switching key generation complete"
);
}
pub
fn
key
S
witch
(
res
:
&
mut
CipherTextQ
,
ksk
:
&
SwitchingKey
,
ct
:
&
CipherTextQN
)
{
pub
fn
key
_s
witch
(
res
:
&
mut
CipherTextQ
,
ksk
:
&
SwitchingKey
,
ct
:
&
CipherTextQN
)
{
for
k
in
0
..
n
{
res
.a
[
k
]
=
Wrapping
(
0
);
// println!("res.a[{}] = {}", k, res.a[k]);
}
res
.b
=
ct
.b
;
// dbg!(res.b);
for
i
in
0
..
N
{
let
a
:
UZmodQ
=
Wrapping
(
-
ct
.a
[
i
]
.
0
as
u32
);
for
j
in
0
..
KS_BASE
{
let
mut
a
:
UZmodQ
=
Wrapping
(
0
)
-
Wrapping
(
ct
.a
[
i
]
.
0
as
u32
);
// println!("i = {}, a = {}", i, a);
for
j
in
0
..
KS_EXP
{
let
a0
:
UZmodQ
=
a
%
Wrapping
(
KS_BASE
as
u32
);
// print!("i = {}, j = {}, ksk[i][{}][j].a = [", i, j, a0.0);
for
k
in
0
..
n
{
res
.a
[
k
]
-=
ksk
.
0
[[
i
,
a0
.
0
as
usize
,
j
]]
.a
[
k
];
res
.b
-=
ksk
.
0
[[
i
,
a0
.
0
as
usize
,
j
]]
.b
;
res
.a
[
k
]
-=
ksk
[[
i
,
a0
.
0
as
usize
,
j
]]
.a
[
k
];
// print!("{},", ksk[[i,a0.0 as usize,j]].a[k])
;
}
// println!("]");
res
.b
-=
ksk
[[
i
,
a0
.
0
as
usize
,
j
]]
.b
;
a
/=
Wrapping
(
KS_BASE
as
u32
);
}
}
}
pub
fn
modSwitch
(
ct
:
&
mut
CipherText
,
c
:
&
CipherTextQ
,
rng
:
&
mut
rand
::
rngs
::
ThreadRng
)
{
for
i
in
0
..
n
{
ct
.a
[
i
]
=
round_qQ
(
c
.a
[
i
]);
}
ct
.b
=
round_qQ
(
c
.b
);
pub
fn
mod_switch
(
ct
:
&
mut
CipherText
,
c
:
&
CipherTextQ
)
{
ct
.a
=
c
.a
.mapv
(
round_q_Q
);
ct
.b
=
round_q_Q
(
c
.b
);
}
pub
fn
round_q
Q
(
v_
:
ZmodQ
)
->
i32
{
(
0.5
+
(
v
_
.
0
as
f64
)
*
(
q
as
f64
)
/
(
Q
as
f64
))
.floor
()
as
i32
pub
fn
round_q
_Q
(
v
:
ZmodQ
)
->
i32
{
(
0.5
+
(
v
.
0
as
f64
)
*
(
q
as
f64
)
/
(
Q
as
f64
))
.floor
()
as
i32
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment