Orchard: tidy keys
This commit is contained in:
parent
e85359c756
commit
0351e6481d
|
@ -17,6 +17,7 @@ use std::{
|
||||||
|
|
||||||
use aes::Aes256;
|
use aes::Aes256;
|
||||||
use bech32::{self, FromBase32, ToBase32, Variant};
|
use bech32::{self, FromBase32, ToBase32, Variant};
|
||||||
|
use bitvec::prelude::*;
|
||||||
use fpe::ff1::{BinaryNumeralString, FF1};
|
use fpe::ff1::{BinaryNumeralString, FF1};
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
use halo2::{
|
use halo2::{
|
||||||
|
@ -65,7 +66,7 @@ fn prp_d(K: [u8; 32], d: [u8; 11]) -> [u8; 11] {
|
||||||
// TODO: This is basically a duplicate of the one in our sapling module, its
|
// TODO: This is basically a duplicate of the one in our sapling module, its
|
||||||
// definition in the draft NU5 spec is incomplete so I'm putting it here in case
|
// definition in the draft NU5 spec is incomplete so I'm putting it here in case
|
||||||
// it changes.
|
// it changes.
|
||||||
fn prf_expand(sk: [u8; 32], t: &[&[u8]]) -> [u8; 64] {
|
fn prf_expand(sk: [u8; 32], t: Vec<&[u8]>) -> [u8; 64] {
|
||||||
let mut state = blake2b_simd::Params::new()
|
let mut state = blake2b_simd::Params::new()
|
||||||
.hash_length(64)
|
.hash_length(64)
|
||||||
.personal(b"Zcash_ExpandSeed")
|
.personal(b"Zcash_ExpandSeed")
|
||||||
|
@ -244,7 +245,7 @@ impl From<SpendingKey> for SpendAuthorizingKey {
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs
|
/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs
|
||||||
fn from(spending_key: SpendingKey) -> SpendAuthorizingKey {
|
fn from(spending_key: SpendingKey) -> SpendAuthorizingKey {
|
||||||
let hash_bytes = prf_expand(spending_key.bytes, &[&[6]]);
|
let hash_bytes = prf_expand(spending_key.bytes, vec![&[6]]);
|
||||||
|
|
||||||
// Handles ToScalar^Orchard
|
// Handles ToScalar^Orchard
|
||||||
Self(pallas::Scalar::from_bytes_wide(&hash_bytes))
|
Self(pallas::Scalar::from_bytes_wide(&hash_bytes))
|
||||||
|
@ -296,7 +297,9 @@ impl From<FullViewingKey> for OutgoingViewingKey {
|
||||||
let R = fvk.to_R();
|
let R = fvk.to_R();
|
||||||
|
|
||||||
// let ovk be the remaining [32] bytes of R [which is 64 bytes]
|
// let ovk be the remaining [32] bytes of R [which is 64 bytes]
|
||||||
Self::from(R[32..64])
|
let ovk_bytes: [u8; 32] = R[32..64].try_into().expect("32 byte array");
|
||||||
|
|
||||||
|
Self::from(ovk_bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,6 +336,7 @@ impl From<SpendValidatingKey> for [u8; 32] {
|
||||||
impl From<SpendAuthorizingKey> for SpendValidatingKey {
|
impl From<SpendAuthorizingKey> for SpendValidatingKey {
|
||||||
fn from(ask: SpendAuthorizingKey) -> Self {
|
fn from(ask: SpendAuthorizingKey) -> Self {
|
||||||
let sk = redpallas::SigningKey::<SpendAuth>::try_from(<[u8; 32]>::from(ask)).unwrap();
|
let sk = redpallas::SigningKey::<SpendAuth>::try_from(<[u8; 32]>::from(ask)).unwrap();
|
||||||
|
|
||||||
Self(redpallas::VerificationKey::from(&sk))
|
Self(redpallas::VerificationKey::from(&sk))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -393,7 +397,7 @@ impl From<SpendingKey> for NullifierDerivingKey {
|
||||||
fn from(sk: SpendingKey) -> Self {
|
fn from(sk: SpendingKey) -> Self {
|
||||||
Self(pallas::Base::from_bytes_wide(&prf_expand(
|
Self(pallas::Base::from_bytes_wide(&prf_expand(
|
||||||
sk.into(),
|
sk.into(),
|
||||||
&[&[7]],
|
vec![&[7]],
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -421,7 +425,7 @@ impl From<SpendingKey> for IvkCommitRandomness {
|
||||||
///
|
///
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||||
fn from(sk: SpendingKey) -> Self {
|
fn from(sk: SpendingKey) -> Self {
|
||||||
let scalar = pallas::Scalar::from_bytes_wide(&prf_expand(sk.into(), &[&[8]]));
|
let scalar = pallas::Scalar::from_bytes_wide(&prf_expand(sk.into(), vec![&[8]]));
|
||||||
|
|
||||||
Self(scalar)
|
Self(scalar)
|
||||||
}
|
}
|
||||||
|
@ -433,6 +437,12 @@ impl From<IvkCommitRandomness> for [u8; 32] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<IvkCommitRandomness> for pallas::Scalar {
|
||||||
|
fn from(rivk: IvkCommitRandomness) -> Self {
|
||||||
|
rivk.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<[u8; 32]> for IvkCommitRandomness {
|
impl TryFrom<[u8; 32]> for IvkCommitRandomness {
|
||||||
type Error = &'static str;
|
type Error = &'static str;
|
||||||
|
|
||||||
|
@ -506,18 +516,22 @@ impl From<FullViewingKey> for IncomingViewingKey {
|
||||||
///
|
///
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
/// https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents
|
||||||
/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs
|
/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn from(fvk: FullViewingKey) -> Self {
|
fn from(fvk: FullViewingKey) -> Self {
|
||||||
let M = (
|
let mut M: BitVec<Lsb0, u8> = BitVec::new();
|
||||||
fvk.spend_validating_key.into(),
|
|
||||||
fvk.nullifier_deriving_key.into(),
|
M.append(&mut BitVec::<Lsb0, u8>::from_slice(
|
||||||
)
|
&<[u8; 32]>::from(fvk.spend_validating_key)[..],
|
||||||
.concat();
|
));
|
||||||
|
M.append(&mut BitVec::<Lsb0, u8>::from_slice(
|
||||||
|
&<[u8; 32]>::from(fvk.nullifier_deriving_key)[..],
|
||||||
|
));
|
||||||
|
|
||||||
// Commit^ivk_rivk
|
// Commit^ivk_rivk
|
||||||
let commit_x = sinsemilla_short_commit(
|
let commit_x = sinsemilla_short_commit(
|
||||||
fvk.ivk_commit_randomness.into(),
|
fvk.ivk_commit_randomness.into(),
|
||||||
b"z.cash:Orchard-CommitIvk",
|
b"z.cash:Orchard-CommitIvk",
|
||||||
M,
|
&M,
|
||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
@ -649,15 +663,12 @@ impl FullViewingKey {
|
||||||
// let K = I2LEBSP_l_sk(rivk)
|
// let K = I2LEBSP_l_sk(rivk)
|
||||||
let K: [u8; 32] = self.ivk_commit_randomness.into();
|
let K: [u8; 32] = self.ivk_commit_randomness.into();
|
||||||
|
|
||||||
|
let t: Vec<&[u8]> = vec![&[0x82u8]];
|
||||||
|
t.push(&<[u8; 32]>::from(self.spend_validating_key));
|
||||||
|
t.push(&<[u8; 32]>::from(self.nullifier_deriving_key));
|
||||||
|
|
||||||
// let R = PRF^expand_K( [0x82] || I2LEOSP256(ak) || I2LEOSP256(nk) )
|
// let R = PRF^expand_K( [0x82] || I2LEOSP256(ak) || I2LEOSP256(nk) )
|
||||||
prf_expand(
|
prf_expand(K, t)
|
||||||
K,
|
|
||||||
&[
|
|
||||||
&[0x82u8],
|
|
||||||
self.spend_validating_key.into(),
|
|
||||||
self.nullifier_deriving_key.into(),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -121,8 +121,8 @@ pub fn sinsemilla_hash(D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Base {
|
||||||
/// https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
|
/// https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn sinsemilla_commit(r: pallas::Scalar, D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Point {
|
pub fn sinsemilla_commit(r: pallas::Scalar, D: &[u8], M: &BitVec<Lsb0, u8>) -> pallas::Point {
|
||||||
sinsemilla_hash_to_point((D, b"-M").concat(), M)
|
sinsemilla_hash_to_point(&[D, b"-M"].concat(), M)
|
||||||
+ pallas_group_hash((D, b"r").concat(), b"") * r
|
+ pallas_group_hash(&[D, b"r"].concat(), b"") * r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SinsemillaShortCommit_r(D, M) := Extract_P(SinsemillaCommit_r(D, M))
|
/// SinsemillaShortCommit_r(D, M) := Extract_P(SinsemillaCommit_r(D, M))
|
||||||
|
|
|
@ -48,12 +48,12 @@ mod private {
|
||||||
}
|
}
|
||||||
impl Sealed for Binding {
|
impl Sealed for Binding {
|
||||||
fn basepoint() -> pallas::Point {
|
fn basepoint() -> pallas::Point {
|
||||||
pallas::Point::from_bytes(constants::BINDINGSIG_BASEPOINT_BYTES).unwrap()
|
pallas::Point::from_bytes(&constants::BINDINGSIG_BASEPOINT_BYTES).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Sealed for SpendAuth {
|
impl Sealed for SpendAuth {
|
||||||
fn basepoint() -> pallas::Point {
|
fn basepoint() -> pallas::Point {
|
||||||
pallas::Point::from_bytes(constants::SPENDAUTHSIG_BASEPOINT_BYTES).unwrap()
|
pallas::Point::from_bytes(&constants::SPENDAUTHSIG_BASEPOINT_BYTES).unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Malformed signing key encoding.")]
|
||||||
|
MalformedSigningKey,
|
||||||
|
#[error("Malformed verification key encoding.")]
|
||||||
|
MalformedVerificationKey,
|
||||||
|
#[error("Invalid signature.")]
|
||||||
|
InvalidSignature,
|
||||||
|
}
|
|
@ -7,7 +7,7 @@ use std::{
|
||||||
use group::{cofactor::CofactorGroup, GroupEncoding};
|
use group::{cofactor::CofactorGroup, GroupEncoding};
|
||||||
use halo2::pasta::pallas;
|
use halo2::pasta::pallas;
|
||||||
|
|
||||||
use super::{Error, SigType, SigningKey};
|
use super::{Error, SigType};
|
||||||
|
|
||||||
/// A refinement type for `[u8; 32]` indicating that the bytes represent
|
/// A refinement type for `[u8; 32]` indicating that the bytes represent
|
||||||
/// an encoding of a RedPallas verification key.
|
/// an encoding of a RedPallas verification key.
|
||||||
|
@ -79,6 +79,18 @@ impl<T: SigType> From<VerificationKey<T>> for [u8; 32] {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: SigType> From<&pallas::Scalar> for VerificationKey<T> {
|
||||||
|
fn from(s: &pallas::Scalar) -> VerificationKey<T> {
|
||||||
|
let point = &T::basepoint() * s;
|
||||||
|
let bytes = VerificationKeyBytes {
|
||||||
|
bytes: pallas::Affine::from(&point).to_bytes(),
|
||||||
|
_marker: PhantomData,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self { bytes, point }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: SigType> TryFrom<VerificationKeyBytes<T>> for VerificationKey<T> {
|
impl<T: SigType> TryFrom<VerificationKeyBytes<T>> for VerificationKey<T> {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
|
@ -109,14 +121,3 @@ impl<T: SigType> TryFrom<[u8; 32]> for VerificationKey<T> {
|
||||||
VerificationKeyBytes::from(bytes).try_into()
|
VerificationKeyBytes::from(bytes).try_into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: SigType> VerificationKey<T> {
|
|
||||||
pub(crate) fn from(s: &pallas::Scalar) -> VerificationKey<T> {
|
|
||||||
let point = &T::basepoint() * s;
|
|
||||||
let bytes = VerificationKeyBytes {
|
|
||||||
bytes: pallas::Affine::from(&point).to_bytes(),
|
|
||||||
_marker: PhantomData,
|
|
||||||
};
|
|
||||||
VerificationKey { bytes, point }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue