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:
parent
b44f149381
commit
84b042003b
22
src/lib.rs
22
src/lib.rs
|
@ -42,9 +42,23 @@ impl SigType for Binding {}
|
||||||
pub struct SpendAuth {}
|
pub struct SpendAuth {}
|
||||||
impl SigType for SpendAuth {}
|
impl SigType for SpendAuth {}
|
||||||
|
|
||||||
mod private {
|
pub(crate) mod private {
|
||||||
use super::*;
|
use super::*;
|
||||||
pub trait Sealed {}
|
pub trait Sealed {
|
||||||
impl Sealed for Binding {}
|
fn basepoint() -> jubjub::ExtendedPoint;
|
||||||
impl Sealed for SpendAuth {}
|
}
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{convert::TryFrom, marker::PhantomData};
|
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
|
/// A refinement type for `[u8; 32]` indicating that the bytes represent
|
||||||
/// an encoding of a RedJubJub public key.
|
/// 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> {
|
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`.
|
/// Randomize this public key with the given `randomizer`.
|
||||||
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
|
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
|
||||||
unimplemented!();
|
unimplemented!();
|
||||||
|
|
|
@ -10,7 +10,7 @@ use rand_core::{CryptoRng, RngCore};
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct SecretKey<T: SigType> {
|
pub struct SecretKey<T: SigType> {
|
||||||
sk: Scalar,
|
sk: Scalar,
|
||||||
_marker: PhantomData<T>,
|
pk: PublicKey<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> From<SecretKey<T>> for [u8; 32] {
|
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> {
|
impl<T: SigType> From<[u8; 32]> for SecretKey<T> {
|
||||||
type Error = Error;
|
fn from(bytes: [u8; 32]) -> Self {
|
||||||
|
let sk = {
|
||||||
fn try_from(bytes: [u8; 32]) -> Result<Self, Self::Error> {
|
// XXX-jubjub: would be nice to unconditionally deser
|
||||||
// XXX-jubjub: it does not make sense for this to be a CtOption...
|
// This incantation ensures deserialization is infallible.
|
||||||
// XXX-jubjub: this takes a borrow but point deser doesn't
|
let mut wide = [0; 64];
|
||||||
let maybe_sk = Scalar::from_bytes(&bytes);
|
wide[0..32].copy_from_slice(&bytes);
|
||||||
if maybe_sk.is_some().into() {
|
Scalar::from_bytes_wide(&wide)
|
||||||
Ok(SecretKey {
|
};
|
||||||
sk: maybe_sk.unwrap(),
|
let pk = PublicKey::from_secret(&sk);
|
||||||
_marker: PhantomData,
|
SecretKey { sk, pk }
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(Error::MalformedSecretKey)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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> {
|
impl<T: SigType> SecretKey<T> {
|
||||||
/// Randomize this public key with the given `randomizer`.
|
/// Randomize this public key with the given `randomizer`.
|
||||||
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
|
pub fn randomize(&self, randomizer: Randomizer) -> PublicKey<T> {
|
||||||
|
|
Loading…
Reference in New Issue