diff --git a/src/constants.rs b/src/constants.rs new file mode 100644 index 0000000..f6bda44 --- /dev/null +++ b/src/constants.rs @@ -0,0 +1,15 @@ +/// The byte-encoding of the basepoint for `SpendAuthSig`. +// Extracted ad-hoc from librustzcash +// XXX add tests for this value. +pub const SPENDAUTHSIG_BASEPOINT_BYTES: [u8; 32] = [ + 48, 181, 242, 170, 173, 50, 86, 48, 188, 221, 219, 206, 77, 103, 101, 109, 5, 253, 28, 194, + 208, 55, 187, 83, 117, 182, 233, 109, 158, 1, 161, 215, +]; + +/// The byte-encoding of the basepoint for `BindingSig`. +// Extracted ad-hoc from librustzcash +// XXX add tests for this value. +pub const BINDINGSIG_BASEPOINT_BYTES: [u8; 32] = [ + 139, 106, 11, 56, 185, 250, 174, 60, 59, 128, 59, 71, 176, 241, 70, 173, 80, 171, 34, 30, 110, + 42, 251, 230, 219, 222, 69, 203, 169, 211, 129, 237, +]; diff --git a/src/error.rs b/src/error.rs index a7c55d8..617773a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,7 +3,10 @@ use thiserror::Error; /// An error related to RedJubJub signatures. #[derive(Error, Debug)] pub enum Error { - /// This is a stub variant to check that thiserror derive works. - #[error("Stub error-- remove this.")] - StubError, + /// The encoding of a secret key was malformed. + #[error("Malformed secret key encoding.")] + MalformedSecretKey, + /// The encoding of a public key was malformed. + #[error("Malformed public key encoding.")] + MalformedPublicKey, } diff --git a/src/lib.rs b/src/lib.rs index 011ed63..7ca40cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ //! Docs require the `nightly` feature until RFC 1990 lands. +mod constants; mod error; mod public_key; mod secret_key; @@ -12,6 +13,9 @@ mod signature; /// An element of the JubJub scalar field used for randomization of public and secret keys. pub type Randomizer = jubjub::Fr; +/// A better name than Fr. +type Scalar = jubjub::Fr; + pub use error::Error; pub use public_key::{PublicKey, PublicKeyBytes}; pub use secret_key::{SecretKey, SecretKeyBytes}; @@ -44,11 +48,3 @@ mod private { impl Sealed for Binding {} impl Sealed for SpendAuth {} } - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/src/public_key.rs b/src/public_key.rs index 42ba6a7..c6d773c 100644 --- a/src/public_key.rs +++ b/src/public_key.rs @@ -1,6 +1,6 @@ use std::{convert::TryFrom, marker::PhantomData}; -use crate::{Error, SigType, SpendAuth, Binding, Randomizer, Signature}; +use crate::{Binding, Error, Randomizer, SigType, Signature, SpendAuth}; /// A refinement type indicating that the inner `[u8; 32]` represents an /// encoding of a RedJubJub public key. @@ -12,7 +12,10 @@ pub struct PublicKeyBytes { impl From<[u8; 32]> for PublicKeyBytes { fn from(bytes: [u8; 32]) -> PublicKeyBytes { - PublicKeyBytes { bytes, _marker: PhantomData } + PublicKeyBytes { + bytes, + _marker: PhantomData, + } } } @@ -26,13 +29,17 @@ impl From> for [u8; 32] { // XXX PartialEq, Eq? #[derive(Copy, Clone, Debug)] pub struct PublicKey { - // fields - _marker: PhantomData, + // XXX-jubjub: this should just be Point + pub(crate) point: jubjub::ExtendedPoint, + // XXX should this just store a PublicKeyBytes? + pub(crate) bytes: [u8; 32], + pub(crate) _marker: PhantomData, } impl From> for PublicKeyBytes { fn from(pk: PublicKey) -> PublicKeyBytes { - unimplemented!(); + let PublicKey { bytes, _marker, .. } = pk; + PublicKeyBytes { bytes, _marker } } } @@ -40,7 +47,18 @@ impl TryFrom> for PublicKey { type Error = Error; fn try_from(bytes: PublicKeyBytes) -> Result { - unimplemented!(); + // XXX-jubjub: this should not use CtOption + // XXX-jubjub: this takes ownership of bytes, while Fr doesn't. + let maybe_point = jubjub::AffinePoint::from_bytes(bytes.bytes); + if maybe_point.is_some().into() { + Ok(PublicKey { + point: maybe_point.unwrap().into(), + bytes: bytes.bytes, + _marker: PhantomData, + }) + } else { + Err(Error::MalformedPublicKey) + } } } diff --git a/src/secret_key.rs b/src/secret_key.rs index 304743e..54a6fdd 100644 --- a/src/secret_key.rs +++ b/src/secret_key.rs @@ -1,6 +1,6 @@ use std::{convert::TryFrom, marker::PhantomData}; -use crate::{Error, PublicKey, SigType, Binding, SpendAuth, Randomizer, Signature}; +use crate::{Binding, Error, PublicKey, Randomizer, Scalar, SigType, Signature, SpendAuth}; /// A refinement type indicating that the inner `[u8; 32]` represents an /// encoding of a RedJubJub secret key. @@ -12,7 +12,10 @@ pub struct SecretKeyBytes { impl From<[u8; 32]> for SecretKeyBytes { fn from(bytes: [u8; 32]) -> SecretKeyBytes { - SecretKeyBytes{ bytes, _marker: PhantomData } + SecretKeyBytes { + bytes, + _marker: PhantomData, + } } } @@ -26,28 +29,72 @@ impl From> for [u8; 32] { // XXX PartialEq, Eq? #[derive(Copy, Clone, Debug)] pub struct SecretKey { - // fields + sk: Scalar, _marker: PhantomData, } impl From> for SecretKeyBytes { - fn from(pk: SecretKey) -> SecretKeyBytes { - unimplemented!(); + fn from(sk: SecretKey) -> SecretKeyBytes { + SecretKeyBytes { + bytes: sk.sk.to_bytes(), + _marker: PhantomData, + } } } // XXX could this be a From impl? +// not unless there's an infallible conversion from bytes to scalars, +// which is not currently present in jubjub impl TryFrom> for SecretKey { type Error = Error; fn try_from(bytes: SecretKeyBytes) -> Result { - unimplemented!(); + // 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.bytes); + if maybe_sk.is_some().into() { + Ok(SecretKey { + sk: maybe_sk.unwrap(), + _marker: PhantomData, + }) + } else { + Err(Error::MalformedSecretKey) + } } } -impl<'a, T: SigType> From<&'a SecretKey> for PublicKey { - fn from(sk: &'a SecretKey) -> PublicKey { - unimplemented!(); +impl<'a> From<&'a SecretKey> for PublicKey { + fn from(sk: &'a SecretKey) -> PublicKey { + // 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> for PublicKey { + fn from(sk: &'a SecretKey) -> PublicKey { + 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( + sk: &SecretKey, + basepoint: jubjub::ExtendedPoint, +) -> PublicKey { + let point = &basepoint * &sk.sk; + let bytes = jubjub::AffinePoint::from(&point).to_bytes(); + PublicKey { + point, + bytes, + _marker: PhantomData, } } diff --git a/src/signature.rs b/src/signature.rs index 0429113..e902eb1 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -1,4 +1,4 @@ -use std::{marker::PhantomData, convert, fmt}; +use std::{convert, fmt, marker::PhantomData}; use crate::SigType; @@ -11,7 +11,8 @@ pub struct Signature { impl From<[u8; 64]> for Signature { fn from(bytes: [u8; 64]) -> Signature { Signature { - bytes, _marker: PhantomData, + bytes, + _marker: PhantomData, } } } @@ -39,7 +40,8 @@ impl Clone for Signature { let mut bytes = [0; 64]; bytes[..].copy_from_slice(&self.bytes[..]); Signature { - bytes, _marker: PhantomData, + bytes, + _marker: PhantomData, } } }