library
libthreefish;
const
EXTENDED_KEY_SCHEDULE_CONST: uint64 =
6148914691236517205
;
const
SUBKEY_INTERVAL:
integer
=
4
;
PI16:
array
[
0..15
]
of
integer
=
(
0
,
9
,
2
,
13
,
6
,
11
,
4
,
15
,
10
,
7
,
12
,
3
,
14
,
5
,
8
,
1
);
const
RPI16:
array
[
0..15
]
of
integer
=
(
0
,
15
,
2
,
11
,
6
,
13
,
4
,
9
,
14
,
1
,
8
,
5
,
10
,
3
,
12
,
7
);
const
DEPTH_OF_D_IN_R:
integer
=
8
;
const
R16:
array
[
0..7
,
0..7
]
of
integer
=
(
(
55
,
43
,
37
,
40
,
16
,
22
,
38
,
12
),
(
25
,
25
,
46
,
13
,
14
,
13
,
52
,
57
),
(
33
,
8
,
18
,
57
,
21
,
12
,
32
,
54
),
(
34
,
43
,
25
,
60
,
44
,
9
,
59
,
34
),
(
28
,
7
,
47
,
48
,
51
,
9
,
35
,
41
),
(
17
,
6
,
18
,
25
,
43
,
42
,
40
,
15
),
(
58
,
7
,
32
,
45
,
19
,
18
,
2
,
56
),
(
47
,
49
,
27
,
58
,
37
,
48
,
53
,
56
));
type
TKey =
array
[
0..16
]
of
uint64;
type
TTweak =
array
[
0..2
]
of
uint64;
type
PKey = ^ TKey;
type
PTweak = ^ TTweak;
var
t: TTweak;
x:
array
[
0..1
]
of
uint64;
y:
array
[
0..1
]
of
uint64;
const
nr:
integer
=
80
;
var
k: TKey;
const
nw:
integer
=
16
;
var
vd:
array
[
0..15
]
of
uint64;
var
ed:
array
[
0..15
]
of
uint64;
var
fd:
array
[
0..15
]
of
uint64;
var
ksd:
array
[
0..15
]
of
uint64;
procedure
mix (j, d:
integer
);
var
rotl: uint64;
begin
y[
0
] := x[
0
] + x[
1
];
rotl := R16[d
mod
DEPTH_OF_D_IN_R][j];
y[
1
] := ((x[
1
]
shl
(rotl))
or
(x[
1
]
shr
(
64
- rotl)));
y[
1
] := y[
1
]
xor
y[
0
];
end
;
procedure
demix (j, d:
integer
);
var
rotr: uint64;
begin
y[
1
] := y[
1
]
xor
y[
0
];
rotr := R16[d
mod
DEPTH_OF_D_IN_R][j];
x[
1
] := (y[
1
]
shr
rotr)
or
(y[
1
]
shl
(
64
- rotr));
x[
0
] := y[
0
] - x[
1
];
end
;
procedure
keySchedule (s:
integer
);
var
i:
integer
;
begin
for
i :=
0
to
nw -
1
do
begin
ksd[i] := k[(s + i)
mod
(nw +
1
)];
if
(i = nw -
3
)
then
begin
ksd[i] := ksd[i] + t[s
mod
3
];
end
else
if
(i = nw -
2
)
then
begin
ksd[i] := ksd[i] + t[(s +
1
)
mod
3
];
end
else
if
(i = nw -
1
)
then
begin
ksd[i] := ksd[i] + s;
end
;
end
;
end
;
procedure
init (key: Pkey; tweak: ptweak);
var
i:
integer
;
knw: uint64;
begin
fillchar(vd,
128
,
0
);
fillchar(ed,
128
,
0
);
fillchar(fd,
128
,
0
);
fillchar(ksd,
128
,
0
);
for
i :=
0
to
nw -
1
do
k[i] := key^[i];
knw := EXTENDED_KEY_SCHEDULE_CONST;
for
i :=
0
to
nw -
1
do
knw := knw
xor
key^[i];
k[nw] := knw;
t[
0
] := tweak^[
0
];
t[
1
] := tweak^[
1
];
t[
2
] := t[
0
]
xor
t[
1
];
end
;
procedure
crypt (p, c: PKey); stdcall; export;
var
i, d, j, s:
integer
;
begin
for
i :=
0
to
nw -
1
do
vd[i] := p^[i];
for
d :=
0
to
nr -
1
do
begin
if
(d
mod
SUBKEY_INTERVAL =
0
)
then
begin
s := d
div
SUBKEY_INTERVAL;
keySchedule(s);
for
i :=
0
to
nw -
1
do
begin
ed[i] := vd[i] + ksd[i];
end
;
end
else
begin
for
i :=
0
to
nw -
1
do
begin
ed[i] := vd[i];
end
;
end
;
for
j :=
0
to
(nw
div
2
) -
1
do
begin
x[
0
] := ed[j *
2
];
x[
1
] := ed[j *
2
+
1
];
mix(j, d);
fd[j *
2
] := y[
0
];
fd[j *
2
+
1
] := y[
1
];
end
;
for
i :=
0
to
nw -
1
do
begin
vd[i] := fd[PI16[i]];
end
;
end
;
keySchedule(nr
div
SUBKEY_INTERVAL);
for
i :=
0
to
nw -
1
do
begin
c^[i] := vd[i] + ksd[i];
end
;
end
;
procedure
decrypt (c, p: PKey); stdcall; export;
var
i, d, j, s:
integer
;
begin
for
i :=
0
to
nw -
1
do
vd[i] := c^[i];
for
d := nr
downto
1
do
begin
if
(d
mod
SUBKEY_INTERVAL =
0
)
then
begin
s := d
div
SUBKEY_INTERVAL;
keySchedule(s);
for
i :=
0
to
nw -
1
do
begin
fd[i] := vd[i] - ksd[i];
end
;
end
else
begin
for
i :=
0
to
nw -
1
do
begin
fd[i] := vd[i];
end
;
end
;
for
i :=
0
to
nw -
1
do
begin
ed[i] := fd[RPI16[i]];
end
;
for
j :=
0
to
(nw
div
2
) -
1
do
begin
y[
0
] := ed[j *
2
];
y[
1
] := ed[j *
2
+
1
];
demix(j, d -
1
);
vd[j *
2
] := x[
0
];
vd[j *
2
+
1
] := x[
1
];
end
;
end
;
keySchedule(
0
);
for
i :=
0
to
nw -
1
do
begin
p^[i] := vd[i] - ksd[i];
end
;
end
;
procedure
setup (key: PKey; tweak: PTweak); stdcall; export;
begin
init(key, tweak);
end
;
exports
crypt,
decrypt,
setup;
end
.