use crate::BinaryHashRepr;
use k256::schnorr;
#[cfg(feature = "proptest")]
use proptest::arbitrary::Arbitrary;
use rand::distributions::{Distribution, Standard};
use rand::rngs::OsRng;
use rand::{CryptoRng, Rng};
use serde::{Deserialize, Serialize};
use serialize::{Deserializable, Serializable, Tagged, VecExt, tag_enforcement_test};
#[cfg(feature = "proptest")]
use serialize::{NoStrategy, simple_arbitrary};
use signature::{RandomizedSigner, Verifier};
use std::borrow::Cow;
use std::cmp::Ordering;
use std::fmt::{self, Debug, Formatter};
use std::hash::Hash;
use std::io::{self, Read, Write};
#[cfg(feature = "proptest")]
use std::marker::PhantomData;
macro_rules! derive_via_to_bytes {
($ty:ty) => {
impl Hash for $ty {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
state.write(&self.0.to_bytes()[..]);
}
}
impl PartialOrd for $ty {
fn partial_cmp(&self, other: &$ty) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for $ty {
fn cmp(&self, other: &$ty) -> Ordering {
let left = self.0.to_bytes();
let right = other.0.to_bytes();
left.cmp(&right)
}
}
};
}
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct VerifyingKey(schnorr::VerifyingKey);
derive_via_to_bytes!(VerifyingKey);
impl Default for VerifyingKey {
fn default() -> Self {
VerifyingKey(
schnorr::VerifyingKey::from_bytes(&[
43, 59, 242, 191, 89, 80, 243, 46, 116, 47, 12, 103, 140, 35, 90, 207, 180, 68,
188, 10, 108, 126, 200, 195, 239, 14, 120, 114, 89, 188, 199, 38,
])
.expect("static verifier key should be valid"),
)
}
}
impl Debug for VerifyingKey {
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
write!(formatter, "<signature verifying key>")
}
}
impl BinaryHashRepr for VerifyingKey {
fn binary_repr<W: crate::MemWrite<u8>>(&self, writer: &mut W) {
writer.write(&self.0.to_bytes());
}
fn binary_len(&self) -> usize {
self.0.to_bytes().len()
}
}
#[cfg(feature = "proptest")]
simple_arbitrary!(VerifyingKey);
#[cfg(feature = "proptest")]
serialize::randomised_serialization_test!(VerifyingKey);
impl Distribution<VerifyingKey> for Standard {
fn sample<R: Rng + ?Sized>(&self, _rng: &mut R) -> VerifyingKey {
SigningKey::sample(OsRng).verifying_key()
}
}
impl Tagged for VerifyingKey {
fn tag() -> Cow<'static, str> {
Cow::Borrowed("signature-verifying-key[v1]")
}
fn tag_unique_factor() -> String {
"signature-verifying-key[v1]".into()
}
}
tag_enforcement_test!(VerifyingKey);
impl Serializable for VerifyingKey {
fn serialize(&self, writer: &mut impl Write) -> io::Result<()> {
writer.write_all(&self.0.to_bytes())
}
fn serialized_size(&self) -> usize {
32
}
}
impl Deserializable for VerifyingKey {
fn deserialize(reader: &mut impl Read, _recursion_depth: u32) -> io::Result<Self> {
let mut bytes = [0u8; 32];
reader.read_exact(&mut bytes)?;
Ok(VerifyingKey(
schnorr::VerifyingKey::from_bytes(&bytes).map_err(|_| {
io::Error::new(
io::ErrorKind::InvalidData,
"Malformed Schnorr verifying key",
)
})?,
))
}
}
impl VerifyingKey {
pub fn verify(&self, msg: &[u8], signature: &Signature) -> bool {
matches!(self.0.verify(msg, &signature.0), Ok(()))
}
}
#[derive(Clone)]
pub struct SigningKey(schnorr::SigningKey);
impl Tagged for SigningKey {
fn tag() -> Cow<'static, str> {
Cow::Borrowed("signing-key[v1]")
}
fn tag_unique_factor() -> String {
"signing-key[v1]".into()
}
}
tag_enforcement_test!(SigningKey);
impl SigningKey {
pub fn sample<R: Rng + CryptoRng>(mut rng: R) -> Self {
SigningKey(schnorr::SigningKey::random(&mut rng))
}
pub fn verifying_key(&self) -> VerifyingKey {
VerifyingKey(*self.0.verifying_key())
}
pub fn sign<R: Rng + CryptoRng>(&self, rng: &mut R, msg: &[u8]) -> Signature {
Signature(self.0.sign_with_rng(rng, msg))
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Box<dyn std::error::Error>> {
let signing_key = schnorr::SigningKey::from_bytes(bytes)?;
Ok(SigningKey(signing_key))
}
}
impl Debug for SigningKey {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<secret key>")
}
}
impl Serializable for SigningKey {
fn serialize(&self, writer: &mut impl Write) -> io::Result<()> {
writer.write_all(&self.0.to_bytes())
}
fn serialized_size(&self) -> usize {
32
}
}
impl Deserializable for SigningKey {
fn deserialize(reader: &mut impl Read, _recursion_depth: u32) -> io::Result<Self> {
let mut bytes = [0u8; 32];
reader.read_exact(&mut bytes)?;
Ok(SigningKey(
schnorr::SigningKey::from_bytes(&bytes).map_err(|_| {
io::Error::new(io::ErrorKind::InvalidData, "Malformed Schnorr signing key")
})?,
))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Signature(schnorr::Signature);
derive_via_to_bytes!(Signature);
impl Default for Signature {
fn default() -> Signature {
Signature(
schnorr::Signature::try_from(
&[
20, 137, 89, 240, 159, 41, 72, 199, 212, 53, 117, 4, 235, 179, 101, 207, 210,
224, 132, 10, 131, 224, 89, 19, 152, 194, 235, 130, 162, 57, 186, 40, 103, 85,
94, 192, 157, 17, 70, 102, 209, 27, 62, 153, 67, 246, 158, 17, 124, 18, 63,
245, 208, 254, 72, 95, 157, 235, 180, 156, 164, 66, 143, 251,
][..],
)
.expect("static signature should be valid"),
)
}
}
#[cfg(feature = "proptest")]
simple_arbitrary!(Signature);
#[cfg(feature = "proptest")]
serialize::randomised_serialization_test!(Signature);
impl Distribution<Signature> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Signature {
let signing_key = SigningKey::sample(OsRng);
let mut message = Vec::with_bounded_capacity(32);
rng.fill_bytes(&mut message);
signing_key.sign(&mut OsRng, &message)
}
}
impl Tagged for Signature {
fn tag() -> Cow<'static, str> {
Cow::Borrowed("signature[v1]")
}
fn tag_unique_factor() -> String {
"signature[v1]".into()
}
}
tag_enforcement_test!(Signature);
impl Serializable for Signature {
fn serialize(&self, writer: &mut impl Write) -> io::Result<()> {
writer.write_all(&self.0.to_bytes())
}
fn serialized_size(&self) -> usize {
schnorr::Signature::BYTE_SIZE
}
}
impl Deserializable for Signature {
fn deserialize(reader: &mut impl Read, _recursion_depth: u32) -> io::Result<Self> {
let mut bytes = [0u8; 64];
reader.read_exact(&mut bytes)?;
Ok(Signature(
schnorr::Signature::try_from(&bytes[..]).map_err(|_| {
io::Error::new(io::ErrorKind::InvalidData, "Malformed Schnorr signature")
})?,
))
}
}