use crate::*;
use elliptic_curve::Group;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Signature {
pub(crate) r: CompressedEdwardsY,
pub(crate) s: [u8; 57],
}
impl Default for Signature {
fn default() -> Self {
Self {
r: CompressedEdwardsY::default(),
s: [0u8; 57],
}
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl TryFrom<Vec<u8>> for Signature {
type Error = SigningError;
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(value.as_slice())
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl TryFrom<&Vec<u8>> for Signature {
type Error = SigningError;
fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
Self::try_from(value.as_slice())
}
}
impl TryFrom<&[u8]> for Signature {
type Error = SigningError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() != SIGNATURE_LENGTH {
return Err(SigningError::InvalidSignatureLength);
}
let mut bytes = [0u8; SIGNATURE_LENGTH];
bytes.copy_from_slice(value);
Self::from_bytes(&bytes)
}
}
#[cfg(any(feature = "alloc", feature = "std"))]
impl TryFrom<Box<[u8]>> for Signature {
type Error = SigningError;
fn try_from(value: Box<[u8]>) -> Result<Self, Self::Error> {
Self::try_from(value.as_ref())
}
}
#[cfg(feature = "serde")]
impl serdect::serde::Serialize for Signature {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: serdect::serde::Serializer,
{
serdect::array::serialize_hex_lower_or_bin(&self.to_bytes(), s)
}
}
#[cfg(feature = "serde")]
impl<'de> serdect::serde::Deserialize<'de> for Signature {
fn deserialize<D>(d: D) -> Result<Self, D::Error>
where
D: serdect::serde::Deserializer<'de>,
{
let mut bytes = [0u8; SIGNATURE_LENGTH];
serdect::array::deserialize_hex_or_bin(&mut bytes, d)?;
Signature::from_bytes(&bytes).map_err(serdect::serde::de::Error::custom)
}
}
impl Signature {
pub fn to_bytes(&self) -> [u8; SIGNATURE_LENGTH] {
let mut bytes = [0u8; SIGNATURE_LENGTH];
bytes[..57].copy_from_slice(self.r.as_bytes());
bytes[57..].copy_from_slice(&self.s);
bytes
}
pub fn from_bytes(bytes: &[u8; SIGNATURE_LENGTH]) -> Result<Self, SigningError> {
let mut r = [0u8; SECRET_KEY_LENGTH];
r.copy_from_slice(&bytes[..SECRET_KEY_LENGTH]);
let mut s = [0u8; SECRET_KEY_LENGTH];
s.copy_from_slice(&bytes[SECRET_KEY_LENGTH..]);
let r = CompressedEdwardsY(r);
let big_r = r.decompress();
if big_r.is_none().into() {
return Err(SigningError::InvalidSignatureRComponent);
}
let big_r = big_r.expect("big_r is not none");
if big_r.is_identity().into() {
return Err(SigningError::InvalidSignatureRComponent);
}
if s[56] != 0x00 {
return Err(SigningError::InvalidSignatureSComponent);
}
let s_bytes = ScalarBytes::from(s);
let ss = Scalar::from_canonical_bytes(&s_bytes);
if ss.is_none().into() {
return Err(SigningError::InvalidSignatureSComponent);
}
let sc = ss.expect("ss is not none");
if sc.is_zero().into() {
return Err(SigningError::InvalidSignatureSComponent);
}
Ok(Self { r, s })
}
pub fn r(&self) -> CompressedEdwardsY {
self.r
}
pub fn s(&self) -> &[u8; SECRET_KEY_LENGTH] {
&self.s
}
}
impl From<InnerSignature> for Signature {
fn from(inner: InnerSignature) -> Self {
let mut s = [0u8; SECRET_KEY_LENGTH];
s.copy_from_slice(&inner.s.to_bytes_rfc_8032());
Self {
r: inner.r.compress(),
s,
}
}
}
impl TryFrom<Signature> for InnerSignature {
type Error = SigningError;
fn try_from(signature: Signature) -> Result<Self, Self::Error> {
let s_bytes = ScalarBytes::from_slice(&signature.s[..]);
let s = Option::from(Scalar::from_canonical_bytes(s_bytes))
.ok_or(SigningError::InvalidSignatureSComponent)?;
let r = Option::from(signature.r.decompress())
.ok_or(SigningError::InvalidSignatureRComponent)?;
Ok(Self { r, s })
}
}
pub(crate) struct InnerSignature {
pub(crate) r: EdwardsPoint,
pub(crate) s: Scalar,
}
#[cfg(feature = "serde")]
#[test]
fn serialization() {
use rand_chacha::ChaCha8Rng;
use rand_core::SeedableRng;
let mut rng = ChaCha8Rng::from_seed([0u8; 32]);
let signing_key = super::SigningKey::generate(&mut rng);
let signature = signing_key.sign_raw(b"Hello, World!");
let bytes = serde_bare::to_vec(&signature).unwrap();
let signature2: Signature = serde_bare::from_slice(&bytes).unwrap();
assert_eq!(signature, signature2);
let string = serde_json::to_string(&signature).unwrap();
let signature3: Signature = serde_json::from_str(&string).unwrap();
assert_eq!(signature, signature3);
}