[][src]Struct merlin::Transcript

pub struct Transcript { /* fields omitted */ }

A transcript of a public-coin argument.

The prover's messages are added to the transcript using commit_bytes, and the verifier's challenges can be computed using challenge_bytes.

Creating and using a Merlin transcript

To create a Merlin transcript, use Transcript::new(). This function takes a domain separation label which should be unique to the application. To use the transcript with a Merlin-based proof implementation, the prover's side creates a Merlin transcript with an application-specific domain separation label, and passes a &mut reference to the transcript to the proving function(s). To verify the resulting proof, the verifier creates their own Merlin transcript using the same domain separation label, then passes a &mut reference to the verifier's transcript to the verification function.

Implementing proofs using Merlin

Implementations of proof protocols should take a &mut Transcript as a parameter, not construct one internally. This provides three benefits:

  1. It forces the API client to initialize their own transcript using Transcript::new(). Since that function takes a domain separation string, this ensures that all proofs are domain-separated, not just with a proof-specific domain separator, but also with a per-application domain separator.

  2. It ensures that protocols are sequentially composable, by running them on a common transcript. (Since transcript instances are domain-separated, it should not be possible to extract a sub-protocol's challenges and commitments as a standalone proof).

  3. It allows API clients to commit contextual data to the proof transcript prior to running the protocol, allowing them to bind proof statements to arbitrary application data.

Defining protocol behaviour with extension traits

This API is byte-oriented, while an actual protocol likely requires typed data — for instance, a protocol probably wants to receive challenge scalars, not challenge bytes. The recommended way to bridge this abstraction gap is to define a protocol-specific extension trait.

For instance, consider a discrete-log based protocol which commits to Ristretto points and requires challenge scalars for the Ristretto group. This protocol can define a protocol-specific extension trait in its crate as follows:

extern crate curve25519_dalek;
use curve25519_dalek::ristretto::RistrettoPoint;
use curve25519_dalek::ristretto::CompressedRistretto;
use curve25519_dalek::scalar::Scalar;

extern crate merlin;
use merlin::Transcript;

trait TranscriptProtocol {
    fn domain_sep(&mut self);
    fn commit_point(&mut self, label: &'static [u8], point: &CompressedRistretto);
    fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar;
}

impl TranscriptProtocol for Transcript {
    fn domain_sep(&mut self) {
        self.commit_bytes(b"dom-sep", b"TranscriptProtocol Example");
    }

    fn commit_point(&mut self, label: &'static [u8], point: &CompressedRistretto) {
        self.commit_bytes(label, point.as_bytes());
    }

    fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar {
        let mut buf = [0; 64];
        self.challenge_bytes(label, &mut buf);
        Scalar::from_bytes_mod_order_wide(&buf)
    }
}

fn example(transcript: &mut Transcript, A: &RistrettoPoint, B: &RistrettoPoint) {
    // Since the TranscriptProtocol trait is in scope, the extension
    // methods are available on the `transcript` object:
    transcript.domain_sep();
    transcript.commit_point(b"A", &A.compress());
    transcript.commit_point(b"B", &B.compress());
    let c = transcript.challenge_scalar(b"c");
    // ...
}

Now, the implementation of the protocol can use the domain_sep to add domain separation to an existing &mut Transcript, and then call the commit_point and challenge_scalar methods, rather than calling commit_bytes and challenge_bytes directly.

However, because the protocol-specific behaviour is defined in a protocol-specific trait, different protocols can use the same Transcript instance without imposing any extra type constraints.

Methods

impl Transcript[src]

pub fn new(label: &'static [u8]) -> Transcript[src]

Initialize a new transcript with the supplied label, which is used as a domain separator.

Note

This function should be called by a protocol's API consumer, and not by the protocol implementation. See above for details.

Implementation

Initializes a STROBE-128 context with a Merlin domain-separator label, then commits the user-supplied label using the STROBE operations

meta-AD( b"dom-sep" || LE32(label.len()) );
AD( label );

pub fn commit_bytes(&mut self, label: &'static [u8], message: &[u8])[src]

Commit a prover's message to the transcript.

The label parameter is metadata about the message, and is also committed to the transcript.

Implementation

Performs the STROBE operations

meta-AD( label || LE32(message.len()) );
AD( message );

pub fn commit_u64(&mut self, label: &'static [u8], x: u64)[src]

Convenience method for committing a u64 to the transcript.

The label parameter is metadata about the message, and is also committed to the transcript.

Implementation

Calls commit_bytes with the little-endian encoding of x.

pub fn challenge_bytes(&mut self, label: &'static [u8], dest: &mut [u8])[src]

Fill the supplied buffer with the verifier's challenge bytes.

The label parameter is metadata about the challenge, and is also committed to the transcript.

Implementation

Performs the STROBE operations

meta-AD( label || LE32(dest.len()) );
dest <- PRF();

pub fn build_rng(&self) -> TranscriptRngBuilder[src]

Fork the current Transcript to construct an RNG whose output is bound to the current transcript state as well as prover's secrets.

See the TranscriptRngBuilder documentation for more details.

Trait Implementations

impl Clone for Transcript[src]

fn clone_from(&mut self, source: &Self)
1.0.0
[src]

Performs copy-assignment from source. Read more

Auto Trait Implementations

impl Send for Transcript

impl Sync for Transcript

Blanket Implementations

impl<T> From for T[src]

impl<T, U> Into for T where
    U: From<T>, 
[src]

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

impl<T, U> TryFrom for T where
    U: Into<T>, 
[src]

type Error = !

🔬 This is a nightly-only experimental API. (try_from)

The type returned in the event of a conversion error.

impl<T> Borrow for T where
    T: ?Sized
[src]

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> BorrowMut for T where
    T: ?Sized
[src]

impl<T, U> TryInto for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

🔬 This is a nightly-only experimental API. (try_from)

The type returned in the event of a conversion error.