use crate::{SchnorrPublicKey, ECPublicKey, tags, ECKeyBase, Signature};
use anyhow::bail;
use bc_ur::prelude::*;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum SigningPublicKey {
Schnorr(SchnorrPublicKey),
ECDSA(ECPublicKey),
}
impl SigningPublicKey {
pub fn from_schnorr(key: SchnorrPublicKey) -> Self {
Self::Schnorr(key)
}
pub fn from_ecdsa(key: ECPublicKey) -> Self {
Self::ECDSA(key)
}
pub fn schnorr(&self) -> Option<&SchnorrPublicKey> {
match self {
Self::Schnorr(key) => Some(key),
_ => None,
}
}
pub fn ecdsa(&self) -> Option<&ECPublicKey> {
match self {
Self::ECDSA(key) => Some(key),
_ => None,
}
}
pub fn verify(&self, signature: &Signature, message: impl AsRef<[u8]>) -> bool {
match self {
SigningPublicKey::Schnorr(key) => {
match signature {
Signature::Schnorr { sig, tag } => key.schnorr_verify(sig, message, tag),
Signature::ECDSA(_) => false,
}
},
SigningPublicKey::ECDSA(key) => {
match signature {
Signature::Schnorr { .. } => false,
Signature::ECDSA(sig) => key.verify(sig, message),
}
},
}
}
}
impl AsRef<SigningPublicKey> for SigningPublicKey {
fn as_ref(&self) -> &SigningPublicKey {
self
}
}
impl CBORTagged for SigningPublicKey {
fn cbor_tags() -> Vec<Tag> {
vec![tags::SIGNING_PUBLIC_KEY]
}
}
impl CBOREncodable for SigningPublicKey {
fn cbor(&self) -> CBOR {
self.tagged_cbor()
}
}
impl From<SigningPublicKey> for CBOR {
fn from(value: SigningPublicKey) -> Self {
value.cbor()
}
}
impl CBORTaggedEncodable for SigningPublicKey {
fn untagged_cbor(&self) -> CBOR {
match self {
SigningPublicKey::Schnorr(key) => {
CBOR::byte_string(key.data())
},
SigningPublicKey::ECDSA(key) => {
vec![
1.cbor(),
CBOR::byte_string(key.data()),
].cbor()
},
}
}
}
impl UREncodable for SigningPublicKey { }
impl CBORDecodable for SigningPublicKey {
fn from_cbor(cbor: &CBOR) -> anyhow::Result<Self> {
Self::from_tagged_cbor(cbor)
}
}
impl TryFrom<CBOR> for SigningPublicKey {
type Error = anyhow::Error;
fn try_from(cbor: CBOR) -> Result<Self, Self::Error> {
Self::from_cbor(&cbor)
}
}
impl TryFrom<&CBOR> for SigningPublicKey {
type Error = anyhow::Error;
fn try_from(cbor: &CBOR) -> Result<Self, Self::Error> {
Self::from_cbor(cbor)
}
}
impl CBORTaggedDecodable for SigningPublicKey {
fn from_untagged_cbor(untagged_cbor: &CBOR) -> anyhow::Result<Self> {
match untagged_cbor.case() {
CBORCase::ByteString(data) => {
Ok(Self::Schnorr(SchnorrPublicKey::from_data_ref(data)?))
},
CBORCase::Array(elements) => {
if elements.len() == 2 {
if let CBORCase::Unsigned(1) = &elements[0].case() {
if let Some(data) = CBOR::as_byte_string(&elements[1]) {
return Ok(Self::ECDSA(ECPublicKey::from_data_ref(&data)?));
}
}
}
bail!("invalid ECDSA public key");
},
_ => bail!("invalid ECDSA public key"),
}
}
}
impl URDecodable for SigningPublicKey { }
impl URCodable for SigningPublicKey { }