mirror of
https://github.com/GaloisInc/cryptol.git
synced 2024-12-18 05:21:57 +03:00
275 lines
13 KiB
Plaintext
275 lines
13 KiB
Plaintext
/*
|
|
* Copyright (c) 2013-2016 Galois, Inc.
|
|
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
|
*/
|
|
|
|
// see http://cr.yp.to/snuffle/spec.pdf
|
|
|
|
module Salsa20 where
|
|
|
|
import LittleEndian
|
|
|
|
quarterround : [4][32] -> [4][32]
|
|
quarterround [y0, y1, y2, y3] = [z0, z1, z2, z3]
|
|
where
|
|
z1 = y1 ^ ((y0 + y3) <<< 0x7)
|
|
z2 = y2 ^ ((z1 + y0) <<< 0x9)
|
|
z3 = y3 ^ ((z2 + z1) <<< 0xd)
|
|
z0 = y0 ^ ((z3 + z2) <<< 0x12)
|
|
|
|
property quarterround_passes_tests =
|
|
(quarterround [0x00000000, 0x00000000, 0x00000000, 0x00000000] == [0x00000000, 0x00000000, 0x00000000, 0x00000000]) &&
|
|
(quarterround [0x00000001, 0x00000000, 0x00000000, 0x00000000] == [0x08008145, 0x00000080, 0x00010200, 0x20500000]) &&
|
|
(quarterround [0x00000000, 0x00000001, 0x00000000, 0x00000000] == [0x88000100, 0x00000001, 0x00000200, 0x00402000]) &&
|
|
(quarterround [0x00000000, 0x00000000, 0x00000001, 0x00000000] == [0x80040000, 0x00000000, 0x00000001, 0x00002000]) &&
|
|
(quarterround [0x00000000, 0x00000000, 0x00000000, 0x00000001] == [0x00048044, 0x00000080, 0x00010000, 0x20100001]) &&
|
|
(quarterround [0xe7e8c006, 0xc4f9417d, 0x6479b4b2, 0x68c67137] == [0xe876d72b, 0x9361dfd5, 0xf1460244, 0x948541a3]) &&
|
|
(quarterround [0xd3917c5b, 0x55f1c407, 0x52a58a7a, 0x8f887a3b] == [0x3e2f308c, 0xd90a8f36, 0x6ab2a923, 0x2883524c])
|
|
|
|
rowround : [16][32] -> [16][32]
|
|
rowround [y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15] =
|
|
[z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15]
|
|
where
|
|
[ z0, z1, z2, z3] = quarterround [ y0, y1, y2, y3]
|
|
[ z5, z6, z7, z4] = quarterround [ y5, y6, y7, y4]
|
|
[z10, z11, z8, z9] = quarterround [y10, y11, y8, y9]
|
|
[z15, z12, z13, z14] = quarterround [y15, y12, y13, y14]
|
|
|
|
property rowround_passes_tests =
|
|
(rowround [0x00000001, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000001, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000001, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000001, 0x00000000, 0x00000000, 0x00000000] ==
|
|
[0x08008145, 0x00000080, 0x00010200, 0x20500000,
|
|
0x20100001, 0x00048044, 0x00000080, 0x00010000,
|
|
0x00000001, 0x00002000, 0x80040000, 0x00000000,
|
|
0x00000001, 0x00000200, 0x00402000, 0x88000100]) &&
|
|
(rowround [0x08521bd6, 0x1fe88837, 0xbb2aa576, 0x3aa26365,
|
|
0xc54c6a5b, 0x2fc74c2f, 0x6dd39cc3, 0xda0a64f6,
|
|
0x90a2f23d, 0x067f95a6, 0x06b35f61, 0x41e4732e,
|
|
0xe859c100, 0xea4d84b7, 0x0f619bff, 0xbc6e965a] ==
|
|
[0xa890d39d, 0x65d71596, 0xe9487daa, 0xc8ca6a86,
|
|
0x949d2192, 0x764b7754, 0xe408d9b9, 0x7a41b4d1,
|
|
0x3402e183, 0x3c3af432, 0x50669f96, 0xd89ef0a8,
|
|
0x0040ede5, 0xb545fbce, 0xd257ed4f, 0x1818882d])
|
|
|
|
|
|
rowround_opt : [16][32] -> [16][32]
|
|
rowround_opt ys = join [ (quarterround (yi<<<i))>>>i | yi <- split ys | i <- [0 .. 3] : [_][8] ]
|
|
|
|
property rowround_opt_is_rowround ys = rowround ys == rowround_opt ys
|
|
|
|
columnround : [16][32] -> [16][32]
|
|
columnround [x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15] =
|
|
[y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11, y12, y13, y14, y15]
|
|
where
|
|
[ y0, y4, y8, y12] = quarterround [ x0, x4, x8, x12]
|
|
[ y5, y9, y13, y1] = quarterround [ x5, x9, x13, x1]
|
|
[y10, y14, y2, y6] = quarterround [x10, x14, x2, x6]
|
|
[y15, y3, y7, y11] = quarterround [x15, x3, x7, x11]
|
|
|
|
property columnround_passes_tests =
|
|
(columnround [0x00000001, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000001, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000001, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000001, 0x00000000, 0x00000000, 0x00000000] ==
|
|
[0x10090288, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000101, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00020401, 0x00000000, 0x00000000, 0x00000000,
|
|
0x40a04001, 0x00000000, 0x00000000, 0x00000000]) &&
|
|
(columnround [0x08521bd6, 0x1fe88837, 0xbb2aa576, 0x3aa26365,
|
|
0xc54c6a5b, 0x2fc74c2f, 0x6dd39cc3, 0xda0a64f6,
|
|
0x90a2f23d, 0x067f95a6, 0x06b35f61, 0x41e4732e,
|
|
0xe859c100, 0xea4d84b7, 0x0f619bff, 0xbc6e965a] ==
|
|
[0x8c9d190a, 0xce8e4c90, 0x1ef8e9d3, 0x1326a71a,
|
|
0x90a20123, 0xead3c4f3, 0x63a091a0, 0xf0708d69,
|
|
0x789b010c, 0xd195a681, 0xeb7d5504, 0xa774135c,
|
|
0x481c2027, 0x53a8e4b5, 0x4c1f89c5, 0x3f78c9c8])
|
|
|
|
|
|
columnround_opt : [16][32] -> [16][32]
|
|
columnround_opt xs = join (transpose [ (quarterround (xi<<<i))>>>i | xi <- transpose(split xs) | i <- [0 .. 3] : [_][8] ])
|
|
|
|
columnround_opt_is_columnround xs = columnround xs == columnround_opt xs
|
|
|
|
property columnround_is_transpose_of_rowround ys =
|
|
rowround ys == join(transpose(split`{4}(columnround xs)))
|
|
where xs = join(transpose(split`{4} ys))
|
|
|
|
doubleround : [16][32] -> [16][32]
|
|
doubleround(xs) = rowround(columnround(xs))
|
|
|
|
property doubleround_passes_tests =
|
|
(doubleround [0x00000001, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000,
|
|
0x00000000, 0x00000000, 0x00000000, 0x00000000] ==
|
|
[0x8186a22d, 0x0040a284, 0x82479210, 0x06929051,
|
|
0x08000090, 0x02402200, 0x00004000, 0x00800000,
|
|
0x00010200, 0x20400000, 0x08008104, 0x00000000,
|
|
0x20500000, 0xa0000040, 0x0008180a, 0x612a8020]) &&
|
|
(doubleround [0xde501066, 0x6f9eb8f7, 0xe4fbbd9b, 0x454e3f57,
|
|
0xb75540d3, 0x43e93a4c, 0x3a6f2aa0, 0x726d6b36,
|
|
0x9243f484, 0x9145d1e8, 0x4fa9d247, 0xdc8dee11,
|
|
0x054bf545, 0x254dd653, 0xd9421b6d, 0x67b276c1] ==
|
|
[0xccaaf672, 0x23d960f7, 0x9153e63a, 0xcd9a60d0,
|
|
0x50440492, 0xf07cad19, 0xae344aa0, 0xdf4cfdfc,
|
|
0xca531c29, 0x8e7943db, 0xac1680cd, 0xd503ca00,
|
|
0xa74b2ad6, 0xbc331c5c, 0x1dda24c7, 0xee928277])
|
|
|
|
Salsa20 : {r} (8 >= width r) => [64][8] -> [64][8]
|
|
Salsa20 xs = join ar
|
|
where
|
|
ar = [ littleendian_inverse words | words <- xw + zs@(`r/2 : [8]) ]
|
|
xw = [ littleendian xi | xi <- split xs ]
|
|
zs = [xw] # [ doubleround zi | zi <- zs ]
|
|
|
|
property Salsa20_bijective a b = (a == b) || (Salsa20 `{r=20} a != Salsa20 `{r=20} b)
|
|
property Salsa20_passes_tests =
|
|
(Salsa20 `{r=20}
|
|
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ==
|
|
[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) &&
|
|
(Salsa20 `{r=20}
|
|
[211, 159, 13, 115, 76, 55, 82, 183, 3, 117, 222, 37, 191, 187, 234, 136,
|
|
49, 237, 179, 48, 1, 106, 178, 219, 175, 199, 166, 48, 86, 16, 179, 207,
|
|
31, 240, 32, 63, 15, 83, 93, 161, 116, 147, 48, 113, 238, 55, 204, 36,
|
|
79, 201, 235, 79, 3, 81, 156, 47, 203, 26, 244, 243, 88, 118, 104, 54] ==
|
|
[109, 42, 178, 168, 156, 240, 248, 238, 168, 196, 190, 203, 26, 110, 170, 154,
|
|
29, 29, 150, 26, 150, 30, 235, 249, 190, 163, 251, 48, 69, 144, 51, 57,
|
|
118, 40, 152, 157, 180, 57, 27, 94, 107, 42, 236, 35, 27, 111, 114, 114,
|
|
219, 236, 232, 135, 111, 155, 110, 18, 24, 232, 95, 158, 179, 19, 48, 202]) &&
|
|
(Salsa20 `{r=20}
|
|
[ 88, 118, 104, 54, 79, 201, 235, 79, 3, 81, 156, 47, 203, 26, 244, 243,
|
|
191, 187, 234, 136, 211, 159, 13, 115, 76, 55, 82, 183, 3, 117, 222, 37,
|
|
86, 16, 179, 207, 49, 237, 179, 48, 1, 106, 178, 219, 175, 199, 166, 48,
|
|
238, 55, 204, 36, 31, 240, 32, 63, 15, 83, 93, 161, 116, 147, 48, 113] ==
|
|
[179, 19, 48, 202, 219, 236, 232, 135, 111, 155, 110, 18, 24, 232, 95, 158,
|
|
26, 110, 170, 154, 109, 42, 178, 168, 156, 240, 248, 238, 168, 196, 190, 203,
|
|
69, 144, 51, 57, 29, 29, 150, 26, 150, 30, 235, 249, 190, 163, 251, 48,
|
|
27, 111, 114, 114, 118, 40, 152, 157, 180, 57, 27, 94, 107, 42, 236, 35])
|
|
|
|
property Salsa20_has_no_collisions x1 x2 =
|
|
x1 == x2 || doubleround x1 != doubleround x2
|
|
// if(x1 != x2) then (doubleround x1) != (doubleround x2) else True
|
|
|
|
property Salsa20_passes_scrypt_tests =
|
|
Salsa20 `{r=8}
|
|
[ 0x7e, 0x87, 0x9a, 0x21, 0x4f, 0x3e, 0xc9, 0x86, 0x7c, 0xa9, 0x40, 0xe6, 0x41, 0x71, 0x8f, 0x26
|
|
, 0xba, 0xee, 0x55, 0x5b, 0x8c, 0x61, 0xc1, 0xb5, 0x0d, 0xf8, 0x46, 0x11, 0x6d, 0xcd, 0x3b, 0x1d
|
|
, 0xee, 0x24, 0xf3, 0x19, 0xdf, 0x9b, 0x3d, 0x85, 0x14, 0x12, 0x1e, 0x4b, 0x5a, 0xc5, 0xaa, 0x32
|
|
, 0x76, 0x02, 0x1d, 0x29, 0x09, 0xc7, 0x48, 0x29, 0xed, 0xeb, 0xc6, 0x8d, 0xb8, 0xb8, 0xc2, 0x5e
|
|
]
|
|
== [ 0xa4, 0x1f, 0x85, 0x9c, 0x66, 0x08, 0xcc, 0x99, 0x3b, 0x81, 0xca, 0xcb, 0x02, 0x0c, 0xef, 0x05
|
|
, 0x04, 0x4b, 0x21, 0x81, 0xa2, 0xfd, 0x33, 0x7d, 0xfd, 0x7b, 0x1c, 0x63, 0x96, 0x68, 0x2f, 0x29
|
|
, 0xb4, 0x39, 0x31, 0x68, 0xe3, 0xc9, 0xe6, 0xbc, 0xfe, 0x6b, 0xc5, 0xb7, 0xa0, 0x6d, 0x96, 0xba
|
|
, 0xe4, 0x24, 0xcc, 0x10, 0x2c, 0x91, 0x74, 0x5c, 0x24, 0xad, 0x67, 0x3d, 0xc7, 0x61, 0x8f, 0x81
|
|
]
|
|
|
|
// Salsa 20 supports two key sizes, [16][8] and [32][8]
|
|
Salsa20_expansion : {a} (a >= 1, 2 >= a) => ([16*a][8], [16][8]) -> [64][8]
|
|
Salsa20_expansion(k, n) = z
|
|
where
|
|
[s0, s1, s2, s3] = split "expand 32-byte k" : [4][4][8]
|
|
[t0, t1, t2, t3] = split "expand 16-byte k" : [4][4][8]
|
|
x = if(`a == (2 : [8])) then s0 # k0 # s1 # n # s2 # k1 # s3
|
|
else t0 # k0 # t1 # n # t2 # k0 # t3
|
|
z = Salsa20 `{r=20} x
|
|
[k0, k1] = (split(k#zero)):[2][16][8]
|
|
|
|
Salsa20_encrypt : {a, l} (a >= 1, 2 >= a, l <= 2^^70) => ([16*a][8], [8][8], [l][8]) -> [l][8]
|
|
Salsa20_encrypt(k, v, m) = c
|
|
where
|
|
salsa = take (join [ Salsa20_expansion(k, v#(split i)) | i <- [0, 1 ... ] ])
|
|
c = m ^ salsa
|
|
|
|
HSalsa20 : {r} (8 >= width r) => Key -> Nonce -> [8][32]
|
|
HSalsa20 key0 nonce0 = zs @@ ([0,5,10,15,6,7,8,9] : [_][8])
|
|
where
|
|
zs = infZs @ (`r/2 :[8])
|
|
infZs = [xs] # [ doubleround x | x <- infZs ]
|
|
|
|
nonce = [ littleendian (split n) | n <- split (join nonce0)]
|
|
[x0,x5,x10,x15] = Salsa20_Constant
|
|
[x1,x2,x3,x4,x11,x12,x13,x14] = [ littleendian (split k) | k <- split (join key0)]
|
|
[x6,x7,x8,x9] = nonce @@ ([0..3] : [_][8])
|
|
|
|
xs : [16][32]
|
|
xs = [x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15]
|
|
|
|
HSalsa20_bytes : {r} (8 >= width r) => Key -> Nonce -> [32][8]
|
|
HSalsa20_bytes key0 nonce0 = join [littleendian_inverse x | x <- HSalsa20 `{r=r} key0 nonce0]
|
|
|
|
type Key = [256/8][8]
|
|
type Nonce = [192/8][8]
|
|
type Counter = [64]
|
|
|
|
Salsa20_Constant : [4][32]
|
|
Salsa20_Constant = [littleendian (split x) | x <- split (join "expand 32-byte k") : [4][32]]
|
|
|
|
XSalsa20 : {r} (8 >= width r) => Key -> Nonce -> Counter -> [64][8]
|
|
XSalsa20 key0 nonce0 ctr =
|
|
split (join [littleendian (split (x' + z')) | x' <- xs' | z' <- zs'])
|
|
where
|
|
nonce = [ littleendian (split n) | n <- split (join nonce0)]
|
|
|
|
subKey = HSalsa20 `{r=r} key0 nonce0 // 'zs' in the literature
|
|
|
|
[x'0,x'5,x'10,x'15] = Salsa20_Constant
|
|
[x'1,x'2,x'3,x'4,x'11,x'12,x'13,x'14] = subKey
|
|
[x'6,x'7] = nonce @@ ([4,5] : [_][8])
|
|
[x'8,x'9] = reverse (split ctr)
|
|
|
|
xs', zs' : [16][32]
|
|
xs' = [ x'0 ,x'1 ,x'2 ,x'3 ,x'4 ,x'5 ,x'6 ,x'7 ,x'8
|
|
, x'9 ,x'10 ,x'11 ,x'12 ,x'13 ,x'14 ,x'15
|
|
]
|
|
infZs' = [xs'] # [ doubleround x | x <- infZs' ]
|
|
zs' = infZs' @ (`r/2 : [8])
|
|
|
|
XSalsa20_expansion : {n,r} (8 >= width r, 64 >= width n) => Key -> Nonce -> [n][8]
|
|
XSalsa20_expansion k n = take (join ks)
|
|
where
|
|
ks = [XSalsa20 `{r=r} k n i | i <- [0...]]
|
|
|
|
XSalsa20_encrypt : {n,r} (8 >= width r, 64 >= width n) => Key -> Nonce -> [n][8] -> [n][8]
|
|
XSalsa20_encrypt k n msg = ks ^ msg
|
|
where ks = XSalsa20_expansion `{r=r} k n
|
|
|
|
property test =
|
|
ct == [0x00, 0x2d, 0x45, 0x13, 0x84, 0x3f, 0xc2, 0x40, 0xc4, 0x01, 0xe5, 0x41]
|
|
where
|
|
ct = XSalsa20_encrypt `{r=20} key nonce "Hello world!"
|
|
key = "this is 32-byte key for xsalsa20"
|
|
nonce = "24-byte nonce for xsalsa"
|
|
|
|
property theorem1 a = quarterround [a, -a, a, -a] == [a,-a,a,-a]
|
|
property theorem2 a b c d = rowround val == val
|
|
where val = [a,-a,a,-a
|
|
,b,-b,b,-b
|
|
,c,-c,c,-c
|
|
,d,-d,d,-d]
|
|
property theorem3 a b c d = columnround val == val
|
|
where val = [a,-b,c,-d
|
|
,-a,b,-c,d
|
|
,a,-b,c,-d
|
|
,-a,b,-c,d]
|
|
property theorem4 a = doubleround val == val
|
|
where val = [a,-a,a,-a
|
|
,-a,a,-a,a
|
|
,a,-a,a,-a
|
|
,-a,a,-a,a]
|
|
property theorem7 a b =
|
|
a ^ b != diff || Salsa20Words a == Salsa20Words b
|
|
where
|
|
diff = [ 0x80000000 | _ <- [0..15]]
|
|
|
|
Salsa20Words : [16][32] -> [16][32]
|
|
Salsa20Words x = [join (reverse r) | r <- split `{each=4} (Salsa20 `{r=20} (join [reverse (split `{4} v) | v <- x]))]
|
|
|