Skip to content

Commit

Permalink
types: add various crypto types
Browse files Browse the repository at this point in the history
  • Loading branch information
bmwill committed Feb 23, 2024
1 parent a325101 commit 2d45e9f
Show file tree
Hide file tree
Showing 8 changed files with 490 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ rand = ["dep:rand_core"]
hash = ["dep:blake2"]

[dependencies]
base64ct = "1.6.0"
bs58 = "0.5.0"
hex = "0.4.3"

Expand Down
87 changes: 87 additions & 0 deletions src/types/crypto/bls12381.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! Implementation of bls12381 min-sig public-key cryptogrophy.

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Bls12381PrivateKey(
#[cfg_attr(
feature = "serde",
serde(with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array32>>")
)]
[u8; Self::LENGTH],
);

impl Bls12381PrivateKey {
/// The length of an bls12381 private key in bytes.
pub const LENGTH: usize = 32;
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Bls12381PublicKey(
#[cfg_attr(
feature = "serde",
serde(
with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array96, [::serde_with::Same; 96]>>"
)
)]
[u8; Self::LENGTH],
);

impl Bls12381PublicKey {
/// The length of an bls12381 public key in bytes.
pub const LENGTH: usize = 96;
}

impl std::fmt::Display for Bls12381PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&super::Base64Display96(&self.0), f)
}
}

impl std::fmt::Debug for Bls12381PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Bls12381PublicKey")
.field(&format_args!("\"{}\"", self))
.finish()
}
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Bls12381Signature(
#[cfg_attr(
feature = "serde",
serde(
with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array48, [::serde_with::Same; 48]>>"
)
)]
[u8; Self::LENGTH],
);

impl Bls12381Signature {
/// The length of an bls12381 signature key in bytes.
pub const LENGTH: usize = 48;
}

impl std::fmt::Display for Bls12381Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&super::Base64Display48(&self.0), f)
}
}

impl std::fmt::Debug for Bls12381Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Bls12381Signature")
.field(&format_args!("\"{}\"", self))
.finish()
}
}
85 changes: 85 additions & 0 deletions src/types/crypto/ed25519.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//! Implementation of ed25519 public-key cryptogrophy.

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Ed25519PrivateKey(
#[cfg_attr(
feature = "serde",
serde(with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array32>>")
)]
[u8; Self::LENGTH],
);

impl Ed25519PrivateKey {
/// The length of an ed25519 private key in bytes.
pub const LENGTH: usize = 32;
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Ed25519PublicKey(
#[cfg_attr(
feature = "serde",
serde(with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array32>>")
)]
[u8; Self::LENGTH],
);

impl Ed25519PublicKey {
/// The length of an ed25519 public key in bytes.
pub const LENGTH: usize = 32;
}

impl std::fmt::Display for Ed25519PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&super::Base64Display32(&self.0), f)
}
}

impl std::fmt::Debug for Ed25519PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Ed25519PublicKey")
.field(&format_args!("\"{}\"", self))
.finish()
}
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Ed25519Signature(
#[cfg_attr(
feature = "serde",
serde(
with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array64, [::serde_with::Same; 64]>>"
)
)]
[u8; Self::LENGTH],
);

impl Ed25519Signature {
/// The length of an ed25519 signature key in bytes.
pub const LENGTH: usize = 64;
}

impl std::fmt::Display for Ed25519Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&super::Base64Display64(&self.0), f)
}
}

impl std::fmt::Debug for Ed25519Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Ed25519Signature")
.field(&format_args!("\"{}\"", self))
.finish()
}
}
95 changes: 95 additions & 0 deletions src/types/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
mod bls12381;
mod ed25519;
mod secp256k1;
mod secp256r1;
mod signature;

pub use bls12381::{Bls12381PrivateKey, Bls12381PublicKey, Bls12381Signature};
pub use ed25519::{Ed25519PrivateKey, Ed25519PublicKey, Ed25519Signature};
pub use secp256k1::{Secp256k1PrivateKey, Secp256k1PublicKey, Secp256k1Signature};
pub use secp256r1::{Secp256r1PrivateKey, Secp256r1PublicKey, Secp256r1Signature};
pub use signature::{SignatureScheme, SimpleSignature, UserSignature};

//
// Implement various base64 fixed-size array helpers
//

