diff --git a/.github/workflows/dusk_ci.yml b/.github/workflows/dusk_ci.yml index d6a64d2..561f348 100644 --- a/.github/workflows/dusk_ci.yml +++ b/.github/workflows/dusk_ci.yml @@ -51,7 +51,7 @@ jobs: args: --release test_nightly_canon: - name: Nightly tests + name: Nightly tests canon runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index c09154a..e00272d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.4.1] - 26-11-20 +## [0.5.0] - 2021-01-28 + +### Added + +- Add `PublicKey` and `SecretKey` (removed from `schnorr`) +- Add `dusk_bytes::Serializable` trait to structure + +### Removed + +- Remove manual implementation of `to_bytes` and `from_bytes` +- Remove `Error` enum +- Remove `decode` function + +### Changed + +- Bump `dusk-jubjub` to `v0.8` +- Bump `poseidon252` to `v0.16.0` +- Bump `canonical` to `v0.5` +- Bump `canonical_derive` `v0.5` +- Update CHANGELOG to ISO 8601 + +## [0.4.1] - 2020-11-26 + ### Changed + - Use poseidon252 dependency. -## [0.4.0] - 17-11-20 +## [0.4.0] - 2020-11-17 + ### Changed + - No-Std compatibility. diff --git a/Cargo.toml b/Cargo.toml index 19f7fb5..d5c99c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,17 @@ [package] name = "dusk-pki" -version = "0.4.1" +version = "0.5.0" authors = ["zer0 ", "Victor Lopez CtOption - where - Self: Sized; -} - -impl From32Bytes for JubJubScalar { - fn from_bytes(bytes: [u8; 32]) -> CtOption { - JubJubScalar::from_bytes(&bytes) - } -} -impl From32Bytes for JubJubAffine { - fn from_bytes(bytes: [u8; 32]) -> CtOption { - JubJubAffine::from_bytes(bytes) - } -} - -/// DecodesJubJub's AffinePoint and JubJub's Scalar from bytes -pub fn decode(bytes: &[u8]) -> Result { - if bytes.len() < 32 { - return Err(Error::BadLength { - found: bytes.len(), - expected: 32, - }); - } - - let mut array = [0u8; 32]; - array.copy_from_slice(&bytes[..32]); - let result = T::from_bytes(array); - - if result.is_none().into() { - return Err(Error::InvalidParameters); - } - Ok(result.unwrap()) -} diff --git a/src/errors.rs b/src/errors.rs deleted file mode 100644 index 45fc074..0000000 --- a/src/errors.rs +++ /dev/null @@ -1,31 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. -// -// Copyright (c) DUSK NETWORK. All rights reserved. - -use core::fmt; - -/// Errors for Dusk PKI -#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Error { - /// Invalid Scalar - InvalidScalar, - /// Invalid Compressed Point" - InvalidPoint, - /// Invalid Parameters - InvalidParameters, - /// Bad Length - BadLength { - /// The found length - found: usize, - /// The expected length - expected: usize, - }, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Dusk PKI Error: {:?}", &self) - } -} diff --git a/src/keys/public.rs b/src/keys/public.rs index 6ff4dca..90baf6c 100644 --- a/src/keys/public.rs +++ b/src/keys/public.rs @@ -5,16 +5,19 @@ // Copyright (c) DUSK NETWORK. All rights reserved. use super::secret::SecretKey; -use crate::{Error, JubJubAffine, JubJubExtended}; -use core::convert::TryFrom; -use core::fmt; +use crate::{JubJubAffine, JubJubExtended}; +use dusk_bytes::{Error, HexDebug, Serializable}; use dusk_jubjub::GENERATOR_EXTENDED; -#[derive(Debug, Default, Copy, Clone, PartialEq)] -#[cfg_attr(feature = "canon", derive(Canon))] +#[cfg(feature = "canon")] +use canonical::Canon; +#[cfg(feature = "canon")] +use canonical_derive::Canon; /// Structure repesenting a [`PublicKey`] -pub struct PublicKey(JubJubExtended); +#[derive(Copy, Clone, PartialEq, HexDebug)] +#[cfg_attr(feature = "canon", derive(Canon))] +pub struct PublicKey(pub(crate) JubJubExtended); impl From<&SecretKey> for PublicKey { fn from(sk: &SecretKey) -> Self { @@ -42,55 +45,14 @@ impl AsRef for PublicKey { } } -impl PublicKey { - /// Copies `self` into a new array of 32 bytes. - pub fn to_bytes(&self) -> [u8; 32] { - JubJubAffine::from(self.0).to_bytes() - } - - /// Create a new `PublicKey` from an array of 32 bytes. - pub fn from_bytes(bytes: &[u8; 32]) -> Result { - match Option::::from(JubJubAffine::from_bytes(*bytes)) { - Some(point) => Ok(PublicKey(JubJubExtended::from(point))), - _ => Err(Error::InvalidPoint), - } - } -} - -impl fmt::LowerHex for PublicKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes = self.to_bytes(); - - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) - } -} - -impl fmt::UpperHex for PublicKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes = self.to_bytes(); +impl Serializable<32> for PublicKey { + type Error = Error; - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) + fn to_bytes(&self) -> [u8; 32] { + JubJubAffine::from(self.0).to_bytes() } -} -impl fmt::Display for PublicKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:x}", self) + fn from_bytes(bytes: &[u8; 32]) -> Result { + Ok(Self(JubJubAffine::from_bytes(bytes)?.into())) } } diff --git a/src/keys/secret.rs b/src/keys/secret.rs index 8a8705f..522db94 100644 --- a/src/keys/secret.rs +++ b/src/keys/secret.rs @@ -4,16 +4,20 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use crate::{Error, JubJubScalar}; -use core::convert::TryFrom; -use core::fmt; +use crate::JubJubScalar; +use dusk_bytes::{Error, HexDebug, Serializable}; use rand_core::{CryptoRng, RngCore}; +#[cfg(feature = "canon")] +use canonical::Canon; +#[cfg(feature = "canon")] +use canonical_derive::Canon; + #[allow(non_snake_case)] -#[derive(Default, Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] #[cfg_attr(feature = "canon", derive(Canon))] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, HexDebug)] /// Structure repesenting a secret key -pub struct SecretKey(JubJubScalar); +pub struct SecretKey(pub(crate) JubJubScalar); impl From for SecretKey { fn from(s: JubJubScalar) -> SecretKey { @@ -36,7 +40,7 @@ impl AsRef for SecretKey { impl SecretKey { /// This will create a random [`SecretKey`] from a scalar /// of the Field JubJubScalar. - pub fn new(rand: &mut T) -> SecretKey + pub fn random(rand: &mut T) -> SecretKey where T: RngCore + CryptoRng, { @@ -44,57 +48,16 @@ impl SecretKey { SecretKey(fr) } - - /// Copies `self` into a new array of 32 bytes. - pub fn to_bytes(&self) -> [u8; 32] { - let mut bytes = [0u8; 32]; - bytes.copy_from_slice(&self.0.to_bytes()); - bytes - } - - /// Create a new [`SecretKey`] from an array of 32 bytes. - pub fn from_bytes(bytes: &[u8; 32]) -> Result { - match Option::from(JubJubScalar::from_bytes(bytes)) { - Some(scalar) => Ok(SecretKey(scalar)), - _ => Err(Error::InvalidScalar), - } - } -} - -impl fmt::LowerHex for SecretKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes = self.to_bytes(); - - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) - } } -impl fmt::UpperHex for SecretKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes = self.to_bytes(); +impl Serializable<32> for SecretKey { + type Error = Error; - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) + fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() } -} -impl fmt::Display for SecretKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:x}", self) + fn from_bytes(bytes: &[u8; 32]) -> Result { + Ok(Self(JubJubScalar::from_bytes(bytes)?)) } } diff --git a/src/keys/spend/public.rs b/src/keys/spend/public.rs index 044b2db..83b4cf6 100644 --- a/src/keys/spend/public.rs +++ b/src/keys/spend/public.rs @@ -4,8 +4,10 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use crate::Error; -use crate::{permutation, JubJubAffine, JubJubExtended, JubJubScalar, StealthAddress}; +use crate::{ + permutation, JubJubAffine, JubJubExtended, JubJubScalar, PublicKey, + StealthAddress, +}; use super::secret::SecretSpendKey; @@ -14,14 +16,12 @@ use canonical::Canon; #[cfg(feature = "canon")] use canonical_derive::Canon; +use dusk_bytes::{DeserializableSlice, Error, HexDebug, Serializable}; use dusk_jubjub::GENERATOR_EXTENDED; use subtle::{Choice, ConstantTimeEq}; -use core::convert::TryFrom; -use core::fmt; - /// Public pair of `a·G` and `b·G` defining a [`PublicSpendKey`] -#[derive(Debug, Clone, Copy)] +#[derive(HexDebug, Clone, Copy)] #[cfg_attr(feature = "canon", derive(Canon))] pub struct PublicSpendKey { A: JubJubExtended, @@ -29,8 +29,8 @@ pub struct PublicSpendKey { } impl PublicSpendKey { - /// This method is used to construct a new `PublicSpendKey` from the given public - /// pair of `a·G` and `b·G` + /// This method is used to construct a new `PublicSpendKey` from the given + /// public pair of `a·G` and `b·G` pub fn new(A: JubJubExtended, B: JubJubExtended) -> Self { Self { A, B } } @@ -55,6 +55,7 @@ impl PublicSpendKey { let rA = G * rA; let pk_r = rA + self.B; + let pk_r = PublicKey(pk_r); StealthAddress { R, pk_r } } @@ -74,12 +75,6 @@ impl PartialEq for PublicSpendKey { impl Eq for PublicSpendKey {} -impl Default for PublicSpendKey { - fn default() -> Self { - SecretSpendKey::default().public_spend_key() - } -} - impl From for PublicSpendKey { fn from(secret: SecretSpendKey) -> Self { secret.public_spend_key() @@ -92,72 +87,20 @@ impl From<&SecretSpendKey> for PublicSpendKey { } } -impl From<&PublicSpendKey> for [u8; 64] { - fn from(pk: &PublicSpendKey) -> [u8; 64] { - let mut bytes = [0u8; 64]; - bytes[..32].copy_from_slice(&JubJubAffine::from(pk.A).to_bytes()[..]); - bytes[32..].copy_from_slice(&JubJubAffine::from(pk.B).to_bytes()[..]); - bytes - } -} - -impl TryFrom<&str> for PublicSpendKey { +impl Serializable<64> for PublicSpendKey { type Error = Error; - fn try_from(s: &str) -> Result { - use crate::decode::decode; - - if s.len() != 128 { - return Err(Error::BadLength { - found: s.len(), - expected: 128, - }); - } - - let A = hex::decode(&s[..64]).map_err(|_| Error::InvalidPoint)?; - let A = JubJubExtended::from(decode::(&A[..])?); - - let B = hex::decode(&s[64..]).map_err(|_| Error::InvalidPoint)?; - let B = JubJubExtended::from(decode::(&B[..])?); - - Ok(PublicSpendKey::new(A, B)) - } -} - -impl fmt::LowerHex for PublicSpendKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes: [u8; 64] = self.into(); - - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) + fn to_bytes(&self) -> [u8; Self::SIZE] { + let mut bytes = [0u8; Self::SIZE]; + bytes[..32].copy_from_slice(&JubJubAffine::from(self.A).to_bytes()); + bytes[32..].copy_from_slice(&JubJubAffine::from(self.B).to_bytes()); + bytes } -} - -impl fmt::UpperHex for PublicSpendKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes: [u8; 64] = self.into(); - - if f.alternate() { - write!(f, "0x")? - } - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) - } -} + fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result { + let A = JubJubExtended::from(JubJubAffine::from_slice(&bytes[..32])?); + let B = JubJubExtended::from(JubJubAffine::from_slice(&bytes[32..])?); -impl fmt::Display for PublicSpendKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:x}", self) + Ok(Self { A, B }) } } diff --git a/src/keys/spend/secret.rs b/src/keys/spend/secret.rs index 7d47619..ea9ff49 100644 --- a/src/keys/spend/secret.rs +++ b/src/keys/spend/secret.rs @@ -4,7 +4,7 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use crate::{permutation, JubJubScalar, ViewKey}; +use crate::{permutation, JubJubScalar, SecretKey, ViewKey}; use super::public::PublicSpendKey; use super::stealth::StealthAddress; @@ -14,13 +14,13 @@ use canonical::Canon; #[cfg(feature = "canon")] use canonical_derive::Canon; +use dusk_bytes::{DeserializableSlice, Error, HexDebug, Serializable}; use dusk_jubjub::GENERATOR_EXTENDED; use rand_core::{CryptoRng, RngCore}; - -use core::fmt; +use subtle::{Choice, ConstantTimeEq}; /// Secret pair of `a` and `b` defining a [`SecretSpendKey`] -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, Eq, HexDebug)] #[cfg_attr(feature = "canon", derive(Canon))] pub struct SecretSpendKey { a: JubJubScalar, @@ -28,8 +28,8 @@ pub struct SecretSpendKey { } impl SecretSpendKey { - /// This method is used to construct a new `SecretSpendKey` from the given secret - /// pair of `a` and `b`. + /// This method is used to construct a new `SecretSpendKey` from the given + /// secret pair of `a` and `b`. pub fn new(a: JubJubScalar, b: JubJubScalar) -> Self { Self { a, b } } @@ -53,12 +53,13 @@ impl SecretSpendKey { SecretSpendKey::new(a, b) } - /// Generate a `sk_r = H(a · R) + b` - pub fn sk_r(&self, sa: &StealthAddress) -> JubJubScalar { + /// Generates a [`SecretKey`] using the [`StealthAddress`] given. + /// With the formula: `sk_r = H(a · R) + b` + pub fn sk_r(&self, sa: &StealthAddress) -> SecretKey { let aR = sa.R() * self.a; let aR = permutation::hash(&aR); - aR + self.b + SecretKey(aR + self.b) } /// Derive the secret to deterministically construct a [`PublicSpendKey`] @@ -77,49 +78,32 @@ impl SecretSpendKey { } } -impl From<&SecretSpendKey> for [u8; 64] { - fn from(pk: &SecretSpendKey) -> Self { - let mut bytes = [0u8; 64]; - bytes[..32].copy_from_slice(&pk.a.to_bytes()[..]); - bytes[32..].copy_from_slice(&pk.b.to_bytes()[..]); - bytes +impl ConstantTimeEq for SecretSpendKey { + fn ct_eq(&self, other: &Self) -> Choice { + self.a.ct_eq(&other.a) & self.b.ct_eq(&other.b) } } -impl fmt::LowerHex for SecretSpendKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes: [u8; 64] = self.into(); - - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) +impl PartialEq for SecretSpendKey { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(&other).into() } } -impl fmt::UpperHex for SecretSpendKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes: [u8; 64] = self.into(); +impl Serializable<64> for SecretSpendKey { + type Error = Error; - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) + fn to_bytes(&self) -> [u8; 64] { + let mut bytes = [0u8; 64]; + bytes[..32].copy_from_slice(&self.a.to_bytes()); + bytes[32..].copy_from_slice(&self.b.to_bytes()); + bytes } -} -impl fmt::Display for SecretSpendKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:x}", self) + fn from_bytes(buf: &[u8; 64]) -> Result { + let a = JubJubScalar::from_slice(&buf[..32])?; + let b = JubJubScalar::from_slice(&buf[32..])?; + + Ok(Self { a, b }) } } diff --git a/src/keys/spend/stealth.rs b/src/keys/spend/stealth.rs index e6bacba..2fdcbc0 100644 --- a/src/keys/spend/stealth.rs +++ b/src/keys/spend/stealth.rs @@ -4,27 +4,24 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use crate::{decode::decode, Error, JubJubAffine, JubJubExtended}; - +use crate::{JubJubAffine, JubJubExtended, PublicKey}; #[cfg(feature = "canon")] use canonical::Canon; #[cfg(feature = "canon")] use canonical_derive::Canon; +use dusk_bytes::{DeserializableSlice, Error, HexDebug, Serializable}; use subtle::{Choice, ConstantTimeEq}; -use core::convert::{TryFrom, TryInto}; -use core::fmt; - -//. To obfuscate the identity of the participants, we utilizes a Stealth Address -//. system. +/// To obfuscate the identity of the participants, we utilizes a Stealth Address +/// system. /// A `StealthAddress` is composed by a one-time public key (`pk_r`, the actual // address) and a random point `R`. -#[derive(Debug, Clone, Copy)] +#[derive(HexDebug, Clone, Copy)] #[cfg_attr(feature = "canon", derive(Canon))] pub struct StealthAddress { pub(crate) R: JubJubExtended, - pub(crate) pk_r: JubJubExtended, + pub(crate) pk_r: PublicKey, } /// The trait `Ownable` is required by any type that wants to prove its @@ -34,32 +31,6 @@ pub trait Ownable { fn stealth_address(&self) -> &StealthAddress; } -impl Ownable for StealthAddress { - fn stealth_address(&self) -> &StealthAddress { - &self - } -} - -impl From<&StealthAddress> for [u8; 64] { - fn from(sa: &StealthAddress) -> [u8; 64] { - let mut bytes = [0u8; 64]; - bytes[..32].copy_from_slice(&JubJubAffine::from(sa.R).to_bytes()[..]); - bytes[32..].copy_from_slice(&JubJubAffine::from(sa.pk_r).to_bytes()[..]); - bytes - } -} - -impl TryFrom<&[u8; 64]> for StealthAddress { - type Error = Error; - - fn try_from(bytes: &[u8; 64]) -> Result { - let R = JubJubExtended::from(decode::(&bytes[..32])?); - let pk_r = JubJubExtended::from(decode::(&bytes[32..])?); - - Ok(StealthAddress { R, pk_r }) - } -} - impl StealthAddress { /// Gets the random point `R` pub fn R(&self) -> &JubJubExtended { @@ -67,29 +38,19 @@ impl StealthAddress { } /// Gets the `pk_r` - pub fn pk_r(&self) -> &JubJubExtended { + pub fn pk_r(&self) -> &PublicKey { &self.pk_r } - /// Alias to `pk_r()` method + /// Gets the underline `JubJubExtended` point of `pk_r` pub fn address(&self) -> &JubJubExtended { - &self.pk_r - } - - /// Encode the `StealthAddress` to an array of 64 bytes - pub fn to_bytes(&self) -> [u8; 64] { - self.into() - } - - /// Decode the `StealthAddress` from an array of 64 bytes - pub fn from_bytes(bytes: &[u8; 64]) -> Result { - bytes.try_into() + &self.pk_r.as_ref() } } impl ConstantTimeEq for StealthAddress { fn ct_eq(&self, other: &Self) -> Choice { - self.pk_r.ct_eq(&other.pk_r) & self.R.ct_eq(&other.R) + self.pk_r.as_ref().ct_eq(&other.pk_r.as_ref()) & self.R.ct_eq(&other.R) } } @@ -99,60 +60,30 @@ impl PartialEq for StealthAddress { } } -impl fmt::LowerHex for StealthAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes: [u8; 64] = self.into(); - - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) - } -} - -impl fmt::UpperHex for StealthAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes: [u8; 64] = self.into(); - - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) - } -} - -impl fmt::Display for StealthAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:x}", self) +impl Ownable for StealthAddress { + fn stealth_address(&self) -> &StealthAddress { + &self } } -impl TryFrom<&str> for StealthAddress { +impl Serializable<64> for StealthAddress { type Error = Error; + /// Encode the `StealthAddress` to an array of 64 bytes + fn to_bytes(&self) -> [u8; Self::SIZE] { + let mut bytes = [0u8; Self::SIZE]; + bytes[..32].copy_from_slice(&JubJubAffine::from(self.R).to_bytes()); + bytes[32..].copy_from_slice( + &JubJubAffine::from(self.pk_r.as_ref()).to_bytes(), + ); + bytes + } - fn try_from(s: &str) -> Result { - if s.len() != 128 { - return Err(Error::BadLength { - found: s.len(), - expected: 128, - }); - } - - let R = hex::decode(&s[..64]).map_err(|_| Error::InvalidPoint)?; - let R = JubJubExtended::from(decode::(&R[..])?); - - let pk_r = hex::decode(&s[64..]).map_err(|_| Error::InvalidPoint)?; - let pk_r = JubJubExtended::from(decode::(&pk_r[..])?); + /// Decode the `StealthAddress` from an array of 64 bytes + fn from_bytes(bytes: &[u8; Self::SIZE]) -> Result { + let R = JubJubExtended::from(JubJubAffine::from_slice(&bytes[..32])?); + let pk_r = + JubJubExtended::from(JubJubAffine::from_slice(&bytes[32..])?); + let pk_r = PublicKey(pk_r); Ok(StealthAddress { R, pk_r }) } diff --git a/src/lib.rs b/src/lib.rs index 369e49c..446412f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,11 +17,6 @@ #![deny(missing_docs)] #![allow(non_snake_case)] -pub use decode::decode as jubjub_decode; - -/// PKI Errors -pub use errors::Error; - /// Public Key pub use keys::public::PublicKey; /// Secret Key @@ -35,8 +30,6 @@ pub use keys::spend::stealth::{Ownable, StealthAddress}; /// ViewKey pub use view::ViewKey; -mod decode; -mod errors; mod keys; mod permutation; mod view; diff --git a/src/view.rs b/src/view.rs index f3129cb..0dcf5df 100644 --- a/src/view.rs +++ b/src/view.rs @@ -6,22 +6,20 @@ use crate::keys::spend::stealth; -use crate::Error; use crate::{ - permutation, JubJubAffine, JubJubExtended, JubJubScalar, PublicSpendKey, SecretSpendKey, + permutation, JubJubAffine, JubJubExtended, JubJubScalar, PublicSpendKey, + SecretSpendKey, }; +use dusk_bytes::{DeserializableSlice, Error, HexDebug, Serializable}; use dusk_jubjub::GENERATOR_EXTENDED; use subtle::{Choice, ConstantTimeEq}; -use core::convert::TryFrom; -use core::fmt; - /// Pair of a secret `a` and public `b·G` /// /// The notes are encrypted against secret a, so this is used to decrypt the /// blinding factor and value -#[derive(Debug, Clone, Copy)] +#[derive(Clone, Copy, HexDebug)] pub struct ViewKey { a: JubJubScalar, B: JubJubExtended, @@ -42,12 +40,6 @@ impl PartialEq for ViewKey { impl Eq for ViewKey {} -impl Default for ViewKey { - fn default() -> Self { - SecretSpendKey::default().view_key() - } -} - impl ViewKey { /// This method is used to construct a new `ViewKey` from the given /// pair of secret `a` and public `b·G`. @@ -81,7 +73,7 @@ impl ViewKey { let aR = GENERATOR_EXTENDED * aR; let pk_r = aR + self.B(); - sa.pk_r() == &pk_r + sa.address() == &pk_r } } @@ -97,72 +89,20 @@ impl From<&SecretSpendKey> for ViewKey { } } -impl From<&ViewKey> for [u8; 64] { - fn from(vk: &ViewKey) -> Self { - let mut bytes = [0u8; 64]; - bytes[..32].copy_from_slice(&vk.a.to_bytes()[..]); - bytes[32..].copy_from_slice(&JubJubAffine::from(&vk.B).to_bytes()[..]); - bytes - } -} - -impl TryFrom<&str> for ViewKey { +impl Serializable<64> for ViewKey { type Error = Error; - fn try_from(s: &str) -> Result { - use crate::decode::decode; - - if s.len() != 128 { - return Err(Error::BadLength { - found: s.len(), - expected: 128, - }); - } - - let a = hex::decode(&s[..64]).map_err(|_| Error::InvalidPoint)?; - let a = decode::(&a[..])?; - - let B = hex::decode(&s[64..]).map_err(|_| Error::InvalidPoint)?; - let B = JubJubExtended::from(decode::(&B[..])?); - - Ok(ViewKey::new(a, B)) - } -} - -impl fmt::LowerHex for ViewKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes: [u8; 64] = self.into(); - - if f.alternate() { - write!(f, "0x")? - } - - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) + fn to_bytes(&self) -> [u8; 64] { + let mut bytes = [0u8; 64]; + bytes[..32].copy_from_slice(&self.a.to_bytes()); + bytes[32..].copy_from_slice(&JubJubAffine::from(&self.B).to_bytes()); + bytes } -} - -impl fmt::UpperHex for ViewKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let bytes: [u8; 64] = self.into(); - - if f.alternate() { - write!(f, "0x")? - } - for byte in &bytes[..] { - write!(f, "{:02X}", &byte)? - } - - Ok(()) - } -} + fn from_bytes(buf: &[u8; 64]) -> Result { + let a = JubJubScalar::from_slice(&buf[..32])?; + let B = JubJubExtended::from(JubJubAffine::from_slice(&buf[32..])?); -impl fmt::Display for ViewKey { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:x}", self) + Ok(Self { a, B }) } } diff --git a/tests/tests.rs b/tests/tests.rs index 8162287..40ba52f 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -5,10 +5,9 @@ // Copyright (c) DUSK NETWORK. All rights reserved. mod std_tests { - use core::convert::TryFrom; + use dusk_bytes::ParseHexStr; use dusk_pki::{PublicSpendKey, SecretSpendKey, ViewKey}; use rand::SeedableRng; - fn ssk_from_str(s: &str) -> SecretSpendKey { use rand::rngs::StdRng; use sha2::{Digest, Sha256}; @@ -39,10 +38,14 @@ mod std_tests { let vk = ssk.view_key(); let psk = ssk.public_spend_key(); - assert_eq!(vk, ViewKey::try_from(format!("{}", vk).as_str()).unwrap()); + assert_eq!( + vk, + ViewKey::from_hex_str(format!("{:x}", vk).as_str()).unwrap() + ); assert_eq!( psk, - PublicSpendKey::try_from(format!("{}", psk).as_str()).unwrap() + PublicSpendKey::from_hex_str(format!("{:x}", psk).as_str()) + .unwrap() ); } @@ -69,7 +72,7 @@ mod std_tests { let sk_r = ssk.sk_r(&sa); let wrong_sk_r = wrong_ssk.sk_r(&sa); - assert_eq!(sa.pk_r(), &(GENERATOR_EXTENDED * &sk_r)); - assert_ne!(sa.pk_r(), &(GENERATOR_EXTENDED * &wrong_sk_r)); + assert_eq!(sa.address(), &(GENERATOR_EXTENDED * sk_r.as_ref())); + assert_ne!(sa.address(), &(GENERATOR_EXTENDED * wrong_sk_r.as_ref())); } }