Skip to content

Commit

Permalink
Enforce the use of the same signer in a given call graph
Browse files Browse the repository at this point in the history
  • Loading branch information
vicsn committed Oct 11, 2023
1 parent 1fa6ac0 commit a5b2d57
Show file tree
Hide file tree
Showing 17 changed files with 184 additions and 23 deletions.
13 changes: 13 additions & 0 deletions circuit/program/src/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ pub struct Request<A: Aleo> {
tvk: Field<A>,
/// The transition commitment.
tcm: Field<A>,
/// The signer commitment.
scm: Field<A>,
}

#[cfg(console)]
Expand All @@ -147,6 +149,9 @@ impl<A: Aleo> Inject for Request<A> {
// Inject the transition commitment `tcm` as `Mode::Public`.
let tcm = Field::new(Mode::Public, *request.tcm());

// Inject the signer commitment `scm` as `Mode::Public`.
let scm = Field::new(Mode::Public, *request.scm());

// Inject the inputs.
let inputs = match request
.input_ids()
Expand Down Expand Up @@ -218,6 +223,7 @@ impl<A: Aleo> Inject for Request<A> {
sk_tag: Field::new(mode, *request.sk_tag()),
tvk: Field::new(mode, *request.tvk()),
tcm,
scm,
}
}
}
Expand Down Expand Up @@ -272,6 +278,11 @@ impl<A: Aleo> Request<A> {
pub const fn tcm(&self) -> &Field<A> {
&self.tcm
}

/// Returns the signer commitment.
pub const fn scm(&self) -> &Field<A> {
&self.scm
}
}

#[cfg(console)]
Expand All @@ -290,6 +301,7 @@ impl<A: Aleo> Eject for Request<A> {
self.sk_tag.eject_mode(),
self.tvk.eject_mode(),
self.tcm.eject_mode(),
self.scm.eject_mode(),
])
}

Expand All @@ -306,6 +318,7 @@ impl<A: Aleo> Eject for Request<A> {
self.sk_tag.eject_value(),
self.tvk.eject_value(),
self.tcm.eject_value(),
self.scm.eject_value(),
))
}
}
8 changes: 6 additions & 2 deletions circuit/program/src/request/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::*;

impl<A: Aleo> Request<A> {
/// Returns `true` if the input IDs are derived correctly, the input records all belong to the signer,
/// and the signature is valid. tpk is passed separately so it can have a Mode different from Self.
/// and the signature is valid.
///
/// Verifies (challenge == challenge') && (address == address') && (serial_numbers == serial_numbers') where:
/// challenge' := HashToScalar(r * G, pk_sig, pr_sig, signer, \[tvk, tcm, function ID, input IDs\])
Expand Down Expand Up @@ -52,15 +52,19 @@ impl<A: Aleo> Request<A> {
None => A::halt("Missing input elements in request verification"),
}

// Verify the transition public key and commitment are well-formed.
// Verify the transition public key and commitments are well-formed.
let tpk_checks = {
// Compute the transition commitment as `Hash(tvk)`.
let tcm = A::hash_psd2(&[self.tvk.clone()]);
// Compute the signer commitment as `Hash(signer)`.
let scm = A::hash_psd2(&[self.signer.to_x_coordinate()]);

// Ensure the transition public key matches with the saved one from the signature.
tpk.is_equal(&self.to_tpk())
// Ensure the computed transition commitment matches.
& tcm.is_equal(&self.tcm)
// Ensure the computed signer commitment matches.
& scm.is_equal(&self.scm)
};

// Verify the signature.
Expand Down
6 changes: 6 additions & 0 deletions circuit/types/address/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ impl<E: Environment> Address<E> {
pub fn zero() -> Self {
Self(Group::zero())
}

/// Outputs the x coordinate of the address
#[inline]
pub fn to_x_coordinate(&self) -> Field<E> {
self.0.to_x_coordinate()
}
}

#[cfg(console)]
Expand Down
22 changes: 19 additions & 3 deletions console/program/src/request/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,22 @@ impl<N: Network> FromBytes for Request<N> {
let tvk = FromBytes::read_le(&mut reader)?;
// Read the transition commitment.
let tcm = FromBytes::read_le(&mut reader)?;

Ok(Self::from((signer, network_id, program_id, function_name, input_ids, inputs, signature, sk_tag, tvk, tcm)))
// Read the signer commitment.
let scm = FromBytes::read_le(&mut reader)?;

Ok(Self::from((
signer,
network_id,
program_id,
function_name,
input_ids,
inputs,
signature,
sk_tag,
tvk,
tcm,
scm,
)))
}
}

Expand Down Expand Up @@ -93,7 +107,9 @@ impl<N: Network> ToBytes for Request<N> {
// Write the transition view key.
self.tvk.write_le(&mut writer)?;
// Write the transition commitment.
self.tcm.write_le(&mut writer)
self.tcm.write_le(&mut writer)?;
// Write the signer commitment.
self.scm.write_le(&mut writer)
}
}

