mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-25 16:36:54 +02:00
More session work, cleanup, AES in core crypto, and vendor the kyber library so we can remove no_std.
This commit is contained in:
parent
b64968ff99
commit
a3b748a0a6
85 changed files with 11032 additions and 335 deletions
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
11
third_party/kyber/.gitignore
vendored
Normal 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
65
third_party/kyber/Cargo.toml
vendored
Normal 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
201
third_party/kyber/LICENSE-APACHE
vendored
Normal 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
74
third_party/kyber/benches/api.rs
vendored
Normal 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
26
third_party/kyber/benches/readme.md
vendored
Normal 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
19
third_party/kyber/build.rs
vendored
Normal 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
17
third_party/kyber/contributing.md
vendored
Normal 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
27
third_party/kyber/examples/ake.rs
vendored
Normal 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
18
third_party/kyber/examples/kem.rs
vendored
Normal 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
27
third_party/kyber/examples/uake.rs
vendored
Normal 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
12
third_party/kyber/fuzz/Cargo.toml
vendored
Normal 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
38
third_party/kyber/fuzz/readme.md
vendored
Normal 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
17
third_party/kyber/fuzz/src/bin/decap.rs
vendored
Normal 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
19
third_party/kyber/fuzz/src/bin/encap.rs
vendored
Normal 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));
|
||||
});
|
||||
};
|
||||
}
|
20
third_party/kyber/fuzz/src/bin/keypair.rs
vendored
Normal file
20
third_party/kyber/fuzz/src/bin/keypair.rs
vendored
Normal 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
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
243
third_party/kyber/readme.md
vendored
Normal file
|
@ -0,0 +1,243 @@
|
|||
|
||||
|
||||
<p align="center">
|
||||
<img src="./kyber.png"/>
|
||||
</p>
|
||||
|
||||
|
||||
# Kyber
|
||||
[](https://github.com/Argyle-Cybersystems/kyber/actions)
|
||||
[](https://crates.io/crates/pqc-kyber)
|
||||
[](https://www.npmjs.com/package/pqc-kyber)
|
||||
[](https://deps.rs/repo/github/Argyle-Cybersystems/kyber)
|
||||
[](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
103
third_party/kyber/src/api.rs
vendored
Normal 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
177
third_party/kyber/src/avx2/aes256ctr.rs
vendored
Normal 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
110
third_party/kyber/src/avx2/align.rs
vendored
Normal 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
103
third_party/kyber/src/avx2/basemul.S
vendored
Normal 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
136
third_party/kyber/src/avx2/cbd.rs
vendored
Normal 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
43
third_party/kyber/src/avx2/consts.h
vendored
Normal 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
116
third_party/kyber/src/avx2/consts.rs
vendored
Normal 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
651
third_party/kyber/src/avx2/fips202.rs
vendored
Normal 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
280
third_party/kyber/src/avx2/fips202x4.rs
vendored
Normal 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
117
third_party/kyber/src/avx2/fq.S
vendored
Normal 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
30
third_party/kyber/src/avx2/fq.inc
vendored
Normal 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
681
third_party/kyber/src/avx2/indcpa.rs
vendored
Normal 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
246
third_party/kyber/src/avx2/invntt.S
vendored
Normal 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
220
third_party/kyber/src/avx2/keccak4x.rs
vendored
Normal 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
13
third_party/kyber/src/avx2/mod.rs
vendored
Normal 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
212
third_party/kyber/src/avx2/ntt.S
vendored
Normal 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
417
third_party/kyber/src/avx2/poly.rs
vendored
Normal 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
290
third_party/kyber/src/avx2/polyvec.rs
vendored
Normal 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
380
third_party/kyber/src/avx2/rejsample.rs
vendored
Normal 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
255
third_party/kyber/src/avx2/shuffle.S
vendored
Normal 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
25
third_party/kyber/src/avx2/shuffle.inc
vendored
Normal 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
43
third_party/kyber/src/avx2/verify.rs
vendored
Normal 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
19
third_party/kyber/src/error.rs
vendored
Normal 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
128
third_party/kyber/src/kem.rs
vendored
Normal 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
388
third_party/kyber/src/kex.rs
vendored
Normal 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
149
third_party/kyber/src/lib.rs
vendored
Normal 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
67
third_party/kyber/src/params.rs
vendored
Normal 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;
|
636
third_party/kyber/src/reference/aes256ctr.rs
vendored
Normal file
636
third_party/kyber/src/reference/aes256ctr.rs
vendored
Normal 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
98
third_party/kyber/src/reference/cbd.rs
vendored
Normal 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)
|
||||
}
|
652
third_party/kyber/src/reference/fips202.rs
vendored
Normal file
652
third_party/kyber/src/reference/fips202.rs
vendored
Normal 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);
|
||||
}
|
||||
|
316
third_party/kyber/src/reference/indcpa.rs
vendored
Normal file
316
third_party/kyber/src/reference/indcpa.rs
vendored
Normal 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);
|
||||
}
|
9
third_party/kyber/src/reference/mod.rs
vendored
Normal file
9
third_party/kyber/src/reference/mod.rs
vendored
Normal 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
154
third_party/kyber/src/reference/ntt.rs
vendored
Normal 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
335
third_party/kyber/src/reference/poly.rs
vendored
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
241
third_party/kyber/src/reference/polyvec.rs
vendored
Normal file
241
third_party/kyber/src/reference/polyvec.rs
vendored
Normal 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]);
|
||||
}
|
||||
}
|
41
third_party/kyber/src/reference/reduce.rs
vendored
Normal file
41
third_party/kyber/src/reference/reduce.rs
vendored
Normal 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
|
||||
}
|
||||
|
||||
|
37
third_party/kyber/src/reference/verify.rs
vendored
Normal file
37
third_party/kyber/src/reference/verify.rs
vendored
Normal 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
10
third_party/kyber/src/rng.rs
vendored
Normal 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
205
third_party/kyber/src/symmetric.rs
vendored
Normal 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
95
third_party/kyber/src/wasm.rs
vendored
Normal 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;
|
||||
}
|
||||
}
|
6
third_party/kyber/tests/KATs/SHA256SUMS_ORIG
vendored
Normal file
6
third_party/kyber/tests/KATs/SHA256SUMS_ORIG
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
6730bb552c22d9d2176ffb5568e48eb30952cf1f065073ec5f9724f6a3c6ea85 tvecs512
|
||||
2ea81fa2d7e3c1970409b9d77d6c5137aeb4573e856ca79eab4393b70352e85b tvecs512-90s
|
||||
667c8ca2ca93729c0df6ff24588460bad1bbdbfb64ece0fe8563852a7ff348c6 tvecs768
|
||||
a1b8fe37e3fc58a8511c63a7187d3626a1a98c5d3bb67000fe9a02be7199d952 tvecs768-90s
|
||||
ff1a854b9b6761a70c65ccae85246fe0596a949e72eae0866a8a2a2d4ea54b10 tvecs1024
|
||||
f547f5361f933e6489d2385524ffd36893063c6b9cc3f921514b4ebb9daefdaa tvecs1024-90s
|
42
third_party/kyber/tests/KATs/build_kats.sh
vendored
Normal file
42
third_party/kyber/tests/KATs/build_kats.sh
vendored
Normal 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
48
third_party/kyber/tests/KATs/readme.md
vendored
Normal 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
75
third_party/kyber/tests/kat.rs
vendored
Normal 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
12
third_party/kyber/tests/kem.rs
vendored
Normal 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
28
third_party/kyber/tests/kex.rs
vendored
Normal 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
100
third_party/kyber/tests/load/mod.rs
vendored
Normal 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>>()
|
||||
}
|
14
third_party/kyber/tests/rand_bufs/Makefile
vendored
Normal file
14
third_party/kyber/tests/rand_bufs/Makefile
vendored
Normal 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
|
||||
|
80
third_party/kyber/tests/rand_bufs/generate_bufs.c
vendored
Normal file
80
third_party/kyber/tests/rand_bufs/generate_bufs.c
vendored
Normal 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;
|
||||
}
|
100
third_party/kyber/tests/rand_bufs/outputs/crypto_kem_keypair
vendored
Normal file
100
third_party/kyber/tests/rand_bufs/outputs/crypto_kem_keypair
vendored
Normal 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
|
100
third_party/kyber/tests/rand_bufs/outputs/encode
vendored
Normal file
100
third_party/kyber/tests/rand_bufs/outputs/encode
vendored
Normal 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
|
100
third_party/kyber/tests/rand_bufs/outputs/indcpa_keypair
vendored
Normal file
100
third_party/kyber/tests/rand_bufs/outputs/indcpa_keypair
vendored
Normal 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
|
27
third_party/kyber/tests/rand_bufs/readme.md
vendored
Normal file
27
third_party/kyber/tests/rand_bufs/readme.md
vendored
Normal 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
221
third_party/kyber/tests/rand_bufs/rng.c
vendored
Normal 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
55
third_party/kyber/tests/rand_bufs/rng.h
vendored
Normal 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
27
third_party/kyber/tests/readme.md
vendored
Normal 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
107
third_party/kyber/tests/run_all_tests.sh
vendored
Normal 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"
|
|
@ -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"
|
||||
|
|
473
zerotier-core-crypto/src/aes.rs
Normal file
473
zerotier-core-crypto/src/aes.rs
Normal 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};
|
|
@ -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;
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue