mirror of
https://github.com/logos-blockchain/sponges.git
synced 2026-07-30 02:23:31 +00:00
ascon: extract Ascon permutation type; MSRV 1.59 (#39)
Adds a struct which wraps the permutation state, using const generics as well as `feature(const_generics_defaults)` to express the `A`/`B` parameters for `Ascon(a,b)`.
This commit is contained in:
parent
d50fca63d2
commit
8eb14719c0
2
.github/workflows/ascon.yml
vendored
2
.github/workflows/ascon.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
||||
set-msrv:
|
||||
uses: RustCrypto/actions/.github/workflows/set-msrv.yml@master
|
||||
with:
|
||||
msrv: 1.41.0
|
||||
msrv: 1.59.0
|
||||
|
||||
benches:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@ -28,7 +28,7 @@ portfolio of the [CAESAR competition].
|
||||
|
||||
## Minimum Supported Rust Version
|
||||
|
||||
This crate requires **Rust 1.41** at a minimum.
|
||||
This crate requires **Rust 1.59** at a minimum.
|
||||
|
||||
We may change the MSRV in the future, but it will be accompanied by a minor
|
||||
version bump.
|
||||
@ -57,7 +57,7 @@ dual licensed as above, without any additional terms or conditions.
|
||||
[build-image]: https://github.com/RustCrypto/sponges/actions/workflows/ascon.yml/badge.svg
|
||||
[build-link]: https://github.com/RustCrypto/sponges/actions/workflows/ascon.yml
|
||||
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
|
||||
[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg
|
||||
[rustc-image]: https://img.shields.io/badge/rustc-1.59+-blue.svg
|
||||
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
|
||||
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/369879-sponges
|
||||
|
||||
|
||||
@ -1,8 +1,17 @@
|
||||
//! Authenticated Encryption with Associated Data.
|
||||
|
||||
use crate::{finalization, initialization, permutation, B, KEY_LEN, RATE, S_SIZE};
|
||||
use crate::{Ascon, KEY_LEN, RATE, S_SIZE};
|
||||
use alloc::{vec, vec::Vec};
|
||||
|
||||
/// Ascon(a,b) `b`-parameter.
|
||||
const B: usize = 8;
|
||||
|
||||
/// Tag length.
|
||||
const TAG_LEN: usize = 16;
|
||||
|
||||
/// Authentication tag.
|
||||
type Tag = [u8; TAG_LEN];
|
||||
|
||||
/// Decryption errors.
|
||||
#[derive(Debug)]
|
||||
pub enum DecryptFail {
|
||||
@ -14,54 +23,54 @@ pub enum DecryptFail {
|
||||
}
|
||||
|
||||
/// AEAD encryption.
|
||||
pub fn encrypt(key: &[u8], iv: &[u8], message: &[u8], aad: &[u8]) -> (Vec<u8>, [u8; KEY_LEN]) {
|
||||
pub fn encrypt(key: &[u8], iv: &[u8], message: &[u8], aad: &[u8]) -> (Vec<u8>, Tag) {
|
||||
let s = aad.len() / RATE + 1;
|
||||
let t = message.len() / RATE + 1;
|
||||
let l = message.len() % RATE;
|
||||
|
||||
let mut ss = [0; S_SIZE];
|
||||
let mut aa = vec![0; s * RATE];
|
||||
let mut mm = vec![0; t * RATE];
|
||||
|
||||
let mut output = vec![0; message.len()];
|
||||
let mut tag = [0; KEY_LEN];
|
||||
|
||||
// pad aad
|
||||
aa[..aad.len()].copy_from_slice(aad);
|
||||
aa[aad.len()] = 0x80;
|
||||
|
||||
// pad message
|
||||
mm[..message.len()].copy_from_slice(message);
|
||||
mm[message.len()] = 0x80;
|
||||
|
||||
// init
|
||||
initialization(&mut ss, key, iv);
|
||||
let mut ss = Ascon::new(key, iv);
|
||||
|
||||
// aad
|
||||
if !aad.is_empty() {
|
||||
process_aad(&mut ss, &aa, s);
|
||||
}
|
||||
ss[S_SIZE - 1] ^= 1;
|
||||
|
||||
ss.state[S_SIZE - 1] ^= 1;
|
||||
|
||||
// plaintext
|
||||
for i in 0..(t - 1) {
|
||||
for j in 0..RATE {
|
||||
ss[j] ^= mm[i * RATE + j];
|
||||
ss.state[j] ^= mm[i * RATE + j];
|
||||
}
|
||||
output[(i * RATE)..(i * RATE + RATE)].copy_from_slice(&ss[..RATE]);
|
||||
permutation(&mut ss, 12 - B, B);
|
||||
}
|
||||
for j in 0..RATE {
|
||||
ss[j] ^= mm[(t - 1) * RATE + j];
|
||||
}
|
||||
for j in 0..l {
|
||||
output[(t - 1) * RATE + j] = ss[j];
|
||||
output[(i * RATE)..(i * RATE + RATE)].copy_from_slice(&ss.state[..RATE]);
|
||||
ss.permutation(12 - B, B);
|
||||
}
|
||||
|
||||
// finalization
|
||||
finalization(&mut ss, key);
|
||||
for j in 0..RATE {
|
||||
ss.state[j] ^= mm[(t - 1) * RATE + j];
|
||||
}
|
||||
|
||||
for j in 0..l {
|
||||
output[(t - 1) * RATE + j] = ss.state[j];
|
||||
}
|
||||
|
||||
// tag
|
||||
tag.copy_from_slice(&ss[S_SIZE - KEY_LEN..]);
|
||||
let mut tag = Tag::default();
|
||||
tag.copy_from_slice(&ss.finalize(key)[S_SIZE - KEY_LEN..]);
|
||||
|
||||
(output, tag)
|
||||
}
|
||||
@ -82,7 +91,6 @@ pub fn decrypt(
|
||||
let t = ciphertext.len() / RATE + 1;
|
||||
let l = ciphertext.len() % RATE;
|
||||
|
||||
let mut ss = [0; S_SIZE];
|
||||
let mut aa = vec![0; s * RATE];
|
||||
let mut mm = vec![0; t * RATE];
|
||||
|
||||
@ -91,34 +99,38 @@ pub fn decrypt(
|
||||
aa[aad.len()] = 0x80;
|
||||
|
||||
// init
|
||||
initialization(&mut ss, key, iv);
|
||||
let mut ss = Ascon::new(key, iv);
|
||||
|
||||
// aad
|
||||
if !aad.is_empty() {
|
||||
process_aad(&mut ss, &aa, s);
|
||||
}
|
||||
ss[S_SIZE - 1] ^= 1;
|
||||
|
||||
ss.state[S_SIZE - 1] ^= 1;
|
||||
|
||||
// ciphertext
|
||||
for i in 0..(t - 1) {
|
||||
for j in 0..RATE {
|
||||
mm[i * RATE + j] = ss[j] ^ ciphertext[i * RATE + j];
|
||||
mm[i * RATE + j] = ss.state[j] ^ ciphertext[i * RATE + j];
|
||||
}
|
||||
ss[..RATE].copy_from_slice(&ciphertext[(i * RATE)..(i * RATE + RATE)]);
|
||||
permutation(&mut ss, 12 - B, B);
|
||||
ss.state[..RATE].copy_from_slice(&ciphertext[(i * RATE)..(i * RATE + RATE)]);
|
||||
ss.permutation(12 - B, B);
|
||||
}
|
||||
|
||||
for j in 0..l {
|
||||
mm[(t - 1) * RATE + j] = ss[j] ^ ciphertext[(t - 1) * RATE + j];
|
||||
mm[(t - 1) * RATE + j] = ss.state[j] ^ ciphertext[(t - 1) * RATE + j];
|
||||
}
|
||||
|
||||
for j in 0..l {
|
||||
ss[j] = ciphertext[(t - 1) * RATE + j];
|
||||
ss.state[j] = ciphertext[(t - 1) * RATE + j];
|
||||
}
|
||||
ss[l] ^= 0x80;
|
||||
|
||||
ss.state[l] ^= 0x80;
|
||||
|
||||
// finalization
|
||||
finalization(&mut ss, key);
|
||||
let expected_tag = ss.finalize(key);
|
||||
|
||||
if ct_eq(&ss[S_SIZE - KEY_LEN..], tag) {
|
||||
if ct_eq(&expected_tag[S_SIZE - KEY_LEN..], tag) {
|
||||
Ok(mm[..ciphertext.len()].into())
|
||||
} else {
|
||||
Err(DecryptFail::AuthenticationFail)
|
||||
@ -138,12 +150,13 @@ fn ct_eq(a: &[u8], b: &[u8]) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn process_aad(ss: &mut [u8], aa: &[u8], s: usize) {
|
||||
fn process_aad(ss: &mut Ascon, aa: &[u8], s: usize) {
|
||||
for i in 0..s {
|
||||
for j in 0..RATE {
|
||||
ss[j] ^= aa[i * RATE + j];
|
||||
ss.state[j] ^= aa[i * RATE + j];
|
||||
}
|
||||
permutation(ss, 12 - B, B);
|
||||
|
||||
ss.permutation(12 - B, B);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -46,20 +46,71 @@ use core::convert::TryInto;
|
||||
/// Key length.
|
||||
const KEY_LEN: usize = 16;
|
||||
|
||||
/// State size in bits.
|
||||
const S_BITS: usize = 320;
|
||||
|
||||
/// State size.
|
||||
const S_SIZE: usize = 320 / 8;
|
||||
const S_SIZE: usize = S_BITS / 8;
|
||||
|
||||
/// Rate: Sᵣ.
|
||||
const RATE: usize = 128 / 8;
|
||||
|
||||
/// Ascon(a,b) a-parameter.
|
||||
const A: usize = 12;
|
||||
/// Ascon(a,b) permutation.
|
||||
pub struct Ascon<const A: usize = 12, const B: usize = 8> {
|
||||
state: [u8; S_SIZE],
|
||||
}
|
||||
|
||||
/// Ascon(a,b) b-parameter.
|
||||
const B: usize = 8;
|
||||
impl<const A: usize, const B: usize> Ascon<A, B> {
|
||||
/// Initialize Ascon permutation.
|
||||
// TODO(tarcieri): validate length of key and nonce
|
||||
pub fn new(key: &[u8], nonce: &[u8]) -> Self {
|
||||
let mut state = [0; S_SIZE];
|
||||
state[0] = KEY_LEN as u8 * 8;
|
||||
state[1] = RATE as u8 * 8;
|
||||
state[2] = A as u8;
|
||||
state[3] = B as u8;
|
||||
|
||||
let mut pos = S_SIZE - 2 * KEY_LEN;
|
||||
state[pos..pos + key.len()].copy_from_slice(key);
|
||||
pos += KEY_LEN;
|
||||
state[pos..pos + nonce.len()].copy_from_slice(nonce);
|
||||
|
||||
permutation(&mut state, 12 - A, A);
|
||||
|
||||
for (i, &b) in key.iter().enumerate() {
|
||||
state[pos + i] ^= b;
|
||||
}
|
||||
|
||||
Self { state }
|
||||
}
|
||||
|
||||
/// Perform Ascon permutation on internal state.
|
||||
pub fn permutation(&mut self, start: usize, rounds: usize) {
|
||||
permutation(&mut self.state, start, rounds);
|
||||
}
|
||||
|
||||
/// Finalize Ascon permutation.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn finalize(self, key: &[u8]) -> [u8; S_SIZE] {
|
||||
let mut s = self.state;
|
||||
|
||||
for (i, &b) in key.iter().enumerate() {
|
||||
s[RATE + i] ^= b;
|
||||
}
|
||||
|
||||
permutation(&mut s, 12 - A, A);
|
||||
|
||||
for (i, &b) in key.iter().enumerate() {
|
||||
s[S_SIZE - KEY_LEN + i] ^= b;
|
||||
}
|
||||
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
/// Ascon permutation.
|
||||
pub fn permutation(s: &mut [u8], start: usize, rounds: usize) {
|
||||
fn permutation(s: &mut [u8], start: usize, rounds: usize) {
|
||||
let mut x = [0; 5];
|
||||
let mut t = [0; 5];
|
||||
|
||||
@ -110,33 +161,3 @@ pub fn permutation(s: &mut [u8], start: usize, rounds: usize) {
|
||||
s[(i * 8)..((i + 1) * 8)].copy_from_slice(&b.to_be_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize Ascon permutation.
|
||||
pub fn initialization(s: &mut [u8], key: &[u8], nonce: &[u8]) {
|
||||
s[0] = KEY_LEN as u8 * 8;
|
||||
s[1] = RATE as u8 * 8;
|
||||
s[2] = A as u8;
|
||||
s[3] = B as u8;
|
||||
|
||||
let mut pos = S_SIZE - 2 * KEY_LEN;
|
||||
s[pos..pos + key.len()].copy_from_slice(key);
|
||||
pos += KEY_LEN;
|
||||
s[pos..pos + nonce.len()].copy_from_slice(nonce);
|
||||
|
||||
permutation(s, 12 - A, A);
|
||||
|
||||
for (i, &b) in key.iter().enumerate() {
|
||||
s[pos + i] ^= b;
|
||||
}
|
||||
}
|
||||
|
||||
/// Finalize Ascon permutation.
|
||||
pub fn finalization(s: &mut [u8], key: &[u8]) {
|
||||
for (i, &b) in key.iter().enumerate() {
|
||||
s[RATE + i] ^= b;
|
||||
}
|
||||
permutation(s, 12 - A, A);
|
||||
for (i, &b) in key.iter().enumerate() {
|
||||
s[S_SIZE - KEY_LEN + i] ^= b;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user