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
//! This module provides common types and constants for encrypted transfers.
use crate::{
    bulletproofs::range_proof::*,
    common::{types::Amount, *},
    curve_arithmetic::*,
    elgamal::*,
    sigma_protocols::{common::*, enc_trans::EncTransResponse},
};

#[derive(Clone, Copy, Serialize, SerdeSerialize, SerdeDeserialize, Debug, Default)]
#[serde(transparent)]
#[repr(transparent)]
/// A sequential index of an incoming encrypted amount on an account.
pub struct EncryptedAmountIndex {
    pub index: u64,
}

#[derive(Clone, Copy, Serialize, SerdeSerialize, SerdeDeserialize, Debug, Default)]
#[serde(transparent)]
#[repr(transparent)]
/// An index that represents which encrypted amounts have been combined into an
/// associated encrypted amount.
/// This is in contrast to [EncryptedAmountIndex] which identifies a single
/// encrypted amount (per account).
pub struct EncryptedAmountAggIndex {
    pub index: u64,
}

impl From<u64> for EncryptedAmountAggIndex {
    fn from(index: u64) -> Self { EncryptedAmountAggIndex { index } }
}

impl From<u64> for EncryptedAmountIndex {
    fn from(index: u64) -> Self { EncryptedAmountIndex { index } }
}

#[derive(PartialEq, Eq, Clone, Serialize, SerdeBase16Serialize, Debug)]
/// An encrypted amount, in two chunks in "little endian limbs". That is, the
/// first chunk represents the low 32 bits of an amount, and the second chunk
/// represents the high 32 bits. The JSON serialization of this is just base16
/// encoded serialized chunks.
pub struct EncryptedAmount<C: Curve> {
    pub encryptions: [Cipher<C>; 2],
}

impl<C: Curve> AsRef<[Cipher<C>; 2]> for EncryptedAmount<C> {
    fn as_ref(&self) -> &[Cipher<C>; 2] { &self.encryptions }
}

impl<C: Curve> AsRef<[Cipher<C>]> for EncryptedAmount<C> {
    fn as_ref(&self) -> &[Cipher<C>] { self.encryptions.as_ref() }
}

/// Randomness used when producing an encrypted amount.
pub struct EncryptedAmountRandomness<C: Curve> {
    pub randomness: [Randomness<C>; 2],
}

/// An encrypted amount that we know the index of.
#[derive(Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
#[serde(rename_all = "camelCase")]
pub struct IndexedEncryptedAmount<C: Curve> {
    /// The actual encrypted amount.
    pub encrypted_chunks: EncryptedAmount<C>,
    /// Index of the amount on the account.
    pub index:            EncryptedAmountIndex,
}

/// Size of the chunk for encrypted amounts.
pub const CHUNK_SIZE: ChunkSize = ChunkSize::ThirtyTwo;

/// Data that will go onto an encrypted amount transfer.
#[derive(Serialize, SerdeSerialize, SerdeDeserialize, Clone, Debug)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
#[serde(rename_all = "camelCase")]
pub struct EncryptedAmountTransferData<C: Curve> {
    /// Encryption of the remaining amount.
    pub remaining_amount: EncryptedAmount<C>,
    /// Amount that will be sent.
    pub transfer_amount:  EncryptedAmount<C>,
    /// The index such that the encrypted amount used in the transfer represents
    /// the aggregate of all encrypted amounts with indices < `index` existing
    /// on the account at the time. New encrypted amounts can only add new
    /// indices.
    pub index:            EncryptedAmountAggIndex,
    /// A collection of all the proofs.
    pub proof:            EncryptedAmountTransferProof<C>,
}

/// Data that will go onto a secret to public amount transfer.
#[derive(Serialize, SerdeSerialize, SerdeDeserialize, Debug, Clone)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
#[serde(rename_all = "camelCase")]
pub struct SecToPubAmountTransferData<C: Curve> {
    /// Encryption of the remaining amount.
    pub remaining_amount: EncryptedAmount<C>,
    /// Amount that will be sent.
    pub transfer_amount:  Amount,
    /// The index such that the encrypted amount used in the transfer represents
    /// the aggregate of all encrypted amounts with indices < `index` existing
    /// on the account at the time. New encrypted amounts can only add new
    /// indices.
    pub index:            EncryptedAmountAggIndex,
    /// A collection of all the proofs.
    pub proof:            SecToPubAmountTransferProof<C>,
}

/// An aggregated encrypted amount with a decrypted plaintext, collecting
/// encrypted amounts with decryption. The only real difference from the above
/// is the meaning of the index field.
#[derive(Serialize, SerdeSerialize, SerdeDeserialize)]
#[serde(bound(serialize = "C: Curve", deserialize = "C: Curve"))]
#[serde(rename_all = "camelCase")]
pub struct AggregatedDecryptedAmount<C: Curve> {
    /// The aggregated encrypted amount.
    pub agg_encrypted_amount: EncryptedAmount<C>,
    /// The plaintext corresponding to the aggregated encrypted amount.
    pub agg_amount:           Amount,
    /// Index such that the `agg_amount` is the sum of all encrypted amounts
    /// on an account with indices strictly below `agg_index`.
    #[serde(default)]
    pub agg_index:            EncryptedAmountAggIndex,
}

// # Proof datatypes

/// Proof that an encrypted transfer data is well-formed
#[derive(Serialize, SerdeBase16Serialize, Clone, Debug)]
pub struct EncryptedAmountTransferProof<C: Curve> {
    /// Proof that accounting is done correctly, i.e., remaining + transfer is
    /// the original amount.
    pub accounting: SigmaProof<EncTransResponse<C>>,
    /// Proof that the transfered amount is correctly encrypted, i.e., chunks
    /// are small enough.
    pub transfer_amount_correct_encryption: RangeProof<C>,
    /// Proof that the remaining amount is correctly encrypted, i.e, chunks
    /// are small enough.
    pub remaining_amount_correct_encryption: RangeProof<C>,
}

/// Proof that an encrypted transfer data is well-formed
#[derive(Serialize, SerdeBase16Serialize, Clone, Debug)]
pub struct SecToPubAmountTransferProof<C: Curve> {
    /// Proof that accounting is done correctly, i.e., remaining + transfer is
    /// the original amount.
    pub accounting: SigmaProof<EncTransResponse<C>>,
    /// Proof that the remaining amount is correctly encrypted, i.e, chunks
    /// small enough.
    pub remaining_amount_correct_encryption: RangeProof<C>,
}