arnaucube
arnaucube/NovaPublic Self-hosted repository
Nova/src/gadgets/ecc.rs
src/gadgets/ecc.rsRaw
   1//! This module implements various elliptic curve gadgets
   2#![allow(non_snake_case)]
   3use crate::{
   4  gadgets::utils::{
   5    alloc_num_equals, alloc_one, alloc_zero, conditionally_select, conditionally_select2,
   6    select_num_or_one, select_num_or_zero, select_num_or_zero2, select_one_or_diff2,
   7    select_one_or_num2, select_zero_or_num2,
   8  },
   9  traits::Group,
  10};
  11use bellperson::{
  12  gadgets::{
  13    boolean::{AllocatedBit, Boolean},
  14    num::AllocatedNum,
  15    Assignment,
  16  },
  17  ConstraintSystem, SynthesisError,
  18};
  19use ff::{Field, PrimeField};
  20
  21/// AllocatedPoint provides an elliptic curve abstraction inside a circuit.
  22#[derive(Clone)]
  23pub struct AllocatedPoint<G>
  24where
  25  G: Group,
  26{
  27  pub(crate) x: AllocatedNum<G::Base>,
  28  pub(crate) y: AllocatedNum<G::Base>,
  29  pub(crate) is_infinity: AllocatedNum<G::Base>,
  30}
  31
  32impl<G> AllocatedPoint<G>
  33where
  34  G: Group,
  35{
  36  /// Allocates a new point on the curve using coordinates provided by `coords`.
  37  /// If coords = None, it allocates the default infinity point
  38  pub fn alloc<CS>(
  39    mut cs: CS,
  40    coords: Option<(G::Base, G::Base, bool)>,
  41  ) -> Result<Self, SynthesisError>
  42  where
  43    CS: ConstraintSystem<G::Base>,
  44  {
  45    let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
  46      Ok(coords.map_or(G::Base::ZERO, |c| c.0))
  47    })?;
  48    let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
  49      Ok(coords.map_or(G::Base::ZERO, |c| c.1))
  50    })?;
  51    let is_infinity = AllocatedNum::alloc(cs.namespace(|| "is_infinity"), || {
  52      Ok(if coords.map_or(true, |c| c.2) {
  53        G::Base::ONE
  54      } else {
  55        G::Base::ZERO
  56      })
  57    })?;
  58    cs.enforce(
  59      || "is_infinity is bit",
  60      |lc| lc + is_infinity.get_variable(),
  61      |lc| lc + CS::one() - is_infinity.get_variable(),
  62      |lc| lc,
  63    );
  64
  65    Ok(AllocatedPoint { x, y, is_infinity })
  66  }
  67
  68  /// Allocates a default point on the curve.
  69  pub fn default<CS>(mut cs: CS) -> Result<Self, SynthesisError>
  70  where
  71    CS: ConstraintSystem<G::Base>,
  72  {
  73    let zero = alloc_zero(cs.namespace(|| "zero"))?;
  74    let one = alloc_one(cs.namespace(|| "one"))?;
  75
  76    Ok(AllocatedPoint {
  77      x: zero.clone(),
  78      y: zero,
  79      is_infinity: one,
  80    })
  81  }
  82
  83  /// Returns coordinates associated with the point.
  84  pub fn get_coordinates(
  85    &self,
  86  ) -> (
  87    &AllocatedNum<G::Base>,
  88    &AllocatedNum<G::Base>,
  89    &AllocatedNum<G::Base>,
  90  ) {
  91    (&self.x, &self.y, &self.is_infinity)
  92  }
  93
  94  /// Negates the provided point
  95  pub fn negate<CS: ConstraintSystem<G::Base>>(&self, mut cs: CS) -> Result<Self, SynthesisError> {
  96    let y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(-*self.y.get_value().get()?))?;
  97
  98    cs.enforce(
  99      || "check y = - self.y",
 100      |lc| lc + self.y.get_variable(),
 101      |lc| lc + CS::one(),
 102      |lc| lc - y.get_variable(),
 103    );
 104
 105    Ok(Self {
 106      x: self.x.clone(),
 107      y,
 108      is_infinity: self.is_infinity.clone(),
 109    })
 110  }
 111
 112  /// Add two points (may be equal)
 113  pub fn add<CS: ConstraintSystem<G::Base>>(
 114    &self,
 115    mut cs: CS,
 116    other: &AllocatedPoint<G>,
 117  ) -> Result<Self, SynthesisError> {
 118    // Compute boolean equal indicating if self = other
 119
 120    let equal_x = alloc_num_equals(
 121      cs.namespace(|| "check self.x == other.x"),
 122      &self.x,
 123      &other.x,
 124    )?;
 125
 126    let equal_y = alloc_num_equals(
 127      cs.namespace(|| "check self.y == other.y"),
 128      &self.y,
 129      &other.y,
 130    )?;
 131
 132    // Compute the result of the addition and the result of double self
 133    let result_from_add = self.add_internal(cs.namespace(|| "add internal"), other, &equal_x)?;
 134    let result_from_double = self.double(cs.namespace(|| "double"))?;
 135
 136    // Output:
 137    // If (self == other) {
 138    //  return double(self)
 139    // }else {
 140    //  if (self.x == other.x){
 141    //      return infinity [negation]
 142    //  } else {
 143    //      return add(self, other)
 144    //  }
 145    // }
 146    let result_for_equal_x = AllocatedPoint::select_point_or_infinity(
 147      cs.namespace(|| "equal_y ? result_from_double : infinity"),
 148      &result_from_double,
 149      &Boolean::from(equal_y),
 150    )?;
 151
 152    AllocatedPoint::conditionally_select(
 153      cs.namespace(|| "equal ? result_from_double : result_from_add"),
 154      &result_for_equal_x,
 155      &result_from_add,
 156      &Boolean::from(equal_x),
 157    )
 158  }
 159
 160  /// Adds other point to this point and returns the result. Assumes that the two points are
 161  /// different and that both other.is_infinity and this.is_infinty are bits
 162  pub fn add_internal<CS: ConstraintSystem<G::Base>>(
 163    &self,
 164    mut cs: CS,
 165    other: &AllocatedPoint<G>,
 166    equal_x: &AllocatedBit,
 167  ) -> Result<Self, SynthesisError> {
 168    //************************************************************************/
 169    // lambda = (other.y - self.y) * (other.x - self.x).invert().unwrap();
 170    //************************************************************************/
 171    // First compute (other.x - self.x).inverse()
 172    // If either self or other are the infinity point or self.x = other.x  then compute bogus values
 173    // Specifically,
 174    // x_diff = self != inf && other != inf && self.x == other.x ? (other.x - self.x) : 1
 175
 176    // Compute self.is_infinity OR other.is_infinity =
 177    // NOT(NOT(self.is_ifninity) AND NOT(other.is_infinity))
 178    let at_least_one_inf = AllocatedNum::alloc(cs.namespace(|| "at least one inf"), || {
 179      Ok(
 180        G::Base::ONE
 181          - (G::Base::ONE - *self.is_infinity.get_value().get()?)
 182            * (G::Base::ONE - *other.is_infinity.get_value().get()?),
 183      )
 184    })?;
 185    cs.enforce(
 186      || "1 - at least one inf = (1-self.is_infinity) * (1-other.is_infinity)",
 187      |lc| lc + CS::one() - self.is_infinity.get_variable(),
 188      |lc| lc + CS::one() - other.is_infinity.get_variable(),
 189      |lc| lc + CS::one() - at_least_one_inf.get_variable(),
 190    );
 191
 192    // Now compute x_diff_is_actual = at_least_one_inf OR equal_x
 193    let x_diff_is_actual =
 194      AllocatedNum::alloc(cs.namespace(|| "allocate x_diff_is_actual"), || {
 195        Ok(if *equal_x.get_value().get()? {
 196          G::Base::ONE
 197        } else {
 198          *at_least_one_inf.get_value().get()?
 199        })
 200      })?;
 201    cs.enforce(
 202      || "1 - x_diff_is_actual = (1-equal_x) * (1-at_least_one_inf)",
 203      |lc| lc + CS::one() - at_least_one_inf.get_variable(),
 204      |lc| lc + CS::one() - equal_x.get_variable(),
 205      |lc| lc + CS::one() - x_diff_is_actual.get_variable(),
 206    );
 207
 208    // x_diff = 1 if either self.is_infinity or other.is_infinity or self.x = other.x else self.x -
 209    // other.x
 210    let x_diff = select_one_or_diff2(
 211      cs.namespace(|| "Compute x_diff"),
 212      &other.x,
 213      &self.x,
 214      &x_diff_is_actual,
 215    )?;
 216
 217    let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
 218      let x_diff_inv = if *x_diff_is_actual.get_value().get()? == G::Base::ONE {
 219        // Set to default
 220        G::Base::ONE
 221      } else {
 222        // Set to the actual inverse
 223        (*other.x.get_value().get()? - *self.x.get_value().get()?)
 224          .invert()
 225          .unwrap()
 226      };
 227
 228      Ok((*other.y.get_value().get()? - *self.y.get_value().get()?) * x_diff_inv)
 229    })?;
 230    cs.enforce(
 231      || "Check that lambda is correct",
 232      |lc| lc + lambda.get_variable(),
 233      |lc| lc + x_diff.get_variable(),
 234      |lc| lc + other.y.get_variable() - self.y.get_variable(),
 235    );
 236
 237    //************************************************************************/
 238    // x = lambda * lambda - self.x - other.x;
 239    //************************************************************************/
 240    let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
 241      Ok(
 242        *lambda.get_value().get()? * lambda.get_value().get()?
 243          - *self.x.get_value().get()?
 244          - *other.x.get_value().get()?,
 245      )
 246    })?;
 247    cs.enforce(
 248      || "check that x is correct",
 249      |lc| lc + lambda.get_variable(),
 250      |lc| lc + lambda.get_variable(),
 251      |lc| lc + x.get_variable() + self.x.get_variable() + other.x.get_variable(),
 252    );
 253
 254    //************************************************************************/
 255    // y = lambda * (self.x - x) - self.y;
 256    //************************************************************************/
 257    let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
 258      Ok(
 259        *lambda.get_value().get()? * (*self.x.get_value().get()? - *x.get_value().get()?)
 260          - *self.y.get_value().get()?,
 261      )
 262    })?;
 263
 264    cs.enforce(
 265      || "Check that y is correct",
 266      |lc| lc + lambda.get_variable(),
 267      |lc| lc + self.x.get_variable() - x.get_variable(),
 268      |lc| lc + y.get_variable() + self.y.get_variable(),
 269    );
 270
 271    //************************************************************************/
 272    // We only return the computed x, y if neither of the points is infinity and self.x != other.y
 273    // if self.is_infinity return other.clone()
 274    // elif other.is_infinity return self.clone()
 275    // elif self.x == other.x return infinity
 276    // Otherwise return the computed points.
 277    //************************************************************************/
 278    // Now compute the output x
 279
 280    let x1 = conditionally_select2(
 281      cs.namespace(|| "x1 = other.is_infinity ? self.x : x"),
 282      &self.x,
 283      &x,
 284      &other.is_infinity,
 285    )?;
 286
 287    let x = conditionally_select2(
 288      cs.namespace(|| "x = self.is_infinity ? other.x : x1"),
 289      &other.x,
 290      &x1,
 291      &self.is_infinity,
 292    )?;
 293
 294    let y1 = conditionally_select2(
 295      cs.namespace(|| "y1 = other.is_infinity ? self.y : y"),
 296      &self.y,
 297      &y,
 298      &other.is_infinity,
 299    )?;
 300
 301    let y = conditionally_select2(
 302      cs.namespace(|| "y = self.is_infinity ? other.y : y1"),
 303      &other.y,
 304      &y1,
 305      &self.is_infinity,
 306    )?;
 307
 308    let is_infinity1 = select_num_or_zero2(
 309      cs.namespace(|| "is_infinity1 = other.is_infinity ? self.is_infinity : 0"),
 310      &self.is_infinity,
 311      &other.is_infinity,
 312    )?;
 313
 314    let is_infinity = conditionally_select2(
 315      cs.namespace(|| "is_infinity = self.is_infinity ? other.is_infinity : is_infinity1"),
 316      &other.is_infinity,
 317      &is_infinity1,
 318      &self.is_infinity,
 319    )?;
 320
 321    Ok(Self { x, y, is_infinity })
 322  }
 323
 324  /// Doubles the supplied point.
 325  pub fn double<CS: ConstraintSystem<G::Base>>(&self, mut cs: CS) -> Result<Self, SynthesisError> {
 326    //*************************************************************/
 327    // lambda = (G::Base::from(3) * self.x * self.x + G::A())
 328    //  * (G::Base::from(2)) * self.y).invert().unwrap();
 329    /*************************************************************/
 330
 331    // Compute tmp = (G::Base::ONE + G::Base::ONE)* self.y ? self != inf : 1
 332    let tmp_actual = AllocatedNum::alloc(cs.namespace(|| "tmp_actual"), || {
 333      Ok(*self.y.get_value().get()? + *self.y.get_value().get()?)
 334    })?;
 335    cs.enforce(
 336      || "check tmp_actual",
 337      |lc| lc + CS::one() + CS::one(),
 338      |lc| lc + self.y.get_variable(),
 339      |lc| lc + tmp_actual.get_variable(),
 340    );
 341
 342    let tmp = select_one_or_num2(cs.namespace(|| "tmp"), &tmp_actual, &self.is_infinity)?;
 343
 344    // Now compute lambda as (G::Base::from(3) * self.x * self.x + G::A()) * tmp_inv
 345
 346    let prod_1 = AllocatedNum::alloc(cs.namespace(|| "alloc prod 1"), || {
 347      Ok(G::Base::from(3) * self.x.get_value().get()? * self.x.get_value().get()?)
 348    })?;
 349    cs.enforce(
 350      || "Check prod 1",
 351      |lc| lc + (G::Base::from(3), self.x.get_variable()),
 352      |lc| lc + self.x.get_variable(),
 353      |lc| lc + prod_1.get_variable(),
 354    );
 355
 356    let lambda = AllocatedNum::alloc(cs.namespace(|| "alloc lambda"), || {
 357      let tmp_inv = if *self.is_infinity.get_value().get()? == G::Base::ONE {
 358        // Return default value 1
 359        G::Base::ONE
 360      } else {
 361        // Return the actual inverse
 362        (*tmp.get_value().get()?).invert().unwrap()
 363      };
 364
 365      Ok(tmp_inv * (*prod_1.get_value().get()? + G::get_curve_params().0))
 366    })?;
 367
 368    cs.enforce(
 369      || "Check lambda",
 370      |lc| lc + tmp.get_variable(),
 371      |lc| lc + lambda.get_variable(),
 372      |lc| lc + prod_1.get_variable() + (G::get_curve_params().0, CS::one()),
 373    );
 374
 375    /*************************************************************/
 376    //          x = lambda * lambda - self.x - self.x;
 377    /*************************************************************/
 378
 379    let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
 380      Ok(
 381        ((*lambda.get_value().get()?) * (*lambda.get_value().get()?))
 382          - *self.x.get_value().get()?
 383          - self.x.get_value().get()?,
 384      )
 385    })?;
 386    cs.enforce(
 387      || "Check x",
 388      |lc| lc + lambda.get_variable(),
 389      |lc| lc + lambda.get_variable(),
 390      |lc| lc + x.get_variable() + self.x.get_variable() + self.x.get_variable(),
 391    );
 392
 393    /*************************************************************/
 394    //        y = lambda * (self.x - x) - self.y;
 395    /*************************************************************/
 396
 397    let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
 398      Ok(
 399        (*lambda.get_value().get()?) * (*self.x.get_value().get()? - x.get_value().get()?)
 400          - self.y.get_value().get()?,
 401      )
 402    })?;
 403    cs.enforce(
 404      || "Check y",
 405      |lc| lc + lambda.get_variable(),
 406      |lc| lc + self.x.get_variable() - x.get_variable(),
 407      |lc| lc + y.get_variable() + self.y.get_variable(),
 408    );
 409
 410    /*************************************************************/
 411    // Only return the computed x and y if the point is not infinity
 412    /*************************************************************/
 413
 414    // x
 415    let x = select_zero_or_num2(cs.namespace(|| "final x"), &x, &self.is_infinity)?;
 416
 417    // y
 418    let y = select_zero_or_num2(cs.namespace(|| "final y"), &y, &self.is_infinity)?;
 419
 420    // is_infinity
 421    let is_infinity = self.is_infinity.clone();
 422
 423    Ok(Self { x, y, is_infinity })
 424  }
 425
 426  /// A gadget for scalar multiplication, optimized to use incomplete addition law.
 427  /// The optimization here is analogous to https://github.com/arkworks-rs/r1cs-std/blob/6d64f379a27011b3629cf4c9cb38b7b7b695d5a0/src/groups/curves/short_weierstrass/mod.rs#L295,
 428  /// except we use complete addition law over affine coordinates instead of projective coordinates for the tail bits
 429  pub fn scalar_mul<CS: ConstraintSystem<G::Base>>(
 430    &self,
 431    mut cs: CS,
 432    scalar_bits: Vec<AllocatedBit>,
 433  ) -> Result<Self, SynthesisError> {
 434    let split_len = core::cmp::min(scalar_bits.len(), (G::Base::NUM_BITS - 2) as usize);
 435    let (incomplete_bits, complete_bits) = scalar_bits.split_at(split_len);
 436
 437    // we convert AllocatedPoint into AllocatedPointNonInfinity; we deal with the case where self.is_infinity = 1 below
 438    let mut p = AllocatedPointNonInfinity::from_allocated_point(self);
 439
 440    // we assume the first bit to be 1, so we must initialize acc to self and double it
 441    // we remove this assumption below
 442    let mut acc = p;
 443    p = acc.double_incomplete(cs.namespace(|| "double"))?;
 444
 445    // perform the double-and-add loop to compute the scalar mul using incomplete addition law
 446    for (i, bit) in incomplete_bits.iter().enumerate().skip(1) {
 447      let temp = acc.add_incomplete(cs.namespace(|| format!("add {i}")), &p)?;
 448      acc = AllocatedPointNonInfinity::conditionally_select(
 449        cs.namespace(|| format!("acc_iteration_{i}")),
 450        &temp,
 451        &acc,
 452        &Boolean::from(bit.clone()),
 453      )?;
 454
 455      p = p.double_incomplete(cs.namespace(|| format!("double {i}")))?;
 456    }
 457
 458    // convert back to AllocatedPoint
 459    let res = {
 460      // we set acc.is_infinity = self.is_infinity
 461      let acc = acc.to_allocated_point(&self.is_infinity)?;
 462
 463      // we remove the initial slack if bits[0] is as not as assumed (i.e., it is not 1)
 464      let acc_minus_initial = {
 465        let neg = self.negate(cs.namespace(|| "negate"))?;
 466        acc.add(cs.namespace(|| "res minus self"), &neg)
 467      }?;
 468
 469      AllocatedPoint::conditionally_select(
 470        cs.namespace(|| "remove slack if necessary"),
 471        &acc,
 472        &acc_minus_initial,
 473        &Boolean::from(scalar_bits[0].clone()),
 474      )?
 475    };
 476
 477    // when self.is_infinity = 1, return the default point, else return res
 478    // we already set res.is_infinity to be self.is_infinity, so we do not need to set it here
 479    let default = Self::default(cs.namespace(|| "default"))?;
 480    let x = conditionally_select2(
 481      cs.namespace(|| "check if self.is_infinity is zero (x)"),
 482      &default.x,
 483      &res.x,
 484      &self.is_infinity,
 485    )?;
 486
 487    let y = conditionally_select2(
 488      cs.namespace(|| "check if self.is_infinity is zero (y)"),
 489      &default.y,
 490      &res.y,
 491      &self.is_infinity,
 492    )?;
 493
 494    // we now perform the remaining scalar mul using complete addition law
 495    let mut acc = AllocatedPoint {
 496      x,
 497      y,
 498      is_infinity: res.is_infinity,
 499    };
 500    let mut p_complete = p.to_allocated_point(&self.is_infinity)?;
 501
 502    for (i, bit) in complete_bits.iter().enumerate() {
 503      let temp = acc.add(cs.namespace(|| format!("add_complete {i}")), &p_complete)?;
 504      acc = AllocatedPoint::conditionally_select(
 505        cs.namespace(|| format!("acc_complete_iteration_{i}")),
 506        &temp,
 507        &acc,
 508        &Boolean::from(bit.clone()),
 509      )?;
 510
 511      p_complete = p_complete.double(cs.namespace(|| format!("double_complete {i}")))?;
 512    }
 513
 514    Ok(acc)
 515  }
 516
 517  /// If condition outputs a otherwise outputs b
 518  pub fn conditionally_select<CS: ConstraintSystem<G::Base>>(
 519    mut cs: CS,
 520    a: &Self,
 521    b: &Self,
 522    condition: &Boolean,
 523  ) -> Result<Self, SynthesisError> {
 524    let x = conditionally_select(cs.namespace(|| "select x"), &a.x, &b.x, condition)?;
 525
 526    let y = conditionally_select(cs.namespace(|| "select y"), &a.y, &b.y, condition)?;
 527
 528    let is_infinity = conditionally_select(
 529      cs.namespace(|| "select is_infinity"),
 530      &a.is_infinity,
 531      &b.is_infinity,
 532      condition,
 533    )?;
 534
 535    Ok(Self { x, y, is_infinity })
 536  }
 537
 538  /// If condition outputs a otherwise infinity
 539  pub fn select_point_or_infinity<CS: ConstraintSystem<G::Base>>(
 540    mut cs: CS,
 541    a: &Self,
 542    condition: &Boolean,
 543  ) -> Result<Self, SynthesisError> {
 544    let x = select_num_or_zero(cs.namespace(|| "select x"), &a.x, condition)?;
 545
 546    let y = select_num_or_zero(cs.namespace(|| "select y"), &a.y, condition)?;
 547
 548    let is_infinity = select_num_or_one(
 549      cs.namespace(|| "select is_infinity"),
 550      &a.is_infinity,
 551      condition,
 552    )?;
 553
 554    Ok(Self { x, y, is_infinity })
 555  }
 556}
 557
 558#[derive(Clone)]
 559/// AllocatedPoint but one that is guaranteed to be not infinity
 560pub struct AllocatedPointNonInfinity<G>
 561where
 562  G: Group,
 563{
 564  x: AllocatedNum<G::Base>,
 565  y: AllocatedNum<G::Base>,
 566}
 567
 568impl<G> AllocatedPointNonInfinity<G>
 569where
 570  G: Group,
 571{
 572  /// Creates a new AllocatedPointNonInfinity from the specified coordinates
 573  pub fn new(x: AllocatedNum<G::Base>, y: AllocatedNum<G::Base>) -> Self {
 574    Self { x, y }
 575  }
 576
 577  /// Allocates a new point on the curve using coordinates provided by `coords`.
 578  pub fn alloc<CS>(mut cs: CS, coords: Option<(G::Base, G::Base)>) -> Result<Self, SynthesisError>
 579  where
 580    CS: ConstraintSystem<G::Base>,
 581  {
 582    let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
 583      coords.map_or(Err(SynthesisError::AssignmentMissing), |c| Ok(c.0))
 584    })?;
 585    let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
 586      coords.map_or(Err(SynthesisError::AssignmentMissing), |c| Ok(c.1))
 587    })?;
 588
 589    Ok(Self { x, y })
 590  }
 591
 592  /// Turns an AllocatedPoint into an AllocatedPointNonInfinity (assumes it is not infinity)
 593  pub fn from_allocated_point(p: &AllocatedPoint<G>) -> Self {
 594    Self {
 595      x: p.x.clone(),
 596      y: p.y.clone(),
 597    }
 598  }
 599
 600  /// Returns an AllocatedPoint from an AllocatedPointNonInfinity
 601  pub fn to_allocated_point(
 602    &self,
 603    is_infinity: &AllocatedNum<G::Base>,
 604  ) -> Result<AllocatedPoint<G>, SynthesisError> {
 605    Ok(AllocatedPoint {
 606      x: self.x.clone(),
 607      y: self.y.clone(),
 608      is_infinity: is_infinity.clone(),
 609    })
 610  }
 611
 612  /// Returns coordinates associated with the point.
 613  pub fn get_coordinates(&self) -> (&AllocatedNum<G::Base>, &AllocatedNum<G::Base>) {
 614    (&self.x, &self.y)
 615  }
 616
 617  /// Add two points assuming self != +/- other
 618  pub fn add_incomplete<CS>(&self, mut cs: CS, other: &Self) -> Result<Self, SynthesisError>
 619  where
 620    CS: ConstraintSystem<G::Base>,
 621  {
 622    // allocate a free variable that an honest prover sets to lambda = (y2-y1)/(x2-x1)
 623    let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
 624      if *other.x.get_value().get()? == *self.x.get_value().get()? {
 625        Ok(G::Base::ONE)
 626      } else {
 627        Ok(
 628          (*other.y.get_value().get()? - *self.y.get_value().get()?)
 629            * (*other.x.get_value().get()? - *self.x.get_value().get()?)
 630              .invert()
 631              .unwrap(),
 632        )
 633      }
 634    })?;
 635    cs.enforce(
 636      || "Check that lambda is computed correctly",
 637      |lc| lc + lambda.get_variable(),
 638      |lc| lc + other.x.get_variable() - self.x.get_variable(),
 639      |lc| lc + other.y.get_variable() - self.y.get_variable(),
 640    );
 641
 642    //************************************************************************/
 643    // x = lambda * lambda - self.x - other.x;
 644    //************************************************************************/
 645    let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
 646      Ok(
 647        *lambda.get_value().get()? * lambda.get_value().get()?
 648          - *self.x.get_value().get()?
 649          - *other.x.get_value().get()?,
 650      )
 651    })?;
 652    cs.enforce(
 653      || "check that x is correct",
 654      |lc| lc + lambda.get_variable(),
 655      |lc| lc + lambda.get_variable(),
 656      |lc| lc + x.get_variable() + self.x.get_variable() + other.x.get_variable(),
 657    );
 658
 659    //************************************************************************/
 660    // y = lambda * (self.x - x) - self.y;
 661    //************************************************************************/
 662    let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
 663      Ok(
 664        *lambda.get_value().get()? * (*self.x.get_value().get()? - *x.get_value().get()?)
 665          - *self.y.get_value().get()?,
 666      )
 667    })?;
 668
 669    cs.enforce(
 670      || "Check that y is correct",
 671      |lc| lc + lambda.get_variable(),
 672      |lc| lc + self.x.get_variable() - x.get_variable(),
 673      |lc| lc + y.get_variable() + self.y.get_variable(),
 674    );
 675
 676    Ok(Self { x, y })
 677  }
 678
 679  /// doubles the point; since this is called with a point not at infinity, it is guaranteed to be not infinity
 680  pub fn double_incomplete<CS>(&self, mut cs: CS) -> Result<Self, SynthesisError>
 681  where
 682    CS: ConstraintSystem<G::Base>,
 683  {
 684    // lambda = (3 x^2 + a) / 2 * y
 685
 686    let x_sq = self.x.square(cs.namespace(|| "x_sq"))?;
 687
 688    let lambda = AllocatedNum::alloc(cs.namespace(|| "lambda"), || {
 689      let n = G::Base::from(3) * x_sq.get_value().get()? + G::get_curve_params().0;
 690      let d = G::Base::from(2) * *self.y.get_value().get()?;
 691      if d == G::Base::ZERO {
 692        Ok(G::Base::ONE)
 693      } else {
 694        Ok(n * d.invert().unwrap())
 695      }
 696    })?;
 697    cs.enforce(
 698      || "Check that lambda is computed correctly",
 699      |lc| lc + lambda.get_variable(),
 700      |lc| lc + (G::Base::from(2), self.y.get_variable()),
 701      |lc| lc + (G::Base::from(3), x_sq.get_variable()) + (G::get_curve_params().0, CS::one()),
 702    );
 703
 704    let x = AllocatedNum::alloc(cs.namespace(|| "x"), || {
 705      Ok(
 706        *lambda.get_value().get()? * *lambda.get_value().get()?
 707          - *self.x.get_value().get()?
 708          - *self.x.get_value().get()?,
 709      )
 710    })?;
 711
 712    cs.enforce(
 713      || "check that x is correct",
 714      |lc| lc + lambda.get_variable(),
 715      |lc| lc + lambda.get_variable(),
 716      |lc| lc + x.get_variable() + (G::Base::from(2), self.x.get_variable()),
 717    );
 718
 719    let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
 720      Ok(
 721        *lambda.get_value().get()? * (*self.x.get_value().get()? - *x.get_value().get()?)
 722          - *self.y.get_value().get()?,
 723      )
 724    })?;
 725
 726    cs.enforce(
 727      || "Check that y is correct",
 728      |lc| lc + lambda.get_variable(),
 729      |lc| lc + self.x.get_variable() - x.get_variable(),
 730      |lc| lc + y.get_variable() + self.y.get_variable(),
 731    );
 732
 733    Ok(Self { x, y })
 734  }
 735
 736  /// If condition outputs a otherwise outputs b
 737  pub fn conditionally_select<CS: ConstraintSystem<G::Base>>(
 738    mut cs: CS,
 739    a: &Self,
 740    b: &Self,
 741    condition: &Boolean,
 742  ) -> Result<Self, SynthesisError> {
 743    let x = conditionally_select(cs.namespace(|| "select x"), &a.x, &b.x, condition)?;
 744    let y = conditionally_select(cs.namespace(|| "select y"), &a.y, &b.y, condition)?;
 745
 746    Ok(Self { x, y })
 747  }
 748}
 749
 750#[cfg(test)]
 751mod tests {
 752  use super::*;
 753  use crate::bellperson::{
 754    r1cs::{NovaShape, NovaWitness},
 755    {shape_cs::ShapeCS, solver::SatisfyingAssignment},
 756  };
 757  use ff::{Field, PrimeFieldBits};
 758  use pasta_curves::{arithmetic::CurveAffine, group::Curve, pallas, vesta};
 759  use rand::rngs::OsRng;
 760
 761  #[derive(Debug, Clone)]
 762  pub struct Point<G>
 763  where
 764    G: Group,
 765  {
 766    x: G::Base,
 767    y: G::Base,
 768    is_infinity: bool,
 769  }
 770
 771  #[cfg(test)]
 772  impl<G> Point<G>
 773  where
 774    G: Group,
 775  {
 776    pub fn new(x: G::Base, y: G::Base, is_infinity: bool) -> Self {
 777      Self { x, y, is_infinity }
 778    }
 779
 780    pub fn random_vartime() -> Self {
 781      loop {
 782        let x = G::Base::random(&mut OsRng);
 783        let y = (x.square() * x + G::get_curve_params().1).sqrt();
 784        if y.is_some().unwrap_u8() == 1 {
 785          return Self {
 786            x,
 787            y: y.unwrap(),
 788            is_infinity: false,
 789          };
 790        }
 791      }
 792    }
 793
 794    /// Add any two points
 795    pub fn add(&self, other: &Point<G>) -> Self {
 796      if self.x == other.x {
 797        // If self == other then call double
 798        if self.y == other.y {
 799          self.double()
 800        } else {
 801          // if self.x == other.x and self.y != other.y then return infinity
 802          Self {
 803            x: G::Base::ZERO,
 804            y: G::Base::ZERO,
 805            is_infinity: true,
 806          }
 807        }
 808      } else {
 809        self.add_internal(other)
 810      }
 811    }
 812
 813    /// Add two different points
 814    pub fn add_internal(&self, other: &Point<G>) -> Self {
 815      if self.is_infinity {
 816        return other.clone();
 817      }
 818
 819      if other.is_infinity {
 820        return self.clone();
 821      }
 822
 823      let lambda = (other.y - self.y) * (other.x - self.x).invert().unwrap();
 824      let x = lambda * lambda - self.x - other.x;
 825      let y = lambda * (self.x - x) - self.y;
 826      Self {
 827        x,
 828        y,
 829        is_infinity: false,
 830      }
 831    }
 832
 833    pub fn double(&self) -> Self {
 834      if self.is_infinity {
 835        return Self {
 836          x: G::Base::ZERO,
 837          y: G::Base::ZERO,
 838          is_infinity: true,
 839        };
 840      }
 841
 842      let lambda = G::Base::from(3)
 843        * self.x
 844        * self.x
 845        * ((G::Base::ONE + G::Base::ONE) * self.y).invert().unwrap();
 846      let x = lambda * lambda - self.x - self.x;
 847      let y = lambda * (self.x - x) - self.y;
 848      Self {
 849        x,
 850        y,
 851        is_infinity: false,
 852      }
 853    }
 854
 855    pub fn scalar_mul(&self, scalar: &G::Scalar) -> Self {
 856      let mut res = Self {
 857        x: G::Base::ZERO,
 858        y: G::Base::ZERO,
 859        is_infinity: true,
 860      };
 861
 862      let bits = scalar.to_le_bits();
 863      for i in (0..bits.len()).rev() {
 864        res = res.double();
 865        if bits[i] {
 866          res = self.add(&res);
 867        }
 868      }
 869      res
 870    }
 871  }
 872
 873  // Allocate a random point. Only used for testing
 874  pub fn alloc_random_point<G: Group, CS: ConstraintSystem<G::Base>>(
 875    mut cs: CS,
 876  ) -> Result<AllocatedPoint<G>, SynthesisError> {
 877    // get a random point
 878    let p = Point::<G>::random_vartime();
 879    AllocatedPoint::alloc(cs.namespace(|| "alloc p"), Some((p.x, p.y, p.is_infinity)))
 880  }
 881
 882  /// Make the point io
 883  pub fn inputize_allocted_point<G: Group, CS: ConstraintSystem<G::Base>>(
 884    p: &AllocatedPoint<G>,
 885    mut cs: CS,
 886  ) -> Result<(), SynthesisError> {
 887    let _ = p.x.inputize(cs.namespace(|| "Input point.x"));
 888    let _ = p.y.inputize(cs.namespace(|| "Input point.y"));
 889    let _ = p
 890      .is_infinity
 891      .inputize(cs.namespace(|| "Input point.is_infinity"));
 892    Ok(())
 893  }
 894
 895  #[test]
 896  fn test_ecc_ops() {
 897    test_ecc_ops_with::<pallas::Affine, pallas::Point>();
 898    test_ecc_ops_with::<vesta::Affine, vesta::Point>();
 899  }
 900
 901  fn test_ecc_ops_with<C, G>()
 902  where
 903    C: CurveAffine<Base = G::Base, ScalarExt = G::Scalar>,
 904    G: Group,
 905  {
 906    // perform some curve arithmetic
 907    let a = Point::<G>::random_vartime();
 908    let b = Point::<G>::random_vartime();
 909    let c = a.add(&b);
 910    let d = a.double();
 911    let s = <G as Group>::Scalar::random(&mut OsRng);
 912    let e = a.scalar_mul(&s);
 913
 914    // perform the same computation by translating to curve types
 915    let a_curve = C::from_xy(
 916      C::Base::from_repr(a.x.to_repr()).unwrap(),
 917      C::Base::from_repr(a.y.to_repr()).unwrap(),
 918    )
 919    .unwrap();
 920    let b_curve = C::from_xy(
 921      C::Base::from_repr(b.x.to_repr()).unwrap(),
 922      C::Base::from_repr(b.y.to_repr()).unwrap(),
 923    )
 924    .unwrap();
 925    let c_curve = (a_curve + b_curve).to_affine();
 926    let d_curve = (a_curve + a_curve).to_affine();
 927    let e_curve = a_curve
 928      .mul(C::Scalar::from_repr(s.to_repr()).unwrap())
 929      .to_affine();
 930
 931    // transform c, d, and e into curve types
 932    let c_curve_2 = C::from_xy(
 933      C::Base::from_repr(c.x.to_repr()).unwrap(),
 934      C::Base::from_repr(c.y.to_repr()).unwrap(),
 935    )
 936    .unwrap();
 937    let d_curve_2 = C::from_xy(
 938      C::Base::from_repr(d.x.to_repr()).unwrap(),
 939      C::Base::from_repr(d.y.to_repr()).unwrap(),
 940    )
 941    .unwrap();
 942    let e_curve_2 = C::from_xy(
 943      C::Base::from_repr(e.x.to_repr()).unwrap(),
 944      C::Base::from_repr(e.y.to_repr()).unwrap(),
 945    )
 946    .unwrap();
 947
 948    // check that we have the same outputs
 949    assert_eq!(c_curve, c_curve_2);
 950    assert_eq!(d_curve, d_curve_2);
 951    assert_eq!(e_curve, e_curve_2);
 952  }
 953
 954  fn synthesize_smul<G, CS>(mut cs: CS) -> (AllocatedPoint<G>, AllocatedPoint<G>, G::Scalar)
 955  where
 956    G: Group,
 957    CS: ConstraintSystem<G::Base>,
 958  {
 959    let a = alloc_random_point(cs.namespace(|| "a")).unwrap();
 960    inputize_allocted_point(&a, cs.namespace(|| "inputize a")).unwrap();
 961
 962    let s = G::Scalar::random(&mut OsRng);
 963    // Allocate bits for s
 964    let bits: Vec<AllocatedBit> = s
 965      .to_le_bits()
 966      .into_iter()
 967      .enumerate()
 968      .map(|(i, bit)| AllocatedBit::alloc(cs.namespace(|| format!("bit {i}")), Some(bit)))
 969      .collect::<Result<Vec<AllocatedBit>, SynthesisError>>()
 970      .unwrap();
 971    let e = a.scalar_mul(cs.namespace(|| "Scalar Mul"), bits).unwrap();
 972    inputize_allocted_point(&e, cs.namespace(|| "inputize e")).unwrap();
 973    (a, e, s)
 974  }
 975
 976  #[test]
 977  fn test_ecc_circuit_ops() {
 978    test_ecc_circuit_ops_with::<pallas::Point, vesta::Point>();
 979    test_ecc_circuit_ops_with::<vesta::Point, pallas::Point>();
 980  }
 981
 982  fn test_ecc_circuit_ops_with<G1, G2>()
 983  where
 984    G1: Group<Base = <G2 as Group>::Scalar>,
 985    G2: Group<Base = <G1 as Group>::Scalar>,
 986  {
 987    // First create the shape
 988    let mut cs: ShapeCS<G2> = ShapeCS::new();
 989    let _ = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize"));
 990    println!("Number of constraints: {}", cs.num_constraints());
 991    let (shape, ck) = cs.r1cs_shape();
 992
 993    // Then the satisfying assignment
 994    let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
 995    let (a, e, s) = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize"));
 996    let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
 997
 998    let a_p: Point<G1> = Point::new(
 999      a.x.get_value().unwrap(),
1000      a.y.get_value().unwrap(),
1001      a.is_infinity.get_value().unwrap() == <G1 as Group>::Base::ONE,
1002    );
1003    let e_p: Point<G1> = Point::new(
1004      e.x.get_value().unwrap(),
1005      e.y.get_value().unwrap(),
1006      e.is_infinity.get_value().unwrap() == <G1 as Group>::Base::ONE,
1007    );
1008    let e_new = a_p.scalar_mul(&s);
1009    assert!(e_p.x == e_new.x && e_p.y == e_new.y);
1010    // Make sure that this is satisfiable
1011    assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
1012  }
1013
1014  fn synthesize_add_equal<G, CS>(mut cs: CS) -> (AllocatedPoint<G>, AllocatedPoint<G>)
1015  where
1016    G: Group,
1017    CS: ConstraintSystem<G::Base>,
1018  {
1019    let a = alloc_random_point(cs.namespace(|| "a")).unwrap();
1020    inputize_allocted_point(&a, cs.namespace(|| "inputize a")).unwrap();
1021    let e = a.add(cs.namespace(|| "add a to a"), &a).unwrap();
1022    inputize_allocted_point(&e, cs.namespace(|| "inputize e")).unwrap();
1023    (a, e)
1024  }
1025
1026  #[test]
1027  fn test_ecc_circuit_add_equal() {
1028    test_ecc_circuit_add_equal_with::<pallas::Point, vesta::Point>();
1029    test_ecc_circuit_add_equal_with::<vesta::Point, pallas::Point>();
1030  }
1031
1032  fn test_ecc_circuit_add_equal_with<G1, G2>()
1033  where
1034    G1: Group<Base = <G2 as Group>::Scalar>,
1035    G2: Group<Base = <G1 as Group>::Scalar>,
1036  {
1037    // First create the shape
1038    let mut cs: ShapeCS<G2> = ShapeCS::new();
1039    let _ = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal"));
1040    println!("Number of constraints: {}", cs.num_constraints());
1041    let (shape, ck) = cs.r1cs_shape();
1042
1043    // Then the satisfying assignment
1044    let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
1045    let (a, e) = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal"));
1046    let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
1047    let a_p: Point<G1> = Point::new(
1048      a.x.get_value().unwrap(),
1049      a.y.get_value().unwrap(),
1050      a.is_infinity.get_value().unwrap() == <G1 as Group>::Base::ONE,
1051    );
1052    let e_p: Point<G1> = Point::new(
1053      e.x.get_value().unwrap(),
1054      e.y.get_value().unwrap(),
1055      e.is_infinity.get_value().unwrap() == <G1 as Group>::Base::ONE,
1056    );
1057    let e_new = a_p.add(&a_p);
1058    assert!(e_p.x == e_new.x && e_p.y == e_new.y);
1059    // Make sure that it is satisfiable
1060    assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
1061  }
1062
1063  fn synthesize_add_negation<G, CS>(mut cs: CS) -> AllocatedPoint<G>
1064  where
1065    G: Group,
1066    CS: ConstraintSystem<G::Base>,
1067  {
1068    let a = alloc_random_point(cs.namespace(|| "a")).unwrap();
1069    inputize_allocted_point(&a, cs.namespace(|| "inputize a")).unwrap();
1070    let mut b = &mut a.clone();
1071    b.y = AllocatedNum::alloc(cs.namespace(|| "allocate negation of a"), || {
1072      Ok(G::Base::ZERO)
1073    })
1074    .unwrap();
1075    inputize_allocted_point(b, cs.namespace(|| "inputize b")).unwrap();
1076    let e = a.add(cs.namespace(|| "add a to b"), b).unwrap();
1077    e
1078  }
1079
1080  #[test]
1081  fn test_ecc_circuit_add_negation() {
1082    test_ecc_circuit_add_negation_with::<pallas::Point, vesta::Point>();
1083    test_ecc_circuit_add_negation_with::<vesta::Point, pallas::Point>();
1084  }
1085
1086  fn test_ecc_circuit_add_negation_with<G1, G2>()
1087  where
1088    G1: Group<Base = <G2 as Group>::Scalar>,
1089    G2: Group<Base = <G1 as Group>::Scalar>,
1090  {
1091    // First create the shape
1092    let mut cs: ShapeCS<G2> = ShapeCS::new();
1093    let _ = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add equal"));
1094    println!("Number of constraints: {}", cs.num_constraints());
1095    let (shape, ck) = cs.r1cs_shape();
1096
1097    // Then the satisfying assignment
1098    let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
1099    let e = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add negation"));
1100    let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
1101    let e_p: Point<G1> = Point::new(
1102      e.x.get_value().unwrap(),
1103      e.y.get_value().unwrap(),
1104      e.is_infinity.get_value().unwrap() == <G1 as Group>::Base::ONE,
1105    );
1106    assert!(e_p.is_infinity);
1107    // Make sure that it is satisfiable
1108    assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
1109  }
1110}