Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flesh out redpallas, direct port of redjubjub #2099

Merged
merged 5 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion zebra-chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,14 @@ zebra-test = { path = "../zebra-test/", optional = true }
bincode = "1"
color-eyre = "0.5.11"
criterion = { version = "0.3", features = ["html_reports"] }
itertools = "0.10.0"
spandoc = "0.2"
tracing = "0.1.25"

proptest = "0.10"
proptest-derive = "0.3"
itertools = "0.10.0"
rand = "0.8"
rand_chacha = "0.3"

zebra-test = { path = "../zebra-test/" }

Expand Down
24 changes: 20 additions & 4 deletions zebra-chain/src/primitives/redpallas.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,35 @@
// XXX: Extracted from redjubjub for now.
// -*- mode: rust; -*-
//
// This file is part of redjubjub.
// Copyright (c) 2019-2021 Zcash Foundation
// See LICENSE for licensing information.
//
// Authors:
// - Deirdre Connolly <deirdre@zfnd.org>
// - Henry de Valence <hdevalence@hdevalence.ca>

use group::GroupEncoding;
use halo2::pasta::pallas;

// pub mod batch;
mod constants;
mod error;
// TODO: full redpallas implementation https://github.com/ZcashFoundation/zebra/issues/2044
mod hash;
mod signature;
mod signing_key;
#[cfg(test)]
mod tests;
mod verification_key;

pub use error::Error;
pub use hash::HStar;
pub use signature::Signature;
pub use signing_key::SigningKey;
pub use verification_key::{VerificationKey, VerificationKeyBytes};

/// An element of the Pallas scalar field used for randomization of verification
/// and signing keys.
pub type Randomizer = pallas::Scalar;

/// Abstracts over different RedPallas parameter choices, [`Binding`]
/// and [`SpendAuth`].
///
Expand All @@ -25,7 +41,7 @@ pub use verification_key::{VerificationKey, VerificationKeyBytes};
/// To handle this, we encode the parameter choice as a genuine type
/// parameter.
///
/// [concretereddsa]: https://zips.z.cash/protocol/protocol.pdf#concretereddsa
/// [concretereddsa]: https://zips.z.cash/protocol/nu5.pdf#concretereddsa
pub trait SigType: private::Sealed {}

/// A type variable corresponding to Zcash's `BindingSig`.
Expand Down
12 changes: 7 additions & 5 deletions zebra-chain/src/primitives/redpallas/constants.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// -*- mode: rust; -*-
//
// This file is part of redjubjub.
// This file is part of redpallas.
// Copyright (c) 2019-2021 Zcash Foundation
// See LICENSE for licensing information.
//
Expand All @@ -10,13 +10,15 @@
/// The byte-encoding of the basepoint for `SpendAuthSig` on the [Pallas curve][pallasandvesta].
///
/// [pallasandvesta]: https://zips.z.cash/protocol/nu5.pdf#pallasandvesta
// Reproducible by pallas::Point::hash_to_curve("z.cash:Orchard")(b"G").to_bytes()
pub const SPENDAUTHSIG_BASEPOINT_BYTES: [u8; 32] = [
215, 148, 162, 4, 167, 65, 231, 17, 216, 7, 4, 206, 68, 161, 32, 20, 67, 192, 174, 143, 131,
35, 240, 117, 113, 113, 7, 198, 56, 190, 133, 53,
99, 201, 117, 184, 132, 114, 26, 141, 12, 161, 112, 123, 227, 12, 127, 12, 95, 68, 95, 62, 124,
24, 141, 59, 6, 214, 241, 40, 179, 35, 85, 183,
];

