Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions bindings/uniffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ fn parse_data_updates(
#[derive(uniffi::Record)]
pub struct Zone {
pub anchor: u32,
pub anchor_hash: Vec<u8>,
pub sovereignty: String,
pub handle: String,
pub canonical: String,
Expand All @@ -120,6 +121,7 @@ pub struct Zone {
fn zone_from_inner(z: &libveritas::Zone) -> Zone {
Zone {
anchor: z.anchor,
anchor_hash: z.anchor_hash.to_vec(),
sovereignty: z.sovereignty.to_string(),
handle: z.handle.to_string(),
canonical: z.canonical.to_string(),
Expand Down Expand Up @@ -227,8 +229,18 @@ fn zone_to_inner(z: &Zone) -> Result<libveritas::Zone, VeritasError> {
CommitmentState::Unknown => libveritas::ProvableOption::Unknown,
};

let mut anchor_hash = [0u8; 32];
if z.anchor_hash.len() == 32 {
anchor_hash.copy_from_slice(&z.anchor_hash);
} else if !z.anchor_hash.is_empty() {
return Err(VeritasError::InvalidInput {
msg: format!("anchor_hash must be 32 bytes, got {}", z.anchor_hash.len()),
});
}

Ok(libveritas::Zone {
anchor: z.anchor,
anchor_hash,
sovereignty: match z.sovereignty.as_str() {
"sovereign" => libveritas::SovereigntyState::Sovereign,
"pending" => libveritas::SovereigntyState::Pending,
Expand Down Expand Up @@ -874,10 +886,6 @@ pub struct VerifiedMessage {

#[uniffi::export]
impl VerifiedMessage {
pub fn root_id(&self) -> Vec<u8> {
self.inner.root_id.to_vec()
}

pub fn zones(&self) -> Vec<Zone> {
self.inner.zones.iter().map(zone_from_inner).collect()
}
Expand Down
6 changes: 0 additions & 6 deletions bindings/wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,12 +479,6 @@ pub struct VerifiedMessage {

#[wasm_bindgen]
impl VerifiedMessage {
/// The root id this message was verified against.
#[wasm_bindgen(js_name = "rootId")]
pub fn root_id(&self) -> Vec<u8> {
self.inner.root_id.to_vec()
}

/// All verified zones as plain JS objects.
pub fn zones(&self) -> Result<JsValue, JsError> {
let array = js_sys::Array::new();
Expand Down
1 change: 1 addition & 0 deletions testutil/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ impl TestHandleTree {
delegate: ProvableOption::Unknown,
commitment: ProvableOption::Unknown,
num_id,
anchor_hash: [0u8; 32],
};

let signature = sign_zone(&zone, &self.ds.ptr.keypair);
Expand Down
51 changes: 46 additions & 5 deletions veritas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ pub const VERIFY_ENABLE_SNARK: u32 = 1 << 1;
/// Contains the verified zones and the original message data.
/// The message can be used to construct certificates for storage.
pub struct VerifiedMessage {
pub root_id: [u8; 32],
pub zones: Vec<Zone>,
pub message: msg::Message,
}
Expand Down Expand Up @@ -184,6 +183,12 @@ impl fmt::Display for SovereigntyState {
pub struct Zone {
/// The block height of the anchor used to prove this zone (snapshot version).
pub anchor: u32,
/// Hash of the root anchor this zone was verified against.
#[serde(
serialize_with = "serialize_hash",
deserialize_with = "deserialize_hash"
)]
pub anchor_hash: Hash,
/// The sovereignty state indicating finality of the zone's commitment.
pub sovereignty: SovereigntyState,
/// Human-readable name (e.g., "nested1.alice@bitcoin").
Expand Down Expand Up @@ -355,6 +360,7 @@ impl<T: BorshDeserialize> BorshDeserialize for ProvableOption<T> {
impl BorshSerialize for Zone {
fn serialize<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
BorshSerialize::serialize(&self.anchor, writer)?;
BorshSerialize::serialize(&self.anchor_hash, writer)?;
BorshSerialize::serialize(&self.sovereignty, writer)?;
BorshSerialize::serialize(&self.canonical, writer)?;
BorshSerialize::serialize(&self.handle, writer)?;
Expand All @@ -371,6 +377,7 @@ impl BorshSerialize for Zone {
impl BorshDeserialize for Zone {
fn deserialize_reader<R: Read>(reader: &mut R) -> std::io::Result<Self> {
let anchor = u32::deserialize_reader(reader)?;
let anchor_hash = <[u8; 32]>::deserialize_reader(reader)?;
let sovereignty = SovereigntyState::deserialize_reader(reader)?;
let canonical = SName::deserialize_reader(reader)?;
let handle = SName::deserialize_reader(reader)?;
Expand All @@ -386,6 +393,7 @@ impl BorshDeserialize for Zone {
let num_id = Option::<NumId>::deserialize_reader(reader)?;
Ok(Zone {
anchor,
anchor_hash,
sovereignty,
handle,
canonical,
Expand Down Expand Up @@ -512,12 +520,13 @@ impl Zone {

/// Returns the zone serialized for signing.
///
/// The `anchor` and `records` fields are zeroed out so delegate
/// signatures remain valid across different anchor snapshots and
/// don't include owner-signed records.
/// The `anchor`, `anchor_hash`, and `records` fields are zeroed out so
/// delegate signatures remain valid across different anchor snapshots
/// and don't include owner-signed records.
pub fn signing_bytes(&self) -> Vec<u8> {
let mut zone = self.clone();
zone.anchor = 0;
zone.anchor_hash = [0u8; 32];
zone.records = sip7::RecordSet::default();
borsh::to_vec(&zone).expect("zone serialization should not fail")
}
Expand Down Expand Up @@ -844,8 +853,12 @@ impl Veritas {
let resolver = names::NameResolver::from_zones(&zones);
resolver.expand_zones(&mut zones);

let anchor_hash = compute_root_id(&anchor);
for zone in &mut zones {
zone.anchor_hash = anchor_hash;
}

Ok(VerifiedMessage {
root_id: compute_root_id(&anchor),
zones,
message: msg::Message {
chain: msg.chain,
Expand Down Expand Up @@ -1190,6 +1203,7 @@ impl Veritas {
delegate: ProvableOption::Unknown,
commitment: ProvableOption::Unknown,
num_id,
anchor_hash: [0u8; 32],
};

// Verify records signature if present
Expand Down Expand Up @@ -1312,6 +1326,7 @@ fn verify_temporary_handle(
delegate: ProvableOption::Unknown,
commitment: ProvableOption::Unknown,
num_id,
anchor_hash: [0u8; 32],
};

zone.verify_signature(handle.signature.as_ref().unwrap(), signer)
Expand Down Expand Up @@ -1399,6 +1414,7 @@ fn verify_final_handle(
delegate: ProvableOption::Unknown,
commitment: ProvableOption::Unknown,
num_id: Some(num_id),
anchor_hash: [0u8; 32],
};

Ok(zone)
Expand Down Expand Up @@ -1646,6 +1662,31 @@ fn decode_journal(
})
}

fn serialize_hash<S>(hash: &Hash, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if serializer.is_human_readable() {
serializer.serialize_str(&hex::encode(hash))
} else {
serializer.serialize_bytes(hash)
}
}

fn deserialize_hash<'de, D>(deserializer: D) -> Result<Hash, D::Error>
where
D: Deserializer<'de>,
{
if deserializer.is_human_readable() {
let s: String = <String as Deserialize>::deserialize(deserializer)?;
let mut bytes = [0u8; 32];
hex::decode_to_slice(&s, &mut bytes).map_err(serde::de::Error::custom)?;
Ok(bytes)
} else {
<[u8; 32] as Deserialize>::deserialize(deserializer)
}
}

fn serialize_option_hash<S>(hash: &Option<Hash>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
Expand Down
1 change: 1 addition & 0 deletions veritas/src/names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ mod tests {
delegate: crate::ProvableOption::Unknown,
commitment: crate::ProvableOption::Unknown,
num_id: None,
anchor_hash: [0u8; 32],
}
}

Expand Down
2 changes: 2 additions & 0 deletions veritas/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ impl TestHandleTree {
delegate: ProvableOption::Unknown,
commitment: ProvableOption::Unknown,
num_id,
anchor_hash: [0u8; 32],
};

let signature = sign_zone(&zone, &self.ds.ptr.keypair);
Expand Down Expand Up @@ -1006,6 +1007,7 @@ fn verify_uses_better_cached_zone() {
delegate: ProvableOption::Unknown,
commitment: ProvableOption::Unknown,
num_id: None,
anchor_hash: [0u8; 32],
};

let ctx = QueryContext::from_zones(vec![cached_zone.clone()]);
Expand Down
Loading