diff --git a/Cargo.toml b/Cargo.toml index 21189bd..508e11b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ blake2b_simd = "0.5" jubjub = "0.3" [dev-dependencies] +rand = "0.7" rand_chacha = "0.2" proptest = "0.9" lazy_static = "1.4" diff --git a/README.md b/README.md index 4a7f711..d39e738 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,51 @@ -# redjubjub-zebra +A minimal [RedJubjub][redjubjub] implementation for use in [Zebra][zebra]. -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. + +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. + +## Examples + +Creating a `BindingSig`, serializing and deserializing it, and verifying the +signature: + +``` +# use std::convert::TryFrom; +use rand::thread_rng; +use redjubjub_zebra::*; + +let msg = b"Hello!"; + +// Generate a secret key and sign the message +let sk = SecretKey::::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(); + +// Deserialize and verify the signature. +let sig: Signature = sig_bytes.into(); +assert!( + PublicKey::try_from(pk_bytes) + .and_then(|pk| pk.verify(msg, &sig)) + .is_ok() +); +``` ## docs -``` +```shell,no_run cargo doc --features "nightly" --open ``` [redjubjub]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa [zebra]: https://github.com/ZcashFoundation/zebra +[refinement]: https://en.wikipedia.org/wiki/Refinement_type +[sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed \ No newline at end of file diff --git a/src/public_key.rs b/src/public_key.rs index 4484eaa..b5a8696 100644 --- a/src/public_key.rs +++ b/src/public_key.rs @@ -29,7 +29,11 @@ impl From> for [u8; 32] { } } -/// A RedJubJub public key. +/// A valid RedJubJub public 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]`. #[derive(Copy, Clone, Debug)] pub struct PublicKey { // XXX-jubjub: this should just be Point @@ -43,6 +47,12 @@ impl From> for PublicKeyBytes { } } +impl From> for [u8; 32] { + fn from(pk: PublicKey) -> [u8; 32] { + pk.bytes.bytes + } +} + impl TryFrom> for PublicKey { type Error = Error; @@ -61,6 +71,15 @@ impl TryFrom> for PublicKey { } } +impl TryFrom<[u8; 32]> for PublicKey { + type Error = Error; + + fn try_from(bytes: [u8; 32]) -> Result { + use std::convert::TryInto; + PublicKeyBytes::from(bytes).try_into() + } +} + impl PublicKey { /// Randomize this public key with the given `randomizer`. ///