mirror of
https://github.com/GaloisInc/cryptol.git
synced 2024-11-28 09:23:04 +03:00
Example: miniLock in Cryptol
This commit is contained in:
parent
58a605e8ff
commit
a4e42b8429
254
examples/MiniLock/File.md
Normal file
254
examples/MiniLock/File.md
Normal file
@ -0,0 +1,254 @@
|
||||
Define the minilock file format, encoding only.
|
||||
|
||||
```cryptol
|
||||
module File where
|
||||
|
||||
import Keys
|
||||
import CfrgCurves
|
||||
import Blake2s
|
||||
import Base64
|
||||
import Poly1305
|
||||
import Salsa20
|
||||
import CryptoBox
|
||||
```
|
||||
|
||||
|
||||
The file format is:
|
||||
|
||||
> miniLock magic bytes (8 bytes)
|
||||
> Header length in bytes (4 bytes, little-endian)
|
||||
> Header bytes (JSON, fields sometimes encrypted)
|
||||
> Ciphertext bytes
|
||||
|
||||
Variable sized formats are potentially awkward for Cryptol because Cryptol
|
||||
encodes the length of values in the type. For example, the header size varies
|
||||
in the JS implementation. Fortunately this variablity is all due to either the
|
||||
arbitrary choices of the encoder or things deterministicly dependent on the
|
||||
input type (vs value). For an example of the later case, the number of
|
||||
recipients leads to a variable header size that is computable from the input
|
||||
type. The former is a larger issue - for example a Base58 encoding of 0 could
|
||||
be an arbitrary number of the letter 'A' ("A", "AA", etc). For encoding this
|
||||
is handled by emitting the maximum encoding (46 bytes for minilock
|
||||
identifications), but this issue prevents us from implementing a decoder that
|
||||
would interoperate with anything interesting.
|
||||
|
||||
|
||||
The header format is:
|
||||
|
||||
> {
|
||||
> version: Version of the miniLock protocol used for this file (Currently 1) (Number)
|
||||
> ephemeral: Public key from ephemeral key pair used to encrypt decryptInfo object (Base64),
|
||||
> decryptInfo: {
|
||||
> (One copy of the below object for every recipient)
|
||||
> Unique nonce for decrypting this object (Base64): {
|
||||
> senderID: Sender's miniLock ID (Base58),
|
||||
> recipientID: miniLock ID of this recipient (used for verfication) (Base58),
|
||||
> fileInfo: {
|
||||
> fileKey: Key for file decryption (Base64),
|
||||
> fileNonce: Nonce for file decryption (Base64),
|
||||
> fileHash: BLAKE2 hash (32 bytes) of the ciphertext bytes. (Base64)
|
||||
> } (fileInfo is encrypted to recipient's public key using long-term key pair) (Base64),
|
||||
> } (encrypted to recipient's public key using ephemeral key pair) (Base64)
|
||||
> }
|
||||
|
||||
```cryptol
|
||||
// Size of a given minilock container depends soley on the number of recipients and the plaintext
|
||||
type MiniLockBytes nrRecip fileSize = 8 + 4 + 89 + (DecryptInfoSize + 1) * nrRecip + EncryptedBytes fileSize - 1
|
||||
|
||||
minilock : {nrRecip, fileNameBytes, msgBytes}
|
||||
( fin nrRecip, fin fileNameBytes, fin msgBytes // All the values are finite
|
||||
, nrRecip >= 1, 22 >= width nrRecip // Between 1 and 4M recipients
|
||||
, 63 >= width msgBytes // Messages leq 2^63 bytes
|
||||
, fileNameBytes >= 1, 256 >= fileNameBytes // Between 1 and 256 byte file name
|
||||
) =>
|
||||
[nrRecip](MinilockID,[24][8]) // Recipients and nonces for the fileInfo field
|
||||
-> [fileNameBytes][8] // File name
|
||||
-> [msgBytes][8] // Plaintext
|
||||
-> (Private25519, Public25519) // Sender keys
|
||||
-> [32][8] // File key (random)
|
||||
-> [16][8] // File nonce (random)
|
||||
-> (Private25519, Public25519) // Ephemeral keys (random)
|
||||
-> [MiniLockBytes nrRecip msgBytes][8]
|
||||
minilock rs fileName0 msg senderKeys fileKey fileNonce ephemKeys = lockFile
|
||||
where
|
||||
filename = take `{256} (fileName0 # (zero : [256][8]))
|
||||
ct = encryptData fileKey fileNonce filename msg
|
||||
fileInfo = mkFileInfoBlob (fileKey, fileNonce, split (blake2s `{nn=32} ct))
|
||||
lockFile = mkMiniLock rs senderKeys ephemKeys fileInfo ct
|
||||
|
||||
private
|
||||
magic : [8][8]
|
||||
magic = [0x6d, 0x69, 0x6e, 0x69, 0x4c, 0x6f, 0x63, 0x6b]
|
||||
|
||||
encryptData : {msgBytes} (63 >= width msgBytes)
|
||||
=> [32][8]-> [16][8] -> [256][8] -> [msgBytes][8] -> [EncryptedBytes msgBytes][8]
|
||||
encryptData k n f m = encryptChunks k n f cs cN
|
||||
where
|
||||
(cs,cN) = mkChunks m
|
||||
|
||||
// encrypt chunks results in the ciphertext AND poly1305 tag for each chunk.
|
||||
encryptChunks : {chunks,rem}
|
||||
(fin chunks, fin rem
|
||||
, 32 >= width rem
|
||||
, 64 >= width chunks)
|
||||
=> [32][8] -> [16][8] -> [256][8] -> [chunks]Chunk -> [rem][8]
|
||||
-> [4 + 16 + 256 + chunks*((2^^20) + 4 + 16) + 4 + 16 + rem][8]
|
||||
encryptChunks key nonce c0 cs end = encChunk0 # join ctChunks # ctFinal
|
||||
where
|
||||
fullNonce0 = nonce # put64le zero
|
||||
encChunk0 = put32le 256 # crypto_secretbox c0 key fullNonce0 : [4 + 16 + 256][8]
|
||||
|
||||
nonces = [nonce # put64le i | i <- [1...]]
|
||||
ctChunks = [put32le (2^^20) # crypto_secretbox cnk key n | n <- nonces | cnk <- cs]
|
||||
|
||||
nFinal = nonce # put64le ((`chunks + 1) || 0x8000000000000000)
|
||||
ctFinal = put32le `rem # crypto_secretbox end key nFinal
|
||||
```
|
||||
|
||||
The minilock file format is a concatenation of the magic, header length field, header, and ciphertext.
|
||||
|
||||
```cryptol
|
||||
|
||||
// Size of the 'decryptInfo' javascript record.
|
||||
type DecryptInfoSize = 549
|
||||
|
||||
|
||||
mkMiniLock : {nrRecip, ctBytes} (22 >= width nrRecip, nrRecip >= 1) =>
|
||||
[nrRecip](MinilockID,[24][8])
|
||||
-> (Private25519, Public25519)
|
||||
-> (Private25519, Public25519)
|
||||
-> FileInfoBlob
|
||||
-> [ctBytes][8]
|
||||
-> [8 + 4 + 89 + (DecryptInfoSize + 1) * nrRecip + ctBytes - 1][8]
|
||||
mkMiniLock rs senderKeys ephemKeys fileInfo ct =
|
||||
magic # put32le (width header) # header # ct
|
||||
where
|
||||
header = mkHeader rs senderKeys ephemKeys fileInfo
|
||||
```
|
||||
|
||||
Construction of the "file info blob" means we build the plaintext value:
|
||||
|
||||
> {
|
||||
> fileKey: Key for file decryption (Base64),
|
||||
> fileNonce: Nonce for file decryption (Base64),
|
||||
> fileHash: BLAKE2 hash (32 bytes) of the ciphertext bytes. (Base64)
|
||||
> }
|
||||
|
||||
```cryptol
|
||||
// The triple of Key and nonce protecting the file along with the file's hash
|
||||
type FileInfo = ([32][8], [16][8], [32][8])
|
||||
type FileInfoBlob = [155][8]
|
||||
|
||||
mkFileInfoBlob : FileInfo
|
||||
-> FileInfoBlob
|
||||
mkFileInfoBlob (key,nonce,hash) =
|
||||
brace(
|
||||
jsonPair "fileKey" (quote64 key) # "," #
|
||||
jsonPair "fileNonce" (quote64 nonce) # "," #
|
||||
jsonPair "fileHash" (quote64 hash)
|
||||
)
|
||||
```
|
||||
|
||||
The header includes the public ephemeral key, version, and NrRecip copies of the
|
||||
fileinfo inside a decryptInfo field as such:
|
||||
|
||||
> version: Version of the miniLock protocol used for this file (Currently 1) (Number)
|
||||
> ephemeral: Public key from ephemeral key pair used to encrypt decryptInfo object (Base64),
|
||||
> decryptInfo: { nonce1 : { encryptedFileInfo }
|
||||
> , nonce2 : ...
|
||||
> , ...
|
||||
> }
|
||||
|
||||
```cryptol
|
||||
mkHeader : {nrRecip} (fin nrRecip, nrRecip >= 1)
|
||||
=> [nrRecip](MinilockID,[24][8])
|
||||
-> (Private25519, Public25519)
|
||||
-> (Private25519, Public25519)
|
||||
-> FileInfoBlob
|
||||
-> [89 + (DecryptInfoSize+1) * nrRecip - 1][8]
|
||||
mkHeader rs senderKeys ephemKeys infoBlob =
|
||||
brace (
|
||||
jsonPair "version" "1" # ","
|
||||
# jsonPair "ephemeral" (quote64 ephemKeys.1) # ","
|
||||
# jsonPair "decryptInfo" (brace decInfoFull)
|
||||
)
|
||||
where
|
||||
ds = [ mkDecryptInfo senderKeys ephemKeys recvID recvNonce infoBlob # "," | (recvID,recvNonce) <- rs ]
|
||||
// Drop the trailing comma
|
||||
decInfoFull = take `{back = min nrRecip 1} (join ds)
|
||||
|
||||
// XXX return 'succ' for successful decode of the public id
|
||||
mkDecryptInfo :
|
||||
(Private25519, Public25519)
|
||||
-> (Private25519, Public25519)
|
||||
-> MinilockID -> [24][8] -> FileInfoBlob -> [DecryptInfoSize][8]
|
||||
mkDecryptInfo senderKeys ephemKeys theirID nonce infoBlob = quote64 nonce # ":" # quote ct
|
||||
where
|
||||
ct = encryptWith nonce (ephemKeys.0) theirPublic internals
|
||||
internals = brace ( jsonPair "senderID" (quote (encodeID senderKeys.1)) # ","
|
||||
# jsonPair "recipientID" (quote theirID) # ","
|
||||
# jsonPair "fileInfo" (quote fileInfoCT)
|
||||
)
|
||||
fileInfoCT = encryptWith nonce (senderKeys.0) theirPublic infoBlob
|
||||
(succ,theirPublic) = decodeID theirID
|
||||
|
||||
encryptWith : {n} (2^^64 >= 32 + n) => [24][8] -> Private25519 -> Public25519 -> [n][8] -> [Enc64 (n+16)][8]
|
||||
encryptWith nonce secret public pt = base64enc (crypto_box pt nonce public secret)
|
||||
|
||||
type NrChunks ptBytes = ptBytes / (2^^20)
|
||||
type LastChunkSize ptBytes = ptBytes - (NrChunks ptBytes) * 2^^20
|
||||
type EncryptedBytes ptBytes = 4 + 16 + 256 + (NrChunks ptBytes) * ((2^^20) + 4 + 16) + 4 + 16 + LastChunkSize ptBytes
|
||||
|
||||
type ChunkSize = 2^^20
|
||||
type Chunk = [ChunkSize][8]
|
||||
type FullChunks bytes = bytes / ChunkSize
|
||||
type Rem bytes = bytes - FullChunks bytes * ChunkSize
|
||||
|
||||
mkChunks : {bytes} ( fin bytes )
|
||||
=> [bytes][8] -> ([FullChunks bytes]Chunk, [Rem bytes][8])
|
||||
mkChunks pt = (cs,last)
|
||||
where cs = split (take `{front = FullChunks bytes * ChunkSize, back = Rem bytes} pt)
|
||||
last = drop `{FullChunks bytes * ChunkSize} pt
|
||||
```
|
||||
|
||||
The above code used some custom utility functions, which appear below.
|
||||
|
||||
```cryptol
|
||||
put32le : [32] -> [4][8]
|
||||
put32le x = reverse (split x)
|
||||
|
||||
put64le : [64] -> [8][8]
|
||||
put64le x = reverse (split x)
|
||||
|
||||
quote : {m} (fin m) => [m][8] -> [m+2][8]
|
||||
quote m = "\"" # m # "\""
|
||||
|
||||
brace : {m} (fin m) => [m][8] -> [m+2][8]
|
||||
brace m = "{" # m # "}"
|
||||
|
||||
quote64 : {m} (fin m) => [m][8] -> [4*(m + (3 - m % 3) % 3)/3 + 2][8]
|
||||
quote64 m = quote (base64enc m)
|
||||
|
||||
jsonPair : {m,n} (fin m) => [m][8] -> [n][8] -> [3+m+n][8]
|
||||
jsonPair m n = quote m # ":" # n
|
||||
|
||||
// Encrypt a file such that one recipient
|
||||
// User: "example@example.com
|
||||
// Pass: "some bears eat all the honey in the jar"
|
||||
//
|
||||
// Can decrypt.
|
||||
test_lock fname cont = file
|
||||
where
|
||||
myPriv = testPriv
|
||||
myPub = testPub
|
||||
theirID = testID
|
||||
ephemPriv = zero # "ephemeral Curve25519"
|
||||
ephemPub = Curve25519 ephemPriv basePoint25519
|
||||
nonceA = zero # "recip1 nonce"
|
||||
nonceF = zero # "file nonce"
|
||||
key = zero # "file key"
|
||||
file = minilock [(theirID,nonceA)] fname cont (myPriv,myPub) key nonceF (ephemPriv,ephemPub)
|
||||
|
||||
test_construction : [MiniLockBytes 1 13][8]
|
||||
test_construction = test_lock "some_filename" "some contents"
|
||||
```
|
71
examples/MiniLock/Keys.cry
Normal file
71
examples/MiniLock/Keys.cry
Normal file
@ -0,0 +1,71 @@
|
||||
module Keys where
|
||||
|
||||
import CfrgCurves
|
||||
import Blake2s
|
||||
import SCrypt
|
||||
import Base58
|
||||
|
||||
type MinilockID = [46][8]
|
||||
|
||||
// Given a public key compute the ASCII ID
|
||||
encodeID : Public25519 -> MinilockID
|
||||
encodeID pub = base58enc (join (pub # [h]))
|
||||
where
|
||||
h = blake2s `{nn=1} pub : [8]
|
||||
|
||||
decodeID : MinilockID -> (Bit,Public25519)
|
||||
decodeID ident = (hComp == hRecv, key)
|
||||
where
|
||||
bs = split (base58dec ident) : [33][8]
|
||||
hRecv = bs ! 0
|
||||
hComp = blake2s `{nn=1} key : [8]
|
||||
key = take bs : [32][8]
|
||||
|
||||
// Accept a possibly-short key (base58 is value dependent encoding)
|
||||
// and expand it to the full, fixed, size.
|
||||
mkFullLengthID : {n} (46 >= n, n>= 1) => [n][8] -> MinilockID
|
||||
mkFullLengthID n = drop (['1' | _ <- [0..45] : [_][8]] # n)
|
||||
|
||||
mkID : {passBytes, saltBytes}
|
||||
( fin passBytes, fin saltBytes
|
||||
, 64 >= width passBytes
|
||||
, 32 >= width (4*saltBytes)
|
||||
)
|
||||
=> [passBytes][8] -> [saltBytes][8] -> (MinilockID,Private25519)
|
||||
mkID pw email = (encodeID pub,priv)
|
||||
where
|
||||
// XXX wait for cryptol 2.3: priv = SCrypt `{N=2^^17,r=8} (split (blake2s `{nn=32} pw)) email
|
||||
priv : Private25519
|
||||
priv = SCrypt `{N=2^^1,r=8} (split (blake2s `{nn=32} pw)) email
|
||||
// XXX we can't interpret N=2^^17 so this N value is a place holder...
|
||||
pub = Curve25519 priv basePoint25519
|
||||
|
||||
// XXX we can not run these tests in the cryptol interpreter, SCrypt is too expensive.
|
||||
testPass = "some bears eat all the honey in the jar"
|
||||
testEmail = "example@example.com"
|
||||
|
||||
testID : MinilockID
|
||||
testID = mkFullLengthID "28ZvW9rqRqvqpFTtHnusUntRqrxb4qqZAaNAd3QsqjSsXq"
|
||||
|
||||
testID_computed = "28ZvW9rqRqvqpFTtHnusUntRqrxb4qqZAaNAd3QsqjSsXq" // Computed on deathstar
|
||||
testPriv_computed =
|
||||
[0x12, 0x86, 0xe0, 0x18, 0xc6, 0x68, 0x34, 0x96, 0x09, 0x2e, 0x53,
|
||||
0x32, 0x37, 0x76, 0x80, 0x3c, 0x30, 0xb4, 0x75, 0x2d, 0xd7, 0x70,
|
||||
0xea, 0xa9, 0x6f, 0x0d, 0xda, 0x25, 0xc7, 0xfe, 0x28, 0x1f]
|
||||
|
||||
// Deathstar results:
|
||||
// ([0x32, 0x38, 0x5a, 0x76, 0x57, 0x39, 0x72, 0x71, 0x52, 0x71, 0x76,
|
||||
// 0x71, 0x70, 0x46, 0x54, 0x74, 0x48, 0x6e, 0x75, 0x73, 0x55, 0x6e,
|
||||
// 0x74, 0x52, 0x71, 0x72, 0x78, 0x62, 0x34, 0x71, 0x71, 0x5a, 0x41,
|
||||
// 0x61, 0x4e, 0x41, 0x64, 0x33, 0x51, 0x73, 0x71, 0x6a, 0x53, 0x73,
|
||||
// 0x58, 0x71],
|
||||
// [0x12, 0x86, 0xe0, 0x18, 0xc6, 0x68, 0x34, 0x96, 0x09, 0x2e, 0x53,
|
||||
// 0x32, 0x37, 0x76, 0x80, 0x3c, 0x30, 0xb4, 0x75, 0x2d, 0xd7, 0x70,
|
||||
// 0xea, 0xa9, 0x6f, 0x0d, 0xda, 0x25, 0xc7, 0xfe, 0x28, 0x1f])
|
||||
|
||||
|
||||
// testPriv : Private25519
|
||||
testPriv = [0x12, 0x86, 0xe0, 0x18, 0xc6, 0x68, 0x34, 0x96, 0x09, 0x2e, 0x53, 0x32, 0x37, 0x76, 0x80, 0x3c, 0x30, 0xb4, 0x75, 0x2d, 0xd7, 0x70,0xea, 0xa9, 0x6f, 0x0d, 0xda, 0x25, 0xc7, 0xfe, 0x28, 0x1f]
|
||||
|
||||
testPub = Curve25519 testPriv basePoint25519
|
||||
property kat_pub_id_eq = testPub == (decodeID testID).1 && encodeID testPub == testID && testID == testID_computed && testPriv == testPriv_computed
|
38
examples/MiniLock/README.md
Normal file
38
examples/MiniLock/README.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Minilock in Cryptol
|
||||
|
||||
[miniLock](https://minilock.io) is a low-barrier to use file encryption utility
|
||||
based on the algorithms:
|
||||
|
||||
* SCrypt
|
||||
- PBKDF2
|
||||
- HMAC-SHA512
|
||||
* Blake2s
|
||||
* Base64
|
||||
* Base58
|
||||
* CryptoBox
|
||||
- Salsa20
|
||||
- Curve25519
|
||||
- Poly1305
|
||||
|
||||
This example is a specification of miniLock file encryption in Cryptol including
|
||||
all component algorithms as well as primitive JSON encoding to allow
|
||||
inter-operability between the official miniLock written in JavaScript and files
|
||||
produced by Cryptol.
|
||||
|
||||
# Use
|
||||
|
||||
To encrypt a file consider:
|
||||
|
||||
```
|
||||
CRYPTOLPATH=`pwd`/prim cryptol File.md
|
||||
```
|
||||
|
||||
Then use the `miniLock` function such as can be seen in `test_lock`:
|
||||
|
||||
```
|
||||
miniLock [(theirID, nonceA)] filename contents (myPrivKey, myPubKey) key nonceF (ephemPriv, ephemPub)
|
||||
```
|
||||
|
||||
Note SCrypt, and thus miniLock ID and key derivation from user passwords, is too
|
||||
expensive for the Cryptol interpreter to compute on all but todays more powerful
|
||||
computers. The ID generation can be done using `mkID` from `Keys.cry`.
|
40
examples/MiniLock/prim/Base58.cry
Normal file
40
examples/MiniLock/prim/Base58.cry
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module Base58 where
|
||||
|
||||
// Base 58 is a dependent format - the length of the encoded value depends on
|
||||
// the value being encoded This does not play well with Cryptol, which expects
|
||||
// a static type. Thus we must consume the worst-case number of bytes and
|
||||
// produce a length value which we return to the callee.
|
||||
|
||||
// Convert an N bit number (33 bytes for minilock) into a big endian base 58 representation (46 byte max for minilock).
|
||||
base58enc : {n,m} (fin n, fin m, n >= 6 ) => [n] -> [m][8]
|
||||
base58enc ns = [ x.1 | x <- reverse (take `{m} (drop `{1} enc))]
|
||||
where
|
||||
enc = [(ns,zero)] # [ (n/58,charOf (n%58)) | (n,_) <- enc ]
|
||||
charOf x = charMap @ x
|
||||
|
||||
charMap : [58][8]
|
||||
charMap = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
|
||||
base58dec : {n,m} (fin n, fin m, n >= 1, n >= width m, n >= 8) => [m][8] -> [n]
|
||||
base58dec ms = sum [ (dec m) * 58 ^^ i | m <- reverse ms | i <- [0..m] ]
|
||||
where
|
||||
dec : [8] -> [n]
|
||||
dec x = zero # dec' x
|
||||
|
||||
dec' : [8] -> [8]
|
||||
dec' x =
|
||||
if x >= 'm'
|
||||
then x - 'm' + 44
|
||||
else if x >= 'a'
|
||||
then x - 'a' + 33
|
||||
else if x >= 'P'
|
||||
then x - 'P' + 22
|
||||
else if x > 'I'
|
||||
then x - 'J' + 17
|
||||
else if x >= 'A'
|
||||
then x - 'A' + 9
|
||||
else x - '1'
|
53
examples/MiniLock/prim/Base64.cry
Normal file
53
examples/MiniLock/prim/Base64.cry
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module Base64 where
|
||||
|
||||
type Enc64 n = 4*(((3-(n%3))%3) + n)/3
|
||||
|
||||
base64enc : {n,m,padZ} (4*(padZ + n)/3 == m, fin n, fin m, padZ == (3-(n%3))%3, 2>=padZ)
|
||||
=> [n][8] -> [Enc64 n][8]
|
||||
base64enc ns = take `{m} (chunks # padEq)
|
||||
where
|
||||
chunks = take `{(4*n+2)/3} (base64chunks `{(n+2)/3} (ns # padZero))
|
||||
padZero = take `{padZ} [zero | _ <- [1..2] : [_][2]]
|
||||
padEq = "=="
|
||||
|
||||
alphabet = ['A'..'Z'] # ['a'..'z'] # ['0'..'9'] # "+/"
|
||||
|
||||
|
||||
base64chunks : {n} (fin n) => [n*3][8] -> [n*4][8]
|
||||
base64chunks m = [basify x | x <- ns]
|
||||
where
|
||||
ns = split (join m) : [_][6]
|
||||
basify : [6] -> [8]
|
||||
basify x = alphabet @ x
|
||||
|
||||
// Base64 strings are always in 4n byte chunks, the final chunk might be
|
||||
// padded. We can not give a proper cryptol implementation that strips the
|
||||
// padding because that would require the type, n, to depend on the value
|
||||
// (dependant types). Instead we return possibly excess bytes and, separetely,
|
||||
// the number of pad bytes (0,1 or 2) as a value.
|
||||
base64dec : {n,m} (fin m, 4*n == 3*m, fin n) => [m][8] -> ([n][8],[2])
|
||||
base64dec ms = (split (join [debase x | x <- ms]), nrEq)
|
||||
where
|
||||
nrEq : [2]
|
||||
nrEq = sum [ zero # [x == '='] | x <- take `{2} (reverse ms # [zero,zero]) ]
|
||||
|
||||
debase : [8] -> [6]
|
||||
debase x = drop `{2} (debase' x)
|
||||
|
||||
debase' : [8] -> [8]
|
||||
debase' x =
|
||||
if x >= 'A' && x <= 'Z'
|
||||
then x - 'A'
|
||||
else if x >= 'a' && x <= 'z'
|
||||
then x - 'a' + 26
|
||||
else if x >= '0' && x <= '9'
|
||||
then x - '0' + 52
|
||||
else if x == '+'
|
||||
then 62
|
||||
else if x == '/'
|
||||
then 63
|
||||
else zero // Pad bytes are decoded as NUL
|
686
examples/MiniLock/prim/Blake2s.cry
Normal file
686
examples/MiniLock/prim/Blake2s.cry
Normal file
@ -0,0 +1,686 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module Blake2s where
|
||||
|
||||
type Block = [16][32]
|
||||
type State = [8][32]
|
||||
type LocalState = [16][32]
|
||||
type BCounter = [64]
|
||||
|
||||
type Context = { state : State, counter : BCounter }
|
||||
|
||||
// Block size
|
||||
bbVal : [64]
|
||||
bbVal = 64
|
||||
|
||||
|
||||
IV : [8][32]
|
||||
IV = [ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||||
]
|
||||
|
||||
SIGMA_TABLE : [10][16][4]
|
||||
SIGMA_TABLE =
|
||||
[ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ]
|
||||
, [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ]
|
||||
, [ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ]
|
||||
, [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ]
|
||||
, [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ]
|
||||
, [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ]
|
||||
, [ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ]
|
||||
, [ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ]
|
||||
, [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ]
|
||||
, [ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ]
|
||||
]
|
||||
|
||||
// Section 2.1 constants
|
||||
R1,R2,R3,R4 : [6]
|
||||
R1 = 16
|
||||
R2 = 12
|
||||
R3 = 08
|
||||
R4 = 07
|
||||
|
||||
// Section 3.1: Mixing function 'G'
|
||||
G : [4] -> [4] -> LocalState -> [4][6] -> Block -> [16][32]
|
||||
G r i vec abcd ms = foldl updateVector vec (zip abcd new)
|
||||
where
|
||||
new = G' r i (vec @@ abcd) ms
|
||||
|
||||
G' : [4] -> [4] -> [4][32] -> Block -> [4][32]
|
||||
G' r i vals ms = [a2, b2, c2, d2]
|
||||
where
|
||||
x = ms @ (SIGMA_TABLE @ r @ (2*i))
|
||||
y = ms @ (SIGMA_TABLE @ r @ (2*i+1))
|
||||
[a,b,c,d] = vals
|
||||
a1 = a + b + x
|
||||
d1 = (d ^ a1) >>> R1
|
||||
c1 = c + d1
|
||||
b1 = (b ^ c1) >>> R2
|
||||
a2 = a1 + b1 + y
|
||||
d2 = (d1 ^ a2) >>> R3
|
||||
c2 = c1 + d2
|
||||
b2 = (b1 ^ c2) >>> R4
|
||||
|
||||
// Section 3.2: Compression function
|
||||
F : State -> Block -> BCounter -> Bit -> State
|
||||
F h ms t f = h ^ (take (vs!0)) ^ (drop (vs!0))
|
||||
where
|
||||
v = h # IV ^ (zero # [t0,t1,f0,zero])
|
||||
[t1,t0] = split t : [2][32]
|
||||
f0 = [f | _ <- [0..31] : [_][6]]
|
||||
vs = [v] # [ round i ms v' | v' <- vs | i <- [0..9] ]
|
||||
|
||||
// Sub-function of F (first for loop)
|
||||
round : [4] -> Block -> LocalState -> LocalState
|
||||
round r ms v = vs ! 0
|
||||
where
|
||||
vs = [v] # [ G r i v' ix ms
|
||||
| v' <- vs
|
||||
| i <- [0..7]
|
||||
| ix <- [ [0,4,8,12], [1,5,9,13]
|
||||
, [2,6,10,14], [3,7,11,15]
|
||||
, [0,5,10,15], [1,6,11,12]
|
||||
, [2,7,8,13], [3,4,9,14] ]
|
||||
]
|
||||
|
||||
// Section 3.3: Padding
|
||||
// Recall kk == key bytes (0)
|
||||
// nn == hash bytes (32)
|
||||
// ll == input bytes (ceiling $ len / 8)
|
||||
// bb == block bytes (64, 1024 bits)
|
||||
// dd == nr Blocks
|
||||
|
||||
blake2s : {ll,nn} (fin ll, 32 >= nn, 64 >= width ll)
|
||||
=> [ll][8] -> [nn*8]
|
||||
blake2s m = blake2s' `{ll=ll,nn=nn} m
|
||||
|
||||
blake2s' : {ll,dd,nn}
|
||||
(fin ll
|
||||
, 32 >= nn
|
||||
, dd == (max 1 ((ll+63)/64)) - 1
|
||||
, 64 >= width ll
|
||||
)
|
||||
=> [ll][8]
|
||||
-> [nn*8]
|
||||
blake2s' m = take `{nn*8} (blake2sFinish ({ state = (hs!0).state, counter = `ll}) lastBlock)
|
||||
where
|
||||
|
||||
fullBlocks : [dd]Block
|
||||
fullBlocks = [mkBlock b | b <- split (join (take `{front=64*dd,back=ll-64*dd} m))]
|
||||
|
||||
partialBlock = drop `{front=64*dd,back=ll-64*dd} m
|
||||
|
||||
lastBlock : Block
|
||||
lastBlock =
|
||||
if (`ll == (zero:[64]))
|
||||
then zero // Special case full zero block for empty messages
|
||||
else mkBlock ((split (join (partialBlock # (zero : [inf][8]))))@0)
|
||||
|
||||
h : Context
|
||||
h = { state = [IV@0 ^ `0x01010000 ^ `nn] # drop `{1} IV, counter = 0 }
|
||||
|
||||
hs : [dd+1]Context
|
||||
hs = [h] # [blake2Update h' dX | h' <- hs | dX <- fullBlocks]
|
||||
|
||||
blake2Update : Context -> Block -> Context
|
||||
blake2Update ctx d = { state = newState, counter = newCount }
|
||||
where newState = F ctx.state d newCount False
|
||||
newCount = ctx.counter + (64 : [64])
|
||||
|
||||
postprocess : {ll} (64 >= ll, 64 >= width ll) => BCounter -> [ll][8] -> Block
|
||||
postprocess c m =
|
||||
if c == 0 && `ll == (zero:[64])
|
||||
then zero
|
||||
else split (join m # zero)
|
||||
|
||||
// The final round of blake
|
||||
blake2sFinish : Context -> Block -> [256]
|
||||
blake2sFinish ctx b = join [ reverseBytes w | w <- F ctx.state b ctx.counter True ]
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Utilities
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
mkBlock x = reverse (split (reverseBytes x))
|
||||
|
||||
reverseBytes x = join (reverse (bytes x))
|
||||
|
||||
bytes x = split x : [_] [8]
|
||||
|
||||
|
||||
// XXX can probably do a cleaner merge-sort style update.
|
||||
updateVector : {a, b, c} (c >= width (a-1), a >= 1, fin a, fin c) => [a]b -> ([c], b) -> [a]b
|
||||
updateVector orig idxNew = vs
|
||||
where
|
||||
idx = idxNew.0
|
||||
new = idxNew.1
|
||||
vs = [if i == idx then new else orig@i | i <- [0..a-1]]
|
||||
|
||||
|
||||
property katsPass = ~zero ==
|
||||
[ nthKat `{0}
|
||||
, nthKat `{1}
|
||||
, nthKat `{2}
|
||||
, nthKat `{3}
|
||||
, nthKat `{4}
|
||||
, nthKat `{5}
|
||||
, nthKat `{6}
|
||||
, nthKat `{7}
|
||||
, nthKat `{8}
|
||||
, nthKat `{9}
|
||||
, nthKat `{10}
|
||||
, nthKat `{11}
|
||||
, nthKat `{12}
|
||||
, nthKat `{13}
|
||||
, nthKat `{14}
|
||||
, nthKat `{15}
|
||||
, nthKat `{16}
|
||||
, nthKat `{17}
|
||||
, nthKat `{18}
|
||||
, nthKat `{19}
|
||||
, nthKat `{20}
|
||||
, nthKat `{21}
|
||||
, nthKat `{22}
|
||||
, nthKat `{23}
|
||||
, nthKat `{24}
|
||||
, nthKat `{25}
|
||||
, nthKat `{26}
|
||||
, nthKat `{27}
|
||||
, nthKat `{28}
|
||||
, nthKat `{29}
|
||||
, nthKat `{30}
|
||||
, nthKat `{31}
|
||||
, nthKat `{32}
|
||||
, nthKat `{33}
|
||||
, nthKat `{34}
|
||||
, nthKat `{35}
|
||||
, nthKat `{36}
|
||||
, nthKat `{37}
|
||||
, nthKat `{38}
|
||||
, nthKat `{39}
|
||||
, nthKat `{40}
|
||||
, nthKat `{41}
|
||||
, nthKat `{42}
|
||||
, nthKat `{43}
|
||||
, nthKat `{44}
|
||||
, nthKat `{45}
|
||||
, nthKat `{46}
|
||||
, nthKat `{47}
|
||||
, nthKat `{48}
|
||||
, nthKat `{49}
|
||||
, nthKat `{50}
|
||||
, nthKat `{51}
|
||||
, nthKat `{52}
|
||||
, nthKat `{53}
|
||||
, nthKat `{54}
|
||||
, nthKat `{55}
|
||||
, nthKat `{56}
|
||||
, nthKat `{57}
|
||||
, nthKat `{58}
|
||||
, nthKat `{59}
|
||||
, nthKat `{60}
|
||||
, nthKat `{61}
|
||||
, nthKat `{62}
|
||||
, nthKat `{63}
|
||||
, nthKat `{64}
|
||||
, nthKat `{65}
|
||||
, nthKat `{66}
|
||||
, nthKat `{67}
|
||||
, nthKat `{68}
|
||||
, nthKat `{69}
|
||||
, nthKat `{70}
|
||||
, nthKat `{71}
|
||||
, nthKat `{72}
|
||||
, nthKat `{73}
|
||||
, nthKat `{74}
|
||||
, nthKat `{75}
|
||||
, nthKat `{76}
|
||||
, nthKat `{77}
|
||||
, nthKat `{78}
|
||||
, nthKat `{79}
|
||||
, nthKat `{80}
|
||||
, nthKat `{81}
|
||||
, nthKat `{82}
|
||||
, nthKat `{83}
|
||||
, nthKat `{84}
|
||||
, nthKat `{85}
|
||||
, nthKat `{86}
|
||||
, nthKat `{87}
|
||||
, nthKat `{88}
|
||||
, nthKat `{89}
|
||||
, nthKat `{90}
|
||||
, nthKat `{91}
|
||||
, nthKat `{92}
|
||||
, nthKat `{93}
|
||||
, nthKat `{94}
|
||||
, nthKat `{95}
|
||||
, nthKat `{96}
|
||||
, nthKat `{97}
|
||||
, nthKat `{98}
|
||||
, nthKat `{99}
|
||||
, nthKat `{100}
|
||||
, nthKat `{101}
|
||||
, nthKat `{102}
|
||||
, nthKat `{103}
|
||||
, nthKat `{104}
|
||||
, nthKat `{105}
|
||||
, nthKat `{106}
|
||||
, nthKat `{107}
|
||||
, nthKat `{108}
|
||||
, nthKat `{109}
|
||||
, nthKat `{110}
|
||||
, nthKat `{111}
|
||||
, nthKat `{112}
|
||||
, nthKat `{113}
|
||||
, nthKat `{114}
|
||||
, nthKat `{115}
|
||||
, nthKat `{116}
|
||||
, nthKat `{117}
|
||||
, nthKat `{118}
|
||||
, nthKat `{119}
|
||||
, nthKat `{120}
|
||||
, nthKat `{121}
|
||||
, nthKat `{122}
|
||||
, nthKat `{123}
|
||||
, nthKat `{124}
|
||||
, nthKat `{125}
|
||||
, nthKat `{126}
|
||||
, nthKat `{127}
|
||||
, nthKat `{128}
|
||||
, nthKat `{129}
|
||||
, nthKat `{130}
|
||||
, nthKat `{131}
|
||||
, nthKat `{132}
|
||||
, nthKat `{133}
|
||||
, nthKat `{134}
|
||||
, nthKat `{135}
|
||||
, nthKat `{136}
|
||||
, nthKat `{137}
|
||||
, nthKat `{138}
|
||||
, nthKat `{139}
|
||||
, nthKat `{140}
|
||||
, nthKat `{141}
|
||||
, nthKat `{142}
|
||||
, nthKat `{143}
|
||||
, nthKat `{144}
|
||||
, nthKat `{145}
|
||||
, nthKat `{146}
|
||||
, nthKat `{147}
|
||||
, nthKat `{148}
|
||||
, nthKat `{149}
|
||||
, nthKat `{150}
|
||||
, nthKat `{151}
|
||||
, nthKat `{152}
|
||||
, nthKat `{153}
|
||||
, nthKat `{154}
|
||||
, nthKat `{155}
|
||||
, nthKat `{156}
|
||||
, nthKat `{157}
|
||||
, nthKat `{158}
|
||||
, nthKat `{159}
|
||||
, nthKat `{160}
|
||||
, nthKat `{161}
|
||||
, nthKat `{162}
|
||||
, nthKat `{163}
|
||||
, nthKat `{164}
|
||||
, nthKat `{165}
|
||||
, nthKat `{166}
|
||||
, nthKat `{167}
|
||||
, nthKat `{168}
|
||||
, nthKat `{169}
|
||||
, nthKat `{170}
|
||||
, nthKat `{171}
|
||||
, nthKat `{172}
|
||||
, nthKat `{173}
|
||||
, nthKat `{174}
|
||||
, nthKat `{175}
|
||||
, nthKat `{176}
|
||||
, nthKat `{177}
|
||||
, nthKat `{178}
|
||||
, nthKat `{179}
|
||||
, nthKat `{180}
|
||||
, nthKat `{181}
|
||||
, nthKat `{182}
|
||||
, nthKat `{183}
|
||||
, nthKat `{184}
|
||||
, nthKat `{185}
|
||||
, nthKat `{186}
|
||||
, nthKat `{187}
|
||||
, nthKat `{188}
|
||||
, nthKat `{189}
|
||||
, nthKat `{190}
|
||||
, nthKat `{191}
|
||||
, nthKat `{192}
|
||||
, nthKat `{193}
|
||||
, nthKat `{194}
|
||||
, nthKat `{195}
|
||||
, nthKat `{196}
|
||||
, nthKat `{197}
|
||||
, nthKat `{198}
|
||||
, nthKat `{199}
|
||||
, nthKat `{200}
|
||||
, nthKat `{201}
|
||||
, nthKat `{202}
|
||||
, nthKat `{203}
|
||||
, nthKat `{204}
|
||||
, nthKat `{205}
|
||||
, nthKat `{206}
|
||||
, nthKat `{207}
|
||||
, nthKat `{208}
|
||||
, nthKat `{209}
|
||||
, nthKat `{210}
|
||||
, nthKat `{211}
|
||||
, nthKat `{212}
|
||||
, nthKat `{213}
|
||||
, nthKat `{214}
|
||||
, nthKat `{215}
|
||||
, nthKat `{216}
|
||||
, nthKat `{217}
|
||||
, nthKat `{218}
|
||||
, nthKat `{219}
|
||||
, nthKat `{220}
|
||||
, nthKat `{221}
|
||||
, nthKat `{222}
|
||||
, nthKat `{223}
|
||||
, nthKat `{224}
|
||||
, nthKat `{225}
|
||||
, nthKat `{226}
|
||||
, nthKat `{227}
|
||||
, nthKat `{228}
|
||||
, nthKat `{229}
|
||||
, nthKat `{230}
|
||||
, nthKat `{231}
|
||||
, nthKat `{232}
|
||||
, nthKat `{233}
|
||||
, nthKat `{234}
|
||||
, nthKat `{235}
|
||||
, nthKat `{236}
|
||||
, nthKat `{237}
|
||||
, nthKat `{238}
|
||||
, nthKat `{239}
|
||||
, nthKat `{240}
|
||||
, nthKat `{241}
|
||||
, nthKat `{242}
|
||||
, nthKat `{243}
|
||||
, nthKat `{244}
|
||||
, nthKat `{245}
|
||||
, nthKat `{246}
|
||||
, nthKat `{247}
|
||||
, nthKat `{248}
|
||||
, nthKat `{249}
|
||||
, nthKat `{250}
|
||||
, nthKat `{251}
|
||||
, nthKat `{252}
|
||||
, nthKat `{253}
|
||||
, nthKat `{254}
|
||||
, nthKat `{255}
|
||||
]
|
||||
|
||||
|
||||
nthKat : {n} (fin n, 8 >= width n) => Bit
|
||||
nthKat = blake2s (nthKatInput `{n}) == kats @ (`n : [8])
|
||||
|
||||
nthKatInput : {n} (fin n) => [n][8]
|
||||
nthKatInput = take ([0 ... ] : [inf][8])
|
||||
|
||||
kats = [ 0x69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9
|
||||
, 0xe34d74dbaf4ff4c6abd871cc220451d2ea2648846c7757fbaac82fe51ad64bea
|
||||
, 0xddad9ab15dac4549ba42f49d262496bef6c0bae1dd342a8808f8ea267c6e210c
|
||||
, 0xe8f91c6ef232a041452ab0e149070cdd7dd1769e75b3a5921be37876c45c9900
|
||||
, 0x0cc70e00348b86ba2944d0c32038b25c55584f90df2304f55fa332af5fb01e20
|
||||
, 0xec1964191087a4fe9df1c795342a02ffc191a5b251764856ae5b8b5769f0c6cd
|
||||
, 0xe1fa51618d7df4eb70cf0d5a9e906f806e9d19f7f4f01e3b621288e4120405d6
|
||||
, 0x598001fafbe8f94ec66dc827d012cfcbba2228569f448e89ea2208c8bf769293
|
||||
, 0xc7e887b546623635e93e0495598f1726821996c2377705b93a1f636f872bfa2d
|
||||
, 0xc315a437dd28062a770d481967136b1b5eb88b21ee53d0329c5897126e9db02c
|
||||
, 0xbb473deddc055fea6228f207da575347bb00404cd349d38c18026307a224cbff
|
||||
, 0x687e1873a8277591bb33d9adf9a13912efefe557cafc39a7952623e47255f16d
|
||||
, 0x1ac7ba754d6e2f94e0e86c46bfb262abbb74f450ef456d6b4d97aa80ce6da767
|
||||
, 0x012c97809614816b5d9494477d4b687d15b96eb69c0e8074a8516f31224b5c98
|
||||
, 0x91ffd26cfa4da5134c7ea262f7889c329f61f6a657225cc212f40056d986b3f4
|
||||
, 0xd97c828d8182a72180a06a78268330673f7c4e0635947c04c02323fd45c0a52d
|
||||
, 0xefc04cdc391c7e9119bd38668a534e65fe31036d6a62112e44ebeb11f9c57080
|
||||
, 0x992cf5c053442a5fbc4faf583e04e50bb70d2f39fbb6a503f89e56a63e18578a
|
||||
, 0x38640e9f21983e67b539caccae5ecf615ae2764f75a09c9c59b76483c1fbc735
|
||||
, 0x213dd34c7efe4fb27a6b35f6b4000d1fe03281af3c723e5c9f94747a5f31cd3b
|
||||
, 0xec246eeeb9ced3f7ad33ed28660dd9bb0732513db4e2fa278b60cde3682a4ccd
|
||||
, 0xac9b61d446648c3005d7892bf3a8719f4c8181cfdcbc2b79fef10a279b911095
|
||||
, 0x7bf8b22959e34e3a43f7079223e83a9754617d391e213dfd808e41b9bead4ce7
|
||||
, 0x68d4b5d4fa0e302b64ccc5af792913ac4c88ec95c07ddf40694256eb88ce9f3d
|
||||
, 0xb2c2420f05f9abe36315919336b37e4e0fa33ff7e76a492767006fdb5d935462
|
||||
, 0x134f61bbd0bbb69aed5343904551a3e6c1aa7dcdd77e903e7023eb7c60320aa7
|
||||
, 0x4693f9bff7d4f3986a7d176e6e06f72ad1490d805c99e25347b8de77b4db6d9b
|
||||
, 0x853e26f741953b0fd5bdb424e8ab9e8b3750eaa8ef61e47902c91e554e9c73b9
|
||||
, 0xf7de536361abaa0e158156cf0ea4f63a99b5e4054f8fa4c9d45f6285cad55694
|
||||
, 0x4c230608860a99ae8d7bd5c2cc17fa52096b9a61bedb17cb7617864ad29ca7a6
|
||||
, 0xaeb920ea87952dadb1fb759291e3388139a872865001886ed84752e93c250c2a
|
||||
, 0xaba4ad9b480b9df3d08ca5e87b0c2440d4e4ea21224c2eb42cbae469d089b931
|
||||
, 0x05825607d7fdf2d82ef4c3c8c2aea961ad98d60edff7d018983e21204c0d93d1
|
||||
, 0xa742f8b6af82d8a6ca2357c5f1cf91defbd066267d75c048b352366585025962
|
||||
, 0x2bcac89599000b42c95ae23835a713704ed79789c84fef149a874ff733f017a2
|
||||
, 0xac1ed07d048f105a9e5b7ab85b09a492d5baff14b8bfb0e9fd789486eea2b974
|
||||
, 0xe48d0ecfaf497d5b27c25d99e156cb0579d440d6e31fb62473696dbf95e010e4
|
||||
, 0x12a91fadf8b21644fd0f934f3c4a8f62ba862ffd20e8e961154c15c13884ed3d
|
||||
, 0x7cbee96e139897dc98fbef3be81ad4d964d235cb12141fb66727e6e5df73a878
|
||||
, 0xebf66abb597ae572a7297cb0871e355accafad8377b8e78bf164ce2a18de4baf
|
||||
, 0x71b933b07e4ff7818ce059d008829e453c6ff02ec0a7db393fc2d870f37a7286
|
||||
, 0x7cf7c51331220b8d3ebaed9c29398a16d98156e2613cb088f2b0e08a1be4cf4f
|
||||
, 0x3e41a108e0f64ad276b979e1ce068279e16f7bc7e4aa1d211e17b81161df1602
|
||||
, 0x886502a82ab47ba8d86710aa9de3d46ea65c47af6ee8de450cceb8b11b045f50
|
||||
, 0xc021bc5f0954fee94f46ea09487e10a84840d02f64810bc08d9e551f7d416814
|
||||
, 0x2030516e8a5fe19ae79c336fce26382a749d3fd0ec91e537d4bd2358c12dfb22
|
||||
, 0x556698dac8317fd36dfbdf25a79cb112d5425860605cbaf507f23bf7e9f42afe
|
||||
, 0x2f867ba67773fdc3e92fced99a6409ad39d0b880fde8f109a81730c4451d0178
|
||||
, 0x172ec218f119dfae98896dff29dd9876c94af87417f9ae4c7014bb4e4b96afc7
|
||||
, 0x3f85814a18195f879aa962f95d26bd82a278f2b82320218f6b3bd6f7f667a6d9
|
||||
, 0x1b618fbaa566b3d498c12e982c9ec52e4da85a8c54f38f34c090394f23c184c1
|
||||
, 0x0c758fb5692ffd41a3575d0af00cc7fbf2cbe5905a58323a88ae4244f6e4c993
|
||||
, 0xa931360cad628c7f12a6c1c4b753b0f4062aef3ce65a1ae3f19369dadf3ae23d
|
||||
, 0xcbac7d773b1e3b3c6691d7abb7e9df045c8ba19268ded153207f5e804352ec5d
|
||||
, 0x23a196d3802ed3c1b384019a82325840d32f71950c4580b03445e0898e14053c
|
||||
, 0xf4495470f226c8c214be08fdfad4bc4a2a9dbea9136a210df0d4b64929e6fc14
|
||||
, 0xe290dd270b467f34ab1c002d340fa016257ff19e5833fdbbf2cb401c3b2817de
|
||||
, 0x9fc7b5ded3c15042b2a6582dc39be016d24a682d5e61ad1eff9c63309848f706
|
||||
, 0x8cca67a36d17d5e6341cb592fd7bef9926c9e3aa1027ea11a7d8bd260b576e04
|
||||
, 0x409392f560f86831da4373ee5e0074260595d7bc24183b60ed700d4583d3f6f0
|
||||
, 0x2802165de090915546f3398cd849164a19f92adbc361adc99b0f20c8ea071054
|
||||
, 0xad839168d9f8a4be95ba9ef9a692f07256ae43fe6f9864e290691b0256ce50a9
|
||||
, 0x75fdaa5038c284b86d6e8affe8b2807e467b86600e79af3689fbc06328cbf894
|
||||
, 0xe57cb79487dd57902432b250733813bd96a84efce59f650fac26e6696aefafc3
|
||||
, 0x56f34e8b96557e90c1f24b52d0c89d51086acf1b00f634cf1dde9233b8eaaa3e
|
||||
, 0x1b53ee94aaf34e4b159d48de352c7f0661d0a40edff95a0b1639b4090e974472
|
||||
, 0x05705e2a81757c14bd383ea98dda544eb10e6bc07bae435e2518dbe133525375
|
||||
, 0xd8b2866e8a309db53e529ec32911d82f5ca16cff76216891a9676aa31aaa6c42
|
||||
, 0xf5041c241270eb04c71ec2c95d4c38d803b1237b0f29fd4db3eb397669e88699
|
||||
, 0x9a4ce077c349322f595e0ee79ed0da5fab66752cbfef8f87d0e9d0723c7530dd
|
||||
, 0x657b09f3d0f52b5b8f2f97163a0edf0c04f075408a07bbeb3a4101a891990d62
|
||||
, 0x1e3f7bd5a58fa533344aa8ed3ac122bb9e70d4ef50d004530821948f5fe6315a
|
||||
, 0x80dccf3fd83dfd0d35aa28585922ab89d5313997673eaf905cea9c0b225c7b5f
|
||||
, 0x8a0d0fbf6377d83bb08b514b4b1c43acc95d751714f8925645cb6bc856ca150a
|
||||
, 0x9fa5b487738ad2844cc6348a901918f659a3b89e9c0dfeead30dd94bcf42ef8e
|
||||
, 0x80832c4a1677f5ea2560f668e9354dd36997f03728cfa55e1b38337c0c9ef818
|
||||
, 0xab37ddb683137e74080d026b590b96ae9bb447722f305a5ac570ec1df9b1743c
|
||||
, 0x3ee735a694c2559b693aa68629361e15d12265ad6a3dedf488b0b00fac9754ba
|
||||
, 0xd6fcd23219b647e4cbd5eb2d0ad01ec8838a4b2901fc325cc3701981ca6c888b
|
||||
, 0x0520ec2f5bf7a755dacb50c6bf233e3515434763db0139ccd9faefbb8207612d
|
||||
, 0xaff3b75f3f581264d7661662b92f5ad37c1d32bd45ff81a4ed8adc9ef30dd989
|
||||
, 0xd0dd650befd3ba63dc25102c627c921b9cbeb0b130686935b5c927cb7ccd5e3b
|
||||
, 0xe1149816b10a8514fb3e2cab2c08bee9f73ce76221701246a589bbb67302d8a9
|
||||
, 0x7da3f441de9054317e72b5dbf979da01e6bceebb8478eae6a22849d90292635c
|
||||
, 0x1230b1fc8a7d9215edc2d4a2decbdd0a6e216c924278c91fc5d10e7d60192d94
|
||||
, 0x5750d716b4808f751febc38806ba170bf6d5199a7816be514e3f932fbe0cb871
|
||||
, 0x6fc59b2f10feba954aa6820b3ca987ee81d5cc1da3c63ce827301c569dfb39ce
|
||||
, 0xc7c3fe1eebdc7b5a939326e8ddb83e8bf2b780b65678cb62f208b040abdd35e2
|
||||
, 0x0c75c1a15cf34a314ee478f4a5ce0b8a6b36528ef7a820696c3e4246c5a15864
|
||||
, 0x216dc12a108569a3c7cdde4aed43a6c330139dda3ccc4a108905db3861899050
|
||||
, 0xa57be6ae6756f28b02f59dadf7e0d7d8807f10fa15ced1ad3585521a1d995a89
|
||||
, 0x816aef875953716cd7a581f732f53dd435dab66d09c361d2d6592de17755d8a8
|
||||
, 0x9a76893226693b6ea97e6a738f9d10fb3d0b43ae0e8b7d8123ea76ce97989c7e
|
||||
, 0x8daedb9a271529dbb7dc3b607fe5eb2d3211770758dd3b0a3593d2d7954e2d5b
|
||||
, 0x16dbc0aa5dd2c774f505100f733786d8a175fcbbb59c43e1fbff3e1eaf31cb4a
|
||||
, 0x8606cb899c6aeaf51b9db0fe4924a9fd5dabc19f8826f2bc1c1d7da14d2c2c99
|
||||
, 0x8479731aeda57bd37eadb51a507e307f3bd95e69dbca94f3bc21726066ad6dfd
|
||||
, 0x58473a9ea82efa3f3b3d8fc83ed8863127b33ae8deae6307201edb6dde61de29
|
||||
, 0x9a9255d53af116de8ba27ce35b4c7e15640657a0fcb888c70d95431dacd8f830
|
||||
, 0x9eb05ffba39fd8596a45493e18d2510bf3ef065c51d6e13abe66aa57e05cfdb7
|
||||
, 0x81dcc3a505eace3f879d8f702776770f9df50e521d1428a85daf04f9ad2150e0
|
||||
, 0xe3e3c4aa3acbbc85332af9d564bc24165e1687f6b1adcbfae77a8f03c72ac28c
|
||||
, 0x6746c80b4eb56aea45e64e7289bba3edbf45ecf8206481ff6302122984cd526a
|
||||
, 0x2b628e52764d7d62c0868b212357cdd12d9149822f4e9845d918a08d1ae990c0
|
||||
, 0xe4bfe80d58c91994613909dc4b1a12496896c004af7b5701483de45d2823d78e
|
||||
, 0xebb4ba150cef2734345b5d641bbed03a21eafae933c99e009212ef04574a8530
|
||||
, 0x3966ec73b154acc697ac5cf5b24b40bdb0db9e398836d76d4b880e3b2af1aa27
|
||||
, 0xef7e4831b3a84636518d6e4bfce64a43db2a5dda9cca2b44f39033bdc40d6243
|
||||
, 0x7abf6acf5c8e549ddbb15ae8d8b388c1c197e698737c9785501ed1f94930b7d9
|
||||
, 0x88018ded66813f0ca95def474c630692019967b9e36888dadd94124719b682f6
|
||||
, 0x3930876b9fc7529036b008b1b8bb997522a441635a0c25ec02fb6d9026e55a97
|
||||
, 0x0a4049d57e833b5695fac93dd1fbef3166b44b12ad11248662383ae051e15827
|
||||
, 0x81dcc0678bb6a765e48c3209654fe90089ce44ff5618477e39ab286476df052b
|
||||
, 0xe69b3a36a4461912dc08346b11ddcb9db796f885fd01936e662fe29297b099a4
|
||||
, 0x5ac6503b0d8da6917646e6dcc87edc58e94245324cc204f4dd4af01563acd427
|
||||
, 0xdf6dda21359a30bc271780971c1abd56a6ef167e480887888e73a86d3bf605e9
|
||||
, 0xe8e6e47071e7b7df2580f225cfbbedf84ce67746626628d33097e4b7dc571107
|
||||
, 0x53e40ead62051e19cb9ba8133e3e5c1ce00ddcad8acf342a224360b0acc14777
|
||||
, 0x9ccd53fe80be786aa984638462fb28afdf122b34d78f4687ec632bb19de2371a
|
||||
, 0xcbd48052c48d788466a3e8118c56c97fe146e5546faaf93e2bc3c47e45939753
|
||||
, 0x256883b14e2af44dadb28e1b34b2ac0f0f4c91c34ec9169e29036158acaa95b9
|
||||
, 0x4471b91ab42db7c4dd8490ab95a2ee8d04e3ef5c3d6fc71ac74b2b26914d1641
|
||||
, 0xa5eb08038f8f1155ed86e631906fc13095f6bba41de5d4e795758ec8c8df8af1
|
||||
, 0xdc1db64ed8b48a910e060a6b866374c578784e9ac49ab2774092ac71501934ac
|
||||
, 0x285413b2f2ee873d34319ee0bbfbb90f32da434cc87e3db5ed121bb398ed964b
|
||||
, 0x0216e0f81f750f26f1998bc3934e3e124c9945e685a60b25e8fbd9625ab6b599
|
||||
, 0x38c410f5b9d4072050755b31dca89fd5395c6785eeb3d790f320ff941c5a93bf
|
||||
, 0xf18417b39d617ab1c18fdf91ebd0fc6d5516bb34cf39364037bce81fa04cecb1
|
||||
, 0x1fa877de67259d19863a2a34bcc6962a2b25fcbf5cbecd7ede8f1fa36688a796
|
||||
, 0x5bd169e67c82c2c2e98ef7008bdf261f2ddf30b1c00f9e7f275bb3e8a28dc9a2
|
||||
, 0xc80abeebb669ad5deeb5f5ec8ea6b7a05ddf7d31ec4c0a2ee20b0b98caec6746
|
||||
, 0xe76d3fbda5ba374e6bf8e50fadc3bbb9ba5c206ebdec89a3a54cf3dd84a07016
|
||||
, 0x7bba9dc5b5db2071d17752b1044c1eced96aaf2dd46e9b433750e8ea0dcc1870
|
||||
, 0xf29b1b1ab9bab163018ee3da15232cca78ec52dbc34eda5b822ec1d80fc21bd0
|
||||
, 0x9ee3e3e7e900f1e11d308c4b2b3076d272cf70124f9f51e1da60f37846cdd2f4
|
||||
, 0x70ea3b0176927d9096a18508cd123a290325920a9d00a89b5de04273fbc76b85
|
||||
, 0x67de25c02a4aaba23bdc973c8bb0b5796d47cc0659d43dff1f97de174963b68e
|
||||
, 0xb2168e4e0f18b0e64100b517ed95257d73f0620df885c13d2ecf79367b384cee
|
||||
, 0x2e7dec2428853b2c71760745541f7afe9825b5dd77df06511d8441a94bacc927
|
||||
, 0xca9ffac4c43f0b48461dc5c263bea3f6f00611ceacabf6f895ba2b0101dbb68d
|
||||
, 0x7410d42d8fd1d5e9d2f5815cb93417998828ef3c4230bfbd412df0a4a7a2507a
|
||||
, 0x5010f684516dccd0b6ee0852c2512b4dc0066cf0d56f35302978db8ae32c6a81
|
||||
, 0xacaab585f7b79b719935ceb89523ddc54827f75c56883856154a56cdcd5ee988
|
||||
, 0x666de5d1440fee7331aaf0123a62ef2d8ba57453a0769635ac6cd01e633f7712
|
||||
, 0xa6f98658f6eabaf902d8b3871a4b101d16196e8a4b241e1558fe29966e103e8d
|
||||
, 0x891546a8b29f3047ddcfe5b00e45fd55756373105ea8637dfcff547b6ea9535f
|
||||
, 0x18dfbc1ac5d25b0761137dbd22c17c829d0f0ef1d82344e9c89c286694da24e8
|
||||
, 0xb54b9b67f8fed54bbf5a2666dbdf4b23cff1d1b6f4afc985b2e6d3305a9ff80f
|
||||
, 0x7db442e132ba59bc1289aa98b0d3e806004f8ec12811af1e2e33c69bfde729e1
|
||||
, 0x250f37cdc15e817d2f160d9956c71fe3eb5db74556e4adf9a4ffafba74010396
|
||||
, 0x4ab8a3dd1ddf8ad43dab13a27f66a6544f290597fa96040e0e1db9263aa479f8
|
||||
, 0xee61727a0766df939ccdc860334044c79a3c9b156200bc3aa32973483d8341ae
|
||||
, 0x3f68c7ec63ac11ebb98f94b339b05c104984fda50103060144e5a2bfccc9da95
|
||||
, 0x056f29816b8af8f56682bc4d7cf094111da7733e726cd13d6b3e8ea03e92a0d5
|
||||
, 0xf5ec43a28acbeff1f3318a5bcac7c66ddb5230b79db2d105bcbe15f3c1148d69
|
||||
, 0x2a6960ad1d8dd547555cfbd5e4600f1eaa1c8eda34de0374ec4a26eaaaa33b4e
|
||||
, 0xdcc1ea7baab93384f76b796866199754742f7b96d6b4c120165c04a6c4f5ce10
|
||||
, 0x13d5df179221379c6a78c07c793ff53487cae6bf9fe882541ab0e735e3eada3b
|
||||
, 0x8c59e4407641a01e8ff91f9980dc236f4ecd6fcf52589a099a961633967714e1
|
||||
, 0x833b1ac6a251fd08fd6d908fea2a4ee1e040bca93fc1a38ec3820e0c10bd82ea
|
||||
, 0xa244f927f3b40b8f6c391570c765418f2f6e708eac9006c51a7feff4af3b2b9e
|
||||
, 0x3d99ed9550cf1196e6c4d20c259620f858c3d703374c128ce7b590310c83046d
|
||||
, 0x2b35c47d7b87761f0ae43ac56ac27b9f25830367b595be8c240e94600c6e3312
|
||||
, 0x5d11ed37d24dc767305cb7e1467d87c065ac4bc8a426de38991ff59aa8735d02
|
||||
, 0xb836478e1ca0640dce6fd910a5096272c8330990cd97864ac2bf14ef6b23914a
|
||||
, 0x9100f946d6ccde3a597f90d39fc1215baddc7413643d85c21c3eee5d2dd32894
|
||||
, 0xda70eedd23e663aa1a74b9766935b479222a72afba5c795158dad41a3bd77e40
|
||||
, 0xf067ed6a0dbd43aa0a9254e69fd66bdd8acb87de936c258cfb02285f2c11fa79
|
||||
, 0x715c99c7d57580cf9753b4c1d795e45a83fbb228c0d36fbe20faf39bdd6d4e85
|
||||
, 0xe457d6ad1e67cb9bbd17cbd698fa6d7dae0c9b7ad6cbd6539634e32a719c8492
|
||||
, 0xece3ea8103e02483c64a70a4bdcee8ceb6278f2533f3f48dbeedfba94531d4ae
|
||||
, 0x388aa5d3667a97c68d3d56f8f3ee8d3d36091f17fe5d1b0d5d84c93b2ffe40bd
|
||||
, 0x8b6b31b9ad7c3d5cd84bf98947b9cdb59df8a25ff738101013be4fd65e1dd1a3
|
||||
, 0x066291f6bbd25f3c853db7d8b95c9a1cfb9bf1c1c99fb95a9b7869d90f1c2903
|
||||
, 0xa707efbccdceed42967a66f5539b93ed7560d467304016c4780d7755a565d4c4
|
||||
, 0x38c53dfb70be7e792b07a6a35b8a6a0aba02c5c5f38baf5c823fdfd9e42d657e
|
||||
, 0xf2911386501d9ab9d720cf8ad10503d5634bf4b7d12b56dfb74fecc6e4093f68
|
||||
, 0xc6f2bdd52b81e6e4f6595abd4d7fb31f651169d00ff326926b34947b28a83959
|
||||
, 0x293d94b18c98bb3223366b8ce74c28fbdf28e1f84a3350b0eb2d1804a577579b
|
||||
, 0x2c2fa5c0b51533165bc375c22e2781768270a383985d13bd6b67b6fd67f889eb
|
||||
, 0xcaa09b82b72562e43f4b2275c091918e624d911661cc811bb5faec51f6088ef7
|
||||
, 0x24761e45e674395379fb17729c78cb939e6f74c5dffb9c961f495982c3ed1fe3
|
||||
, 0x55b70a82131ec94888d7ab54a7c515255c3938bb10bc784dc9b67f076e341a73
|
||||
, 0x6ab9057b977ebc3ca4d4ce74506c25cccdc566497c450b5415a39486f8657a03
|
||||
, 0x24066deee0ecee15a45f0a326d0f8dbc79761ebb93cf8c0377af440978fcf994
|
||||
, 0x20000d3f66ba76860d5a950688b9aa0d76cfea59b005d859914b1a46653a939b
|
||||
, 0xb92daa79603e3bdbc3bfe0f419e409b2ea10dc435beefe2959da16895d5dca1c
|
||||
, 0xe947948705b206d572b0e8f62f66a6551cbd6bc305d26ce7539a12f9aadf7571
|
||||
, 0x3d67c1b3f9b23910e3d35e6b0f2ccf44a0b540a45c18ba3c36264dd48e96af6a
|
||||
, 0xc7558babda04bccb764d0bbf3358425141902d22391d9f8c59159fec9e49b151
|
||||
, 0x0b732bb035675a50ff58f2c242e4710aece64670079c13044c79c9b7491f7000
|
||||
, 0xd120b5ef6d57ebf06eaf96bc933c967b16cbe6e2bf00741c30aa1c54ba64801f
|
||||
, 0x58d212ad6f58aef0f80116b441e57f6195bfef26b61463edec1183cdb04fe76d
|
||||
, 0xb8836f51d1e29bdfdba325565360268b8fad627473edecef7eaefee837c74003
|
||||
, 0xc547a3c124ae5685ffa7b8edaf96ec86f8b2d0d50cee8be3b1f0c76763069d9c
|
||||
, 0x5d168b769a2f67853d6295f7568be40bb7a16b8d65ba87635d1978d2ab11ba2a
|
||||
, 0xa2f675dc7302638cb60201064ca55077714d71fe096a315f2fe7401277caa5af
|
||||
, 0xc8aab5cd0160ae78cd2e8ac5fb0e093cdb5c4b6052a0a97bb04216826fa7a437
|
||||
, 0xff68ca4035bfeb43fbf145fddd5e43f1cea54f11f7bee13058f027329a4a5fa4
|
||||
, 0x1d4e5487ae3c740f2ba6e541ac91bc2bfcd2999c518d807b426748803a350fd4
|
||||
, 0x6d244e1a06ce4ef578dd0f63aff0936706735119ca9c8d22d86c801414ab9741
|
||||
, 0xdecf7329dbcc827b8fc524c9431e8998029ece12ce93b7b2f3e769a941fb8cea
|
||||
, 0x2fafcc0f2e63cbd07755be7b75ecea0adff9aa5ede2a52fdab4dfd0374cd483f
|
||||
, 0xaa85010dd46a546b535ef4cf5f07d65161e89828f3a77db7b9b56f0df59aae45
|
||||
, 0x07e8e1ee732cb0d356c9c0d1069c89d17adf6a9a334f745ec7867332548ca8e9
|
||||
, 0x0e01e81cada8162bfd5f8a8c818a6c69fedf02ceb5208523cbe5313b89ca1053
|
||||
, 0x6bb6c6472655084399852e00249f8cb247896d392b02d73b7f0dd818e1e29b07
|
||||
, 0x42d4636e2060f08f41c882e76b396b112ef627cc24c43dd5f83a1d1a7ead711a
|
||||
, 0x4858c9a188b0234fb9a8d47d0b4133650a030bd0611b87c3892e94951f8df852
|
||||
, 0x3fab3e36988d445a51c8783e531be3a02be40cd04796cfb61d40347442d3f794
|
||||
, 0xebabc49636bd433d2ec8f0e518732ef8fa21d4d071cc3bc46cd79fa38a28b810
|
||||
, 0xa1d0343523b893fca84f47feb4a64d350a17d8eef5497ece697d02d79178b591
|
||||
, 0x262ebfd9130b7d28760d08ef8bfd3b86cdd3b2113d2caef7ea951a303dfa3846
|
||||
, 0xf76158edd50a154fa78203ed2362932fcb8253aae378903eded1e03f7021a257
|
||||
, 0x26178e950ac722f67ae56e571b284c0207684a6334a17748a94d260bc5f55274
|
||||
, 0xc378d1e493b40ef11fe6a15d9c2737a37809634c5abad5b33d7e393b4ae05d03
|
||||
, 0x984bd8379101be8fd80612d8ea2959a7865ec9718523550107ae3938df32011b
|
||||
, 0xc6f25a812a144858ac5ced37a93a9f4759ba0b1c0fdc431dce35f9ec1f1f4a99
|
||||
, 0x924c75c94424ff75e74b8b4e94358958b027b171df5e57899ad0d4dac37353b6
|
||||
, 0x0af35892a63f45931f6846ed190361cd073089e077165714b50b81a2e3dd9ba1
|
||||
, 0xcc80cefb26c3b2b0daef233e606d5ffc80fa17427d18e30489673e06ef4b87f7
|
||||
, 0xc2f8c8117447f3978b0818dcf6f70116ac56fd184dd1278494e103fc6d74a887
|
||||
, 0xbdecf6bfc1ba0df6e862c831992207796acc797968358828c06e7a51e090098f
|
||||
, 0x24d1a26e3dab02fe4572d2aa7dbd3ec30f0693db26f273d0ab2cb0c13b5e6451
|
||||
, 0xec56f58b09299a300b140565d7d3e68782b6e2fbeb4b7ea97ac057989061dd3f
|
||||
, 0x11a437c1aba3c119ddfab31b3e8c841deeeb913ef57f7e48f2c9cf5a28fa42bc
|
||||
, 0x53c7e6114b850a2cb496c9b3c69a623eaea2cb1d33dd817e4765edaa6823c228
|
||||
, 0x154c3e96fee5db14f8773e18af14857913509da999b46cdd3d4c169760c83ad2
|
||||
, 0x40b9916f093e027a8786641818920620472fbcf68f701d1b680632e6996bded3
|
||||
, 0x24c4cbba07119831a726b05305d96da02ff8b148f0da440fe233bcaa32c72f6f
|
||||
, 0x5d201510250020b783689688abbf8ecf2594a96a08f2bfec6ce0574465dded71
|
||||
, 0x043b97e336ee6fdbbe2b50f22af83275a4084805d2d5645962454b6c9b8053a0
|
||||
, 0x564835cbaea774948568be36cf52fcdd83934eb0a27512dbe3e2db47b9e6635a
|
||||
, 0xf21c33f47bde40a2a101c9cde8027aaf61a3137de2422b30035a04c270894183
|
||||
, 0x9db0ef74e66cbb842eb0e07343a03c5c567e372b3f23b943c788a4f250f67891
|
||||
, 0xab8d08655ff1d3fe8758d562235fd23e7cf9dcaad658872a49e5d3183b6ccebd
|
||||
, 0x6f27f77e7bcf46a1e963ade0309733543031dccdd47caac174d7d27ce8077e8b
|
||||
, 0xe3cd54da7e444caa6207569525a670ebae1278de4e3fe2684b3e33f5ef90cc1b
|
||||
, 0xb2c3e33a51d22c4c08fc0989c873c9cc4150579b1e6163fa694ad51d53d712dc
|
||||
, 0xbe7fda983e13189b4c77e0a80920b6e0e0ea80c3b84dbe7e7117d253f48112f4
|
||||
, 0xb6008c28fae08aa427e5bd3aad36f10021f16c77cfeabed07f97cc7dc1f1284a
|
||||
, 0x6e4e6760c538f2e97b3adbfbbcde57f8966b7ea8fcb5bf7efec913fd2a2b0c55
|
||||
, 0x4ae51fd1834aa5bd9a6f7ec39fc663338dc5d2e20761566d90cc68b1cb875ed8
|
||||
, 0xb673aad75ab1fdb5401abfa1bf89f3add2ebc468df3624a478f4fe859d8d55e2
|
||||
, 0x13c9471a9855913539836660398da0f3f99ada08479c69d1b7fcaa3461dd7e59
|
||||
, 0x2c11f4a7f99a1d23a58bb636350fe849f29cbac1b2a1112d9f1ed5bc5b313ccd
|
||||
, 0xc7d3c0706b11ae741c05a1ef150dd65b5494d6d54c9a86e2617854e6aeeebbd9
|
||||
, 0x194e10c93893afa064c3ac04c0dd808d791c3d4b7556e89d8d9cb225c4b33339
|
||||
, 0x6fc4988b8f78546b1688991845908f134b6a482e6994b3d48317bf08db292185
|
||||
, 0x5665beb8b0955525813b5981cd142ed4d03fba38a6f3e5ad268e0cc270d1cd11
|
||||
, 0xb883d68f5fe51936431ba4256738053b1d0426d4cb64b16e83badc5e9fbe3b81
|
||||
, 0x53e7b27ea59c2f6dbb50769e43554df35af89f4822d0466b007dd6f6deafff02
|
||||
, 0x1f1a0229d4640f01901588d9dec22d13fc3eb34a61b32938efbf5334b2800afa
|
||||
, 0xc2b405afa0fa6668852aee4d88040853fab800e72b57581418e5506f214c7d1f
|
||||
, 0xc08aa1c286d709fdc7473744977188c895ba011014247e4efa8d07e78fec695c
|
||||
, 0xf03f5789d3336b80d002d59fdf918bdb775b00956ed5528e86aa994acb38fe2d
|
||||
]
|
||||
|
1071
examples/MiniLock/prim/CfrgCurves.md
Normal file
1071
examples/MiniLock/prim/CfrgCurves.md
Normal file
File diff suppressed because it is too large
Load Diff
61
examples/MiniLock/prim/CryptoBox.cry
Normal file
61
examples/MiniLock/prim/CryptoBox.cry
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
|
||||
|
||||
module CryptoBox where
|
||||
|
||||
import Salsa20
|
||||
import Poly1305
|
||||
import CfrgCurves
|
||||
|
||||
crypto_box : {msgBytes} (fin msgBytes, 2^^64 >= msgBytes + 32) => [msgBytes][8] -> [24][8] -> Public25519 -> Private25519 -> [msgBytes + 16][8]
|
||||
crypto_box m n pub priv = crypto_secretbox m k n
|
||||
where
|
||||
s = Curve25519 priv pub
|
||||
k = HSalsa20_bytes `{r=20} s zero
|
||||
|
||||
crypto_box_open : {msgBytes} (fin msgBytes, 2^^64 >= msgBytes + 32) => [msgBytes+16][8] -> [24][8] -> Public25519 -> Private25519 -> (Bit,[msgBytes][8])
|
||||
crypto_box_open box n pub priv = crypto_secretbox_open box k n
|
||||
where
|
||||
(tag,ct) = splitAt `{16} box
|
||||
s = Curve25519 priv pub
|
||||
k = HSalsa20_bytes `{r=20} s zero
|
||||
|
||||
crypto_secretbox : {msgBytes} (fin msgBytes, 2^^64 >= msgBytes + 32)
|
||||
=> [msgBytes][8] -> [32][8] -> [24][8] -> [msgBytes + 16][8]
|
||||
crypto_secretbox m k n = box
|
||||
where
|
||||
blob = XSalsa20_encrypt `{r=20} k n ((zero : [32][8]) # m)
|
||||
authKey = join (take `{32} blob)
|
||||
ciphertext = drop `{32} blob
|
||||
authTag = Poly1305 authKey ciphertext
|
||||
box = authTag # ciphertext
|
||||
|
||||
crypto_secretbox_open : {msgBytes} (fin msgBytes, 2^^64 >= msgBytes + 32)
|
||||
=> [msgBytes + 16][8] -> [32][8] -> [24][8] -> (Bit,[msgBytes][8])
|
||||
crypto_secretbox_open box k n = (valid,pt)
|
||||
where
|
||||
(tag,ct) = splitAt `{16} box
|
||||
blob = XSalsa20_encrypt `{r=20} k n ((zero : [32][8]) # ct)
|
||||
authKey = join (take `{32} blob)
|
||||
plaintext = drop blob : [msgBytes][8]
|
||||
cTag = Poly1305 authKey ct
|
||||
valid = cTag == tag
|
||||
pt = if valid then plaintext else zero
|
||||
|
||||
property cat_in_a_box priv1 priv2 msg nonce = open == msg
|
||||
where pub1 = Curve25519 priv1 basePoint25519
|
||||
pub2 = Curve25519 priv2 basePoint25519
|
||||
box = crypto_box (msg : [100][8]) nonce pub2 priv1
|
||||
open = (crypto_box_open box nonce pub1 priv2).1
|
||||
|
||||
property hat_in_a_box k msg nonce = open == msg
|
||||
where box = crypto_secretbox (msg : [88][8]) k nonce
|
||||
open = (crypto_secretbox_open box k nonce).1
|
||||
|
||||
property crypto_box_kats = zero != [ katTest1 ]
|
||||
|
||||
// KAT generated from sodium
|
||||
katTest1 = crypto_secretbox "hello" zero zero == split 0xc769f9d535dc338e99ac93440502c7ceae5bd79391
|
58
examples/MiniLock/prim/HMAC.cry
Normal file
58
examples/MiniLock/prim/HMAC.cry
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module HMAC where
|
||||
|
||||
import SHA256
|
||||
|
||||
hmacSHA256 : {pwBytes, msgBytes}
|
||||
(fin pwBytes, fin msgBytes
|
||||
, 32 >= width msgBytes
|
||||
, 64 >= width (8*pwBytes)
|
||||
, 64 >= width (8 * (64 + msgBytes))
|
||||
// Keeping cryptol <2.3 happy
|
||||
, max 6 (width pwBytes) >= 6
|
||||
, max 6 (width pwBytes) >= width pwBytes
|
||||
, max 7 (width pwBytes) >= 7
|
||||
, max 7 (width pwBytes) >= width pwBytes
|
||||
, max (width pwBytes) 7 >= 7
|
||||
, max (width pwBytes) 7 >= width pwBytes
|
||||
) => [pwBytes][8] -> [msgBytes][8] -> [256]
|
||||
hmacSHA256 = hmac `{blockLength=64} SHA256 SHA256 SHA256
|
||||
|
||||
// Due to limitations of the type system we must accept two
|
||||
// separate arguments (both aledgedly the same) for two
|
||||
// separate length inputs.
|
||||
hmac : { msgBytes, pwBytes, digest, blockLength }
|
||||
( fin pwBytes, fin digest, fin blockLength
|
||||
// Keeping cryptol <2.3 happy
|
||||
, max (width digest) (width pwBytes) >= width pwBytes // XXX cryptol! width digest == width pwBytes
|
||||
, max (width digest) (width pwBytes) >= width digest
|
||||
, max (width blockLength) (width pwBytes) >= width blockLength
|
||||
, max (width blockLength) (width pwBytes) >= width pwBytes
|
||||
, max (width pwBytes) (width blockLength) >= width blockLength
|
||||
, max (width pwBytes) (width blockLength) >= width pwBytes
|
||||
)
|
||||
=> ([blockLength + msgBytes][8] -> [8*digest])
|
||||
-> ([blockLength + digest][8] -> [8*digest])
|
||||
-> ([pwBytes][8] -> [8*digest])
|
||||
-> [pwBytes][8]
|
||||
-> [msgBytes][8]
|
||||
-> [digest*8]
|
||||
hmac hash hash2 hash3 key message = hash2 (okey # internal)
|
||||
where
|
||||
ks : [blockLength][8]
|
||||
ks = if `pwBytes > (`blockLength : [max (width pwBytes) (width blockLength)])
|
||||
then take `{blockLength} (split (hash3 key) # (zero : [blockLength][8]))
|
||||
else take `{blockLength} (key # (zero : [blockLength][8]))
|
||||
okey = [k ^ 0x5C | k <- ks]
|
||||
ikey = [k ^ 0x36 | k <- ks]
|
||||
internal = split (hash (ikey # message))
|
||||
|
||||
property pass =
|
||||
~zero ==
|
||||
[ hmacSHA256 [0x0b | _ <- [1..20] : [_][6]] "Hi There" == 0xb0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7
|
||||
, hmacSHA256 "Jefe" "what do ya want for nothing?" == 0x5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
|
||||
]
|
||||
|
21
examples/MiniLock/prim/LittleEndian.cry
Normal file
21
examples/MiniLock/prim/LittleEndian.cry
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module LittleEndian where
|
||||
|
||||
|
||||
// Takes a finite sequence of bytes, and turns them into a word via
|
||||
// a little-endian interpretation
|
||||
littleendian : {a}(fin a) => [a][8] -> [a*8]
|
||||
littleendian b = join(reverse b)
|
||||
|
||||
property littleendian_passes_tests =
|
||||
(littleendian [ 0, 0, 0, 0] == 0x00000000) &&
|
||||
(littleendian [ 86, 75, 30, 9] == 0x091e4b56) &&
|
||||
(littleendian [255, 255, 255, 250] == 0xfaffffff)
|
||||
|
||||
littleendian_inverse : [32] -> [4][8]
|
||||
littleendian_inverse b = reverse(split b)
|
||||
|
||||
property littleendian_is_invertable b = littleendian_inverse(littleendian b) == b
|
73
examples/MiniLock/prim/PBKDF2.cry
Normal file
73
examples/MiniLock/prim/PBKDF2.cry
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module PBKDF2 where
|
||||
|
||||
import SHA256
|
||||
import HMAC
|
||||
|
||||
// PBKDF2 specialized to HMAC_SHA256 to avoid monomorphic type issues.
|
||||
pbkdf2 : {pwBytes, saltBytes, dkLenBits, len, C}
|
||||
( 32 >= width (pwBytes*8), len == (dkLenBits + 255)/256
|
||||
, len >= 1, 32 >= width len, fin saltBytes, fin dkLenBits, fin pwBytes
|
||||
, 64 >= width (8 * (pwBytes + (4 + saltBytes)))
|
||||
, 64 >= width (8 * (pwBytes + 32))
|
||||
, C >= 1, fin C, 64 >= width (8*(pwBytes + (2 + saltBytes))), 16 >= width C
|
||||
, 16 >= width len
|
||||
// cryptol < 2.3 can't math!
|
||||
, dkLenBits == 256 * len // Cryptol 2.3 doesn't understand 'take'?
|
||||
, max 6 (width pwBytes) >= width pwBytes
|
||||
, max 6 (width pwBytes) >= 6
|
||||
, max 7 (width pwBytes) >= 7
|
||||
, max 7 (width pwBytes) >= width pwBytes
|
||||
, max (width pwBytes) 7 >= 7
|
||||
, max (width pwBytes) 7 >= width pwBytes
|
||||
, 64 >= width (8 * pwBytes)
|
||||
, 64 >= width (8 * (68 + saltBytes))
|
||||
, 32 >= width (4 + saltBytes)
|
||||
)
|
||||
=> [pwBytes][8] -> [saltBytes][8] -> [dkLenBits]
|
||||
pbkdf2 P S = take `{dkLenBits} (join Ts)
|
||||
where
|
||||
Ts : [_][256]
|
||||
Ts = [ inner `{C=C} P (split (hmacSHA256 P (S # split i))) | i <- [1..len] : [_][32] ]
|
||||
|
||||
inner : {pwBytes, C}
|
||||
( fin pwBytes
|
||||
, 64 >= width (8 * (pwBytes + 32))
|
||||
, fin C, C >= 1, 16 >= width C
|
||||
// Cryptol < 2.3 can't math
|
||||
, 64 >= width (8 * pwBytes)
|
||||
, max 7 (width pwBytes) >= width pwBytes
|
||||
, max 7 (width pwBytes) >= 7
|
||||
, max (width pwBytes) 7 >= width pwBytes
|
||||
, max (width pwBytes) 7 >= 7
|
||||
, max 6 (width pwBytes) >= width pwBytes
|
||||
, max 6 (width pwBytes) >= 6
|
||||
)
|
||||
=> [pwBytes][8] -> [32][8] -> [256]
|
||||
inner P U0 = (Ts @ 0).0 // XXX should be ! 0
|
||||
where
|
||||
// Ts : [_][([256],[32][8])]
|
||||
Ts = [(join U0, U0)] # [ F P t u | _ <- [1..C] : [_][16] | (t,u) <- Ts ]
|
||||
|
||||
F : {pwBytes} (fin pwBytes
|
||||
, 64 >= width (8*(32+pwBytes))
|
||||
// cryptol < 2.3 can't math
|
||||
, 64 >= width (8 * pwBytes)
|
||||
, max 7 (width pwBytes) >= width pwBytes
|
||||
, max 7 (width pwBytes) >= 7
|
||||
, max (width pwBytes) 7 >= width pwBytes
|
||||
, max (width pwBytes) 7 >= 7
|
||||
, max 6 (width pwBytes) >= width pwBytes
|
||||
, max 6 (width pwBytes) >= 6
|
||||
) => [pwBytes][8] -> [256] -> [32][8] -> ([256],[32][8])
|
||||
F P Tprev Uprev = (Tnext,Unext)
|
||||
where
|
||||
Unext = split (hmacSHA256 P Uprev)
|
||||
Tnext = Tprev ^ join Unext
|
||||
|
||||
|
||||
test1 : Bit
|
||||
property test1 = pbkdf2 `{C=1,dkLenBits=64*8} "passwd" "salt" == 0x55ac046e56e3089fec1691c22544b605f94185216dde0465e68b9d57c20dacbc49ca9cccf179b645991664b39d77ef317c71b845b1e30bd509112041d3a19783
|
686
examples/MiniLock/prim/Poly1305.md
Normal file
686
examples/MiniLock/prim/Poly1305.md
Normal file
@ -0,0 +1,686 @@
|
||||
% Poly1305 for IETF protocols
|
||||
% Y. Nir (Check Point), A. Langley (Google Inc), D. McNamee (Galois, Inc)
|
||||
% July 28, 2014
|
||||
%
|
||||
% Poly1305 extracted from the original RFC by Thomas DuBuisson
|
||||
|
||||
```cryptol
|
||||
module Poly1305 where
|
||||
```
|
||||
|
||||
|
||||
# The Poly1305 algorithm
|
||||
|
||||
Poly1305 is a one-time authenticator designed by D. J. Bernstein.
|
||||
Poly1305 takes a 32-byte one-time key and a message and produces a
|
||||
16-byte tag.
|
||||
|
||||
The original article ([poly1305]) is entitled "The Poly1305-AES
|
||||
message-authentication code", and the MAC function there requires a
|
||||
128-bit AES key, a 128-bit "additional key", and a 128-bit (non-
|
||||
secret) nonce. AES is used there for encrypting the nonce, so as to
|
||||
get a unique (and secret) 128-bit string, but as the paper states,
|
||||
"There is nothing special about AES here. One can replace AES with
|
||||
an arbitrary keyed function from an arbitrary set of nonces to 16-
|
||||
byte strings."
|
||||
|
||||
Regardless of how the key is generated, the key is partitioned into
|
||||
two parts, called "r" and "s". The pair ``(r,s)`` should be unique, and
|
||||
MUST be unpredictable for each invocation (that is why it was
|
||||
originally obtained by encrypting a nonce), while "r" MAY be
|
||||
constant, but needs to be modified as follows before being used: ("r"
|
||||
is treated as a 16-octet little-endian number):
|
||||
|
||||
* r[3], r[7], r[11], and r[15] are required to have their top four
|
||||
bits clear (be smaller than 16)
|
||||
|
||||
```cryptol
|
||||
Om = 15 // odd masks - for 3, 7, 11 & 15
|
||||
```
|
||||
* r[4], r[8], and r[12] are required to have their bottom two bits
|
||||
clear (be divisible by 4)
|
||||
|
||||
The following Cryptol code clamps "r" to be appropriate:
|
||||
|
||||
```cryptol
|
||||
Em = 252 // even masks - for 4, 8 & 12
|
||||
nm = 255 // no mask
|
||||
|
||||
PolyMasks : [16][8] // mask indices
|
||||
PolyMasks = [ nm, nm, nm, Om, // 0-3
|
||||
Em, nm, nm, Om, // 4-7
|
||||
Em, nm, nm, Om, // 8-11
|
||||
Em, nm, nm, Om ] // 12-15
|
||||
|
||||
Poly1305_clamp : [16][8] -> [16][8]
|
||||
Poly1305_clamp r = [ re && mask | re <- r | mask <- PolyMasks ]
|
||||
```
|
||||
|
||||
The "s" should be unpredictable, but it is perfectly acceptable to
|
||||
generate both "r" and "s" uniquely each time. Because each of them
|
||||
is 128-bit, pseudo-randomly generating them (see "Generating the
|
||||
Poly1305 key using ChaCha20") is also acceptable.
|
||||
|
||||
The inputs to Poly1305 are:
|
||||
|
||||
* A 256-bit one-time key
|
||||
* An arbitrary length message (comprised of `floorBlocks` 16-byte blocks,
|
||||
and `rem` bytes left over)
|
||||
|
||||
The output is a 128-bit tag.
|
||||
|
||||
```cryptol
|
||||
Poly1305 : {m, floorBlocks, rem} (fin m, floorBlocks == m/16, rem == m - floorBlocks*16)
|
||||
=> [256] -> [m][8] -> [16][8]
|
||||
```
|
||||
|
||||
Set the constant prime "P" be 2^130-5.
|
||||
|
||||
```cryptol
|
||||
P : [136]
|
||||
P = 2^^130 - 5
|
||||
```
|
||||
|
||||
First, the "r" value should be clamped.
|
||||
|
||||
```cryptol
|
||||
Poly1305 key msg = result where
|
||||
[ru, su] = split key
|
||||
r : [136] // internal arithmetic on (128+8)-bit numbers
|
||||
r = littleendian ((Poly1305_clamp (split ru)) # [0x00])
|
||||
s = littleendian ((split su) # [0x00])
|
||||
```
|
||||
|
||||
Next, divide the message into 16-byte blocks. The last block might be shorter:
|
||||
|
||||
* Read each block as a little-endian number.
|
||||
* Add one bit beyond the number of octets. For a 16-byte block this
|
||||
is equivalent to adding 2^128 to the number. For the shorter
|
||||
block it can be 2^120, 2^112, or any power of two that is evenly
|
||||
divisible by 8, all the way down to 2^8.
|
||||
|
||||
```cryptol
|
||||
// pad all the blocks uniformly (we'll handle the final block later)
|
||||
paddedBlocks = [ 0x01 # (littleendian block)
|
||||
| block <- groupBy`{16}(msg # (zero:[inf][8])) ]
|
||||
```
|
||||
* If the block is not 17 bytes long (the last block), then left-pad it with
|
||||
zeros. This is meaningless if you're treating them as numbers.
|
||||
|
||||
```cryptol
|
||||
lastBlock : [136]
|
||||
lastBlock = zero # 0x01 # (littleendian (drop`{16*floorBlocks} msg))
|
||||
```
|
||||
|
||||
* Add the current block to the accumulator.
|
||||
* Multiply by "r"
|
||||
* Set the accumulator to the result modulo p. To summarize:
|
||||
``accum[i+1] = ((accum[i]+block)*r) % p``.
|
||||
|
||||
```cryptol
|
||||
accum:[_][136]
|
||||
accum = [zero:[136]] # [ computeElt a b r P | a <- accum | b <- paddedBlocks ]
|
||||
// ^ the accumulator starts at zero
|
||||
```
|
||||
|
||||
* If the block division leaves no remainder, the last value of the accumulator is good
|
||||
otherwise compute the special-case padded block, and compute the final value of the accumulator
|
||||
|
||||
```cryptol
|
||||
lastAccum : [136]
|
||||
lastAccum = if `rem == 0
|
||||
then accum@`floorBlocks
|
||||
else computeElt (accum@`floorBlocks) lastBlock r P
|
||||
```
|
||||
|
||||
Finally, the value of the secret key "s" is added to the accumulator,
|
||||
and the 128 least significant bits are serialized in little-endian
|
||||
order to form the tag.
|
||||
|
||||
```cryptol
|
||||
result = reverse (groupBy`{8} (drop`{8}(lastAccum + s)))
|
||||
|
||||
// Compute ((a + b) * r ) % P being pedantic about bit-widths
|
||||
computeElt : [136] -> [136] -> [136] -> [136] -> [136]
|
||||
computeElt a b r p = (drop`{137}bigResult) where
|
||||
bigResult : [273]
|
||||
aPlusB : [137]
|
||||
aPlusB = (0b0#a) + (0b0#b) // make room for carry
|
||||
timesR : [273]
|
||||
timesR = ((zero:[136])#aPlusB) * ((zero:[137])#r) // [a]*[b]=[a+b]
|
||||
bigResult = timesR % ((zero:[137])#p)
|
||||
|
||||
```
|
||||
|
||||
### Poly1305 Example and Test Vector
|
||||
|
||||
For our example, we will dispense with generating the one-time key
|
||||
using AES, and assume that we got the following keying material:
|
||||
|
||||
* Key Material: 85:d6:be:78:57:55:6d:33:7f:44:52:fe:42:d5:06:a8:01:
|
||||
03:80:8a:fb:0d:b2:fd:4a:bf:f6:af:41:49:f5:1b
|
||||
|
||||
```cryptol
|
||||
Poly1305TestKey = join (parseHexString
|
||||
( "85:d6:be:78:57:55:6d:33:7f:44:52:fe:42:d5:06:a8:01:"
|
||||
# "03:80:8a:fb:0d:b2:fd:4a:bf:f6:af:41:49:f5:1b."
|
||||
) )
|
||||
```
|
||||
|
||||
* s as an octet string: 01:03:80:8a:fb:0d:b2:fd:4a:bf:f6:af:41:49:f5:1b
|
||||
* s as a 128-bit number: 1bf54941aff6bf4afdb20dfb8a800301
|
||||
|
||||
```cryptol
|
||||
Poly1305Test_s = parseHexString
|
||||
"01:03:80:8a:fb:0d:b2:fd:4a:bf:f6:af:41:49:f5:1b."
|
||||
Poly1305Test_sbits = join (reverse Poly1305Test_s)
|
||||
|
||||
property poly1306Sokay = Poly1305Test_sbits == 0x1bf54941aff6bf4afdb20dfb8a800301
|
||||
```
|
||||
|
||||
|
||||
```cryptol
|
||||
Poly1305TestMessage = "Cryptographic Forum Research Group"
|
||||
```
|
||||
|
||||
* r before clamping: 85:d6:be:78:57:55:6d:33:7f:44:52:fe:42:d5:06:a8
|
||||
* Clamped r as a number: 806d5400e52447c036d555408bed685.
|
||||
|
||||
Since Poly1305 works in 16-byte chunks, the 34-byte message divides
|
||||
into 3 blocks. In the following calculation, "Acc" denotes the
|
||||
accumulator and "Block" the current block:
|
||||
|
||||
Here we define a Cryptol function that returns all of the intermediate
|
||||
values of the accumulator:
|
||||
|
||||
```cryptol
|
||||
// TODO: refactor the Poly function in terms of this AccumBlocks
|
||||
// challenge: doing so while maintaining the clean literate correspondence with the spec
|
||||
AccumBlocks : {m, floorBlocks, rem} (fin m, floorBlocks == m/16, rem == m - floorBlocks*16)
|
||||
=> [256] -> [m][8] -> ([_][136], [136])
|
||||
|
||||
AccumBlocks key msg = (accum, lastAccum) where
|
||||
[ru, su] = split key
|
||||
r : [136] // internal arithmetic on (128+8)-bit numbers
|
||||
r = littleendian ((Poly1305_clamp (split ru)) # [0x00])
|
||||
s = littleendian ((split su) # [0x00])
|
||||
// pad all the blocks uniformly (we'll handle the final block later)
|
||||
paddedBlocks = [ 0x01 # (littleendian block)
|
||||
| block <- groupBy`{16}(msg # (zero:[inf][8])) ]
|
||||
lastBlock : [136]
|
||||
lastBlock = zero # 0x01 # (littleendian (drop`{16*floorBlocks} msg))
|
||||
accum:[_][136]
|
||||
accum = [zero:[136]] # [ computeElt a b r P | a <- accum | b <- paddedBlocks ]
|
||||
// ^ the accumulator starts at zero
|
||||
lastAccum : [136]
|
||||
lastAccum = if `rem == 0
|
||||
then accum@`floorBlocks
|
||||
else computeElt (accum@`floorBlocks) lastBlock r P
|
||||
|
||||
```
|
||||
|
||||
```example
|
||||
Block #1
|
||||
|
||||
Acc = 00
|
||||
Block = 6f4620636968706172676f7470797243
|
||||
Block with 0x01 byte = 016f4620636968706172676f7470797243
|
||||
Acc + block = 016f4620636968706172676f7470797243
|
||||
(Acc+Block) * r =
|
||||
b83fe991ca66800489155dcd69e8426ba2779453994ac90ed284034da565ecf
|
||||
Acc = ((Acc+Block)*r) % P = 2c88c77849d64ae9147ddeb88e69c83fc
|
||||
|
||||
Block #2
|
||||
|
||||
Acc = 2c88c77849d64ae9147ddeb88e69c83fc
|
||||
Block = 6f7247206863726165736552206d7572
|
||||
Block with 0x01 byte = 016f7247206863726165736552206d7572
|
||||
Acc + block = 437febea505c820f2ad5150db0709f96e
|
||||
(Acc+Block) * r =
|
||||
21dcc992d0c659ba4036f65bb7f88562ae59b32c2b3b8f7efc8b00f78e548a26
|
||||
Acc = ((Acc+Block)*r) % P = 2d8adaf23b0337fa7cccfb4ea344b30de
|
||||
|
||||
Last Block
|
||||
|
||||
Acc = 2d8adaf23b0337fa7cccfb4ea344b30de
|
||||
Block = 7075
|
||||
Block with 0x01 byte = 017075
|
||||
Acc + block = 2d8adaf23b0337fa7cccfb4ea344ca153
|
||||
(Acc + Block) * r =
|
||||
16d8e08a0f3fe1de4fe4a15486aca7a270a29f1e6c849221e4a6798b8e45321f
|
||||
((Acc + Block) * r) % P = 28d31b7caff946c77c8844335369d03a7
|
||||
```
|
||||
|
||||
```cryptol
|
||||
property polyBlocksOK =
|
||||
(blocks @ 1 == 0x02c88c77849d64ae9147ddeb88e69c83fc) &&
|
||||
(blocks @ 2 == 0x02d8adaf23b0337fa7cccfb4ea344b30de) &&
|
||||
(lastBlock == 0x028d31b7caff946c77c8844335369d03a7) where
|
||||
(blocks, lastBlock) = AccumBlocks Poly1305TestKey Poly1305TestMessage
|
||||
```
|
||||
|
||||
Adding s we get this number, and serialize if to get the tag:
|
||||
|
||||
Acc + s = 2a927010caf8b2bc2c6365130c11d06a8
|
||||
|
||||
Tag: a8:06:1d:c1:30:51:36:c6:c2:2b:8b:af:0c:01:27:a9
|
||||
|
||||
```cryptol
|
||||
// Putting it all together and testing:
|
||||
|
||||
Poly1305TestTag = "a8:06:1d:c1:30:51:36:c6:c2:2b:8b:af:0c:01:27:a9."
|
||||
|
||||
property Poly1305_passes_test = Poly1305 Poly1305TestKey Poly1305TestMessage ==
|
||||
parseHexString Poly1305TestTag
|
||||
```
|
||||
|
||||
## Generating the Poly1305 key using ChaCha20
|
||||
|
||||
As said in the "Poly 1305 Algorithm" section, it is acceptable to generate
|
||||
the one-time Poly1305 pseudo-randomly. This section proposes such a method.
|
||||
|
||||
To generate such a key pair (r,s), we will use the ChaCha20 block
|
||||
function described in Section 2.3. This assumes that we have a 256-
|
||||
bit session key for the MAC function, such as SK_ai and SK_ar in
|
||||
IKEv2 ([RFC5996]), the integrity key in ESP and AH, or the
|
||||
client_write_MAC_key and server_write_MAC_key in TLS. Any document
|
||||
that specifies the use of Poly1305 as a MAC algorithm for some
|
||||
protocol must specify that 256 bits are allocated for the integrity
|
||||
key. Note that in the AEAD construction defined in Section 2.8, the
|
||||
same key is used for encryption and key generation, so the use of
|
||||
SK_a* or *_write_MAC_key is only for stand-alone Poly1305.
|
||||
|
||||
The method is to call the block function with the following
|
||||
parameters:
|
||||
|
||||
* The 256-bit session integrity key is used as the ChaCha20 key.
|
||||
* The block counter is set to zero.
|
||||
* The protocol will specify a 96-bit or 64-bit nonce. This MUST be
|
||||
unique per invocation with the same key, so it MUST NOT be
|
||||
randomly generated. A counter is a good way to implement this,
|
||||
but other methods, such as an LFSR are also acceptable. ChaCha20
|
||||
as specified here requires a 96-bit nonce. So if the provided
|
||||
nonce is only 64-bit, then the first 32 bits of the nonce will be
|
||||
set to a constant number. This will usually be zero, but for
|
||||
protocols with multiple senders it may be different for each
|
||||
sender, but should be the same for all invocations of the function
|
||||
with the same key by a particular sender.
|
||||
|
||||
After running the block function, we have a 512-bit state. We take
|
||||
the first 256 bits or the serialized state, and use those as the one-
|
||||
time Poly1305 key: The first 128 bits are clamped, and form "r",
|
||||
while the next 128 bits become "s". The other 256 bits are
|
||||
discarded.
|
||||
|
||||
Note that while many protocols have provisions for a nonce for
|
||||
encryption algorithms (often called Initialization Vectors, or IVs),
|
||||
they usually don't have such a provision for the MAC function. In
|
||||
that case the per-invocation nonce will have to come from somewhere
|
||||
else, such as a message counter.
|
||||
|
||||
### Poly1305 Key Generation Test Vector
|
||||
|
||||
For this example, we'll set:
|
||||
|
||||
```cryptol
|
||||
PolyKeyTest = join (parseHexString (
|
||||
"80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f " #
|
||||
"90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f "
|
||||
))
|
||||
|
||||
PolyNonceTest : [96]
|
||||
PolyNonceTest = join (
|
||||
parseHexString ("00 00 00 00 00 01 02 03 04 05 06 07 "))
|
||||
```
|
||||
|
||||
The ChaCha state set up with key, nonce, and block counter zero:
|
||||
|
||||
## A Pseudo-Random Function for ChaCha/Poly-1305 based Crypto Suites
|
||||
|
||||
Some protocols such as IKEv2([RFC5996]) require a Pseudo-Random
|
||||
Function (PRF), mostly for key derivation. In the IKEv2 definition,
|
||||
a PRF is a function that accepts a variable-length key and a
|
||||
variable-length input, and returns a fixed-length output. This
|
||||
section does not specify such a function.
|
||||
|
||||
Poly-1305 is an obvious choice, because MAC functions are often used
|
||||
as PRFs. However, Poly-1305 prohibits using the same key twice,
|
||||
whereas the PRF in IKEv2 is used multiple times with the same key.
|
||||
Adding a nonce or a counter to Poly-1305 can solve this issue, much
|
||||
as we do when using this function as a MAC, but that would require
|
||||
changing the interface for the PRF function.
|
||||
|
||||
Chacha20 could be used as a key-derivation function, by generating an
|
||||
arbitrarily long keystream. However, that is not what protocols such
|
||||
as IKEv2 require.
|
||||
|
||||
For this reason, this document does not specify a PRF, and recommends
|
||||
that crypto suites use some other PRF such as PRF_HMAC_SHA2_256
|
||||
(section 2.1.2 of [RFC4868])
|
||||
|
||||
## AEAD Construction
|
||||
|
||||
AEAD_CHACHA20-POLY1305 is an authenticated encryption with additional
|
||||
data algorithm. The inputs to AEAD_CHACHA20-POLY1305 are:
|
||||
|
||||
* A 256-bit key
|
||||
* A 96-bit nonce - different for each invocation with the same key.
|
||||
* An arbitrary length plaintext (fewer than 2^64 bytes)
|
||||
* Arbitrary length additional data (AAD) (fewer than 2^64 bytes)
|
||||
|
||||
Some protocols may have unique per-invocation inputs that are not 96-
|
||||
bit in length. For example, IPsec may specify a 64-bit nonce. In
|
||||
such a case, it is up to the protocol document to define how to
|
||||
transform the protocol nonce into a 96-bit nonce, for example by
|
||||
concatenating a constant value.
|
||||
|
||||
The ChaCha20 and Poly1305 primitives are combined into an AEAD that
|
||||
takes a 256-bit key and 96-bit nonce as follows:
|
||||
|
||||
* First, a Poly1305 one-time key is generated from the 256-bit key
|
||||
and nonce using the procedure described in "Generating the Poly1305 key using ChaCha20".
|
||||
|
||||
* Next, the ChaCha20 encryption function is called to encrypt the
|
||||
plaintext, using the input key and nonce, and with the initial
|
||||
counter set to 1.
|
||||
|
||||
* Finally, the Poly1305 function is called with the Poly1305 key
|
||||
calculated above, and a message constructed as a concatenation of
|
||||
the following:
|
||||
* The AAD
|
||||
* padding1 - the padding is up to 15 zero bytes, and it brings
|
||||
the total length so far to an integral multiple of 16. If the
|
||||
length of the AAD was already an integral multiple of 16 bytes,
|
||||
this field is zero-length.
|
||||
* The ciphertext
|
||||
* padding2 - the padding is up to 15 zero bytes, and it brings
|
||||
the total length so far to an integral multiple of 16. If the
|
||||
length of the ciphertext was already an integral multiple of 16
|
||||
bytes, this field is zero-length.
|
||||
* The length of the additional data in octets (as a 64-bit
|
||||
little-endian integer).
|
||||
* The length of the ciphertext in octets (as a 64-bit little-
|
||||
endian integer).
|
||||
|
||||
The output from the AEAD is twofold:
|
||||
|
||||
* A ciphertext of the same length as the plaintext.
|
||||
* A 128-bit tag, which is the output of the Poly1305 function.
|
||||
|
||||
Decryption is pretty much the same thing.
|
||||
|
||||
A few notes about this design:
|
||||
|
||||
1. The amount of encrypted data possible in a single invocation is
|
||||
2^32-1 blocks of 64 bytes each, because of the size of the block
|
||||
counter field in the ChaCha20 block function. This gives a total
|
||||
of 247,877,906,880 bytes, or nearly 256 GB. This should be
|
||||
enough for traffic protocols such as IPsec and TLS, but may be
|
||||
too small for file and/or disk encryption. For such uses, we can
|
||||
return to the original design, reduce the nonce to 64 bits, and
|
||||
use the integer at position 13 as the top 32 bits of a 64-bit
|
||||
block counter, increasing the total message size to over a
|
||||
million petabytes (1,180,591,620,717,411,303,360 bytes to be
|
||||
exact).
|
||||
|
||||
1. Despite the previous item, the ciphertext length field in the
|
||||
construction of the buffer on which Poly1305 runs limits the
|
||||
ciphertext (and hence, the plaintext) size to 2^64 bytes, or
|
||||
sixteen thousand petabytes (18,446,744,073,709,551,616 bytes to
|
||||
be exact).
|
||||
|
||||
### Example and Test Vector for AEAD_CHACHA20-POLY1305
|
||||
|
||||
For a test vector, we will use the following inputs to the
|
||||
AEAD_CHACHA20-POLY1305 function:
|
||||
|
||||
Plaintext:
|
||||
|
||||
```cryptol
|
||||
AeadPt = "Ladies and Gentlemen of the class of '99: " #
|
||||
"If I could offer you only one tip for " #
|
||||
"the future, sunscreen would be it."
|
||||
|
||||
AeadAAD = parseHexString "50 51 52 53 c0 c1 c2 c3 c4 c5 c6 c7 "
|
||||
|
||||
AeadKey = join (parseHexString (
|
||||
"80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f " #
|
||||
"90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f " ))
|
||||
|
||||
|
||||
AeadIV = join [ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47 ]
|
||||
|
||||
AeadC = join [0x07, 0x00, 0x00, 0x00]
|
||||
|
||||
AeadNonce = AeadC # AeadIV
|
||||
```
|
||||
|
||||
32-bit fixed-common part:
|
||||
|
||||
Poly1305 Key:
|
||||
|
||||
```cryptol
|
||||
AeadConstructionTestVector = parseHexString (
|
||||
"50:51:52:53:c0:c1:c2:c3:c4:c5:c6:c7:00:00:00:00:" #
|
||||
"d3:1a:8d:34:64:8e:60:db:7b:86:af:bc:53:ef:7e:c2:" #
|
||||
"a4:ad:ed:51:29:6e:08:fe:a9:e2:b5:a7:36:ee:62:d6:" #
|
||||
"3d:be:a4:5e:8c:a9:67:12:82:fa:fb:69:da:92:72:8b:" #
|
||||
"1a:71:de:0a:9e:06:0b:29:05:d6:a5:b6:7e:cd:3b:36:" #
|
||||
"92:dd:bd:7f:2d:77:8b:8c:98:03:ae:e3:28:09:1b:58:" #
|
||||
"fa:b3:24:e4:fa:d6:75:94:55:85:80:8b:48:31:d7:bc:" #
|
||||
"3f:f4:de:f0:8e:4b:7a:9d:e5:76:d2:65:86:ce:c6:4b:" #
|
||||
"61:16:00:00:00:00:00:00:00:00:00:00:00:00:00:00:" #
|
||||
"0c:00:00:00:00:00:00:00:72:00:00:00:00:00:00:00." )
|
||||
```
|
||||
|
||||
Note the 4 zero bytes in line 000 and the 14 zero bytes in line 128
|
||||
|
||||
```cryptol
|
||||
// Tag:
|
||||
AeadTagTestVector = parseHexString "1a:e1:0b:59:4f:09:e2:6a:7e:90:2e:cb:d0:60:06:91."
|
||||
```
|
||||
|
||||
# Implementation Advice
|
||||
|
||||
Each block of ChaCha20 involves 16 move operations and one increment
|
||||
operation for loading the state, 80 each of XOR, addition and Roll
|
||||
operations for the rounds, 16 more add operations and 16 XOR
|
||||
operations for protecting the plaintext. Section 2.3 describes the
|
||||
ChaCha block function as "adding the original input words". This
|
||||
implies that before starting the rounds on the ChaCha state, we copy
|
||||
it aside, only to add it in later. This is correct, but we can save
|
||||
a few operations if we instead copy the state and do the work on the
|
||||
copy. This way, for the next block you don't need to recreate the
|
||||
state, but only to increment the block counter. This saves
|
||||
approximately 5.5% of the cycles.
|
||||
|
||||
It is not recommended to use a generic big number library such as the
|
||||
one in OpenSSL for the arithmetic operations in Poly1305. Such
|
||||
libraries use dynamic allocation to be able to handle any-sized
|
||||
integer, but that flexibility comes at the expense of performance as
|
||||
well as side-channel security. More efficient implementations that
|
||||
run in constant time are available, one of them in DJB's own library,
|
||||
NaCl ([NaCl]). A constant-time but not optimal approach would be to
|
||||
naively implement the arithmetic operations for a 288-bit integers,
|
||||
because even a naive implementation will not exceed 2^288 in the
|
||||
multiplication of (acc+block) and r. An efficient constant-time
|
||||
implementation can be found in the public domain library poly1305-
|
||||
donna ([poly1305_donna]).
|
||||
|
||||
|
||||
# Security Considerations
|
||||
|
||||
The ChaCha20 cipher is designed to provide 256-bit security.
|
||||
|
||||
The Poly1305 authenticator is designed to ensure that forged messages
|
||||
are rejected with a probability of 1-(n/(2^102)) for a 16n-byte
|
||||
message, even after sending 2^64 legitimate messages, so it is SUF-
|
||||
CMA in the terminology of [AE].
|
||||
|
||||
Proving the security of either of these is beyond the scope of this
|
||||
document. Such proofs are available in the referenced academic
|
||||
papers.
|
||||
|
||||
The most important security consideration in implementing this draft
|
||||
is the uniqueness of the nonce used in ChaCha20. Counters and LFSRs
|
||||
are both acceptable ways of generating unique nonces, as is
|
||||
encrypting a counter using a 64-bit cipher such as DES. Note that it
|
||||
is not acceptable to use a truncation of a counter encrypted with a
|
||||
128-bit or 256-bit cipher, because such a truncation may repeat after
|
||||
a short time.
|
||||
|
||||
The Poly1305 key MUST be unpredictable to an attacker. Randomly
|
||||
generating the key would fulfill this requirement, except that
|
||||
Poly1305 is often used in communications protocols, so the receiver
|
||||
should know the key. Pseudo-random number generation such as by
|
||||
encrypting a counter is acceptable. Using ChaCha with a secret key
|
||||
and a nonce is also acceptable.
|
||||
|
||||
The algorithms presented here were designed to be easy to implement
|
||||
in constant time to avoid side-channel vulnerabilities. The
|
||||
operations used in ChaCha20 are all additions, XORs, and fixed
|
||||
rotations. All of these can and should be implemented in constant
|
||||
time. Access to offsets into the ChaCha state and the number of
|
||||
operations do not depend on any property of the key, eliminating the
|
||||
chance of information about the key leaking through the timing of
|
||||
cache misses.
|
||||
|
||||
For Poly1305, the operations are addition, multiplication and
|
||||
modulus, all on >128-bit numbers. This can be done in constant time,
|
||||
but a naive implementation (such as using some generic big number
|
||||
library) will not be constant time. For example, if the
|
||||
multiplication is performed as a separate operation from the modulus,
|
||||
the result will some times be under 2^256 and some times be above
|
||||
2^256. Implementers should be careful about timing side-channels for
|
||||
Poly1305 by using the appropriate implementation of these operations.
|
||||
|
||||
|
||||
# IANA Considerations
|
||||
|
||||
There are no IANA considerations for this document.
|
||||
|
||||
|
||||
# Acknowledgements
|
||||
|
||||
ChaCha20 and Poly1305 were invented by Daniel J. Bernstein. The AEAD
|
||||
construction and the method of creating the one-time poly1305 key
|
||||
were invented by Adam Langley.
|
||||
|
||||
Thanks to Robert Ransom, Watson Ladd, Stefan Buhler, and kenny
|
||||
patterson for their helpful comments and explanations. Thanks to
|
||||
Niels Moeller for suggesting the more efficient AEAD construction in
|
||||
this document. Special thanks to Ilari Liusvaara for providing extra
|
||||
test vectors, helpful comments, and for being the first to attempt an
|
||||
implementation from this draft.
|
||||
|
||||
# References
|
||||
|
||||
## Normative References
|
||||
|
||||
```example
|
||||
[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
|
||||
Requirement Levels", BCP 14, RFC 2119, March 1997.
|
||||
|
||||
[chacha] Bernstein, D., "ChaCha, a variant of Salsa20", Jan 2008.
|
||||
|
||||
[poly1305]
|
||||
Bernstein, D., "The Poly1305-AES message-authentication
|
||||
code", Mar 2005.
|
||||
```
|
||||
|
||||
## Informative References
|
||||
|
||||
```example
|
||||
[AE] Bellare, M. and C. Namprempre, "Authenticated Encryption:
|
||||
Relations among notions and analysis of the generic
|
||||
composition paradigm",
|
||||
<http://cseweb.ucsd.edu/~mihir/papers/oem.html>.
|
||||
|
||||
[FIPS-197]
|
||||
National Institute of Standards and Technology, "Advanced
|
||||
Encryption Standard (AES)", FIPS PUB 197, November 2001.
|
||||
|
||||
[FIPS-46] National Institute of Standards and Technology, "Data
|
||||
Encryption Standard", FIPS PUB 46-2, December 1993,
|
||||
<http://www.itl.nist.gov/fipspubs/fip46-2.htm>.
|
||||
|
||||
[LatinDances]
|
||||
Aumasson, J., Fischer, S., Khazaei, S., Meier, W., and C.
|
||||
Rechberger, "New Features of Latin Dances: Analysis of
|
||||
Salsa, ChaCha, and Rumba", Dec 2007.
|
||||
|
||||
[NaCl] Bernstein, D., Lange, T., and P. Schwabe, "NaCl:
|
||||
Networking and Cryptography library",
|
||||
<http://nacl.cace-project.eu/index.html>.
|
||||
|
||||
[RFC4868] Kelly, S. and S. Frankel, "Using HMAC-SHA-256, HMAC-SHA-
|
||||
384, and HMAC-SHA-512 with IPsec", RFC 4868, May 2007.
|
||||
|
||||
[RFC5116] McGrew, D., "An Interface and Algorithms for Authenticated
|
||||
Encryption", RFC 5116, January 2008.
|
||||
|
||||
[RFC5996] Kaufman, C., Hoffman, P., Nir, Y., and P. Eronen,
|
||||
"Internet Key Exchange Protocol Version 2 (IKEv2)",
|
||||
RFC 5996, September 2010.
|
||||
|
||||
[Zhenqing2012]
|
||||
Zhenqing, S., Bin, Z., Dengguo, F., and W. Wenling,
|
||||
"Improved key recovery attacks on reduced-round salsa20
|
||||
and chacha", 2012.
|
||||
|
||||
[poly1305_donna]
|
||||
Floodyberry, A., "Poly1305-donna",
|
||||
<https://github.com/floodyberry/poly1305-donna>.
|
||||
|
||||
[standby-cipher]
|
||||
McGrew, D., Grieco, A., and Y. Sheffer, "Selection of
|
||||
Future Cryptographic Standards",
|
||||
draft-mcgrew-standby-cipher (work in progress).
|
||||
```
|
||||
|
||||
|
||||
Authors' Addresses
|
||||
|
||||
```verbatim
|
||||
Yoav Nir
|
||||
Check Point Software Technologies Ltd.
|
||||
5 Hasolelim st.
|
||||
Tel Aviv 6789735
|
||||
Israel
|
||||
Email: ynir.ietf@gmail.com
|
||||
|
||||
Adam Langley
|
||||
Google Inc
|
||||
Email: agl@google.com
|
||||
|
||||
Dylan McNamee
|
||||
Galois Inc
|
||||
Email: dylan@galois.com
|
||||
```
|
||||
|
||||
## Utilities
|
||||
|
||||
|
||||
```cryptol
|
||||
// Converts a bytestring encoded like "fe:ed:fa:ce." into a sequence of bytes
|
||||
// Note: the trailing punctuation is needed
|
||||
parseHexString : {n} (fin n) => [3*n][8] -> [n][8]
|
||||
parseHexString hexString = [ charsToByte (take`{2} cs) | cs <- groupBy`{3} hexString ] where
|
||||
charsToByte : [2][8] -> [8]
|
||||
charsToByte [ ub, lb ] = (charToByte ub) << 4 || (charToByte lb)
|
||||
charToByte c = if c >= '0' && c <= '9' then c-'0'
|
||||
| c >= 'a' && c <= 'f' then 10+(c-'a')
|
||||
else 0 // error case
|
||||
|
||||
property parseHexString_check =
|
||||
join (parseHexString
|
||||
("00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f:10:11:12:13:" #
|
||||
"14:15:16:17:18:19:1a:1b:1c:1d:1e:1f.")) ==
|
||||
0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
|
||||
|
||||
// Takes a finite sequence of bytes, and turns them into a word via
|
||||
// a little-endian interpretation
|
||||
littleendian : {a}(fin a) => [a][8] -> [a*8]
|
||||
littleendian b = join(reverse b)
|
||||
|
||||
```
|
89
examples/MiniLock/prim/SCrypt.cry
Normal file
89
examples/MiniLock/prim/SCrypt.cry
Normal file
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module SCrypt where
|
||||
|
||||
import Salsa20
|
||||
import PBKDF2
|
||||
|
||||
// SCrypt paper page 10: BlockMix specialized to Salsa20
|
||||
BlockMix : {r} (fin r, r >= 1) => [2*r][64*8] -> [2*r][64*8]
|
||||
BlockMix B = ys @@ ([0,2..2*r-2] # [1,3..2*r-1])
|
||||
where
|
||||
rs = [B!0] # [ join (Salsa20 `{r=8} (split (X ^ bi))) | X <- rs | bi <- B ]
|
||||
ys = drop `{1} rs
|
||||
|
||||
// SMix with the ROMix algorithm (section 5) inlined (specialized to BlockMix)
|
||||
// N = 2^^17
|
||||
SMix : {N,r} (fin N, fin r, r >= 1, N >= 1, 512 >= width N, 1 + width N >= width (N-1)) => [128 * 8 * r] -> [128 * 8 * r]
|
||||
SMix B = join (Xs ! 0)
|
||||
where
|
||||
Vs = [split B] # [ BlockMix x | x <- Vs | _ <- [0..N-1] : [_][width N + 1]]
|
||||
V = take `{front=N} Vs
|
||||
|
||||
Xs : [N+1][2*r][64*8]
|
||||
Xs = [Vs!0] # [ (x' where
|
||||
j = integerify x
|
||||
T = x ^ (V@j)
|
||||
x' = BlockMix T)
|
||||
| x <- Xs | _ <- [0..N-1] : [_][width N + 1] ]
|
||||
|
||||
integerify w = (join (reverse (split `{each=8} (w!0)))) % `N
|
||||
|
||||
// SCrypt paper, page 11: MFCrypt specialized to sha256 (see the 'pbkdf2' function)
|
||||
// p = 1
|
||||
MFcrypt : { pwBytes, saltBytes, dkLen, r, N }
|
||||
( fin pwBytes, fin saltBytes, fin r
|
||||
, 4*r >= 1, 16 >= width (4*r)
|
||||
, ((dkLen*8 + 255) / 256) >= 1
|
||||
, 32 >= width (8*pwBytes)
|
||||
, 32 >= width (4 + saltBytes)
|
||||
, 16 >= width ((255 + 8 * dkLen) / 256)
|
||||
, 8 * dkLen == 256 * ((255 + 8 * dkLen) / 256) // seriously cryptol?
|
||||
, fin N, N >= 1, 512 >= width N, 1+width N >= width (N-1)
|
||||
)
|
||||
=> [pwBytes][8] -> [saltBytes][8] -> [dkLen][8]
|
||||
MFcrypt P S = split DK
|
||||
where
|
||||
B = pbkdf2 `{C=1} P S
|
||||
B' = SMix `{N=N,r=r} B
|
||||
DK = pbkdf2 `{len=((dkLen*8)+255)/256,C=1} P (split B')
|
||||
|
||||
SCrypt : {pwBytes, saltBytes, dkBytes, r, N}
|
||||
( fin pwBytes, fin saltBytes, fin r
|
||||
, 4*r >= 1, 16 >= width (4*r)
|
||||
, (dkBytes * 8 + 255) / 256 >= 1
|
||||
, 16 >= width ((255 + 8 * dkBytes) / 256)
|
||||
, 8 * dkBytes == 256 * ((255 + 8 * dkBytes) / 256)
|
||||
, 32 >= width (8 * pwBytes)
|
||||
, 32 >= width (4 * saltBytes)
|
||||
, fin N, N >= 1, 512 >= width N, 1+width N >= width (N-1)
|
||||
)
|
||||
=> [pwBytes][8] -> [saltBytes][8] -> [dkBytes][8]
|
||||
SCrypt P S = MFcrypt `{r=r,N=N} P S
|
||||
|
||||
property kats_pass = ~zero ==
|
||||
[ SCrypt `{N=2^^4,r=1} "" "" ==
|
||||
[ 0x77, 0xd6, 0x57, 0x62, 0x38, 0x65, 0x7b, 0x20
|
||||
, 0x3b, 0x19, 0xca, 0x42, 0xc1, 0x8a, 0x04, 0x97
|
||||
, 0xf1, 0x6b, 0x48, 0x44, 0xe3, 0x07, 0x4a, 0xe8
|
||||
, 0xdf, 0xdf, 0xfa, 0x3f, 0xed, 0xe2, 0x14, 0x42
|
||||
, 0xfc, 0xd0, 0x06, 0x9d, 0xed, 0x09, 0x48, 0xf8
|
||||
, 0x32, 0x6a, 0x75, 0x3a, 0x0f, 0xc8, 0x1f, 0x17
|
||||
, 0xe8, 0xd3, 0xe0, 0xfb, 0x2e, 0x0d, 0x36, 0x28
|
||||
, 0xcf, 0x35, 0xe2, 0x0c, 0x38, 0xd1, 0x89, 0x06
|
||||
]
|
||||
// This tests takes too long in the Cryptol interpreter. Run once, comment it
|
||||
// out and be happy.
|
||||
// , SCrypt {N=2^^14, r=8} "pleaseletmein" "SodiumChloride" ==
|
||||
// [ 0x70, 0x23, 0xbd, 0xcb, 0x3a, 0xfd, 0x73, 0x48
|
||||
// , 0x46, 0x1c, 0x06, 0xcd, 0x81, 0xfd, 0x38, 0xeb
|
||||
// , 0xfd, 0xa8, 0xfb, 0xba, 0x90, 0x4f, 0x8e, 0x3e
|
||||
// , 0xa9, 0xb5, 0x43, 0xf6, 0x54, 0x5d, 0xa1, 0xf2
|
||||
// , 0xd5, 0x43, 0x29, 0x55, 0x61, 0x3f, 0x0f, 0xcf
|
||||
// , 0x62, 0xd4, 0x97, 0x05, 0x24, 0x2a, 0x9a, 0xf9
|
||||
// , 0xe6, 0x1e, 0x85, 0xdc, 0x0d, 0x65, 0x1e, 0x40
|
||||
// , 0xdf, 0xcf, 0x01, 0x7b, 0x45, 0x57, 0x58, 0x87
|
||||
// ]
|
||||
]
|
120
examples/MiniLock/prim/SHA256.cry
Normal file
120
examples/MiniLock/prim/SHA256.cry
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* @tmd - 24 April 2015 - took Ian's SHA512, converted to SHA256
|
||||
* @ian - 15 August 2015 - he lies, probably ment 2014.
|
||||
*
|
||||
* This is a very simple implementation of SHA256, designed to be as clearly
|
||||
* mathced to the specification in NIST's FIPS-PUB-180-4 as possible
|
||||
*
|
||||
* * The output correctly matches on all test vectors from
|
||||
* http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf
|
||||
*/
|
||||
module SHA256 where
|
||||
|
||||
/*
|
||||
* SHA256 Functions : Section 4.1.2
|
||||
*/
|
||||
|
||||
Ch : [32] -> [32] -> [32] -> [32]
|
||||
Ch x y z = (x && y) ^ (~x && z)
|
||||
|
||||
Maj : [32] -> [32] -> [32] -> [32]
|
||||
Maj x y z = (x && y) ^ (x && z) ^ (y && z)
|
||||
|
||||
S0 : [32] -> [32]
|
||||
S0 x = (x >>> 2) ^ (x >>> 13) ^ (x >>> 22)
|
||||
|
||||
S1 : [32] -> [32]
|
||||
S1 x = (x >>> 6) ^ (x >>> 11) ^ (x >>> 25)
|
||||
|
||||
s0 : [32] -> [32]
|
||||
s0 x = (x >>> 7) ^ (x >>> 18) ^ (x >> 3)
|
||||
|
||||
s1 : [32] -> [32]
|
||||
s1 x = (x >>> 17) ^ (x >>> 19) ^ (x >> 10)
|
||||
|
||||
/*
|
||||
* SHA256 Constants : Section 4.2.2
|
||||
*/
|
||||
|
||||
K : [64][32]
|
||||
K = [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
]
|
||||
|
||||
/*
|
||||
* Preprocessing (padding and parsing) for SHA256 : Section 5.1.1 and 5.2.1
|
||||
*/
|
||||
preprocess : {msgLen,contentLen,chunks,padding}
|
||||
( fin msgLen
|
||||
, 64 >= width msgLen // message width fits in a word
|
||||
, contentLen == msgLen + 65 // message + header
|
||||
, chunks == (contentLen+511) / 512
|
||||
, padding == (512 - contentLen % 512) % 512 // prettier if type #'s could be < 0
|
||||
)
|
||||
=> [msgLen] -> [chunks][512]
|
||||
preprocess msg = split (msg # [True] # (zero:[padding]) # (`msgLen:[64]))
|
||||
|
||||
/*
|
||||
* SHA256 Initial Hash Value : Section 5.3.3
|
||||
*/
|
||||
|
||||
H0 : [8][32]
|
||||
H0 = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]
|
||||
|
||||
/*
|
||||
* The SHA256 Hash computation : Section 6.2.2
|
||||
*
|
||||
* We have split the computation into a message scheduling function, corresponding
|
||||
* to step 1 in the documents loop, and a compression function, corresponding to steps 2-4.
|
||||
*/
|
||||
|
||||
SHA256MessageSchedule : [16][32] -> [64][32]
|
||||
SHA256MessageSchedule M = W where
|
||||
W = M # [ s1 (W@(j-2)) + (W@(j-7)) + s0 (W@(j-15)) + (W@(j-16)) | j <- [16 .. 63]:[_][8] ]
|
||||
|
||||
|
||||
SHA256Compress : [8][32] -> [64][32] -> [8][32]
|
||||
SHA256Compress H W = [as!0 + H@0, bs!0 + H@1, cs!0 + H@2, ds!0 + H@3, es!0 + H@4, fs!0 + H@5, gs!0 + H@6, hs!0 + H@7] where
|
||||
T1 = [h + S1 e + Ch e f g + k + w | h <- hs | e <- es | f <- fs | g <- gs | k <- K | w <- W]
|
||||
T2 = [S0 a + Maj a b c | a <- as | b <- bs | c <- cs]
|
||||
hs = take `{65} ([H@7] # gs)
|
||||
gs = take `{65} ([H@6] # fs)
|
||||
fs = take `{65} ([H@5] # es)
|
||||
es = take `{65} ([H@4] # [d + t1 | d <- ds | t1 <- T1])
|
||||
ds = take `{65} ([H@3] # cs)
|
||||
cs = take `{65} ([H@2] # bs)
|
||||
bs = take `{65} ([H@1] # as)
|
||||
as = take `{65} ([H@0] # [t1 + t2 | t1 <- T1 | t2 <- T2])
|
||||
|
||||
/*
|
||||
* The SHA256' function hashes a preprocessed sequence of blocks with the
|
||||
* compression function. The SHA256 function hashes a sequence of bytes, and
|
||||
* is more likely the function that will be similar to those seein in an
|
||||
* implementation to be verified.
|
||||
*/
|
||||
|
||||
SHA256' : {a} (fin a) => [a][16][32] -> [8][32]
|
||||
SHA256' blocks = hash!0 where
|
||||
hash = [H0] # [SHA256Compress h (SHA256MessageSchedule b) | h <- hash | b <- blocks]
|
||||
|
||||
SHA256 : {a} (fin a, 64 >= width (8*a)) => [a][8] -> [256]
|
||||
SHA256 msg = join (SHA256' [ split x | x <- preprocess(join msg)])
|
||||
|
||||
property katsPass = ~zero == [test == kat | (test,kat) <- kats ]
|
||||
|
||||
kats = [ (SHA256 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
, 0x248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1)
|
||||
, (SHA256 ""
|
||||
,0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855)
|
||||
, (SHA256 "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"
|
||||
, 0xcf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1)
|
||||
// , (SHA256 [0x61 | i <- [1..1000000] : [_][32]]
|
||||
// , 0xcdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0)
|
||||
]
|
274
examples/MiniLock/prim/Salsa20.cry
Normal file
274
examples/MiniLock/prim/Salsa20.cry
Normal file
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* 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]))]
|
||||
|
10
examples/MiniLock/prim/TestHMAC.cry
Normal file
10
examples/MiniLock/prim/TestHMAC.cry
Normal file
@ -0,0 +1,10 @@
|
||||
module TestHMAC where
|
||||
|
||||
import HMAC
|
||||
import SHA256
|
||||
|
||||
property pass =
|
||||
~zero ==
|
||||
[ hmacSHA256 [0x0b | _ <- [1..20] : [_][6]] "Hi There" == 0xb0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7
|
||||
, hmacSHA256 "Jefe" "what do ya want for nothing?" == 0x5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843
|
||||
]
|
42
examples/MiniLock/prim/bv.cry
Normal file
42
examples/MiniLock/prim/bv.cry
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module bv where
|
||||
|
||||
/* Unsigned word extension. */
|
||||
uext : {a, b} (fin b,fin a) => [a] -> [a+b]
|
||||
uext(x) = zero # x
|
||||
|
||||
iext : {a, b} (fin b,fin a) => [a] -> [a+b]
|
||||
iext(x) = (if x@0 then ~zero else zero) # x
|
||||
|
||||
/* Returns the (n+1)-bit sum of two n-bit numbers. */
|
||||
safe_add : {n} (fin n) => ([n],[n]) -> [n+1]
|
||||
safe_add(x,y) = uext(x) + uext(y)
|
||||
|
||||
/* returns the (n+1)-bit subtraction of two n-bit numbers. */
|
||||
safe_sub : {n} (fin n) => ([n],[n]) -> [n+1]
|
||||
safe_sub(x,y) = uext(x) - uext(y)
|
||||
|
||||
/* Is x in normalized form (relative to prime p)? */
|
||||
is_normal : {a} (fin a) => [a] -> [a] -> Bit
|
||||
is_normal p x = (x < p)
|
||||
|
||||
/* Returns the product of two inputs. */
|
||||
safe_product : {a} (fin a) => ([a],[a]) -> [2*a]
|
||||
safe_product(x,y) = uext(x) * uext(y)
|
||||
|
||||
/* Returns module reduction on input. */
|
||||
safe_mod : {a, b} (fin a, fin b) => ([b],[a+b]) -> [b]
|
||||
safe_mod(p,x) = drop `{a} (x % uext(p))
|
||||
|
||||
/* Add two n-bit numbers and input carry to obtain a n bit number and output carry. */
|
||||
adc : {n} (fin n) => ([n],[n]) -> ([n],Bit)
|
||||
adc(x,y) = (drop(sm), sm@0)
|
||||
where sm = safe_add(x,y)
|
||||
|
||||
/* sbb(x,y) subtracts y from x, and returns result along with output borrow bit. */
|
||||
sbb : {n} (fin n) => ([n],[n]) -> ([n],Bit)
|
||||
sbb(x,y) = (drop(r), r@0)
|
||||
where r = ([False] # x) - ([False] # y)
|
55
examples/MiniLock/prim/mod_arith.cry
Normal file
55
examples/MiniLock/prim/mod_arith.cry
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Galois, Inc.
|
||||
* Distributed under the terms of the BSD3 license (see LICENSE file)
|
||||
*/
|
||||
module mod_arith where
|
||||
|
||||
import bv
|
||||
|
||||
/* Add two numbers in normalized form. */
|
||||
mod_add : {n} (fin n) => ([n],[n],[n]) -> [n]
|
||||
mod_add(p,x,y) = if c1 || ~c2 then r2 else r1
|
||||
where
|
||||
(r1,c1) = adc( x, y)
|
||||
(r2,c2) = sbb(r1, p)
|
||||
|
||||
/* Subtract two numbers in normalized form. */
|
||||
mod_sub : {n} (fin n) => ([n],[n],[n]) -> [n]
|
||||
mod_sub(p,x,y) = if b then r2 else r1
|
||||
where
|
||||
(r1,b) = sbb( x, y)
|
||||
(r2,_) = adc(r1, p)
|
||||
|
||||
mod_neg : {n} (fin n) => ([n],[n]) -> [n]
|
||||
mod_neg(p,x) = if x == 0 then 0 else (p - x)
|
||||
|
||||
mod_half : {n} (fin n, n >= 1) => ([n],[n]) -> [n]
|
||||
mod_half(p, x) = if even(x) then x >> 1
|
||||
else take(safe_add(x, p))
|
||||
where even y = (y && 1) == 0
|
||||
|
||||
/* Definition of modular multiplication. */
|
||||
mod_mul : {n} (fin n) => ([n],[n],[n]) -> [n]
|
||||
mod_mul(p,x,y) = safe_mod(p, safe_product(x, y))
|
||||
|
||||
/* Returns x/y in F_p using Euler's binary gcd algorithm. */
|
||||
/* Taken from [HMV] */
|
||||
mod_div : {a} (fin a, a >= 1) => ([a],[a],[a]) -> [a]
|
||||
mod_div(p,x,y) = egcd(p,0,y,x)
|
||||
where
|
||||
/* In code below, a is always odd. */
|
||||
egcd(a,ra,b,rb) =
|
||||
if b == 0 then
|
||||
ra
|
||||
else if (b && 1) == 0 then /* b is even. */
|
||||
egcd(a, ra, b >> 1, mod_half(p, rb))
|
||||
else if a < b then
|
||||
egcd(a, ra, (b - a) >> 1, mod_half(p, mod_sub(p, rb, ra)))
|
||||
else
|
||||
egcd(b, rb, (a - b) >> 1, mod_half(p, mod_sub(p, ra, rb)))
|
||||
|
||||
mod_pow : {a} (fin a, a >= 1) => ([a] , [a] , [a]) -> [a]
|
||||
mod_pow (p,x0,e0) = (results ! 0).2
|
||||
where
|
||||
results = [(x0,e0,1)] # [ (mod_mul (p,x,x), e>>1, if(e!0) then mod_mul(p,result,x) else result)
|
||||
| (x,e,result) <- results | _ <- [0..a] :[_][width a] ]
|
Loading…
Reference in New Issue
Block a user