From 6ca14abeec422dee45bf619100e4b945a4b4b70e Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 3 Dec 2019 12:22:35 -0800 Subject: [PATCH] Make the signature type be a type parameter. This means that using a BindingSig as a SpendAuthSig or vice versa becomes a compile error. Internally, we can share implementations, but having type parameters and specialized impls means that the correct parameters can be substituted in to whatever inner functions exist. --- src/lib.rs | 28 +++++++++++++++++++++ src/public_key.rs | 60 ++++++++++++++++++++++++++++---------------- src/secret_key.rs | 64 +++++++++++++++++++++++++++++------------------ src/signature.rs | 45 ++++++++++++++++++++------------- 4 files changed, 134 insertions(+), 63 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fe58798..011ed63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,34 @@ pub use public_key::{PublicKey, PublicKeyBytes}; pub use secret_key::{SecretKey, SecretKeyBytes}; pub use signature::Signature; +/// Abstracts over different RedJubJub parameter choices. +/// +/// As described [at the end of ยง5.4.6][concretereddsa] of the Zcash +/// protocol specification, the generator used in RedJubjub is left as +/// an unspecified parameter, chosen differently for each of +/// `BindingSig` and `SpendAuthSig`. +/// +/// To handle this, we encode the parameter choice as a genuine type +/// parameter. +/// +/// [concretereddsa]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa +pub trait SigType: private::Sealed {} + +/// A type variable corresponding to Zcash's `BindingSig`. +pub struct Binding {} +impl SigType for Binding {} + +/// A type variable corresponding to Zcash's `SpendAuthSig`. +pub struct SpendAuth {} +impl SigType for SpendAuth {} + +mod private { + use super::*; + pub trait Sealed {} + impl Sealed for Binding {} + impl Sealed for SpendAuth {} +} + #[cfg(test)] mod tests { #[test] diff --git a/src/public_key.rs b/src/public_key.rs index 3f7aed9..42ba6a7 100644 --- a/src/public_key.rs +++ b/src/public_key.rs @@ -1,54 +1,70 @@ -use std::convert::TryFrom; +use std::{convert::TryFrom, marker::PhantomData}; -use crate::{Error, Randomizer, Signature}; +use crate::{Error, SigType, SpendAuth, Binding, Randomizer, Signature}; /// A refinement type indicating that the inner `[u8; 32]` represents an /// encoding of a RedJubJub public key. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct PublicKeyBytes(pub [u8; 32]); +pub struct PublicKeyBytes { + bytes: [u8; 32], + _marker: PhantomData, +} -impl From<[u8; 32]> for PublicKeyBytes { - fn from(raw: [u8; 32]) -> PublicKeyBytes { - PublicKeyBytes(raw) +impl From<[u8; 32]> for PublicKeyBytes { + fn from(bytes: [u8; 32]) -> PublicKeyBytes { + PublicKeyBytes { bytes, _marker: PhantomData } } } -impl From for [u8; 32] { - fn from(refined: PublicKeyBytes) -> [u8; 32] { - refined.0 +impl From> for [u8; 32] { + fn from(refined: PublicKeyBytes) -> [u8; 32] { + refined.bytes } } /// A RedJubJub public key. // XXX PartialEq, Eq? #[derive(Copy, Clone, Debug)] -pub struct PublicKey { +pub struct PublicKey { // fields + _marker: PhantomData, } -impl From for PublicKeyBytes { - fn from(pk: PublicKey) -> PublicKeyBytes { +impl From> for PublicKeyBytes { + fn from(pk: PublicKey) -> PublicKeyBytes { unimplemented!(); } } -impl TryFrom for PublicKey { +impl TryFrom> for PublicKey { type Error = Error; - fn try_from(bytes: PublicKeyBytes) -> Result { + fn try_from(bytes: PublicKeyBytes) -> Result { unimplemented!(); } } -impl PublicKey { +impl PublicKey { /// Randomize this public key with the given `randomizer`. - pub fn randomize(&self, randomizer: Randomizer) -> PublicKey { - unimplemented!(); - } - - /// Verify a supposed `signature` over `msg` made by this public key. - // This is similar to impl signature::Verifier but without boxed errors - pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> { + pub fn randomize(&self, randomizer: Randomizer) -> PublicKey { + unimplemented!(); + } +} + +impl PublicKey { + /// Verify a Zcash `BindingSig` over `msg` made by this public key. + // This is similar to impl signature::Verifier but without boxed errors + pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> { + // this lets us specialize the basepoint parameter, could call a verify_inner + unimplemented!(); + } +} + +impl PublicKey { + /// Verify a Zcash `SpendAuthSig` over `msg` made by this public key. + // This is similar to impl signature::Verifier but without boxed errors + pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> { + // this lets us specialize the basepoint parameter, could call a verify_inner unimplemented!(); } } diff --git a/src/secret_key.rs b/src/secret_key.rs index 637fc11..304743e 100644 --- a/src/secret_key.rs +++ b/src/secret_key.rs @@ -1,61 +1,77 @@ -use std::convert::TryFrom; +use std::{convert::TryFrom, marker::PhantomData}; -use crate::{Error, Randomizer, PublicKey, Signature}; +use crate::{Error, PublicKey, SigType, Binding, SpendAuth, Randomizer, Signature}; /// A refinement type indicating that the inner `[u8; 32]` represents an /// encoding of a RedJubJub secret key. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct SecretKeyBytes(pub [u8; 32]); +pub struct SecretKeyBytes { + bytes: [u8; 32], + _marker: PhantomData, +} -impl From<[u8; 32]> for SecretKeyBytes { - fn from(raw: [u8; 32]) -> SecretKeyBytes { - SecretKeyBytes(raw) +impl From<[u8; 32]> for SecretKeyBytes { + fn from(bytes: [u8; 32]) -> SecretKeyBytes { + SecretKeyBytes{ bytes, _marker: PhantomData } } } -impl From for [u8; 32] { - fn from(refined: SecretKeyBytes) -> [u8; 32] { - refined.0 +impl From> for [u8; 32] { + fn from(refined: SecretKeyBytes) -> [u8; 32] { + refined.bytes } } /// A RedJubJub secret key. // XXX PartialEq, Eq? #[derive(Copy, Clone, Debug)] -pub struct SecretKey { +pub struct SecretKey { // fields + _marker: PhantomData, } -impl From for SecretKeyBytes { - fn from(pk: SecretKey) -> SecretKeyBytes { +impl From> for SecretKeyBytes { + fn from(pk: SecretKey) -> SecretKeyBytes { unimplemented!(); } } // XXX could this be a From impl? -impl TryFrom for SecretKey { +impl TryFrom> for SecretKey { type Error = Error; - fn try_from(bytes: SecretKeyBytes) -> Result { + fn try_from(bytes: SecretKeyBytes) -> Result { unimplemented!(); } } -impl<'a> From<&'a SecretKey> for PublicKey { - fn from(sk: &'a SecretKey) -> PublicKey { +impl<'a, T: SigType> From<&'a SecretKey> for PublicKey { + fn from(sk: &'a SecretKey) -> PublicKey { unimplemented!(); } } -impl SecretKey { +impl SecretKey { /// Randomize this public key with the given `randomizer`. - pub fn randomize(&self, randomizer: Randomizer) -> PublicKey { - unimplemented!(); - } - - /// Sign the given `msg` with this `SecretKey`. - // Similar to signature::Signer but without boxed errors. - pub fn sign(&self, msg: &[u8]) -> Signature { + pub fn randomize(&self, randomizer: Randomizer) -> PublicKey { + unimplemented!(); + } +} + +impl SecretKey { + /// Create a Zcash `BindingSig` on `msg` using this `SecretKey`. + // Similar to signature::Signer but without boxed errors. + pub fn sign(&self, msg: &[u8]) -> Signature { + // could use sign_inner + unimplemented!(); + } +} + +impl SecretKey { + /// Create a Zcash `SpendAuthSig` on `msg` using this `SecretKey`. + // Similar to signature::Signer but without boxed errors. + pub fn sign(&self, msg: &[u8]) -> Signature { + // could use sign_inner unimplemented!(); } } diff --git a/src/signature.rs b/src/signature.rs index 8042fee..0429113 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,42 +1,53 @@ -use std::{convert, fmt}; +use std::{marker::PhantomData, convert, fmt}; + +use crate::SigType; /// A RedJubJub signature. -pub struct Signature(pub [u8; 64]); +pub struct Signature { + bytes: [u8; 64], + _marker: PhantomData, +} -impl From<[u8; 64]> for Signature { - fn from(bytes: [u8; 64]) -> Signature { - Signature(bytes) +impl From<[u8; 64]> for Signature { + fn from(bytes: [u8; 64]) -> Signature { + Signature { + bytes, _marker: PhantomData, + } } } -impl From for [u8; 64] { - fn from(s: Signature) -> [u8; 64] { - s.0 +impl From> for [u8; 64] { + fn from(s: Signature) -> [u8; 64] { + s.bytes } } // These impls all only exist because of array length restrictions. -impl fmt::Debug for Signature { +// XXX print the type variable +impl fmt::Debug for Signature { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_tuple("Signature").field(&self.0[..]).finish() + //f.debug_tuple("Signature").field(&self.0[..]).finish() + f.debug_tuple("Signature").finish() } } -impl Copy for Signature {} +impl Copy for Signature {} -impl Clone for Signature { +impl Clone for Signature { fn clone(&self) -> Self { let mut bytes = [0; 64]; - bytes[..].copy_from_slice(&self.0[..]); - Self(bytes) + bytes[..].copy_from_slice(&self.bytes[..]); + Signature { + bytes, _marker: PhantomData, + } } } -impl PartialEq for Signature { +impl PartialEq for Signature { fn eq(&self, other: &Self) -> bool { - self.0[..] == other.0[..] + self.bytes[..] == other.bytes[..] } } -impl Eq for Signature {} +impl Eq for Signature {}