/// Utility for calculating base64 encoding lenghths.
///
/// In the Base64 encoding each character is used to represent 6 bits (log2(64) = 6). This means
/// that 4 characters are used to represnet 4*6 = 24 bits = 3 bytes. So you need 4*(`n`/3)
/// characters in order to represent `n` bytes, and this needs to be rounded up to a multiple of 4.
/// The number of unused padding characters resulting from the rounding will be 0, 1, 2, or 3.
const fn base64_encoded_length(len: usize) -> usize {
((4 * len / 3) + 3) & !3
}

macro_rules! impl_base64_helper {
($base:ident, $display:ident, $fromstr:ident, $array_length:literal) => {
struct $base;

impl $base {
const LENGTH: usize = $array_length;
const ENCODED_LENGTH: usize = base64_encoded_length(Self::LENGTH);
}

struct $display<'a>(&'a [u8; $base::LENGTH]);

impl<'a> std::fmt::Display for $display<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut buf = [0; $base::ENCODED_LENGTH];
let encoded =
<base64ct::Base64 as base64ct::Encoding>::encode(self.0, &mut buf).unwrap();
f.write_str(encoded)
}
}

struct $fromstr([u8; $base::LENGTH]);

impl std::str::FromStr for $fromstr {
type Err = base64ct::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut buf = [0; $base::LENGTH];
let decoded = <base64ct::Base64 as base64ct::Encoding>::decode(s, &mut buf)?;
assert_eq!(decoded.len(), $base::LENGTH);
Ok(Self(buf))
}
}

#[cfg(feature = "serde")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
impl serde_with::SerializeAs<[u8; Self::LENGTH]> for $base {
fn serialize_as<S>(
source: &[u8; Self::LENGTH],
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let display = $display(source);
serde_with::DisplayFromStr::serialize_as(&display, serializer)
}
}

#[cfg(feature = "serde")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
impl<'de> serde_with::DeserializeAs<'de, [u8; Self::LENGTH]> for $base {
fn deserialize_as<D>(deserializer: D) -> Result<[u8; Self::LENGTH], D::Error>
where
D: serde::Deserializer<'de>,
{
let array: $fromstr = serde_with::DisplayFromStr::deserialize_as(deserializer)?;
Ok(array.0)
}
}

// TODO add tests
};
}

impl_base64_helper!(Base64Array32, Base64Display32, Base64FromStr32, 32);
impl_base64_helper!(Base64Array33, Base64Display33, Base64FromStr33, 33);
impl_base64_helper!(Base64Array48, Base64Display48, Base64FromStr48, 48);
impl_base64_helper!(Base64Array64, Base64Display64, Base64FromStr64, 64);
impl_base64_helper!(Base64Array96, Base64Display96, Base64FromStr96, 96);
87 changes: 87 additions & 0 deletions src/types/crypto/secp256k1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! Implementation of secp256k1 public-key cryptogrophy.

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Secp256k1PrivateKey(
#[cfg_attr(
feature = "serde",
serde(with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array32>>")
)]
[u8; Self::LENGTH],
);

impl Secp256k1PrivateKey {
/// The length of an secp256k1 private key in bytes.
pub const LENGTH: usize = 32;
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Secp256k1PublicKey(
#[cfg_attr(
feature = "serde",
serde(
with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array33, [::serde_with::Same; 33]>>"
)
)]
[u8; Self::LENGTH],
);

impl Secp256k1PublicKey {
/// The length of an secp256k1 public key in bytes.
pub const LENGTH: usize = 33;
}

impl std::fmt::Display for Secp256k1PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&super::Base64Display33(&self.0), f)
}
}

impl std::fmt::Debug for Secp256k1PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Secp256k1PublicKey")
.field(&format_args!("\"{}\"", self))
.finish()
}
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(
feature = "serde",
derive(serde_derive::Serialize, serde_derive::Deserialize)
)]
pub struct Secp256k1Signature(
#[cfg_attr(
feature = "serde",
serde(
with = "::serde_with::As::<::serde_with::IfIsHumanReadable<super::Base64Array64, [::serde_with::Same; 64]>>"
)
)]
[u8; Self::LENGTH],
);

impl Secp256k1Signature {
/// The length of an secp256k1 signature key in bytes.
pub const LENGTH: usize = 64;
}

impl std::fmt::Display for Secp256k1Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&super::Base64Display64(&self.0), f)
}
}

impl std::fmt::Debug for Secp256k1Signature {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Secp256k1Signature")
.field(&format_args!("\"{}\"", self))
.finish()
}
}
Loading

0 comments on commit 2d45e9f

Please sign in to comment.