|
| 1 | +#![allow(non_snake_case)] |
1 | 2 | //! Definition of the proof struct. |
2 | 3 |
|
3 | 4 | use curve25519_dalek::ristretto::CompressedRistretto; |
4 | 5 | use curve25519_dalek::scalar::Scalar; |
5 | 6 |
|
| 7 | +use errors::R1CSError; |
6 | 8 | use inner_product_proof::InnerProductProof; |
| 9 | +use util; |
| 10 | + |
| 11 | +use serde::de::Visitor; |
| 12 | +use serde::{self, Deserialize, Deserializer, Serialize, Serializer}; |
7 | 13 |
|
8 | 14 | /// A proof of some statement specified by a |
9 | 15 | /// [`ConstraintSystem`](::r1cs::ConstraintSystem). |
@@ -56,3 +62,135 @@ pub struct R1CSProof { |
56 | 62 | /// Proof data for the inner-product argument. |
57 | 63 | pub(super) ipp_proof: InnerProductProof, |
58 | 64 | } |
| 65 | + |
| 66 | +impl R1CSProof { |
| 67 | + /// Serializes the proof into a byte array of \\(16 + 2k\\) 32-byte elements, |
| 68 | + /// where \\(k=\lceil \log_2(n) \rceil\\) and \\(n\\) is the number of multiplication gates. |
| 69 | + /// |
| 70 | + /// # Layout |
| 71 | + /// |
| 72 | + /// The layout of the r1cs proof encoding is: |
| 73 | + /// |
| 74 | + /// * eleven compressed Ristretto points \\(A_{I1},A_{O1},S_1,A_{I2},A_{O2},S_2,T_1,...,T_6\\), |
| 75 | + /// * three scalars \\(t_x, \tilde{t}_x, \tilde{e}\\), |
| 76 | + /// * \\(k\\) pairs of compressed Ristretto points \\(L_0,R_0\dots,L_{k-1},R_{k-1}\\), |
| 77 | + /// * two scalars \\(a, b\\). |
| 78 | + pub fn to_bytes(&self) -> Vec<u8> { |
| 79 | + let mut buf = Vec::with_capacity(self.serialized_size()); |
| 80 | + buf.extend_from_slice(self.A_I1.as_bytes()); |
| 81 | + buf.extend_from_slice(self.A_O1.as_bytes()); |
| 82 | + buf.extend_from_slice(self.S1.as_bytes()); |
| 83 | + buf.extend_from_slice(self.A_I2.as_bytes()); |
| 84 | + buf.extend_from_slice(self.A_O2.as_bytes()); |
| 85 | + buf.extend_from_slice(self.S2.as_bytes()); |
| 86 | + buf.extend_from_slice(self.T_1.as_bytes()); |
| 87 | + buf.extend_from_slice(self.T_3.as_bytes()); |
| 88 | + buf.extend_from_slice(self.T_4.as_bytes()); |
| 89 | + buf.extend_from_slice(self.T_5.as_bytes()); |
| 90 | + buf.extend_from_slice(self.T_6.as_bytes()); |
| 91 | + buf.extend_from_slice(self.t_x.as_bytes()); |
| 92 | + buf.extend_from_slice(self.t_x_blinding.as_bytes()); |
| 93 | + buf.extend_from_slice(self.e_blinding.as_bytes()); |
| 94 | + // XXX this costs an extra alloc |
| 95 | + buf.extend_from_slice(self.ipp_proof.to_bytes().as_slice()); |
| 96 | + buf |
| 97 | + } |
| 98 | + |
| 99 | + /// Returns the size in bytes required to serialize the `R1CSProof`. |
| 100 | + pub fn serialized_size(&self) -> usize { |
| 101 | + // 14 elements + the ipp |
| 102 | + 14 * 32 + self.ipp_proof.serialized_size() |
| 103 | + } |
| 104 | + |
| 105 | + /// Deserializes the proof from a byte slice. |
| 106 | + /// |
| 107 | + /// Returns an error if the byte slice cannot be parsed into a `R1CSProof`. |
| 108 | + pub fn from_bytes(mut slice: &[u8]) -> Result<R1CSProof, R1CSError> { |
| 109 | + if slice.len() % 32 != 0 { |
| 110 | + return Err(R1CSError::FormatError); |
| 111 | + } |
| 112 | + if slice.len() < 14 * 32 { |
| 113 | + return Err(R1CSError::FormatError); |
| 114 | + } |
| 115 | + |
| 116 | + // This macro takes care of counting bytes in the slice |
| 117 | + macro_rules! read32 { |
| 118 | + () => {{ |
| 119 | + let tmp = util::read32(slice); |
| 120 | + slice = &slice[32..]; |
| 121 | + tmp |
| 122 | + }}; |
| 123 | + } |
| 124 | + |
| 125 | + let A_I1 = CompressedRistretto(read32!()); |
| 126 | + let A_O1 = CompressedRistretto(read32!()); |
| 127 | + let S1 = CompressedRistretto(read32!()); |
| 128 | + let A_I2 = CompressedRistretto(read32!()); |
| 129 | + let A_O2 = CompressedRistretto(read32!()); |
| 130 | + let S2 = CompressedRistretto(read32!()); |
| 131 | + let T_1 = CompressedRistretto(read32!()); |
| 132 | + let T_3 = CompressedRistretto(read32!()); |
| 133 | + let T_4 = CompressedRistretto(read32!()); |
| 134 | + let T_5 = CompressedRistretto(read32!()); |
| 135 | + let T_6 = CompressedRistretto(read32!()); |
| 136 | + let t_x = Scalar::from_canonical_bytes(read32!()).ok_or(R1CSError::FormatError)?; |
| 137 | + let t_x_blinding = Scalar::from_canonical_bytes(read32!()).ok_or(R1CSError::FormatError)?; |
| 138 | + let e_blinding = Scalar::from_canonical_bytes(read32!()).ok_or(R1CSError::FormatError)?; |
| 139 | + |
| 140 | + // XXX: IPPProof from_bytes gives ProofError. |
| 141 | + let ipp_proof = InnerProductProof::from_bytes(slice).map_err(|_| R1CSError::FormatError)?; |
| 142 | + |
| 143 | + Ok(R1CSProof { |
| 144 | + A_I1, |
| 145 | + A_O1, |
| 146 | + S1, |
| 147 | + A_I2, |
| 148 | + A_O2, |
| 149 | + S2, |
| 150 | + T_1, |
| 151 | + T_3, |
| 152 | + T_4, |
| 153 | + T_5, |
| 154 | + T_6, |
| 155 | + t_x, |
| 156 | + t_x_blinding, |
| 157 | + e_blinding, |
| 158 | + ipp_proof, |
| 159 | + }) |
| 160 | + } |
| 161 | +} |
| 162 | + |
| 163 | +impl Serialize for R1CSProof { |
| 164 | + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
| 165 | + where |
| 166 | + S: Serializer, |
| 167 | + { |
| 168 | + serializer.serialize_bytes(&self.to_bytes()[..]) |
| 169 | + } |
| 170 | +} |
| 171 | + |
| 172 | +impl<'de> Deserialize<'de> for R1CSProof { |
| 173 | + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
| 174 | + where |
| 175 | + D: Deserializer<'de>, |
| 176 | + { |
| 177 | + struct R1CSProofVisitor; |
| 178 | + |
| 179 | + impl<'de> Visitor<'de> for R1CSProofVisitor { |
| 180 | + type Value = R1CSProof; |
| 181 | + |
| 182 | + fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { |
| 183 | + formatter.write_str("a valid R1CSProof") |
| 184 | + } |
| 185 | + |
| 186 | + fn visit_bytes<E>(self, v: &[u8]) -> Result<R1CSProof, E> |
| 187 | + where |
| 188 | + E: serde::de::Error, |
| 189 | + { |
| 190 | + R1CSProof::from_bytes(v).map_err(serde::de::Error::custom) |
| 191 | + } |
| 192 | + } |
| 193 | + |
| 194 | + deserializer.deserialize_bytes(R1CSProofVisitor) |
| 195 | + } |
| 196 | +} |
0 commit comments