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.

313 lines
7.3 KiB

[refactorings] Leftovers (pot-pourri?) (#184) * test: compute_path * refactor: path computation - Improve path concatenation by utilizing built-in `join` method * refactor: replace `PartialEq` with derived instance - Derive `PartialEq` for `SatisfyingAssignment` struct - Remove redundant manual implementation of `PartialEq` Cargo-expand generates: ``` #[automatically_derived] impl<G: ::core::cmp::PartialEq + Group> ::core::cmp::PartialEq for SatisfyingAssignment<G> where G::Scalar: PrimeField, G::Scalar: ::core::cmp::PartialEq, G::Scalar: ::core::cmp::PartialEq, G::Scalar: ::core::cmp::PartialEq, G::Scalar: ::core::cmp::PartialEq, G::Scalar: ::core::cmp::PartialEq, { #[inline] fn eq(&self, other: &SatisfyingAssignment<G>) -> bool { self.a_aux_density == other.a_aux_density && self.b_input_density == other.b_input_density && self.b_aux_density == other.b_aux_density && self.a == other.a && self.b == other.b && self.c == other.c && self.input_assignment == other.input_assignment && self.aux_assignment == other.aux_assignment } } ``` * refactor: avoid default for PhantomData Unit type * refactor: replace fold with sum where applicable - Simplify code by replacing `fold` with `sum` in various instances * refactor: decompression method in sumcheck.rs * refactor: test functions to use slice instead of vector conversion * refactor: use more references in functions - Update parameter types to use references instead of owned values in various functions that do not need them - Replace cloning instances with references
1 year ago
  1. use bellperson::{
  2. gadgets::{boolean::AllocatedBit, test::TestConstraintSystem},
  3. ConstraintSystem, SynthesisError,
  4. };
  5. use core::ops::{AddAssign, MulAssign};
  6. use ff::{
  7. derive::byteorder::{ByteOrder, LittleEndian},
  8. Field, PrimeField, PrimeFieldBits,
  9. };
  10. use nova_snark::{gadgets::ecc::AllocatedPoint, traits::Group as NovaGroup};
  11. use num_bigint::BigUint;
  12. use pasta_curves::{
  13. arithmetic::CurveAffine,
  14. group::{Curve, Group},
  15. };
  16. use rand::{rngs::OsRng, RngCore};
  17. use sha3::{Digest, Sha3_512};
  18. #[derive(Debug, Clone, Copy)]
  19. pub struct SecretKey<G: Group>(G::Scalar);
  20. impl<G> SecretKey<G>
  21. where
  22. G: Group,
  23. {
  24. pub fn random(mut rng: impl RngCore) -> Self {
  25. let secret = G::Scalar::random(&mut rng);
  26. Self(secret)
  27. }
  28. }
  29. #[derive(Debug, Clone, Copy)]
  30. pub struct PublicKey<G: Group>(G);
  31. impl<G> PublicKey<G>
  32. where
  33. G: Group,
  34. {
  35. pub fn from_secret_key(s: &SecretKey<G>) -> Self {
  36. let point = G::generator() * s.0;
  37. Self(point)
  38. }
  39. }
  40. #[derive(Clone)]
  41. pub struct Signature<G: Group> {
  42. pub r: G,
  43. pub s: G::Scalar,
  44. }
  45. impl<G> SecretKey<G>
  46. where
  47. G: Group,
  48. {
  49. pub fn sign(self, c: G::Scalar, mut rng: impl RngCore) -> Signature<G> {
  50. // T
  51. let mut t = [0u8; 80];
  52. rng.fill_bytes(&mut t[..]);
  53. // h = H(T || M)
  54. let h = Self::hash_to_scalar(b"Nova_Ecdsa_Hash", &t[..], c.to_repr().as_mut());
  55. // R = [h]G
  56. let r = G::generator().mul(h);
  57. // s = h + c * sk
  58. let mut s = c;
  59. s.mul_assign(&self.0);
  60. s.add_assign(&h);
  61. Signature { r, s }
  62. }
  63. fn mul_bits<B: AsRef<[u64]>>(s: &G::Scalar, bits: BitIterator<B>) -> G::Scalar {
  64. let mut x = G::Scalar::ZERO;
  65. for bit in bits {
  66. x = x.double();
  67. if bit {
  68. x.add_assign(s)
  69. }
  70. }
  71. x
  72. }
  73. fn to_uniform(digest: &[u8]) -> G::Scalar {
  74. assert_eq!(digest.len(), 64);
  75. let mut bits: [u64; 8] = [0; 8];
  76. LittleEndian::read_u64_into(digest, &mut bits);
  77. Self::mul_bits(&G::Scalar::ONE, BitIterator::new(bits))
  78. }
  79. pub fn to_uniform_32(digest: &[u8]) -> G::Scalar {
  80. assert_eq!(digest.len(), 32);
  81. let mut bits: [u64; 4] = [0; 4];
  82. LittleEndian::read_u64_into(digest, &mut bits);
  83. Self::mul_bits(&G::Scalar::ONE, BitIterator::new(bits))
  84. }
  85. pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> G::Scalar {
  86. let mut hasher = Sha3_512::new();
  87. hasher.update(persona);
  88. hasher.update(a);
  89. hasher.update(b);
  90. let digest = hasher.finalize();
  91. Self::to_uniform(digest.as_ref())
  92. }
  93. }
  94. impl<G> PublicKey<G>
  95. where
  96. G: Group,
  97. G::Scalar: PrimeFieldBits,
  98. {
  99. pub fn verify(&self, c: G::Scalar, signature: &Signature<G>) -> bool {
  100. let modulus = Self::modulus_as_scalar();
  101. let order_check_pk = self.0.mul(modulus);
  102. if !order_check_pk.eq(&G::identity()) {
  103. return false;
  104. }
  105. let order_check_r = signature.r.mul(modulus);
  106. if !order_check_r.eq(&G::identity()) {
  107. return false;
  108. }
  109. // 0 = [-s]G + R + [c]PK
  110. self
  111. .0
  112. .mul(c)
  113. .add(&signature.r)
  114. .add(G::generator().mul(signature.s).neg())
  115. .eq(&G::identity())
  116. }
  117. fn modulus_as_scalar() -> G::Scalar {
  118. let mut bits = G::Scalar::char_le_bits().to_bitvec();
  119. let mut acc = BigUint::new(Vec::<u32>::new());
  120. while let Some(b) = bits.pop() {
  121. acc <<= 1_i32;
  122. acc += b as u8;
  123. }
  124. let modulus = acc.to_str_radix(10);
  125. G::Scalar::from_str_vartime(&modulus).unwrap()
  126. }
  127. }
  128. #[derive(Debug)]
  129. pub struct BitIterator<E> {
  130. t: E,
  131. n: usize,
  132. }
  133. impl<E: AsRef<[u64]>> BitIterator<E> {
  134. pub fn new(t: E) -> Self {
  135. let n = t.as_ref().len() * 64;
  136. BitIterator { t, n }
  137. }
  138. }
  139. impl<E: AsRef<[u64]>> Iterator for BitIterator<E> {
  140. type Item = bool;
  141. fn next(&mut self) -> Option<bool> {
  142. if self.n == 0 {
  143. None
  144. } else {
  145. self.n -= 1;
  146. let part = self.n / 64;
  147. let bit = self.n - (64 * part);
  148. Some(self.t.as_ref()[part] & (1 << bit) > 0)
  149. }
  150. }
  151. }
  152. // Synthesize a bit representation into circuit gadgets.
  153. pub fn synthesize_bits<F: PrimeField, CS: ConstraintSystem<F>>(
  154. cs: &mut CS,
  155. bits: Option<Vec<bool>>,
  156. ) -> Result<Vec<AllocatedBit>, SynthesisError> {
  157. (0..F::NUM_BITS)
  158. .map(|i| {
  159. AllocatedBit::alloc(
  160. cs.namespace(|| format!("bit {i}")),
  161. Some(bits.as_ref().unwrap()[i as usize]),
  162. )
  163. })
  164. .collect::<Result<Vec<AllocatedBit>, SynthesisError>>()
  165. }
  166. pub fn verify_signature<G: NovaGroup, CS: ConstraintSystem<G::Base>>(
  167. cs: &mut CS,
  168. pk: AllocatedPoint<G>,
  169. r: AllocatedPoint<G>,
  170. s_bits: Vec<AllocatedBit>,
  171. c_bits: Vec<AllocatedBit>,
  172. ) -> Result<(), SynthesisError> {
  173. let g = AllocatedPoint::<G>::alloc(
  174. cs.namespace(|| "g"),
  175. Some((
  176. G::Base::from_str_vartime(
  177. "28948022309329048855892746252171976963363056481941647379679742748393362948096",
  178. )
  179. .unwrap(),
  180. G::Base::from_str_vartime("2").unwrap(),
  181. false,
  182. )),
  183. )
  184. .unwrap();
  185. cs.enforce(
  186. || "gx is vesta curve",
  187. |lc| lc + g.get_coordinates().0.get_variable(),
  188. |lc| lc + CS::one(),
  189. |lc| {
  190. lc + (
  191. G::Base::from_str_vartime(
  192. "28948022309329048855892746252171976963363056481941647379679742748393362948096",
  193. )
  194. .unwrap(),
  195. CS::one(),
  196. )
  197. },
  198. );
  199. cs.enforce(
  200. || "gy is vesta curve",
  201. |lc| lc + g.get_coordinates().1.get_variable(),
  202. |lc| lc + CS::one(),
  203. |lc| lc + (G::Base::from_str_vartime("2").unwrap(), CS::one()),
  204. );
  205. let sg = g.scalar_mul(cs.namespace(|| "[s]G"), &s_bits)?;
  206. let cpk = pk.scalar_mul(&mut cs.namespace(|| "[c]PK"), &c_bits)?;
  207. let rcpk = cpk.add(&mut cs.namespace(|| "R + [c]PK"), &r)?;
  208. let (rcpk_x, rcpk_y, _) = rcpk.get_coordinates();
  209. let (sg_x, sg_y, _) = sg.get_coordinates();
  210. cs.enforce(
  211. || "sg_x == rcpk_x",
  212. |lc| lc + sg_x.get_variable(),
  213. |lc| lc + CS::one(),
  214. |lc| lc + rcpk_x.get_variable(),
  215. );
  216. cs.enforce(
  217. || "sg_y == rcpk_y",
  218. |lc| lc + sg_y.get_variable(),
  219. |lc| lc + CS::one(),
  220. |lc| lc + rcpk_y.get_variable(),
  221. );
  222. Ok(())
  223. }
  224. type G1 = pasta_curves::pallas::Point;
  225. type G2 = pasta_curves::vesta::Point;
  226. fn main() {
  227. let mut cs = TestConstraintSystem::<<G1 as Group>::Scalar>::new();
  228. assert!(cs.is_satisfied());
  229. assert_eq!(cs.num_constraints(), 0);
  230. let sk = SecretKey::<G2>::random(&mut OsRng);
  231. let pk = PublicKey::from_secret_key(&sk);
  232. // generate a random message to sign
  233. let c = <G2 as Group>::Scalar::random(&mut OsRng);
  234. // sign and verify
  235. let signature = sk.sign(c, &mut OsRng);
  236. let result = pk.verify(c, &signature);
  237. assert!(result);
  238. // prepare inputs to the circuit gadget
  239. let pk = {
  240. let pkxy = pk.0.to_affine().coordinates().unwrap();
  241. AllocatedPoint::<G2>::alloc(
  242. cs.namespace(|| "pub key"),
  243. Some((*pkxy.x(), *pkxy.y(), false)),
  244. )
  245. .unwrap()
  246. };
  247. let r = {
  248. let rxy = signature.r.to_affine().coordinates().unwrap();
  249. AllocatedPoint::alloc(cs.namespace(|| "r"), Some((*rxy.x(), *rxy.y(), false))).unwrap()
  250. };
  251. let s = {
  252. let s_bits = signature
  253. .s
  254. .to_le_bits()
  255. .iter()
  256. .map(|b| *b)
  257. .collect::<Vec<bool>>();
  258. synthesize_bits(&mut cs.namespace(|| "s bits"), Some(s_bits)).unwrap()
  259. };
  260. let c = {
  261. let c_bits = c.to_le_bits().iter().map(|b| *b).collect::<Vec<bool>>();
  262. synthesize_bits(&mut cs.namespace(|| "c bits"), Some(c_bits)).unwrap()
  263. };
  264. // Check the signature was signed by the correct sk using the pk
  265. verify_signature(&mut cs, pk, r, s, c).unwrap();
  266. assert!(cs.is_satisfied());
  267. }