Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
29 changes: 29 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Use the latest 2.1 version of CircleCI pipeline process engine.
# See: https://circleci.com/docs/2.0/configuration-reference
version: 2.1

# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
jobs:
cargo-test:
# Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub.
# See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor
docker:
- image: cimg/rust:1.59.0
# Add steps to the job
# See: https://circleci.com/docs/2.0/configuration-reference/#steps
steps:
- checkout
- run:
name: "cargo test"
command: |
cargo version;
cargo test;


# Invoke jobs via workflows
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
workflows:
build-and-test:
jobs:
- cargo-test
94 changes: 94 additions & 0 deletions src/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,94 @@ impl SpendValidatingKey {
}
}

/// An issuer authorizing key, used to create issuer authorization signatures.
/// This type enforces that the corresponding public point (ik^ℙ) has ỹ = 0.
///
/// $\mathsf{isk}$ as defined in
/// [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
#[derive(Clone, Debug)]
pub struct IssuerAuthorizingKey(redpallas::SigningKey<SpendAuth>);

impl IssuerAuthorizingKey {
/// Derives isk from sk. Internal use only, does not enforce all constraints.
fn derive_inner(sk: &SpendingKey) -> pallas::Scalar {
to_scalar(PrfExpand::ZsaIsk.expand(&sk.0))
}
}

impl From<&SpendingKey> for IssuerAuthorizingKey {
fn from(sk: &SpendingKey) -> Self {
let isk = Self::derive_inner(sk);
// IssuerSigningKey cannot be constructed such that this assertion would fail.
assert!(!bool::from(isk.is_zero()));
let ret = IssuerAuthorizingKey(isk.to_repr().try_into().unwrap());
// If the last bit of repr_P(ik) is 1, negate isk.
if (<[u8; 32]>::from(IssuerValidatingKey::from(&ret).0)[31] >> 7) == 1 {
IssuerAuthorizingKey((-isk).to_repr().try_into().unwrap())
} else {
ret
}
}
}

/// A key used to validate issuer authorization signatures.
///
/// Defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
/// Note that this is $\mathsf{ik}^\mathbb{P}$, which by construction is equivalent to
/// $\mathsf{ik}$ but stored here as a RedPallas verification key.
///
/// [orchardkeycomponents]: https://zips.z.cash/protocol/nu5.pdf#orchardkeycomponents
#[derive(Debug, Clone, PartialOrd, Ord)]
pub struct IssuerValidatingKey(redpallas::VerificationKey<SpendAuth>);
impl From<&IssuerAuthorizingKey> for IssuerValidatingKey {
fn from(isk: &IssuerAuthorizingKey) -> Self {
IssuerValidatingKey((&isk.0).into())
}
}

impl From<&IssuerValidatingKey> for pallas::Point {
fn from(issuer_validating_key: &IssuerValidatingKey) -> pallas::Point {
pallas::Point::from_bytes(&(&issuer_validating_key.0).into()).unwrap()
}
}

impl PartialEq for IssuerValidatingKey {
fn eq(&self, other: &Self) -> bool {
<[u8; 32]>::from(&self.0).eq(&<[u8; 32]>::from(&other.0))
}
}

impl Eq for IssuerValidatingKey {}

