Skip to content

Conversation

cronokirby
Copy link
Collaborator

c.f. #1483

@cronokirby cronokirby force-pushed the cronokirby/transcript branch 6 times, most recently from 3acebd9 to e9a54b0 Compare September 2, 2025 21:21
@cronokirby cronokirby marked this pull request as ready for review September 2, 2025 21:22
@cronokirby cronokirby force-pushed the cronokirby/transcript branch from e9a54b0 to ea49ed3 Compare September 2, 2025 21:24
}

fn flush(&mut self) {
let (n, bytes) = encode_u64(self.pending);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally wanted to avoid encoding the length as a full 8 bytes, because that's a lot of overhead for small messages.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure the code as-written is the same as self.hasher.update(UInt(self.pending).encode).as_ref()); However, it seems you are doing this to avoid a heap allocation (?) Related to #1507

I would probably just stick with what's clearer for now (possible heap allocation)

Copy link
Contributor

@patrick-ogrady patrick-ogrady Sep 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intentionally wanted to avoid encoding the length as a full 8 bytes, because that's a lot of overhead for small messages.

Curious how much overhead this actually ends up being? When running on a 64-bit machine, seems like this would get padded up anyways (not to mention you avoid the extra work of encoding a varint)?

If you were ok with u64, it would just look like this (avoids the heap as well):

    fn flush(&mut self) {
        self.hasher.update(&self.pending.encode_fixed::<8>());
        self.pending = 0;
    }

I would probably just stick with what's clearer for now (possible heap allocation)

If you do want to keep UInt, I echo Brendan's point that we should try to use codec directly for this (or put up a preliminary PR that allows you to take it to a level of efficiency you are happy with).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we are using codec by virtue of using Write, which Encode requires as a super trait.

}

fn flush(&mut self) {
let (n, bytes) = encode_u64(self.pending);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure the code as-written is the same as self.hasher.update(UInt(self.pending).encode).as_ref()); However, it seems you are doing this to avoid a heap allocation (?) Related to #1507

I would probably just stick with what's clearer for now (possible heap allocation)

self
}

/// Like [Self::commit], except that subsequent calls are considered part of the same message.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clarity:

  • subsequent calls to what? Maybe: "...append and commit are considered part of the same message until the end of the next commit call." (?0
  • Mention that no other functions (besides append) can be called until commit is called, otherwise it will panic

Comment on lines 222 to 221
pub fn noise(&self, label: &'static [u8]) -> impl CryptoRngCore {
let mut out = Self::start(StartTag::Noise, Some(self.summarize().hash.as_bytes()));
out.commit(label);
Rng::new(out.hasher.finalize_xof())
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

finalizing twice (once in summarize and once in finalize_xof) seems a bit inefficient, so I considered recommending doing self.hasher.clone() and doing something with that, but I realize that creates kind of a minefield for possible collisions. So maybe the way your doing it is safest

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another possibility is adding in an EndTag which would get appended right before calling hasher.finalize (or finalize_xof). Then you could distinguish between summarize and noise without an additional compression function call.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a second look, this seems unavoidable if you want to keep &self, because you can't write in the label without modifying the state, and what you want to do instead is initialize a new hash object. I've pushed a commit which makes initialization take an optional Summary instead, to be used as the key, but you still need to commit the data to this new keyed hash function.

@cronokirby cronokirby changed the title WIP: Transcript API Transcript API Sep 3, 2025
This allows us to use the `rand_core::CryptoRngCore` trait alias,
which is very convenient.
Closes #1483

This creates a minimal API for cryptographic Transcripts. This is useful
for hashing, particularly in cases where we want some kind of hash,
but don't need to conform to a particular specification, and want to avoid
footguns around message sequencing, length extension, etc.
@cronokirby cronokirby force-pushed the cronokirby/transcript branch from ea49ed3 to c336372 Compare September 3, 2025 19:07
This makes it so that the inner method for initializating a transcript
will always take an Option key, either creating a normal hash,
or a keyed hash.
@cronokirby
Copy link
Collaborator Author

@BrendanChou did a pass on your review comments!

BrendanChou
BrendanChou previously approved these changes Sep 3, 2025
@cronokirby cronokirby force-pushed the cronokirby/transcript branch from cb142c9 to ba7d32e Compare September 3, 2025 21:17
Copy link
Contributor

@patrick-ogrady patrick-ogrady left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit on mod comment?

/// The namespace serves to disamiguate two transcripts, so that even if they record
/// the same information, the results will be different:
/// ```
/// # use commonware_cryptography::transcript::Transcript;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL

@patrick-ogrady patrick-ogrady merged commit 60b9b5a into main Sep 3, 2025
37 checks passed
@patrick-ogrady patrick-ogrady deleted the cronokirby/transcript branch September 3, 2025 22:16
@patrick-ogrady patrick-ogrady linked an issue Sep 3, 2025 that may be closed by this pull request
Copy link

codecov bot commented Sep 3, 2025

Codecov Report

❌ Patch coverage is 94.18605% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.07%. Comparing base (df8437d) to head (915602f).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
cryptography/src/transcript.rs 94.18% 10 Missing ⚠️
@@           Coverage Diff            @@
##             main    #1501    +/-   ##
========================================
  Coverage   92.06%   92.07%            
========================================
  Files         283      284     +1     
  Lines       73182    73354   +172     
========================================
+ Hits        67377    67540   +163     
- Misses       5805     5814     +9     
Files with missing lines Coverage Δ
cryptography/src/lib.rs 100.00% <ø> (ø)
cryptography/src/transcript.rs 94.18% <94.18%> (ø)

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update df8437d...915602f. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[cryptography] create transcript abstraction

3 participants