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:
parent
1a9569dca2
commit
6ca14abeec
28
src/lib.rs
28
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]
|
||||
|
|
|
@ -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!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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!();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> {}
|
||||
|
|
Loading…
Reference in New Issue