diff --git a/README.md b/README.md index 51b8313..2c78935 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,20 @@ A minimal [RedJubjub][redjubjub] implementation for use in [Zebra][zebra]. -Two parameterizations of RedJubjub are used in Zcash, one for `BindingSig` -and one for `SpendAuthSig`. This library distinguishes these in the type -system, using the [sealed] `SigType` trait as a type-level enum. +Two parameterizations of RedJubjub are used in Zcash, one for +`BindingSig` and one for `SpendAuthSig`. This library distinguishes +these in the type system, using the [sealed] `SigType` trait as a +type-level enum. -In addition to the usual `Signature`, `SecretKey`, `PublicKey` types, the -library also provides `PublicKeyBytes`, a [refinement] of a `[u8; 32]` -indicating that bytes represent an encoding of a RedJubjub public key. This -allows the `PublicKey` type to cache verification checks related to the -public key encoding. +In addition to the `Signature`, `SigningKey`, `VerificationKey` types, +the library also provides `VerificationKeyBytes`, a [refinement] of a +`[u8; 32]` indicating that bytes represent an encoding of a RedJubjub +verification key. This allows the `VerificationKey` type to cache +verification checks related to the verification key encoding. ## Examples -Creating a `BindingSig`, serializing and deserializing it, and verifying the -signature: +Creating a `BindingSig`, serializing and deserializing it, and +verifying the signature: ``` # use std::convert::TryFrom; @@ -23,17 +24,17 @@ use redjubjub::*; let msg = b"Hello!"; // Generate a secret key and sign the message -let sk = SecretKey::::new(thread_rng()); +let sk = SigningKey::::new(thread_rng()); let sig = sk.sign(thread_rng(), msg); // Types can be converted to raw byte arrays using From/Into let sig_bytes: [u8; 64] = sig.into(); -let pk_bytes: [u8; 32] = PublicKey::from(&sk).into(); +let pk_bytes: [u8; 32] = VerificationKey::from(&sk).into(); // Deserialize and verify the signature. let sig: Signature = sig_bytes.into(); assert!( - PublicKey::try_from(pk_bytes) + VerificationKey::try_from(pk_bytes) .and_then(|pk| pk.verify(msg, &sig)) .is_ok() ); diff --git a/src/error.rs b/src/error.rs index d1f2842..e36f064 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,12 +3,12 @@ use thiserror::Error; /// An error related to RedJubJub signatures. #[derive(Error, Debug, Copy, Clone, Eq, PartialEq)] pub enum Error { - /// 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, + /// The encoding of a signing key was malformed. + #[error("Malformed signing key encoding.")] + MalformedSigningKey, + /// The encoding of a verification key was malformed. + #[error("Malformed verification key encoding.")] + MalformedVerificationKey, /// Signature verification failed. #[error("Invalid signature.")] InvalidSignature, diff --git a/src/lib.rs b/src/lib.rs index fdbe171..7f3efdd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,9 +8,9 @@ mod constants; mod error; mod hash; -mod public_key; -mod secret_key; mod signature; +mod signing_key; +mod verification_key; /// An element of the JubJub scalar field used for randomization of public and secret keys. pub type Randomizer = jubjub::Fr; @@ -22,9 +22,9 @@ type Scalar = jubjub::Fr; use hash::HStar; pub use error::Error; -pub use public_key::{PublicKey, PublicKeyBytes}; -pub use secret_key::SecretKey; pub use signature::Signature; +pub use signing_key::SigningKey; +pub use verification_key::{VerificationKey, VerificationKeyBytes}; /// Abstracts over different RedJubJub parameter choices, [`Binding`] /// and [`SpendAuth`]. diff --git a/src/secret_key.rs b/src/signing_key.rs similarity index 66% rename from src/secret_key.rs rename to src/signing_key.rs index b293b3a..9659e84 100644 --- a/src/secret_key.rs +++ b/src/signing_key.rs @@ -3,34 +3,34 @@ use std::{ marker::PhantomData, }; -use crate::{Error, PublicKey, Randomizer, Scalar, SigType, Signature, SpendAuth}; +use crate::{Error, Randomizer, Scalar, SigType, Signature, SpendAuth, VerificationKey}; use rand_core::{CryptoRng, RngCore}; -/// A RedJubJub secret key. +/// A RedJubJub signing key. #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", serde(try_from = "SerdeHelper"))] #[cfg_attr(feature = "serde", serde(into = "SerdeHelper"))] #[cfg_attr(feature = "serde", serde(bound = "T: SigType"))] -pub struct SecretKey { +pub struct SigningKey { sk: Scalar, - pk: PublicKey, + pk: VerificationKey, } -impl<'a, T: SigType> From<&'a SecretKey> for PublicKey { - fn from(sk: &'a SecretKey) -> PublicKey { +impl<'a, T: SigType> From<&'a SigningKey> for VerificationKey { + fn from(sk: &'a SigningKey) -> VerificationKey { sk.pk.clone() } } -impl From> for [u8; 32] { - fn from(sk: SecretKey) -> [u8; 32] { +impl From> for [u8; 32] { + fn from(sk: SigningKey) -> [u8; 32] { sk.sk.to_bytes() } } -impl TryFrom<[u8; 32]> for SecretKey { +impl TryFrom<[u8; 32]> for SigningKey { type Error = Error; fn try_from(bytes: [u8; 32]) -> Result { @@ -38,10 +38,10 @@ impl TryFrom<[u8; 32]> for SecretKey { let maybe_sk = Scalar::from_bytes(&bytes); if maybe_sk.is_some().into() { let sk = maybe_sk.unwrap(); - let pk = PublicKey::from_secret(&sk); - Ok(SecretKey { sk, pk }) + let pk = VerificationKey::from(&sk); + Ok(SigningKey { sk, pk }) } else { - Err(Error::MalformedSecretKey) + Err(Error::MalformedSigningKey) } } } @@ -49,7 +49,7 @@ impl TryFrom<[u8; 32]> for SecretKey { #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] struct SerdeHelper([u8; 32]); -impl TryFrom for SecretKey { +impl TryFrom for SigningKey { type Error = Error; fn try_from(helper: SerdeHelper) -> Result { @@ -57,34 +57,34 @@ impl TryFrom for SecretKey { } } -impl From> for SerdeHelper { - fn from(sk: SecretKey) -> Self { +impl From> for SerdeHelper { + fn from(sk: SigningKey) -> Self { Self(sk.into()) } } -impl SecretKey { +impl SigningKey { /// Randomize this public key with the given `randomizer`. - pub fn randomize(&self, randomizer: &Randomizer) -> SecretKey { + pub fn randomize(&self, randomizer: &Randomizer) -> SigningKey { let sk = &self.sk + randomizer; - let pk = PublicKey::from_secret(&sk); - SecretKey { sk, pk } + let pk = VerificationKey::from(&sk); + SigningKey { sk, pk } } } -impl SecretKey { - /// Generate a new secret key. - pub fn new(mut rng: R) -> SecretKey { +impl SigningKey { + /// Generate a new signing key. + pub fn new(mut rng: R) -> SigningKey { let sk = { let mut bytes = [0; 64]; rng.fill_bytes(&mut bytes); Scalar::from_bytes_wide(&bytes) }; - let pk = PublicKey::from_secret(&sk); - SecretKey { sk, pk } + let pk = VerificationKey::from(&sk); + SigningKey { sk, pk } } - /// Create a signature of type `T` on `msg` using this `SecretKey`. + /// Create a signature of type `T` on `msg` using this `SigningKey`. // Similar to signature::Signer but without boxed errors. pub fn sign(&self, mut rng: R, msg: &[u8]) -> Signature { use crate::HStar; diff --git a/src/public_key.rs b/src/verification_key.rs similarity index 60% rename from src/public_key.rs rename to src/verification_key.rs index ac93b42..64e9b37 100644 --- a/src/public_key.rs +++ b/src/verification_key.rs @@ -3,126 +3,126 @@ use std::{convert::TryFrom, marker::PhantomData}; use crate::{Error, Randomizer, Scalar, SigType, Signature, SpendAuth}; /// A refinement type for `[u8; 32]` indicating that the bytes represent -/// an encoding of a RedJubJub public key. +/// an encoding of a RedJubJub verification key. /// -/// This is useful for representing a compressed public key; the -/// [`PublicKey`] type in this library holds other decompressed state +/// This is useful for representing a compressed verification key; the +/// [`VerificationKey`] type in this library holds other decompressed state /// used in signature verification. #[derive(Copy, Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct PublicKeyBytes { +pub struct VerificationKeyBytes { pub(crate) bytes: [u8; 32], pub(crate) _marker: PhantomData, } -impl From<[u8; 32]> for PublicKeyBytes { - fn from(bytes: [u8; 32]) -> PublicKeyBytes { - PublicKeyBytes { +impl From<[u8; 32]> for VerificationKeyBytes { + fn from(bytes: [u8; 32]) -> VerificationKeyBytes { + VerificationKeyBytes { bytes, _marker: PhantomData, } } } -impl From> for [u8; 32] { - fn from(refined: PublicKeyBytes) -> [u8; 32] { +impl From> for [u8; 32] { + fn from(refined: VerificationKeyBytes) -> [u8; 32] { refined.bytes } } -/// A valid RedJubJub public key. +/// A valid RedJubJub verification key. /// /// This type holds decompressed state used in signature verification; if the -/// public key may not be used immediately, it is probably better to use -/// [`PublicKeyBytes`], which is a refinement type for `[u8; 32]`. +/// verification key may not be used immediately, it is probably better to use +/// [`VerificationKeyBytes`], which is a refinement type for `[u8; 32]`. /// /// ## Consensus properties /// -/// The `TryFrom` conversion performs the following Zcash +/// The `TryFrom` conversion performs the following Zcash /// consensus rule checks: /// -/// 1. The check that the bytes are a canonical encoding of a public key; -/// 2. The check that the public key is not a point of small order. +/// 1. The check that the bytes are a canonical encoding of a verification key; +/// 2. The check that the verification key is not a point of small order. #[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "serde", serde(try_from = "PublicKeyBytes"))] -#[cfg_attr(feature = "serde", serde(into = "PublicKeyBytes"))] +#[cfg_attr(feature = "serde", serde(try_from = "VerificationKeyBytes"))] +#[cfg_attr(feature = "serde", serde(into = "VerificationKeyBytes"))] #[cfg_attr(feature = "serde", serde(bound = "T: SigType"))] -pub struct PublicKey { +pub struct VerificationKey { // XXX-jubjub: this should just be Point pub(crate) point: jubjub::ExtendedPoint, - pub(crate) bytes: PublicKeyBytes, + pub(crate) bytes: VerificationKeyBytes, } -impl From> for PublicKeyBytes { - fn from(pk: PublicKey) -> PublicKeyBytes { +impl From> for VerificationKeyBytes { + fn from(pk: VerificationKey) -> VerificationKeyBytes { pk.bytes } } -impl From> for [u8; 32] { - fn from(pk: PublicKey) -> [u8; 32] { +impl From> for [u8; 32] { + fn from(pk: VerificationKey) -> [u8; 32] { pk.bytes.bytes } } -impl TryFrom> for PublicKey { +impl TryFrom> for VerificationKey { type Error = Error; - fn try_from(bytes: PublicKeyBytes) -> Result { + fn try_from(bytes: VerificationKeyBytes) -> Result { // XXX-jubjub: this should not use CtOption // XXX-jubjub: this takes ownership of bytes, while Fr doesn't. // This checks that the encoding is canonical... let maybe_point = jubjub::AffinePoint::from_bytes(bytes.bytes); if maybe_point.is_some().into() { let point: jubjub::ExtendedPoint = maybe_point.unwrap().into(); - // This checks that the public key is not of small order. + // This checks that the verification key is not of small order. if ::from(point.is_small_order()) == false { - Ok(PublicKey { point, bytes }) + Ok(VerificationKey { point, bytes }) } else { - Err(Error::MalformedPublicKey) + Err(Error::MalformedVerificationKey) } } else { - Err(Error::MalformedPublicKey) + Err(Error::MalformedVerificationKey) } } } -impl TryFrom<[u8; 32]> for PublicKey { +impl TryFrom<[u8; 32]> for VerificationKey { type Error = Error; fn try_from(bytes: [u8; 32]) -> Result { use std::convert::TryInto; - PublicKeyBytes::from(bytes).try_into() + VerificationKeyBytes::from(bytes).try_into() } } -impl PublicKey { - /// Randomize this public key with the given `randomizer`. +impl VerificationKey { + /// Randomize this verification key with the given `randomizer`. /// /// Randomization is only supported for `SpendAuth` keys. - pub fn randomize(&self, randomizer: &Randomizer) -> PublicKey { + pub fn randomize(&self, randomizer: &Randomizer) -> VerificationKey { use crate::private::Sealed; let point = &self.point + &(&SpendAuth::basepoint() * randomizer); - let bytes = PublicKeyBytes { + let bytes = VerificationKeyBytes { bytes: jubjub::AffinePoint::from(&point).to_bytes(), _marker: PhantomData, }; - PublicKey { bytes, point } + VerificationKey { bytes, point } } } -impl PublicKey { - pub(crate) fn from_secret(s: &Scalar) -> PublicKey { +impl VerificationKey { + pub(crate) fn from(s: &Scalar) -> VerificationKey { let point = &T::basepoint() * s; - let bytes = PublicKeyBytes { + let bytes = VerificationKeyBytes { bytes: jubjub::AffinePoint::from(&point).to_bytes(), _marker: PhantomData, }; - PublicKey { bytes, point } + VerificationKey { bytes, point } } - /// Verify a purported `signature` over `msg` made by this public key. + /// Verify a purported `signature` over `msg` made by this verification key. // This is similar to impl signature::Verifier but without boxed errors pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> { #![allow(non_snake_case)] diff --git a/tests/bincode.rs b/tests/bincode.rs index 1094d6f..3cca7cd 100644 --- a/tests/bincode.rs +++ b/tests/bincode.rs @@ -9,16 +9,16 @@ proptest! { fn secretkey_serialization( bytes in prop::array::uniform32(any::()), ) { - let sk_result_from = SecretKey::::try_from(bytes); - let sk_result_bincode: Result, _> + let sk_result_from = SigningKey::::try_from(bytes); + let sk_result_bincode: Result, _> = bincode::deserialize(&bytes[..]); // Check 1: both decoding methods should agree match (sk_result_from, sk_result_bincode) { // Both agree on success (Ok(sk_from), Ok(sk_bincode)) => { - let pk_bytes_from = PublicKeyBytes::from(PublicKey::from(&sk_from)); - let pk_bytes_bincode = PublicKeyBytes::from(PublicKey::from(&sk_bincode)); + let pk_bytes_from = VerificationKeyBytes::from(VerificationKey::from(&sk_from)); + let pk_bytes_bincode = VerificationKeyBytes::from(VerificationKey::from(&sk_bincode)); assert_eq!(pk_bytes_from, pk_bytes_bincode); // Check 2: bincode encoding should match original bytes. @@ -39,8 +39,8 @@ proptest! { fn publickeybytes_serialization( bytes in prop::array::uniform32(any::()), ) { - let pk_bytes_from = PublicKeyBytes::::from(bytes); - let pk_bytes_bincode: PublicKeyBytes:: + let pk_bytes_from = VerificationKeyBytes::::from(bytes); + let pk_bytes_bincode: VerificationKeyBytes:: = bincode::deserialize(&bytes[..]).unwrap(); // Check 1: both decoding methods should have the same result. @@ -59,8 +59,8 @@ proptest! { fn publickey_serialization( bytes in prop::array::uniform32(any::()), ) { - let pk_result_try_from = PublicKey::::try_from(bytes); - let pk_result_bincode: Result, _> + let pk_result_try_from = VerificationKey::::try_from(bytes); + let pk_result_bincode: Result, _> = bincode::deserialize(&bytes[..]); // Check 1: both decoding methods should have the same result diff --git a/tests/librustzcash_vectors.rs b/tests/librustzcash_vectors.rs index 1cc3632..7e2af6c 100644 --- a/tests/librustzcash_vectors.rs +++ b/tests/librustzcash_vectors.rs @@ -8,7 +8,7 @@ use redjubjub::*; #[test] fn verify_librustzcash_spendauth() { for (msg, sig, pk_bytes) in LIBRUSTZCASH_SPENDAUTH_SIGS.iter() { - assert!(PublicKey::try_from(*pk_bytes) + assert!(VerificationKey::try_from(*pk_bytes) .and_then(|pk| pk.verify(&msg, &sig)) .is_ok()); } @@ -17,14 +17,18 @@ fn verify_librustzcash_spendauth() { #[test] fn verify_librustzcash_binding() { for (msg, sig, pk_bytes) in LIBRUSTZCASH_BINDING_SIGS.iter() { - assert!(PublicKey::try_from(*pk_bytes) + assert!(VerificationKey::try_from(*pk_bytes) .and_then(|pk| pk.verify(&msg, &sig)) .is_ok()); } } lazy_static! { - static ref LIBRUSTZCASH_SPENDAUTH_SIGS: [(Vec, Signature, PublicKeyBytes); 32] = [ + static ref LIBRUSTZCASH_SPENDAUTH_SIGS: [( + Vec, + Signature, + VerificationKeyBytes + ); 32] = [ ( [ 16, 28, 190, 75, 156, 66, 96, 79, 4, 199, 3, 195, 150, 247, 136, 198, 203, 45, 109, @@ -634,7 +638,7 @@ lazy_static! { .into(), ), ]; - static ref LIBRUSTZCASH_BINDING_SIGS: [(Vec, Signature, PublicKeyBytes); 32] = [ + static ref LIBRUSTZCASH_BINDING_SIGS: [(Vec, Signature, VerificationKeyBytes); 32] = [ ( [ 16, 28, 190, 75, 156, 66, 96, 79, 4, 199, 3, 195, 150, 247, 136, 198, 203, 45, 109, diff --git a/tests/proptests.rs b/tests/proptests.rs index baaacdc..ac5dd45 100644 --- a/tests/proptests.rs +++ b/tests/proptests.rs @@ -10,7 +10,7 @@ use redjubjub::*; struct SignatureCase { msg: Vec, sig: Signature, - pk_bytes: PublicKeyBytes, + pk_bytes: VerificationKeyBytes, is_valid: bool, } @@ -37,9 +37,9 @@ enum Tweak { impl SignatureCase { fn new(mut rng: R, msg: Vec) -> Self { - let sk = SecretKey::new(&mut rng); + let sk = SigningKey::new(&mut rng); let sig = sk.sign(&mut rng, &msg); - let pk_bytes = PublicKey::from(&sk).into(); + let pk_bytes = VerificationKey::from(&sk).into(); Self { msg, sig, @@ -58,12 +58,12 @@ impl SignatureCase { }; let pk_bytes = { let bytes: [u8; 32] = self.pk_bytes.into(); - PublicKeyBytes::::from(bytes) + VerificationKeyBytes::::from(bytes) }; // Check that signature validation has the expected result. self.is_valid - == PublicKey::try_from(pk_bytes) + == VerificationKey::try_from(pk_bytes) .and_then(|pk| pk.verify(&self.msg, &sig)) .is_ok() } @@ -142,14 +142,14 @@ proptest! { Randomizer::from_bytes_wide(&bytes) }; - let sk = SecretKey::::new(&mut rng); - let pk = PublicKey::from(&sk); + let sk = SigningKey::::new(&mut rng); + let pk = VerificationKey::from(&sk); let sk_r = sk.randomize(&r); let pk_r = pk.randomize(&r); - let pk_r_via_sk_rand: [u8; 32] = PublicKeyBytes::from(PublicKey::from(&sk_r)).into(); - let pk_r_via_pk_rand: [u8; 32] = PublicKeyBytes::from(pk_r).into(); + let pk_r_via_sk_rand: [u8; 32] = VerificationKeyBytes::from(VerificationKey::from(&sk_r)).into(); + let pk_r_via_pk_rand: [u8; 32] = VerificationKeyBytes::from(pk_r).into(); assert_eq!(pk_r_via_pk_rand, pk_r_via_sk_rand); } diff --git a/tests/smallorder.rs b/tests/smallorder.rs index 88665e5..3631779 100644 --- a/tests/smallorder.rs +++ b/tests/smallorder.rs @@ -10,6 +10,6 @@ fn smallorder_publickey_fails() { let order4 = AffinePoint::from_raw_unchecked(Fq::one(), Fq::zero()); assert_eq!(::from(order4.is_small_order()), true); let bytes = order4.to_bytes(); - let pk_bytes = PublicKeyBytes::::from(bytes); - assert!(PublicKey::::try_from(pk_bytes).is_err()); + let pk_bytes = VerificationKeyBytes::::from(bytes); + assert!(VerificationKey::::try_from(pk_bytes).is_err()); }