- BLS12-381
- Input format
- BigInt templates
- BigInt functions
log_ceil(n)
long_add(n, k, a, b)
long_add_unequal(n, k1, k2, a, b)
long_sub(n, k, a, b)
long_scalar_mult(n, k, a, b)
long_div2(n, k, m, a, b)
signed_long_to_short(n, k, a)
prod(n, k, a, b)
prod2D(n, k, l, a, b)
long_add_mod(n, k, a, b, p)
long_sub_mod(n, k, a, b, p)
prod_mod(n, k, a, b, p)
mod_exp(n, k, a, p, e)
mod_inv(n, k, a, p)
- Fp templates
- Fp2 templates
SignedFp2MultiplyNoCarryUnequal(n, ka, kb, m_out)
SignedFp2MultiplyNoCarry(n, k, m_out)
Fp2Compress(n, k, m, p, m_out)
SignedFp2MultiplyNoCarryCompress(n, k, p, m_in, m_out)
SignedFp2MultiplyNoCarryCompressThree(n, k, p, m_in, m_out)
RangeCheck2D(n, k)
SignedFp2CarryModP(n, k, overflow, p)
Fp2Multiply(n, k, p)
Fp2MultiplyThree(n, k, p)
Fp2Negate(n, k, p)
Fp2Invert(n, k, p)
SignedFp2Divide(n, k, overflowa, overflowb, p)
Fp2Conjugate(n, k, p)
Fp2FrobeniusMap(n, k, power, p)
Fp2Sgn0(n, k, p)
Fp2IsZero(n, k, p)
Fp2IsEqual(n, k, p)
- Fp12 templates
Fp12FrobeniusMap(n, k, power)
SignedFp12ScalarMultiplyNoCarryUnequal(n, ka, kb, m_out)
SignedFp12ScalarMultiplyNoCarry(n, k, m_out)
SignedFp12Fp2MultiplyNoCarryUnequal(n, ka, kb, m_out)
SignedFp12Fp2MultiplyNoCarry(n, k, m_out)
SignedFp12MultiplyNoCarryUnequal(n, ka, kb, m_out)
SignedFp12MultiplyNoCarry(n, k, m_out)
Fp12Compress(n, k, m, p, m_out)
SignedFp12MultiplyNoCarryCompress(n, k, p, m_in, m_out)
SignedFp12CarryModP(n, k, overflow, p)
Fp12Multiply(n, k, p)
Fp12Invert(n, k, p)
- Finite field functions
get_fp_sng0(a)
find_Fp_inverse(n, k, num, p)
get_signed_Fp_carry_witness(n, k, m, a, p)
get_signed_Fp2_carry_witness(n, k, m, a, p)
get_fp2_sgn0(k, a)
find_Fp2_product(n, k, a, b, p)
find_Fp2_sum(n, k, a, b, p)
find_Fp2_diff(n, k, a, b, p)
find_Fp2_exp(n, k, a, p, e)
is_equal_Fp2(n, k, a, b)
signed_Fp2_mult_w6(k, a, XI0)
find_Fp12_sum(n, k, a, b, p)
find_Fp12_diff(n, k, a, b, p)
find_Fp12_product(n, k, a, b, p)
find_Fp2_inverse(n, k, a, p)
find_Fp6_inverse(n, k, p, a0, a1, a2)
find_Fp12_inverse(n, k, p, a)
- Elliptic curve templates
PointOnLine(n, k, p)
PointOnCurve(n, k, a, b, p)
PointOnTangent(n, k, a, p)
EllipticCurveAddUnequal(n, k, p)
EllipticCurveDouble(n, k, a, b, p)
EllipticCurveAdd(n, k, p)
EllipticCurveScalarMultiply(n, k, b, x, p)
EllipticCurveScalarMultiplyUnequal(n, k, b, x, p)
SignedLineFunctionUnequalNoCarry(n, k, m_out)
SignedLineFunctionEqualNoCarry(n, k, m_out)
LineFunctionUnequal(n, k, p)
LineFunctionEqual(n, k, p)
Fp12MultplyWithLineUnequal(n, k, kg, overflowg, p)
MillerLoop(n, k, b, x, p)
BLSMillerLoop(n, k, p)
- Elliptic curve over
F_{p^2}
templatesPointOnLineFp2(n, k, p)
PointOnCurveFp2(n, k, a, b, p)
EllipticCurveFunction(n, k, a, b, p)
PointOnTangentFp2(n, k, a, p)
EllipticCurveAddUnequalFp2(n, k, p)
EllipticCurveDoubleFp2(n, k, a, b, p)
EllipticCurveAddFp2(n, k, p)
EllipticCurveScalarMultiplyFp2(n, k, b, x, p)
EllipticCurveScalarMultiplyUnequalFp2(n, k, b, x, p)
SignedLineFunctionUnequalNoCarryFp2(n, k, m_out)
SignedLineFunctionEqualNoCarryFp2(n, k, m_out)
LineFunctionUnequalFp2(n, k, p)
LineFunctionEqualFp2(n, k, p)
Fp12MultplyWithLineUnequalFp2(n, k, kg, overflowg, p)
MillerLoopFp2(n, k, b, x, p)
MillerLoopFp2Two(n, k, b, x, p)
- Final exponentiation templates
- BLS12-381 Map to G2 and subgroup checks
- Pairing templates
- BLS Signature templates
We refer to BLS12-381 For The Rest Of Us for details about the curve BLS12-381.
The curve E
is
y^2 = x^3 + 4
over F_q
for a 381
-bit prime q
.
The twist E2
of E
is the curve
y^2 = x^3 + 4(1+u)
over F_{q^2}
(see below).
For general implementations not particular to BLS12-381, we denote the prime by p
below.
To format inputs correctly for our circuits, in Python
one can use the functions in python/field_helper.py
which are designed to work with py_ecc. In Typescript
one can see test/test.ts
for an example of how to format inputs compatibly with @noble/bls12-381.
Almost every template we use contains two parameters n
and k
(in practice we use n = 55, k = 7
), where n
denotes the register bit size and k
denotes the number of registers: for a large integer A
we can represent it as an array a
of length k
such that
A = 2^0 * a[0] + 2^n * a[1] + ... + 2^{n(k-1)} * a[k-1]
where each register 0 <= a[i] < 2^n
for all i
. In other words, this is base 2^n
little-endian notation. We call this a proper BigInt representation.
For the purposes of optimizing constraints, in many intermediate circuits we store a big integer in the form
A = 2^0 * a[0] + 2^n * a[1] + ... + 2^{n(k-1)} * a[k-1]
where each register a[i]
is signed and allowed to have absolute value possibly larger than 2^n
. Here signed means: for a positive number 0 <= b < 2^252
, we can store -b
as BabyJubJubPrime - b > 2^252
, where BabyJubJubPrime
is the inherent 254
-bit field modulus in circom.
Since we store numbers in this overflow representation, we need to make sure that as we perform other operations (such as multiplying two numbers), the absolute value of each array element stays < 2^252
. This will involve keeping track of various bounds that we make note of both in this documentation and in the code.
An element in F_p
uniquely corresponds to an integer 0 <= A < p
.
While our witness generation always produces F_p
elements 0 <= A < p
, to save constraints we usually only constrain A >= 0
to be a proper BigInt and further constrain A < p
only when necessary. In other words, unless otherwise specified, we constrain an F_p
element representing A
to be any proper BigInt (necessarily < 2^{n*k}
) congruent to A
modulo p
.
We construct F_{p^2} = F_p[u]/(u^2+1)
(this requires p = 3 (mod 4)
). An element in F_{p^2}
has the form
A_0 + A_1 u
with A_0, A_1
in F_p
. We represent this element as a 2 x k
array a
with a[0], a[1]
in F_p
(with the same caveats as above).
We construct F_{p^12} = F_{p^2}[w]/(w^6 - (1+u))
(this requires 1+u
to not be a square or cube in F_{p^2}
). An element in F_{p^12}
has the form
\sum_{i=0}^5 A_i w^i
for A_i
in F_{p^2}
. We represent it as a 6 x 2 x k
array a
where a[i]
represents A_i
.
A point in E(F_p)
is a pair (x, y)
with x,y
in F_p
so we represent it as a 2 x k
array P
where P[0]
represents x
and P[1]
represents y
.
A point in E_2(F_{p^2})
is a pair (x, y)
with x,y
in F_{p^2}
so we represent it as a 2 x 2 x k
array Q
where Q[0]
represents x
and Q[1]
represents y
.
A point in E(F_{p^12})
is a pair (X, Y)
with X,Y
in F_{p^12}
so we represent it as a 2 x 6 x 2 x k
array Q
where Q[0]
represents x
and Q[1]
represents y
.
bigint.circom
is a fork of circom-ecdsa, containing templates for operating on numbers represented in array form (usually because the number may exceed the size of the circom prime BabyJubJubPrime
). See Input format for a review of different ways to represent numbers.
Here are the main circuits we use from bigint.circom
:
Multiplication of two polynomials in one variable X
.
Inputs:
a = a[0] + a[1] * X + ... + a[k-1] * X^{k-1}
a degreek - 1
polynomialb = b[0] + b[1] * X + ... + b[k-1] * X^{k-1}
a degreek - 1
polynomial
Output:
out = out[0] + out[1] * X + ... + out[2 * k - 2] * X^{2*k - 2}
out = a * b
as polynomials inX
Notes:
- Optimization due to xJsnark:
- witness is calculated by normal polynomial multiplication
out
is contrained by evaluatingout(X) === a(X) * b(X)
atX = 0, ..., 2*k - 2
- If all
a[i], b[i]
have absolute values< B
, thenout[i]
has absolute value< k * B^2
For code readability/verification, m_out
is passed as a parameter with the expected max number of bits in the output registers out[i]
.
This is the same as BigMultShortLong
except a
has degree ka - 1
and b
has degree kb - 1
.
- If all
a[i], b[i]
have absolute values< B
, thenout[i]
has absolute value< min(ka, kb) * B^2
Inputs:
a,b
in BigInt format
Output:
out = (a < b) ? 1 : 0
Inputs:
- BigInts
a,b
- Assume
a >= b
Output:
- BigInt
out = a - b
underflow
= how much is borrowed at the highest register of subtraction, only nonzero ifa < b
Input:
in = in[0] + in[1] * X + ... + in[k-1] * X^{k-1}
as signed overflow representation- Assume each
in[i]
is in range(-2^{m-1}, 2^{m-1})
. - Assume
m < 252
.
Implements:
- Constrain that
in
evaluated atX = 2^n
as a big integer equals zero. - Costs roughly
k * (m - n)
constraints.
This template compresses the array length of a signed overflow BigInt at the cost of increasing the overflow size.
Input: Let X = 2^n
.
in
is lengthk + m
array in signed overflow representationin = in[0] + in[1] * X + ... + in[k+m-1] * X^{k+m-1}
- Assume each
in[i]
is a signed integer such thatabs(in[i] * 2^n) < 2^252
p
is prime in proper BigInt format passed as parameter.
Output:
out = out[0] + out[1] * X + ... + out[k-1] * X^{k-1}
is BigInt congruent toin (mod p)
Implementation:
- For
i >= k
, we precomputeX^i = r[i] mod p
, wherer[i][]
is a proper BigInt< p
. in[i] * X^i
is replaced bysum_j in[i] * r[i][j] * X^j
- If each
in[i]
has absolute value<B
, thenout[i]
has absolute value< (m+1) * 2^n * B
.
m_out
is the expected max number of bits in the output registers.
Polynomial multiplication in 2 variables.
Input:
a = sum_{i=0}^{l-1} sum_{j=0}^{k-1} a[i][j] * w^i * X^j
b = sum_{i=0}^{l-1} sum_{j=0}^{k-1} b[i][j] * w^i * X^j
Output:
out = sum_{i=0}^{2*l-2} sum_{j=0}^{2*k-1} out[i][j] * w^i * X^j
out = a * b
as product of polynomials in two variablesw, X
Implementation:
- Uses same xJsnark optimization as
BigMultShortLong
- If
a[i][j], b[i][j]
have absolute value< B
, thenout[i][j]
has absolute value< l * k * B^2
.
Use case: one variable will end up being 2^n
; the other will be the field extension generator.
bigint_func.circom
contains helper functions for witness generation on proper BigInts represented in array form. The parameters n,k
always mean the register bit size and number of registers. Unless otherwise specified, BigInts are always represented in proper format.
Parameters:
n
: an integer assumed< 2^253
.
Outputs:
- Returns
$\lceil \log_2 n\rceil$ .
Parameters:
a
: BigInt withk
registersb
: BigInt withk
registers
Outputs:
- Returns BigInt
out = a + b
withk + 1
registers.
Assumptions:
- Assumes
k+1 <= 50
(becausevar
array sizes are static).
Parameters:
a
: BigInt withk1
registersb
: BigInt withk2
registers
Outputs:
- Returns BigInt
out = a + b
withk1 + 1
registers.
Assumptions:
- Assumes
k1 >= k2
andk1 + 1 <= 50
.
Parameters:
a
: BigInt withk
registersb
: BigInt withk
registers
Outputs:
- Returns BigInt
out = a - b
.
Assumptions:
- Assumes
a >= b
andk <= 50
.
Parameters:
a
:n
-bit integer.b
: BigInt withk
registers
Outputs:
- Returns a BigInt
out = a * b
withk+1
registers.
Assumptions:
- Assumes
k+1 <= 50
.
Parameters:
a
: BigInt withk + m
registersb
: BigInt withk
registers
Outputs:
- Returns BigInt
out[0]
withm + 1
registers andout[1]
withk
registers such thata = out[0] * b + out[1]
.
Assumptions:
- Assumes
k + m <= 50
. - Assumes
b[k-1]
is nonzero.
Parameters:
a
: BigInt in signed overflow representation withk
registers.
Outputs:
- Returns a length
50
arrayout
representinga
in proper BigInt form. out[50] = 0
ifa
is positive,1
ifa
is negative.
Assumptions:
- Assumes
a[i] < 2^{252}
for alli
and that the proper representation ofa
uses at most50
registers. (Anassert
will fail otherwise.)
Parameters:
a
: BigInt withk
registersb
: BigInt withk
registers
Outputs:
- Returns BigInt
out = a * b
with2k - 1
registers.
Note that the difference between prod
and BigMultShortLong
is that the registers of out
here are in [0, 2^n)
. We are no longer doing polynomial multiplication and must "carry" using base 2^n
.
Assumptions:
- Assumes
k <= 25
.
Parameters:
a
: lengthl x k
array representing a degreel - 1
polynomiala = a[0] + a[1] * w + ... + a[l-1] * w^{l-1}
witha[i]
BigInts withk
registers.b
: lengthl x k
array representing a degreel - 1
polynomialb = b[0] + b[1] * w + ... + b[l-1] * w^{l-1}
withb[i]
BigInts withk
registers.
Outputs:
- Returns length
2l - 1 x 2k
array representingout = a * b
as product of polynomials inw
. out = out[0] + out[1] * w + ... + out[2l-2] * w^{2l-2}
Note that the difference between prod2D
and BigMultShortLong2D
is that the registers of out
here are in [0, 2^n)
. Despite the name, prod2D
is multiplication of polynomials in one variable, whereas BigMultShortLong2D
is multiplication of polynomials in two variables.
Assumptions:
k <= 25
l <= 10
These are the same as long_add, long_sub, prod
except we return out % p
as BigInts. Note that long_sub_mod
assumes that a,b < p
.
Parameters:
a
: BigInt withk
registersp
: BigInt withk
registers (notep
doesn't need to be prime!)e
: BigInt withk
registers
Outputs:
- Returns BigInt
out = a^e (mod p)
.
Assumptions:
- Assumes
k <= 50
andk * n <= 500
.
Implementation:
- A small optimization is to compute the bit length of
e
first, and then do the square-and-multiply method as a loop on the bit length.
Parameters:
a
: BigInt withk
registersp
: a prime BigInt withk
registers
Outputs:
- Returns BigInt with
k
registersout = a^{-1} (mod p)
. Returns0
ifa = 0
.
Assumptions:
- Assumes
k <= 50
andk * n <= 500
.
Implementation:
- Uses Fermat's Little Theorem and computes
out = a^{p-2} (mod p)
.
fp.circom
contains templates for operating on elements of F_p
. See Fp element for a reminder on how an element of F_p
is represented. By default, an F_p
element means a proper BigInt with k
registers of bit size n
. Unless explicitly stated, we do not constrain elements to be < p
.
The templates all take a parameter p
, which is a length k
array representing p
in proper BigInt format with bit size n
registers.
Input:
in
:F_p
element
Output:
out
:-in (mod p) = p - in
ifin != 0
, else0
.
Circuit constrains in <= p
.
Inputs:
in
: signed overflow representation withk
registers with absolute value< 2^overflow
X
: signed overflow representation withm
registers with absolute value< 2^{overflow - n - log(min(k,m)) - 1}
Y
:F_p
element
Implements:
- Constrain
in = p * X + Y
. UsesCheckCarryToZero
.
Assumptions:
- Assume
overflow < 251
- Assume
overflow - 1 >= n
.
Inputs:
in
: signed overflow representation withk
registers with absolute value< 2^overflow
Outputs:
X
: signed overflow representation withceil(overflow / n)
registers in[-2^n, 2^n)
out
:F_p
element such thatin = p * X + out
as integers.
Implements:
- Witnesses for
X, out
are precomputed. The witness forout
satisfiesout < p
. - Constrain
in === p * X + out
usingCheckCarryModP
. Does not constrainout < p
.
Assumptions:
- Input registers have absolute value
< 2^overflow
n + 1 <= overflow < 251
Input:
a,b
:F_p
elements
Output:
out
:F_p
element congruent toa * b (mod p)
.
Implementation:
- We first prove a computation of
a * b
as an overflow BigInt representation with2k-1
registers usingBigMultShortLong
. - We "compress" the above computation to a congruent representation
mod p
withk
registers usingPrimeReduce
. This is an optimization for the next step. - We use
SignedFpCarryModP
to generate a witnessout
and constrain thatout = a * b (mod p)
.
Assumption:
k^2 * 2^{3n} < 251
Constrains that the input is congruent to 0 (mod p)
. The method is the same as SignedFpCarryModP
except we save constraints by not having to range check out = 0
.
Input:
in
: signed overflow BigInt representation withk
registers- Assume
in[i]
has absolute value< 2^overflow
Output:
X
is signed overflow BigInt withceil(overflow / n)
registers in[-2^n, 2^n)
such thatin = p * X
as integers.
Assumption:
overflow < 251
This is a proof of computation of sgn0
as described in the IRTF draft.
Input:
in
:F_p
element
Output:
out = sgn0(in)
is0
or1
.
Implementation:
sgn0(in) = in % 2
.- Constrains
in < p
since the formula forsgn0
assumes this.
Input:
in
:F_p
element
Output:
out = (in == 0 ? 1 : 0)
Implementation:
- Constrains
in < p
and then checks ifin = 0
as BigInt.
Input:
in[0], in[1]
: twoF_p
elements
Output:
out = (in[0] == in[1])
Implementation:
- Constrains
in[0] < p
andin[1] < p
and then checks if they are equal as BigInts.
fp2.circom
contains templates for operating on elements of F_{p^2}
. See Fp2 element for a reminder on how an element of F_{p^2}
is represented. Unless explicitly stated, we do not constrain the corresponding F_p
elements to be < p
.
Inputs:
a = a[0] + a[1] u
wherea[i]
is signed overflow representation withka
registers.b = b[0] + b[1] u
whereb[i]
is signed overflow representation withkb
registers
Output:
out = out[0] + out[1] u
whereout[i]
is signed overflow representation withka + kb - 1
registers such thatout = a * b
inZ[u]/(u^2 + 1)
(Z
denotes integers).
Implementation:
- Uses
BigMultShortLongUnequal
to multiplya * b
without carries. - Uses the identity
u^2 = -1
. - Despite the naming, does not involve any prime
p
. - If
a[i][j], b[i][j]
all have absolute value< B
, thenout[i][j]
has absolute value< 2k * B^2
.
Assumptions:
- Assume
2 * k * B^2 < 2^252
wherea[i][j], b[i][j] < B
for alli,j
.
Parameter m_out
is passed when calling template with the expected max number of bits in the output registers.
Calls SignedFp2MultiplyNoCarryUnequal(n, k, k, m_out)
.
Inputs:
in = in[0] + in[1] u
wherein[i]
is signed overflow representation withk + m
registers.
Output:
out = out[0] + out[1] u
whereout[i]
is signed overflow representation withk
registersout[i] = in[i] (mod p)
Implementation:
- Calls
PrimeReduce
twice. - If
in[i][j]
all have absolute value< B
, thenout[i][j]
has absolute value< (m+1) * 2^n * B
.
Assumptions:
- Assume
(m+1) * 2^n * B < 2^252
Parameter m_out
is passed when calling template with the expected max number of bits in the output registers.
Inputs:
a = a[0] + a[1] u
wherea[i]
is signed overflow representation withk
registers.b = b[0] + b[1] u
whereb[i]
is signed overflow representation withk
registers
Output:
out = out[0] + out[1] u
whereout[i]
is signed overflow representation withk
registersout
is equal toa * b
as elements inF_{p^2}
Implementation:
- Combines
SignedFp2MultiplyNoCarry
andFp2Compress
. - If
a[i][j], b[i][j]
all have absolute value< B
, thenout[i][j]
has absolute value< 2k^2 * 2^n * B^2
.
Parameters:
m_in
: expected max number of bits in the input registers (soB = 2^{m_in}
)m_out
: expected max number of bits in the output registers (so2k^2 * 2^{n + 2*m_in} <= 2^{m_out}
)
Inputs:
a = a[0] + a[1] u
wherea[i]
is signed overflow representation withk
registers.b = b[0] + b[1] u
whereb[i]
is signed overflow representation withk
registersc = c[0] + c[1] u
wherec[i]
is signed overflow representation withk
registers
Output:
out = out[0] + out[1] u
whereout[i]
is signed overflow representation withk
registersout
is equal toa * b * c
as elements inF_{p^2}
Implementation:
- Calls
SignedFp2MultiplyNoCarry
twice to computea * b
and(a * b) * c
and then appliesFp2Compress
toa * b * c
. - If
a[i][j], b[i][j], c[i][j]
all have absolute value< B
, thenout[i][j]
has absolute value< 4k^2 * (2k-1) * 2^n * B^3
.
Parameters:
m_in
: expected max number of bits in the input registers (soB = 2^{m_in}
)m_out
: expected max number of bits in the output registers (so4k^2 * (2k-1) * 2^{n + 3*m_in} <= 2^{m_out}
)
Inputs:
in
: length2 x k
array of integers
Implements:
- Proves that
0 <= in[i][j] < 2^n
for alli,j
. In other words,in[0], in[1]
are proper BigInt representations.
Input:
in = in[0] + in[1] u
wherein[i]
is signed overflow representation withk
registers
Outputs:
X = X[0] + X[1] u
whereX[i]
is signed overflow representation withceil(overflow / n)
registers in[-2^n, 2^n)
out
:F_{p^2}
elementout = out[0] + out[1] u
such thatin[i] = p * X[i] + out[i]
as integers.
Implements:
- Calls
SignedFpCarryModP
twice. - We do not constrain
out[i] < p
.
Assumptions:
- Input registers have absolute value
< 2^overflow
n + 1 <= overflow < 251
Inputs:
a,b
:F_{p^2}
elements
Output:
out
:F_{p^2}
element such thatout = a * b
inF_{p^2}
Implements:
- Combines
SignedFp2MultiplyNoCarryCompress
andSignedFp2CarryModP
- We do not constrain
out[i] < p
.
Assumptions:
- All BigInts are in proper format, i.e., registers in
[0, 2^n)
2k^2 * 2^{3n} < 2^251
Inputs:
a,b,c
:F_{p^2}
elements
Output:
out
:F_{p^2}
element such thatout = a * b * c
inF_{p^2}
Implements:
- Combines
SignedFp2MultiplyNoCarryCompressThree
andSignedFp2CarryModP
- We do not constrain
out[i] < p
.
Assumptions:
- All BigInts are in proper format, i.e., registers in
[0, 2^n)
4k^2 * (2k-1) * 2^{4n} < 2^251
Input:
in
:F_{p^2}
element
Output:
out
:F_{p^2}
elementout = (p - in[0]) + (p - in[1]) u
soout = -in
inF_{p^2}
Implementation:
- Constrains
0 <= in[0], in[1] <= p
- Calls
FpNegate
twice
Input:
in
:F_{p^2}
element
Output:
out
:F_{p^2}
element equal toin^{-1}
Implementation:
- Precompute witness for
in^{-1}
usingfind_Fp2_inverse
helper function - Constrain
out * in == 1
inF_{p^2}
usingFp2Multiply
Assumptions:
2k^2 * 2^{3n} < 2^251
Inputs:
a = a[0] + a[1] u
wherea[i]
are signed overflow representations withk
registersb = b[0] + b[1] u
whereb[i]
are signed overflow representations withk
registers
Output:
out
:F_{p^2}
element equal toa / b
inF_{p^2}
.
Assumptions:
- Registers of
a
have absolute value< 2^overflowa
- Registers of
b
have absolute value< 2^overflowb
k + ceil(overflowa / n) <= 50
2k + ceil(overflowb / n) <= 50
overflowa < 250
2k^2 * 2^{2n + overflowb} < 2^250
Input:
in
:F_{p^2}
element
Output:
out
:F_{p^2}
element equal to conjugate ofin
out = in[0] - in[1] u
Input:
in
:F_{p^2}
element
Output:
out
:F_{p^2}
element equal toin^{p^power}
Implements:
- Conjugates
in
ifpower
is odd,out = in
ifpower
is even.
Assumption:
p = 3 (mod 4)
so thata - b u = (a + b u)^p
This is a proof of computation of sgn0
as described in the IRTF draft.
Input:
in
:F_{p^2}
element
Output:
out = sgn0(in)
is either0
or1
Implementation:
sgn0(in) = sgn0(in[0]) || ( in[0] == 0 && sgn0(in[1]) )
- Calls
FpSgn0
twice, in the process constrainsin[0], in[1] < p
Input:
in
:F_{p^2}
element
Output:
out = (in == 0)
Implementation:
- Constrains
in[0], in[1] < p
and then checks ifin[0] == 0 && in[1] == 0
.
Input:
a, b
:F_{p^2}
elements
Output:
out = (a == b)
Implementation:
- Constrains
a[i], b[i] < p
and then checks ifa[i] == b[i]
as BigInts fori=0,1
fp12.circom
contains templates for operating on elements of F_{p^12}
. See Fp12 element for a reminder on how an element of F_{p^12} is represented. Unless explicitly stated, we do not constrain the corresponding F_p
elements to be < p
.
This circuit computes power
applications of the Frobenius map (i.e., raising to p
-th power). It is specialized to p = q
the BLS12-381 base field modulus, due to the need to precompute Frobenius coefficients.
Input:
in
:F_{p^12}
element
Output:
out
:F_{p^12}
element equal toin^{p^power}
Implementation:
- We follow the methodology from this paper and @noble/bls12-381
- We load values for
FP12_FROBENIUS_COEFFICIENTS
precomputed in Python.
Assumption:
- Assume
p = 1 (mod 6)
Inputs:
a
: BigInt in signed overflow representation withka
registers.b = sum_{i=0}^5 sum_{j=0}^1 b[i][j] w^i u^j
whereb[i][j]
is signed overflow representation withkb
registers
Output:
out = sum_{i=0}^5 sum_{j=0}^1 out[i][j] w^i u^j
whereout[i][j]
is signed overflow representation withka + kb - 1
registersout = a * b
as12
-dimensional vector with integer coefficients
Implementation:
- Uses
BigMultShortLongUnequal
to multiplyout[i][j] = a * b[i][j]
without carries. - If input registers all have absolute value
< B
, thenout[i][j]
has absolute value< min(ka, kb) * B^2
.
Assumption:
- Assume
min(ka, kb) * B^2 < 2^252
.
Parameter m_out
is passed when calling template with the expected max number of bits in the output registers.
Calls SignedFp12ScalarMultiplyNoCarryUnequal(n, k, k, m_out)
.
Inputs:
a = a[0] + a[1] u
wherea[i]
is signed overflow representation withka
registers.b = sum_{i=0}^5 sum_{j=0}^1 b[i][j] w^i u^j
whereb[i][j]
is signed overflow representation withkb
registers
Output:
out = sum_{i=0}^5 sum_{j=0}^1 out[i][j] w^i u^j
whereout[i][j]
is signed overflow representation withka + kb - 1
registersout = a * b
inF_{p^12}
as overflow representations
Implementation:
- Multiplies
out[i] = a * b[i]
as inSignedFp2MultiplyNoCarry
usingu^2 = -1
. - If input registers all have absolute value
< B
, thenout[i][j]
has absolute value< 2*min(ka, kb) * B^2
.
Assumption:
- Assume
2*min(ka, kb) * B^2 < 2^252
.
Parameter m_out
is passed when calling template with the expected max number of bits in the output registers.
Calls SignedFp12Fp2MultiplyNoCarryUnequal(n, k, k, m_out)
.
Inputs:
a = sum_{i=0}^5 sum_{j=0}^1 a[i][j] w^i u^j
wherea[i][j]
is signed overflow representation withka
registersb = sum_{i=0}^5 sum_{j=0}^1 b[i][j] w^i u^j
whereb[i][j]
is signed overflow representation withkb
registers
Output:
out = sum_{i=0}^5 sum_{j=0}^1 out[i][j] w^i u^j
whereout[i][j]
is signed overflow representation withka + kb - 1
registersout = a * b
inF_{p^12}
as overflow representations
Implementation:
- Write
a = a[][0] + a[][1] u
andb = b[][0] + b[][1] u
. - Prove computation of
a * b = (a[][0] * b[][0] - a[][1] * b[][1]) + (a[][0] * b[][1] + a[][1] * b[][0]) u
using identityu^2 = -1
.- Prove computation of
a[][i] * b[][j]
as polynomials in two variablesw, X
usingBigMultShortLong2DUnequal
whereX
is variable for2^n
.
- Prove computation of
- Result is polynomial of degree
10
inw
and degreeka + kb - 2
inX
. - Use identity
w^6 = 1 + u
to turn into degree5
polynomial inw
- If input registers all have absolute value
< B
, thenout[i][j]
has absolute value< 18*min(ka, kb) * B^2
.
Assumption:
- Assume
18*min(ka, kb) * B^2 < 2^252
.
Parameter m_out
is passed when calling template with the expected max number of bits in the output registers.
Calls SignedFp12MultiplyNoCarryUnequal(n, k, k, m_out)
Inputs:
in = sum_{i=0}^5 sum_{j=0}^1 in[i][j] w^i u^j
wherein[i][j]
is signed overflow representation withk + m
registers
Outputs:
out = sum_{i=0}^5 sum_{j=0}^1 out[i][j] w^i u^j
whereout[i][j]
is signed overflow representation withk
registers
Implements:
- Calls
PrimeReduce
12
times. - If all input registers have absolute value
< B
, then output registers have absolute value< (m+1) * 2^n * B
.
Assumption:
(m+1) * 2^n * B < 2^252
Inputs:
a = sum_{i=0}^5 sum_{j=0}^1 a[i][j] w^i u^j
wherea[i][j]
is signed overflow representation withk
registersb = sum_{i=0}^5 sum_{j=0}^1 b[i][j] w^i u^j
whereb[i][j]
is signed overflow representation withk
registers
Output:
out = sum_{i=0}^5 sum_{j=0}^1 out[i][j] w^i u^j
whereout[i][j]
is signed overflow representation withk
registersout = a * b
inF_{p^12}
as overflow representations
Implementation:
- Combines
SignedFp12MultiplyNoCarry
andFp12Compress
. - If all input registers have absolute value
< B
, then output registers have absolute value< 18k^2 * 2^n * B^2
Assumption:
18k^2 * 2^n * B^2 < 2^252
Inputs:
in = sum_{i=0}^5 sum_{j=0}^1 in[i][j] w^i u^j
wherein[i][j]
is signed overflow representation withk
registers
Outputs:
X = sum_{i=0}^5 sum_{j=0}^1 X[i][j] w^i u^j
whereX[i][j]
is signed overflow representation withceil(overflow / n)
registers in[-2^n, 2^n)
out
: properF_{p^12}
elementin = p * X + out
inZ[u,w]/(u^2 + 1, w^6 - (1+u))
.
Implements:
- Calls
SignedFpCarryModP
12
times. - We do not constrain
out[i][j] < p
.
Assumptions:
- Input registers have absolute value
< 2^overflow
n + 1 <= overflow < 251
Inputs:
a,b
:F_{p^12}
elements
Output:
out
:F_{p^12}
element such thatout = a * b
inF_{p^12}
Implements:
- Combines
SignedFp12MultiplyNoCarryCompress
andSignedFp12CarryModP
- We do not constrain
out[i][j] < p
.
Assumptions:
- All BigInts are in proper format, i.e., registers in
[0, 2^n)
18k^2 * 2^{3n} < 2^251
Input:
in
:F_{p^12}
element
Output:
out
:F_{p^12}
element equal toin^{-1}
Implementation:
- Precompute witness for
in^{-1}
usingfind_Fp12_inverse
helper function - Constrain
out * in == 1
inF_{p^12}
usingFp12Multiply
Assumptions:
18k^2 * 2^{3n} < 2^251
field_elements_func.circom
contains helper functions for witness generation involving field operations in F_p, F_{p^2}, F_{p^12}
. Unless otherwise specified, all representations are in proper BigInt format with k
registers of bit size n
, and corresponding F_p
elements are < p
.
Parameter:
a
:F_p
element
Output:
- Returns
a % 2
This is never used anywhere. Did not empirically lead to faster witness generation times versus Fermat's Little Theorem.
Parameter:
num
:F_p
element
Output:
- Returns
num^{-1}
asF_p
element using extended Euclidean algorithm.
Parameter:
a
: BigInt in signed overflow representation withk
registers
Output:
- Return
out
as length2 x 50
array out[0]
hasm
registers in range[-2^n, 2^n)
out[1]
isF_p
element withk
registers,0 <= out[1] < p
a = p * out[0] + out[1]
soout[1] = a (mod p)
Assumptions:
- Assume actual integer value of
a
has absolute value< 2^{n*(k+m)}
k + m <= 50
Parameter:
a
: length2 x k
array witha[i]
in signed overflow representation withk
registers
Output:
- Return
out
as length2 x 2 x 50
array out[i] = a[i] (mod p)
by callingget_signed_Fp_carry_witness
twice
Assumptions:
- Assume actual integer value of
a[i]
has absolute value< 2^{n*(k+m)}
k + m <= 50
Parameter:
a
:F_{p^2}
element
Output:
- Returns
sgn0(a[0]) || (a[0] == 0 && sgn0(a[1]))
Parameters:
a,b
:F_{p^2}
elements
Output:
- Return
a * b
as properF_{p^2}
element
Parameters:
a,b
:F_{p^2}
elements
Output:
- Return
a + b
as properF_{p^2}
element
Parameters:
a,b
:F_{p^2}
elements
Output:
- Return
a - b
as properF_{p^2}
element
Parameters:
a
:F_{p^2}
elemente
: proper BigInt representation with2k
registers
Output:
- Return
a^e
as properF_{p^2}
element
Implementation:
- Small optimization to compute bit length of
e
first before running square-and-multiply loop on the bit length.
Assumption:
- Assume
k * n <= 400
Parameters:
a,b
:F_{p^2}
elements
Output:
- Returns
a == b
This is a macro.
Parameter:
a = a[0] + a[1] u
witha[i]
signed overflow representations.
Output:
- Returns
a * (XI0 + u)
inZ[u]/(u^2 + 1)
.
Parameters:
a,b
:F_{p^12}
elements
Output:
- Returns
a + b
as properF_{p^12}
element
Parameters:
a,b
:F_{p^12}
elements
Output:
- Returns
a - b
as properF_{p^12}
element
Parameters:
a,b
:F_{p^12}
elements
Output:
- Returns
a * b
as properF_{p^12}
element
Parameters:
a
:F_{p^2}
element
Output:
- Returns
a^{-1}
as properF_{p^2}
element - Uses fact that
(a + b u)^{-1} = (a^2 + b^2)^{-1} * (a - b u)
and reduces to compute anF_p
inverse.
This is only used as an intermediary to find inverses in F_{p^12}
.
Parameters:
a0, a1, a2
:F_{p^2}
elements- Consider
a = a0 + a1 v + a2 v^2
asF_{p^6}
element, wherev = w^2
andv^3 = 1 + u
.
Output:
- Returns
a^{-1}
inF_{p^6}
as a properF_{p^12}
representation (length6 x 2 x k
array) - Computed by solving a system of equations with
F_{p^2}
coefficients.
Parameters:
a
:F_{p^12}
element
Output:
- Return
a^{-1}
as properF_{p^12}
element - Write
a = a0 + a1 w
and use fact that(a0 + a1 w) * (a0 - a1 w) = a0^2 - a1^2 v
is an element inF_{p^6}
, wherev = w^2
, to reduce to finding inverses inF_{p^6}
.
curve.circom
contains circuits for operations on F_p
points of an elliptic curve. Most of the circuits work for an arbitrary elliptic curve E
in short Weierstrass form y^2 = x^3 + a x + b
where a,b
are "short" integers, i.e., < 2^n
. For optimization purposes and simplicity, a few circuits only work for curves of the form y^2 = x^3 + b
(i.e., a = 0
), but can be easily modified to work in the case a != 0
if further need arises.
See Point in E(F_p)
for a reminder on how we represent points in E(F_p)
. Unless otherwise specificied, all BigInts use k
registers of bit size n
. Unless explicitly stated, we do not constrain a point in E(F_p)
to actually lie on the curve.
Prove that three points (x_0, y_0), (x_1, y_1), (x_2, -y_2)
are co-linear.
Input:
in
: length3 x 2 x k
array within[i][j]
element ofF_p
Implementation:
- Let
in[i] = (x_i, y_i)
. - Proves that
(y_0 + y_2) * (x_1 - x_0) - (y_1 - y_0) * (x_0 - x_2) == 0 (mod p)
. (y_0 + y_2) * (x_1 - x_0) - (y_1 - y_0) * (x_0 - x_2)
is computed "without carry" usingBigMultShortLong
and then compressed usingPrimeReduce
.- Use
SignedCheckCarryModToZero
to prove congruence to0 (mod p)
.
Assumption:
in[0] != in[1]
- Requires
8k^2 * 2^{3n} < 2^251
to prevent overflow
Prove that a point (x,y)
lies on an elliptic curve y^2 = x^3 + a x + b
.
Input:
in
: length2 x k
array representing twoF_p
elements
Implementation:
- Let
in = (x,y)
. - Proves that
x^3 + a x + b - y^2 = 0 (mod p)
. - Computes
x^3 + a x + b - y^2
without carries usingBigMultShortLong
and then compresses usingPrimeReduce
. - Use
SignedCheckCarryModToZero
to prove congruence to0 (mod p)
.
Assumptions:
- Curve parameters
0 <= a,b < 2^n
- Requires
(k^2 + 1) * (2k-1) * 2^{4n} < 2^251
to prevent overflow.
Prove that a point (x_3, -y_3)
lies on the tangent line to curve E : y^2 = x^3 + a x + b
at a point (x_1, y_1)
. Does not check that (x_1, y_1)
is on the curve. Note that the circuit does not require b
.
Input:
in
: length2 x 2 x k
array representing fourF_p
elements
Implementation:
- Let
in[0] = (x_1, y_1)
andin[1] = (x_3, y_3)
. - Proves that
2y_1 (y_1 + y_3) = (3 x_1^2 + a)(x_1 - x_3)
.
Assumptions:
- Curve parameter
0 <= a < 2^n
in[0]
is onE(F_p)
- Require
(3k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 5k(2k - 1) <= 2^n
Verify the computation of addition of two points P1 + P2
on an elliptic curve E : y^2 = x^3 + a1 x + b1
assuming that P1 != P2
and P1 != -P2
. We do not verify these assumptions and do not check that P1, P2
actually lie on the curve. Note that the circuit does not require knowledge of curve parameters a1, b1
.
Inputs:
a
: point onE(F_p)
b
: point onE(F_p)
Output:
out
: point onE(F_p)
equal toa + b
using elliptic curve addition.
Implementation:
- Let
a = (x_1, y_1), b = (x_2, y_2), out = (x_3, y_3)
. - Precomputes witness for
out
and then proves that: (x_1 + x_2 + x_3)*(x_2 - x_1)^2 = (y_2 - y_1)^2
(y_1 + y_3)*(x_2 - x_1) = (y_2 - y_1)*(x_1 - x_3)
usingPointOnLine
Assumptions:
a, b
are onE(F_p)
x_1 != x_2
, i.e.,a != b
anda != -b
.- Require
(3k^2(2k-1) + 1) * 2^{4n} < 2^251
to prevent overflow. k(2k-1) <= 2^n
Verify the computation of doubling a point on the elliptic curve E : y^2 = x^3 + a x + b
. We do not check that the point actually lies on the curve.
Inputs:
in
: point onE(F_p)
Output:
out
: point onE(F_p)
equal to2 * in
using elliptic curve doubling formula.
Implementation:
- Let
in = (x_1, y_1), out = (x_3, y_3)
. - Precomputes witness for
out
and then proves that: (x_3, y_3)
lies onE
usingPointOnCurve
(x_3, y_3)
is on the tangent line toE
at(x_1, y_1)
usingPointOnTangent
x_1 != x_3
: the only points of intersection of the tangent line at(x_1, y_1)
with curveE
are(x_1, y_1)
and(x_3, y_3)
.
Assumptions:
- Curve parameters
0 <= a, b < 2^n
in
lies onE(F_p)
y_1 != 0
, i.e.,in
is not a point of order2
. (Fact: BLS12-381 has no points of order2
.)- Require
(3k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 5k(2k - 1) <= 2^n
Verify the computation of addition of two points P1 + P2
on an elliptic curve E : y^2 = x^3 + a1 x + b1
without any assumptions on P1, P2
. Moreover, we allow P1, P2
to be the point at infinity.
We do not check that P1, P2
actually lie on the curve. Due to the deterministic nature of circom
, this circuit costs the sum of the constraints of EllipticCurveAddUnequal
and EllipticCurveDouble
.
Inputs:
a
: point onE(F_p)
aIsInfinity
:1
if we should interpreta
as point at infinity;0
otherwiseb
: point onE(F_p)
bIsInfinity
:1
if we should interpretb
as point at infinity;0
otherwise
Output:
out
: point onE(F_p)
equal toa + b
using elliptic curve addition.isInfinity
:1
ifa + b
is point at infinity;0
otherwise- If
a,b
are onE(F_p)
(even ifaIsInfinity == 1
), thenout
is onE(F_p)
(even ifisInfinity == 1
)
Implementation:
- Proves computations of both
EllipticCurveAddUnequal
andEllipticCurveDouble
- Case analysis of
a = b
,a = -b
,a, b
equal point at infinity
Assumptions:
a, b
are onE(F_p)
E(F_p)
has no points of order2
- Require
(3k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 5k(2k - 1) <= 2^n
Proves computation of scalar multiplication [x]P
on elliptic curve of form E : y^2 = x^3 + b
using the double-and-add method.
Parameter:
x
: integer in[0, 2^250)
to scalar multiply by
Inputs:
in
: point onE(F_p)
inIsInfinity
:1
ifin
should be interpreted as point at infinity;0
otherwise
Outputs:
out
: point onE(F_p)
equal to[x]P
whereP = in
isInfinity
:1
ifout
should be interpreted as point at infinity;0
otherwise- Assuming
in
is a point onE(F_p)
(even wheninIsInfinity == 1
),out
is a point onE(F_p)
(even whenisInfinity == 1
).
Implementation:
- Double-and-add method. Uses
EllipticCurveAdd
in the "add" part since we cannot guarantee we are adding two unequal points.
Assumptions:
0 <= x < 2^250
in
is point onE(F_p)
even ifinIsInfinity == 1
E(F_p)
has no points of order2
- Require
(3k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 5k(2k - 1) <= 2^n
Proves computation of scalar multiplication [x]P
on elliptic curve of form E : y^2 = x^3 + b
using the double-and-add method, assuming that P
has order > x
so we never arrive at the point at infinity and we are always adding unequal points.
Parameter:
x
: integer in[0, 2^250)
to scalar multiply by
Inputs:
in
: point onE(F_p)
Outputs:
out
: point onE(F_p)
equal to[x]P
whereP = in
.
Implementation:
- Double-and-add method. Uses
EllipticCurveAddUnequal
in the "add" part because ifP
has order> x
, then[i]P != [j]P
for any0 < i,j <= x
.
Assumptions:
0 <= x < 2^250
in
is point onE(F_p)
of order> x
E(F_p)
has no points of order2
- Require
(3k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 5k(2k - 1) <= 2^n
Proves evaluation of a line through two unequal E(F_p)
points at a E(F_{p^12})
point, evaluated without carries.
Inputs:
P
: twoE(F_p)
pointsP[0], P[1]
Q
: a point inE(F_{p^12})
Output:
out
: an element inF_{p^12}
without[i][j]
in signed overflow representation with2k-1
registers
Implementation:
- Let
P[0] = (x_1, y_1), P[1] = (x_2, y_2)
andQ = (X, Y)
. out = (y_1 - y_2) X + (x_2 - x_1) Y + (x_1 y_2 - x_2 y_1)
- We evaluate
out
usingSignedFp12ScalarMultiplyNoCarry
- If all input registers are in
[0, B)
, then output registers have absolute value< 3k * B^2
Assumptions:
P[0] != P[1]
3k * B^2 < 2^252
Parameter m_out
is the expected max number of bits in the output registers.
Proves evaluation of a tangent line to curve E : y^2 = x^3 + b
through an E(F_p)
point P
at a E(F_{p^12})
point Q
, evaluated without carries.
Inputs:
P
:E(F_p)
pointQ
:E(F_{p^12})
point
Output:
out
: an element inF_{p^12}
without[i][j]
in signed overflow representation with3k-2
registers
Implementation:
- Let
P = (x, y)
andQ = (X, Y)
. out = 3 x^2 (-X + x) + 2 y (Y - y)
- We evaluate
out
usingSignedFp12ScalarMultiplyNoCarry
- If all input registers are in
[0, B)
, then output registers have absolute value< (3k^2 + 2k/B) * B^3
assuming2k <= B
Assumptions:
(3k^2 + 2k/B) * B^3 < 2^252
Proves evaluation of a line through two unequal E(F_p)
points at a E(F_{p^12})
point.
Inputs:
P
: twoE(F_p)
pointsP[0], P[1]
Q
:E(F_{p^12})
point
Output:
out
:F_{p^12}
element equal tol_{P[0], P[1]}(Q)
Implementation:
- Calls
SignedLineFunctionUnequalNoCarry
, then compresses usingFp12Compress
, and finally carries usingSignedFp12CarryModP
Assumptions:
P[0] != P[1]
- Requires
3k^2 * 2^{3n} < 2^251
to prevent overflow.
Proves evaluation of a tangent line to curve E : y^2 = x^3 + b
through an E(F_p)
point P
at a E(F_{p^12})
point Q
.
Inputs:
P
:E(F_p)
pointQ
:E(F_{p^12})
point
Output:
out
:F_{p^12}
element equal tol_{P,P}(Q)
Implementation:
- Calls
SignedLineFunctionEqualNoCarry
, then compresses usingFp12Compress
, and finally carries usingSignedFp12CarryModP
Assumptions:
- Requires
(3k^2(2k-1) + 1) * 2^{4n} < 2^251
to prevent overflow. - Assumes
2k(2k - 1) <= 2^n
Inputs:
g
: element ofF_{p^12}
in signed overflow format withkg
registersP
: twoE(F_p)
pointsQ
:E(F_{p^12})
point
Output:
out
:F_{p^12}
element equal tog * l_{P[0], P[1]}(Q)
Implementation:
- Calls
SignedLineFunctionUnequalNoCarry
to computel_{P[0], P[1]}(Q)
- Calls
SignedFp12MultiplyNoCarryUnequal
to computeg * l_{P[0], P[1]}(Q)
all without carries - Compresses using
Fp12Compress
and finally carries just once usingSignedFp12CarryModP
Assumptions:
P[0] != P[1]
- Requires
3k * min(kg, 2k-1) * 18 * (k + kg - 1) * 2^{overflowg + 3n} < 2^251
to prevent overflow. (In practicekg = k
andoverflowg = n
.)
The point is that l_{P[0], P[1]}(Q)
is quadratic, so we can squeeze in another multiplication before we need to carry. This is used in MillerLoop
.
Proves computation of Miller's algorithm on a curve of the form y^2 = x^3 + b
. Only used for the Tate pairing.
Parameters:
b
: curve parameterx
: integer
Inputs:
in
:F_{p^12}
elementP
:E(F_p)
pointQ
:E(F_{p^12})
point
Outputs:
out
:F_{p^12}
elementxP
:E(F_p)
point equal to[x]P
Implementation:
out = f_x(P, Q)
wheref_i(P,Q)
is defined recursively using Miller's algorithm:f_0(P,Q) = in
f_{i+j}(P,Q) = f_i(P,Q) * f_j(P,Q) * l_{[i]P, [j]P}(Q)
f_x(P, Q)
and[x]P
are computed using the double-and-add method.
Assumptions:
0 <= b < 2^n
0 <= x < 2^250
P
lies onE(F_p)
P
has order> x
andP
is not point at infinity- Requires
(18k)^2 * (2k-1) * 2^{4n} < 2^251
to prevent overflow
Proves computation of Miller's algorithm on the curve BLS12-381 for the Tate pairing.
Inputs:
P
:E(F_p)
pointQ
:E(F_{p^12})
point
Output:
out
:F_{p^12}
element equal tof_r(P, Q)
wherer
is the prime order of torsion in Tate pairing
Implementation:
- Uses the specific form of
r = x^4 - x^2 + 1
wherex
is parameter of BLS12-381, 64-bit integer with low Hamming weight - Calls
MillerLoop
four times
Assumptions:
P
lies onE(F_p)
P
has orderr
(but we do not constrain this) wherer
is primeP
is not point at infinity- Requires
(18k)^2 * (2k-1) * 2^{4n} < 2^251
to prevent overflow
curve_fp2.circom
contains circuits for operations on F_{p^2}
points of an elliptic curve. These circuits are almost entirely parallel to those in curve.circom
(see Elliptic curve templates).
Most of the circuits work for an arbitrary elliptic curve E_2
in short Weierstrass form y^2 = x^3 + a x + b
where a,b
are "short" F_{p^2}
points (e.g., a = a[0] + a[1] u
with 0 <= a[0], a[1] < 2^n
). For optimization purposes and simplicity, a few circuits only work for curves of the form y^2 = x^3 + b
(i.e., a = 0
), but can be easily modified to work in the case a != 0
if further need arises.
See Point in E_2(F_{p^2})
for a reminder on how we represent points in E_2(F_{p^2})
. Unless otherwise specificied, all BigInts use k
registers of bit size n
. Unless explicitly stated, we do not constrain a point in E_2(F_{p^2})
to actually lie on the curve.
Prove that three points (x_0, y_0), (x_1, y_1), (x_2, -y_2)
are co-linear.
Input:
in
: length3 x 2 x 2 x k
array within[i][j]
element ofF_{p^2}
Implementation:
- Let
in[i] = (x_i, y_i)
. - Proves that
(y_0 + y_2) * (x_1 - x_0) - (y_1 - y_0) * (x_0 - x_2) == 0
inF_{p^2}
. (y_0 + y_2) * (x_1 - x_0) - (y_1 - y_0) * (x_0 - x_2)
is computed "without carry" usingBigMultShortLong2D
and then compressed usingPrimeReduce
.- Use
SignedCheckCarryModToZero
to prove congruence to0 (mod p)
.
Assumption:
in[0] != in[1]
- Requires
6k^2 * 2^{3n} < 2^251
to prevent overflow
Prove that a point (x,y)
lies on an elliptic curve y^2 = x^3 + a x + b
.
Parameters:
a,b
: length2
arrays
Input:
in
: length2 x 2 x k
array representing twoF_{p^2}
elements
Implementation:
- Let
in = (x,y)
. - Proves that
x^3 + a x + b - y^2 == 0
inF_{p^2}
. - Computes
x^3 + a x + b - y^2
without carries usingSignedFp2MultiplyNoCarryUnequal
and then compresses usingPrimeReduce
. - Use
SignedCheckCarryModToZero
to prove congruence to0 (mod p)
.
Assumptions:
- Curve parameters
0 <= a[i],b[i] < 2^n
fori=0,1
- Requires
((4k^2(2k-1) + 1) * 2^{4n} < 2^251
to prevent overflow. 2k^2 + 2(2k-1) <= 2^n
Prove evaluation of x^3 + a x + b
for input x
.
Parameters:
a,b
: length2
arrays
Input:
in
:F_{p^2}
element
Output:
out
:F_{p^2}
element equal toin^3 + a * in + b
Assumptions:
- Curve parameters
0 <= a[i],b[i] < 2^n
fori=0,1
- Requires
(4k^2(2k-1) + 1) * 2^{4n} < 2^251
to prevent overflow. 2k - 1 <= 2^n
Prove that a point (x_3, -y_3)
lies on the tangent line to curve E_2 : y^2 = x^3 + a x + b
at a point (x_1, y_1)
. Does not check that (x_1, y_1)
is on the curve. Note that the circuit does not require b
.
Parameter:
a
: length2
array
Input:
in
: length2 x 2 x 2 x k
array representing fourF_{p^2}
elements
Implementation:
- Let
in[0] = (x_1, y_1)
andin[1] = (x_3, y_3)
. - Proves that
2y_1 (y_1 + y_3) = (3 x_1^2 + a)(x_1 - x_3)
inF_{p^2}
.
Assumptions:
- Curve parameters
0 <= a[0], a[1] < 2^n
in[0]
is onE_2
- Require
(12k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 12k(2k - 1) <= 2^n
Verify the computation of addition of two points P1 + P2
on an elliptic curve E_2 : y^2 = x^3 + a2 x + b2
assuming that P1 != P2
and P1 != -P2
. We do not verify these assumptions and do not check that P1, P2
actually lie on the curve. Note that the circuit does not require knowledge of curve parameters a2, b2
.
Inputs:
a
: point onE_2(F_{p^2})
b
: point onE_2(F_{p^2})
Output:
out
: point onE_2(F_{p^2})
equal toa + b
using elliptic curve addition.
Implementation:
- Let
a = (x_1, y_1), b = (x_2, y_2), out = (x_3, y_3)
. - Precomputes witness for
out
and then proves that: (x_1 + x_2 + x_3)*(x_2 - x_1)^2 = (y_2 - y_1)^2
inF_{p^2}
(y_1 + y_3)*(x_2 - x_1) = (y_2 - y_1)*(x_1 - x_3)
usingPointOnLineFp2
Assumptions:
a, b
are onE_2
x_1 != x_2
, i.e.,a != b
anda != -b
.- Require
(12k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 2k(2k - 1) <= 2^n
Verify the computation of doubling a point on the elliptic curve E_2 : y^2 = x^3 + a x + b
. We do not check that the point actually lies on the curve.
Parameters:
a,b
: length2
arrays
Inputs:
in
: point onE_2(F_{p^2})
Output:
out
: point onE_2(F_{p^2})
equal to2 * in
using elliptic curve doubling formula.
Implementation:
- Let
in = (x_1, y_1), out = (x_3, y_3)
. - Precomputes witness for
out
and then proves that: (x_3, y_3)
lies onE_2
usingPointOnCurveFp2
(x_3, y_3)
is on the tangent line toE_2
at(x_1, y_1)
usingPointOnTangentFp2
x_1 != x_3
: the only points of intersection of the tangent line at(x_1, y_1)
with curveE_2
are(x_1, y_1)
and(x_3, y_3)
.
Assumptions:
- Curve parameters
0 <= a[i], b[i] < 2^n
fori = 0,1
. in
lies onE_2
y_1 != 0
, i.e.,in
is not a point of order2
. (Fact: BLS12-381 twistE_2
has no points of order2
.)- Require
(12k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 12k(2k - 1) <= 2^n
Verify the computation of addition of two points P1 + P2
on an elliptic curve E_2 : y^2 = x^3 + a2 x + b2
without any assumptions on P1, P2
. Moreover, we allow P1, P2
to be the point at infinity.
We do not check that P1, P2
actually lie on the curve. Due to the deterministic nature of circom
, this circuit costs the sum of the constraints of EllipticCurveAddUnequalFp2
and EllipticCurveDoubleFp2
.
Inputs:
a
: point onE_2(F_{p^2})
aIsInfinity
:1
if we should interpreta
as point at infinity;0
otherwiseb
: point onE_2(F_{p^2})
bIsInfinity
:1
if we should interpretb
as point at infinity;0
otherwise
Output:
out
: point onE_2(F_{p^2})
equal toa + b
using elliptic curve addition.isInfinity
:1
ifa + b
is point at infinity;0
otherwise- If
a,b
are onE_2
(even ifaIsInfinity == 1
), thenout
is onE_2
(even ifisInfinity == 1
)
Implementation:
- Proves computations of both
EllipticCurveAddUnequalFp2
andEllipticCurveDoubleFp2
- Case analysis of
a = b
,a = -b
,a, b
equal point at infinity
Assumptions:
a, b
are onE_2
E_2(F_{p^2})
has no points of order2
- Require
(12k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 12k(2k - 1) <= 2^n
Proves computation of scalar multiplication [x]P
on elliptic curve of form E_2 : y^2 = x^3 + b
using the double-and-add method.
Parameter:
b
: length2
arrayx
: integer in[0, 2^250)
to scalar multiply by
Inputs:
in
: point onE_2(F_{p^2})
inIsInfinity
:1
ifin
should be interpreted as point at infinity;0
otherwise
Outputs:
out
: point onE_2(F_{p^2})
equal to[x]P
whereP = in
isInfinity
:1
ifout
should be interpreted as point at infinity;0
otherwise- Assuming
in
is a point onE_2
(even wheninIsInfinity == 1
),out
is a point onE_2
(even whenisInfinity == 1
). - Require
(12k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 12k(2k - 1) <= 2^n
Implementation:
- Double-and-add method. Uses
EllipticCurveAddFp2
in the "add" part since we cannot guarantee we are adding two unequal points.
Assumptions:
0 <= x < 2^250
in
is point onE_2
even ifinIsInfinity == 1
E_2(F_{p^2})
has no points of order2
Proves computation of scalar multiplication [x]P
on elliptic curve of form E_2 : y^2 = x^3 + b
using the double-and-add method, assuming that P
has order > x
so we never arrive at the point at infinity and we are always adding unequal points.
Parameter:
b
: length2
arrayx
: integer in[0, 2^250)
to scalar multiply by
Inputs:
in
: point onE_2(F_{p^2})
Outputs:
out
: point onE_2(F_{p^2})
equal to[x]P
whereP = in
.
Implementation:
- Double-and-add method. Uses
EllipticCurveAddUnequalFp2
in the "add" part because ifP
has order> x
, then[i]P != [j]P
for any0 < i,j <= x
.
Assumptions:
0 <= x < 2^250
in
is point onE_2
of order> x
E_2(F_{p^2})
has no points of order2
- Require
(12k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 12k(2k - 1) <= 2^n
Proves evaluation of a line through two unequal E_2(F_{p^2})
points at a E(F_p)
point, evaluated without carries. To give this circuit meaning, we implicitly assume that E_2
is a sextic twist of E
, and we are embedding E_2(F_{p^2})
into E(F_{p^12})
using the twist homomorphism Psi(x,y) = (x/w^2, y/w^3)
.
Inputs:
P
: twoE_2(F_{p^2})
pointsP[0], P[1]
Q
:E(F_p)
point
Output:
out
: an element inF_{p^12}
without[i][j]
in signed overflow representation with2k-1
registers
Implementation:
- Let
P[0] = (x_1, y_1), P[1] = (x_2, y_2)
andQ = (X, Y)
. out = w^3 (y_1 - y_2) X + w^4 (x_2 - x_1) Y + w (x_1 y_2 - x_2 y_1)
- We evaluate
out
usingSignedFp2MultiplyNoCarry
and optimize using the knowledge that1, w, ..., w^5
is aF_{p^2}
-basis forF_{p^12}
. - If all input registers are in
[0, B)
, then output registers have absolute value< 2k * B^2
Assumptions:
P[0] != P[1]
2k * B^2 < 2^252
Parameter m_out
is the expected max number of bits in the output registers.
Proves evaluation of a tangent line to curve E_2 : y^2 = x^3 + b
through an E_2(F_{p^2})
point P
at a E(F_p)
point Q
, evaluated without carries. To give this circuit meaning, we implicitly assume that E_2
is a sextic twist of E
, and we are embedding E_2(F_{p^2})
into E(F_{p^12})
using the twist homomorphism Psi(x,y) = (x/w^2, y/w^3)
.
Inputs:
P
:E_2(F_{p^2})
pointQ
:E(F_p)
point
Output:
out
: an element inF_{p^12}
without[i][j]
in signed overflow representation with3k-2
registers
Implementation:
- Let
P = (x, y)
andQ = (X, Y)
. out = (3x^3 - 2y^2) + w^2 (-3 x^2 X) + w^3 (2 y Y)
- We evaluate
out
usingSignedFp2MultiplyNoCarryUnequal
and optimize using the knowledge that1, w, ..., w^5
is aF_{p^2}
-basis forF_{p^12}
. - If all input registers are in
[0, B)
, then output registers have absolute value< (12k^2 + 4k/B) * B^3
Assumptions:
P
is onE_2
(12k^2 + 4k/B) * B^3 < 2^252
Proves evaluation of a line through two unequal E_2(F_{p^2})
points at a E(F_p)
point. To give this circuit meaning, we implicitly assume that E_2
is a sextic twist of E
, and we are embedding E_2(F_{p^2})
into E(F_{p^12})
using the twist homomorphism Psi(x,y) = (x/w^2, y/w^3)
.
Inputs:
P
: twoE_2(F_{p^2})
pointsP[0], P[1]
Q
:E(F_p)
point
Output:
out
:F_{p^12}
element equal tol_{Psi(P[0]), Psi(P[1])}(Q)
Implementation:
- Calls
SignedLineFunctionUnequalNoCarryFp2
, then compresses usingFp12Compress
, and finally carries usingSignedFp12CarryModP
Assumptions:
P[0] != P[1]
- Requires
2k^2 * 2^{3n} < 2^251
to prevent overflow.
Proves evaluation of a tangent line to curve E_2 : y^2 = x^3 + b
through an E_2(F_{p^2})
point P
at a E(F_p)
point Q
. To give this circuit meaning, we implicitly assume that E_2
is a sextic twist of E
, and we are embedding E_2(F_{p^2})
into E(F_{p^12})
using the twist homomorphism Psi(x,y) = (x/w^2, y/w^3)
.
Inputs:
P
:E_2(F_{p^2})
pointQ
:E(F_p)
point
Output:
out
:F_{p^12}
element equal tol_{Psi(P), Psi(P)}(Q)
Implementation:
- Calls
SignedLineFunctionEqualNoCarryFp2
, then compresses usingFp12Compress
, and finally carries usingSignedFp12CarryModP
Assumptions:
P
is onE_2
- Requires
(12k^2(2k - 1) + 1) * 2^{4n} < 2^251
to prevent overflow. 4k(2k-1) <= 2^n
Inputs:
g
: element ofF_{p^12}
in signed overflow format withkg
registersP
: twoE_2(F_{p^2})
pointsQ
:E(F_p)
point
Output:
out
:F_{p^12}
element equal tog * l_{Psi(P[0]), Psi(P[1])}(Q)
Implementation:
- Calls
SignedLineFunctionUnequalNoCarryFp2
to computel_{Psi(P[0]), Psi(P[1])}(Q)
- Calls
SignedFp12MultiplyNoCarryUnequal
to computeg * l_{Psi(P[0]), Psi(P[1])}(Q)
all without carries - Compresses using
Fp12Compress
and finally carries just once usingSignedFp12CarryModP
Assumptions:
P[0] != P[1]
- Requires
12k * min(kg, 2k-1) * 18 * (k + kg - 1) * 2^{overflowg + 3n} < 2^251
to prevent overflow. (In practicekg = k
andoverflowg = n
.)
The point is that l_{Psi(P[0]), Psi(P[1])}(Q)
is quadratic, so we can squeeze in another multiplication before we need to carry. This is used in MillerLoopFp2
.
Proves computation of Miller's algorithm on a curve of the form y^2 = x^3 + b
. Used for the optimal Ate pairing. We assume that E_2
is a sextic twist of E
, and we are embedding E_2(F_{p^2})
into E(F_{p^12})
using the twist homomorphism Psi(x,y) = (x/w^2, y/w^3)
.
Parameters:
b
: length2
arrayx
: integer
Inputs:
P
:E_2(F_{p^2})
pointQ
:E(F_p)
point
Outputs:
out
:F_{p^12}
elementxP
:E(F_p)
point equal to[x]P
Implementation:
out = f_x(P, Q)
wheref_i(P,Q)
is defined recursively using Miller's algorithm:f_0(P,Q) = 1
f_{i+j}(P,Q) = f_i(P,Q) * f_j(P,Q) * l_{Psi([i]P), Psi([j]P)}(Q)
f_x(P, Q)
and[x]P
are computed using the double-and-add method.
Assumptions:
0 <= b[0], b[1] < 2^n
0 <= x < 2^250
P
is onE_2
P
has order> x
andP
is not point at infinity- Requires
(18k)^2 * (2k-1) * 2^{4n} < 2^251
to prevent overflow
Proves computation of running Miller's algorithm twice on a curve of the form y^2 = x^3 + b
. Used for BLS signatures. We assume that E_2
is a sextic twist of E
, and we are embedding E_2(F_{p^2})
into E(F_{p^12})
using the twist homomorphism Psi(x,y) = (x/w^2, y/w^3)
.
Parameters:
b
: length2
arrayx
: integer
Inputs:
P
: twoE_2(F_{p^2})
pointsP[0], P[1]
Q
: twoE(F_p)
pointsQ[0], Q[1]
Outputs:
out
:F_{p^12}
element equal tof_x(P[0], Q[0]) * f_x(P[1], Q[1])
Implementation:
out = f_x(P[0], Q[0]) * f_x(P[1], Q[1])
wheref_i(P,Q)
is defined recursively using Miller's algorithm:f_0(P,Q) = 1
f_{i+j}(P,Q) = f_i(P,Q) * f_j(P,Q) * l_{Psi([i]P), Psi([j]P)}(Q)
- We use the double-and-add method with an optimization that we only need to keep track of the product
f_i(P[0], Q[0]) * f_i(P[1], Q[1])
. This means we only need to square once inF_{p^12}
instead of twice.
Assumptions:
0 <= b[0], b[1] < 2^n
0 <= x < 2^250
P[0], P[1]
are onE_2
P[i]
has order> x
andP[i]
is not point at infinity fori = 0,1
.- Requires
(18k)^2 * (2k-1) * 2^{4n} < 2^251
to prevent overflow
final_exp.circom
contains circuits for exponentiating an F_{p^12}
element to the (p^12 - 1)/r
power, which is necessary for the Tate pairing and optimal Ate pairing. The exponentiation can be separated into two parts: an easy part utilizing Frobenius maps and a hard part.
For the hard part we use the approach of Hayashida-Hayasaka-Teruya. The hard part involves exponentiating an element in the cyclotomic subgroup, and we optimize this by using the optimization for cyclotomic squaring of Karabina.
The cyclotomic subgroup of F_{p^12}
is defined as the subgroup of all elements a
such that a^{q^4 - q^2 + 1} = 1
, where q^4 - q^2 + 1
is the 12th cyclotomic polynomial.
Theorem 3.1 of Karabina shows that an element in the cyclotomic subgroup can be recovered (decompressed) from data in a compressed format. This circuit verifies the compression step.
Input:
in
:F_{p^12}
element
Output:
out
: fourF_{p^2}
elements
Implementation:
- Let
in = g0 + g2 w + g4 w^2 + g1 w^3 + g3 w^4 + g5 w^5
whereg_i
areF_{p^2}
elements. out = [g2, g3, g4, g5]
Assumption:
in
is in the cyclotomic subgroup
This circuit verifies the decompression step mentioned above.
Input:
in
: fourF_{p^2}
elements
Output:
out
:F_{p^12}
element
Implementation:
- Let
in = [g2, g3, g4, g5]
- If
g2 != 0
:(g5^2 * (1+u) + 3 g4^2 - 2 g3)/(4g2)
(2 g1^2 + g2 * g5 - 3 g3*g4) * (1+u) + 1
- If
g2 == 0
:g1 = (2 g4 * g5)/g3
g0 = (2 g1^2 - 3 g3 * g4) * (1+u) + 1
- Uses
SignedFp2Divide
out = [g0, g2, g4, g1, g3, g5]
Assumptions:
- Require
(10k^2 + 1) * 2^{3n} < 2^250
to prevent overflow
Theorem 3.2 of Karabina gives a formula for how to square a cyclotomic element in its compressed form. This circuit verifies the computation where no carries are performed.
Input:
in
: fourF_{p^2}
elements
Output:
out
: fourF_{p^2}
elements with BigInts in signed overflow representation with2k - 1
registers
Implementation:
- Let
c = 1 + u
h2 = 2(g2 + 3*c*B_45)
h3 = 3(A_45 - (c+1)B_45) - 2g3
h4 = 3(A_23 - (c+1)B_23) - 2g4
h5 = 2(g5 + 3B_23)
A_ij = (g_i + g_j)(g_i + c g_j)
B_ij = g_i g_j
out = [h2, h3, h4, h5]
- All operations are done without carrying.
- If all input registers have absolute value
< B
, then output registers have absolute value< (54k + 2/B) * B^2
Assumption:
(54k + 2/B) * B^2 < 252
Verifies computation of cyclotomic squaring in compressed form with carries.
Input:
in
: fourF_{p^2}
elements
Output:
out
: fourF_{p^2}
elements
Implementation:
- Calls
SignedFp12CyclotomicSquareNoCarry
and then four calls toFp2Compress
andSignedFp2CarryModP
Assumption:
- Requires
(54k^2 + 1) * 2^{3n} < 251
to prevent overflow.
Circuit verifies computation of exponentiation of cyclotomic element to e
power.
Parameter:
e
: positive integer
Input:
in
:F_{p^12}
element
Output:
out
:F_{p^12}
element equal toin^e
Implementation:
- We exponentiate using the square-and-multiply method.
- Compress
in
at the beginning and compute squares in compressed format. - Decompress and multiply at the bits equal to
1
ine
Assumptions:
0 < e < BabyJubJubPrime
in
is in the cyclotomic subgroup- Require
(10k^2 + 1) * 2^{3n} < 2^250
to prevent overflow
This circuit is specialized to BLS12-381 as it uses the parameter x
generating BLS curves. It uses the approach of Hayashida-Hayasaka-Teruya, top of p. 14.
Input:
in
:F_{p^12}
element
Output:
out
:F_{p^12}
element equal toin^{(p^4 - p^2 + 1)/r}
Assumptions:
0 < e < BabyJubJubPrime
in
is in the cyclotomic subgroup- Require
(10k^2 + 1) * 2^{3n} < 2^250
to prevent overflow
Input:
in
:F_{p^12}
element
Output:
out
:F_{p^12}
element equal toin^{(p^6 - 1)(p^2+1)}
Implementation:
- Uses
Fp12FrobeniusMap
Assumption:
18k^2 * 2^{3n} < 2^251
This circuit is specialized to BLS12-381.
Input:
in
:F_{p^12}
element
Output:
out
:F_{p^12}
element equal toin^{(p^12 - 1)/r}
Implementation:
- Combines
FinalExpEasyPart
andFinalExpHardPart
.
Assumption:
(10k^2 + 1) * 2^{3n} < 2^250
bls12_381_hash_to_G2.circom
contains circuits for proving computations that hash a message to the subgroup G2
of E_2(F_{p^2})
, the twist of BLS12-381. These are in accordance with the IRTF Internet draft. The implementation is rather technical so we refer to the code for details.
bls12_381_hash_to_G2.circom
also contains optimized circuits for proving that input elements lie in the subgroups G1
of BLS12-381 E(F_p)
and G2
of E_2(F_{p^2})
its twist. These use the method of endomorphisms.
Implements steps 2-6 of hash_to_curve as specified in https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#section-3 for BLS12-381.
Input:
in
: twoF_{p^2}
elements
Output:
out
:E_2(F_{p^2})
point that lies in subgroupG2
isInfinity
:1
ifout
should be interpreted as point at infinity;0
otherwise
In practice in = hash_to_field(msg, 2)
for an arbitrary-length byte string msg
, in which case out = hash_to_curve(msg)
.
Input:
in
: pair ofF_{p^2}
elements
Implements:
- Proves that
in
is a point onE_2(F_{p^2})
, the twist of BLS12-381 - Proves that
in
has orderr
, i.e.,in
is in subgroupG2
Input:
in
: pair ofF_p
elements
Implements:
- Proves that
in
is a point on BLS12-381E(F_p)
- Proves that
in
has orderr
, i.e.,in
is in subgroupG1
pairing.circom
contains the circuits for the Tate pairing and optimal Ate pairing, specialized to BLS12-381.
Input:
P
:E(F_p)
elementQ
:E(F_{p^12})
element
Output:
out
:F_{p^12}
element equal to Tate pairinge(P,Q)
Assumption:
P
is onE
and has orderr
Q
is onE
Input:
P
:E_2(F_{p^2})
element whereE_2
is twist of BLS12-381Q
:E(F_p)
element
Output:
out
:F_{p^12}
element equal to optimal Ate pairinge(P,Q)
Assumption:
P
is onE_2
and has orderr
Q
is onE
bls_signature.circom
contains the circuits for BLS signature verification, specialized to BLS12-381.
Circuit to verify BLS signature where public key size is minimized (so public key is in subgroup G1
) and we are given the hash H(m)
of a message as a point in subgroup G2
.
Inputs:
pubkey
:E(F_p)
pointsignature
:E_2(F_{p^2})
pointHm
:E_2(F_{p^2})
point
Output:
out
:1
if valid BLS signature;0
otherwise
Implementation:
- Checks if
e(g1, signature) == e(pubkey, H(m))
by checking ife(g1, signature) * e(pubkey, -H(m)) == 1
wheree(,)
is the optimal Ate pairing,g1
is a fixed public generator ofG1
. - Computes
e(g1, signature) * e(pubkey, -H(m))
by callingMillerLoopFp2Two
and thenFinalExponentiate
.
Assumptions:
pubkey
is onE
and in subgroupG1
signature
is onE_2
and in subgroupG2
Hm
is onE_2
and in subgroupG2
Circuit to verify BLS signature where public key size is minimized (so public key is in subgroup G1
) and we are given a hashed message in the form of two F_{p^2}
elements (in practice, hash = hash_to_field(msg,2)
).
Inputs:
pubkey
: length2 x k
arraysignature
: length2 x 2 x k
arrayhash
: length2 x 2 x k
array
Implements:
- Verifies that
pubkey
,signature
,hash
have entries in[0, 2^n)
- Verifies that
pubkey
is point onE(F_p)
- Proves that each
F_p
coordinate is< p
- Proves that
pubkey
lies onE
- Proves that each
- Verifies that
pubkey
is in subgroupG1
- Verifies that
signature
is point onE_2(F_{p^2})
- Proves that each
F_p
coordinate is< p
- Proves that
signature
lies onE_2
- Proves that each
- Verifies that
signature
is in subgroupG2
- Verifies that
hash[i][j] < p
for0 <= i,j < 2
sohash
is a pair ofF_{p^2}
elements. - Verifies that
e(g1, signature) == e(pubkey, H(m))
whereH(m) = MapToG2(hash)
.