librustzcash/zcash_primitives/src/sapling.rs

146 lines
3.6 KiB
Rust
Raw Normal View History

2019-04-16 00:29:09 -07:00
//! Structs and constants specific to the Sapling shielded pool.
2021-03-04 09:26:00 -08:00
pub mod group_hash;
pub mod pedersen_hash;
pub mod prover;
2021-03-04 09:33:14 -08:00
pub mod redjubjub;
pub mod util;
2021-03-04 09:26:00 -08:00
use bitvec::{order::Lsb0, view::AsBits};
use ff::PrimeField;
use group::{Curve, GroupEncoding};
2019-10-08 06:06:02 -07:00
use lazy_static::lazy_static;
2019-08-15 09:39:55 -07:00
use rand_core::{CryptoRng, RngCore};
use std::io::{self, Read, Write};
use crate::{constants::SPENDING_KEY_GENERATOR, merkle_tree::Hashable, primitives::Note};
use self::{
pedersen_hash::{pedersen_hash, Personalization},
redjubjub::{PrivateKey, PublicKey, Signature},
};
pub const SAPLING_COMMITMENT_TREE_DEPTH: usize = 32;
/// Compute a parent node in the Sapling commitment tree given its two children.
pub fn merkle_hash(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> [u8; 32] {
let lhs = {
let mut tmp = [false; 256];
for (a, b) in tmp.iter_mut().zip(lhs.as_bits::<Lsb0>()) {
*a = *b;
}
tmp
};
let rhs = {
let mut tmp = [false; 256];
for (a, b) in tmp.iter_mut().zip(rhs.as_bits::<Lsb0>()) {
*a = *b;
}
tmp
};
jubjub::ExtendedPoint::from(pedersen_hash(
Personalization::MerkleTree(depth),
lhs.iter()
.copied()
.take(bls12_381::Scalar::NUM_BITS as usize)
.chain(
rhs.iter()
.copied()
.take(bls12_381::Scalar::NUM_BITS as usize),
),
))
.to_affine()
.get_u()
.to_repr()
}
2019-04-16 00:29:09 -07:00
/// A node within the Sapling commitment tree.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Node {
repr: [u8; 32],
}
impl Node {
pub fn new(repr: [u8; 32]) -> Self {
Node { repr }
}
}
impl Hashable for Node {
fn read<R: Read>(mut reader: R) -> io::Result<Self> {
let mut repr = [0u8; 32];
reader.read_exact(&mut repr)?;
Ok(Node::new(repr))
}
fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
writer.write_all(self.repr.as_ref())
}
fn combine(depth: usize, lhs: &Self, rhs: &Self) -> Self {
Node {
repr: merkle_hash(depth, &lhs.repr, &rhs.repr),
}
}
fn blank() -> Self {
Node {
repr: Note::uncommitted().to_repr(),
}
}
fn empty_root(depth: usize) -> Self {
EMPTY_ROOTS[depth]
}
}
impl From<Node> for bls12_381::Scalar {
fn from(node: Node) -> Self {
bls12_381::Scalar::from_repr(node.repr).expect("Tree nodes should be in the prime field")
}
}
lazy_static! {
static ref EMPTY_ROOTS: Vec<Node> = {
let mut v = vec![Node::blank()];
for d in 0..SAPLING_COMMITMENT_TREE_DEPTH {
let next = Node::combine(d, &v[d], &v[d]);
v.push(next);
}
v
};
}
/// Create the spendAuthSig for a Sapling SpendDescription.
2019-06-12 15:12:55 -07:00
pub fn spend_sig<R: RngCore + CryptoRng>(
ask: PrivateKey,
ar: jubjub::Fr,
sighash: &[u8; 32],
2019-06-12 15:12:55 -07:00
rng: &mut R,
) -> Signature {
spend_sig_internal(ask, ar, sighash, rng)
}
pub(crate) fn spend_sig_internal<R: RngCore>(
ask: PrivateKey,
ar: jubjub::Fr,
sighash: &[u8; 32],
rng: &mut R,
) -> Signature {
// We compute `rsk`...
let rsk = ask.randomize(ar);
// We compute `rk` from there (needed for key prefixing)
let rk = PublicKey::from_private(&rsk, SPENDING_KEY_GENERATOR);
// Compute the signature's message for rk/spend_auth_sig
let mut data_to_be_signed = [0u8; 64];
data_to_be_signed[0..32].copy_from_slice(&rk.0.to_bytes());
(&mut data_to_be_signed[32..64]).copy_from_slice(&sighash[..]);
// Do the signing
rsk.sign(&data_to_be_signed, rng, SPENDING_KEY_GENERATOR)
}