Derive a Sprout nullifier from a nullifier seed (rho) and spending key

This commit is contained in:
Deirdre Connolly 2020-07-10 18:10:36 -04:00 committed by Deirdre Connolly
parent 0d618a3abf
commit fa053e2b0b
2 changed files with 66 additions and 18 deletions

View File

@ -40,6 +40,9 @@ fn prf_addr(x: [u8; 32], t: u8) -> [u8; 32] {
let mut block = [0u8; 64];
block[0..32].copy_from_slice(&x[..]);
// The first four bits i.e. the most signicant four bits of the
// first byte are used to separate distinct uses
// ofSHA256Compress, ensuring that the functions are independent.
block[0] |= 0b1100_0000;
block[32] = t;
@ -107,19 +110,6 @@ impl fmt::Display for SpendingKey {
}
}
impl std::str::FromStr for SpendingKey {
type Err = SerializationError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let result = &bs58::decode(s).with_check(None).into_vec();
match result {
Ok(bytes) => Self::zcash_deserialize(&bytes[..]),
Err(_) => Err(SerializationError::Parse("bs58 decoding error")),
}
}
}
impl From<[u8; 32]> for SpendingKey {
/// Generate a _SpendingKey_ from existing bytes, with the high 4
/// bits of the first byte set to zero (ie, 256 bits clamped to
@ -134,6 +124,25 @@ impl From<[u8; 32]> for SpendingKey {
}
}
impl From<SpendingKey> for [u8; 32] {
fn from(spending_key: SpendingKey) -> [u8; 32] {
spending_key.bytes
}
}
impl std::str::FromStr for SpendingKey {
type Err = SerializationError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let result = &bs58::decode(s).with_check(None).into_vec();
match result {
Ok(bytes) => Self::zcash_deserialize(&bytes[..]),
Err(_) => Err(SerializationError::Parse("bs58 decoding error")),
}
}
}
impl SpendingKey {
/// Generate a new _SpendingKey_ with the high 4 bits of the first
/// byte set to zero (ie, 256 random bits, clamped to 252).

View File

@ -4,11 +4,12 @@
use std::{fmt, io};
use byteorder::{ByteOrder, LittleEndian};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::{
keys::sprout::PayingKey,
keys::sprout::{PayingKey, SpendingKey},
serde_helpers,
serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize},
types::amount::{Amount, NonNegative},
@ -16,6 +17,32 @@ use crate::{
use super::memo::Memo;
/// PRF^nf is used to derive a Sprout nullifer from the receiver's
/// spending key a_sk and a nullifier seed ρ, instantiated using the
/// SHA-256 compression function.
///
/// https://zips.z.cash/protocol/protocol.pdf#abstractprfs
/// https://zips.z.cash/protocol/protocol.pdf#commitmentsandnullifiers
fn prf_nf(a_sk: [u8; 32], rho: [u8; 32]) -> [u8; 32] {
let mut state = [0u32; 8];
let mut block = [0u8; 64];
block[0..32].copy_from_slice(&a_sk[..]);
// The first four bits i.e. the most signicant four bits of the
// first byte are used to separate distinct uses
// ofSHA256Compress, ensuring that the functions are independent.
block[0] |= 0b1110_0000;
block[32..].copy_from_slice(&rho[..]);
sha2::compress256(&mut state, &block);
let mut derived_bytes = [0u8; 32];
LittleEndian::write_u32_into(&state, &mut derived_bytes);
derived_bytes
}
/// Nullifier seed, named rho in the [spec][ps].
///
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#sproutkeycomponents
@ -28,14 +55,26 @@ impl AsRef<[u8]> for NullifierSeed {
}
}
/// A Nullifier Set for Sprout transactions
impl From<[u8; 32]> for NullifierSeed {
fn from(bytes: [u8; 32]) -> Self {
Self(bytes)
}
}
/// A Nullifier for Sprout transactions
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct Nullifier([u8; 32]);
impl From<[u8; 32]> for Nullifier {
fn from(buf: [u8; 32]) -> Self {
Self(buf)
impl From<NullifierSeed> for [u8; 32] {
fn from(rho: NullifierSeed) -> Self {
rho.0
}
}
impl From<(SpendingKey, NullifierSeed)> for Nullifier {
fn from((a_sk, rho): (SpendingKey, NullifierSeed)) -> Self {
Self(prf_nf(a_sk.into(), rho.into()))
}
}