+233
-121
Diff
round #0
+21
.tangled/workflows/miri.yml
+21
.tangled/workflows/miri.yml
···
1
+
when:
2
+
- event: ["push", "pull_request"]
3
+
branch: main
4
+
5
+
engine: nixery
6
+
7
+
dependencies:
8
+
nixpkgs:
9
+
- clang
10
+
- rustup
11
+
12
+
steps:
13
+
- name: Install Nightly
14
+
command: |
15
+
rustup toolchain install nightly --component miri
16
+
rustup override set nightly
17
+
cargo miri setup
18
+
- name: Miri Test
19
+
command: cargo miri test --locked -p wharrgarbl-neko
20
+
environment:
21
+
RUSTFLAGS: -Zrandomize-layout
+2
-2
src/handshake.rs
+2
-2
src/handshake.rs
···
36
36
}
37
37
38
38
neko.ad(&K::K::to_u8().to_le_bytes());
39
-
neko.ad(&S::to_bytes());
39
+
neko.ad(&S::BYTES);
40
40
neko.ratchet();
41
41
42
42
Self {
···
119
119
}
120
120
121
121
neko.ad(&K::K::to_u8().to_le_bytes());
122
-
neko.ad(&S::to_bytes());
122
+
neko.ad(&S::BYTES);
123
123
neko.ratchet();
124
124
125
125
Self {
+3
-1
src/lib.rs
+3
-1
src/lib.rs
···
2
2
#![forbid(unsafe_code)]
3
3
4
4
use ml_kem::{MlKem512, MlKem768};
5
-
pub use wharrgarbl_neko::{Neko128, Neko256};
5
+
pub use wharrgarbl_neko::{Neko128, Neko192, Neko256};
6
6
7
7
pub mod handshake;
8
8
pub mod transport;
···
33
33
34
34
pub type NekoClientHandshake128 = handshake::ClientHandshake<Neko128, MlKem512>;
35
35
pub type NekoServerHandshake128 = handshake::ServerHandshake<Neko128, MlKem512>;
36
+
pub type NekoClientHandshake192 = handshake::ClientHandshake<Neko192, MlKem768>;
37
+
pub type NekoServerHandshake192 = handshake::ServerHandshake<Neko192, MlKem768>;
36
38
pub type NekoClientHandshake256 = handshake::ClientHandshake<Neko256, MlKem768>;
37
39
pub type NekoServerHandshake256 = handshake::ServerHandshake<Neko256, MlKem768>;
+15
-5
wharrgarbl-neko/SPEC.md
+15
-5
wharrgarbl-neko/SPEC.md
···
1
-
# NEKO Specification
1
+
# NEKO Specification v0.2.1
2
2
3
3
NEKO is inspired by STROBE in that it uses Keccak in a duplex construction to perform encryption and message authentication. It has stripped down the amount of operation flags it uses and simplifies the internals, ridding the need to have "streaming" by instead opting for having different operating modes.
4
4
···
28
28
29
29
## Construction
30
30
31
-
NEKO internally uses the Keccakf1600 state buffer directly, with its layout of `[u64; 25]`. It operates on blocks of `u64`, and mixes `[u8]` input into these blocks. If a block isn't "filled" completely, the remainder of that block is left as padding, with then the position incremented to point to the next block. It tracks a block counter and an op counter.
31
+
NEKO internally uses the Keccakp1600 state buffer directly, with its layout of `[u64; 25]`. It operates on blocks of `u64`, and mixes `[u8]` input into these blocks. If a block isn't "filled" completely, the remainder of that block is left as padding, with then the position incremented to point to the next block. It tracks a block counter and an op counter.
32
32
33
-
NEKO has two security levels, 128-bit and 256-bit security. Each level determines the *rate*, which is how many blocks are available for input, so 128 gives 21 blocks for input with 4 blocks for entropy/*capacity*, while 256 gives 17 blocks and 8 blocks for entropy/*capacity*. The input blocks are separated for data input with the last block reserved for encoding ops. 256 mode will require permuting more often than 128 mode, as it won't have as much input capacity before its input buffer is exhausted.
33
+
NEKO has three security levels, 128-bit, 192-bit and 256-bit security. Each level determines the *rate*, which is how many blocks are available for input, so 128 gives 21 blocks for input with 4 blocks for entropy/*capacity*, while 256 gives 17 blocks and 8 blocks for entropy/*capacity*. The input blocks are separated for data input with the last block reserved for encoding ops. 256 mode will require permuting more often than 128 mode, as it won't have as much input capacity before its input buffer is exhausted.
34
34
35
-
Ops are tracked with a stack, with a max of 4 ops being "stacked" before a permutation must occur. When a permutation starts, the ops encoding block is selected (position block + 1) and then it is XOR'd with the list of op bits on the \[0..4\] part of the block, going from first op to last, with the \[4..8\] part of the block XOR'd with the ops count, the block position on the first bytes, with then `0x80` & `0` on the last bytes. This creates the start of the padding structure. The padding terminator is then XOR'd on the last byte of the reserved block with a `0x80` value that is rotated by the position counter. If the input fills the buffer completely, the position+1 and reserved block are the same, so the combined XOR'd blocks will form a single block construction. The permutation is then executed with the f1600 function, after which the block & ops counters are reset along with the ops stack.
35
+
Ops are tracked with a stack, with a max of 4 ops being "stacked" before a permutation must occur. When a permutation starts, the ops encoding block is selected (position block + 1) and then it is XOR'd with the list of op bits on the \[0..4\] part of the block, going from first op to last, with the \[4..8\] part of the block XOR'd with the ops count, the block position on the first bytes, with then `0x80` & `0` on the last bytes. This creates the start of the padding structure. The padding terminator is then XOR'd on the last byte of the reserved block with a `0x80` value that is rotated by the position counter. If the input fills the buffer completely, the position+1 and reserved block are the same, so the combined XOR'd blocks will form a single block construction. The permutation is then executed with the p1600 function with 12 rounds (KangarooTwelve), after which the block & ops counters are reset along with the ops stack.
36
36
37
37
After the permutation concludes, the op which triggered the permutation is then encoded into the stack. There are two ways a permutation is invoked: via a user OP, or from a *continuation* for ingesting more data. In the case of a user op, the counter is set to zero, and the stack fully zeroed so the op can encode its flags onto the first slot when it begins. In the case of a *continuation*, the counter is set to `1`, and the first slot is encoded with the `CONT` flag bits with the rest of the slots zeroed. This ensures that in **every** case, there will always be 3 remaining free slots to form a 4 op chain.
38
38
···
90
90
91
91
Then, we must encode the preamble & NEKO version onto the state buffer. The preamble is defined as `[0x01, RATE, 0x07, 0x60]`. The `RATE` is calculated as `(200 - SecLevel / 4) / 8 - 1` and encoded as a `u8` value. So for `Neko128`, the `RATE` should resolve to `20`, and `Neko256` should resolve to `16`. These represent the max buffer position that input data can be absorbed into before needing to permute.
92
92
93
-
The NEKO version string is then concatenated to the preamble. For version v0.2 of this specification, the string is `NEKOv0.2.0`, and it should be concatenated as a byte string. Then the combined preamble+version bytes should be written to the buffer in an `OVERWRITE` action.
93
+
The NEKO version string is then concatenated to the preamble. For version v0.2.1 of this specification, the string is `NEKOv0.2.1`, and it should be concatenated as a byte string. Then the combined preamble+version bytes should be written to the buffer in an `OVERWRITE` action.
94
94
95
95
Additionally, a protocol byte string can be written to the state, following after the preamble+version with its own `OVERWRITE` action.
96
96
···
114
114
All user operations follow a chain of 4 ops. Non-permuting ops can *stack*, so they add to the stack if their inputs don't cause the state to permute. Permuting ops always *reset* the stack, as they permute the state. When the stack resets due to an op, the stack is cleared and the op that triggered the reset is encoded into the first slot. `INIT` is always the very first op, so `KEY` + `NONCE` + `AD` can be added as ops without triggering a permutation. If another non-permuting op were to be chained at this point (like `CLR`), this would cause a panic. To resolve this, call a permuting op like `ENC` or `RATCHET`, and the stack is reset to be just the permuting op on the stack, with three more free slots.
115
115
116
116
A panic is a must, because any occasion that we are going over 4 chained ops is a misuse of the protocol and thus MUST fail quickly. Under normal usage, no sequence of ops should cause a chain of more than 4 to occur, and with large enough payloads, the state would be getting permuted enough to ensure this is not required.
117
+
118
+
## Changes
119
+
120
+
### v0.2
121
+
122
+
Initial publication and base specification.
123
+
124
+
### v0.2.1
125
+
126
+
Changed from f1600 to p1600 with 12 rounds for Keccak permutation function, and introduced Neko192 (192-bit) strength.
+90
-74
wharrgarbl-neko/src/kats.rs
+90
-74
wharrgarbl-neko/src/kats.rs
···
1
1
use hybrid_array::Array;
2
2
use zerocopy::IntoBytes;
3
3
4
-
use crate::{Neko128, Neko256, NekoState};
4
+
use crate::{Neko128, Neko192, Neko256, NekoState};
5
5
6
6
extern crate alloc;
7
7
···
15
15
16
16
assert_eq!(&first, b"\x01\x14\x07\x60NEKO");
17
17
// Values that don't fill the block entirely leave padding
18
-
assert_eq!(&second, b"v0.2.0\0\0");
18
+
assert_eq!(&second, b"v0.2.1\0\0");
19
+
assert_eq!(&third[..4], b"test");
20
+
// The rest of the state is zeroed
21
+
assert_eq!(&neko.state[3..], &[0; 22]);
22
+
}
23
+
24
+
#[test]
25
+
fn neko_192_init_state() {
26
+
let neko = NekoState::<Neko192>::new(b"test");
27
+
28
+
let first = neko.state[0].to_le_bytes();
29
+
let second = neko.state[1].to_le_bytes();
30
+
let third = neko.state[2].to_le_bytes();
31
+
32
+
assert_eq!(&first, b"\x01\x12\x07\x60NEKO");
33
+
// Values that don't fill the block entirely leave padding
34
+
assert_eq!(&second, b"v0.2.1\0\0");
19
35
assert_eq!(&third[..4], b"test");
20
36
// The rest of the state is zeroed
21
37
assert_eq!(&neko.state[3..], &[0; 22]);
···
31
47
32
48
assert_eq!(&first, b"\x01\x10\x07\x60NEKO");
33
49
// Values that don't fill the block entirely leave padding
34
-
assert_eq!(&second, b"v0.2.0\0\0");
50
+
assert_eq!(&second, b"v0.2.1\0\0");
35
51
assert_eq!(&third[..4], b"test");
36
52
// The rest of the state is zeroed
37
53
assert_eq!(&neko.state[3..], &[0; 22]);
···
114
130
let expected_state = [
115
131
0x0000000000000000,
116
132
0x0000000000000000,
117
-
0x14fd15236a301dbc,
118
-
0x3d7a0f031c2332c7,
119
-
0x13d95db32a39a74c,
120
-
0xbfce1f9678690375,
121
-
0xc444bd0f9bb70133,
122
-
0x59600201db93b1de,
123
-
0x6bc376b646e898ea,
124
-
0x2e8a6c345fd3dca3,
125
-
0x9df94788a5fc9f4d,
126
-
0x2541272cca7a631c,
127
-
0xabc8b248a4e0eee3,
128
-
0x2a6befaf570b0120,
129
-
0x5e296ccc9b587798,
130
-
0x9b9d5caef6fc7d3c,
131
-
0x371099e20d7965db,
132
-
0x52b7fecf8d06aed7,
133
-
0xae285d1c6cada2c7,
134
-
0x12d17a37884449ea,
135
-
0x85846b16d640a55b,
136
-
0x0e7d16c0c2bf5a3e,
137
-
0xce32132c0b110014,
138
-
0x6620fda4f7642f84,
139
-
0xd1ea97aadb49a663,
133
+
0xd3c9627ab3f60112,
134
+
0xf9bc5a3ce86c0308,
135
+
0x1b649c672f8291e7,
136
+
0x348b76389636d1c5,
137
+
0x7e7b242854a89160,
138
+
0xc588e1bab9fff3f3,
139
+
0x6869595e613dce2f,
140
+
0x21aa5dd9c8ace1ed,
141
+
0x976ac27c1542f2e3,
142
+
0x271c24a505720c01,
143
+
0x1cf4dbfd172716ec,
144
+
0x5e338536048f69cd,
145
+
0x198c6a958d8215a6,
146
+
0x7e181ad612b4ec51,
147
+
0xd3c7adc0e13f29fd,
148
+
0x92adbe76b85f49a9,
149
+
0xc05147b39c222c68,
150
+
0xea1f4797623a1431,
151
+
0x4d837d8b8ef79878,
152
+
0x59b03ae6c5f3c16f,
153
+
0x2b5da88884b6b1d9,
154
+
0x04ecf618b84acb0a,
155
+
0x58ae3cfc3b9574c2,
140
156
];
141
157
142
158
assert_eq!(&neko.state, &expected_state);
···
187
203
assert_eq!(neko.state[0..2].as_bytes(), &message);
188
204
189
205
let expected_state = [
190
-
0x33e5964098e69bb2,
191
-
0xe8aae76360864f1d,
192
-
0x6c10b3c273ae582c,
193
-
0xd9584d46c8025d46,
194
-
0x8eeace52fffacd4c,
195
-
0x2346ce9726155884,
196
-
0x0f3427af0a3c77f1,
197
-
0xe2706ecbbd9596b4,
198
-
0x840b7500b73e537c,
199
-
0x0015960758c2e30e,
200
-
0xf2cd5efad521e8e2,
201
-
0xca7199cf34822634,
202
-
0xe21f1c3744135b1a,
203
-
0xe91599f57a74f2c9,
204
-
0x1395bb13bd8eec8d,
205
-
0x8417dd11dfee0671,
206
-
0x95d9c20086520a10,
207
-
0x90cfb46fc5a4963d,
208
-
0x2aaf5cd4d234a06d,
209
-
0x5e4372caf96bd84a,
210
-
0x6a858536f819bb62,
211
-
0xf7f33ca323c59700,
212
-
0x38b5d9a41b4d08e1,
213
-
0x39c33af857ae9a82,
214
-
0x39ed20d798ecd321,
206
+
0x376ff3f6beb5164d,
207
+
0x6fce4cdd41481b09,
208
+
0x62c9980b6ebd4375,
209
+
0x35bebdd63cbae3f2,
210
+
0xe82c6eed7a9482b1,
211
+
0xe3948f44d30e1b63,
212
+
0x64f3fbd74d1485a9,
213
+
0xe3a5c716bab805e0,
214
+
0xdb50cee154ae7634,
215
+
0xc5f16a574d98aaa0,
216
+
0xa701afa0ce5e483a,
217
+
0xffdb8ceedc0e2137,
218
+
0x1ced87c9b390ad78,
219
+
0xc066d80fecc4e712,
220
+
0x4d8d46e5f5972a6d,
221
+
0xa948bf5cb8e4442f,
222
+
0x1f08d0ca81e27400,
223
+
0x2234e5f1e79cc913,
224
+
0x4238eb75cde4fa79,
225
+
0xe163927593ef0bfa,
226
+
0x1665d19a25c4a420,
227
+
0x3ec458a9b98e00cb,
228
+
0xf19ee10721f39c29,
229
+
0x96f715bbe8f84a73,
230
+
0xaec74c90f467207c,
215
231
];
216
232
217
233
assert_eq!(&neko.state, &expected_state);
···
223
239
let ratched_expected_state = [
224
240
0x0000000000000000,
225
241
0x0000000000000000,
226
-
0xe72010d5d3b254c0,
227
-
0x34007830a1c7585d,
228
-
0xbcd95dec900847a5,
229
-
0xfe1be2676e130078,
230
-
0xe6c29c4c48f292e6,
231
-
0x3d711aed9763e259,
232
-
0xa9b1329692f19ebd,
233
-
0xf1378893d98ad184,
234
-
0xe6f31bb95f5c361f,
235
-
0x549decbceeac0f78,
236
-
0x81b85f3f3d3a687d,
237
-
0x7dac55db9b73bf34,
238
-
0x6f07454e89ec5950,
239
-
0x9abd19c6e33eec92,
240
-
0x7358043c28de6955,
241
-
0x625421243d6b4bd5,
242
-
0xc986349494886128,
243
-
0xc00e8e52d7734dff,
244
-
0xbafa4f2b57d93144,
245
-
0x022f1aa724503cd5,
246
-
0x4b3633798cc9ae5e,
247
-
0x532b723068ab8c72,
248
-
0xa48327750108017c,
242
+
0x01e23e724c12db57,
243
+
0xe92a5c3fae8b582d,
244
+
0x36454900c0add829,
245
+
0x225646c8528ce4ff,
246
+
0xe0cf79fd5e3e495a,
247
+
0x77aed0a3813ef760,
248
+
0xcbc0aa13baee85be,
249
+
0x3fd706b857c5e671,
250
+
0xfcbe3c0cefddfc6d,
251
+
0xf8d1978f52c0d7e0,
252
+
0x06c874e792fd7180,
253
+
0xa6b978b38814727b,
254
+
0x412d8e5666bde321,
255
+
0x29e578d4ed104740,
256
+
0x17b53fbaf1257b55,
257
+
0x24cc8a75a308d641,
258
+
0x3345c778c83c4882,
259
+
0x1ea9692aff46faf8,
260
+
0x68ce75a36d554dbc,
261
+
0xe1faa52728b78408,
262
+
0xdcabac6ec8e018e4,
263
+
0xc631647d96ed3f06,
264
+
0x8e29b59ab6a8956b,
249
265
];
250
266
251
267
assert_eq!(&neko.state, &ratched_expected_state);
+59
-19
wharrgarbl-neko/src/lib.rs
+59
-19
wharrgarbl-neko/src/lib.rs
···
1
1
#![no_std]
2
-
#![forbid(unsafe_code)]
3
2
4
3
mod flags;
5
4
#[cfg(test)]
···
13
12
use aead::{
14
13
KeySizeUser,
15
14
common::IvSizeUser,
16
-
consts::{U4, U10, U16, U25, U32, U128, U256},
15
+
consts::{U4, U10, U16, U25, U32, U128, U192, U256},
17
16
};
18
17
use ctutils::CtEq;
19
18
use hybrid_array::Array;
···
24
23
pub use crate::traits::NekoSec;
25
24
26
25
pub type Neko128 = U128;
26
+
pub type Neko192 = U192;
27
27
pub type Neko256 = U256;
28
28
pub type NekoNonce<S> = Array<u8, <NekoState<S> as IvSizeUser>::IvSize>;
29
29
pub type NekoKey<S> = Array<u8, <NekoState<S> as KeySizeUser>::KeySize>;
30
30
pub type NekoTag = Array<u8, U16>;
31
31
32
-
pub static NEKO_VERSION: &str = "NEKOv0.2.0";
32
+
pub static NEKO_VERSION: &str = "NEKOv0.2.1";
33
33
const U64_CHUNK: usize = core::mem::size_of::<u64>();
34
34
const MAX_OPS: usize = core::mem::size_of::<u32>();
35
35
···
76
76
///
77
77
/// let neko = NekoState::<Neko128>::new(b"whimsical");
78
78
///
79
-
/// assert_eq!(format!("{neko}"), "NEKOv0.2.0/1600-128");
79
+
/// assert_eq!(format!("{neko}"), "NEKOv0.2.1/1600-128");
80
80
/// ```
81
81
pub fn new(protocol: &[u8]) -> Self {
82
+
const {
83
+
assert!(Sec::RATE < keccak::PLEN);
84
+
assert!(Sec::RATE < u8::MAX as usize);
85
+
};
86
+
82
87
// OPS stack MUST be initialised with the INIT flag as the first op.
83
88
let ops_stack = [ops::INIT.bits(), 0, 0, 0];
84
89
···
95
100
96
101
// Preamble is defined with 0x01 as the first byte, the RATE as the second byte
97
102
// and then 0x07 & 0x60 as the third & fourth byte.
98
-
let preamble: Array<u8, U4> = Array::from([0x01, Sec::rate() as u8, 0x07, 0x60]);
103
+
let preamble: Array<u8, U4> = Array::from([0x01, Sec::RATE as u8, 0x07, 0x60]);
99
104
100
105
// This is safe because the specification version string is always 10 bytes long.
101
106
let version: Array<u8, U10> = Array::try_from(NEKO_VERSION.as_bytes()).unwrap();
···
114
119
neko
115
120
}
116
121
122
+
#[inline(always)]
123
+
#[must_use]
124
+
pub(crate) fn block(&self) -> usize {
125
+
let block = usize::from(self.raw_position()).div_ceil(U64_CHUNK);
126
+
debug_assert!(block < Sec::RATE);
127
+
if block < Sec::RATE {
128
+
block
129
+
} else {
130
+
// SAFETY: the type enforces that `block` is always smaller than `RATE`
131
+
unsafe { core::hint::unreachable_unchecked() };
132
+
}
133
+
}
134
+
135
+
#[inline(always)]
136
+
#[must_use]
137
+
fn raw_position(&self) -> u8 {
138
+
debug_assert!(self.position < u8::MAX as usize && self.position < Sec::RATE * U64_CHUNK);
139
+
if self.position < u8::MAX as usize && self.position < Sec::RATE * U64_CHUNK {
140
+
self.position as u8
141
+
} else {
142
+
// SAFETY: the type enforces that `position` is always smaller than
143
+
// `RATE * U64_CHUNK` & `u8::MAX`
144
+
unsafe { core::hint::unreachable_unchecked() };
145
+
}
146
+
}
147
+
117
148
#[inline]
118
149
#[track_caller]
119
150
fn begin_op(&mut self, red_flags: OpFlags) {
···
132
163
self.ops_stack[op_index] = red_flags.bits();
133
164
}
134
165
135
-
fn permutation_f(&mut self, continuation: OpFlags) {
166
+
fn permutation_p12(&mut self, continuation: OpFlags) {
167
+
const {
168
+
assert!(Sec::RATE < keccak::PLEN);
169
+
assert!(Sec::RATE < u8::MAX as usize);
170
+
};
171
+
136
172
// Last byte is zeroed in case the terminator overlaps
137
173
let permuter: Array<u8, U4> =
138
-
Array([self.ops_count as u8, self.position as u8, 0x80u8.to_le(), 0]);
174
+
Array([self.ops_count as u8, self.raw_position(), 0x80u8.to_le(), 0]);
139
175
140
176
let permuter_block = u64::from_ne_bytes(self.ops_stack.concat(permuter).0);
141
177
···
144
180
self.state[self.position.div_ceil(U64_CHUNK) + 1] ^= permuter_block;
145
181
// Flip a bit in the last byte of the first entropy block with a 1 to act as the padding terminator.
146
182
// The bit is selected via rotating right the value 0x80 (0b1000_0000) by the position counter.
147
-
self.state[Sec::rate()].as_mut_bytes()[7] ^=
183
+
self.state[Sec::RATE].as_mut_bytes()[7] ^=
148
184
0x80u8.to_le().rotate_right(self.position as u32);
149
185
150
-
// The state has been fully prepared, and now can be permuted by the F1600 function.
151
-
keccak::Keccak::new().with_f1600(|permute| permute(&mut self.state.0));
186
+
// The state has been fully prepared, and now can be permuted by the p1600(12) function.
187
+
keccak::Keccak::new().with_p1600::<12>(|permute| permute(&mut self.state.0));
152
188
153
189
// Reset the state, zeroing all counters/stack unless a CONTINUATION, in which case
154
190
// ops count is set to 1 and the first op slot is encoded with 0x01.
···
159
195
160
196
#[inline]
161
197
fn zero_state(&mut self) {
198
+
const {
199
+
assert!(Sec::RATCHET < keccak::PLEN);
200
+
assert!(Sec::RATCHET < u8::MAX as usize);
201
+
};
162
202
// Select the amount of bytes to zero, according to Security level
163
203
// 128 bits = 16 bytes to zero out to achieve forward secrecy
164
204
// 256 bits = 32 bytes to zero out to achieve forward secrecy
165
-
let ratchet_bytes = Sec::ratchet_bytes();
205
+
let ratchet_bytes = Sec::RATCHET;
166
206
167
207
self.state[0..ratchet_bytes].iter_mut().for_each(|block| {
168
208
*block = 0;
···
203
243
///
204
244
/// **This is a PERMUTING operation**
205
245
pub fn prf(&mut self, data: &mut [u8]) {
206
-
self.permutation_f(ops::RST);
246
+
self.permutation_p12(ops::RST);
207
247
208
248
self.begin_op(ops::PRF);
209
249
···
215
255
///
216
256
/// **This is a PERMUTING operation**
217
257
pub fn create_mac(&mut self) -> NekoTag {
218
-
self.permutation_f(ops::RST);
258
+
self.permutation_p12(ops::RST);
219
259
220
260
self.begin_op(ops::MAC);
221
261
···
232
272
///
233
273
/// **This is a PERMUTING operation**
234
274
pub fn verify_mac(&mut self, data: &NekoTag) -> aead::Result<()> {
235
-
self.permutation_f(ops::RST);
275
+
self.permutation_p12(ops::RST);
236
276
237
277
self.begin_op(ops::MAC);
238
278
···
256
296
///
257
297
/// **This is a PERMUTING operation**
258
298
pub fn encrypt(&mut self, data: &mut [u8]) {
259
-
self.permutation_f(ops::RST);
299
+
self.permutation_p12(ops::RST);
260
300
261
301
self.begin_op(ops::ENC);
262
302
···
267
307
///
268
308
/// **This is a PERMUTING operation**
269
309
pub fn decrypt(&mut self, data: &mut [u8]) {
270
-
self.permutation_f(ops::RST);
310
+
self.permutation_p12(ops::RST);
271
311
272
312
self.begin_op(ops::ENC);
273
313
···
290
330
///
291
331
/// **This is a PERMUTING operation**
292
332
pub fn ratchet(&mut self) {
293
-
self.permutation_f(ops::RST);
333
+
self.permutation_p12(ops::RST);
294
334
295
335
self.begin_op(ops::RATCHET);
296
336
···
327
367
let display = std::format!("{s}");
328
368
let debug = std::format!("{s:?}");
329
369
330
-
assert_eq!(&display, "NEKOv0.2.0/1600-128");
370
+
assert_eq!(&display, "NEKOv0.2.1/1600-128");
331
371
assert_eq!(
332
372
&debug,
333
-
"NekoState { sec: 128, version: \"NEKOv0.2.0\", .. }"
373
+
"NekoState { sec: 128, version: \"NEKOv0.2.1\", .. }"
334
374
);
335
375
}
336
376
}
+19
-7
wharrgarbl-neko/src/operators.rs
+19
-7
wharrgarbl-neko/src/operators.rs
···
1
1
use zerocopy::IntoBytes;
2
2
3
-
use crate::{NekoSec, NekoState, U64_CHUNK, ops};
3
+
use crate::{NekoSec, NekoState, ops};
4
4
5
5
pub(crate) struct NekoOperateMut<'s, S: NekoSec> {
6
6
neko: &'s mut NekoState<S>,
···
15
15
16
16
#[inline(always)]
17
17
fn operate_mut(&'s mut self, operation: fn((&mut u8, &mut u8))) {
18
+
const {
19
+
assert!(S::RATE < keccak::PLEN);
20
+
assert!(S::RATE < u8::MAX as usize);
21
+
};
22
+
18
23
loop {
24
+
let block = self.neko.block();
25
+
19
26
// Trans the neko
20
-
let transed_bytes =
21
-
self.neko.state[self.neko.position.div_ceil(U64_CHUNK)..S::rate()].as_mut_bytes();
27
+
let transed_bytes = self.neko.state[block..S::RATE].as_mut_bytes();
22
28
23
29
let take = transed_bytes
24
30
.iter_mut()
···
29
35
self.data = &mut self.data[take..];
30
36
31
37
if !self.data.is_empty() {
32
-
self.neko.permutation_f(ops::CONT);
38
+
self.neko.permutation_p12(ops::CONT);
33
39
} else {
34
40
self.neko.position += take;
35
41
break;
···
80
86
81
87
#[inline(always)]
82
88
fn operate(&'s mut self, operation: fn((&mut u8, &u8))) {
89
+
const {
90
+
assert!(S::RATE < keccak::PLEN);
91
+
assert!(S::RATE < u8::MAX as usize);
92
+
};
93
+
83
94
loop {
95
+
let block = self.neko.block();
96
+
84
97
// Trans the neko
85
-
let transed_bytes =
86
-
self.neko.state[self.neko.position.div_ceil(U64_CHUNK)..S::rate()].as_mut_bytes();
98
+
let transed_bytes = self.neko.state[block..S::RATE].as_mut_bytes();
87
99
88
100
let take = transed_bytes
89
101
.iter_mut()
···
94
106
self.data = &self.data[take..];
95
107
96
108
if !self.data.is_empty() {
97
-
self.neko.permutation_f(ops::CONT);
109
+
self.neko.permutation_p12(ops::CONT);
98
110
} else {
99
111
self.neko.position += take;
100
112
break;
+24
-13
wharrgarbl-neko/src/traits.rs
+24
-13
wharrgarbl-neko/src/traits.rs
···
1
-
use aead::consts::{U128, U200, U256};
1
+
use aead::consts::{U128, U192, U200, U256};
2
2
use hybrid_array::typenum::Unsigned;
3
3
4
4
pub trait NekoSec: Unsigned {
5
-
fn to_bytes() -> [u8; 2] {
6
-
Self::U16.to_le_bytes()
7
-
}
8
-
9
-
fn ratchet_bytes() -> usize {
10
-
Self::USIZE.wrapping_shr(6)
11
-
}
5
+
const RATE: usize;
6
+
const RATCHET: usize;
7
+
const BYTES: [u8; 2];
8
+
}
12
9
13
-
fn rate() -> usize {
14
-
(U200::USIZE - Self::USIZE / 4) / 8 - 1
15
-
}
10
+
impl NekoSec for U128 {
11
+
const RATE: usize = calc_rate(Self::USIZE);
12
+
const BYTES: [u8; 2] = Self::U16.to_le_bytes();
13
+
const RATCHET: usize = Self::USIZE.wrapping_shr(6);
14
+
}
15
+
impl NekoSec for U192 {
16
+
const RATE: usize = calc_rate(Self::USIZE);
17
+
const BYTES: [u8; 2] = Self::U16.to_le_bytes();
18
+
const RATCHET: usize = Self::USIZE.wrapping_shr(6);
19
+
}
20
+
impl NekoSec for U256 {
21
+
const RATE: usize = calc_rate(Self::USIZE);
22
+
const BYTES: [u8; 2] = Self::U16.to_le_bytes();
23
+
const RATCHET: usize = Self::USIZE.wrapping_shr(6);
16
24
}
17
25
18
-
impl NekoSec for U128 {}
19
-
impl NekoSec for U256 {}
26
+
const fn calc_rate(sec: usize) -> usize {
27
+
let rate = (U200::USIZE - sec / 4) / 8 - 1;
28
+
assert!(rate < keccak::PLEN && rate < u8::MAX as usize);
29
+
rate
30
+
}
History
7 rounds
0 comments
1 commit
expand
collapse
NEKO v0.2.1 spec, 192 bit mode, const type asserts
merge conflicts detected
expand
collapse
expand
collapse
- src/handshake.rs:36
- src/lib.rs:2
- wharrgarbl-neko/SPEC.md:1
- wharrgarbl-neko/src/kats.rs:1
- wharrgarbl-neko/src/lib.rs:1
- wharrgarbl-neko/src/operators.rs:1
- wharrgarbl-neko/src/traits.rs:1