Factor Sprout transaction elements into a separate module.
This commit is contained in:
parent
6e371a8c13
commit
7fcb7bbe99
|
@ -23,15 +23,11 @@ use crate::{
|
|||
};
|
||||
|
||||
pub mod amount;
|
||||
pub use self::amount::Amount;
|
||||
pub mod sprout;
|
||||
pub use self::{amount::Amount, sprout::JSDescription};
|
||||
|
||||
// π_A + π_B + π_C
|
||||
pub const GROTH_PROOF_SIZE: usize = 48 + 96 + 48;
|
||||
// π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H
|
||||
const PHGR_PROOF_SIZE: usize = 33 + 33 + 65 + 33 + 33 + 33 + 33 + 33;
|
||||
|
||||
const ZC_NUM_JS_INPUTS: usize = 2;
|
||||
const ZC_NUM_JS_OUTPUTS: usize = 2;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct OutPoint {
|
||||
|
@ -440,164 +436,3 @@ impl OutputDescription {
|
|||
writer.write_all(&self.zkproof)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum SproutProof {
|
||||
Groth([u8; GROTH_PROOF_SIZE]),
|
||||
PHGR([u8; PHGR_PROOF_SIZE]),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SproutProof {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
SproutProof::Groth(_) => write!(f, "SproutProof::Groth"),
|
||||
SproutProof::PHGR(_) => write!(f, "SproutProof::PHGR"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct JSDescription {
|
||||
pub(crate) vpub_old: Amount,
|
||||
pub(crate) vpub_new: Amount,
|
||||
pub(crate) anchor: [u8; 32],
|
||||
pub(crate) nullifiers: [[u8; 32]; ZC_NUM_JS_INPUTS],
|
||||
pub(crate) commitments: [[u8; 32]; ZC_NUM_JS_OUTPUTS],
|
||||
pub(crate) ephemeral_key: [u8; 32],
|
||||
pub(crate) random_seed: [u8; 32],
|
||||
pub(crate) macs: [[u8; 32]; ZC_NUM_JS_INPUTS],
|
||||
pub(crate) proof: SproutProof,
|
||||
pub(crate) ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS],
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for JSDescription {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"JSDescription(
|
||||
vpub_old = {:?}, vpub_new = {:?},
|
||||
anchor = {:?},
|
||||
nullifiers = {:?},
|
||||
commitments = {:?},
|
||||
ephemeral_key = {:?},
|
||||
random_seed = {:?},
|
||||
macs = {:?})",
|
||||
self.vpub_old,
|
||||
self.vpub_new,
|
||||
self.anchor,
|
||||
self.nullifiers,
|
||||
self.commitments,
|
||||
self.ephemeral_key,
|
||||
self.random_seed,
|
||||
self.macs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl JSDescription {
|
||||
pub fn read<R: Read>(mut reader: R, use_groth: bool) -> io::Result<Self> {
|
||||
// Consensus rule (§4.3): Canonical encoding is enforced here
|
||||
let vpub_old = {
|
||||
let mut tmp = [0u8; 8];
|
||||
reader.read_exact(&mut tmp)?;
|
||||
Amount::from_u64_le_bytes(tmp)
|
||||
}
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "vpub_old out of range"))?;
|
||||
|
||||
// Consensus rule (§4.3): Canonical encoding is enforced here
|
||||
let vpub_new = {
|
||||
let mut tmp = [0u8; 8];
|
||||
reader.read_exact(&mut tmp)?;
|
||||
Amount::from_u64_le_bytes(tmp)
|
||||
}
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "vpub_new out of range"))?;
|
||||
|
||||
// Consensus rule (§4.3): One of vpub_old and vpub_new being zero is
|
||||
// enforced by CheckTransactionWithoutProofVerification() in zcashd.
|
||||
|
||||
let mut anchor = [0u8; 32];
|
||||
reader.read_exact(&mut anchor)?;
|
||||
|
||||
let mut nullifiers = [[0u8; 32]; ZC_NUM_JS_INPUTS];
|
||||
nullifiers
|
||||
.iter_mut()
|
||||
.map(|nf| reader.read_exact(nf))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
let mut commitments = [[0u8; 32]; ZC_NUM_JS_OUTPUTS];
|
||||
commitments
|
||||
.iter_mut()
|
||||
.map(|cm| reader.read_exact(cm))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
// Consensus rule (§4.3): Canonical encoding is enforced by
|
||||
// ZCNoteDecryption::decrypt() in zcashd
|
||||
let mut ephemeral_key = [0u8; 32];
|
||||
reader.read_exact(&mut ephemeral_key)?;
|
||||
|
||||
let mut random_seed = [0u8; 32];
|
||||
reader.read_exact(&mut random_seed)?;
|
||||
|
||||
let mut macs = [[0u8; 32]; ZC_NUM_JS_INPUTS];
|
||||
macs.iter_mut()
|
||||
.map(|mac| reader.read_exact(mac))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
let proof = if use_groth {
|
||||
// Consensus rules (§4.3):
|
||||
// - Canonical encoding is enforced in librustzcash_sprout_verify()
|
||||
// - Proof validity is enforced in librustzcash_sprout_verify()
|
||||
let mut proof = [0u8; GROTH_PROOF_SIZE];
|
||||
reader.read_exact(&mut proof)?;
|
||||
SproutProof::Groth(proof)
|
||||
} else {
|
||||
// Consensus rules (§4.3):
|
||||
// - Canonical encoding is enforced by PHGRProof in zcashd
|
||||
// - Proof validity is enforced by JSDescription::Verify() in zcashd
|
||||
let mut proof = [0u8; PHGR_PROOF_SIZE];
|
||||
reader.read_exact(&mut proof)?;
|
||||
SproutProof::PHGR(proof)
|
||||
};
|
||||
|
||||
let mut ciphertexts = [[0u8; 601]; ZC_NUM_JS_OUTPUTS];
|
||||
ciphertexts
|
||||
.iter_mut()
|
||||
.map(|ct| reader.read_exact(ct))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
Ok(JSDescription {
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
anchor,
|
||||
nullifiers,
|
||||
commitments,
|
||||
ephemeral_key,
|
||||
random_seed,
|
||||
macs,
|
||||
proof,
|
||||
ciphertexts,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
writer.write_all(&self.vpub_old.to_i64_le_bytes())?;
|
||||
writer.write_all(&self.vpub_new.to_i64_le_bytes())?;
|
||||
writer.write_all(&self.anchor)?;
|
||||
writer.write_all(&self.nullifiers[0])?;
|
||||
writer.write_all(&self.nullifiers[1])?;
|
||||
writer.write_all(&self.commitments[0])?;
|
||||
writer.write_all(&self.commitments[1])?;
|
||||
writer.write_all(&self.ephemeral_key)?;
|
||||
writer.write_all(&self.random_seed)?;
|
||||
writer.write_all(&self.macs[0])?;
|
||||
writer.write_all(&self.macs[1])?;
|
||||
|
||||
match &self.proof {
|
||||
SproutProof::Groth(p) => writer.write_all(p)?,
|
||||
SproutProof::PHGR(p) => writer.write_all(p)?,
|
||||
}
|
||||
|
||||
writer.write_all(&self.ciphertexts[0])?;
|
||||
writer.write_all(&self.ciphertexts[1])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
//! Structs representing the components within Zcash transactions.
|
||||
|
||||
use std::io::{self, Read, Write};
|
||||
|
||||
use super::{amount::Amount, GROTH_PROOF_SIZE};
|
||||
|
||||
// π_A + π_A' + π_B + π_B' + π_C + π_C' + π_K + π_H
|
||||
const PHGR_PROOF_SIZE: usize = 33 + 33 + 65 + 33 + 33 + 33 + 33 + 33;
|
||||
|
||||
const ZC_NUM_JS_INPUTS: usize = 2;
|
||||
const ZC_NUM_JS_OUTPUTS: usize = 2;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum SproutProof {
|
||||
Groth([u8; GROTH_PROOF_SIZE]),
|
||||
PHGR([u8; PHGR_PROOF_SIZE]),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SproutProof {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
match self {
|
||||
SproutProof::Groth(_) => write!(f, "SproutProof::Groth"),
|
||||
SproutProof::PHGR(_) => write!(f, "SproutProof::PHGR"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct JSDescription {
|
||||
pub(crate) vpub_old: Amount,
|
||||
pub(crate) vpub_new: Amount,
|
||||
pub(crate) anchor: [u8; 32],
|
||||
pub(crate) nullifiers: [[u8; 32]; ZC_NUM_JS_INPUTS],
|
||||
pub(crate) commitments: [[u8; 32]; ZC_NUM_JS_OUTPUTS],
|
||||
pub(crate) ephemeral_key: [u8; 32],
|
||||
pub(crate) random_seed: [u8; 32],
|
||||
pub(crate) macs: [[u8; 32]; ZC_NUM_JS_INPUTS],
|
||||
pub(crate) proof: SproutProof,
|
||||
pub(crate) ciphertexts: [[u8; 601]; ZC_NUM_JS_OUTPUTS],
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for JSDescription {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
write!(
|
||||
f,
|
||||
"JSDescription(
|
||||
vpub_old = {:?}, vpub_new = {:?},
|
||||
anchor = {:?},
|
||||
nullifiers = {:?},
|
||||
commitments = {:?},
|
||||
ephemeral_key = {:?},
|
||||
random_seed = {:?},
|
||||
macs = {:?})",
|
||||
self.vpub_old,
|
||||
self.vpub_new,
|
||||
self.anchor,
|
||||
self.nullifiers,
|
||||
self.commitments,
|
||||
self.ephemeral_key,
|
||||
self.random_seed,
|
||||
self.macs
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl JSDescription {
|
||||
pub fn read<R: Read>(mut reader: R, use_groth: bool) -> io::Result<Self> {
|
||||
// Consensus rule (§4.3): Canonical encoding is enforced here
|
||||
let vpub_old = {
|
||||
let mut tmp = [0u8; 8];
|
||||
reader.read_exact(&mut tmp)?;
|
||||
Amount::from_u64_le_bytes(tmp)
|
||||
}
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "vpub_old out of range"))?;
|
||||
|
||||
// Consensus rule (§4.3): Canonical encoding is enforced here
|
||||
let vpub_new = {
|
||||
let mut tmp = [0u8; 8];
|
||||
reader.read_exact(&mut tmp)?;
|
||||
Amount::from_u64_le_bytes(tmp)
|
||||
}
|
||||
.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "vpub_new out of range"))?;
|
||||
|
||||
// Consensus rule (§4.3): One of vpub_old and vpub_new being zero is
|
||||
// enforced by CheckTransactionWithoutProofVerification() in zcashd.
|
||||
|
||||
let mut anchor = [0u8; 32];
|
||||
reader.read_exact(&mut anchor)?;
|
||||
|
||||
let mut nullifiers = [[0u8; 32]; ZC_NUM_JS_INPUTS];
|
||||
nullifiers
|
||||
.iter_mut()
|
||||
.map(|nf| reader.read_exact(nf))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
let mut commitments = [[0u8; 32]; ZC_NUM_JS_OUTPUTS];
|
||||
commitments
|
||||
.iter_mut()
|
||||
.map(|cm| reader.read_exact(cm))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
// Consensus rule (§4.3): Canonical encoding is enforced by
|
||||
// ZCNoteDecryption::decrypt() in zcashd
|
||||
let mut ephemeral_key = [0u8; 32];
|
||||
reader.read_exact(&mut ephemeral_key)?;
|
||||
|
||||
let mut random_seed = [0u8; 32];
|
||||
reader.read_exact(&mut random_seed)?;
|
||||
|
||||
let mut macs = [[0u8; 32]; ZC_NUM_JS_INPUTS];
|
||||
macs.iter_mut()
|
||||
.map(|mac| reader.read_exact(mac))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
let proof = if use_groth {
|
||||
// Consensus rules (§4.3):
|
||||
// - Canonical encoding is enforced in librustzcash_sprout_verify()
|
||||
// - Proof validity is enforced in librustzcash_sprout_verify()
|
||||
let mut proof = [0u8; GROTH_PROOF_SIZE];
|
||||
reader.read_exact(&mut proof)?;
|
||||
SproutProof::Groth(proof)
|
||||
} else {
|
||||
// Consensus rules (§4.3):
|
||||
// - Canonical encoding is enforced by PHGRProof in zcashd
|
||||
// - Proof validity is enforced by JSDescription::Verify() in zcashd
|
||||
let mut proof = [0u8; PHGR_PROOF_SIZE];
|
||||
reader.read_exact(&mut proof)?;
|
||||
SproutProof::PHGR(proof)
|
||||
};
|
||||
|
||||
let mut ciphertexts = [[0u8; 601]; ZC_NUM_JS_OUTPUTS];
|
||||
ciphertexts
|
||||
.iter_mut()
|
||||
.map(|ct| reader.read_exact(ct))
|
||||
.collect::<io::Result<()>>()?;
|
||||
|
||||
Ok(JSDescription {
|
||||
vpub_old,
|
||||
vpub_new,
|
||||
anchor,
|
||||
nullifiers,
|
||||
commitments,
|
||||
ephemeral_key,
|
||||
random_seed,
|
||||
macs,
|
||||
proof,
|
||||
ciphertexts,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write<W: Write>(&self, mut writer: W) -> io::Result<()> {
|
||||
writer.write_all(&self.vpub_old.to_i64_le_bytes())?;
|
||||
writer.write_all(&self.vpub_new.to_i64_le_bytes())?;
|
||||
writer.write_all(&self.anchor)?;
|
||||
writer.write_all(&self.nullifiers[0])?;
|
||||
writer.write_all(&self.nullifiers[1])?;
|
||||
writer.write_all(&self.commitments[0])?;
|
||||
writer.write_all(&self.commitments[1])?;
|
||||
writer.write_all(&self.ephemeral_key)?;
|
||||
writer.write_all(&self.random_seed)?;
|
||||
writer.write_all(&self.macs[0])?;
|
||||
writer.write_all(&self.macs[1])?;
|
||||
|
||||
match &self.proof {
|
||||
SproutProof::Groth(p) => writer.write_all(p)?,
|
||||
SproutProof::PHGR(p) => writer.write_all(p)?,
|
||||
}
|
||||
|
||||
writer.write_all(&self.ciphertexts[0])?;
|
||||
writer.write_all(&self.ciphertexts[1])
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue