Add methods to the Sealed trait, simplifying types.

The motivation is as follows.  The sealed trait pattern allows creating
a type-level equivalent of an enum: the trait corresponds to the enum
type and its implementors correspond to the enum variants; the `Sealed`
restriction ensures that there is a fixed set of enum variants.

In this picture, adding methods to the public trait corresponds to a
public method on an enum, while adding methods to the private trait
corresponds to a private method on an enum.  This means that we can add
a method to get the basepoint (whose possible choices are enumerated by
SigType) and avoid having to do specialized impls.
This commit is contained in:
Henry de Valence 2019-12-03 18:20:45 -08:00
parent b44f149381
commit 84b042003b
3 changed files with 40 additions and 55 deletions

View File

@ -42,9 +42,23 @@ impl SigType for Binding {}
pub struct SpendAuth {}
impl SigType for SpendAuth {}
mod private {
pub(crate) mod private {
use super::*;
pub trait Sealed {}
impl Sealed for Binding {}
impl Sealed for SpendAuth {}
pub trait Sealed {
fn basepoint() -> jubjub::ExtendedPoint;
}
impl Sealed for Binding {
fn basepoint() -> jubjub::ExtendedPoint {
jubjub::AffinePoint::from_bytes(constants::BINDINGSIG_BASEPOINT_BYTES)
.unwrap()
.into()
}
}
impl Sealed for SpendAuth {
fn basepoint() -> jubjub::ExtendedPoint {
jubjub::AffinePoint::from_bytes(constants::SPENDAUTHSIG_BASEPOINT_BYTES)
.unwrap()
.into()
}
}
}

View File

@ -1,6 +1,6 @@
use std::{convert::TryFrom, marker::PhantomData};
use crate::{Binding, Error, Randomizer, SigType, Signature, SpendAuth};
use crate::{Binding, Error, Randomizer, Scalar, SigType, Signature, SpendAuth};
/// A refinement type for `[u8; 32]` indicating that the bytes represent
/// an encoding of a RedJubJub public key.
@ -62,6 +62,15 @@ impl<T: SigType> TryFrom<PublicKeyBytes<T>> for PublicKey<T> {
}
impl<T: SigType> PublicKey<T> {
pub(crate) fn from_secret(s: &Scalar) -> PublicKey<T> {
let point = &T::basepoint() * s;
let bytes = PublicKeyBytes {
bytes: jubjub::AffinePoint::from(&point).to_bytes(),
_marker: PhantomData,
};
PublicKey { bytes, point }
}
/// Randomize this public key with the given `randomizer`.
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
unimplemented!();

View File

@ -10,7 +10,7 @@ use rand_core::{CryptoRng, RngCore};
#[derive(Copy, Clone, Debug)]
pub struct SecretKey<T: SigType> {
sk: Scalar,
_marker: PhantomData<T>,
pk: PublicKey<T>,
}
impl<T: SigType> From<SecretKey<T>> for [u8; 32] {
@ -19,21 +19,17 @@ impl<T: SigType> From<SecretKey<T>> for [u8; 32] {
}
}
impl<T: SigType> TryFrom<[u8; 32]> for SecretKey<T> {
type Error = Error;
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
// XXX-jubjub: it does not make sense for this to be a CtOption...
// XXX-jubjub: this takes a borrow but point deser doesn't
let maybe_sk = Scalar::from_bytes(&bytes);
if maybe_sk.is_some().into() {
Ok(SecretKey {
sk: maybe_sk.unwrap(),
_marker: PhantomData,
})
} else {
Err(Error::MalformedSecretKey)
}
impl<T: SigType> From<[u8; 32]> for SecretKey<T> {
fn from(bytes: [u8; 32]) -> Self {
let sk = {
// XXX-jubjub: would be nice to unconditionally deser
// This incantation ensures deserialization is infallible.
let mut wide = [0; 64];
wide[0..32].copy_from_slice(&bytes);
Scalar::from_bytes_wide(&wide)
};
let pk = PublicKey::from_secret(&sk);
SecretKey { sk, pk }
}
}
@ -54,40 +50,6 @@ where
}
*/
impl<'a> From<&'a SecretKey<SpendAuth>> for PublicKey<SpendAuth> {
fn from(sk: &'a SecretKey<SpendAuth>) -> PublicKey<SpendAuth> {
// XXX-jubjub: this is pretty baroque
// XXX-jubjub: provide basepoint tables for generators
let basepoint: jubjub::ExtendedPoint =
jubjub::AffinePoint::from_bytes(crate::constants::SPENDAUTHSIG_BASEPOINT_BYTES)
.unwrap()
.into();
pk_from_sk_inner(sk, basepoint)
}
}
impl<'a> From<&'a SecretKey<Binding>> for PublicKey<Binding> {
fn from(sk: &'a SecretKey<Binding>) -> PublicKey<Binding> {
let basepoint: jubjub::ExtendedPoint =
jubjub::AffinePoint::from_bytes(crate::constants::BINDINGSIG_BASEPOINT_BYTES)
.unwrap()
.into();
pk_from_sk_inner(sk, basepoint)
}
}
fn pk_from_sk_inner<T: SigType>(
sk: &SecretKey<T>,
basepoint: jubjub::ExtendedPoint,
) -> PublicKey<T> {
let point = &basepoint * &sk.sk;
let bytes = PublicKeyBytes {
bytes: jubjub::AffinePoint::from(&point).to_bytes(),
_marker: PhantomData,
};
PublicKey { bytes, point }
}
impl<T: SigType> SecretKey<T> {
/// Randomize this public key with the given `randomizer`.
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {