//! Structs and constants specific to the Sapling shielded pool. pub mod group_hash; pub mod prover; pub mod redjubjub; use crate::{ constants::SPENDING_KEY_GENERATOR, pedersen_hash::{pedersen_hash, Personalization}, primitives::Note, }; use bitvec::{order::Lsb0, view::AsBits}; use ff::PrimeField; use group::{Curve, GroupEncoding}; use lazy_static::lazy_static; use rand_core::{CryptoRng, RngCore}; use std::io::{self, Read, Write}; use self::redjubjub::{PrivateKey, PublicKey, Signature}; use crate::merkle_tree::Hashable; 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::()) { *a = *b; } tmp }; let rhs = { let mut tmp = [false; 256]; for (a, b) in tmp.iter_mut().zip(rhs.as_bits::()) { *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() } /// 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(mut reader: R) -> io::Result { let mut repr = [0u8; 32]; reader.read_exact(&mut repr)?; Ok(Node::new(repr)) } fn 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 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 = { 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. pub fn spend_sig( ask: PrivateKey, ar: jubjub::Fr, sighash: &[u8; 32], rng: &mut R, ) -> Signature { spend_sig_internal(ask, ar, sighash, rng) } pub(crate) fn spend_sig_internal( 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) }