push online

This commit is contained in:
h 2024-05-08 15:26:44 -04:00
commit 955b8c396c
10 changed files with 1129 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

290
Cargo.lock generated Normal file
View File

@ -0,0 +1,290 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
dependencies = [
"cfg-if",
]
[[package]]
name = "crunchy"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "either"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "gcc"
version = "0.3.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2"
[[package]]
name = "getrandom"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [
"cfg-if",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "mayo"
version = "0.1.0"
dependencies = [
"rand 0.8.5",
"rayon",
"rust-crypto",
"tiny-keccak",
]
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "rand"
version = "0.3.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
dependencies = [
"libc",
"rand 0.4.6",
]
[[package]]
name = "rand"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
dependencies = [
"fuchsia-cprng",
"libc",
"rand_core 0.3.1",
"rdrand",
"winapi",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.4",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rayon"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rust-crypto"
version = "0.2.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a"
dependencies = [
"gcc",
"libc",
"rand 0.3.23",
"rustc-serialize",
"time",
]
[[package]]
name = "rustc-serialize"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe834bc780604f4674073badbad26d7219cadfb4a2275802db12cbae17498401"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "time"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
dependencies = [
"libc",
"wasi 0.10.0+wasi-snapshot-preview1",
"winapi",
]
[[package]]
name = "tiny-keccak"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
dependencies = [
"crunchy",
]
[[package]]
name = "wasi"
version = "0.10.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "mayo"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tiny-keccak = { version = "2.0", features = ["shake"] }
rand = "0.8.5"
rust-crypto = "0.2.36"
rayon = "1.8.0"

11
src/lib.rs Normal file
View File

@ -0,0 +1,11 @@
#![feature(adt_const_params)]
#![feature(generic_arg_infer)]
#![feature(generic_const_exprs)]
#![feature(portable_simd)]
mod math;
mod params;
mod sig;
mod sym;
pub mod mayo;

330
src/math.rs Normal file
View File

@ -0,0 +1,330 @@
use crate::params::{k, m, n, o, Level};
use std::ops::{Add, Neg};
#[derive(Debug, Clone, Copy)]
pub struct Mat<const R: usize, const C: usize>(pub [[u8; C]; R]);
// TODO: Bitslicing (not u8's) (see below) (fix this so KATs verify)
// TODO: Finish Simd optimization
// TODO: convert these to Rayon: put loops over things into mp
// TODO: Optimize matrix Mul: Strassen or smth
const MUL_LOOKUP: [[u8; 16]; 16] = [
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[0, 2, 4, 6, 8, 10, 12, 14, 3, 1, 7, 5, 11, 9, 15, 13],
[0, 3, 6, 5, 12, 15, 10, 9, 11, 8, 13, 14, 7, 4, 1, 2],
[0, 4, 8, 12, 3, 7, 11, 15, 6, 2, 14, 10, 5, 1, 13, 9],
[0, 5, 10, 15, 7, 2, 13, 8, 14, 11, 4, 1, 9, 12, 3, 6],
[0, 6, 12, 10, 11, 13, 7, 1, 5, 3, 9, 15, 14, 8, 2, 4],
[0, 7, 14, 9, 15, 8, 1, 6, 13, 10, 3, 4, 2, 5, 12, 11],
[0, 8, 3, 11, 6, 14, 5, 13, 12, 4, 15, 7, 10, 2, 9, 1],
[0, 9, 1, 8, 2, 11, 3, 10, 4, 13, 5, 12, 6, 15, 7, 14],
[0, 10, 7, 13, 14, 4, 9, 3, 15, 5, 8, 2, 1, 11, 6, 12],
[0, 11, 5, 14, 10, 1, 15, 4, 7, 12, 2, 9, 13, 6, 8, 3],
[0, 12, 11, 7, 5, 9, 14, 2, 10, 6, 1, 13, 15, 3, 4, 8],
[0, 13, 9, 4, 1, 12, 8, 5, 2, 15, 11, 6, 3, 14, 10, 7],
[0, 14, 15, 1, 13, 3, 2, 12, 9, 7, 6, 8, 4, 10, 11, 5],
[0, 15, 13, 2, 9, 6, 4, 11, 1, 14, 12, 3, 8, 7, 5, 10],
];
#[inline]
pub fn mul(f16_1: u8, f16_2: u8) -> u8 {
MUL_LOOKUP[f16_1 as usize][f16_2 as usize]
}
pub fn upper<const N: usize>(mat: Mat<N, N>) -> Mat<N, N> {
let mut up = Mat([[0; N]; N]);
for i in 0..N {
for j in (i + 1)..N {
up.write(i, j, mat.access(i, j) + mat.access(j, i));
}
for i in 0..N {
up.write(i, i, mat.access(i, i));
}
}
up
}
impl<const R: usize, const C: usize> Mat<R, C> {
#[inline]
pub fn access(&self, i: usize, j: usize) -> u8 {
self.0[i][j]
}
#[inline]
pub fn write(&mut self, i: usize, j: usize, v: u8) {
self.0[i][j] = v;
}
pub fn tp(&self) -> Mat<C, R> {
let mut tp = Mat([[0; R]; C]);
for i in 0..R {
for j in 0..C {
tp.write(j, i, self.access(i, j));
}
}
tp
}
pub fn mul_right<const N: usize>(&self, other: Mat<C, N>) -> Mat<R, N> {
let other_tp = other.tp();
let mut out = Mat([[0; N]; R]);
for i in 0..R {
for j in 0..N {
let write = (0..C)
.map(|k| mul(other_tp.0[j][k], self.0[i][k]))
.fold(0, |acc, x| acc ^ x);
out.write(i, j, write);
}
}
out
}
}
impl<const R: usize, const C: usize> Add for Mat<R, C> {
type Output = Mat<R, C>;
fn add(self, rhs: Self) -> Self::Output {
let mut out = Mat([[0; C]; R]);
for i in 0..R {
for j in 0..C {
out.write(i, j, self.access(i, j) ^ rhs.access(i, j))
}
}
out
}
}
impl<const R: usize, const C: usize> Neg for Mat<R, C> {
type Output = Mat<R, C>;
fn neg(self) -> Self::Output {
self
}
}
pub fn decode_matrix<const R: usize, const C: usize, const L: Level>(bs: &[u8]) -> Mat<R, C> {
let mut mat = Mat([[0; C]; R]);
for i in 0..R {
for j in 0..C {
if (j + C * i) % 2 == 0 {
mat.write(i, j, (bs[(j + C * i) / 2] >> 4) & 0xf);
} else {
mat.write(i, j, bs[(j + C * i) / 2] & 0xf);
}
}
}
mat
}
pub fn decode_matrices<const R: usize, const C: usize, const M: usize, const L: Level>(
bs: &[u8],
num: usize,
triangular: bool,
) -> [Mat<R, C>; M] {
let mut m = [Mat([[0; C]; R]); M];
match triangular {
true => {
let mut ind = 0;
for s in 0..M {
for i in 0..R {
for j in i..C {
if ind % 2 == 0 {
m[s].write(i, j, (bs[ind / 2] >> 4) & 0xf);
} else {
m[s].write(i, j, bs[ind / 2] & 0xf);
}
ind += 1;
}
}
}
}
false => {
for s in 0..M {
for i in 0..R {
for j in 0..C {
if (j + C * i) % 2 == 0 {
m[s].write(i, j, (bs[(j + C * i + R * C * s) / 2] >> 4) & 0xf);
} else {
m[s].write(i, j, bs[(j + C * i + R * C * s) / 2] & 0xf);
}
}
}
}
}
}
m
}
pub fn encode_matrices<const R: usize, const C: usize, const M: usize, const L: Level>(
bs: &[Mat<R, C>],
triangular: bool,
) -> Vec<u8> {
let mut outvec = vec![];
match triangular {
true => {
let mut ind = 0;
for mat in bs {
for i in 0..R {
for j in i..C {
if ind % 2 == 0 {
outvec.push(mat.access(i, j) << 4);
} else {
outvec[ind / 2] |= mat.access(i, j);
}
ind += 1;
}
}
}
}
false => {
for mat in bs {
for i in 0..R {
for j in 0..C {
if (j + C * i) % 2 == 0 {
outvec.push(mat.access(i, j) << 4);
} else {
outvec[(j + C * i) / 2] |= mat.access(i, j);
}
}
}
}
}
}
outvec
}
pub fn decode_vec<const R: usize>(bs: &[u8]) -> Mat<R, 1> {
let mut ret = Mat([[0; 1]; R]);
for i in 0..((R + 1) / 2) {
ret.write(2 * i, 0, (bs[i] >> 4) & 0xf);
if 2 * i + 1 < R {
ret.write(2 * i + 1, 0, bs[i] & 0xf);
}
}
ret
}
pub fn encode_vec<const R: usize>(vec: Mat<R, 1>) -> [u8; (R + 1) / 2] {
let mut out = [0; (R + 1) / 2];
for i in 0..((R + 1) / 2) {
out[i] = vec.access(2 * i, 0) << 4;
if 2 * i + 1 < R {
out[i] |= vec.access(2 * i + 1, 0);
}
}
out
}
pub fn sample_solution<const L: Level>(
mat: Mat<{ m(L) }, { k(L) * o(L) }>,
y: Mat<{ m(L) }, 1>,
r: Mat<{ k(L) * o(L) }, 1>,
) -> Mat<{ n(L) }, 1> {
todo!()
}
// pub struct FullMat<const R: usize, const C: usize>([[u8; C]; R]);
//
// pub const fn tpn(n: usize) -> usize {
// (n * (n + 1)) / 2
// }
//
// pub struct TMat<const N: usize>([u8; tpn(N)])
// where
// [(); tpn(N)]:;
//
// pub enum Mat<const R: usize, const C: usize>
// where
// [(); tpn(R)]:,
// {
// Full(FullMat<R, C>),
// Upper(TMat<R>),
// }
//
// pub fn upper<const N: usize>(mat: Mat<N, N>) -> Mat<N, N>
// where
// [(); tpn(N)]:,
// {
// match mat {
// Mat::Full(f) => {
// let mut up = Mat::Upper(TMat([0; tpn(N)]));
// for i in 0..N {
// for j in (i + 1)..N {
// up.write(i, j, mat.access(i, j) + mat.access(j, i));
// }
// }
// for i in 0..N {
// up.write(i, i, mat.access(i, i));
// }
// up
// }
// Mat::Upper(u) => mat,
// }
// }
//
// impl<const R: usize, const C: usize> Mat<R, C>
// where
// [(); tpn(R)]:,
// [(); tpn(C)]:,
// {
// pub fn access(&self, i: usize, j: usize) -> u8 {
// match self {
// Mat::Full(f) => f.0[i][j],
// Mat::Upper(u) => {
// if i > j {
// 0
// } else {
// u.0[tpn(R) - tpn(R - i) + j - i]
// }
// }
// }
// }
//
// pub fn write(&mut self, i: usize, j: usize, v: u8) {
// match self {
// Mat::Full(f) => {
// f.0[i][j] = v;
// }
// Mat::Upper(u) => {
// if i <= j {
// u.0[tpn(R) - tpn(R - i) + j - i] = v;
// }
// }
// }
// }
//
// pub fn tp(&self) -> Mat<C, R> {
// todo!()
// }
// }
//
// pub fn decode_matrix<const R: usize, const C: usize, const L: Level>(bs: &[u8]) -> Mat<R, C>
// where
// [(); tpn(R)]:,
// {
// todo!()
// })
//
// pub fn decode_matrices<const R: usize, const C: usize, const M: usize, const L: Level>(
// bs: &[u8],
// num: usize,
// triangular: bool,
// ) -> [Mat<R, C>; M]
// where
// [(); tpn(R)]:,
// {
// todo!()
// }
#[cfg(test)]
mod test {
use crate::math::{upper, Mat};
#[test]
fn test_upper() {
let m = Mat([[0, 1, 2], [3, 4, 5], [6, 7, 8]]);
println!("{:?}", upper(m));
assert!(true);
}
}

278
src/mayo.rs Normal file
View File

@ -0,0 +1,278 @@
use crate::math::{
decode_matrices, decode_matrix, decode_vec, encode_matrices, encode_vec, sample_solution,
upper, Mat,
};
use crate::params::Level;
use crate::params::{
digest_bytes, k, l_bytes, m, n, o, o_bytes, p1_bytes, p2_bytes, p3_bytes, pk_seed_bytes,
polymat, salt_bytes, v_bytes,
};
use crate::sig::{KeyGen, Signer, Verifier};
use crate::sym::{aes_128_ctr, shake_256};
use rand::rngs::OsRng;
use rand::RngCore;
use rayon::prelude::*;
#[derive(Debug)]
pub struct SigningKey<const L: Level>([u8; salt_bytes(L)], VerifyKey<L>)
where
[(); salt_bytes(L)]:,
[(); pk_seed_bytes(L) + p3_bytes(L)]:;
#[derive(Debug)]
pub struct VerifyKey<const L: Level>([u8; pk_seed_bytes(L) + p3_bytes(L)])
where
[(); pk_seed_bytes(L) + p3_bytes(L)]:;
impl<const L: Level> KeyGen for SigningKey<L>
where
[(); salt_bytes(L)]:,
[(); pk_seed_bytes(L) + p3_bytes(L)]:,
[(); o_bytes(L) + pk_seed_bytes(L)]:,
[(); n(L) - o(L)]:,
[(); m(L)]:,
{
fn gen() -> Self {
let mut seed_sk: [u8; salt_bytes(L)] = [0; salt_bytes(L)];
OsRng.fill_bytes(&mut seed_sk);
let s: [u8; o_bytes(L) + pk_seed_bytes(L)] = shake_256(vec![&seed_sk]);
let seed_pk = &s[0..pk_seed_bytes(L)];
let o_bs = &s[pk_seed_bytes(L)..(pk_seed_bytes(L) + o_bytes(L))];
let om: Mat<{ n(L) - o(L) }, { o(L) }> =
decode_matrix::<{ n(L) - o(L) }, { o(L) }, { L }>(o_bs);
let p = aes_128_ctr(seed_pk, p1_bytes(L) + p2_bytes(L));
let p1: [Mat<{ n(L) - o(L) }, { n(L) - o(L) }>; m(L)] =
decode_matrices::<{ n(L) - o(L) }, { n(L) - o(L) }, { m(L) }, { L }>(
&p[0..p1_bytes(L)],
m(L),
true,
);
let p2: [Mat<{ n(L) - o(L) }, { o(L) }>; m(L)] =
decode_matrices::<{ n(L) - o(L) }, { o(L) }, { m(L) }, { L }>(
&p[p1_bytes(L)..(p1_bytes(L) + p2_bytes(L))],
m(L),
false,
);
let p3 = (0..m(L))
.into_par_iter()
.map(|i| upper(-om.tp().mul_right(p1[i].mul_right(om)) + (-om.tp().mul_right(p2[i]))))
.collect::<Vec<Mat<{ o(L) }, { o(L) }>>>();
let p3_enc = encode_matrices::<{ o(L) }, { o(L) }, { m(L) }, { L }>(&p3, true);
let mut out = [0; pk_seed_bytes(L) + p3_bytes(L)];
out[..pk_seed_bytes(L)].copy_from_slice(&seed_pk[..pk_seed_bytes(L)]);
out[pk_seed_bytes(L)..].copy_from_slice(&p3_enc);
SigningKey(seed_sk, VerifyKey(out))
}
}
pub fn expand_sk<const L: Level>(
csk: [u8; salt_bytes(L)],
) -> [u8; salt_bytes(L) + o_bytes(L) + p1_bytes(L) + l_bytes(L)]
where
[(); salt_bytes(L)]:,
[(); pk_seed_bytes(L) + p3_bytes(L)]:,
[(); o_bytes(L) + pk_seed_bytes(L)]:,
[(); n(L) - o(L)]:,
[(); m(L)]:,
{
let seed_sk = csk;
let s: [u8; o_bytes(L) + pk_seed_bytes(L)] = shake_256(vec![&seed_sk]);
let seed_pk = &s[0..pk_seed_bytes(L)];
let o_bs = &s[pk_seed_bytes(L)..(pk_seed_bytes(L) + o_bytes(L))];
let om: Mat<{ n(L) - o(L) }, { o(L) }> =
decode_matrix::<{ n(L) - o(L) }, { o(L) }, { L }>(o_bs);
let p = aes_128_ctr(seed_pk, p1_bytes(L) + p2_bytes(L));
let p1: [Mat<{ n(L) - o(L) }, { n(L) - o(L) }>; m(L)] = decode_matrices::<
{ n(L) - o(L) },
{ n(L) - o(L) },
{ m(L) },
{ L },
>(&p[0..p1_bytes(L)], m(L), true);
let p1_bm = encode_matrices::<{ n(L) - o(L) }, { n(L) - o(L) }, { m(L) }, { L }>(&p1, true);
let p2: [Mat<{ n(L) - o(L) }, { o(L) }>; m(L)] =
decode_matrices::<{ n(L) - o(L) }, { o(L) }, { m(L) }, { L }>(
&p[p1_bytes(L)..(p1_bytes(L) + p2_bytes(L))],
m(L),
false,
);
let l = (0..m(L))
.into_par_iter()
.map(|i| (p1[i] + p1[i].tp()).mul_right(om) + p2[i])
.collect::<Vec<Mat<{ n(L) - o(L) }, { o(L) }>>>();
let l_bs = encode_matrices::<{ n(L) - o(L) }, { o(L) }, { m(L) }, { L }>(&l, false);
let mut out = [0; salt_bytes(L) + o_bytes(L) + p1_bytes(L) + l_bytes(L)];
out[..salt_bytes(L)].copy_from_slice(&seed_sk);
out[salt_bytes(L)..(salt_bytes(L) + o_bytes(L))].copy_from_slice(o_bs);
out[(salt_bytes(L) + o_bytes(L))..(salt_bytes(L) + o_bytes(L) + p1_bytes(L))]
.copy_from_slice(&p1_bm);
out[(salt_bytes(L) + o_bytes(L) + p1_bytes(L))..].copy_from_slice(&l_bs);
out
}
impl<const L: Level> Signer<Vec<u8>> for SigningKey<L>
where
[(); salt_bytes(L)]:,
[(); pk_seed_bytes(L) + p3_bytes(L)]:,
[(); o_bytes(L) + pk_seed_bytes(L)]:,
[(); n(L) - o(L)]:,
[(); k(L) * n(L)]:,
[(); m(L)]:,
[(); m(L) / 2]:,
[(); (k(L) * n(L) + 1) / 2]:,
[(); k(L) * v_bytes(L) + ((k(L) * o(L) + 1) / 2)]:,
[(); salt_bytes(L) + o_bytes(L) + p1_bytes(L) + l_bytes(L)]:,
[(); digest_bytes(L)]:,
{
fn sign(&self, msg: &[u8]) -> Vec<u8> {
let esk = expand_sk(self.0);
let seed_sk = &esk[..salt_bytes(L)];
let om: Mat<{ n(L) - o(L) }, { o(L) }> = decode_matrix::<{ n(L) - o(L) }, { o(L) }, { L }>(
&esk[salt_bytes(L)..(salt_bytes(L) + o_bytes(L))],
);
let p1: [Mat<{ n(L) - o(L) }, { n(L) - o(L) }>; m(L)] =
decode_matrices::<{ n(L) - o(L) }, { n(L) - o(L) }, { m(L) }, { L }>(
&esk[(salt_bytes(L) + o_bytes(L))..(salt_bytes(L) + o_bytes(L) + p1_bytes(L))],
m(L),
true,
);
let li: [Mat<{ n(L) - o(L) }, { o(L) }>; m(L)] =
decode_matrices::<{ n(L) - o(L) }, { o(L) }, { m(L) }, { L }>(
&esk[(salt_bytes(L) + o_bytes(L) + p1_bytes(L))..],
m(L),
false,
);
let m_digest: [u8; digest_bytes(L)] = shake_256(vec![msg]);
let salt: [u8; salt_bytes(L)] = shake_256(vec![&m_digest, seed_sk]);
let t_bs: [u8; m(L) / 2] = shake_256(vec![&m_digest, &salt]);
let mut t = decode_vec::<{ m(L) }>(&t_bs);
let v: [u8; k(L) * v_bytes(L) + ((k(L) * o(L) + 1) / 2)] =
shake_256(vec![&m_digest, &salt, seed_sk, &[128]]);
let mut vv: Vec<Mat<{ n(L) - o(L) }, 1>> = vec![];
for i in 0..k(L) {
vv.push(decode_vec::<{ n(L) - o(L) }>(
&v[(i * v_bytes(L))..((i + 1) * v_bytes(L))],
));
}
let r = decode_vec::<{ k(L) * o(L) }>(&v[(k(L) * v_bytes(L))..]);
let mut A = Mat([[0; { m(L) }]; { k(L) * o(L) }]);
let mut l = 0;
let mut el = Mat([[0; m(L)]; m(L)]);
for i in 0..m(L) {
el.write(i, i, 1);
}
let mut Mi = [Mat([[0; { o(L) }]; { m(L) }]); k(L)];
for i in 0..k(L) {
Mi[i] = Mat([[0; { o(L) }]; { m(L) }]);
for j in 0..m(L) {
Mi[i].0[j] = (vv[i].tp().mul_right(li[i])).0[0];
}
}
for i in 0..k(L) {
for j in (i..(k(L))).rev() {
let mut u: Mat<{ m(L) }, 1> = Mat([[0; 1]; m(L)]);
if j == i {
for a in 0..m(L) {
u.write(a, 0, vv[i].tp().mul_right(p1[a]).mul_right(vv[i]).0[0][0]);
}
} else {
for a in 0..m(L) {
u.write(
a,
0,
(vv[i].tp().mul_right(p1[a]).mul_right(vv[j])
+ vv[j].tp().mul_right(p1[a]).mul_right(vv[i]))
.0[0][0],
);
}
}
t = t + (-el.mul_right(u));
for z in (i * o(L))..((i + 1) * o(L)) {
for y in 0..(m(L)) {
A.write(y, z, A.access(y, z) + el.mul_right(Mi[j]).0[y][z]);
}
}
if i != j {
for z in (j * o(L))..((j + 1) * o(L)) {
for y in 0..(m(L)) {
A.write(y, z, A.access(y, z) + el.mul_right(Mi[i]).0[y][z]);
}
}
}
l += 1;
el = el.mul_right(Mat(polymat()));
}
}
let x = sample_solution(A.tp(), t, r).tp();
let mut s = Mat([[0; k(L) * n(L)]; 1]);
for i in 0..(k(L)) {
let x_inner = &x.0[0][(i * o(L))..((i + 1) * o(L))];
let mut xi = [0; o(L)];
for i in 0..o(L) {
xi[i] = x_inner[i];
}
s.0[0][(i * n(L))..((i + 1) * n(L) - o(L))]
.copy_from_slice(&(vv[i] + (om.mul_right(Mat([xi; 1]).tp()))).0[0]);
s.0[0][((i + 1) * n(L) - o(L))..((i + 1) * n(L))]
.copy_from_slice(&x.0[0][(i * o(L))..((i + 1) * o(L))]);
}
let mut sig = encode_vec::<{ k(L) * n(L) }>(s.tp()).to_vec();
for i in salt {
sig.push(i);
}
return sig;
}
}
impl<const L: Level> Verifier<Vec<u8>> for VerifyKey<L>
where
[(); pk_seed_bytes(L) + p3_bytes(L)]:,
{
fn verify(&self, sig: &Vec<u8>, msg: &[u8]) -> bool {
todo!();
}
}
#[cfg(test)]
mod tests {
use super::SigningKey;
use crate::params::Level;
use crate::sig::KeyGen;
#[test]
fn test_gen() {
let s: SigningKey<{ Level::MAYO1 }> = SigningKey::gen();
println!("{:?}", s);
}
}

52
src/naive/mod.rs Normal file
View File

@ -0,0 +1,52 @@
use crate::sig::KeyGen;
use aes::Aes128;
use rand::RngCore;
use tiny_keccak::{Shake, Xof};
pub struct SigParams {
m: u16,
n: u16,
o: u16,
k: u16,
salt_bytes: u8,
digest_bytes: u8,
pk_seed_bytes: u8,
}
// sk_seed_bytes = salt_bytes
// R_bytes = salt_bytes
// O_bytes = ceil((n - o)(o)/2)
// v_bytes = ceil((n - o)/2)
// P1_bytes = m*binom((n - o + 1), 2) / 2
// P2_bytes = m * (n - o) * o / 2
// P3_bytes = m * binom((o + 1), 2) / 2
// L_bytes = m * (n - o) * o / 2
// csk_bytes = salt_bytes
// esk_bytes = salt_bytes + O_bytes + P1_bytes + L_bytes
// cpk_bytes = pk_seed_bytes + P3_bytes
// epk_bytes = P1_bytes + P2_bytes + P3_bytes
// sig_bytes = ceil(nk / 2) + salt_bytes
pub struct SigningKey {
v: VerifyKey,
}
pub struct VerifyKey {}
impl<'a> KeyGen<'a, SigParams> for SigningKey {
fn gen(params: SigParams, rand: &'a mut dyn RngCore) -> Self {
let sk_seed_bytes = params.salt_bytes as usize;
// Pick seed_sk at random
let mut seed_sk: Vec<u8> = vec![0; sk_seed_bytes];
rand.fill_bytes(&mut seed_sk);
// Derive seed_pk and O from seed_sk
let mut shake = Shake::v256();
let O_bytes = ((((params.n - params.o) as usize) * (params.o as usize)) + 1) / 2;
let mut S = vec![0; params.pk_seed_bytes as usize + O_bytes];
shake.squeeze(&mut S);
SigningKey { v: VerifyKey {} }
}
}

119
src/params.rs Normal file
View File

@ -0,0 +1,119 @@
use std::marker::ConstParamTy;
#[derive(ConstParamTy, PartialEq, Eq, Clone, Copy)]
pub enum Level {
MAYO1,
MAYO2,
MAYO3,
MAYO5,
}
pub const fn n(level: Level) -> usize {
match level {
Level::MAYO1 => 66,
Level::MAYO2 => 78,
Level::MAYO3 => 99,
Level::MAYO5 => 133,
}
}
pub const fn m(level: Level) -> usize {
match level {
Level::MAYO1 => 64,
Level::MAYO2 => 64,
Level::MAYO3 => 99,
Level::MAYO5 => 128,
}
}
pub const fn o(level: Level) -> usize {
match level {
Level::MAYO1 => 8,
Level::MAYO2 => 18,
Level::MAYO3 => 10,
Level::MAYO5 => 12,
}
}
pub const fn k(level: Level) -> usize {
match level {
Level::MAYO1 => 9,
Level::MAYO2 => 4,
Level::MAYO3 => 11,
Level::MAYO5 => 12,
}
}
pub const fn q(level: Level) -> usize {
16
}
pub const fn salt_bytes(level: Level) -> usize {
match level {
Level::MAYO1 => 24,
Level::MAYO2 => 24,
Level::MAYO3 => 32,
Level::MAYO5 => 40,
}
}
pub const fn digest_bytes(level: Level) -> usize {
match level {
Level::MAYO1 => 32,
Level::MAYO2 => 32,
Level::MAYO3 => 48,
Level::MAYO5 => 64,
}
}
pub const fn pk_seed_bytes(_level: Level) -> usize {
16
}
pub const fn poly(level: Level) -> usize {
match level {
Level::MAYO1 => 64,
Level::MAYO2 => 64,
Level::MAYO3 => 96,
Level::MAYO5 => 128,
}
}
pub const fn polymat<const L: Level>() -> [[u8; m(L)]; m(L)] {
match poly(L) {
64 => {
todo!()
}
96 => {
todo!()
}
128 => {
todo!()
}
_ => unimplemented!(),
}
}
pub const fn v_bytes(level: Level) -> usize {
(n(level) - o(level) + 1) / 2
}
pub const fn o_bytes(level: Level) -> usize {
(((n(level) - o(level)) * o(level)) + 1) / 2
}
pub const fn p1_bytes(level: Level) -> usize {
m(level) * ((n(level) - o(level) + 1) * (n(level) - o(level))) / 2
}
pub const fn p2_bytes(level: Level) -> usize {
m(level) * (n(level) - o(level)) * o(level) / 2
}
pub const fn p3_bytes(level: Level) -> usize {
m(level) * (o(level) + 1) * (o(level)) / 4
}
pub const fn l_bytes(level: Level) -> usize {
m(level) * (n(level) - o(level)) * o(level) / 2
}

11
src/sig.rs Normal file
View File

@ -0,0 +1,11 @@
pub trait KeyGen {
fn gen() -> Self;
}
pub trait Signer<S> {
fn sign(&self, msg: &[u8]) -> S;
}
pub trait Verifier<S> {
fn verify(&self, sig: &S, msg: &[u8]) -> bool;
}

25
src/sym.rs Normal file
View File

@ -0,0 +1,25 @@
use crypto::aes::{self, KeySize};
use tiny_keccak::{Hasher, Shake};
pub fn aes_128_ctr(seed: &[u8], l: usize) -> Vec<u8> {
let nonce = [0u8; 16];
let mut cipher = aes::ctr(KeySize::KeySize128, seed, &nonce);
let enc = vec![0u8; l];
let mut out = vec![0u8; l];
cipher.process(&enc, &mut out[..]);
out
}
pub fn shake_256<const S: usize>(inputs: Vec<&[u8]>) -> [u8; S] {
let mut shake = Shake::v256();
for inp in inputs {
shake.update(inp);
}
let mut out: [u8; S] = [0; S];
shake.finalize(&mut out);
out
}