Expand Down
13 changes: 11 additions & 2 deletions console/program/src/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub struct Request<N: Network> {
tvk: Field<N>,
/// The transition commitment.
tcm: Field<N>,
/// The signer commitment.
scm: Field<N>,
}

impl<N: Network>
Expand All @@ -62,11 +64,12 @@ impl<N: Network>
Field<N>,
Field<N>,
Field<N>,
Field<N>,
)> for Request<N>
{
/// Note: See `Request::sign` to create the request. This method is used to eject from a circuit.
fn from(
(signer, network_id, program_id, function_name, input_ids, inputs, signature, sk_tag, tvk, tcm): (
(signer, network_id, program_id, function_name, input_ids, inputs, signature, sk_tag, tvk, tcm, scm): (
Address<N>,
U16<N>,
ProgramID<N>,
Expand All @@ -77,13 +80,14 @@ impl<N: Network>
Field<N>,
Field<N>,
Field<N>,
Field<N>,
),
) -> Self {
// Ensure the network ID is correct.
if *network_id != N::ID {
N::halt(format!("Invalid network ID. Expected {}, found {}", N::ID, *network_id))
} else {
Self { signer, network_id, program_id, function_name, input_ids, inputs, signature, sk_tag, tvk, tcm }
Self { signer, network_id, program_id, function_name, input_ids, inputs, signature, sk_tag, tvk, tcm, scm }
}
}
}
Expand Down Expand Up @@ -150,6 +154,11 @@ impl<N: Network> Request<N> {
pub const fn tcm(&self) -> &Field<N> {
&self.tcm
}

/// Returns the signer commitment `scm`.
pub const fn scm(&self) -> &Field<N> {
&self.scm
}
}

#[cfg(test)]
Expand Down
3 changes: 3 additions & 0 deletions console/program/src/request/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ impl<N: Network> Serialize for Request<N> {
transition.serialize_field("sk_tag", &self.sk_tag)?;
transition.serialize_field("tvk", &self.tvk)?;
transition.serialize_field("tcm", &self.tcm)?;
transition.serialize_field("scm", &self.scm)?;
transition.end()
}
false => ToBytesSerializer::serialize_with_size_encoding(self, serializer),
Expand Down Expand Up @@ -68,6 +69,8 @@ impl<'de, N: Network> Deserialize<'de> for Request<N> {
DeserializeExt::take_from_value::<D>(&mut request, "tvk")?,
// Retrieve the `tcm`.
DeserializeExt::take_from_value::<D>(&mut request, "tcm")?,
// Retrieve the `scm`.
DeserializeExt::take_from_value::<D>(&mut request, "scm")?,
)))
}
false => FromBytesDeserializer::<Self>::deserialize_with_size_encoding(deserializer, "request"),
Expand Down
3 changes: 3 additions & 0 deletions console/program/src/request/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ impl<N: Network> Request<N> {
let tvk = (*signer * r).to_x_coordinate();
// Compute the transition commitment `tcm` as `Hash(tvk)`.
let tcm = N::hash_psd2(&[tvk])?;
// Compute the signer commitment `scm` as `Hash(signer)`.
let scm = N::hash_psd2(&[signer.deref().to_x_coordinate()])?;

// Compute the function ID as `Hash(network_id, program_id, function_name)`.
let function_id = N::hash_bhp1024(
Expand Down Expand Up @@ -231,6 +233,7 @@ impl<N: Network> Request<N> {
sk_tag,
tvk,
tcm,
scm,
})
}
}
8 changes: 6 additions & 2 deletions ledger/block/src/transition/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,12 @@ impl<N: Network> FromBytes for Transition<N> {
let tpk = FromBytes::read_le(&mut reader)?;
// Read the transition commitment.
let tcm = FromBytes::read_le(&mut reader)?;
// Read the signer commitment.
let scm = FromBytes::read_le(&mut reader)?;

// Construct the candidate transition.
let transition =
Self::new(program_id, function_name, inputs, outputs, tpk, tcm).map_err(|e| error(e.to_string()))?;
Self::new(program_id, function_name, inputs, outputs, tpk, tcm, scm).map_err(|e| error(e.to_string()))?;
// Ensure the transition ID matches the expected ID.
match transition_id == *transition.id() {
true => Ok(transition),
Expand Down Expand Up @@ -91,7 +93,9 @@ impl<N: Network> ToBytes for Transition<N> {
// Write the transition public key.
self.tpk.write_le(&mut writer)?;
// Write the transition commitment.
self.tcm.write_le(&mut writer)
self.tcm.write_le(&mut writer)?;
// Write the signer commitment.
self.scm.write_le(&mut writer)
}
}

Expand Down
14 changes: 12 additions & 2 deletions ledger/block/src/transition/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub struct Transition<N: Network> {
tpk: Group<N>,
/// The transition commitment.
tcm: Field<N>,
/// The transition signer commitment.
scm: Field<N>,
}

impl<N: Network> Transition<N> {
Expand All @@ -73,12 +75,13 @@ impl<N: Network> Transition<N> {
outputs: Vec<Output<N>>,
tpk: Group<N>,
tcm: Field<N>,
scm: Field<N>,
) -> Result<Self> {
// Compute the transition ID.
let function_tree = Self::function_tree(&inputs, &outputs)?;
let id = N::hash_bhp512(&(*function_tree.root(), tcm).to_bits_le())?;
// Return the transition.
Ok(Self { id: id.into(), program_id, function_name, inputs, outputs, tpk, tcm })
Ok(Self { id: id.into(), program_id, function_name, inputs, outputs, tpk, tcm, scm })
}

/// Initializes a new transition from a request and response.
Expand Down Expand Up @@ -255,8 +258,10 @@ impl<N: Network> Transition<N> {
let tpk = request.to_tpk();
// Retrieve the `tcm`.
let tcm = *request.tcm();
// Retrieve the `scm`.
let scm = *request.scm();
// Return the transition.
Self::new(program_id, function_name, inputs, outputs, tpk, tcm)
Self::new(program_id, function_name, inputs, outputs, tpk, tcm, scm)
}
}

Expand Down Expand Up @@ -295,6 +300,11 @@ impl<N: Network> Transition<N> {
pub const fn tcm(&self) -> &Field<N> {
&self.tcm
}

/// Returns the signer commitment.
pub const fn scm(&self) -> &Field<N> {
&self.scm
}
}

impl<N: Network> Transition<N> {
Expand Down
3 changes: 3 additions & 0 deletions ledger/block/src/transition/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ impl<N: Network> Serialize for Transition<N> {
transition.serialize_field("outputs", &self.outputs)?;
transition.serialize_field("tpk", &self.tpk)?;
transition.serialize_field("tcm", &self.tcm)?;
transition.serialize_field("scm", &self.scm)?;
transition.end()
}
false => ToBytesSerializer::serialize_with_size_encoding(self, serializer),
Expand Down Expand Up @@ -58,6 +59,8 @@ impl<'de, N: Network> Deserialize<'de> for Transition<N> {
DeserializeExt::take_from_value::<D>(&mut transition, "tpk")?,
// Retrieve the `tcm`.
DeserializeExt::take_from_value::<D>(&mut transition, "tcm")?,
// Retrieve the `scm`.
DeserializeExt::take_from_value::<D>(&mut transition, "scm")?,
)
.map_err(de::Error::custom)?;

Expand Down
1 change: 1 addition & 0 deletions ledger/block/src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ impl<N: Network> Block<N> {
if has_duplicates(self.transition_commitments()) {
bail!("Found a duplicate transition commitment in block {height}");
}

Ok(())
}
}
Expand Down
18 changes: 18 additions & 0 deletions ledger/store/src/helpers/memory/transition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ pub struct TransitionMemory<N: Network> {
tcm_map: MemoryMap<N::TransitionID, Field<N>>,
/// The reverse `tcm` map.
reverse_tcm_map: MemoryMap<Field<N>, N::TransitionID>,
/// The signer commitments.
scm_map: MemoryMap<N::TransitionID, Field<N>>,
/// The reverse `scm` map.
reverse_scm_map: MemoryMap<Field<N>, N::TransitionID>,
}

#[rustfmt::skip]
Expand All @@ -47,6 +51,8 @@ impl<N: Network> TransitionStorage<N> for TransitionMemory<N> {
type ReverseTPKMap = MemoryMap<Group<N>, N::TransitionID>;
type TCMMap = MemoryMap<N::TransitionID, Field<N>>;
type ReverseTCMMap = MemoryMap<Field<N>, N::TransitionID>;
type SCMMap = MemoryMap<N::TransitionID, Field<N>>;
type ReverseSCMMap = MemoryMap<Field<N>, N::TransitionID>;

/// Initializes the transition storage.
fn open(dev: Option<u16>) -> Result<Self> {
Expand All @@ -58,6 +64,8 @@ impl<N: Network> TransitionStorage<N> for TransitionMemory<N> {
reverse_tpk_map: MemoryMap::default(),
tcm_map: MemoryMap::default(),
reverse_tcm_map: MemoryMap::default(),
scm_map: MemoryMap::default(),
reverse_scm_map: MemoryMap::default(),
})
}

Expand Down Expand Up @@ -95,6 +103,16 @@ impl<N: Network> TransitionStorage<N> for TransitionMemory<N> {
fn reverse_tcm_map(&self) -> &Self::ReverseTCMMap {
&self.reverse_tcm_map
}

/// Returns the signer commitments.
fn scm_map(&self) -> &Self::TCMMap {
&self.scm_map
}

/// Returns the reverse `scm` map.
fn reverse_scm_map(&self) -> &Self::ReverseTCMMap {
&self.reverse_scm_map
}
}

/// An in-memory transition input storage.
Expand Down
Loading

0 comments on commit a5b2d57

Please sign in to comment.