/// The byte-encoding of the basepoint for `BindingSig` on the Pallas curve.
// Reproducible by pallas::Point::hash_to_curve("z.cash:Orchard-cv")(b"r").to_bytes()
pub const BINDINGSIG_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,
145, 90, 60, 136, 104, 198, 195, 14, 47, 128, 144, 238, 69, 215, 110, 64, 72, 32, 141, 234, 91,
35, 102, 79, 187, 9, 164, 15, 85, 68, 244, 7,
];
40 changes: 40 additions & 0 deletions zebra-chain/src/primitives/redpallas/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// -*- mode: rust; -*-
//
// This file is part of redpallas.
// Copyright (c) 2019-2021 Zcash Foundation
// See LICENSE for licensing information.
//
// Authors:
// - Deirdre Connolly <deirdre@zfnd.org>
// - Henry de Valence <hdevalence@hdevalence.ca>

use blake2b_simd::{Params, State};
use halo2::{arithmetic::FieldExt, pasta::pallas::Scalar};

/// Provides H^star, the hash-to-scalar function used by RedPallas.
pub struct HStar {
state: State,
}

impl Default for HStar {
fn default() -> Self {
let state = Params::new()
.hash_length(64)
.personal(b"Zcash_RedPallasH")
.to_state();
Self { state }
}
}

impl HStar {
/// Add `data` to the hash, and return `Self` for chaining.
pub fn update(&mut self, data: impl AsRef<[u8]>) -> &mut Self {
self.state.update(data.as_ref());
self
}

/// Consume `self` to compute the hash output.
pub fn finalize(&self) -> Scalar {
Scalar::from_bytes_wide(self.state.finalize().as_array())
}
}
45 changes: 45 additions & 0 deletions zebra-chain/src/primitives/redpallas/signature.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// -*- mode: rust; -*-
//
// This file is part of redpallas.
// Copyright (c) 2019-2021 Zcash Foundation
// See LICENSE for licensing information.
//
// Authors:
// - Henry de Valence <hdevalence@hdevalence.ca>
// - Deirdre Connolly <deirdre@zfnd.org>

use std::marker::PhantomData;

use super::SigType;

/// A RedPallas signature.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Signature<T: SigType> {
pub(crate) r_bytes: [u8; 32],
pub(crate) s_bytes: [u8; 32],
pub(crate) _marker: PhantomData<T>,
}

impl<T: SigType> From<[u8; 64]> for Signature<T> {
fn from(bytes: [u8; 64]) -> Signature<T> {
let mut r_bytes = [0; 32];
r_bytes.copy_from_slice(&bytes[0..32]);
let mut s_bytes = [0; 32];
s_bytes.copy_from_slice(&bytes[32..64]);
Signature {
r_bytes,
s_bytes,
_marker: PhantomData,
}
}
}

impl<T: SigType> From<Signature<T>> for [u8; 64] {
fn from(sig: Signature<T>) -> [u8; 64] {
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&sig.r_bytes[..]);
bytes[32..64].copy_from_slice(&sig.s_bytes[..]);
bytes
}
}
96 changes: 91 additions & 5 deletions zebra-chain/src/primitives/redpallas/signing_key.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::convert::TryFrom;
use std::convert::{TryFrom, TryInto};
use std::marker::PhantomData;

use halo2::arithmetic::FieldExt;
use halo2::pasta::pallas;
use group::GroupEncoding;
use halo2::{arithmetic::FieldExt, pasta::pallas};
use rand_core::{CryptoRng, RngCore};

use super::{Error, SigType, VerificationKey};
use super::{Error, SigType, Signature, SpendAuth, VerificationKey};

/// A RedPallas signing key.
#[derive(Copy, Clone, Debug)]
Expand All @@ -22,6 +24,12 @@ impl<'a, T: SigType> From<&'a SigningKey<T>> for VerificationKey<T> {
}
}

impl<T: SigType> From<SigningKey<T>> for [u8; 32] {
fn from(sk: SigningKey<T>) -> [u8; 32] {
sk.sk.to_bytes()
}
}

impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {
type Error = Error;

Expand All @@ -30,10 +38,88 @@ impl<T: SigType> TryFrom<[u8; 32]> for SigningKey<T> {

if maybe_sk.is_some().into() {
let sk = maybe_sk.unwrap();
let pk = VerificationKey::from(&sk);
let pk = VerificationKey::from_scalar(&sk);
Ok(SigningKey { sk, pk })
} else {
Err(Error::MalformedSigningKey)
}
}
}

#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
struct SerdeHelper([u8; 32]);

impl<T: SigType> TryFrom<SerdeHelper> for SigningKey<T> {
type Error = Error;

fn try_from(helper: SerdeHelper) -> Result<Self, Self::Error> {
helper.0.try_into()
}
}

impl<T: SigType> From<SigningKey<T>> for SerdeHelper {
fn from(sk: SigningKey<T>) -> Self {
Self(sk.into())
}
}

impl SigningKey<SpendAuth> {
/// Randomize this public key with the given `randomizer`.
pub fn randomize(&self, randomizer: &pallas::Scalar) -> SigningKey<SpendAuth> {
let sk = self.sk + randomizer;
let pk = VerificationKey::from_scalar(&sk);
SigningKey { sk, pk }
}
}

impl<T: SigType> SigningKey<T> {
/// Generate a new signing key.
pub fn new<R: RngCore + CryptoRng>(mut rng: R) -> SigningKey<T> {
let sk = {
let mut bytes = [0; 64];
rng.fill_bytes(&mut bytes);
pallas::Scalar::from_bytes_wide(&bytes)
};
let pk = VerificationKey::from_scalar(&sk);
SigningKey { sk, pk }
}

/// Create a signature of type `T` on `msg` using this `SigningKey`.
///
/// https://zips.z.cash/protocol/nu5.pdf#concretereddsa
// Similar to signature::Signer but without boxed errors.
pub fn sign<R: RngCore + CryptoRng>(&self, mut rng: R, msg: &[u8]) -> Signature<T> {
use super::HStar;

// RedDSA.GenRandom:() → R RedDSA.Random
// Choose a byte sequence uniformly at random of length
// (\ell_H + 128)/8 bytes. For RedPallas this is (512 + 128)/8 = 80.
let random_bytes = {
let mut bytes = [0; 80];
rng.fill_bytes(&mut bytes);
bytes
};

let nonce = HStar::default()
.update(&random_bytes[..])
.update(&self.pk.bytes.bytes[..]) // XXX ugly
.update(msg)
.finalize();

let r_bytes = pallas::Affine::from(T::basepoint() * nonce).to_bytes();

let c = HStar::default()
.update(&r_bytes[..])
.update(&self.pk.bytes.bytes[..]) // XXX ugly
dconnolly marked this conversation as resolved.
Show resolved Hide resolved
.update(msg)
.finalize();

let s_bytes = (nonce + (c * self.sk)).to_bytes();

Signature {
r_bytes,
s_bytes,
_marker: PhantomData,
}
}
}
2 changes: 2 additions & 0 deletions zebra-chain/src/primitives/redpallas/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod basepoints;
mod prop;
22 changes: 22 additions & 0 deletions zebra-chain/src/primitives/redpallas/tests/basepoints.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use group::GroupEncoding;
use halo2::pasta::{arithmetic::CurveExt, pallas};

use super::super::constants;

#[test]
fn orchard_spendauth_basepoint() {
assert_eq!(
// An instance of _GroupHash^P_
pallas::Point::hash_to_curve("z.cash:Orchard")(b"G").to_bytes(),
constants::SPENDAUTHSIG_BASEPOINT_BYTES
);
}

#[test]
fn orchard_binding_basepoint() {
assert_eq!(
// An instance of _GroupHash^P_
pallas::Point::hash_to_curve("z.cash:Orchard-cv")(b"r").to_bytes(),
constants::BINDINGSIG_BASEPOINT_BYTES
);
}
Loading