mirror of
https://github.com/RustCrypto/signatures
synced 2026-06-21 13:45:42 +00:00
lms: convert to hybrid-array (#865)
This commit is contained in:
@@ -24,7 +24,7 @@ jobs:
|
||||
- thumbv7em-none-eabi
|
||||
- wasm32-unknown-unknown
|
||||
toolchain:
|
||||
- 1.72.0 # MSRV
|
||||
- 1.81.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
toolchain:
|
||||
- 1.72.0 # MSRV
|
||||
- 1.81.0 # MSRV
|
||||
- stable
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
|
||||
@@ -26,7 +26,7 @@ jobs:
|
||||
- thumbv7em-none-eabi
|
||||
- wasm32-unknown-unknown
|
||||
rust:
|
||||
- 1.73.0 # MSRV
|
||||
- 1.81.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.73.0 # MSRV
|
||||
- 1.81.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.73.0 # MSRV
|
||||
- 1.81.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
- thumbv7em-none-eabi
|
||||
- wasm32-unknown-unknown
|
||||
rust:
|
||||
- 1.72.0 # MSRV
|
||||
- 1.81.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.72.0 # MSRV
|
||||
- 1.81.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.75.0 # MSRV
|
||||
- 1.81.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -29,6 +29,6 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: 1.75.0
|
||||
toolchain: 1.81.0
|
||||
components: clippy
|
||||
- run: cargo clippy --all-features -- -D warnings
|
||||
|
||||
Generated
+6
-7
@@ -488,7 +488,6 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -564,9 +563,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "hybrid-array"
|
||||
version = "0.2.0-rc.9"
|
||||
version = "0.2.0-rc.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d306b679262030ad8813a82d4915fc04efff97776e4db7f8eb5137039d56400"
|
||||
checksum = "a5a41e5b0754cae5aaf7915f1df1147ba8d316fc6e019cfcc00fbaba96d5e030"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"zeroize",
|
||||
@@ -654,15 +653,15 @@ checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
|
||||
|
||||
[[package]]
|
||||
name = "lms-signature"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0-pre"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
"generic-array",
|
||||
"digest 0.11.0-pre.9",
|
||||
"hex",
|
||||
"hex-literal",
|
||||
"hybrid-array",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"sha2 0.10.8",
|
||||
"sha2 0.11.0-pre.4",
|
||||
"signature",
|
||||
"static_assertions",
|
||||
"typenum",
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ homepage = "https://github.com/RustCrypto/signatures/tree/master/dsa"
|
||||
repository = "https://github.com/RustCrypto/signatures"
|
||||
categories = ["cryptography", "no-std"]
|
||||
keywords = ["crypto", "nist", "signature"]
|
||||
rust-version = "1.72"
|
||||
rust-version = "1.81"
|
||||
|
||||
[dependencies]
|
||||
digest = "=0.11.0-pre.9"
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ readme = "README.md"
|
||||
categories = ["cryptography", "no-std"]
|
||||
keywords = ["crypto", "ecc", "nist", "secp256k1", "signature"]
|
||||
edition = "2021"
|
||||
rust-version = "1.73"
|
||||
rust-version = "1.81"
|
||||
|
||||
[dependencies]
|
||||
elliptic-curve = { version = "0.14.0-rc.1", default-features = false, features = ["digest", "sec1"] }
|
||||
|
||||
@@ -30,10 +30,7 @@ pub use pkcs8::der::{
|
||||
use core::fmt;
|
||||
|
||||
#[cfg(feature = "pem")]
|
||||
use {
|
||||
alloc::string::{String, ToString},
|
||||
core::str,
|
||||
};
|
||||
use core::str;
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
use zeroize::Zeroize;
|
||||
@@ -323,10 +320,13 @@ impl str::FromStr for PublicKeyBytes {
|
||||
}
|
||||
|
||||
#[cfg(feature = "pem")]
|
||||
impl ToString for PublicKeyBytes {
|
||||
fn to_string(&self) -> String {
|
||||
self.to_public_key_pem(Default::default())
|
||||
.expect("PEM serialization error")
|
||||
impl fmt::Display for PublicKeyBytes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(
|
||||
&self
|
||||
.to_public_key_pem(Default::default())
|
||||
.expect("PEM serialization error"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
-225
@@ -1,225 +0,0 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.10.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.2.0-pre.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc17eb697364b18256ec92675ebe6b7b153d2f1041e568d74533c5d0fc1ca162"
|
||||
dependencies = [
|
||||
"hybrid-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"crypto-common 0.1.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.11.0-pre.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eb3be3c52e023de5662dc05a32f747d09a1d6024fdd1f64b0850e373269efb43"
|
||||
dependencies = [
|
||||
"crypto-common 0.2.0-pre.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
|
||||
|
||||
[[package]]
|
||||
name = "hybrid-array"
|
||||
version = "0.2.0-pre.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27fbaf242418fe980caf09ed348d5a6aeabe71fc1bd8bebad641f4591ae0a46d"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "lms"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"digest 0.10.7",
|
||||
"generic-array",
|
||||
"hex",
|
||||
"hex-literal",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"sha2",
|
||||
"signature",
|
||||
"static_assertions",
|
||||
"typenum",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[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.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[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",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signature"
|
||||
version = "2.3.0-pre.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68a9b544e1447a755027450a51bc29aa51772e071bd839aca18136a7dab1b93e"
|
||||
dependencies = [
|
||||
"digest 0.11.0-pre.3",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
|
||||
+5
-5
@@ -1,21 +1,21 @@
|
||||
[package]
|
||||
name = "lms-signature"
|
||||
description = "Pure Rust implementation of Leighton-Micali Hash-Based Signatures (RFC 8554)"
|
||||
version = "0.0.1"
|
||||
version = "0.1.0-pre"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
homepage = "https://github.com/RustCrypto/signatures/tree/master/lms"
|
||||
repository = "https://github.com/RustCrypto/signatures"
|
||||
readme = "README.md"
|
||||
rust-version = "1.73"
|
||||
rust-version = "1.81"
|
||||
categories = ["cryptography"]
|
||||
keywords = ["crypto", "signature"]
|
||||
|
||||
[dependencies]
|
||||
digest = "0.10.7"
|
||||
generic-array = { version = "0.14.4", features = ["zeroize"] }
|
||||
digest = "=0.11.0-pre.9"
|
||||
hybrid-array = { version = "0.2.0-rc.11", features = ["extra-sizes", "zeroize"] }
|
||||
rand = "0.8.5"
|
||||
sha2 = "0.10.8"
|
||||
sha2 = "=0.11.0-pre.4"
|
||||
static_assertions = "1.1.0"
|
||||
rand_core = "0.6.4"
|
||||
signature = { version = "2.3.0-pre.0", features = ["digest", "std", "rand_core"] }
|
||||
|
||||
+9
-10
@@ -2,8 +2,7 @@
|
||||
use crate::ots::modes::LmsOtsMode;
|
||||
use crate::types::Typecode;
|
||||
use digest::Digest;
|
||||
use digest::Output;
|
||||
use generic_array::ArrayLength;
|
||||
use hybrid_array::ArraySize;
|
||||
use std::ops::Add;
|
||||
use std::{
|
||||
marker::PhantomData,
|
||||
@@ -18,9 +17,9 @@ pub trait LmsMode: Typecode + Clone {
|
||||
/// The underlying LM-OTS mode
|
||||
type OtsMode: LmsOtsMode;
|
||||
/// Length of the internal Merkle tree, computed as `2^(h+1)-1`
|
||||
type TreeLen: ArrayLength<Output<Self::Hasher>>;
|
||||
type TreeLen: ArraySize;
|
||||
/// `h` as a type
|
||||
type HLen: ArrayLength<Output<Self::Hasher>>;
|
||||
type HLen: ArraySize;
|
||||
/// The length of the hash function output as a type
|
||||
const M: usize;
|
||||
/// `h` as a [usize]
|
||||
@@ -35,7 +34,7 @@ pub trait LmsMode: Typecode + Clone {
|
||||
pub struct LmsModeInternal<
|
||||
OtsMode: LmsOtsMode,
|
||||
Hasher: Digest,
|
||||
HLen: ArrayLength<Output<Hasher>>,
|
||||
HLen: ArraySize,
|
||||
const M: usize,
|
||||
const H: usize,
|
||||
const TC: u32,
|
||||
@@ -48,7 +47,7 @@ pub struct LmsModeInternal<
|
||||
impl<
|
||||
OtsMode: LmsOtsMode,
|
||||
Hasher: Digest,
|
||||
TreeLen: ArrayLength<Output<Hasher>>,
|
||||
TreeLen: ArraySize,
|
||||
const M: usize,
|
||||
const H: usize,
|
||||
const TC: u32,
|
||||
@@ -62,7 +61,7 @@ impl<
|
||||
impl<
|
||||
OtsMode: LmsOtsMode,
|
||||
Hasher: Digest,
|
||||
TreeLen: ArrayLength<Output<Hasher>>,
|
||||
TreeLen: ArraySize,
|
||||
const M: usize,
|
||||
const H: usize,
|
||||
const TC: u32,
|
||||
@@ -73,7 +72,7 @@ impl<
|
||||
impl<
|
||||
OtsMode: LmsOtsMode,
|
||||
Hasher: Digest,
|
||||
HLen: ArrayLength<Output<Hasher>>,
|
||||
HLen: ArraySize,
|
||||
const M: usize,
|
||||
const H: usize,
|
||||
const TC: u32,
|
||||
@@ -82,7 +81,7 @@ where
|
||||
HLen: Add<typenum::B1>,
|
||||
U1: Shl<<HLen as Add<B1>>::Output>,
|
||||
Shleft<U1, <HLen as Add<B1>>::Output>: Sub<B1>,
|
||||
Sub1<Shleft<U1, <HLen as Add<B1>>::Output>>: ArrayLength<Output<Hasher>>,
|
||||
Sub1<Shleft<U1, <HLen as Add<B1>>::Output>>: ArraySize,
|
||||
{
|
||||
type OtsMode = OtsMode;
|
||||
type Hasher = Hasher;
|
||||
@@ -97,7 +96,7 @@ where
|
||||
impl<
|
||||
Hasher: Digest,
|
||||
OtsMode: LmsOtsMode,
|
||||
TreeLen: ArrayLength<Output<Hasher>>,
|
||||
TreeLen: ArraySize,
|
||||
const M: usize,
|
||||
const H: usize,
|
||||
const TC: u32,
|
||||
|
||||
+22
-19
@@ -6,10 +6,11 @@ use crate::ots::SigningKey as OtsPrivateKey;
|
||||
use crate::types::{Identifier, Typecode};
|
||||
|
||||
use digest::{Digest, Output, OutputSizeUser};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use rand::{CryptoRng, Rng};
|
||||
use signature::{Error, RandomizedSignerMut};
|
||||
|
||||
use core::array::TryFromSliceError;
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::Add;
|
||||
use typenum::{Sum, U28};
|
||||
@@ -23,7 +24,7 @@ use typenum::{Sum, U28};
|
||||
pub struct SigningKey<Mode: LmsMode> {
|
||||
id: Identifier,
|
||||
seed: Output<Mode::Hasher>, // Re-generate the leaf privkeys as-needed from a seed
|
||||
auth_tree: GenericArray<Output<Mode::Hasher>, Mode::TreeLen>, // TODO: Decide whether/when to precompute
|
||||
auth_tree: Array<Output<Mode::Hasher>, Mode::TreeLen>, // TODO: Decide whether/when to precompute
|
||||
q: u32,
|
||||
}
|
||||
|
||||
@@ -36,27 +37,26 @@ impl<Mode: LmsMode> SigningKey<Mode> {
|
||||
|
||||
let mut seed = Output::<Mode::Hasher>::default();
|
||||
rng.fill_bytes(seed.as_mut());
|
||||
Self::new_from_seed(id, seed)
|
||||
Self::new_from_seed(id, seed).expect("size invariant violation")
|
||||
}
|
||||
|
||||
// Returns a new LMS private key generated pseudorandomly from an identifier
|
||||
// and secret seed. The seed must be equal to the hash output length of the
|
||||
// LMS mode ([Mode::M])
|
||||
//
|
||||
// TODO: Return error rather than panic? Or just make the input a
|
||||
// GenericArray? This is the algorithm from Appendix A of
|
||||
// <https://datatracker.ietf.org/doc/html/rfc8554#appendix-A>
|
||||
pub fn new_from_seed(id: Identifier, seed: impl AsRef<[u8]>) -> Self {
|
||||
pub fn new_from_seed(
|
||||
id: Identifier,
|
||||
seed: impl AsRef<[u8]>,
|
||||
) -> Result<Self, TryFromSliceError> {
|
||||
//let seed = seed.as_ref();
|
||||
let seed = GenericArray::clone_from_slice(seed.as_ref());
|
||||
let seed = Array::try_from(seed.as_ref())?;
|
||||
let mut sk = Self {
|
||||
id,
|
||||
seed,
|
||||
auth_tree: GenericArray::default(),
|
||||
auth_tree: Array::default(),
|
||||
q: 0, // we set q = 0 when generating keys; it will change
|
||||
};
|
||||
sk.gen_pk_tree(); // TODO: Use lazy generation / MTT
|
||||
sk
|
||||
Ok(sk)
|
||||
}
|
||||
|
||||
/// Generates a Merkle tree of OTS public key hashes, using the indexing scheme of RFC 8554 offset by 1
|
||||
@@ -135,14 +135,14 @@ impl<Mode: LmsMode> RandomizedSignerMut<Signature<Mode>> for SigningKey<Mode> {
|
||||
|
||||
/// Converts a [PrivateKey] into its byte representation
|
||||
impl<Mode: LmsMode> From<SigningKey<Mode>>
|
||||
for GenericArray<u8, Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U28>>
|
||||
for Array<u8, Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U28>>
|
||||
where
|
||||
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U28>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U28>: ArrayLength<u8>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U28>: ArraySize,
|
||||
{
|
||||
fn from(pk: SigningKey<Mode>) -> Self {
|
||||
// Return u32(type) || u32(otstype) || u32(q) || id || seed
|
||||
GenericArray::from_exact_iter(
|
||||
Array::try_from_iter(
|
||||
std::iter::empty()
|
||||
.chain(Mode::TYPECODE.to_be_bytes())
|
||||
.chain(Mode::OtsMode::TYPECODE.to_be_bytes())
|
||||
@@ -188,8 +188,8 @@ impl<'a, Mode: LmsMode> TryFrom<&'a [u8]> for SigningKey<Mode> {
|
||||
let mut key = Self {
|
||||
q: u32::from_be_bytes(q.try_into().expect("ok")),
|
||||
id: id.try_into().expect("ok"),
|
||||
seed: GenericArray::clone_from_slice(seed),
|
||||
auth_tree: GenericArray::default(),
|
||||
seed: Array::try_from(seed).expect("ok"),
|
||||
auth_tree: Array::default(),
|
||||
};
|
||||
key.gen_pk_tree();
|
||||
Ok(key)
|
||||
@@ -215,7 +215,8 @@ mod tests {
|
||||
let id = hex!("d08fabd4a2091ff0a8cb4ed834e74534");
|
||||
let expected_k = hex!("32a58885cd9ba0431235466bff9651c6c92124404d45fa53cf161c28f1ad5a8e");
|
||||
|
||||
let lms_priv = SigningKey::<LmsSha256M32H10<LmsOtsSha256N32W4>>::new_from_seed(id, seed);
|
||||
let lms_priv =
|
||||
SigningKey::<LmsSha256M32H10<LmsOtsSha256N32W4>>::new_from_seed(id, seed).unwrap();
|
||||
let lms_pub = lms_priv.public();
|
||||
assert_eq!(lms_pub.k(), expected_k);
|
||||
assert_eq!(lms_pub.id(), &id);
|
||||
@@ -229,7 +230,8 @@ mod tests {
|
||||
let id = hex!("215f83b7ccb9acbcd08db97b0d04dc2b");
|
||||
let expected_k = hex!("a1cd035833e0e90059603f26e07ad2aad152338e7a5e5984bcd5f7bb4eba40b7");
|
||||
|
||||
let lms_priv = SigningKey::<LmsSha256M32H5<LmsOtsSha256N32W8>>::new_from_seed(id, seed);
|
||||
let lms_priv =
|
||||
SigningKey::<LmsSha256M32H5<LmsOtsSha256N32W8>>::new_from_seed(id, seed).unwrap();
|
||||
let lms_pub = lms_priv.public();
|
||||
assert_eq!(lms_pub.k(), expected_k);
|
||||
assert_eq!(lms_pub.id(), &id);
|
||||
@@ -339,7 +341,8 @@ mod tests {
|
||||
let id = hex!("215f83b7ccb9acbcd08db97b0d04dc2b");
|
||||
let _expected_k = hex!("a1cd035833e0e90059603f26e07ad2aad152338e7a5e5984bcd5f7bb4eba40b7");
|
||||
|
||||
let mut lms_priv = SigningKey::<LmsSha256M32H5<LmsOtsSha256N32W8>>::new_from_seed(id, seed);
|
||||
let mut lms_priv =
|
||||
SigningKey::<LmsSha256M32H5<LmsOtsSha256N32W8>>::new_from_seed(id, seed).unwrap();
|
||||
lms_priv.q = 4;
|
||||
let _lms_pub = lms_priv.public();
|
||||
|
||||
|
||||
+13
-14
@@ -8,7 +8,7 @@ use crate::lms::Signature;
|
||||
use crate::types::Typecode;
|
||||
use crate::{constants::D_INTR, lms::LmsMode};
|
||||
use digest::{Digest, OutputSizeUser};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use signature::{Error, Verifier};
|
||||
use typenum::{Sum, U24};
|
||||
|
||||
@@ -99,14 +99,14 @@ impl<Mode: LmsMode> Verifier<Signature<Mode>> for VerifyingKey<Mode> {
|
||||
|
||||
/// Converts a [`VerifyingKey`] into its byte representation
|
||||
impl<Mode: LmsMode> From<VerifyingKey<Mode>>
|
||||
for GenericArray<u8, Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>>
|
||||
for Array<u8, Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>>
|
||||
where
|
||||
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U24>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>: ArrayLength<u8>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>: ArraySize,
|
||||
{
|
||||
fn from(pk: VerifyingKey<Mode>) -> Self {
|
||||
// Return u32(type) || u32(otstype) || id || k
|
||||
GenericArray::from_exact_iter(
|
||||
Array::try_from_iter(
|
||||
std::iter::empty()
|
||||
.chain(Mode::TYPECODE.to_be_bytes())
|
||||
.chain(Mode::OtsMode::TYPECODE.to_be_bytes())
|
||||
@@ -149,7 +149,7 @@ impl<'a, Mode: LmsMode> TryFrom<&'a [u8]> for VerifyingKey<Mode> {
|
||||
|
||||
Ok(Self {
|
||||
id: id.try_into().unwrap(),
|
||||
k: GenericArray::clone_from_slice(k),
|
||||
k: Array::try_from(k).expect("size invariant violation"),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -165,8 +165,8 @@ mod tests {
|
||||
ots::{LmsOtsSha256N32W4, LmsOtsSha256N32W8},
|
||||
};
|
||||
use digest::OutputSizeUser;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hex_literal::hex;
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use typenum::{Sum, U24};
|
||||
|
||||
// RFC 8554 Appendix F. Test Case 1
|
||||
@@ -222,7 +222,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_kat1_round_trip() {
|
||||
let pk = VerifyingKey::<LmsSha256M32H5<LmsOtsSha256N32W8>>::try_from(&KAT1[..]).unwrap();
|
||||
let pk_serialized: GenericArray<u8, _> = pk.clone().into();
|
||||
let pk_serialized: Array<u8, _> = pk.clone().into();
|
||||
let bytes = pk_serialized.as_slice();
|
||||
assert_eq!(bytes, &KAT1[..]);
|
||||
}
|
||||
@@ -244,9 +244,10 @@ mod tests {
|
||||
c92124404d45fa53cf161c28f1ad5a8e
|
||||
"
|
||||
);
|
||||
let lms_priv = SigningKey::<LmsSha256M32H10<LmsOtsSha256N32W4>>::new_from_seed(id, seed);
|
||||
let lms_priv =
|
||||
SigningKey::<LmsSha256M32H10<LmsOtsSha256N32W4>>::new_from_seed(id, seed).unwrap();
|
||||
let lms_pub = lms_priv.public();
|
||||
let lms_pub_serialized: GenericArray<u8, _> = lms_pub.into();
|
||||
let lms_pub_serialized: Array<u8, _> = lms_pub.into();
|
||||
let bytes = lms_pub_serialized.as_slice();
|
||||
assert_eq!(bytes, &expected_pubkey[..]);
|
||||
}
|
||||
@@ -255,15 +256,13 @@ mod tests {
|
||||
where
|
||||
VerifyingKey<Mode>: std::fmt::Debug,
|
||||
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U24>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>: ArrayLength<u8>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>: ArraySize,
|
||||
{
|
||||
let rng = rand::thread_rng();
|
||||
let lms_priv = SigningKey::<Mode>::new(rng);
|
||||
let lms_pub = lms_priv.public();
|
||||
let lms_pub_serialized: GenericArray<
|
||||
u8,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>,
|
||||
> = lms_pub.clone().into();
|
||||
let lms_pub_serialized: Array<u8, Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>> =
|
||||
lms_pub.clone().into();
|
||||
let bytes = lms_pub_serialized.as_slice();
|
||||
let lms_pub_deserialized = VerifyingKey::<Mode>::try_from(bytes).unwrap();
|
||||
assert_eq!(lms_pub, lms_pub_deserialized);
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::error::LmsDeserializeError;
|
||||
use crate::lms::LmsMode;
|
||||
use crate::ots::modes::LmsOtsMode;
|
||||
use crate::ots::Signature as OtsSignature;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use signature::SignatureEncoding;
|
||||
|
||||
use std::{
|
||||
@@ -18,7 +18,7 @@ use typenum::{Prod, Sum, U1, U4};
|
||||
pub struct Signature<Mode: LmsMode> {
|
||||
pub(crate) q: u32, // TODO: do these really need to be public?
|
||||
pub(crate) lmots_sig: OtsSignature<Mode::OtsMode>,
|
||||
pub(crate) path: GenericArray<digest::Output<Mode::Hasher>, Mode::HLen>,
|
||||
pub(crate) path: Array<digest::Output<Mode::Hasher>, Mode::HLen>,
|
||||
}
|
||||
|
||||
// manual implementation is required to not require bounds on Mode
|
||||
@@ -48,9 +48,9 @@ where
|
||||
Sum<
|
||||
Prod<<Mode::OtsMode as LmsOtsMode>::NLen, Sum<<Mode::OtsMode as LmsOtsMode>::PLen, U1>>,
|
||||
U4,
|
||||
>: ArrayLength<u8>,
|
||||
>: ArraySize,
|
||||
{
|
||||
type Repr = Vec<u8>; // TODO: GenericArray
|
||||
type Repr = Vec<u8>; // TODO: Array
|
||||
}
|
||||
|
||||
impl<Mode: LmsMode> From<Signature<Mode>> for Vec<u8>
|
||||
@@ -62,12 +62,12 @@ where
|
||||
Sum<
|
||||
Prod<<Mode::OtsMode as LmsOtsMode>::NLen, Sum<<Mode::OtsMode as LmsOtsMode>::PLen, U1>>,
|
||||
U4,
|
||||
>: ArrayLength<u8>,
|
||||
>: ArraySize,
|
||||
{
|
||||
fn from(val: Signature<Mode>) -> Self {
|
||||
let mut sig = Vec::new();
|
||||
sig.extend_from_slice(&val.q.to_be_bytes());
|
||||
let lms_sig: GenericArray<u8, _> = val.lmots_sig.into();
|
||||
let lms_sig: Array<u8, _> = val.lmots_sig.into();
|
||||
sig.extend_from_slice(&lms_sig);
|
||||
sig.extend_from_slice(&Mode::TYPECODE.to_be_bytes());
|
||||
for node in val.path {
|
||||
@@ -121,7 +121,7 @@ impl<Mode: LmsMode> TryFrom<&[u8]> for Signature<Mode> {
|
||||
// Path length is already validated by initial length check
|
||||
let path = path
|
||||
.chunks_exact(Mode::M)
|
||||
.map(GenericArray::clone_from_slice)
|
||||
.map(|chunk| Array::try_from(chunk).expect("size invariant violation"))
|
||||
.collect();
|
||||
|
||||
Ok(Self {
|
||||
@@ -139,8 +139,8 @@ mod tests {
|
||||
use crate::lms::modes::*;
|
||||
use crate::lms::{Signature, SigningKey, VerifyingKey};
|
||||
use crate::ots::modes::*;
|
||||
use generic_array::ArrayLength;
|
||||
use hex_literal::hex;
|
||||
use hybrid_array::ArraySize;
|
||||
use rand::thread_rng;
|
||||
use signature::{RandomizedSignerMut, Verifier};
|
||||
use typenum::{Prod, Sum, U1, U4};
|
||||
@@ -264,7 +264,7 @@ mod tests {
|
||||
Sum<
|
||||
Prod<<Mode::OtsMode as LmsOtsMode>::NLen, Sum<<Mode::OtsMode as LmsOtsMode>::PLen, U1>>,
|
||||
U4,
|
||||
>: ArrayLength<u8>,
|
||||
>: ArraySize,
|
||||
{
|
||||
let mut rng = thread_rng();
|
||||
let mut sk = SigningKey::<Mode>::new(&mut rng);
|
||||
|
||||
+5
-5
@@ -24,8 +24,8 @@ pub mod tests {
|
||||
use crate::ots::private::SigningKey;
|
||||
use digest::Digest;
|
||||
use digest::OutputSizeUser;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hex_literal::hex;
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use rand::thread_rng;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use signature::RandomizedSignerMut;
|
||||
@@ -39,7 +39,7 @@ pub mod tests {
|
||||
fn test_sign<Mode: LmsOtsMode>()
|
||||
where
|
||||
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U2>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U2>: ArrayLength<u8>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U2>: ArraySize,
|
||||
{
|
||||
let mut rng = thread_rng();
|
||||
let mut sk = SigningKey::<Mode>::new(0, [0xcc; ID_LEN], &mut rng);
|
||||
@@ -63,7 +63,7 @@ pub mod tests {
|
||||
fn test_sign_fail_verify<Mode: LmsOtsMode>()
|
||||
where
|
||||
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U2>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U2>: ArrayLength<u8>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U2>: ArraySize,
|
||||
{
|
||||
let mut rng = thread_rng();
|
||||
let mut sk = SigningKey::<Mode>::new(0, [0xcc; ID_LEN], &mut rng);
|
||||
@@ -175,8 +175,8 @@ pub mod tests {
|
||||
let msg = "The enumeration in the Constitution, of certain rights, shall not be construed to deny or disparage others retained by the people.\n".as_bytes();
|
||||
let sig = sk.try_sign_with_rng(&mut rng, msg).unwrap();
|
||||
|
||||
assert_eq!(&sig.c, GenericArray::from_slice(&c));
|
||||
assert_eq!(&sig.y[0], GenericArray::from_slice(&y0));
|
||||
assert_eq!(sig.c, Array::from(c));
|
||||
assert_eq!(sig.y[0], Array::from(y0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+15
-28
@@ -1,7 +1,7 @@
|
||||
use crate::ots::util::coefs;
|
||||
use crate::types::Typecode;
|
||||
use digest::{Digest, Output};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use sha2::Sha256;
|
||||
use static_assertions::const_assert_eq;
|
||||
use std::marker::PhantomData;
|
||||
@@ -13,9 +13,9 @@ pub trait LmsOtsMode: Typecode {
|
||||
/// The underlying hash function
|
||||
type Hasher: Digest;
|
||||
/// The length of the hash function output as a type
|
||||
type NLen: ArrayLength<u8>;
|
||||
type NLen: ArraySize;
|
||||
/// The value of P as a type
|
||||
type PLen: ArrayLength<Output<Self::Hasher>> + ArrayLength<u8>;
|
||||
type PLen: ArraySize;
|
||||
/// The length of the hash function output as a [usize]
|
||||
const N: usize;
|
||||
/// The Winternitz window, which should be a value that divides 8
|
||||
@@ -32,7 +32,7 @@ pub trait LmsOtsMode: Typecode {
|
||||
const SIG_LEN: usize;
|
||||
|
||||
/// Expands a message into its Winternitz coefficients and checksum
|
||||
fn expand(message: &Output<Self::Hasher>) -> GenericArray<u8, Self::PLen> {
|
||||
fn expand(message: &Output<Self::Hasher>) -> Array<u8, Self::PLen> {
|
||||
// Returns an array containing Coefs(message, w, U) || Coefs(checksum, w, V)
|
||||
// where Coefs(M, w, L) is an array containing coef(M, i, w) for each i in 0..L
|
||||
// See RFC 8554 section 3.1.3.
|
||||
@@ -40,7 +40,7 @@ pub trait LmsOtsMode: Typecode {
|
||||
// Expand the message into its coefficients
|
||||
// Immediately allocates full expanded length, but only the first U coefficients are used
|
||||
// in this step
|
||||
let mut arr: GenericArray<u8, <Self as LmsOtsMode>::PLen> = GenericArray::default();
|
||||
let mut arr: Array<u8, <Self as LmsOtsMode>::PLen> = Array::default();
|
||||
for (i, c) in coefs(message, Self::W).enumerate().take(Self::U) {
|
||||
arr[i] = c;
|
||||
}
|
||||
@@ -70,21 +70,12 @@ pub trait LmsOtsMode: Typecode {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LmsOtsModeInternal<
|
||||
Hasher: Digest,
|
||||
const W: usize,
|
||||
PP: ArrayLength<GenericArray<u8, Hasher::OutputSize>> + ArrayLength<u8>,
|
||||
const TC: u32,
|
||||
> {
|
||||
pub struct LmsOtsModeInternal<Hasher: Digest, const W: usize, PP: ArraySize, const TC: u32> {
|
||||
_phantomdata: PhantomData<(Hasher, PP)>,
|
||||
}
|
||||
|
||||
impl<
|
||||
Hasher: Digest,
|
||||
const W: usize,
|
||||
PP: ArrayLength<GenericArray<u8, Hasher::OutputSize>> + ArrayLength<u8>,
|
||||
const TC: u32,
|
||||
> Typecode for LmsOtsModeInternal<Hasher, W, PP, TC>
|
||||
impl<Hasher: Digest, const W: usize, PP: ArraySize, const TC: u32> Typecode
|
||||
for LmsOtsModeInternal<Hasher, W, PP, TC>
|
||||
{
|
||||
const TYPECODE: u32 = TC;
|
||||
}
|
||||
@@ -94,12 +85,8 @@ impl<
|
||||
///
|
||||
/// NLen and N are calculated using the associated OutputSize of the given Digest, as specified by
|
||||
/// https://datatracker.ietf.org/doc/html/rfc8554#section-4.1
|
||||
impl<
|
||||
Hasher: Digest,
|
||||
const W: usize,
|
||||
PP: ArrayLength<GenericArray<u8, Hasher::OutputSize>> + ArrayLength<u8>,
|
||||
const TC: u32,
|
||||
> LmsOtsMode for LmsOtsModeInternal<Hasher, W, PP, TC>
|
||||
impl<Hasher: Digest, const W: usize, PP: ArraySize, const TC: u32> LmsOtsMode
|
||||
for LmsOtsModeInternal<Hasher, W, PP, TC>
|
||||
{
|
||||
type Hasher = Hasher;
|
||||
type NLen = Hasher::OutputSize;
|
||||
@@ -177,13 +164,13 @@ const_assert_eq!(LmsOtsSha256N32W8::SIG_LEN, 1124);
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use generic_array::GenericArray;
|
||||
use hybrid_array::Array;
|
||||
|
||||
use super::LmsOtsMode;
|
||||
#[test]
|
||||
fn test_checksum_zero_w1() {
|
||||
let arr = [0u8; super::LmsOtsSha256N32W1::N];
|
||||
let cksm = super::LmsOtsSha256N32W1::expand(GenericArray::from_slice(&arr));
|
||||
let cksm = super::LmsOtsSha256N32W1::expand(&Array::from(arr));
|
||||
assert_eq!(
|
||||
&cksm[super::LmsOtsSha256N32W1::U..],
|
||||
&[1, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
@@ -193,7 +180,7 @@ mod test {
|
||||
#[test]
|
||||
fn test_checksum_ones_w1() {
|
||||
let arr = [255u8; super::LmsOtsSha256N32W1::N];
|
||||
let cksm = super::LmsOtsSha256N32W1::expand(GenericArray::from_slice(&arr));
|
||||
let cksm = super::LmsOtsSha256N32W1::expand(&Array::from(arr));
|
||||
assert_eq!(
|
||||
&cksm[super::LmsOtsSha256N32W1::U..],
|
||||
&[0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
@@ -203,14 +190,14 @@ mod test {
|
||||
#[test]
|
||||
fn test_checksum_ten_w4() {
|
||||
let arr = [0xaa; super::LmsOtsSha256N32W4::N];
|
||||
let cksm = super::LmsOtsSha256N32W4::expand(GenericArray::from_slice(&arr));
|
||||
let cksm = super::LmsOtsSha256N32W4::expand(&Array::from(arr));
|
||||
assert_eq!(&cksm[super::LmsOtsSha256N32W4::U..], &[0x01, 0x04, 0x00]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_expand_zero_w8() {
|
||||
let arr = [0u8; super::LmsOtsSha256N32W8::N];
|
||||
let expanded = super::LmsOtsSha256N32W8::expand(GenericArray::from_slice(&arr));
|
||||
let expanded = super::LmsOtsSha256N32W8::expand(&Array::from(arr));
|
||||
let mut expected = [0u8; super::LmsOtsSha256N32W8::P];
|
||||
expected[super::LmsOtsSha256N32W8::U] = 0x1f;
|
||||
expected[super::LmsOtsSha256N32W8::U + 1] = 0xe0;
|
||||
|
||||
@@ -6,8 +6,7 @@ use crate::ots::signature::Signature;
|
||||
|
||||
use crate::types::Identifier;
|
||||
use digest::{Digest, Output};
|
||||
use generic_array::sequence::GenericSequence;
|
||||
use generic_array::GenericArray;
|
||||
use hybrid_array::Array;
|
||||
use rand_core::CryptoRngCore;
|
||||
use signature::{Error, RandomizedSignerMut};
|
||||
use zeroize::Zeroize;
|
||||
@@ -19,19 +18,19 @@ use zeroize::Zeroize;
|
||||
pub struct SigningKey<Mode: LmsOtsMode> {
|
||||
q: u32,
|
||||
id: Identifier,
|
||||
x: GenericArray<Output<Mode::Hasher>, Mode::PLen>,
|
||||
x: Array<Output<Mode::Hasher>, Mode::PLen>,
|
||||
valid: bool,
|
||||
}
|
||||
|
||||
impl<Mode: LmsOtsMode> SigningKey<Mode> {
|
||||
/// Generate a private key, expanded pseudorandomly from a seed generated by `rng`.
|
||||
/// Uses the algorithm from appendix A <https://datatracker.ietf.org/doc/html/rfc8554#appendix-A>
|
||||
// a key part of this code working is the DerefMut impl for GenericArray which we abuse in a similar manner to
|
||||
// a key part of this code working is the DerefMut impl for Array which we abuse in a similar manner to
|
||||
// generic_array::ArrayBuilder's internal implementation
|
||||
/// If LM-OTS is being used directly, q MUST be set to the all-zero value
|
||||
/// <https://datatracker.ietf.org/doc/html/rfc8554#section-4>
|
||||
pub fn new(q: u32, id: Identifier, rng: &mut impl CryptoRngCore) -> Self {
|
||||
let mut seed: GenericArray<u8, Mode::NLen> = GenericArray::default();
|
||||
let mut seed: Array<u8, Mode::NLen> = Array::default();
|
||||
rng.fill_bytes(&mut seed);
|
||||
Self::new_from_seed(q, id, seed)
|
||||
}
|
||||
@@ -40,7 +39,7 @@ impl<Mode: LmsOtsMode> SigningKey<Mode> {
|
||||
/// according to Appendix A of <https://datatracker.ietf.org/doc/html/rfc8554#appendix-A>
|
||||
pub fn new_from_seed(q: u32, id: Identifier, seed: impl AsRef<[u8]>) -> Self {
|
||||
let seed = seed.as_ref();
|
||||
let x = GenericArray::generate(|i| {
|
||||
let x = Array::from_fn(|i| {
|
||||
Mode::Hasher::new()
|
||||
.chain_update(id)
|
||||
.chain_update(q.to_be_bytes())
|
||||
@@ -134,7 +133,7 @@ impl<Mode: LmsOtsMode> RandomizedSignerMut<Signature<Mode>> for SigningKey<Mode>
|
||||
}
|
||||
tmp
|
||||
});
|
||||
let y = GenericArray::from_iter(y);
|
||||
let y = Array::from_iter(y);
|
||||
|
||||
let sig = Signature { c, y };
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::ots::signature::Signature;
|
||||
use crate::types::Identifier;
|
||||
use digest::{Output, OutputSizeUser};
|
||||
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use signature::{Error, Verifier};
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::Add;
|
||||
@@ -44,7 +44,7 @@ impl<Mode: LmsOtsMode> Verifier<Signature<Mode>> for VerifyingKey<Mode>
|
||||
where
|
||||
// required to concat Q and cksm(Q)
|
||||
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U2>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U2>: ArrayLength<u8>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U2>: ArraySize,
|
||||
{
|
||||
// this implements algorithm 4a of https://datatracker.ietf.org/doc/html/rfc8554#section-4.6
|
||||
fn verify(&self, msg: &[u8], signature: &Signature<Mode>) -> Result<(), Error> {
|
||||
@@ -62,14 +62,14 @@ where
|
||||
|
||||
/// Converts a [`VerifyingKey`] into its byte representation
|
||||
impl<Mode: LmsOtsMode> From<VerifyingKey<Mode>>
|
||||
for GenericArray<u8, Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>>
|
||||
for Array<u8, Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>>
|
||||
where
|
||||
<Mode::Hasher as OutputSizeUser>::OutputSize: Add<U24>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>: ArrayLength<u8>,
|
||||
Sum<<Mode::Hasher as OutputSizeUser>::OutputSize, U24>: ArraySize,
|
||||
{
|
||||
fn from(pk: VerifyingKey<Mode>) -> Self {
|
||||
// Return u32str(type) || I || u32str(q) || K
|
||||
GenericArray::from_exact_iter(
|
||||
Array::try_from_iter(
|
||||
std::iter::empty()
|
||||
.chain(Mode::TYPECODE.to_be_bytes())
|
||||
.chain(pk.id)
|
||||
@@ -108,7 +108,7 @@ impl<'a, Mode: LmsOtsMode> TryFrom<&'a [u8]> for VerifyingKey<Mode> {
|
||||
Ok(Self {
|
||||
q: u32::from_be_bytes(q.try_into().expect("ok")),
|
||||
id: i.try_into().expect("ok"),
|
||||
k: GenericArray::clone_from_slice(k),
|
||||
k: Array::try_from(k).expect("ok"),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -122,14 +122,14 @@ mod tests {
|
||||
use crate::ots::modes::{LmsOtsSha256N32W4, LmsOtsSha256N32W8};
|
||||
use crate::ots::private::SigningKey;
|
||||
use crate::ots::public::VerifyingKey;
|
||||
use generic_array::GenericArray;
|
||||
use hybrid_array::Array;
|
||||
use rand::thread_rng;
|
||||
|
||||
#[test]
|
||||
fn test_serde() {
|
||||
let pk =
|
||||
SigningKey::<LmsOtsSha256N32W8>::new(0, [0xbb; ID_LEN], &mut thread_rng()).public();
|
||||
let pk_serialized: GenericArray<u8, _> = pk.clone().into();
|
||||
let pk_serialized: Array<u8, _> = pk.clone().into();
|
||||
let bytes = pk_serialized.as_slice();
|
||||
let pk_deserialized = VerifyingKey::<LmsOtsSha256N32W8>::try_from(bytes);
|
||||
|
||||
|
||||
+15
-15
@@ -5,7 +5,7 @@ use crate::error::LmsDeserializeError;
|
||||
use crate::ots::modes::LmsOtsMode;
|
||||
use crate::types::Identifier;
|
||||
use digest::Digest;
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use signature::SignatureEncoding;
|
||||
use std::cmp::Ordering;
|
||||
use std::ops::{Add, Mul};
|
||||
@@ -17,7 +17,7 @@ use super::VerifyingKey;
|
||||
/// Opaque struct representing a LM-OTS signature
|
||||
pub struct Signature<Mode: LmsOtsMode> {
|
||||
pub(crate) c: digest::Output<Mode::Hasher>,
|
||||
pub(crate) y: GenericArray<digest::Output<Mode::Hasher>, Mode::PLen>,
|
||||
pub(crate) y: Array<digest::Output<Mode::Hasher>, Mode::PLen>,
|
||||
}
|
||||
|
||||
// manual implementation is required to not require bounds on Mode
|
||||
@@ -37,11 +37,9 @@ impl<Mode: LmsOtsMode> PartialEq for Signature<Mode> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Useful type alias to get the [`GenericArray`] representation
|
||||
pub type Output<Mode> = GenericArray<
|
||||
u8,
|
||||
Sum<Prod<<Mode as LmsOtsMode>::NLen, Sum<<Mode as LmsOtsMode>::PLen, U1>>, U4>,
|
||||
>;
|
||||
/// Useful type alias to get the [`Array`] representation
|
||||
pub type Output<Mode> =
|
||||
Array<u8, Sum<Prod<<Mode as LmsOtsMode>::NLen, Sum<<Mode as LmsOtsMode>::PLen, U1>>, U4>>;
|
||||
|
||||
/// Converts a [`Signature`] into its byte representation
|
||||
impl<Mode: LmsOtsMode> From<Signature<Mode>> for Output<Mode>
|
||||
@@ -50,10 +48,10 @@ where
|
||||
Mode::PLen: Add<U1>,
|
||||
Mode::NLen: Mul<Sum<Mode::PLen, U1>>,
|
||||
Prod<Mode::NLen, Sum<Mode::PLen, U1>>: Add<U4>,
|
||||
Sum<Prod<Mode::NLen, Sum<Mode::PLen, U1>>, U4>: ArrayLength<u8>,
|
||||
Sum<Prod<Mode::NLen, Sum<Mode::PLen, U1>>, U4>: ArraySize,
|
||||
{
|
||||
fn from(sig: Signature<Mode>) -> Self {
|
||||
GenericArray::from_exact_iter(
|
||||
Array::try_from_iter(
|
||||
std::iter::empty()
|
||||
.chain(Mode::TYPECODE.to_be_bytes())
|
||||
.chain(sig.c.clone())
|
||||
@@ -88,12 +86,14 @@ impl<'a, Mode: LmsOtsMode> TryFrom<&'a [u8]> for Signature<Mode> {
|
||||
// sig is now guaranteed to be of the form C || y[0] || ... || y[p - 1]
|
||||
let (c, y) = sig.split_at(Mode::N);
|
||||
|
||||
let c = GenericArray::clone_from_slice(c);
|
||||
let c = Array::try_from(c).expect("size invariant violation");
|
||||
|
||||
// ys is an iterator over GenericArray<u8, Mode::NLen> of length p
|
||||
let ys = y.chunks_exact(Mode::N).map(GenericArray::clone_from_slice);
|
||||
// ys is an iterator over Array<u8, Mode::NLen> of length p
|
||||
let ys = y
|
||||
.chunks_exact(Mode::N)
|
||||
.map(|chunk| Array::try_from(chunk).expect("size invariant violation"));
|
||||
debug_assert!(ys.len() == Mode::P);
|
||||
let y = GenericArray::from_iter(ys);
|
||||
let y = Array::from_iter(ys);
|
||||
|
||||
Ok(Self { c, y })
|
||||
}
|
||||
@@ -124,7 +124,7 @@ impl<Mode: LmsOtsMode> Signature<Mode> {
|
||||
.chain_update(q.to_be_bytes())
|
||||
.chain_update(D_PBLC);
|
||||
|
||||
let mut tmp = GenericArray::default();
|
||||
let mut tmp = Array::default();
|
||||
for (i, a) in Mode::expand(&msg_hash).into_iter().enumerate() {
|
||||
tmp.clone_from(&self.y[i]);
|
||||
|
||||
@@ -158,7 +158,7 @@ where
|
||||
Mode::PLen: Add<U1>,
|
||||
Mode::NLen: Mul<Sum<Mode::PLen, U1>>,
|
||||
Prod<Mode::NLen, Sum<Mode::PLen, U1>>: Add<U4>,
|
||||
Sum<Prod<Mode::NLen, Sum<Mode::PLen, U1>>, U4>: ArrayLength<u8>,
|
||||
Sum<Prod<Mode::NLen, Sum<Mode::PLen, U1>>, U4>: ArraySize,
|
||||
{
|
||||
type Repr = Output<Mode>;
|
||||
}
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ readme = "README.md"
|
||||
categories = ["cryptography", "no-std"]
|
||||
keywords = ["dsa", "ecdsa", "signature"]
|
||||
edition = "2021"
|
||||
rust-version = "1.72"
|
||||
rust-version = "1.81"
|
||||
|
||||
[dependencies]
|
||||
hmac = { version = "=0.13.0-pre.4", default-features = false, features = ["reset"] }
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ FIPS-205 standard
|
||||
"""
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.75"
|
||||
rust-version = "1.81"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
homepage = "https://github.com/RustCrypto/signatures/tree/master/slh-dsa"
|
||||
repository = "https://github.com/RustCrypto/signatures"
|
||||
|
||||
Reference in New Issue
Block a user