2021-03-05 15:46:20 -08:00
|
|
|
//! A minimal RedPallas implementation for use in Zcash.
|
2021-01-20 12:35:54 -08:00
|
|
|
|
2021-03-05 16:03:26 -08:00
|
|
|
use std::convert::{TryFrom, TryInto};
|
|
|
|
|
2021-04-14 21:33:15 -07:00
|
|
|
use pasta_curves::pallas;
|
2021-04-14 21:14:34 -07:00
|
|
|
use rand_7::{CryptoRng, RngCore};
|
2021-04-14 21:33:15 -07:00
|
|
|
|
2021-01-20 12:35:54 -08:00
|
|
|
/// A RedPallas signature type.
|
2021-03-05 15:46:20 -08:00
|
|
|
pub trait SigType: reddsa::SigType + private::Sealed {}
|
2021-01-20 12:35:54 -08:00
|
|
|
|
|
|
|
/// A type variable corresponding to an Orchard spend authorization signature.
|
2021-03-05 15:46:20 -08:00
|
|
|
pub type SpendAuth = reddsa::orchard::SpendAuth;
|
2021-01-20 12:35:54 -08:00
|
|
|
impl SigType for SpendAuth {}
|
|
|
|
|
|
|
|
/// A type variable corresponding to an Orchard binding signature.
|
2021-03-05 15:46:20 -08:00
|
|
|
pub type Binding = reddsa::orchard::Binding;
|
2021-01-20 12:35:54 -08:00
|
|
|
impl SigType for Binding {}
|
|
|
|
|
|
|
|
/// A RedPallas signing key.
|
|
|
|
#[derive(Debug)]
|
2021-04-27 06:49:49 -07:00
|
|
|
pub struct SigningKey<T: SigType>(pub(crate) reddsa::SigningKey<T>);
|
2021-01-20 12:35:54 -08:00
|
|
|
|
2021-03-05 16:03:26 -08:00
|
|
|
impl<T: SigType> From<SigningKey<T>> for [u8; 32] {
|
|
|
|
fn from(sk: SigningKey<T>) -> [u8; 32] {
|
|
|
|
sk.0.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: SigType> From<&SigningKey<T>> for [u8; 32] {
|
|
|
|
fn from(sk: &SigningKey<T>) -> [u8; 32] {
|
|
|
|
sk.0.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {
|
|
|
|
type Error = reddsa::Error;
|
|
|
|
|
|
|
|
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
|
|
|
|
bytes.try_into().map(SigningKey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-14 21:14:34 -07:00
|
|
|
impl<T: SigType> SigningKey<T> {
|
|
|
|
/// Creates a signature of type `T` on `msg` using this `SigningKey`.
|
|
|
|
pub fn sign<R: RngCore + CryptoRng>(&self, rng: R, msg: &[u8]) -> Signature<T> {
|
|
|
|
Signature(self.0.sign(rng, msg))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-20 12:35:54 -08:00
|
|
|
/// A RedPallas verification key.
|
2021-04-14 21:14:34 -07:00
|
|
|
#[derive(Clone, Debug)]
|
2021-03-05 15:46:20 -08:00
|
|
|
pub struct VerificationKey<T: SigType>(reddsa::VerificationKey<T>);
|
2021-01-20 12:35:54 -08:00
|
|
|
|
2021-03-05 16:03:26 -08:00
|
|
|
impl<T: SigType> From<VerificationKey<T>> for [u8; 32] {
|
|
|
|
fn from(vk: VerificationKey<T>) -> [u8; 32] {
|
|
|
|
vk.0.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: SigType> From<&VerificationKey<T>> for [u8; 32] {
|
|
|
|
fn from(vk: &VerificationKey<T>) -> [u8; 32] {
|
|
|
|
vk.0.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: SigType> TryFrom<[u8; 32]> for VerificationKey<T> {
|
|
|
|
type Error = reddsa::Error;
|
|
|
|
|
|
|
|
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
|
|
|
|
bytes.try_into().map(VerificationKey)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, T: SigType> From<&'a SigningKey<T>> for VerificationKey<T> {
|
|
|
|
fn from(sk: &'a SigningKey<T>) -> VerificationKey<T> {
|
|
|
|
VerificationKey((&sk.0).into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-14 21:13:41 -07:00
|
|
|
impl<T: SigType> PartialEq for VerificationKey<T> {
|
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
<[u8; 32]>::from(self).eq(&<[u8; 32]>::from(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-14 21:33:15 -07:00
|
|
|
impl VerificationKey<SpendAuth> {
|
|
|
|
/// Randomizes this verification key with the given `randomizer`.
|
|
|
|
///
|
|
|
|
/// Randomization is only supported for `SpendAuth` keys.
|
|
|
|
pub fn randomize(&self, randomizer: &pallas::Scalar) -> Self {
|
|
|
|
VerificationKey(self.0.randomize(randomizer))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-20 12:35:54 -08:00
|
|
|
/// A RedPallas signature.
|
|
|
|
#[derive(Debug)]
|
2021-03-05 15:46:20 -08:00
|
|
|
pub struct Signature<T: SigType>(reddsa::Signature<T>);
|
2021-01-20 12:35:54 -08:00
|
|
|
|
2021-04-21 08:57:48 -07:00
|
|
|
impl<T: SigType> From<[u8; 64]> for Signature<T> {
|
|
|
|
fn from(bytes: [u8; 64]) -> Self {
|
|
|
|
Signature(bytes.into())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-21 13:32:54 -07:00
|
|
|
impl<T: SigType> From<&Signature<T>> for [u8; 64] {
|
|
|
|
fn from(sig: &Signature<T>) -> Self {
|
|
|
|
sig.0.into()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-20 12:35:54 -08:00
|
|
|
pub(crate) mod private {
|
|
|
|
use super::{Binding, SpendAuth};
|
|
|
|
|
|
|
|
pub trait Sealed {}
|
|
|
|
|
|
|
|
impl Sealed for SpendAuth {}
|
|
|
|
|
|
|
|
impl Sealed for Binding {}
|
|
|
|
}
|
2021-04-27 06:49:49 -07:00
|
|
|
|
|
|
|
/// Generators for property testing.
|
|
|
|
#[cfg(any(test, feature = "test-dependencies"))]
|
|
|
|
pub mod testing {
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
|
|
|
use proptest::prelude::*;
|
|
|
|
|
|
|
|
use super::{Binding, SigningKey, SpendAuth, VerificationKey};
|
|
|
|
|
|
|
|
prop_compose! {
|
|
|
|
/// Generate a uniformly distributed nullifier value.
|
|
|
|
pub fn arb_spendauth_signing_key()(
|
|
|
|
sk in prop::array::uniform32(prop::num::u8::ANY)
|
|
|
|
.prop_map(reddsa::SigningKey::try_from)
|
|
|
|
.prop_filter("Values must be parseable as valid signing keys", |r| r.is_ok())
|
|
|
|
) -> SigningKey<SpendAuth> {
|
|
|
|
SigningKey(sk.unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prop_compose! {
|
|
|
|
/// Generate a uniformly distributed nullifier value.
|
|
|
|
pub fn arb_binding_signing_key()(
|
|
|
|
sk in prop::array::uniform32(prop::num::u8::ANY)
|
|
|
|
.prop_map(reddsa::SigningKey::try_from)
|
|
|
|
.prop_filter("Values must be parseable as valid signing keys", |r| r.is_ok())
|
|
|
|
) -> SigningKey<Binding> {
|
|
|
|
SigningKey(sk.unwrap())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prop_compose! {
|
|
|
|
/// Generate a uniformly distributed nullifier value.
|
|
|
|
pub fn arb_spendauth_verification_key()(sk in arb_spendauth_signing_key()) -> VerificationKey<SpendAuth> {
|
|
|
|
VerificationKey::from(&sk)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
prop_compose! {
|
|
|
|
/// Generate a uniformly distributed nullifier value.
|
|
|
|
pub fn arb_binding_verification_key()(sk in arb_binding_signing_key()) -> VerificationKey<Binding> {
|
|
|
|
VerificationKey::from(&sk)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|