bc_components/
signing_public_key.rsuse crate::{ tags, ECKeyBase, ECPublicKey, Ed25519PublicKey, SchnorrPublicKey, Signature, Verifier };
use anyhow::{ bail, Result, Error };
use bc_ur::prelude::*;
use ssh_key::public::PublicKey as SSHPublicKey;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum SigningPublicKey {
Schnorr(SchnorrPublicKey),
ECDSA(ECPublicKey),
Ed25519(Ed25519PublicKey),
SSH(SSHPublicKey),
}
impl SigningPublicKey {
pub fn from_schnorr(key: SchnorrPublicKey) -> Self {
Self::Schnorr(key)
}
pub fn from_ecdsa(key: ECPublicKey) -> Self {
Self::ECDSA(key)
}
pub fn from_ed25519(key: Ed25519PublicKey) -> Self {
Self::Ed25519(key)
}
pub fn from_ssh(key: SSHPublicKey) -> Self {
Self::SSH(key)
}
pub fn to_schnorr(&self) -> Option<&SchnorrPublicKey> {
match self {
Self::Schnorr(key) => Some(key),
_ => None,
}
}
pub fn to_ecdsa(&self) -> Option<&ECPublicKey> {
match self {
Self::ECDSA(key) => Some(key),
_ => None,
}
}
pub fn to_ssh(&self) -> Option<&SSHPublicKey> {
match self {
Self::SSH(key) => Some(key),
_ => None,
}
}
}
impl Verifier for SigningPublicKey {
fn verify(&self, signature: &Signature, message: &dyn AsRef<[u8]>) -> bool {
match self {
SigningPublicKey::Schnorr(key) => {
match signature {
Signature::Schnorr(sig) => key.schnorr_verify::<_, &[u8]>(sig, message),
_ => false,
}
}
SigningPublicKey::ECDSA(key) => {
match signature {
Signature::ECDSA(sig) => key.verify(sig, message),
_ => false,
}
}
SigningPublicKey::Ed25519(key) => {
match signature {
Signature::Ed25519(sig) => key.verify(sig, message),
_ => false,
}
}
SigningPublicKey::SSH(key) => {
match signature {
Signature::SSH(sig) =>
key.verify(sig.namespace(), message.as_ref(), sig).is_ok(),
_ => false,
}
}
}
}
}
impl AsRef<SigningPublicKey> for SigningPublicKey {
fn as_ref(&self) -> &SigningPublicKey {
self
}
}
impl CBORTagged for SigningPublicKey {
fn cbor_tags() -> Vec<Tag> {
tags_for_values(&[tags::TAG_SIGNING_PUBLIC_KEY])
}
}
impl From<SigningPublicKey> for CBOR {
fn from(value: SigningPublicKey) -> Self {
value.tagged_cbor()
}
}
impl CBORTaggedEncodable for SigningPublicKey {
fn untagged_cbor(&self) -> CBOR {
match self {
SigningPublicKey::Schnorr(key) => { CBOR::to_byte_string(key.data()) }
SigningPublicKey::ECDSA(key) => {
vec![(1).into(), CBOR::to_byte_string(key.data())].into()
}
SigningPublicKey::Ed25519(key) => {
vec![(2).into(), CBOR::to_byte_string(key.data())].into()
}
SigningPublicKey::SSH(key) => {
let string = key.to_openssh().unwrap();
CBOR::to_tagged_value(tags::TAG_SSH_TEXT_PUBLIC_KEY, string)
}
}
}
}
impl TryFrom<CBOR> for SigningPublicKey {
type Error = Error;
fn try_from(cbor: CBOR) -> Result<Self, Self::Error> {
Self::from_tagged_cbor(cbor)
}
}
impl CBORTaggedDecodable for SigningPublicKey {
fn from_untagged_cbor(untagged_cbor: CBOR) -> Result<Self> {
match untagged_cbor.into_case() {
CBORCase::ByteString(data) => {
Ok(Self::Schnorr(SchnorrPublicKey::from_data_ref(data)?))
}
CBORCase::Array(mut elements) => {
if elements.len() == 2 {
let mut drain = elements.drain(0..);
let ele_0 = drain.next().unwrap().into_case();
let ele_1 = drain.next().unwrap().into_case();
if let CBORCase::Unsigned(1) = ele_0 {
if let CBORCase::ByteString(data) = ele_1 {
return Ok(Self::ECDSA(ECPublicKey::from_data_ref(data)?));
}
} else if let CBORCase::Unsigned(2) = ele_0 {
if let CBORCase::ByteString(data) = ele_1 {
return Ok(Self::Ed25519(Ed25519PublicKey::from_data_ref(data)?));
}
}
}
bail!("invalid signing public key");
}
CBORCase::Tagged(tag, item) => {
if tag.value() == tags::TAG_SSH_TEXT_PUBLIC_KEY {
let string = item.try_into_text()?;
let key = SSHPublicKey::from_openssh(&string)?;
return Ok(Self::SSH(key));
}
bail!("invalid signing public key");
}
_ => bail!("invalid signing public key"),
}
}
}