mod ed25519;
mod hash;
#[allow(dead_code)]
mod secp256k1;
use std::{fmt::Display, io, num::ParseIntError, str::FromStr};
use alloy_primitives::FixedBytes;
use custom_debug_derive::Debug;
pub use ed25519::{Ed25519PublicKey, Ed25519SecretKey, Ed25519Signature};
pub use hash::*;
use linera_witty::{WitLoad, WitStore, WitType};
pub use secp256k1::{
evm::{EvmPublicKey, EvmSecretKey, EvmSignature},
Secp256k1PublicKey, Secp256k1SecretKey, Secp256k1Signature,
};
use serde::{Deserialize, Serialize};
use thiserror::Error;
pub type ValidatorPublicKey = secp256k1::Secp256k1PublicKey;
pub type ValidatorSecretKey = secp256k1::Secp256k1SecretKey;
pub type ValidatorSignature = secp256k1::Secp256k1Signature;
pub type ValidatorKeypair = secp256k1::Secp256k1KeyPair;
#[derive(Serialize, Deserialize, Debug, Copy, Clone, Eq, PartialEq)]
pub enum SignatureScheme {
Ed25519,
Secp256k1,
EvmSecp256k1,
}
#[derive(
Serialize,
Deserialize,
Debug,
Eq,
PartialEq,
Ord,
PartialOrd,
Copy,
Clone,
Hash,
WitType,
WitLoad,
WitStore,
)]
pub enum AccountPublicKey {
Ed25519(ed25519::Ed25519PublicKey),
Secp256k1(secp256k1::Secp256k1PublicKey),
EvmSecp256k1(secp256k1::evm::EvmPublicKey),
}
#[derive(Serialize, Deserialize)]
pub enum AccountSecretKey {
Ed25519(ed25519::Ed25519SecretKey),
Secp256k1(secp256k1::Secp256k1SecretKey),
EvmSecp256k1(secp256k1::evm::EvmSecretKey),
}
#[derive(Eq, PartialEq, Copy, Clone, Debug, Serialize, Deserialize)]
pub enum AccountSignature {
Ed25519(ed25519::Ed25519Signature),
Secp256k1(secp256k1::Secp256k1Signature),
EvmSecp256k1(secp256k1::evm::EvmSignature),
}
impl AccountSecretKey {
pub fn public(&self) -> AccountPublicKey {
match self {
AccountSecretKey::Ed25519(secret) => AccountPublicKey::Ed25519(secret.public()),
AccountSecretKey::Secp256k1(secret) => AccountPublicKey::Secp256k1(secret.public()),
AccountSecretKey::EvmSecp256k1(secret) => {
AccountPublicKey::EvmSecp256k1(secret.public())
}
}
}
pub fn copy(&self) -> Self {
match self {
AccountSecretKey::Ed25519(secret) => AccountSecretKey::Ed25519(secret.copy()),
AccountSecretKey::Secp256k1(secret) => AccountSecretKey::Secp256k1(secret.copy()),
AccountSecretKey::EvmSecp256k1(secret) => AccountSecretKey::EvmSecp256k1(secret.copy()),
}
}
pub fn sign<'de, T>(&self, value: &T) -> AccountSignature
where
T: BcsSignable<'de>,
{
match self {
AccountSecretKey::Ed25519(secret) => {
let signature = Ed25519Signature::new(value, secret);
AccountSignature::Ed25519(signature)
}
AccountSecretKey::Secp256k1(secret) => {
let signature = secp256k1::Secp256k1Signature::new(value, secret);
AccountSignature::Secp256k1(signature)
}
AccountSecretKey::EvmSecp256k1(secret) => {
let signature = secp256k1::evm::EvmSignature::new(value, secret);
AccountSignature::EvmSecp256k1(signature)
}
}
}
#[cfg(all(with_testing, with_getrandom))]
pub fn generate() -> Self {
AccountSecretKey::Ed25519(Ed25519SecretKey::generate())
}
}
impl AccountPublicKey {
pub fn scheme(&self) -> SignatureScheme {
match self {
AccountPublicKey::Ed25519(_) => SignatureScheme::Ed25519,
AccountPublicKey::Secp256k1(_) => SignatureScheme::Secp256k1,
AccountPublicKey::EvmSecp256k1(_) => SignatureScheme::EvmSecp256k1,
}
}
pub fn as_bytes(&self) -> Vec<u8> {
bcs::to_bytes(&self).expect("serialization to bytes should not fail")
}
pub fn from_slice(bytes: &[u8]) -> Result<Self, CryptoError> {
bcs::from_bytes(bytes).map_err(CryptoError::PublicKeyParseError)
}
#[cfg(with_testing)]
pub fn test_key(name: u8) -> Self {
AccountPublicKey::Ed25519(Ed25519PublicKey::test_key(name))
}
}
impl AccountSignature {
pub fn verify<'de, T>(&self, value: &T, author: AccountPublicKey) -> Result<(), CryptoError>
where
T: BcsSignable<'de> + std::fmt::Debug,
{
match (self, author) {
(AccountSignature::Ed25519(signature), AccountPublicKey::Ed25519(public_key)) => {
signature.check(value, public_key)
}
(AccountSignature::Secp256k1(signature), AccountPublicKey::Secp256k1(public_key)) => {
signature.check(value, &public_key)
}
(
AccountSignature::EvmSecp256k1(signature),
AccountPublicKey::EvmSecp256k1(public_key),
) => signature.check(value, &public_key),
(AccountSignature::Ed25519(_), _) => {
let type_name = std::any::type_name::<T>();
Err(CryptoError::InvalidSignature {
error: "invalid signature scheme. Expected Ed25519 signature.".to_string(),
type_name: type_name.to_string(),
})
}
(AccountSignature::Secp256k1(_), _) => {
let type_name = std::any::type_name::<T>();
Err(CryptoError::InvalidSignature {
error: "invalid signature scheme. Expected secp256k1 signature.".to_string(),
type_name: type_name.to_string(),
})
}
(AccountSignature::EvmSecp256k1(_), _) => {
let type_name = std::any::type_name::<T>();
Err(CryptoError::InvalidSignature {
error: "invalid signature scheme. Expected EvmSecp256k1 signature.".to_string(),
type_name: type_name.to_string(),
})
}
}
}
pub fn to_bytes(&self) -> Vec<u8> {
bcs::to_bytes(&self).expect("serialization to bytes should not fail")
}
pub fn from_slice(bytes: &[u8]) -> Result<Self, CryptoError> {
bcs::from_bytes(bytes).map_err(CryptoError::SignatureParseError)
}
}
impl FromStr for AccountPublicKey {
type Err = CryptoError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let value = hex::decode(s)?;
AccountPublicKey::from_slice(value.as_slice())
}
}
impl Display for AccountPublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", hex::encode(self.as_bytes()))
}
}
impl TryFrom<&[u8]> for AccountSignature {
type Error = CryptoError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
AccountSignature::from_slice(bytes)
}
}
#[derive(Error, Debug)]
#[allow(missing_docs)]
pub enum CryptoError {
#[error("Signature for object {type_name} is not valid: {error}")]
InvalidSignature { error: String, type_name: String },
#[error("Signature from validator is missing")]
MissingValidatorSignature,
#[error(transparent)]
NonHexDigits(#[from] hex::FromHexError),
#[error(
"Byte slice has length {0} but a `CryptoHash` requires exactly {expected} bytes",
expected = FixedBytes::<32>::len_bytes(),
)]
IncorrectHashSize(usize),
#[error(
"Byte slice has length {len} but a {scheme} `PublicKey` requires exactly {expected} bytes"
)]
IncorrectPublicKeySize {
scheme: &'static str,
len: usize,
expected: usize,
},
#[error(
"byte slice has length {len} but a {scheme} `Signature` requires exactly {expected} bytes"
)]
IncorrectSignatureBytes {
scheme: &'static str,
len: usize,
expected: usize,
},
#[error("Could not parse integer: {0}")]
ParseIntError(#[from] ParseIntError),
#[error("secp256k1 error: {0}")]
Secp256k1Error(k256::ecdsa::Error),
#[error("could not parse public key: {0}: point at infinity")]
Secp256k1PointAtInfinity(String),
#[error("could not parse public key: {0}")]
PublicKeyParseError(bcs::Error),
#[error("could not parse signature: {0}")]
SignatureParseError(bcs::Error),
}
#[cfg(with_getrandom)]
pub trait CryptoRng: rand::CryptoRng + rand::RngCore + Send + Sync {}
#[cfg(with_getrandom)]
impl<T: rand::CryptoRng + rand::RngCore + Send + Sync> CryptoRng for T {}
#[cfg(with_getrandom)]
impl From<Option<u64>> for Box<dyn CryptoRng> {
fn from(seed: Option<u64>) -> Self {
use rand::SeedableRng;
match seed {
Some(seed) => Box::new(rand::rngs::StdRng::seed_from_u64(seed)),
None => Box::new(rand::rngs::OsRng),
}
}
}
pub trait Hashable<Hasher> {
fn write(&self, hasher: &mut Hasher);
}
pub trait HasTypeName {
fn type_name() -> &'static str;
}
pub trait BcsHashable<'de>: Serialize + Deserialize<'de> {}
pub trait BcsSignable<'de>: Serialize + Deserialize<'de> {}
impl<'de, T: BcsSignable<'de>> BcsHashable<'de> for T {}
impl<'de, T, Hasher> Hashable<Hasher> for T
where
T: BcsHashable<'de>,
Hasher: io::Write,
{
fn write(&self, hasher: &mut Hasher) {
let name = <Self as HasTypeName>::type_name();
write!(hasher, "{}::", name).expect("Hasher should not fail");
bcs::serialize_into(hasher, &self).expect("Message serialization should not fail");
}
}
impl<Hasher> Hashable<Hasher> for [u8]
where
Hasher: io::Write,
{
fn write(&self, hasher: &mut Hasher) {
hasher.write_all(self).expect("Hasher should not fail");
}
}
impl<'de, T> HasTypeName for T
where
T: BcsHashable<'de>,
{
fn type_name() -> &'static str {
serde_name::trace_name::<Self>().expect("Self must be a struct or an enum")
}
}
#[cfg(with_testing)]
#[derive(Debug, Serialize, Deserialize)]
pub struct TestString(pub String);
#[cfg(with_testing)]
impl TestString {
pub fn new(s: impl Into<String>) -> Self {
Self(s.into())
}
}
#[cfg(with_testing)]
impl BcsSignable<'_> for TestString {}
pub(crate) fn le_bytes_to_u64_array(bytes: &[u8]) -> [u64; 4] {
let mut integers = [0u64; 4];
integers[0] = u64::from_le_bytes(bytes[0..8].try_into().expect("incorrect indices"));
integers[1] = u64::from_le_bytes(bytes[8..16].try_into().expect("incorrect indices"));
integers[2] = u64::from_le_bytes(bytes[16..24].try_into().expect("incorrect indices"));
integers[3] = u64::from_le_bytes(bytes[24..32].try_into().expect("incorrect indices"));
integers
}
pub(crate) fn be_bytes_to_u64_array(bytes: &[u8]) -> [u64; 4] {
let mut integers = [0u64; 4];
integers[0] = u64::from_be_bytes(bytes[0..8].try_into().expect("incorrect indices"));
integers[1] = u64::from_be_bytes(bytes[8..16].try_into().expect("incorrect indices"));
integers[2] = u64::from_be_bytes(bytes[16..24].try_into().expect("incorrect indices"));
integers[3] = u64::from_be_bytes(bytes[24..32].try_into().expect("incorrect indices"));
integers
}
pub(crate) fn u64_array_to_le_bytes(integers: [u64; 4]) -> [u8; 32] {
let mut bytes = [0u8; 32];
bytes[0..8].copy_from_slice(&integers[0].to_le_bytes());
bytes[8..16].copy_from_slice(&integers[1].to_le_bytes());
bytes[16..24].copy_from_slice(&integers[2].to_le_bytes());
bytes[24..32].copy_from_slice(&integers[3].to_le_bytes());
bytes
}
pub(crate) fn u64_array_to_be_bytes(integers: [u64; 4]) -> [u8; 32] {
let mut bytes = [0u8; 32];
bytes[0..8].copy_from_slice(&integers[0].to_be_bytes());
bytes[8..16].copy_from_slice(&integers[1].to_be_bytes());
bytes[16..24].copy_from_slice(&integers[2].to_be_bytes());
bytes[24..32].copy_from_slice(&integers[3].to_be_bytes());
bytes
}
#[cfg(test)]
mod tests {
use super::*;
use crate::crypto::{ed25519::Ed25519SecretKey, secp256k1::Secp256k1KeyPair};
#[test]
fn test_u64_array_to_be_bytes() {
let input = [
0x0123456789ABCDEF,
0xFEDCBA9876543210,
0x0011223344556677,
0x8899AABBCCDDEEFF,
];
let expected_output = [
0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54,
0x32, 0x10, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB,
0xCC, 0xDD, 0xEE, 0xFF,
];
let output = u64_array_to_be_bytes(input);
assert_eq!(output, expected_output);
assert_eq!(input, be_bytes_to_u64_array(&u64_array_to_be_bytes(input)));
}
#[test]
fn test_u64_array_to_le_bytes() {
let input = [
0x0123456789ABCDEF,
0xFEDCBA9876543210,
0x0011223344556677,
0x8899AABBCCDDEEFF,
];
let expected_output = [
0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01, 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA,
0xDC, 0xFE, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC,
0xBB, 0xAA, 0x99, 0x88,
];
let output = u64_array_to_le_bytes(input);
assert_eq!(output, expected_output);
assert_eq!(input, le_bytes_to_u64_array(&u64_array_to_le_bytes(input)));
}
#[test]
fn roundtrip_account_pk_bytes_repr() {
fn roundtrip_test(secret: AccountSecretKey) {
let public = secret.public();
let bytes = public.as_bytes();
let parsed = AccountPublicKey::from_slice(&bytes).unwrap();
assert_eq!(public, parsed);
}
roundtrip_test(AccountSecretKey::Ed25519(Ed25519SecretKey::generate()));
roundtrip_test(AccountSecretKey::Secp256k1(
Secp256k1KeyPair::generate().secret_key,
));
}
#[test]
fn roundtrip_signature_bytes_repr() {
fn roundtrip_test(secret: AccountSecretKey) {
let test_string = TestString::new("test");
let signature = secret.sign(&test_string);
let bytes = signature.to_bytes();
let parsed = AccountSignature::from_slice(&bytes).unwrap();
assert_eq!(signature, parsed);
}
roundtrip_test(AccountSecretKey::Ed25519(Ed25519SecretKey::generate()));
roundtrip_test(AccountSecretKey::Secp256k1(
Secp256k1KeyPair::generate().secret_key,
));
}
#[test]
fn roundtrip_display_from_str_pk() {
fn test(secret: AccountSecretKey) {
let public = secret.public();
let display = public.to_string();
let parsed = AccountPublicKey::from_str(&display).unwrap();
assert_eq!(public, parsed);
}
test(AccountSecretKey::Ed25519(Ed25519SecretKey::generate()));
test(AccountSecretKey::Secp256k1(
Secp256k1KeyPair::generate().secret_key,
));
}
}