Skip to content

Commit

Permalink
Expose the randomness used to create descriptions.
Browse files Browse the repository at this point in the history
  • Loading branch information
murisi committed Apr 22, 2024
1 parent 6cbc8bd commit e423e98
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 48 deletions.
49 changes: 31 additions & 18 deletions masp_primitives/src/sapling/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ pub trait TxProver {
value: u64,
anchor: bls12_381::Scalar,
merkle_path: MerklePath<Node>,
) -> Result<([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint, PublicKey), ()>;
) -> Result<
(
[u8; GROTH_PROOF_SIZE],
jubjub::ExtendedPoint,
jubjub::Fr,
PublicKey,
),
(),
>;

/// Create the value commitment and proof for a MASP OutputDescription,
/// while accumulating its value commitment randomness inside the context for later
Expand All @@ -52,7 +60,7 @@ pub trait TxProver {
rcm: jubjub::Fr,
asset_type: AssetType,
value: u64,
) -> ([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint);
) -> ([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint, jubjub::Fr);

/// Create the value commitment, and proof for a MASP ConvertDescription,
/// while accumulating its value commitment randomness inside
Expand All @@ -65,7 +73,7 @@ pub trait TxProver {
value: u64,
anchor: bls12_381::Scalar,
merkle_path: MerklePath<Node>,
) -> Result<([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint), ()>;
) -> Result<([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint, jubjub::Fr), ()>;

/// Create the `bindingSig` for a Sapling transaction. All calls to
/// [`TxProver::spend_proof`] and [`TxProver::output_proof`] must be completed before
Expand Down Expand Up @@ -115,18 +123,24 @@ pub mod mock {
value: u64,
_anchor: bls12_381::Scalar,
_merkle_path: MerklePath<Node>,
) -> Result<([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint, PublicKey), ()> {
) -> Result<
(
[u8; GROTH_PROOF_SIZE],
jubjub::ExtendedPoint,
jubjub::Fr,
PublicKey,
),
(),
> {
let mut rng = OsRng;

let cv = asset_type
.value_commitment(value, jubjub::Fr::random(&mut rng))
.commitment()
.into();
let rcv = jubjub::Fr::random(&mut rng);
let cv = asset_type.value_commitment(value, rcv).commitment().into();

let rk =
PublicKey(proof_generation_key.ak.into()).randomize(ar, SPENDING_KEY_GENERATOR);

Ok(([0u8; GROTH_PROOF_SIZE], cv, rk))
Ok(([0u8; GROTH_PROOF_SIZE], cv, rcv, rk))
}

fn output_proof(
Expand All @@ -137,15 +151,13 @@ pub mod mock {
_rcm: jubjub::Fr,
asset_type: AssetType,
value: u64,
) -> ([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint) {
) -> ([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint, jubjub::Fr) {
let mut rng = OsRng;

let cv = asset_type
.value_commitment(value, jubjub::Fr::random(&mut rng))
.commitment()
.into();
let rcv = jubjub::Fr::random(&mut rng);
let cv = asset_type.value_commitment(value, rcv).commitment().into();

([0u8; GROTH_PROOF_SIZE], cv)
([0u8; GROTH_PROOF_SIZE], cv, rcv)
}

fn convert_proof(
Expand All @@ -155,15 +167,16 @@ pub mod mock {
value: u64,
_anchor: bls12_381::Scalar,
_merkle_path: MerklePath<Node>,
) -> Result<([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint), ()> {
) -> Result<([u8; GROTH_PROOF_SIZE], jubjub::ExtendedPoint, jubjub::Fr), ()> {
let mut rng = OsRng;

let rcv = jubjub::Fr::random(&mut rng);
let cv = allowed_conversion
.value_commitment(value, jubjub::Fr::random(&mut rng))
.value_commitment(value, rcv)
.commitment()
.into();

Ok(([0u8; GROTH_PROOF_SIZE], cv))
Ok(([0u8; GROTH_PROOF_SIZE], cv, rcv))
}

fn binding_sig(
Expand Down
139 changes: 124 additions & 15 deletions masp_primitives/src/transaction/components/sapling/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,10 @@ impl SaplingOutputInfo {
prover: &Pr,
ctx: &mut Pr::SaplingProvingContext,
rng: &mut R,
) -> OutputDescription<GrothProofBytes> {
) -> (OutputDescription<GrothProofBytes>, jubjub::Fr) {
let encryptor = sapling_note_encryption::<P>(self.ovk, self.note, self.to, self.memo);

let (zkproof, cv) = prover.output_proof(
let (zkproof, cv, rcv) = prover.output_proof(
ctx,
*encryptor.esk(),
self.to,
Expand All @@ -222,14 +222,17 @@ impl SaplingOutputInfo {

let epk = *encryptor.epk();

OutputDescription {
cv,
cmu,
ephemeral_key: epk.to_bytes().into(),
enc_ciphertext,
out_ciphertext,
zkproof,
}
(
OutputDescription {
cv,
cmu,
ephemeral_key: epk.to_bytes().into(),
enc_ciphertext,
out_ciphertext,
zkproof,
},
rcv,
)
}
}

Expand All @@ -248,11 +251,91 @@ impl fees::OutputView for SaplingOutputInfo {
}

/// Metadata about a transaction created by a [`SaplingBuilder`].
#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, BorshSchema)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SaplingMetadata {
spend_indices: Vec<usize>,
convert_indices: Vec<usize>,
output_indices: Vec<usize>,
spend_rcvs: Vec<jubjub::Fr>,
convert_rcvs: Vec<jubjub::Fr>,
output_rcvs: Vec<jubjub::Fr>,
}

impl BorshSchema for SaplingMetadata {
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let definition = Definition::Struct {
fields: Fields::NamedFields(vec![
("spend_indices".into(), Vec::<usize>::declaration()),
("convert_indices".into(), Vec::<usize>::declaration()),
("output_indices".into(), Vec::<usize>::declaration()),
("spend_rcvs".into(), Vec::<[u8; 32]>::declaration()),
("convert_rcvs".into(), Vec::<[u8; 32]>::declaration()),
("output_rcvs".into(), Vec::<[u8; 32]>::declaration()),
]),
};
add_definition(Self::declaration(), definition, definitions);
Vec::<usize>::add_definitions_recursively(definitions);
Vec::<[u8; 32]>::add_definitions_recursively(definitions);
}

fn declaration() -> Declaration {
"SaplingMetadata".into()
}
}

impl BorshSerialize for SaplingMetadata {
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
self.spend_indices.serialize(writer)?;
self.convert_indices.serialize(writer)?;
self.output_indices.serialize(writer)?;
self.spend_rcvs
.iter()
.map(|rcv| rcv.to_bytes())
.collect::<Vec<[u8; 32]>>()
.serialize(writer)?;
self.convert_rcvs
.iter()
.map(|rcv| rcv.to_bytes())
.collect::<Vec<[u8; 32]>>()
.serialize(writer)?;
self.output_rcvs
.iter()
.map(|rcv| rcv.to_bytes())
.collect::<Vec<[u8; 32]>>()
.serialize(writer)?;
Ok(())
}
}

impl BorshDeserialize for SaplingMetadata {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
let spend_indices = Vec::<usize>::deserialize_reader(reader)?;
let convert_indices = Vec::<usize>::deserialize_reader(reader)?;
let output_indices = Vec::<usize>::deserialize_reader(reader)?;
let spend_rcvs = Vec::<[u8; 32]>::deserialize_reader(reader)?
.iter()
.map(|rcv| jubjub::Fr::from_bytes(&rcv).into())

Check failure on line 317 in masp_primitives/src/transaction/components/sapling/builder.rs

View workflow job for this annotation

GitHub Actions / Clippy (MSRV)

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> masp_primitives/src/transaction/components/sapling/builder.rs:317:47 | 317 | .map(|rcv| jubjub::Fr::from_bytes(&rcv).into()) | ^^^^ help: change this to: `rcv` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `-D clippy::needless-borrow` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`

Check failure on line 317 in masp_primitives/src/transaction/components/sapling/builder.rs

View workflow job for this annotation

GitHub Actions / Clippy (MSRV)

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> masp_primitives/src/transaction/components/sapling/builder.rs:317:47 | 317 | .map(|rcv| jubjub::Fr::from_bytes(&rcv).into()) | ^^^^ help: change this to: `rcv` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow = note: `-D clippy::needless-borrow` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::needless_borrow)]`
.collect::<Option<Vec<jubjub::Fr>>>()
.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::InvalidData))?;
let convert_rcvs = Vec::<[u8; 32]>::deserialize_reader(reader)?
.iter()
.map(|rcv| jubjub::Fr::from_bytes(&rcv).into())

Check failure on line 322 in masp_primitives/src/transaction/components/sapling/builder.rs

View workflow job for this annotation

GitHub Actions / Clippy (MSRV)

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> masp_primitives/src/transaction/components/sapling/builder.rs:322:47 | 322 | .map(|rcv| jubjub::Fr::from_bytes(&rcv).into()) | ^^^^ help: change this to: `rcv` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

Check failure on line 322 in masp_primitives/src/transaction/components/sapling/builder.rs

View workflow job for this annotation

GitHub Actions / Clippy (MSRV)

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> masp_primitives/src/transaction/components/sapling/builder.rs:322:47 | 322 | .map(|rcv| jubjub::Fr::from_bytes(&rcv).into()) | ^^^^ help: change this to: `rcv` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
.collect::<Option<Vec<jubjub::Fr>>>()
.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::InvalidData))?;
let output_rcvs = Vec::<[u8; 32]>::deserialize_reader(reader)?
.iter()
.map(|rcv| jubjub::Fr::from_bytes(&rcv).into())

Check failure on line 327 in masp_primitives/src/transaction/components/sapling/builder.rs

View workflow job for this annotation

GitHub Actions / Clippy (MSRV)

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> masp_primitives/src/transaction/components/sapling/builder.rs:327:47 | 327 | .map(|rcv| jubjub::Fr::from_bytes(&rcv).into()) | ^^^^ help: change this to: `rcv` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow

Check failure on line 327 in masp_primitives/src/transaction/components/sapling/builder.rs

View workflow job for this annotation

GitHub Actions / Clippy (MSRV)

this expression creates a reference which is immediately dereferenced by the compiler

error: this expression creates a reference which is immediately dereferenced by the compiler --> masp_primitives/src/transaction/components/sapling/builder.rs:327:47 | 327 | .map(|rcv| jubjub::Fr::from_bytes(&rcv).into()) | ^^^^ help: change this to: `rcv` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow
.collect::<Option<Vec<jubjub::Fr>>>()
.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::InvalidData))?;
Ok(SaplingMetadata {
spend_indices,
convert_indices,
output_indices,
spend_rcvs,
convert_rcvs,
output_rcvs,
})
}
}

impl SaplingMetadata {
Expand All @@ -261,6 +344,9 @@ impl SaplingMetadata {
spend_indices: vec![],
convert_indices: vec![],
output_indices: vec![],
spend_rcvs: vec![],
convert_rcvs: vec![],
output_rcvs: vec![],
}
}

Expand Down Expand Up @@ -584,6 +670,17 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
}
}

