1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use {
    crate::{errors::TranscriptError, zk_token_elgamal::pod},
    curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar, traits::IsIdentity},
    merlin::Transcript,
};

pub trait TranscriptProtocol {
    /// Append a domain separator for an `n`-bit rangeproof for ElGamalKeypair
    /// ciphertext using a decryption key
    fn rangeproof_from_key_domain_sep(&mut self, n: u64);

    /// Append a domain separator for an `n`-bit rangeproof for ElGamalKeypair
    /// ciphertext using an opening
    fn rangeproof_from_opening_domain_sep(&mut self, n: u64);

    /// Append a domain separator for a length-`n` inner product proof.
    fn innerproduct_domain_sep(&mut self, n: u64);

    /// Append a domain separator for close account proof.
    fn close_account_proof_domain_sep(&mut self);

    /// Append a domain separator for withdraw proof.
    fn withdraw_proof_domain_sep(&mut self);

    /// Append a domain separator for transfer proof.
    fn transfer_proof_domain_sep(&mut self);

    /// Append a `scalar` with the given `label`.
    fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar);

    /// Append a `point` with the given `label`.
    fn append_point(&mut self, label: &'static [u8], point: &CompressedRistretto);

    /// Append an ElGamal pubkey with the given `label`.
    fn append_pubkey(&mut self, label: &'static [u8], point: &pod::ElGamalPubkey);

    /// Append an ElGamal ciphertext with the given `label`.
    fn append_ciphertext(&mut self, label: &'static [u8], point: &pod::ElGamalCiphertext);

    /// Append a Pedersen commitment with the given `label`.
    fn append_commitment(&mut self, label: &'static [u8], point: &pod::PedersenCommitment);

    /// Append an ElGamal decryption handle with the given `label`.
    fn append_handle(&mut self, label: &'static [u8], point: &pod::DecryptHandle);

    /// Append a domain separator for equality proof.
    fn equality_proof_domain_sep(&mut self);

    /// Append a domain separator for zero-balance proof.
    fn zero_balance_proof_domain_sep(&mut self);

    /// Append a domain separator for validity proof.
    fn validity_proof_domain_sep(&mut self);

    /// Append a domain separator for aggregated validity proof.
    fn aggregated_validity_proof_domain_sep(&mut self);

    /// Append a domain separator for fee sigma proof.
    fn fee_sigma_proof_domain_sep(&mut self);

    /// Check that a point is not the identity, then append it to the
    /// transcript.  Otherwise, return an error.
    fn validate_and_append_point(
        &mut self,
        label: &'static [u8],
        point: &CompressedRistretto,
    ) -> Result<(), TranscriptError>;

    /// Compute a `label`ed challenge variable.
    fn challenge_scalar(&mut self, label: &'static [u8]) -> Scalar;
}

impl TranscriptProtocol for Transcript {
    fn rangeproof_from_key_domain_sep(&mut self, n: u64) {
        self.append_message(b"dom-sep", b"rangeproof from opening v1");
        self.append_u64(b"n", n);
    }

    fn rangeproof_from_opening_domain_sep(&mut self, n: u64) {
        self.append_message(b"dom-sep", b"rangeproof from opening v1");
        self.append_u64(b"n", n);
    }

    fn innerproduct_domain_sep(&mut self, n: u64) {
        self.append_message(b"dom-sep", b"ipp v1");
        self.append_u64(b"n", n);
    }

    fn close_account_proof_domain_sep(&mut self) {
        self.append_message(b"dom-sep", b"CloseAccountProof");
    }

    fn withdraw_proof_domain_sep(&mut self) {
        self.append_message(b"dom-sep", b"WithdrawProof");
    }

    fn transfer_proof_domain_sep(&mut self) {
        self.append_message(b"dom-sep", b"TransferProof");
    }

    fn append_scalar(&mut self, label: &'static [u8], scalar: &Scalar) {
        self.append_message(label, scalar.as_bytes());
    }

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

    fn validate_and_append_point(
        &mut self,
        label: &'static [u8],
        point: &CompressedRistretto,
    ) -> Result<(), TranscriptError> {
        if point.is_identity() {
            Err(TranscriptError::ValidationError)
        } else {
            self.append_message(label, point.as_bytes());
            Ok(())
        }
    }

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

        Scalar::from_bytes_mod_order_wide(&buf)
    }

    fn append_pubkey(&mut self, label: &'static [u8], pubkey: &pod::ElGamalPubkey) {
        self.append_message(label, &pubkey.0);
    }

    fn append_ciphertext(&mut self, label: &'static [u8], ciphertext: &pod::ElGamalCiphertext) {
        self.append_message(label, &ciphertext.0);
    }

    fn append_commitment(&mut self, label: &'static [u8], commitment: &pod::PedersenCommitment) {
        self.append_message(label, &commitment.0);
    }

    fn append_handle(&mut self, label: &'static [u8], handle: &pod::DecryptHandle) {
        self.append_message(label, &handle.0);
    }

    fn equality_proof_domain_sep(&mut self) {
        self.append_message(b"dom-sep", b"equality-proof")
    }

    fn zero_balance_proof_domain_sep(&mut self) {
        self.append_message(b"dom-sep", b"zero-balance-proof")
    }

    fn validity_proof_domain_sep(&mut self) {
        self.append_message(b"dom-sep", b"validity-proof")
    }

    fn aggregated_validity_proof_domain_sep(&mut self) {
        self.append_message(b"dom-sep", b"aggregated-validity-proof")
    }

    fn fee_sigma_proof_domain_sep(&mut self) {
        self.append_message(b"dom-sep", b"fee-sigma-proof")
    }
}