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.

309 lines
9.2 KiB

  1. //! Demonstrates how to use Nova to produce a recursive proof of an ECDSA signature.
  2. //! This example proves the knowledge of a sequence of ECDSA signatures with different public keys on different messages,
  3. //! but the example can be adapted to other settings (e.g., proving the validity of the certificate chain with a well-known root public key)
  4. //! Scheme borrowed from https://github.com/filecoin-project/bellperson-gadgets/blob/main/src/eddsa.rs
  5. //! Sign using G1 curve, and prove using G2 curve.
  6. use core::ops::{Add, AddAssign, Mul, MulAssign, Neg};
  7. use ff::{
  8. derive::byteorder::{ByteOrder, LittleEndian},
  9. Field, PrimeField, PrimeFieldBits,
  10. };
  11. use generic_array::typenum::U8;
  12. use neptune::{poseidon::PoseidonConstants, Strength};
  13. use nova_snark::{
  14. traits::{circuit::TrivialTestCircuit, Group as Nova_Group},
  15. CompressedSNARK, PublicParams, RecursiveSNARK,
  16. };
  17. use num_bigint::BigUint;
  18. use pasta_curves::{
  19. arithmetic::CurveAffine,
  20. group::{Curve, Group},
  21. };
  22. use rand::{rngs::OsRng, RngCore};
  23. use sha3::{Digest, Sha3_512};
  24. use subtle::Choice;
  25. mod circuit;
  26. mod utils;
  27. use crate::circuit::{Coordinate, EcdsaCircuit, EcdsaSignature};
  28. use crate::utils::BitIterator;
  29. type G1 = pasta_curves::pallas::Point;
  30. type G2 = pasta_curves::vesta::Point;
  31. type S1 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G2>;
  32. type S2 = nova_snark::spartan_with_ipa_pc::RelaxedR1CSSNARK<G1>;
  33. #[derive(Debug, Clone, Copy)]
  34. pub struct SecretKey(pub <G1 as Group>::Scalar);
  35. impl SecretKey {
  36. pub fn random(mut rng: impl RngCore) -> Self {
  37. let secret = <G1 as Group>::Scalar::random(&mut rng);
  38. Self(secret)
  39. }
  40. }
  41. #[derive(Debug, Clone, Copy)]
  42. pub struct PublicKey(pub G1);
  43. impl PublicKey {
  44. pub fn from_secret_key(s: &SecretKey) -> Self {
  45. let point = G1::generator() * s.0;
  46. Self(point)
  47. }
  48. }
  49. #[derive(Clone)]
  50. pub struct Signature {
  51. pub r: G1,
  52. pub s: <G1 as Group>::Scalar,
  53. }
  54. impl SecretKey {
  55. pub fn sign(self, c: <G1 as Group>::Scalar, mut rng: impl RngCore) -> Signature {
  56. // T
  57. let mut t = [0u8; 80];
  58. rng.fill_bytes(&mut t[..]);
  59. // h = H*(T || M)
  60. let h = Self::hash_to_scalar(b"Nova_Ecdsa_Hash", &t[..], &c.to_repr());
  61. // R = [h]G
  62. let r = G1::generator().mul(h);
  63. // s = h + c * sk
  64. let mut s = c;
  65. s.mul_assign(&self.0);
  66. s.add_assign(&h);
  67. Signature { r, s }
  68. }
  69. fn mul_bits<B: AsRef<[u64]>>(
  70. s: &<G1 as Group>::Scalar,
  71. bits: BitIterator<B>,
  72. ) -> <G1 as Group>::Scalar {
  73. let mut x = <G1 as Group>::Scalar::zero();
  74. for bit in bits {
  75. x.double();
  76. if bit {
  77. x.add_assign(s)
  78. }
  79. }
  80. x
  81. }
  82. fn to_uniform(digest: &[u8]) -> <G1 as Group>::Scalar {
  83. assert_eq!(digest.len(), 64);
  84. let mut bits: [u64; 8] = [0; 8];
  85. LittleEndian::read_u64_into(digest, &mut bits);
  86. Self::mul_bits(&<G1 as Group>::Scalar::one(), BitIterator::new(bits))
  87. }
  88. pub fn to_uniform_32(digest: &[u8]) -> <G1 as Group>::Scalar {
  89. assert_eq!(digest.len(), 32);
  90. let mut bits: [u64; 4] = [0; 4];
  91. LittleEndian::read_u64_into(digest, &mut bits);
  92. Self::mul_bits(&<G1 as Group>::Scalar::one(), BitIterator::new(bits))
  93. }
  94. pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> <G1 as Group>::Scalar {
  95. let mut hasher = Sha3_512::new();
  96. hasher.input(persona);
  97. hasher.input(a);
  98. hasher.input(b);
  99. let digest = hasher.result();
  100. Self::to_uniform(digest.as_ref())
  101. }
  102. }
  103. impl PublicKey {
  104. pub fn verify(&self, c: <G1 as Group>::Scalar, signature: &Signature) -> bool {
  105. let modulus = Self::modulus_as_scalar();
  106. let order_check_pk = self.0.mul(modulus);
  107. if !order_check_pk.eq(&G1::identity()) {
  108. return false;
  109. }
  110. let order_check_r = signature.r.mul(modulus);
  111. if !order_check_r.eq(&G1::identity()) {
  112. return false;
  113. }
  114. // 0 = [-s]G + R + [c]PK
  115. self
  116. .0
  117. .mul(c)
  118. .add(&signature.r)
  119. .add(G1::generator().mul(signature.s).neg())
  120. .eq(&G1::identity())
  121. }
  122. fn modulus_as_scalar() -> <G1 as Group>::Scalar {
  123. let mut bits = <G1 as Group>::Scalar::char_le_bits().to_bitvec();
  124. let mut acc = BigUint::new(Vec::<u32>::new());
  125. while let Some(b) = bits.pop() {
  126. acc <<= 1_i32;
  127. acc += b as u8;
  128. }
  129. let modulus = acc.to_str_radix(10);
  130. <G1 as Group>::Scalar::from_str_vartime(&modulus).unwrap()
  131. }
  132. }
  133. fn main() {
  134. // In a VERY LIMITED case of messages known to be unique due to application level
  135. // and being less than the group order when interpreted as integer, one can sign
  136. // the message directly without hashing
  137. pub const MAX_MESSAGE_LEN: usize = 16;
  138. assert!(MAX_MESSAGE_LEN * 8 <= <G1 as Group>::Scalar::CAPACITY as usize);
  139. // produce public parameters
  140. println!("Generating public parameters...");
  141. let pc = PoseidonConstants::<<G2 as Group>::Scalar, U8>::new_with_strength(Strength::Standard);
  142. let circuit_primary = EcdsaCircuit::<<G2 as Nova_Group>::Scalar> {
  143. z_r: Coordinate::new(
  144. <G2 as Nova_Group>::Scalar::zero(),
  145. <G2 as Nova_Group>::Scalar::zero(),
  146. ),
  147. z_g: Coordinate::new(
  148. <G2 as Nova_Group>::Scalar::zero(),
  149. <G2 as Nova_Group>::Scalar::zero(),
  150. ),
  151. z_pk: Coordinate::new(
  152. <G2 as Nova_Group>::Scalar::zero(),
  153. <G2 as Nova_Group>::Scalar::zero(),
  154. ),
  155. z_c: <G2 as Nova_Group>::Scalar::zero(),
  156. z_s: <G2 as Nova_Group>::Scalar::zero(),
  157. r: Coordinate::new(
  158. <G2 as Nova_Group>::Scalar::zero(),
  159. <G2 as Nova_Group>::Scalar::zero(),
  160. ),
  161. g: Coordinate::new(
  162. <G2 as Nova_Group>::Scalar::zero(),
  163. <G2 as Nova_Group>::Scalar::zero(),
  164. ),
  165. pk: Coordinate::new(
  166. <G2 as Nova_Group>::Scalar::zero(),
  167. <G2 as Nova_Group>::Scalar::zero(),
  168. ),
  169. c: <G2 as Nova_Group>::Scalar::zero(),
  170. s: <G2 as Nova_Group>::Scalar::zero(),
  171. c_bits: vec![Choice::from(0u8); 256],
  172. s_bits: vec![Choice::from(0u8); 256],
  173. pc: pc.clone(),
  174. };
  175. let circuit_secondary = TrivialTestCircuit::default();
  176. let pp = PublicParams::<
  177. G2,
  178. G1,
  179. EcdsaCircuit<<G2 as Group>::Scalar>,
  180. TrivialTestCircuit<<G1 as Group>::Scalar>,
  181. >::setup(circuit_primary, circuit_secondary.clone());
  182. // produce non-deterministic advice
  183. println!("Generating non-deterministic advice...");
  184. let num_steps = 3;
  185. let signatures = || {
  186. let mut signatures = Vec::new();
  187. for i in 0..num_steps {
  188. let sk = SecretKey::random(&mut OsRng);
  189. let pk = PublicKey::from_secret_key(&sk);
  190. let message = format!("MESSAGE{}", i).as_bytes().to_owned();
  191. assert!(message.len() <= MAX_MESSAGE_LEN);
  192. let mut digest: Vec<u8> = message.to_vec();
  193. for _ in 0..(32 - message.len() as u32) {
  194. digest.extend(&[0u8; 1]);
  195. }
  196. let c = SecretKey::to_uniform_32(digest.as_ref());
  197. let signature_primary = sk.sign(c, &mut OsRng);
  198. let result = pk.verify(c, &signature_primary);
  199. assert!(result);
  200. // Affine coordinates guaranteed to be on the curve
  201. let rxy = signature_primary.r.to_affine().coordinates().unwrap();
  202. let gxy = G1::generator().to_affine().coordinates().unwrap();
  203. let pkxy = pk.0.to_affine().coordinates().unwrap();
  204. let s = signature_primary.s;
  205. signatures.push(EcdsaSignature::<
  206. <G1 as Nova_Group>::Base,
  207. <G1 as Nova_Group>::Scalar,
  208. >::new(
  209. Coordinate::<<G1 as Nova_Group>::Base>::new(*pkxy.x(), *pkxy.y()),
  210. Coordinate::<<G1 as Nova_Group>::Base>::new(*rxy.x(), *rxy.y()),
  211. s,
  212. c,
  213. Coordinate::<<G1 as Nova_Group>::Base>::new(*gxy.x(), *gxy.y()),
  214. ));
  215. }
  216. signatures
  217. };
  218. let (z0_primary, circuits_primary) = EcdsaCircuit::<<G2 as Nova_Group>::Scalar>::new::<
  219. <G1 as Nova_Group>::Base,
  220. <G1 as Nova_Group>::Scalar,
  221. >(num_steps, &signatures(), &pc);
  222. // Secondary circuit
  223. let z0_secondary = <G1 as Group>::Scalar::zero();
  224. // produce a recursive SNARK
  225. println!("Generating a RecursiveSNARK...");
  226. type C1 = EcdsaCircuit<<G2 as Nova_Group>::Scalar>;
  227. type C2 = TrivialTestCircuit<<G1 as Nova_Group>::Scalar>;
  228. let mut recursive_snark: Option<RecursiveSNARK<G2, G1, C1, C2>> = None;
  229. for (i, circuit_primary) in circuits_primary.iter().take(num_steps).enumerate() {
  230. let result = RecursiveSNARK::prove_step(
  231. &pp,
  232. recursive_snark,
  233. circuit_primary.clone(),
  234. circuit_secondary.clone(),
  235. z0_primary,
  236. z0_secondary,
  237. );
  238. assert!(result.is_ok());
  239. println!("RecursiveSNARK::prove_step {}: {:?}", i, result.is_ok());
  240. recursive_snark = Some(result.unwrap());
  241. }
  242. assert!(recursive_snark.is_some());
  243. let recursive_snark = recursive_snark.unwrap();
  244. // verify the recursive SNARK
  245. println!("Verifying the RecursiveSNARK...");
  246. let res = recursive_snark.verify(&pp, num_steps, z0_primary, z0_secondary);
  247. println!("RecursiveSNARK::verify: {:?}", res.is_ok());
  248. assert!(res.is_ok());
  249. // produce a compressed SNARK
  250. println!("Generating a CompressedSNARK...");
  251. let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark);
  252. println!("CompressedSNARK::prove: {:?}", res.is_ok());
  253. assert!(res.is_ok());
  254. let compressed_snark = res.unwrap();
  255. // verify the compressed SNARK
  256. println!("Verifying a CompressedSNARK...");
  257. let res = compressed_snark.verify(&pp, num_steps, z0_primary, z0_secondary);
  258. println!("CompressedSNARK::verify: {:?}", res.is_ok());
  259. assert!(res.is_ok());
  260. }