Add mixing_pedersen_hash
Tidy constructors for NoteCommitment
This commit is contained in:
parent
ed888b38ef
commit
65f8f2c613
|
@ -12,15 +12,28 @@ use rand_core::{CryptoRng, RngCore};
|
|||
|
||||
use crate::{
|
||||
keys::sapling::{find_group_hash, Diversifier, TransmissionKey},
|
||||
notes::sapling::Note,
|
||||
serde_helpers,
|
||||
serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize},
|
||||
types::amount::{Amount, NonNegative},
|
||||
};
|
||||
|
||||
// TODO: replace with reference to redjubjub or jubjub when merged and
|
||||
// exported.
|
||||
type Scalar = jubjub::Fr;
|
||||
/// Generates a random scalar from the scalar field \mathbb{F}_r_𝕁.
|
||||
///
|
||||
/// The prime order subgroup 𝕁^(r) is the order-r_𝕁 subgroup of 𝕁
|
||||
/// after the Edwards cofactor h_𝕁 = 8 is factored out. This function
|
||||
/// is useful when generating the uniform distribution on
|
||||
/// \mathbb{F}_r_𝕁 needed for Sapling commitment schemes' trapdoor
|
||||
/// generators.
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#jubjub
|
||||
pub fn generate_trapdoor<T>(csprng: &mut T) -> jubjub::Fr
|
||||
where
|
||||
T: RngCore + CryptoRng,
|
||||
{
|
||||
let mut bytes = [0u8; 32];
|
||||
csprng.fill_bytes(&mut bytes);
|
||||
jubjub::Fr::from_bytes(&bytes).unwrap()
|
||||
}
|
||||
|
||||
/// "...an algebraic hash function with collision resistance (for
|
||||
/// fixed input length) derived from assumed hardness of the Discrete
|
||||
|
@ -40,7 +53,7 @@ pub fn pedersen_hash_to_point(domain: [u8; 8], M: &BitVec<Lsb0, u8>) -> jubjub::
|
|||
}
|
||||
|
||||
// ⟨Mᵢ⟩
|
||||
fn M_i(segment: &BitSlice<Lsb0, u8>) -> Scalar {
|
||||
fn M_i(segment: &BitSlice<Lsb0, u8>) -> jubjub::Fr {
|
||||
let mut m_i = [0u8; 32];
|
||||
|
||||
for (j, chunk) in segment.chunks(3).enumerate() {
|
||||
|
@ -53,7 +66,7 @@ pub fn pedersen_hash_to_point(domain: [u8; 8], M: &BitVec<Lsb0, u8>) -> jubjub::
|
|||
m_i[0] += enc_m_j * (1 << (4 * j))
|
||||
}
|
||||
|
||||
Scalar::from_bytes(&m_i).unwrap()
|
||||
jubjub::Fr::from_bytes(&m_i).unwrap()
|
||||
}
|
||||
|
||||
let mut result = jubjub::ExtendedPoint::identity();
|
||||
|
@ -77,6 +90,22 @@ pub fn pedersen_hash(domain: [u8; 8], M: &BitVec<Lsb0, u8>) -> jubjub::Fq {
|
|||
jubjub::AffinePoint::from(pedersen_hash_to_point(domain, M)).get_u()
|
||||
}
|
||||
|
||||
/// Mixing Pedersen Hash Function
|
||||
///
|
||||
/// Used to compute ρ from a note commitment and its position in the
|
||||
/// note commitment tree. It takes as input a Pedersen commitment P,
|
||||
/// and hashes it with another input x.
|
||||
///
|
||||
/// MixingPedersenHash(P, x) := P + [x]FindGroupHash^J^(r)(“Zcash_J_”, “”)
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#concretemixinghash
|
||||
#[allow(non_snake_case)]
|
||||
pub fn mixing_pedersen_hash(P: jubjub::ExtendedPoint, x: jubjub::Fr) -> jubjub::ExtendedPoint {
|
||||
const J: [u8; 8] = *b"Zcash_J_";
|
||||
|
||||
P + find_group_hash(J, b"") * x
|
||||
}
|
||||
|
||||
/// Construct a 'windowed' Pedersen commitment by reusing a Perderson
|
||||
/// hash constructon, and adding a randomized point on the Jubjub
|
||||
/// curve.
|
||||
|
@ -85,22 +114,18 @@ pub fn pedersen_hash(domain: [u8; 8], M: &BitVec<Lsb0, u8>) -> jubjub::Fq {
|
|||
/// PedersenHashToPoint(“Zcash_PH”, s) + [r]FindGroupHash^J^(r)(“Zcash_PH”, “r”)
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit
|
||||
pub fn windowed_pedersen_commitment_r(
|
||||
rcm: CommitmentRandomness,
|
||||
s: &BitVec<Lsb0, u8>,
|
||||
) -> jubjub::ExtendedPoint {
|
||||
pub fn windowed_pedersen_commitment(r: jubjub::Fr, s: &BitVec<Lsb0, u8>) -> jubjub::ExtendedPoint {
|
||||
const D: [u8; 8] = *b"Zcash_PH";
|
||||
|
||||
pedersen_hash_to_point(D, &s) + find_group_hash(D, b"r") * rcm.0
|
||||
pedersen_hash_to_point(D, &s) + find_group_hash(D, b"r") * r
|
||||
}
|
||||
|
||||
/// The randomness used in the Pedersen Hash for note commitment.
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct CommitmentRandomness(redjubjub::Randomizer);
|
||||
pub struct CommitmentRandomness(jubjub::Fr);
|
||||
|
||||
/// Note commitments for the output notes.
|
||||
#[derive(Clone, Copy, Deserialize, PartialEq, Serialize)]
|
||||
//#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
|
||||
pub struct NoteCommitment(#[serde(with = "serde_helpers::AffinePoint")] pub jubjub::AffinePoint);
|
||||
|
||||
impl fmt::Debug for NoteCommitment {
|
||||
|
@ -130,28 +155,6 @@ impl From<NoteCommitment> for [u8; 32] {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Note> for NoteCommitment {
|
||||
/// Construct a “windowed” Pedersen commitment by reusing a
|
||||
/// Perderson hash constructon, and adding a randomized point on
|
||||
/// the Jubjub curve.
|
||||
///
|
||||
/// WindowedPedersenCommit_r (s) := \
|
||||
/// PedersenHashToPoint(“Zcash_PH”, s) + [r]FindGroupHash^J^(r)∗(“Zcash_PH”, “r”)
|
||||
///
|
||||
/// NoteCommit^Sapling_rcm (g*_d , pk*_d , v) := \
|
||||
/// WindowedPedersenCommit_rcm([1; 6] || I2LEBSP_64(v) || g*_d || pk*_d)
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit
|
||||
fn from(note: Note) -> NoteCommitment {
|
||||
NoteCommitment::new(
|
||||
note.rcm,
|
||||
note.diversifier,
|
||||
note.transmission_key,
|
||||
note.value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for NoteCommitment {}
|
||||
|
||||
impl ZcashSerialize for NoteCommitment {
|
||||
|
@ -170,19 +173,27 @@ impl ZcashDeserialize for NoteCommitment {
|
|||
}
|
||||
|
||||
impl NoteCommitment {
|
||||
/// Generate a new _NoteCommitment_.
|
||||
/// Generate a new _NoteCommitment_ and the randomness used to
|
||||
/// create it.
|
||||
///
|
||||
/// We return the randomness because it is needed to construct a
|
||||
/// _Note_, before it is encrypted as part of an _Output
|
||||
/// Description_.
|
||||
///
|
||||
/// NoteCommit^Sapling_rcm (g*_d , pk*_d , v) := \
|
||||
/// WindowedPedersenCommit_rcm([1; 6] || I2LEBSP_64(v) || g*_d || pk*_d)
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#concretewindowedcommit
|
||||
#[allow(non_snake_case)]
|
||||
pub fn new(
|
||||
rcm: CommitmentRandomness,
|
||||
pub fn new<T>(
|
||||
csprng: &mut T,
|
||||
diversifier: Diversifier,
|
||||
transmission_key: TransmissionKey,
|
||||
value: Amount<NonNegative>,
|
||||
) -> Self {
|
||||
) -> (CommitmentRandomness, Self)
|
||||
where
|
||||
T: RngCore + CryptoRng,
|
||||
{
|
||||
// s as in the argument name for WindowedPedersenCommit_r(s)
|
||||
let mut s: BitVec<Lsb0, u8> = BitVec::new();
|
||||
|
||||
|
@ -199,13 +210,18 @@ impl NoteCommitment {
|
|||
s.append(&mut BitVec::<Lsb0, u8>::from_slice(&pk_d_bytes[..]));
|
||||
s.append(&mut BitVec::<Lsb0, u8>::from_slice(&v_bytes[..]));
|
||||
|
||||
Self::from(windowed_pedersen_commitment_r(rcm, &s))
|
||||
let rcm = CommitmentRandomness(generate_trapdoor(csprng));
|
||||
|
||||
(
|
||||
rcm,
|
||||
NoteCommitment::from(windowed_pedersen_commitment(rcm.0, &s)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Hash Extractor for Jubjub (?)
|
||||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#concreteextractorjubjub
|
||||
pub fn extract_u(self) -> jubjub::Fq {
|
||||
pub fn extract_u(&self) -> jubjub::Fq {
|
||||
self.0.get_u()
|
||||
}
|
||||
}
|
||||
|
@ -215,7 +231,6 @@ impl NoteCommitment {
|
|||
///
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#concretehomomorphiccommit
|
||||
#[derive(Clone, Deserialize, PartialEq, Serialize)]
|
||||
//#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
|
||||
pub struct ValueCommitment(#[serde(with = "serde_helpers::AffinePoint")] pub jubjub::AffinePoint);
|
||||
|
||||
impl fmt::Debug for ValueCommitment {
|
||||
|
@ -276,11 +291,8 @@ impl ValueCommitment {
|
|||
where
|
||||
T: RngCore + CryptoRng,
|
||||
{
|
||||
let v = Scalar::from_bytes(&value_bytes).unwrap();
|
||||
|
||||
let mut rcv_bytes = [0u8; 32];
|
||||
csprng.fill_bytes(&mut rcv_bytes);
|
||||
let rcv = Scalar::from_bytes(&rcv_bytes).unwrap();
|
||||
let v = jubjub::Fr::from_bytes(&value_bytes).unwrap();
|
||||
let rcv = generate_trapdoor(csprng);
|
||||
|
||||
let V = find_group_hash(*b"Zcash_cv", b"v");
|
||||
let R = find_group_hash(*b"Zcash_cv", b"r");
|
||||
|
|
Loading…
Reference in New Issue