You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

317 lines
9.0 KiB

  1. use bellperson::{
  2. gadgets::{boolean::AllocatedBit, num::AllocatedNum},
  3. ConstraintSystem, SynthesisError,
  4. };
  5. use ff::{PrimeField, PrimeFieldBits};
  6. use generic_array::typenum::U8;
  7. use neptune::{
  8. circuit::poseidon_hash,
  9. poseidon::{Poseidon, PoseidonConstants},
  10. };
  11. use nova_snark::{gadgets::ecc::AllocatedPoint, traits::circuit::StepCircuit};
  12. use subtle::Choice;
  13. // An affine point coordinate that is on the curve.
  14. #[derive(Clone, Copy, Debug)]
  15. pub struct Coordinate<F>
  16. where
  17. F: PrimeField<Repr = [u8; 32]>,
  18. {
  19. pub x: F,
  20. pub y: F,
  21. pub is_infinity: bool,
  22. }
  23. impl<F> Coordinate<F>
  24. where
  25. F: PrimeField<Repr = [u8; 32]>,
  26. {
  27. // New affine point coordiante on the curve so is_infinity = false.
  28. pub fn new(x: F, y: F) -> Self {
  29. Self {
  30. x,
  31. y,
  32. is_infinity: false,
  33. }
  34. }
  35. }
  36. // An ECDSA signature
  37. #[derive(Clone, Debug)]
  38. pub struct EcdsaSignature<Fb, Fs>
  39. where
  40. Fb: PrimeField<Repr = [u8; 32]>,
  41. Fs: PrimeField<Repr = [u8; 32]> + PrimeFieldBits,
  42. {
  43. pk: Coordinate<Fb>, // public key
  44. r: Coordinate<Fb>, // (r, s) is the ECDSA signature
  45. s: Fs,
  46. c: Fs, // hash of the message
  47. g: Coordinate<Fb>, // generator of the group; could be omitted if Nova's traits allow accessing the generator
  48. }
  49. impl<Fb, Fs> EcdsaSignature<Fb, Fs>
  50. where
  51. Fb: PrimeField<Repr = [u8; 32]>,
  52. Fs: PrimeField<Repr = [u8; 32]> + PrimeFieldBits,
  53. {
  54. pub fn new(pk: Coordinate<Fb>, r: Coordinate<Fb>, s: Fs, c: Fs, g: Coordinate<Fb>) -> Self {
  55. Self { pk, r, s, c, g }
  56. }
  57. }
  58. // An ECDSA signature proof that we will use on the primary curve
  59. #[derive(Clone, Debug)]
  60. pub struct EcdsaCircuit<F>
  61. where
  62. F: PrimeField<Repr = [u8; 32]>,
  63. {
  64. pub z_r: Coordinate<F>,
  65. pub z_g: Coordinate<F>,
  66. pub z_pk: Coordinate<F>,
  67. pub z_c: F,
  68. pub z_s: F,
  69. pub r: Coordinate<F>,
  70. pub g: Coordinate<F>,
  71. pub pk: Coordinate<F>,
  72. pub c: F,
  73. pub s: F,
  74. pub c_bits: Vec<Choice>,
  75. pub s_bits: Vec<Choice>,
  76. pub pc: PoseidonConstants<F, U8>,
  77. }
  78. impl<F> EcdsaCircuit<F>
  79. where
  80. F: PrimeField<Repr = [u8; 32]>,
  81. {
  82. // Creates a new [`EcdsaCircuit<Fb, Fs>`]. The base and scalar field elements from the curve
  83. // field used by the signature are converted to scalar field elements from the cyclic curve
  84. // field used by the circuit.
  85. pub fn new<Fb, Fs>(
  86. num_steps: usize,
  87. signatures: &[EcdsaSignature<Fb, Fs>],
  88. pc: &PoseidonConstants<F, U8>,
  89. ) -> (F, Vec<Self>)
  90. where
  91. Fb: PrimeField<Repr = [u8; 32]>,
  92. Fs: PrimeField<Repr = [u8; 32]> + PrimeFieldBits,
  93. {
  94. let mut z0 = F::zero();
  95. let mut circuits = Vec::new();
  96. for i in 0..num_steps {
  97. let mut j = i;
  98. if i > 0 {
  99. j = i - 1
  100. };
  101. let z_signature = &signatures[j];
  102. let z_r = Coordinate::new(
  103. F::from_repr(z_signature.r.x.to_repr()).unwrap(),
  104. F::from_repr(z_signature.r.y.to_repr()).unwrap(),
  105. );
  106. let z_g = Coordinate::new(
  107. F::from_repr(z_signature.g.x.to_repr()).unwrap(),
  108. F::from_repr(z_signature.g.y.to_repr()).unwrap(),
  109. );
  110. let z_pk = Coordinate::new(
  111. F::from_repr(z_signature.pk.x.to_repr()).unwrap(),
  112. F::from_repr(z_signature.pk.y.to_repr()).unwrap(),
  113. );
  114. let z_c = F::from_repr(z_signature.c.to_repr()).unwrap();
  115. let z_s = F::from_repr(z_signature.s.to_repr()).unwrap();
  116. let signature = &signatures[i];
  117. let r = Coordinate::new(
  118. F::from_repr(signature.r.x.to_repr()).unwrap(),
  119. F::from_repr(signature.r.y.to_repr()).unwrap(),
  120. );
  121. let g = Coordinate::new(
  122. F::from_repr(signature.g.x.to_repr()).unwrap(),
  123. F::from_repr(signature.g.y.to_repr()).unwrap(),
  124. );
  125. let pk = Coordinate::new(
  126. F::from_repr(signature.pk.x.to_repr()).unwrap(),
  127. F::from_repr(signature.pk.y.to_repr()).unwrap(),
  128. );
  129. let c_bits = Self::to_le_bits(&signature.c);
  130. let s_bits = Self::to_le_bits(&signature.s);
  131. let c = F::from_repr(signature.c.to_repr()).unwrap();
  132. let s = F::from_repr(signature.s.to_repr()).unwrap();
  133. let circuit = EcdsaCircuit {
  134. z_r,
  135. z_g,
  136. z_pk,
  137. z_c,
  138. z_s,
  139. r,
  140. g,
  141. pk,
  142. c,
  143. s,
  144. c_bits,
  145. s_bits,
  146. pc: pc.clone(),
  147. };
  148. circuits.push(circuit);
  149. if i == 0 {
  150. z0 =
  151. Poseidon::<F, U8>::new_with_preimage(&[r.x, r.y, g.x, g.y, pk.x, pk.y, c, s], pc).hash();
  152. }
  153. }
  154. (z0, circuits)
  155. }
  156. // Converts the scalar field element from the curve used by the signature to a bit represenation
  157. // for later use in scalar multiplication using the cyclic curve used by the circuit.
  158. fn to_le_bits<Fs>(fs: &Fs) -> Vec<Choice>
  159. where
  160. Fs: PrimeField<Repr = [u8; 32]> + PrimeFieldBits,
  161. {
  162. let bits = fs
  163. .to_repr()
  164. .iter()
  165. .flat_map(|byte| (0..8).map(move |i| Choice::from((byte >> i) & 1u8)))
  166. .collect::<Vec<Choice>>();
  167. bits
  168. }
  169. // Synthesize a bit representation into circuit gadgets.
  170. fn synthesize_bits<CS: ConstraintSystem<F>>(
  171. cs: &mut CS,
  172. bits: &[Choice],
  173. ) -> Result<Vec<AllocatedBit>, SynthesisError> {
  174. let alloc_bits: Vec<AllocatedBit> = bits
  175. .iter()
  176. .enumerate()
  177. .map(|(i, bit)| {
  178. AllocatedBit::alloc(
  179. cs.namespace(|| format!("bit {}", i)),
  180. Some(bit.unwrap_u8() == 1u8),
  181. )
  182. })
  183. .collect::<Result<Vec<AllocatedBit>, SynthesisError>>()
  184. .unwrap();
  185. Ok(alloc_bits)
  186. }
  187. }
  188. impl<F> StepCircuit<F> for EcdsaCircuit<F>
  189. where
  190. F: PrimeField<Repr = [u8; 32]> + PrimeFieldBits,
  191. {
  192. // Prove knowledge of the sk used to generate the Ecdsa signature (R,s)
  193. // with public key PK and message commitment c.
  194. // [s]G == R + [c]PK
  195. fn synthesize<CS: ConstraintSystem<F>>(
  196. &self,
  197. cs: &mut CS,
  198. z: AllocatedNum<F>,
  199. ) -> Result<AllocatedNum<F>, SynthesisError> {
  200. let z_rx = AllocatedNum::alloc(cs.namespace(|| "z_rx"), || Ok(self.z_r.x))?;
  201. let z_ry = AllocatedNum::alloc(cs.namespace(|| "z_ry"), || Ok(self.z_r.y))?;
  202. let z_gx = AllocatedNum::alloc(cs.namespace(|| "z_gx"), || Ok(self.z_g.x))?;
  203. let z_gy = AllocatedNum::alloc(cs.namespace(|| "z_gy"), || Ok(self.z_g.y))?;
  204. let z_pkx = AllocatedNum::alloc(cs.namespace(|| "z_pkx"), || Ok(self.z_pk.x))?;
  205. let z_pky = AllocatedNum::alloc(cs.namespace(|| "z_pky"), || Ok(self.z_pk.y))?;
  206. let z_c = AllocatedNum::alloc(cs.namespace(|| "z_c"), || Ok(self.z_c))?;
  207. let z_s = AllocatedNum::alloc(cs.namespace(|| "z_s"), || Ok(self.z_s))?;
  208. let z_hash = poseidon_hash(
  209. cs.namespace(|| "input hash"),
  210. vec![z_rx, z_ry, z_gx, z_gy, z_pkx, z_pky, z_c, z_s],
  211. &self.pc,
  212. )?;
  213. cs.enforce(
  214. || "z == z1",
  215. |lc| lc + z.get_variable(),
  216. |lc| lc + CS::one(),
  217. |lc| lc + z_hash.get_variable(),
  218. );
  219. let g = AllocatedPoint::alloc(
  220. cs.namespace(|| "G"),
  221. Some((self.g.x, self.g.y, self.g.is_infinity)),
  222. )?;
  223. let s_bits = Self::synthesize_bits(&mut cs.namespace(|| "s_bits"), &self.s_bits)?;
  224. let sg = g.scalar_mul(cs.namespace(|| "[s]G"), s_bits)?;
  225. let r = AllocatedPoint::alloc(
  226. cs.namespace(|| "R"),
  227. Some((self.r.x, self.r.y, self.r.is_infinity)),
  228. )?;
  229. let c_bits = Self::synthesize_bits(&mut cs.namespace(|| "c_bits"), &self.c_bits)?;
  230. let pk = AllocatedPoint::alloc(
  231. cs.namespace(|| "PK"),
  232. Some((self.pk.x, self.pk.y, self.pk.is_infinity)),
  233. )?;
  234. let cpk = pk.scalar_mul(&mut cs.namespace(|| "[c]PK"), c_bits)?;
  235. let rcpk = cpk.add(&mut cs.namespace(|| "R + [c]PK"), &r)?;
  236. let (rcpk_x, rcpk_y, _) = rcpk.get_coordinates();
  237. let (sg_x, sg_y, _) = sg.get_coordinates();
  238. cs.enforce(
  239. || "sg_x == rcpk_x",
  240. |lc| lc + sg_x.get_variable(),
  241. |lc| lc + CS::one(),
  242. |lc| lc + rcpk_x.get_variable(),
  243. );
  244. cs.enforce(
  245. || "sg_y == rcpk_y",
  246. |lc| lc + sg_y.get_variable(),
  247. |lc| lc + CS::one(),
  248. |lc| lc + rcpk_y.get_variable(),
  249. );
  250. let rx = AllocatedNum::alloc(cs.namespace(|| "rx"), || Ok(self.r.x))?;
  251. let ry = AllocatedNum::alloc(cs.namespace(|| "ry"), || Ok(self.r.y))?;
  252. let gx = AllocatedNum::alloc(cs.namespace(|| "gx"), || Ok(self.g.x))?;
  253. let gy = AllocatedNum::alloc(cs.namespace(|| "gy"), || Ok(self.g.y))?;
  254. let pkx = AllocatedNum::alloc(cs.namespace(|| "pkx"), || Ok(self.pk.x))?;
  255. let pky = AllocatedNum::alloc(cs.namespace(|| "pky"), || Ok(self.pk.y))?;
  256. let c = AllocatedNum::alloc(cs.namespace(|| "c"), || Ok(self.c))?;
  257. let s = AllocatedNum::alloc(cs.namespace(|| "s"), || Ok(self.s))?;
  258. poseidon_hash(
  259. cs.namespace(|| "output hash"),
  260. vec![rx, ry, gx, gy, pkx, pky, c, s],
  261. &self.pc,
  262. )
  263. }
  264. fn compute(&self, z: &F) -> F {
  265. let z_hash = Poseidon::<F, U8>::new_with_preimage(
  266. &[
  267. self.z_r.x,
  268. self.z_r.y,
  269. self.z_g.x,
  270. self.z_g.y,
  271. self.z_pk.x,
  272. self.z_pk.y,
  273. self.z_c,
  274. self.z_s,
  275. ],
  276. &self.pc,
  277. )
  278. .hash();
  279. debug_assert_eq!(z, &z_hash);
  280. Poseidon::<F, U8>::new_with_preimage(
  281. &[
  282. self.r.x, self.r.y, self.g.x, self.g.y, self.pk.x, self.pk.y, self.c, self.s,
  283. ],
  284. &self.pc,
  285. )
  286. .hash()
  287. }
  288. }