More session work, cleanup, AES in core crypto, and vendor the kyber library so we can remove no_std.

This commit is contained in:
Adam Ierymenko 2022-07-13 20:12:32 -04:00
parent b64968ff99
commit a3b748a0a6
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
85 changed files with 11032 additions and 335 deletions

View file

@ -21,7 +21,20 @@ const kCCAlgorithmAES: i32 = 0;
const kCCOptionECBMode: i32 = 2;
extern "C" {
fn CCCryptorCreateWithMode(op: i32, mode: i32, alg: i32, padding: i32, iv: *const c_void, key: *const c_void, key_len: usize, tweak: *const c_void, tweak_len: usize, num_rounds: c_int, options: i32, cryyptor_ref: *mut *mut c_void) -> i32;
fn CCCryptorCreateWithMode(
op: i32,
mode: i32,
alg: i32,
padding: i32,
iv: *const c_void,
key: *const c_void,
key_len: usize,
tweak: *const c_void,
tweak_len: usize,
num_rounds: c_int,
options: i32,
cryyptor_ref: *mut *mut c_void,
) -> i32;
fn CCCryptorUpdate(cryptor_ref: *mut c_void, data_in: *const c_void, data_in_len: usize, data_out: *mut c_void, data_out_len: usize, data_out_written: *mut usize) -> i32;
fn CCCryptorReset(cryptor_ref: *mut c_void, iv: *const c_void) -> i32;
fn CCCryptorRelease(cryptor_ref: *mut c_void) -> i32;
@ -31,84 +44,6 @@ extern "C" {
fn CCCryptorGCMReset(cryptor_ref: *mut c_void) -> i32;
}
pub struct Aes(*mut c_void, *mut c_void);
impl Drop for Aes {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
CCCryptorRelease(self.0);
}
}
if !self.1.is_null() {
unsafe {
CCCryptorRelease(self.1);
}
}
}
}
impl Aes {
pub fn new(k: &[u8]) -> Self {
unsafe {
if k.len() != 32 && k.len() != 24 && k.len() != 16 {
panic!("AES supports 128, 192, or 256 bits keys");
}
let mut aes: Self = std::mem::zeroed();
let enc = CCCryptorCreateWithMode(kCCEncrypt, kCCModeECB, kCCAlgorithmAES, 0, crate::ZEROES.as_ptr().cast(), k.as_ptr().cast(), k.len(), null(), 0, 0, kCCOptionECBMode, &mut aes.0);
if enc != 0 {
panic!("CCCryptorCreateWithMode for ECB encrypt mode returned {}", enc);
}
let dec = CCCryptorCreateWithMode(kCCDecrypt, kCCModeECB, kCCAlgorithmAES, 0, crate::ZEROES.as_ptr().cast(), k.as_ptr().cast(), k.len(), null(), 0, 0, kCCOptionECBMode, &mut aes.1);
if dec != 0 {
panic!("CCCryptorCreateWithMode for ECB decrypt mode returned {}", dec);
}
aes
}
}
#[inline(always)]
pub fn encrypt_block(&self, plaintext: &[u8], ciphertext: &mut [u8]) {
assert_eq!(plaintext.len(), 16);
assert_eq!(ciphertext.len(), 16);
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.0, plaintext.as_ptr().cast(), 16, ciphertext.as_mut_ptr().cast(), 16, &mut data_out_written);
}
}
#[inline(always)]
pub fn encrypt_block_in_place(&self, data: &mut [u8]) {
assert_eq!(data.len(), 16);
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.0, data.as_ptr().cast(), 16, data.as_mut_ptr().cast(), 16, &mut data_out_written);
}
}
#[inline(always)]
pub fn decrypt_block(&self, ciphertext: &[u8], plaintext: &mut [u8]) {
assert_eq!(plaintext.len(), 16);
assert_eq!(ciphertext.len(), 16);
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.1, ciphertext.as_ptr().cast(), 16, plaintext.as_mut_ptr().cast(), 16, &mut data_out_written);
}
}
#[inline(always)]
pub fn decrypt_block_in_place(&self, data: &mut [u8]) {
assert_eq!(data.len(), 16);
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.1, data.as_ptr().cast(), 16, data.as_mut_ptr().cast(), 16, &mut data_out_written);
}
}
}
unsafe impl Send for Aes {}
unsafe impl Sync for Aes {}
pub struct AesCtr(*mut c_void);
impl Drop for AesCtr {
@ -229,19 +164,47 @@ impl AesGmacSiv {
gmac: null_mut(),
};
unsafe {
let result = CCCryptorCreateWithMode(kCCEncrypt, kCCModeCTR, kCCAlgorithmAES, 0, crate::ZEROES.as_ptr().cast(), k1.as_ptr().cast(), k1.len(), null(), 0, 0, 0, &mut c.ctr);
let result =
CCCryptorCreateWithMode(kCCEncrypt, kCCModeCTR, kCCAlgorithmAES, 0, crate::ZEROES.as_ptr().cast(), k1.as_ptr().cast(), k1.len(), null(), 0, 0, 0, &mut c.ctr);
if result != 0 {
panic!("CCCryptorCreateWithMode for CTR mode returned {}", result);
}
let result = CCCryptorCreateWithMode(kCCEncrypt, kCCModeECB, kCCAlgorithmAES, 0, crate::ZEROES.as_ptr().cast(), k1.as_ptr().cast(), k1.len(), null(), 0, 0, kCCOptionECBMode, &mut c.ecb_enc);
let result = CCCryptorCreateWithMode(
kCCEncrypt,
kCCModeECB,
kCCAlgorithmAES,
0,
crate::ZEROES.as_ptr().cast(),
k1.as_ptr().cast(),
k1.len(),
null(),
0,
0,
kCCOptionECBMode,
&mut c.ecb_enc,
);
if result != 0 {
panic!("CCCryptorCreateWithMode for ECB encrypt mode returned {}", result);
}
let result = CCCryptorCreateWithMode(kCCDecrypt, kCCModeECB, kCCAlgorithmAES, 0, crate::ZEROES.as_ptr().cast(), k1.as_ptr().cast(), k1.len(), null(), 0, 0, kCCOptionECBMode, &mut c.ecb_dec);
let result = CCCryptorCreateWithMode(
kCCDecrypt,
kCCModeECB,
kCCAlgorithmAES,
0,
crate::ZEROES.as_ptr().cast(),
k1.as_ptr().cast(),
k1.len(),
null(),
0,
0,
kCCOptionECBMode,
&mut c.ecb_dec,
);
if result != 0 {
panic!("CCCryptorCreateWithMode for ECB decrypt mode returned {}", result);
}
let result = CCCryptorCreateWithMode(kCCEncrypt, kCCModeGCM, kCCAlgorithmAES, 0, crate::ZEROES.as_ptr().cast(), k0.as_ptr().cast(), k0.len(), null(), 0, 0, 0, &mut c.gmac);
let result =
CCCryptorCreateWithMode(kCCEncrypt, kCCModeGCM, kCCAlgorithmAES, 0, crate::ZEROES.as_ptr().cast(), k0.as_ptr().cast(), k0.len(), null(), 0, 0, 0, &mut c.gmac);
if result != 0 {
panic!("CCCryptorCreateWithMode for GCM (GMAC) mode returned {}", result);
}
@ -327,7 +290,14 @@ impl AesGmacSiv {
pub fn encrypt_second_pass_in_place(&mut self, plaintext_to_ciphertext: &mut [u8]) {
unsafe {
let mut data_out_written: usize = 0;
CCCryptorUpdate(self.ctr, plaintext_to_ciphertext.as_ptr().cast(), plaintext_to_ciphertext.len(), plaintext_to_ciphertext.as_mut_ptr().cast(), plaintext_to_ciphertext.len(), &mut data_out_written);
CCCryptorUpdate(
self.ctr,
plaintext_to_ciphertext.as_ptr().cast(),
plaintext_to_ciphertext.len(),
plaintext_to_ciphertext.as_mut_ptr().cast(),
plaintext_to_ciphertext.len(),
&mut data_out_written,
);
}
}
@ -386,7 +356,14 @@ impl AesGmacSiv {
pub fn decrypt_in_place(&mut self, ciphertext_to_plaintext: &mut [u8]) {
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.ctr, ciphertext_to_plaintext.as_ptr().cast(), ciphertext_to_plaintext.len(), ciphertext_to_plaintext.as_mut_ptr().cast(), ciphertext_to_plaintext.len(), &mut data_out_written);
CCCryptorUpdate(
self.ctr,
ciphertext_to_plaintext.as_ptr().cast(),
ciphertext_to_plaintext.len(),
ciphertext_to_plaintext.as_mut_ptr().cast(),
ciphertext_to_plaintext.len(),
&mut data_out_written,
);
CCCryptorGCMAddAAD(self.gmac, ciphertext_to_plaintext.as_ptr().cast(), ciphertext_to_plaintext.len());
}
}

View file

@ -40,55 +40,6 @@ fn aes_ecb_by_key_size(ks: usize) -> Cipher {
}
}
pub struct Aes(Crypter, Crypter);
impl Aes {
pub fn new(k: &[u8]) -> Self {
let mut aes = Self(Crypter::new(aes_ecb_by_key_size(k.len()), Mode::Encrypt, k, None).unwrap(), Crypter::new(aes_ecb_by_key_size(k.len()), Mode::Decrypt, k, None).unwrap());
aes.0.pad(false);
aes.1.pad(false);
}
#[inline(always)]
pub fn encrypt_block(&self, plaintext: &[u8], ciphertext: &mut [u8]) {
let mut tmp = [0_u8; 32];
if self.0.update(plaintext, &mut tmp).unwrap() != 16 {
assert_eq!(ecb.finalize(&mut tmp).unwrap(), 16);
}
ciphertext[..16].copy_from_slice(&tmp[..16]);
}
#[inline(always)]
pub fn encrypt_block_in_place(&self, data: &mut [u8]) {
let mut tmp = [0_u8; 32];
if self.0.update(data, &mut tmp).unwrap() != 16 {
assert_eq!(ecb.finalize(&mut tmp).unwrap(), 16);
}
data[..16].copy_from_slice(&tmp[..16]);
}
#[inline(always)]
pub fn decrypt_block(&self, ciphertext: &[u8], plaintext: &mut [u8]) {
let mut tmp = [0_u8; 32];
if self.1.update(plaintext, &mut tmp).unwrap() != 16 {
assert_eq!(ecb.finalize(&mut tmp).unwrap(), 16);
}
ciphertext[..16].copy_from_slice(&tmp[..16]);
}
#[inline(always)]
pub fn decrypt_block_in_place(&self, data: &mut [u8]) {
let mut tmp = [0_u8; 32];
if self.1.update(data, &mut tmp).unwrap() != 16 {
assert_eq!(ecb.finalize(&mut tmp).unwrap(), 16);
}
data[..16].copy_from_slice(&tmp[..16]);
}
}
unsafe impl Send for Aes {}
unsafe impl Sync for Aes {}
pub struct AesCtr(Vec<u8>, Option<Crypter>);
impl AesCtr {

View file

@ -7,10 +7,10 @@ mod impl_macos;
mod impl_openssl;
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub use impl_macos::{Aes, AesCtr, AesGmacSiv};
pub use impl_macos::{AesCtr, AesGmacSiv};
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub use impl_openssl::{Aes, AesCtr, AesGmacSiv};
pub use impl_openssl::{AesCtr, AesGmacSiv};
pub(crate) const ZEROES: [u8; 16] = [0_u8; 16];

11
third_party/kyber/.gitignore vendored Normal file
View file

@ -0,0 +1,11 @@
/target
Cargo.lock
/.vscode
/tests/rand_bufs/generate
package-lock.json
/tests/KATs/tvecs*
/tests/KATs/SHA256SUMS
/test/KATs/kyber
/fuzz/hfuzz_target
/fuzz/hfuzz_workspace
/fuzz/target

65
third_party/kyber/Cargo.toml vendored Normal file
View file

@ -0,0 +1,65 @@
[package]
name = "pqc_kyber"
version = "0.2.0"
authors = ["Mitchell Berry <foss@mitchellberry.com>"]
edition = "2018"
license = "Apache-2.0"
repository = "https://github.com/Argyle-Cybersystems/kyber"
documentation = "https://docs.rs/crate/pqc_kyber/"
categories = ["algorithms", "cryptography"]
description = "A rust implementation of the post-quantum Kyber KEM algorithm"
keywords = ["kyber", "kem", "key-exchange", "kex", "post-quantum"]
readme = "readme.md"
[dependencies]
rand_core = {version = "0.6.2", default-features = false }
wasm-bindgen = { version = "0.2.74", optional = true }
sha2 = { version = "0.9.5", optional = true }
# TODO: Add rustcrypto AES-CTR feature for 90's mode
# aes-ctr = {version = "0.6.0", optional = true}
[dev-dependencies]
criterion = "0.3.4"
rand = "0.8.3"
[build-dependencies]
cc = "1.0.67"
[lib]
crate-type = ["cdylib", "rlib"]
[[bench]]
name = "api"
harness = false
[features]
### Security Levels ###
# Defaults to "kyber764" if none selected
# Will throw a compile-time error if more than one level is chosen
kyber512 = []
kyber1024 =[]
### Additional features ###
# 90s mode uses AES-CTR and SHA2 as primitives instead
90s = ["sha2"]
# Force usage of the reference codebase on x86_64 architectures
reference = []
# For compiling to wasm targets
wasm = ["wasm-bindgen"]
# Known Answer Tests
# Allows private internal api access to seed the RNG output.
# Do not use this feature for any purpose other than testing.
KATs = []
# Prevents leak sanitiser failing in tests
[profile.test]
opt-level = 2
[profile.test.package."*"]
opt-level = 0
[profile.test.build-override]
opt-level = 0

201
third_party/kyber/LICENSE-APACHE vendored Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

74
third_party/kyber/benches/api.rs vendored Normal file
View file

@ -0,0 +1,74 @@
use criterion::{criterion_group, criterion_main, Criterion};
use pqc_kyber::*;
// First set in KAT_2400
const PK_HEX: &str = "A0B71F67C6CEC0D35686D513423432E512AC4044557E868A624800109A3355F98F151444E2852E27EA6EDB1992CAD3973C3A6FF79A5A049A259EB5415AA2A262456EC9495BBB5200D8D3163A5B10226292ECA01021389DA37881E276306550C6EFB6440EC51A2F7348349B851CD4AA0175A0550213C4791D91011220824B2B61650813ADFD2CB10538BFAB0A726F81129ED2C0F06A16B701090BF048C5A40126D572FCD47AA1218FB01547D150792D2316CB320D5144BA3508A1EBBB5AC1C22913E8295FAB59BF5837A778CF28227E07E1032DAB7D0E09A15F134148C12009DA536B22CC62474E69CC1554C0814D6CA0B722594383A9D0A2C77FD365A5544295FBB973F91EA56490D6CA6876497B98B3CB12417C257B6D0F7183DBB69E33075BEB0117B6914C69BA38349422F2F43364822A2570952DD5077B90755F1574115B8E221427585961913A9BFA0502B5D79AB7811744E6563C5B62C5CC4E93239A0A8CC60FE848F84A95F5902599B54A066293A2021DA196766C17C7E863AF790C270B216A25138DDA0C8126E09377879859DB358F9B82B7C8A6792ACEE92A4CBDE3CEDD4500ACBC555C288EFF9795265B9005351C52E2653554ABAAF872DF95CA7F795903F0B0A182B18AEB0475B29F6E3ABF4C2250FE7B842A73655016A8FC729F390507ACA936825A98B3A32E6B2554CE9528941A3BB8C90996008D74FBCD020A02E706A6DE7B02AF404C10DB00FAEC02D3EAA6D9561A1565A7B05C6366D09DA7A537F20C7B2859A83E029E13A9BD289157C5B74C84EAA307753D431202A3D9B6162218BEC5346945BFEF55B624C5C6E373359BB1C479952BBABA4D6555C276573E5152B553901999F69402D150BEF79D74FB2953018FF48666746ACE607814A1FA33195720F83878D3B575C725744A72070DD044018042DA25714D173090323A51E6C063D203881380912761FC3410839095F26C0E687A00705495E171B57151ACE0498E30F14CA9B02F6E40831854C2E0AB1ECD0C21D8E4C7E669CD728230B9D11F72C266E34466F9C0159EF424F8F31D95A57BA0E210543C10C6503FB5C63ED23AA36CD6A6F378261B0B1E79509D8BEB36AA263DC91545E53369DF26837F394C56777C95B648BD1A72921ABF49563F99CB9D98EAB5C66666F6B16F74022481FA214E617698D3BBD13CB308713FDCC7CFD397B9CA39AFF4C744D5715D58966F2CF9707015C8F3543ED286A3D8D5CBF64ACEDFC02971A91072C69D2EF49829F1037F050C5B92229856CB12B456CC095282A62687EA38C9778AEA491DFF069711FBBE05E8CD9BF44A8E712619573E12EAA7B23829DC6726BFE33DA136B81E153251508F6285BA15B2C1237677FE5B14B4E33F98C326BC58B9D8E075A25B94C8A23233029DCC786B135C56164BA3D160CBCEA854B7971F9CD73A383AAC050A302AD83B3E3AB90246AD160A321D330ACDEC7CA6643D7EC01F91691F16325BDF396950B88DAFE369C654B852055C970362C61380460757C65890F4E59222E4A4060B26C0EBC10197590DE3C8F0955D654B371CCB90ACA371B294476C16A4596A1DE8309E2A3612C69B7125310501E0C049B87440D9A6D0ECB999C9A0942AA340F60365EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922";
const SK_HEX: &str = "07638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405DA0B71F67C6CEC0D35686D513423432E512AC4044557E868A624800109A3355F98F151444E2852E27EA6EDB1992CAD3973C3A6FF79A5A049A259EB5415AA2A262456EC9495BBB5200D8D3163A5B10226292ECA01021389DA37881E276306550C6EFB6440EC51A2F7348349B851CD4AA0175A0550213C4791D91011220824B2B61650813ADFD2CB10538BFAB0A726F81129ED2C0F06A16B701090BF048C5A40126D572FCD47AA1218FB01547D150792D2316CB320D5144BA3508A1EBBB5AC1C22913E8295FAB59BF5837A778CF28227E07E1032DAB7D0E09A15F134148C12009DA536B22CC62474E69CC1554C0814D6CA0B722594383A9D0A2C77FD365A5544295FBB973F91EA56490D6CA6876497B98B3CB12417C257B6D0F7183DBB69E33075BEB0117B6914C69BA38349422F2F43364822A2570952DD5077B90755F1574115B8E221427585961913A9BFA0502B5D79AB7811744E6563C5B62C5CC4E93239A0A8CC60FE848F84A95F5902599B54A066293A2021DA196766C17C7E863AF790C270B216A25138DDA0C8126E09377879859DB358F9B82B7C8A6792ACEE92A4CBDE3CEDD4500ACBC555C288EFF9795265B9005351C52E2653554ABAAF872DF95CA7F795903F0B0A182B18AEB0475B29F6E3ABF4C2250FE7B842A73655016A8FC729F390507ACA936825A98B3A32E6B2554CE9528941A3BB8C90996008D74FBCD020A02E706A6DE7B02AF404C10DB00FAEC02D3EAA6D9561A1565A7B05C6366D09DA7A537F20C7B2859A83E029E13A9BD289157C5B74C84EAA307753D431202A3D9B6162218BEC5346945BFEF55B624C5C6E373359BB1C479952BBABA4D6555C276573E5152B553901999F69402D150BEF79D74FB2953018FF48666746ACE607814A1FA33195720F83878D3B575C725744A72070DD044018042DA25714D173090323A51E6C063D203881380912761FC3410839095F26C0E687A00705495E171B57151ACE0498E30F14CA9B02F6E40831854C2E0AB1ECD0C21D8E4C7E669CD728230B9D11F72C266E34466F9C0159EF424F8F31D95A57BA0E210543C10C6503FB5C63ED23AA36CD6A6F378261B0B1E79509D8BEB36AA263DC91545E53369DF26837F394C56777C95B648BD1A72921ABF49563F99CB9D98EAB5C66666F6B16F74022481FA214E617698D3BBD13CB308713FDCC7CFD397B9CA39AFF4C744D5715D58966F2CF9707015C8F3543ED286A3D8D5CBF64ACEDFC02971A91072C69D2EF49829F1037F050C5B92229856CB12B456CC095282A62687EA38C9778AEA491DFF069711FBBE05E8CD9BF44A8E712619573E12EAA7B23829DC6726BFE33DA136B81E153251508F6285BA15B2C1237677FE5B14B4E33F98C326BC58B9D8E075A25B94C8A23233029DCC786B135C56164BA3D160CBCEA854B7971F9CD73A383AAC050A302AD83B3E3AB90246AD160A321D330ACDEC7CA6643D7EC01F91691F16325BDF396950B88DAFE369C654B852055C970362C61380460757C65890F4E59222E4A4060B26C0EBC10197590DE3C8F0955D654B371CCB90ACA371B294476C16A4596A1DE8309E2A3612C69B7125310501E0C049B87440D9A6D0ECB999C9A0942AA340F60365EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922DEE4ABA000389581717D36F56F39AF7300B31D831A4D8C976128E09DEDE71A5A8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F";
const BAD_SK: &str = "17638FB69868F3D320E5862BD96933FEB311B362093C9B5D50170BCED43F1B536D9A204BB1F22695950BA1F2A9E8EB828B284488760B3FC84FABA04275D5628E39C5B2471374283C503299C0AB49B66B8BBB56A4186624F919A2BA59BB08D8551880C2BEFC4F87F25F59AB587A79C327D792D54C974A69262FF8A78938289E9A87B688B083E0595FE218B6BB1505941CE2E81A5A64C5AAC60417256985349EE47A52420A5F97477B7236AC76BC70E8288729287EE3E34A3DBC3683C0B7B10029FC203418537E7466BA6385A8FF301EE12708F82AAA1E380FC7A88F8F205AB7E88D7E95952A55BA20D09B79A47141D62BF6EB7DD307B08ECA13A5BC5F6B68581C6865B27BBCDDAB142F4B2CBFF488C8A22705FAA98A2B9EEA3530C76662335CC7EA3A00777725EBCCCD2A4636B2D9122FF3AB77123CE0883C1911115E50C9E8A94194E48DD0D09CFFB3ADCD2C1E92430903D07ADBF00532031575AA7F9E7B5A1F3362DEC936D4043C05F2476C07578BC9CBAF2AB4E382727AD41686A96B2548820BB03B32F11B2811AD62F489E951632ABA0D1DF89680CC8A8B53B481D92A68D70B4EA1C3A6A561C0692882B5CA8CC942A8D495AFCB06DE89498FB935B775908FE7A03E324D54CC19D4E1AABD3593B38B19EE1388FE492B43127E5A504253786A0D69AD32601C28E2C88504A5BA599706023A61363E17C6B9BB59BDC697452CD059451983D738CA3FD034E3F5988854CA05031DB09611498988197C6B30D258DFE26265541C89A4B31D6864E9389B03CB74F7EC4323FB9421A4B9790A26D17B0398A26767350909F84D57B6694DF830664CA8B3C3C03ED2AE67B89006868A68527CCD666459AB7F056671000C6164D3A7F266A14D97CBD7004D6C92CACA770B844A4FA9B182E7B18CA885082AC5646FCB4A14E1685FEB0C9CE3372AB95365C04FD83084F80A23FF10A05BF15F7FA5ACC6C0CB462C33CA524FA6B8BB359043BA68609EAA2536E81D08463B19653B5435BA946C9ADDEB202B04B031CC960DCC12E4518D428B32B257A4FC7313D3A7980D80082E934F9D95C32B0A0191A23604384DD9E079BBBAA266D14C3F756B9F2133107433A4E83FA7187282A809203A4FAF841851833D121AC383843A5E55BC2381425E16C7DB4CC9AB5C1B0D91A47E2B8DE0E582C86B6B0D907BB360B97F40AB5D038F6B75C814B27D9B968D419832BC8C2BEE605EF6E5059D33100D90485D378450014221736C07407CAC260408AA64926619788B8601C2A752D1A6CBF820D7C7A04716203225B3895B9342D147A8185CFC1BB65BA06B4142339903C0AC4651385B45D98A8B19D28CD6BAB088787F7EE1B12461766B43CBCCB96434427D93C065550688F6948ED1B5475A425F1B85209D061C08B56C1CC069F6C0A7C6F29358CAB911087732A649D27C9B98F9A48879387D9B00C25959A71654D6F6A946164513E47A75D005986C2363C09F6B537ECA78B9303A5FA457608A586A653A347DB04DFCC19175B3A301172536062A658A95277570C8852CA8973F4AE123A334047DD711C8927A634A03388A527B034BF7A8170FA702C1F7C23EC32D18A2374890BE9C787A9409C82D192C4BB705A2F996CE405DA0B71F67C6CEC0D35686D513423432E512AC4044557E868A624800109A3355F98F151444E2852E27EA6EDB1992CAD3973C3A6FF79A5A049A259EB5415AA2A262456EC9495BBB5200D8D3163A5B10226292ECA01021389DA37881E276306550C6EFB6440EC51A2F7348349B851CD4AA0175A0550213C4791D91011220824B2B61650813ADFD2CB10538BFAB0A726F81129ED2C0F06A16B701090BF048C5A40126D572FCD47AA1218FB01547D150792D2316CB320D5144BA3508A1EBBB5AC1C22913E8295FAB59BF5837A778CF28227E07E1032DAB7D0E09A15F134148C12009DA536B22CC62474E69CC1554C0814D6CA0B722594383A9D0A2C77FD365A5544295FBB973F91EA56490D6CA6876497B98B3CB12417C257B6D0F7183DBB69E33075BEB0117B6914C69BA38349422F2F43364822A2570952DD5077B90755F1574115B8E221427585961913A9BFA0502B5D79AB7811744E6563C5B62C5CC4E93239A0A8CC60FE848F84A95F5902599B54A066293A2021DA196766C17C7E863AF790C270B216A25138DDA0C8126E09377879859DB358F9B82B7C8A6792ACEE92A4CBDE3CEDD4500ACBC555C288EFF9795265B9005351C52E2653554ABAAF872DF95CA7F795903F0B0A182B18AEB0475B29F6E3ABF4C2250FE7B842A73655016A8FC729F390507ACA936825A98B3A32E6B2554CE9528941A3BB8C90996008D74FBCD020A02E706A6DE7B02AF404C10DB00FAEC02D3EAA6D9561A1565A7B05C6366D09DA7A537F20C7B2859A83E029E13A9BD289157C5B74C84EAA307753D431202A3D9B6162218BEC5346945BFEF55B624C5C6E373359BB1C479952BBABA4D6555C276573E5152B553901999F69402D150BEF79D74FB2953018FF48666746ACE607814A1FA33195720F83878D3B575C725744A72070DD044018042DA25714D173090323A51E6C063D203881380912761FC3410839095F26C0E687A00705495E171B57151ACE0498E30F14CA9B02F6E40831854C2E0AB1ECD0C21D8E4C7E669CD728230B9D11F72C266E34466F9C0159EF424F8F31D95A57BA0E210543C10C6503FB5C63ED23AA36CD6A6F378261B0B1E79509D8BEB36AA263DC91545E53369DF26837F394C56777C95B648BD1A72921ABF49563F99CB9D98EAB5C66666F6B16F74022481FA214E617698D3BBD13CB308713FDCC7CFD397B9CA39AFF4C744D5715D58966F2CF9707015C8F3543ED286A3D8D5CBF64ACEDFC02971A91072C69D2EF49829F1037F050C5B92229856CB12B456CC095282A62687EA38C9778AEA491DFF069711FBBE05E8CD9BF44A8E712619573E12EAA7B23829DC6726BFE33DA136B81E153251508F6285BA15B2C1237677FE5B14B4E33F98C326BC58B9D8E075A25B94C8A23233029DCC786B135C56164BA3D160CBCEA854B7971F9CD73A383AAC050A302AD83B3E3AB90246AD160A321D330ACDEC7CA6643D7EC01F91691F16325BDF396950B88DAFE369C654B852055C970362C61380460757C65890F4E59222E4A4060B26C0EBC10197590DE3C8F0955D654B371CCB90ACA371B294476C16A4596A1DE8309E2A3612C69B7125310501E0C049B87440D9A6D0ECB999C9A0942AA340F60365EAFD465FC64A0C5F8F3F9003489415899D59A543D8208C54A3166529B53922DEE4ABA000389581717D36F56F39AF7300B31D831A4D8C976128E09DEDE71A5A8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F";
const CT_HEX: &str = "EADD5ADA14DA57F0AEF3505F1CAA6485D4238D999A3EF4B0A59A1CDBE0A27E478547A3A99D2AB09AC7D7C8F5AE3D6432045CBA3FA778345892542BD81C05BEFCD2E5CC9A579BEFB7C58D02FB94F33392FE17F4EBA2CB510EC74CC9D1D8A87C1066A4869A3983E664BFE9DEA5AE4FDF310C8F59815A678FA325F369AF84FFEBC1D150431FE3BD2734F636CF658E6C1A6A6E2CBE071F9A7C26119AD105098EDA622CAB8E176762109877D9AE9D6729D44A58E707D6B8AD6E696A33C672DA9D08DA2A7F9E3BF02218238722A46B31D49DAFF9AF00A6363C3A423B2E873DEFDDBCD969B75A81053D9A97C06DE2BFE3D0CFD3D3C77983B18DBDE23C0728604A71435AD40DF1579096DDBE02E4612210CAA034DCEFB8B4D7B5E6D2EBA37A79FB61F34B5AF7D9B27B13E4936222411249B7FBB69E73461DAF4AA6F3E2C73944F10CE67C86FED260BDA7B40DB39B1DE3C7D8F09A77F3C84BC62931D228B24A574AC3F4EB745CFF7E031A3FB2A08595C15370A3C82DB7D9F41BB1D8ECC429CFA3A65833016AB6EA60C9390CFA1B65CCEAE550940795386ED24133FBAE8B3017502AF3CFE951D781D36CFEFF85BFDF5AF040BE4065681B3B0A63C2747F0808CF3DA725169DDED1003DA6CD5DE4CB041942938D0A7F8802D48F2E3C6EEB45CD90AF6FC9F4507E9F8380AC33CACA7751487F65500441D920B94880A497D01C0802BB08D74C5D4C6BF2D865EE5822B3375C755D1A5E3D3244C320510A1E30357702CD4252072CF86437F7A9DE5561C7E59B94B9584100131AC399F4C1EB19FB4BDF65E62785E97C194B8764CCF32FD05D804C2E439DDA2A109274FBFFA81A837C51B26D154F974B882A5B174B308FC48768D222922532B183ABDF6FBB0BC7492766974D321EE6FB7C5F7B3EEA2378DC6D6BB48019250B8D8D8DEDB522421AEEDB318676982A80E7961EC40E6D7F3339694255BAFF51BE3A7EA7D8793A109BE3AE4423BF082E206A573B4F0F93FC16DDE81BD5DC583F528C08A0A9AB8E6CD524E297C9CF0F43C344913830ECB16F91441477BA782EDD4E73E732979D3A664EB99EA5D24B6C84AA69F377CB0CAD5AE4E641E38B197A0994D58B2387E91760E9B6FEBCB445CF85BBA24A94CDA75E338674428249FE6DE4692601D1EAE0EA021D9BC8077BE8665D0737748FA30FCF80F7E482584674F633A5006A538267627FD91854E0871268A6B0B05DD51495135DEFB9376E9B841B64E5DBF43CE6C74BCF3AE1FC427E810B7CBF6957DBF904690E87842543897DE78F13D08D92EBD27FB2CFCC0C765430589057B16B15F207CA1E6F08D52616DD57AD43EFEA6FDDAAEA18D33731FAC7ECAAE950E1DF3C5A4E6FCB223DF5E86B487FD7092D0822EFFAEC82C4BEC10C600FDB90E77482911B1595277738841409D0F8F113191D47F5E56C115A05DEA759AA6FB1D047F9FCA4ED519EA5D21FE3BA5B9434FEA1283DFAD63D01589B0EB61F244351D03341DCD4DF62265AFCAEC6676A877D5CACB359EBB5319610DD447DA97E950B0C";
// Benchmarking key generation
fn keypair_bench(c: &mut Criterion) {
let mut rng = rand::thread_rng();
c.bench_function(
"Keypair Generation",
|b| b.iter(
|| {
let _keys = keypair(&mut rng);
}
)
);
}
// Encapsulating a single public key
fn encap_bench(c: &mut Criterion) {
let pk = crate::decode_hex(PK_HEX);
let mut rng = rand::thread_rng();
c.bench_function(
"Encapsulate",
|b| b.iter(
|| {
let _enc = encapsulate(&pk, &mut rng);
}
)
);
}
// Decapsulating a single correct ciphertext
fn decap_bench(c: &mut Criterion) {
let sk = decode_hex(SK_HEX);
let ct = decode_hex(CT_HEX);
c.bench_function(
"Decapsulate",
|b| b.iter(
|| {
let _dec = decapsulate(&ct, &sk);
}
)
);
}
// Decapsulating a single incorrect ciphertext
fn decap_fail_bench(c: &mut Criterion) {
let sk = decode_hex(BAD_SK);
let ct = decode_hex(CT_HEX);
c.bench_function(
"Decapsulate Failure",
|b| b.iter(
|| {
let _dec = decapsulate(&ct, &sk);
}
)
);
}
criterion_group!(benches, keypair_bench, encap_bench, decap_bench, decap_fail_bench);
criterion_main!(benches);
// Decodes a hex string into a vector of bytes
pub fn decode_hex(s: &str) -> Vec<u8> {
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("Hex string decoding"))
.collect::<Vec<u8>>()
}

26
third_party/kyber/benches/readme.md vendored Normal file
View file

@ -0,0 +1,26 @@
# Benchmarking
On x86_64 platforms using optimised code include the following target features in RUSTFLAGS:
```bash
RUSTFLAGS="-C target-cpu=native -C target-feature=+aes,+avx2,+sse2,+sse4.1,+bmi2,+popcnt" cargo bench
```
This library uses [Criterion](https://github.com/bheisler/criterion.rs) for benchmarks.
After running the bench command the report can be viewed at [`target/criterion/report/index.html`](../target/criterion/report/index.html).
Note there will be significant differences when you choose different security levels or 90's mode. Saving a baseline for different modes can be useful. eg.
```bash
cargo bench --features kyber1024 -- --save-baseline kyber1024
```
More details on criterion usage [here](https://bheisler.github.io/criterion.rs/book/user_guide/command_line_options.html)
Current benches:
* Keypair generation
* Encapsulation
* Correct Decapsulation
* Decapsulation failure

19
third_party/kyber/build.rs vendored Normal file
View file

@ -0,0 +1,19 @@
fn main() {
#[cfg(all(target_arch = "x86_64", not(feature = "reference")))]
cc::Build::new()
.include("src/avx2/")
.file("src/avx2/basemul.S")
.file("src/avx2/fq.S")
.file("src/avx2/invntt.S")
.file("src/avx2/ntt.S")
.file("src/avx2/shuffle.S")
.compile("pqc_kyber");
// #[cfg(
// all(
// any(target_arch = "arm", target_arch="aarch64"),
// not(feature = "reference")
// )
// )]
// cc::Build::new()
// .include("src/neon/");
}

17
third_party/kyber/contributing.md vendored Normal file
View file

@ -0,0 +1,17 @@
# Contributing
Contributions always welcome. For pull requests create a feature fork and submit it to the development branch. If possible please run a benchmark first for any significant regressions.
Current areas of focus aka "aspirational TODO's":
* **Idiomatic rust** - For the moment this crate closely follows the C reference code and will likely stay that way until the PQC standardization project finishes. Still there is a few things that could cleaned up to make it more rusty in preparation for that.
* **Neon ARM intrinsics** - There is a [neon library](https://github.com/cothan/kyber/tree/round3/neon) for Kyber, though currently many ARM intrinsics still don't exist in rust, so there's two branches, `neon` is a rust port of his work that will have to wait until the intrinsics are upstream, `neon_c` is using the original C code with a FFI.
* **Translated Docs**: Localization of readmes and other docs.
* **Optimizations** - See the benchmarking readme, possibly some fat that can still be trimmed off.
* **Add RustCrypto primitives feature for 90s mode** - This is half done yet commented out, still needs some cleaning up to fit in.
* **Add a zeroize feature** - Clean out ephemeral keys after use, also might be worthwhile to zero out polynomials and other internals, which will need benchmarking.
* **Serde** - Implement Serialize/Deserialize traits for the structs and put it behind a feature gate.
By submitting any code to this repository you agree to have it licensed under both Apache 2.0 and MIT.

27
third_party/kyber/examples/ake.rs vendored Normal file
View file

@ -0,0 +1,27 @@
use pqc_kyber::*;
fn main() -> Result<(), KyberError> {
let mut rng = rand::thread_rng();
let mut alice = Ake::new();
let mut bob = Ake::new();
let alice_keys = keypair(&mut rng);
let bob_keys = keypair(&mut rng);
// Alice initiates key exchange with bob
let client_send = alice.client_init(&bob_keys.public, &mut rng);
// Bob receives the request and authenticates Alice, sends
// encapsulated shared secret back
let server_send = bob.server_receive(
client_send, &alice_keys.public, &bob_keys.secret, &mut rng
)?;
// Alice autheticates and decapsulates
alice.client_confirm(server_send, &alice_keys.secret)?;
// Both structs now have the shared secret
assert_eq!(alice.shared_secret, bob.shared_secret);
Ok(())
}

18
third_party/kyber/examples/kem.rs vendored Normal file
View file

@ -0,0 +1,18 @@
use pqc_kyber::*;
fn main () -> Result<(), KyberError> {
let mut rng = rand::thread_rng();
// Alice generates a keypair
let alice_keys = keypair(&mut rng);
// Bob encapsulates a shared secret
let (ciphertext, shared_secret_bob) = encapsulate(&alice_keys.public, &mut rng)?;
// Alice decapsulates the shared secret
let shared_secret_alice = decapsulate(&ciphertext, &alice_keys.secret)?;
// Both can now communicate symetrically
assert_eq!(shared_secret_alice, shared_secret_bob);
Ok(())
}

27
third_party/kyber/examples/uake.rs vendored Normal file
View file

@ -0,0 +1,27 @@
use pqc_kyber::*;
fn main() -> Result<(), KyberError> {
let mut rng = rand::thread_rng();
let mut alice = Uake::new();
let mut bob = Uake::new();
let bob_keys = keypair(&mut rng);
// Alice initiates key exchange with bob
let client_send = alice.client_init(&bob_keys.public, &mut rng);
// Bob receives the request and authenticates Alice, sends
// encapsulated shared secret back
let server_send = bob.server_receive(
client_send, &bob_keys.secret, &mut rng
)?;
// Alice autheticates and decapsulates
alice.client_confirm(server_send)?;
// Both structs now have the shared secret
assert_eq!(alice.shared_secret, bob.shared_secret);
Ok(())
}

12
third_party/kyber/fuzz/Cargo.toml vendored Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "kyber-fuzz"
version = "0.0.1"
authors = ["null"]
edition = "2018"
publish = false
[dependencies]
honggfuzz = "0.5.54"
rand_xoshiro = "0.6.0"
rand = "0.8.3"
pqc-kyber = { path = ".." }

38
third_party/kyber/fuzz/readme.md vendored Normal file
View file

@ -0,0 +1,38 @@
# Fuzzing
This library uses Google's honggfuzz, for more information see the [official page](https://honggfuzz.dev/) or the [rust docs](https://docs.rs/honggfuzz/0.5.54/honggfuzz/)
### Dependencies
* C compiler: cc
* GNU Make: make
* GNU Binutils development files for the BFD library: libbfd.h
* libunwind development files: libunwind.h
* liblzma development files
To install on Debian:
```bash
sudo apt install build-essential binutils-dev libunwind-dev
cargo install honggfuzz
```
The best place to start probing is the unsafe code in the avx2 optimized version.
So to run on x86_64 platforms:
```bash
export RUSTFLAGS="-Z sanitizer=address -C target-cpu=native -C target-feature=+aes,+avx2,+sse2,+sse4.1,+bmi2,+popcnt"
cargo hfuzz run <TARGET>
```
Run different security levels and modes:
```bash
cargo hfuzz run <TARGET> --features "kyber512 90s"
```
Current targets are:
* keypair
* encap
* decap

17
third_party/kyber/fuzz/src/bin/decap.rs vendored Normal file
View file

@ -0,0 +1,17 @@
use honggfuzz::fuzz;
use pqc_kyber::*;
fn main() -> Result<(), KyberError> {
let mut ss = [0u8; KYBER_SSBYTES];
const CTBYTES: usize = KYBER_CIPHERTEXTBYTES;
const SKBYTES: usize = KYBER_SECRETKEYBYTES;
loop {
fuzz!(|data: &[u8] | {
if data.len() != CTBYTES + SKBYTES {return};
match crypto_kem_dec(&mut ss, &data[..CTBYTES], &data[CTBYTES..SKBYTES]) {
Ok(_) => (),
Err(_) => ()
}
});
};
}

19
third_party/kyber/fuzz/src/bin/encap.rs vendored Normal file
View file

@ -0,0 +1,19 @@
use honggfuzz::fuzz;
use pqc_kyber::*;
use rand_xoshiro::rand_core::{SeedableRng, RngCore};
use rand_xoshiro::Xoshiro256Plus;
fn main() -> Result<(), KyberError> {
let mut _rng = rand::thread_rng(); //placeholder
let mut rng = Xoshiro256Plus::seed_from_u64(0);
let mut ct = [0u8; KYBER_CIPHERTEXTBYTES];
let mut ss = [0u8; KYBER_SSBYTES];
let mut s1 = [0u8; 32];
loop {
rng.fill_bytes(&mut s1);
fuzz!(|data: &[u8] | {
if data.len() != KYBER_PUBLICKEYBYTES {return};
crypto_kem_enc(&mut ct, &mut ss, data, &mut _rng, Some(&s1));
});
};
}

View file

@ -0,0 +1,20 @@
use honggfuzz::fuzz;
use pqc_kyber::*;
use rand_xoshiro::rand_core::{SeedableRng, RngCore};
use rand_xoshiro::Xoshiro256Plus;
fn main() -> Result<(), KyberError> {
let mut _rng = rand::thread_rng(); //placeholder
let mut rng = Xoshiro256Plus::seed_from_u64(0);
let mut public = [0u8; KYBER_PUBLICKEYBYTES];
let mut secret = [0u8; KYBER_SECRETKEYBYTES];
let mut s1 = [0u8; 32];
let mut s2 = [0u8; 32];
loop {
rng.fill_bytes(&mut s1);
rng.fill_bytes(&mut s2);
fuzz!(|data: ()| {
crypto_kem_keypair(&mut public, &mut secret, &mut _rng, Some((&s1, &s2)));
});
};
}

BIN
third_party/kyber/kyber.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

243
third_party/kyber/readme.md vendored Normal file
View file

@ -0,0 +1,243 @@
<p align="center">
<img src="./kyber.png"/>
</p>
# Kyber
[![Build Status](https://github.com/Argyle-Cybersystems/kyber/actions/workflows/ci.yml/badge.svg)](https://github.com/Argyle-Cybersystems/kyber/actions)
[![Crates](https://img.shields.io/crates/v/pqc-kyber)](https://crates.io/crates/pqc-kyber)
[![NPM](https://img.shields.io/npm/v/pqc-kyber)](https://www.npmjs.com/package/pqc-kyber)
[![dependency status](https://deps.rs/repo/github/Argyle-Cybersystems/kyber/status.svg)](https://deps.rs/repo/github/Argyle-Cybersystems/kyber)
[![License](https://img.shields.io/badge/license-Apache-blue.svg)](https://github.com/Argyle-Cybersystems/kyber/blob/master/LICENSE)
A rust implementation of the Kyber algorithm, a post-quantum KEM that is a finalist in NIST's Post-Quantum Standardization Project.
This library:
* Is no_std compatible and needs no allocator, suitable for embedded devices.
* Reference files contain no unsafe code and are written in pure rust.
* On x86_64 platforms uses an avx2 optimized version by default, which includes some assembly code taken from the C repo.
* Compiles to WASM using wasm-bindgen and has a ready-to-use binary published on NPM.
See the [**features**](#features) section for different options regarding security levels and modes of operation. The default security setting is kyber764.
Please also read the [**security considerations**](#security-considerations) before use.
---
## Installation
In `Cargo.toml`:
```toml
[dependencies]
pqc_kyber = "0.2.0"
```
## Usage
```rust
use pqc_kyber::*;
```
The higher level structs will be appropriate for most use-cases.
Both unilateral or mutually authenticated key exchanges are possible.
---
### Unilaterally Authenticated Key Exchange
```rust
let mut rng = rand::thread_rng();
// Initialize the key exchange structs
let mut alice = Uake::new();
let mut bob = Uake::new();
// Generate Bob's Keypair
let bob_keys = keypair(&mut rng);
// Alice initiates key exchange
let client_init = alice.client_init(&bob_keys.public, &mut rng);
// Bob authenticates and responds
let server_response = bob.server_receive(
client_init, &bob_keys.secret, &mut rng
)?;
// Alice decapsulates the shared secret
alice.client_confirm(server_response)?;
// Both key exchange structs now have the same shared secret
assert_eq!(alice.shared_secret, bob.shared_secret);
```
---
### Mutually Authenticated Key Exchange
Mutual authentication follows the same workflow but with additional keys passed to the functions:
```rust
let mut alice = Ake::new();
let mut bob = Ake::new();
let alice_keys = keypair(&mut rng);
let bob_keys = keypair(&mut rng);
let client_init = alice.client_init(&bob_keys.public, &mut rng);
let server_response = bob.server_receive(
client_init, &alice_keys.public, &bob_keys.secret, &mut rng
)?;
alice.client_confirm(server_response, &alice_keys.secret)?;
assert_eq!(alice.shared_secret, bob.shared_secret);
```
---
### Key Encapsulation
Lower level functions for using the Kyber algorithm directly.
```rust
// Generate Keypair
let keys_bob = keypair(&mut rng);
// Alice encapsulates a shared secret using Bob's public key
let (ciphertext, shared_secret_alice) = encapsulate(&keys_bob.public, &mut rng)?;
// Bob decapsulates a shared secret using the ciphertext sent by Alice
let shared_secret_bob = decapsulate(&ciphertext, &keys_bob.secret)?;
assert_eq!(shared_secret_alice, shared_secret_bob);
```
---
## Errors
The KyberError enum handles errors. It has two variants:
* **InvalidInput** - One or more inputs to a function are incorrectly sized. A possible cause of this is two parties using different security levels while trying to negotiate a key exchange.
* **Decapsulation** - The ciphertext was unable to be authenticated. The shared secret was not decapsulated.
---
## Features
If no security level is specified then kyber764 is used by default as recommended by the authors. It is roughly equivalent to AES-196. Apart from the two security levels, all other features can be combined as needed. For example:
```toml
[dependencies]
pqc_kyber = {version = "0.2.0", features = ["kyber512", "90s", "reference"]}
```
| Feature | Description |
|-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| kyber512 | Enables kyber512 mode, with a security level roughly equivalent to AES-128. |
| kyber1024 | Enables kyber1024 mode, with a security level roughly equivalent to AES-256. A compile-time error is raised if more than one security level is specified. |
| 90s | Uses SHA2 and AES in counter mode as a replacement for SHAKE. This can provide hardware speedups in some cases. |
| reference | On x86_64 platforms the optimized version is used by default. Enabling this feature will force usage of the reference codebase. This flag is redundant on other architectures and has no effect. |
| wasm | For compiling to WASM targets. |
---
## Testing
The [run_all_tests](tests/run_all_tests.sh) script will traverse all possible codepaths by running a matrix of the security levels and variants.
Known Answer Tests require deterministic rng seeds, enable the `KATs` feature to run them, you must also specify the module as noted below. Using this feature outside of `cargo test` will result in a compile-time error.
```bash
# This example runs all KATs for kyber512-90s, note `--test kat` is needed here.
cargo test --test kat --features "KATs kyber512 90s"
```
The test vector files are quite large, you will need to build them yourself from the C reference code. There's a helper script to do this [here](./tests/KATs/build_kats.sh).
See the [testing readme](./tests/readme.md) for more comprehensive info.
---
## Benchmarking
Uses criterion for benchmarking. If you have GNUPlot installed it will generate statistical graphs in `target/criterion/`.
See the [benchmarking readme](./benches/readme.md) for information on correct usage.
---
## Fuzzing
The fuzzing suite uses honggfuzz, installation and instructions are on the [fuzzing](./fuzz/readme.md) page.
---
## WebAssembly
This library has been compiled and published as a WASM binary package. Usage instructions are published on npm:
https://www.npmjs.com/package/pqc-kyber
Which is also located here in the [wasm readme](./pkg/README.md)
To install:
```
npm i pqc-kyber
```
To use this library for web assembly purposes you'll need the `wasm` feature enabled.
```toml
[dependencies]
pqc-kyber = {version = "0.2.0", features = ["wasm"]
```
You will also need `wasm-pack` and `wasm32-unknown-unknown` or `wasm32-unknown-emscripten` toolchains installed
To build include the feature flag:
```shell
wasm-pack build -- --features wasm
```
---
## Security Considerations
The NIST post quantum standardisation project is still ongoing and changes may still be made to the underlying reference code at any time.
While much care has been taken porting from the C reference codebase, this library has not undergone any third-party security auditing nor can any guarantees be made about the potential for underlying vulnerabilities in LWE cryptography or potential side-channel attacks arising from this implementation.
Please use at your own risk.
---
## About
Kyber is an IND-CCA2-secure key encapsulation mechanism (KEM), whose security is based on the hardness of solving the learning-with-errors (LWE) problem over module lattices. It is one of the round 3 finalist algorithms submitted to the [NIST post-quantum cryptography project](https://csrc.nist.gov/Projects/Post-Quantum-Cryptography).
The official website: https://pq-crystals.org/kyber/
Authors of the Kyber Algorithm:
* Roberto Avanzi, ARM Limited (DE)
* Joppe Bos, NXP Semiconductors (BE)
* Léo Ducas, CWI Amsterdam (NL)
* Eike Kiltz, Ruhr University Bochum (DE)
* Tancrède Lepoint, SRI International (US)
* Vadim Lyubashevsky, IBM Research Zurich (CH)
* John M. Schanck, University of Waterloo (CA)
* Peter Schwabe, Radboud University (NL)
* Gregor Seiler, IBM Research Zurich (CH)
* Damien Stehle, ENS Lyon (FR)
---
### Contributing
Contributions welcome. For pull requests create a feature fork and submit it to the development branch. More information is available on the [contributing page](./contributing.md)

103
third_party/kyber/src/api.rs vendored Normal file
View file

@ -0,0 +1,103 @@
use crate::{
params::*,
error::KyberError,
RngCore, CryptoRng,
kem::*,
kex::{PublicKey, SecretKey, Encapsulated, Decapsulated}
};
/// Keypair generation with a provided RNG.
///
/// ### Example
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(), KyberError> {
/// let mut rng = rand::thread_rng();
/// let keys = keypair(&mut rng);
/// # Ok(())}
/// ```
pub fn keypair<R>(rng: &mut R) -> Keypair
where R: RngCore + CryptoRng
{
let mut public = [0u8; KYBER_PUBLICKEYBYTES];
let mut secret = [0u8; KYBER_SECRETKEYBYTES];
crypto_kem_keypair(&mut public, &mut secret, rng, None);
Keypair { public, secret }
}
/// Encapsulates a public key returning the ciphertext to send
/// and the shared secret
///
/// ### Example
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(), KyberError> {
/// let mut rng = rand::thread_rng();
/// let keys = keypair(&mut rng);
/// let (ciphertext, shared_secret) = encapsulate(&keys.public, &mut rng)?;
/// # Ok(())}
/// ```
pub fn encapsulate<R>(pk: &[u8], rng: &mut R) -> Encapsulated
where R: CryptoRng + RngCore
{
if pk.len() != KYBER_PUBLICKEYBYTES {
return Err(KyberError::InvalidInput)
}
let mut ct = [0u8; KYBER_CIPHERTEXTBYTES];
let mut ss = [0u8; KYBER_SSBYTES];
crypto_kem_enc(&mut ct, &mut ss, pk, rng, None);
Ok((ct, ss))
}
/// Decapsulates ciphertext with a secret key, the result will contain
/// a KyberError if decapsulation fails
///
/// ### Example
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(), KyberError> {
/// let mut rng = rand::thread_rng();
/// let keys = keypair(&mut rng);
/// let (ct, ss1) = encapsulate(&keys.public, &mut rng)?;
/// let ss2 = decapsulate(&ct, &keys.secret)?;
/// assert_eq!(ss1, ss2);
/// # Ok(())}
/// ```
pub fn decapsulate(ct: &[u8], sk: &[u8]) -> Decapsulated
{
if ct.len() != KYBER_CIPHERTEXTBYTES || sk.len() != KYBER_SECRETKEYBYTES {
return Err(KyberError::InvalidInput)
}
let mut ss = [0u8; KYBER_SSBYTES];
match crypto_kem_dec(&mut ss, ct, sk) {
Ok(_) => Ok(ss),
Err(e) => Err(e)
}
}
/// A public/secret keypair for use with Kyber.
///
/// Byte lengths of the keys are determined by the security level chosen.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Keypair {
pub public: PublicKey,
pub secret: SecretKey
}
impl Keypair {
/// Securely generates a new keypair`
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(), KyberError> {
/// let mut rng = rand::thread_rng();
/// let keys = Keypair::generate(&mut rng);
/// # let empty_keys = Keypair{
/// public: [0u8; KYBER_PUBLICKEYBYTES], secret: [0u8; KYBER_SECRETKEYBYTES]
/// };
/// # assert!(empty_keys != keys);
/// # Ok(()) }
/// ```
pub fn generate<R: CryptoRng + RngCore>(rng: &mut R) -> Keypair {
keypair(rng)
}
}

177
third_party/kyber/src/avx2/aes256ctr.rs vendored Normal file
View file

@ -0,0 +1,177 @@
// Based heavily on public-domain code by Romain Dolbeau
// Different handling of nonce+counter than original version using
// separated 64-bit nonce and internal 64-bit counter, starting from zero
// Public Domain
#![cfg(feature="90s")]
use core::arch::x86_64::*;
#[derive(Clone, Copy)]
#[repr(C)]
pub(crate) struct Aes256CtrCtx {
pub rkeys: [__m128i; 16],
pub n: __m128i
}
impl Aes256CtrCtx {
pub fn new() -> Self {
unsafe {
Self {
rkeys: [_mm_setzero_si128(); 16],
n: _mm_setzero_si128()
}
}
}
}
unsafe fn aesni_encrypt4(out: &mut[u8], n :&mut __m128i, rkeys: &[__m128i; 16])
{
let idx: __m128i = _mm_set_epi8(8,9,10,11,12,13,14,15,7,6,5,4,3,2,1,0);
// Load current counter value
let mut f = _mm_load_si128(n);
// Increase counter in 4 consecutive blocks
let mut f0 = _mm_shuffle_epi8(_mm_add_epi64(f,_mm_set_epi64x(0,0)),idx);
let mut f1 = _mm_shuffle_epi8(_mm_add_epi64(f,_mm_set_epi64x(1,0)),idx);
let mut f2 = _mm_shuffle_epi8(_mm_add_epi64(f,_mm_set_epi64x(2,0)),idx);
let mut f3 = _mm_shuffle_epi8(_mm_add_epi64(f,_mm_set_epi64x(3,0)),idx);
// Write counter for next iteration, increased by 4
_mm_store_si128(n as *mut __m128i,_mm_add_epi64(f,_mm_set_epi64x(4,0)));
// Actual AES encryption, 4x interleaved4
f = _mm_load_si128(&rkeys[0]);
f0 = _mm_xor_si128(f0,f);
f1 = _mm_xor_si128(f1,f);
f2 = _mm_xor_si128(f2,f);
f3 = _mm_xor_si128(f3,f);
for i in 1..14 {
f = _mm_load_si128(&rkeys[i]);
f0 = _mm_aesenc_si128(f0,f);
f1 = _mm_aesenc_si128(f1,f);
f2 = _mm_aesenc_si128(f2,f);
f3 = _mm_aesenc_si128(f3,f);
}
f = _mm_load_si128(&rkeys[14]);
f0 = _mm_aesenclast_si128(f0,f);
f1 = _mm_aesenclast_si128(f1,f);
f2 = _mm_aesenclast_si128(f2,f);
f3 = _mm_aesenclast_si128(f3,f);
// Write results
_mm_storeu_si128(out[..].as_mut_ptr() as *mut __m128i, f0);
_mm_storeu_si128(out[16..].as_mut_ptr() as *mut __m128i, f1);
_mm_storeu_si128(out[32..].as_mut_ptr() as *mut __m128i, f2);
_mm_storeu_si128(out[48..].as_mut_ptr() as *mut __m128i, f3);
}
// Casting aliases
unsafe fn cast_128i(x: __m128) -> __m128i
{
_mm_castps_si128(x)
}
unsafe fn cast_128(x: __m128i) -> __m128
{
_mm_castsi128_ps(x)
}
pub(crate) fn aes256ctr_init(state: &mut Aes256CtrCtx, key: &[u8], nonce: [u8; 12])
{
unsafe {
let mut idx = 0;
let key0 = _mm_loadu_si128(key.as_ptr() as *const __m128i);
let key1 = _mm_loadu_si128(key[16..].as_ptr() as *const __m128i);
state.n = _mm_loadl_epi64(nonce[..].as_ptr() as *const __m128i);
state.rkeys[idx] = key0;
idx += 1;
let mut temp0 = key0;
let mut temp1;
let mut temp2 = key1;
let mut temp4 = _mm_setzero_si128();
macro_rules! block1 {
($imm:expr) => {
temp1 = _mm_aeskeygenassist_si128(temp2, $imm);
state.rkeys[idx] = temp2;
idx += 1;
temp4 = cast_128i(_mm_shuffle_ps(cast_128(temp4), cast_128(temp0), 0x10));
temp0 = _mm_xor_si128(temp0, temp4);
temp4 = cast_128i(_mm_shuffle_ps(cast_128(temp4), cast_128(temp0), 0x8c));
temp0 = _mm_xor_si128(temp0, temp4);
temp1 = cast_128i(_mm_shuffle_ps(cast_128(temp1), cast_128(temp1), 0xff));
temp0 = _mm_xor_si128(temp0, temp1)
};
}
macro_rules! block2 {
($imm:expr) => {
temp1 = _mm_aeskeygenassist_si128(temp0, $imm);
state.rkeys[idx] = temp0;
idx += 1;
temp4 = cast_128i(_mm_shuffle_ps(cast_128(temp4), cast_128(temp2), 0x10));
temp2 = _mm_xor_si128(temp2, temp4);
temp4 = cast_128i(_mm_shuffle_ps(cast_128(temp4), cast_128(temp2), 0x8c));
temp2 = _mm_xor_si128(temp2, temp4);
temp1 = cast_128i(_mm_shuffle_ps(cast_128(temp1), cast_128(temp1), 0xaa));
temp2 = _mm_xor_si128(temp2, temp1)
};
}
block1!(0x01);
block2!(0x01);
block1!(0x02);
block2!(0x02);
block1!(0x04);
block2!(0x04);
block1!(0x08);
block2!(0x08);
block1!(0x10);
block2!(0x10);
block1!(0x20);
block2!(0x20);
block1!(0x40);
state.rkeys[idx] = temp0;
}
}
pub(crate) fn aes256ctr_squeezeblocks(out: &mut[u8], nblocks: usize, state: &mut Aes256CtrCtx)
{
let mut idx = 0;
for _ in 0..nblocks {
unsafe { aesni_encrypt4(&mut out[idx..], &mut state.n, &state.rkeys); }
idx += 64
}
}
#[cfg(feature="90s")]
pub(crate) fn aes256ctr_prf(out: &mut[u8], mut outlen: usize, seed: &[u8], nonce: u8)
{
let mut buf = [0u8; 64];
let mut idx = 0;
let mut pad_nonce = [0u8; 12];
let mut state = unsafe{
Aes256CtrCtx{rkeys: [ _mm_setzero_si128(); 16], n: _mm_setzero_si128()}
};
pad_nonce[0] = nonce;
aes256ctr_init(&mut state, seed, pad_nonce);
while outlen >= 64 {
unsafe { aesni_encrypt4(&mut out[idx..], &mut state.n, &state.rkeys); }
outlen -= 64;
idx += 64;
}
if outlen != 0 {
unsafe { aesni_encrypt4(&mut buf, &mut state.n, &state.rkeys); }
out[idx..][..outlen].copy_from_slice(&buf[..outlen]);
}
}

110
third_party/kyber/src/avx2/align.rs vendored Normal file
View file

@ -0,0 +1,110 @@
#![allow(dead_code)]
use core::arch::x86_64::*;
use crate::params::*;
use crate::poly::NOISE_NBLOCKS;
use crate::fips202::{SHAKE128_RATE, SHAKE256_RATE};
use crate::symmetric::*;
use crate::avx2::rejsample::REJ_UNIFORM_AVX_NBLOCKS;
// Buffer unions
// #[derive(Copy, Clone)]
// #[repr(C, align(8))]
// pub(crate) union Align8<const N: usize, const V: usize> {
// pub coeffs: [u8; N],
// pub vec: [__m256i; V]
// }
// impl<const N: usize, const V: usize> Align8 <N, V>{
// pub fn new() -> Self {
// Self {
// coeffs: [0u8; N]
// }
// }
// }
#[derive(Copy, Clone)]
#[repr(C, align(32))]
pub union GenMatrixBuf {
pub coeffs: [u8; REJ_UNIFORM_AVX_NBLOCKS*SHAKE128_RATE],
pub vec: [__m256i; (REJ_UNIFORM_AVX_NBLOCKS*SHAKE128_RATE+31)/32]
}
impl GenMatrixBuf {
pub fn new() -> Self {
Self { coeffs: [0u8; REJ_UNIFORM_AVX_NBLOCKS*SHAKE128_RATE]}
}
}
#[cfg(feature="90s")]
#[repr(C)]
pub union GenMatrixBuf90s {
pub coeffs:
[u8; REJ_UNIFORM_AVX_NBLOCKS*XOF_BLOCKBYTES],
pub vec:
[__m256i; (REJ_UNIFORM_AVX_NBLOCKS*XOF_BLOCKBYTES+31)/32]
}
#[cfg(feature="90s")]
impl GenMatrixBuf90s {
pub fn new() -> Self {
Self {
coeffs: [0u8; REJ_UNIFORM_AVX_NBLOCKS*XOF_BLOCKBYTES]
}
}
#[cfg(debug_assertions)]
pub fn checksum(&self) -> i16 {
let mut out = 0;
for i in 0..REJ_UNIFORM_AVX_NBLOCKS*XOF_BLOCKBYTES {
unsafe { out ^= self.coeffs[i] as i16; }
}
out
}
}
#[repr(C)]
pub union IndcpaBuf {
pub coeffs: [u8;
(KYBER_ETA1*KYBER_N/4)
/XOF_BLOCKBYTES*XOF_BLOCKBYTES+32],
pub vec: [__m256i;
((KYBER_ETA1*KYBER_N/4)
/XOF_BLOCKBYTES*XOF_BLOCKBYTES+32+31)/32]
}
impl IndcpaBuf {
pub fn new() -> Self {
Self {
coeffs: [0u8;
(KYBER_ETA1*KYBER_N/4)
/XOF_BLOCKBYTES*XOF_BLOCKBYTES+32]
}
}
}
#[repr(C, align(8))]
pub union Eta2Buf {
pub coeffs: [u8; KYBER_ETA2*KYBER_N/4],
pub vec: [__m256i; (KYBER_ETA2*KYBER_N/4+31)/32]
}
impl Eta2Buf {
pub fn new() -> Self {
Self { coeffs: [0u8; KYBER_ETA2*KYBER_N/4] }
}
}
#[derive(Copy, Clone)]
#[repr(C, align(8))]
pub union Eta4xBuf {
pub coeffs: [u8; NOISE_NBLOCKS*SHAKE256_RATE],
pub vec: [__m256i; (NOISE_NBLOCKS*SHAKE256_RATE+31)/32]
}
impl Eta4xBuf {
pub fn new() -> Self {
Self { coeffs: [0u8; NOISE_NBLOCKS*SHAKE256_RATE] }
}
}

103
third_party/kyber/src/avx2/basemul.S vendored Normal file
View file

@ -0,0 +1,103 @@
.macro schoolbook off
vmovdqa 32(%rcx),%ymm0
vmovdqa (64*\off+ 0)*2(%rsi),%ymm1 # a0
vmovdqa (64*\off+16)*2(%rsi),%ymm2 # b0
vmovdqa (64*\off+32)*2(%rsi),%ymm3 # a1
vmovdqa (64*\off+48)*2(%rsi),%ymm4 # b1
vpmullw %ymm0,%ymm1,%ymm9 # a0.lo
vpmullw %ymm0,%ymm2,%ymm10 # b0.lo
vpmullw %ymm0,%ymm3,%ymm11 # a1.lo
vpmullw %ymm0,%ymm4,%ymm12 # b1.lo
vmovdqa (64*\off+ 0)*2(%rdx),%ymm5 # c0
vmovdqa (64*\off+16)*2(%rdx),%ymm6 # d0
vpmulhw %ymm5,%ymm1,%ymm13 # a0c0.hi
vpmulhw %ymm6,%ymm1,%ymm1 # a0d0.hi
vpmulhw %ymm5,%ymm2,%ymm14 # b0c0.hi
vpmulhw %ymm6,%ymm2,%ymm2 # b0d0.hi
vmovdqa (64*\off+32)*2(%rdx),%ymm7 # c1
vmovdqa (64*\off+48)*2(%rdx),%ymm8 # d1
vpmulhw %ymm7,%ymm3,%ymm15 # a1c1.hi
vpmulhw %ymm8,%ymm3,%ymm3 # a1d1.hi
vpmulhw %ymm7,%ymm4,%ymm0 # b1c1.hi
vpmulhw %ymm8,%ymm4,%ymm4 # b1d1.hi
vmovdqa %ymm13,(%rsp)
vpmullw %ymm5,%ymm9,%ymm13 # a0c0.lo
vpmullw %ymm6,%ymm9,%ymm9 # a0d0.lo
vpmullw %ymm5,%ymm10,%ymm5 # b0c0.lo
vpmullw %ymm6,%ymm10,%ymm10 # b0d0.lo
vpmullw %ymm7,%ymm11,%ymm6 # a1c1.lo
vpmullw %ymm8,%ymm11,%ymm11 # a1d1.lo
vpmullw %ymm7,%ymm12,%ymm7 # b1c1.lo
vpmullw %ymm8,%ymm12,%ymm12 # b1d1.lo
vmovdqa 0*2(%rcx),%ymm8
vpmulhw %ymm8,%ymm13,%ymm13
vpmulhw %ymm8,%ymm9,%ymm9
vpmulhw %ymm8,%ymm5,%ymm5
vpmulhw %ymm8,%ymm10,%ymm10
vpmulhw %ymm8,%ymm6,%ymm6
vpmulhw %ymm8,%ymm11,%ymm11
vpmulhw %ymm8,%ymm7,%ymm7
vpmulhw %ymm8,%ymm12,%ymm12
vpsubw (%rsp),%ymm13,%ymm13 # -a0c0
vpsubw %ymm9,%ymm1,%ymm9 # a0d0
vpsubw %ymm5,%ymm14,%ymm5 # b0c0
vpsubw %ymm10,%ymm2,%ymm10 # b0d0
vpsubw %ymm6,%ymm15,%ymm6 # a1c1
vpsubw %ymm11,%ymm3,%ymm11 # a1d1
vpsubw %ymm7,%ymm0,%ymm7 # b1c1
vpsubw %ymm12,%ymm4,%ymm12 # b1d1
vmovdqa (%r9),%ymm0
vmovdqa 32(%r9),%ymm1
vpmullw %ymm0,%ymm10,%ymm2
vpmullw %ymm0,%ymm12,%ymm3
vpmulhw %ymm1,%ymm10,%ymm10
vpmulhw %ymm1,%ymm12,%ymm12
vpmulhw %ymm8,%ymm2,%ymm2
vpmulhw %ymm8,%ymm3,%ymm3
vpsubw %ymm2,%ymm10,%ymm10 # rb0d0
vpsubw %ymm3,%ymm12,%ymm12 # rb1d1
vpaddw %ymm5,%ymm9,%ymm9
vpaddw %ymm7,%ymm11,%ymm11
vpsubw %ymm13,%ymm10,%ymm13
vpsubw %ymm12,%ymm6,%ymm6
vmovdqa %ymm13,(64*\off+ 0)*2(%rdi)
vmovdqa %ymm9,(64*\off+16)*2(%rdi)
vmovdqa %ymm6,(64*\off+32)*2(%rdi)
vmovdqa %ymm11,(64*\off+48)*2(%rdi)
.endm
.text
.global basemul_avx
basemul_avx:
mov %rsp,%r8
and $-32,%rsp
sub $32,%rsp
lea (336)*2(%rcx),%r9
schoolbook 0
add $32*2,%r9
schoolbook 1
add $192*2,%r9
schoolbook 2
add $32*2,%r9
schoolbook 3
mov %r8,%rsp
ret

136
third_party/kyber/src/avx2/cbd.rs vendored Normal file
View file

@ -0,0 +1,136 @@
#![allow(non_snake_case, dead_code)]
use core::arch::x86_64::*;
use crate::params::KYBER_N;
use crate::poly::*;
use crate::align::Eta4xBuf;
#[cfg(feature="90s")]
use crate::align::IndcpaBuf;
fn cbd2(r: &mut Poly, buf: &[__m256i]) {
unsafe {
let mask55: __m256i = _mm256_set1_epi32(0x55555555);
let mask33: __m256i = _mm256_set1_epi32(0x33333333);
let mask03: __m256i = _mm256_set1_epi32(0x03030303);
let mask0F: __m256i = _mm256_set1_epi32(0x0F0F0F0F);
let (mut f0, mut f1, mut f2, mut f3);
for i in 0..(KYBER_N/64) {
f0 = _mm256_load_si256(&buf[i]);
f1 = _mm256_srli_epi16(f0, 1);
f0 = _mm256_and_si256(mask55, f0);
f1 = _mm256_and_si256(mask55, f1);
f0 = _mm256_add_epi8(f0, f1);
f1 = _mm256_srli_epi16(f0, 2);
f0 = _mm256_and_si256(mask33, f0);
f1 = _mm256_and_si256(mask33, f1);
f0 = _mm256_add_epi8(f0, mask33);
f0 = _mm256_sub_epi8(f0, f1);
f1 = _mm256_srli_epi16(f0, 4);
f0 = _mm256_and_si256(mask0F, f0);
f1 = _mm256_and_si256(mask0F, f1);
f0 = _mm256_sub_epi8(f0, mask03);
f1 = _mm256_sub_epi8(f1, mask03);
f2 = _mm256_unpacklo_epi8(f0, f1);
f3 = _mm256_unpackhi_epi8(f0, f1);
f0 = _mm256_cvtepi8_epi16(_mm256_castsi256_si128(f2));
f1 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(f2,1));
f2 = _mm256_cvtepi8_epi16(_mm256_castsi256_si128(f3));
f3 = _mm256_cvtepi8_epi16(_mm256_extracti128_si256(f3,1));
_mm256_store_si256(&mut r.vec[4*i+0], f0);
_mm256_store_si256(&mut r.vec[4*i+1], f2);
_mm256_store_si256(&mut r.vec[4*i+2], f1);
_mm256_store_si256(&mut r.vec[4*i+3], f3);
}
}
}
fn cbd3(r: &mut Poly, buf: &[u8]) {
unsafe {
let (mut f0, mut f1, mut f2, mut f3);
let mask249: __m256i = _mm256_set1_epi32(0x249249);
let mask6DB: __m256i = _mm256_set1_epi32(0x6DB6DB);
let mask07: __m256i = _mm256_set1_epi32(7);
let mask70: __m256i = _mm256_set1_epi32(7 << 16);
let mask: __m256i = _mm256_set1_epi16(3);
let shufbidx: __m256i = _mm256_set_epi8(
-1,15,14,13,-1,12,11,10,-1, 9, 8, 7,-1, 6, 5, 4,
-1,11,10, 9,-1, 8, 7, 6,-1, 5, 4, 3,-1, 2, 1, 0
);
for i in 0..(KYBER_N/32) {
f0 = _mm256_loadu_si256(buf[24*i..].as_ptr() as *const __m256i);
f0 = _mm256_permute4x64_epi64(f0,0x94);
f0 = _mm256_shuffle_epi8(f0,shufbidx);
f1 = _mm256_srli_epi32(f0,1);
f2 = _mm256_srli_epi32(f0,2);
f0 = _mm256_and_si256(mask249,f0);
f1 = _mm256_and_si256(mask249,f1);
f2 = _mm256_and_si256(mask249,f2);
f0 = _mm256_add_epi32(f0,f1);
f0 = _mm256_add_epi32(f0,f2);
f1 = _mm256_srli_epi32(f0,3);
f0 = _mm256_add_epi32(f0,mask6DB);
f0 = _mm256_sub_epi32(f0,f1);
f1 = _mm256_slli_epi32(f0,10);
f2 = _mm256_srli_epi32(f0,12);
f3 = _mm256_srli_epi32(f0, 2);
f0 = _mm256_and_si256(f0,mask07);
f1 = _mm256_and_si256(f1,mask70);
f2 = _mm256_and_si256(f2,mask07);
f3 = _mm256_and_si256(f3,mask70);
f0 = _mm256_add_epi16(f0,f1);
f1 = _mm256_add_epi16(f2,f3);
f0 = _mm256_sub_epi16(f0,mask);
f1 = _mm256_sub_epi16(f1,mask);
f2 = _mm256_unpacklo_epi32(f0,f1);
f3 = _mm256_unpackhi_epi32(f0,f1);
f0 = _mm256_permute2x128_si256(f2,f3,0x20);
f1 = _mm256_permute2x128_si256(f2,f3,0x31);
_mm256_store_si256(&mut r.vec[2*i+0], f0);
_mm256_store_si256(&mut r.vec[2*i+1], f1);
}
}
}
pub fn poly_cbd_eta1(r: &mut Poly, buf: &Eta4xBuf)
{
unsafe {
if cfg!(feature="kyber512") {
cbd3(r, &buf.coeffs)
}
else {
cbd2(r, &buf.vec)
}
}
}
#[cfg(feature="90s")]
pub fn poly_cbd_eta1_90s(r: &mut Poly, buf: &IndcpaBuf)
{
unsafe {
if cfg!(feature="kyber512") {
cbd3(r, &buf.coeffs)
}
else {
cbd2(r, &buf.vec)
}
}
}
pub fn poly_cbd_eta2(r: &mut Poly, buf: &[__m256i])
{
cbd2(r, &buf)
}

43
third_party/kyber/src/avx2/consts.h vendored Normal file
View file

@ -0,0 +1,43 @@
// #ifndef CONSTS_H
// #define CONSTS_H
// #include "params.h"
#define _16XQ 0
#define _16XQINV 16
#define _16XV 32
#define _16XFLO 48
#define _16XFHI 64
#define _16XMONTSQLO 80
#define _16XMONTSQHI 96
#define _16XMASK 112
#define _REVIDXB 128
#define _REVIDXD 144
#define _ZETAS_EXP 160
#define _16XSHIFT 624
/* The C ABI on MacOS exports all symbols with a leading
* underscore. This means that any symbols we refer to from
* C files (functions) can't be found, and all symbols we
* refer to from ASM also can't be found.
*
* This define helps us get around this
*/
// #ifdef __ASSEMBLER__
// #if defined(__WIN32__) || defined(__APPLE__)
// #define decorate(s) _##s
// #define cdecl2(s) decorate(s)
// #define cdecl(s) cdecl2(KYBER_NAMESPACE(##s))
// #else
// #define cdecl(s) KYBER_NAMESPACE(##s)
// #endif
// #endif
// #ifndef __ASSEMBLER__
// #include "align.h"
// typedef ALIGNED_INT16(640) qdata_t;
// #define qdata KYBER_NAMESPACE(qdata)
// extern const qdata_t qdata;
// #endif
// #endif

116
third_party/kyber/src/avx2/consts.rs vendored Normal file
View file

@ -0,0 +1,116 @@
use core::arch::x86_64::*;
use crate::params::KYBER_Q;
pub(crate) const Q: i16 = KYBER_Q as i16;
// pub(crate) const MONT: i16 = -1044; // 2^16 mod q
pub(crate) const QINV: i16 = -3327; // q^-1 mod 2^16
pub(crate) const V: i16 = 20159; // floor(2^26/q + 0.5)
pub(crate) const FHI: i16 = 1441; // mont^2/128
pub(crate) const FLO: i16 = -10079; // qinv*FHI
pub(crate) const MONTSQHI: i16 = 1353; // mont^2
pub(crate) const MONTSQLO: i16 = 20553; // qinv*MONTSQHI
pub(crate) const MASK: i16 = 4095;
pub(crate) const SHIFT: i16 = 32;
pub(crate) const _16XQ: usize = 0;
pub(crate) const _16XQINV: usize = 16;
pub(crate) const _16XV: usize = 32;
pub(crate) const _16XFLO: usize = 48;
pub(crate) const _16XFHI: usize = 64;
pub(crate) const _16XMONTSQLO: usize = 80;
pub(crate) const _16XMONTSQHI: usize = 96;
pub(crate) const _16XMASK: usize = 112;
pub(crate) const _REVIDXB: usize = 128;
pub(crate) const _REVIDXD: usize = 144;
pub(crate) const _ZETAS_EXP: usize = 160;
pub(crate) const _16XSHIFT: usize = 624;
#[repr(C, align(32))]
pub union Qdata {
pub coeffs: [i16; 640],
pub vec: [__m256i; 40]
}
pub const QDATA: Qdata = Qdata { coeffs:
[ Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q,
QINV, QINV, QINV, QINV, QINV, QINV, QINV, QINV,
QINV, QINV, QINV, QINV, QINV, QINV, QINV, QINV,
V, V, V, V, V, V, V, V, V, V, V, V, V, V, V, V,
FLO, FLO, FLO, FLO, FLO, FLO, FLO, FLO,
FLO, FLO, FLO, FLO, FLO, FLO, FLO, FLO,
FHI, FHI, FHI, FHI, FHI, FHI, FHI, FHI,
FHI, FHI, FHI, FHI, FHI, FHI, FHI, FHI,
MONTSQLO, MONTSQLO, MONTSQLO, MONTSQLO,
MONTSQLO, MONTSQLO, MONTSQLO, MONTSQLO,
MONTSQLO, MONTSQLO, MONTSQLO, MONTSQLO,
MONTSQLO, MONTSQLO, MONTSQLO, MONTSQLO,
MONTSQHI, MONTSQHI, MONTSQHI, MONTSQHI,
MONTSQHI, MONTSQHI, MONTSQHI, MONTSQHI,
MONTSQHI, MONTSQHI, MONTSQHI, MONTSQHI,
MONTSQHI, MONTSQHI, MONTSQHI, MONTSQHI,
MASK, MASK, MASK, MASK, MASK, MASK, MASK, MASK,
MASK, MASK, MASK, MASK, MASK, MASK, MASK, MASK,
3854, 3340, 2826, 2312, 1798, 1284, 770, 256,
3854, 3340, 2826, 2312, 1798, 1284, 770, 256,
7, 0, 6, 0, 5, 0, 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
31498, 31498, 31498, 31498, -758, -758, -758, -758,
5237, 5237, 5237, 5237, 1397, 1397, 1397, 1397,
14745, 14745, 14745, 14745, 14745, 14745, 14745, 14745,
14745, 14745, 14745, 14745, 14745, 14745, 14745, 14745,
-359, -359, -359, -359, -359, -359, -359, -359,
-359, -359, -359, -359, -359, -359, -359, -359,
13525, 13525, 13525, 13525, 13525, 13525, 13525, 13525,
-12402, -12402, -12402, -12402, -12402, -12402, -12402, -12402,
1493, 1493, 1493, 1493, 1493, 1493, 1493, 1493,
1422, 1422, 1422, 1422, 1422, 1422, 1422, 1422,
-20907, -20907, -20907, -20907, 27758, 27758, 27758, 27758,
-3799, -3799, -3799, -3799, -15690, -15690, -15690, -15690,
-171, -171, -171, -171, 622, 622, 622, 622,
1577, 1577, 1577, 1577, 182, 182, 182, 182,
-5827, -5827, 17363, 17363, -26360, -26360, -29057, -29057,
5571, 5571, -1102, -1102, 21438, 21438, -26242, -26242,
573, 573, -1325, -1325, 264, 264, 383, 383,
-829, -829, 1458, 1458, -1602, -1602, -130, -130,
-5689, -6516, 1496, 30967, -23565, 20179, 20710, 25080,
-12796, 26616, 16064, -12442, 9134, -650, -25986, 27837,
1223, 652, -552, 1015, -1293, 1491, -282, -1544,
516, -8, -320, -666, -1618, -1162, 126, 1469,
-335, -11477, -32227, 20494, -27738, 945, -14883, 6182,
32010, 10631, 29175, -28762, -18486, 17560, -14430, -5276,
-1103, 555, -1251, 1550, 422, 177, -291, 1574,
-246, 1159, -777, -602, -1590, -872, 418, -156,
11182, 13387, -14233, -21655, 13131, -4587, 23092, 5493,
-32502, 30317, -18741, 12639, 20100, 18525, 19529, -12619,
430, 843, 871, 105, 587, -235, -460, 1653,
778, -147, 1483, 1119, 644, 349, 329, -75,
787, 787, 787, 787, 787, 787, 787, 787,
787, 787, 787, 787, 787, 787, 787, 787,
-1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517,
-1517, -1517, -1517, -1517, -1517, -1517, -1517, -1517,
28191, 28191, 28191, 28191, 28191, 28191, 28191, 28191,
-16694, -16694, -16694, -16694, -16694, -16694, -16694, -16694,
287, 287, 287, 287, 287, 287, 287, 287,
202, 202, 202, 202, 202, 202, 202, 202,
10690, 10690, 10690, 10690, 1358, 1358, 1358, 1358,
-11202, -11202, -11202, -11202, 31164, 31164, 31164, 31164,
962, 962, 962, 962, -1202, -1202, -1202, -1202,
-1474, -1474, -1474, -1474, 1468, 1468, 1468, 1468,
-28073, -28073, 24313, 24313, -10532, -10532, 8800, 8800,
18426, 18426, 8859, 8859, 26675, 26675, -16163, -16163,
-681, -681, 1017, 1017, 732, 732, 608, 608,
-1542, -1542, 411, 411, -205, -205, -1571, -1571,
19883, -28250, -15887, -8898, -28309, 9075, -30199, 18249,
13426, 14017, -29156, -12757, 16832, 4311, -24155, -17915,
-853, -90, -271, 830, 107, -1421, -247, -951,
-398, 961, -1508, -725, 448, -1065, 677, -1275,
-31183, 25435, -7382, 24391, -20927, 10946, 24214, 16989,
10335, -7934, -22502, 10906, 31636, 28644, 23998, -17422,
817, 603, 1322, -1465, -1215, 1218, -874, -1187,
-1185, -1278, -1510, -870, -108, 996, 958, 1522,
20297, 2146, 15355, -32384, -6280, -14903, -11044, 14469,
-21498, -20198, 23210, -17442, -23860, -20257, 7756, 23132,
1097, 610, -1285, 384, -136, -1335, 220, -1659,
-1530, 794, -854, 478, -308, 991, -1460, 1628,
SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT,
SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT, SHIFT ]
};

651
third_party/kyber/src/avx2/fips202.rs vendored Normal file
View file

@ -0,0 +1,651 @@
#![allow(clippy::needless_range_loop, dead_code)]
use crate::symmetric::KeccakState;
pub(crate) const SHAKE128_RATE: usize = 168;
pub(crate) const SHAKE256_RATE: usize = 136;
const SHA3_256_RATE: usize = 136;
const SHA3_512_RATE: usize = 72;
const NROUNDS: usize = 24;
fn rol(a: u64, offset: u64) -> u64
{
(a << offset) ^ (a >> (64-offset))
}
// Name: load64
//
// Description: Load 8 bytes into u64 in little-endian order
//
// Arguments: - const [u8] x: input byte array
//
// Returns the loaded 64-bit unsigned integer
pub fn load64(x: &[u8]) -> u64
{
let mut r = 0u64;
for i in 0..8 {
r |= (x[i] as u64) << (8 * i);
}
r
}
// Name: store64
//
// Description: Store a 64-bit integer to a byte array in little-endian order
//
// Arguments: - [u8] x: the output byte array
// - u64 u: input 64-bit unsigned integer
pub fn store64(x: &mut[u8], mut u: u64)
{
for i in x.iter_mut().take(8) {
*i = u as u8;
u >>= 8;
}
}
// Keccak round constants
const KECCAKF_ROUNDCONSTANTS: [u64; NROUNDS] = [
0x0000000000000001,
0x0000000000008082,
0x800000000000808a,
0x8000000080008000,
0x000000000000808b,
0x0000000080000001,
0x8000000080008081,
0x8000000000008009,
0x000000000000008a,
0x0000000000000088,
0x0000000080008009,
0x000000008000000a,
0x000000008000808b,
0x800000000000008b,
0x8000000000008089,
0x8000000000008003,
0x8000000000008002,
0x8000000000000080,
0x000000000000800a,
0x800000008000000a,
0x8000000080008081,
0x8000000000008080,
0x0000000080000001,
0x8000000080008008
];
// Name: KeccakF1600_StatePermute
//
// Description: The Keccak F1600 Permutation
//
// Arguments: - u64 * state: in/output Keccak state
pub(crate) fn keccakf1600_statepermute(state: &mut[u64])
{
//copyFromState(A, state)
let mut aba = state[ 0];
let mut abe = state[ 1];
let mut abi = state[ 2];
let mut abo = state[ 3];
let mut abu = state[ 4];
let mut aga = state[ 5];
let mut age = state[ 6];
let mut agi = state[ 7];
let mut ago = state[ 8];
let mut agu = state[ 9];
let mut aka = state[10];
let mut ake = state[11];
let mut aki = state[12];
let mut ako = state[13];
let mut aku = state[14];
let mut ama = state[15];
let mut ame = state[16];
let mut ami = state[17];
let mut amo = state[18];
let mut amu = state[19];
let mut asa = state[20];
let mut ase = state[21];
let mut asi = state[22];
let mut aso = state[23];
let mut asu = state[24];
for round in (0..NROUNDS).step_by(2) {
// prepareTheta
let mut bca = aba^aga^aka^ama^asa;
let mut bce = abe^age^ake^ame^ase;
let mut bci = abi^agi^aki^ami^asi;
let mut bco = abo^ago^ako^amo^aso;
let mut bcu = abu^agu^aku^amu^asu;
//thetaRhoPiChiIotaPrepareTheta(round , A, E)
let mut da = bcu^rol(bce, 1);
let mut de = bca^rol(bci, 1);
let mut di = bce^rol(bco, 1);
let mut d_o = bci^rol(bcu, 1);
let mut du = bco^rol(bca, 1);
aba ^= da;
bca = aba;
age ^= de;
bce = rol(age, 44);
aki ^= di;
bci = rol(aki, 43);
amo ^= d_o;
bco = rol(amo, 21);
asu ^= du;
bcu = rol(asu, 14);
let mut eba = bca ^((!bce)& bci );
eba ^= KECCAKF_ROUNDCONSTANTS[round];
let mut ebe = bce ^((!bci)& bco );
let mut ebi = bci ^((!bco)& bcu );
let mut ebo = bco ^((!bcu)& bca );
let mut ebu = bcu ^((!bca)& bce );
abo ^= d_o;
bca = rol(abo, 28);
agu ^= du;
bce = rol(agu, 20);
aka ^= da;
bci = rol(aka, 3);
ame ^= de;
bco = rol(ame, 45);
asi ^= di;
bcu = rol(asi, 61);
let mut ega = bca ^((!bce)& bci );
let mut ege = bce ^((!bci)& bco );
let mut egi = bci ^((!bco)& bcu );
let mut ego = bco ^((!bcu)& bca );
let mut egu = bcu ^((!bca)& bce );
abe ^= de;
bca = rol(abe, 1);
agi ^= di;
bce = rol(agi, 6);
ako ^= d_o;
bci = rol(ako, 25);
amu ^= du;
bco = rol(amu, 8);
asa ^= da;
bcu = rol(asa, 18);
let mut eka = bca ^((!bce)& bci );
let mut eke = bce ^((!bci)& bco );
let mut eki = bci ^((!bco)& bcu );
let mut eko = bco ^((!bcu)& bca );
let mut eku = bcu ^((!bca)& bce );
abu ^= du;
bca = rol(abu, 27);
aga ^= da;
bce = rol(aga, 36);
ake ^= de;
bci = rol(ake, 10);
ami ^= di;
bco = rol(ami, 15);
aso ^= d_o;
bcu = rol(aso, 56);
let mut ema = bca ^((!bce)& bci );
let mut eme = bce ^((!bci)& bco );
let mut emi = bci ^((!bco)& bcu );
let mut emo = bco ^((!bcu)& bca );
let mut emu = bcu ^((!bca)& bce );
abi ^= di;
bca = rol(abi, 62);
ago ^= d_o;
bce = rol(ago, 55);
aku ^= du;
bci = rol(aku, 39);
ama ^= da;
bco = rol(ama, 41);
ase ^= de;
bcu = rol(ase, 2);
let mut esa = bca ^((!bce)& bci );
let mut ese = bce ^((!bci)& bco );
let mut esi = bci ^((!bco)& bcu );
let mut eso = bco ^((!bcu)& bca );
let mut esu = bcu ^((!bca)& bce );
// prepareTheta
bca = eba^ega^eka^ema^esa;
bce = ebe^ege^eke^eme^ese;
bci = ebi^egi^eki^emi^esi;
bco = ebo^ego^eko^emo^eso;
bcu = ebu^egu^eku^emu^esu;
//thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
da = bcu^rol(bce, 1);
de = bca^rol(bci, 1);
di = bce^rol(bco, 1);
d_o = bci^rol(bcu, 1);
du = bco^rol(bca, 1);
eba ^= da;
bca = eba;
ege ^= de;
bce = rol(ege, 44);
eki ^= di;
bci = rol(eki, 43);
emo ^= d_o;
bco = rol(emo, 21);
esu ^= du;
bcu = rol(esu, 14);
aba = bca ^((!bce)& bci );
aba ^= KECCAKF_ROUNDCONSTANTS[round+1];
abe = bce ^((!bci)& bco );
abi = bci ^((!bco)& bcu );
abo = bco ^((!bcu)& bca );
abu = bcu ^((!bca)& bce );
ebo ^= d_o;
bca = rol(ebo, 28);
egu ^= du;
bce = rol(egu, 20);
eka ^= da;
bci = rol(eka, 3);
eme ^= de;
bco = rol(eme, 45);
esi ^= di;
bcu = rol(esi, 61);
aga = bca ^((!bce)& bci );
age = bce ^((!bci)& bco );
agi = bci ^((!bco)& bcu );
ago = bco ^((!bcu)& bca );
agu = bcu ^((!bca)& bce );
ebe ^= de;
bca = rol(ebe, 1);
egi ^= di;
bce = rol(egi, 6);
eko ^= d_o;
bci = rol(eko, 25);
emu ^= du;
bco = rol(emu, 8);
esa ^= da;
bcu = rol(esa, 18);
aka = bca ^((!bce)& bci );
ake = bce ^((!bci)& bco );
aki = bci ^((!bco)& bcu );
ako = bco ^((!bcu)& bca );
aku = bcu ^((!bca)& bce );
ebu ^= du;
bca = rol(ebu, 27);
ega ^= da;
bce = rol(ega, 36);
eke ^= de;
bci = rol(eke, 10);
emi ^= di;
bco = rol(emi, 15);
eso ^= d_o;
bcu = rol(eso, 56);
ama = bca ^((!bce)& bci );
ame = bce ^((!bci)& bco );
ami = bci ^((!bco)& bcu );
amo = bco ^((!bcu)& bca );
amu = bcu ^((!bca)& bce );
ebi ^= di;
bca = rol(ebi, 62);
ego ^= d_o;
bce = rol(ego, 55);
eku ^= du;
bci = rol(eku, 39);
ema ^= da;
bco = rol(ema, 41);
ese ^= de;
bcu = rol(ese, 2);
asa = bca ^((!bce)& bci );
ase = bce ^((!bci)& bco );
asi = bci ^((!bco)& bcu );
aso = bco ^((!bcu)& bca );
asu = bcu ^((!bca)& bce );
}
state[ 0] = aba;
state[ 1] = abe;
state[ 2] = abi;
state[ 3] = abo;
state[ 4] = abu;
state[ 5] = aga;
state[ 6] = age;
state[ 7] = agi;
state[ 8] = ago;
state[ 9] = agu;
state[10] = aka;
state[11] = ake;
state[12] = aki;
state[13] = ako;
state[14] = aku;
state[15] = ama;
state[16] = ame;
state[17] = ami;
state[18] = amo;
state[19] = amu;
state[20] = asa;
state[21] = ase;
state[22] = asi;
state[23] = aso;
state[24] = asu;
}
// Name: keccak_absorb
//
// Description: Absorb step of Keccak;
// non-incremental, starts by zeroing the state.
//
// Arguments: - u64 s: Keccak state
// usize pos: position in current block to be absorbed
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
// - const [u8] input: pointer to input to be absorbed into s
// - u64 inlen: length of input in bytes
pub(crate) fn keccak_absorb(
s: &mut[u64],
mut pos: usize,
r: usize,
input: &[u8],
mut inlen: usize
) -> usize
{
let mut idx = 0usize;
while pos+inlen >= r {
for i in pos..r {
s[i/8] ^= (input[idx] as u64) << 8 * (i%8);
idx += 1;
}
inlen -= r-pos;
keccakf1600_statepermute(s);
pos = 0;
}
let new_pos = pos+inlen;
for i in pos..new_pos {
s[i/8] ^= (input[idx] as u64) << 8 * (i%8);
}
new_pos
}
// Name: keccak_squeezeblocks
//
// Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each.
// Modifies the state. Can be called multiple times to keep squeezing,
// i.e., is incremental.
//
// Arguments: - [u8] h: output blocks
// - u64 nblocks: number of blocks to be squeezed (written to h)
// - u64 *s: in/output Keccak state
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
pub(crate) fn keccak_squeezeblocks(h: &mut[u8], mut nblocks: usize, s: &mut [u64], r: usize)
{
let mut idx = 0usize;
while nblocks > 0 {
keccakf1600_statepermute(s);
for i in 0..r/8 {
store64(&mut h[idx+8*i..], s[i])
}
idx += r;
nblocks -= 1;
}
}
// Name: shake128_absorb
//
// Description: Absorb step of the SHAKE128 XOF.
// non-incremental, starts by zeroing the state.
//
// Arguments: - u64 *s: (uninitialized) output Keccak state
// - const [u8] input: input to be absorbed into s
// - u64 inputByteLen: length of input in bytes
pub(crate) fn shake128_absorb(state: &mut KeccakState, input: &[u8], inlen: usize)
{
let pos = state.pos;
state.pos =keccak_absorb(&mut state.s, pos, SHAKE128_RATE, input, inlen);
}
// Name: shake128_squeezeblocks
//
// Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of
// SHAKE128_RATE bytes each. Can be called multiple times
// to keep squeezing. Assumes new block has not yet been
// started (state->pos = SHAKE128_RATE).
//
// Arguments: - [u8] out: pointer to output blocks
// - u64 nblocks: number of blocks to be squeezed (written to output)
// - KeccakState state: pointer to input/output Keccak state
pub(crate) fn shake128_squeezeblocks(out: &mut[u8], nblocks: usize, state: &mut KeccakState)
{
keccak_squeezeblocks(out, nblocks, &mut state.s, SHAKE128_RATE);
}
// Name: shake256
//
// Description: SHAKE256 XOF with non-incremental API
//
// Arguments: - [u8] output: output
// - usize outlen: requested output length in bytes
// - [u8] input: input
// - usize inlen: length of input in bytes
pub(crate) fn shake256(out: &mut[u8], mut outlen: usize, input: &[u8], inlen: usize)
{
let mut state = KeccakState::new();
let mut idx = 0;
shake256_absorb_once(&mut state, input, inlen);
let nblocks = outlen/SHAKE256_RATE;
shake256_squeezeblocks(&mut out[idx..], nblocks, &mut state);
outlen -= nblocks*SHAKE256_RATE;
idx += nblocks*SHAKE256_RATE;
shake256_squeeze(&mut out[idx..], outlen, &mut state);
}
// Name: sha3_256
//
// Description: SHA3-256 with non-incremental API
//
// Arguments: - [u8] h: output (32 bytes)
// - const [u8] input: input
// - usize inlen: length of input in bytes
pub(crate) fn sha3_256(h: &mut[u8], input: &[u8], inlen: usize)
{
let mut s = [0u64; 25];
keccak_absorb_once(&mut s, SHA3_256_RATE, input, inlen, 0x06);
keccakf1600_statepermute(&mut s);
for i in 0..4 {
store64(&mut h[8*i..], s[i]);
}
}
// Name: sha3_512
//
// Description: SHA3-512 with non-incremental API
//
// Arguments: - [u8] h: output (64 bytes)
// - const [u8] input: input
// - usize inlen: length of input in bytes
pub(crate) fn sha3_512(h: &mut[u8], input: &[u8], inlen: usize)
{
let mut s = [0u64; 25];
keccak_absorb_once(&mut s, SHA3_512_RATE, input, inlen, 0x06);
keccakf1600_statepermute(&mut s);
for i in 0..8 {
store64(&mut h[8*i..], s[i]);
}
}
// Name: keccak_finalize
//
// Description: Finalize absorb step.
//
// Arguments: - u64 s: pointer to Keccak state
// - usize pos: position in current block to be absorbed
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
// - u8 p: domain separation byte
fn keccak_finalize(s: &mut[u64], pos: usize, r: usize, p: u8)
{
s[pos/8] ^= (p as u64) << 8*(pos%8);
s[r/8-1] ^= 1u64 << 63;
}
// Name: keccak_absorb_once
//
// Description: Absorb step of Keccak;
// non-incremental, starts by zeroing the state.
//
// Arguments: - u64 *s: (uninitialized) output Keccak state
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
// - const [u8] input: input to be absorbed into s
// - u64 mlen: length of input in bytes
// - [u8] p: domain-separation byte for different Keccak-derived functions
pub(crate) fn keccak_absorb_once(
s: &mut[u64],
r: usize,
input: &[u8],
mut inlen:
usize,
p: u8)
{
// Zero State
for i in s.iter_mut() {
*i = 0;
}
let mut idx = 0usize;
while inlen >= r {
for i in 0..(r/8) {
s[i] ^= load64(&input[idx+8*i..]);
}
idx += r;
inlen -= r;
keccakf1600_statepermute(s);
}
for i in 0..inlen {
s[i/8] ^= (input[idx+i] as u64) << 8*(i%8);
}
s[inlen/8] ^= (p as u64) << 8*(inlen%8);
s[(r-1)/8] ^= 1u64 << 63;
}
// Name: keccak_squeeze
//
// Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each.
// Modifies the state. Can be called multiple times to keep squeezing,
// i.e., is incremental.
//
// Arguments: - [u8] out: output blocks
// - u64 nblocks: number of blocks to be squeezed (written to out)
// - u64 *s: in/output Keccak state
// usize pos: number of bytes in current block already squeezed
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
// Returns new position pos in current block
pub(crate) fn keccak_squeeze(
out: &mut[u8],
mut outlen: usize,
s: &mut [u64],
mut pos: usize,
r: usize
) -> usize
{
let mut idx = 0;
while outlen > 0 {
if pos == r {
keccakf1600_statepermute(s);
pos = 0
}
let mut i = pos;
while i < r && i < pos+outlen {
out[idx] = (s[i/8] >> 8*(i%8)) as u8;
i += 1;
idx += 1;
}
outlen -= i-pos;
pos = i;
}
pos
}
// Name: shake128_init
//
// Description: Initializes Keccak state for use as SHAKE128 XOF
//
// Arguments: - keccak_state state: (uninitialized) Keccak state
fn shake128_init(state: &mut KeccakState)
{
state.reset()
}
// Name: shake128_finalize
//
// Description: Finalize absorb step of the SHAKE128 XOF.
//
// Arguments: - keccak_state state: pointer to Keccak state
fn shake128_finalize(state: &mut KeccakState)
{
keccak_finalize(&mut state.s, state.pos, SHAKE128_RATE, 0x1F);
state.pos = SHAKE128_RATE;
}
// Name: shake128_squeeze
//
// Description: Squeeze step of SHAKE128 XOF. Squeezes arbitrarily many
// bytes. Can be called multiple times to keep squeezing.
//
// Arguments: - [u8] out: pointer to output blocks
// - usize outlen : number of bytes to be squeezed (written to output)
// - keccak_state s: pointer to input/output Keccak state
fn shake128_squeeze(out: &mut[u8], outlen: usize, state: &mut KeccakState)
{
state.pos = keccak_squeeze(out, outlen, &mut state.s, state.pos, SHAKE128_RATE);
}
// Name: shake128_absorb_once
//
// Description: Initialize, absorb into and finalize SHAKE128 XOF; non-incremental.
//
// Arguments: - keccak_state state: pointer to (uninitialized) output Keccak state
// - const [u8] in: input to be absorbed into s
// - usize inlen: length of input in bytes
pub(crate) fn shake128_absorb_once(state: &mut KeccakState, input: &[u8], inlen: usize)
{
keccak_absorb_once(&mut state.s, SHAKE128_RATE, input, inlen, 0x1F);
state.pos = SHAKE128_RATE;
}
fn shake256_init(state: &mut KeccakState) {
state.reset();
}
fn shake256_absorb(state: &mut KeccakState, input: &[u8], inlen: usize)
{
state.pos = keccak_absorb(&mut state.s, state.pos, SHAKE256_RATE, input, inlen);
}
fn shake256_finalize(state: &mut KeccakState)
{
keccak_finalize(&mut state.s, state.pos, SHAKE256_RATE, 0x1F);
state.pos = SHAKE256_RATE;
}
fn shake256_squeeze(out: &mut[u8], outlen: usize, state: &mut KeccakState)
{
state.pos = keccak_squeeze(out, outlen, &mut state.s, state.pos, SHAKE256_RATE);
}
pub(crate) fn shake256_absorb_once(state: &mut KeccakState, input: &[u8], inlen: usize)
{
keccak_absorb_once(&mut state.s, SHAKE256_RATE, input, inlen, 0x1F);
state.pos = SHAKE256_RATE;
}
fn shake256_squeezeblocks(out: &mut[u8], nblocks: usize, state: &mut KeccakState)
{
keccak_squeezeblocks(out, nblocks, &mut state.s, SHAKE256_RATE);
}
fn shake128(out: &mut[u8], mut outlen: usize, input: &[u8], inlen: usize)
{
let mut state = KeccakState::new();
let mut idx = 0;
shake128_absorb_once(&mut state, input, inlen);
let nblocks = outlen/SHAKE128_RATE;
shake128_squeezeblocks(&mut out[idx..], nblocks, &mut state);
outlen -= nblocks*SHAKE128_RATE;
idx += nblocks*SHAKE128_RATE;
shake128_squeeze(&mut out[idx..], outlen, &mut state);
}

280
third_party/kyber/src/avx2/fips202x4.rs vendored Normal file
View file

@ -0,0 +1,280 @@
#![allow(dead_code)]
use core::arch::x86_64::*;
use crate::fips202::*;
use crate::keccak4x::f1600_x4;
use crate::align::{GenMatrixBuf, Eta4xBuf};
#[repr(C)]
pub struct Keccakx4State {
s: [__m256i; 25]
}
impl Keccakx4State {
pub fn new() -> Self {
unsafe {Keccakx4State { s: [_mm256_setzero_si256(); 25]}}
}
}
pub unsafe fn keccakx4_absorb_once(
s: &mut[__m256i; 25],
r: usize,
in0: &[u8],
in1: &[u8],
in2: &[u8],
in3: &[u8],
mut inlen: usize,
p: u8
)
{
let mut pos = 0i64;
let mut t;
for i in 0..25 {
s[i] = _mm256_setzero_si256();
}
let mut idx = _mm256_set_epi64x(
in3.as_ptr() as i64,
in2.as_ptr() as i64,
in1.as_ptr() as i64,
in0.as_ptr() as i64,
);
while inlen >= r {
for i in 0..(r/8) {
t = _mm256_i64gather_epi64(pos as *const i64, idx, 1);
s[i] = _mm256_xor_si256(s[i], t);
pos += 8;
}
inlen -= r;
f1600_x4(s);
}
let end = inlen/8;
for i in 0..end {
t = _mm256_i64gather_epi64(pos as *const i64, idx, 1);
s[i] = _mm256_xor_si256(s[i], t);
pos += 8;
}
inlen -= 8*end;
if inlen > 0 {
t = _mm256_i64gather_epi64(pos as *const i64, idx, 1);
idx = _mm256_set1_epi64x(((1u64 << (8*inlen)) - 1) as i64);
t = _mm256_and_si256(t, idx);
s[end] = _mm256_xor_si256(s[end], t);
}
t = _mm256_set1_epi64x(((p as u64) << 8*inlen) as i64);
s[end] = _mm256_xor_si256(s[end], t);
t = _mm256_set1_epi64x((1u64 << 63) as i64);
s[r/8 - 1] = _mm256_xor_si256(s[r/8 - 1], t);
}
pub unsafe fn keccakx4_squeezeblocks128(
out: &mut [GenMatrixBuf; 4],
mut nblocks: usize,
r: usize,
s: &mut [__m256i; 25]
)
{
let mut t;
let mut idx = 0usize;
while nblocks > 0 {
f1600_x4(s);
for i in 0..(r/8) {
t = _mm_castsi128_pd(_mm256_castsi256_si128(s[i]));
let out0_ptr = out[0].coeffs[idx+8*i..].as_mut_ptr();
let out1_ptr = out[1].coeffs[idx+8*i..].as_mut_ptr();
_mm_storel_pd(out0_ptr as *mut f64, t);
_mm_storeh_pd(out1_ptr as *mut f64, t);
t = _mm_castsi128_pd(_mm256_extracti128_si256(s[i],1));
let out2_ptr = out[2].coeffs[idx+8*i..].as_mut_ptr();
let out3_ptr = out[3].coeffs[idx+8*i..].as_mut_ptr();
_mm_storel_pd(out2_ptr as *mut f64, t);
_mm_storeh_pd(out3_ptr as *mut f64, t);
}
idx += r;
nblocks -= 1;
}
}
pub unsafe fn keccakx4_squeezeblocks256(
out: &mut [Eta4xBuf; 4],
mut nblocks: usize,
r: usize,
s: &mut [__m256i; 25]
)
{
let mut t;
let mut idx = 0usize;
while nblocks > 0 {
f1600_x4(s);
for i in 0..(r/8) {
t = _mm_castsi128_pd(_mm256_castsi256_si128(s[i]));
_mm_storel_pd(out[0].coeffs[idx+8*i..].as_mut_ptr() as *mut f64, t);
_mm_storeh_pd(out[1].coeffs[idx+8*i..].as_mut_ptr() as *mut f64, t);
t = _mm_castsi128_pd(_mm256_extracti128_si256(s[i],1));
_mm_storel_pd(out[2].coeffs[idx+8*i..].as_mut_ptr() as *mut f64, t);
_mm_storeh_pd(out[3].coeffs[idx+8*i..].as_mut_ptr() as *mut f64, t);
}
idx += r;
nblocks -= 1;
}
}
// pub unsafe fn keccakx4_squeezeonce128(
// out: &mut [[u8; 168]; 4],
// s: &mut [__m256i; 25]
// )
// {
// let mut t;
// f1600_x4(s);
// for i in 0..(SHAKE128_RATE/8) {
// t = _mm_castsi128_pd(_mm256_castsi256_si128(s[i]));
// let out0_ptr = out[0][8*i] as *mut f64;
// _mm_storel_pd(out0_ptr, t);
// _mm_storeh_pd(out[1][8*i] as *mut f64, t);
// t = _mm_castsi128_pd(_mm256_extracti128_si256(s[i],1));
// _mm_storel_pd(out[2][8*i] as *mut f64, t);
// _mm_storeh_pd(out[3][8*i] as *mut f64, t);
// }
// }
// pub unsafe fn keccakx4_squeezeonce256(
// out: &mut [[u8; 136]; 4],
// s: &mut [__m256i; 25]
// )
// {
// let mut t;
// f1600_x4(s);
// for i in 0..(SHAKE256_RATE/8) {
// t = _mm_castsi128_pd(_mm256_castsi256_si128(s[i]));
// _mm_storel_pd(out[0][8*i] as *mut f64, t);
// _mm_storeh_pd(out[1][8*i] as *mut f64, t);
// t = _mm_castsi128_pd(_mm256_extracti128_si256(s[i],1));
// _mm_storel_pd(out[2][8*i] as *mut f64, t);
// _mm_storeh_pd(out[3][8*i] as *mut f64, t);
// }
// }
pub unsafe fn shake128x4_absorb_once(
state: &mut Keccakx4State,
in0: &[u8],
in1: &[u8],
in2: &[u8],
in3: &[u8],
inlen: usize,
)
{
keccakx4_absorb_once(
&mut state.s,
SHAKE128_RATE,
in0, in1, in2, in3, inlen,
0x1F
)
}
pub unsafe fn shake128x4_squeezeblocks(
out: &mut[GenMatrixBuf; 4],
nblocks: usize,
state: &mut Keccakx4State
)
{
keccakx4_squeezeblocks128(
out,
nblocks,
SHAKE128_RATE,
&mut state.s
);
}
pub unsafe fn shake256x4_absorb_once(
state: &mut Keccakx4State,
in0: &[u8],
in1: &[u8],
in2: &[u8],
in3: &[u8],
inlen: usize,
)
{
keccakx4_absorb_once(
&mut state.s,
SHAKE256_RATE,
in0, in1, in2, in3, inlen,
0x1F
)
}
pub unsafe fn shake256x4_squeezeblocks(
out: &mut[Eta4xBuf; 4],
nblocks: usize,
state: &mut Keccakx4State
)
{
keccakx4_squeezeblocks256(
out,
nblocks,
SHAKE256_RATE,
&mut state.s
);
}
// pub unsafe fn shake128x4(
// out: &mut [GenMatrixBuf; 4],
// mut outlen: usize,
// in0: &[u8],
// in1: &[u8],
// in2: &[u8],
// in3: &[u8],
// inlen: usize
// )
// {
// let nblocks = outlen/SHAKE128_RATE;
// let mut t = [[0u8; SHAKE128_RATE]; 4];
// let mut state = Keccakx4State::new();
// shake128x4_absorb_once(&mut state, in0, in1, in2, in3, inlen);
// shake128x4_squeezeblocks(out, nblocks, &mut state);
// let idx = nblocks*SHAKE128_RATE;
// outlen -= idx;
// if outlen > 0 {
// keccakx4_squeezeonce128(&mut t, &mut state.s);
// for i in 0..outlen {
// out[0].coeffs[idx+i] = t[0][i];
// out[1].coeffs[idx+i] = t[1][i];
// out[2].coeffs[idx+i] = t[2][i];
// out[3].coeffs[idx+i] = t[3][i];
// }
// }
// }
// pub unsafe fn shake256x4(
// out: &mut [Eta4xBuf; 4],
// mut outlen: usize,
// in0: &[u8],
// in1: &[u8],
// in2: &[u8],
// in3: &[u8],
// inlen: usize
// )
// {
// let nblocks = outlen/SHAKE256_RATE;
// let mut t = [[0u8; SHAKE256_RATE] ; 4];
// let mut state = Keccakx4State::new();
// shake256x4_absorb_once(&mut state, in0, in1, in2, in3, inlen);
// shake256x4_squeezeblocks(out, nblocks, &mut state);
// let idx = nblocks*SHAKE256_RATE;
// outlen -= nblocks*SHAKE256_RATE;
// if outlen > 0 {
// keccakx4_squeezeonce256(&mut t, &mut state.s);
// for i in 0..outlen {
// out[0].coeffs[idx+i] = t[0][i];
// out[1].coeffs[idx+i] = t[1][i];
// out[2].coeffs[idx+i] = t[2][i];
// out[3].coeffs[idx+i] = t[3][i];
// }
// }
// }

117
third_party/kyber/src/avx2/fq.S vendored Normal file
View file

@ -0,0 +1,117 @@
.macro red16 r,rs=0,x=12
vpmulhw %ymm1,%ymm\r,%ymm\x
.if \rs
vpmulhrsw %ymm\rs,%ymm\x,%ymm\x
.else
vpsraw $10,%ymm\x,%ymm\x
.endif
vpmullw %ymm0,%ymm\x,%ymm\x
vpsubw %ymm\x,%ymm\r,%ymm\r
.endm
.macro csubq r,x=12
vpsubw %ymm0,%ymm\r,%ymm\r
vpsraw $15,%ymm\r,%ymm\x
vpand %ymm0,%ymm\x,%ymm\x
vpaddw %ymm\x,%ymm\r,%ymm\r
.endm
.macro caddq r,x=12
vpsraw $15,%ymm\r,%ymm\x
vpand %ymm0,%ymm\x,%ymm\x
vpaddw %ymm\x,%ymm\r,%ymm\r
.endm
.macro fqmulprecomp al,ah,b,x=12
vpmullw %ymm\al,%ymm\b,%ymm\x
vpmulhw %ymm\ah,%ymm\b,%ymm\b
vpmulhw %ymm0,%ymm\x,%ymm\x
vpsubw %ymm\x,%ymm\b,%ymm\b
.endm
.text
reduce128_avx:
#load
vmovdqa (%rdi),%ymm2
vmovdqa 32(%rdi),%ymm3
vmovdqa 64(%rdi),%ymm4
vmovdqa 96(%rdi),%ymm5
vmovdqa 128(%rdi),%ymm6
vmovdqa 160(%rdi),%ymm7
vmovdqa 192(%rdi),%ymm8
vmovdqa 224(%rdi),%ymm9
red16 2
red16 3
red16 4
red16 5
red16 6
red16 7
red16 8
red16 9
#store
vmovdqa %ymm2,(%rdi)
vmovdqa %ymm3,32(%rdi)
vmovdqa %ymm4,64(%rdi)
vmovdqa %ymm5,96(%rdi)
vmovdqa %ymm6,128(%rdi)
vmovdqa %ymm7,160(%rdi)
vmovdqa %ymm8,192(%rdi)
vmovdqa %ymm9,224(%rdi)
ret
.global reduce_avx
reduce_avx:
#consts
vmovdqa 0*2(%rsi),%ymm0
vmovdqa 32*2(%rsi),%ymm1
call reduce128_avx
add $256,%rdi
call reduce128_avx
ret
tomont128_avx:
#load
vmovdqa (%rdi),%ymm3
vmovdqa 32(%rdi),%ymm4
vmovdqa 64(%rdi),%ymm5
vmovdqa 96(%rdi),%ymm6
vmovdqa 128(%rdi),%ymm7
vmovdqa 160(%rdi),%ymm8
vmovdqa 192(%rdi),%ymm9
vmovdqa 224(%rdi),%ymm10
fqmulprecomp 1,2,3,11
fqmulprecomp 1,2,4,12
fqmulprecomp 1,2,5,13
fqmulprecomp 1,2,6,14
fqmulprecomp 1,2,7,15
fqmulprecomp 1,2,8,11
fqmulprecomp 1,2,9,12
fqmulprecomp 1,2,10,13
#store
vmovdqa %ymm3,(%rdi)
vmovdqa %ymm4,32(%rdi)
vmovdqa %ymm5,64(%rdi)
vmovdqa %ymm6,96(%rdi)
vmovdqa %ymm7,128(%rdi)
vmovdqa %ymm8,160(%rdi)
vmovdqa %ymm9,192(%rdi)
vmovdqa %ymm10,224(%rdi)
ret
.global tomont_avx
tomont_avx:
#consts
vmovdqa 0*2(%rsi),%ymm0
vmovdqa 80*2(%rsi),%ymm1
vmovdqa 96*2(%rsi),%ymm2
call tomont128_avx
add $256,%rdi
call tomont128_avx
ret

30
third_party/kyber/src/avx2/fq.inc vendored Normal file
View file

@ -0,0 +1,30 @@
.macro red16 r,rs=0,x=12
vpmulhw %ymm1,%ymm\r,%ymm\x
.if \rs
vpmulhrsw %ymm\rs,%ymm\x,%ymm\x
.else
vpsraw $10,%ymm\x,%ymm\x
.endif
vpmullw %ymm0,%ymm\x,%ymm\x
vpsubw %ymm\x,%ymm\r,%ymm\r
.endm
.macro csubq r,x=12
vpsubw %ymm0,%ymm\r,%ymm\r
vpsraw $15,%ymm\r,%ymm\x
vpand %ymm0,%ymm\x,%ymm\x
vpaddw %ymm\x,%ymm\r,%ymm\r
.endm
.macro caddq r,x=12
vpsraw $15,%ymm\r,%ymm\x
vpand %ymm0,%ymm\x,%ymm\x
vpaddw %ymm\x,%ymm\r,%ymm\r
.endm
.macro fqmulprecomp al,ah,b,x=12
vpmullw %ymm\al,%ymm\b,%ymm\x
vpmulhw %ymm\ah,%ymm\b,%ymm\b
vpmulhw %ymm0,%ymm\x,%ymm\x
vpsubw %ymm\x,%ymm\b,%ymm\b
.endm

681
third_party/kyber/src/avx2/indcpa.rs vendored Normal file
View file

@ -0,0 +1,681 @@
use core::arch::x86_64::*;
#[cfg(not(feature = "90s"))]
use crate::{fips202::*, fips202x4::*};
#[cfg(feature = "90s")]
use crate::{aes256ctr::*, cbd::*};
#[cfg(not(feature="KATs"))]
use crate::rng::randombytes;
use crate::{
align::*,
CryptoRng,
params::*,
poly::*,
polyvec::*,
rejsample::*,
RngCore,
symmetric::*,
};
// Name: pack_pk
//
// Description: Serialize the public key as concatenation of the
// serialized vector of polynomials pk
// and the public seed used to generate the matrix A.
//
// Arguments: [u8] r: the output serialized public key
// const poly *pk: the input public-key polynomial
// const [u8] seed: the input public seed
fn pack_pk(r: &mut[u8], pk: &Polyvec, seed: &[u8])
{
polyvec_tobytes(r, pk);
r[KYBER_POLYVECBYTES..][..KYBER_SYMBYTES]
.copy_from_slice(&seed[..KYBER_SYMBYTES]);
}
// Name: unpack_pk
//
// Description: De-serialize public key from a byte array;
// approximate inverse of pack_pk
//
// Arguments: - Polyvec pk: output public-key vector of polynomials
// - [u8] seed: output seed to generate matrix A
// - const [u8] packedpk: input serialized public key
fn unpack_pk(pk: &mut Polyvec, seed: &mut[u8], packedpk: &[u8])
{
unsafe {polyvec_frombytes(pk, packedpk);}
seed[..KYBER_SYMBYTES]
.copy_from_slice(&packedpk[KYBER_POLYVECBYTES..][..KYBER_SYMBYTES]);
}
// Name: pack_sk
//
// Description: Serialize the secret key
//
// Arguments: - [u8] r: output serialized secret key
// - const Polyvec sk: input vector of polynomials (secret key)
fn pack_sk(r: &mut[u8], sk: &Polyvec)
{
polyvec_tobytes(r, sk);
}
// Name: unpack_sk
//
// Description: De-serialize the secret key;
// inverse of pack_sk
//
// Arguments: - Polyvec sk: output vector of polynomials (secret key)
// - const [u8] packedsk: input serialized secret key
fn unpack_sk(sk: &mut Polyvec, packedsk: &[u8])
{
unsafe {polyvec_frombytes(sk, packedsk);}
}
// Name: pack_ciphertext
//
// Description: Serialize the ciphertext as concatenation of the
// compressed and serialized vector of polynomials b
// and the compressed and serialized polynomial v
//
// Arguments: [u8] r: the output serialized ciphertext
// const poly *pk: the input vector of polynomials b
// const [u8] seed: the input polynomial v
fn pack_ciphertext(r: &mut[u8], b: &Polyvec, v: Poly)
{
unsafe {
polyvec_compress(r, b);
poly_compress(&mut r[KYBER_POLYVECCOMPRESSEDBYTES..], v);
}
}
// Name: unpack_ciphertext
//
// Description: De-serialize and decompress ciphertext from a byte array;
// approximate inverse of pack_ciphertext
//
// Arguments: - Polyvec b: output vector of polynomials b
// - Poly *v: output polynomial v
// - const [u8] c: input serialized ciphertext
fn unpack_ciphertext(b: &mut Polyvec, v: &mut Poly, c: &[u8])
{
unsafe {
polyvec_decompress(b, c);
poly_decompress(v, &c[KYBER_POLYVECCOMPRESSEDBYTES..]);
}
}
// Name: rej_uniform
//
// Description: Run rejection sampling on uniform random bytes to generate
// uniform random integers mod q
//
// Arguments: - i16 *r: output buffer
// - usize len: requested number of 16-bit integers (uniform mod q)
// - const [u8] buf: input buffer (assumed to be uniform random bytes)
// - usize buflen: length of input buffer in bytes
//
// Returns number of sampled 16-bit integers (at most len)
fn rej_uniform(r: &mut[i16], len: usize, buf: &[u8], buflen: usize) -> usize
{
let (mut ctr, mut pos) = (0usize, 0usize);
let (mut val0, mut val1);
while ctr < len && pos + 3 <= buflen {
val0 = ((buf[pos+0] >> 0) as u16 | (buf[pos+1] as u16) << 8) & 0xFFF;
val1 = ((buf[pos+1] >> 4) as u16 | (buf[pos+2] as u16) << 4) & 0xFFF;
pos += 3;
if val0 < KYBER_Q as u16 {
r[ctr] = val0 as i16;
ctr += 1;
}
if ctr < len && val1 < KYBER_Q as u16 {
r[ctr] = val1 as i16;
ctr += 1;
}
}
ctr
}
pub fn gen_a(a: &mut[Polyvec], b: &[u8])
{
unsafe { gen_matrix(a, b, false); }
}
pub fn gen_at(a: &mut[Polyvec], b: &[u8])
{
unsafe { gen_matrix(a, b, true); }
}
#[cfg(feature="90s")]
unsafe fn gen_matrix(a: &mut[Polyvec], seed: &[u8], transposed: bool)
{
let (mut ctr, mut off, mut buflen);
let mut nonce: u64;
let mut state = Aes256CtrCtx::new();
let mut buf = GenMatrixBuf90s::new();
aes256ctr_init(&mut state, seed, [0u8; 12]);
for i in 0..KYBER_K {
for j in 0..KYBER_K {
if transposed {
nonce = ((j << 8) | i) as u64;
} else {
nonce = ((i << 8) | j) as u64;
}
state.n = _mm_loadl_epi64([nonce].as_ptr() as *const __m128i);
aes256ctr_squeezeblocks(&mut buf.coeffs, REJ_UNIFORM_AVX_NBLOCKS, &mut state);
buflen = REJ_UNIFORM_AVX_NBLOCKS*XOF_BLOCKBYTES;
ctr = rej_uniform_avx(&mut a[i].vec[j].coeffs, &buf.coeffs);
while ctr < KYBER_N {
off = buflen % 3;
for k in 0..off {
buf.coeffs[k] = buf.coeffs[buflen - off + k];
}
aes256ctr_squeezeblocks(&mut buf.coeffs[off..], 1, &mut state);
buflen = off + XOF_BLOCKBYTES;
ctr += rej_uniform(&mut a[i].vec[j].coeffs[ctr..], KYBER_N-ctr, &buf.coeffs, buflen);
}
poly_nttunpack(&mut a[i].vec[j]);
}
}
}
#[cfg(all(feature="kyber512", not(feature="90s")))]
unsafe fn gen_matrix(a: &mut[Polyvec], seed: &[u8], transposed: bool)
{
let mut state = Keccakx4State::new();
let mut buf = [GenMatrixBuf::new(); 4];
let f = _mm256_loadu_si256(seed[..].as_ptr() as *const __m256i);
_mm256_store_si256(buf[0].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[1].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[2].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[3].vec.as_mut_ptr(), f);
if transposed {
buf[0].coeffs[32] = 0;
buf[0].coeffs[33] = 0;
buf[1].coeffs[32] = 0;
buf[1].coeffs[33] = 1;
buf[2].coeffs[32] = 1;
buf[2].coeffs[33] = 0;
buf[3].coeffs[32] = 1;
buf[3].coeffs[33] = 1;
}
else {
buf[0].coeffs[32] = 0;
buf[0].coeffs[33] = 0;
buf[1].coeffs[32] = 1;
buf[1].coeffs[33] = 0;
buf[2].coeffs[32] = 0;
buf[2].coeffs[33] = 1;
buf[3].coeffs[32] = 1;
buf[3].coeffs[33] = 1;
}
shake128x4_absorb_once(
&mut state, &buf[0].coeffs, &buf[1].coeffs, &buf[2].coeffs, &buf[3].coeffs, 34
);
shake128x4_squeezeblocks(&mut buf, REJ_UNIFORM_AVX_NBLOCKS, &mut state);
let mut ctr0 = rej_uniform_avx(&mut a[0].vec[0].coeffs, &buf[0].coeffs);
let mut ctr1 = rej_uniform_avx(&mut a[0].vec[1].coeffs, &buf[1].coeffs);
let mut ctr2 = rej_uniform_avx(&mut a[1].vec[0].coeffs, &buf[2].coeffs);
let mut ctr3 = rej_uniform_avx(&mut a[1].vec[1].coeffs, &buf[3].coeffs);
while ctr0 < KYBER_N || ctr1 < KYBER_N || ctr2 < KYBER_N || ctr3 < KYBER_N {
shake128x4_squeezeblocks(&mut buf, 1, &mut state);
ctr0 += rej_uniform(
&mut a[0].vec[0].coeffs[ctr0..], KYBER_N - ctr0, &buf[0].coeffs, SHAKE128_RATE
);
ctr1 += rej_uniform(
&mut a[0].vec[1].coeffs[ctr1..], KYBER_N - ctr1, &buf[1].coeffs, SHAKE128_RATE
);
ctr2 += rej_uniform(
&mut a[1].vec[0].coeffs[ctr2..], KYBER_N - ctr2, &buf[2].coeffs, SHAKE128_RATE
);
ctr3 += rej_uniform(
&mut a[1].vec[1].coeffs[ctr3..], KYBER_N - ctr3, &buf[3].coeffs, SHAKE128_RATE
);
}
poly_nttunpack(&mut a[0].vec[0]);
poly_nttunpack(&mut a[0].vec[1]);
poly_nttunpack(&mut a[1].vec[0]);
poly_nttunpack(&mut a[1].vec[1]);
}
#[cfg(all(not(feature="kyber512"), not(feature="kyber1024"), not(feature="90s")))]
unsafe fn gen_matrix(a: &mut[Polyvec], seed: &[u8], transposed: bool)
{
let mut state = Keccakx4State::new();
let mut state1x = KeccakState::new();
let mut buf = [GenMatrixBuf::new(); 4];
let mut f = _mm256_loadu_si256(seed.as_ptr() as *const __m256i);
_mm256_store_si256(buf[0].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[1].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[2].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[3].vec.as_mut_ptr(), f);
if transposed {
buf[0].coeffs[32] = 0;
buf[0].coeffs[33] = 0;
buf[1].coeffs[32] = 0;
buf[1].coeffs[33] = 1;
buf[2].coeffs[32] = 0;
buf[2].coeffs[33] = 2;
buf[3].coeffs[32] = 1;
buf[3].coeffs[33] = 0;
}
else {
buf[0].coeffs[32] = 0;
buf[0].coeffs[33] = 0;
buf[1].coeffs[32] = 1;
buf[1].coeffs[33] = 0;
buf[2].coeffs[32] = 2;
buf[2].coeffs[33] = 0;
buf[3].coeffs[32] = 0;
buf[3].coeffs[33] = 1;
}
shake128x4_absorb_once(
&mut state,
&buf[0].coeffs, &buf[1].coeffs,
&buf[2].coeffs, &buf[3].coeffs,
34
);
shake128x4_squeezeblocks(
&mut buf,
REJ_UNIFORM_AVX_NBLOCKS, &mut state
);
let mut ctr0 = rej_uniform_avx(&mut a[0].vec[0].coeffs, &buf[0].coeffs);
let mut ctr1 = rej_uniform_avx(&mut a[0].vec[1].coeffs, &buf[1].coeffs);
let mut ctr2 = rej_uniform_avx(&mut a[0].vec[2].coeffs, &buf[2].coeffs);
let mut ctr3 = rej_uniform_avx(&mut a[1].vec[0].coeffs, &buf[3].coeffs);
while ctr0 < KYBER_N || ctr1 < KYBER_N || ctr2 < KYBER_N || ctr3 < KYBER_N {
shake128x4_squeezeblocks(&mut buf, 1, &mut state);
ctr0 += rej_uniform(
&mut a[0].vec[0].coeffs[ctr0..], KYBER_N - ctr0, &buf[0].coeffs, SHAKE128_RATE
);
ctr1 += rej_uniform(
&mut a[0].vec[1].coeffs[ctr1..], KYBER_N - ctr1, &buf[1].coeffs, SHAKE128_RATE
);
ctr2 += rej_uniform(
&mut a[0].vec[2].coeffs[ctr2..], KYBER_N - ctr2, &buf[2].coeffs, SHAKE128_RATE
);
ctr3 += rej_uniform(
&mut a[1].vec[0].coeffs[ctr3..], KYBER_N - ctr3, &buf[3].coeffs, SHAKE128_RATE
);
}
poly_nttunpack(&mut a[0].vec[0]);
poly_nttunpack(&mut a[0].vec[1]);
poly_nttunpack(&mut a[0].vec[2]);
poly_nttunpack(&mut a[1].vec[0]);
f = _mm256_loadu_si256(seed.as_ptr() as *const __m256i);
_mm256_store_si256(buf[0].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[1].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[2].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[3].vec.as_mut_ptr(), f);
if transposed {
buf[0].coeffs[32] = 1;
buf[0].coeffs[33] = 1;
buf[1].coeffs[32] = 1;
buf[1].coeffs[33] = 2;
buf[2].coeffs[32] = 2;
buf[2].coeffs[33] = 0;
buf[3].coeffs[32] = 2;
buf[3].coeffs[33] = 1;
}
else {
buf[0].coeffs[32] = 1;
buf[0].coeffs[33] = 1;
buf[1].coeffs[32] = 2;
buf[1].coeffs[33] = 1;
buf[2].coeffs[32] = 0;
buf[2].coeffs[33] = 2;
buf[3].coeffs[32] = 1;
buf[3].coeffs[33] = 2;
}
shake128x4_absorb_once(
&mut state,
&buf[0].coeffs, &buf[1].coeffs,
&buf[2].coeffs, &buf[3].coeffs,
34
);
shake128x4_squeezeblocks(&mut buf, REJ_UNIFORM_AVX_NBLOCKS, &mut state);
ctr0 = rej_uniform_avx(&mut a[1].vec[1].coeffs, &buf[0].coeffs);
ctr1 = rej_uniform_avx(&mut a[1].vec[2].coeffs, &buf[1].coeffs);
ctr2 = rej_uniform_avx(&mut a[2].vec[0].coeffs, &buf[2].coeffs);
ctr3 = rej_uniform_avx(&mut a[2].vec[1].coeffs, &buf[3].coeffs);
while ctr0 < KYBER_N || ctr1 < KYBER_N || ctr2 < KYBER_N || ctr3 < KYBER_N {
shake128x4_squeezeblocks(&mut buf, 1, &mut state);
ctr0 += rej_uniform(
&mut a[1].vec[1].coeffs[ctr0..], KYBER_N - ctr0, &buf[0].coeffs, SHAKE128_RATE
);
ctr1 += rej_uniform(
&mut a[1].vec[2].coeffs[ctr1..], KYBER_N - ctr1, &buf[1].coeffs, SHAKE128_RATE
);
ctr2 += rej_uniform(
&mut a[2].vec[0].coeffs[ctr2..], KYBER_N - ctr2, &buf[2].coeffs, SHAKE128_RATE
);
ctr3 += rej_uniform(
&mut a[2].vec[1].coeffs[ctr3..], KYBER_N - ctr3, &buf[3].coeffs, SHAKE128_RATE
);
}
poly_nttunpack(&mut a[1].vec[1]);
poly_nttunpack(&mut a[1].vec[2]);
poly_nttunpack(&mut a[2].vec[0]);
poly_nttunpack(&mut a[2].vec[1]);
f = _mm256_loadu_si256(seed.as_ptr() as *const __m256i);
_mm256_store_si256(buf[0].vec.as_mut_ptr(), f);
buf[0].coeffs[32] = 2;
buf[0].coeffs[33] = 2;
shake128_absorb_once(&mut state1x, &buf[0].coeffs, 34);
shake128_squeezeblocks(&mut buf[0].coeffs, REJ_UNIFORM_AVX_NBLOCKS, &mut state1x);
ctr0 = rej_uniform_avx(&mut a[2].vec[2].coeffs, &buf[0].coeffs);
while ctr0 < KYBER_N {
shake128_squeezeblocks(&mut buf[0].coeffs, 1, &mut state1x);
ctr0 += rej_uniform(
&mut a[2].vec[2].coeffs[ctr0..], KYBER_N - ctr0, &buf[0].coeffs, SHAKE128_RATE
);
}
poly_nttunpack(&mut a[2].vec[2]);
}
#[cfg(all(feature="kyber1024", not(feature="90s")))]
unsafe fn gen_matrix(a: &mut[Polyvec], seed: &[u8], transposed: bool)
{
let mut f;
let mut state = Keccakx4State::new();
let mut buf = [GenMatrixBuf::new(); 4];
for i in 0..4usize {
f = _mm256_loadu_si256(seed[..].as_ptr() as *const __m256i);
_mm256_store_si256(buf[0].coeffs.as_mut_ptr() as *mut __m256i, f);
_mm256_store_si256(buf[1].coeffs.as_mut_ptr() as *mut __m256i, f);
_mm256_store_si256(buf[2].coeffs.as_mut_ptr() as *mut __m256i, f);
_mm256_store_si256(buf[3].coeffs.as_mut_ptr() as *mut __m256i, f);
if transposed {
for j in 0..4 {
buf[j].coeffs[32] = i as u8;
buf[j].coeffs[33] = j as u8;
}
} else {
for j in 0..4 {
buf[j].coeffs[32] = j as u8;
buf[j].coeffs[33] = i as u8;
}
}
shake128x4_absorb_once(
&mut state,
&buf[0].coeffs, &buf[1].coeffs, &buf[2].coeffs, &buf[3].coeffs, 34
);
shake128x4_squeezeblocks(&mut buf, REJ_UNIFORM_AVX_NBLOCKS, &mut state);
let mut ctr0 = rej_uniform_avx(&mut a[i].vec[0].coeffs, &buf[0].coeffs);
let mut ctr1 = rej_uniform_avx(&mut a[i].vec[1].coeffs, &buf[1].coeffs);
let mut ctr2 = rej_uniform_avx(&mut a[i].vec[2].coeffs, &buf[2].coeffs);
let mut ctr3 = rej_uniform_avx(&mut a[i].vec[3].coeffs, &buf[3].coeffs);
while ctr0 < KYBER_N || ctr1 < KYBER_N || ctr2 < KYBER_N || ctr3 < KYBER_N {
shake128x4_squeezeblocks(&mut buf, 1, &mut state);
ctr0 += rej_uniform(
&mut a[i].vec[0].coeffs[ctr0..], KYBER_N - ctr0, &buf[0].coeffs, SHAKE128_RATE
);
ctr1 += rej_uniform(
&mut a[i].vec[1].coeffs[ctr1..], KYBER_N - ctr1, &buf[1].coeffs, SHAKE128_RATE
);
ctr2 += rej_uniform(
&mut a[i].vec[2].coeffs[ctr2..], KYBER_N - ctr2, &buf[2].coeffs, SHAKE128_RATE
);
ctr3 += rej_uniform(
&mut a[i].vec[3].coeffs[ctr3..], KYBER_N - ctr3, &buf[3].coeffs, SHAKE128_RATE
);
}
poly_nttunpack(&mut a[i].vec[0]);
poly_nttunpack(&mut a[i].vec[1]);
poly_nttunpack(&mut a[i].vec[2]);
poly_nttunpack(&mut a[i].vec[3]);
}
}
pub fn indcpa_keypair<R>(
pk: &mut[u8],
sk: &mut[u8],
_seed: Option<(&[u8], &[u8])>,
_rng: &mut R
)
where R: CryptoRng + RngCore
{
let mut a = [Polyvec::new(); KYBER_K];
let (mut e, mut pkpv, mut skpv) = (Polyvec::new(), Polyvec::new(), Polyvec::new());
let mut buf = [0u8; 2*KYBER_SYMBYTES];
let mut randbuf = [0u8; 2*KYBER_SYMBYTES];
#[cfg(not(feature="KATs"))]
randombytes(&mut randbuf, KYBER_SYMBYTES, _rng);
#[cfg(feature="KATs")]
randbuf[..KYBER_SYMBYTES].copy_from_slice(&_seed.expect("KAT seed").0);
hash_g(&mut buf, &randbuf, KYBER_SYMBYTES);
let (publicseed, noiseseed) = buf.split_at(KYBER_SYMBYTES);
gen_a(&mut a, publicseed);
#[cfg(feature="90s")]
{
// Assumes divisibility
const NOISE_NBLOCKS: usize = (KYBER_ETA1*KYBER_N/4)/XOF_BLOCKBYTES;
let mut nonce = 0u64;
let mut state = Aes256CtrCtx::new();
let mut coins = IndcpaBuf::new();
aes256ctr_init(&mut state, noiseseed, [0u8; 12]);
nonce += 1;
unsafe {
for i in 0..KYBER_K {
aes256ctr_squeezeblocks(&mut coins.coeffs, NOISE_NBLOCKS, &mut state);
state.n = _mm_loadl_epi64([nonce].as_ptr() as *const __m128i);
nonce += 1;
poly_cbd_eta1_90s(&mut skpv.vec[i], &coins);
}
for i in 0..KYBER_K {
aes256ctr_squeezeblocks(&mut coins.coeffs, NOISE_NBLOCKS, &mut state);
state.n = _mm_loadl_epi64([nonce].as_ptr() as *const __m128i);
nonce += 1;
poly_cbd_eta1_90s(&mut e.vec[i], &coins);
}
}
}
#[cfg(all(feature="kyber512", not(feature="90s")))]
{
let (skpv0, skpv1) =skpv.vec.split_at_mut(1);
let (e0, e1) = e.vec.split_at_mut(1);
poly_getnoise_eta1_4x(
&mut skpv0[0], &mut skpv1[0], &mut e0[0], &mut e1[0], noiseseed, 0, 1, 2, 3
);
}
#[cfg(all(feature="kyber1024", not(feature="90s")))]
{
let (skpv0, skpv1) = skpv.vec.split_at_mut(1);
let (skpv1, skpv2) = skpv1.split_at_mut(1);
let (skpv2, skpv3) = skpv2.split_at_mut(1);
poly_getnoise_eta1_4x(
&mut skpv0[0], &mut skpv1[0], &mut skpv2[0], &mut skpv3[0], noiseseed, 0, 1, 2, 3
);
let (e0, e1) = e.vec.split_at_mut(1);
let (e1, e2) = e1.split_at_mut(1);
let (e2, e3) = e2.split_at_mut(1);
poly_getnoise_eta1_4x(
&mut e0[0], &mut e1[0], &mut e2[0], &mut e3[0], noiseseed, 4, 5, 6, 7
);
}
#[cfg(not(any(feature="kyber1024", feature="kyber512", feature="90s")))] // kyber764
{
let (skpv0, skpv1) = skpv.vec.split_at_mut(1);
let (skpv1, skpv2) = skpv1.split_at_mut(1);
poly_getnoise_eta1_4x(
&mut skpv0[0], &mut skpv1[0], &mut skpv2[0], &mut e.vec[0], noiseseed, 0, 1, 2, 3
);
let (e1, e2) = e.vec.split_at_mut(2);
let (pkpv0, pkpv1) = pkpv.vec.split_at_mut(1);
poly_getnoise_eta1_4x(
&mut e1[1], &mut e2[0], &mut pkpv0[0], &mut pkpv1[0], noiseseed, 4, 5, 6, 7
);
}
polyvec_ntt(&mut skpv);
polyvec_reduce(&mut skpv);
polyvec_ntt(&mut e);
for i in 0..KYBER_K {
polyvec_basemul_acc_montgomery(&mut pkpv.vec[i], &a[i], &skpv);
poly_tomont(&mut pkpv.vec[i]);
}
polyvec_add(&mut pkpv, &e);
polyvec_reduce(&mut pkpv);
pack_sk(sk, &skpv);
pack_pk(pk, &pkpv, publicseed);
}
pub fn indcpa_enc(c: &mut[u8], m: &[u8], pk: &[u8], coins: &[u8])
{
unsafe {
let mut at = [Polyvec::new(); KYBER_K];
let (mut sp, mut pkpv, mut ep, mut b) = (Polyvec::new(),Polyvec::new(), Polyvec::new(), Polyvec::new());
let (mut v, mut k, mut epp) = (Poly::new(), Poly::new(), Poly::new());
let mut seed = [0u8; KYBER_SYMBYTES];
unpack_pk(&mut pkpv, &mut seed, pk);
poly_frommsg(&mut k, m);
gen_at(&mut at, &seed);
#[cfg(feature="90s")]
{
const NOISE_NBLOCKS: usize = (KYBER_ETA1*KYBER_N/4)/XOF_BLOCKBYTES;
const CIPHERTEXTNOISE_NBLOCKS: usize = (KYBER_ETA2*KYBER_N/4)/XOF_BLOCKBYTES;
let mut buf = IndcpaBuf::new();
let mut state = Aes256CtrCtx::new();
let mut nonce = 0u64;
aes256ctr_init(&mut state, coins, [0u8; 12]);
nonce += 1;
for i in 0..KYBER_K {
aes256ctr_squeezeblocks(&mut buf.coeffs, NOISE_NBLOCKS, &mut state);
state.n = _mm_loadl_epi64([nonce, 0].as_ptr() as *const __m128i);
nonce += 1;
poly_cbd_eta1_90s(&mut sp.vec[i], &buf);
}
for i in 0..KYBER_K {
aes256ctr_squeezeblocks(&mut buf.coeffs, CIPHERTEXTNOISE_NBLOCKS, &mut state);
state.n = _mm_loadl_epi64([nonce, 0].as_ptr() as *const __m128i);
nonce += 1;
poly_cbd_eta2(&mut ep.vec[i], &buf.vec);
}
aes256ctr_squeezeblocks(&mut buf.coeffs, CIPHERTEXTNOISE_NBLOCKS, &mut state);
state.n = _mm_loadl_epi64([nonce, 0].as_ptr() as *const __m128i);
poly_cbd_eta2(&mut epp, &buf.vec);
}
#[cfg(all(feature="kyber512", not(feature="90s")))]
{
let (sp0, sp1) = sp.vec.split_at_mut(1);
let (ep0, ep1) = ep.vec.split_at_mut(1);
poly_getnoise_eta1122_4x(
&mut sp0[0], &mut sp1[0], &mut ep0[0], &mut ep1[0], coins, 0, 1, 2, 3
);
poly_getnoise_eta2(&mut epp, coins, 4);
}
#[cfg(not(any(feature="kyber1024", feature="kyber512", feature="90s")))] // kyber764)
{
let (sp0, sp1) = sp.vec.split_at_mut(1);
let (sp1, sp2) = sp1.split_at_mut(1);
poly_getnoise_eta1_4x(
&mut sp0[0], &mut sp1[0], &mut sp2[0], &mut ep.vec[0], coins, 0, 1, 2 ,3
);
let (ep1, ep2) = ep.vec.split_at_mut(2);
poly_getnoise_eta1_4x(
&mut ep1[1], &mut ep2[0], &mut epp, &mut b.vec[0], coins, 4, 5, 6, 7
);
}
#[cfg(all(feature="kyber1024", not(feature="90s")))]
{
let (sp0, sp1) = sp.vec.split_at_mut(1);
let (sp1, sp2) = sp1.split_at_mut(1);
let (sp2, sp3) = sp2.split_at_mut(1);
poly_getnoise_eta1_4x(
&mut sp0[0], &mut sp1[0], &mut sp2[0],&mut sp3[0], coins, 0, 1, 2, 3
);
let (ep0, ep1) = ep.vec.split_at_mut(1);
let (ep1, ep2) = ep1.split_at_mut(1);
let (ep2, ep3) = ep2.split_at_mut(1);
poly_getnoise_eta1_4x(
&mut ep0[0], &mut ep1[0], &mut ep2[0],&mut ep3[0], coins, 4, 5, 6, 7
);
poly_getnoise_eta2(&mut epp, coins, 8);
}
polyvec_ntt(&mut sp);
for i in 0..KYBER_K {
polyvec_basemul_acc_montgomery(&mut b.vec[i], &at[i], &sp);
}
polyvec_basemul_acc_montgomery(&mut v, &pkpv, &sp);
polyvec_invntt_tomont(&mut b);
poly_invntt_tomont(&mut v);
polyvec_add(&mut b, &ep);
poly_add(&mut v, &epp);
poly_add(&mut v, &k);
polyvec_reduce(&mut b);
poly_reduce(&mut v);
pack_ciphertext(c, &b, v);
}
}
pub fn indcpa_dec(m: &mut[u8], c: &[u8], sk: &[u8])
{
let (mut b, mut skpv) = (Polyvec::new(),Polyvec::new());
let (mut v, mut mp) = (Poly::new(),Poly::new());
unpack_ciphertext(&mut b, &mut v, c);
unpack_sk(&mut skpv, sk);
polyvec_ntt(&mut b);
polyvec_basemul_acc_montgomery(&mut mp, &skpv, &b);
poly_invntt_tomont(&mut mp);
poly_sub(&mut mp, &v);
poly_reduce(&mut mp);
poly_tomsg(m, mp);
}

246
third_party/kyber/src/avx2/invntt.S vendored Normal file
View file

@ -0,0 +1,246 @@
.macro shuffle8 r0,r1,r2,r3
vperm2i128 $0x20,%ymm\r1,%ymm\r0,%ymm\r2
vperm2i128 $0x31,%ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle4 r0,r1,r2,r3
vpunpcklqdq %ymm\r1,%ymm\r0,%ymm\r2
vpunpckhqdq %ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle2 r0,r1,r2,r3
#vpsllq $32,%ymm\r1,%ymm\r2
vmovsldup %ymm\r1,%ymm\r2
vpblendd $0xAA,%ymm\r2,%ymm\r0,%ymm\r2
vpsrlq $32,%ymm\r0,%ymm\r0
#vmovshdup %ymm\r0,%ymm\r0
vpblendd $0xAA,%ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle1 r0,r1,r2,r3
vpslld $16,%ymm\r1,%ymm\r2
vpblendw $0xAA,%ymm\r2,%ymm\r0,%ymm\r2
vpsrld $16,%ymm\r0,%ymm\r0
vpblendw $0xAA,%ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro red16 r,rs=0,x=12
vpmulhw %ymm1,%ymm\r,%ymm\x
.if \rs
vpmulhrsw %ymm\rs,%ymm\x,%ymm\x
.else
vpsraw $10,%ymm\x,%ymm\x
.endif
vpmullw %ymm0,%ymm\x,%ymm\x
vpsubw %ymm\x,%ymm\r,%ymm\r
.endm
.macro csubq r,x=12
vpsubw %ymm0,%ymm\r,%ymm\r
vpsraw $15,%ymm\r,%ymm\x
vpand %ymm0,%ymm\x,%ymm\x
vpaddw %ymm\x,%ymm\r,%ymm\r
.endm
.macro caddq r,x=12
vpsraw $15,%ymm\r,%ymm\x
vpand %ymm0,%ymm\x,%ymm\x
vpaddw %ymm\x,%ymm\r,%ymm\r
.endm
.macro fqmulprecomp al,ah,b,x=12
vpmullw %ymm\al,%ymm\b,%ymm\x
vpmulhw %ymm\ah,%ymm\b,%ymm\b
vpmulhw %ymm0,%ymm\x,%ymm\x
vpsubw %ymm\x,%ymm\b,%ymm\b
.endm
.macro butterfly rl0,rl1,rl2,rl3,rh0,rh1,rh2,rh3,zl0=2,zl1=2,zh0=3,zh1=3
vpsubw %ymm\rl0,%ymm\rh0,%ymm12
vpaddw %ymm\rh0,%ymm\rl0,%ymm\rl0
vpsubw %ymm\rl1,%ymm\rh1,%ymm13
vpmullw %ymm\zl0,%ymm12,%ymm\rh0
vpaddw %ymm\rh1,%ymm\rl1,%ymm\rl1
vpsubw %ymm\rl2,%ymm\rh2,%ymm14
vpmullw %ymm\zl0,%ymm13,%ymm\rh1
vpaddw %ymm\rh2,%ymm\rl2,%ymm\rl2
vpsubw %ymm\rl3,%ymm\rh3,%ymm15
vpmullw %ymm\zl1,%ymm14,%ymm\rh2
vpaddw %ymm\rh3,%ymm\rl3,%ymm\rl3
vpmullw %ymm\zl1,%ymm15,%ymm\rh3
vpmulhw %ymm\zh0,%ymm12,%ymm12
vpmulhw %ymm\zh0,%ymm13,%ymm13
vpmulhw %ymm\zh1,%ymm14,%ymm14
vpmulhw %ymm\zh1,%ymm15,%ymm15
vpmulhw %ymm0,%ymm\rh0,%ymm\rh0
vpmulhw %ymm0,%ymm\rh1,%ymm\rh1
vpmulhw %ymm0,%ymm\rh2,%ymm\rh2
vpmulhw %ymm0,%ymm\rh3,%ymm\rh3
#
#
vpsubw %ymm\rh0,%ymm12,%ymm\rh0
vpsubw %ymm\rh1,%ymm13,%ymm\rh1
vpsubw %ymm\rh2,%ymm14,%ymm\rh2
vpsubw %ymm\rh3,%ymm15,%ymm\rh3
.endm
.macro intt_levels0t5 off
/* level 0 */
vmovdqa 48*2(%rsi),%ymm2
vmovdqa 64*2(%rsi),%ymm3
vmovdqa (128*\off+ 0)*2(%rdi),%ymm4
vmovdqa (128*\off+ 32)*2(%rdi),%ymm6
vmovdqa (128*\off+ 16)*2(%rdi),%ymm5
vmovdqa (128*\off+ 48)*2(%rdi),%ymm7
fqmulprecomp 2,3,4
fqmulprecomp 2,3,6
fqmulprecomp 2,3,5
fqmulprecomp 2,3,7
vmovdqa (128*\off+ 64)*2(%rdi),%ymm8
vmovdqa (128*\off+ 96)*2(%rdi),%ymm10
vmovdqa (128*\off+ 80)*2(%rdi),%ymm9
vmovdqa (128*\off+112)*2(%rdi),%ymm11
fqmulprecomp 2,3,8
fqmulprecomp 2,3,10
fqmulprecomp 2,3,9
fqmulprecomp 2,3,11
vpermq $0x4E,(160+(1-\off)*224+208)*2(%rsi),%ymm15
vpermq $0x4E,(160+(1-\off)*224+176)*2(%rsi),%ymm1
vpermq $0x4E,(160+(1-\off)*224+224)*2(%rsi),%ymm2
vpermq $0x4E,(160+(1-\off)*224+192)*2(%rsi),%ymm3
vmovdqa 128*2(%rsi),%ymm12
vpshufb %ymm12,%ymm15,%ymm15
vpshufb %ymm12,%ymm1,%ymm1
vpshufb %ymm12,%ymm2,%ymm2
vpshufb %ymm12,%ymm3,%ymm3
butterfly 4,5,8,9,6,7,10,11,15,1,2,3
/* level 1 */
vpermq $0x4E,(160+(1-\off)*224+144)*2(%rsi),%ymm2
vpermq $0x4E,(160+(1-\off)*224+160)*2(%rsi),%ymm3
vmovdqa 128*2(%rsi),%ymm1
vpshufb %ymm1,%ymm2,%ymm2
vpshufb %ymm1,%ymm3,%ymm3
butterfly 4,5,6,7,8,9,10,11,2,2,3,3
shuffle1 4,5,3,5
shuffle1 6,7,4,7
shuffle1 8,9,6,9
shuffle1 10,11,8,11
/* level 2 */
vmovdqa 144*2(%rsi),%ymm12
vpermd (160+(1-\off)*224+112)*2(%rsi),%ymm12,%ymm2
vpermd (160+(1-\off)*224+128)*2(%rsi),%ymm12,%ymm10
butterfly 3,4,6,8,5,7,9,11,2,2,10,10
vmovdqa 32*2(%rsi),%ymm1
red16 3
shuffle2 3,4,10,4
shuffle2 6,8,3,8
shuffle2 5,7,6,7
shuffle2 9,11,5,11
/* level 3 */
vpermq $0x1B,(160+(1-\off)*224+80)*2(%rsi),%ymm2
vpermq $0x1B,(160+(1-\off)*224+96)*2(%rsi),%ymm9
butterfly 10,3,6,5,4,8,7,11,2,2,9,9
shuffle4 10,3,9,3
shuffle4 6,5,10,5
shuffle4 4,8,6,8
shuffle4 7,11,4,11
/* level 4 */
vpermq $0x4E,(160+(1-\off)*224+48)*2(%rsi),%ymm2
vpermq $0x4E,(160+(1-\off)*224+64)*2(%rsi),%ymm7
butterfly 9,10,6,4,3,5,8,11,2,2,7,7
red16 9
shuffle8 9,10,7,10
shuffle8 6,4,9,4
shuffle8 3,5,6,5
shuffle8 8,11,3,11
/* level5 */
vmovdqa (160+(1-\off)*224+16)*2(%rsi),%ymm2
vmovdqa (160+(1-\off)*224+32)*2(%rsi),%ymm8
butterfly 7,9,6,3,10,4,5,11,2,2,8,8
vmovdqa %ymm7,(128*\off+ 0)*2(%rdi)
vmovdqa %ymm9,(128*\off+ 16)*2(%rdi)
vmovdqa %ymm6,(128*\off+ 32)*2(%rdi)
vmovdqa %ymm3,(128*\off+ 48)*2(%rdi)
vmovdqa %ymm10,(128*\off+ 64)*2(%rdi)
vmovdqa %ymm4,(128*\off+ 80)*2(%rdi)
vmovdqa %ymm5,(128*\off+ 96)*2(%rdi)
vmovdqa %ymm11,(128*\off+112)*2(%rdi)
.endm
.macro intt_level6 off
/* level 6 */
vmovdqa (64*\off+ 0)*2(%rdi),%ymm4
vmovdqa (64*\off+128)*2(%rdi),%ymm8
vmovdqa (64*\off+ 16)*2(%rdi),%ymm5
vmovdqa (64*\off+144)*2(%rdi),%ymm9
vpbroadcastq (160+0)*2(%rsi),%ymm2
vmovdqa (64*\off+ 32)*2(%rdi),%ymm6
vmovdqa (64*\off+160)*2(%rdi),%ymm10
vmovdqa (64*\off+ 48)*2(%rdi),%ymm7
vmovdqa (64*\off+176)*2(%rdi),%ymm11
vpbroadcastq (160+4)*2(%rsi),%ymm3
butterfly 4,5,6,7,8,9,10,11
.if \off == 0
red16 4
.endif
vmovdqa %ymm4,(64*\off+ 0)*2(%rdi)
vmovdqa %ymm5,(64*\off+ 16)*2(%rdi)
vmovdqa %ymm6,(64*\off+ 32)*2(%rdi)
vmovdqa %ymm7,(64*\off+ 48)*2(%rdi)
vmovdqa %ymm8,(64*\off+128)*2(%rdi)
vmovdqa %ymm9,(64*\off+144)*2(%rdi)
vmovdqa %ymm10,(64*\off+160)*2(%rdi)
vmovdqa %ymm11,(64*\off+176)*2(%rdi)
.endm
.text
.global invntt_avx
invntt_avx:
vmovdqa 0*2(%rsi),%ymm0
intt_levels0t5 0
intt_levels0t5 1
intt_level6 0
intt_level6 1
ret

220
third_party/kyber/src/avx2/keccak4x.rs vendored Normal file
View file

@ -0,0 +1,220 @@
// Macro and function code structure is the work of Marek Kotewicz
// plus contributors to the tiny-keccak crate licensed under
// Creative Commons CC0 1.0 Universal. Thankyou.
// https://github.com/debris/tiny-keccak
// Copyright 2020-2021 Mitchell Berry
// Licensed under the Apache License, Version 2.0
// Drop-in Rust replacement for KeccakP-1600-times4 function for
// the eXtended Keccak Code Package https://github.com/XKCP/XKCP
// Test vectors taken from:
// https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-1600-IntermediateValues.txt
use core::arch::x86_64::*;
#[repr(C, align(32))]
union RC_Data {
vecs: [__m256i; 24],
u: [u64; 96]
}
#[repr(C, align(32))]
union Temp {
pub vec: __m256i,
pub u: [u64; 4]
}
const RHO: [u32; 24] = [
1, 3, 6, 10, 15, 21, 28, 36,
45, 55, 2, 14, 27, 41, 56, 8,
25, 43, 62, 18, 39, 61, 20, 44,
];
const PI: [usize; 24] = [
10, 7, 11, 17, 18, 3, 5, 16,
8, 21, 24, 4, 15, 23, 19, 13,
12, 2, 20, 14, 22, 9, 6, 1,
];
// Set __mm256i constants with a union
const RC_X4: RC_Data = RC_Data { u: [
0x0000000000000001, 0x0000000000000001, 0x0000000000000001, 0x0000000000000001,
0x0000000000008082, 0x0000000000008082, 0x0000000000008082, 0x0000000000008082,
0x800000000000808a, 0x800000000000808a, 0x800000000000808a, 0x800000000000808a,
0x8000000080008000, 0x8000000080008000, 0x8000000080008000, 0x8000000080008000,
0x000000000000808b, 0x000000000000808b, 0x000000000000808b, 0x000000000000808b,
0x0000000080000001, 0x0000000080000001, 0x0000000080000001, 0x0000000080000001,
0x8000000080008081, 0x8000000080008081, 0x8000000080008081, 0x8000000080008081,
0x8000000000008009, 0x8000000000008009, 0x8000000000008009, 0x8000000000008009,
0x000000000000008a, 0x000000000000008a, 0x000000000000008a, 0x000000000000008a,
0x0000000000000088, 0x0000000000000088, 0x0000000000000088, 0x0000000000000088,
0x0000000080008009, 0x0000000080008009, 0x0000000080008009, 0x0000000080008009,
0x000000008000000a, 0x000000008000000a, 0x000000008000000a, 0x000000008000000a,
0x000000008000808b, 0x000000008000808b, 0x000000008000808b, 0x000000008000808b,
0x800000000000008b, 0x800000000000008b, 0x800000000000008b, 0x800000000000008b,
0x8000000000008089, 0x8000000000008089, 0x8000000000008089, 0x8000000000008089,
0x8000000000008003, 0x8000000000008003, 0x8000000000008003, 0x8000000000008003,
0x8000000000008002, 0x8000000000008002, 0x8000000000008002, 0x8000000000008002,
0x8000000000000080, 0x8000000000000080, 0x8000000000000080, 0x8000000000000080,
0x000000000000800a, 0x000000000000800a, 0x000000000000800a, 0x000000000000800a,
0x800000008000000a, 0x800000008000000a, 0x800000008000000a, 0x800000008000000a,
0x8000000080008081, 0x8000000080008081, 0x8000000080008081, 0x8000000080008081,
0x8000000000008080, 0x8000000000008080, 0x8000000000008080, 0x8000000000008080,
0x0000000080000001, 0x0000000080000001, 0x0000000080000001, 0x0000000080000001,
0x8000000080008008, 0x8000000080008008, 0x8000000080008008, 0x8000000080008008
]};
macro_rules! unroll5 {
($var:ident, $body:block) => {
{ const $var: usize = 0; $body; }
{ const $var: usize = 1; $body; }
{ const $var: usize = 2; $body; }
{ const $var: usize = 3; $body; }
{ const $var: usize = 4; $body; }
};
}
macro_rules! unroll24 {
($var: ident, $body: block) => {
{ const $var: usize = 0; $body; }
{ const $var: usize = 1; $body; }
{ const $var: usize = 2; $body; }
{ const $var: usize = 3; $body; }
{ const $var: usize = 4; $body; }
{ const $var: usize = 5; $body; }
{ const $var: usize = 6; $body; }
{ const $var: usize = 7; $body; }
{ const $var: usize = 8; $body; }
{ const $var: usize = 9; $body; }
{ const $var: usize = 10; $body; }
{ const $var: usize = 11; $body; }
{ const $var: usize = 12; $body; }
{ const $var: usize = 13; $body; }
{ const $var: usize = 14; $body; }
{ const $var: usize = 15; $body; }
{ const $var: usize = 16; $body; }
{ const $var: usize = 17; $body; }
{ const $var: usize = 18; $body; }
{ const $var: usize = 19; $body; }
{ const $var: usize = 20; $body; }
{ const $var: usize = 21; $body; }
{ const $var: usize = 22; $body; }
{ const $var: usize = 23; $body; }
};
}
#[allow(unused_assignments, non_upper_case_globals)]
pub fn f1600_x4(a: &mut [__m256i]) {
unsafe {
for i in 0..24 {
let mut array = [_mm256_setzero_si256(); 5];
// Theta
unroll5!(x, {
unroll5!(y, {
array[x] = _mm256_xor_si256(array[x], a[5 * y + x]);
});
});
unroll5!(x, {
unroll5!(y, {
let t1 = array[(x + 4) % 5];
let mut t2 = Temp {vec: array[(x + 1) % 5]};
for i in 0..4 {
t2.u[i] = t2.u[i].rotate_left(1);
}
a[5 * y + x] = _mm256_xor_si256(a[5 * y + x], _mm256_xor_si256(t1, t2.vec));
});
});
// Rho and pi
let mut last = a[1];
unroll24!(x, {
array[0] = a[PI[x]];
let mut temp_last = Temp {vec: last};
for i in 0..4 {
temp_last.u[i] = temp_last.u[i].rotate_left(RHO[x]);
}
a[PI[x]] = temp_last.vec;
last = array[0];
});
// Chi
unroll5!(y_step, {
let y = 5 * y_step;
unroll5!(x, {
array[x] = a[y + x];
});
unroll5!(x, {
let t1 = array[(x + 1) % 5];
let t2 = array[(x + 2) % 5];
let tmp = _mm256_xor_si256(array[x], _mm256_andnot_si256(t1, t2));
a[y+x] = tmp;
});
});
a[0] = _mm256_xor_si256(a[0], RC_X4.vecs[i]);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const PLEN: usize = 25;
// Test vectors from XKCP
// https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-1600-IntermediateValues.txt
#[test]
fn known_vectors() {
let vec1: [u64; 25] = [
0xF1258F7940E1DDE7, 0x84D5CCF933C0478A, 0xD598261EA65AA9EE, 0xBD1547306F80494D,
0x8B284E056253D057, 0xFF97A42D7F8E6FD4, 0x90FEE5A0A44647C4, 0x8C5BDA0CD6192E76,
0xAD30A6F71B19059C, 0x30935AB7D08FFC64, 0xEB5AA93F2317D635, 0xA9A6E6260D712103,
0x81A57C16DBCF555F, 0x43B831CD0347C826, 0x01F22F1A11A5569F, 0x05E5635A21D9AE61,
0x64BEFEF28CC970F2, 0x613670957BC46611, 0xB87C5A554FD00ECB, 0x8C3EE88A1CCF32C8,
0x940C7922AE3A2614, 0x1841F924A2C509E4, 0x16F53526E70465C2, 0x75F644E97F30A13B,
0xEAF1FF7B5CECA249
];
let vec2: [u64; 25] = [
0x2D5C954DF96ECB3C, 0x6A332CD07057B56D, 0x093D8D1270D76B6C, 0x8A20D9B25569D094,
0x4F9C4F99E5E7F156, 0xF957B9A2DA65FB38, 0x85773DAE1275AF0D, 0xFAF4F247C3D810F7,
0x1F1B9EE6F79A8759, 0xE4FECC0FEE98B425, 0x68CE61B6B9CE68A1, 0xDEEA66C4BA8F974F,
0x33C43D836EAFB1F5, 0xE00654042719DBD9, 0x7CF8A9F009831265, 0xFD5449A6BF174743,
0x97DDAD33D8994B40, 0x48EAD5FC5D0BE774, 0xE3B8C8EE55B7B03C, 0x91A0226E649E42E9,
0x900E3129E7BADD7B, 0x202A9EC5FAA3CCE8, 0x5B3402464E1C3DB6, 0x609F4E62A44C1059,
0x20D06CD26A8FBF5C
];
// repeat values to check all lanes
let tvec1 = expand(vec1);
let tvec2 = expand(vec2);
unsafe {
let mut data = Data { u: [0u64;100] };
f1600_x4(&mut data.lanes);
assert_eq!(&data.u , &tvec1);
f1600_x4(&mut data.lanes);
assert_eq!(data.u, tvec2);
}
}
#[repr(C)]
pub union Data {
pub lanes: [__m256i; PLEN],
pub u: [u64; PLEN * 4]
}
// [0,1...] expands to [0,0,0,0,1,1,1,1...]
fn expand(vec: [u64; PLEN]) -> [u64; 100] {
let mut out = [0u64; 100];
for (i,u) in vec.iter().enumerate() {
out[i*4..][..4].copy_from_slice(&[*u; 4]);
}
out
}
}

13
third_party/kyber/src/avx2/mod.rs vendored Normal file
View file

@ -0,0 +1,13 @@
pub mod aes256ctr;
pub mod align;
pub mod cbd;
pub mod consts;
pub mod fips202;
pub mod fips202x4;
pub mod indcpa;
pub mod keccak4x;
pub mod poly;
pub mod polyvec;
pub mod rejsample;
pub mod verify;

212
third_party/kyber/src/avx2/ntt.S vendored Normal file
View file

@ -0,0 +1,212 @@
.macro shuffle8 r0,r1,r2,r3
vperm2i128 $0x20,%ymm\r1,%ymm\r0,%ymm\r2
vperm2i128 $0x31,%ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle4 r0,r1,r2,r3
vpunpcklqdq %ymm\r1,%ymm\r0,%ymm\r2
vpunpckhqdq %ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle2 r0,r1,r2,r3
#vpsllq $32,%ymm\r1,%ymm\r2
vmovsldup %ymm\r1,%ymm\r2
vpblendd $0xAA,%ymm\r2,%ymm\r0,%ymm\r2
vpsrlq $32,%ymm\r0,%ymm\r0
#vmovshdup %ymm\r0,%ymm\r0
vpblendd $0xAA,%ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle1 r0,r1,r2,r3
vpslld $16,%ymm\r1,%ymm\r2
vpblendw $0xAA,%ymm\r2,%ymm\r0,%ymm\r2
vpsrld $16,%ymm\r0,%ymm\r0
vpblendw $0xAA,%ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro mul rh0,rh1,rh2,rh3,zl0=15,zl1=15,zh0=2,zh1=2
vpmullw %ymm\zl0,%ymm\rh0,%ymm12
vpmullw %ymm\zl0,%ymm\rh1,%ymm13
vpmullw %ymm\zl1,%ymm\rh2,%ymm14
vpmullw %ymm\zl1,%ymm\rh3,%ymm15
vpmulhw %ymm\zh0,%ymm\rh0,%ymm\rh0
vpmulhw %ymm\zh0,%ymm\rh1,%ymm\rh1
vpmulhw %ymm\zh1,%ymm\rh2,%ymm\rh2
vpmulhw %ymm\zh1,%ymm\rh3,%ymm\rh3
.endm
.macro reduce
vpmulhw %ymm0,%ymm12,%ymm12
vpmulhw %ymm0,%ymm13,%ymm13
vpmulhw %ymm0,%ymm14,%ymm14
vpmulhw %ymm0,%ymm15,%ymm15
.endm
.macro update rln,rl0,rl1,rl2,rl3,rh0,rh1,rh2,rh3
vpaddw %ymm\rh0,%ymm\rl0,%ymm\rln
vpsubw %ymm\rh0,%ymm\rl0,%ymm\rh0
vpaddw %ymm\rh1,%ymm\rl1,%ymm\rl0
vpsubw %ymm\rh1,%ymm\rl1,%ymm\rh1
vpaddw %ymm\rh2,%ymm\rl2,%ymm\rl1
vpsubw %ymm\rh2,%ymm\rl2,%ymm\rh2
vpaddw %ymm\rh3,%ymm\rl3,%ymm\rl2
vpsubw %ymm\rh3,%ymm\rl3,%ymm\rh3
vpsubw %ymm12,%ymm\rln,%ymm\rln
vpaddw %ymm12,%ymm\rh0,%ymm\rh0
vpsubw %ymm13,%ymm\rl0,%ymm\rl0
vpaddw %ymm13,%ymm\rh1,%ymm\rh1
vpsubw %ymm14,%ymm\rl1,%ymm\rl1
vpaddw %ymm14,%ymm\rh2,%ymm\rh2
vpsubw %ymm15,%ymm\rl2,%ymm\rl2
vpaddw %ymm15,%ymm\rh3,%ymm\rh3
.endm
.macro level0 off
vpbroadcastq (160+0)*2(%rsi),%ymm15
vmovdqa (64*\off+128)*2(%rdi),%ymm8
vmovdqa (64*\off+144)*2(%rdi),%ymm9
vmovdqa (64*\off+160)*2(%rdi),%ymm10
vmovdqa (64*\off+176)*2(%rdi),%ymm11
vpbroadcastq (160+4)*2(%rsi),%ymm2
mul 8,9,10,11
vmovdqa (64*\off+ 0)*2(%rdi),%ymm4
vmovdqa (64*\off+ 16)*2(%rdi),%ymm5
vmovdqa (64*\off+ 32)*2(%rdi),%ymm6
vmovdqa (64*\off+ 48)*2(%rdi),%ymm7
reduce
update 3,4,5,6,7,8,9,10,11
vmovdqa %ymm3,(64*\off+ 0)*2(%rdi)
vmovdqa %ymm4,(64*\off+ 16)*2(%rdi)
vmovdqa %ymm5,(64*\off+ 32)*2(%rdi)
vmovdqa %ymm6,(64*\off+ 48)*2(%rdi)
vmovdqa %ymm8,(64*\off+128)*2(%rdi)
vmovdqa %ymm9,(64*\off+144)*2(%rdi)
vmovdqa %ymm10,(64*\off+160)*2(%rdi)
vmovdqa %ymm11,(64*\off+176)*2(%rdi)
.endm
.macro levels1t6 off
/* level 1 */
vmovdqa (160+224*\off+16)*2(%rsi),%ymm15
vmovdqa (128*\off+ 64)*2(%rdi),%ymm8
vmovdqa (128*\off+ 80)*2(%rdi),%ymm9
vmovdqa (128*\off+ 96)*2(%rdi),%ymm10
vmovdqa (128*\off+112)*2(%rdi),%ymm11
vmovdqa (160+224*\off+32)*2(%rsi),%ymm2
mul 8,9,10,11
vmovdqa (128*\off+ 0)*2(%rdi),%ymm4
vmovdqa (128*\off+ 16)*2(%rdi),%ymm5
vmovdqa (128*\off+ 32)*2(%rdi),%ymm6
vmovdqa (128*\off+ 48)*2(%rdi),%ymm7
reduce
update 3,4,5,6,7,8,9,10,11
/* level 2 */
shuffle8 5,10,7,10
shuffle8 6,11,5,11
vmovdqa (160+224*\off+48)*2(%rsi),%ymm15
vmovdqa (160+224*\off+64)*2(%rsi),%ymm2
mul 7,10,5,11
shuffle8 3,8,6,8
shuffle8 4,9,3,9
reduce
update 4,6,8,3,9,7,10,5,11
/* level 3 */
shuffle4 8,5,9,5
shuffle4 3,11,8,11
vmovdqa (160+224*\off+80)*2(%rsi),%ymm15
vmovdqa (160+224*\off+96)*2(%rsi),%ymm2
mul 9,5,8,11
shuffle4 4,7,3,7
shuffle4 6,10,4,10
reduce
update 6,3,7,4,10,9,5,8,11
/* level 4 */
shuffle2 7,8,10,8
shuffle2 4,11,7,11
vmovdqa (160+224*\off+112)*2(%rsi),%ymm15
vmovdqa (160+224*\off+128)*2(%rsi),%ymm2
mul 10,8,7,11
shuffle2 6,9,4,9
shuffle2 3,5,6,5
reduce
update 3,4,9,6,5,10,8,7,11
/* level 5 */
shuffle1 9,7,5,7
shuffle1 6,11,9,11
vmovdqa (160+224*\off+144)*2(%rsi),%ymm15
vmovdqa (160+224*\off+160)*2(%rsi),%ymm2
mul 5,7,9,11
shuffle1 3,10,6,10
shuffle1 4,8,3,8
reduce
update 4,6,10,3,8,5,7,9,11
/* level 6 */
vmovdqa (160+224*\off+176)*2(%rsi),%ymm14
vmovdqa (160+224*\off+208)*2(%rsi),%ymm15
vmovdqa (160+224*\off+192)*2(%rsi),%ymm8
vmovdqa (160+224*\off+224)*2(%rsi),%ymm2
mul 10,3,9,11,14,15,8,2
reduce
update 8,4,6,5,7,10,3,9,11
vmovdqa %ymm8,(128*\off+ 0)*2(%rdi)
vmovdqa %ymm4,(128*\off+ 16)*2(%rdi)
vmovdqa %ymm10,(128*\off+ 32)*2(%rdi)
vmovdqa %ymm3,(128*\off+ 48)*2(%rdi)
vmovdqa %ymm6,(128*\off+ 64)*2(%rdi)
vmovdqa %ymm5,(128*\off+ 80)*2(%rdi)
vmovdqa %ymm9,(128*\off+ 96)*2(%rdi)
vmovdqa %ymm11,(128*\off+112)*2(%rdi)
.endm
.text
.global ntt_avx
ntt_avx:
vmovdqa 0*2(%rsi),%ymm0
level0 0
level0 1
levels1t6 0
levels1t6 1
ret

417
third_party/kyber/src/avx2/poly.rs vendored Normal file
View file

@ -0,0 +1,417 @@
#![allow(unused_imports)]
use core::arch::x86_64::*;
use crate::{
align::*,
cbd::*,
consts::*,
fips202::*,
fips202x4::*,
params::*,
symmetric::*,
};
pub(crate) const NOISE_NBLOCKS: usize =
(KYBER_ETA1*KYBER_N/4+SHAKE256_RATE-1)/SHAKE256_RATE;
#[derive(Clone)]
#[repr(C)]
pub union Poly {
pub coeffs: [i16; KYBER_N],
pub vec: [__m256i; (KYBER_N+15)/16]
}
impl Copy for Poly {}
impl Poly {
pub fn new() -> Self {
Poly {
coeffs: [0i16; KYBER_N]
}
}
// Basic polynomial value checking for development
// #[cfg(debug_assertions)]
// fn checksum(&self) -> i16 {
// unsafe{
// let mut out = 0;
// for x in &self.coeffs {
// out ^= x;
// }
// out
// }
// }
}
extern {
fn ntt_avx(r: &mut [i16; KYBER_N], q_data: &[i16; 640]);
fn invntt_avx(r: &mut [i16; KYBER_N], q_data: &[i16; 640]);
fn nttunpack_avx(r: &mut [i16; KYBER_N], q_data: &[i16; 640]);
fn basemul_avx(
r: &mut[i16; KYBER_N],
a: &[i16; KYBER_N],
b: &[i16; KYBER_N],
q_data: &[i16; 640]
);
fn tomont_avx(r: &mut [i16; KYBER_N], q_data: &[i16; 640]);
fn reduce_avx(r: &mut [i16; KYBER_N], q_data: &[i16; 640]);
fn ntttobytes_avx(r: *mut u8 , a: &[i16; KYBER_N] , q_data: &[i16; 640]);
fn nttfrombytes_avx(r: *mut i16, a: *const u8, q_data: &[i16; 640]);
}
// #[target_feature(enable = "avx2")]
#[cfg(any(feature="kyber512", not(feature="kyber1024")))]
pub unsafe fn poly_compress(r: &mut[u8], a: Poly)
{
let (mut f0, mut f1, mut f2, mut f3);
let v: __m256i = _mm256_load_si256(QDATA.vec[_16XV/16..].as_ptr());
let shift1: __m256i = _mm256_set1_epi16(1 << 9);
let mask: __m256i = _mm256_set1_epi16(15);
let shift2: __m256i = _mm256_set1_epi16((16 << 8) + 1);
let permdidx: __m256i = _mm256_set_epi32(7,3,6,2,5,1,4,0);
for i in 0..KYBER_N/64 {
f0 = _mm256_load_si256(&a.vec[4*i+0]);
f1 = _mm256_load_si256(&a.vec[4*i+1]);
f2 = _mm256_load_si256(&a.vec[4*i+2]);
f3 = _mm256_load_si256(&a.vec[4*i+3]);
f0 = _mm256_mulhi_epi16(f0,v);
f1 = _mm256_mulhi_epi16(f1,v);
f2 = _mm256_mulhi_epi16(f2,v);
f3 = _mm256_mulhi_epi16(f3,v);
f0 = _mm256_mulhrs_epi16(f0,shift1);
f1 = _mm256_mulhrs_epi16(f1,shift1);
f2 = _mm256_mulhrs_epi16(f2,shift1);
f3 = _mm256_mulhrs_epi16(f3,shift1);
f0 = _mm256_and_si256(f0,mask);
f1 = _mm256_and_si256(f1,mask);
f2 = _mm256_and_si256(f2,mask);
f3 = _mm256_and_si256(f3,mask);
f0 = _mm256_packus_epi16(f0,f1);
f2 = _mm256_packus_epi16(f2,f3);
f0 = _mm256_maddubs_epi16(f0,shift2);
f2 = _mm256_maddubs_epi16(f2,shift2);
f0 = _mm256_packus_epi16(f0,f2);
f0 = _mm256_permutevar8x32_epi32(f0,permdidx);
_mm256_storeu_si256(r[32*i..].as_mut_ptr() as *mut __m256i,f0);
}
}
// #[target_feature(enable = "avx2")]
#[cfg(any(feature="kyber512", not(feature="kyber1024")))]
pub unsafe fn poly_decompress(r: &mut Poly, a: &[u8])
{
let (mut t, mut f);
let q: __m256i = _mm256_load_si256(QDATA.vec[_16XQ/16..].as_ptr());
let shufbidx: __m256i = _mm256_set_epi8(
7,7,7,7,6,6,6,6,5,5,5,5,4,4,4,4,
3,3,3,3,2,2,2,2,1,1,1,1,0,0,0,0
);
let mask: __m256i = _mm256_set1_epi32(0x00F0000F);
let shift: __m256i = _mm256_set1_epi32((128 << 16) + 2048);
for i in 0..KYBER_N/16 {
t = _mm_loadl_epi64(a[8*i..].as_ptr() as *const __m128i);
f = _mm256_broadcastsi128_si256(t);
f = _mm256_shuffle_epi8(f,shufbidx);
f = _mm256_and_si256(f,mask);
f = _mm256_mullo_epi16(f,shift);
f = _mm256_mulhrs_epi16(f,q);
_mm256_store_si256(&mut r.vec[i],f);
}
}
// #[target_feature(enable = "avx2")]
#[cfg(feature="kyber1024")]
pub unsafe fn poly_compress(r: &mut[u8], a: Poly)
{
let (mut f0, mut f1);
let (mut t0, mut t1);
let mut tmp;
let v: __m256i = _mm256_load_si256(&QDATA.vec[_16XV/16]);
let shift1: __m256i = _mm256_set1_epi16(1 << 10);
let mask: __m256i = _mm256_set1_epi16(31);
let shift2: __m256i = _mm256_set1_epi16((32 << 8) + 1);
let shift3: __m256i = _mm256_set1_epi32((1024 << 16) + 1);
let sllvdidx: __m256i = _mm256_set1_epi64x(12);
let shufbidx: __m256i = _mm256_set_epi8(
8,-1,-1,-1,-1,-1, 4, 3, 2, 1, 0,-1,12,11,10, 9,
-1,12,11,10, 9, 8,-1,-1,-1,-1,-1 ,4, 3, 2, 1, 0
);
for i in 0..(KYBER_N/32) {
f0 = _mm256_load_si256(&a.vec[2*i+0]);
f1 = _mm256_load_si256(&a.vec[2*i+1]);
f0 = _mm256_mulhi_epi16(f0,v);
f1 = _mm256_mulhi_epi16(f1,v);
f0 = _mm256_mulhrs_epi16(f0,shift1);
f1 = _mm256_mulhrs_epi16(f1,shift1);
f0 = _mm256_and_si256(f0,mask);
f1 = _mm256_and_si256(f1,mask);
f0 = _mm256_packus_epi16(f0,f1);
f0 = _mm256_maddubs_epi16(f0,shift2);
f0 = _mm256_madd_epi16(f0,shift3);
f0 = _mm256_sllv_epi32(f0,sllvdidx);
f0 = _mm256_srlv_epi64(f0,sllvdidx);
f0 = _mm256_shuffle_epi8(f0,shufbidx);
t0 = _mm256_castsi256_si128(f0);
t1 = _mm256_extracti128_si256(f0,1);
t0 = _mm_blendv_epi8(t0,t1,_mm256_castsi256_si128(shufbidx));
_mm_storeu_si128(r[20*i+ 0..].as_mut_ptr() as *mut __m128i,t0);
tmp = _mm_cvtsi128_si32(t1);
r[20*i+16..20*i+20].copy_from_slice(&tmp.to_le_bytes());
}
}
// #[target_feature(enable = "avx2")]
#[cfg(feature="kyber1024")]
pub unsafe fn poly_decompress(r: &mut Poly, a: &[u8])
{
let (mut t, mut f, mut ti);
let q = _mm256_load_si256(&QDATA.vec[_16XQ/16]);
let shufbidx = _mm256_set_epi8(
9,9,9,8,8,8,8,7,7,6,6,6,6,5,5,5,
4,4,4,3,3,3,3,2,2,1,1,1,1,0,0,0
);
let mask = _mm256_set_epi16(
248,1984,62,496,3968,124,992,31,
248,1984,62,496,3968,124,992,31
);
let shift = _mm256_set_epi16(
128,16,512,64,8,256,32,1024,
128,16,512,64,8,256,32,1024
);
for i in 0..KYBER_N/16 {
t = _mm_loadl_epi64(a[10*i+0..].as_ptr() as *const __m128i);
ti = i32::from_le_bytes([a[10*i+8], a[10*i+9], 0, 0]);
t = _mm_insert_epi16(t, ti, 4);
f = _mm256_broadcastsi128_si256(t);
f = _mm256_shuffle_epi8(f,shufbidx);
f = _mm256_and_si256(f,mask);
f = _mm256_mullo_epi16(f,shift);
f = _mm256_mulhrs_epi16(f,q);
_mm256_store_si256(r.vec[i..].as_mut_ptr() as *mut __m256i,f);
}
}
pub fn poly_frombytes(r: &mut Poly, a: &[u8])
{
unsafe {
nttfrombytes_avx(r.coeffs.as_mut_ptr(), a.as_ptr(), &QDATA.coeffs);
}
}
pub fn poly_tobytes(r: &mut[u8], a: Poly)
{
let mut buf = [0u8; KYBER_POLYBYTES];
unsafe { ntttobytes_avx(buf.as_mut_ptr(), &a.coeffs, &QDATA.coeffs); }
r[..KYBER_POLYBYTES].copy_from_slice(&buf[..]);
}
// #[target_feature(enable = "avx2")]
pub unsafe fn poly_frommsg(r: &mut Poly, msg: &[u8])
{
let shift = _mm256_broadcastsi128_si256(_mm_set_epi32(0,1,2,3));
let idx = _mm256_broadcastsi128_si256(
_mm_set_epi8(15,14,11,10,7,6,3,2,13,12,9,8,5,4,1,0)
);
let hqs: __m256i = _mm256_set1_epi16((KYBER_Q+1) as i16/2);
let f = _mm256_loadu_si256(msg.as_ptr() as *const __m256i);
let mut frommsg64 = |i: usize, mut g3: __m256i| {
g3 = _mm256_sllv_epi32(g3,shift);
g3 = _mm256_shuffle_epi8(g3,idx);
let mut g0 = _mm256_slli_epi16(g3,12);
let mut g1 = _mm256_slli_epi16(g3,8);
let mut g2 = _mm256_slli_epi16(g3,4);
g0 = _mm256_srai_epi16(g0,15);
g1 = _mm256_srai_epi16(g1,15);
g2 = _mm256_srai_epi16(g2,15);
g3 = _mm256_srai_epi16(g3,15);
g0 = _mm256_and_si256(g0,hqs); // 19 18 17 16 3 2 1 0
g1 = _mm256_and_si256(g1,hqs); // 23 22 21 20 7 6 5 4
g2 = _mm256_and_si256(g2,hqs); // 27 26 25 24 11 10 9 8
g3 = _mm256_and_si256(g3,hqs); // 31 30 29 28 15 14 13 12
let h0 = _mm256_unpacklo_epi64(g0,g1);
let h2 = _mm256_unpackhi_epi64(g0,g1);
let h1 = _mm256_unpacklo_epi64(g2,g3);
let h3 = _mm256_unpackhi_epi64(g2,g3);
g0 = _mm256_permute2x128_si256(h0,h1,0x20);
g2 = _mm256_permute2x128_si256(h0,h1,0x31);
g1 = _mm256_permute2x128_si256(h2,h3,0x20);
g3 = _mm256_permute2x128_si256(h2,h3,0x31);
_mm256_store_si256(&mut r.vec[0+2*i+0],g0);
_mm256_store_si256(&mut r.vec[0+2*i+1],g1);
_mm256_store_si256(&mut r.vec[8+2*i+0],g2);
_mm256_store_si256(&mut r.vec[8+2*i+1],g3);
};
frommsg64(0, _mm256_shuffle_epi32(f, 0));
frommsg64(1, _mm256_shuffle_epi32(f, 85));
frommsg64(2, _mm256_shuffle_epi32(f, 170));
frommsg64(3, _mm256_shuffle_epi32(f, 255));
}
// #[target_feature(enable = "avx2")]
pub fn poly_tomsg(msg: &mut[u8], a: Poly)
{
unsafe {
let (mut f0, mut f1, mut g0, mut g1);
let hq: __m256i = _mm256_set1_epi16((KYBER_Q - 1) as i16/2);
let hhq: __m256i = _mm256_set1_epi16((KYBER_Q - 1) as i16/4);
for i in 0..KYBER_N/32 {
f0 = _mm256_load_si256(&a.vec[2*i+0]);
f1 = _mm256_load_si256(&a.vec[2*i+1]);
f0 = _mm256_sub_epi16(hq, f0);
f1 = _mm256_sub_epi16(hq, f1);
g0 = _mm256_srai_epi16(f0, 15);
g1 = _mm256_srai_epi16(f1, 15);
f0 = _mm256_xor_si256(f0, g0);
f1 = _mm256_xor_si256(f1, g1);
f0 = _mm256_sub_epi16(f0, hhq);
f1 = _mm256_sub_epi16(f1, hhq);
f0 = _mm256_packs_epi16(f0, f1);
f0 = _mm256_permute4x64_epi64(f0, 0xD8);
let small = _mm256_movemask_epi8(f0);
msg[4*i..][..4].copy_from_slice(&small.to_ne_bytes());
}
}
}
#[cfg(all(any(feature="kyber1024", feature="kyber512"), not(feature="90s")))]
pub fn poly_getnoise_eta2(r: &mut Poly, seed: &[u8], nonce: u8)
{
let mut buf = Eta2Buf::new();
unsafe {
prf(&mut buf.coeffs, KYBER_ETA2*KYBER_N/4, seed, nonce);
poly_cbd_eta2(r, &buf.vec);
}
}
#[cfg(not(feature="90s"))]
pub fn poly_getnoise_eta1_4x(
r0: &mut Poly, r1: &mut Poly, r2: &mut Poly, r3: &mut Poly, seed: &[u8],
nonce0: u8, nonce1: u8, nonce2: u8, nonce3: u8
)
{
unsafe {
let mut buf = [Eta4xBuf::new(); 4];
let mut state = Keccakx4State::new();
let f = _mm256_loadu_si256(seed.as_ptr() as *const __m256i);
_mm256_store_si256(buf[0].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[1].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[2].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[3].vec.as_mut_ptr(), f);
buf[0].coeffs[32] = nonce0;
buf[1].coeffs[32] = nonce1;
buf[2].coeffs[32] = nonce2;
buf[3].coeffs[32] = nonce3;
shake256x4_absorb_once(
&mut state,
&buf[0].coeffs, &buf[1].coeffs,
&buf[2].coeffs, &buf[3].coeffs,
33
);
shake256x4_squeezeblocks(&mut buf, NOISE_NBLOCKS, &mut state);
poly_cbd_eta1(r0, &buf[0]);
poly_cbd_eta1(r1, &buf[1]);
poly_cbd_eta1(r2, &buf[2]);
poly_cbd_eta1(r3, &buf[3]);
}
}
#[cfg(all(feature="kyber512", not(feature="90s")))]
pub fn poly_getnoise_eta1122_4x(
r0: &mut Poly, r1: &mut Poly, r2: &mut Poly, r3: &mut Poly, seed: &[u8],
nonce0: u8, nonce1: u8, nonce2: u8, nonce3: u8,
)
{
let mut buf = [Eta4xBuf::new(); 4];
let mut state = Keccakx4State::new();
unsafe {
let f = _mm256_loadu_si256(seed.as_ptr() as *const __m256i);
_mm256_store_si256(buf[0].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[1].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[2].vec.as_mut_ptr(), f);
_mm256_store_si256(buf[3].vec.as_mut_ptr(), f);
buf[0].coeffs[32] = nonce0;
buf[1].coeffs[32] = nonce1;
buf[2].coeffs[32] = nonce2;
buf[3].coeffs[32] = nonce3;
shake256x4_absorb_once(
&mut state,
&buf[0].coeffs, &buf[1].coeffs,
&buf[2].coeffs, &buf[3].coeffs,
33
);
shake256x4_squeezeblocks(&mut buf, NOISE_NBLOCKS, &mut state);
poly_cbd_eta1(r0, &buf[0]);
poly_cbd_eta1(r1, &buf[1]);
poly_cbd_eta2(r2, &buf[2].vec);
poly_cbd_eta2(r3, &buf[3].vec);
}
}
pub fn poly_ntt(r: &mut Poly)
{
unsafe { ntt_avx(&mut r.coeffs, &QDATA.coeffs); }
}
pub fn poly_invntt_tomont(r: &mut Poly)
{
unsafe { invntt_avx(&mut r.coeffs, &QDATA.coeffs); }
}
pub fn poly_nttunpack(r: &mut Poly)
{
unsafe { nttunpack_avx(&mut r.coeffs, &QDATA.coeffs); }
}
pub fn poly_basemul(r: &mut Poly, a: &Poly, b: &Poly)
{
unsafe { basemul_avx(&mut r.coeffs, &a.coeffs, &b.coeffs, &QDATA.coeffs); }
}
pub fn poly_tomont(r: &mut Poly)
{
unsafe { tomont_avx(&mut r.coeffs, &QDATA.coeffs); }
}
pub fn poly_reduce(r: &mut Poly)
{
unsafe { reduce_avx(&mut r.coeffs, &QDATA.coeffs); }
}
pub fn poly_add(r: &mut Poly, b: &Poly)
{
let (mut f0, mut f1);
for i in 0..(KYBER_N/16) {
unsafe {
f0 = _mm256_load_si256(&r.vec[i]);
f1 = _mm256_load_si256(&b.vec[i]);
f0 = _mm256_add_epi16(f0, f1);
_mm256_store_si256(&mut r.vec[i] , f0);
}
}
}
pub fn poly_sub(r: &mut Poly, a: &Poly)
{
let (mut f0, mut f1);
for i in 0..(KYBER_N/16) {
unsafe {
f0 = _mm256_load_si256(&a.vec[i]);
f1 = _mm256_load_si256(&r.vec[i]);
f0 = _mm256_sub_epi16(f0, f1);
_mm256_store_si256(&mut r.vec[i], f0);
}
}
}

290
third_party/kyber/src/avx2/polyvec.rs vendored Normal file
View file

@ -0,0 +1,290 @@
use core::arch::x86_64::*;
use crate::{
poly::*,
params::*,
consts::*
};
#[derive(Clone)]
pub struct Polyvec {
pub vec: [Poly; KYBER_K]
}
impl Copy for Polyvec {}
impl Polyvec {
pub fn new() -> Self {
Polyvec {
vec: [Poly::new(); KYBER_K]
}
}
// Basic polynomial value check for development
// #[cfg(debug_assertions)]
// pub fn checksum(&self) -> i16 {
// unsafe {
// let mut out = 0i16;
// for i in 0..KYBER_K {
// for j in 0..KYBER_N {
// out ^= &self.vec[i].coeffs[j];
// }
// }
// out
// }
// }
}
// #[target_feature(enable = "avx")]
pub unsafe fn poly_compress10(r: &mut[u8], a: &Poly)
{
let (mut f0, mut f1, mut f2);
let (mut t0, mut t1);
let v = _mm256_load_si256(QDATA.vec[_16XV/16..].as_ptr());
let v8 = _mm256_slli_epi16(v,3);
let off = _mm256_set1_epi16(15);
let shift1 = _mm256_set1_epi16(1 << 12);
let mask = _mm256_set1_epi16(1023);
let shift2 = _mm256_set1_epi64x(
((1024u64 << 48) + (1u64 << 32) + (1024 << 16) + 1) as i64
);
let sllvdidx = _mm256_set1_epi64x(12);
let shufbidx = _mm256_set_epi8(
8, 4, 3, 2, 1, 0,-1,-1,-1,-1,-1,-1,12,11,10, 9,
-1,-1,-1,-1,-1,-1,12,11,10, 9, 8, 4, 3, 2, 1, 0
);
for i in 0..(KYBER_N/16) {
f0 = _mm256_load_si256(&a.vec[i]);
f1 = _mm256_mullo_epi16(f0,v8);
f2 = _mm256_add_epi16(f0,off);
f0 = _mm256_slli_epi16(f0,3);
f0 = _mm256_mulhi_epi16(f0,v);
f2 = _mm256_sub_epi16(f1,f2);
f1 = _mm256_andnot_si256(f1,f2);
f1 = _mm256_srli_epi16(f1,15);
f0 = _mm256_sub_epi16(f0,f1);
f0 = _mm256_mulhrs_epi16(f0,shift1);
f0 = _mm256_and_si256(f0,mask);
f0 = _mm256_madd_epi16(f0,shift2);
f0 = _mm256_sllv_epi32(f0,sllvdidx);
f0 = _mm256_srli_epi64(f0,12);
f0 = _mm256_shuffle_epi8(f0,shufbidx);
t0 = _mm256_castsi256_si128(f0);
t1 = _mm256_extracti128_si256(f0,1);
t0 = _mm_blend_epi16(t0,t1,0xE0);
_mm_storeu_si128(r[20*i..].as_mut_ptr() as *mut __m128i,t0);
_mm_storeu_si128(r[20*i+16..].as_mut_ptr() as *mut __m128i, t1);
}
}
// #[target_feature(enable = "avx")]
pub unsafe fn poly_decompress10(r: &mut Poly, a: &[u8])
{
let mut f;
let q = _mm256_set1_epi32(((KYBER_Q as i32) << 16) + 4*KYBER_Q as i32);
let shufbidx = _mm256_set_epi8(11,10,10, 9, 9, 8, 8, 7,
6, 5, 5, 4, 4, 3, 3, 2,
9, 8, 8, 7, 7, 6, 6, 5,
4, 3, 3, 2, 2, 1, 1, 0);
let sllvdidx = _mm256_set1_epi64x(4);
let mask = _mm256_set1_epi32((32736 << 16) + 8184);
for i in 0..KYBER_N/16 {
f = _mm256_loadu_si256(a[20*i..].as_ptr() as *const __m256i);
f = _mm256_permute4x64_epi64(f,0x94);
f = _mm256_shuffle_epi8(f,shufbidx);
f = _mm256_sllv_epi32(f,sllvdidx);
f = _mm256_srli_epi16(f,1);
f = _mm256_and_si256(f,mask);
f = _mm256_mulhrs_epi16(f,q);
_mm256_store_si256(&mut r.vec[i],f);
}
}
// #[target_feature(enable = "avx")]
pub unsafe fn poly_compress11(r: &mut[u8], a: &Poly)
{
let (mut f0, mut f1, mut f2);
let (mut t0, mut t1);
let v = _mm256_load_si256(QDATA.vec[_16XV/16..].as_ptr());
let v8 = _mm256_slli_epi16(v,3);
let off = _mm256_set1_epi16(36);
let shift1 = _mm256_set1_epi16(1 << 13);
let mask = _mm256_set1_epi16(2047);
let shift2 = _mm256_set1_epi64x(
((2048u64 << 48) + (1u64 << 32) + (2048 << 16) + 1) as i64
);
let sllvdidx = _mm256_set1_epi64x(10);
let srlvqidx = _mm256_set_epi64x(30,10,30,10);
let shufbidx = _mm256_set_epi8(
4, 3, 2, 1, 0, 0,-1,-1,-1,-1,10, 9, 8, 7, 6, 5,
-1,-1,-1,-1,-1,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
);
for i in 0..KYBER_N/16 {
f0 = _mm256_load_si256(&a.vec[i]);
f1 = _mm256_mullo_epi16(f0,v8);
f2 = _mm256_add_epi16(f0,off);
f0 = _mm256_slli_epi16(f0,3);
f0 = _mm256_mulhi_epi16(f0,v);
f2 = _mm256_sub_epi16(f1,f2);
f1 = _mm256_andnot_si256(f1,f2);
f1 = _mm256_srli_epi16(f1,15);
f0 = _mm256_sub_epi16(f0,f1);
f0 = _mm256_mulhrs_epi16(f0,shift1);
f0 = _mm256_and_si256(f0,mask);
f0 = _mm256_madd_epi16(f0,shift2);
f0 = _mm256_sllv_epi32(f0,sllvdidx);
f1 = _mm256_bsrli_epi128(f0,8);
f0 = _mm256_srlv_epi64(f0,srlvqidx);
f1 = _mm256_slli_epi64(f1,34);
f0 = _mm256_add_epi64(f0,f1);
f0 = _mm256_shuffle_epi8(f0,shufbidx);
t0 = _mm256_castsi256_si128(f0);
t1 = _mm256_extracti128_si256(f0,1);
t0 = _mm_blendv_epi8(t0,t1,_mm256_castsi256_si128(shufbidx));
_mm_storeu_si128(r[22*i+ 0..].as_mut_ptr() as *mut __m128i,t0);
_mm_storel_epi64(r[22*i+16..].as_mut_ptr() as *mut __m128i,t1);
}
}
// #[target_feature(enable = "avx")]
pub unsafe fn poly_decompress11(r: &mut Poly, a: &[u8])
{
let mut f;
let q = _mm256_load_si256(QDATA.vec[_16XQ/16..].as_ptr());
let shufbidx = _mm256_set_epi8(
13,12,12,11,10, 9, 9, 8,
8, 7, 6, 5, 5, 4, 4, 3,
10, 9, 9, 8, 7, 6, 6, 5,
5, 4, 3, 2, 2, 1, 1, 0
);
let srlvdidx = _mm256_set_epi32(0,0,1,0,0,0,1,0);
let srlvqidx = _mm256_set_epi64x(2,0,2,0);
let shift = _mm256_set_epi16(4,32,1,8,32,1,4,32,4,32,1,8,32,1,4,32);
let mask = _mm256_set1_epi16(32752);
for i in 0..(KYBER_N/16) {
f = _mm256_loadu_si256(a[22*i..].as_ptr() as *const __m256i);
f = _mm256_permute4x64_epi64(f,0x94);
f = _mm256_shuffle_epi8(f,shufbidx);
f = _mm256_srlv_epi32(f,srlvdidx);
f = _mm256_srlv_epi64(f,srlvqidx);
f = _mm256_mullo_epi16(f,shift);
f = _mm256_srli_epi16(f,1);
f = _mm256_and_si256(f,mask);
f = _mm256_mulhrs_epi16(f,q);
_mm256_store_si256(&mut r.vec[i],f);
}
}
pub unsafe fn polyvec_compress(r: &mut[u8], a: &Polyvec)
{
if cfg!(feature="kyber1024") {
for i in 0..KYBER_K {
poly_compress11(&mut r[352*i..], &a.vec[i]);
}
} else {
for i in 0..KYBER_K {
poly_compress10(&mut r[320*i..], &a.vec[i]);
}
}
}
pub unsafe fn polyvec_decompress(r: &mut Polyvec, a: &[u8])
{
if cfg!(feature="kyber1024") {
for i in 0..KYBER_K {
poly_decompress11(&mut r.vec[i], &a[352*i..]);
}
} else {
for i in 0..KYBER_K {
poly_decompress10(&mut r.vec[i], &a[320*i..]);
}
}
}
pub fn polyvec_tobytes(r: &mut[u8], a: &Polyvec)
{
for i in 0..KYBER_K {
poly_tobytes(&mut r[i*KYBER_POLYBYTES..], a.vec[i]);
}
}
pub unsafe fn polyvec_frombytes(r: &mut Polyvec, a: &[u8])
{
for i in 0..KYBER_K {
poly_frombytes(&mut r.vec[i], &a[i*KYBER_POLYBYTES..]);
}
}
// Name: polyvec_ntt
//
// Description: Apply forward NTT to all elements of a vector of polynomials
//
// Arguments: - Polyvec r: in/output vector of polynomials
pub fn polyvec_ntt(r: &mut Polyvec)
{
for i in 0..KYBER_K {
poly_ntt(&mut r.vec[i]);
}
}
// Name: polyvec_invntt
//
// Description: Apply inverse NTT to all elements of a vector of polynomials
//
// Arguments: - Polyvec r: in/output vector of polynomials
pub fn polyvec_invntt_tomont(r: &mut Polyvec)
{
for i in 0..KYBER_K {
poly_invntt_tomont(&mut r.vec[i]);
}
}
// Name: polyvec_basemul_acc_montgomery
//
// Description: Pointwise multiply elements of a and b and accumulate into r
//
// Arguments: - poly *r: output polynomial
// - const Polyvec a: first input vector of polynomials
// - const Polyvec b: second input vector of polynomials
pub fn polyvec_basemul_acc_montgomery(r: &mut Poly, a: &Polyvec, b: &Polyvec)
{
let mut t = Poly::new();
poly_basemul(r, &a.vec[0], &b.vec[0]);
for i in 1..KYBER_K {
poly_basemul(&mut t, &a.vec[i], &b.vec[i]);
poly_add(r, &t);
}
}
// Name: polyvec_reduce
//
// Description: Applies Barrett reduction to each coefficient
// of each element of a vector of polynomials
// for details of the Barrett reduction see comments in reduce.c
//
// Arguments: - poly *r: input/output polynomial
pub fn polyvec_reduce(r: &mut Polyvec)
{
for i in 0..KYBER_K {
poly_reduce(&mut r.vec[i]);
}
}
// Name: polyvec_add
//
// Description: Add vectors of polynomials
//
// Arguments: - Polyvec r: output vector of polynomials
// - const Polyvec a: first input vector of polynomials
// - const Polyvec b: second input vector of polynomials
pub fn polyvec_add(r: &mut Polyvec, b: &Polyvec)
{
for i in 0..KYBER_K {
poly_add(&mut r.vec[i], &b.vec[i]);
}
}

380
third_party/kyber/src/avx2/rejsample.rs vendored Normal file
View file

@ -0,0 +1,380 @@
use core::arch::x86_64::*;
use crate::{
params::*,
consts::*,
symmetric::*
};
pub(crate) const REJ_UNIFORM_AVX_NBLOCKS: usize =
(12*KYBER_N/8*(1 << 12)/KYBER_Q + XOF_BLOCKBYTES)/XOF_BLOCKBYTES;
const REJ_UNIFORM_AVX_BUFLEN: usize = REJ_UNIFORM_AVX_NBLOCKS*XOF_BLOCKBYTES;
pub unsafe fn _mm256_cmpge_epu16(a: __m256i, b: __m256i) -> __m256i {
_mm256_cmpeq_epi16(_mm256_max_epu16(a, b), a)
}
pub unsafe fn _mm_cmpge_epu16(a: __m128i, b: __m128i) -> __m128i {
_mm_cmpeq_epi16(_mm_max_epu16(a, b), a)
}
pub unsafe fn rej_uniform_avx(r: &mut[i16], buf: &[u8]) -> usize {
let mut ctr = 0;
let mut pos = 0;
let mut good: usize;
let (mut val0, mut val1);
let (mut f0, mut f1, mut g0, mut g1, mut g2, mut g3);
let (mut f, mut t, mut pilo, mut pihi);
let qdata_ptr = QDATA.coeffs[_16XQ..].as_ptr();
let bound = _mm256_load_si256(qdata_ptr as *const __m256i);
let ones = _mm256_set1_epi8(1);
let mask = _mm256_set1_epi16(0xFFF);
let idx8 = _mm256_set_epi8(
15,14,14,13,12,11,11,10,
9, 8, 8, 7, 6, 5, 5, 4,
11,10,10, 9, 8, 7, 7, 6,
5, 4, 4, 3, 2, 1, 1, 0
);
while ctr <= KYBER_N - 32 && pos <= REJ_UNIFORM_AVX_BUFLEN - 48 {
f0 = _mm256_loadu_si256(buf[pos..].as_ptr() as *const __m256i);
f1 = _mm256_loadu_si256(buf[pos+24..].as_ptr() as *const __m256i);
f0 = _mm256_permute4x64_epi64(f0, 0x94);
f1 = _mm256_permute4x64_epi64(f1, 0x94);
f0 = _mm256_shuffle_epi8(f0, idx8);
f1 = _mm256_shuffle_epi8(f1, idx8);
g0 = _mm256_srli_epi16(f0, 4);
g1 = _mm256_srli_epi16(f1, 4);
f0 = _mm256_blend_epi16(f0, g0, 0xAA);
f1 = _mm256_blend_epi16(f1, g1, 0xAA);
f0 = _mm256_and_si256(f0, mask);
f1 = _mm256_and_si256(f1, mask);
pos += 48;
g0 = _mm256_cmpgt_epi16(bound, f0);
g1 = _mm256_cmpgt_epi16(bound, f1);
g0 = _mm256_packs_epi16(g0, g1);
good = _mm256_movemask_epi8(g0) as usize;
let mut l0 = _mm_loadl_epi64(IDX[(good >> 0) & 0xFF].as_ptr() as * const __m128i);
g0 = _mm256_castsi128_si256(l0);
let mut l1 = _mm_loadl_epi64(IDX[(good >> 8) & 0xFF].as_ptr() as *const __m128i);
g1 = _mm256_castsi128_si256(l1);
l0 = _mm_loadl_epi64(IDX[(good >> 16) & 0xFF].as_ptr() as *const __m128i);
g0 = _mm256_inserti128_si256(g0, l0, 1);
l1 = _mm_loadl_epi64(IDX[(good >> 24) & 0xFF].as_ptr() as *const __m128i);
g1 = _mm256_inserti128_si256(g1, l1, 1);
g2 = _mm256_add_epi8(g0, ones);
g3 = _mm256_add_epi8(g1, ones);
g0 = _mm256_unpacklo_epi8(g0, g2);
g1 = _mm256_unpacklo_epi8(g1, g3);
f0 = _mm256_shuffle_epi8(f0, g0);
f1 = _mm256_shuffle_epi8(f1, g1);
_mm_storeu_si128(r[ctr..].as_mut_ptr() as *mut __m128i, _mm256_castsi256_si128(f0));
ctr += _popcnt32(((good >> 0) & 0xFF) as i32) as usize;
_mm_storeu_si128(r[ctr..].as_mut_ptr() as *mut __m128i, _mm256_extracti128_si256(f0, 1));
ctr += _popcnt32(((good >> 16) & 0xFF) as i32) as usize;
_mm_storeu_si128(r[ctr..].as_mut_ptr() as *mut __m128i, _mm256_castsi256_si128(f1));
ctr += _popcnt32(((good >> 8) & 0xFF) as i32) as usize;
_mm_storeu_si128(r[ctr..].as_mut_ptr() as *mut __m128i, _mm256_extracti128_si256(f1, 1));
ctr += _popcnt32(((good >> 24) & 0xFF) as i32) as usize;
}
while ctr <= KYBER_N - 8 && pos <= REJ_UNIFORM_AVX_BUFLEN - 12 {
f = _mm_loadu_si128(buf[pos..].as_ptr() as *const __m128i);
f = _mm_shuffle_epi8(f, _mm256_castsi256_si128(idx8));
t = _mm_srli_epi16(f, 4);
f = _mm_blend_epi16(f, t, 0xAA);
f = _mm_and_si128(f, _mm256_castsi256_si128(mask));
pos += 12;
t = _mm_cmpgt_epi16(_mm256_castsi256_si128(bound), f);
good = _mm_movemask_epi8(t) as usize;
let good = _pext_u32(good as u32, 0x5555) as usize;
pilo = _mm_loadl_epi64(IDX[good][..].as_ptr() as *const __m128i);
pihi = _mm_add_epi8(pilo, _mm256_castsi256_si128(ones));
pilo = _mm_unpacklo_epi8(pilo, pihi);
f = _mm_shuffle_epi8(f, pilo);
_mm_storeu_si128(r[ctr..].as_mut_ptr() as *mut __m128i, f);
ctr += _popcnt32(good as i32) as usize;
}
while ctr < KYBER_N && pos <= REJ_UNIFORM_AVX_BUFLEN - 3 {
val0 = (buf[pos+0] >> 0) as u16 | ((buf[pos+1] as u16) << 8) & 0xFFF;
val1 = (buf[pos+1] >> 4) as u16 | ((buf[pos+2] as u16) << 4);
pos += 3;
if (val0 as usize) < KYBER_Q {
r[ctr] = val0 as i16;
ctr += 1;
}
if (val1 as usize) < KYBER_Q && ctr < KYBER_N {
r[ctr] = val1 as i16;
ctr += 1;
}
}
ctr
}
const IDX: [[i8; 8]; 256] = [
[-1, -1, -1, -1, -1, -1, -1, -1],
[ 0, -1, -1, -1, -1, -1, -1, -1],
[ 2, -1, -1, -1, -1, -1, -1, -1],
[ 0, 2, -1, -1, -1, -1, -1, -1],
[ 4, -1, -1, -1, -1, -1, -1, -1],
[ 0, 4, -1, -1, -1, -1, -1, -1],
[ 2, 4, -1, -1, -1, -1, -1, -1],
[ 0, 2, 4, -1, -1, -1, -1, -1],
[ 6, -1, -1, -1, -1, -1, -1, -1],
[ 0, 6, -1, -1, -1, -1, -1, -1],
[ 2, 6, -1, -1, -1, -1, -1, -1],
[ 0, 2, 6, -1, -1, -1, -1, -1],
[ 4, 6, -1, -1, -1, -1, -1, -1],
[ 0, 4, 6, -1, -1, -1, -1, -1],
[ 2, 4, 6, -1, -1, -1, -1, -1],
[ 0, 2, 4, 6, -1, -1, -1, -1],
[ 8, -1, -1, -1, -1, -1, -1, -1],
[ 0, 8, -1, -1, -1, -1, -1, -1],
[ 2, 8, -1, -1, -1, -1, -1, -1],
[ 0, 2, 8, -1, -1, -1, -1, -1],
[ 4, 8, -1, -1, -1, -1, -1, -1],
[ 0, 4, 8, -1, -1, -1, -1, -1],
[ 2, 4, 8, -1, -1, -1, -1, -1],
[ 0, 2, 4, 8, -1, -1, -1, -1],
[ 6, 8, -1, -1, -1, -1, -1, -1],
[ 0, 6, 8, -1, -1, -1, -1, -1],
[ 2, 6, 8, -1, -1, -1, -1, -1],
[ 0, 2, 6, 8, -1, -1, -1, -1],
[ 4, 6, 8, -1, -1, -1, -1, -1],
[ 0, 4, 6, 8, -1, -1, -1, -1],
[ 2, 4, 6, 8, -1, -1, -1, -1],
[ 0, 2, 4, 6, 8, -1, -1, -1],
[10, -1, -1, -1, -1, -1, -1, -1],
[ 0, 10, -1, -1, -1, -1, -1, -1],
[ 2, 10, -1, -1, -1, -1, -1, -1],
[ 0, 2, 10, -1, -1, -1, -1, -1],
[ 4, 10, -1, -1, -1, -1, -1, -1],
[ 0, 4, 10, -1, -1, -1, -1, -1],
[ 2, 4, 10, -1, -1, -1, -1, -1],
[ 0, 2, 4, 10, -1, -1, -1, -1],
[ 6, 10, -1, -1, -1, -1, -1, -1],
[ 0, 6, 10, -1, -1, -1, -1, -1],
[ 2, 6, 10, -1, -1, -1, -1, -1],
[ 0, 2, 6, 10, -1, -1, -1, -1],
[ 4, 6, 10, -1, -1, -1, -1, -1],
[ 0, 4, 6, 10, -1, -1, -1, -1],
[ 2, 4, 6, 10, -1, -1, -1, -1],
[ 0, 2, 4, 6, 10, -1, -1, -1],
[ 8, 10, -1, -1, -1, -1, -1, -1],
[ 0, 8, 10, -1, -1, -1, -1, -1],
[ 2, 8, 10, -1, -1, -1, -1, -1],
[ 0, 2, 8, 10, -1, -1, -1, -1],
[ 4, 8, 10, -1, -1, -1, -1, -1],
[ 0, 4, 8, 10, -1, -1, -1, -1],
[ 2, 4, 8, 10, -1, -1, -1, -1],
[ 0, 2, 4, 8, 10, -1, -1, -1],
[ 6, 8, 10, -1, -1, -1, -1, -1],
[ 0, 6, 8, 10, -1, -1, -1, -1],
[ 2, 6, 8, 10, -1, -1, -1, -1],
[ 0, 2, 6, 8, 10, -1, -1, -1],
[ 4, 6, 8, 10, -1, -1, -1, -1],
[ 0, 4, 6, 8, 10, -1, -1, -1],
[ 2, 4, 6, 8, 10, -1, -1, -1],
[ 0, 2, 4, 6, 8, 10, -1, -1],
[12, -1, -1, -1, -1, -1, -1, -1],
[ 0, 12, -1, -1, -1, -1, -1, -1],
[ 2, 12, -1, -1, -1, -1, -1, -1],
[ 0, 2, 12, -1, -1, -1, -1, -1],
[ 4, 12, -1, -1, -1, -1, -1, -1],
[ 0, 4, 12, -1, -1, -1, -1, -1],
[ 2, 4, 12, -1, -1, -1, -1, -1],
[ 0, 2, 4, 12, -1, -1, -1, -1],
[ 6, 12, -1, -1, -1, -1, -1, -1],
[ 0, 6, 12, -1, -1, -1, -1, -1],
[ 2, 6, 12, -1, -1, -1, -1, -1],
[ 0, 2, 6, 12, -1, -1, -1, -1],
[ 4, 6, 12, -1, -1, -1, -1, -1],
[ 0, 4, 6, 12, -1, -1, -1, -1],
[ 2, 4, 6, 12, -1, -1, -1, -1],
[ 0, 2, 4, 6, 12, -1, -1, -1],
[ 8, 12, -1, -1, -1, -1, -1, -1],
[ 0, 8, 12, -1, -1, -1, -1, -1],
[ 2, 8, 12, -1, -1, -1, -1, -1],
[ 0, 2, 8, 12, -1, -1, -1, -1],
[ 4, 8, 12, -1, -1, -1, -1, -1],
[ 0, 4, 8, 12, -1, -1, -1, -1],
[ 2, 4, 8, 12, -1, -1, -1, -1],
[ 0, 2, 4, 8, 12, -1, -1, -1],
[ 6, 8, 12, -1, -1, -1, -1, -1],
[ 0, 6, 8, 12, -1, -1, -1, -1],
[ 2, 6, 8, 12, -1, -1, -1, -1],
[ 0, 2, 6, 8, 12, -1, -1, -1],
[ 4, 6, 8, 12, -1, -1, -1, -1],
[ 0, 4, 6, 8, 12, -1, -1, -1],
[ 2, 4, 6, 8, 12, -1, -1, -1],
[ 0, 2, 4, 6, 8, 12, -1, -1],
[10, 12, -1, -1, -1, -1, -1, -1],
[ 0, 10, 12, -1, -1, -1, -1, -1],
[ 2, 10, 12, -1, -1, -1, -1, -1],
[ 0, 2, 10, 12, -1, -1, -1, -1],
[ 4, 10, 12, -1, -1, -1, -1, -1],
[ 0, 4, 10, 12, -1, -1, -1, -1],
[ 2, 4, 10, 12, -1, -1, -1, -1],
[ 0, 2, 4, 10, 12, -1, -1, -1],
[ 6, 10, 12, -1, -1, -1, -1, -1],
[ 0, 6, 10, 12, -1, -1, -1, -1],
[ 2, 6, 10, 12, -1, -1, -1, -1],
[ 0, 2, 6, 10, 12, -1, -1, -1],
[ 4, 6, 10, 12, -1, -1, -1, -1],
[ 0, 4, 6, 10, 12, -1, -1, -1],
[ 2, 4, 6, 10, 12, -1, -1, -1],
[ 0, 2, 4, 6, 10, 12, -1, -1],
[ 8, 10, 12, -1, -1, -1, -1, -1],
[ 0, 8, 10, 12, -1, -1, -1, -1],
[ 2, 8, 10, 12, -1, -1, -1, -1],
[ 0, 2, 8, 10, 12, -1, -1, -1],
[ 4, 8, 10, 12, -1, -1, -1, -1],
[ 0, 4, 8, 10, 12, -1, -1, -1],
[ 2, 4, 8, 10, 12, -1, -1, -1],
[ 0, 2, 4, 8, 10, 12, -1, -1],
[ 6, 8, 10, 12, -1, -1, -1, -1],
[ 0, 6, 8, 10, 12, -1, -1, -1],
[ 2, 6, 8, 10, 12, -1, -1, -1],
[ 0, 2, 6, 8, 10, 12, -1, -1],
[ 4, 6, 8, 10, 12, -1, -1, -1],
[ 0, 4, 6, 8, 10, 12, -1, -1],
[ 2, 4, 6, 8, 10, 12, -1, -1],
[ 0, 2, 4, 6, 8, 10, 12, -1],
[14, -1, -1, -1, -1, -1, -1, -1],
[ 0, 14, -1, -1, -1, -1, -1, -1],
[ 2, 14, -1, -1, -1, -1, -1, -1],
[ 0, 2, 14, -1, -1, -1, -1, -1],
[ 4, 14, -1, -1, -1, -1, -1, -1],
[ 0, 4, 14, -1, -1, -1, -1, -1],
[ 2, 4, 14, -1, -1, -1, -1, -1],
[ 0, 2, 4, 14, -1, -1, -1, -1],
[ 6, 14, -1, -1, -1, -1, -1, -1],
[ 0, 6, 14, -1, -1, -1, -1, -1],
[ 2, 6, 14, -1, -1, -1, -1, -1],
[ 0, 2, 6, 14, -1, -1, -1, -1],
[ 4, 6, 14, -1, -1, -1, -1, -1],
[ 0, 4, 6, 14, -1, -1, -1, -1],
[ 2, 4, 6, 14, -1, -1, -1, -1],
[ 0, 2, 4, 6, 14, -1, -1, -1],
[ 8, 14, -1, -1, -1, -1, -1, -1],
[ 0, 8, 14, -1, -1, -1, -1, -1],
[ 2, 8, 14, -1, -1, -1, -1, -1],
[ 0, 2, 8, 14, -1, -1, -1, -1],
[ 4, 8, 14, -1, -1, -1, -1, -1],
[ 0, 4, 8, 14, -1, -1, -1, -1],
[ 2, 4, 8, 14, -1, -1, -1, -1],
[ 0, 2, 4, 8, 14, -1, -1, -1],
[ 6, 8, 14, -1, -1, -1, -1, -1],
[ 0, 6, 8, 14, -1, -1, -1, -1],
[ 2, 6, 8, 14, -1, -1, -1, -1],
[ 0, 2, 6, 8, 14, -1, -1, -1],
[ 4, 6, 8, 14, -1, -1, -1, -1],
[ 0, 4, 6, 8, 14, -1, -1, -1],
[ 2, 4, 6, 8, 14, -1, -1, -1],
[ 0, 2, 4, 6, 8, 14, -1, -1],
[10, 14, -1, -1, -1, -1, -1, -1],
[ 0, 10, 14, -1, -1, -1, -1, -1],
[ 2, 10, 14, -1, -1, -1, -1, -1],
[ 0, 2, 10, 14, -1, -1, -1, -1],
[ 4, 10, 14, -1, -1, -1, -1, -1],
[ 0, 4, 10, 14, -1, -1, -1, -1],
[ 2, 4, 10, 14, -1, -1, -1, -1],
[ 0, 2, 4, 10, 14, -1, -1, -1],
[ 6, 10, 14, -1, -1, -1, -1, -1],
[ 0, 6, 10, 14, -1, -1, -1, -1],
[ 2, 6, 10, 14, -1, -1, -1, -1],
[ 0, 2, 6, 10, 14, -1, -1, -1],
[ 4, 6, 10, 14, -1, -1, -1, -1],
[ 0, 4, 6, 10, 14, -1, -1, -1],
[ 2, 4, 6, 10, 14, -1, -1, -1],
[ 0, 2, 4, 6, 10, 14, -1, -1],
[ 8, 10, 14, -1, -1, -1, -1, -1],
[ 0, 8, 10, 14, -1, -1, -1, -1],
[ 2, 8, 10, 14, -1, -1, -1, -1],
[ 0, 2, 8, 10, 14, -1, -1, -1],
[ 4, 8, 10, 14, -1, -1, -1, -1],
[ 0, 4, 8, 10, 14, -1, -1, -1],
[ 2, 4, 8, 10, 14, -1, -1, -1],
[ 0, 2, 4, 8, 10, 14, -1, -1],
[ 6, 8, 10, 14, -1, -1, -1, -1],
[ 0, 6, 8, 10, 14, -1, -1, -1],
[ 2, 6, 8, 10, 14, -1, -1, -1],
[ 0, 2, 6, 8, 10, 14, -1, -1],
[ 4, 6, 8, 10, 14, -1, -1, -1],
[ 0, 4, 6, 8, 10, 14, -1, -1],
[ 2, 4, 6, 8, 10, 14, -1, -1],
[ 0, 2, 4, 6, 8, 10, 14, -1],
[12, 14, -1, -1, -1, -1, -1, -1],
[ 0, 12, 14, -1, -1, -1, -1, -1],
[ 2, 12, 14, -1, -1, -1, -1, -1],
[ 0, 2, 12, 14, -1, -1, -1, -1],
[ 4, 12, 14, -1, -1, -1, -1, -1],
[ 0, 4, 12, 14, -1, -1, -1, -1],
[ 2, 4, 12, 14, -1, -1, -1, -1],
[ 0, 2, 4, 12, 14, -1, -1, -1],
[ 6, 12, 14, -1, -1, -1, -1, -1],
[ 0, 6, 12, 14, -1, -1, -1, -1],
[ 2, 6, 12, 14, -1, -1, -1, -1],
[ 0, 2, 6, 12, 14, -1, -1, -1],
[ 4, 6, 12, 14, -1, -1, -1, -1],
[ 0, 4, 6, 12, 14, -1, -1, -1],
[ 2, 4, 6, 12, 14, -1, -1, -1],
[ 0, 2, 4, 6, 12, 14, -1, -1],
[ 8, 12, 14, -1, -1, -1, -1, -1],
[ 0, 8, 12, 14, -1, -1, -1, -1],
[ 2, 8, 12, 14, -1, -1, -1, -1],
[ 0, 2, 8, 12, 14, -1, -1, -1],
[ 4, 8, 12, 14, -1, -1, -1, -1],
[ 0, 4, 8, 12, 14, -1, -1, -1],
[ 2, 4, 8, 12, 14, -1, -1, -1],
[ 0, 2, 4, 8, 12, 14, -1, -1],
[ 6, 8, 12, 14, -1, -1, -1, -1],
[ 0, 6, 8, 12, 14, -1, -1, -1],
[ 2, 6, 8, 12, 14, -1, -1, -1],
[ 0, 2, 6, 8, 12, 14, -1, -1],
[ 4, 6, 8, 12, 14, -1, -1, -1],
[ 0, 4, 6, 8, 12, 14, -1, -1],
[ 2, 4, 6, 8, 12, 14, -1, -1],
[ 0, 2, 4, 6, 8, 12, 14, -1],
[10, 12, 14, -1, -1, -1, -1, -1],
[ 0, 10, 12, 14, -1, -1, -1, -1],
[ 2, 10, 12, 14, -1, -1, -1, -1],
[ 0, 2, 10, 12, 14, -1, -1, -1],
[ 4, 10, 12, 14, -1, -1, -1, -1],
[ 0, 4, 10, 12, 14, -1, -1, -1],
[ 2, 4, 10, 12, 14, -1, -1, -1],
[ 0, 2, 4, 10, 12, 14, -1, -1],
[ 6, 10, 12, 14, -1, -1, -1, -1],
[ 0, 6, 10, 12, 14, -1, -1, -1],
[ 2, 6, 10, 12, 14, -1, -1, -1],
[ 0, 2, 6, 10, 12, 14, -1, -1],
[ 4, 6, 10, 12, 14, -1, -1, -1],
[ 0, 4, 6, 10, 12, 14, -1, -1],
[ 2, 4, 6, 10, 12, 14, -1, -1],
[ 0, 2, 4, 6, 10, 12, 14, -1],
[ 8, 10, 12, 14, -1, -1, -1, -1],
[ 0, 8, 10, 12, 14, -1, -1, -1],
[ 2, 8, 10, 12, 14, -1, -1, -1],
[ 0, 2, 8, 10, 12, 14, -1, -1],
[ 4, 8, 10, 12, 14, -1, -1, -1],
[ 0, 4, 8, 10, 12, 14, -1, -1],
[ 2, 4, 8, 10, 12, 14, -1, -1],
[ 0, 2, 4, 8, 10, 12, 14, -1],
[ 6, 8, 10, 12, 14, -1, -1, -1],
[ 0, 6, 8, 10, 12, 14, -1, -1],
[ 2, 6, 8, 10, 12, 14, -1, -1],
[ 0, 2, 6, 8, 10, 12, 14, -1],
[ 4, 6, 8, 10, 12, 14, -1, -1],
[ 0, 4, 6, 8, 10, 12, 14, -1],
[ 2, 4, 6, 8, 10, 12, 14, -1],
[ 0, 2, 4, 6, 8, 10, 12, 14]
];

255
third_party/kyber/src/avx2/shuffle.S vendored Normal file
View file

@ -0,0 +1,255 @@
#include "consts.h"
.include "fq.inc"
.include "shuffle.inc"
/*
nttpack_avx:
#load
vmovdqa (%rdi),%ymm4
vmovdqa 32(%rdi),%ymm5
vmovdqa 64(%rdi),%ymm6
vmovdqa 96(%rdi),%ymm7
vmovdqa 128(%rdi),%ymm8
vmovdqa 160(%rdi),%ymm9
vmovdqa 192(%rdi),%ymm10
vmovdqa 224(%rdi),%ymm11
shuffle1 4,5,3,5
shuffle1 6,7,4,7
shuffle1 8,9,6,9
shuffle1 10,11,8,11
shuffle2 3,4,10,4
shuffle2 6,8,3,8
shuffle2 5,7,6,7
shuffle2 9,11,5,11
shuffle4 10,3,9,3
shuffle4 6,5,10,5
shuffle4 4,8,6,8
shuffle4 7,11,4,11
shuffle8 9,10,7,10
shuffle8 6,4,9,4
shuffle8 3,5,6,5
shuffle8 8,11,3,11
#store
vmovdqa %ymm7,(%rdi)
vmovdqa %ymm9,32(%rdi)
vmovdqa %ymm6,64(%rdi)
vmovdqa %ymm3,96(%rdi)
vmovdqa %ymm10,128(%rdi)
vmovdqa %ymm4,160(%rdi)
vmovdqa %ymm5,192(%rdi)
vmovdqa %ymm11,224(%rdi)
ret
*/
.text
nttunpack128_avx:
#load
vmovdqa (%rdi),%ymm4
vmovdqa 32(%rdi),%ymm5
vmovdqa 64(%rdi),%ymm6
vmovdqa 96(%rdi),%ymm7
vmovdqa 128(%rdi),%ymm8
vmovdqa 160(%rdi),%ymm9
vmovdqa 192(%rdi),%ymm10
vmovdqa 224(%rdi),%ymm11
shuffle8 4,8,3,8
shuffle8 5,9,4,9
shuffle8 6,10,5,10
shuffle8 7,11,6,11
shuffle4 3,5,7,5
shuffle4 8,10,3,10
shuffle4 4,6,8,6
shuffle4 9,11,4,11
shuffle2 7,8,9,8
shuffle2 5,6,7,6
shuffle2 3,4,5,4
shuffle2 10,11,3,11
shuffle1 9,5,10,5
shuffle1 8,4,9,4
shuffle1 7,3,8,3
shuffle1 6,11,7,11
#store
vmovdqa %ymm10,(%rdi)
vmovdqa %ymm5,32(%rdi)
vmovdqa %ymm9,64(%rdi)
vmovdqa %ymm4,96(%rdi)
vmovdqa %ymm8,128(%rdi)
vmovdqa %ymm3,160(%rdi)
vmovdqa %ymm7,192(%rdi)
vmovdqa %ymm11,224(%rdi)
ret
.global nttunpack_avx
nttunpack_avx:
call nttunpack128_avx
add $256,%rdi
call nttunpack128_avx
ret
ntttobytes128_avx:
#load
vmovdqa (%rsi),%ymm5
vmovdqa 32(%rsi),%ymm6
vmovdqa 64(%rsi),%ymm7
vmovdqa 96(%rsi),%ymm8
vmovdqa 128(%rsi),%ymm9
vmovdqa 160(%rsi),%ymm10
vmovdqa 192(%rsi),%ymm11
vmovdqa 224(%rsi),%ymm12
#csubq
csubq 5,13
csubq 6,13
csubq 7,13
csubq 8,13
csubq 9,13
csubq 10,13
csubq 11,13
csubq 12,13
#bitpack
vpsllw $12,%ymm6,%ymm4
vpor %ymm4,%ymm5,%ymm4
vpsrlw $4,%ymm6,%ymm5
vpsllw $8,%ymm7,%ymm6
vpor %ymm5,%ymm6,%ymm5
vpsrlw $8,%ymm7,%ymm6
vpsllw $4,%ymm8,%ymm7
vpor %ymm6,%ymm7,%ymm6
vpsllw $12,%ymm10,%ymm7
vpor %ymm7,%ymm9,%ymm7
vpsrlw $4,%ymm10,%ymm8
vpsllw $8,%ymm11,%ymm9
vpor %ymm8,%ymm9,%ymm8
vpsrlw $8,%ymm11,%ymm9
vpsllw $4,%ymm12,%ymm10
vpor %ymm9,%ymm10,%ymm9
shuffle1 4,5,3,5
shuffle1 6,7,4,7
shuffle1 8,9,6,9
shuffle2 3,4,8,4
shuffle2 6,5,3,5
shuffle2 7,9,6,9
shuffle4 8,3,7,3
shuffle4 6,4,8,4
shuffle4 5,9,6,9
shuffle8 7,8,5,8
shuffle8 6,3,7,3
shuffle8 4,9,6,9
#store
vmovdqu %ymm5,(%rdi)
vmovdqu %ymm7,32(%rdi)
vmovdqu %ymm6,64(%rdi)
vmovdqu %ymm8,96(%rdi)
vmovdqu %ymm3,128(%rdi)
vmovdqu %ymm9,160(%rdi)
ret
.global ntttobytes_avx
ntttobytes_avx:
#consts
vmovdqa _16XQ*2(%rdx),%ymm0
call ntttobytes128_avx
add $256,%rsi
add $192,%rdi
call ntttobytes128_avx
ret
nttfrombytes128_avx:
#load
vmovdqu (%rsi),%ymm4
vmovdqu 32(%rsi),%ymm5
vmovdqu 64(%rsi),%ymm6
vmovdqu 96(%rsi),%ymm7
vmovdqu 128(%rsi),%ymm8
vmovdqu 160(%rsi),%ymm9
shuffle8 4,7,3,7
shuffle8 5,8,4,8
shuffle8 6,9,5,9
shuffle4 3,8,6,8
shuffle4 7,5,3,5
shuffle4 4,9,7,9
shuffle2 6,5,4,5
shuffle2 8,7,6,7
shuffle2 3,9,8,9
shuffle1 4,7,10,7
shuffle1 5,8,4,8
shuffle1 6,9,5,9
#bitunpack
vpsrlw $12,%ymm10,%ymm11
vpsllw $4,%ymm7,%ymm12
vpor %ymm11,%ymm12,%ymm11
vpand %ymm0,%ymm10,%ymm10
vpand %ymm0,%ymm11,%ymm11
vpsrlw $8,%ymm7,%ymm12
vpsllw $8,%ymm4,%ymm13
vpor %ymm12,%ymm13,%ymm12
vpand %ymm0,%ymm12,%ymm12
vpsrlw $4,%ymm4,%ymm13
vpand %ymm0,%ymm13,%ymm13
vpsrlw $12,%ymm8,%ymm14
vpsllw $4,%ymm5,%ymm15
vpor %ymm14,%ymm15,%ymm14
vpand %ymm0,%ymm8,%ymm8
vpand %ymm0,%ymm14,%ymm14
vpsrlw $8,%ymm5,%ymm15
vpsllw $8,%ymm9,%ymm1
vpor %ymm15,%ymm1,%ymm15
vpand %ymm0,%ymm15,%ymm15
vpsrlw $4,%ymm9,%ymm1
vpand %ymm0,%ymm1,%ymm1
#store
vmovdqa %ymm10,(%rdi)
vmovdqa %ymm11,32(%rdi)
vmovdqa %ymm12,64(%rdi)
vmovdqa %ymm13,96(%rdi)
vmovdqa %ymm8,128(%rdi)
vmovdqa %ymm14,160(%rdi)
vmovdqa %ymm15,192(%rdi)
vmovdqa %ymm1,224(%rdi)
ret
.global nttfrombytes_avx
nttfrombytes_avx:
#consts
vmovdqa _16XMASK*2(%rdx),%ymm0
call nttfrombytes128_avx
add $256,%rdi
add $192,%rsi
call nttfrombytes128_avx
ret

25
third_party/kyber/src/avx2/shuffle.inc vendored Normal file
View file

@ -0,0 +1,25 @@
.macro shuffle8 r0,r1,r2,r3
vperm2i128 $0x20,%ymm\r1,%ymm\r0,%ymm\r2
vperm2i128 $0x31,%ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle4 r0,r1,r2,r3
vpunpcklqdq %ymm\r1,%ymm\r0,%ymm\r2
vpunpckhqdq %ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle2 r0,r1,r2,r3
#vpsllq $32,%ymm\r1,%ymm\r2
vmovsldup %ymm\r1,%ymm\r2
vpblendd $0xAA,%ymm\r2,%ymm\r0,%ymm\r2
vpsrlq $32,%ymm\r0,%ymm\r0
#vmovshdup %ymm\r0,%ymm\r0
vpblendd $0xAA,%ymm\r1,%ymm\r0,%ymm\r3
.endm
.macro shuffle1 r0,r1,r2,r3
vpslld $16,%ymm\r1,%ymm\r2
vpblendw $0xAA,%ymm\r2,%ymm\r0,%ymm\r2
vpsrld $16,%ymm\r0,%ymm\r0
vpblendw $0xAA,%ymm\r1,%ymm\r0,%ymm\r3
.endm

43
third_party/kyber/src/avx2/verify.rs vendored Normal file
View file

@ -0,0 +1,43 @@
use core::arch::x86_64::*;
pub fn verify(a: &[u8], b: &[u8], mut len: usize) -> u8
{
let (mut f, mut g);
let mut r: u64;
unsafe {
let mut h = _mm256_setzero_si256();
for i in 0..(len/32) {
f = _mm256_loadu_si256(a[32*i..].as_ptr() as *const __m256i);
g = _mm256_loadu_si256(b[32*i..].as_ptr() as *const __m256i);
f = _mm256_xor_si256(f,g);
h = _mm256_or_si256(h,f);
}
r = 1 - _mm256_testz_si256(h,h) as u64;
}
let idx = 32*(len/32);
len -= idx;
for i in 0..len {
r |= (a[idx+i] ^ b[idx+i]) as u64;
}
(r.wrapping_neg() >> 63) as u8
}
pub fn cmov(r: &mut[u8], x: &[u8], mut len: usize, mut b: u8)
{
let (mut xvec, mut rvec);
unsafe {
let bvec = _mm256_set1_epi64x(b as i64);
for i in 0..(len/32) {
rvec = _mm256_loadu_si256(r[32*i..].as_ptr() as *const __m256i);
xvec = _mm256_loadu_si256(x[32*i..].as_ptr() as *const __m256i);
rvec = _mm256_blendv_epi8(rvec,xvec,bvec);
_mm256_storeu_si256(r[32*i..].as_mut_ptr() as *mut __m256i,rvec);
}
}
let idx = 32*(len/32);
len -= idx;
b = b.wrapping_neg();
for i in 0..len {
r[idx+i] ^= b & (x[idx+i] ^ r[idx+i]);
}
}

19
third_party/kyber/src/error.rs vendored Normal file
View file

@ -0,0 +1,19 @@
#[derive(Debug, PartialEq)]
/// Error types for the failure modes
pub enum KyberError {
/// One or more inputs to a function are incorrectly sized. A likely cause of this is two parties using different security
/// levels while trying to negotiate a key exchange.
InvalidInput,
/// The ciphertext was unable to be authenticated.
/// The shared secret was not decapsulated.
Decapsulation,
}
impl core::fmt::Display for KyberError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match *self {
KyberError::InvalidInput => write!(f, "Function input is of incorrect length"),
KyberError::Decapsulation => write!(f, "Decapsulation Failure, unable to obtain shared secret from ciphertext"),
}
}
}

128
third_party/kyber/src/kem.rs vendored Normal file
View file

@ -0,0 +1,128 @@
#[cfg(not(feature="KATs"))]
use crate::rng::randombytes;
use rand_core::{RngCore, CryptoRng};
use crate::{
params::*,
indcpa::*,
symmetric::*,
error::KyberError,
verify::*
};
// Name: crypto_kem_keypair
//
// Description: Generates public and private key
// for CCA-secure Kyber key encapsulation mechanism
//
// Arguments: - [u8] pk: output public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes)
// - [u8] sk: output private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes)
pub fn crypto_kem_keypair<R>(
pk: &mut[u8], sk: &mut[u8], _rng: &mut R, _seed: Option<(&[u8], &[u8])>
)
where R: RngCore + CryptoRng
{
const PK_START: usize = KYBER_SECRETKEYBYTES - (2 * KYBER_SYMBYTES);
const SK_START: usize = KYBER_SECRETKEYBYTES-KYBER_SYMBYTES;
const END: usize = KYBER_INDCPA_PUBLICKEYBYTES + KYBER_INDCPA_SECRETKEYBYTES;
indcpa_keypair(pk, sk, _seed, _rng);
sk[KYBER_INDCPA_SECRETKEYBYTES..END]
.copy_from_slice(&pk[..KYBER_INDCPA_PUBLICKEYBYTES]);
hash_h(&mut sk[PK_START..], pk, KYBER_PUBLICKEYBYTES);
#[cfg(feature="KATs")]
sk[SK_START..].copy_from_slice(&_seed.expect("KATs feature only for testing").1);
#[cfg(not(feature="KATs"))]
randombytes(&mut sk[SK_START..],KYBER_SYMBYTES, _rng);
}
// Name: crypto_kem_enc
//
// Description: Generates cipher text and shared
// secret for given public key
//
// Arguments: - [u8] ct: output cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes)
// - [u8] ss: output shared secret (an already allocated array of CRYPTO_BYTES bytes)
// - const [u8] pk: input public key (an already allocated array of CRYPTO_PUBLICKEYBYTES bytes)
pub fn crypto_kem_enc<R>(
ct: &mut[u8], ss: &mut[u8], pk: &[u8], _rng: &mut R,_seed: Option<&[u8]>
)
where R: RngCore + CryptoRng
{
let mut kr = [0u8; 2*KYBER_SYMBYTES];
let mut buf = [0u8; 2*KYBER_SYMBYTES];
let mut randbuf = [0u8; 2*KYBER_SYMBYTES];
#[cfg(not(feature="KATs"))]
randombytes(&mut randbuf, KYBER_SYMBYTES, _rng);
// Deterministic randbuf for KAT's
#[cfg(feature="KATs")]
randbuf[..KYBER_SYMBYTES]
.copy_from_slice(&_seed.expect("KATs feature only works with `cargo test`"));
// Don't release system RNG output
hash_h(&mut buf, &randbuf, KYBER_SYMBYTES);
// Multitarget countermeasure for coins + contributory KEM
hash_h(&mut buf[KYBER_SYMBYTES..], pk, KYBER_PUBLICKEYBYTES);
hash_g(&mut kr, &buf, 2*KYBER_SYMBYTES);
// coins are in kr[KYBER_SYMBYTES..]
indcpa_enc(ct, &buf, pk, &kr[KYBER_SYMBYTES..]);
// overwrite coins in kr with H(c)
hash_h(&mut kr[KYBER_SYMBYTES..], ct, KYBER_CIPHERTEXTBYTES);
// hash concatenation of pre-k and H(c) to k
kdf(ss, &kr, 2*KYBER_SYMBYTES);
}
// Name: crypto_kem_dec
//
// Description: Generates shared secret for given
// cipher text and private key
//
// Arguments: - [u8] ss: output shared secret (an already allocated array of CRYPTO_BYTES bytes)
// - const [u8] ct: input cipher text (an already allocated array of CRYPTO_CIPHERTEXTBYTES bytes)
// - const [u8] sk: input private key (an already allocated array of CRYPTO_SECRETKEYBYTES bytes)
//
// On failure, ss will contain a pseudo-random value.
pub fn crypto_kem_dec(
ss: &mut[u8], ct: &[u8], sk: &[u8]
)
-> Result<(), KyberError>
{
let mut buf = [0u8; 2*KYBER_SYMBYTES];
let mut kr = [0u8; 2*KYBER_SYMBYTES];
let mut cmp = [0u8; KYBER_CIPHERTEXTBYTES];
let mut pk = [0u8; KYBER_INDCPA_PUBLICKEYBYTES + 2*KYBER_SYMBYTES];
pk.copy_from_slice(&sk[KYBER_INDCPA_SECRETKEYBYTES..]);
indcpa_dec(&mut buf, ct, sk);
// Multitarget countermeasure for coins + contributory KEM
const START: usize = KYBER_SECRETKEYBYTES-2*KYBER_SYMBYTES;
const END: usize = KYBER_SECRETKEYBYTES-KYBER_SYMBYTES;
buf[KYBER_SYMBYTES..].copy_from_slice(&sk[START..END]);
hash_g(&mut kr, &buf, 2*KYBER_SYMBYTES);
// coins are in kr[KYBER_SYMBYTES..]
indcpa_enc(&mut cmp, &buf, &pk, &kr[KYBER_SYMBYTES..]);
let fail = verify(ct, &cmp, KYBER_CIPHERTEXTBYTES);
// overwrite coins in kr with H(c)
hash_h(&mut kr[KYBER_SYMBYTES..], ct, KYBER_CIPHERTEXTBYTES);
// Overwrite pre-k with z on re-encryption failure
cmov(&mut kr, &sk[END..], KYBER_SYMBYTES, fail);
// hash concatenation of pre-k and H(c) to k
kdf(ss, &kr, 2*KYBER_SYMBYTES);
match fail {
0 => Ok(()),
_ => Err(KyberError::Decapsulation)
}
}

388
third_party/kyber/src/kex.rs vendored Normal file
View file

@ -0,0 +1,388 @@
use rand_core::{RngCore, CryptoRng};
use crate::{
kem::*,
symmetric::kdf,
params::*,
KyberError
};
/// Unilateral Key Exchange Initiation Byte Length
pub const UAKE_INIT_BYTES: usize = KYBER_PUBLICKEYBYTES + KYBER_CIPHERTEXTBYTES;
/// Unilateral Key Exchange Response Byte Length
pub const UAKE_RESPONSE_BYTES: usize = KYBER_CIPHERTEXTBYTES;
/// Mutual Key Exchange Initiation Byte Length
pub const AKE_INIT_BYTES: usize = KYBER_PUBLICKEYBYTES + KYBER_CIPHERTEXTBYTES;
/// Mutual Key Exchange Response Byte Length
pub const AKE_RESPONSE_BYTES: usize = 2 * KYBER_CIPHERTEXTBYTES;
/// Result of encapsulating a public key which includes the ciphertext and shared secret
pub type Encapsulated = Result<([u8; KYBER_CIPHERTEXTBYTES], [u8; KYBER_SSBYTES]), KyberError>;
/// The result of decapsulating a ciphertext which produces a shared secret when confirmed
pub type Decapsulated = Result<[u8; KYBER_SSBYTES], KyberError>;
/// Kyber public key
pub type PublicKey = [u8; KYBER_PUBLICKEYBYTES];
/// Kyber secret key
pub type SecretKey = [u8; KYBER_SECRETKEYBYTES];
/// Kyber Shared Secret
pub type SharedSecret = [u8; KYBER_SSBYTES];
/// Bytes to send when initiating a unilateral key exchange
pub type UakeSendInit = [u8; UAKE_INIT_BYTES];
/// Bytes to send when responding to a unilateral key exchange
pub type UakeSendResponse = [u8; UAKE_RESPONSE_BYTES];
/// Bytes to send when initiating a mutual key exchange
pub type AkeSendInit = [u8; AKE_INIT_BYTES];
/// Bytes to send when responding to a mutual key exchange
pub type AkeSendResponse = [u8; AKE_RESPONSE_BYTES];
// Ephemeral keys
type TempKey = [u8; KYBER_SSBYTES];
type Eska = [u8; KYBER_SECRETKEYBYTES];
// TODO: implement zeroise feature
/// Used for unilaterally authenticated key exchange between two parties.
///
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(),KyberError> {
/// let mut rng = rand::thread_rng();
///
/// let mut alice = Uake::new();
/// let mut bob = Uake::new();
/// let bob_keys = keypair(&mut rng);
///
/// let client_init = alice.client_init(&bob_keys.public, &mut rng);
/// let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng)?;
/// let client_confirm = alice.client_confirm(server_send);
///
/// assert_eq!(alice.shared_secret, bob.shared_secret);
/// # Ok(()) }
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Uake {
/// The resulting shared secret from a key exchange
pub shared_secret: SharedSecret,
/// Sent when initiating a key exchange
send_a: UakeSendInit,
/// Response to a key exchange initiation
send_b: UakeSendResponse,
// Epheremal keys
temp_key: TempKey,
eska: Eska
}
impl Default for Uake {
fn default() -> Self {
Uake {
shared_secret: [0u8; KYBER_SSBYTES],
send_a: [0u8; UAKE_INIT_BYTES],
send_b: [0u8; UAKE_RESPONSE_BYTES],
temp_key: [0u8; KYBER_SSBYTES],
eska: [0u8; KYBER_SECRETKEYBYTES],
}
}
}
impl Uake {
/// Builds new UAKE struct
/// ```
/// # use pqc_kyber::Uake;
/// let mut kex = Uake::new();
/// ```
pub fn new() -> Self {
Self::default()
}
/// Initiates a Unilaterally Authenticated Key Exchange.
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(),KyberError> {
/// let mut rng = rand::thread_rng();
/// let mut alice = Uake::new();
/// let bob_keys = keypair(&mut rng);
/// let client_init = alice.client_init(&bob_keys.public, &mut rng);
/// # Ok(()) }
/// ```
pub fn client_init<R>(&mut self, pubkey: &PublicKey, rng: &mut R)
-> UakeSendInit
where R: CryptoRng + RngCore
{
uake_init_a(
&mut self.send_a, &mut self.temp_key,
&mut self.eska, pubkey, rng
);
self.send_a
}
/// Handles the output of a `client_init()` request
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(),KyberError> {
/// # let mut rng = rand::thread_rng();
/// let mut alice = Uake::new();
/// let mut bob = Uake::new();
/// let mut bob_keys = keypair(&mut rng);
/// let client_init = alice.client_init(&bob_keys.public, &mut rng);
/// let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng)?;
/// # Ok(()) }
pub fn server_receive<R>(
&mut self, send_a: UakeSendInit, secretkey: &SecretKey, rng: &mut R
)
-> Result<UakeSendResponse, KyberError>
where R: CryptoRng + RngCore
{
uake_shared_b(
&mut self.send_b, &mut self.shared_secret,
&send_a, secretkey, rng
)?;
Ok(self.send_b)
}
/// Decapsulates and authenticates the shared secret from the output of
/// `server_receive()`
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(),KyberError> {
/// # let mut rng = rand::thread_rng();
/// # let mut alice = Uake::new();
/// # let mut bob = Uake::new();
/// # let bob_keys = keypair(&mut rng);
/// let client_init = alice.client_init(&bob_keys.public, &mut rng);
/// let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng)?;
/// let client_confirm = alice.client_confirm(server_send);
/// assert_eq!(alice.shared_secret, bob.shared_secret);
/// # Ok(()) }
pub fn client_confirm(&mut self, send_b: UakeSendResponse)
-> Result<(), KyberError>
{
uake_shared_a(
&mut self.shared_secret, &send_b,
&self.temp_key, &self.eska
)?;
Ok(())
}
}
/// Used for mutually authenticated key exchange between two parties.
///
/// # Example:
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(),KyberError> {
/// let mut rng = rand::thread_rng();
///
/// let mut alice = Ake::new();
/// let mut bob = Ake::new();
///
/// let alice_keys = keypair(&mut rng);
/// let bob_keys = keypair(&mut rng);
///
/// let client_init = alice.client_init(&bob_keys.public, &mut rng);
/// let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng)?;
/// let client_confirm = alice.client_confirm(server_send, &alice_keys.secret);
///
/// assert_eq!(alice.shared_secret, bob.shared_secret);
/// # Ok(()) }
/// ```
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Ake {
/// The resulting shared secret from a key exchange
pub shared_secret: SharedSecret,
/// Sent when initiating a key exchange
send_a: AkeSendInit,
/// Sent back responding to a key exchange initiation
send_b: AkeSendResponse,
// Epheremal keys
temp_key: TempKey,
eska: Eska
}
impl Default for Ake {
fn default() -> Self {
Ake {
shared_secret: [0u8; KYBER_SSBYTES],
send_a: [0u8; AKE_INIT_BYTES],
send_b: [0u8; AKE_RESPONSE_BYTES],
temp_key: [0u8; KYBER_SSBYTES],
eska: [0u8; KYBER_SECRETKEYBYTES],
}
}
}
impl Ake {
/// Builds a new AKE struct
/// ```
/// # use pqc_kyber::Ake;
/// let mut kex = Ake::new();
/// ```
pub fn new() -> Self {
Self::default()
}
/// Initiates a Mutually Authenticated Key Exchange.
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(),KyberError> {
/// let mut rng = rand::thread_rng();
/// let mut alice = Ake::new();
/// let bob_keys = keypair(&mut rng);
/// let client_init = alice.client_init(&bob_keys.public, &mut rng);
/// # Ok(()) }
/// ```
pub fn client_init<R>(&mut self, pubkey: &PublicKey, rng: &mut R)
-> AkeSendInit
where R: CryptoRng + RngCore
{
ake_init_a(
&mut self.send_a, &mut self.temp_key,
&mut self.eska, pubkey, rng
);
self.send_a
}
/// Handles and authenticates the output of a `client_init()` request
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(),KyberError> {
/// # let mut rng = rand::thread_rng();
/// let mut alice = Ake::new();
/// let mut bob = Ake::new();
/// let alice_keys = keypair(&mut rng);
/// let bob_keys = keypair(&mut rng);
/// let client_init = alice.client_init(&bob_keys.public, &mut rng);
/// let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng)?;
/// # Ok(()) }
pub fn server_receive<R>(
&mut self, ake_send_a: AkeSendInit, pubkey: &PublicKey,
secretkey: &SecretKey, rng: &mut R
)
-> Result<AkeSendResponse, KyberError>
where R: CryptoRng + RngCore
{
ake_shared_b(
&mut self.send_b, &mut self.shared_secret,
&ake_send_a, secretkey, pubkey, rng
)?;
Ok(self.send_b)
}
/// Decapsulates and authenticates the shared secret from the output of
/// `server_receive()`
/// ```
/// # use pqc_kyber::*;
/// # fn main() -> Result<(),KyberError> {
/// # let mut rng = rand::thread_rng();
/// # let mut alice = Ake::new();
/// # let mut bob = Ake::new();
/// # let alice_keys = keypair(&mut rng);
/// # let bob_keys = keypair(&mut rng);
/// # let client_init = alice.client_init(&bob_keys.public, &mut rng);
/// let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng)?;
/// let client_confirm = alice.client_confirm(server_send, &alice_keys.secret);
/// assert_eq!(alice.shared_secret, bob.shared_secret);
/// # Ok(()) }
pub fn client_confirm(&mut self, send_b: AkeSendResponse, secretkey: &SecretKey)
-> Result<(), KyberError>
{
ake_shared_a(
&mut self.shared_secret, &send_b,
&self.temp_key, &self.eska, secretkey
)?;
Ok(())
}
}
// Unilaterally Authenticated Key Exchange initiation
fn uake_init_a<R>(
send: &mut[u8],
tk: &mut[u8],
sk: &mut[u8],
pkb: &[u8],
rng: &mut R
)
where R: CryptoRng + RngCore
{
crypto_kem_keypair(send, sk, rng, None);
crypto_kem_enc(&mut send[KYBER_PUBLICKEYBYTES..], tk, pkb, rng, None);
}
// Unilaterally authenticated key exchange computation by Bob
fn uake_shared_b<R>(
send: &mut[u8],
k: &mut[u8],
recv: &[u8],
skb: &[u8],
rng: &mut R
) -> Result<(), KyberError>
where R: CryptoRng + RngCore
{
let mut buf = [0u8; 2*KYBER_SYMBYTES];
crypto_kem_enc(send, &mut buf, recv, rng, None);
crypto_kem_dec(&mut buf[KYBER_SYMBYTES..], &recv[KYBER_PUBLICKEYBYTES..], skb)?;
kdf(k, &buf, 2*KYBER_SYMBYTES);
Ok(())
}
// Unilaterally authenticated key exchange computation by Alice
fn uake_shared_a(
k: &mut[u8],
recv: &[u8],
tk: &[u8],
sk: &[u8]
) -> Result<(), KyberError>
{
let mut buf = [0u8; 2*KYBER_SYMBYTES];
crypto_kem_dec(&mut buf, recv, sk)?;
buf[KYBER_SYMBYTES..].copy_from_slice(&tk[..]);
kdf(k, &buf, 2*KYBER_SYMBYTES);
Ok(())
}
// Authenticated key exchange initiation by Alice
fn ake_init_a<R>(
send: &mut[u8],
tk: &mut[u8],
sk: &mut[u8],
pkb: &[u8],
rng: &mut R
)
where R: CryptoRng + RngCore
{
crypto_kem_keypair(send, sk, rng, None);
crypto_kem_enc(&mut send[KYBER_PUBLICKEYBYTES..], tk, pkb, rng, None);
}
// Mutually authenticated key exchange computation by Bob
fn ake_shared_b<R>(
send: &mut[u8],
k: &mut[u8],
recv: &[u8],
skb: &[u8],
pka: &[u8],
rng: &mut R
) -> Result<(), KyberError>
where R: CryptoRng + RngCore
{
let mut buf = [0u8; 3*KYBER_SYMBYTES];
crypto_kem_enc(send, &mut buf, recv, rng, None);
crypto_kem_enc(&mut send[KYBER_CIPHERTEXTBYTES..], &mut buf[KYBER_SYMBYTES..], pka, rng, None);
crypto_kem_dec(&mut buf[2*KYBER_SYMBYTES..], &recv[KYBER_PUBLICKEYBYTES..], skb)?;
kdf(k, &buf, 3*KYBER_SYMBYTES);
Ok(())
}
// Mutually authenticated key exchange computation by Alice
fn ake_shared_a(
k: &mut[u8],
recv: &[u8],
tk: &[u8],
sk: &[u8],
ska: &[u8]
) -> Result<(), KyberError>
{
let mut buf = [0u8; 3*KYBER_SYMBYTES];
crypto_kem_dec(&mut buf, recv, sk)?;
crypto_kem_dec(&mut buf[KYBER_SYMBYTES..], &recv[KYBER_CIPHERTEXTBYTES..], ska)?;
buf[2*KYBER_SYMBYTES..].copy_from_slice(&tk[..]);
kdf(k, &buf, 3*KYBER_SYMBYTES);
Ok(())
}

149
third_party/kyber/src/lib.rs vendored Normal file
View file

@ -0,0 +1,149 @@
//! # Kyber
//!
//! A rust implementation of the Kyber algorithm
//!
//! This library:
//! * Is no_std compatible and uses no allocations, suitable for embedded devices.
//! * The reference files contain no unsafe code.
//! * On x86_64 platforms uses an optimized avx2 version by default.
//! * Compiles to WASM using wasm-bindgen.
//!
//! ## Features
//! If no security level is set then Kyber764 is used, this is roughly equivalent to AES-196. See below for setting other levels.
//! A compile-time error is raised if more than one level is specified. Besides that all other features can be mixed as needed:
//!
//! | Feature | Description |
//! |-----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
//! | kyber512 | Enables kyber512 mode, with a security level roughly equivalent to AES-128. |
//! | kyber1024 | Enables kyber1024 mode, with a security level roughly equivalent to AES-256. |
//! | 90s | 90's mode uses SHA2 and AES-CTR as a replacement for SHAKE. This may provide hardware speedups on certain architectures. |
//! | reference | On x86_64 platforms the optimized version is used by default. Enabling this feature will force usage of the reference codebase. This is unnecessary on other architectures |
//! | wasm | For compiling to WASM targets. |
//!
//! ## Usage
//!
//! ```
//! use pqc_kyber::*;
//! ```
//!
//! The higher level structs will be appropriate for most use-cases.
//! Both [unilateral](struct.Uake.html) or [mutually](struct.Ake.html) authenticated key exchanges are possible.
//!
//! #### Unilaterally Authenticated Key Exchange
//! ```
//! # use pqc_kyber::*;
//! # fn main() -> Result<(),KyberError> {
//! let mut rng = rand::thread_rng();
//!
//! // Initialize the key exchange structs
//! let mut alice = Uake::new();
//! let mut bob = Uake::new();
//!
//! // Generate Keypairs
//! let alice_keys = keypair(&mut rng);
//! let bob_keys = keypair(&mut rng);
//!
//! // Alice initiates key exchange
//! let client_init = alice.client_init(&bob_keys.public, &mut rng);
//!
//! // Bob authenticates and responds
//! let server_send = bob.server_receive(
//! client_init, &bob_keys.secret, &mut rng
//! )?;
//!
//! // Alice decapsulates the shared secret
//! alice.client_confirm(server_send)?;
//!
//! // Both key exchange structs now have the shared secret
//! assert_eq!(alice.shared_secret, bob.shared_secret);
//! # Ok(()) }
//! ```
//!
//! #### Mutually Authenticated Key Exchange
//! Mutual authentication follows the same workflow but with additional keys passed to the functions:
//!
//! ```
//! # use pqc_kyber::*;
//! # fn main() -> Result<(),KyberError> {
//! # let mut rng = rand::thread_rng();
//! let mut alice = Ake::new();
//! let mut bob = Ake::new();
//!
//! let alice_keys = keypair(&mut rng);
//! let bob_keys = keypair(&mut rng);
//!
//! let client_init = alice.client_init(&bob_keys.public, &mut rng);
//!
//! let server_send = bob.server_receive(
//! client_init, &alice_keys.public, &bob_keys.secret, &mut rng
//! )?;
//!
//! alice.client_confirm(server_send, &alice_keys.secret)?;
//!
//! assert_eq!(alice.shared_secret, bob.shared_secret);
//! # Ok(()) }
//! ```
//!
//! ##### Key Encapsulation
//! Lower level functions for using the Kyber algorithm directly.
//! ```
//! # use pqc_kyber::*;
//! # fn main() -> Result<(),KyberError> {
//! # let mut rng = rand::thread_rng();
//! // Generate Keypair
//! let keys_bob = keypair(&mut rng);
//!
//! // Alice encapsulates a shared secret using Bob's public key
//! let (ciphertext, shared_secret_alice) = encapsulate(&keys_bob.public, &mut rng)?;
//!
//! // Bob decapsulates a shared secret using the ciphertext sent by Alice
//! let shared_secret_bob = decapsulate(&ciphertext, &keys_bob.secret)?;
//!
//! assert_eq!(shared_secret_alice, shared_secret_bob);
//! # Ok(()) }
//! ```
//!
//! ## Errors
//! The [KyberError](enum.KyberError.html) enum handles errors. It has two variants:
//!
//! * **InvalidInput** - One or more byte inputs to a function are incorrectly sized. A likely cause of
//! this is two parties using different security levels while trying to negotiate a key exchange.
//!
//! * **Decapsulation** - The ciphertext was unable to be authenticated. The shared secret was not decapsulated
//#![no_std]
#![allow(clippy::many_single_char_names)]
// Prevent usage of mutually exclusive features
#[cfg(all(feature = "kyber1024", feature = "kyber512"))]
compile_error!("Only one security level can be specified");
#[cfg(all(target_arch = "x86_64", not(feature = "reference")))]
mod avx2;
#[cfg(all(target_arch = "x86_64", not(feature = "reference")))]
use avx2::*;
#[cfg(any(not(target_arch = "x86_64"), feature = "reference"))]
mod reference;
#[cfg(any(not(target_arch = "x86_64"), feature = "reference"))]
use reference::*;
mod api;
mod error;
mod kem;
mod kex;
mod params;
mod rng;
mod symmetric;
pub use api::*;
pub use error::KyberError;
pub use kex::*;
pub use params::*;
pub use rand_core::{CryptoRng, RngCore};
// Feature hack to expose private functions for the Known Answer Tests
// and fuzzing. Will fail to compile if used outside `cargo test` or
// the fuzz binaries.
#[cfg(any(feature = "KATs", fuzzing))]
pub use kem::*;

67
third_party/kyber/src/params.rs vendored Normal file
View file

@ -0,0 +1,67 @@
/// The security level of Kyber
///
/// Defaults to 3 (kyber768), will be 2 or 4 repsectively when
/// kyber512 or kyber1024 are selected with feature flags.
///
/// * Kyber-512 aims at security roughly equivalent to AES-128
/// * Kyber-768 aims at security roughly equivalent to AES-192
/// * Kyber-1024 aims at security roughly equivalent to AES-256
#[cfg(not(any(feature = "kyber512", feature = "kyber1024")))]
pub const KYBER_K: usize = 3;
#[cfg(feature = "kyber512")]
pub const KYBER_K: usize = 2;
#[cfg(feature = "kyber1024")]
pub const KYBER_K: usize = 4;
/// A boolean flag for whether 90's mode is activated.
///
/// If true AES-CTR and SHA2 will be used as cryptographic primitives instead,
/// which may have hardware speed-ups on certain platforms.
///
/// Defaults to false, set`features = ["90s"]` in Cargo.toml to enable.
#[cfg(not(feature = "90s"))]
pub const KYBER_90S: bool = false;
#[cfg(feature = "90s")]
pub const KYBER_90S: bool = true;
pub(crate) const KYBER_N: usize = 256;
pub(crate) const KYBER_Q: usize = 3329;
#[cfg(feature = "kyber512")]
pub(crate) const KYBER_ETA1: usize = 3;
#[cfg(not(feature = "kyber512"))]
pub(crate) const KYBER_ETA1: usize = 2;
pub(crate) const KYBER_ETA2: usize = 2;
// Size of the hashes and seeds
pub(crate) const KYBER_SYMBYTES: usize = 32;
/// Size of the shared key
pub const KYBER_SSBYTES: usize = 32;
pub(crate) const KYBER_POLYBYTES: usize = 384;
pub(crate) const KYBER_POLYVECBYTES: usize = KYBER_K * KYBER_POLYBYTES;
#[cfg(not(feature = "kyber1024"))]
pub(crate) const KYBER_POLYCOMPRESSEDBYTES: usize = 128;
#[cfg(not(feature = "kyber1024"))]
pub(crate) const KYBER_POLYVECCOMPRESSEDBYTES: usize = KYBER_K * 320;
#[cfg(feature = "kyber1024")]
pub(crate) const KYBER_POLYCOMPRESSEDBYTES: usize = 160;
#[cfg(feature = "kyber1024")]
pub(crate) const KYBER_POLYVECCOMPRESSEDBYTES: usize = KYBER_K * 352;
pub(crate) const KYBER_INDCPA_PUBLICKEYBYTES: usize = KYBER_POLYVECBYTES + KYBER_SYMBYTES;
pub(crate) const KYBER_INDCPA_SECRETKEYBYTES: usize = KYBER_POLYVECBYTES;
pub(crate) const KYBER_INDCPA_BYTES: usize = KYBER_POLYVECCOMPRESSEDBYTES + KYBER_POLYCOMPRESSEDBYTES;
/// Size in bytes of the Kyber public key
pub const KYBER_PUBLICKEYBYTES: usize = KYBER_INDCPA_PUBLICKEYBYTES;
/// Size in bytes of the Kyber secret key
pub const KYBER_SECRETKEYBYTES: usize = KYBER_INDCPA_SECRETKEYBYTES + KYBER_INDCPA_PUBLICKEYBYTES + 2*KYBER_SYMBYTES;
/// Size in bytes of the Kyber ciphertext
pub const KYBER_CIPHERTEXTBYTES: usize = KYBER_INDCPA_BYTES;

View file

@ -0,0 +1,636 @@
// Translated from the public-domain code by Thomas Pornin as
// found in the Kyber C reference library.
// https://github.com/pq-crystals/kyber/blob/master/ref/aes256ctr.c
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#![cfg(feature="90s")]
pub struct Aes256CtrCtx {
pub sk_exp: [u64; 120],
pub ivw: [u32; 16]
}
impl Aes256CtrCtx {
pub fn new() -> Self {
Self {
sk_exp: [0u64; 120],
ivw: [0u32; 16]
}
}
}
fn br_dec32le(src: &[u8]) -> u32
{
src[0] as u32
| (src[1] as u32) << 8
| (src[2] as u32) << 16
| (src[3] as u32) << 24
}
fn br_range_dec32le(v: &mut [u32], mut num: usize, src: &[u8])
{
let mut v_idx: usize = 0;
let mut src_idx: usize = 0;
while num > 0 {
num -= 1;
v[v_idx] = br_dec32le(&src[src_idx..]);
v_idx += 1;
src_idx += 4;
}
}
fn br_swap32(mut x: u32) -> u32
{
x = ((x & 0x00FF00FFu32 ) << 8) | ((x >> 8) & 0x00FF00FFu32);
(x << 16) | (x >> 16)
}
fn br_enc32le(dst: &mut [u8], x: u32)
{
dst[0] = x as u8;
dst[1] = (x >> 8) as u8;
dst[2] = (x >> 16) as u8;
dst[3] = (x >> 24) as u8;
}
fn br_range_enc32le(dst: &mut [u8], v: &[u32], mut num: usize)
{
let mut v_idx = 0;
let mut dst_idx = 0;
while num > 0 {
br_enc32le(&mut dst[dst_idx..], v[v_idx]);
v_idx += 1;
dst_idx += 4;
num -= 1;
}
}
fn br_aes_ct64_bitslice_sbox(q: &mut [u64])
{
// This S-box implementation is a straightforward translation of
// the circuit described by Boyar and Peralta in "A new
// combinational logic minimization technique with applications
// to cryptology" (https://eprint.iacr.org/2009/191.pdf).
// Note that variables x(input) and s(output) are numbered
// in "reverse" order (x0 is the high bit, x7 is the low bit).
let (x0, x1, x2, x3, x4, x5, x6, x7): (u64, u64, u64, u64, u64, u64, u64, u64);
let (y1, y2, y3, y4, y5, y6, y7, y8, y9): (u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (y10, y11, y12, y13, y14, y15, y16, y17, y18, y19): (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64) ;
let (y20, y21): (u64, u64) ;
let (z0, z1, z2, z3, z4, z5, z6, z7, z8, z9): (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (z10, z11, z12, z13, z14, z15, z16, z17): (u64, u64, u64, u64, u64, u64, u64, u64);
let (t0, t1, t2, t3, t4, t5, t6, t7, t8, t9): (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (t10, t11, t12, t13, t14, t15, t16, t17, t18, t19): (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (t20, t21, t22, t23, t24, t25, t26, t27, t28, t29): (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (t30, t31, t32, t33, t34, t35, t36, t37, t38, t39): (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (t40, t41, t42, t43, t44, t45, t46, t47, t48, t49): (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (t50, t51, t52, t53, t54, t55, t56, t57, t58, t59): (u64, u64, u64, u64, u64, u64, u64, u64, u64, u64);
let (t60, t61, t62, t63, t64, t65, t66, t67): (u64, u64, u64, u64, u64, u64, u64, u64);
let (s0, s1, s2, s3, s4, s5, s6, s7): (u64, u64, u64, u64, u64, u64, u64, u64);
x0 = q[7];
x1 = q[6];
x2 = q[5];
x3 = q[4];
x4 = q[3];
x5 = q[2];
x6 = q[1];
x7 = q[0];
// Top linear transformation.
y14 = x3 ^ x5;
y13 = x0 ^ x6;
y9 = x0 ^ x3;
y8 = x0 ^ x5;
t0 = x1 ^ x2;
y1 = t0 ^ x7;
y4 = y1 ^ x3;
y12 = y13 ^ y14;
y2 = y1 ^ x0;
y5 = y1 ^ x6;
y3 = y5 ^ y8;
t1 = x4 ^ y12;
y15 = t1 ^ x5;
y20 = t1 ^ x1;
y6 = y15 ^ x7;
y10 = y15 ^ t0;
y11 = y20 ^ y9;
y7 = x7 ^ y11;
y17 = y10 ^ y11;
y19 = y10 ^ y8;
y16 = t0 ^ y11;
y21 = y13 ^ y16;
y18 = x0 ^ y16;
// Non-linear section.
t2 = y12 & y15;
t3 = y3 & y6;
t4 = t3 ^ t2;
t5 = y4 & x7;
t6 = t5 ^ t2;
t7 = y13 & y16;
t8 = y5 & y1;
t9 = t8 ^ t7;
t10 = y2 & y7;
t11 = t10 ^ t7;
t12 = y9 & y11;
t13 = y14 & y17;
t14 = t13 ^ t12;
t15 = y8 & y10;
t16 = t15 ^ t12;
t17 = t4 ^ t14;
t18 = t6 ^ t16;
t19 = t9 ^ t14;
t20 = t11 ^ t16;
t21 = t17 ^ y20;
t22 = t18 ^ y19;
t23 = t19 ^ y21;
t24 = t20 ^ y18;
t25 = t21 ^ t22;
t26 = t21 & t23;
t27 = t24 ^ t26;
t28 = t25 & t27;
t29 = t28 ^ t22;
t30 = t23 ^ t24;
t31 = t22 ^ t26;
t32 = t31 & t30;
t33 = t32 ^ t24;
t34 = t23 ^ t33;
t35 = t27 ^ t33;
t36 = t24 & t35;
t37 = t36 ^ t34;
t38 = t27 ^ t36;
t39 = t29 & t38;
t40 = t25 ^ t39;
t41 = t40 ^ t37;
t42 = t29 ^ t33;
t43 = t29 ^ t40;
t44 = t33 ^ t37;
t45 = t42 ^ t41;
z0 = t44 & y15;
z1 = t37 & y6;
z2 = t33 & x7;
z3 = t43 & y16;
z4 = t40 & y1;
z5 = t29 & y7;
z6 = t42 & y11;
z7 = t45 & y17;
z8 = t41 & y10;
z9 = t44 & y12;
z10 = t37 & y3;
z11 = t33 & y4;
z12 = t43 & y13;
z13 = t40 & y5;
z14 = t29 & y2;
z15 = t42 & y9;
z16 = t45 & y14;
z17 = t41 & y8;
// Bottom linear transformation.
t46 = z15 ^ z16;
t47 = z10 ^ z11;
t48 = z5 ^ z13;
t49 = z9 ^ z10;
t50 = z2 ^ z12;
t51 = z2 ^ z5;
t52 = z7 ^ z8;
t53 = z0 ^ z3;
t54 = z6 ^ z7;
t55 = z16 ^ z17;
t56 = z12 ^ t48;
t57 = t50 ^ t53;
t58 = z4 ^ t46;
t59 = z3 ^ t54;
t60 = t46 ^ t57;
t61 = z14 ^ t57;
t62 = t52 ^ t58;
t63 = t49 ^ t58;
t64 = z4 ^ t59;
t65 = t61 ^ t62;
t66 = z1 ^ t63;
s0 = t59 ^ t63;
s6 = t56 ^ !t62;
s7 = t48 ^ !t60;
t67 = t64 ^ t65;
s3 = t53 ^ t66;
s4 = t51 ^ t66;
s5 = t47 ^ t65;
s1 = t64 ^ !s3;
s2 = t55 ^ !t67;
q[7] = s0;
q[6] = s1;
q[5] = s2;
q[4] = s3;
q[3] = s4;
q[2] = s5;
q[1] = s6;
q[0] = s7;
}
fn swapn(cl: u64, ch: u64, s: usize, x: u64, y: &mut u64) -> u64
{
let a = x;
let b = *y;
*y = ((a & ch) >> (s)) | (b & ch); // update y
(a & cl) | ((b & cl) << s) // return x
}
fn swap2(x: u64, y: &mut u64) -> u64
{
swapn(0x5555555555555555u64, 0xAAAAAAAAAAAAAAAAu64, 1, x, y)
}
fn swap4(x: u64, y: &mut u64) -> u64
{
swapn(0x3333333333333333u64, 0xCCCCCCCCCCCCCCCCu64, 2, x, y)
}
fn swap8(x: u64, y: &mut u64) -> u64
{
swapn(0x0F0F0F0F0F0F0F0Fu64, 0xF0F0F0F0F0F0F0F0u64, 4, x, y)
}
fn br_aes_ct64_ortho(q: &mut [u64])
{
q[0] = swap2(q[0], &mut q[1]);
q[2] = swap2(q[2], &mut q[3]);
q[4] = swap2(q[4], &mut q[5]);
q[6] = swap2(q[6], &mut q[7]);
q[0] = swap4(q[0], &mut q[2]);
q[1] = swap4(q[1], &mut q[3]);
q[4] = swap4(q[4], &mut q[6]);
q[5] = swap4(q[5], &mut q[7]);
q[0] = swap8(q[0], &mut q[4]);
q[1] = swap8(q[1], &mut q[5]);
q[2] = swap8(q[2], &mut q[6]);
q[3] =swap8(q[3], &mut q[7]);
}
fn br_aes_ct64_interleave_in(q0: &mut u64, q1: &mut u64, w: &[u32])
{
let (mut x0, mut x1, mut x2, mut x3): (u64, u64, u64, u64);
x0 = w[0].into();
x1 = w[1].into();
x2 = w[2].into();
x3 = w[3].into();
x0 |= x0 << 16;
x1 |= x1 << 16;
x2 |= x2 << 16;
x3 |= x3 << 16;
x0 &= 0x0000FFFF0000FFFFu64;
x1 &= 0x0000FFFF0000FFFFu64;
x2 &= 0x0000FFFF0000FFFFu64;
x3 &= 0x0000FFFF0000FFFFu64;
x0 |= x0 << 8;
x1 |= x1 << 8;
x2 |= x2 << 8;
x3 |= x3 << 8;
x0 &= 0x00FF00FF00FF00FFu64;
x1 &= 0x00FF00FF00FF00FFu64;
x2 &= 0x00FF00FF00FF00FFu64;
x3 &= 0x00FF00FF00FF00FFu64;
*q0 = x0 | (x2 << 8);
*q1 = x1 | (x3 << 8);
}
fn br_aes_ct64_interleave_out(w: &mut[u32], q0: u64, q1: u64)
{
let (mut x0, mut x1, mut x2, mut x3): (u64, u64, u64, u64);
x0 = q0 & 0x00FF00FF00FF00FFu64;
x1 = q1 & 0x00FF00FF00FF00FFu64;
x2 = (q0 >> 8) & 0x00FF00FF00FF00FFu64;
x3 = (q1 >> 8) & 0x00FF00FF00FF00FFu64;
x0 |= x0 >> 8;
x1 |= x1 >> 8;
x2 |= x2 >> 8;
x3 |= x3 >> 8;
x0 &= 0x0000FFFF0000FFFFu64;
x1 &= 0x0000FFFF0000FFFFu64;
x2 &= 0x0000FFFF0000FFFFu64;
x3 &= 0x0000FFFF0000FFFFu64;
w[0] = x0 as u32 | (x0 >> 16) as u32 ;
w[1] = x1 as u32 | (x1 >> 16) as u32 ;
w[2] = x2 as u32 | (x2 >> 16) as u32 ;
w[3] = x3 as u32 | (x3 >> 16) as u32 ;
}
fn sub_word(x: u32) -> u32 {
let mut q = [0u64; 8];
q[0] = x.into();
br_aes_ct64_ortho(&mut q);
br_aes_ct64_bitslice_sbox(&mut q);
br_aes_ct64_ortho(&mut q);
q[0] as u32
}
const RCON: [u32; 10] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36];
fn br_aes_ct64_keysched(comp_skey: &mut[u64], key: &[u8])
{
let (mut j, mut k) = (0usize, 0usize);
let mut skey = [0u32; 60];
let key_len = 32usize;
let nk = key_len >> 2;
let nkf = (14 + 1) << 2;
br_range_dec32le(&mut skey, (key_len >> 2) as usize, key);
let mut tmp = skey[(key_len >> 2) - 1];
for i in nk..nkf {
if j == 0 {
tmp = (tmp << 24) | (tmp >> 8);
tmp = sub_word(tmp) ^ RCON[k];
} else if nk > 6 && j == 4 {
tmp = sub_word(tmp);
}
tmp ^= skey[i - nk];
skey[i] = tmp;
j += 1;
if j == nk {
j = 0;
k += 1;
}
}
j = 0;
for idx in (0..nkf).step_by(4) {
let mut q = [0u64; 8];
let (q0, q1) = q.split_at_mut(4);
br_aes_ct64_interleave_in(&mut q0[0], &mut q1[0], &skey[idx..] );
q[1] = q[0];
q[2] = q[0];
q[3] = q[0];
q[5] = q[4];
q[6] = q[4];
q[7] = q[4];
br_aes_ct64_ortho(&mut q);
comp_skey[j] =
(q[0] & 0x1111111111111111)
| (q[1] & 0x2222222222222222)
| (q[2] & 0x4444444444444444)
| (q[3] & 0x8888888888888888);
comp_skey[j + 1] =
(q[4] & 0x1111111111111111)
| (q[5] & 0x2222222222222222)
| (q[6] & 0x4444444444444444)
| (q[7] & 0x8888888888888888);
j += 2;
}
}
fn br_aes_ct64_skey_expand(skey: &mut[u64], comp_skey: &[u64])
{
const N: usize = 15 << 1;
let mut u = 0;
let mut v = 0;
let mut x0: u64;
let mut x1: u64;
let mut x2: u64;
let mut x3: u64;
while u < N {
x0 = comp_skey[u];
x1 = comp_skey[u];
x2 = comp_skey[u];
x3 = comp_skey[u];
x0 &= 0x1111111111111111;
x1 &= 0x2222222222222222;
x2 &= 0x4444444444444444;
x3 &= 0x8888888888888888;
x1 >>= 1;
x2 >>= 2;
x3 >>= 3;
skey[v ] = (x0 << 4).wrapping_sub(x0);
skey[v + 1] = (x1 << 4).wrapping_sub(x1);
skey[v + 2] = (x2 << 4).wrapping_sub(x2);
skey[v + 3] = (x3 << 4).wrapping_sub(x3);
v += 4;
u += 1;
}
}
fn add_round_key(q: &mut[u64], sk: &[u64])
{
q[0] ^= sk[0];
q[1] ^= sk[1];
q[2] ^= sk[2];
q[3] ^= sk[3];
q[4] ^= sk[4];
q[5] ^= sk[5];
q[6] ^= sk[6];
q[7] ^= sk[7];
}
fn shift_rows(q: &mut [u64])
{
for x in q.iter_mut() {
*x = (*x & 0x000000000000FFFF)
| ((*x & 0x00000000FFF00000) >> 4)
| ((*x & 0x00000000000F0000) << 12)
| ((*x & 0x0000FF0000000000) >> 8)
| ((*x & 0x000000FF00000000) << 8)
| ((*x & 0xF000000000000000) >> 12)
| ((*x & 0x0FFF000000000000) << 4)
};
}
fn rotr32(x: u64) -> u64
{
(x << 32) | (x >> 32)
}
fn mix_columns(q: &mut [u64])
{
let q0 = q[0];
let q1 = q[1];
let q2 = q[2];
let q3 = q[3];
let q4 = q[4];
let q5 = q[5];
let q6 = q[6];
let q7 = q[7];
let r0 = (q0 >> 16) | (q0 << 48);
let r1 = (q1 >> 16) | (q1 << 48);
let r2 = (q2 >> 16) | (q2 << 48);
let r3 = (q3 >> 16) | (q3 << 48);
let r4 = (q4 >> 16) | (q4 << 48);
let r5 = (q5 >> 16) | (q5 << 48);
let r6 = (q6 >> 16) | (q6 << 48);
let r7 = (q7 >> 16) | (q7 << 48);
q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
}
fn inc4_be(x: u32) -> u32
{
let t = br_swap32(x) + 4;
br_swap32(t)
}
fn aes_ctr4x(out: &mut [u8], ivw: &mut [u32], sk_exp: &[u64])
{
let mut w = [0u32; 16];
w.copy_from_slice(&ivw);
let mut q = [0u64; 8];
let (q0, q1) = q.split_at_mut(4);
for i in 0..4 {
br_aes_ct64_interleave_in(&mut q0[i], &mut q1[i], &w[(i << 2)..]);
}
br_aes_ct64_ortho(&mut q);
add_round_key(&mut q, sk_exp);
for i in 1..14 {
br_aes_ct64_bitslice_sbox(&mut q);
shift_rows(&mut q);
mix_columns(&mut q);
add_round_key(&mut q, &sk_exp[(i << 3)..]);
}
br_aes_ct64_bitslice_sbox(&mut q);
shift_rows(&mut q);
add_round_key(&mut q, &sk_exp[112..]);
br_aes_ct64_ortho(&mut q);
for i in 0..4 {
br_aes_ct64_interleave_out(&mut w[(i << 2)..], q[i], q[i + 4]);
}
br_range_enc32le(out, &w, 16);
/* Increase counter for next 4 blocks */
ivw[3] = inc4_be(ivw[3]);
ivw[7] = inc4_be(ivw[7]);
ivw[11] = inc4_be(ivw[11]);
ivw[15] = inc4_be(ivw[15]);
}
fn br_aes_ct64_ctr_init(sk_exp: &mut [u64], key: &[u8])
{
let mut skey = [0u64; 30];
br_aes_ct64_keysched(&mut skey, key);
br_aes_ct64_skey_expand(sk_exp, &skey);
}
fn br_aes_ct64_ctr_run(sk_exp: &mut[u64], iv: &[u8], cc: u32, data: &mut[u8], mut len: usize)
{
let mut ivw = [0u32; 16];
br_range_dec32le(&mut ivw, 3, iv);
let mut slice = [0u32; 3];
slice.copy_from_slice(&ivw[0..3]);
ivw[4..7].copy_from_slice(&slice);
ivw[8..11].copy_from_slice(&slice);
ivw[12..15].copy_from_slice(&slice);
ivw[ 3] = br_swap32(cc);
ivw[ 7] = br_swap32(cc + 1);
ivw[11] = br_swap32(cc + 2);
ivw[15] = br_swap32(cc + 3);
let mut idx = 0;
while len > 64 {
aes_ctr4x(&mut data[idx..], &mut ivw, sk_exp);
idx += 64;
len -= 64;
}
if len > 0 {
let mut tmp = [0u8; 64];
aes_ctr4x(&mut tmp, &mut ivw, sk_exp);
data[idx..].copy_from_slice(&tmp[..len])
}
}
// Name: aes256_prf
//
// Description: AES256 stream generation in CTR mode using 32-bit counter,
// nonce is zero-padded to 12 bytes, counter starts at zero
//
// Arguments: - [u8] output: output
// - usize outlen: length of requested output in bytes
// - const [u8] key: 32-byte key
// - const u8 nonce: 1-byte nonce (will be zero-padded to 12 bytes)
pub fn aes256ctr_prf(output: &mut[u8], outlen: usize, key: &[u8], nonce: u8)
{
let mut sk_exp = [0u64; 120];
let mut pad_nonce = [0u8; 12];
pad_nonce[0] = nonce;
br_aes_ct64_ctr_init(&mut sk_exp, key);
br_aes_ct64_ctr_run(&mut sk_exp, &pad_nonce, 0, output, outlen);
}
// Name: aes256ctr_init
//
// Description: AES256 CTR used as a replacement for a XOF; this function
// "absorbs" a 32-byte key and two additional bytes that are zero-padded
// to a 12-byte nonce
//
// Arguments: - aes256xof_ctx *s: state to "absorb" key and IV into
// - const [u8] key: 32-byte key
// - [u8] nonce: additional bytes to "absorb"
pub fn aes256ctr_init(
s: &mut Aes256CtrCtx,
key: &[u8],
nonce: [u8; 12]
)
{
br_aes_ct64_ctr_init(&mut s.sk_exp, key);
br_range_dec32le(&mut s.ivw, 3, &nonce);
let mut slice = [0u32; 3];
slice.copy_from_slice(&s.ivw[..3]);
s.ivw[4..7].copy_from_slice(&slice);
s.ivw[8..11].copy_from_slice(&slice);
s.ivw[12..15].copy_from_slice(&slice);
s.ivw[ 3] = br_swap32(0);
s.ivw[ 7] = br_swap32(1);
s.ivw[11] = br_swap32(2);
s.ivw[15] = br_swap32(3);
}
pub fn aes256ctr_squeezeblocks(
out: &mut[u8],
mut nblocks: usize,
s: &mut Aes256CtrCtx
)
{
let mut idx = 0;
while nblocks > 0 {
aes_ctr4x(&mut out[idx..], &mut s.ivw, &s.sk_exp);
idx += 64;
nblocks -= 1;
}
}

98
third_party/kyber/src/reference/cbd.rs vendored Normal file
View file

@ -0,0 +1,98 @@
use crate::poly::Poly;
use crate::params::KYBER_N;
// Name: load32_littleendian
//
// Description: load 4 bytes into a 32-bit integer
// in little-endian order
//
// Arguments: - const [u8] x: input byte array
//
// Returns 32-bit unsigned integer loaded from x
fn load32_littleendian(x: &[u8]) -> u32
{
let mut r = x[0] as u32;
r |= (x[1] as u32) << 8;
r |= (x[2] as u32) << 16;
r |= (x[3] as u32) << 24;
r
}
// Name: load32_littleendian
//
// Description: load 3 bytes into a 32-bit integer
// in little-endian order
// This function is only needed for Kyber-512
//
// Arguments: - const [u8] x: input byte array
//
// Returns 32-bit unsigned integer loaded from x
fn load24_littleendian(x: &[u8]) -> u32
{
let mut r = x[0] as u32;
r |= (x[1] as u32) << 8;
r |= (x[2] as u32) << 16;
r
}
// Name: cbd2
//
// Description: Given an array of uniformly random bytes, compute
// polynomial with coefficients distributed according to
// a centered binomial distribution with parameter eta=2
//
// Arguments: - poly *r: output polynomial
// - const [u8] buf: input byte array
pub fn cbd2(r: &mut Poly, buf: &[u8])
{
let (mut d, mut t, mut a, mut b);
for i in 0..(KYBER_N/8) {
t = load32_littleendian(&buf[4*i..]);
d = t & 0x55555555;
d += (t>>1) & 0x55555555;
for j in 0..8 {
a = ((d >> (4*j)) & 0x3) as i16;
b = ((d >> (4*j+2)) & 0x3) as i16;
r.coeffs[8*i+j] = a - b;
}
}
}
// Name: cbd3
//
// Description: Given an array of uniformly random bytes, compute
// polynomial with coefficients distributed according to
// a centered binomial distribution with parameter eta=3
// This function is only needed for Kyber-512
// Arguments: - poly *r: output polynomial
// - const [u8] buf: input byte array
pub fn cbd3(r: &mut Poly, buf: &[u8])
{
let (mut d, mut t, mut a, mut b);
for i in 0..(KYBER_N/4) {
t = load24_littleendian(&buf[3*i..]);
d = t & 0x00249249;
d += (t>>1) & 0x00249249;
d += (t>>2) & 0x00249249;
for j in 0..4 {
a = ((d >> (6*j)) & 0x7) as i16;
b = ((d >> (6*j+3)) & 0x7) as i16;
r.coeffs[4*i+j] = a - b;
}
}
}
pub fn poly_cbd_eta1(r: &mut Poly, buf: &[u8])
{
if cfg!(feature="kyber512") {
cbd3(r, buf)
}
else {
cbd2(r, buf)
}
}
pub fn poly_cbd_eta2(r: &mut Poly, buf: &[u8])
{
cbd2(r, buf)
}

View file

@ -0,0 +1,652 @@
#![allow(clippy::needless_range_loop, dead_code)]
use crate::symmetric::KeccakState;
pub(crate) const SHAKE128_RATE: usize = 168;
const SHAKE256_RATE: usize = 136;
const SHA3_256_RATE: usize = 136;
const SHA3_512_RATE: usize = 72;
const NROUNDS: usize = 24;
fn rol(a: u64, offset: u64) -> u64
{
(a << offset) ^ (a >> (64-offset))
}
// Name: load64
//
// Description: Load 8 bytes into u64 in little-endian order
//
// Arguments: - const [u8] x: input byte array
//
// Returns the loaded 64-bit unsigned integer
pub fn load64(x: &[u8]) -> u64
{
let mut r = 0u64;
for i in 0..8 {
r |= (x[i] as u64) << (8 * i);
}
r
}
// Name: store64
//
// Description: Store a 64-bit integer to a byte array in little-endian order
//
// Arguments: - [u8] x: the output byte array
// - u64 u: input 64-bit unsigned integer
pub fn store64(x: &mut[u8], mut u: u64)
{
for i in x.iter_mut().take(8) {
*i = u as u8;
u >>= 8;
}
}
// Keccak round constants
const KECCAKF_ROUNDCONSTANTS: [u64; NROUNDS] = [
0x0000000000000001,
0x0000000000008082,
0x800000000000808a,
0x8000000080008000,
0x000000000000808b,
0x0000000080000001,
0x8000000080008081,
0x8000000000008009,
0x000000000000008a,
0x0000000000000088,
0x0000000080008009,
0x000000008000000a,
0x000000008000808b,
0x800000000000008b,
0x8000000000008089,
0x8000000000008003,
0x8000000000008002,
0x8000000000000080,
0x000000000000800a,
0x800000008000000a,
0x8000000080008081,
0x8000000000008080,
0x0000000080000001,
0x8000000080008008
];
// Name: KeccakF1600_StatePermute
//
// Description: The Keccak F1600 Permutation
//
// Arguments: - u64 * state: in/output Keccak state
pub fn keccakf1600_statepermute(state: &mut[u64])
{
//copyFromState(A, state)
let mut aba = state[ 0];
let mut abe = state[ 1];
let mut abi = state[ 2];
let mut abo = state[ 3];
let mut abu = state[ 4];
let mut aga = state[ 5];
let mut age = state[ 6];
let mut agi = state[ 7];
let mut ago = state[ 8];
let mut agu = state[ 9];
let mut aka = state[10];
let mut ake = state[11];
let mut aki = state[12];
let mut ako = state[13];
let mut aku = state[14];
let mut ama = state[15];
let mut ame = state[16];
let mut ami = state[17];
let mut amo = state[18];
let mut amu = state[19];
let mut asa = state[20];
let mut ase = state[21];
let mut asi = state[22];
let mut aso = state[23];
let mut asu = state[24];
for round in (0..NROUNDS).step_by(2) {
// prepareTheta
let mut bca = aba^aga^aka^ama^asa;
let mut bce = abe^age^ake^ame^ase;
let mut bci = abi^agi^aki^ami^asi;
let mut bco = abo^ago^ako^amo^aso;
let mut bcu = abu^agu^aku^amu^asu;
//thetaRhoPiChiIotaPrepareTheta(round , A, E)
let mut da = bcu^rol(bce, 1);
let mut de = bca^rol(bci, 1);
let mut di = bce^rol(bco, 1);
let mut d_o = bci^rol(bcu, 1);
let mut du = bco^rol(bca, 1);
aba ^= da;
bca = aba;
age ^= de;
bce = rol(age, 44);
aki ^= di;
bci = rol(aki, 43);
amo ^= d_o;
bco = rol(amo, 21);
asu ^= du;
bcu = rol(asu, 14);
let mut eba = bca ^((!bce)& bci );
eba ^= KECCAKF_ROUNDCONSTANTS[round];
let mut ebe = bce ^((!bci)& bco );
let mut ebi = bci ^((!bco)& bcu );
let mut ebo = bco ^((!bcu)& bca );
let mut ebu = bcu ^((!bca)& bce );
abo ^= d_o;
bca = rol(abo, 28);
agu ^= du;
bce = rol(agu, 20);
aka ^= da;
bci = rol(aka, 3);
ame ^= de;
bco = rol(ame, 45);
asi ^= di;
bcu = rol(asi, 61);
let mut ega = bca ^((!bce)& bci );
let mut ege = bce ^((!bci)& bco );
let mut egi = bci ^((!bco)& bcu );
let mut ego = bco ^((!bcu)& bca );
let mut egu = bcu ^((!bca)& bce );
abe ^= de;
bca = rol(abe, 1);
agi ^= di;
bce = rol(agi, 6);
ako ^= d_o;
bci = rol(ako, 25);
amu ^= du;
bco = rol(amu, 8);
asa ^= da;
bcu = rol(asa, 18);
let mut eka = bca ^((!bce)& bci );
let mut eke = bce ^((!bci)& bco );
let mut eki = bci ^((!bco)& bcu );
let mut eko = bco ^((!bcu)& bca );
let mut eku = bcu ^((!bca)& bce );
abu ^= du;
bca = rol(abu, 27);
aga ^= da;
bce = rol(aga, 36);
ake ^= de;
bci = rol(ake, 10);
ami ^= di;
bco = rol(ami, 15);
aso ^= d_o;
bcu = rol(aso, 56);
let mut ema = bca ^((!bce)& bci );
let mut eme = bce ^((!bci)& bco );
let mut emi = bci ^((!bco)& bcu );
let mut emo = bco ^((!bcu)& bca );
let mut emu = bcu ^((!bca)& bce );
abi ^= di;
bca = rol(abi, 62);
ago ^= d_o;
bce = rol(ago, 55);
aku ^= du;
bci = rol(aku, 39);
ama ^= da;
bco = rol(ama, 41);
ase ^= de;
bcu = rol(ase, 2);
let mut esa = bca ^((!bce)& bci );
let mut ese = bce ^((!bci)& bco );
let mut esi = bci ^((!bco)& bcu );
let mut eso = bco ^((!bcu)& bca );
let mut esu = bcu ^((!bca)& bce );
// prepareTheta
bca = eba^ega^eka^ema^esa;
bce = ebe^ege^eke^eme^ese;
bci = ebi^egi^eki^emi^esi;
bco = ebo^ego^eko^emo^eso;
bcu = ebu^egu^eku^emu^esu;
//thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
da = bcu^rol(bce, 1);
de = bca^rol(bci, 1);
di = bce^rol(bco, 1);
d_o = bci^rol(bcu, 1);
du = bco^rol(bca, 1);
eba ^= da;
bca = eba;
ege ^= de;
bce = rol(ege, 44);
eki ^= di;
bci = rol(eki, 43);
emo ^= d_o;
bco = rol(emo, 21);
esu ^= du;
bcu = rol(esu, 14);
aba = bca ^((!bce)& bci );
aba ^= KECCAKF_ROUNDCONSTANTS[round+1];
abe = bce ^((!bci)& bco );
abi = bci ^((!bco)& bcu );
abo = bco ^((!bcu)& bca );
abu = bcu ^((!bca)& bce );
ebo ^= d_o;
bca = rol(ebo, 28);
egu ^= du;
bce = rol(egu, 20);
eka ^= da;
bci = rol(eka, 3);
eme ^= de;
bco = rol(eme, 45);
esi ^= di;
bcu = rol(esi, 61);
aga = bca ^((!bce)& bci );
age = bce ^((!bci)& bco );
agi = bci ^((!bco)& bcu );
ago = bco ^((!bcu)& bca );
agu = bcu ^((!bca)& bce );
ebe ^= de;
bca = rol(ebe, 1);
egi ^= di;
bce = rol(egi, 6);
eko ^= d_o;
bci = rol(eko, 25);
emu ^= du;
bco = rol(emu, 8);
esa ^= da;
bcu = rol(esa, 18);
aka = bca ^((!bce)& bci );
ake = bce ^((!bci)& bco );
aki = bci ^((!bco)& bcu );
ako = bco ^((!bcu)& bca );
aku = bcu ^((!bca)& bce );
ebu ^= du;
bca = rol(ebu, 27);
ega ^= da;
bce = rol(ega, 36);
eke ^= de;
bci = rol(eke, 10);
emi ^= di;
bco = rol(emi, 15);
eso ^= d_o;
bcu = rol(eso, 56);
ama = bca ^((!bce)& bci );
ame = bce ^((!bci)& bco );
ami = bci ^((!bco)& bcu );
amo = bco ^((!bcu)& bca );
amu = bcu ^((!bca)& bce );
ebi ^= di;
bca = rol(ebi, 62);
ego ^= d_o;
bce = rol(ego, 55);
eku ^= du;
bci = rol(eku, 39);
ema ^= da;
bco = rol(ema, 41);
ese ^= de;
bcu = rol(ese, 2);
asa = bca ^((!bce)& bci );
ase = bce ^((!bci)& bco );
asi = bci ^((!bco)& bcu );
aso = bco ^((!bcu)& bca );
asu = bcu ^((!bca)& bce );
}
state[ 0] = aba;
state[ 1] = abe;
state[ 2] = abi;
state[ 3] = abo;
state[ 4] = abu;
state[ 5] = aga;
state[ 6] = age;
state[ 7] = agi;
state[ 8] = ago;
state[ 9] = agu;
state[10] = aka;
state[11] = ake;
state[12] = aki;
state[13] = ako;
state[14] = aku;
state[15] = ama;
state[16] = ame;
state[17] = ami;
state[18] = amo;
state[19] = amu;
state[20] = asa;
state[21] = ase;
state[22] = asi;
state[23] = aso;
state[24] = asu;
}
// Name: keccak_absorb
//
// Description: Absorb step of Keccak;
// non-incremental, starts by zeroeing the state.
//
// Arguments: - u64 s: Keccak state
// usize pos: position in current block to be absorbed
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
// - const [u8] input: pointer to input to be absorbed into s
// - u64 inlen: length of input in bytes
pub(crate) fn keccak_absorb(
s: &mut[u64],
mut pos: usize,
r: usize,
input: &[u8],
mut inlen: usize
) -> usize
{
let mut idx = 0usize;
while pos+inlen >= r {
for i in pos..r {
s[i/8] ^= (input[idx] as u64) << 8 * (i%8);
idx += 1;
}
inlen -= r-pos;
keccakf1600_statepermute(s);
pos = 0;
}
let new_pos = pos+inlen;
for i in pos..new_pos {
s[i/8] ^= (input[idx] as u64) << 8 * (i%8);
}
new_pos
}
// Name: keccak_squeezeblocks
//
// Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each.
// Modifies the state. Can be called multiple times to keep squeezing,
// i.e., is incremental.
//
// Arguments: - [u8] h: output blocks
// - u64 nblocks: number of blocks to be squeezed (written to h)
// - u64 *s: in/output Keccak state
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
pub(crate) fn keccak_squeezeblocks(h: &mut[u8], mut nblocks: usize, s: &mut [u64], r: usize)
{
let mut idx = 0usize;
while nblocks > 0 {
keccakf1600_statepermute(s);
for i in 0..r/8 {
store64(&mut h[idx+8*i..], s[i])
}
idx += r;
nblocks -= 1;
}
}
// Name: shake128_absorb
//
// Description: Absorb step of the SHAKE128 XOF.
// non-incremental, starts by zeroeing the state.
//
// Arguments: - u64 *s: (uninitialized) output Keccak state
// - const [u8] input: input to be absorbed into s
// - u64 inputByteLen: length of input in bytes
pub(crate) fn shake128_absorb(state: &mut KeccakState, input: &[u8], inlen: usize)
{
let pos = state.pos;
state.pos =keccak_absorb(&mut state.s, pos, SHAKE128_RATE, input, inlen);
}
// Name: shake128_squeezeblocks
//
// Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of
// SHAKE128_RATE bytes each. Can be called multiple times
// to keep squeezing. Assumes new block has not yet been
// started (state->pos = SHAKE128_RATE).
//
// Arguments: - [u8] out: pointer to output blocks
// - u64 nblocks: number of blocks to be squeezed (written to output)
// - KeccakState state: pointer to input/output Keccak state
pub(crate) fn shake128_squeezeblocks(out: &mut[u8], nblocks: usize, state: &mut KeccakState)
{
keccak_squeezeblocks(out, nblocks, &mut state.s, SHAKE128_RATE);
}
// Name: shake256
//
// Description: SHAKE256 XOF with non-incremental API
//
// Arguments: - [u8] output: output
// - usize outlen: requested output length in bytes
// - [u8] input: input
// - usize inlen: length of input in bytes
pub(crate) fn shake256(out: &mut[u8], mut outlen: usize, input: &[u8], inlen: usize)
{
let mut state = KeccakState::new();
let mut idx = 0;
shake256_absorb_once(&mut state, input, inlen);
let nblocks = outlen/SHAKE256_RATE;
shake256_squeezeblocks(&mut out[idx..], nblocks, &mut state);
outlen -= nblocks*SHAKE256_RATE;
idx += nblocks*SHAKE256_RATE;
shake256_squeeze(&mut out[idx..], outlen, &mut state);
}
// Name: sha3_256
//
// Description: SHA3-256 with non-incremental API
//
// Arguments: - [u8] h: output (32 bytes)
// - const [u8] input: input
// - usize inlen: length of input in bytes
pub(crate) fn sha3_256(h: &mut[u8], input: &[u8], inlen: usize)
{
let mut s = [0u64; 25];
keccak_absorb_once(&mut s, SHA3_256_RATE, input, inlen, 0x06);
keccakf1600_statepermute(&mut s);
for i in 0..4 {
store64(&mut h[8*i..], s[i]);
}
}
// Name: sha3_512
//
// Description: SHA3-512 with non-incremental API
//
// Arguments: - [u8] h: output (64 bytes)
// - const [u8] input: input
// - usize inlen: length of input in bytes
pub(crate) fn sha3_512(h: &mut[u8], input: &[u8], inlen: usize)
{
let mut s = [0u64; 25];
keccak_absorb_once(&mut s, SHA3_512_RATE, input, inlen, 0x06);
keccakf1600_statepermute(&mut s);
for i in 0..8 {
store64(&mut h[8*i..], s[i]);
}
}
// Name: keccak_finalize
//
// Description: Finalize absorb step.
//
// Arguments: - u64 s: pointer to Keccak state
// - usize pos: position in current block to be absorbed
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
// - u8 p: domain separation byte
fn keccak_finalize(s: &mut[u64], pos: usize, r: usize, p: u8)
{
s[pos/8] ^= (p as u64) << 8*(pos%8);
s[r/8-1] ^= 1u64 << 63;
}
// Name: keccak_absorb_once
//
// Description: Absorb step of Keccak;
// non-incremental, starts by zeroeing the state.
//
// Arguments: - u64 *s: (uninitialized) output Keccak state
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
// - const [u8] input: input to be absorbed into s
// - u64 mlen: length of input in bytes
// - [u8] p: domain-separation byte for different Keccak-derived functions
pub(crate) fn keccak_absorb_once(
s: &mut[u64],
r: usize,
input: &[u8],
mut inlen:
usize,
p: u8)
{
// Zero State
for i in s.iter_mut() {
*i = 0;
}
let mut idx = 0usize;
while inlen >= r {
for i in 0..(r/8) {
s[i] ^= load64(&input[idx+8*i..]);
}
idx += r;
inlen -= r;
keccakf1600_statepermute(s);
}
for i in 0..inlen {
s[i/8] ^= (input[idx+i] as u64) << 8*(i%8);
}
s[inlen/8] ^= (p as u64) << 8*(inlen%8);
s[(r-1)/8] ^= 1u64 << 63;
}
// Name: keccak_squeeze
//
// Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each.
// Modifies the state. Can be called multiple times to keep squeezing,
// i.e., is incremental.
//
// Arguments: - [u8] out: output blocks
// - u64 nblocks: number of blocks to be squeezed (written to out)
// - u64 *s: in/output Keccak state
// usize pos: number of bytes in current block already squeezed
// - usize r: rate in bytes (e.g., 168 for SHAKE128)
// Returns new position pos in current block
pub(crate) fn keccak_squeeze(
out: &mut[u8],
mut outlen: usize,
s: &mut [u64],
mut pos: usize,
r: usize
) -> usize
{
let mut idx = 0;
while outlen > 0 {
if pos == r {
keccakf1600_statepermute(s);
pos = 0
}
let mut i = pos;
while i < r && i < pos+outlen {
out[idx] = (s[i/8] >> 8*(i%8)) as u8;
i += 1;
idx += 1;
}
outlen -= i-pos;
pos = i;
}
pos
}
// Name: shake128_init
//
// Description: Initilizes Keccak state for use as SHAKE128 XOF
//
// Arguments: - keccak_state state: (uninitialized) Keccak state
fn shake128_init(state: &mut KeccakState)
{
state.reset()
}
// Name: shake128_finalize
//
// Description: Finalize absorb step of the SHAKE128 XOF.
//
// Arguments: - keccak_state state: pointer to Keccak state
fn shake128_finalize(state: &mut KeccakState)
{
keccak_finalize(&mut state.s, state.pos, SHAKE128_RATE, 0x1F);
state.pos = SHAKE128_RATE;
}
// Name: shake128_squeeze
//
// Description: Squeeze step of SHAKE128 XOF. Squeezes arbitraily many
// bytes. Can be called multiple times to keep squeezing.
//
// Arguments: - [u8] out: pointer to output blocks
// - usize outlen : number of bytes to be squeezed (written to output)
// - keccak_state s: pointer to input/output Keccak state
fn shake128_squeeze(out: &mut[u8], outlen: usize, state: &mut KeccakState)
{
state.pos = keccak_squeeze(out, outlen, &mut state.s, state.pos, SHAKE128_RATE);
}
// Name: shake128_absorb_once
//
// Description: Initialize, absorb into and finalize SHAKE128 XOF; non-incremental.
//
// Arguments: - keccak_state state: pointer to (uninitialized) output Keccak state
// - const [u8] in: input to be absorbed into s
// - usize inlen: length of input in bytes
pub(crate) fn shake128_absorb_once(state: &mut KeccakState, input: &[u8], inlen: usize)
{
keccak_absorb_once(&mut state.s, SHAKE128_RATE, input, inlen, 0x1F);
state.pos = SHAKE128_RATE;
}
fn shake256_init(state: &mut KeccakState) {
state.reset();
}
fn shake256_absorb(state: &mut KeccakState, input: &[u8], inlen: usize)
{
state.pos = keccak_absorb(&mut state.s, state.pos, SHAKE256_RATE, input, inlen);
}
fn shake256_finalize(state: &mut KeccakState)
{
keccak_finalize(&mut state.s, state.pos, SHAKE256_RATE, 0x1F);
state.pos = SHAKE256_RATE;
}
fn shake256_squeeze(out: &mut[u8], outlen: usize, state: &mut KeccakState)
{
state.pos = keccak_squeeze(out, outlen, &mut state.s, state.pos, SHAKE256_RATE);
}
fn shake256_absorb_once(state: &mut KeccakState, input: &[u8], inlen: usize)
{
keccak_absorb_once(&mut state.s, SHAKE256_RATE, input, inlen, 0x1F);
state.pos = SHAKE256_RATE;
}
fn shake256_squeezeblocks(out: &mut[u8], nblocks: usize, state: &mut KeccakState)
{
keccak_squeezeblocks(out, nblocks, &mut state.s, SHAKE256_RATE);
}
fn shake128(out: &mut[u8], mut outlen: usize, input: &[u8], inlen: usize)
{
let mut state = KeccakState::new();
let mut idx = 0;
shake128_absorb_once(&mut state, input, inlen);
let nblocks = outlen/SHAKE128_RATE;
shake128_squeezeblocks(&mut out[idx..], nblocks, &mut state);
outlen -= nblocks*SHAKE128_RATE;
idx += nblocks*SHAKE128_RATE;
shake128_squeeze(&mut out[idx..], outlen, &mut state);
}

View file

@ -0,0 +1,316 @@
#[cfg(not(feature="KATs"))]
use crate::rng::randombytes;
use crate::{
poly::*,
polyvec::*,
symmetric::*,
params::*,
RngCore,
CryptoRng,
};
// Name: pack_pk
//
// Description: Serialize the public key as concatenation of the
// serialized vector of polynomials pk
// and the public seed used to generate the matrix A.
//
// Arguments: [u8] r: the output serialized public key
// const poly *pk: the input public-key polynomial
// const [u8] seed: the input public seed
fn pack_pk(r: &mut[u8], pk: &mut Polyvec, seed: &[u8])
{
const END: usize = KYBER_SYMBYTES + KYBER_POLYVECBYTES;
polyvec_tobytes(r, pk);
r[KYBER_POLYVECBYTES..END].copy_from_slice(&seed[..KYBER_SYMBYTES]);
}
// Name: unpack_pk
//
// Description: De-serialize public key from a byte array;
// approximate inverse of pack_pk
//
// Arguments: - Polyvec pk: output public-key vector of polynomials
// - [u8] seed: output seed to generate matrix A
// - const [u8] packedpk: input serialized public key
fn unpack_pk(pk: &mut Polyvec, seed: &mut[u8], packedpk: &[u8])
{
const END: usize = KYBER_SYMBYTES + KYBER_POLYVECBYTES;
polyvec_frombytes(pk, packedpk);
seed[..KYBER_SYMBYTES].copy_from_slice(&packedpk[KYBER_POLYVECBYTES..END]);
}
// Name: pack_sk
//
// Description: Serialize the secret key
//
// Arguments: - [u8] r: output serialized secret key
// - const Polyvec sk: input vector of polynomials (secret key)
fn pack_sk(r: &mut[u8], sk: &mut Polyvec)
{
polyvec_tobytes(r, sk);
}
// Name: unpack_sk
//
// Description: De-serialize the secret key, inverse of pack_sk
//
// Arguments: - Polyvec sk: output vector of polynomials (secret key)
// - const [u8] packedsk: input serialized secret key
fn unpack_sk(sk: &mut Polyvec, packedsk: &[u8])
{
polyvec_frombytes(sk, packedsk);
}
// Name: pack_ciphertext
//
// Description: Serialize the ciphertext as concatenation of the
// compressed and serialized vector of polynomials b
// and the compressed and serialized polynomial v
//
// Arguments: [u8] r: the output serialized ciphertext
// const poly *pk: the input vector of polynomials b
// const [u8] seed: the input polynomial v
fn pack_ciphertext(r: &mut[u8], b: &mut Polyvec, v: Poly)
{
polyvec_compress(r, *b);
poly_compress(&mut r[KYBER_POLYVECCOMPRESSEDBYTES..], v);
}
// Name: unpack_ciphertext
//
// Description: De-serialize and decompress ciphertext from a byte array;
// approximate inverse of pack_ciphertext
//
// Arguments: - Polyvec b: output vector of polynomials b
// - poly *v: output polynomial v
// - const [u8] c: input serialized ciphertext
fn unpack_ciphertext(b: &mut Polyvec, v: &mut Poly, c: &[u8])
{
polyvec_decompress(b, c);
poly_decompress(v, &c[KYBER_POLYVECCOMPRESSEDBYTES..]);
}
// Name: rej_uniform
//
// Description: Run rejection sampling on uniform random bytes to generate
// uniform random integers mod q
//
// Arguments: - i16 *r: output buffer
// - usize len: requested number of 16-bit integers (uniform mod q)
// - const [u8] buf: input buffer (assumed to be uniform random bytes)
// - usize buflen: length of input buffer in bytes
//
// Returns number of sampled 16-bit integers (at most len)
fn rej_uniform(r: &mut[i16], len: usize, buf: &[u8], buflen: usize) -> usize
{
let (mut ctr, mut pos) = (0usize, 0usize);
let (mut val0, mut val1);
while ctr < len && pos + 3 <= buflen {
val0 = ((buf[pos+0] >> 0) as u16 | (buf[pos+1] as u16) << 8) & 0xFFF;
val1 = ((buf[pos+1] >> 4) as u16 | (buf[pos+2] as u16) << 4) & 0xFFF;
pos += 3;
if val0 < KYBER_Q as u16 {
r[ctr] = val0 as i16;
ctr += 1;
}
if ctr < len && val1 < KYBER_Q as u16 {
r[ctr] = val1 as i16;
ctr += 1;
}
}
ctr
}
fn gen_a(a: &mut [Polyvec], b: &[u8])
{
gen_matrix(a, b, false);
}
fn gen_at(a: &mut [Polyvec], b: &[u8])
{
gen_matrix(a, b, true);
}
// Name: gen_matrix
//
// Description: Deterministically generate matrix A (or the transpose of A)
// from a seed. Entries of the matrix are polynomials that look
// uniformly random. Performs rejection sampling on output of
// a XOF
//
// Arguments: - Polyvec a: ouptput matrix A
// - const [u8] seed: input seed
// - bool transposed: boolean deciding whether A or A^T is generated
fn gen_matrix(a: &mut [Polyvec], seed: &[u8], transposed: bool)
{
let mut ctr;
// 530 is expected number of required bytes
const GEN_MATRIX_NBLOCKS: usize =
(12*KYBER_N/8*(1 << 12)/KYBER_Q + XOF_BLOCKBYTES)/XOF_BLOCKBYTES;
const BUFLEN: usize = GEN_MATRIX_NBLOCKS*XOF_BLOCKBYTES;
let mut buf = [0u8; BUFLEN+2];
let mut off: usize;
let mut state = XofState::new();
for i in 0..KYBER_K {
for j in 0..KYBER_K {
if transposed {
xof_absorb(&mut state, seed, i as u8, j as u8);
}
else {
xof_absorb(&mut state, seed, j as u8, i as u8);
}
xof_squeezeblocks(&mut buf, GEN_MATRIX_NBLOCKS, &mut state);
ctr = rej_uniform(&mut a[i].vec[j].coeffs, KYBER_N, &buf, BUFLEN);
while ctr < KYBER_N
{
off = BUFLEN % 3;
for k in 0..off {
buf[k] = buf[BUFLEN - off + k];
}
xof_squeezeblocks(&mut buf[off..], 1, &mut state);
ctr += rej_uniform(&mut a[i].vec[j].coeffs[ctr..], KYBER_N - ctr, &buf, BUFLEN);
}
}
}
}
// Name: indcpa_keypair
//
// Description: Generates public and private key for the CPA-secure
// public-key encryption scheme underlying Kyber
//
// Arguments: - [u8] pk: output public key (length KYBER_INDCPA_PUBLICKEYBYTES)
// - [u8] sk: output private key (length KYBER_INDCPA_SECRETKEYBYTES)
pub fn indcpa_keypair<R>(
pk : &mut[u8],
sk: &mut[u8],
_seed: Option<(&[u8], &[u8])>,
_rng: &mut R
)
where R: CryptoRng + RngCore
{
let mut a = [Polyvec::new(); KYBER_K];
let (mut e, mut pkpv, mut skpv) = (Polyvec::new(), Polyvec::new(), Polyvec::new());
let mut nonce = 0u8;
let mut buf = [0u8; 2*KYBER_SYMBYTES];
let mut randbuf = [0u8; 2*KYBER_SYMBYTES];
#[cfg(not(feature="KATs"))]
randombytes(&mut randbuf, KYBER_SYMBYTES, _rng);
// Use rng seed for test vectors
#[cfg(feature="KATs")]
randbuf[..KYBER_SYMBYTES].copy_from_slice(&_seed.expect("KAT feature only for testing").0);
hash_g(&mut buf, &randbuf, KYBER_SYMBYTES);
let (publicseed, noiseseed) = buf.split_at(KYBER_SYMBYTES);
gen_a(&mut a, publicseed);
for i in 0..KYBER_K {
poly_getnoise_eta1(&mut skpv.vec[i], noiseseed, nonce);
nonce += 1;
}
for i in 0..KYBER_K {
poly_getnoise_eta1(&mut e.vec[i], noiseseed, nonce);
nonce += 1;
}
polyvec_ntt(&mut skpv);
polyvec_ntt(&mut e);
// matrix-vector multiplication
for i in 0..KYBER_K {
polyvec_basemul_acc_montgomery(&mut pkpv.vec[i], &a[i], &skpv);
poly_frommont(&mut pkpv.vec[i]);
}
polyvec_add(&mut pkpv, &e);
polyvec_reduce(&mut pkpv);
pack_sk(sk, &mut skpv);
pack_pk(pk, &mut pkpv, publicseed);
}
// Name: indcpa_enc
//
// Description: Encryption function of the CPA-secure
// public-key encryption scheme underlying Kyber.
//
// Arguments: - [u8] c: output ciphertext (length KYBER_INDCPA_BYTES)
// - const [u8] m: input message (length KYBER_INDCPA_MSGBYTES)
// - const [u8] pk: input public key (length KYBER_INDCPA_PUBLICKEYBYTES)
// - const [u8] coin: input random coins used as seed (length KYBER_SYMBYTES)
// to deterministically generate all randomness
pub fn indcpa_enc(c: &mut[u8], m: &[u8], pk: &[u8], coins: &[u8])
{
let mut at = [Polyvec::new(); KYBER_K];
let (mut sp, mut pkpv, mut ep, mut b) =
(Polyvec::new(),Polyvec::new(), Polyvec::new(), Polyvec::new());
let (mut v, mut k, mut epp) = (Poly::new(), Poly::new(), Poly::new());
let mut seed = [0u8; KYBER_SYMBYTES];
let mut nonce = 0u8;
unpack_pk(&mut pkpv, &mut seed, pk);
poly_frommsg(&mut k, m);
gen_at(&mut at, &seed);
for i in 0..KYBER_K {
poly_getnoise_eta1(&mut sp.vec[i], coins, nonce);
nonce += 1;
}
for i in 0..KYBER_K {
poly_getnoise_eta2(&mut ep.vec[i], coins, nonce);
nonce += 1;
}
poly_getnoise_eta2(&mut epp, coins, nonce);
polyvec_ntt(&mut sp);
// matrix-vector multiplication
for i in 0..KYBER_K {
polyvec_basemul_acc_montgomery(&mut b.vec[i], &at[i], &sp);
}
polyvec_basemul_acc_montgomery(&mut v, &pkpv, &sp);
polyvec_invntt_tomont(&mut b);
poly_invntt_tomont(&mut v);
polyvec_add(&mut b, &ep);
poly_add(&mut v, &epp);
poly_add(&mut v, &k);
polyvec_reduce(&mut b);
poly_reduce(&mut v);
pack_ciphertext(c, &mut b, v);
}
// Name: indcpa_dec
//
// Description: Decryption function of the CPA-secure
// public-key encryption scheme underlying Kyber.
//
// Arguments: - [u8] m: output decrypted message (of length KYBER_INDCPA_MSGBYTES)
// - const [u8] c: input ciphertext (of length KYBER_INDCPA_BYTES)
// - const [u8] sk: input secret key (of length KYBER_INDCPA_SECRETKEYBYTES)
pub fn indcpa_dec(m: &mut[u8], c: &[u8], sk: &[u8])
{
let (mut b, mut skpv) = (Polyvec::new(),Polyvec::new());
let (mut v, mut mp) = (Poly::new(),Poly::new());
unpack_ciphertext(&mut b, &mut v, c);
unpack_sk(&mut skpv, sk);
polyvec_ntt(&mut b);
polyvec_basemul_acc_montgomery(&mut mp, &skpv, &b);
poly_invntt_tomont(&mut mp);
poly_sub(&mut mp, &v);
poly_reduce(&mut mp);
poly_tomsg(m, mp);
}

View file

@ -0,0 +1,9 @@
pub mod aes256ctr;
pub mod cbd;
pub mod fips202;
pub mod indcpa;
pub mod ntt;
pub mod poly;
pub mod polyvec;
pub mod reduce;
pub mod verify;

154
third_party/kyber/src/reference/ntt.rs vendored Normal file
View file

@ -0,0 +1,154 @@
use crate::reduce::*;
// Code to generate zetas used in the number-theoretic transform:
//
//#define KYBER_ROOT_OF_UNITY 17
//
//static const uint8_t tree[128] = {
// 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120,
// 4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124,
// 2, 66, 34, 98, 18, 82, 50, 114, 10, 74, 42, 106, 26, 90, 58, 122,
// 6, 70, 38, 102, 22, 86, 54, 118, 14, 78, 46, 110, 30, 94, 62, 126,
// 1, 65, 33, 97, 17, 81, 49, 113, 9, 73, 41, 105, 25, 89, 57, 121,
// 5, 69, 37, 101, 21, 85, 53, 117, 13, 77, 45, 109, 29, 93, 61, 125,
// 3, 67, 35, 99, 19, 83, 51, 115, 11, 75, 43, 107, 27, 91, 59, 123,
// 7, 71, 39, 103, 23, 87, 55, 119, 15, 79, 47, 111, 31, 95, 63, 127};
//
//
// static int16_t fqmul(int16_t a, int16_t b) {
// return montgomery_reduce((int32_t)a*b);
//}
//
// void init_ntt() {
// unsigned int i;
// int16_t tmp[128];
//
// tmp[0] = MONT;
// for(i = 1; i < 128; ++i)
// tmp[i] = fqmul(tmp[i-1], MONT*KYBER_ROOT_OF_UNITY % KYBER_Q);
//
// for(i = 0; i < 128; ++i)
// zetas[i] = tmp[tree[i]];
//
// if(zetas[i] > KYBER_Q/2)
// zetas[i] -= KYBER_Q;
// if(zetas[i] < -KYBER_Q/2)
// zetas[i] += KYBER_Q;
//}
pub const ZETAS: [i16; 128] = [
-1044, -758, -359, -1517, 1493, 1422, 287, 202,
-171, 622, 1577, 182, 962, -1202, -1474, 1468,
573, -1325, 264, 383, -829, 1458, -1602, -130,
-681, 1017, 732, 608, -1542, 411, -205, -1571,
1223, 652, -552, 1015, -1293, 1491, -282, -1544,
516, -8, -320, -666, -1618, -1162, 126, 1469,
-853, -90, -271, 830, 107, -1421, -247, -951,
-398, 961, -1508, -725, 448, -1065, 677, -1275,
-1103, 430, 555, 843, -1251, 871, 1550, 105,
422, 587, 177, -235, -291, -460, 1574, 1653,
-246, 778, 1159, -147, -777, 1483, -602, 1119,
-1590, 644, -872, 349, 418, 329, -156, -75,
817, 1097, 603, 610, 1322, -1285, -1465, 384,
-1215, -136, 1218, -1335, -874, 220, -1187, -1659,
-1185, -1530, -1278, 794, -1510, -854, -870, 478,
-108, -308, 996, 991, 958, -1460, 1522, 1628
];
// Name: fqmul
//
// Description: Multiplication followed by Montgomery reduction
//
// Arguments: - i16 a: first factor
// - i16 b: second factor
//
// Returns 16-bit integer congruent to a*b*R^{-1} mod q
pub fn fqmul(a: i16, b: i16) -> i16
{
montgomery_reduce(a as i32 * b as i32)
}
// Name: ntt
//
// Description: Inplace number-theoretic transform (NTT) in Rq
// input is in standard order, output is in bitreversed order
//
// Arguments: - i16 r[256]: input/output vector of elements of Zq
pub fn ntt(r: &mut[i16])
{
let mut j;
let mut k = 1usize;
let mut len = 128;
let (mut t, mut zeta);
while len >= 2 {
let mut start = 0;
while start < 256 {
zeta = ZETAS[k];
k += 1;
j = start;
while j < (start + len) {
t = fqmul(zeta, r[j + len]);
r[j + len] = r[j] - t;
r[j] += t;
j += 1;
}
start = j + len;
}
len >>= 1;
}
}
// Name: invntt
//
// Description: Inplace inverse number-theoretic transform in Rq
// input is in bitreversed order, output is in standard order
//
// Arguments: - i16 r[256]: input/output vector of elements of Zq
pub fn invntt(r: &mut[i16])
{
let mut j;
let mut k = 127usize;
let mut len = 2;
let (mut t, mut zeta);
const F: i16 = 1441; // mont^2/128
while len <= 128 {
let mut start = 0;
while start < 256 {
zeta = ZETAS[k];
k -= 1;
j = start;
while j < (start + len) {
t = r[j];
r[j] = barrett_reduce(t + r[j + len]);
r[j + len] = r[j + len] -t;
r[j + len] = fqmul(zeta, r[j + len]);
j += 1
}
start = j + len;
}
len <<= 1;
}
for j in 0..256 {
r[j] = fqmul(r[j], F);
}
}
// Name: basemul
//
// Description: Multiplication of polynomials in Zq[X]/((X^2-zeta))
// used for multiplication of elements in Rq in NTT domain
//
// Arguments: - i16 r[2]: the output polynomial
// - const i16 a[2]: the first factor
// - const i16 b[2]: the second factor
// - i16 zeta: integer defining the reduction polynomial
pub fn basemul(r: &mut[i16], a: &[i16], b: &[i16], zeta: i16)
{
r[0] = fqmul(a[1], b[1]);
r[0] = fqmul(r[0], zeta);
r[0] += fqmul(a[0], b[0]);
r[1] = fqmul(a[0], b[1]);
r[1] += fqmul(a[1], b[0]);
}

335
third_party/kyber/src/reference/poly.rs vendored Normal file
View file

@ -0,0 +1,335 @@
use crate::{
params::*,
ntt::*,
reduce::*,
cbd::*,
symmetric::*
};
#[derive(Clone)]
pub struct Poly {
pub coeffs: [i16; KYBER_N]
}
impl Copy for Poly {}
impl Default for Poly {
fn default() -> Self {
Poly {
coeffs: [0i16; KYBER_N]
}
}
}
// new() is nicer
impl Poly {
pub fn new() -> Self {
Self::default()
}
}
// Name: poly_compress
//
// Description: Compression and subsequent serialization of a polynomial
//
// Arguments: - [u8] r: output byte array (needs space for KYBER_POLYCOMPRESSEDBYTES bytes)
// - const poly *a: input polynomial
pub fn poly_compress(r: &mut[u8], a: Poly)
{
let mut t = [0u8; 8];
let mut k = 0usize;
let mut u: i16;
match KYBER_POLYCOMPRESSEDBYTES {
128 => {
for i in 0..KYBER_N/8 {
for j in 0..8 {
// map to positive standard representatives
u = a.coeffs[8*i+j];
u += (u >> 15) & KYBER_Q as i16;
t[j] = (((((u as u16) << 4) + KYBER_Q as u16 /2) / KYBER_Q as u16) & 15) as u8;
}
r[k] = t[0] | (t[1] << 4);
r[k+1] = t[2] | (t[3] << 4);
r[k+2] = t[4] | (t[5] << 4);
r[k+3] = t[6] | (t[7] << 4);
k += 4;
}
},
160 => {
for i in 0..(KYBER_N/8) {
for j in 0..8 {
// map to positive standard representatives
u = a.coeffs[8*i+j];
u += (u >> 15) & KYBER_Q as i16;
t[j] = (((((u as u32) << 5) + KYBER_Q as u32/2) / KYBER_Q as u32) & 31) as u8;
}
r[k] = t[0] | (t[1] << 5);
r[k+1] = (t[1] >> 3) | (t[2] << 2) | (t[3] << 7);
r[k+2] = (t[3] >> 1) | (t[4] << 4);
r[k+3] = (t[4] >> 4) | (t[5] << 1) | (t[6] << 6);
r[k+4] = (t[6] >> 2) | (t[7] << 3);
k += 5;
}
},
_ => panic!("KYBER_POLYCOMPRESSEDBYTES needs to be one of (128, 160)")
}
}
// Name: poly_decompress
//
// Description: De-serialization and subsequent decompression of a polynomial;
// approximate inverse of poly_compress
//
// Arguments: - poly *r: output polynomial
// - const [u8] a: input byte array (of length KYBER_POLYCOMPRESSEDBYTES bytes)
pub fn poly_decompress(r: &mut Poly, a: &[u8])
{
match KYBER_POLYCOMPRESSEDBYTES {
128 => {
let mut idx = 0usize;
for i in 0..KYBER_N/2 {
r.coeffs[2*i+0] = ((((a[idx] & 15) as usize * KYBER_Q) + 8) >> 4) as i16;
r.coeffs[2*i+1] = ((((a[idx] >> 4) as usize * KYBER_Q) + 8) >> 4) as i16;
idx += 1;
}
},
160 => {
let mut idx = 0usize;
let mut t = [0u8;8];
for i in 0..KYBER_N/8 {
t[0] = a[idx+0];
t[1] = (a[idx+0] >> 5) | (a[idx+1] << 3);
t[2] = a[idx+1] >> 2;
t[3] = (a[idx+1] >> 7) | (a[idx+2] << 1);
t[4] = (a[idx+2] >> 4) | (a[idx+3] << 4);
t[5] = a[idx+3] >> 1;
t[6] = (a[idx+3] >> 6) | (a[idx+4] << 2);
t[7] = a[idx+4] >> 3;
idx += 5;
for j in 0..8 {
r.coeffs[8*i+j] = ((((t[j] as u32) & 31)*KYBER_Q as u32 + 16) >> 5) as i16;
}
}
},
_ => panic!("KYBER_POLYCOMPRESSEDBYTES needs to be either (128, 160)")
}
}
// Name: poly_tobytes
//
// Description: Serialization of a polynomial
//
// Arguments: - [u8] r: output byte array (needs space for KYBER_POLYBYTES bytes)
// - const poly *a: input polynomial
pub fn poly_tobytes(r: &mut[u8], a: Poly)
{
let (mut t0, mut t1);
for i in 0..(KYBER_N/2) {
// map to positive standard representatives
t0 = a.coeffs[2*i];
t0 += (t0 >> 15) & KYBER_Q as i16;
t1 = a.coeffs[2*i+1];
t1 += (t1 >> 15) & KYBER_Q as i16;
r[3*i+0] = (t0 >> 0) as u8;
r[3*i+1] = ((t0 >> 8) | (t1 << 4)) as u8;
r[3*i+2] = (t1 >> 4) as u8;
}
}
// Name: poly_frombytes
//
// Description: De-serialization of a polynomial;
// inverse of poly_tobytes
//
// Arguments: - poly *r: output polynomial
// - const [u8] a: input byte array (of KYBER_POLYBYTES bytes)
pub fn poly_frombytes(r: &mut Poly, a: &[u8])
{
for i in 0..(KYBER_N/2) {
r.coeffs[2*i+0] = ((a[3*i+0] >> 0) as u16 | ((a[3*i+1] as u16) << 8) & 0xFFF) as i16;
r.coeffs[2*i+1] = ((a[3*i+1] >> 4) as u16 | ((a[3*i+2] as u16) << 4) & 0xFFF) as i16;
}
}
// Name: poly_getnoise_eta1
//
// Description: Sample a polynomial deterministically from a seed and a nonce,
// with output polynomial close to centered binomial distribution
// with parameter KYBER_ETA1
//
// Arguments: - poly *r: output polynomial
// - const [u8] seed: input seed (pointing to array of length KYBER_SYMBYTES bytes)
// - [u8] nonce: one-byte input nonce
pub fn poly_getnoise_eta1(r: &mut Poly, seed: &[u8], nonce: u8)
{
const LENGTH: usize = KYBER_ETA1*KYBER_N/4;
let mut buf = [0u8; LENGTH];
prf(&mut buf, LENGTH, seed, nonce);
poly_cbd_eta1(r, &buf);
}
// Name: poly_getnoise_eta2
//
// Description: Sample a polynomial deterministically from a seed and a nonce,
// with output polynomial close to centered binomial distribution
// with parameter KYBER_ETA2
//
// Arguments: - poly *r: output polynomial
// - const [u8] seed: input seed (pointing to array of length KYBER_SYMBYTES bytes)
// - [u8] nonce: one-byte input nonce
pub fn poly_getnoise_eta2(r: &mut Poly, seed: &[u8], nonce: u8)
{
const LENGTH: usize = KYBER_ETA2*KYBER_N/4;
let mut buf = [0u8; LENGTH];
prf(&mut buf, LENGTH, seed, nonce);
poly_cbd_eta2(r, &buf);
}
// Name: poly_ntt
//
// Description: Computes negacyclic number-theoretic transform (NTT) of
// a polynomial in place;
// inputs assumed to be in normal order, output in bitreversed order
//
// Arguments: - Poly r: in/output polynomial
pub fn poly_ntt(r: &mut Poly)
{
ntt(&mut r.coeffs);
poly_reduce(r);
}
// Name: poly_invntt
//
// Description: Computes inverse of negacyclic number-theoretic transform (NTT) of
// a polynomial in place;
// inputs assumed to be in bitreversed order, output in normal order
//
// Arguments: - Poly a: in/output polynomial
pub fn poly_invntt_tomont(r: &mut Poly)
{
invntt(&mut r.coeffs);
}
// Name: poly_basemul
//
// Description: Multiplication of two polynomials in NTT domain
//
// Arguments: - poly *r: output polynomial
// - const poly *a: first input polynomial
// - const poly *b: second input polynomial
pub fn poly_basemul(r: &mut Poly, a: &Poly, b: &Poly)
{
for i in 0..(KYBER_N/4) {
basemul(
&mut r.coeffs[4*i..],
&a.coeffs[4*i..],
&b.coeffs[4*i..],
ZETAS[64 + i]
);
basemul(
&mut r.coeffs[4*i+2..],
&a.coeffs[4*i+2..],
&b.coeffs[4*i+2..],
-(ZETAS[64 + i]));
}
}
// Name: poly_frommont
//
// Description: Inplace conversion of all coefficients of a polynomial
// from Montgomery domain to normal domain
//
// Arguments: - poly *r: input/output polynomial
pub fn poly_frommont(r: &mut Poly)
{
let f = ((1u64 << 32) % KYBER_Q as u64) as i16;
for i in 0..KYBER_N {
let a = r.coeffs[i] as i32 * f as i32;
r.coeffs[i] = montgomery_reduce(a);
}
}
// Name: poly_reduce
//
// Description: Applies Barrett reduction to all coefficients of a polynomial
// for details of the Barrett reduction see comments in reduce.c
//
// Arguments: - poly *r: input/output polynomial
pub fn poly_reduce(r: &mut Poly)
{
for i in 0..KYBER_N {
r.coeffs[i] = barrett_reduce(r.coeffs[i]);
}
}
// Name: poly_add
//
// Description: Add two polynomials; no modular reduction is performed
//
// Arguments: - poly *r: output polynomial
// - const poly *a: first input polynomial
// - const poly *b: second input polynomial
pub fn poly_add(r: &mut Poly, b: &Poly)
{
for i in 0..KYBER_N {
r.coeffs[i] += b.coeffs[i];
}
}
// Name: poly_sub
//
// Description: Subtract two polynomials; no modular reduction is performed
//
// Arguments: - poly *r: output polynomial
// - const poly *a: first input polynomial
// - const poly *b: second input polynomial
pub fn poly_sub(r: &mut Poly, a: &Poly)
{
for i in 0..KYBER_N {
r.coeffs[i] = a.coeffs[i] - r.coeffs[i];
}
}
// Name: poly_frommsg
//
// Description: Convert 32-byte message to polynomial
//
// Arguments: - poly *r: output polynomial
// - const [u8] msg: input message
pub fn poly_frommsg(r: &mut Poly, msg: &[u8])
{
let mut mask;
for i in 0..KYBER_SYMBYTES {
for j in 0..8 {
mask = ((msg[i] as u16 >> j) & 1 ).wrapping_neg();
r.coeffs[8*i+j] = (mask & ((KYBER_Q+1)/2) as u16) as i16;
}
}
}
// Name: poly_tomsg
//
// Description: Convert polynomial to 32-byte message
//
// Arguments: - [u8] msg: output message
// - const poly *a: input polynomial
pub fn poly_tomsg(msg: &mut[u8], a: Poly)
{
let mut t;
for i in 0..KYBER_SYMBYTES {
msg[i] = 0;
for j in 0..8 {
t = a.coeffs[8*i+j];
t += (t >> 15) & KYBER_Q as i16;
t = (((t << 1) + KYBER_Q as i16 /2) / KYBER_Q as i16) & 1;
msg[i] |= (t << j) as u8;
}
}
}

View file

@ -0,0 +1,241 @@
#![allow(clippy::precedence)]
use crate::{
poly::*,
params::*
};
#[derive(Clone)]
pub struct Polyvec {
pub vec: [Poly; KYBER_K]
}
impl Copy for Polyvec {}
impl Polyvec {
pub fn new() -> Self {
Polyvec {
vec: [Poly::new(); KYBER_K]
}
}
// #[cfg(debug_assertions)]
// pub fn checksum(&self) -> i16 {
// let mut out = 0i16;
// for i in 0..KYBER_K {
// for j in 0..KYBER_N {
// out ^= &self.vec[i].coeffs[j]
// }
// }
// out
// }
}
// Name: polyvec_compress
//
// Description: Compress and serialize vector of polynomials
//
// Arguments: - [u8] r: output byte array (needs space for KYBER_POLYVECCOMPRESSEDBYTES)
// - const Polyvec a: input vector of polynomials
pub fn polyvec_compress(r: &mut[u8], a: Polyvec)
{
#[cfg(feature="kyber1024")]
{
let mut t = [0u16; 8];
let mut idx = 0usize;
for i in 0..KYBER_K {
for j in 0..KYBER_N/8 {
for k in 0..8 {
t[k] = a.vec[i].coeffs[8*j+k] as u16;
t[k] = t[k].wrapping_add((((t[k] as i16) >> 15) & KYBER_Q as i16) as u16);
t[k] = (((((t[k] as u32) << 11) + KYBER_Q as u32/2)/KYBER_Q as u32) & 0x7ff ) as u16;
}
r[idx+0] = (t[0] >> 0) as u8;
r[idx+1] = ((t[0] >> 8) | (t[1] << 3)) as u8;
r[idx+2] = ((t[1] >> 5) | (t[2] << 6)) as u8;
r[idx+3] = (t[2] >> 2) as u8;
r[idx+4] = ((t[2] >> 10) | (t[3] << 1)) as u8;
r[idx+5] = ((t[3] >> 7) | (t[4] << 4)) as u8;
r[idx+6] = ((t[4] >> 4) | (t[5] << 7)) as u8;
r[idx+7] = (t[5] >> 1) as u8;
r[idx+8] = ((t[5] >> 9) | (t[6] << 2)) as u8;
r[idx+9] = ((t[6] >> 6) | (t[7] << 5)) as u8;
r[idx+10] = (t[7] >> 3) as u8;
idx += 11
}
}
}
#[cfg(not(feature="kyber1024"))]
{
let mut t = [0u16; 4];
let mut idx = 0usize;
for i in 0..KYBER_K {
for j in 0..KYBER_N/4 {
for k in 0..4 {
t[k] = a.vec[i].coeffs[4*j+k] as u16;
t[k] = t[k].wrapping_add((((t[k] as i16) >> 15) & KYBER_Q as i16) as u16);
t[k] =
(((((t[k] as u32) << 10) + KYBER_Q as u32/2)/ KYBER_Q as u32) & 0x3ff) as u16;
}
r[idx+0] = (t[0] >> 0) as u8;
r[idx+1] = ((t[0] >> 8) | (t[1] << 2)) as u8;
r[idx+2] = ((t[1] >> 6) | (t[2] << 4)) as u8;
r[idx+3] = ((t[2] >> 4) | (t[3] << 6)) as u8;
r[idx+4] = (t[3] >> 2) as u8;
idx += 5;
}
}
}
}
// Name: polyvec_decompress
//
// Description: De-serialize and decompress vector of polynomials;
// approximate inverse of polyvec_compress
//
// Arguments: - Polyvec r: output vector of polynomials
// - [u8] a: input byte array (of length KYBER_POLYVECCOMPRESSEDBYTES)
pub fn polyvec_decompress(r: &mut Polyvec, a: &[u8])
{
#[cfg(feature="kyber1024")]
{
let mut t = [0u16; 8];
let mut idx = 0usize;
for i in 0..KYBER_K {
for j in 0..KYBER_N/8 {
t[0] = (a[idx+0] >> 0) as u16 | (a[idx+ 1] as u16) << 8;
t[1] = (a[idx+1] >> 3) as u16 | (a[idx+ 2] as u16) << 5;
t[2] = (a[idx+2] >> 6) as u16 | (a[idx+ 3] as u16) << 2 | (a[idx+4] as u16) << 10;
t[3] = (a[idx+4] >> 1) as u16 | (a[idx+ 5] as u16) << 7;
t[4] = (a[idx+5] >> 4) as u16 | (a[idx+ 6] as u16) << 4;
t[5] = (a[idx+6] >> 7) as u16 | (a[idx+ 7] as u16) << 1 | (a[idx+8] as u16) << 9;
t[6] = (a[idx+8] >> 2) as u16 | (a[idx+ 9] as u16) << 6;
t[7] = (a[idx+9] >> 5) as u16 | (a[idx+10] as u16) << 3;
idx += 11;
for k in 0..8 {
r.vec[i].coeffs[8*j+k] =
(((t[k] & 0x7FF)as u32 * KYBER_Q as u32 + 1024) >> 11) as i16;
}
}
}
}
#[cfg(not(feature="kyber1024"))]
{
let mut idx = 0usize;
let mut t = [0u16; 4];
for i in 0..KYBER_K {
for j in 0..KYBER_N/4 {
t[0] = (a[idx+0] >> 0) as u16 | (a[idx+1] as u16) << 8;
t[1] = (a[idx+1] >> 2) as u16 | (a[idx+2] as u16) << 6;
t[2] = (a[idx+2] >> 4) as u16 | (a[idx+3] as u16) << 4;
t[3] = (a[idx+3] >> 6) as u16 | (a[idx+4] as u16) << 2;
idx += 5;
for k in 0..4 {
r.vec[i].coeffs[4*j+k] =
((((t[k] as u32) & 0x3FF) * KYBER_Q as u32 + 512) >> 10) as i16;
}
}
}
}
}
// Name: polyvec_tobytes
//
// Description: Serialize vector of polynomials
//
// Arguments: - [u8] r: output byte array (needs space for KYBER_POLYVECBYTES)
// - const Polyvec a: input vector of polynomials
pub fn polyvec_tobytes(r: &mut[u8], a: &Polyvec)
{
for i in 0..KYBER_K {
poly_tobytes(&mut r[i*KYBER_POLYBYTES..], a.vec[i]);
}
}
// Name: polyvec_frombytes
//
// Description: De-serialize vector of polynomials;
// inverse of polyvec_tobytes
//
// Arguments: - [u8] r: output byte array
// - const Polyvec a: input vector of polynomials (of length KYBER_POLYVECBYTES)
pub fn polyvec_frombytes(r: &mut Polyvec, a: &[u8])
{
for i in 0..KYBER_K {
poly_frombytes(&mut r.vec[i], &a[i*KYBER_POLYBYTES..]);
}
}
// Name: polyvec_ntt
//
// Description: Apply forward NTT to all elements of a vector of polynomials
//
// Arguments: - Polyvec r: in/output vector of polynomials
pub fn polyvec_ntt(r: &mut Polyvec)
{
for i in 0..KYBER_K {
poly_ntt(&mut r.vec[i]);
}
}
// Name: polyvec_invntt
//
// Description: Apply inverse NTT to all elements of a vector of polynomials
//
// Arguments: - Polyvec r: in/output vector of polynomials
pub fn polyvec_invntt_tomont(r: &mut Polyvec)
{
for i in 0..KYBER_K {
poly_invntt_tomont(&mut r.vec[i]);
}
}
// Name: polyvec_basemul_acc_montgomery
//
// Description: Pointwise multiply elements of a and b and accumulate into r
//
// Arguments: - poly *r: output polynomial
// - const Polyvec a: first input vector of polynomials
// - const Polyvec b: second input vector of polynomials
pub fn polyvec_basemul_acc_montgomery(r: &mut Poly, a: &Polyvec, b: &Polyvec)
{
let mut t = Poly::new();
poly_basemul(r, &a.vec[0], &b.vec[0]);
for i in 1..KYBER_K {
poly_basemul(&mut t, &a.vec[i], &b.vec[i]);
poly_add(r, &t);
}
poly_reduce(r);
}
// Name: polyvec_reduce
//
// Description: Applies Barrett reduction to each coefficient
// of each element of a vector of polynomials
// for details of the Barrett reduction see comments in reduce.c
//
// Arguments: - poly *r: input/output polynomial
pub fn polyvec_reduce(r: &mut Polyvec)
{
for i in 0..KYBER_K {
poly_reduce(&mut r.vec[i]);
}
}
// Name: polyvec_add
//
// Description: Add vectors of polynomials
//
// Arguments: - Polyvec r: output vector of polynomials
// - const Polyvec b: second input vector of polynomials
pub fn polyvec_add(r: &mut Polyvec, b: &Polyvec)
{
for i in 0..KYBER_K {
poly_add(&mut r.vec[i], &b.vec[i]);
}
}

View file

@ -0,0 +1,41 @@
use crate::params::*;
const QINV: i32 = 62209; // q^(-1) mod 2^16
// Name: montgomery_reduce
//
// Description: Montgomery reduction; given a 32-bit integer a, computes
// 16-bit integer congruent to a * R^-1 mod q,
// where R=2^16
//
// Arguments: - i32 a: input integer to be reduced; has to be in {-q2^15,...,q2^15-1}
//
// Returns: integer in {-q+1,...,q-1} congruent to a * R^-1 modulo q.
pub fn montgomery_reduce(a: i32) -> i16
{
let ua = a.wrapping_mul(QINV) as i16;
let u = ua as i32;
let mut t = u * KYBER_Q as i32;
t = a - t;
t >>= 16;
t as i16
}
// Name: barrett_reduce
//
// Description: Barrett reduction; given a 16-bit integer a, computes
// centered representative congruent to a mod q in {-(q-1)/2,...,(q-1)/2}
//
// Arguments: - i16 a: input integer to be reduced
//
// Returns: i16 in {-(q-1)/2,...,(q-1)/2} congruent to a modulo q.
pub fn barrett_reduce(a: i16) -> i16
{
let v = ((1u32 << 26)/KYBER_Q as u32 + 1) as i32;
let mut t = v * a as i32 + (1 << 25);
t >>= 26;
t *= KYBER_Q as i32;
a - t as i16
}

View file

@ -0,0 +1,37 @@
// Name: verify
//
// Description: Compare two arrays for equality in constant time.
//
// Arguments: const [u8] a: first byte array
// const [u8] b: second byte array
// size_t len: length of the byte arrays
//
// Returns 0 if the byte arrays are equal, 1 otherwise
pub fn verify(a: &[u8], b: &[u8], len: usize) -> u8
{
let mut r = 0u64;
for i in 0..len {
r |= (a[i] ^ b[i]) as u64;
}
r = r.wrapping_neg() >> 63;
r as u8
}
// Name: cmov
//
// Description: Copy len bytes from x to r if b is 1;
// don't modify x if b is 0. Requires b to be in {0,1};
// assumes two's complement representation of negative integers.
// Runs in constant time.
//
// Arguments: [u8] r: output byte array
// const [u8] x: input byte array
// size_t len: Amount of bytes to be copied
// [u8] b: Condition bit; has to be in {0,1}
pub fn cmov(r: &mut[u8], x: &[u8], len: usize, mut b: u8)
{
b = b.wrapping_neg();
for i in 0..len {
r[i] ^= b & (x[i] ^ r[i]);
}
}

10
third_party/kyber/src/rng.rs vendored Normal file
View file

@ -0,0 +1,10 @@
#![cfg(not(feature="KATs"))]
use rand_core::*;
// Fills buffer x with len bytes, RNG must satisfy the
// RngCore trait and CryptoRng marker trait requirements
pub fn randombytes<R>(x: &mut [u8], len: usize, rng: &mut R)
where R: RngCore + CryptoRng,
{
rng.fill_bytes(&mut x[..len]);
}

205
third_party/kyber/src/symmetric.rs vendored Normal file
View file

@ -0,0 +1,205 @@
#![allow(dead_code)]
#[cfg(not(feature = "90s"))] use crate::{fips202::*, params::*};
#[cfg(feature = "90s")] use crate::aes256ctr::*;
#[cfg(feature = "90s")] use sha2::{Sha256, Sha512, Digest};
// TODO: Rustrypto AES-CTR feature
// #[cfg(feature = "90s")] use aes_ctr::Aes256Ctr;
// #[cfg(feature = "90s")] use aes_ctr::cipher::{
// generic_array::GenericArray,
// stream::{NewStreamCipher, SyncStreamCipher}
// };
#[cfg(feature = "90s")]
pub(crate) const AES256CTR_BLOCKBYTES: usize = 64;
#[cfg(feature = "90s")]
pub(crate) const XOF_BLOCKBYTES: usize = AES256CTR_BLOCKBYTES;
#[cfg(not(feature = "90s"))]
pub(crate) const XOF_BLOCKBYTES: usize = SHAKE128_RATE;
#[cfg(not(feature = "90s"))]
pub(crate) type XofState = KeccakState;
#[cfg(feature = "90s")]
pub(crate) type XofState = Aes256CtrCtx;
#[derive(Copy, Clone)]
pub(crate) struct KeccakState {
pub s: [u64; 25],
pub pos: usize
}
impl KeccakState {
pub fn new() -> Self {
KeccakState {
s: [0u64; 25],
pos: 0usize
}
}
pub fn reset(&mut self) {
self.s = [0u64; 25];
self.pos = 0;
}
}
// SHA3-256
#[cfg(not(feature = "90s"))]
pub(crate) fn hash_h(out: &mut[u8], input: &[u8], inlen: usize)
{
sha3_256(out, input, inlen);
}
// 90s mode SHA2-256
#[cfg(feature = "90s")]
pub(crate) fn hash_h(out: &mut[u8], input: &[u8], inlen: usize)
{
let mut hasher = Sha256::new();
hasher.update(&input[..inlen]);
let digest = hasher.finalize();
out[..digest.len()].copy_from_slice(&digest);
}
#[cfg(not(feature = "90s"))]
pub(crate) fn hash_g(out: &mut[u8], input: &[u8], inlen: usize)
{
sha3_512(out, input, inlen);
}
#[cfg(feature = "90s")]
pub(crate) fn hash_g(out: &mut[u8], input: &[u8], inlen: usize)
{
let mut hasher = Sha512::new();
hasher.update(&input[..inlen]);
let digest = hasher.finalize();
out[..digest.len()].copy_from_slice(&digest);
}
#[cfg(not(feature = "90s"))]
pub(crate) fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8)
{
kyber_shake128_absorb(state, &input, x, y);
}
#[cfg(feature = "90s")]
pub(crate) fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8)
{
let mut nonce = [0u8; 12];
nonce[0] = x;
nonce[1] = y;
aes256ctr_init(state, &input, nonce);
}
#[cfg(not(feature = "90s"))]
pub(crate) fn xof_squeezeblocks(out: &mut[u8], outblocks: usize, state: &mut XofState)
{
kyber_shake128_squeezeblocks(out, outblocks, state);
}
#[cfg(feature = "90s")]
pub(crate) fn xof_squeezeblocks(out: &mut[u8], outblocks: usize, state: &mut XofState)
{
aes256ctr_squeezeblocks(out, outblocks, state);
}
#[cfg(not(feature = "90s"))]
pub(crate) fn prf(out: &mut[u8], outbytes: usize, key: &[u8], nonce: u8)
{
shake256_prf(out, outbytes, &key, nonce);
}
#[cfg(feature = "90s")]
pub(crate) fn prf(out: &mut[u8], outbytes: usize, key: &[u8], nonce: u8)
{
aes256ctr_prf(out, outbytes, &key, nonce);
// TODO: Add feature to use RustCrypto AES_CTR
// implementation with no lookup tables
// Perhaps add an option for ring also.
// Working RustCrypto code:
// if cfg!(feature = "rustcrypto-aes") {
// let mut expnonce = [0u8; 16];
// expnonce[0] = nonce;
// let key = GenericArray::from_slice(key);
// let iv = GenericArray::from_slice(&expnonce);
// let mut cipher = Aes256Ctr::new(&key, &iv);
// cipher.apply_keystream(out);
// }
}
#[cfg(not(feature = "90s"))]
pub(crate) fn kdf(out: &mut[u8], input: &[u8], inlen: usize)
{
shake256(out, KYBER_SSBYTES, input, inlen);
}
#[cfg(feature = "90s")]
pub(crate) fn kdf(out: &mut[u8], input: &[u8], inlen: usize)
{
let mut hasher = Sha256::new();
hasher.update(&input[..inlen]);
let digest = hasher.finalize();
out[..digest.len()].copy_from_slice(&digest);
}
// Name: kyber_shake128_absorb
//
// Description: Absorb step of the SHAKE128 specialized for the Kyber context.
//
// Arguments: - u64 *s: (uninitialized) output Keccak state
// - const [u8] input: KYBER_SYMBYTES input to be absorbed into s
// - u8 x additional byte of input
// - u8 y additional byte of input
#[cfg(not(feature = "90s"))]
fn kyber_shake128_absorb(
s: &mut KeccakState,
input: &[u8],
x: u8,
y: u8
)
{
let mut extseed = [0u8; KYBER_SYMBYTES + 2];
extseed[..KYBER_SYMBYTES].copy_from_slice(input);
extseed[KYBER_SYMBYTES] = x;
extseed[KYBER_SYMBYTES+1] = y;
shake128_absorb_once(s, &extseed, KYBER_SYMBYTES + 2);
}
// Name: kyber_shake128_squeezeblocks
//
// Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of SHAKE128_RATE bytes each.
// Modifies the state. Can be called multiple times to keep squeezing,
// i.e., is incremental.
//
// Arguments: - [u8] output: output blocks
// - u64 nblocks: number of blocks to be squeezed (written to output)
// - keccak_state *s: in/output Keccak state
#[cfg(not(feature = "90s"))]
fn kyber_shake128_squeezeblocks(
output: &mut[u8],
nblocks: usize,
s: &mut KeccakState
)
{
shake128_squeezeblocks(output, nblocks, s);
}
// Name: shake256_prf
//
// Description: Usage of SHAKE256 as a PRF, concatenates secret and public input
// and then generates outlen bytes of SHAKE256 output
//
// Arguments: - [u8] output: output
// - u64 outlen: number of requested output bytes
// - const [u8] key: the key (of length KYBER_SYMBYTES)
// - const [u8] nonce: single-byte nonce (public PRF input)
#[cfg(not(feature = "90s"))]
fn shake256_prf(output: &mut[u8], outlen: usize, key: &[u8], nonce: u8)
{
let mut extkey = [0u8; KYBER_SYMBYTES+1];
extkey[..KYBER_SYMBYTES].copy_from_slice(key);
extkey[KYBER_SYMBYTES] = nonce;
shake256(output, outlen, &extkey, KYBER_SYMBYTES + 1);
}

95
third_party/kyber/src/wasm.rs vendored Normal file
View file

@ -0,0 +1,95 @@
use super::*;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn keypair() -> Keys {
let mut pk = [0u8; KYBER_PUBLICKEYBYTES];
let mut sk = [0u8; KYBER_SECRETKEYBYTES];
kem::crypto_kem_keypair(&mut pk, &mut sk, None);
Keys{
pubkey: Box::new(pk),
secret: Box::new(sk),
..Default::default()
}
}
#[wasm_bindgen]
pub fn encapsulate(pk: Box<[u8]>) -> Result<Keys, JsValue> {
if pk.len() != KYBER_PUBLICKEYBYTES {
return Err(JsValue::null())
}
let mut ct = [0u8; KYBER_CIPHERTEXTBYTES];
let mut ss = [0u8; KYBER_SSBYTES];
kem::crypto_kem_enc(&mut ct, &mut ss, &pk, None);
Ok(Keys{
ciphertext: Box::new(ct),
shared_secret: Box::new(ss),
..Default::default()
})
}
#[wasm_bindgen]
pub fn decapsulate(ct: Box<[u8]>, sk: Box<[u8]>) -> Result<Keys, JsValue> {
let mut ss = [0u8; KYBER_SSBYTES];
match kem::crypto_kem_dec(&mut ss, &ct, &sk) {
Ok(_) => Ok(Keys {shared_secret: Box::new(ss), ..Default::default()}),
Err(_) => Err(JsValue::null())
}
}
#[wasm_bindgen]
#[derive(Default, Clone, Debug)]
pub struct Keys{
pubkey: Box<[u8]>,
secret: Box<[u8]>,
ciphertext: Box<[u8]>,
shared_secret: Box<[u8]>,
}
#[wasm_bindgen]
impl Keys {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
Keys::default()
}
#[wasm_bindgen(getter)]
pub fn pubkey(&self) -> Box<[u8]> {
self.pubkey.clone()
}
#[wasm_bindgen(getter)]
pub fn secret(&self) -> Box<[u8]> {
self.secret.clone()
}
#[wasm_bindgen(getter)]
pub fn ciphertext(&self) -> Box<[u8]> {
self.ciphertext.clone()
}
#[wasm_bindgen(getter)]
pub fn shared_secret(&self) -> Box<[u8]> {
self.shared_secret.clone()
}
#[wasm_bindgen(setter)]
pub fn set_pubkey(&mut self, pubkey: Box<[u8]>) {
self.pubkey = pubkey;
}
#[wasm_bindgen(setter)]
pub fn set_secret(&mut self, secret: Box<[u8]>) {
self.secret = secret;
}
#[wasm_bindgen(setter)]
pub fn set_ciphertext(&mut self, ciphertext: Box<[u8]>) {
self.ciphertext = ciphertext;
}
#[wasm_bindgen(setter)]
pub fn set_shared_secret(&mut self, shared_secret: Box<[u8]>) {
self.shared_secret = shared_secret;
}
}

View file

@ -0,0 +1,6 @@
6730bb552c22d9d2176ffb5568e48eb30952cf1f065073ec5f9724f6a3c6ea85 tvecs512
2ea81fa2d7e3c1970409b9d77d6c5137aeb4573e856ca79eab4393b70352e85b tvecs512-90s
667c8ca2ca93729c0df6ff24588460bad1bbdbfb64ece0fe8563852a7ff348c6 tvecs768
a1b8fe37e3fc58a8511c63a7187d3626a1a98c5d3bb67000fe9a02be7199d952 tvecs768-90s
ff1a854b9b6761a70c65ccae85246fe0596a949e72eae0866a8a2a2d4ea54b10 tvecs1024
f547f5361f933e6489d2385524ffd36893063c6b9cc3f921514b4ebb9daefdaa tvecs1024-90s

View file

@ -0,0 +1,42 @@
#!/bin/env bash
set -e
current_dir="${PWD##*/}"
if [ $current_dir != "KATs" ];
then
echo "Script needs to be run from inside the KATs folder";
echo "Current working directory: "$current_dir
exit;
fi;
git clone https://github.com/pq-crystals/kyber.git;
cd kyber/ref;
make all;
# Create vectors for each security level and mode
for tvec in test_vectors*[^.c];
do
sub_str=${tvec/est_/};
./$tvec > ${sub_str/tor/};
done;
echo 'Moving Files...'
# Move test vectors and sha256sums into the PQC-Kyber KATs folder
mv tvecs* ../..
cd ../..
echo 'Calculating SHA256 digests...'
# SHA256SUMS
for tvec in tvecs{5,7,1}*;
do
shasum -a 256 $tvec >> SHA256SUMS;
done;
# Confirm SHA256SUMS match rust repo KAT's
# Please submit a github issue if upstream tests vectors have changed
echo "Checking SHA256SUMS of test vectors built match those used in the test suite..."
diff -s SHA256SUMS_ORIG SHA256SUMS

48
third_party/kyber/tests/KATs/readme.md vendored Normal file
View file

@ -0,0 +1,48 @@
# Known Answer Tests
The test vectors need to be generated locally. Running [build_kats.sh](./build_kats.sh) will automate the process, otherwise follow the instructions below to clone the C reference repo, compile the test binaries, then generate and rename the files.
This results in 6 files, each containing 10000 KATs, total size is ~600MB:
* tvecs512
* tvecs512-90s
* tvecs768
* tvecs768-90s
* tvecs1024
* tvecs1024-90s
These need to be then moved into the `tests/KATs` folder. The `SHA256SUMS_ORIG` file contains
the digests this library was tested against.
C Reference Repo: https://github.com/pq-crystals/kyber
## Generating test vectors
```bash
git clone https://github.com/pq-crystals/kyber.git;
cd kyber/ref;
make all;
# Write binary output to file for each security level and mode
# Rename to match C repo sums
for tvec in test_vectors*[^.c];
do
sub_str=${tvec/est_/};
./$tvec > ${sub_str/tor/};
done;
# Move test vectors and sha256sums into the PQC-Kyber KATs folder
mv tvecs* <Project Root>/tests/KATs
# SHA256SUMS
for tvec in tvecs{5,7,1}*;
do
sha256sum $tvec >> SHA256SUMS;
done;
# Confirm SHA256SUMS match rust repo KAT's
# Please submit a github issue if upstream test vectors have changed
diff SHA256SUMS_ORIG SHA256SUMS
```

75
third_party/kyber/tests/kat.rs vendored Normal file
View file

@ -0,0 +1,75 @@
#![cfg(feature="KATs")]
mod load;
use pqc_kyber::*;
use load::*;
// Generate KAT keypairs from seeds.
#[test]
fn keypairs() {
let kats = build_kats();
let mut _rng = rand::thread_rng(); // placeholder
for kat in kats {
let known_pk = decode_hex(&kat.pk);
let known_sk = decode_hex(&kat.sk);
let buf1 = decode_hex(&kat.keygen_buffer1);
let buf2 = decode_hex(&kat.keygen_buffer2);
let bufs = Some((&buf1[..], &buf2[..]));
let mut pk = [0u8; KYBER_PUBLICKEYBYTES];
let mut sk = [0u8; KYBER_SECRETKEYBYTES];
crypto_kem_keypair(&mut pk, &mut sk, &mut _rng, bufs);
assert_eq!(&pk[..], &known_pk[..], "Public key KAT mismatch");
assert_eq!(&sk[..], &known_sk[..], "Secret key KAT mismatch");
}
}
// Encapsulating KAT's using deterministic rand buffers
#[test]
fn encaps() {
let kats = build_kats();
let mut _rng = rand::thread_rng(); // placeholder
for kat in kats {
let known_ss = decode_hex(&kat.ss);
let pk = decode_hex(&kat.pk);
let buf1 = decode_hex(&kat.encap_buffer);
let encap_buf = Some(&buf1[..]);
let mut ct = [0u8; KYBER_CIPHERTEXTBYTES];
let mut ss = [0u8; KYBER_SSBYTES];
crypto_kem_enc(&mut ct, &mut ss, &pk, &mut _rng, encap_buf);
assert_eq!(&ss[..], &known_ss[..], "Shared secret KAT mismatch");
}
}
// Decapsulating KAT's
#[test]
fn decaps() {
let kats = build_kats();
for kat in kats {
let sk = decode_hex(&kat.sk);
let ct = decode_hex(&kat.ct);
let known_ss = decode_hex(&kat.ss);
let decap_result = decapsulate(&ct, &sk);
assert!(decap_result.is_ok(), "KEM decapsulation failure");
assert_eq!(&decap_result.unwrap()[..], &known_ss[..], "Shared secret KAT doesn't match")
}
}
// Helper functions
// Encodes byte slice into a hex string
pub fn encode_hex(bytes: &[u8]) -> String {
let mut output = String::new();
for b in bytes {
output.push_str(&format!("{:02X}", b));
}
output
}
// Decodes hex string into a vector of bytes
pub fn decode_hex(s: &str) -> Vec<u8> {
(0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16).expect("Hex string decoding"))
.collect::<Vec<u8>>()
}

12
third_party/kyber/tests/kem.rs vendored Normal file
View file

@ -0,0 +1,12 @@
#![cfg(not(feature="KATs"))]
use pqc_kyber::*;
#[test]
fn keypair_encap_decap_kem() {
let mut rng = rand::thread_rng();
let keys = keypair(&mut rng);
let (ct, ss1) = encapsulate(&keys.public, &mut rng).unwrap();
let ss2 = decapsulate(&ct, &keys.secret).unwrap();
assert_eq!(ss1, ss2);
}

28
third_party/kyber/tests/kex.rs vendored Normal file
View file

@ -0,0 +1,28 @@
#![cfg(not(feature="KATs"))]
use pqc_kyber::*;
// Kyber struct uake and ake functions
#[test]
fn kyber_uake() {
let mut rng = rand::thread_rng();
let mut alice = Uake::new();
let mut bob = Uake::new();
let bob_keys = keypair(&mut rng);
let client_init = alice.client_init(&bob_keys.public, &mut rng);
let server_send = bob.server_receive(client_init, &bob_keys.secret, &mut rng).unwrap();
let _client_confirm = alice.client_confirm(server_send).unwrap();
assert_eq!(alice.shared_secret, bob.shared_secret);
}
#[test]
fn kyber_ake() {
let mut rng = rand::thread_rng();
let mut alice = Ake::new();
let mut bob = Ake::new();
let alice_keys = keypair(&mut rng);
let bob_keys = keypair(&mut rng);
let client_init = alice.client_init(&bob_keys.public, &mut rng);
let server_send = bob.server_receive(client_init, &alice_keys.public, &bob_keys.secret, &mut rng).unwrap();
let _client_confirm = alice.client_confirm(server_send, &alice_keys.secret).unwrap();
assert_eq!(alice.shared_secret, bob.shared_secret);
}

100
third_party/kyber/tests/load/mod.rs vendored Normal file
View file

@ -0,0 +1,100 @@
use std::fs::File;
use std::path::PathBuf;
use std::io::{prelude::*, BufReader};
use pqc_kyber::{KYBER_K, KYBER_90S};
// Known Answer Tests
#[derive(Debug)]
pub struct Kat {
// Deterministic RNG buffers
pub keygen_buffer1: String,
pub keygen_buffer2: String,
pub encap_buffer: String,
// Keys, Ciphertext and Shared Secret
pub pk: String,
pub sk: String,
pub ct: String,
pub ss: String
}
// Converts string octuples from tvec files into Kat structs
impl From<&[String]> for Kat {
fn from(kat: &[String]) -> Self {
// Extract values from key:value lines
let values: Vec<String> = kat.iter()
.map(
|katline| {
let val: Vec<&str> = katline.split(": ").collect();
if val.len() > 1 {
val[1].into()
} else {
val[0].into()
}
}
)
.collect();
// Build KAT from values
Kat {
keygen_buffer1: values[0].clone(),
keygen_buffer2: values[1].clone(),
pk: values[2].clone(),
sk: values[3].clone(),
encap_buffer: values[4].clone(),
ct: values[5].clone(),
ss: values[6].clone(),
}
}
}
// Get KAT filename based on security level and if 90s mode
fn get_filename() -> String {
let mut filename = match KYBER_K {
2 => "tvecs512".to_string(),
3 => "tvecs768".to_string(),
4 => "tvecs1024".to_string(),
_ => panic!("No security level set")
};
if KYBER_90S {
filename.push_str("-90s");
}
println!("Using KAT file: {}", &filename);
filename
}
// Base dir
fn get_test_dir() -> PathBuf {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.extend(&["tests"]);
path
}
// KATs path
fn get_kat_filepath() -> PathBuf {
let mut path = get_test_dir();
path.extend(&["KATs"]);
path.extend(&[get_filename()]);
path
}
fn load_file(filepath: PathBuf) -> File {
File::open(filepath).expect("Error loading KAT file")
}
fn parse_kats() -> Vec<String> {
let file = load_file(get_kat_filepath());
let buf = BufReader::new(file);
buf.lines()
.map(|l| l.expect("Unable to parse line"))
.collect()
}
// Packs chunks of lines into Kat structs
pub fn build_kats() -> Vec<Kat> {
let lines = parse_kats();
let kats = lines.chunks_exact(8);
// Map String slices into Vec<KAT>
kats.map(
|c| {c.into()}
)
.collect::<Vec<Kat>>()
}

View file

@ -0,0 +1,14 @@
CC=/usr/bin/gcc
LDFLAGS=-lcrypto
SOURCES= rng.c generate_bufs.c
HEADERS= rng.h
generate: $(HEADERS) $(SOURCES)
$(CC) -g -o $@ $(SOURCES) $(LDFLAGS)
.PHONY: clean
clean:
-rm generate

View file

@ -0,0 +1,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "rng.h"
#define SUCCESS 0
#define FILE_OPEN_ERROR -1
#define KYBER_SYMBYTES 32
void fprintBstr(FILE *fp, unsigned char *A, unsigned long L)
{
unsigned long i;
for ( i=0; i<L; i++ )
fprintf(fp, "%02X", A[i]);
fprintf(fp, "\n");
}
int main()
{
unsigned char seed[48];
unsigned char seeds[100][48];
unsigned char entropy_input[48];
unsigned char ckk[32], indcpa[32], enc[32];
FILE *fp_ckk, *fp_indcpa, *fp_enc;
char fn_ckk[32], fn_indcpa[32], fn_enc[32];
// Create the crypto_kem_keypair file
sprintf(fn_ckk, "crypto_kem_keypair");
if ( (fp_ckk = fopen(fn_ckk, "w")) == NULL ) {
printf("Couldn't open <%s> for write\n", fn_ckk);
return FILE_OPEN_ERROR;
}
// Create the indcpa_keypair file
sprintf(fn_indcpa, "indcpa_keypair");
if ( (fp_indcpa = fopen(fn_indcpa, "w")) == NULL ) {
printf("Couldn't open <%s> for write\n", fn_indcpa);
return FILE_OPEN_ERROR;
}
// Create the encode file
sprintf(fn_enc, "encode");
if ( (fp_enc = fopen(fn_enc, "w")) == NULL ) {
printf("Couldn't open <%s> for write\n", fn_enc);
return FILE_OPEN_ERROR;
}
// 1 .. 48 initial seed
for (int i=0; i<48; i++)
entropy_input[i] = i;
// initialise
randombytes_init(entropy_input, NULL, 256);
for (int i=0; i<100; i++) {
randombytes(seed, 48);
for (int j=0;j<48;j++)
seeds[i][j] = seed[j];
}
for (int i=0; i<100; i++) {
randombytes_init(seeds[i], NULL, 256);
randombytes(indcpa, KYBER_SYMBYTES);
randombytes(ckk, KYBER_SYMBYTES);
randombytes(enc, KYBER_SYMBYTES);
fprintBstr(fp_indcpa, indcpa, KYBER_SYMBYTES);
fprintBstr(fp_ckk, ckk, KYBER_SYMBYTES);
fprintBstr(fp_enc, enc, KYBER_SYMBYTES);
}
fclose(fp_indcpa);
fclose(fp_ckk);
fclose(fp_enc);
return SUCCESS;
}

View file

@ -0,0 +1,100 @@
8626ED79D451140800E03B59B956F8210E556067407D13DC90FA9E8B872BFB8F
003271531CF27285B8721ED5CB46853043B346A66CBA6CF765F1B0EAA40BF672
E82FCC97CA60CCB27BF6938C975658AEB8B4D37CFFBDE25D97E561F36C219ADE
DE950541FD53A8A47AAA8CDFE80D928262A5EF7F8129EC3EF92F78D7CC32EF60
BE2D3C64D38269A1EE8660B9A2BEAEB9F5AC022E8F0A357FEEBFD13B06813854
A08CCF451B049FD51D7A9AD77AE14A81569DF8C9BD3A8F1EBEA86FDCFB823082
84EF52DB5EAA6DF8EC3A0BC5FFA730DB0DDE8C5F38F266D5C680A78D264A7B96
99DAF37400CFE59841AFC412EC97F2929DC84A6F3C36F378EE84CE3E46CD1209
DA1804DDB5AA9B1C6A47A98F8505A49BAE2AFFDE5FE75E69E828E546A6771004
56047447B810CC094D400AB204CF9AE71E3AFA68B88586ECB6498C68AC0E51B9
8D6C42E7270EE2B77B6045385F3D175984A0E260363166C73B0C70C971644363
812083BFA3B670E3EAF9B443702FB6DB16AC1197656BBD61A8E25ED523B8D1E5
8E9A30597E4B52FFA87A54B83C91D12A5E9C2CD90FCAC2C11B3A348240411A4C
8AEC87A9A79204CEE2986867A2906EB851B734B8B22B91D6749B1A5F07C44E3B
A2ACF359556DF4A2ABAEB9DCEE945829BEB71185B4D6BD18B76E5668F253383A
DF05318B5F655EFE36F1B678CF4B875108A18DB2FA312261CAF839F84BD956C5
DF7D92DDA83E6B2EF4CCE08C9134563063068A196D7B1A1A13623E48AE12528E
0F6AA3E88F7FA8A96067F8CDAECEEAC90C2D0B5E277E56E9C405EC9420C30252
4F3029E1BE4E1C0258C3A22FF5B50B2674CC094BA7018DA2A61569845C17D26F
1C0EC046899A777655233E4E1B5CA44E9AFBDC67964BFD5D5E3DBB45E60D03CF
6590A2E5C7ED86CF2C5C2A898662BC9A81418720BBB632EF9CF0B845ED052D73
B6591121E25D64010C25A18676033E1D7278AC5F2D0B43A31F3A4156AE710465
76EAE84D11C4528382828F7A689A0D5CFF87B8CA0BBA97FEACB39B935A8788CB
FC9EBBE336DC464489861DB8253606971BD0A9008A433ED17752D04023781552
FF8563038AAD865A817CAB9CE98846BA75BE9363718ECF5FEA538AEA90B2A558
E1FB7456AC0AA1B97068F452CBA64EBDC138BCF5D36B0A0FADA2A3B374141EB9
9DA0C5DA5F195B80FBB99C2E8B06926074F3F604B3F6195B5A5B9737876BBA72
71600A8982C350DF524CDE514431DED7AEC23576530894BCBF0EC0BFEF0BB64F
0E145E44AAE52CFC609E6F47FD7A6F6AF877190FF52256D0AC5B05B89C3F449F
50A7A2354F7E5CEFA6F4A4E9A1C411EB9364506E9E1204A8ACB3CB77FBD2C4ED
F072D9B5A99F9C7A0A011E4DC10F6B600D611F40BBA75071E7BEE61D23FD5EDA
5A4D0A8A41C4F666854E9B13673071CEB2FD61DEF9A850C211E7C50071B1DDAD
36B817736CBC5F7B1DD6EEF5FE6332FB1A598F3871E5470D440FD2EA631DA28A
75D12195EC32A8686D0600E45D4A7F54219B0D7A3826D193A51B9156ECF2EDD6
248C0A21EA0BB6D6F56F12300E8584D8E9A34E0E6F52227281151AE4C305FB8F
1646460817A0FCE5836BDFE124A7448E7ADF7B8ECC2652AC6D280E986682DF71
79238A80DCFD7C992D84B2DFFA67493E669243D4FA38C46B090BDF86BC548411
1F135CF64B6403E103AFAE34DA038613E2853BBFC36BAAFA3C6A95347193F37C
62D7033947AE42CA53522A65FBAFE18D3BC3E0CB66164E9A094FE4B44D8977ED
01C8E376FDB140EE343106C093AF7CB149B316BA79446CEB4E5E0CEDB9B164F9
0E860576285483BB5FD36E2F944D32C4317BEBC1E441470C1372046A790D79D4
F89D7D99D5C3E0D10D6EF9AF054D842375F695ABB28E3B8EB495100F04306E92
CD292E4C5F9E1A55E0489BCEFFB204D672A6215F4F3980A646D9F880817C52DD
8C64C049C6DFC0F1476CFFD520B055756162F7EC94243DE6B14AC0B9E5FB366C
E40771856EB77E4633504899FCB86C6A3D433D0B8D60E26F07BD61F1D4ED69BD
DED5EDAEC5DE3BF5B4D7C2F2E18E87F499C1968993EFF196753DB8045E2C8BA8
1C96249919CEDC2369D8D739AB125E0D2CCB82DFEBCD90240A545CDFE07511F2
BDC370460375A778D1A31D01C42B66367ED8D9E8F84551002F552F0E52102B5D
FD5A08F656A6EB8CD20679930A31CAA6A6331C4B133A6838C223EF9F769F6246
20A7237801F470FCC2BD9FD7BEA8322859B850F7882D362947432913DD068C01
7B534537ADDABA4ECF14F02AB317D36CB9F0F50222CED7CF029DFF8A0D3D2FD9
F48A9254DD40B117941FA35A66BB50296327B725525DEEF70E128CA8045EC451
E6C45C7FC62329B13C8D29844405DB8FF6860DE474BF727ECD19E54E6E1A141B
5A3407F591791A5DB4578B5972093A95BEC3B8E70C1D542C9B5C9789729F8922
B9402BF02481CE4B27A52E87FEB92C4399C7F2988D40E942E7496AD15AD2AA88
24C3DA70FE850E80AA818301D60C70F3038153866DCD5D179E22DB59B8991BB4
3AFDB8A246A56EE71465591831C371F2EB87467B0559DEDD776BA063EE6D2F93
230E05B7114FF0395CC6634DB1EAE8258072D09C09F291E92D6620B177DC50D7
1100CED48ADD211A5C937B8D6079D8E271AF3F949EDC61F70E60453AEF20DEA9
7A3CC8AA3239D4C52CE4C95AFDEFF6EFBFACAC10D294EDC0E7CF4535059BFDBA
8F1481D7CAB000E33FA07DE8DC9627A85E76FABB4428A3376E66300CF12A0787
E2F8D320AC3CB0C52EFDC753282F092BC39BAF4A18783A48EA031A191865EB78
393308641A9A4647F230201E1389624A296B55192A9819FCB19AB77C25F95445
EAC9D531A532770837A854B4F5531F6E0C8D6C10183B30D3435498C2DD142951
3FC3D8392CB53F36ED647364A04E37278A0E0A45B720F4A75C580C9920EBA98D
D7E4B5D8021C486B9C3114D7CBBEB7CD49EBA8A61BC2BCAE1F1BEF30A1DAF76D
B2DCA81E3F5F748D23C9D356A2209F6B2D60247B2E45C9808DE497F64F124643
ABA5068AF837BE962F439F233593D193CE5E08F7D66EFB3389885927B89D2523
0F4DFF8E56F68440836A072412A30D851ACE2C7C6F02D60E7A8420001A63E6C6
B28F7E7A15A005F92400CE33DB073D49B53871594A88FC45E0F94207B5F0F2DC
D8128601C28B1DEF8D393A0DB283229F7C7383152A814E7CEFE8EF9D9768C473
B6D75EAC6C76CED1B0A025B40A55440712AD8424672E761E9BC400D63812006F
273B38BDDC18488024EC90E62A4110129A42A16D2A93C45439888E76008604C6
A3729672816F3EBA84C9638A79676EEAC0F22C8A48E0C5D50A26FF0844C66B99
E03FF73E02A217659F53D8C47556BF3D8C94040F630D63605E2D0F923579370C
9F684FB055ECE19459EB464E91E126A7A6E3ED11CCEE0046DA234D964C985110
F03A8ABB0A5010F400AE5722A75BDF5A2F6D5B546B34D73857CB1BFC7E587AA7
A59B3BD23B49A95BC1FAD20070FEC930B6060BD827D742B077092E422268E15D
E99C0E7B82BE89BC3C1EAEE6680AA4EFD394E40C2B3F30523C8117F7C26A8969
9C35D165453E5FCDC6F9DF64526D9DE698F2BD3E6BAC6C7FDD86601B9BA5F4A5
5FE6141A25F7AB9F875F79E0A82D6EA5CDE5A017AB637D5FDB7C42646A1D71DF
11EAFECA9E810796C34E8CFCE9D59342884456007B01DDD12EDCE6D10ED87E4C
11136E2681DF2EF881B51A092A9BADBE72C9772C169808521C47149578621E28
6CEB14F7662BE0C42779459F69A145C0E2CE9F0BD9A0CD1BF32ED5694CC9AE32
FAEB2EF44D2F608621E831187CE79B2D2F4A20F1568BBE76B0D3D5AF36111714
A2985C1C4D203778597947D710DEC806E36B0CD949FE460EF141213BFC525E5B
CE7683F8A03D3CF04E46970FF7D6A12494AE12558346DFC8FD9370BF944A0102
7F7054814869CF7625E45647BC1547AFF288DBB90699B2AD84893F3B755D9722
D82C2F1BF2E6AEBDE5660FA73356982E12999D8FDAFBB3CB186341D0386DEAD0
8B2809FD40008BE70A6B184981101724BC3D5EC5E1956B510B82FD5AD0668A5A
C95FA08ED106CE84660E8A4C90BD2B22634E40769AA0090A101C5DDDAD45EDC5
E15274A8E2BC08FE818B117BA28C5DFAE74D54FCDF6F20052F79BE333EDC8DDE
81C38C2CB5CFAFAC81B96A810AB749B61806B6D54C9F8CF4BF1BE0192423288F
C06C5BEF7B6508409DAF847A64C8D30D0974FD3BA7476DC76C46B458A036D884
4F797C007E4061F95C7D56CFC7EE5C49E849DDE3FEA8F25E7876DF2A18515C34
E32D432B4F9F751BDE0496C580A181FFED762AA35454A02D3F1F47EE0394C89C
5AEDA108EA4D6C6BC0FB958286850422BC357CA67B83C986048E0D0087FA11EC
E63F8FFDA3565C2424C89B20974B748A65A5ABA75133FCB3156DFB6626A83BAB
FDA268813EFAB5204EFA60F78BF81D320D01AC09AC06244F7AFBD2D80FD356D9
AE77E0F9F21EABD8C0C6EEA7767F4E10FDE5C2D79B8400BF96B19014B457EC21

View file

@ -0,0 +1,100 @@
147C03F7A5BEBBA406C8FAE1874D7F13C80EFE79A3A9A874CC09FE76F6997615
CDE797DF8CE67231F6C5D15811843E01EB2AB84C7490931240822ADBDDD72046
F43F68FBD694F0A6D307297110ECD4739876489FDF07EB9B03364E2ED0FF96E9
EA74FBC3C546500ED684BED6FE3C496D3B86D2D6DFAF223969B942E9A8C95E85
64EFA87A12CB96F98B9B81A7E5128A959C74E5332AAAB0444FCA7B4A5E5E0216
8A95D71228ACAA5F9AE6F9D9CA8AE55FDE296463B41083A39E833E37C4C90F88
90D79D75D0BBB8921CF70D46BAB497022A8E750EFDC99E5F1BAE653275441C7B
BE8A32F97B9A8D596382C02FA2A0EEEBC15C083E970DDAA4F2622B91D6718663
DA2CFAF69E25B2A89FF2557BBB6F69E01D8E2E7BB27A7A1CE7E40FEAD16F33B2
511C2AB40782322C06111E144E505328C4E5BFC890A5980A2BBC44AEDA4C738B
DCA92DBEC9B260DD97E8886F876862D6EFFC3B91FCF3FBC986CF56AB93AE79A2
57C170E691D7A914A901B9A11C62B8B569B3806427557A9DBAC9FAA720EC3641
6B5A14E1473ABF5A33D44975CA2088BD8FA6FDDCB3F80E8FD5C45B9D90C24A5C
40E593754E6EDDB7F9CF176BA2D5FD1087C90AD377556D0B0F686537B1A3165E
C152523ABD8248BED40C3827BCF0F8E8127037A55C780695E2C28EA3E041A44C
AD6466DD59F26B762FB02B19EEDF5F79964DA68BCE0459B91C3A6EE5A7E01183
1A4D5DFF5847CFB48333E33BB00CA7301B144AA89DCD412FF5A3B1081D775B7F
34F44EC2092EEAF686F2EA170591A98527CBB03A4FA9477A7AEF6B41A54FEEB2
6250C81126572EEC2DA330271DB36EE591F060FC7E53EEEFE2E1C476C675FA33
35D470BCC5880872754810DFB3F2796DA2FD7F397537146F6488C27804072B34
8D667921C5DB401A86FE1C35DFCF164A6BB2AB7400FD6A0B67EAFD4A0ED11940
EC750B3939385A3F8DF868119DC76F77CA845567EF068DE6ADA5478A56BC78B6
74F1D52AF09B12C36EB062EA7528550CB4C18A3CE8E4F4EA9FAC43AE383BC925
4B3A70D85F640D1A2A852FB6FE96704AF56A7415A8EE4282E9207BC3A2DC116A
26E38AC804FB5B4D59DDF747715E7E6041D875F99C7B638024B4AF82D622DA60
A319D2B8F114F1ACD866478BCDEBA6FD164DC4E37B0ADFA8D8034AFB3E197376
FF646071B2509E6B75790917E08E4F0B0D9F0116EC6291C0B59EAA4B583AD830
0584270EC26F3B9818E4AF074D17B2D51037CC8DFDCBE3B140FA4FED5DEEBC54
51E05C7B4CA3079781E8293F4ECCEBEEB2F8C8B4C59468EDDB62A21BCB4AB8A3
9ECA0FE36C80FC5EBA171C3AE66A5B1C923FAA50B4521BB055E7BF51005C93DF
0C5719261CAAB51AE66B8C32E21C34E6D86EE4AA127D1B0195663C066497B2E9
0E59F6F9047C784C1F00B24454AA4F1BD32C92AE7E626549972F86FAB90E7E89
A3963ADE17D69DEBBC358DDA82C7BEBE2C39D25B36813058E7A161542E3F8C2B
97BEAFABF2C8575586487C7A80E8AF5FC50F94B6051C1BC66A5AE9F66BE3CEA7
75461DECD34C50D6A094B4A64FB75E5E9479F8F9250D82BB7D729DEDEB2D4B65
2607DCF4FD6CA1C614C21B5E37C24981C32B91C8C3E6955777DA8A3F5D9C9335
38C89BBE7145C29E9A831C11431EB9929CB24FB4992DB20737E4687D397FD732
B2C35E33C72D90182791F0E12A0324F5B216EFCAB2C8DA1BEE025DFBE13F4152
AFB7D6DC2B7EB6D84ACC080C1BE63C98AFE7B07786B5801F716444A3E8E64800
28F5E9DBDA122B2CF8F3754FE9E0C73A84AD4B0C093522E0B62CF815D60BBC3C
B0D713CBEF0BB1DF70CBB425D1E9373E9F7790FDC7980CC96A240DFC53F1E8E2
32BDCDB7059FE27F6409901980C080308951FFD90DEFFA8317B4D213A5F04495
4ED7C92D83BD03B2A25B567F17AE55542E2F6A4308EC0F3FE69F8BA5AE24331B
060EA5D2ED1DD88144A9885E79278590821C22917B55A48920F96B53EBE0E689
10EF9426F8C4A13B52325C5BB4EAD4596ECF2C6B5BD2D37D8350E90D4164FDD9
A4BD30A64CBF29A4E290FA1CC1DFB99E68348713041E4409A1AF23C5D80C15C4
F4B66A7D3B65B896DFE100B2CAD24B175A1168CFD2AE11FD704B835F6BCD311A
1D7B03D3C5EEFB8AE5799DC569AA668F1BCB8C86607B089D3530CF61D6380147
554F3385B382F4A46314DE37EE3885ADDFC5332BD4038785094E0A832E9E8C2C
38BF0033B779EDF5367D9EBC01C988AF90904C560970815837380650E4749EEA
048EA516D0EBBD9F709B47EAAC66F344C571CF50F0D01C9466AA061A50B66A24
686C921C9DB1263E78AE753B1C9C2E7936B8229DCA48C0942C56C6BCA4F10917
2387772E50059CABDA53CB93BA24B19AE529496C03B36584169451525C4A0E7E
155C29C5F0378DF0CD0E847A80A07143CF7522FCD880C9229EB9FEB1CE340CD2
A9CB9A61A3324B1EA5AFE693B32784E2871096B2CA14A11ACC9577C52359A241
E99FBAE8A024EBBBDCEF32CE213F6AA942E3ECA925E5DA4C09975D773B33A175
67A216F37D67F5E74F782F1BADBCE1CC8C80A6130AEC305B421899A4FAA0A6C3
52B19FEA232C9154A3E431E9D69CDA40013CF2D485C3CD027AD24E645420420B
64440ADB05DB3308B189BF999F9EE16E8EE3A6CCBE11EEBF0D3AE4B172DA7D2F
C8BB46B3A7344AD170C2052FB042B5A3B62E0590562EE82577B1081F6F114D16
2E2B70609F3FE029A14D09D5D659871AC776CE2797A0355F16E2EB68F5613FD1
4725DD8FB314BFD8EE23731C2341DBE114606D9ABE6434C471B5573E7DF193BB
818D3BB8EBFB32BF464775F7139BAC0A5BDDCE80EC5798595992F9403002CD5D
C92AA5FB91C980D9CADE9CE99D4C75B2FFA7D6A6FF9BD59DEF1AA701F2A0992B
7E8086A01DC5B3BB9EDA25BCC45D27F99874841B97237968495800E007696AC5
BB321EF14D44D8698DF879FD52450567657F52A2DF8D111185DCD7D4F30A72D4
210A423DADD899B810F011794B79AA7F860823AC1962370E791287D3A1AFA384
BC856AFE24213E3D14C3D6F9B89223BBCFB2C890722D770FA3492C1E46D1C302
5FC00F89563E44B24CD67D0CE684EFFE5731619FD08E7D72E2406EB016AFB66B
EA22A76065DB4B565EE1807FBD813B43BDE72B0E08407FB867C6A18995025E50
E9602B34FE73AD57F4BF6EAD99743D645641553A5B9B9BF2E7016629E3E9BD76
F72B9080A6C051BBDB9B0ABC1949034BE0F89A9F73FE277EC4D4740C78D04A83
F1E5542190DB8ECF4B8D617A04FD3783AD0DF78BF8DAB749AFB57DB8321D151B
74EFA414AE171BF60B6F884CB7E5CE12028F49365DACCFA23E845D551711660B
0B4C3CFFB2BA4380EAD13DC0D8ACAD2356B448A810DA1DF29F264C44AAB6D24F
1C82471DCDFCA3A6942061AB4F3D5BF0D197321437C706D9CCCCCCE449447002
46FE60A18124125AB93E0C578F1C02F1BD1301595013001C7F3C2FA56CDE294E
52FB7CB6A633FD2E83F2892BD9441B48FE59ECEE6D026F5246FA7F2A5E55EE3B
0F81A5F97082121244403DA3FEEB734F6084B314B8D94BEB11627AA6AD1914E9
31AF9345365549EA0360169ED57DAF98CC5444799D4C75D9F1F5D615E9DF8A91
774AE54093D694EF40B63B62C73E6C98295F606FEB8699807EDA1D030FFB996D
9F27A47604AB5146CAAF0AAFE6D149424F8D66E39BA3BAF5E6C73B19221B7E21
90044031B7597B5E60A4F946B713E8996D0426D2CB013243D9B7D8F8EF159A0F
A7A31E140891EA37D2B6424B59B1F84F89220F32DCB73E037EB912B389D34A48
70EB3F791FAA91F1F982FA477DBCDDEB2C55691C07F93B04CD31B37544C94B42
30F4095015BA88B6D969672CA3F438C395DACF7D476EA7A9E805CE932D270A13
CF31220F44DE862E1719570E1B26E897790159366A385452334FE24CDCAE28BA
BB5E65669A44E5D5C709BAFA98C16CCBA6AC2C4AE923334F69A11543EDA64F5D
9DDB3AA9C7905D1A438C93BCF78E3E321813580371AB4E1289E2DBF3701972C2
26D90B190A6C3D0D9A86CF66005154E7086749E966E7187C249CCB9329FD3B8B
7DB6D1A129D6123F1F805B79AD3B413012EA86AED42A05E98E7B1F32F9FBBDEC
1D129B27BE7384C359D04311FE5C44917D1FDE4BFB57314F483AC617EDD5AC49
BBC773EBD2DF42C36AE05952D6A64C63A5DFB82CEB3EF4F8D4DF3A30EC8C0467
5B17A6ADAD541EFCBF5AE4B0C0452CD2CE32E4F0F8701801C5B63E197C1FCBF4
61AB87659525DE9656AF41246F20E1DBE85C24E335E7ECF9493F46168BC14E94
ECA2ADC3DA1FB15F34033405EC08EF2F46163DF4BFCCCF8842C600CE0BC2026C
C4F15BEC2D7701339D0ADE4835193BEA3632EDCF89E74992620D9EB623A0D0D4
28878249E2AC2B6263422993923A0C8BD05CE56E385ED13C943B03D226856947
17FC65F7FBD7C75CEEC421DEE84DFF5A8CB22764A182DB17E0EBE857F54D60EB
FA0489F3730100609488E951E6AAA15C0F193BC1DBCFCD013BC418D6C507B176

View file

@ -0,0 +1,100 @@
7C9935A0B07694AA0C6D10E4DB6B1ADD2FD81A25CCB148032DCD739936737F2D
D60B93492A1D8C1C7BA6FC0B733137F3406CEE8110A93F170E7A78658AF326D9
4B622DE1350119C45A9F2E2EF3DC5DF50A759D138CDFBD64C81CC7CC2F513345
050D58F9F757EDC1E8180E3808B806F5BBB3586DB3470B069826D1BB9A4EFC2C
66B79B844E0C2ADAD694E0478661AC46FE6B6001F6A71FF8E2F034B1FD8833D3
7EC408F52C9AA723D0C41D9987682A5F4CE6C9DA7CD0215AF60BBAF5484AB353
C121915BFEF6ABDFC177DAE2F5A24218F9ABDA2559AFC6741B08E0E61AB433EB
D86634ECF96CC2603761E284C0E36734CEDEC64E7FF486469E38539C71141C5A
0610678FF4DC3128E1619F915DC192C220F8FAD94DA1943B90AAEC401683A492
D322D56D8EF067BA1F24C92492B9C56DF3A6EF54A304ADC1B69913766A1CE697
2F1D8A3BEBB34540324B9485FDF3D5BE3B858F544ABC3FC641B5728CAFAB03BA
31BEDA3462627F601CBC56F3DDF4424E1529C04737EF0EF2AF6D7401F653B8A1
CBDFF028766D558AF4466EF14043A1A9CF765F7748C63CC09DCEB59AB39A4E4D
4C04310BEA66305C6CA8BA6B8F61CA96257A67663AFC11761F13FB5C7B324B6B
38A0D5F41D7DC1896EFD1B45B0485634CEF149828751B96087A0A6DD81B4D58A
97B5665676E59E3538EBADAA8CD50DF1F9FDA1502D9894C616A946078E56B621
EF99224A03A85A46EF115474EC5B5D620DA6795D6EFCCA4C9135D19958A9DE62
B12F6FD965EA9C5B947DB80FC60C83D5E232DCA82E7263027C19BD62E5A6FF55
9F52AF92CA165FDC38788F2B59BA02E01C8281FF7C1E60504688043A5FE814B0
851EA90FD3854CBF28FE39FB81F68E4B14345CF0D6EEE7EC4CE772513DF8410D
D304C9389CC973477F169788ABCB9D511F843219D246A9B587822F422A70C238
89A6E3BE304A3518FB82B18CA730F0B359CD6BA90664A493FB4F8EDAF965B9C3
D569B935CE015C85F792F8F7FB0D83C4F53B492959361DD4F75FB764D6564501
5CBB141C2763425C274F7404FE530D9116E08C33F9F200A20B011CF563A28990
293ABB6D1C207927945417CF84883EF010823E11B487ED55239E466E83696D0C
74D87C7556F2671F2D666854A4D6E073E69F35421E6E1A428CCCEA49C37F972C
013BAB0212D04ECD54B478DAF72748003A25E2CB060BA6CC50BF95C292B8206B
CCB073C4B90BE0AD746E26FB093B60C70110BD1DCBCDDB566A8CFFB7B3CAF80E
2E889F44E28901E9AC7CA6B2FFFCB124C8979401B17064D7E1D51A7E3C3ADBFA
174AAA36410566DC15A5E62874218D7ABDDE0B2C0F30D877BB80B1ABD5F5A0A4
351FE4313E2DA7FAC83D509F3103CAF7B4C64A4D458FEFDF636785AC361A1390
9BC5315580207C6C16DCF3A30C48DAF278DE12E8C27DF6733E62F799068AD23D
D8B907B34D152FF8603B73051F772DAA71EB902C47B7E2F070508269D757E02E
684A29E4E5480A5F2533E1526B5FAC8CDF5927F3D85087C71F928C59690EB565
D76B3573F596EB286AB5231FEEC7499686B13021BE36CB126C7EBEB9D7030DAF
B87439FDE81C9E39EEBE7CF741C685785532C1DD23E8EF868B9CE7A541010F3D
056661B38038DA4FDD7426F32A81576C73ED84843B305168A374F934E27A4E1B
A1B52D871612A1C611AE0944F9E71858F35D3BD14F20E96A931720668BDF0A6B
952B49C803D6D6FBA69F4375ADCE8594847A00BCAE2179DA49AF2AED04232502
3C815E57E9233E975FA1630208AAB206B71AE0DB37A7A8789AC683D9F9B2D298
588760826DCFBD36D9ABE6AE44A669BB3EBBA6A218EAB69E30F18A3BD536576E
47550E9EDACB6DDCE3D9AB81F6B61080DD4F2693854ACB05E0CCC7A4FB6390FB
610AFB64BE8CC1DF288CFB016EE2F44C6C07113DE7F6FEE071FE0C3FE31C6215
E1953800ACAA85AC02A906C72CB8E8D704E8D27820345F88F71E89C1F549AFCC
C719F9B2D16399B7326CE4ECA30DABEFE8FDAAB18E9F6DF888B0A134EF355570
E9ACBB774BE970206C3A738E243B420805A509FA59FA902044BE2F0D013650D2
C1B3CBFFAD4B306F9AF0CDD3028876486DBE858875C9B6497FE20172A986C82B
FF7495B8575B5A98E4FD21FB4C3E58CBB60F14BEF21AA74CF8802E3153F14807
BDC3FBA1C32751139FC45BACFFB3EA97F26573D804A5F27A459293D95190ED8E
447F6076A627BBC5AD7773FBFEB14B4BA9AC43A0F8B99FB6DCD5E452AA3C47EC
2D5DF64D62CB07FE630310BB801C658DBF3D97993E68626745DE39D37FBFC2B2
25056D1B8113BB362DD979D98643D7A7AC9C4F95994C0BA060609B6D07002FF3
E4D34E12982AEEB1D62FD488D9B9E28557ED3429292239FB4F76FA9098009ACA
CD6A99396EB3539CA663A51E42063A3A262CC1C5A5FCE1566F0597B52AD9FA32
6C8C53ED6F65E6B2E324B84364E10DE42D1C26A106D4D1C99EEE79C78586FB55
2107204CD995F1DF14314D5381F8C5440F09A347502E161CFFC0A2EC3DCFBC73
63A925685A8AC5BBD918FAA33AC397D1FFBCF99135D9DA7C3D6FF7AA4C50AF3D
6A1AEE5E708C1B47F02BDACCE4F56C860F74FC7CFEC1EF3B58285B1C8AD7FEC2
6396B328B100E4C7F4BCAE69875EDEA1A1982421558C608C13C592BF7B5D0FEF
A453BCACDD2B0D4646009E5ED451C3C45F08FB827EF733DB3C517A9DC1AF93E6
47CA2B77C5B717F423222C2730CA5CB9C856BC951D01B2B2C80BD76CCB5539B7
AAF6EB40E596A5E3E8218871E708B089240DCBE7FD3641F0E5E41E071CE49107
6500F32C93415CFDBC0BD31D78D5BE95CB9060C8CFA2013955B56F8B6868B322
7643CEF2D62CC5AAEECF754653EA62294CD2208E5BF3DDEEA209E3DC45373D49
F8EE95521060C03BB8DACC79F7EB7DB640F545F315613A35D447A09E504CB4E1
B8BD0493A882E3A49B4E0F6256FB1FEA0912562FD9BA26EC3D6C9CC12C8973AB
C0407E41DDF48D333978B89BCF2DB01E4613425B456249E76A6F25B8A2827BF5
334382D39164D1989696A2FF77B25A28AF8BEAD9883B5365EB6FCCA7C1781CC9
6995143E8EB8A6E93840F76EEC844F67D2B5F75B1839A5040337E61F9806764A
995EFF7E0D195C6D0533F3DC194D47E60F9AD14696144CDE694D60A95F3E96B4
3E809EC8DD0FEC0D911A4E3FAC20F70FBB128C5DE94DC7184CA7310AE9157A98
DBF1C465FFF3D9F783BD9EE61A573715E45691147B8904439B5FFAA64F94FF7B
1F7CFD2B70863154E8A69D1758532E86C20CFC763D67C758BD10A13B24E759B5
3A19577908EFD37697B8EDC7FDAF47D1BD3AD01A1B77FAF794BEE5B9C3192A6F
AE0F65E29F38804A6759F70F4D01E2AAFF7FE1C91EBC4F892DD0DE3AB2E68EA5
6084A235F79DD093EF6D185B54E69DF33DACEE73A9BF2F379004421A10E3A79D
ACD1C0217FAD5CAA4235544DD9DE153AB1880CCF4C76F16F236FAE4E4BFDA04C
241191401A63AFA750F05662E354DDDBC683C776CE3222BEB83E3CF913D7ED7C
B9A6B0C05677E957D41A34BA03BD06F2A9092E31F63389397D7E70FDE6409D18
28A96C71577BA00C94F99FE965BC595A26DB2B3CA6AB5CF8E443CDD8462B1792
C08BA2EF8C3A0A043AFAD931652D7A19E6E8CB670F840DE5F1FA03309B2CA9EC
0E3B30E102D707538C2671060F603BB0B8A014103F132D63B09ECE07E4A4C75B
2478F7D3DE6041E7E5CD11C5E2EF483D1AA6218EB126444091535F6AE532FA73
9D405D3EBDAF35FA8722DE431B669722ACAAEA2FD10B814310B17F78B66147D1
9A86490F0615F3EDF789CB0654066E9EE339CC59F968281F3B89213F83C692ED
6DFD9B575872560C7BDC2732C4A28DAC4DB04E535EB8E402C3DFFD145C09CE47
6FCA9F4E384D8418075CC064C70730801BDB8249899D456A77130D5BEEB3662C
E58F71BF175C0550A67E00E0F7B3B7FC36BC2707BF0C93044A492626DE36301A
E3FC575ED51513E62ABA655D24CD9C8F1C6C848AAFFA946C49A53AC3EA59E474
470B4943F0FE7FD0D8EC5185ABA0D1DB09D112934E4FB4787E2BBC6B88466E7B
6DF4385DB978D27B27D2AA5E452E4152B36F097503D9581AC3390105C5727E7D
DBACBA825728444921B227CDBA54446B3F6881B47BE9CD02832F78B023B1BEE0
690EB71FD7052B906EAEC09937A8ED374E0B02AFA27C2F14399932BE5839FAD2
32E0EA9089FA928482C0770DA545AF1BB871A03CE38604138B0D08EA2A10CA2B
6FB2EC719F2A0DEA152BF3F64B9D148F8AB8BA88F64E61F5DB53E12D59F52557
527FB88C8BD9A4D6031DAD15E63878ABD2B559E7E08D61F69E8E78FCA964EE6A
AC6FCFAEEEF795B6EF9E062F02BF42975FA01E7D91BA832F74E05269A72684D0
BA2FB9318D4DBE7488057C33E95E6F054583A2800C41BB83083C330A914A12CF
AA6DD1E5799CDF7AF9C4FC632B3EB9D51D66E85C8E0A21EC98664FC51AB63C7D
195D6C86A3DF4C21E3007D7F2768B43C74CB3060E0ECA77F0A5D3271542B9A84

View file

@ -0,0 +1,27 @@
# Randbuf Generation
This program generates the deterministic rng output used in the intermediate stages of keypair generation and encoding from KAT seed values.
`rng.c` and `rng.h` are directly from the NIST submission, `generate_bufs.c` is a stripped down version of `PQCgenKAT_kem.c` to print out the seeded values from `randombytes()` into their respective files.
These values are then used in place of regular rng output when running the KATs.
### Usage
To build and use:
```shell
cd tests/rand_bufs
make
./generate
mkdir outputs
mv crypto_kem_keypair indcpa_keypair encode outputs/
```
### Original Files
* [rng.c](https://github.com/pq-crystals/kyber/blob/master/ref/rng.c)
* [rng.h](https://github.com/pq-crystals/kyber/blob/master/ref/rng.h)
* [PQCgenKAT_kem.c](https://github.com/pq-crystals/kyber/blob/master/ref/PQCgenKAT_kem.c)

221
third_party/kyber/tests/rand_bufs/rng.c vendored Normal file
View file

@ -0,0 +1,221 @@
//
// rng.c
//
// Created by Bassham, Lawrence E (Fed) on 8/29/17.
// Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved.
//
#include <string.h>
#include "rng.h"
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
AES256_CTR_DRBG_struct DRBG_ctx;
void AES256_ECB(unsigned char *key, unsigned char *ctr, unsigned char *buffer);
/*
seedexpander_init()
ctx - stores the current state of an instance of the seed expander
seed - a 32 byte random value
diversifier - an 8 byte diversifier
maxlen - maximum number of bytes (less than 2**32) generated under this seed and diversifier
*/
int
seedexpander_init(AES_XOF_struct *ctx,
unsigned char *seed,
unsigned char *diversifier,
unsigned long maxlen)
{
if ( maxlen >= 0x100000000 )
return RNG_BAD_MAXLEN;
ctx->length_remaining = maxlen;
memcpy(ctx->key, seed, 32);
memcpy(ctx->ctr, diversifier, 8);
ctx->ctr[11] = maxlen % 256;
maxlen >>= 8;
ctx->ctr[10] = maxlen % 256;
maxlen >>= 8;
ctx->ctr[9] = maxlen % 256;
maxlen >>= 8;
ctx->ctr[8] = maxlen % 256;
memset(ctx->ctr+12, 0x00, 4);
ctx->buffer_pos = 16;
memset(ctx->buffer, 0x00, 16);
return RNG_SUCCESS;
}
/*
seedexpander()
ctx - stores the current state of an instance of the seed expander
x - returns the XOF data
xlen - number of bytes to return
*/
int
seedexpander(AES_XOF_struct *ctx, unsigned char *x, unsigned long xlen)
{
unsigned long offset;
if ( x == NULL )
return RNG_BAD_OUTBUF;
if ( xlen >= ctx->length_remaining )
return RNG_BAD_REQ_LEN;
ctx->length_remaining -= xlen;
offset = 0;
while ( xlen > 0 ) {
if ( xlen <= (16-ctx->buffer_pos) ) { // buffer has what we need
memcpy(x+offset, ctx->buffer+ctx->buffer_pos, xlen);
ctx->buffer_pos += xlen;
return RNG_SUCCESS;
}
// take what's in the buffer
memcpy(x+offset, ctx->buffer+ctx->buffer_pos, 16-ctx->buffer_pos);
xlen -= 16-ctx->buffer_pos;
offset += 16-ctx->buffer_pos;
AES256_ECB(ctx->key, ctx->ctr, ctx->buffer);
ctx->buffer_pos = 0;
//increment the counter
for (int i=15; i>=12; i--) {
if ( ctx->ctr[i] == 0xff )
ctx->ctr[i] = 0x00;
else {
ctx->ctr[i]++;
break;
}
}
}
return RNG_SUCCESS;
}
void handleErrors(void)
{
ERR_print_errors_fp(stderr);
abort();
}
// Use whatever AES implementation you have. This uses AES from openSSL library
// key - 256-bit AES key
// ctr - a 128-bit plaintext value
// buffer - a 128-bit ciphertext value
void
AES256_ECB(unsigned char *key, unsigned char *ctr, unsigned char *buffer)
{
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;
/* Create and initialise the context */
if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ecb(), NULL, key, NULL))
handleErrors();
if(1 != EVP_EncryptUpdate(ctx, buffer, &len, ctr, 16))
handleErrors();
ciphertext_len = len;
/* Clean up */
EVP_CIPHER_CTX_free(ctx);
}
void
randombytes_init(unsigned char *entropy_input,
unsigned char *personalization_string,
int security_strength)
{
unsigned char seed_material[48];
memcpy(seed_material, entropy_input, 48);
if (personalization_string)
for (int i=0; i<48; i++)
seed_material[i] ^= personalization_string[i];
memset(DRBG_ctx.Key, 0x00, 32);
memset(DRBG_ctx.V, 0x00, 16);
AES256_CTR_DRBG_Update(seed_material, DRBG_ctx.Key, DRBG_ctx.V);
DRBG_ctx.reseed_counter = 1;
}
int
randombytes(unsigned char *x, unsigned long long xlen)
{
unsigned char block[16];
int i = 0;
while ( xlen > 0 ) {
//increment V
for (int j=15; j>=0; j--) {
if ( DRBG_ctx.V[j] == 0xff )
DRBG_ctx.V[j] = 0x00;
else {
DRBG_ctx.V[j]++;
break;
}
}
AES256_ECB(DRBG_ctx.Key, DRBG_ctx.V, block);
if ( xlen > 15 ) {
memcpy(x+i, block, 16);
i += 16;
xlen -= 16;
}
else {
memcpy(x+i, block, xlen);
xlen = 0;
}
}
AES256_CTR_DRBG_Update(NULL, DRBG_ctx.Key, DRBG_ctx.V);
DRBG_ctx.reseed_counter++;
return RNG_SUCCESS;
}
void
AES256_CTR_DRBG_Update(unsigned char *provided_data,
unsigned char *Key,
unsigned char *V)
{
unsigned char temp[48];
for (int i=0; i<3; i++) {
//increment V
for (int j=15; j>=0; j--) {
if ( V[j] == 0xff )
V[j] = 0x00;
else {
V[j]++;
break;
}
}
AES256_ECB(Key, V, temp+16*i);
}
if ( provided_data != NULL )
for (int i=0; i<48; i++)
temp[i] ^= provided_data[i];
memcpy(Key, temp, 32);
memcpy(V, temp+32, 16);
}

55
third_party/kyber/tests/rand_bufs/rng.h vendored Normal file
View file

@ -0,0 +1,55 @@
//
// rng.h
//
// Created by Bassham, Lawrence E (Fed) on 8/29/17.
// Copyright © 2017 Bassham, Lawrence E (Fed). All rights reserved.
//
#ifndef rng_h
#define rng_h
#include <stdio.h>
#define RNG_SUCCESS 0
#define RNG_BAD_MAXLEN -1
#define RNG_BAD_OUTBUF -2
#define RNG_BAD_REQ_LEN -3
typedef struct {
unsigned char buffer[16];
int buffer_pos;
unsigned long length_remaining;
unsigned char key[32];
unsigned char ctr[16];
} AES_XOF_struct;
typedef struct {
unsigned char Key[32];
unsigned char V[16];
int reseed_counter;
} AES256_CTR_DRBG_struct;
void
AES256_CTR_DRBG_Update(unsigned char *provided_data,
unsigned char *Key,
unsigned char *V);
int
seedexpander_init(AES_XOF_struct *ctx,
unsigned char *seed,
unsigned char *diversifier,
unsigned long maxlen);
int
seedexpander(AES_XOF_struct *ctx, unsigned char *x, unsigned long xlen);
void
randombytes_init(unsigned char *entropy_input,
unsigned char *personalization_string,
int security_strength);
int
randombytes(unsigned char *x, unsigned long long xlen);
#endif /* rng_h */

27
third_party/kyber/tests/readme.md vendored Normal file
View file

@ -0,0 +1,27 @@
# Testing
Without any feature flags `cargo test` will run through the key exchange functions and some doctests for the selected security level and mode. Running the Known Answer Tests require deterministic rng buffers from the test vector files. These files are quite large, you will need to generate them yourself. Instructions for building the KAT files are [here](./KATs/readme.md). Otherwise you can run:
```bash
cd KATs
./build_kats.sh
```
Which will clone the C reference repo, generate the KAT files, then rename and put them in the correct folder for testing.
To run the known answer tests you will need to use the `KATs` feature flag and only test that module by itself. To check different Kyber levels or 90's mode you will need to include those flags also. eg:
```bash
cargo test --test kat --features "KATs kyber1024 90s"
```
To run a matrix of all possible tests use the helper script from this folder:
```bash
./run_all_tests.sh
```
Test files:
* [kat.rs](./kat.rs) - Runs a battery of test vectors using the Known Answer Test file of the selected security level and mode. There are 10,000 KATs per file.
* [kex.rs](./kex.rs) - Goes through a full key exchange procedure for both the UAKE and AKE functions.
* [kem.rs](./kem.rs) - A single run of random key generation, encapsulation and decapsulation.

107
third_party/kyber/tests/run_all_tests.sh vendored Normal file
View file

@ -0,0 +1,107 @@
#!/bin/env bash
set -e
# This script runs a matrix of every valid feature combination
# Known Answer Tests are run seperately at the end
# Enable avx2 target features
# Enable LLVM address sanitser checks
export RUSTFLAGS="-Z sanitizer=address -C target-cpu=native -C target-feature=+aes,+avx2,+sse2,+sse4.1,+bmi2,+popcnt"
export RUSTDOCFLAGS="-Z sanitizer=address"
TARGET=$(rustc -vV | sed -n 's|host: ||p')
# Required for address sanitiser checks
rustup default nightly
# Print Headers
announce(){
title="# $1 #"
edge=$(echo "$title" | sed 's/./#/g')
echo -e "\n\n$edge"; echo "$title"; echo -e "$edge\n\n";
}
##############################################################
# Initial compile
cargo build --tests --features "kyber512" --target $TARGET
announce "Kyber512"
cargo test --features "kyber512" --target $TARGET
announce "Kyber764"
cargo test --target $TARGET
announce "Kyber1024"
cargo test --features "kyber1024" --target $TARGET
announce "Kyber512-90s"
cargo test --features "kyber512 90s" --target $TARGET
announce "Kyber764-90s"
cargo test --features "90s" --target $TARGET
announce "Kyber1024-90s"
cargo test --features "kyber1024 90s" --target $TARGET
announce "Reference Kyber512"
cargo test --features "reference kyber512" --target $TARGET
announce "Reference Kyber764"
cargo test --features "reference" --target $TARGET
announce "Reference Kyber1024"
cargo test --features "reference kyber1024" --target $TARGET
announce "Reference Kyber764-90s"
cargo test --features "reference 90s" --target $TARGET
announce "Reference Kyber512-90s"
cargo test --features "reference kyber512 90s" --target $TARGET
announce "Reference Kyber1024-90s"
cargo test --features "reference kyber1024 90s" --target $TARGET
##############################################################
# Omit santiser for faster test vectors
export RUSTFLAGS="-C target-cpu=native -C target-feature=+aes,+avx2,+sse2,+sse4.1,+bmi2,+popcnt"
cargo build --test kat --features "KATs kyber512"
announce "Kyber512 KATs"
cargo test --test kat --features "KATs kyber512"
announce "Kyber764 KATs"
cargo test --test kat --features "KATs"
announce "Kyber1024 KATs"
cargo test --test kat --features "KATs kyber1024"
announce "Kyber512-90s KATs"
cargo test --test kat --features "KATs kyber512 90s"
announce "Kyber764-90s KATs"
cargo test --test kat --features "KATs 90s"
announce "Kyber1024-90s KATs"
cargo test --test kat --features "KATs kyber1024 90s"
announce "Reference Kyber512 KATs"
cargo test --test kat --features "reference KATs kyber512"
announce "Reference Kyber764 KATs"
cargo test --test kat --features "reference KATs"
announce "Reference Kyber1024 KATs"
cargo test --test kat --features "reference KATs kyber1024"
announce "Reference Kyber764-90s KATs"
cargo test --test kat --features "reference KATs 90s"
announce "Reference Kyber512-90s KATs"
cargo test --test kat --features "reference KATs kyber512 90s"
announce "Reference Kyber1024-90s KATs"
cargo test --test kat --features "reference KATs kyber1024 90s"

View file

@ -16,7 +16,7 @@ openssl = { version = "^0", features = [], default-features = false }
lazy_static = "^1"
foreign-types = "0.3.1"
poly1305 = { version = "0.7.2", features = [], default-features = false }
pqc_kyber = { version = "0.2.0", features = ["kyber512"], default-features = false }
pqc_kyber = { path = "../third_party/kyber", features = [], default-features = false }
[dev-dependencies]
quickcheck = "1.0.3"

View file

@ -0,0 +1,473 @@
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
// MacOS implementation of AES primitives since CommonCrypto seems to be faster than OpenSSL, especially on ARM64.
#[cfg(target_os = "macos")]
mod fruit_flavored {
use std::os::raw::{c_int, c_void};
use std::ptr::{null, null_mut};
#[allow(non_upper_case_globals)]
const kCCModeECB: i32 = 1;
#[allow(non_upper_case_globals)]
const kCCModeCTR: i32 = 4;
#[allow(non_upper_case_globals)]
const kCCModeGCM: i32 = 11;
#[allow(non_upper_case_globals)]
const kCCEncrypt: i32 = 0;
#[allow(non_upper_case_globals)]
const kCCDecrypt: i32 = 1;
#[allow(non_upper_case_globals)]
const kCCAlgorithmAES: i32 = 0;
#[allow(non_upper_case_globals)]
const kCCOptionECBMode: i32 = 2;
extern "C" {
fn CCCryptorCreateWithMode(
op: i32,
mode: i32,
alg: i32,
padding: i32,
iv: *const c_void,
key: *const c_void,
key_len: usize,
tweak: *const c_void,
tweak_len: usize,
num_rounds: c_int,
options: i32,
cryyptor_ref: *mut *mut c_void,
) -> i32;
fn CCCryptorUpdate(cryptor_ref: *mut c_void, data_in: *const c_void, data_in_len: usize, data_out: *mut c_void, data_out_len: usize, data_out_written: *mut usize) -> i32;
fn CCCryptorReset(cryptor_ref: *mut c_void, iv: *const c_void) -> i32;
fn CCCryptorRelease(cryptor_ref: *mut c_void) -> i32;
fn CCCryptorGCMSetIV(cryptor_ref: *mut c_void, iv: *const c_void, iv_len: usize) -> i32;
fn CCCryptorGCMAddAAD(cryptor_ref: *mut c_void, aad: *const c_void, len: usize) -> i32;
fn CCCryptorGCMFinalize(cryptor_ref: *mut c_void, tag: *mut c_void, tag_len: usize) -> i32;
fn CCCryptorGCMReset(cryptor_ref: *mut c_void) -> i32;
}
pub struct Aes(*mut c_void, *mut c_void);
impl Drop for Aes {
#[inline(always)]
fn drop(&mut self) {
unsafe {
CCCryptorRelease(self.0);
CCCryptorRelease(self.1);
}
}
}
impl Aes {
pub fn new(k: &[u8]) -> Self {
unsafe {
if k.len() != 32 && k.len() != 24 && k.len() != 16 {
panic!("AES supports 128, 192, or 256 bits keys");
}
let mut aes: Self = std::mem::zeroed();
let enc = CCCryptorCreateWithMode(kCCEncrypt, kCCModeECB, kCCAlgorithmAES, 0, null(), k.as_ptr().cast(), k.len(), null(), 0, 0, kCCOptionECBMode, &mut aes.0);
if enc != 0 {
panic!("CCCryptorCreateWithMode for ECB encrypt mode returned {}", enc);
}
let dec = CCCryptorCreateWithMode(kCCDecrypt, kCCModeECB, kCCAlgorithmAES, 0, null(), k.as_ptr().cast(), k.len(), null(), 0, 0, kCCOptionECBMode, &mut aes.1);
if dec != 0 {
panic!("CCCryptorCreateWithMode for ECB decrypt mode returned {}", dec);
}
aes
}
}
#[inline(always)]
pub fn encrypt_block(&self, plaintext: &[u8], ciphertext: &mut [u8]) {
assert_eq!(plaintext.len(), 16);
assert_eq!(ciphertext.len(), 16);
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.0, plaintext.as_ptr().cast(), 16, ciphertext.as_mut_ptr().cast(), 16, &mut data_out_written);
}
}
#[inline(always)]
pub fn encrypt_block_in_place(&self, data: &mut [u8]) {
assert_eq!(data.len(), 16);
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.0, data.as_ptr().cast(), 16, data.as_mut_ptr().cast(), 16, &mut data_out_written);
}
}
#[inline(always)]
pub fn decrypt_block(&self, ciphertext: &[u8], plaintext: &mut [u8]) {
assert_eq!(plaintext.len(), 16);
assert_eq!(ciphertext.len(), 16);
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.1, ciphertext.as_ptr().cast(), 16, plaintext.as_mut_ptr().cast(), 16, &mut data_out_written);
}
}
#[inline(always)]
pub fn decrypt_block_in_place(&self, data: &mut [u8]) {
assert_eq!(data.len(), 16);
unsafe {
let mut data_out_written = 0;
CCCryptorUpdate(self.1, data.as_ptr().cast(), 16, data.as_mut_ptr().cast(), 16, &mut data_out_written);
}
}
}
unsafe impl Send for Aes {}
unsafe impl Sync for Aes {}
pub struct AesCtr(*mut c_void);
impl Drop for AesCtr {
#[inline(always)]
fn drop(&mut self) {
unsafe { CCCryptorRelease(self.0) };
}
}
impl AesCtr {
/// Construct a new AES-CTR cipher.
/// Key must be 16, 24, or 32 bytes in length or a panic will occur.
pub fn new(k: &[u8]) -> Self {
if k.len() != 32 && k.len() != 24 && k.len() != 16 {
panic!("AES supports 128, 192, or 256 bits keys");
}
unsafe {
let mut ptr: *mut c_void = null_mut();
let result = CCCryptorCreateWithMode(kCCEncrypt, kCCModeCTR, kCCAlgorithmAES, 0, [0_u64; 2].as_ptr().cast(), k.as_ptr().cast(), k.len(), null(), 0, 0, 0, &mut ptr);
if result != 0 {
panic!("CCCryptorCreateWithMode for CTR mode returned {}", result);
}
AesCtr(ptr)
}
}
/// Initialize AES-CTR for encryption or decryption with the given IV.
/// If it's already been used, this also resets the cipher. There is no separate reset.
pub fn init(&mut self, iv: &[u8]) {
unsafe {
if iv.len() == 16 {
if CCCryptorReset(self.0, iv.as_ptr().cast()) != 0 {
panic!("CCCryptorReset for CTR mode failed (old MacOS bug)");
}
} else if iv.len() < 16 {
let mut iv2 = [0_u8; 16];
iv2[0..iv.len()].copy_from_slice(iv);
if CCCryptorReset(self.0, iv2.as_ptr().cast()) != 0 {
panic!("CCCryptorReset for CTR mode failed (old MacOS bug)");
}
} else {
panic!("CTR IV must be less than or equal to 16 bytes in length");
}
}
}
/// Encrypt or decrypt (same operation with CTR mode)
#[inline(always)]
pub fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
unsafe {
assert!(output.len() >= input.len());
let mut data_out_written: usize = 0;
CCCryptorUpdate(self.0, input.as_ptr().cast(), input.len(), output.as_mut_ptr().cast(), output.len(), &mut data_out_written);
}
}
/// Encrypt or decrypt in place (same operation with CTR mode)
#[inline(always)]
pub fn crypt_in_place(&mut self, data: &mut [u8]) {
unsafe {
let mut data_out_written: usize = 0;
CCCryptorUpdate(self.0, data.as_ptr().cast(), data.len(), data.as_mut_ptr().cast(), data.len(), &mut data_out_written);
}
}
}
unsafe impl Send for AesCtr {}
pub struct AesGcm(*mut c_void);
impl Drop for AesGcm {
#[inline(always)]
fn drop(&mut self) {
unsafe { CCCryptorRelease(self.0) };
}
}
impl AesGcm {
pub fn new(k: &[u8], encrypt: bool) -> Self {
if k.len() != 32 && k.len() != 24 && k.len() != 16 {
panic!("AES supports 128, 192, or 256 bits keys");
}
unsafe {
let mut ptr: *mut c_void = null_mut();
let result = CCCryptorCreateWithMode(
if encrypt { kCCEncrypt } else { kCCDecrypt },
kCCModeGCM,
kCCAlgorithmAES,
0,
[0_u64; 2].as_ptr().cast(),
k.as_ptr().cast(),
k.len(),
null(),
0,
0,
0,
&mut ptr,
);
if result != 0 {
panic!("CCCryptorCreateWithMode for GCM mode returned {}", result);
}
AesGcm(ptr)
}
}
#[inline(always)]
pub fn init(&mut self, iv: &[u8]) {
assert_eq!(iv.len(), 12);
unsafe {
assert_eq!(CCCryptorGCMReset(self.0), 0);
CCCryptorGCMSetIV(self.0, iv.as_ptr().cast(), 12);
}
}
#[inline(always)]
pub fn aad(&mut self, aad: &[u8]) {
unsafe {
CCCryptorGCMAddAAD(self.0, aad.as_ptr().cast(), aad.len());
}
}
#[inline(always)]
pub fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
assert_eq!(input.len(), output.len());
unsafe {
let mut data_out_written: usize = 0;
CCCryptorUpdate(self.0, input.as_ptr().cast(), input.len(), output.as_mut_ptr().cast(), output.len(), &mut data_out_written);
}
}
#[inline(always)]
pub fn finish(&mut self) -> [u8; 16] {
let mut tag = [0_u8; 16];
unsafe {
if CCCryptorGCMFinalize(self.0, tag.as_mut_ptr().cast(), 16) != 0 {
tag.fill(0);
}
}
tag
}
}
unsafe impl Send for AesGcm {}
}
#[cfg(not(target_os = "macos"))]
mod openssl {
use crate::secret::Secret;
use openssl::symm::{Cipher, Crypter, Mode};
use std::cell::UnsafeCell;
#[inline(always)]
fn aes_ctr_by_key_size(ks: usize) -> Cipher {
match ks {
16 => Cipher::aes_128_ctr(),
24 => Cipher::aes_192_ctr(),
32 => Cipher::aes_256_ctr(),
_ => {
panic!("AES supports 128, 192, or 256 bits keys");
}
}
}
#[inline(always)]
fn aes_gcm_by_key_size(ks: usize) -> Cipher {
match ks {
16 => Cipher::aes_128_gcm(),
24 => Cipher::aes_192_gcm(),
32 => Cipher::aes_256_gcm(),
_ => {
panic!("AES supports 128, 192, or 256 bits keys");
}
}
}
#[inline(always)]
fn aes_ecb_by_key_size(ks: usize) -> Cipher {
match ks {
16 => Cipher::aes_128_ecb(),
24 => Cipher::aes_192_ecb(),
32 => Cipher::aes_256_ecb(),
_ => {
panic!("AES supports 128, 192, or 256 bits keys");
}
}
}
pub struct Aes(UnsafeCell<Crypter>, UnsafeCell<Crypter>);
impl Aes {
#[inline(always)]
pub fn new(k: &[u8]) -> Self {
let (mut c, mut d) =
(Crypter::new(aes_ecb_by_key_size(k.len()), Mode::Encrypt, k, None).unwrap(), Crypter::new(aes_ecb_by_key_size(k.len()), Mode::Decrypt, k, None).unwrap());
c.pad(false);
d.pad(false);
Self(UnsafeCell::new(c), UnsafeCell::new(d))
}
#[inline(always)]
pub fn encrypt_block(&self, plaintext: &[u8], ciphertext: &mut [u8]) {
let mut tmp = [0_u8; 32];
let c: &mut Crypter = unsafe { &mut *self.0.get() };
if c.update(plaintext, &mut tmp).unwrap() != 16 {
assert_eq!(c.finalize(&mut tmp).unwrap(), 16);
}
ciphertext[..16].copy_from_slice(&tmp[..16]);
}
#[inline(always)]
pub fn encrypt_block_in_place(&self, data: &mut [u8]) {
let mut tmp = [0_u8; 32];
let c: &mut Crypter = unsafe { &mut *self.0.get() };
if c.update(data, &mut tmp).unwrap() != 16 {
assert_eq!(c.finalize(&mut tmp).unwrap(), 16);
}
data[..16].copy_from_slice(&tmp[..16]);
}
#[inline(always)]
pub fn decrypt_block(&self, ciphertext: &[u8], plaintext: &mut [u8]) {
let mut tmp = [0_u8; 32];
let c: &mut Crypter = unsafe { &mut *self.1.get() };
if c.update(plaintext, &mut tmp).unwrap() != 16 {
assert_eq!(c.finalize(&mut tmp).unwrap(), 16);
}
plaintext[..16].copy_from_slice(&tmp[..16]);
}
#[inline(always)]
pub fn decrypt_block_in_place(&self, data: &mut [u8]) {
let mut tmp = [0_u8; 32];
let c: &mut Crypter = unsafe { &mut *self.1.get() };
if c.update(data, &mut tmp).unwrap() != 16 {
assert_eq!(c.finalize(&mut tmp).unwrap(), 16);
}
data[..16].copy_from_slice(&tmp[..16]);
}
}
unsafe impl Send for Aes {}
unsafe impl Sync for Aes {}
pub struct AesCtr(Secret<32>, usize, Option<Crypter>);
impl AesCtr {
/// Construct a new AES-CTR cipher.
/// Key must be 16, 24, or 32 bytes in length or a panic will occur.
#[inline(always)]
pub fn new(k: &[u8]) -> Self {
let mut s: Secret<32> = Secret::default();
match k.len() {
16 | 24 | 32 => {
s.0[..k.len()].copy_from_slice(k);
Self(s, k.len(), None)
}
_ => {
panic!("AES supports 128, 192, or 256 bits keys");
}
}
}
/// Initialize AES-CTR for encryption or decryption with the given IV.
/// If it's already been used, this also resets the cipher. There is no separate reset.
#[inline(always)]
pub fn init(&mut self, iv: &[u8]) {
let mut c = Crypter::new(aes_ctr_by_key_size(self.1), Mode::Encrypt, &self.0 .0[..self.1], Some(iv)).unwrap();
c.pad(false);
let _ = self.2.replace(c);
}
/// Encrypt or decrypt (same operation with CTR mode)
#[inline(always)]
pub fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
let _ = self.2.as_mut().unwrap().update(input, output);
}
/// Encrypt or decrypt in place (same operation with CTR mode)
#[inline(always)]
pub fn crypt_in_place(&mut self, data: &mut [u8]) {
let _ = self.2.as_mut().unwrap().update(unsafe { &*std::slice::from_raw_parts(data.as_ptr(), data.len()) }, data);
}
}
unsafe impl Send for AesCtr {}
pub struct AesGcm(Secret<32>, usize, Option<Crypter>, bool);
impl AesGcm {
/// Construct a new AES-GCM cipher.
/// Key must be 16, 24, or 32 bytes in length or a panic will occur.
#[inline(always)]
pub fn new(k: &[u8], encrypt: bool) -> Self {
let mut s: Secret<32> = Secret::default();
match k.len() {
16 | 24 | 32 => {
s.0[..k.len()].copy_from_slice(k);
Self(s, k.len(), None, encrypt)
}
_ => {
panic!("AES supports 128, 192, or 256 bits keys");
}
}
}
/// Initialize AES-CTR for encryption or decryption with the given IV.
/// If it's already been used, this also resets the cipher. There is no separate reset.
#[inline(always)]
pub fn init(&mut self, iv: &[u8]) {
assert_eq!(iv.len(), 12);
let mut c = Crypter::new(aes_gcm_by_key_size(self.1), if self.3 { Mode::Encrypt } else { Mode::Decrypt }, &self.0 .0[..self.1], Some(iv)).unwrap();
c.pad(false);
let _ = self.2.replace(c);
}
#[inline(always)]
pub fn aad(&mut self, aad: &[u8]) {
let _ = self.2.as_mut().unwrap().aad_update(aad);
}
/// Encrypt or decrypt (same operation with CTR mode)
#[inline(always)]
pub fn crypt(&mut self, input: &[u8], output: &mut [u8]) {
let _ = self.2.as_mut().unwrap().update(input, output);
}
/// Encrypt or decrypt in place (same operation with CTR mode)
#[inline(always)]
pub fn crypt_in_place(&mut self, data: &mut [u8]) {
let _ = self.2.as_mut().unwrap().update(unsafe { &*std::slice::from_raw_parts(data.as_ptr(), data.len()) }, data);
}
#[inline(always)]
pub fn finish(&mut self) -> [u8; 16] {
let mut tag = [0_u8; 16];
let c = self.2.as_mut().unwrap();
if c.finalize(&mut []).is_ok() {
if !c.get_tag(&mut tag).is_ok() {
tag.fill(0);
}
}
tag
}
}
unsafe impl Send for AesGcm {}
}
#[cfg(target_os = "macos")]
pub use fruit_flavored::{Aes, AesCtr, AesGcm};
#[cfg(not(target_os = "macos"))]
pub use openssl::{Aes, AesCtr, AesGcm};

View file

@ -1,5 +1,6 @@
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
pub mod aes;
pub mod hash;
pub mod hex;
pub mod kbkdf;

View file

@ -77,7 +77,8 @@ impl rand_core::RngCore for SecureRandom {
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
rand_bytes(dest).map_err(|e| rand_core::Error::new(Box::new(e)))
fill_bytes_secure(dest);
Ok(())
}
}
@ -101,7 +102,8 @@ impl rand_core_062::RngCore for SecureRandom {
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_062::Error> {
rand_bytes(dest).map_err(|e| rand_core_062::Error::new(Box::new(e)))
fill_bytes_secure(dest);
Ok(())
}
}

View file

@ -6,18 +6,18 @@ use std::sync::{Arc, Weak};
use parking_lot::Mutex;
/// Each pool requires a factory that creates and resets (for re-use) pooled objects.
pub trait PoolFactory<O> {
pub trait PoolFactory<O: Send> {
fn create(&self) -> O;
fn reset(&self, obj: &mut O);
}
#[repr(C)]
struct PoolEntry<O, F: PoolFactory<O>> {
obj: O,
struct PoolEntry<O: Send, F: PoolFactory<O>> {
obj: O, // must be first
return_pool: Weak<PoolInner<O, F>>,
}
struct PoolInner<O, F: PoolFactory<O>> {
struct PoolInner<O: Send, F: PoolFactory<O>> {
factory: F,
pool: Mutex<Vec<NonNull<PoolEntry<O, F>>>>,
}
@ -33,16 +33,16 @@ struct PoolInner<O, F: PoolFactory<O>> {
/// Note that pooled objects are not clonable. If you want to share them use Rc<>
/// or Arc<>.
#[repr(transparent)]
pub struct Pooled<O, F: PoolFactory<O>>(NonNull<PoolEntry<O, F>>);
pub struct Pooled<O: Send, F: PoolFactory<O>>(NonNull<PoolEntry<O, F>>);
impl<O, F: PoolFactory<O>> Pooled<O, F> {
impl<O: Send, F: PoolFactory<O>> Pooled<O, F> {
/// Get a raw pointer to the object wrapped by this pooled object container.
/// The returned raw pointer MUST be restored into a Pooled instance with
/// from_raw() or memory will leak.
#[inline(always)]
pub unsafe fn into_raw(self) -> *mut O {
// Verify that the structure is not padded before 'obj'.
debug_assert_eq!((&self.0.as_ref().obj as *const O).cast::<u8>(), (self.0.as_ref() as *const PoolEntry<O, F>).cast::<u8>());
assert_eq!((&self.0.as_ref().obj as *const O).cast::<u8>(), (self.0.as_ref() as *const PoolEntry<O, F>).cast::<u8>());
let ptr = self.0.as_ptr().cast::<O>();
std::mem::forget(self);
@ -63,11 +63,10 @@ impl<O, F: PoolFactory<O>> Pooled<O, F> {
}
}
unsafe impl<O, F: PoolFactory<O>> Send for Pooled<O, F> where O: Send {}
unsafe impl<O: Send, F: PoolFactory<O>> Send for Pooled<O, F> {}
unsafe impl<O: Send, F: PoolFactory<O>> Sync for Pooled<O, F> where O: Sync {}
unsafe impl<O, F: PoolFactory<O>> Sync for Pooled<O, F> where O: Sync {}
impl<O, F: PoolFactory<O>> std::ops::Deref for Pooled<O, F> {
impl<O: Send, F: PoolFactory<O>> std::ops::Deref for Pooled<O, F> {
type Target = O;
#[inline(always)]
@ -76,28 +75,29 @@ impl<O, F: PoolFactory<O>> std::ops::Deref for Pooled<O, F> {
}
}
impl<O, F: PoolFactory<O>> AsRef<O> for Pooled<O, F> {
impl<O: Send, F: PoolFactory<O>> AsRef<O> for Pooled<O, F> {
#[inline(always)]
fn as_ref(&self) -> &O {
unsafe { &self.0.as_ref().obj }
}
}
impl<O, F: PoolFactory<O>> std::ops::DerefMut for Pooled<O, F> {
impl<O: Send, F: PoolFactory<O>> std::ops::DerefMut for Pooled<O, F> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut self.0.as_mut().obj }
}
}
impl<O, F: PoolFactory<O>> AsMut<O> for Pooled<O, F> {
impl<O: Send, F: PoolFactory<O>> AsMut<O> for Pooled<O, F> {
#[inline(always)]
fn as_mut(&mut self) -> &mut O {
unsafe { &mut self.0.as_mut().obj }
}
}
impl<O, F: PoolFactory<O>> Drop for Pooled<O, F> {
impl<O: Send, F: PoolFactory<O>> Drop for Pooled<O, F> {
#[inline(always)]
fn drop(&mut self) {
let internal = unsafe { self.0.as_mut() };
if let Some(p) = internal.return_pool.upgrade() {
@ -112,9 +112,9 @@ impl<O, F: PoolFactory<O>> Drop for Pooled<O, F> {
/// An object pool for Reusable objects.
/// Checked out objects are held by a guard object that returns them when dropped if
/// the pool still exists or drops them if the pool has itself been dropped.
pub struct Pool<O, F: PoolFactory<O>>(Arc<PoolInner<O, F>>);
pub struct Pool<O: Send, F: PoolFactory<O>>(Arc<PoolInner<O, F>>);
impl<O, F: PoolFactory<O>> Pool<O, F> {
impl<O: Send, F: PoolFactory<O>> Pool<O, F> {
pub fn new(initial_stack_capacity: usize, factory: F) -> Self {
Self(Arc::new(PoolInner::<O, F> {
factory,
@ -123,6 +123,7 @@ impl<O, F: PoolFactory<O>> Pool<O, F> {
}
/// Get a pooled object, or allocate one if the pool is empty.
#[inline(always)]
pub fn get(&self) -> Pooled<O, F> {
if let Some(o) = self.0.pool.lock().pop() {
return Pooled::<O, F>(o);
@ -147,15 +148,15 @@ impl<O, F: PoolFactory<O>> Pool<O, F> {
}
}
impl<O, F: PoolFactory<O>> Drop for Pool<O, F> {
impl<O: Send, F: PoolFactory<O>> Drop for Pool<O, F> {
#[inline(always)]
fn drop(&mut self) {
self.purge();
}
}
unsafe impl<O, F: PoolFactory<O>> Sync for Pool<O, F> {}
unsafe impl<O, F: PoolFactory<O>> Send for Pool<O, F> {}
unsafe impl<O: Send, F: PoolFactory<O>> Send for Pool<O, F> {}
unsafe impl<O: Send, F: PoolFactory<O>> Sync for Pool<O, F> {}
#[cfg(test)]
mod tests {

View file

@ -218,14 +218,11 @@ pub mod security_constants {
/// KBKDF usage label for the second AES-GMAC-SIV key.
pub const KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1: u8 = b'1';
/// KBKDF usage label for the private section of HELLOs.
pub const KBKDF_KEY_USAGE_LABEL_HELLO_PRIVATE_SECTION: u8 = b'h';
/// KBKDF usage label for AES-GCM session keys.
pub const KBKDF_KEY_USAGE_LABEL_AES_GCM_SESSION_KEY: u8 = b's';
/// KBKDF usage label for a unique ID for ephemeral keys (not actually a key).
pub const KBKDF_KEY_USAGE_LABEL_EPHEMERAL_KEY_ID: u8 = b'e';
/// KBKDF usage label for a unique ID for ephemeral keys (not actually a key).
pub const KBKDF_KEY_USAGE_LABEL_RATCHET_KEY: u8 = b'+';
/// KBKDF usage label for ephemeral session key ratcheting.
pub const KBKDF_KEY_USAGE_LABEL_RATCHET_KEY: u8 = b'r';
/// Try to re-key ephemeral keys after this time.
pub const EPHEMERAL_SECRET_REKEY_AFTER_TIME: i64 = 300000; // 5 minutes

View file

@ -3,7 +3,7 @@
use std::mem::size_of;
use std::sync::atomic::AtomicU32;
use zerotier_core_crypto::aes_gmac_siv::{Aes, AesCtr};
use zerotier_core_crypto::aes::*;
use zerotier_core_crypto::hash::{hmac_sha384, SHA384};
use zerotier_core_crypto::kbkdf::zt_kbkdf_hmac_sha512;
use zerotier_core_crypto::p384::*;
@ -14,6 +14,7 @@ use zerotier_core_crypto::x25519::*;
use crate::util::buffer::Buffer;
use crate::util::marshalable::Marshalable;
use crate::util::pool::*;
use crate::vl1::identity::Identity;
use crate::vl1::symmetricsecret::SymmetricSecret;
@ -27,70 +28,76 @@ Basic outline of the ZeroTier V2 session protocol:
(1) Initiator sends INIT:
[16] random IV
[12] random IV
[4] always zero
[4] session ID
[1] FFFFTTTT where F == flags, T == message type (1 for INIT)
[1] ZeroTier protocol version
[4] reserved, always zero
[1] field ID of unencrypted initial ephemeral key
[...] outer ephemeral public key (currently always NIST P-384)
-- begin AES-CTR encryption using ephemeral/static AES key
-- begin AES-CTR encryption using ephemeral/static AES key ("setup key")
[...] additional tuples of field ID and field data
-- end AES-CTR encryption
[48] HMAC-SHA384 using static/static HMAC key
[48] HMAC-SHA384 using static HMAC key
Additional fields in INIT:
- Optional: additional ephemeral public keys
- Optional: first 16 bytes of SHA384 of "current" session key
- Optional: first 16 bytes of SHA384 of current session key (to check ratchet)
- Required: static ZeroTier identity of initiator
- Required: timestamp
- Required: timestamp to be echoed in ACK
(2) Responder sends ACK:
[16] random IV
[12] random IV
[4] always zero
[4] session ID
[1] FFFFTTTT where F == flags, T == message type (2 for ACK)
[1] ZeroTier protocol version
[4] reserved, always zero
-- begin AES-CTR encryption using same ephemeral/static AES key as INIT
-- begin AES-CTR encryption using SAME ephemeral/static AES key ("setup key")
[...] tuples of field ID and field data
-- end AES-CTR encryption
[48] HMAC-SHA384 using static/static HMAC key
[48] HMAC-SHA384 using static HMAC key
Fields in ACK:
- Required: ephemeral public key matching at least one ephemeral sent
- Optional: additional matching ephemeral keys
- Optional: first 16 bytes of SHA384 of "current" session key
- Required: timestamp
- Required: new ratchet count, 0 if no starting key supplied or can't ratchet
- Required: SHA384 of all (field ID, key) ephemeral keys from INIT in order sent
- Required: timestamp to be echoed in CONFIRM
- Required: echo of timestamp from INIT
(3) Initiator sends CONFIRM:
[16] AES-GMAC-SIV opaque tag
[12] AES-GCM tag
[4] counter (little-endian)
[4] session ID
[1] FFFFTTTT where F == flags, T == message type (3 for CONFIRM)
-- begin AES-GMAC-SIV encryption
-- begin AES-GCM encryption
[...] tuples of field ID and field data
?[48] optional extended authentication HMAC-SHA384 w/static key
Fields in CONFIRM:
- Required: echo of timestamp from ACK
CONFIRM is technically optional as a valid DATA message also counts as
confirmation, but having an explicit message allows for mutual exchange
of latency information and in the future other things.
CONFIRM has almost the same format as DATA and serves to notify the responder
side that a session is fully established.
It's important that the counter be incremented for CONFIRM and that this is
the same counter as DATA because this counts as a use of AES-GCM.
*** DATA packets:
[16] AES-GMAC-SIV opaque tag
[12] AES-GCM tag
[4] counter (little-endian)
[4] session ID
[1] FFFFTTTT where F == flags, T == message type (0 for DATA)
-- begin AES-GMAC-SIV encrypted data packet
-- begin AES-GCM encrypted data packet
[1] LNNNNNNN where N == fragment number and L is set if it's the last fragment
[...] data payload, typically starting with a ZeroTier VL1/VL2 protocol verb
?[48] optional extended authentication HMAC-SHA384 w/static key
When AES-GMAC-SIV packets are decrypted and authenticated, a sequential
message ID is exposed. This is used as a counter to prohibit replay attacks
within a session.
DATA payload must be at least two bytes in length. If it is not it will be zero
padded.
*** SINGLETON packets:
@ -104,6 +111,20 @@ in this case, so these messages should only be used for things that are
idempotent or have their own resistance to replay. There is also no automatic
fragmentation, so the full packet must fit in the underlying transport.
*** REJECT:
[12] random IV
[4] always zero
[4] session ID
[1] FFFFTTTT where F == flags, T == message type (2 for ACK)
[1] ZeroTier protocol version
[1] Error code
[48] HMAC-SHA384 using static HMAC key
A REJECT packet can be sent in response to INIT if the recipient will not accept
the connection attempt. REJECT is optional in that a rejected INIT can simply be
ignored.
*** Notes:
The initiator creates one or more ephemeral public keys and sends the first of
@ -135,9 +156,9 @@ When the responder receives INIT it computes the session key as follows:
Key agreements in (3) are performed in the following order, skipping any where both
sides have not furnished a key:
(1) Curve25519 ECDH
(2) Kyber (768)
(3) NIST P-384 ECDH
(1) Curve25519 ECDH (not currently sent but supported)
(2) Kyber768 (optional, for long duration forward secrecy against QC)
(3) NIST P-384 ECDH (the default outer ephemeral type)
The NIST key must be last for FIPS compliance reasons as it's a FIPS-compliant
algorithm and elliptic curve. FIPS allows HKDF using HMAC(salt, key) and allows
@ -158,28 +179,66 @@ its own key pair for this exchange. The raw Kyber algorithm is used since the
authentication in this session protocol is provided by HMAC-SHA384 using identity
keys.
HMAC always uses the static HMAC key derived from agreement between the sender and
the recipient identity, providing identity authentication of the exchange. It is
computed and appended after encryption but before obfuscation and is not itself
encrypted.
*** AES-CTR and AES-GCM IVs:
It's critically important never to duplicate and IV with CTR or GCM mode.
The AES-CTR IV is composed of the 12-byte random IV provided in the packet header
but with byte 0 set 0x00 if this side was the initiator (INIT sender) or 0x01 if
this side was the responder (ACK sender). The setup key is only used twice, for
INIT and ACK, so this makes a collision impossible instead of just improbable.
The AES-GCM IV is 12 bytes long and is created as follows:
RTSSIIIICCCC
- R: role: 0x00 if this side was the initiator, 0x01 if it was the responder
- T: type/flags field from outer header
- S: packet size modulo 65536 (little-endian)
- I: session ID
- C: counter (little-endian)
The first byte being 0 or 1 is critical here because the same key is used at
both ends and both counters will start at zero. If all else were the same then
both sides would use the same series of IVs. The placement of type/flags in
the second byte accomplishes the same as feeding the type byte in as AAD but
with less performance impact. The packet size in bytes 2 and 3 is technically
filler but may provide margin if someone figures out a way to do some kind of
length extension attack or something. Session ID inclusion also indirectly
includes the session ID as AAD. The counter MUST be incremented for each packet
or leopards will eat your face.
A single AES-GCM key can be used to send up to a maximum of 2^32 packets. Re-key
thresholds are set far below this, but the implementation will refuse to send
packets if the counter actually reaches the end.
*** Flags:
- 0x80 - use extended authentication: this flag is only used in DATA and is ignored
in setup exchanges. It indicates that the packet is terminated by a 48-byte full
HMAC-SHA384 using the HMAC key derived from the session key. Enabling this slows
things down but significantly strengthens the authentication posture of the
protocol. It's generally only used if required for compliance.
0x80 - use extended authentication: meaningful only in CONFIRM and DATA, this
flag indicates that a final HMAC-SHA384 has been appended to the packet
after encryption (but before DPI obfuscation) as in INIT and ACK. This
should be checked in addition to the GCM tag, providing even stronger
authentication at the expense of extra overhead. HMAC always uses the
static/static ("permanent") key.
*** Anti-DPI Obfuscation:
Obfuscation is applied to all session packets by AES encrypting a single block (ECB)
starting at byte index 12 in each packet. This single block is then decrypted by
the receiving end. The key for AES encryption is the first 32 bytes of the fingerprint
of the receiving side's ZeroTier identity.
Obfuscation is not technically part of our security posture with regard to either data
privacy or authentication. Its purpose is to make it much more difficult for deep packet
inspection (DPI) devices to classify ZeroTier traffic and therefore to provide some
additional margin against de-anonymization at scale.
This technically serves no purpose in terms of cryptographic security or authentication.
Its purpose is to make it difficult for deep packet inspectors to easily detect ZeroTier
traffic. For a DPI to correctly classify ZeroTier traffic it must know the identity of
the recipient and perform one single AES decrypt per packet.
It's applied by using AES-128 to encrypt one block (ECB) of each packet starting at byte
index 8. The key for encryption is the first 16 bytes of the recipient's ZeroTier
identity fingerprint hash. The receiving side then decrypts this block before processing
the packet. This 16-byte block covers all parts of the packet that aren't random.
Starting at byte index 12 randomizes this AES block even if other fields such as the
session ID are the same, as this incorporates four bytes of the random IV or tag field.
This forces a DPI device to know the identity of the recipient and to perform one AES
decryption per packet in order to distinguish ZeroTier traffic from pure noise.
*** Credits:
@ -188,10 +247,8 @@ Trevor Perrin and the Wireguard VPN protocol by Jason Donenfeld.
*/
pub const SESSION_SETUP_PACKET_SIZE_MAX: usize = 1400;
pub const SESSION_PACKET_SIZE_MIN: usize = 28;
pub const SESSION_DATA_HEADER_SIZE: usize = 22;
pub const SESSION_DATA_PAYLOAD_SIZE_MIN: usize = SESSION_PACKET_SIZE_MIN - SESSION_DATA_HEADER_SIZE;
pub const SESSION_SETUP_PACKET_SIZE_MAX: usize = crate::vl1::protocol::UDP_DEFAULT_MTU;
pub const SESSION_PACKET_SIZE_MIN: usize = 24;
const FLAGS_TYPE_INDEX: usize = 20;
const FLAGS_TYPE_TYPE_MASK: u8 = 0x0f;
@ -200,7 +257,8 @@ const MESSAGE_TYPE_DATA: u8 = 0x00;
const MESSAGE_TYPE_INIT: u8 = 0x01;
const MESSAGE_TYPE_ACK: u8 = 0x02;
const MESSAGE_TYPE_CONFIRM: u8 = 0x03;
const MESSAGE_TYPE_SINGLETON: u8 = 0x04;
const MESSAGE_TYPE_REJECT: u8 = 0x04;
const MESSAGE_TYPE_SINGLETON: u8 = 0x05;
const MESSAGE_FLAGS_EXTENDED_AUTH: u8 = 0x80;
@ -210,18 +268,24 @@ const FIELD_EPHEMERAL_C25519: u8 = 0x02;
const FIELD_EPHEMERAL_NISTP384: u8 = 0x03;
const FIELD_EPHEMERAL_KYBER_PUBLIC: u8 = 0x04;
const FIELD_EPHEMERAL_KYBER_ENCAPSULATED_SECRET: u8 = 0x05;
const FIELD_CURRENT_SESSION_KEY_HASH: u8 = 0x06;
const FIELD_TIMESTAMP: u8 = 0x07;
const FIELD_TIMESTAMP_ECHO: u8 = 0x08;
const FIELD_RATCHET_STARTING_KEY_HASH: u8 = 0x06;
const FIELD_ACK_RATCHET_COUNT: u8 = 0x07;
const FIELD_TIMESTAMP: u8 = 0x08;
const FIELD_TIMESTAMP_ECHO: u8 = 0x09;
const OBFUSCATION_INDEX: usize = 8;
const ROLE_INITIATOR: u8 = 0x00;
const ROLE_RESPONDER: u8 = 0x01;
#[derive(Clone, Copy)]
#[repr(C, packed)]
struct InitAckSingletonHeader {
iv: [u8; 16],
iv: [u8; 12],
zero: u32,
session_id: u32,
flags_type: u8,
protocol_version: u8,
zero: [u8; 4],
}
#[derive(Clone, Copy)]
@ -235,7 +299,8 @@ struct InitSingletonHeader {
#[derive(Clone, Copy)]
#[repr(C, packed)]
struct ConfirmDataHeader {
tag: [u8; 16],
tag: [u8; 12],
counter: u32,
session_id: u32,
flags_type: u8,
}
@ -244,29 +309,25 @@ struct InitiatorOfferedKeys {
p384: P384KeyPair,
kyber: Option<pqc_kyber::Keypair>,
ratchet_starting_key: Secret<64>,
ratchet_starting_count: u64,
setup_key: Secret<32>,
}
struct Keys {
/// Keys offered by local node and sent to remote, generated by initiate().
local_offered: Option<Box<InitiatorOfferedKeys>>,
/// Key resulting from agreement between the outer (unencrypted) ephemeral sent with INIT and the recipient's static identity key.
setup_key: Option<Secret<32>>,
/// Final key ratcheted from previous or starting key via agreement between all matching ephemeral pairs.
session_key: Option<SymmetricSecret>,
}
#[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64"))]
#[inline(always)]
fn zero_is_zero(z: &[u8; 4]) -> bool {
unsafe { *(z as *const [u8; 4]).cast::<u32>() == 0 }
}
/// Pool of encryptors and decryptors for AES-GCM initialized with the session key.
aes_gcm_pool: Option<(Pool<AesGcm, AesGcmPoolFactory>, Pool<AesGcm, AesGcmPoolFactory>)>,
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64", target_arch = "aarch64", target_arch = "powerpc64")))]
#[inline(always)]
fn zero_is_zero(z: &[u8; 4]) -> bool {
u32::from_ne_bytes(*z) == 0
/// Number of times ephemeral ratcheting has taken place, starts at 0 if starting from static.
ratchet_count: u64,
/// Set to true on initiator side when ACK is received on and on responder once CONFIRM is received.
established: bool,
}
/// ZeroTier V2 forward-secure session
@ -279,8 +340,8 @@ fn zero_is_zero(z: &[u8; 4]) -> bool {
/// as a ZeroTier peer.
#[allow(unused)]
pub(crate) struct Session<RD> {
/// Arbitrary object that may be attached by external code to this session (e.g. a peer).
pub related_data: RwLock<Option<RD>>,
/// Arbitrary object that may be attached by external code to this session.
pub related_data: RD,
/// Session keys of various types.
keys: RwLock<Keys>,
@ -291,26 +352,42 @@ pub(crate) struct Session<RD> {
/// A random number added to sent timestamps to not reveal exact local tick counter.
latency_timestamp_delta: u32,
/// Number of times session key has been used to encrypt data.
encrypt_uses: AtomicU32,
/// Number of times session key has been used to encrypt data with AES-GCM.
outgoing_counter: AtomicU32,
/// Number of times session key has been used to decrypt data.
decrypt_uses: AtomicU32,
/// Most recent incoming counter value.
last_incoming_counter: AtomicU32,
/// Most recent measured latency in milliseconds.
latency: AtomicU32,
/// Random session ID generated by initiator.
pub id: u32,
/// 0x00 for the initiator, 0x01 for the responder side.
role: u8,
}
pub(crate) trait SessionContext<RD> {
/// Iterate through all sessions matching an ID until the supplied function returns false.
fn sessions_with_id<F: FnMut(&Session<RD>) -> bool>(&self, id: u32, f: F);
/// Check whether or not to accept a new session and get initial related data value.
///
/// This is called when this side gets an INIT. A return of None causes the request to be
/// silently ignored. Otherwise this must return the initial value of the related_data
/// field for the new session.
fn incoming_session(&self, new_session_id: u32, remote_identity: &Identity) -> Option<RD>;
}
impl<RD> Session<RD> {
/// Create an initiator session and return it and the packet to be sent.
///
/// ZeroTier V2 sessions can only currently be used with identities that also contain
/// a NIST P-384 ECDH public key.
///
/// The obfuscation key must be an AES-128 ECB instance initialized from the first 16
/// bytes of the remote identity's fingerprint hash.
pub fn initiate(
local_identity: &Identity,
remote_identity: &Identity,
@ -318,22 +395,23 @@ impl<RD> Session<RD> {
static_key: &SymmetricSecret,
current_session: Option<&Self>,
current_time: i64,
initial_related_data: RD,
) -> Option<(Self, Buffer<SESSION_SETUP_PACKET_SIZE_MAX>)> {
let mut packet: Buffer<SESSION_SETUP_PACKET_SIZE_MAX> = Buffer::new();
let mut id = random::next_u32_secure();
id |= (id == 0) as u32;
let id = random::next_u32_secure();
let ephemeral_p384 = P384KeyPair::generate();
{
let mut ctr_iv = {
let h: &mut InitSingletonHeader = packet.append_struct_get_mut().unwrap();
random::fill_bytes_secure(&mut h.h.iv);
h.h.session_id = id; // actually [u8; 4] so endian is irrelevant
h.h.flags_type = MESSAGE_FLAGS_EXTENDED_AUTH | MESSAGE_TYPE_INIT;
h.h.protocol_version = crate::vl1::protocol::PROTOCOL_VERSION;
h.outer_ephemeral_field_id = FIELD_EPHEMERAL_NISTP384;
h.outer_ephemeral = *ephemeral_p384.public_key_bytes();
}
h.outer_ephemeral.copy_from_slice(ephemeral_p384.public_key_bytes());
h.h.iv.clone()
};
ctr_iv[0] = ROLE_INITIATOR;
assert!(packet.append_u8(FIELD_INITIATOR_IDENTITY).is_ok());
assert!(local_identity.marshal(&mut packet).is_ok());
@ -342,17 +420,20 @@ impl<RD> Session<RD> {
assert!(packet.append_u8(FIELD_EPHEMERAL_KYBER_PUBLIC).is_ok());
assert!(packet.append_bytes_fixed(&ephemeral_kyber.public).is_ok());
let mut ratchet_starting_count = 0;
let ratchet_starting_key = current_session
.and_then(|cs| {
cs.keys.read().session_key.as_ref().map(|cs_key| {
assert!(packet.append_u8(FIELD_CURRENT_SESSION_KEY_HASH).is_ok());
assert!(packet.append_bytes_fixed(&cs_key.key_hash).is_ok());
let keys = cs.keys.read();
keys.session_key.as_ref().map(|cs_key| {
ratchet_starting_count = keys.ratchet_count;
assert!(packet.append_u8(FIELD_RATCHET_STARTING_KEY_HASH).is_ok());
assert!(packet.append_bytes(&SHA384::hash(&cs_key.key.0)[..16]).is_ok());
zt_kbkdf_hmac_sha512(cs_key.key.as_bytes(), crate::vl1::protocol::security_constants::KBKDF_KEY_USAGE_LABEL_RATCHET_KEY)
})
})
.unwrap_or_else(|| zt_kbkdf_hmac_sha512(static_key.key.as_bytes(), crate::vl1::protocol::security_constants::KBKDF_KEY_USAGE_LABEL_RATCHET_KEY));
let latency_timestamp_delta = random::next_u32_secure();
let latency_timestamp_delta = random::xorshift64_random() as u32;
assert!(packet.append_u8(FIELD_TIMESTAMP).is_ok());
assert!(packet.append_u64((current_time as u64).wrapping_add(latency_timestamp_delta as u64)).is_ok());
@ -360,7 +441,9 @@ impl<RD> Session<RD> {
if let Some(responder_p384) = remote_identity.p384.as_ref() {
if let Some(sk) = ephemeral_p384.agree(&responder_p384.ecdh) {
setup_key = Secret(SHA384::hash(sk.as_bytes())[..32].try_into().unwrap());
AesCtr::new(setup_key.as_bytes()).crypt_in_place(&mut packet.as_bytes_mut()[size_of::<InitSingletonHeader>()..]);
let mut ctr = AesCtr::new(setup_key.as_bytes());
ctr.init(&ctr_iv);
ctr.crypt_in_place(&mut packet.as_bytes_mut()[size_of::<InitSingletonHeader>()..]);
} else {
return None;
}
@ -370,26 +453,31 @@ impl<RD> Session<RD> {
assert!(packet.append_bytes(&hmac_sha384(static_key.packet_hmac_key.as_bytes(), packet.as_bytes())).is_ok());
obfuscation_key.encrypt_block_in_place(&mut packet.as_bytes_mut()[12..28]);
obfuscation_key.encrypt_block_in_place(&mut packet.as_bytes_mut()[OBFUSCATION_INDEX..(OBFUSCATION_INDEX + 16)]);
return Some((
Self {
related_data: RwLock::new(None),
related_data: initial_related_data,
keys: RwLock::new(Keys {
local_offered: Some(Box::new(InitiatorOfferedKeys {
p384: ephemeral_p384,
kyber: Some(ephemeral_kyber),
ratchet_starting_key,
ratchet_starting_count,
setup_key,
})),
setup_key: Some(setup_key),
session_key: None,
aes_gcm_pool: None,
ratchet_count: 0, // updated if the remote side can also ratchet
established: false,
}),
creation_time: current_time,
latency_timestamp_delta,
encrypt_uses: AtomicU32::new(0),
decrypt_uses: AtomicU32::new(0),
outgoing_counter: AtomicU32::new(0),
last_incoming_counter: AtomicU32::new(0),
latency: AtomicU32::new(0),
id,
role: ROLE_INITIATOR,
},
packet,
));
@ -404,85 +492,85 @@ impl<RD> Session<RD> {
packet: &mut Buffer<L>,
) -> bool {
if packet.len() >= SESSION_PACKET_SIZE_MIN {
obfuscation_key.decrypt_block_in_place(&mut packet.as_bytes_mut()[12..28]);
obfuscation_key.decrypt_block_in_place(&mut packet.as_bytes_mut()[OBFUSCATION_INDEX..(OBFUSCATION_INDEX + 16)]);
let flags = packet.u8_at(FLAGS_TYPE_INDEX).unwrap();
let message_type = flags & FLAGS_TYPE_TYPE_MASK;
match message_type {
MESSAGE_TYPE_DATA | MESSAGE_TYPE_CONFIRM => if let Ok(header) = packet.struct_at::<ConfirmDataHeader>(0) {},
MESSAGE_TYPE_INIT | MESSAGE_TYPE_ACK | MESSAGE_TYPE_SINGLETON => {
if let Ok(header) = packet.struct_at::<InitAckSingletonHeader>(0) {
if zero_is_zero(&header.zero) {
let (
mut remote_identity,
mut remote_offered_c25519,
mut remote_offered_nistp384,
mut remote_offered_kyber_public,
mut remote_timestamp,
mut remote_session_key_hash,
) = (None, None, None, None, -1, None);
let (
mut remote_identity,
mut remote_offered_c25519,
mut remote_offered_nistp384,
mut remote_offered_kyber_public,
mut remote_timestamp,
mut remote_session_key_hash,
) = (None, None, None, None, -1, None);
let mut cursor = size_of::<InitAckSingletonHeader>();
loop {
if let Ok(field_type) = packet.read_u8(&mut cursor) {
match field_type {
FIELD_DATA => {}
FIELD_INITIATOR_IDENTITY => {
if let Ok(id) = Identity::unmarshal(packet, &mut cursor) {
remote_identity = Some(id);
} else {
return false;
}
let mut cursor = size_of::<InitAckSingletonHeader>();
loop {
if let Ok(field_type) = packet.read_u8(&mut cursor) {
match field_type {
FIELD_DATA => {}
FIELD_INITIATOR_IDENTITY => {
if let Ok(id) = Identity::unmarshal(packet, &mut cursor) {
remote_identity = Some(id);
} else {
return false;
}
FIELD_EPHEMERAL_C25519 => {
if let Ok(k) = packet.read_bytes_fixed::<C25519_PUBLIC_KEY_SIZE>(&mut cursor) {
remote_offered_c25519 = Some(k);
} else {
return false;
}
}
FIELD_EPHEMERAL_NISTP384 => {
if let Ok(k) = packet.read_bytes_fixed::<P384_PUBLIC_KEY_SIZE>(&mut cursor) {
remote_offered_nistp384 = Some(k);
} else {
return false;
}
}
FIELD_EPHEMERAL_KYBER_PUBLIC => {
if let Ok(k) = packet.read_bytes_fixed::<{ pqc_kyber::KYBER_PUBLICKEYBYTES }>(&mut cursor) {
remote_offered_kyber_public = Some(k);
} else {
return false;
}
}
FIELD_EPHEMERAL_KYBER_ENCAPSULATED_SECRET => {}
FIELD_CURRENT_SESSION_KEY_HASH => {
if let Ok(k) = packet.read_bytes_fixed::<16>(&mut cursor) {
remote_session_key_hash = Some(k);
} else {
return false;
}
}
FIELD_TIMESTAMP => {
if let Ok(ts) = packet.read_varint(&mut cursor) {
remote_timestamp = ts as i64;
} else {
return false;
}
}
FIELD_TIMESTAMP_ECHO => {
if let Ok(ts) = packet.read_varint(&mut cursor) {
} else {
return false;
}
}
_ => {}
}
if message_type == MESSAGE_TYPE_INIT {}
} else {
break;
FIELD_EPHEMERAL_C25519 => {
if let Ok(k) = packet.read_bytes_fixed::<C25519_PUBLIC_KEY_SIZE>(&mut cursor) {
remote_offered_c25519 = Some(k);
} else {
return false;
}
}
FIELD_EPHEMERAL_NISTP384 => {
if let Ok(k) = packet.read_bytes_fixed::<P384_PUBLIC_KEY_SIZE>(&mut cursor) {
remote_offered_nistp384 = Some(k);
} else {
return false;
}
}
FIELD_EPHEMERAL_KYBER_PUBLIC => {
if let Ok(k) = packet.read_bytes_fixed::<{ pqc_kyber::KYBER_PUBLICKEYBYTES }>(&mut cursor) {
remote_offered_kyber_public = Some(k);
} else {
return false;
}
}
FIELD_EPHEMERAL_KYBER_ENCAPSULATED_SECRET => {}
FIELD_CURRENT_SESSION_KEY_HASH => {
if let Ok(k) = packet.read_bytes_fixed::<16>(&mut cursor) {
remote_session_key_hash = Some(k);
} else {
return false;
}
}
FIELD_TIMESTAMP => {
if let Ok(ts) = packet.read_varint(&mut cursor) {
remote_timestamp = ts as i64;
} else {
return false;
}
}
FIELD_TIMESTAMP_ECHO => {
if let Ok(ts) = packet.read_varint(&mut cursor) {
} else {
return false;
}
}
_ => {}
}
if message_type == MESSAGE_TYPE_INIT {}
} else {
break;
}
}
}
@ -495,6 +583,18 @@ impl<RD> Session<RD> {
}
}
pub(crate) struct AesGcmPoolFactory(Secret<32>, bool);
impl PoolFactory<AesGcm> for AesGcmPoolFactory {
#[inline(always)]
fn create(&self) -> AesGcm {
AesGcm::new(&self.0 .0, self.1)
}
#[inline(always)]
fn reset(&self, _: &mut AesGcm) {}
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -1,7 +1,6 @@
// (c) 2020-2022 ZeroTier, Inc. -- currently propritery pending actual release and licensing. See LICENSE.md.
use zerotier_core_crypto::aes_gmac_siv::AesGmacSiv;
use zerotier_core_crypto::hash::SHA384;
use zerotier_core_crypto::kbkdf::*;
use zerotier_core_crypto::secret::Secret;
@ -15,12 +14,6 @@ pub(crate) struct SymmetricSecret {
/// Master key from which other keys are derived.
pub key: Secret<64>,
/// First 16 bytes of SHA384(key), used to identify sessions for ratcheting.
pub key_hash: [u8; 16],
/// Key for private fields in HELLO packets.
pub hello_private_section_key: Secret<48>,
/// Key used for HMAC extended validation on packets like HELLO.
pub packet_hmac_key: Secret<48>,
@ -31,15 +24,13 @@ pub(crate) struct SymmetricSecret {
impl SymmetricSecret {
/// Create a new symmetric secret, deriving all sub-keys and such.
pub fn new(key: Secret<64>) -> SymmetricSecret {
let hello_private_section_key = zt_kbkdf_hmac_sha384(&key.0[..48], security_constants::KBKDF_KEY_USAGE_LABEL_HELLO_PRIVATE_SECTION);
let packet_hmac_key = zt_kbkdf_hmac_sha384(&key.0[..48], security_constants::KBKDF_KEY_USAGE_LABEL_PACKET_HMAC);
let aes_factory =
AesGmacSivPoolFactory(zt_kbkdf_hmac_sha384(&key.0[..48], security_constants::KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0).first_n(), zt_kbkdf_hmac_sha384(&key.0[..48], security_constants::KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1).first_n());
let key_hash = SHA384::hash(key.as_bytes())[..16].try_into().unwrap();
let aes_factory = AesGmacSivPoolFactory(
zt_kbkdf_hmac_sha384(&key.0[..48], security_constants::KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K0).first_n(),
zt_kbkdf_hmac_sha384(&key.0[..48], security_constants::KBKDF_KEY_USAGE_LABEL_AES_GMAC_SIV_K1).first_n(),
);
SymmetricSecret {
key,
key_hash,
hello_private_section_key,
packet_hmac_key,
aes_gmac_siv: Pool::new(2, aes_factory),
}