plonky2/evm/src/bn254_pairing.rs

358 lines
11 KiB
Rust
Raw Normal View History

2023-01-21 15:55:45 +07:00
use std::ops::Add;
2023-02-01 19:15:56 -08:00
use rand::Rng;
2023-03-21 19:19:02 -07:00
use crate::extension_tower::{FieldExt, Fp12, Fp2, Fp6, BN254};
2023-01-17 23:58:36 +07:00
2023-03-21 19:19:02 -07:00
// The curve consists of pairs (x, y): (BN254, BN254) | y^2 = x^3 + 2
2023-01-21 14:17:01 +07:00
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Curve {
2023-03-21 19:19:02 -07:00
pub x: BN254,
pub y: BN254,
2023-01-21 14:17:01 +07:00
}
2023-01-18 14:41:09 +07:00
2023-01-21 16:15:27 +07:00
/// Standard addition formula for elliptic curves, restricted to the cases
/// where neither inputs nor output would ever be the identity O. source:
2023-01-21 15:55:45 +07:00
/// https://en.wikipedia.org/wiki/Elliptic_curve#Algebraic_interpretation
impl Add for Curve {
type Output = Self;
fn add(self, other: Self) -> Self {
let m = if self == other {
2023-03-21 19:19:02 -07:00
BN254::new(3) * self.x * self.x / (BN254::new(2) * self.y)
2023-01-21 15:55:45 +07:00
} else {
(other.y - self.y) / (other.x - self.x)
};
let x = m * m - (self.x + other.x);
Curve {
x,
y: m * (self.x - x) - self.y,
}
}
}
// The twisted curve consists of pairs (x, y): (Fp2, Fp2) | y^2 = x^3 + 3/(9 + i)
2023-01-21 14:17:01 +07:00
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct TwistedCurve {
2023-03-21 19:19:02 -07:00
pub x: Fp2<BN254>,
pub y: Fp2<BN254>,
2023-01-18 14:41:09 +07:00
}
2023-01-23 14:59:08 +07:00
// The tate pairing takes a point each from the curve and its twist and outputs an Fp12 element
2023-03-21 19:19:02 -07:00
pub fn tate(p: Curve, q: TwistedCurve) -> Fp12<BN254> {
2023-01-21 14:17:01 +07:00
let miller_output = miller_loop(p, q);
2023-02-07 14:54:07 -08:00
invariant_exponent(miller_output)
2023-01-21 14:17:01 +07:00
}
2023-02-01 18:57:50 -08:00
/// Standard code for miller loop, can be found on page 99 at this url:
/// https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf#page=107
/// where EXP is a hardcoding of the array of Booleans that the loop traverses
2023-03-21 19:19:02 -07:00
pub fn miller_loop(p: Curve, q: TwistedCurve) -> Fp12<BN254> {
2023-02-01 18:57:50 -08:00
let mut r = p;
2023-03-21 19:19:02 -07:00
let mut acc: Fp12<BN254> = Fp12::<BN254>::UNIT;
let mut line: Fp12<BN254>;
2023-01-21 14:17:01 +07:00
for i in EXP {
2023-02-01 18:57:50 -08:00
line = tangent(r, q);
r = r + r;
acc = line * acc * acc;
2023-01-25 16:41:42 +07:00
if i {
2023-02-01 18:57:50 -08:00
line = cord(p, r, q);
r = r + p;
2023-01-21 14:17:01 +07:00
acc = line * acc;
}
}
acc
2023-01-18 14:41:09 +07:00
}
2023-01-17 23:58:36 +07:00
2023-02-01 18:57:50 -08:00
/// The sloped line function for doubling a point
2023-03-21 19:19:02 -07:00
pub fn tangent(p: Curve, q: TwistedCurve) -> Fp12<BN254> {
let cx = -BN254::new(3) * p.x * p.x;
let cy = BN254::new(2) * p.y;
2023-03-22 17:26:14 -07:00
sparse_embed(p.y * p.y - BN254::new(9), q.x * cx, q.y * cy)
2023-01-24 09:42:42 +07:00
}
2023-02-01 18:57:50 -08:00
/// The sloped line function for adding two points
2023-03-21 19:19:02 -07:00
pub fn cord(p1: Curve, p2: Curve, q: TwistedCurve) -> Fp12<BN254> {
2023-01-24 09:42:42 +07:00
let cx = p2.y - p1.y;
let cy = p1.x - p2.x;
2023-03-22 17:26:14 -07:00
sparse_embed(p1.y * p2.x - p2.y * p1.x, q.x * cx, q.y * cy)
2023-01-23 14:59:08 +07:00
}
2023-01-25 16:20:24 +07:00
/// The tangent and cord functions output sparse Fp12 elements.
/// This map embeds the nonzero coefficients into an Fp12.
2023-03-21 19:19:02 -07:00
pub fn sparse_embed(g000: BN254, g01: Fp2<BN254>, g11: Fp2<BN254>) -> Fp12<BN254> {
2023-01-23 14:59:08 +07:00
let g0 = Fp6 {
t0: Fp2 {
re: g000,
2023-03-21 19:19:02 -07:00
im: BN254::ZERO,
2023-01-23 14:59:08 +07:00
},
t1: g01,
2023-03-21 19:19:02 -07:00
t2: Fp2::<BN254>::ZERO,
2023-01-23 14:59:08 +07:00
};
let g1 = Fp6 {
2023-03-21 19:19:02 -07:00
t0: Fp2::<BN254>::ZERO,
2023-01-23 14:59:08 +07:00
t1: g11,
2023-03-21 19:19:02 -07:00
t2: Fp2::<BN254>::ZERO,
2023-01-23 14:59:08 +07:00
};
Fp12 { z0: g0, z1: g1 }
}
2023-03-21 19:19:02 -07:00
pub fn gen_fp12_sparse<R: Rng + ?Sized>(rng: &mut R) -> Fp12<BN254> {
sparse_embed(
rng.gen::<BN254>(),
rng.gen::<Fp2<BN254>>(),
rng.gen::<Fp2<BN254>>(),
)
2023-01-21 16:15:27 +07:00
}
2023-01-24 16:35:49 +07:00
/// The output y of the miller loop is not an invariant,
/// but one gets an invariant by raising y to the power
2023-01-23 14:59:08 +07:00
/// (p^12 - 1)/N = (p^6 - 1)(p^2 + 1)(p^4 - p^2 + 1)/N
/// where N is the cyclic group order of the curve.
2023-01-24 16:35:49 +07:00
/// To achieve this, we first exponentiate y by p^6 - 1 via
/// y = y_6 / y
2023-01-23 14:59:08 +07:00
/// and then exponentiate the result by p^2 + 1 via
2023-01-24 16:35:49 +07:00
/// y = y_2 * y
2023-01-23 14:59:08 +07:00
/// We then note that (p^4 - p^2 + 1)/N can be rewritten as
/// (p^4 - p^2 + 1)/N = p^3 + (a2)p^2 - (a1)p - a0
/// where 0 < a0, a1, a2 < p. Then the final power is given by
2023-01-24 16:35:49 +07:00
/// y = y_3 * (y^a2)_2 * (y^-a1)_1 * (y^-a0)
2023-03-21 19:19:02 -07:00
pub fn invariant_exponent(f: Fp12<BN254>) -> Fp12<BN254> {
2023-01-24 16:35:49 +07:00
let mut y = f.frob(6) / f;
y = y.frob(2) * y;
let (y_a2, y_a1, y_a0) = get_custom_powers(y);
y.frob(3) * y_a2.frob(2) * y_a1.frob(1) * y_a0
2023-01-23 14:59:08 +07:00
}
2023-01-25 15:31:32 +07:00
/// We first together (so as to avoid repeated steps) compute
2023-01-24 16:35:49 +07:00
/// y^a4, y^a2, y^a0
2023-01-24 14:56:15 +07:00
/// where a1 is given by
/// a1 = a4 + 2a2 - a0
2023-01-25 15:31:32 +07:00
/// we then invert y^a0 and return
/// y^a2, y^a1 = y^a4 * y^a2 * y^a2 * y^(-a0), y^(-a0)
///
2023-01-26 10:42:31 +07:00
/// Representing a4, a2, a0 in *little endian* binary, define
2023-01-25 15:31:32 +07:00
/// EXPS4 = [(a4[i], a2[i], a0[i]) for i in 0..len(a4)]
/// EXPS2 = [ (a2[i], a0[i]) for i in len(a4)..len(a2)]
/// EXPS0 = [ a0[i] for i in len(a2)..len(a0)]
2023-03-21 19:19:02 -07:00
fn get_custom_powers(f: Fp12<BN254>) -> (Fp12<BN254>, Fp12<BN254>, Fp12<BN254>) {
let mut sq: Fp12<BN254> = f;
let mut y0: Fp12<BN254> = Fp12::<BN254>::UNIT;
let mut y2: Fp12<BN254> = Fp12::<BN254>::UNIT;
let mut y4: Fp12<BN254> = Fp12::<BN254>::UNIT;
2023-01-17 23:58:36 +07:00
2023-01-25 15:31:32 +07:00
// proceed via standard squaring algorithm for exponentiation
// must keep multiplying all three values: a4, a2, a0
2023-01-17 23:58:36 +07:00
for (a, b, c) in EXPS4 {
2023-01-25 16:41:42 +07:00
if a {
2023-01-20 15:43:17 +07:00
y4 = y4 * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-25 16:41:42 +07:00
if b {
2023-01-20 15:43:17 +07:00
y2 = y2 * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-25 16:41:42 +07:00
if c {
2023-01-20 15:43:17 +07:00
y0 = y0 * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-20 15:43:17 +07:00
sq = sq * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-25 15:31:32 +07:00
// leading term of a4 is always 1
2023-01-20 15:43:17 +07:00
y4 = y4 * sq;
2023-01-17 23:58:36 +07:00
2023-01-25 15:31:32 +07:00
// must keep multiplying remaining two values: a2, a0
2023-01-17 23:58:36 +07:00
for (a, b) in EXPS2 {
2023-01-25 16:41:42 +07:00
if a {
2023-01-20 15:43:17 +07:00
y2 = y2 * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-25 16:41:42 +07:00
if b {
2023-01-20 15:43:17 +07:00
y0 = y0 * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-20 15:43:17 +07:00
sq = sq * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-25 15:31:32 +07:00
// leading term of a2 is always 1
2023-01-20 15:43:17 +07:00
y2 = y2 * sq;
2023-01-17 23:58:36 +07:00
2023-01-26 10:42:31 +07:00
// must keep multiplying final remaining value: a0
2023-01-17 23:58:36 +07:00
for a in EXPS0 {
2023-01-25 16:41:42 +07:00
if a {
2023-01-20 15:43:17 +07:00
y0 = y0 * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-20 15:43:17 +07:00
sq = sq * sq;
2023-01-17 23:58:36 +07:00
}
2023-01-25 15:31:32 +07:00
// leading term of a0 is always 1
2023-01-20 15:43:17 +07:00
y0 = y0 * sq;
2023-01-17 23:58:36 +07:00
2023-01-25 15:31:32 +07:00
// invert y0 to compute y^(-a0)
2023-01-24 14:56:15 +07:00
let y0_inv = y0.inv();
2023-01-25 15:31:32 +07:00
2023-01-26 10:42:31 +07:00
// return y^a2 = y2, y^a1 = y4 * y2^2 * y^(-a0), y^(-a0)
2023-01-24 14:56:15 +07:00
(y2, y4 * y2 * y2 * y0_inv, y0_inv)
2023-01-17 23:58:36 +07:00
}
2023-01-25 16:41:42 +07:00
const EXP: [bool; 253] = [
true, false, false, false, false, false, true, true, false, false, true, false, false, false,
true, false, false, true, true, true, false, false, true, true, true, false, false, true,
false, true, true, true, false, false, false, false, true, false, false, true, true, false,
false, false, true, true, false, true, false, false, false, false, false, false, false, true,
false, true, false, false, true, true, false, true, true, true, false, false, false, false,
true, false, true, false, false, false, false, false, true, false, false, false, true, false,
true, true, false, true, true, false, true, true, false, true, false, false, false, false,
false, false, true, true, false, false, false, false, false, false, true, false, true, false,
true, true, false, false, false, false, true, false, true, true, true, false, true, false,
false, true, false, true, false, false, false, false, false, true, true, false, false, true,
true, true, true, true, false, true, false, false, false, false, true, false, false, true,
false, false, false, false, true, true, true, true, false, false, true, true, false, true,
true, true, false, false, true, false, true, true, true, false, false, false, false, true,
false, false, true, false, false, false, true, false, true, false, false, false, false, true,
true, true, true, true, false, false, false, false, true, true, true, true, true, false, true,
false, true, true, false, false, true, false, false, true, true, true, true, true, true, false,
false, false, false, false, false, false, false, false, false, false, false, false, false,
false, false, false, false, false, false, false, false, false, false, false, false, false,
false,
2023-01-25 16:20:24 +07:00
];
2023-01-25 16:10:53 +07:00
// The folowing constants are defined above get_custom_powers
2023-01-25 15:31:32 +07:00
2023-01-25 16:41:42 +07:00
const EXPS4: [(bool, bool, bool); 64] = [
(true, true, false),
(true, true, true),
(true, true, true),
(false, false, false),
(false, false, true),
(true, false, true),
(false, true, false),
(true, false, true),
(true, true, false),
(true, false, true),
(false, true, false),
(true, true, false),
(true, true, false),
(true, true, false),
(false, true, false),
(false, true, false),
(false, false, true),
(true, false, true),
(true, true, false),
(false, true, false),
(true, true, false),
(true, true, false),
(true, true, false),
(false, false, true),
(false, false, true),
(true, false, true),
(true, false, true),
(true, true, false),
(true, false, false),
(true, true, false),
(false, true, false),
(true, true, false),
(true, false, false),
(false, true, false),
(false, false, false),
(true, false, false),
(true, false, false),
(true, false, true),
(false, false, true),
(false, true, true),
(false, false, true),
(false, true, true),
(false, true, true),
(false, false, false),
(true, true, true),
(true, false, true),
(true, false, true),
(false, true, true),
(true, false, true),
(false, true, true),
(false, true, true),
(true, true, false),
(true, true, false),
(true, true, false),
(true, false, false),
(false, false, true),
(true, false, false),
(false, false, true),
(true, false, true),
(true, true, false),
(true, true, true),
(false, true, true),
(false, true, false),
(true, true, true),
2023-01-25 15:31:32 +07:00
];
2023-01-25 16:41:42 +07:00
const EXPS2: [(bool, bool); 62] = [
(true, false),
(true, true),
(false, false),
(true, false),
(true, false),
(true, true),
(true, false),
(true, true),
(true, false),
(false, true),
(false, true),
(true, true),
(true, true),
(false, false),
(true, true),
(false, false),
(false, false),
(false, true),
(false, true),
(true, true),
(true, true),
(true, true),
(false, true),
(true, true),
(false, false),
(true, true),
(true, false),
(true, true),
(false, false),
(true, true),
(true, true),
(true, false),
(false, false),
(false, true),
(false, false),
(true, true),
(false, true),
(false, false),
(true, false),
(false, true),
(false, true),
(true, false),
(false, true),
(false, false),
(false, false),
(false, false),
(false, true),
(true, false),
(true, true),
(false, true),
(true, true),
(true, false),
(false, true),
(false, false),
(true, false),
(false, true),
(true, false),
(true, true),
(true, false),
(true, true),
(false, true),
(true, true),
2023-01-25 15:31:32 +07:00
];
2023-01-25 16:41:42 +07:00
const EXPS0: [bool; 65] = [
false, false, true, false, false, true, true, false, true, false, true, true, true, false,
true, false, false, false, true, false, false, true, false, true, false, true, true, false,
false, false, false, false, true, false, true, false, true, true, true, false, false, true,
true, true, true, false, true, false, true, true, false, false, true, false, false, false,
true, true, true, true, false, false, true, true, false,
2023-01-25 15:31:32 +07:00
];