// Setup the structures that will receive the value commitment randomness
tx_metadata
.spend_rcvs
.resize(indexed_spends.len(), jubjub::Fr::zero());
tx_metadata
.convert_rcvs
.resize(indexed_converts.len(), jubjub::Fr::zero());
tx_metadata
.output_rcvs
.resize(indexed_outputs.len(), jubjub::Fr::zero());

// Randomize order of inputs and outputs
indexed_spends.shuffle(&mut rng);
indexed_converts.shuffle(&mut rng);
Expand All @@ -610,7 +707,7 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
spend.merkle_path.position,
);

let (zkproof, cv, rk) = prover
let (zkproof, cv, rcv, rk) = prover
.spend_proof(
ctx,
proof_generation_key,
Expand All @@ -627,6 +724,9 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
// Record the post-randomized spend location
tx_metadata.spend_indices[pos] = i;

// Map the post-randomized spends to commitment value randomness
tx_metadata.spend_rcvs[i] = rcv;

// Update progress and send a notification on the channel
progress += 1;
if let Some(sender) = progress_notifier {
Expand Down Expand Up @@ -661,7 +761,7 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
.into_iter()
.enumerate()
.map(|(i, (pos, convert))| {
let (zkproof, cv) = prover
let (zkproof, cv, rcv) = prover
.convert_proof(
ctx,
convert.allowed.clone(),
Expand All @@ -674,6 +774,9 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
// Record the post-randomized spend location
tx_metadata.convert_indices[pos] = i;

// Map the post-randomized converts to commitment value randomness
tx_metadata.convert_rcvs[i] = rcv;

// Update progress and send a notification on the channel
progress += 1;
if let Some(sender) = progress_notifier {
Expand Down Expand Up @@ -703,7 +806,10 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
// Record the post-randomized output location
tx_metadata.output_indices[pos] = i;

output.clone().build::<P, _, _>(prover, ctx, &mut rng)
let (desc, rcv) = output.clone().build::<P, _, _>(prover, ctx, &mut rng);
// Map the post-randomized outputs to commitment value randomness
tx_metadata.output_rcvs[i] = rcv;
desc
} else {
// This is a dummy output
let (dummy_to, dummy_note) = {
Expand Down Expand Up @@ -747,7 +853,7 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
let esk = dummy_note.generate_or_derive_esk_internal(&mut rng);
let epk = dummy_note.g_d * esk;

let (zkproof, cv) = prover.output_proof(
let (zkproof, cv, rcv) = prover.output_proof(
ctx,
esk,
dummy_to,
Expand All @@ -756,6 +862,9 @@ impl<P: consensus::Parameters> SaplingBuilder<P> {
dummy_note.value,
);

// Map the post-randomized outputs to commitment value randomness
tx_metadata.output_rcvs[i] = rcv;

let cmu = dummy_note.cmu();

let mut enc_ciphertext = [0u8; 580 + 32];
Expand Down
Loading

0 comments on commit e423e98

Please sign in to comment.