impl IssuerValidatingKey {
/// Converts this spend validating key to its serialized form,
/// I2LEOSP_256(ik).
pub(crate) fn to_bytes(&self) -> [u8; 32] {
// This is correct because the wrapped point must have ỹ = 0, and
// so the point repr is the same as I2LEOSP of its x-coordinate.
<[u8; 32]>::from(&self.0)
}

pub(crate) fn from_bytes(bytes: &[u8]) -> Option<Self> {
<[u8; 32]>::try_from(bytes)
.ok()
.and_then(|b| {
// Structural validity checks for ik_P:
// - The point must not be the identity
// (which for Pallas is canonically encoded as all-zeroes).
// - The sign of the y-coordinate must be positive.
if b != [0; 32] && b[31] & 0x80 == 0 {
<redpallas::VerificationKey<SpendAuth>>::try_from(b).ok()
} else {
None
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is critical, let's extract this into a function to prevent duplication with ak,
something like

fn check_structural_validity(verification_key_bytes: &[u8; 32]) -> Option<&[u8; 32]> {

}

})
.map(IssuerValidatingKey)
}
}

/// A key used to derive [`Nullifier`]s from [`Note`]s.
///
/// $\mathsf{nk}$ as defined in [Zcash Protocol Spec § 4.2.3: Orchard Key Components][orchardkeycomponents].
Expand Down Expand Up @@ -1021,9 +1109,15 @@ mod tests {
let ask: SpendAuthorizingKey = (&sk).into();
assert_eq!(<[u8; 32]>::from(&ask.0), tv.ask);

let isk: IssuerAuthorizingKey = (&sk).into();
assert_eq!(<[u8; 32]>::from(&isk.0), tv.isk);

let ak: SpendValidatingKey = (&ask).into();
assert_eq!(<[u8; 32]>::from(ak.0), tv.ak);

let ik: IssuerValidatingKey = (&isk).into();
assert_eq!(<[u8; 32]>::from(ik.0), tv.ik);

let nk: NullifierDerivingKey = (&sk).into();
assert_eq!(nk.0.to_repr(), tv.nk);

Expand Down
2 changes: 2 additions & 0 deletions src/spec/prf_expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub(crate) enum PrfExpand {
OrchardNk,
OrchardRivk,
Psi,
ZsaIsk,
OrchardZip32Child,
OrchardDkOvk,
OrchardRivkInternal,
Expand All @@ -24,6 +25,7 @@ impl PrfExpand {
Self::OrchardNk => 0x07,
Self::OrchardRivk => 0x08,
Self::Psi => 0x09,
Self::ZsaIsk => 0x0a,
Self::OrchardZip32Child => 0x81,
Self::OrchardDkOvk => 0x82,
Self::OrchardRivkInternal => 0x83,
Expand Down
102 changes: 102 additions & 0 deletions src/test_vectors/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub(crate) struct TestVector {
pub(crate) sk: [u8; 32],
pub(crate) ask: [u8; 32],
pub(crate) ak: [u8; 32],
pub(crate) isk: [u8; 32],
pub(crate) ik: [u8; 32],
pub(crate) nk: [u8; 32],
pub(crate) rivk: [u8; 32],
pub(crate) ivk: [u8; 32],
Expand Down Expand Up @@ -41,6 +43,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0x12, 0x8b, 0x9a, 0x14, 0x0d, 0x5e, 0x07, 0xc1, 0x51, 0x72, 0x1d, 0xc1, 0x6d, 0x25,
0xd4, 0xe2, 0x0f, 0x15,
],
isk: [
0x95, 0x4a, 0x86, 0xc7, 0xa7, 0x15, 0x53, 0xfa, 0x6c, 0x8b, 0x67, 0x58, 0x54, 0x26,
0x8e, 0xa5, 0x4c, 0x51, 0xfb, 0x17, 0xd8, 0x3d, 0x80, 0xee, 0x71, 0xd4, 0xae, 0x42,
0xa1, 0xf8, 0xc8, 0x16,
],
ik: [
0x2e, 0x4f, 0xd4, 0xa6, 0xec, 0x39, 0x94, 0x87, 0xd3, 0x78, 0xb4, 0xc7, 0x25, 0xfb,
0x9b, 0xaf, 0xbc, 0x01, 0xa5, 0xe2, 0xb7, 0xf3, 0x68, 0x2e, 0xf4, 0x53, 0x95, 0x91,
0xbc, 0xf0, 0x59, 0x02,
],
nk: [
0x9f, 0x2f, 0x82, 0x67, 0x38, 0x94, 0x5a, 0xd0, 0x1f, 0x47, 0xf7, 0x0d, 0xb0, 0xc3,
0x67, 0xc2, 0x46, 0xc2, 0x0c, 0x61, 0xff, 0x55, 0x83, 0x94, 0x8c, 0x39, 0xde, 0xa9,
Expand Down Expand Up @@ -132,6 +144,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0x2a, 0xd6, 0x43, 0x23, 0x62, 0x9c, 0xfe, 0xd1, 0xe3, 0xaa, 0x24, 0xef, 0x05, 0x2f,
0x56, 0xe4, 0x00, 0x2a,
],
isk: [
0xee, 0xf5, 0xe9, 0x1b, 0x36, 0xb8, 0x06, 0x86, 0x72, 0x3d, 0x14, 0xdc, 0xc7, 0x04,
0xad, 0x59, 0x67, 0x08, 0x0b, 0x7d, 0x6e, 0x49, 0xaf, 0x97, 0x03, 0x0e, 0x4f, 0xa0,
0xbf, 0x5a, 0xd9, 0x0b,
],
ik: [
0x2e, 0xde, 0xfb, 0x15, 0x8e, 0xa4, 0x48, 0x82, 0x57, 0x2b, 0xcd, 0xb2, 0x35, 0xca,
0x36, 0xab, 0x39, 0xc7, 0x47, 0xbb, 0x71, 0xfe, 0x0f, 0x10, 0xfa, 0xa3, 0x9b, 0xfd,
0x62, 0x0a, 0xcc, 0x04,
],
nk: [
0xa8, 0xb7, 0x3d, 0x97, 0x9b, 0x6e, 0xaa, 0xda, 0x89, 0x24, 0xbc, 0xbd, 0xc6, 0x3a,
0x9e, 0xf4, 0xe8, 0x73, 0x46, 0xf2, 0x30, 0xab, 0xa6, 0xbb, 0xe1, 0xe2, 0xb4, 0x3c,
Expand Down Expand Up @@ -223,6 +245,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0xed, 0xb4, 0x26, 0x65, 0x7b, 0x2d, 0x07, 0x40, 0x66, 0x64, 0xd8, 0x95, 0x31, 0x2e,
0xa1, 0xc3, 0xb3, 0x34,
],
isk: [
0x5b, 0x1f, 0xc4, 0x57, 0xae, 0x71, 0x38, 0x3c, 0x53, 0xf4, 0x69, 0x41, 0xb7, 0xcb,
0x4c, 0xec, 0x3d, 0xea, 0xc0, 0xc6, 0x03, 0xe2, 0xcd, 0xd0, 0xd1, 0x8d, 0x94, 0x01,
0x9e, 0x43, 0xe2, 0x07,
],
ik: [
0x4f, 0x43, 0xeb, 0x7d, 0x9e, 0x03, 0x6f, 0xa6, 0x15, 0xfd, 0x04, 0xa5, 0xef, 0x6a,
0xeb, 0x21, 0x6e, 0x06, 0x9b, 0xe9, 0x2d, 0x30, 0xe8, 0xf7, 0x16, 0x3e, 0xe3, 0x15,
0x11, 0x6f, 0x18, 0x32,
],
nk: [
0x04, 0x51, 0x4e, 0xa0, 0x48, 0xb9, 0x43, 0x63, 0xde, 0xa7, 0xcb, 0x3b, 0xe8, 0xd6,
0x25, 0x82, 0xac, 0x52, 0x92, 0x2e, 0x08, 0x65, 0xf6, 0x62, 0x74, 0x3b, 0x05, 0xea,
Expand Down Expand Up @@ -314,6 +346,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0xe7, 0x2c, 0x3b, 0x64, 0x00, 0x06, 0xff, 0x08, 0x50, 0x52, 0x80, 0xe4, 0xf0, 0x0f,
0xad, 0xf7, 0x63, 0x28,
],
isk: [
0x71, 0xd0, 0x64, 0xaa, 0xa0, 0x82, 0x63, 0xb8, 0xe4, 0xc3, 0xed, 0x70, 0x3c, 0x6f,
0x54, 0x25, 0x4a, 0x88, 0x8c, 0x36, 0xec, 0x69, 0x86, 0x62, 0xf7, 0x1f, 0xbb, 0xf4,
0x26, 0xd9, 0x09, 0x28,
],
ik: [
0x12, 0xb3, 0xab, 0xff, 0x96, 0x75, 0x20, 0x9e, 0x94, 0x54, 0x07, 0x0c, 0x14, 0xac,
0x15, 0x54, 0x65, 0xae, 0x83, 0xbe, 0x2c, 0x39, 0x46, 0x63, 0x5e, 0x38, 0x77, 0xba,
0x67, 0xdf, 0x49, 0x12,
],
nk: [
0xcf, 0x36, 0xad, 0x6a, 0x06, 0x6c, 0xd2, 0x13, 0xe1, 0xd7, 0x67, 0xab, 0x07, 0x1d,
0xc1, 0x16, 0x78, 0x85, 0xc4, 0x16, 0x8b, 0xc2, 0xe2, 0x17, 0x54, 0x48, 0x56, 0x3a,
Expand Down Expand Up @@ -405,6 +447,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0xf5, 0x6d, 0x83, 0x20, 0x09, 0xf7, 0x24, 0x2e, 0x1f, 0x7c, 0x77, 0x0a, 0x12, 0x24,
0x1d, 0xfa, 0x28, 0x07,
],
isk: [
0x44, 0x36, 0x1a, 0x7b, 0xa6, 0xa1, 0xaa, 0x17, 0x8e, 0x72, 0xaf, 0x47, 0xbd, 0xc1,
0x60, 0x40, 0xce, 0x1c, 0x54, 0xdd, 0x4b, 0x56, 0x33, 0x21, 0x55, 0xba, 0x9d, 0x04,
0x09, 0x71, 0xd0, 0x07,
],
ik: [
0x1f, 0x17, 0x2d, 0x79, 0xae, 0xdc, 0xc2, 0x06, 0x8c, 0x3a, 0x09, 0x08, 0x93, 0xe1,
0xa1, 0x75, 0xd9, 0xb5, 0x78, 0xf8, 0x91, 0xaf, 0x9a, 0xb6, 0x8d, 0x4f, 0xe1, 0xe9,
0x05, 0xa3, 0xb2, 0x11,
],
nk: [
0x51, 0xba, 0xf3, 0x33, 0xcf, 0xf1, 0xf2, 0xd0, 0xc7, 0xe3, 0xcf, 0xf4, 0xd3, 0x01,
0x29, 0x9d, 0xc1, 0xef, 0xe9, 0x83, 0x00, 0x31, 0x4a, 0x54, 0x19, 0x38, 0x02, 0x9b,
Expand Down Expand Up @@ -496,6 +548,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0xdf, 0x28, 0xbb, 0x0f, 0x10, 0x21, 0xea, 0x84, 0x3f, 0x86, 0x7f, 0x8a, 0x17, 0x0f,
0x5c, 0x33, 0x90, 0x1f,
],
isk: [
0xdc, 0x93, 0x72, 0x9f, 0x3f, 0x28, 0x30, 0xed, 0x79, 0x1c, 0x21, 0xbe, 0xbe, 0x45,
0x0f, 0xcf, 0x1f, 0x8f, 0xef, 0x49, 0x81, 0x39, 0xc7, 0x99, 0xd1, 0x63, 0x66, 0x5a,
0x8c, 0x51, 0xe5, 0x2d,
],
ik: [
0x1d, 0xb6, 0x1c, 0x29, 0x3e, 0x3a, 0x93, 0x34, 0x5d, 0x06, 0xb9, 0x0b, 0xd7, 0x1f,
0xd3, 0x21, 0x5c, 0x2c, 0x1c, 0x29, 0x53, 0x5a, 0x10, 0xde, 0x9d, 0x31, 0x40, 0xb7,
0x4d, 0xb6, 0x1d, 0x07,
],
nk: [
0x9e, 0x99, 0x7d, 0x9d, 0x26, 0x97, 0x87, 0x26, 0x8e, 0x09, 0x2a, 0x7c, 0x85, 0x41,
0x7d, 0xa5, 0x30, 0xea, 0x42, 0xfa, 0xc6, 0x68, 0xa7, 0x49, 0xaf, 0x55, 0xdf, 0xb7,
Expand Down Expand Up @@ -587,6 +649,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0x65, 0x43, 0x46, 0x2a, 0x13, 0x7f, 0xfe, 0xa3, 0x7b, 0xaf, 0x41, 0xef, 0x28, 0x6b,
0xb7, 0x32, 0xbe, 0x2c,
],
isk: [
0xf2, 0x34, 0x52, 0x32, 0xc9, 0x19, 0xc1, 0x29, 0xe0, 0x4b, 0x0c, 0x46, 0xac, 0x2c,
0xa8, 0x50, 0x65, 0xd9, 0x54, 0x85, 0xb9, 0x02, 0xab, 0x0f, 0x98, 0xf9, 0x3a, 0xee,
0x59, 0x4b, 0x5f, 0x02,
],
ik: [
0x2c, 0x83, 0xd9, 0x20, 0xe9, 0xf6, 0x6d, 0xa5, 0x04, 0x86, 0x37, 0xad, 0x9a, 0xa2,
0xcc, 0xe6, 0xe1, 0x6e, 0xf4, 0x8f, 0x86, 0x50, 0xea, 0x00, 0xd8, 0xc2, 0xd7, 0x68,
0x61, 0x8a, 0xe3, 0x36,
],
nk: [
0xfd, 0x31, 0x64, 0xc6, 0x32, 0xbe, 0xc9, 0x4c, 0xe9, 0xfb, 0x2f, 0x30, 0x22, 0x63,
0xb8, 0x84, 0xab, 0xb9, 0xc1, 0x0e, 0x55, 0xe4, 0x48, 0x64, 0x7f, 0x67, 0x98, 0x49,
Expand Down Expand Up @@ -678,6 +750,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0xb3, 0x65, 0x1f, 0xfa, 0x1c, 0x69, 0x69, 0x15, 0xac, 0x00, 0xa2, 0x5e, 0xa3, 0xac,
0x7d, 0xff, 0x99, 0x01,
],
isk: [
0x3d, 0xa9, 0x08, 0x88, 0xba, 0x18, 0x24, 0xc8, 0x16, 0x29, 0x2d, 0x7f, 0x17, 0x33,
0xac, 0x4c, 0xbe, 0x72, 0x2c, 0x6a, 0x12, 0x1c, 0xc7, 0x80, 0x17, 0x06, 0x26, 0xb7,
0x0a, 0x26, 0x95, 0x28,
],
ik: [
0x16, 0xa8, 0xff, 0x29, 0xb5, 0x17, 0xb5, 0xa8, 0xf7, 0xd0, 0x9b, 0x4e, 0x5e, 0x71,
0x3a, 0x9a, 0x78, 0x4c, 0x74, 0x04, 0xd6, 0x1e, 0x3a, 0xf5, 0x30, 0x19, 0xc3, 0x47,
0x0e, 0x90, 0x95, 0x22,
],
nk: [
0x02, 0xab, 0x99, 0x5c, 0xe9, 0x8f, 0x63, 0x02, 0x5f, 0xb6, 0x24, 0x28, 0xa0, 0xfb,
0xf5, 0x2f, 0x25, 0x22, 0xe6, 0xa2, 0x72, 0x61, 0x07, 0x8a, 0x9f, 0x4d, 0x6a, 0x36,
Expand Down Expand Up @@ -769,6 +851,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0x3b, 0x02, 0xd2, 0x5c, 0xc1, 0x0c, 0x90, 0x71, 0xfc, 0x02, 0x19, 0xe9, 0x7f, 0x93,
0x92, 0xd0, 0x67, 0x0c,
],
isk: [
0x01, 0x65, 0x33, 0x68, 0x4f, 0xb9, 0x81, 0x15, 0xa4, 0x05, 0xc9, 0xc7, 0xad, 0x47,
0x72, 0x76, 0xab, 0x7c, 0x72, 0xfd, 0x67, 0x1a, 0x27, 0xe3, 0x6c, 0x0a, 0x7a, 0xbe,
0x0a, 0x76, 0x90, 0x09,
],
ik: [
0xff, 0xd7, 0x5f, 0x6f, 0x9e, 0xf4, 0x27, 0xf3, 0x26, 0xcd, 0xbf, 0x3a, 0x98, 0xbc,
0xb5, 0x93, 0x63, 0x5a, 0x2c, 0x1a, 0xd7, 0x2b, 0x39, 0x99, 0x12, 0x61, 0xe2, 0x75,
0xa9, 0xec, 0x6f, 0x10,
],
nk: [
0x25, 0x91, 0xed, 0xf7, 0xef, 0x4c, 0xf2, 0x18, 0x4c, 0x34, 0xbe, 0x93, 0xfc, 0xf6,
0x12, 0x91, 0x50, 0x42, 0xf1, 0x5a, 0xb5, 0x08, 0x4b, 0x14, 0xe1, 0x66, 0x79, 0x5b,
Expand Down Expand Up @@ -860,6 +952,16 @@ pub(crate) fn test_vectors() -> Vec<TestVector> {
0x8d, 0x4b, 0x02, 0x5f, 0x8c, 0xc1, 0x60, 0xe1, 0xf4, 0xe9, 0x5f, 0x0a, 0x85, 0x3e,
0xbc, 0x41, 0x6a, 0x2b,
],
isk: [
0x76, 0x08, 0x32, 0x9d, 0xfa, 0x77, 0xc4, 0x2c, 0x4f, 0xc7, 0x6a, 0xc2, 0x95, 0x94,
0xa2, 0x72, 0x83, 0x93, 0x4f, 0x5a, 0x93, 0x40, 0x71, 0xb9, 0xf8, 0xcd, 0x34, 0x4e,
0x1f, 0x98, 0x45, 0x0e,
],
ik: [
0x72, 0xa0, 0xac, 0x97, 0x8a, 0x2d, 0xa1, 0x61, 0xf4, 0x1f, 0x5b, 0x7a, 0x40, 0xbd,
0x83, 0xc0, 0x58, 0x41, 0xf8, 0x1b, 0xc5, 0x11, 0x40, 0x67, 0xb8, 0x85, 0x98, 0x7f,
0x48, 0xca, 0x52, 0x2d,
],
nk: [
0x3e, 0x88, 0xf2, 0x07, 0x1f, 0xd9, 0xa2, 0xbb, 0x26, 0xcd, 0xa2, 0xea, 0x85, 0x6a,
0xa0, 0xfb, 0x3a, 0x80, 0xa8, 0x7d, 0x2f, 0xb6, 0x13, 0x6f, 0xab, 0x85, 0xe3, 0x6c,
Expand Down