[][src]Struct zkp::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]

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

Performs copy-assignment from source. Read more

impl TranscriptProtocol for Transcript[src]

Auto Trait Implementations

impl Send for Transcript

impl Sync for Transcript

Blanket Implementations

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> From for T[src]

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

type Error = Infallible

The type returned in the event of a conversion error.

impl<T> Borrow for T where
    T: ?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

The type returned in the event of a conversion error.

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

impl<T> Same for T

type Output = T

Should always be Self