Skip to content

Commit

Permalink
Merge of #3962
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Jun 28, 2022
2 parents 0e955b6 + 786d2c2 commit 06ab590
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 14 deletions.
4 changes: 3 additions & 1 deletion zebra-chain/src/orchard/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ mod tests {
// Default diversifier, where index = 0.
let diversifier_key = keys::DiversifierKey::from(full_viewing_key);

let incoming_viewing_key = keys::IncomingViewingKey::from(full_viewing_key);
// This should fail with negligible probability.
let incoming_viewing_key = keys::IncomingViewingKey::try_from(full_viewing_key)
.expect("a valid incoming viewing key");

let diversifier = keys::Diversifier::from(diversifier_key);
let transmission_key = keys::TransmissionKey::from((incoming_viewing_key, diversifier));
Expand Down
3 changes: 2 additions & 1 deletion zebra-chain/src/orchard/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ impl Arbitrary for keys::TransmissionKey {
let diversifier_key = keys::DiversifierKey::from(full_viewing_key);

let diversifier = Diversifier::from(diversifier_key);
let incoming_viewing_key = keys::IncomingViewingKey::from(full_viewing_key);
let incoming_viewing_key = keys::IncomingViewingKey::try_from(full_viewing_key)
.expect("a valid incoming viewing key");

Self::from((incoming_viewing_key, diversifier))
})
Expand Down
79 changes: 69 additions & 10 deletions zebra-chain/src/orchard/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use bitvec::prelude::*;
use fpe::ff1::{BinaryNumeralString, FF1};
use group::{ff::PrimeField, prime::PrimeCurveAffine, Group, GroupEncoding};
use halo2::{
arithmetic::{Coordinates, CurveAffine, FieldExt},
arithmetic::{Coordinates, CurveAffine, Field, FieldExt},
pasta::pallas,
};
use rand_core::{CryptoRng, RngCore};
Expand Down Expand Up @@ -205,7 +205,12 @@ impl SpendingKey {
let sk = Self::from_bytes(bytes, network);

// "if ask = 0, discard this key and repeat with a new sk"
if SpendAuthorizingKey::from(sk).0 == pallas::Scalar::zero() {
if SpendAuthorizingKey::from(sk).0.is_zero().into() {
continue;
}

// "if ivk ∈ {0, ⊥}, discard this key and repeat with a new sk"
if IncomingViewingKey::try_from(FullViewingKey::from(sk)).is_err() {
continue;
}

Expand Down Expand Up @@ -599,7 +604,7 @@ impl PartialEq for FullViewingKey {
#[derive(Copy, Clone)]
pub struct IncomingViewingKey {
dk: DiversifierKey,
// TODO: refine type
// TODO: refine type, so that IncomingViewingkey.ivk cannot be 0
ivk: pallas::Scalar,
}

Expand Down Expand Up @@ -646,7 +651,46 @@ impl From<IncomingViewingKey> for [u8; 64] {
}
}

impl From<FullViewingKey> for IncomingViewingKey {
impl TryFrom<[u8; 64]> for IncomingViewingKey {
type Error = &'static str;

/// Convert an array of bytes into a [`IncomingViewingKey`].
///
/// Returns an error if the encoding is malformed or if it [encodes the scalar additive
/// identity, 0][1].
///
/// > ivk MUST be in the range {1 .. 𝑞P - 1}
///
/// [1]: https://zips.z.cash/protocol/protocol.pdf#orchardinviewingkeyencoding
fn try_from(bytes: [u8; 64]) -> Result<Self, Self::Error> {
let mut dk_bytes = [0u8; 32];
dk_bytes.copy_from_slice(&bytes[..32]);
let dk = DiversifierKey::from(dk_bytes);

let mut ivk_bytes = [0u8; 32];
ivk_bytes.copy_from_slice(&bytes[32..]);

let possible_scalar = pallas::Scalar::from_repr(ivk_bytes);

if possible_scalar.is_some().into() {
let scalar = possible_scalar.unwrap();
if scalar.is_zero().into() {
Err("pallas::Scalar value for Orchard IncomingViewingKey is 0")
} else {
Ok(Self {
dk,
ivk: possible_scalar.unwrap(),
})
}
} else {
Err("Invalid pallas::Scalar value for Orchard IncomingViewingKey")
}
}
}

impl TryFrom<FullViewingKey> for IncomingViewingKey {
type Error = &'static str;

/// Commit^ivk_rivk(ak, nk) :=
/// SinsemillaShortCommit_rcm(︁
/// "z.cash:Orchard-CommitIvk",
Expand All @@ -656,7 +700,7 @@ impl From<FullViewingKey> for IncomingViewingKey {
/// <https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents>
/// <https://zips.z.cash/protocol/nu5.pdf#concreteprfs>
#[allow(non_snake_case)]
fn from(fvk: FullViewingKey) -> Self {
fn try_from(fvk: FullViewingKey) -> Result<Self, Self::Error> {
let mut M: BitVec<u8, Lsb0> = BitVec::new();

// I2LEBSP_l^Orchard_base(ak)︁
Expand All @@ -678,10 +722,18 @@ impl From<FullViewingKey> for IncomingViewingKey {
)
.expect("deriving orchard commit^ivk should not output ⊥ ");

Self {
dk: fvk.into(),
// mod r_P
ivk: pallas::Scalar::from_repr(commit_x.into()).unwrap(),
let ivk_ctoption = pallas::Scalar::from_repr(commit_x.into());

// if ivk ∈ {0, ⊥}, discard this key

// [`Scalar::is_zero()`] is constant-time under the hood, and ivk is mod r_P
if ivk_ctoption.is_some().into() && !<bool>::from(ivk_ctoption.unwrap().is_zero()) {
Ok(Self {
dk: fvk.into(),
ivk: ivk_ctoption.unwrap(),
})
} else {
Err("generated ivk is the additive identity 0, invalid")
}
}
}
Expand Down Expand Up @@ -808,6 +860,12 @@ impl From<FullViewingKey> for DiversifierKey {
}
}

impl From<[u8; 32]> for DiversifierKey {
fn from(bytes: [u8; 32]) -> DiversifierKey {
DiversifierKey(bytes)
}
}

impl From<DiversifierKey> for [u8; 32] {
fn from(dk: DiversifierKey) -> [u8; 32] {
dk.0
Expand Down Expand Up @@ -1006,10 +1064,11 @@ impl From<&OutgoingCipherKey> for [u8; 32] {

// TODO: implement PrivateKey: #2192

/// An ephemeral private key for Orchard key agreement.
/// An _ephemeral private key_ for Orchard key agreement.
///
/// <https://zips.z.cash/protocol/nu5.pdf#concreteorchardkeyagreement>
/// <https://zips.z.cash/protocol/nu5.pdf#saplingandorchardencrypt>
// TODO: refine so that the inner `Scalar` != 0
#[derive(Copy, Clone, Debug)]
pub struct EphemeralPrivateKey(pub(crate) pallas::Scalar);

Expand Down
5 changes: 3 additions & 2 deletions zebra-chain/src/orchard/keys/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ fn generate_keys_from_test_vectors() {
let diversifier_key = DiversifierKey::from(full_viewing_key);
assert_eq!(diversifier_key, test_vector.dk);

let incoming_viewing_key = IncomingViewingKey::from(full_viewing_key);
let incoming_viewing_key =
IncomingViewingKey::try_from(full_viewing_key).expect("a valid incoming viewing key");
assert_eq!(<[u8; 32]>::from(incoming_viewing_key.ivk), test_vector.ivk);

let outgoing_viewing_key = OutgoingViewingKey::from(full_viewing_key);
Expand Down Expand Up @@ -84,7 +85,7 @@ proptest! {
// Test ConstantTimeEq, Eq, PartialEq
assert_eq!(diversifier_key, diversifier_key.clone());

let incoming_viewing_key = IncomingViewingKey::from(full_viewing_key);
let incoming_viewing_key = IncomingViewingKey::try_from(full_viewing_key).expect("a valid incoming viewing key");
// Test ConstantTimeEq, Eq, PartialEq
assert_eq!(incoming_viewing_key, incoming_viewing_key.clone());

Expand Down

0 comments on commit 06ab590

Please sign in to comment.