feat: initial migration out of exp
This commit is contained in:
commit
06c945c4aa
|
@ -0,0 +1,9 @@
|
|||
/.cargo
|
||||
/pubkeys.ron
|
||||
/ownedkeys.ron
|
||||
/scripts/dist
|
||||
/Cargo.lock
|
||||
/target
|
||||
/dilithium/target
|
||||
/dilithium/Cargo.lock
|
||||
/dilithium/.github
|
|
@ -0,0 +1,25 @@
|
|||
[package]
|
||||
name = "kdt"
|
||||
version = "0.1.0-alpha"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
pqc_kyber = { git = "https://github.com/Argyle-Software/kyber.git", features = ["std", "kyber1024"] }
|
||||
# normal dilithium lib with a patch to create `Keypair`s from their values
|
||||
pqc_dilithium = { path = "./dilithium/" }
|
||||
base64 = "0.21.2"
|
||||
aes-gcm = "0.10.2"
|
||||
generic-array = "0.14.7"
|
||||
clap = { version = "4.3.0", features = ["derive"] }
|
||||
sha2 = "0.10.6"
|
||||
colored = "2.0.0"
|
||||
ron = "0.8.0"
|
||||
serde = { version = "1.0.163", features = ["derive"] }
|
||||
|
||||
[profile.release]
|
||||
strip = true
|
||||
opt-level = 3
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
panic = "abort"
|
|
@ -0,0 +1,21 @@
|
|||
# KDT
|
||||
Mirai's experimental, post-quantum successor to GPG 🔒
|
||||
|
||||
---
|
||||
|
||||
KDT is the experimental Kyber-Dilithium Toolset - like GPG, but post-quantum! It's not ready for production use just yet, but our aim is that it'll help usher in a "new era" of communications safety, and one that's not vulnerable to quantum attacks.
|
||||
|
||||
## To-dos
|
||||
- [x] Store keyset and private keys in local files
|
||||
- [x] Asymmetric encryption and decryption (CRYSTALS-Kyber-backed 256 bit AES)
|
||||
- [ ] Wrap encryption with RSA to undoubtedly achieve the verified cryptographic strength of RSA (because CRYSTALS-Kyber's security hasn't been completely verified)
|
||||
- [ ] Signing and signature verification (CRYSTALS-Dilithium)
|
||||
- [ ] Improve user friendliness
|
||||
|
||||
---
|
||||
|
||||
Developed with <3 by [Mirai](https://git.disroot.org/mirai).
|
||||
|
||||
![Mirai organisation logo](https://git.disroot.org/avatars/8c879ce5f27a376a3f79b11a4e59c9fcb622d43de8a08dde39333aecf673ac9c)
|
||||
|
||||
みらい • ˶ᵔ ᵕ ᵔ˶ • Mirai
|
|
@ -0,0 +1,12 @@
|
|||
## 0.1.1 - 2023-2-2
|
||||
|
||||
* Refactor: Consolidated symmetric modules
|
||||
|
||||
## 0.1.0 - 2023-2-1
|
||||
|
||||
Initial release
|
||||
|
||||
### Added
|
||||
- AES mode
|
||||
- Randomised signing
|
||||
- CI runners for linux, macOS and Windows on stable and v1.50.0
|
|
@ -0,0 +1,41 @@
|
|||
[package]
|
||||
name = "pqc_dilithium"
|
||||
version = "0.1.1"
|
||||
authors = ["Mitchell Berry <foss@mitchellberry.com>"]
|
||||
description = "A post-quantum cryptographic signature scheme based on the hardness of lattice problems over module lattices"
|
||||
edition = "2018"
|
||||
categories = ["cryptography"]
|
||||
keywords = ["signature", "post-quantum", "signing"]
|
||||
repository = "https://github.com/Argyle-Software/dilithium/"
|
||||
license = "MIT OR Apache-2.0"
|
||||
exclude = ["tests/KAT"]
|
||||
rust-version = "1.50"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
|
||||
[dev-dependencies]
|
||||
pqc_core = {version = "0.1.0", features = ["load"]}
|
||||
|
||||
[target.'cfg(bench)'.dev-dependencies.criterion]
|
||||
criterion = "0.4.0"
|
||||
|
||||
[[bench]]
|
||||
name = "api"
|
||||
harness = false
|
||||
|
||||
[features]
|
||||
# By default this library uses mode3, also called Dilithium3
|
||||
mode2 = []
|
||||
mode3 = []
|
||||
mode5 = []
|
||||
|
||||
# Enables AES mode which uses AES-256 in counter mode instead of SHAKE
|
||||
aes = []
|
||||
|
||||
# Produces a random signature everytime when signing the same message.
|
||||
# One may want to consider randomized signatures in situations where the side channel
|
||||
# attacks exploiting determinism are applicable. Another situation
|
||||
# where one may want to avoid determinism is when the signer does not wish to reveal the
|
||||
# message that is being signed.
|
||||
random_signing = []
|
|
@ -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.
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2023 Mitchell Berry
|
||||
|
||||
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.
|
|
@ -0,0 +1,143 @@
|
|||
<p align="center">
|
||||
<img src="./dilithium.png"/>
|
||||
</p>
|
||||
|
||||
|
||||
# Dilithium
|
||||
[![Build Status](https://github.com/Argyle-Software/dilithium/actions/workflows/kat.yml/badge.svg)](https://github.com/Argyle-Software/dilithium/actions)
|
||||
[![Crates](https://img.shields.io/crates/v/pqc-dilithium)](https://crates.io/crates/pqc-dilithium)
|
||||
[![License](https://img.shields.io/crates/l/pqc_dilithium)](https://github.com/Argyle-Software/dilithium/blob/master/LICENSE-MIT)
|
||||
[![License](https://img.shields.io/crates/l/pqc_dilithium)](https://github.com/Argyle-Software/dilithium/blob/master/LICENSE-APACHE)
|
||||
|
||||
A rust implementation of the Dilithium, a KEM standardised by the NIST Post-Quantum Standardization Project - fork with `KeyPair` restoration support.
|
||||
|
||||
See the [**features**](#features) section for different options regarding security levels and modes of operation. The default security setting is Dilithium3.
|
||||
|
||||
It is recommended to use Dilithium in a hybrid system alongside a traditional signature algorithm such as ed25519.
|
||||
|
||||
**Minimum Supported Rust Version: 1.50.0**
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
cargo add pqc_dilithium
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```rust
|
||||
use pqc_dilithium::*;
|
||||
```
|
||||
|
||||
### Key Generation
|
||||
```rust
|
||||
let keys = Keypair::generate();
|
||||
assert!(keys.public.len() == PUBLICKEYBYTES);
|
||||
assert!(keys.expose_secret().len() == SECRETKEYBYTES);
|
||||
```
|
||||
|
||||
### Signing
|
||||
```rust
|
||||
let msg = "Hello".as_bytes();
|
||||
let sig = keys.sign(&msg);
|
||||
assert!(sig.len() == SIGNBYTES);
|
||||
```
|
||||
|
||||
### Verification
|
||||
```rust
|
||||
let sig_verify = verify(&sig, &msg, &keys.public);
|
||||
assert!(sig_verify.is_ok());
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## AES mode
|
||||
|
||||
Dilithium-AES, that uses AES-256 in counter mode instead of SHAKE to
|
||||
expand the matrix and the masking vectors, and to sample the secret polynomials.
|
||||
This offers hardware speedups on certain platforms.
|
||||
|
||||
---
|
||||
|
||||
## Randomized signing
|
||||
|
||||
One may want to consider randomized signatures in situations where the side channel
|
||||
attacks of [SBB+18, PSS+18] exploiting determinism are applicable. Another situation
|
||||
where one may want to avoid determinism is when the signer does not wish to reveal the
|
||||
message that is being signed. While there is no timing leakage of the secret key, there is
|
||||
timing leakage of the message if the scheme is deterministic. Since the randomness of the
|
||||
scheme is derived from the message, the number of aborts for a particular message will
|
||||
always be the same.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
By default this library uses Dilithium3
|
||||
|
||||
| Name | Description |
|
||||
|----------------|-------------------------------------------------------------------------------------------------------------------|
|
||||
| mode2 | Uses Dilithium2 |
|
||||
| mode5 | Uses Dilithium5 |
|
||||
| aes | Uses AES256-CTR instead of SHAKE |
|
||||
| random_signing | Enables randomized signing of messages |
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
To run the known answer tests, you'll need to enable the `dilithium_kat` in `RUSTFLAGS` eg.
|
||||
|
||||
```shell
|
||||
RUSTFLAGS="--cfg dilithium_kat" cargo test
|
||||
```
|
||||
|
||||
To run through all possible features use the [`test_matrix.sh`](./tests/test_matrix.sh) script.
|
||||
|
||||
---
|
||||
|
||||
# Benchmarking
|
||||
|
||||
This library uses the criterion benchmarking suite. To use you must enable
|
||||
`bench` eg.
|
||||
|
||||
```shell
|
||||
RUSTFLAGS="--cfg bench" cargo bench
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alternatives
|
||||
|
||||
The PQClean project has rust bindings for their C post quantum libraries.
|
||||
|
||||
https://github.com/rustpq/pqcrypto/tree/main/pqcrypto-dilithium
|
||||
|
||||
---
|
||||
|
||||
## About
|
||||
|
||||
Dilithium is a digital signature scheme that is strongly secure under chosen message attacks based on the hardness of lattice problems over module lattices. The security notion means that an adversary having access to a signing oracle cannot produce a signature of a message whose signature he hasn't yet seen, nor produce a different signature of a message that he already saw signed. Dilithium has been standardised by the [NIST post-quantum cryptography project](https://csrc.nist.gov/Projects/post-quantum-cryptography/selected-algorithms-2022).
|
||||
|
||||
The official website: https://pq-crystals.org/dilithium/
|
||||
|
||||
Authors of the Dilithium 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, by submitting PR's you agree for the code to be dual licensed under MIT/Apache 2.0
|
|
@ -0,0 +1,8 @@
|
|||
# Benchmarking
|
||||
|
||||
This library uses the criterion benchmarking suite. To use you must enable
|
||||
`bench` in `RUSTFLAGS` eg.
|
||||
|
||||
```shell
|
||||
RUSTFLAGS="--cfg bench" cargo bench
|
||||
```
|
|
@ -0,0 +1,22 @@
|
|||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use pqc_dilithium::*;
|
||||
|
||||
fn sign_small_msg(c: &mut Criterion) {
|
||||
let keys = Keypair::generate();
|
||||
let msg = "Hello".as_bytes();
|
||||
c.bench_function("Sign Small Message", |b| {
|
||||
b.iter(|| keys.sign(black_box(msg)))
|
||||
});
|
||||
}
|
||||
|
||||
fn verify_small_msg(c: &mut Criterion) {
|
||||
let keys = Keypair::generate();
|
||||
let msg = "Hello".as_bytes();
|
||||
let sig = keys.sign(msg);
|
||||
c.bench_function("Verify Small Message", |b| {
|
||||
b.iter(|| verify(black_box(sig), black_box(msg), black_box(&keys.public)))
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, sign_small_msg, verify_small_msg);
|
||||
criterion_main!(benches);
|
Binary file not shown.
After Width: | Height: | Size: 5.6 KiB |
|
@ -0,0 +1,2 @@
|
|||
tab_spaces = 2
|
||||
max_width = 80
|
|
@ -0,0 +1,502 @@
|
|||
pub const AES256CTR_BLOCKBYTES: usize = 64;
|
||||
|
||||
pub struct Aes256ctrCtx {
|
||||
pub sk_exp: [u64; 120],
|
||||
pub ivw: [u32; 16],
|
||||
}
|
||||
|
||||
impl Default for Aes256ctrCtx {
|
||||
fn default() -> 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 = q[7];
|
||||
let x1 = q[6];
|
||||
let x2 = q[5];
|
||||
let x3 = q[4];
|
||||
let x4 = q[3];
|
||||
let x5 = q[2];
|
||||
let x6 = q[1];
|
||||
let x7 = q[0];
|
||||
|
||||
// Top linear transformation.
|
||||
let y14 = x3 ^ x5;
|
||||
let y13 = x0 ^ x6;
|
||||
let y9 = x0 ^ x3;
|
||||
let y8 = x0 ^ x5;
|
||||
let t0 = x1 ^ x2;
|
||||
let y1 = t0 ^ x7;
|
||||
let y4 = y1 ^ x3;
|
||||
let y12 = y13 ^ y14;
|
||||
let y2 = y1 ^ x0;
|
||||
let y5 = y1 ^ x6;
|
||||
let y3 = y5 ^ y8;
|
||||
let t1 = x4 ^ y12;
|
||||
let y15 = t1 ^ x5;
|
||||
let y20 = t1 ^ x1;
|
||||
let y6 = y15 ^ x7;
|
||||
let y10 = y15 ^ t0;
|
||||
let y11 = y20 ^ y9;
|
||||
let y7 = x7 ^ y11;
|
||||
let y17 = y10 ^ y11;
|
||||
let y19 = y10 ^ y8;
|
||||
let y16 = t0 ^ y11;
|
||||
let y21 = y13 ^ y16;
|
||||
let y18 = x0 ^ y16;
|
||||
|
||||
// Non-linear section.
|
||||
let t2 = y12 & y15;
|
||||
let t3 = y3 & y6;
|
||||
let t4 = t3 ^ t2;
|
||||
let t5 = y4 & x7;
|
||||
let t6 = t5 ^ t2;
|
||||
let t7 = y13 & y16;
|
||||
let t8 = y5 & y1;
|
||||
let t9 = t8 ^ t7;
|
||||
let t10 = y2 & y7;
|
||||
let t11 = t10 ^ t7;
|
||||
let t12 = y9 & y11;
|
||||
let t13 = y14 & y17;
|
||||
let t14 = t13 ^ t12;
|
||||
let t15 = y8 & y10;
|
||||
let t16 = t15 ^ t12;
|
||||
let t17 = t4 ^ t14;
|
||||
let t18 = t6 ^ t16;
|
||||
let t19 = t9 ^ t14;
|
||||
let t20 = t11 ^ t16;
|
||||
let t21 = t17 ^ y20;
|
||||
let t22 = t18 ^ y19;
|
||||
let t23 = t19 ^ y21;
|
||||
let t24 = t20 ^ y18;
|
||||
|
||||
let t25 = t21 ^ t22;
|
||||
let t26 = t21 & t23;
|
||||
let t27 = t24 ^ t26;
|
||||
let t28 = t25 & t27;
|
||||
let t29 = t28 ^ t22;
|
||||
let t30 = t23 ^ t24;
|
||||
let t31 = t22 ^ t26;
|
||||
let t32 = t31 & t30;
|
||||
let t33 = t32 ^ t24;
|
||||
let t34 = t23 ^ t33;
|
||||
let t35 = t27 ^ t33;
|
||||
let t36 = t24 & t35;
|
||||
let t37 = t36 ^ t34;
|
||||
let t38 = t27 ^ t36;
|
||||
let t39 = t29 & t38;
|
||||
let t40 = t25 ^ t39;
|
||||
|
||||
let t41 = t40 ^ t37;
|
||||
let t42 = t29 ^ t33;
|
||||
let t43 = t29 ^ t40;
|
||||
let t44 = t33 ^ t37;
|
||||
let t45 = t42 ^ t41;
|
||||
let z0 = t44 & y15;
|
||||
let z1 = t37 & y6;
|
||||
let z2 = t33 & x7;
|
||||
let z3 = t43 & y16;
|
||||
let z4 = t40 & y1;
|
||||
let z5 = t29 & y7;
|
||||
let z6 = t42 & y11;
|
||||
let z7 = t45 & y17;
|
||||
let z8 = t41 & y10;
|
||||
let z9 = t44 & y12;
|
||||
let z10 = t37 & y3;
|
||||
let z11 = t33 & y4;
|
||||
let z12 = t43 & y13;
|
||||
let z13 = t40 & y5;
|
||||
let z14 = t29 & y2;
|
||||
let z15 = t42 & y9;
|
||||
let z16 = t45 & y14;
|
||||
let z17 = t41 & y8;
|
||||
|
||||
// Bottom linear transformation.
|
||||
let t46 = z15 ^ z16;
|
||||
let t47 = z10 ^ z11;
|
||||
let t48 = z5 ^ z13;
|
||||
let t49 = z9 ^ z10;
|
||||
let t50 = z2 ^ z12;
|
||||
let t51 = z2 ^ z5;
|
||||
let t52 = z7 ^ z8;
|
||||
let t53 = z0 ^ z3;
|
||||
let t54 = z6 ^ z7;
|
||||
let t55 = z16 ^ z17;
|
||||
let t56 = z12 ^ t48;
|
||||
let t57 = t50 ^ t53;
|
||||
let t58 = z4 ^ t46;
|
||||
let t59 = z3 ^ t54;
|
||||
let t60 = t46 ^ t57;
|
||||
let t61 = z14 ^ t57;
|
||||
let t62 = t52 ^ t58;
|
||||
let t63 = t49 ^ t58;
|
||||
let t64 = z4 ^ t59;
|
||||
let t65 = t61 ^ t62;
|
||||
let t66 = z1 ^ t63;
|
||||
let s0 = t59 ^ t63;
|
||||
let s6 = t56 ^ !t62;
|
||||
let s7 = t48 ^ !t60;
|
||||
let t67 = t64 ^ t65;
|
||||
let s3 = t53 ^ t66;
|
||||
let s4 = t51 ^ t66;
|
||||
let s5 = t47 ^ t65;
|
||||
let s1 = t64 ^ !s3;
|
||||
let 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 = w[0] as u64;
|
||||
let mut x1 = w[1] as u64;
|
||||
let mut x2 = w[2] as u64;
|
||||
let mut x3 = w[3] as u64;
|
||||
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 = q0 & 0x00FF00FF00FF00FFu64;
|
||||
let mut x1 = q1 & 0x00FF00FF00FF00FFu64;
|
||||
let mut x2 = (q0 >> 8) & 0x00FF00FF00FF00FFu64;
|
||||
let mut 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 as u64;
|
||||
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);
|
||||
}
|
||||
|
||||
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: u64,
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
use crate::params::{PUBLICKEYBYTES, SECRETKEYBYTES, SIGNBYTES};
|
||||
use crate::sign::*;
|
||||
use std::convert::TryInto;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct Keypair {
|
||||
pub public: [u8; PUBLICKEYBYTES],
|
||||
secret: [u8; SECRETKEYBYTES],
|
||||
}
|
||||
|
||||
/// Secret key elided
|
||||
impl std::fmt::Debug for Keypair {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "public: {:?}\nsecret: <elided>", self.public)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum SignError {
|
||||
Input,
|
||||
Verify,
|
||||
}
|
||||
|
||||
impl Keypair {
|
||||
/// Explicitly expose secret key
|
||||
/// ```
|
||||
/// # use pqc_dilithium::*;
|
||||
/// let keys = Keypair::generate();
|
||||
/// let secret_key = keys.expose_secret();
|
||||
/// assert!(secret_key.len() == SECRETKEYBYTES);
|
||||
/// ```
|
||||
pub fn expose_secret(&self) -> &[u8] {
|
||||
&self.secret
|
||||
}
|
||||
|
||||
/// Generates a keypair for signing and verification
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// # use pqc_dilithium::*;
|
||||
/// let keys = Keypair::generate();
|
||||
/// assert!(keys.public.len() == PUBLICKEYBYTES);
|
||||
/// assert!(keys.expose_secret().len() == SECRETKEYBYTES);
|
||||
/// ```
|
||||
pub fn generate() -> Keypair {
|
||||
let mut public = [0u8; PUBLICKEYBYTES];
|
||||
let mut secret = [0u8; SECRETKEYBYTES];
|
||||
crypto_sign_keypair(&mut public, &mut secret, None);
|
||||
Keypair { public, secret }
|
||||
}
|
||||
|
||||
/// Generates a signature for the given message using a keypair
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// # use pqc_dilithium::*;
|
||||
/// # let keys = Keypair::generate();
|
||||
/// let msg = "Hello".as_bytes();
|
||||
/// let sig = keys.sign(&msg);
|
||||
/// assert!(sig.len() == SIGNBYTES);
|
||||
/// ```
|
||||
pub fn sign(&self, msg: &[u8]) -> [u8; SIGNBYTES] {
|
||||
let mut sig = [0u8; SIGNBYTES];
|
||||
crypto_sign_signature(&mut sig, msg, &self.secret);
|
||||
sig
|
||||
}
|
||||
|
||||
/// Restores a `Keypair` from the specified `public` key and
|
||||
/// `secret` key.
|
||||
pub fn restore_from_keys(public: Vec<u8>, secret: Vec<u8>) -> Self {
|
||||
Self {
|
||||
public: public.try_into().unwrap(),
|
||||
secret: secret.try_into().unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify signature using keypair
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// # use pqc_dilithium::*;
|
||||
/// # let keys = Keypair::generate();
|
||||
/// # let msg = [0u8; 32];
|
||||
/// # let sig = keys.sign(&msg);
|
||||
/// let sig_verify = verify(&sig, &msg, &keys.public);
|
||||
/// assert!(sig_verify.is_ok());
|
||||
pub fn verify(
|
||||
sig: &[u8],
|
||||
msg: &[u8],
|
||||
public_key: &[u8],
|
||||
) -> Result<(), SignError> {
|
||||
if sig.len() != SIGNBYTES {
|
||||
return Err(SignError::Input);
|
||||
}
|
||||
crypto_sign_verify(&sig, &msg, public_key)
|
||||
}
|
|
@ -0,0 +1,525 @@
|
|||
#![allow(clippy::needless_range_loop)]
|
||||
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub const SHAKE128_RATE: usize = 168;
|
||||
pub const SHAKE256_RATE: usize = 136;
|
||||
|
||||
const NROUNDS: usize = 24;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct KeccakState {
|
||||
pub s: [u64; 25],
|
||||
pub pos: usize,
|
||||
}
|
||||
|
||||
// Replaces init functions
|
||||
impl Default for KeccakState {
|
||||
fn default() -> Self {
|
||||
KeccakState {
|
||||
s: [0u64; 25],
|
||||
pos: 0usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl KeccakState {
|
||||
pub fn init(&mut self) {
|
||||
self.s.fill(0);
|
||||
self.pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fn rol(a: u64, offset: u64) -> u64 {
|
||||
(a << offset) ^ (a >> (64 - offset))
|
||||
}
|
||||
|
||||
/// Load 8 bytes into uint64_t in little-endian order/
|
||||
pub fn load64(x: &[u8]) -> u64 {
|
||||
let mut r = 0u64;
|
||||
for i in 0..8 {
|
||||
r |= (x[i] as u64) << (8 * i);
|
||||
}
|
||||
r
|
||||
}
|
||||
|
||||
/// Store a 64-bit integer to array of 8 bytes in little-endian order
|
||||
pub fn store64(x: &mut [u8], u: u64) {
|
||||
for i in 0..8 {
|
||||
x[i] = (u >> 8 * i) as u8;
|
||||
}
|
||||
}
|
||||
|
||||
/// Keccak round constants
|
||||
const KECCAKF_ROUNDCONSTANTS: [u64; NROUNDS] = [
|
||||
0x0000000000000001u64,
|
||||
0x0000000000008082u64,
|
||||
0x800000000000808au64,
|
||||
0x8000000080008000u64,
|
||||
0x000000000000808bu64,
|
||||
0x0000000080000001u64,
|
||||
0x8000000080008081u64,
|
||||
0x8000000000008009u64,
|
||||
0x000000000000008au64,
|
||||
0x0000000000000088u64,
|
||||
0x0000000080008009u64,
|
||||
0x000000008000000au64,
|
||||
0x000000008000808bu64,
|
||||
0x800000000000008bu64,
|
||||
0x8000000000008089u64,
|
||||
0x8000000000008003u64,
|
||||
0x8000000000008002u64,
|
||||
0x8000000000000080u64,
|
||||
0x000000000000800au64,
|
||||
0x800000008000000au64,
|
||||
0x8000000080008081u64,
|
||||
0x8000000000008080u64,
|
||||
0x0000000080000001u64,
|
||||
0x8000000080008008u64,
|
||||
];
|
||||
|
||||
/// The Keccak F1600 Permutation
|
||||
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;
|
||||
}
|
||||
|
||||
/// Absorb step of Keccak; incremental.
|
||||
fn keccak_absorb(
|
||||
state: &mut KeccakState,
|
||||
r: usize,
|
||||
input: &[u8],
|
||||
mut inlen: usize,
|
||||
) {
|
||||
let mut idx = 0;
|
||||
let mut pos = state.pos;
|
||||
while pos + inlen >= r {
|
||||
for i in pos..r {
|
||||
state.s[i / 8] ^= (input[idx] as u64) << 8 * (i % 8);
|
||||
idx += 1;
|
||||
}
|
||||
inlen -= r - pos;
|
||||
keccakf1600_statepermute(&mut state.s);
|
||||
pos = 0;
|
||||
}
|
||||
let mut i = pos;
|
||||
while i < pos + inlen {
|
||||
state.s[i / 8] ^= (input[idx] as u64) << 8 * (i % 8);
|
||||
idx += 1;
|
||||
i += 1
|
||||
}
|
||||
state.pos = i;
|
||||
}
|
||||
|
||||
/// Finalize absorb step.
|
||||
fn keccak_finalize(s: &mut [u64; 25], pos: usize, r: usize, p: u8) {
|
||||
s[pos / 8] ^= (p as u64) << 8 * (pos % 8);
|
||||
s[r / 8 - 1] ^= 1u64 << 63;
|
||||
}
|
||||
|
||||
/// Squeeze step of Keccak. Squeezes arbitratrily many bytes.
|
||||
/// Modifies the state. Can be called multiple times to keep
|
||||
/// squeezing, i.e., is incremental.
|
||||
///
|
||||
// Returns new position pos in current block
|
||||
fn keccak_squeeze(
|
||||
out: &mut [u8],
|
||||
mut outlen: usize,
|
||||
s: &mut [u64; 25],
|
||||
mut pos: usize,
|
||||
r: usize,
|
||||
) -> usize {
|
||||
while outlen != 0 {
|
||||
if pos == r {
|
||||
keccakf1600_statepermute(s);
|
||||
pos = 0;
|
||||
}
|
||||
let mut i = pos;
|
||||
let mut idx = 0;
|
||||
while i < r && i < pos + outlen {
|
||||
out[idx] = (s[i / 8] >> 8 * (i % 8)) as u8;
|
||||
idx += 1;
|
||||
i += 1;
|
||||
}
|
||||
outlen -= i - pos;
|
||||
pos = i;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/// Absorb step of Keccak;
|
||||
/// non-incremental, starts by zeroeing the state.
|
||||
fn keccak_absorb_once(
|
||||
s: &mut [u64; 25],
|
||||
r: usize,
|
||||
input: &[u8],
|
||||
mut inlen: usize,
|
||||
p: u8,
|
||||
) {
|
||||
s.fill(0);
|
||||
let mut idx = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/// 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. Assumes zero bytes of current
|
||||
/// block have already been squeezed.
|
||||
fn keccak_squeezeblocks(
|
||||
out: &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 >> 3) {
|
||||
store64(&mut out[idx + 8 * i..], s[i])
|
||||
}
|
||||
idx += r;
|
||||
nblocks -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Description: Absorb step of the SHAKE128 XOF; incremental.
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub fn shake128_absorb(state: &mut KeccakState, input: &[u8], inlen: usize) {
|
||||
keccak_absorb(state, SHAKE128_RATE, input, inlen);
|
||||
}
|
||||
|
||||
/// Finalize absorb step of the SHAKE128 XOF.
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub fn shake128_finalize(state: &mut KeccakState) {
|
||||
keccak_finalize(&mut state.s, state.pos as usize, SHAKE128_RATE, 0x1F);
|
||||
state.pos = SHAKE128_RATE;
|
||||
}
|
||||
|
||||
/// 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).
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub fn shake128_squeezeblocks(
|
||||
output: &mut [u8],
|
||||
nblocks: usize,
|
||||
s: &mut KeccakState,
|
||||
) {
|
||||
keccak_squeezeblocks(output, nblocks, &mut s.s, SHAKE128_RATE);
|
||||
}
|
||||
|
||||
/// Absorb step of the SHAKE256 XOF; incremental.
|
||||
pub fn shake256_absorb(state: &mut KeccakState, input: &[u8], inlen: usize) {
|
||||
keccak_absorb(state, SHAKE256_RATE, input, inlen);
|
||||
}
|
||||
|
||||
/// Finalize absorb step of the SHAKE256 XOF.*/
|
||||
pub fn shake256_finalize(state: &mut KeccakState) {
|
||||
keccak_finalize(&mut state.s, state.pos, SHAKE256_RATE, 0x1F);
|
||||
state.pos = SHAKE256_RATE;
|
||||
}
|
||||
|
||||
///Squeeze step of SHAKE256 XOF. Squeezes arbitraily many
|
||||
/// bytes. Can be called multiple times to keep squeezing.
|
||||
pub fn shake256_squeeze(
|
||||
out: &mut [u8],
|
||||
outlen: usize,
|
||||
state: &mut KeccakState,
|
||||
) {
|
||||
state.pos =
|
||||
keccak_squeeze(out, outlen, &mut state.s, state.pos, SHAKE256_RATE);
|
||||
}
|
||||
/// Initialize, absorb into and finalize SHAKE256 XOF; non-incremental.
|
||||
pub 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;
|
||||
}
|
||||
|
||||
/// Squeeze step of SHAKE256 XOF. Squeezes full blocks of
|
||||
/// SHAKE256_RATE bytes each. Can be called multiple times
|
||||
/// to keep squeezing. Assumes next block has not yet been
|
||||
/// started (state.pos = SHAKE256_RATE).
|
||||
pub fn shake256_squeezeblocks(
|
||||
out: &mut [u8],
|
||||
nblocks: usize,
|
||||
state: &mut KeccakState,
|
||||
) {
|
||||
keccak_squeezeblocks(out, nblocks, &mut state.s, SHAKE256_RATE);
|
||||
}
|
||||
|
||||
/// SHAKE256 XOF with non-incremental API
|
||||
pub fn shake256(
|
||||
output: &mut [u8],
|
||||
mut outlen: usize,
|
||||
input: &[u8],
|
||||
inlen: usize,
|
||||
) {
|
||||
let mut state = KeccakState::default();
|
||||
|
||||
shake256_absorb_once(&mut state, input, inlen);
|
||||
let nblocks = outlen / SHAKE256_RATE;
|
||||
shake256_squeezeblocks(output, nblocks, &mut state);
|
||||
outlen -= nblocks * SHAKE256_RATE;
|
||||
let idx = nblocks * SHAKE256_RATE;
|
||||
shake256_squeeze(&mut output[idx..], outlen, &mut state);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#[cfg(feature = "aes")]
|
||||
mod aes256ctr;
|
||||
mod api;
|
||||
mod fips202;
|
||||
mod ntt;
|
||||
mod packing;
|
||||
mod params;
|
||||
mod poly;
|
||||
mod polyvec;
|
||||
mod randombytes;
|
||||
mod reduce;
|
||||
mod rounding;
|
||||
mod sign;
|
||||
mod symmetric;
|
||||
pub use params::*;
|
||||
|
||||
pub use api::*;
|
||||
|
||||
#[cfg(dilithium_kat)]
|
||||
pub use sign::{
|
||||
crypto_sign_keypair, crypto_sign_signature, crypto_sign_verify,
|
||||
};
|
|
@ -0,0 +1,243 @@
|
|||
use crate::{params::*, reduce::*};
|
||||
|
||||
// Roots of unity in order needed by forward ntt
|
||||
pub const ZETAS: [i32; N] = [
|
||||
0, 25847, -2608894, -518909, 237124, -777960, -876248, 466468, 1826347,
|
||||
2353451, -359251, -2091905, 3119733, -2884855, 3111497, 2680103, 2725464,
|
||||
1024112, -1079900, 3585928, -549488, -1119584, 2619752, -2108549, -2118186,
|
||||
-3859737, -1399561, -3277672, 1757237, -19422, 4010497, 280005, 2706023,
|
||||
95776, 3077325, 3530437, -1661693, -3592148, -2537516, 3915439, -3861115,
|
||||
-3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267,
|
||||
-1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, 811944,
|
||||
531354, 954230, 3881043, 3900724, -2556880, 2071892, -2797779, -3930395,
|
||||
-1528703, -3677745, -3041255, -1452451, 3475950, 2176455, -1585221, -1257611,
|
||||
1939314, -4083598, -1000202, -3190144, -3157330, -3632928, 126922, 3412210,
|
||||
-983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047, -671102,
|
||||
-1228525, -22981, -1308169, -381987, 1349076, 1852771, -1430430, -3343383,
|
||||
264944, 508951, 3097992, 44288, -1100098, 904516, 3958618, -3724342, -8578,
|
||||
1653064, -3249728, 2389356, -210977, 759969, -1316856, 189548, -3553272,
|
||||
3159746, -1851402, -2409325, -177440, 1315589, 1341330, 1285669, -1584928,
|
||||
-812732, -1439742, -3019102, -3881060, -3628969, 3839961, 2091667, 3407706,
|
||||
2316500, 3817976, -3342478, 2244091, -2446433, -3562462, 266997, 2434439,
|
||||
-1235728, 3513181, -3520352, -3759364, -1197226, -3193378, 900702, 1859098,
|
||||
909542, 819034, 495491, -1613174, -43260, -522500, -655327, -3122442,
|
||||
2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297, 286988,
|
||||
-2437823, 4108315, 3437287, -3342277, 1735879, 203044, 2842341, 2691481,
|
||||
-2590150, 1265009, 4055324, 1247620, 2486353, 1595974, -3767016, 1250494,
|
||||
2635921, -3548272, -2994039, 1869119, 1903435, -1050970, -1333058, 1237275,
|
||||
-3318210, -1430225, -451100, 1312455, 3306115, -1962642, -1279661, 1917081,
|
||||
-2546312, -1374803, 1500165, 777191, 2235880, 3406031, -542412, -2831860,
|
||||
-1671176, -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395,
|
||||
2454455, -164721, 1957272, 3369112, 185531, -1207385, -3183426, 162844,
|
||||
1616392, 3014001, 810149, 1652634, -3694233, -1799107, -3038916, 3523897,
|
||||
3866901, 269760, 2213111, -975884, 1717735, 472078, -426683, 1723600,
|
||||
-1803090, 1910376, -1667432, -1104333, -260646, -3833893, -2939036, -2235985,
|
||||
-420899, -2286327, 183443, -976891, 1612842, -3545687, -554416, 3919660,
|
||||
-48306, -1362209, 3937738, 1400424, -846154, 1976782,
|
||||
];
|
||||
|
||||
/// Name: ntt
|
||||
//
|
||||
/// Forward NTT, in-place. No modular reduction is performed after
|
||||
/// additions or subtractions. Output vector is in bitreversed order.
|
||||
//
|
||||
/// Arguments: - uint32_t p[N]: input/output coefficient array
|
||||
pub fn ntt(a: &mut [i32]) {
|
||||
let mut j;
|
||||
let mut k = 0usize;
|
||||
let mut len = 128;
|
||||
let (mut t, mut zeta);
|
||||
|
||||
while len > 0 {
|
||||
let mut start = 0;
|
||||
while start < N {
|
||||
k += 1;
|
||||
zeta = ZETAS[k] as i64;
|
||||
j = start;
|
||||
while j < (start + len) {
|
||||
t = montgomery_reduce(zeta * a[j + len] as i64);
|
||||
a[j + len] = a[j] - t;
|
||||
a[j] += t;
|
||||
j += 1;
|
||||
}
|
||||
start = j + len;
|
||||
}
|
||||
len >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Name: invntt
|
||||
//
|
||||
/// Inverse NTT and multiplication by Montgomery factor 2^32.
|
||||
/// In-place. No modular reductions after additions or
|
||||
/// subtractions; input coefficients need to be smaller than
|
||||
/// Q in absolute value. Output coefficient are smaller than Q in
|
||||
/// absolute value.
|
||||
//
|
||||
/// Arguments: - uint32_t p[N]: input/output coefficient array
|
||||
pub fn invntt_tomont(a: &mut [i32]) {
|
||||
let mut j;
|
||||
let mut k = 256usize;
|
||||
let mut len = 1;
|
||||
let (mut t, mut zeta);
|
||||
const F: i64 = 41978; // mont^2/256
|
||||
|
||||
while len < N {
|
||||
let mut start = 0;
|
||||
while start < 256 {
|
||||
k -= 1;
|
||||
zeta = -ZETAS[k] as i64;
|
||||
j = start;
|
||||
while j < (start + len) {
|
||||
t = a[j];
|
||||
a[j] = t + a[j + len];
|
||||
a[j + len] = t - a[j + len];
|
||||
a[j + len] = montgomery_reduce(zeta * a[j + len] as i64);
|
||||
j += 1
|
||||
}
|
||||
start = j + len;
|
||||
}
|
||||
len <<= 1;
|
||||
}
|
||||
for j in 0..N {
|
||||
a[j] = montgomery_reduce(F * a[j] as i64);
|
||||
}
|
||||
}
|
||||
|
||||
mod tests {
|
||||
#[test]
|
||||
fn ntt() {
|
||||
let mut a = [
|
||||
-1, 1, -4, -3, -4, 4, 1, 1, 2, 4, 1, 2, -2, 3, 1, 0, -3, 1, -1, -2, 4,
|
||||
-4, -1, -3, -4, -3, 3, -3, -1, 0, 0, 2, 3, -4, 3, 4, 1, -3, -1, 3, 0, 0,
|
||||
1, -4, -1, -2, -2, 2, 3, 0, 1, 1, 4, 1, 2, 2, 4, 1, -2, 2, 0, 3, 1, -3,
|
||||
4, -3, 2, -1, 3, 2, -3, 4, 3, -4, -2, 2, 4, -1, 3, -2, -1, -4, -1, -4,
|
||||
-3, 4, -1, -3, -2, 0, -4, 3, -4, -1, -1, 4, -4, 0, 1, -1, 4, 1, -4, 3, 4,
|
||||
-3, -2, -2, -3, 0, 3, -1, 2, -4, -3, -2, 1, -3, -3, -3, 1, 1, 4, -1, 2,
|
||||
4, 4, -3, 3, 1, -4, 2, -4, -3, 2, -4, -1, 3, 4, -4, 3, -3, 4, 0, -2, 2,
|
||||
1, -3, 1, 0, 4, 2, 3, -2, 2, -2, 4, -1, 3, -2, 1, -3, 3, -3, 3, 4, 1, 4,
|
||||
3, 3, -1, 0, -2, 1, 3, -4, 2, -1, 4, 1, 0, 2, -1, -2, 1, 4, -4, 0, 0, 3,
|
||||
-3, 1, -4, 4, -3, 1, -4, 3, -1, 2, 4, -1, 0, -4, -2, 4, -4, 4, 4, -2, -3,
|
||||
3, 2, -2, -4, -1, 3, 1, 3, 1, -4, 2, -3, 2, 4, 4, -3, 3, -4, 3, -4, 0,
|
||||
-2, 3, -3, -2, 3, 1, -4, -3, 3, -2, -3, 4, -3, 1, 1, 2, -1, -1, 0, -3,
|
||||
-3, 0, -1, 3,
|
||||
];
|
||||
let a_output = [
|
||||
-262661, -8506629, 3427761, 2784265, 3141917, -2372709, -8049215,
|
||||
-2353801, 3022212, 7731946, 1644566, 3053540, -255898, -2738860, 876613,
|
||||
9132009, 10276178, 7874020, -11588, 1969958, 12632850, 8341150, 8287818,
|
||||
3925510, -8773920, -747228, 898118, -2317034, 3897976, -4414032, -834621,
|
||||
4071501, -1432521, -9685153, -13990476, -13659378, -7289253, -7755363,
|
||||
3791227, -3833707, -9487410, -8901660, -19000363, -13214259, 544413,
|
||||
-6844765, -6105586, -11435970, -2978543, -1014713, -5667934, -13166438,
|
||||
-5875092, -12621756, -9964452, -5673368, -3935130, -4224380, -7354605,
|
||||
-7906865, -4353982, 1618188, 4762265, 2833189, -310581, -3991895,
|
||||
-11913640, -5312548, 3570135, -4704135, -3170969, -5592951, 1453785,
|
||||
-4560687, -1182968, 2521098, -3751247, -4714079, 301131, -2224209,
|
||||
-5642042, 458282, 5403769, 2707403, 12215228, 5224740, 6413907, 6815913,
|
||||
4580029, 425581, 1318364, -783726, 7326262, 7568074, 689180, -547668,
|
||||
-4653694, -11442820, -7832628, -5377838, -11257920, -8298570, -4596359,
|
||||
-4150699, -3065694, -10682906, -2769659, 937211, 1653867, 3120263,
|
||||
-1126589, 7211075, -14877134, -18262456, -8293726, -9183292, -10773770,
|
||||
-6705792, -5315674, 2787012, -2270115, -9841689, -5051871, -7388413,
|
||||
4234814, 1052190, -2471397, -6463519, 10137330, 5496024, 4753901,
|
||||
-645043, 7223139, 1246181, 9902026, 8334682, 6254834, 13121436, 5157886,
|
||||
5524544, 3335176, -1444146, 7151165, 8213713, 5425362, 2999358, 9659970,
|
||||
4975850, 10923812, 12903596, 3807803, 8025009, -5468017, -1536129,
|
||||
-2185854, 2751920, 6580366, 4468658, 8981903, 2405433, 8513375, 9863111,
|
||||
7777890, 11623292, -484225, 2094367, 6670303, -1190953, -113377, 7560821,
|
||||
-1565727, 512851, 2493128, -2496028, -2851481, -11119827, -3547676,
|
||||
-6187460, 4743114, -1430434, 8695423, 404053, -5689198, -237334,
|
||||
-10292594, -2482562, -4377285, -8964791, -8246037, -13793329, -106937,
|
||||
-5784361, 16421657, 16169825, 17295701, 14750529, 15111685, 13365139,
|
||||
5665684, 6845556, 3012973, 2469901, -34925, 3554251, 2179597, 9005783,
|
||||
11178922, 11448090, 4172918, 6892142, -3097350, -2378354, -2508563,
|
||||
-3588283, -7774392, -7426678, 3013820, 8971556, 11583329, 6634515,
|
||||
657092, 6937984, -6083813, -1488819, -1315854, 5205578, -7934583,
|
||||
-2186897, 6308547, 3324877, 10276044, 2595056, 8209625, 2358083, 6005802,
|
||||
2915382, 1471531, -1624379, -3631962, -4158290, 544917, -6606555, 998696,
|
||||
584554, 1926740, 844426, 1017867, -3082165, -5819081, -8499759, 521737,
|
||||
-7231469, -4117257, -5370457, -6235069, 314971,
|
||||
];
|
||||
super::ntt(&mut a);
|
||||
assert_eq!(a, a_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invntt_tomont() {
|
||||
let mut a = [
|
||||
-410121, -3439227, -1510274, 1543151, -2293562, -1024787, -1768713,
|
||||
3416108, -1829266, -39421, 1553720, 383193, -1303564, 2601404, 178534,
|
||||
3075833, -1669488, 2938151, 419856, 3374895, -3659025, 2791925, -2014544,
|
||||
-4116040, 528058, -460960, -498884, -3726436, 1576721, 1111713, -2404662,
|
||||
289307, 3590938, 362196, -2812407, -1463477, 1001050, 2798150, -472041,
|
||||
1298972, -601719, -3341683, -2239048, -3200450, -1250550, -2932037,
|
||||
-158803, -42310, 1710565, 1768181, 3343337, -4124626, -970397, 2715826,
|
||||
650012, -2014903, 4155312, -570039, -1014542, -1136867, -2854295,
|
||||
3545986, 3534334, 1775063, 543277, 1440396, -2274992, -1666074, -2522410,
|
||||
1374130, 2546411, 2357995, 3246445, -1637839, -3940900, -22882, 3617374,
|
||||
3695910, 3135497, 3461903, 321845, 1837065, -4102518, 2025912, 4037956,
|
||||
3262194, -1077158, -104681, 1543795, 2067328, -3128599, 3610959, 1154470,
|
||||
-1950084, 3161277, -1484341, 3056494, 145395, -2412862, 3811285,
|
||||
-2651526, 794539, -1077785, -3775793, 1851954, 925186, -1420046,
|
||||
-2129292, -2572721, -1709299, 2466220, -1148025, -631434, 1616317,
|
||||
1979838, 1787596, -2046122, 4145612, 2425669, -1207333, -3920849,
|
||||
2920839, -1437055, 2250361, -2512504, -2660187, -2934830, 3926550,
|
||||
1895481, -763893, 1348485, 3392907, -2603573, 748841, 3508436, -3904020,
|
||||
800986, 1434045, 3024446, -2067148, 4058529, -1797892, 2428719, -1661266,
|
||||
-1174918, -1085872, -437562, 2040521, 3475996, 35877, 3621178, -1269117,
|
||||
-743638, 442376, -278296, -2265303, 1611044, -1440032, 545695, 3186212,
|
||||
2126009, -93566, 1381483, -4000405, -1074727, 291811, 3040864, -1459167,
|
||||
-3809294, -1446926, -2959019, 1110797, -2346583, 1125183, -1458376,
|
||||
476652, 2246737, -1552594, -321172, -328787, 3727158, 2578512, -637322,
|
||||
2145686, 124009, 316574, 598758, -2180345, -40300, 1777560, -712912,
|
||||
3969900, -837615, 4186858, -1992625, 1592425, 4172055, 1030316, 1732649,
|
||||
3365500, -2209545, -2216165, 1598405, 4122715, 4094540, 363060, 369838,
|
||||
-1841354, 3772391, 1383675, -1268324, -237400, -3972626, 1314275,
|
||||
-128037, -810499, -3799034, -1750396, 766339, 1350337, -519324, -3673999,
|
||||
873780, -2497778, 1159808, 3552922, 900408, 3883840, -4073441, 2974189,
|
||||
763212, -1033993, -1137934, -3359093, 452287, 2935586, -917124, 608771,
|
||||
3625009, -2851574, -207975, -101949, -3075118, -1522612, -3819111,
|
||||
3826184, 2419692, 1871952, -1722545, -710127, 3035522, -3436794,
|
||||
-2649023, 383072, 2434951, 3052038,
|
||||
];
|
||||
let a_output = [
|
||||
775832, -3236070, 3979117, -477690, -3845958, 3442130, 3288278, 3510572,
|
||||
-4059961, 398894, -2353757, 2033799, 1142104, -1503727, -1966738,
|
||||
-646014, -1208934, 2807801, 1786267, 77787, -3034606, -2018590, -4138114,
|
||||
-119863, -2143281, -2656209, -1161853, -1355718, -3330698, 535482,
|
||||
3053760, 1831603, 2290608, 2796725, -2609926, -663097, 1464007, 2958053,
|
||||
-2816324, 2906926, 500159, 943996, 524888, -4163949, -834472, 964151,
|
||||
2161202, 1983774, -3656476, -3020535, 952201, 2170010, 711358, 1519731,
|
||||
-3738927, -3756753, 921738, -3392868, 2699399, 3324418, -1453193,
|
||||
1620721, 449384, -39155, 3109821, 1029974, 142649, 921233, 3727107,
|
||||
637146, -756794, 34504, -1893151, -603841, 2330154, 1322568, -1191265,
|
||||
-748922, 1386438, 2435097, 355691, 705695, -504939, 1785625, 3011361,
|
||||
2599030, -721431, 3258978, 826952, 3134195, 1786978, -2063102, 3719340,
|
||||
-3791185, 766135, 1412965, 2002641, 344357, -3493197, -3971320, -1589376,
|
||||
3333787, -886393, -3473781, 2615969, 258578, -1357515, 31929, -2417061,
|
||||
3279057, 623958, 402549, -3223514, 1434146, 2674659, 4184013, 2350081,
|
||||
-2255267, 3242948, -2755729, 3141850, -3642170, -410070, -3603228,
|
||||
509187, 747235, -2733439, 2951878, 934726, -1464030, -3685617, -177281,
|
||||
-2026915, -2014190, 3892744, -2765709, 178393, 1247779, -328544, -647840,
|
||||
227976, -1303803, -407239, 2659686, 330785, 22660, 3150838, -49448,
|
||||
-3247191, 3366409, 3515827, 2681493, -3955013, 957672, 2270951, -2324620,
|
||||
848541, 252308, 2362816, -480849, 1886753, 1946701, -3448907, 3931255,
|
||||
-2029213, -3650910, 3939281, 730275, 2214811, 1201755, -694587, -2004861,
|
||||
2583875, 3279717, 3819665, 2574119, -2112908, -2400101, -1349537,
|
||||
3495414, 1347624, -2225620, -2050682, -2951590, -3996103, -3607935,
|
||||
3247458, -2175324, -1553702, -2091666, 1571828, -1878102, 2718529,
|
||||
-541427, -662267, -1324341, -370258, -474473, 2224715, 2128310, -345001,
|
||||
1208578, -1376070, 3433670, 3140605, 875985, -1831696, 449356, -220450,
|
||||
1787974, 2388192, -34248, -3456146, 2415580, 1786863, -2849072, -212492,
|
||||
59437, -716203, 1968326, 1107129, 434519, 185631, 3036577, -2325373,
|
||||
567821, 1988023, 2839088, -1233636, -3135158, 4161465, -3730607, 1882010,
|
||||
-3271303, -2556717, -1387745, -3161242, 1813752, -3561981, 130118,
|
||||
-2005282, -3396498, 1716289, -3253036, -1302754, 2500212, -1918240,
|
||||
1201565, -1106518, 743553, 902331, 804710, -3047027, 3654086, 911638,
|
||||
3708051,
|
||||
];
|
||||
super::invntt_tomont(&mut a);
|
||||
assert_eq!(a, a_output);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
use crate::{params::*, poly::*, polyvec::*, SignError};
|
||||
|
||||
/// Bit-pack public key pk = (rho, t1).
|
||||
pub fn pack_pk(pk: &mut [u8], rho: &[u8], t1: &Polyveck) {
|
||||
pk[..SEEDBYTES].copy_from_slice(&rho[..SEEDBYTES]);
|
||||
for i in 0..K {
|
||||
polyt1_pack(&mut pk[SEEDBYTES + i * POLYT1_PACKEDBYTES..], &t1.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Unpack public key pk = (rho, t1).
|
||||
pub fn unpack_pk(rho: &mut [u8], t1: &mut Polyveck, pk: &[u8]) {
|
||||
rho[..SEEDBYTES].copy_from_slice(&pk[..SEEDBYTES]);
|
||||
for i in 0..K {
|
||||
polyt1_unpack(&mut t1.vec[i], &pk[SEEDBYTES + i * POLYT1_PACKEDBYTES..])
|
||||
}
|
||||
}
|
||||
|
||||
/// Bit-pack secret key sk = (rho, key, tr, s1, s2, t0).
|
||||
pub fn pack_sk(
|
||||
sk: &mut [u8],
|
||||
rho: &[u8],
|
||||
tr: &[u8],
|
||||
key: &[u8],
|
||||
t0: &Polyveck,
|
||||
s1: &Polyvecl,
|
||||
s2: &Polyveck,
|
||||
) {
|
||||
let mut idx = 0usize;
|
||||
|
||||
sk[idx..SEEDBYTES].copy_from_slice(&rho[0..SEEDBYTES]);
|
||||
idx += SEEDBYTES;
|
||||
|
||||
sk[idx..idx + SEEDBYTES].copy_from_slice(&key[0..SEEDBYTES]);
|
||||
idx += SEEDBYTES;
|
||||
|
||||
sk[idx..idx + SEEDBYTES].copy_from_slice(&tr[0..SEEDBYTES]);
|
||||
idx += SEEDBYTES;
|
||||
|
||||
for i in 0..L {
|
||||
polyeta_pack(&mut sk[idx + i * POLYETA_PACKEDBYTES..], &s1.vec[i]);
|
||||
}
|
||||
idx += L * POLYETA_PACKEDBYTES;
|
||||
|
||||
for i in 0..K {
|
||||
polyeta_pack(&mut sk[idx + i * POLYETA_PACKEDBYTES..], &s2.vec[i]);
|
||||
}
|
||||
idx += K * POLYETA_PACKEDBYTES;
|
||||
|
||||
for i in 0..K {
|
||||
polyt0_pack(&mut sk[idx + i * POLYT0_PACKEDBYTES..], &t0.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Unpack secret key sk = (rho, key, tr, s1, s2, t0).
|
||||
pub fn unpack_sk(
|
||||
rho: &mut [u8],
|
||||
tr: &mut [u8],
|
||||
key: &mut [u8],
|
||||
t0: &mut Polyveck,
|
||||
s1: &mut Polyvecl,
|
||||
s2: &mut Polyveck,
|
||||
sk: &[u8],
|
||||
) {
|
||||
let mut idx = 0usize;
|
||||
|
||||
rho[..SEEDBYTES].copy_from_slice(&sk[..SEEDBYTES]);
|
||||
idx += SEEDBYTES;
|
||||
|
||||
key[..SEEDBYTES].copy_from_slice(&sk[idx..idx + SEEDBYTES]);
|
||||
idx += SEEDBYTES;
|
||||
|
||||
tr[..SEEDBYTES].copy_from_slice(&sk[idx..idx + SEEDBYTES]);
|
||||
idx += SEEDBYTES;
|
||||
|
||||
for i in 0..L {
|
||||
polyeta_unpack(&mut s1.vec[i], &sk[idx + i * POLYETA_PACKEDBYTES..]);
|
||||
}
|
||||
idx += L * POLYETA_PACKEDBYTES;
|
||||
|
||||
for i in 0..K {
|
||||
polyeta_unpack(&mut s2.vec[i], &sk[idx + i * POLYETA_PACKEDBYTES..]);
|
||||
}
|
||||
idx += K * POLYETA_PACKEDBYTES;
|
||||
|
||||
for i in 0..K {
|
||||
polyt0_unpack(&mut t0.vec[i], &sk[idx + i * POLYT0_PACKEDBYTES..]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Bit-pack signature sig = (c, z, h).
|
||||
pub fn pack_sig(sig: &mut [u8], c: Option<&[u8]>, z: &Polyvecl, h: &Polyveck) {
|
||||
let mut idx = 0usize;
|
||||
|
||||
if let Some(challenge) = c {
|
||||
sig[..SEEDBYTES].copy_from_slice(&challenge[..SEEDBYTES]);
|
||||
}
|
||||
|
||||
idx += SEEDBYTES;
|
||||
|
||||
for i in 0..L {
|
||||
polyz_pack(&mut sig[idx + i * POLYZ_PACKEDBYTES..], &z.vec[i]);
|
||||
}
|
||||
idx += L * POLYZ_PACKEDBYTES;
|
||||
// Encode H
|
||||
sig[idx..idx + OMEGA + K].copy_from_slice(&[0u8; OMEGA + K]);
|
||||
|
||||
let mut k = 0;
|
||||
for i in 0..K {
|
||||
for j in 0..N {
|
||||
if h.vec[i].coeffs[j] != 0 {
|
||||
sig[idx + k] = j as u8;
|
||||
k += 1;
|
||||
}
|
||||
}
|
||||
sig[idx + OMEGA + i] = k as u8;
|
||||
}
|
||||
}
|
||||
|
||||
/// Unpack signature sig = (z, h, c).
|
||||
pub fn unpack_sig(
|
||||
c: &mut [u8],
|
||||
z: &mut Polyvecl,
|
||||
h: &mut Polyveck,
|
||||
sig: &[u8],
|
||||
) -> Result<(), SignError> {
|
||||
let mut idx = 0usize;
|
||||
|
||||
c[..SEEDBYTES].copy_from_slice(&sig[..SEEDBYTES]);
|
||||
idx += SEEDBYTES;
|
||||
|
||||
for i in 0..L {
|
||||
polyz_unpack(&mut z.vec[i], &sig[idx + i * POLYZ_PACKEDBYTES..]);
|
||||
}
|
||||
idx += L * POLYZ_PACKEDBYTES;
|
||||
|
||||
// Decode h
|
||||
let mut k = 0usize;
|
||||
for i in 0..K {
|
||||
if sig[idx + OMEGA + i] < k as u8 || sig[idx + OMEGA + i] > OMEGA_U8 {
|
||||
return Err(SignError::Input);
|
||||
}
|
||||
for j in k..sig[idx + OMEGA + i] as usize {
|
||||
// Coefficients are ordered for strong unforgeability
|
||||
if j > k && sig[idx + j as usize] <= sig[idx + j as usize - 1] {
|
||||
return Err(SignError::Input);
|
||||
}
|
||||
h.vec[i].coeffs[sig[idx + j] as usize] = 1;
|
||||
}
|
||||
k = sig[idx + OMEGA + i] as usize;
|
||||
}
|
||||
|
||||
// Extra indices are zero for strong unforgeability
|
||||
for j in k..OMEGA {
|
||||
if sig[idx + j as usize] > 0 {
|
||||
return Err(SignError::Input);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#[cfg(feature = "mode2")]
|
||||
mod mode_2;
|
||||
#[cfg(not(any(feature = "mode2", feature = "mode5")))]
|
||||
mod mode_3;
|
||||
#[cfg(feature = "mode5")]
|
||||
mod mode_5;
|
||||
|
||||
#[cfg(feature = "mode2")]
|
||||
pub use mode_2::*;
|
||||
#[cfg(not(any(feature = "mode2", feature = "mode5")))]
|
||||
pub use mode_3::*;
|
||||
#[cfg(feature = "mode5")]
|
||||
pub use mode_5::*;
|
||||
|
||||
pub const SEEDBYTES: usize = 32;
|
||||
pub const CRHBYTES: usize = 64;
|
||||
pub const N: usize = 256;
|
||||
pub const Q: usize = 8380417;
|
||||
pub const D: usize = 13;
|
||||
pub const ROOT_OF_UNITY: usize = 1753;
|
||||
|
||||
pub const POLYT1_PACKEDBYTES: usize = 320;
|
||||
pub const POLYT0_PACKEDBYTES: usize = 416;
|
||||
pub const POLYVECH_PACKEDBYTES: usize = OMEGA + K;
|
||||
|
||||
pub const POLYZ_PACKEDBYTES: usize =
|
||||
if cfg!(feature = "mode2") { 576 } else { 640 };
|
||||
pub const POLYW1_PACKEDBYTES: usize =
|
||||
if cfg!(feature = "mode2") { 192 } else { 128 };
|
||||
|
||||
pub const POLYETA_PACKEDBYTES: usize =
|
||||
if cfg!(not(any(feature = "mode2", feature = "mode5"))) {
|
||||
128
|
||||
} else {
|
||||
96
|
||||
};
|
||||
|
||||
// Concise types to avoid cast cluttering
|
||||
pub const Q_I32: i32 = Q as i32;
|
||||
pub const N_U32: u32 = N as u32;
|
||||
pub const L_U16: u16 = L as u16;
|
||||
pub const BETA_I32: i32 = BETA as i32;
|
||||
pub const GAMMA1_I32: i32 = GAMMA1 as i32;
|
||||
pub const GAMMA2_I32: i32 = GAMMA2 as i32;
|
||||
pub const OMEGA_U8: u8 = OMEGA as u8;
|
||||
pub const ETA_I32: i32 = ETA as i32;
|
||||
pub const GAMMA1_SUB_BETA: i32 = (GAMMA1 - BETA) as i32;
|
||||
|
||||
pub const PUBLICKEYBYTES: usize = SEEDBYTES + K * POLYT1_PACKEDBYTES;
|
||||
pub const SECRETKEYBYTES: usize = 3 * SEEDBYTES
|
||||
+ L * POLYETA_PACKEDBYTES
|
||||
+ K * POLYETA_PACKEDBYTES
|
||||
+ K * POLYT0_PACKEDBYTES;
|
||||
pub const SIGNBYTES: usize =
|
||||
SEEDBYTES + L * POLYZ_PACKEDBYTES + POLYVECH_PACKEDBYTES;
|
||||
|
||||
pub const RANDOMIZED_SIGNING: bool = cfg!(feature = "random_signing");
|
|
@ -0,0 +1,10 @@
|
|||
use super::Q;
|
||||
|
||||
pub const K: usize = 4;
|
||||
pub const L: usize = 4;
|
||||
pub const ETA: usize = 2;
|
||||
pub const TAU: usize = 39;
|
||||
pub const BETA: usize = 78;
|
||||
pub const GAMMA1: usize = 1 << 17;
|
||||
pub const GAMMA2: usize = (Q - 1) / 88;
|
||||
pub const OMEGA: usize = 80;
|
|
@ -0,0 +1,10 @@
|
|||
use super::Q;
|
||||
|
||||
pub const K: usize = 6;
|
||||
pub const L: usize = 5;
|
||||
pub const ETA: usize = 4;
|
||||
pub const TAU: usize = 49;
|
||||
pub const BETA: usize = 196;
|
||||
pub const GAMMA1: usize = 1 << 19;
|
||||
pub const GAMMA2: usize = (Q - 1) / 32;
|
||||
pub const OMEGA: usize = 55;
|
|
@ -0,0 +1,10 @@
|
|||
use super::Q;
|
||||
|
||||
pub const K: usize = 8;
|
||||
pub const L: usize = 7;
|
||||
pub const ETA: usize = 2;
|
||||
pub const TAU: usize = 60;
|
||||
pub const BETA: usize = 120;
|
||||
pub const GAMMA1: usize = 1 << 19;
|
||||
pub const GAMMA2: usize = (Q - 1) / 32;
|
||||
pub const OMEGA: usize = 75;
|
|
@ -0,0 +1,620 @@
|
|||
use crate::{
|
||||
fips202::*, ntt::*, params::*, reduce::*, rounding::*, symmetric::*,
|
||||
};
|
||||
|
||||
const D_SHL: i32 = 1i32 << (D - 1);
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Poly {
|
||||
pub coeffs: [i32; N],
|
||||
}
|
||||
|
||||
impl Default for Poly {
|
||||
fn default() -> Self {
|
||||
Poly { coeffs: [0i32; N] }
|
||||
}
|
||||
}
|
||||
|
||||
/// Inplace reduction of all coefficients of polynomial to
|
||||
/// representative in [0,2*Q].
|
||||
pub fn poly_reduce(a: &mut Poly) {
|
||||
for i in 0..N {
|
||||
a.coeffs[i] = reduce32(a.coeffs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// For all coefficients of in/out polynomial add Q if
|
||||
/// coefficient is negative.
|
||||
pub fn poly_caddq(a: &mut Poly) {
|
||||
for i in 0..N {
|
||||
a.coeffs[i] = caddq(a.coeffs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add polynomials. No modular reduction is performed.
|
||||
pub fn poly_add(c: &mut Poly, b: &Poly) {
|
||||
for i in 0..N {
|
||||
c.coeffs[i] = c.coeffs[i] + b.coeffs[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// Subtract polynomials. Assumes coefficients of second input
|
||||
/// polynomial to be less than 2*Q. No modular reduction is
|
||||
/// performed.
|
||||
pub fn poly_sub(c: &mut Poly, b: &Poly) {
|
||||
for i in 0..N {
|
||||
c.coeffs[i] = c.coeffs[i] - b.coeffs[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiply polynomial by 2^D without modular reduction. Assumes
|
||||
/// input coefficients to be less than 2^{32-D}.
|
||||
pub fn poly_shiftl(a: &mut Poly) {
|
||||
for i in 0..N {
|
||||
a.coeffs[i] <<= D;
|
||||
}
|
||||
}
|
||||
|
||||
/// Inplace forward NTT. Output coefficients can be up to
|
||||
/// 16*Q larger than input coefficients.
|
||||
pub fn poly_ntt(a: &mut Poly) {
|
||||
ntt(&mut a.coeffs);
|
||||
}
|
||||
|
||||
/// Inplace inverse NTT and multiplication by 2^{32}.
|
||||
/// Input coefficients need to be less than 2*Q.
|
||||
/// Output coefficients are less than 2*Q.
|
||||
pub fn poly_invntt_tomont(a: &mut Poly) {
|
||||
invntt_tomont(&mut a.coeffs);
|
||||
}
|
||||
|
||||
/// Pointwise multiplication of polynomials in NTT domain
|
||||
/// representation and multiplication of resulting polynomial
|
||||
/// by 2^{-32}. Output coefficients are less than 2*Q if input
|
||||
/// coefficient are less than 22*Q.
|
||||
pub fn poly_pointwise_montgomery(c: &mut Poly, a: &Poly, b: &Poly) {
|
||||
for i in 0..N {
|
||||
c.coeffs[i] = montgomery_reduce((a.coeffs[i] as i64) * b.coeffs[i] as i64);
|
||||
}
|
||||
}
|
||||
|
||||
/// For all coefficients c of the input polynomial,
|
||||
/// compute c0, c1 such that c mod Q = c1*2^D + c0
|
||||
/// with -2^{D-1} < c0 <= 2^{D-1}. Assumes coefficients to be
|
||||
/// standard representatives.
|
||||
pub fn poly_power2round(a1: &mut Poly, a0: &mut Poly) {
|
||||
for i in 0..N {
|
||||
a1.coeffs[i] = power2round(a1.coeffs[i], &mut a0.coeffs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// For all coefficients c of the input polynomial,
|
||||
/// compute high and low bits c0, c1 such c mod Q = c1*ALPHA + c0
|
||||
/// with -ALPHA/2 < c0 <= ALPHA/2 except c1 = (Q-1)/ALPHA where we
|
||||
/// set c1 = 0 and -ALPHA/2 <= c0 = c mod Q - Q < 0.
|
||||
/// Assumes coefficients to be standard representatives.
|
||||
pub fn poly_decompose(a1: &mut Poly, a0: &mut Poly) {
|
||||
for i in 0..N {
|
||||
a1.coeffs[i] = decompose(&mut a0.coeffs[i], a1.coeffs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute hint polynomial. The coefficients of which indicate
|
||||
/// whether the low bits of the corresponding coefficient of
|
||||
/// the input polynomial overflow into the high bits.
|
||||
pub fn poly_make_hint(h: &mut Poly, a0: &Poly, a1: &Poly) -> i32 {
|
||||
let mut s = 0i32;
|
||||
for i in 0..N {
|
||||
h.coeffs[i] = make_hint(a0.coeffs[i], a1.coeffs[i]) as i32;
|
||||
s += h.coeffs[i];
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Use hint polynomial to correct the high bits of a polynomial.
|
||||
///
|
||||
/// Arguments: - poly *b: pointer to output polynomial with corrected high bits
|
||||
/// - const poly *a: pointer to input polynomial
|
||||
/// - const poly *h: pointer to input hint polynomial
|
||||
pub fn poly_use_hint(b: &mut Poly, h: &Poly) {
|
||||
for i in 0..N {
|
||||
b.coeffs[i] = use_hint(b.coeffs[i], h.coeffs[i] as u8);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check infinity norm of polynomial against given bound.
|
||||
/// Assumes input coefficients to be standard representatives.
|
||||
/// Returns 0 if norm is strictly smaller than B and 1 otherwise.
|
||||
pub fn poly_chknorm(a: &Poly, b: i32) -> u8 {
|
||||
// It is ok to leak which coefficient violates the bound since
|
||||
// the probability for each coefficient is independent of secret
|
||||
// data but we must not leak the sign of the centralized representative.
|
||||
let mut t;
|
||||
|
||||
if b > (Q_I32 - 1) / 8 {
|
||||
return 1;
|
||||
}
|
||||
for i in 0..N {
|
||||
// Absolute value of centralized representative
|
||||
t = a.coeffs[i] >> 31;
|
||||
t = a.coeffs[i] - (t & 2 * a.coeffs[i]);
|
||||
|
||||
if t >= b {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Sample uniformly random coefficients in [0, Q-1] by
|
||||
/// performing rejection sampling on array of random bytes.
|
||||
/// Returns number of sampled coefficients. Can be smaller than len if not enough
|
||||
/// random bytes were given.
|
||||
pub fn rej_uniform(a: &mut [i32], len: u32, buf: &[u8], buflen: usize) -> u32 {
|
||||
let (mut ctr, mut pos) = (0usize, 0usize);
|
||||
let mut t;
|
||||
while ctr < len as usize && pos + 3 <= buflen {
|
||||
t = buf[pos] as u32;
|
||||
pos += 1;
|
||||
t |= (buf[pos] as u32) << 8;
|
||||
pos += 1;
|
||||
t |= (buf[pos] as u32) << 16;
|
||||
pos += 1;
|
||||
t &= 0x7FFFFF;
|
||||
|
||||
if t < Q as u32 {
|
||||
a[ctr] = t as i32;
|
||||
ctr += 1;
|
||||
}
|
||||
}
|
||||
ctr as u32
|
||||
}
|
||||
|
||||
const POLY_UNIFORM_NBLOCKS: usize =
|
||||
(768 + STREAM128_BLOCKBYTES - 1) / STREAM128_BLOCKBYTES;
|
||||
|
||||
/// Sample polynomial with uniformly random coefficients
|
||||
/// in [0, Q-1] by performing rejection sampling using the
|
||||
/// output stream of SHAKE256(seed|nonce) or AES256CTR(seed,nonce).
|
||||
pub fn poly_uniform(a: &mut Poly, seed: &[u8], nonce: u16) {
|
||||
let mut buflen = POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES;
|
||||
let mut buf = [0u8; POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES + 2];
|
||||
let mut state = Stream128State::default();
|
||||
|
||||
stream128_init(&mut state, seed, nonce);
|
||||
stream128_squeezeblocks(&mut buf, POLY_UNIFORM_NBLOCKS as u64, &mut state);
|
||||
|
||||
let mut ctr = rej_uniform(&mut a.coeffs, N_U32, &mut buf, buflen);
|
||||
let mut off;
|
||||
while ctr < N_U32 {
|
||||
off = buflen % 3;
|
||||
for i in 0..off {
|
||||
buf[i] = buf[buflen - off + i];
|
||||
}
|
||||
buflen = STREAM128_BLOCKBYTES + off;
|
||||
stream128_squeezeblocks(&mut buf[off..], 1, &mut state);
|
||||
ctr += rej_uniform(
|
||||
&mut a.coeffs[(ctr as usize)..],
|
||||
N_U32 - ctr,
|
||||
&mut buf,
|
||||
buflen,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sample uniformly random coefficients in [-ETA, ETA] by
|
||||
/// performing rejection sampling using array of random bytes.
|
||||
pub fn rej_eta(a: &mut [i32], len: usize, buf: &[u8], buflen: usize) -> u32 {
|
||||
let (mut ctr, mut pos) = (0usize, 0usize);
|
||||
let (mut t0, mut t1);
|
||||
while ctr < len && pos < buflen {
|
||||
t0 = (buf[pos] & 0x0F) as u32;
|
||||
t1 = (buf[pos] >> 4) as u32;
|
||||
pos += 1;
|
||||
|
||||
if ETA == 2 {
|
||||
if t0 < 15 {
|
||||
t0 = t0 - (205 * t0 >> 10) * 5;
|
||||
a[ctr] = 2 - t0 as i32;
|
||||
ctr += 1;
|
||||
}
|
||||
if t1 < 15 && ctr < len {
|
||||
t1 = t1 - (205 * t1 >> 10) * 5;
|
||||
a[ctr] = 2 - t1 as i32;
|
||||
ctr += 1;
|
||||
}
|
||||
} else if ETA == 4 {
|
||||
if t0 < 9 {
|
||||
a[ctr] = 4 - t0 as i32;
|
||||
ctr += 1;
|
||||
}
|
||||
if t1 < 9 && ctr < len {
|
||||
a[ctr] = 4 - t1 as i32;
|
||||
ctr += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctr as u32
|
||||
}
|
||||
|
||||
/// Sample polynomial with uniformly random coefficients
|
||||
/// in [-ETA,ETA] by performing rejection sampling using the
|
||||
/// output stream from SHAKE256(seed|nonce) or AES256CTR(seed,nonce).
|
||||
const POLY_UNIFORM_ETA_NBLOCKS: usize = if ETA == 2 {
|
||||
(136 + STREAM256_BLOCKBYTES - 1) / STREAM256_BLOCKBYTES
|
||||
} else {
|
||||
(227 + STREAM256_BLOCKBYTES - 1) / STREAM256_BLOCKBYTES
|
||||
};
|
||||
|
||||
pub fn poly_uniform_eta(a: &mut Poly, seed: &[u8], nonce: u16) {
|
||||
let buflen = POLY_UNIFORM_ETA_NBLOCKS * STREAM256_BLOCKBYTES;
|
||||
let mut buf = [0u8; POLY_UNIFORM_ETA_NBLOCKS * STREAM256_BLOCKBYTES];
|
||||
let mut state = Stream256State::default();
|
||||
stream256_init(&mut state, seed, nonce);
|
||||
stream256_squeezeblocks(
|
||||
&mut buf,
|
||||
POLY_UNIFORM_ETA_NBLOCKS as u64,
|
||||
&mut state,
|
||||
);
|
||||
|
||||
let mut ctr = rej_eta(&mut a.coeffs, N, &buf, buflen);
|
||||
|
||||
while ctr < N_U32 {
|
||||
stream256_squeezeblocks(&mut buf, 1, &mut state);
|
||||
ctr += rej_eta(
|
||||
&mut a.coeffs[ctr as usize..],
|
||||
N - ctr as usize,
|
||||
&buf,
|
||||
STREAM256_BLOCKBYTES,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const POLY_UNIFORM_GAMMA1_NBLOCKS: usize =
|
||||
(POLYZ_PACKEDBYTES + STREAM256_BLOCKBYTES - 1) / STREAM256_BLOCKBYTES;
|
||||
|
||||
/// Sample polynomial with uniformly random coefficients
|
||||
/// in [-(GAMMA1 - 1), GAMMA1 - 1] by performing rejection
|
||||
/// sampling on output stream of SHAKE256(seed|nonce)
|
||||
/// or AES256CTR(seed,nonce).
|
||||
pub fn poly_uniform_gamma1(a: &mut Poly, seed: &[u8], nonce: u16) {
|
||||
let mut buf = [0u8; POLY_UNIFORM_GAMMA1_NBLOCKS * STREAM256_BLOCKBYTES];
|
||||
let mut state = Stream256State::default();
|
||||
|
||||
stream256_init(&mut state, seed, nonce);
|
||||
stream256_squeezeblocks(
|
||||
&mut buf,
|
||||
POLY_UNIFORM_GAMMA1_NBLOCKS as u64,
|
||||
&mut state,
|
||||
);
|
||||
polyz_unpack(a, &mut buf);
|
||||
}
|
||||
|
||||
/// Implementation of H. Samples polynomial with TAU nonzero
|
||||
/// coefficients in {-1,1} using the output stream of
|
||||
/// SHAKE256(seed).
|
||||
pub fn poly_challenge(c: &mut Poly, seed: &[u8]) {
|
||||
let mut _signs = 0u64;
|
||||
let mut buf = [0u8; SHAKE256_RATE];
|
||||
let mut state = KeccakState::default(); //shake256_init
|
||||
|
||||
shake256_absorb(&mut state, seed, SEEDBYTES);
|
||||
shake256_finalize(&mut state);
|
||||
shake256_squeezeblocks(&mut buf, 1, &mut state);
|
||||
|
||||
for i in 0..8 {
|
||||
_signs |= (buf[i] as u64) << 8 * i;
|
||||
}
|
||||
let mut pos: usize = 8;
|
||||
// let mut b = buf[pos];
|
||||
let mut b;
|
||||
c.coeffs.fill(0);
|
||||
for i in N - TAU..N {
|
||||
loop {
|
||||
if pos >= SHAKE256_RATE {
|
||||
shake256_squeezeblocks(&mut buf, 1, &mut state);
|
||||
pos = 0;
|
||||
}
|
||||
b = buf[pos] as usize;
|
||||
pos += 1;
|
||||
if b <= i {
|
||||
break;
|
||||
}
|
||||
}
|
||||
c.coeffs[i] = c.coeffs[b as usize];
|
||||
c.coeffs[b as usize] = 1i32 - 2 * (_signs & 1) as i32;
|
||||
_signs >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Bit-pack polynomial with coefficients in [-ETA,ETA].
|
||||
/// Input coefficients are assumed to lie in [Q-ETA,Q+ETA].
|
||||
pub fn polyeta_pack(r: &mut [u8], a: &Poly) {
|
||||
let mut t = [0u8; 8];
|
||||
if ETA == 2 {
|
||||
for i in 0..N / 8 {
|
||||
t[0] = (ETA_I32 - a.coeffs[8 * i + 0]) as u8;
|
||||
t[1] = (ETA_I32 - a.coeffs[8 * i + 1]) as u8;
|
||||
t[2] = (ETA_I32 - a.coeffs[8 * i + 2]) as u8;
|
||||
t[3] = (ETA_I32 - a.coeffs[8 * i + 3]) as u8;
|
||||
t[4] = (ETA_I32 - a.coeffs[8 * i + 4]) as u8;
|
||||
t[5] = (ETA_I32 - a.coeffs[8 * i + 5]) as u8;
|
||||
t[6] = (ETA_I32 - a.coeffs[8 * i + 6]) as u8;
|
||||
t[7] = (ETA_I32 - a.coeffs[8 * i + 7]) as u8;
|
||||
|
||||
r[3 * i + 0] = (t[0] >> 0) | (t[1] << 3) | (t[2] << 6);
|
||||
r[3 * i + 1] = (t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7);
|
||||
r[3 * i + 2] = (t[5] >> 1) | (t[6] << 2) | (t[7] << 5);
|
||||
}
|
||||
} else {
|
||||
for i in 0..N / 2 {
|
||||
t[0] = (ETA_I32 - a.coeffs[2 * i + 0]) as u8;
|
||||
t[1] = (ETA_I32 - a.coeffs[2 * i + 1]) as u8;
|
||||
r[i] = t[0] | (t[1] << 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unpack polynomial with coefficients in [-ETA,ETA].
|
||||
pub fn polyeta_unpack(r: &mut Poly, a: &[u8]) {
|
||||
if ETA == 2 {
|
||||
for i in 0..N / 8 {
|
||||
r.coeffs[8 * i + 0] = (a[3 * i + 0] & 0x07) as i32;
|
||||
r.coeffs[8 * i + 1] = ((a[3 * i + 0] >> 3) & 0x07) as i32;
|
||||
r.coeffs[8 * i + 2] =
|
||||
(((a[3 * i + 0] >> 6) | (a[3 * i + 1] << 2)) & 0x07) as i32;
|
||||
r.coeffs[8 * i + 3] = ((a[3 * i + 1] >> 1) & 0x07) as i32;
|
||||
r.coeffs[8 * i + 4] = ((a[3 * i + 1] >> 4) & 0x07) as i32;
|
||||
r.coeffs[8 * i + 5] =
|
||||
(((a[3 * i + 1] >> 7) | (a[3 * i + 2] << 1)) & 0x07) as i32;
|
||||
r.coeffs[8 * i + 6] = ((a[3 * i + 2] >> 2) & 0x07) as i32;
|
||||
r.coeffs[8 * i + 7] = ((a[3 * i + 2] >> 5) & 0x07) as i32;
|
||||
|
||||
r.coeffs[8 * i + 0] = (ETA_I32 - r.coeffs[8 * i + 0]) as i32;
|
||||
r.coeffs[8 * i + 1] = (ETA_I32 - r.coeffs[8 * i + 1]) as i32;
|
||||
r.coeffs[8 * i + 2] = (ETA_I32 - r.coeffs[8 * i + 2]) as i32;
|
||||
r.coeffs[8 * i + 3] = (ETA_I32 - r.coeffs[8 * i + 3]) as i32;
|
||||
r.coeffs[8 * i + 4] = (ETA_I32 - r.coeffs[8 * i + 4]) as i32;
|
||||
r.coeffs[8 * i + 5] = (ETA_I32 - r.coeffs[8 * i + 5]) as i32;
|
||||
r.coeffs[8 * i + 6] = (ETA_I32 - r.coeffs[8 * i + 6]) as i32;
|
||||
r.coeffs[8 * i + 7] = (ETA_I32 - r.coeffs[8 * i + 7]) as i32;
|
||||
}
|
||||
} else {
|
||||
for i in 0..N / 2 {
|
||||
r.coeffs[2 * i + 0] = (a[i] & 0x0F) as i32;
|
||||
r.coeffs[2 * i + 1] = (a[i] >> 4) as i32;
|
||||
r.coeffs[2 * i + 0] = (ETA_I32 - r.coeffs[2 * i + 0]) as i32;
|
||||
r.coeffs[2 * i + 1] = (ETA_I32 - r.coeffs[2 * i + 1]) as i32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Bit-pack polynomial t1 with coefficients fitting in 10 bits.
|
||||
/// Input coefficients are assumed to be standard representatives.
|
||||
pub fn polyt1_pack(r: &mut [u8], a: &Poly) {
|
||||
for i in 0..N / 4 {
|
||||
r[5 * i + 0] = (a.coeffs[4 * i + 0] >> 0) as u8;
|
||||
r[5 * i + 1] =
|
||||
((a.coeffs[4 * i + 0] >> 8) | (a.coeffs[4 * i + 1] << 2)) as u8;
|
||||
r[5 * i + 2] =
|
||||
((a.coeffs[4 * i + 1] >> 6) | (a.coeffs[4 * i + 2] << 4)) as u8;
|
||||
r[5 * i + 3] =
|
||||
((a.coeffs[4 * i + 2] >> 4) | (a.coeffs[4 * i + 3] << 6)) as u8;
|
||||
r[5 * i + 4] = (a.coeffs[4 * i + 3] >> 2) as u8;
|
||||
}
|
||||
}
|
||||
|
||||
/// Unpack polynomial t1 with 9-bit coefficients.
|
||||
/// Output coefficients are standard representatives.
|
||||
pub fn polyt1_unpack(r: &mut Poly, a: &[u8]) {
|
||||
for i in 0..N / 4 {
|
||||
r.coeffs[4 * i + 0] = (((a[5 * i + 0] >> 0) as u32
|
||||
| (a[5 * i + 1] as u32) << 8)
|
||||
& 0x3FF) as i32;
|
||||
r.coeffs[4 * i + 1] = (((a[5 * i + 1] >> 2) as u32
|
||||
| (a[5 * i + 2] as u32) << 6)
|
||||
& 0x3FF) as i32;
|
||||
r.coeffs[4 * i + 2] = (((a[5 * i + 2] >> 4) as u32
|
||||
| (a[5 * i + 3] as u32) << 4)
|
||||
& 0x3FF) as i32;
|
||||
r.coeffs[4 * i + 3] = (((a[5 * i + 3] >> 6) as u32
|
||||
| (a[5 * i + 4] as u32) << 2)
|
||||
& 0x3FF) as i32;
|
||||
}
|
||||
}
|
||||
|
||||
/// Bit-pack polynomial t0 with coefficients in [-2^{D-1}, 2^{D-1}].
|
||||
pub fn polyt0_pack(r: &mut [u8], a: &Poly) {
|
||||
let mut t = [0i32; 8];
|
||||
|
||||
for i in 0..N / 8 {
|
||||
t[0] = D_SHL - a.coeffs[8 * i + 0];
|
||||
t[1] = D_SHL - a.coeffs[8 * i + 1];
|
||||
t[2] = D_SHL - a.coeffs[8 * i + 2];
|
||||
t[3] = D_SHL - a.coeffs[8 * i + 3];
|
||||
t[4] = D_SHL - a.coeffs[8 * i + 4];
|
||||
t[5] = D_SHL - a.coeffs[8 * i + 5];
|
||||
t[6] = D_SHL - a.coeffs[8 * i + 6];
|
||||
t[7] = D_SHL - a.coeffs[8 * i + 7];
|
||||
|
||||
r[13 * i + 0] = (t[0]) as u8;
|
||||
r[13 * i + 1] = (t[0] >> 8) as u8;
|
||||
r[13 * i + 1] |= (t[1] << 5) as u8;
|
||||
r[13 * i + 2] = (t[1] >> 3) as u8;
|
||||
r[13 * i + 3] = (t[1] >> 11) as u8;
|
||||
r[13 * i + 3] |= (t[2] << 2) as u8;
|
||||
r[13 * i + 4] = (t[2] >> 6) as u8;
|
||||
r[13 * i + 4] |= (t[3] << 7) as u8;
|
||||
r[13 * i + 5] = (t[3] >> 1) as u8;
|
||||
r[13 * i + 6] = (t[3] >> 9) as u8;
|
||||
r[13 * i + 6] |= (t[4] << 4) as u8;
|
||||
r[13 * i + 7] = (t[4] >> 4) as u8;
|
||||
r[13 * i + 8] = (t[4] >> 12) as u8;
|
||||
r[13 * i + 8] |= (t[5] << 1) as u8;
|
||||
r[13 * i + 9] = (t[5] >> 7) as u8;
|
||||
r[13 * i + 9] |= (t[6] << 6) as u8;
|
||||
r[13 * i + 10] = (t[6] >> 2) as u8;
|
||||
r[13 * i + 11] = (t[6] >> 10) as u8;
|
||||
r[13 * i + 11] |= (t[7] << 3) as u8;
|
||||
r[13 * i + 12] = (t[7] >> 5) as u8;
|
||||
}
|
||||
}
|
||||
|
||||
/// Unpack polynomial t0 with coefficients in ]-2^{D-1}, 2^{D-1}].
|
||||
/// Output coefficients lie in ]Q-2^{D-1},Q+2^{D-1}].
|
||||
pub fn polyt0_unpack(r: &mut Poly, a: &[u8]) {
|
||||
for i in 0..N / 8 {
|
||||
r.coeffs[8 * i + 0] = a[13 * i + 0] as i32;
|
||||
r.coeffs[8 * i + 0] |= (a[13 * i + 1] as i32) << 8;
|
||||
r.coeffs[8 * i + 0] &= 0x1FFF;
|
||||
|
||||
r.coeffs[8 * i + 1] = (a[13 * i + 1] as i32) >> 5;
|
||||
r.coeffs[8 * i + 1] |= (a[13 * i + 2] as i32) << 3;
|
||||
r.coeffs[8 * i + 1] |= (a[13 * i + 3] as i32) << 11;
|
||||
r.coeffs[8 * i + 1] &= 0x1FFF;
|
||||
|
||||
r.coeffs[8 * i + 2] = (a[13 * i + 3] as i32) >> 2;
|
||||
r.coeffs[8 * i + 2] |= (a[13 * i + 4] as i32) << 6;
|
||||
r.coeffs[8 * i + 2] &= 0x1FFF;
|
||||
|
||||
r.coeffs[8 * i + 3] = (a[13 * i + 4] as i32) >> 7;
|
||||
r.coeffs[8 * i + 3] |= (a[13 * i + 5] as i32) << 1;
|
||||
r.coeffs[8 * i + 3] |= (a[13 * i + 6] as i32) << 9;
|
||||
r.coeffs[8 * i + 3] &= 0x1FFF;
|
||||
|
||||
r.coeffs[8 * i + 4] = (a[13 * i + 6] as i32) >> 4;
|
||||
r.coeffs[8 * i + 4] |= (a[13 * i + 7] as i32) << 4;
|
||||
r.coeffs[8 * i + 4] |= (a[13 * i + 8] as i32) << 12;
|
||||
r.coeffs[8 * i + 4] &= 0x1FFF;
|
||||
|
||||
r.coeffs[8 * i + 5] = (a[13 * i + 8] as i32) >> 1;
|
||||
r.coeffs[8 * i + 5] |= (a[13 * i + 9] as i32) << 7;
|
||||
r.coeffs[8 * i + 5] &= 0x1FFF;
|
||||
|
||||
r.coeffs[8 * i + 6] = (a[13 * i + 9] as i32) >> 6;
|
||||
r.coeffs[8 * i + 6] |= (a[13 * i + 10] as i32) << 2;
|
||||
r.coeffs[8 * i + 6] |= (a[13 * i + 11] as i32) << 10;
|
||||
r.coeffs[8 * i + 6] &= 0x1FFF;
|
||||
|
||||
r.coeffs[8 * i + 7] = (a[13 * i + 11] as i32) >> 3;
|
||||
r.coeffs[8 * i + 7] |= (a[13 * i + 12] as i32) << 5;
|
||||
r.coeffs[8 * i + 7] &= 0x1FFF; // TODO: Unnecessary mask?
|
||||
|
||||
r.coeffs[8 * i + 0] = D_SHL - r.coeffs[8 * i + 0];
|
||||
r.coeffs[8 * i + 1] = D_SHL - r.coeffs[8 * i + 1];
|
||||
r.coeffs[8 * i + 2] = D_SHL - r.coeffs[8 * i + 2];
|
||||
r.coeffs[8 * i + 3] = D_SHL - r.coeffs[8 * i + 3];
|
||||
r.coeffs[8 * i + 4] = D_SHL - r.coeffs[8 * i + 4];
|
||||
r.coeffs[8 * i + 5] = D_SHL - r.coeffs[8 * i + 5];
|
||||
r.coeffs[8 * i + 6] = D_SHL - r.coeffs[8 * i + 6];
|
||||
r.coeffs[8 * i + 7] = D_SHL - r.coeffs[8 * i + 7];
|
||||
}
|
||||
}
|
||||
|
||||
/// Bit-pack polynomial z with coefficients
|
||||
/// in [-(GAMMA1 - 1), GAMMA1 - 1].
|
||||
/// Input coefficients are assumed to be standard representatives.*
|
||||
pub fn polyz_pack(r: &mut [u8], a: &Poly) {
|
||||
let mut t = [0i32; 4];
|
||||
if GAMMA1 == (1 << 17) {
|
||||
for i in 0..N / 4 {
|
||||
t[0] = GAMMA1_I32 - a.coeffs[4 * i + 0];
|
||||
t[1] = GAMMA1_I32 - a.coeffs[4 * i + 1];
|
||||
t[2] = GAMMA1_I32 - a.coeffs[4 * i + 2];
|
||||
t[3] = GAMMA1_I32 - a.coeffs[4 * i + 3];
|
||||
|
||||
r[9 * i + 0] = (t[0]) as u8;
|
||||
r[9 * i + 1] = (t[0] >> 8) as u8;
|
||||
r[9 * i + 2] = (t[0] >> 16) as u8;
|
||||
r[9 * i + 2] |= (t[1] << 2) as u8;
|
||||
r[9 * i + 3] = (t[1] >> 6) as u8;
|
||||
r[9 * i + 4] = (t[1] >> 14) as u8;
|
||||
r[9 * i + 4] |= (t[2] << 4) as u8;
|
||||
r[9 * i + 5] = (t[2] >> 4) as u8;
|
||||
r[9 * i + 6] = (t[2] >> 12) as u8;
|
||||
r[9 * i + 6] |= (t[3] << 6) as u8;
|
||||
r[9 * i + 7] = (t[3] >> 2) as u8;
|
||||
r[9 * i + 8] = (t[3] >> 10) as u8;
|
||||
}
|
||||
} else if GAMMA1 == 1 << 19 {
|
||||
for i in 0..N / 2 {
|
||||
t[0] = GAMMA1_I32 - a.coeffs[2 * i + 0];
|
||||
t[1] = GAMMA1_I32 - a.coeffs[2 * i + 1];
|
||||
|
||||
r[5 * i + 0] = (t[0]) as u8;
|
||||
r[5 * i + 1] = (t[0] >> 8) as u8;
|
||||
r[5 * i + 2] = (t[0] >> 16) as u8;
|
||||
r[5 * i + 2] |= (t[1] << 4) as u8;
|
||||
r[5 * i + 3] = (t[1] >> 4) as u8;
|
||||
r[5 * i + 4] = (t[1] >> 12) as u8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Unpack polynomial z with coefficients
|
||||
/// in [-(GAMMA1 - 1), GAMMA1 - 1].
|
||||
/// Output coefficients are standard representatives.
|
||||
pub fn polyz_unpack(r: &mut Poly, a: &[u8]) {
|
||||
if GAMMA1 == (1 << 17) {
|
||||
for i in 0..N / 4 {
|
||||
r.coeffs[4 * i + 0] = a[9 * i + 0] as i32;
|
||||
r.coeffs[4 * i + 0] |= (a[9 * i + 1] as i32) << 8;
|
||||
r.coeffs[4 * i + 0] |= (a[9 * i + 2] as i32) << 16;
|
||||
r.coeffs[4 * i + 0] &= 0x3FFFF;
|
||||
|
||||
r.coeffs[4 * i + 1] = (a[9 * i + 2] as i32) >> 2;
|
||||
r.coeffs[4 * i + 1] |= (a[9 * i + 3] as i32) << 6;
|
||||
r.coeffs[4 * i + 1] |= (a[9 * i + 4] as i32) << 14;
|
||||
r.coeffs[4 * i + 1] &= 0x3FFFF;
|
||||
|
||||
r.coeffs[4 * i + 2] = (a[9 * i + 4] as i32) >> 4;
|
||||
r.coeffs[4 * i + 2] |= (a[9 * i + 5] as i32) << 4;
|
||||
r.coeffs[4 * i + 2] |= (a[9 * i + 6] as i32) << 12;
|
||||
r.coeffs[4 * i + 2] &= 0x3FFFF;
|
||||
|
||||
r.coeffs[4 * i + 3] = (a[9 * i + 6] as i32) >> 6;
|
||||
r.coeffs[4 * i + 3] |= (a[9 * i + 7] as i32) << 2;
|
||||
r.coeffs[4 * i + 3] |= (a[9 * i + 8] as i32) << 10;
|
||||
r.coeffs[4 * i + 3] &= 0x3FFFF; // TODO: Unnecessary mask?
|
||||
|
||||
r.coeffs[4 * i + 0] = GAMMA1_I32 - r.coeffs[4 * i + 0];
|
||||
r.coeffs[4 * i + 1] = GAMMA1_I32 - r.coeffs[4 * i + 1];
|
||||
r.coeffs[4 * i + 2] = GAMMA1_I32 - r.coeffs[4 * i + 2];
|
||||
r.coeffs[4 * i + 3] = GAMMA1_I32 - r.coeffs[4 * i + 3];
|
||||
}
|
||||
} else if GAMMA1 == 1 << 19 {
|
||||
for i in 0..N / 2 {
|
||||
r.coeffs[2 * i + 0] = a[5 * i + 0] as i32;
|
||||
r.coeffs[2 * i + 0] |= (a[5 * i + 1] as i32) << 8;
|
||||
r.coeffs[2 * i + 0] |= (a[5 * i + 2] as i32) << 16;
|
||||
r.coeffs[2 * i + 0] &= 0xFFFFF;
|
||||
|
||||
r.coeffs[2 * i + 1] = (a[5 * i + 2] as i32) >> 4;
|
||||
r.coeffs[2 * i + 1] |= (a[5 * i + 3] as i32) << 4;
|
||||
r.coeffs[2 * i + 1] |= (a[5 * i + 4] as i32) << 12;
|
||||
r.coeffs[2 * i + 0] &= 0xFFFFF; // TODO: Unnecessary mask?
|
||||
|
||||
r.coeffs[2 * i + 0] = GAMMA1_I32 - r.coeffs[2 * i + 0];
|
||||
r.coeffs[2 * i + 1] = GAMMA1_I32 - r.coeffs[2 * i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Bit-pack polynomial w1 with coefficients in [0, 15].
|
||||
/// Input coefficients are assumed to be standard representatives.
|
||||
pub fn polyw1_pack(r: &mut [u8], a: &Poly) {
|
||||
if GAMMA2 == (Q - 1) / 88 {
|
||||
for i in 0..N / 4 {
|
||||
r[3 * i + 0] = a.coeffs[4 * i + 0] as u8;
|
||||
r[3 * i + 0] |= (a.coeffs[4 * i + 1] << 6) as u8;
|
||||
r[3 * i + 1] = (a.coeffs[4 * i + 1] >> 2) as u8;
|
||||
r[3 * i + 1] |= (a.coeffs[4 * i + 2] << 4) as u8;
|
||||
r[3 * i + 2] = (a.coeffs[4 * i + 2] >> 4) as u8;
|
||||
r[3 * i + 2] |= (a.coeffs[4 * i + 3] << 2) as u8;
|
||||
}
|
||||
} else {
|
||||
for i in 0..N / 2 {
|
||||
r[i] = (a.coeffs[2 * i + 0] | (a.coeffs[2 * i + 1] << 4)) as u8;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,273 @@
|
|||
use crate::params::*;
|
||||
use crate::poly::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Polyveck {
|
||||
pub vec: [Poly; K],
|
||||
}
|
||||
|
||||
impl Default for Polyveck {
|
||||
fn default() -> Self {
|
||||
Polyveck {
|
||||
vec: [Poly::default(); K],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Polyvecl {
|
||||
pub vec: [Poly; L],
|
||||
}
|
||||
|
||||
impl Default for Polyvecl {
|
||||
fn default() -> Self {
|
||||
Polyvecl {
|
||||
vec: [Poly::default(); L],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implementation of ExpandA. Generates matrix A with uniformly
|
||||
/// random coefficients a_{i,j} by performing rejection
|
||||
/// sampling on the output stream of SHAKE128(rho|j|i)
|
||||
/// or AES256CTR(rho,j|i).
|
||||
pub fn polyvec_matrix_expand(mat: &mut [Polyvecl], rho: &[u8]) {
|
||||
for i in 0..K {
|
||||
for j in 0..L {
|
||||
poly_uniform(&mut mat[i].vec[j], rho, ((i << 8) + j) as u16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn polyvec_matrix_pointwise_montgomery(
|
||||
t: &mut Polyveck,
|
||||
mat: &[Polyvecl],
|
||||
v: &Polyvecl,
|
||||
) {
|
||||
for i in 0..K {
|
||||
polyvecl_pointwise_acc_montgomery(&mut t.vec[i], &mat[i], v);
|
||||
}
|
||||
}
|
||||
|
||||
//*********** Vectors of polynomials of length L ****************************
|
||||
|
||||
pub fn polyvecl_uniform_eta(v: &mut Polyvecl, seed: &[u8], mut nonce: u16) {
|
||||
for i in 0..L {
|
||||
poly_uniform_eta(&mut v.vec[i], seed, nonce);
|
||||
nonce += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn polyvecl_uniform_gamma1(v: &mut Polyvecl, seed: &[u8], nonce: u16) {
|
||||
for i in 0..L {
|
||||
poly_uniform_gamma1(&mut v.vec[i], seed, L_U16 * nonce + i as u16);
|
||||
}
|
||||
}
|
||||
pub fn polyvecl_reduce(v: &mut Polyvecl) {
|
||||
for i in 0..L {
|
||||
poly_reduce(&mut v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add vectors of polynomials of length L.
|
||||
/// No modular reduction is performed.
|
||||
pub fn polyvecl_add(w: &mut Polyvecl, v: &Polyvecl) {
|
||||
for i in 0..L {
|
||||
poly_add(&mut w.vec[i], &v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Forward NTT of all polynomials in vector of length L. Output
|
||||
/// coefficients can be up to 16*Q larger than input coefficients.*
|
||||
pub fn polyvecl_ntt(v: &mut Polyvecl) {
|
||||
for i in 0..L {
|
||||
poly_ntt(&mut v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn polyvecl_invntt_tomont(v: &mut Polyvecl) {
|
||||
for i in 0..L {
|
||||
poly_invntt_tomont(&mut v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn polyvecl_pointwise_poly_montgomery(
|
||||
r: &mut Polyvecl,
|
||||
a: &Poly,
|
||||
v: &Polyvecl,
|
||||
) {
|
||||
for i in 0..L {
|
||||
poly_pointwise_montgomery(&mut r.vec[i], a, &v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Pointwise multiply vectors of polynomials of length L, multiply
|
||||
/// resulting vector by 2^{-32} and add (accumulate) polynomials
|
||||
/// in it. Input/output vectors are in NTT domain representation.
|
||||
/// Input coefficients are assumed to be less than 22*Q. Output
|
||||
/// coeffcient are less than 2*L*Q.
|
||||
pub fn polyvecl_pointwise_acc_montgomery(
|
||||
w: &mut Poly,
|
||||
u: &Polyvecl,
|
||||
v: &Polyvecl,
|
||||
) {
|
||||
let mut t = Poly::default();
|
||||
poly_pointwise_montgomery(w, &u.vec[0], &v.vec[0]);
|
||||
for i in 1..L {
|
||||
poly_pointwise_montgomery(&mut t, &u.vec[i], &v.vec[i]);
|
||||
poly_add(w, &t);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check infinity norm of polynomials in vector of length L.
|
||||
/// Assumes input coefficients to be standard representatives.
|
||||
/// Returns 0 if norm of all polynomials is strictly smaller than B and 1
|
||||
/// otherwise.
|
||||
pub fn polyvecl_chknorm(v: &Polyvecl, bound: i32) -> u8 {
|
||||
for i in 0..L {
|
||||
if poly_chknorm(&v.vec[i], bound) > 0 {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//*********** Vectors of polynomials of length K ****************************
|
||||
|
||||
pub fn polyveck_uniform_eta(v: &mut Polyveck, seed: &[u8], mut nonce: u16) {
|
||||
for i in 0..K {
|
||||
poly_uniform_eta(&mut v.vec[i], seed, nonce);
|
||||
nonce += 1
|
||||
}
|
||||
}
|
||||
|
||||
/// Reduce coefficients of polynomials in vector of length K
|
||||
/// to representatives in [0,2*Q].
|
||||
pub fn polyveck_reduce(v: &mut Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_reduce(&mut v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// For all coefficients of polynomials in vector of length K
|
||||
/// add Q if coefficient is negative.
|
||||
pub fn polyveck_caddq(v: &mut Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_caddq(&mut v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add vectors of polynomials of length K.
|
||||
/// No modular reduction is performed.
|
||||
pub fn polyveck_add(w: &mut Polyveck, v: &Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_add(&mut w.vec[i], &v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Subtract vectors of polynomials of length K.
|
||||
/// Assumes coefficients of polynomials in second input vector
|
||||
/// to be less than 2*Q. No modular reduction is performed.
|
||||
pub fn polyveck_sub(w: &mut Polyveck, v: &Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_sub(&mut w.vec[i], &v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Multiply vector of polynomials of Length K by 2^D without modular
|
||||
/// reduction. Assumes input coefficients to be less than 2^{32-D}.
|
||||
pub fn polyveck_shiftl(v: &mut Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_shiftl(&mut v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Forward NTT of all polynomials in vector of length K. Output
|
||||
/// coefficients can be up to 16*Q larger than input coefficients.
|
||||
pub fn polyveck_ntt(v: &mut Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_ntt(&mut v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Inverse NTT and multiplication by 2^{32} of polynomials
|
||||
/// in vector of length K. Input coefficients need to be less
|
||||
/// than 2*Q.
|
||||
pub fn polyveck_invntt_tomont(v: &mut Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_invntt_tomont(&mut v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn polyveck_pointwise_poly_montgomery(
|
||||
r: &mut Polyveck,
|
||||
a: &Poly,
|
||||
v: &Polyveck,
|
||||
) {
|
||||
for i in 0..K {
|
||||
poly_pointwise_montgomery(&mut r.vec[i], a, &v.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check infinity norm of polynomials in vector of length K.
|
||||
/// Assumes input coefficients to be standard representatives.
|
||||
//
|
||||
/// Returns 0 if norm of all polynomials are strictly smaller than B and 1
|
||||
/// otherwise.
|
||||
pub fn polyveck_chknorm(v: &Polyveck, bound: i32) -> u8 {
|
||||
for i in 0..K {
|
||||
if poly_chknorm(&v.vec[i], bound) > 0 {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// For all coefficients a of polynomials in vector of length K,
|
||||
/// compute a0, a1 such that a mod Q = a1*2^D + a0
|
||||
/// with -2^{D-1} < a0 <= 2^{D-1}. Assumes coefficients to be
|
||||
/// standard representatives.
|
||||
pub fn polyveck_power2round(v1: &mut Polyveck, v0: &mut Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_power2round(&mut v1.vec[i], &mut v0.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// For all coefficients a of polynomials in vector of length K,
|
||||
/// compute high and low bits a0, a1 such a mod Q = a1*ALPHA + a0
|
||||
/// with -ALPHA/2 < a0 <= ALPHA/2 except a1 = (Q-1)/ALPHA where we
|
||||
/// set a1 = 0 and -ALPHA/2 <= a0 = a mod Q - Q < 0.
|
||||
/// Assumes coefficients to be standard representatives.
|
||||
pub fn polyveck_decompose(v1: &mut Polyveck, v0: &mut Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_decompose(&mut v1.vec[i], &mut v0.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute hint vector.
|
||||
///
|
||||
/// Returns number of 1 bits.
|
||||
pub fn polyveck_make_hint(
|
||||
h: &mut Polyveck,
|
||||
v0: &Polyveck,
|
||||
v1: &Polyveck,
|
||||
) -> i32 {
|
||||
let mut s = 0i32;
|
||||
for i in 0..K {
|
||||
s += poly_make_hint(&mut h.vec[i], &v0.vec[i], &v1.vec[i]);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// Use hint vector to correct the high bits of input vector.
|
||||
pub fn polyveck_use_hint(w: &mut Polyveck, h: &Polyveck) {
|
||||
for i in 0..K {
|
||||
poly_use_hint(&mut w.vec[i], &h.vec[i]);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn polyveck_pack_w1(r: &mut [u8], w1: &Polyveck) {
|
||||
for i in 0..K {
|
||||
polyw1_pack(&mut r[i * POLYW1_PACKEDBYTES..], &w1.vec[i]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
use rand::prelude::*;
|
||||
|
||||
pub fn randombytes(x: &mut [u8], len: usize) {
|
||||
thread_rng().fill_bytes(&mut x[..len])
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
use crate::params::*;
|
||||
|
||||
pub const QINV: i32 = 58728449; // q^(-1) mod 2^32
|
||||
|
||||
/// For finite field element a with -2^{31}Q <= a <= Q*2^31,
|
||||
/// compute r \equiv a*2^{-32} (mod Q) such that -Q < r < Q.
|
||||
///
|
||||
/// Returns r.
|
||||
pub fn montgomery_reduce(a: i64) -> i32 {
|
||||
let mut t = (a as i32).wrapping_mul(QINV) as i64;
|
||||
t = (a as i64 - t * Q as i64) >> 32;
|
||||
t as i32
|
||||
}
|
||||
|
||||
/// For finite field element a with a <= 2^{31} - 2^{22} - 1,
|
||||
/// compute r \equiv a (mod Q) such that -6283009 <= r <= 6283007.
|
||||
//
|
||||
/// Returns r.
|
||||
pub fn reduce32(a: i32) -> i32 {
|
||||
let mut t = (a + (1 << 22)) >> 23;
|
||||
t = a - t * Q as i32;
|
||||
t
|
||||
}
|
||||
|
||||
/// Add Q if input coefficient is negative.
|
||||
///
|
||||
/// Returns r.
|
||||
pub fn caddq(a: i32) -> i32 {
|
||||
a + ((a >> 31) & Q as i32)
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
use crate::params::*;
|
||||
|
||||
/// For finite field element a, compute a0, a1 such that
|
||||
/// a mod^+ Q = a1*2^D + a0 with -2^{D-1} < a0 <= 2^{D-1}.
|
||||
/// Assumes a to be standard representative.
|
||||
///
|
||||
/// Returns a1.
|
||||
pub fn power2round(a: i32, a0: &mut i32) -> i32 {
|
||||
let a1 = (a + (1 << (D - 1)) - 1) >> D;
|
||||
*a0 = a - (a1 << D);
|
||||
return a1;
|
||||
}
|
||||
|
||||
/// For finite field element a, compute high and low bits a0, a1 such
|
||||
/// that a mod^+ Q = a1*ALPHA + a0 with -ALPHA/2 < a0 <= ALPHA/2 except
|
||||
/// if a1 = (Q-1)/ALPHA where we set a1 = 0 and
|
||||
/// -ALPHA/2 <= a0 = a mod^+ Q - Q < 0. Assumes a to be standard
|
||||
/// representative.
|
||||
///
|
||||
/// Returns a1.
|
||||
pub fn decompose(a0: &mut i32, a: i32) -> i32 {
|
||||
let mut a1 = (a + 127) >> 7;
|
||||
if GAMMA2 == (Q - 1) / 32 {
|
||||
a1 = (a1 * 1025 + (1 << 21)) >> 22;
|
||||
a1 &= 15;
|
||||
} else if GAMMA2 == (Q - 1) / 88 {
|
||||
a1 = (a1 * 11275 + (1 << 23)) >> 24;
|
||||
a1 ^= ((43 - a1) >> 31) & a1;
|
||||
}
|
||||
*a0 = a - a1 * 2 * GAMMA2_I32;
|
||||
*a0 -= (((Q_I32 - 1) / 2 - *a0) >> 31) & Q_I32;
|
||||
a1
|
||||
}
|
||||
|
||||
/// Compute hint bit indicating whether the low bits of the
|
||||
/// input element overflow into the high bits.
|
||||
///
|
||||
/// Returns 1 if overflow.
|
||||
pub fn make_hint(a0: i32, a1: i32) -> u8 {
|
||||
if a0 > GAMMA2_I32 || a0 < -GAMMA2_I32 || (a0 == -GAMMA2_I32 && a1 != 0) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Correct high bits according to hint.
|
||||
///
|
||||
/// Returns corrected high bits.
|
||||
pub fn use_hint(a: i32, hint: u8) -> i32 {
|
||||
let mut a0 = 0i32;
|
||||
let a1 = decompose(&mut a0, a);
|
||||
if hint == 0 {
|
||||
return a1;
|
||||
}
|
||||
|
||||
if GAMMA2 == (Q - 1) / 32 {
|
||||
if a0 > 0 {
|
||||
return (a1 + 1) & 15;
|
||||
} else {
|
||||
return (a1 - 1) & 15;
|
||||
}
|
||||
} else {
|
||||
if a0 > 0 {
|
||||
if a1 == 43 {
|
||||
return 0;
|
||||
} else {
|
||||
return a1 + 1;
|
||||
};
|
||||
} else {
|
||||
if a1 == 0 {
|
||||
return 43;
|
||||
} else {
|
||||
return a1 - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,247 @@
|
|||
use crate::{
|
||||
fips202::*, packing::*, params::*, poly::*, polyvec::*, randombytes::*,
|
||||
SignError,
|
||||
};
|
||||
|
||||
pub fn crypto_sign_keypair(
|
||||
pk: &mut [u8],
|
||||
sk: &mut [u8],
|
||||
seed: Option<&[u8]>,
|
||||
) -> u8 {
|
||||
let mut init_seed = [0u8; SEEDBYTES];
|
||||
match seed {
|
||||
Some(x) => init_seed.copy_from_slice(x),
|
||||
None => randombytes(&mut init_seed, SEEDBYTES),
|
||||
};
|
||||
let mut seedbuf = [0u8; 2 * SEEDBYTES + CRHBYTES];
|
||||
let mut tr = [0u8; SEEDBYTES];
|
||||
let (mut rho, mut rhoprime, mut key) =
|
||||
([0u8; SEEDBYTES], [0u8; CRHBYTES], [0u8; SEEDBYTES]);
|
||||
let mut mat = [Polyvecl::default(); K];
|
||||
let mut s1 = Polyvecl::default();
|
||||
let (mut s2, mut t1, mut t0) = (
|
||||
Polyveck::default(),
|
||||
Polyveck::default(),
|
||||
Polyveck::default(),
|
||||
);
|
||||
|
||||
// Get randomness for rho, rhoprime and key
|
||||
shake256(
|
||||
&mut seedbuf,
|
||||
2 * SEEDBYTES + CRHBYTES,
|
||||
&init_seed,
|
||||
SEEDBYTES,
|
||||
);
|
||||
rho.copy_from_slice(&seedbuf[..SEEDBYTES]);
|
||||
rhoprime.copy_from_slice(&seedbuf[SEEDBYTES..SEEDBYTES + CRHBYTES]);
|
||||
key.copy_from_slice(&seedbuf[SEEDBYTES + CRHBYTES..]);
|
||||
|
||||
// Expand matrix
|
||||
polyvec_matrix_expand(&mut mat, &rho);
|
||||
// Sample short vectors s1 and s2
|
||||
polyvecl_uniform_eta(&mut s1, &rhoprime, 0);
|
||||
polyveck_uniform_eta(&mut s2, &rhoprime, L_U16);
|
||||
|
||||
// Matrix-vector multiplication
|
||||
let mut s1hat = s1;
|
||||
polyvecl_ntt(&mut s1hat);
|
||||
|
||||
polyvec_matrix_pointwise_montgomery(&mut t1, &mat, &s1hat);
|
||||
polyveck_reduce(&mut t1);
|
||||
polyveck_invntt_tomont(&mut t1);
|
||||
|
||||
// Add error vector s2
|
||||
polyveck_add(&mut t1, &s2);
|
||||
// Extract t1 and write public key
|
||||
polyveck_caddq(&mut t1);
|
||||
polyveck_power2round(&mut t1, &mut t0);
|
||||
pack_pk(pk, &rho, &t1);
|
||||
|
||||
// Compute H(rho, t1) and write secret key
|
||||
shake256(&mut tr, SEEDBYTES, pk, PUBLICKEYBYTES);
|
||||
pack_sk(sk, &rho, &tr, &key, &t0, &s1, &s2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn crypto_sign_signature(sig: &mut [u8], m: &[u8], sk: &[u8]) {
|
||||
// `key` and `mu` are concatenated
|
||||
let mut keymu = [0u8; SEEDBYTES + CRHBYTES];
|
||||
|
||||
let mut nonce = 0u16;
|
||||
let mut mat = [Polyvecl::default(); K];
|
||||
let (mut s1, mut y) = (Polyvecl::default(), Polyvecl::default());
|
||||
let (mut s2, mut t0) = (Polyveck::default(), Polyveck::default());
|
||||
let (mut w1, mut w0) = (Polyveck::default(), Polyveck::default());
|
||||
let mut h = Polyveck::default();
|
||||
let mut cp = Poly::default();
|
||||
let mut state = KeccakState::default(); //shake256_init()
|
||||
let mut rho = [0u8; SEEDBYTES];
|
||||
let mut tr = [0u8; SEEDBYTES];
|
||||
let mut rhoprime = [0u8; CRHBYTES];
|
||||
|
||||
unpack_sk(
|
||||
&mut rho,
|
||||
&mut tr,
|
||||
&mut keymu[..SEEDBYTES],
|
||||
&mut t0,
|
||||
&mut s1,
|
||||
&mut s2,
|
||||
&sk,
|
||||
);
|
||||
|
||||
// Compute CRH(tr, msg)
|
||||
shake256_absorb(&mut state, &tr, SEEDBYTES);
|
||||
shake256_absorb(&mut state, m, m.len());
|
||||
shake256_finalize(&mut state);
|
||||
shake256_squeeze(&mut keymu[SEEDBYTES..], CRHBYTES, &mut state);
|
||||
|
||||
if RANDOMIZED_SIGNING {
|
||||
randombytes(&mut rhoprime, CRHBYTES);
|
||||
} else {
|
||||
shake256(&mut rhoprime, CRHBYTES, &keymu, SEEDBYTES + CRHBYTES);
|
||||
}
|
||||
|
||||
// Expand matrix and transform vectors
|
||||
polyvec_matrix_expand(&mut mat, &rho);
|
||||
polyvecl_ntt(&mut s1);
|
||||
polyveck_ntt(&mut s2);
|
||||
polyveck_ntt(&mut t0);
|
||||
|
||||
loop {
|
||||
// Sample intermediate vector y
|
||||
polyvecl_uniform_gamma1(&mut y, &rhoprime, nonce);
|
||||
nonce += 1;
|
||||
|
||||
// Matrix-vector multiplication
|
||||
let mut z = y;
|
||||
polyvecl_ntt(&mut z);
|
||||
polyvec_matrix_pointwise_montgomery(&mut w1, &mat, &z);
|
||||
polyveck_reduce(&mut w1);
|
||||
polyveck_invntt_tomont(&mut w1);
|
||||
|
||||
// Decompose w and call the random oracle
|
||||
polyveck_caddq(&mut w1);
|
||||
polyveck_decompose(&mut w1, &mut w0);
|
||||
polyveck_pack_w1(sig, &w1);
|
||||
|
||||
state.init();
|
||||
shake256_absorb(&mut state, &keymu[SEEDBYTES..], CRHBYTES);
|
||||
shake256_absorb(&mut state, &sig, K * POLYW1_PACKEDBYTES);
|
||||
shake256_finalize(&mut state);
|
||||
shake256_squeeze(sig, SEEDBYTES, &mut state);
|
||||
poly_challenge(&mut cp, sig);
|
||||
poly_ntt(&mut cp);
|
||||
|
||||
// Compute z, reject if it reveals secret
|
||||
polyvecl_pointwise_poly_montgomery(&mut z, &cp, &s1);
|
||||
polyvecl_invntt_tomont(&mut z);
|
||||
polyvecl_add(&mut z, &y);
|
||||
polyvecl_reduce(&mut z);
|
||||
if polyvecl_chknorm(&z, (GAMMA1 - BETA) as i32) > 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check that subtracting cs2 does not change high bits of w and low bits
|
||||
* do not reveal secret information */
|
||||
polyveck_pointwise_poly_montgomery(&mut h, &cp, &s2);
|
||||
polyveck_invntt_tomont(&mut h);
|
||||
polyveck_sub(&mut w0, &h);
|
||||
polyveck_reduce(&mut w0);
|
||||
if polyveck_chknorm(&w0, (GAMMA2 - BETA) as i32) > 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compute hints for w1
|
||||
polyveck_pointwise_poly_montgomery(&mut h, &cp, &t0);
|
||||
polyveck_invntt_tomont(&mut h);
|
||||
polyveck_reduce(&mut h);
|
||||
if polyveck_chknorm(&h, GAMMA2_I32) > 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
polyveck_add(&mut w0, &h);
|
||||
let n = polyveck_make_hint(&mut h, &w0, &w1);
|
||||
if n > OMEGA as i32 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Write signature
|
||||
pack_sig(sig, None, &z, &h);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn crypto_sign_verify(
|
||||
sig: &[u8],
|
||||
m: &[u8],
|
||||
pk: &[u8],
|
||||
) -> Result<(), SignError> {
|
||||
let mut buf = [0u8; K * POLYW1_PACKEDBYTES];
|
||||
let mut rho = [0u8; SEEDBYTES];
|
||||
let mut mu = [0u8; CRHBYTES];
|
||||
let mut c = [0u8; SEEDBYTES];
|
||||
let mut c2 = [0u8; SEEDBYTES];
|
||||
let mut cp = Poly::default();
|
||||
let (mut mat, mut z) = ([Polyvecl::default(); K], Polyvecl::default());
|
||||
let (mut t1, mut w1, mut h) = (
|
||||
Polyveck::default(),
|
||||
Polyveck::default(),
|
||||
Polyveck::default(),
|
||||
);
|
||||
let mut state = KeccakState::default(); // shake256_init()
|
||||
|
||||
if sig.len() != SIGNBYTES {
|
||||
return Err(SignError::Input);
|
||||
}
|
||||
|
||||
unpack_pk(&mut rho, &mut t1, pk);
|
||||
if let Err(e) = unpack_sig(&mut c, &mut z, &mut h, sig) {
|
||||
return Err(e);
|
||||
}
|
||||
if polyvecl_chknorm(&z, (GAMMA1 - BETA) as i32) > 0 {
|
||||
return Err(SignError::Input);
|
||||
}
|
||||
|
||||
// Compute CRH(CRH(rho, t1), msg)
|
||||
shake256(&mut mu, SEEDBYTES, pk, PUBLICKEYBYTES);
|
||||
shake256_absorb(&mut state, &mu, SEEDBYTES);
|
||||
shake256_absorb(&mut state, m, m.len());
|
||||
shake256_finalize(&mut state);
|
||||
shake256_squeeze(&mut mu, CRHBYTES, &mut state);
|
||||
|
||||
// Matrix-vector multiplication; compute Az - c2^dt1
|
||||
poly_challenge(&mut cp, &c);
|
||||
polyvec_matrix_expand(&mut mat, &rho);
|
||||
|
||||
polyvecl_ntt(&mut z);
|
||||
polyvec_matrix_pointwise_montgomery(&mut w1, &mat, &z);
|
||||
|
||||
poly_ntt(&mut cp);
|
||||
polyveck_shiftl(&mut t1);
|
||||
polyveck_ntt(&mut t1);
|
||||
let t1_2 = t1.clone();
|
||||
polyveck_pointwise_poly_montgomery(&mut t1, &cp, &t1_2);
|
||||
|
||||
polyveck_sub(&mut w1, &t1);
|
||||
polyveck_reduce(&mut w1);
|
||||
polyveck_invntt_tomont(&mut w1);
|
||||
|
||||
// Reconstruct w1
|
||||
polyveck_caddq(&mut w1);
|
||||
polyveck_use_hint(&mut w1, &h);
|
||||
polyveck_pack_w1(&mut buf, &w1);
|
||||
|
||||
// Call random oracle and verify challenge
|
||||
state.init();
|
||||
shake256_absorb(&mut state, &mu, CRHBYTES);
|
||||
shake256_absorb(&mut state, &buf, K * POLYW1_PACKEDBYTES);
|
||||
shake256_finalize(&mut state);
|
||||
shake256_squeeze(&mut c2, SEEDBYTES, &mut state);
|
||||
// Doesn't require constant time equality check
|
||||
if c != c2 {
|
||||
Err(SignError::Verify)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
use crate::fips202::*;
|
||||
use crate::params::{CRHBYTES, SEEDBYTES};
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
use crate::aes256ctr::*;
|
||||
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub type Stream128State = KeccakState;
|
||||
#[cfg(feature = "aes")]
|
||||
pub type Stream128State = Aes256ctrCtx;
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub type Stream256State = KeccakState;
|
||||
#[cfg(feature = "aes")]
|
||||
pub type Stream256State = Aes256ctrCtx;
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
pub const STREAM128_BLOCKBYTES: usize = AES256CTR_BLOCKBYTES;
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub const STREAM128_BLOCKBYTES: usize = SHAKE128_RATE;
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
pub const STREAM256_BLOCKBYTES: usize = AES256CTR_BLOCKBYTES;
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub const STREAM256_BLOCKBYTES: usize = SHAKE256_RATE;
|
||||
|
||||
pub fn _crh(out: &mut [u8], input: &[u8], inbytes: usize) {
|
||||
shake256(out, CRHBYTES, input, inbytes)
|
||||
}
|
||||
|
||||
pub fn stream128_init(state: &mut Stream128State, seed: &[u8], nonce: u16) {
|
||||
#[cfg(not(feature = "aes"))]
|
||||
dilithium_shake128_stream_init(state, seed, nonce);
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
dilithium_aes256ctr_init(state, seed, nonce)
|
||||
}
|
||||
|
||||
pub fn stream128_squeezeblocks(
|
||||
out: &mut [u8],
|
||||
outblocks: u64,
|
||||
state: &mut Stream128State,
|
||||
) {
|
||||
#[cfg(not(feature = "aes"))]
|
||||
shake128_squeezeblocks(out, outblocks as usize, state);
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
aes256ctr_squeezeblocks(out, outblocks, state);
|
||||
}
|
||||
|
||||
pub fn stream256_init(state: &mut Stream256State, seed: &[u8], nonce: u16) {
|
||||
#[cfg(not(feature = "aes"))]
|
||||
dilithium_shake256_stream_init(state, seed, nonce);
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
dilithium_aes256ctr_init(state, seed, nonce)
|
||||
}
|
||||
|
||||
pub fn stream256_squeezeblocks(
|
||||
out: &mut [u8],
|
||||
outblocks: u64,
|
||||
state: &mut Stream256State,
|
||||
) {
|
||||
#[cfg(not(feature = "aes"))]
|
||||
shake256_squeezeblocks(out, outblocks as usize, state);
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
aes256ctr_squeezeblocks(out, outblocks, state);
|
||||
}
|
||||
|
||||
#[cfg(feature = "aes")]
|
||||
pub fn dilithium_aes256ctr_init(
|
||||
state: &mut Aes256ctrCtx,
|
||||
key: &[u8],
|
||||
nonce: u16,
|
||||
) {
|
||||
let mut expnonce = [0u8; 12];
|
||||
expnonce[0] = nonce as u8;
|
||||
expnonce[1] = (nonce >> 8) as u8;
|
||||
aes256ctr_init(state, key, expnonce);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub fn dilithium_shake128_stream_init(
|
||||
state: &mut KeccakState,
|
||||
seed: &[u8],
|
||||
nonce: u16,
|
||||
) {
|
||||
let t = [nonce as u8, (nonce >> 8) as u8];
|
||||
state.init();
|
||||
shake128_absorb(state, seed, SEEDBYTES);
|
||||
shake128_absorb(state, &t, 2);
|
||||
shake128_finalize(state);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "aes"))]
|
||||
pub fn dilithium_shake256_stream_init(
|
||||
state: &mut KeccakState,
|
||||
seed: &[u8],
|
||||
nonce: u16,
|
||||
) {
|
||||
let t = [nonce as u8, (nonce >> 8) as u8];
|
||||
state.init();
|
||||
shake256_absorb(state, seed, CRHBYTES);
|
||||
shake256_absorb(state, &t, 2);
|
||||
shake256_finalize(state);
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,100 @@
|
|||
7C9935A0B07694AA0C6D10E4DB6B1ADD2FD81A25CCB148032DCD739936737F2D
|
||||
4B622DE1350119C45A9F2E2EF3DC5DF50A759D138CDFBD64C81CC7CC2F513345
|
||||
1D836E889E46259BCD1CCD2B369583C5B47CFBB919EC2B72C280247CB15A5569
|
||||
539577CB7F2088FBEDFF1B53F235D607321857DB32BBA645F8DF3A89DD426552
|
||||
2CA59C6CF33C53803749F69EF5ABFA9482FCEE7EFD87FBF17135ECC3FF3FD7F7
|
||||
E17E72290E49A44C9C534F211195257CF13B0D45405782CEDA2D7F982A551721
|
||||
3B7388E675DE5C59A78AF095481C7DD999C6EEA898595B1E7DCDA7EDC3A2C25C
|
||||
DC9F40CABE2E8E4F3D1538FBC1ADA27B61B99081455AB0C4C41B5B3DA8101000
|
||||
1DADE637AE98C393260F5BBBE288373100DD7AF37EBA913C528D2B7B998767CB
|
||||
8866693CEE12B909E32A0C64381796633666417E1246B51A2643564B464B4113
|
||||
D6DAD5B2746422F4487B72536D70DF88AF4B2F9040AA45999F8D7784EF696DA0
|
||||
68E7818F33B97BA6166768C395BD010CEF7BCE9995891D164303B53C1123A991
|
||||
35B153A7706109D4A13D7C4B26AA5B56D9E3FAC53B47E91B0C10BD4E0EAAFC19
|
||||
0E1A1634FB2396E187CD8980EF29663C42DC3EF963CCD491F817A84283A11FA0
|
||||
B0BFA060F1C1A70F1AC55E321E6186A6613605DD732574B5FE6E14F0FF6F7A82
|
||||
A33BC0A7A08C13C0D4C1174DDD886AAC4C5666E1F4831F006C9519D36B2CE882
|
||||
C7E33FA5329142B668CCDDE1057EB7A8619397537F2B4C6D6755B3B9FF936441
|
||||
7611B5B7D4195D5F8B97244B6811748EFEA929EA272E66435A36D0BD16E3BF21
|
||||
5A1E3E05C72CEF1A73EF98840DA035E4FD2552912DB8DAE28A79011DE4BBC1A4
|
||||
8F3920A235EEC3659CFCFE62931474204EAE264959702F901D461B66D9BB563D
|
||||
0B2B3EB50681403A0B9A99B25041A489C6D45D2A49DE0EC83E1FD10922ABE2D5
|
||||
8217D32CD15658D39CDCA92C41B59F5780869A68838A3579DEA48B5E3EA768AA
|
||||
CC625322C9D52898E7F60AE47BC2847E20F3722794DE41E30FDB20CA1A093208
|
||||
950226D6AB0B774C5F439AFCFD0113B5DBF5905960C445F5E6E03E5D5C687A9A
|
||||
A6B534767A6D839FD19075AE0BA10147C46862BF7BBCBE83F2B72F72F1368A1F
|
||||
103164ED522DF0DB131C15E139C0F83D9B1B7A1B6ECF7F89A5248CAD7E68DE8C
|
||||
BC962D978F38881085C1B813BC90EEE44AD9E7651681C20BA46402F557C454DE
|
||||
C3DE54854A4060EA09ED92A363F71C7863EBA64195E9AC79E7AD7EB6A183CFAC
|
||||
828B9804524BDD17D0EB387368B01B0E95B4960057ED63FC2289D858201E207E
|
||||
4A84CA5C3954FAAFA11AE87FCBE701EBB5AFBCC5F8ECAE7786D10821E01ADA5A
|
||||
3E74AE2B1D49EE6F149076F0BAE2D26A5CADFD5DE7BEF66DFCAE6B588A1F4067
|
||||
39550BD2782D66FA95380F5F101D827377B11410F8BF3BCCFBE0E504FC09AE38
|
||||
B18F0FDF9DC4F514107F88CC43FB29190608EBC5A2CD00B49FE20631761038DF
|
||||
D4FA14DA39548392300A41BE413EBD53BD7BCBD045B4D3C8CA44ABC9599E269D
|
||||
C796FD12D1FEB1DF46B162C38292684C09059E4463CB95DBDBF498A4DD4F7F00
|
||||
A18A366A5ECACAE4732DC9E954333EAD153203013BAC4E3C50BEE15269F983FB
|
||||
585E714D565AA66078BC2B12699F1E86C6FF30A1ABC8CBD19563BCDDD2F1F6D2
|
||||
662CF70D3D5E95A9C6A33BD7C6ABF0E8CD23AB2D2D9420878C4835DE14A6C606
|
||||
1924A71628292AA3D2D34EA72E2BFC2520864205F54EC6F19F7714733AA34CC9
|
||||
EF7BA21809AE7E0BC3230B6061C5FEE206D805572CF1345198E1EF22A8FE7322
|
||||
CB0B305FB54E1CB23B63EC1F6F4689137E5048D095FB3EADC854C852CA86BE93
|
||||
F92FFA3A36F43F9177763AD320FD651D9357C6D99F09549FE6AF12943B58BE90
|
||||
5D3CCE926A795ABC5F6632CABFF8BF66275DCC7E4A4AB3B8399D23E62A28BD16
|
||||
BA2386BA92AA89049C64ECFE60FDDBE136815D3874527414B63ED32215F2E06F
|
||||
B4E1AF25E8DC6934BA391A89984A358702BDD36838BABEBD982638703F20EEF8
|
||||
A62875A3A6D305E120DC7975962552126CD844554857C2943872A4E524A6EEB5
|
||||
76AE71DED1F9E73AF77A2FEAE4EEF80F87414DFB7580FB4AE0325BFF20D74A5D
|
||||
A8F65BE046001A6814F537915BE3F03F3670E1169E4AAA6D7E726174ACAEC77C
|
||||
802E08C14F6E3446BBF7F4666C8DDF7755DC718C3E02B7865FF33E9D8290ABEC
|
||||
23D7A85A824DF3D904A511281A973C979F67F5BFAF3AB0546E85D0597F91120F
|
||||
771CBB7C9FBD9FC5DB93E3E4DE6C034E58BE9BADE93748C42297142124696234
|
||||
FA812D8CC3A9631A0239474EB93AD3A2A3480F2D973D3324228EF92A3B043163
|
||||
C660B84D558A7E6B4EAC47C7B62135668E0EF0FBF74D514EAA3D0D428014282A
|
||||
929F309AB3F90CDD9C21EB77A7CA762CA3AFCACBFE3E67B056290835694BA3D8
|
||||
DAE1EBA78AD1568590348088AAE88C1ABEB59626EF65991CD76AB81198E52837
|
||||
15ED428927A7EB0C7C2DC7A98CFBB77BDD773FA8747B8232A6EC4B87CD7DBCE1
|
||||
BA7E359B1F669783521AD35EDABE97141A816C2FABF0AD0E001E21F73CCF7736
|
||||
9DAEF95C8D5A61D3A3A267FEFB9F37D6E677D7BA26A3A5BFDBDA8C281BE89CCB
|
||||
0531B4105CB209585F9FBC29CAA57E64C2D40F0829931A42CAF7701717D9096E
|
||||
7F8515AA82DBC9EC8CF1DED5AB58EC0D08CF686E25A8C01FB1109A3C68D19E48
|
||||
5AF3838060E0F83352A75A0EC4ACE2CE8BA119BF89F34CB4D6B8E27007CAE7FB
|
||||
B323D48B567F7EFFFFD47A7C9ABF0ADD5F11141737A8AF62B56E042EE498AD6E
|
||||
C1CF3107EA9B283419E27DC563ECCE950BEA78C048A3F49FB42128819959E51C
|
||||
A50FC40F0D9EFA5D254943DC599F7DCC2F6D197A4D2666D5D69CFACCDA560817
|
||||
4C0F0EF1CA8073A562D5414584EDF268913D53D5FB39FA639E02E900891EA82C
|
||||
5BA8AD9B66C93CDE7E7E616A97FED8AA91BC7235FB4DB086CB4021877780C6B4
|
||||
25D957B9BF68326D2EFEC93DA464F43E3DF16DD6571CEB1AB68BD58E87734A51
|
||||
24F0CD3B05D964F82D3702BF0A613139808D49283286294BE57E13A983C3C961
|
||||
5EF2732B63A1CBD2CC239EA6FED62F7FEB3102715A5BAFD8C83AAC33702FACCF
|
||||
6A27B1666AB6FC4483D14CF84EDE49FEDFE05BB24E008AE8A01C52D83B8D40FE
|
||||
2A855572E7E2ADD2888022BDB585B61577A75A31AA8ACEDE59ACB27EEB2936AE
|
||||
7967E9DE70A7F95E69371F812C2FBF932CEC07AB4C235AE9E8A6799F3F537D36
|
||||
5ABA340A8E541568FBEF49E77F94CFB4B3A5E9CF14C6755CE6412CF86CF62898
|
||||
DF4853F482CC1D0B3A2D71E9EACA064E57C5D100DF79BD004BA81B43EACEC401
|
||||
95DA16B844BAF559C2CD6E68B237614BB9927D90811106347B5849FEE2F48640
|
||||
F258FF1178CC42A3CEBE238C8418B4974812A05F43B8FA95639CC46BC0738BC5
|
||||
5EFBBBE99CF5C2B6830FB8E990250BE308E662200526889EA973C8D33823EC19
|
||||
47A048D8799784F6EC385EB984E70C62CE7C8A107232871B69B99F7BF4C3DBB5
|
||||
1D9E243A35118BC7C50A50746E1CF19C9FC310C7D54181FB95F44753EAB1B94A
|
||||
0A46FDA6BA71125F3415E8BB6C2D8C00601107FA563E7F6386486A88F87701FB
|
||||
5229DFE11090EFFBE94EE161054CD5FF58B31E23F567B282DB42EB1FE42E44AA
|
||||
18AA77795AA6D7ADE8B6CDCED81A1959A8329677F042283DC8CA71E13EB3ADEE
|
||||
4B2D6EC32BE9C5D8FA11F3FC0008F4F26B945064D98362AD912F452692AC383D
|
||||
196B8144DFBFB47EC01E96A6B8443211D6C9C4AA7853A8131B5218349BD6D953
|
||||
C171793029D0CBAF8D2661A823243AD50D67F2619533180F25B50C94B1310389
|
||||
615FA91F3D206B908649399F216950EC7B2420EB04AEC6ABFCB7B4528E8E33E6
|
||||
626C19B8553B2D9E5A47A758615D80B15BE11FD016D3A1962D8DE58ED5CA2219
|
||||
B0D4BA39ADB4E8712B3A3E6495ABA2F04A29E45C68671A960BC0D8D89900C97E
|
||||
E04328A783C10DACD96702D2E726BB11CE4ECC571564CE7CB10722D1C98C2842
|
||||
CEE2E53099D8CB576F8F76C5C155470F87A6EC5F7D73256A0A2AEE62CBC53597
|
||||
02D9755C369932E7F99A2E1614B03E2C86D713563785965E008BA987A6C89F49
|
||||
2B2BF7CBB0957A86BBEC97001B60C7C6AD98A56E94542FF561F78FED211DA755
|
||||
049569CC5FB969C6EEBB8AEA1AF1FCAF46F8A9E6CD6C796FC7193592BCA9CF23
|
||||
9D89B9A327DF0D341CD2968BA9218BBC3E934502CD88919D8BB16DD3D39FEBF7
|
||||
4544C2F21054605B0EEE46F62A87DFCBC3BFEC473B9850886266F478BF9E33D7
|
||||
D9931E321732BD82EC9CA1DF12BA48549BFC7D3E76A404B71892F4198777FFBB
|
||||
F838451E4A5929B8BAE9084B40B1DC0EDFB76A9354BF27F981960C88B0BA3A11
|
||||
8E4334B2589D0CAECF0FD9BA584EA26A4123D4543A8A0FE126D4A7E07F6067AF
|
||||
37519A02E8021F2257259C0D2E499AF3533C8ED8DD5BF7751CCE920D79B518FA
|
||||
690482BFF6C1D0BA6C071DD395ADF69E55E1BFC4E0992A8650FFB5E60A02B172
|
|
@ -0,0 +1,18 @@
|
|||
use pqc_dilithium::*;
|
||||
|
||||
#[test]
|
||||
fn sign_then_verify_valid() {
|
||||
let msg = b"Hello";
|
||||
let keys = Keypair::generate();
|
||||
let signature = keys.sign(msg);
|
||||
assert!(verify(&signature, msg, &keys.public).is_ok())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sign_then_verify_invalid() {
|
||||
let msg = b"Hello";
|
||||
let keys = Keypair::generate();
|
||||
let mut signature = keys.sign(msg);
|
||||
signature[..4].copy_from_slice(&[255u8; 4]);
|
||||
assert!(verify(&signature, msg, &keys.public).is_err())
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#![cfg(all(dilithium_kat, not(feature = "random_signing")))]
|
||||
|
||||
use pqc_core::load::*;
|
||||
use pqc_dilithium::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
const MODE: u8 = if cfg!(feature = "mode2") {
|
||||
2
|
||||
} else if cfg!(feature = "mode5") {
|
||||
5
|
||||
} else {
|
||||
3
|
||||
};
|
||||
|
||||
const AES: &str = if cfg!(feature = "aes") { "-AES" } else { "" };
|
||||
|
||||
#[test]
|
||||
fn keypair() {
|
||||
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let filename = format!("PQCsignKAT_Dilithium{}{}.rsp", MODE, AES);
|
||||
let katvec = kats(&mut path.clone(), &filename);
|
||||
let bufvec = bufs(&mut path, "SeedBuffer_Dilithium");
|
||||
for (i, kat) in katvec.iter().enumerate() {
|
||||
let pk = kat.pk.clone();
|
||||
let sk = kat.sk.clone();
|
||||
let mut pk2 = [0u8; PUBLICKEYBYTES];
|
||||
let mut sk2 = [0u8; SECRETKEYBYTES];
|
||||
crypto_sign_keypair(&mut pk2, &mut sk2, Some(&bufvec[i]));
|
||||
assert_eq!(pk, pk2);
|
||||
assert_eq!(sk, sk2);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn sign() {
|
||||
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let filename = format!("PQCsignKAT_Dilithium{}{}.rsp", MODE, AES);
|
||||
let katvec = kats(&mut path, &filename);
|
||||
for kat in katvec {
|
||||
let sm = kat.sm.clone();
|
||||
let msg = kat.msg.clone();
|
||||
let sk = kat.sk.clone();
|
||||
let mut sig = vec![0u8; SIGNBYTES];
|
||||
crypto_sign_signature(&mut sig, &msg, &sk);
|
||||
assert_eq!(sm[..SIGNBYTES], sig);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn verify() {
|
||||
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
||||
let filename = format!("PQCsignKAT_Dilithium{}{}.rsp", MODE, AES);
|
||||
let katvec = kats(&mut path, &filename);
|
||||
for kat in katvec {
|
||||
let sm = kat.sm.clone();
|
||||
let msg = kat.msg.clone();
|
||||
let pk = kat.pk.clone();
|
||||
let res = crypto_sign_verify(&sm[..SIGNBYTES], &msg, &pk);
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Print test header
|
||||
announce(){
|
||||
title="# $1 #"
|
||||
edge=$(echo "$title" | sed 's/./#/g')
|
||||
echo -e "\n\n$edge"; echo "$title"; echo "$edge";
|
||||
}
|
||||
|
||||
# Keep existing RUSTFLAGS
|
||||
RUSTFLAGS=${RUSTFLAGS:-""}
|
||||
RUSTFLAGS+=" --cfg dilithium_kat"
|
||||
|
||||
MODE=("mode2" "mode3" "mode5")
|
||||
|
||||
for mode in ${MODE[@]}; do
|
||||
announce "Dilithium $mode"
|
||||
RUSTFLAGS=$RUSTFLAGS cargo test --features "$mode"
|
||||
|
||||
announce "Dilithium $mode AES"
|
||||
RUSTFLAGS=$RUSTFLAGS cargo test --features "$mode aes"
|
||||
|
||||
announce "Dilithium $mode Random Signing"
|
||||
RUSTFLAGS=$RUSTFLAGS cargo test --features "$mode random_signing"
|
||||
done
|
|
@ -0,0 +1,7 @@
|
|||
unstable_features = true
|
||||
wrap_comments = true
|
||||
comment_width = 100
|
||||
control_brace_style = "AlwaysSameLine"
|
||||
fn_params_layout = "Compressed"
|
||||
reorder_imports = true
|
||||
imports_layout = "Vertical"
|
|
@ -0,0 +1,26 @@
|
|||
#!/bin/bash
|
||||
# This is a script to automatically create musl-linked
|
||||
# executables so kdt can run on any system (any linux
|
||||
# system*), regardless of the included libc. This doesn't
|
||||
# do command existence checking, so it WILL fail if you're
|
||||
# missing the dependencies!
|
||||
|
||||
_main () {
|
||||
rm -rf dist
|
||||
mkdir dist
|
||||
echo "Building with \`cargo build --release --target=x86_64-unknown-linux-musl\`..."
|
||||
cargo build --release --target=x86_64-unknown-linux-musl
|
||||
echo "Successfully built musl release for kdt!"
|
||||
|
||||
echo "Packing into .tar.gz..."
|
||||
mkdir kdt
|
||||
cd kdt
|
||||
cp ../../target/x86_64-unknown-linux-musl/release/kdt .
|
||||
cd ..
|
||||
tar -czf "kdt_$(cargo get version --pretty).tar.gz" ./kdt/
|
||||
mv "kdt_$(cargo get version --pretty).tar.gz" dist
|
||||
echo "Successfully packed executable into tar archive! View it at ./dist/kdt_$(cargo get version --pretty).tar.gz."
|
||||
rm -rf kdt
|
||||
}
|
||||
|
||||
_main
|
|
@ -0,0 +1,30 @@
|
|||
#!/bin/bash
|
||||
# Since our our `rustfmt.toml` uses some nightly formatting features, you can
|
||||
# invoke this shell script as shorthand for everything you'd normally need to
|
||||
# manually do (configure rustup, add the nightly profile, etc...)
|
||||
|
||||
_command_exists () {
|
||||
command -v "${1}" 2>/dev/null >&2
|
||||
}
|
||||
|
||||
_main () {
|
||||
|
||||
# get rustup if it's not installed
|
||||
if ! _command_exists "rustup"; then
|
||||
# panic if `curl` isn't installed
|
||||
if ! _command_exists "curl"; then
|
||||
echo "You need to install \`curl\`."
|
||||
exit 1
|
||||
fi
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
fi
|
||||
# alias for easy usage
|
||||
alias rustup="$HOME/.cargo/bin/rustup"
|
||||
|
||||
rustup toolchain install nightly-x86_64-unknown-linux-gnu &>/dev/null
|
||||
echo "Formatting code..."
|
||||
rustup run nightly cargo fmt
|
||||
echo "Formatted code!"
|
||||
}
|
||||
|
||||
_main
|
|
@ -0,0 +1,88 @@
|
|||
// -- imports --
|
||||
use crate::core::*;
|
||||
use clap::Parser;
|
||||
use std::error::Error;
|
||||
|
||||
// -- clap options --
|
||||
/// Mirai's experimental, quantum-safe successor to GPG
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Args {
|
||||
/// Generates a new KDT owned key set and stores it in the
|
||||
/// local owned key database
|
||||
#[arg(short, long)]
|
||||
pub gen_key: bool,
|
||||
|
||||
/// Imports a KDT public key from stdin and stores it in the
|
||||
/// local public key database
|
||||
#[arg(short, long)]
|
||||
pub import: bool,
|
||||
|
||||
/// Launches KDT in decryption mode
|
||||
#[arg(short, long, value_name = "PRIVATE_KEY_ID")]
|
||||
pub decrypt: Option<String>,
|
||||
|
||||
/// Launches KDT in encryption mode
|
||||
#[arg(short, long, value_name = "PUBLIC_KEY_ID")]
|
||||
pub encrypt: Option<String>,
|
||||
|
||||
/// Lists all keys in the public key database
|
||||
#[arg(long)]
|
||||
pub list_keys: bool,
|
||||
|
||||
/// Lists all keys in the owned key database
|
||||
#[arg(short, long)]
|
||||
pub list_key_pairs: bool,
|
||||
|
||||
/// Exports the public key in the owned key set containing
|
||||
/// a private key of id `PRIVATE_KEY_ID`
|
||||
#[arg(long, value_name = "PRIVATE_KEY_ID")]
|
||||
pub export_pubkey: Option<String>,
|
||||
|
||||
/// Removes the public key with id `PUBLIC_KEY_ID`
|
||||
/// from the public key database
|
||||
#[arg(long, value_name = "PUBLIC_KEY_ID")]
|
||||
pub del_pubkey: Option<String>,
|
||||
|
||||
/// Removes the owned key set with private key of
|
||||
/// id `PRIVATE_KEY_ID` from the owned key database
|
||||
#[arg(long, value_name = "PRIVATE_KEY_ID")]
|
||||
pub del_keyset: Option<String>,
|
||||
|
||||
/// Signs a message with the given private key
|
||||
#[arg(short, long, value_name = "PRIVATE_KEY_ID")]
|
||||
pub sign: Option<String>,
|
||||
|
||||
/// Verifies the integrity of the given signed message
|
||||
/// against the given public key
|
||||
#[arg(short, long, value_name = "PUBLIC_KEY_ID")]
|
||||
pub verify: Option<String>,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn get_num_called(&self) -> usize {
|
||||
[
|
||||
self.gen_key,
|
||||
self.import,
|
||||
self.list_keys,
|
||||
self.list_key_pairs,
|
||||
self.encrypt.is_some(),
|
||||
self.export_pubkey.is_some(),
|
||||
self.del_pubkey.is_some(),
|
||||
self.del_keyset.is_some(),
|
||||
self.decrypt.is_some(),
|
||||
self.sign.is_some(),
|
||||
self.verify.is_some(),
|
||||
]
|
||||
.iter()
|
||||
.filter(|&b| *b)
|
||||
.count()
|
||||
}
|
||||
|
||||
pub fn fail_if_invalid(&self) -> Result<(), Box<dyn Error>> {
|
||||
if self.get_num_called() > 1 {
|
||||
return Err(Box::new(KdtErr::TooManyArgs));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
// -- imports --
|
||||
use crate::core::*;
|
||||
use aes_gcm::{
|
||||
aead::{
|
||||
Aead,
|
||||
AeadCore,
|
||||
KeyInit,
|
||||
OsRng,
|
||||
},
|
||||
Aes256Gcm,
|
||||
Key,
|
||||
};
|
||||
use generic_array::GenericArray;
|
||||
use pqc_kyber::{
|
||||
decapsulate,
|
||||
encapsulate,
|
||||
SecretKey,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt,
|
||||
};
|
||||
|
||||
// -- base crypto handling --
|
||||
/// Core cryptography handler for KDT. Handles everything when
|
||||
/// it comes to AES and Kyber. Signatures are handled by the
|
||||
/// `KdtSignageHandler` though.
|
||||
pub struct KdtCryptoHandler;
|
||||
|
||||
impl KdtCryptoHandler {
|
||||
/// Encrypts a string of text against the provided Kyber
|
||||
/// public key. We use AES in the backend here because
|
||||
/// the way Kyber works is that it establishes a shared
|
||||
/// symmetric key inside of the asymmetric stuff. Magic!
|
||||
pub fn encrypt_text(text: String, pubkey_str: String) -> Result<Message, Box<dyn Error>> {
|
||||
let pubkey = PubKeyPair::from_str(pubkey_str).init();
|
||||
let mut rng = rand::thread_rng();
|
||||
let (encrypted_secret, secret_bytes) =
|
||||
encapsulate(&Base64::decode_string(pubkey.crypto_key), &mut rng)?;
|
||||
let key = Key::<Aes256Gcm>::from_slice(&secret_bytes);
|
||||
let cipher = Aes256Gcm::new(&key);
|
||||
let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
|
||||
let encrypted_message =
|
||||
Base64::encode_bytes(&cipher.encrypt(&nonce, text.as_ref()).unwrap());
|
||||
let encoded_nonce = Base64::encode_bytes(&nonce.into_iter().collect::<Vec<u8>>());
|
||||
|
||||
Ok(Message::new(
|
||||
Base64::encode_bytes(&encrypted_secret),
|
||||
encrypted_message,
|
||||
encoded_nonce,
|
||||
))
|
||||
}
|
||||
|
||||
/// Decrypts a pre-deserialized `Message` object with the
|
||||
/// provided private key. Note that, as stated above, this uses
|
||||
/// AES under the hood because of the magic way Kyber works -
|
||||
/// a shared symmetric key is established using the asymmetric
|
||||
/// keys, and then both parties can encrypt sensitive data
|
||||
/// with that! Pure magic, obviously.
|
||||
pub fn decrypt_msg(message: Message, privkey_str: String) -> String {
|
||||
// Uses the private key we have to decrypt the symmetric
|
||||
// shared secret.
|
||||
let secret_bytes = decapsulate(
|
||||
&Base64::decode_string(message.encrypted_secret),
|
||||
&Base64::decode_string(privkey_str),
|
||||
)
|
||||
.expect("You used the wrong private key!");
|
||||
let key = Key::<Aes256Gcm>::from_slice(&secret_bytes);
|
||||
let cipher = Aes256Gcm::new(&key);
|
||||
let nonce = Base64::decode_string(message.nonce);
|
||||
|
||||
// Converts the raw text bytes to a UTF-8 encoded string.
|
||||
String::from_utf8_lossy(
|
||||
&cipher
|
||||
.decrypt(
|
||||
&GenericArray::clone_from_slice(&nonce),
|
||||
Base64::decode_string(message.encrypted_message).as_ref(),
|
||||
)
|
||||
.unwrap(),
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Message {
|
||||
/// The shared secret established by Kyber, encrypted
|
||||
/// asymmetrically so only you can see it.
|
||||
pub encrypted_secret: String,
|
||||
|
||||
/// The actual encrypted data. This is a base64 encoded
|
||||
/// representation of the shifted bytes.
|
||||
pub encrypted_message: String,
|
||||
|
||||
/// The AES-GCM nonce. From
|
||||
/// https://cryptography.io/en/latest/hazmat/primitives/symmetric-encryption/#cryptography.hazmat.primitives.ciphers.algorithms.ChaCha20:
|
||||
/// `The nonce does not need to be kept secret and may be included with the ciphertext.`
|
||||
pub nonce: String,
|
||||
}
|
||||
|
||||
impl Message {
|
||||
/// Creates a new `Message` object from the given encrypted secret,
|
||||
/// encrypted message, and unencrypted nonce.
|
||||
pub fn new(encrypted_secret: String, encrypted_message: String, nonce: String) -> Self {
|
||||
Self {
|
||||
encrypted_secret,
|
||||
encrypted_message,
|
||||
nonce,
|
||||
}
|
||||
}
|
||||
|
||||
/// Restores a `Message` object from the given message string.
|
||||
#[inline(always)]
|
||||
pub fn from_str(message: String) -> Self {
|
||||
let message_split: Vec<String> = message
|
||||
.chars()
|
||||
.skip(27)
|
||||
.take(message.len() - 27 - 26)
|
||||
.collect::<String>()
|
||||
.replace("\n", "")
|
||||
.split('*')
|
||||
.map(String::from)
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
encrypted_secret: message_split[0].to_owned(),
|
||||
encrypted_message: message_split[1].to_owned(),
|
||||
nonce: message_split[2].to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Message {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let message = format!(
|
||||
"{}*{}*{}",
|
||||
self.encrypted_secret, self.encrypted_message, self.nonce
|
||||
)
|
||||
.chars()
|
||||
.enumerate()
|
||||
.flat_map(|(i, c)| {
|
||||
if (i + 1) % 64 == 0 {
|
||||
vec![c, '\n']
|
||||
} else {
|
||||
vec![c]
|
||||
}
|
||||
})
|
||||
.collect::<String>();
|
||||
write!(
|
||||
f,
|
||||
"-----BEGIN KDT MESSAGE-----\n{}\n-----END KDT MESSAGE-----",
|
||||
message.trim_end()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// -- imports --
|
||||
use base64::{
|
||||
engine::general_purpose,
|
||||
Engine as _,
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
// -- simple base64 interface --
|
||||
/// Incredibly minimalist base64 conversion object. Can
|
||||
/// encode bytes, and decode strings. That's it, because that's
|
||||
/// all we need.
|
||||
pub struct Base64;
|
||||
|
||||
impl Base64 {
|
||||
/// Converts a bytearray to a base64 string.
|
||||
#[inline(always)]
|
||||
pub fn encode_bytes(b: &[u8]) -> String {
|
||||
general_purpose::STANDARD.encode(b)
|
||||
}
|
||||
|
||||
/// Converts a base64 string to a bytearray.
|
||||
#[inline(always)]
|
||||
pub fn decode_string<S: fmt::Display>(s: S) -> Vec<u8> {
|
||||
general_purpose::STANDARD.decode(s.to_string()).unwrap()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub mod base64;
|
||||
|
||||
pub use self::base64::*;
|
|
@ -0,0 +1,36 @@
|
|||
// -- imports --
|
||||
use core::fmt;
|
||||
use std::error::Error;
|
||||
|
||||
// -- error struct --
|
||||
#[derive(Debug)]
|
||||
/// Custom error struct. Helps ensure error handling
|
||||
/// doesn't get *too* ugly.
|
||||
pub enum KdtErr {
|
||||
TooManyArgs,
|
||||
PubDbOpenFailed,
|
||||
PrivDbOpenFailed,
|
||||
DbDumpFailed,
|
||||
KeyAlreadyExists,
|
||||
}
|
||||
|
||||
impl fmt::Display for KdtErr {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::TooManyArgs => write!(
|
||||
f,
|
||||
"Too many arguments were passed! You can only use one argument at a time."
|
||||
),
|
||||
Self::PubDbOpenFailed => write!(f, "Failed to open public keys database!"),
|
||||
Self::PrivDbOpenFailed => write!(f, "Failed to open private keys database!"),
|
||||
Self::DbDumpFailed => write!(f, "Failed to dump to database!"),
|
||||
Self::KeyAlreadyExists => write!(f, "This key already exists in the database!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pointless trait implementation to ensure `KdtErr` is
|
||||
// considered an `Error` type so you can return it
|
||||
// in a function that returns eg `Result<(), Box<dyn Error>>`.
|
||||
impl Error for KdtErr {}
|
|
@ -0,0 +1,69 @@
|
|||
// -- imports --
|
||||
use crate::core::*;
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
|
||||
// -- public key database --
|
||||
#[derive(Serialize, Deserialize)]
|
||||
/// A database of public keys stored locally in
|
||||
/// `pubkeys.ron`.
|
||||
pub struct PubKeyDb {
|
||||
/// A list of public key objects.
|
||||
pub keys: Vec<PubKeyPair>,
|
||||
}
|
||||
|
||||
impl PubKeyDb {
|
||||
/// Takes in the hexadecimal string id of a public key, and returns
|
||||
/// the public key object.
|
||||
pub fn get_by_id(&self, id: String) -> PubKeyPair {
|
||||
let filtered = self.keys.iter().filter(|k| k.id == id).collect::<Vec<_>>();
|
||||
if filtered.len() > 1 {
|
||||
unreachable!();
|
||||
} else {
|
||||
filtered[0].clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Shorthand for `self.keys.is_empty()` to avoid deep nesting
|
||||
/// and pointlessly annoying function access.
|
||||
#[inline(always)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.keys.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
// -- owned key database --
|
||||
#[derive(Serialize, Deserialize)]
|
||||
/// A database of owned keys (ie private-public pairs) stored
|
||||
/// locally in `ownedkeys.ron`. Remember, `ownedkeys.ron` is for your
|
||||
/// eyes only - don't let anyone else see it!
|
||||
pub struct OwnedKeyDb {
|
||||
/// A list of private- and public-key pairs that you're in control of.
|
||||
pub keys: Vec<OwnedKeySet>,
|
||||
}
|
||||
|
||||
impl OwnedKeyDb {
|
||||
/// Takes in the hexadecimal string id of a private key,
|
||||
/// and returns the private-public key pair.
|
||||
pub fn get_by_id(&self, id: String) -> OwnedKeySet {
|
||||
let filtered = self
|
||||
.keys
|
||||
.iter()
|
||||
.filter(|k| k.privkey_pair.id == id)
|
||||
.collect::<Vec<_>>();
|
||||
if filtered.len() > 1 {
|
||||
unreachable!();
|
||||
} else {
|
||||
filtered[0].clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Shorthand for `self.keys.is_empty()` to avoid deep nesting
|
||||
/// and pointlessly annoying function access.
|
||||
#[inline(always)]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.keys.is_empty()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// -- imports --
|
||||
use crate::core::*;
|
||||
use pqc_dilithium::Keypair as dilithium_keypair;
|
||||
use pqc_kyber::keypair as kyber_keypair;
|
||||
|
||||
// -- fully controlled keyset (privkey pair + pubkey pair) --
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct OwnedKeySet {
|
||||
pub pubkey_pair: PubKeyPair,
|
||||
pub privkey_pair: PrivKeyPair,
|
||||
}
|
||||
|
||||
impl OwnedKeySet {
|
||||
/// Generates a new key set (public, private; encryption, signage) on-demand.
|
||||
/// No errors should occur here, but if they do they probably aren't our fault
|
||||
/// (take a look at the libraries we use - they're probably the culprit!)
|
||||
pub fn generate(owner_name: String) -> Self {
|
||||
let encryption_keys = kyber_keypair(&mut rand::thread_rng());
|
||||
let signage_keys = dilithium_keypair::generate();
|
||||
let pubkey_pair = PubKeyPair::new(
|
||||
Base64::encode_bytes(&encryption_keys.public),
|
||||
Base64::encode_bytes(&signage_keys.public),
|
||||
Base64::encode_bytes(owner_name.as_bytes()),
|
||||
)
|
||||
.init();
|
||||
let privkey_pair = PrivKeyPair::new(
|
||||
Base64::encode_bytes(&encryption_keys.secret),
|
||||
Base64::encode_bytes(&signage_keys.expose_secret()),
|
||||
Base64::encode_bytes(owner_name.as_bytes()),
|
||||
)
|
||||
.init();
|
||||
|
||||
Self {
|
||||
pubkey_pair,
|
||||
privkey_pair,
|
||||
}
|
||||
}
|
||||
|
||||
/// Derives an `OwnedKeySet` from a public- and private-key base64 string pair.
|
||||
pub fn from_strs(pubkey_pair_str: String, privkey_pair_str: String) -> Self {
|
||||
Self {
|
||||
pubkey_pair: PubKeyPair::from_str(pubkey_pair_str).init(),
|
||||
privkey_pair: PrivKeyPair::from_str(privkey_pair_str).init(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// -- compiler flags --
|
||||
#![allow(dead_code)]
|
||||
|
||||
// -- local modules --
|
||||
pub mod database;
|
||||
pub mod key;
|
||||
pub mod privkey;
|
||||
pub mod pubkey;
|
||||
|
||||
pub use database::*;
|
||||
pub use key::*;
|
||||
pub use privkey::*;
|
||||
pub use pubkey::*;
|
|
@ -0,0 +1,113 @@
|
|||
// -- imports --
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use sha2::{
|
||||
Digest,
|
||||
Sha256,
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
// -- private key pair (signing key + crypto key) --
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct PrivKeyPair {
|
||||
/// Base64-encoded bytes for private cryptographic
|
||||
/// (ie Kyber) key.
|
||||
pub crypto_key: String,
|
||||
|
||||
/// Base64-encoded bytes for private signage
|
||||
/// (ie Dilithium) key.
|
||||
pub signage_key: String,
|
||||
|
||||
/// Base64-encoded representation of the key
|
||||
/// owner's name.
|
||||
pub owner: String,
|
||||
|
||||
/// Sha256 hashsum of this object when the two
|
||||
/// above values are set. On initialization, this is
|
||||
/// `String::new()`, but a `PrivKeyPair::init()` call
|
||||
/// generates it on-demand. Ids are very important for key
|
||||
/// identification, so you should *always* call `PrivKeyPair::init()`
|
||||
/// after `PrivKeyPair::new()`.
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
impl PrivKeyPair {
|
||||
/// Creates a new `PrivKeyPair` object from the provided cryptographic key
|
||||
/// base64 string, the provided signage key string, and the owner base64
|
||||
/// string. This doesn't validate the passed inputs, so it *will* panic if
|
||||
/// you pass bad inputs.
|
||||
pub fn new(crypto_key: String, signage_key: String, owner: String) -> Self {
|
||||
Self {
|
||||
crypto_key,
|
||||
signage_key,
|
||||
owner,
|
||||
id: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes a hash for the key pair, then sets the id as the hash. This
|
||||
/// helps maintain distinctness between key ids.
|
||||
#[inline(always)]
|
||||
pub fn init(mut self) -> Self {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(self.to_string());
|
||||
self.id = format!("{:X}", hasher.finalize());
|
||||
self
|
||||
}
|
||||
|
||||
/// Derives a `PrivKeyPair` object from the provided KDT private
|
||||
/// key string. Doesn't validate input, so it *will* panic if you pass
|
||||
/// invalid inputs.
|
||||
pub fn from_str(privkey_str: String) -> Self {
|
||||
let privkey: Vec<String> = privkey_str
|
||||
.chars()
|
||||
// Removes the `-----BEGIN KDT PRIVKEY BLOCK-----` header.
|
||||
.skip(33)
|
||||
// Removes the `-----END KDT PRIVKEY BLOCK-----` footer.
|
||||
.take(privkey_str.len() - 33 - 32)
|
||||
.collect::<String>()
|
||||
// Turns the human-readable formatting to something that can be parsed
|
||||
// programmatically.
|
||||
.replace("\n", "")
|
||||
// Splits the private key into a cryptographic key and signage key.
|
||||
.split('*')
|
||||
.map(String::from)
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
crypto_key: privkey[0].to_owned(),
|
||||
signage_key: privkey[1].to_owned(),
|
||||
owner: privkey[2].to_owned(),
|
||||
id: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- human-readable key output impl --
|
||||
impl fmt::Display for PrivKeyPair {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// An asterisk separates the encryption key from the
|
||||
// signing key during key exchanges.
|
||||
let keypair = format!("{}*{}*{}", &self.crypto_key, &self.signage_key, &self.owner)
|
||||
.chars()
|
||||
.enumerate()
|
||||
// This helps maintain readability when printing messages. It
|
||||
// inserts a new line at every nth (n = multiple of 64) character.
|
||||
// This is identical to GPG's output style.
|
||||
.flat_map(|(i, c)| {
|
||||
if (i + 1) % 64 == 0 {
|
||||
vec![c, '\n']
|
||||
} else {
|
||||
vec![c]
|
||||
}
|
||||
})
|
||||
.collect::<String>();
|
||||
write!(
|
||||
f,
|
||||
"-----BEGIN KDT PRIVKEY BLOCK-----\n{}\n-----END KDT PRIVKEY BLOCK-----",
|
||||
keypair.trim_end()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
// -- imports --
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use sha2::{
|
||||
Digest,
|
||||
Sha256,
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
// -- public key pair (signing key + crypto key) --
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct PubKeyPair {
|
||||
/// Base64-encoded bytes for public cryptographic
|
||||
/// (ie Kyber) key.
|
||||
pub crypto_key: String,
|
||||
|
||||
/// Base64-encoded bytes for public signage
|
||||
/// (ie Dilithium) key.
|
||||
pub signage_key: String,
|
||||
|
||||
/// Base64-encoded representation of the key
|
||||
/// owner's name.
|
||||
pub owner: String,
|
||||
|
||||
/// Sha256 hashsum of this object when the two
|
||||
/// above values are set. On initialization, this is
|
||||
/// `String::new()`, but a `PrivKeyPair::init()` call
|
||||
/// generates it on-demand. Ids are very important for key
|
||||
/// identification, so you should *always* call `PrivKeyPair::init()`
|
||||
/// after `PrivKeyPair::new()`.
|
||||
pub id: String,
|
||||
}
|
||||
|
||||
impl PubKeyPair {
|
||||
/// Creates a new `PubKeyPair` object from the provided cryptographic key
|
||||
/// base64 string, the provided signage key string, and the owner base64
|
||||
/// string. This doesn't validate the passed inputs, so it *will* panic if
|
||||
/// you pass bad inputs.
|
||||
pub fn new(crypto_key: String, signage_key: String, owner: String) -> Self {
|
||||
Self {
|
||||
crypto_key,
|
||||
signage_key,
|
||||
owner,
|
||||
id: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes a hash for the key pair, then sets the id as the hash. This
|
||||
/// helps maintain distinctness between key ids.
|
||||
#[inline(always)]
|
||||
pub fn init(mut self) -> Self {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(self.to_string());
|
||||
self.id = format!("{:X}", hasher.finalize());
|
||||
self
|
||||
}
|
||||
|
||||
/// Derives a `PubKeyPair` object from the provided KDT public
|
||||
/// key string. Doesn't validate input, so it *will* panic if you pass
|
||||
/// invalid inputs.
|
||||
pub fn from_str(pubkey_str: String) -> Self {
|
||||
let pubkey: Vec<String> = pubkey_str
|
||||
.chars()
|
||||
// Removes the `-----BEGIN KDT PUBKEY BLOCK-----` header.
|
||||
.skip(32)
|
||||
// Removes the `-----END KDT PRIVKEY BLOCK-----` footer.
|
||||
.take(pubkey_str.len() - 32 - 31)
|
||||
.collect::<String>()
|
||||
// Turns the human-readable formatting to something that can be parsed
|
||||
// programmatically.
|
||||
.replace("\n", "")
|
||||
// Splits the public key into a cryptographic key and signage key.
|
||||
.split('*')
|
||||
.map(String::from)
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
crypto_key: pubkey[0].to_owned(),
|
||||
signage_key: pubkey[1].to_owned(),
|
||||
owner: pubkey[2].to_owned(),
|
||||
id: String::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- human-readable key output impl --
|
||||
impl fmt::Display for PubKeyPair {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// An asterisk separates the encryption key from the
|
||||
// signing key during key exchanges.
|
||||
let keypair = format!("{}*{}*{}", &self.crypto_key, &self.signage_key, &self.owner)
|
||||
.chars()
|
||||
.enumerate()
|
||||
// This helps maintain readability when printing messages. It
|
||||
// inserts a new line at every nth (n = multiple of 64) character.
|
||||
// This is identical to GPG's output style.
|
||||
.flat_map(|(i, c)| {
|
||||
if (i + 1) % 64 == 0 {
|
||||
vec![c, '\n']
|
||||
} else {
|
||||
vec![c]
|
||||
}
|
||||
})
|
||||
.collect::<String>();
|
||||
write!(
|
||||
f,
|
||||
"-----BEGIN KDT PUBKEY BLOCK-----\n{}\n-----END KDT PUBKEY BLOCK-----",
|
||||
keypair.trim_end()
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
|
||||
* Copyright (c) 2023-present Artemis Mirai <artemismirai@waifu.club>
|
||||
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// -- imports --
|
||||
use colored::*;
|
||||
use std::{
|
||||
fmt::Display,
|
||||
io::{
|
||||
self,
|
||||
Read,
|
||||
Write,
|
||||
},
|
||||
process,
|
||||
};
|
||||
|
||||
/// Base styled logs object. Object stores `debug`
|
||||
/// boolean which dictates whether or not anything should
|
||||
/// actually be logged to stdout or not.
|
||||
pub struct Logger {
|
||||
debug: bool,
|
||||
}
|
||||
|
||||
// -- core implementation --
|
||||
impl Logger {
|
||||
/// Creates a new `Logger` object based on a
|
||||
/// `debug` boolean that determines whether or
|
||||
/// not anything should actually be logged.
|
||||
pub fn new(debug: bool) -> Self {
|
||||
Self { debug }
|
||||
}
|
||||
|
||||
/// Writes information to stdout.
|
||||
pub fn info<S: Display>(&self, s: S) {
|
||||
if self.debug {
|
||||
println!("{} {}", "(info)".bright_yellow(), s);
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a warn to stdout.
|
||||
pub fn warn<S: Display>(&self, s: S) {
|
||||
if self.debug {
|
||||
println!("{} {}", "(warn)".bright_red(), s);
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes a fatal log to stdout, then panics. Doesn't
|
||||
/// care if the logger is in debug mode or not because
|
||||
/// users should always see fatal logs.
|
||||
pub fn fatal<S: Display>(&self, s: S) -> ! {
|
||||
println!("{} {}", "(FATAL)".red(), s);
|
||||
process::exit(1);
|
||||
}
|
||||
|
||||
/// Writes a success message to stdout.
|
||||
pub fn success<S: Display>(&self, s: S) {
|
||||
if self.debug {
|
||||
println!("{} {}", "(success)".bright_green(), s);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets user input from stdin.
|
||||
pub fn input(&self) -> String {
|
||||
let mut i = String::new();
|
||||
io::stdout()
|
||||
.flush()
|
||||
.expect("Failed to flush standard output!");
|
||||
io::stdin()
|
||||
.read_to_string(&mut i)
|
||||
.expect("Failed to read input!");
|
||||
|
||||
i.trim().to_string()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* The MIT License (MIT)
|
||||
|
||||
* Copyright (c) 2023-present Artemis Mirai <artemismirai@waifu.club>
|
||||
|
||||
* 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.
|
||||
*/
|
||||
|
||||
pub mod log;
|
||||
pub use log::*;
|
|
@ -0,0 +1,237 @@
|
|||
// -- compiler flags --
|
||||
#![allow(unused_imports)]
|
||||
|
||||
// -- local modules (+ exports) --
|
||||
pub mod crypto;
|
||||
pub mod encoding;
|
||||
pub mod errors;
|
||||
pub mod keys;
|
||||
pub mod logging;
|
||||
pub mod signing;
|
||||
|
||||
pub use crypto::*;
|
||||
pub use encoding::*;
|
||||
pub use errors::*;
|
||||
pub use keys::*;
|
||||
pub use logging::*;
|
||||
pub use signing::*;
|
||||
|
||||
// -- external imports --
|
||||
use ron::{
|
||||
de::from_reader,
|
||||
ser::{
|
||||
to_string_pretty,
|
||||
PrettyConfig,
|
||||
},
|
||||
};
|
||||
use serde::{
|
||||
Deserialize,
|
||||
Serialize,
|
||||
};
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt,
|
||||
fs::{
|
||||
self,
|
||||
File,
|
||||
},
|
||||
io::{
|
||||
Read,
|
||||
Write,
|
||||
},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
// -- core kdt object --
|
||||
/// Highest level KDT object. Handles encryption, decryption,
|
||||
/// signing, input validation, key importation, database loading,
|
||||
/// etc.
|
||||
pub struct CoreKdtHandler {
|
||||
/// Public key database, loaded in ram from `pubkeys.ron`.
|
||||
pub pubkey_db: PubKeyDb,
|
||||
|
||||
/// Owned key database, loaded in ram from `ownedkeys.ron`.
|
||||
pub ownedkey_db: OwnedKeyDb,
|
||||
}
|
||||
|
||||
impl CoreKdtHandler {
|
||||
/// Creates a new `CoreKdtHandler` by loading the necessary
|
||||
/// databases, and creating them if they don't exist.
|
||||
pub fn new() -> Result<Self, Box<dyn Error>> {
|
||||
if !Path::new("pubkeys.ron").exists() {
|
||||
let mut f = File::create("pubkeys.ron").unwrap();
|
||||
f.write_all(
|
||||
r#"(
|
||||
keys: []
|
||||
)"#
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
if !Path::new("ownedkeys.ron").exists() {
|
||||
let mut f = File::create("ownedkeys.ron").unwrap();
|
||||
f.write_all(
|
||||
r#"(
|
||||
keys: []
|
||||
)"#
|
||||
.as_bytes(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
let pubkey_db: PubKeyDb = match File::open("pubkeys.ron") {
|
||||
Ok(f) => match from_reader(f) {
|
||||
Ok(database) => database,
|
||||
Err(_) => return Err(Box::new(KdtErr::PubDbOpenFailed)),
|
||||
},
|
||||
Err(_) => return Err(Box::new(KdtErr::PubDbOpenFailed)),
|
||||
};
|
||||
let ownedkey_db: OwnedKeyDb = match File::open("ownedkeys.ron") {
|
||||
Ok(f) => match from_reader(f) {
|
||||
Ok(database) => database,
|
||||
Err(_) => return Err(Box::new(KdtErr::PrivDbOpenFailed)),
|
||||
},
|
||||
Err(_) => return Err(Box::new(KdtErr::PrivDbOpenFailed)),
|
||||
};
|
||||
Ok(Self {
|
||||
pubkey_db,
|
||||
ownedkey_db,
|
||||
})
|
||||
}
|
||||
|
||||
/// Generates a new owned key set on demand, then
|
||||
/// appends that new keyset to the owned key database.
|
||||
pub fn gen_key(&mut self, name: String) -> String {
|
||||
let key = OwnedKeySet::generate(name);
|
||||
self.ownedkey_db.keys.push(key.clone());
|
||||
key.privkey_pair.id
|
||||
}
|
||||
|
||||
/// Removes the public key with the specified id from the
|
||||
/// public key database in memory.
|
||||
pub fn del_pubkey(&mut self, keyid: String) {
|
||||
self.pubkey_db.keys = self
|
||||
.pubkey_db
|
||||
.keys
|
||||
.iter()
|
||||
.filter(|x| x.id != keyid)
|
||||
.map(|k| k.to_owned())
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Removes the owned key set with the specified id from the
|
||||
/// owned key database in memory.
|
||||
pub fn del_ownedkey(&mut self, keyid: String) {
|
||||
self.ownedkey_db.keys = self
|
||||
.ownedkey_db
|
||||
.keys
|
||||
.iter()
|
||||
.filter(|k| k.privkey_pair.id != keyid)
|
||||
.map(|k| k.to_owned())
|
||||
.collect();
|
||||
}
|
||||
|
||||
/// Adds the given public key to the in-memory key
|
||||
/// database.
|
||||
pub fn register_pubkey<S: fmt::Display>(
|
||||
&mut self, pubkey_str: S,
|
||||
) -> Result<String, Box<dyn Error>> {
|
||||
// Construct a public key using the given string
|
||||
let pubkey = PubKeyPair::from_str(pubkey_str.to_string()).init();
|
||||
// Make sure this public key isn't already registered to the database
|
||||
if self
|
||||
.pubkey_db
|
||||
.keys
|
||||
.iter()
|
||||
.filter(|k| k.id == pubkey.id)
|
||||
.collect::<Vec<_>>()
|
||||
.len()
|
||||
!= 0
|
||||
{
|
||||
Err(Box::new(KdtErr::KeyAlreadyExists))
|
||||
} else {
|
||||
// Add it to the database, then return the id
|
||||
self.pubkey_db.keys.push(pubkey.clone());
|
||||
Ok(pubkey.id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Dumps the public- and owned-key-databases to their
|
||||
/// respective files.
|
||||
pub fn dump_db(self) -> Result<(), Box<dyn Error>> {
|
||||
let pretty = PrettyConfig::new()
|
||||
.depth_limit(6)
|
||||
.separate_tuple_members(true);
|
||||
|
||||
match File::create("pubkeys.ron") {
|
||||
Ok(ref mut f) => f
|
||||
.write_all(to_string_pretty(&self.pubkey_db, pretty.clone())?.as_bytes())
|
||||
.unwrap(),
|
||||
Err(_) => return Err(Box::new(KdtErr::DbDumpFailed)),
|
||||
}
|
||||
match File::create("ownedkeys.ron") {
|
||||
Ok(ref mut f) => f
|
||||
.write_all(format!("// This file contains the private-key-public-key pairs for your owned keys. These are used for decryption and signing. Don't share this file's contents with anyone!\n{}", to_string_pretty(&self.ownedkey_db, pretty)?).as_bytes())
|
||||
.unwrap(),
|
||||
Err(_) => return Err(Box::new(KdtErr::DbDumpFailed)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Encrypts the given message against the public key of the given
|
||||
/// id.
|
||||
pub fn encrypt(&self, pubkey_id: String, text: String) -> String {
|
||||
let public_key = self.pubkey_db.get_by_id(pubkey_id).to_string();
|
||||
KdtCryptoHandler::encrypt_text(text, public_key)
|
||||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
/// Decrypts the given message with the private key of the given id.
|
||||
pub fn decrypt(&self, privkey_id: String, message: String) -> String {
|
||||
let message = Message::from_str(message);
|
||||
let private_key = self
|
||||
.ownedkey_db
|
||||
.get_by_id(privkey_id)
|
||||
.privkey_pair
|
||||
.crypto_key;
|
||||
KdtCryptoHandler::decrypt_msg(message, private_key).to_string()
|
||||
}
|
||||
|
||||
/// Signs the given message with the private key of the given id.
|
||||
pub fn sign(&self, privkey_id: String, text: String) -> String {
|
||||
let signing_pubkey = self
|
||||
.ownedkey_db
|
||||
.get_by_id(privkey_id.clone())
|
||||
.pubkey_pair
|
||||
.signage_key;
|
||||
let signing_privkey = self
|
||||
.ownedkey_db
|
||||
.get_by_id(privkey_id.clone())
|
||||
.privkey_pair
|
||||
.signage_key;
|
||||
KdtSignageHandler::sign_text(text, signing_privkey, signing_pubkey).to_string()
|
||||
}
|
||||
|
||||
/// Verifies the given KDT-signed message with the public key of the
|
||||
/// given id.
|
||||
pub fn verify(&self, pubkey_id: String, full_text: String) -> Option<bool> {
|
||||
let verification_pubkey = self.pubkey_db.get_by_id(pubkey_id).signage_key;
|
||||
let parts: Vec<String> = full_text
|
||||
.chars()
|
||||
.skip(35)
|
||||
.take(full_text.len() - 35 - 27)
|
||||
.collect::<String>()
|
||||
.split("-----BEGIN KDT SIGNATURE-----")
|
||||
.map(|x| x.trim())
|
||||
.map(String::from)
|
||||
.collect();
|
||||
let text = parts.first()?.trim().to_owned();
|
||||
let signature = parts.last()?.replace("\n", "");
|
||||
Some(KdtSignageHandler::verify(
|
||||
text,
|
||||
signature,
|
||||
verification_pubkey,
|
||||
))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
// -- compiler flags --
|
||||
#![allow(dead_code)]
|
||||
|
||||
pub mod signatures;
|
||||
|
||||
pub use signatures::*;
|
|
@ -0,0 +1,42 @@
|
|||
// -- imports --
|
||||
use crate::core::*;
|
||||
use pqc_dilithium::verify as dilithium_verify;
|
||||
use pqc_dilithium::Keypair;
|
||||
|
||||
// -- signage handler struct --
|
||||
/// Base Dilithium signature handler object. Incredibly WIP.
|
||||
pub struct KdtSignageHandler;
|
||||
|
||||
impl KdtSignageHandler {
|
||||
/// Generates a KDT Dilithium signature from a passed message
|
||||
/// and a key pair, then formats the message with the signature
|
||||
/// in a visually appealing way (mostly just stole GPG's output
|
||||
/// styling).
|
||||
#[inline(always)]
|
||||
pub fn sign_text(text: String, privkey_str: String, pubkey_str: String) -> String {
|
||||
let signkey = Keypair::restore_from_keys(
|
||||
Base64::decode_string(pubkey_str),
|
||||
Base64::decode_string(privkey_str),
|
||||
);
|
||||
format!("-----BEGIN KDT SIGNED MESSAGE-----\n{}\n\n-----BEGIN KDT SIGNATURE-----\n{}\n-----END KDT SIGNATURE-----", text, Base64::encode_bytes(&signkey.sign(text.as_bytes())).chars()
|
||||
.enumerate()
|
||||
.flat_map(|(i, c)| {
|
||||
if (i + 1) % 64 == 0 {
|
||||
vec![c, '\n']
|
||||
} else {
|
||||
vec![c]
|
||||
}
|
||||
})
|
||||
.collect::<String>())
|
||||
}
|
||||
|
||||
/// Verifies a KDT dilithium-signed message against its
|
||||
/// corresponding public key.
|
||||
#[inline(always)]
|
||||
pub fn verify(text: String, signature: String, pubkey_str: String) -> bool {
|
||||
let text_bytes = text.as_bytes();
|
||||
let sig_bytes = Base64::decode_string(signature);
|
||||
let pubkey = Base64::decode_string(pubkey_str);
|
||||
dilithium_verify(&sig_bytes, &text_bytes, &pubkey).is_ok()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
// -- imports --
|
||||
mod arguments;
|
||||
mod core;
|
||||
use crate::arguments::*;
|
||||
use crate::core::*;
|
||||
use clap::Parser;
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
let logger = Logger::new(true);
|
||||
if let Err(e) = args.fail_if_invalid() {
|
||||
logger.fatal(e);
|
||||
}
|
||||
if args.get_num_called() == 0 {
|
||||
logger.fatal(
|
||||
"You didn't pass any arguments! Run `kdt -h` for a list of possible flags and args.",
|
||||
);
|
||||
}
|
||||
let mut kdt = match CoreKdtHandler::new() {
|
||||
Ok(k) => k,
|
||||
Err(e) => logger.fatal(e),
|
||||
};
|
||||
|
||||
// ~ arg handling ~
|
||||
// Note to self - figure out how to make this
|
||||
// part of the code less ugly.
|
||||
{
|
||||
// options
|
||||
// `--export-pubkey`
|
||||
if let Some(pubkey_id) = args.export_pubkey {
|
||||
logger.success(format!("Public key for key id {}:", pubkey_id));
|
||||
println!(
|
||||
"{}",
|
||||
kdt.ownedkey_db.get_by_id(pubkey_id).pubkey_pair.to_string()
|
||||
);
|
||||
}
|
||||
// `--del-pubkey`
|
||||
if let Some(pubkey_id) = args.del_pubkey {
|
||||
logger.info(format!("Removing public key with id {}...", pubkey_id));
|
||||
kdt.del_pubkey(pubkey_id);
|
||||
logger.success("Successfully removed the public key!");
|
||||
}
|
||||
// `--del-keyset`
|
||||
if let Some(privkey_id) = args.del_keyset {
|
||||
logger.info(format!(
|
||||
"Removing owned key set with private key id {}...",
|
||||
privkey_id
|
||||
));
|
||||
kdt.del_ownedkey(privkey_id);
|
||||
logger.success("Succesfully removed the owned key set!");
|
||||
}
|
||||
// `-e | --encrypt`
|
||||
if let Some(id) = args.encrypt {
|
||||
logger.info("Type your message below (CTRL-D to finish):");
|
||||
let message = logger.input();
|
||||
logger.info("Encrypted message:");
|
||||
println!("{}", kdt.encrypt(id, message));
|
||||
}
|
||||
// `-d | --decrypt`
|
||||
if let Some(privkey_id) = args.decrypt {
|
||||
logger.info("Input the encrypted message below (CTRL-D to finish):");
|
||||
let message = logger.input();
|
||||
logger.info("Decrypted message:");
|
||||
println!("{}", kdt.decrypt(privkey_id, message));
|
||||
}
|
||||
// `-s | --sign`
|
||||
if let Some(privkey_id) = args.sign {
|
||||
logger.info("Input the message to sign below (CTRL-D to finish):");
|
||||
let message = logger.input();
|
||||
logger.info("Signed message:");
|
||||
println!("{}", kdt.sign(privkey_id, message));
|
||||
}
|
||||
// `-v | --verify`
|
||||
if let Some(pubkey_id) = args.verify {
|
||||
logger.info("Input the signed message below (CTRL-D to finish):");
|
||||
let message = logger.input();
|
||||
let is_valid = kdt.verify(pubkey_id, message);
|
||||
match is_valid {
|
||||
Some(v) => {
|
||||
if v {
|
||||
logger.success("The provided message is valid!");
|
||||
} else {
|
||||
logger.warn("The given message is not valid!");
|
||||
}
|
||||
}
|
||||
None => logger.fatal("There was an error parsing your input!"),
|
||||
}
|
||||
}
|
||||
|
||||
// flags
|
||||
// `-l | --list-key-pairs`
|
||||
if args.list_key_pairs {
|
||||
if kdt.ownedkey_db.is_empty() {
|
||||
logger.fatal("You don't have any private keys!");
|
||||
}
|
||||
logger.info("Keys in your owned key database:");
|
||||
for key in &kdt.ownedkey_db.keys {
|
||||
println!(
|
||||
"ID: {}\nOwner: {}",
|
||||
key.privkey_pair.id,
|
||||
String::from_utf8_lossy(&Base64::decode_string(key.clone().privkey_pair.owner))
|
||||
);
|
||||
}
|
||||
}
|
||||
// `-g | --gen-key`
|
||||
if args.gen_key {
|
||||
logger.info("Type your name below. Note that this will be visible to everyone who imports your public key.");
|
||||
let name = logger.input();
|
||||
logger.info("Generating owned key set...");
|
||||
let privkey_id = kdt.gen_key(if name.is_empty() {
|
||||
String::from("No name was provided by the key owner!")
|
||||
} else {
|
||||
name
|
||||
});
|
||||
logger.success(format!(
|
||||
"Successfully created owned key with private id {}!",
|
||||
privkey_id
|
||||
))
|
||||
}
|
||||
// `-i | --import`
|
||||
if args.import {
|
||||
logger.info("Input the public KDT key below (CTRL-D to finish):");
|
||||
let pubkey = logger.input();
|
||||
let maybe_pubkey_id = kdt.register_pubkey(pubkey);
|
||||
match maybe_pubkey_id {
|
||||
Ok(id) => logger.success(format!(
|
||||
"Successfully imported KDT public key with id `{}`!",
|
||||
id
|
||||
)),
|
||||
Err(e) => {
|
||||
logger.fatal(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
// `--list-keys`
|
||||
if args.list_keys {
|
||||
if kdt.pubkey_db.is_empty() {
|
||||
logger.fatal("You don't have any public keys!");
|
||||
}
|
||||
logger.info("Keys in your public key database:");
|
||||
for key in &kdt.pubkey_db.keys {
|
||||
println!(
|
||||
"ID: {}\nOwner: {}",
|
||||
key.id,
|
||||
String::from_utf8_lossy(&Base64::decode_string(key.clone().owner))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Dump the datasets loaded in memory back to
|
||||
// their respective files. If this fails, write
|
||||
// a fatal log then panic.
|
||||
if let Err(e) = kdt.dump_db() {
|
||||
logger.fatal(e);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue