// -*- mode: rust; -*- // // This file is part of reddsa. // Copyright (c) 2019-2021 Zcash Foundation // See LICENSE for licensing information. // // Authors: // - Deirdre Connolly // - Henry de Valence use core::{ convert::{TryFrom, TryInto}, marker::PhantomData, }; use crate::{ private::SealedScalar, Error, Randomizer, SigType, Signature, SpendAuth, VerificationKey, }; use group::{ff::PrimeField, GroupEncoding}; use rand_core::{CryptoRng, RngCore}; /// A RedDSA signing key. #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(try_from = "SerdeHelper"))] #[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))] #[cfg_attr(feature = "serde", serde(bound = "T: SigType"))] pub struct SigningKey { sk: T::Scalar, pk: VerificationKey, } impl From<&SigningKey> for VerificationKey { fn from(sk: &SigningKey) -> VerificationKey { sk.pk } } impl From> for [u8; 32] { fn from(sk: SigningKey) -> [u8; 32] { sk.sk.to_repr().as_ref().try_into().unwrap() } } impl TryFrom<[u8; 32]> for SigningKey { type Error = Error; fn try_from(bytes: [u8; 32]) -> Result { // XXX-jubjub: this should not use CtOption let mut repr = ::Repr::default(); repr.as_mut().copy_from_slice(&bytes); let maybe_sk = T::Scalar::from_repr(repr); if maybe_sk.is_some().into() { let sk = maybe_sk.unwrap(); let pk = VerificationKey::from(&sk); Ok(SigningKey { sk, pk }) } else { Err(Error::MalformedSigningKey) } } } #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] struct SerdeHelper([u8; 32]); impl TryFrom for SigningKey { type Error = Error; fn try_from(helper: SerdeHelper) -> Result { helper.0.try_into() } } impl From> for SerdeHelper { fn from(sk: SigningKey) -> Self { Self(sk.into()) } } impl SigningKey { /// Randomize this public key with the given `randomizer`. pub fn randomize(&self, randomizer: &Randomizer) -> SigningKey { let sk = self.sk + randomizer; let pk = VerificationKey::from(&sk); SigningKey { sk, pk } } } impl SigningKey { /// Generate a new signing key. pub fn new(mut rng: R) -> SigningKey { let sk = { let mut bytes = [0; 64]; rng.fill_bytes(&mut bytes); T::Scalar::from_bytes_wide(&bytes) }; let pk = VerificationKey::from(&sk); SigningKey { sk, pk } } /// Create a signature of type `T` on `msg` using this `SigningKey`. // Similar to signature::Signer but without boxed errors. pub fn sign(&self, mut rng: R, msg: &[u8]) -> Signature { use crate::HStar; // Choose a byte sequence uniformly at random of length // (\ell_H + 128)/8 bytes. For RedJubjub and RedPallas this is // (512 + 128)/8 = 80. let random_bytes = { let mut bytes = [0; 80]; rng.fill_bytes(&mut bytes); bytes }; let nonce = HStar::::default() .update(&random_bytes[..]) .update(&self.pk.bytes.bytes[..]) // XXX ugly .update(msg) .finalize(); let r: T::Point = T::basepoint() * nonce; let r_bytes: [u8; 32] = r.to_bytes().as_ref().try_into().unwrap(); let c = HStar::::default() .update(&r_bytes[..]) .update(&self.pk.bytes.bytes[..]) // XXX ugly .update(msg) .finalize(); let s = nonce + (c * self.sk); let s_bytes = s.to_repr().as_ref().try_into().unwrap(); Signature { r_bytes, s_bytes, _marker: PhantomData, } } }