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.
This commit is contained in:
Henry de Valence 2019-12-03 12:22:35 -08:00
parent 1a9569dca2
commit 6ca14abeec
4 changed files with 134 additions and 63 deletions

View File

@ -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]

View File

@ -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<T: SigType> {
bytes: [u8; 32],
_marker: PhantomData<T>,
}
impl From<[u8; 32]> for PublicKeyBytes {
fn from(raw: [u8; 32]) -> PublicKeyBytes {
PublicKeyBytes(raw)
impl<T: SigType> From<[u8; 32]> for PublicKeyBytes<T> {
fn from(bytes: [u8; 32]) -> PublicKeyBytes<T> {
PublicKeyBytes { bytes, _marker: PhantomData }
}
}
impl From<PublicKeyBytes> for [u8; 32] {
fn from(refined: PublicKeyBytes) -> [u8; 32] {
refined.0
impl<T: SigType> From<PublicKeyBytes<T>> for [u8; 32] {
fn from(refined: PublicKeyBytes<T>) -> [u8; 32] {
refined.bytes
}
}
/// A RedJubJub public key.
// XXX PartialEq, Eq?
#[derive(Copy, Clone, Debug)]
pub struct PublicKey {
pub struct PublicKey<T: SigType> {
// fields
_marker: PhantomData<T>,
}
impl From<PublicKey> for PublicKeyBytes {
fn from(pk: PublicKey) -> PublicKeyBytes {
impl<T: SigType> From<PublicKey<T>> for PublicKeyBytes<T> {
fn from(pk: PublicKey<T>) -> PublicKeyBytes<T> {
unimplemented!();
}
}
impl TryFrom<PublicKeyBytes> for PublicKey {
impl<T: SigType> TryFrom<PublicKeyBytes<T>> for PublicKey<T> {
type Error = Error;
fn try_from(bytes: PublicKeyBytes) -> Result<Self, Self::Error> {
fn try_from(bytes: PublicKeyBytes<T>) -> Result<Self, Self::Error> {
unimplemented!();
}
}
impl PublicKey {
impl<T: SigType> PublicKey<T> {
/// 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<T> {
unimplemented!();
}
}
impl PublicKey<Binding> {
/// 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<Binding>) -> Result<(), Error> {
// this lets us specialize the basepoint parameter, could call a verify_inner
unimplemented!();
}
}
impl PublicKey<SpendAuth> {
/// 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<SpendAuth>) -> Result<(), Error> {
// this lets us specialize the basepoint parameter, could call a verify_inner
unimplemented!();
}
}

View File

@ -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<T: SigType> {
bytes: [u8; 32],
_marker: PhantomData<T>,
}
impl From<[u8; 32]> for SecretKeyBytes {
fn from(raw: [u8; 32]) -> SecretKeyBytes {
SecretKeyBytes(raw)
impl<T: SigType> From<[u8; 32]> for SecretKeyBytes<T> {
fn from(bytes: [u8; 32]) -> SecretKeyBytes<T> {
SecretKeyBytes{ bytes, _marker: PhantomData }
}
}
impl From<SecretKeyBytes> for [u8; 32] {
fn from(refined: SecretKeyBytes) -> [u8; 32] {
refined.0
impl<T: SigType> From<SecretKeyBytes<T>> for [u8; 32] {
fn from(refined: SecretKeyBytes<T>) -> [u8; 32] {
refined.bytes
}
}
/// A RedJubJub secret key.
// XXX PartialEq, Eq?
#[derive(Copy, Clone, Debug)]
pub struct SecretKey {
pub struct SecretKey<T: SigType> {
// fields
_marker: PhantomData<T>,
}
impl From<SecretKey> for SecretKeyBytes {
fn from(pk: SecretKey) -> SecretKeyBytes {
impl<T: SigType> From<SecretKey<T>> for SecretKeyBytes<T> {
fn from(pk: SecretKey<T>) -> SecretKeyBytes<T> {
unimplemented!();
}
}
// XXX could this be a From impl?
impl TryFrom<SecretKeyBytes> for SecretKey {
impl<T: SigType> TryFrom<SecretKeyBytes<T>> for SecretKey<T> {
type Error = Error;
fn try_from(bytes: SecretKeyBytes) -> Result<Self, Self::Error> {
fn try_from(bytes: SecretKeyBytes<T>) -> Result<Self, Self::Error> {
unimplemented!();
}
}
impl<'a> From<&'a SecretKey> for PublicKey {
fn from(sk: &'a SecretKey) -> PublicKey {
impl<'a, T: SigType> From<&'a SecretKey<T>> for PublicKey<T> {
fn from(sk: &'a SecretKey<T>) -> PublicKey<T> {
unimplemented!();
}
}
impl SecretKey {
impl<T: SigType> SecretKey<T> {
/// 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<T> {
unimplemented!();
}
}
impl SecretKey<Binding> {
/// Create a Zcash `BindingSig` on `msg` using this `SecretKey`.
// Similar to signature::Signer but without boxed errors.
pub fn sign(&self, msg: &[u8]) -> Signature<Binding> {
// could use sign_inner
unimplemented!();
}
}
impl SecretKey<SpendAuth> {
/// Create a Zcash `SpendAuthSig` on `msg` using this `SecretKey`.
// Similar to signature::Signer but without boxed errors.
pub fn sign(&self, msg: &[u8]) -> Signature<SpendAuth> {
// could use sign_inner
unimplemented!();
}
}

View File

@ -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<T: SigType> {
bytes: [u8; 64],
_marker: PhantomData<T>,
}
impl From<[u8; 64]> for Signature {
fn from(bytes: [u8; 64]) -> Signature {
Signature(bytes)
impl<T: SigType> From<[u8; 64]> for Signature<T> {
fn from(bytes: [u8; 64]) -> Signature<T> {
Signature {
bytes, _marker: PhantomData,
}
}
}
impl From<Signature> for [u8; 64] {
fn from(s: Signature) -> [u8; 64] {
s.0
impl<T: SigType> From<Signature<T>> for [u8; 64] {
fn from(s: Signature<T>) -> [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<T: SigType> fmt::Debug for Signature<T> {
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<T: SigType> Copy for Signature<T> {}
impl Clone for Signature {
impl<T: SigType> Clone for Signature<T> {
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<T: SigType> PartialEq for Signature<T> {
fn eq(&self, other: &Self) -> bool {
self.0[..] == other.0[..]
self.bytes[..] == other.bytes[..]
}
}
impl Eq for Signature {}
impl<T: SigType> Eq for Signature<T> {}