Derive a Sprout nullifier from a nullifier seed (rho) and spending key
This commit is contained in:
parent
0d618a3abf
commit
fa053e2b0b
|
|
@ -40,6 +40,9 @@ fn prf_addr(x: [u8; 32], t: u8) -> [u8; 32] {
|
||||||
let mut block = [0u8; 64];
|
let mut block = [0u8; 64];
|
||||||
|
|
||||||
block[0..32].copy_from_slice(&x[..]);
|
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[0] |= 0b1100_0000;
|
||||||
|
|
||||||
block[32] = t;
|
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 {
|
impl From<[u8; 32]> for SpendingKey {
|
||||||
/// Generate a _SpendingKey_ from existing bytes, with the high 4
|
/// Generate a _SpendingKey_ from existing bytes, with the high 4
|
||||||
/// bits of the first byte set to zero (ie, 256 bits clamped to
|
/// 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 {
|
impl SpendingKey {
|
||||||
/// Generate a new _SpendingKey_ with the high 4 bits of the first
|
/// Generate a new _SpendingKey_ with the high 4 bits of the first
|
||||||
/// byte set to zero (ie, 256 random bits, clamped to 252).
|
/// byte set to zero (ie, 256 random bits, clamped to 252).
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@
|
||||||
|
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
|
use byteorder::{ByteOrder, LittleEndian};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
keys::sprout::PayingKey,
|
keys::sprout::{PayingKey, SpendingKey},
|
||||||
serde_helpers,
|
serde_helpers,
|
||||||
serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize},
|
serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize},
|
||||||
types::amount::{Amount, NonNegative},
|
types::amount::{Amount, NonNegative},
|
||||||
|
|
@ -16,6 +17,32 @@ use crate::{
|
||||||
|
|
||||||
use super::memo::Memo;
|
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].
|
/// Nullifier seed, named rho in the [spec][ps].
|
||||||
///
|
///
|
||||||
/// [ps]: https://zips.z.cash/protocol/protocol.pdf#sproutkeycomponents
|
/// [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)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
|
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
|
||||||
pub struct Nullifier([u8; 32]);
|
pub struct Nullifier([u8; 32]);
|
||||||
|
|
||||||
impl From<[u8; 32]> for Nullifier {
|
impl From<NullifierSeed> for [u8; 32] {
|
||||||
fn from(buf: [u8; 32]) -> Self {
|
fn from(rho: NullifierSeed) -> Self {
|
||||||
Self(buf)
|
rho.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(SpendingKey, NullifierSeed)> for Nullifier {
|
||||||
|
fn from((a_sk, rho): (SpendingKey, NullifierSeed)) -> Self {
|
||||||
|
Self(prf_nf(a_sk.into(), rho.into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue