use p256::ecdsa::VerifyingKey;
use crate::errors::EnclaveEncryptError;
pub const TURNKEY_PRODUCTION_SIGNER_QUORUM_PUBLIC_KEY: &str = "04ca7c0d624c75de6f34af342e87a21e0d8c83efd1bd5b5da0c0177c147f744fba6f01f9f37356f9c617659aafa55f6e0af8d169a8f054d153ab3201901fb63ecb04cf288fe433cc4e1aa0ce1632feac4ea26bf2f5a09dcfe5a42c398e06898710330f0572882f4dbdf0f5304b8fc8703acd69adca9a4bbf7f5d00d20a5e364b2569";
pub const TURNKEY_PREPROD_SIGNER_QUORUM_PUBLIC_KEY: &str = "048e92f6cdcc0b375505980a298d9b79201db1f08b1f135360d2864af1a67186ec0dbeb570d396a456226b0844be93dbc0180abbf7e2e4c9cfde8d5da4e3f8a49004f3422b8afbe425d6ece77b8d2469954715a2ff273ab7ac89f1ed70e0a9325eaa1698b4351fd1b23734e65c0b6a86b62dd49d70b37c94606aac402cbd84353212";
pub const QUORUM_PUBLIC_KEY_BYTE_LENGTH: usize = 130;
#[derive(Debug, PartialEq, Eq)]
pub struct QuorumPublicKey {
bytes: Vec<u8>,
}
impl QuorumPublicKey {
pub fn from_bytes<B: AsRef<[u8]>>(b: B) -> Result<Self, EnclaveEncryptError> {
if b.as_ref().len() != QUORUM_PUBLIC_KEY_BYTE_LENGTH {
return Err(EnclaveEncryptError::IncorrectQuorumPublicKeyBytesLength(
b.as_ref().len(),
));
}
Ok(Self {
bytes: b.as_ref().to_vec(),
})
}
pub fn from_string<S: AsRef<str>>(s: S) -> Result<Self, EnclaveEncryptError> {
let b =
hex::decode(s.as_ref()).map_err(|e| EnclaveEncryptError::HexDecode(e.to_string()))?;
Self::from_bytes(b)
}
#[must_use]
pub fn production_signer() -> Self {
Self::from_string(TURNKEY_PRODUCTION_SIGNER_QUORUM_PUBLIC_KEY)
.expect("static public key should be valid")
}
#[must_use]
pub fn preprod_signer() -> Self {
Self::from_string(TURNKEY_PREPROD_SIGNER_QUORUM_PUBLIC_KEY)
.expect("static public key should be valid")
}
pub fn verifying_key(&self) -> Result<VerifyingKey, EnclaveEncryptError> {
VerifyingKey::from_sec1_bytes(&self.bytes[65..])
.map_err(|_| EnclaveEncryptError::InvalidVerifyingKeyBytes)
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn from_bytes_and_from_str_valid() {
let prod_pub1 = QuorumPublicKey::from_bytes(
hex::decode(TURNKEY_PRODUCTION_SIGNER_QUORUM_PUBLIC_KEY).unwrap(),
)
.unwrap();
let prod_pub2 =
QuorumPublicKey::from_string(TURNKEY_PRODUCTION_SIGNER_QUORUM_PUBLIC_KEY).unwrap();
let prod_pub3 = QuorumPublicKey::production_signer();
assert!(prod_pub1.verifying_key().is_ok());
assert_eq!(prod_pub1, prod_pub2);
assert_eq!(prod_pub2, prod_pub3);
let preprod_pub1 = QuorumPublicKey::from_bytes(
hex::decode(TURNKEY_PREPROD_SIGNER_QUORUM_PUBLIC_KEY).unwrap(),
)
.unwrap();
let preprod_pub2 =
QuorumPublicKey::from_string(TURNKEY_PREPROD_SIGNER_QUORUM_PUBLIC_KEY).unwrap();
let preprod_pub3 = QuorumPublicKey::preprod_signer();
assert!(preprod_pub1.verifying_key().is_ok());
assert_eq!(preprod_pub1, preprod_pub2);
assert_eq!(preprod_pub2, preprod_pub3);
}
#[test]
fn from_bytes_invalid_length() {
let bytes = vec![0u8; 64]; assert_eq!(
QuorumPublicKey::from_bytes(&bytes).unwrap_err(),
EnclaveEncryptError::IncorrectQuorumPublicKeyBytesLength(64)
);
}
#[test]
fn from_str_valid() {
const VALID_HEX_KEY: &str = concat!(
"04", "aabbccddeeff00112233445566778899aabbccddeeff00112233445566778899", "99887766554433221100ffeeddccbbaa99887766554433221100ffeeddccbbaa", "04", "11223344556677889900aabbccddeeff11223344556677889900aabbccddeeff", "ffeeddccbbaa00998877665544332211ffeeddccbbaa00998877665544332211" );
let quorum_pub = QuorumPublicKey::from_string(VALID_HEX_KEY).unwrap();
assert_eq!(
quorum_pub.verifying_key().unwrap_err(),
EnclaveEncryptError::InvalidVerifyingKeyBytes
);
}
#[test]
fn from_str_invalid_hex() {
assert_eq!(
QuorumPublicKey::from_string("not hex!").unwrap_err(),
EnclaveEncryptError::HexDecode("Invalid character 'n' at position 0".to_string()),
);
}
}