use super::{AlgorithmIdentifier, digest};
use crate::{Error, Result};
use structured_asn1::memory::Work;
pub mod parameters;
pub use parameters::{Curve, ExplicitCurve, NamedCurve, Parameters, Reduction, read_parameters};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Basis {
Polynomial,
OptimalNormal,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ByteOrder {
LittleEndian,
BigEndian,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Profile {
digest: digest::Algorithm,
basis: Basis,
byte_order: ByteOrder,
}
impl Profile {
#[must_use]
pub const fn digest(self) -> digest::Algorithm {
self.digest
}
#[must_use]
pub const fn basis(self) -> Basis {
self.basis
}
#[must_use]
pub const fn byte_order(self) -> ByteOrder {
self.byte_order
}
}
pub fn identify<W: Work>(
identifier: AlgorithmIdentifier<'_>,
execution: &W,
) -> Result<Option<Profile>> {
let bytes = identifier.algorithm().as_bytes();
identifier
.query_in(execution)
.charge_work(bytes.len() as u64 + 1)
.map_err(|reason| Error::resource(reason, identifier.field, identifier.offset()))?;
Ok(from_octets(bytes))
}
pub(super) fn from_octets(bytes: &[u8]) -> Option<Profile> {
use digest::Algorithm::{Gost34311, Kupyna256, Kupyna384, Kupyna512};
let (digest, basis, tail) = match bytes {
[0x2a, 0x86, 0x24, 2, 1, 1, 1, 1, 3, 1, basis, tail @ ..] => (Gost34311, basis, tail),
[
0x2a,
0x86,
0x24,
2,
1,
1,
1,
1,
3,
6,
hash,
basis,
tail @ ..,
] => {
let digest = match hash {
1 => Kupyna256,
2 => Kupyna384,
3 => Kupyna512,
_ => return None,
};
(digest, basis, tail)
}
_ => return None,
};
let basis = match basis {
1 => Basis::Polynomial,
2 => Basis::OptimalNormal,
_ => return None,
};
let byte_order = match tail {
[] => ByteOrder::LittleEndian,
[1, 1] => ByteOrder::BigEndian,
_ => return None,
};
Some(Profile {
digest,
basis,
byte_order,
})
}
#[derive(Debug, Clone, Copy)]
pub struct Octets<'a> {
bytes: &'a [u8],
byte_order: ByteOrder,
offset: u64,
}
impl<'a> Octets<'a> {
pub(crate) const fn new(bytes: &'a [u8], byte_order: ByteOrder, offset: u64) -> Self {
Self {
bytes,
byte_order,
offset,
}
}
#[must_use]
pub const fn as_bytes(self) -> &'a [u8] {
self.bytes
}
#[must_use]
pub const fn byte_order(self) -> ByteOrder {
self.byte_order
}
#[must_use]
pub const fn offset(self) -> u64 {
self.offset
}
pub fn big_endian(self) -> impl ExactSizeIterator<Item = u8> + DoubleEndedIterator + 'a {
let bytes = self.bytes;
(0..bytes.len()).map(move |index| match self.byte_order {
ByteOrder::BigEndian => bytes[index],
ByteOrder::LittleEndian => bytes[bytes.len() - 1 - index],
})
}
}