Tower drop concepts (#153)

* Fix affine instantiation

* drop concept from the codebase

* Remove alignment requirement, this cases problem in sequences on 32-bit for t_fp12_anti_regression

* slight sparse optim
This commit is contained in:
Mamy Ratsimbazafy 2021-02-07 14:03:56 +01:00 committed by GitHub
parent ffc77cd087
commit e23f990280
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 137 additions and 148 deletions

View File

@ -124,6 +124,7 @@ func trySetFromCoordX*[F, Tw](
## will be provided, this is intended for testing purposes.
P.y.curve_eq_rhs(x, Tw)
result = sqrt_if_square(P.y)
P.x = x
func neg*(P: var ECP_ShortW_Aff, Q: ECP_ShortW_Aff) =
## Negate ``P``

View File

@ -12,6 +12,7 @@ import
std/typetraits,
# Internal
./io_bigints, ./io_fields,
../primitives,
../arithmetic/finite_fields,
../tower_field_extensions/tower_instantiation
@ -30,11 +31,11 @@ export tower_instantiation
func appendHex*(accum: var string, f: Fp2 or Fp4 or Fp6 or Fp12, order: static Endianness = bigEndian) =
## Hex accumulator
accum.add static($f.typeof.genericHead() & '(')
for fieldName, fieldValue in fieldPairs(f):
when fieldName != "c0":
staticFor i, 0, f.coords.len:
when i != 0:
accum.add ", "
accum.add fieldName & ": "
accum.appendHex(fieldValue, order)
accum.add "c" & $i & ": "
accum.appendHex(f.coords[i], order)
accum.add ")"
func toHex*(f: Fp2 or Fp4 or Fp6 or Fp12, order: static Endianness = bigEndian): string =
@ -109,18 +110,14 @@ func fromHex*(T: typedesc[Fp12],
func fromUint*(a: var ExtensionField, src: SomeUnsignedInt) =
## Set ``a`` to the bigint value int eh extension field
for fieldName, fA in fieldPairs(a):
when fieldName == "c0":
fA.fromUint(src)
else:
fA.setZero()
a.coords[0].fromUint(src)
staticFor i, 1, a.coords.len:
a.coords[i].setZero()
func fromInt*(a: var ExtensionField, src: SomeInteger) =
## Parse a regular signed integer
## and store it into a Fp^n
## A negative integer will be instantiated as a negated number (mod p^n)
for fieldName, fA in fieldPairs(a):
when fieldName == "c0":
fA.fromInt(src)
else:
fA.setZero()
a.coords[0].fromInt(src)
staticFor i, 1, a.coords.len:
a.coords[i].setZero()

View File

@ -10,6 +10,7 @@ import
std/macros,
../arithmetic,
../towers,
../primitives,
../curves/zoo_frobenius
# Frobenius Map
@ -79,9 +80,9 @@ func frobenius_map*[C](r: var Fp12[C], a: Fp12[C], k: static int = 1) {.inline.}
## Computes a^(p^k)
## The p-power frobenius automorphism on 𝔽p12
static: doAssert r.c0 is Fp4
for r_fp4, a_fp4 in fields(r, a):
for r_fp2, a_fp2 in fields(r_fp4, a_fp4):
r_fp2.frobenius_map(a_fp2, k)
staticFor i, 0, r.coords.len:
staticFor j, 0, r.coords[0].coords.len:
r.coords[i].coords[j].frobenius_map(a.coords[i].coords[j], k)
r.c0.c0.mulCheckSparse frobMapConst(C, 0, k)
r.c0.c1.mulCheckSparse frobMapConst(C, 3, k)

View File

@ -158,18 +158,18 @@ func line_eval_add[F](
when F.C.getSexticTwist() == M_Twist:
A *= SexticNonResidue # A = ξ (X₁ - Z₁X₂)
func line_eval_fused_double[F](
line: var Line[F],
T: var ECP_ShortW_Prj[F, OnTwist]) =
func line_eval_fused_double[Field](
line: var Line[Field],
T: var ECP_ShortW_Prj[Field, OnTwist]) =
## Fused line evaluation and elliptic point doubling
# Grewal et al, 2012 adapted to Scott 2019 line notation
var A {.noInit.}, B {.noInit.}, C {.noInit.}: F
var E {.noInit.}, F {.noInit.}, G {.noInit.}: F
var A {.noInit.}, B {.noInit.}, C {.noInit.}: Field
var E {.noInit.}, F {.noInit.}, G {.noInit.}: Field
template H: untyped = line.x
const b3 = 3*F.C.getCoefB()
const b3 = 3*Field.C.getCoefB()
var snrY = T.y
when F.C.getSexticTwist() == D_Twist:
when Field.C.getSexticTwist() == D_Twist:
snrY *= SexticNonResidue
A.prod(T.x, snrY)
@ -178,11 +178,11 @@ func line_eval_fused_double[F](
C.square(T.z) # C = Z²
var snrB = B
when F.C.getSexticTwist() == D_Twist:
when Field.C.getSexticTwist() == D_Twist:
snrB *= SexticNonResidue
E.prod(C, b3)
when F.C.getSexticTwist() == M_Twist:
when Field.C.getSexticTwist() == M_Twist:
E *= SexticNonResidue # E = 3b'Z² = 3bξ Z²
F.prod(E, 3) # F = 3E = 9bZ²
@ -195,7 +195,7 @@ func line_eval_fused_double[F](
line.z.square(T.x)
line.z *= 3 # lz = 3X²
when F.C.getSexticTwist() == D_Twist:
when Field.C.getSexticTwist() == D_Twist:
line.z *= SexticNonResidue
line.y.diff(E, snrB) # ly = E-B = 3b'Z² - Y²
@ -213,7 +213,7 @@ func line_eval_fused_double[F](
# M-twist: (Y²+9bξZ²)²/4 - 3*(3bξZ²)²
# D-Twist: (ξY²+9bZ²)²/4 - 3*(3bZ²)²
when F.C.getSexticTwist() == D_Twist:
when Field.C.getSexticTwist() == D_Twist:
H *= SexticNonResidue
T.z.prod(snrB, H) # Z₃ = BH = Y²((Y+Z)² - (Y²+Z²)) = 2Y³Z
# M-twist: 2Y³Z
@ -221,26 +221,26 @@ func line_eval_fused_double[F](
# Correction for Fp4 towering
H.neg() # lx = -H
when F.C.getSexticTwist() == M_Twist:
when Field.C.getSexticTwist() == M_Twist:
H *= SexticNonResidue
# else: the SNR is already integrated in H
func line_eval_fused_add[F](
line: var Line[F],
T: var ECP_ShortW_Prj[F, OnTwist],
Q: ECP_ShortW_Aff[F, OnTwist]) =
func line_eval_fused_add[Field](
line: var Line[Field],
T: var ECP_ShortW_Prj[Field, OnTwist],
Q: ECP_ShortW_Aff[Field, OnTwist]) =
## Fused line evaluation and elliptic point addition
# Grewal et al, 2012 adapted to Scott 2019 line notation
var
A {.noInit.}: F
B {.noInit.}: F
C {.noInit.}: F
D {.noInit.}: F
E {.noInit.}: F
F {.noInit.}: F
G {.noInit.}: F
H {.noInit.}: F
I {.noInit.}: F
A {.noInit.}: Field
B {.noInit.}: Field
C {.noInit.}: Field
D {.noInit.}: Field
E {.noInit.}: Field
F {.noInit.}: Field
G {.noInit.}: Field
H {.noInit.}: Field
I {.noInit.}: Field
template lambda: untyped = line.x
template theta: untyped = line.z
@ -275,7 +275,7 @@ func line_eval_fused_add[F](
# Line evaluation
theta.neg()
when F.C.getSexticTwist() == M_Twist:
when Field.C.getSexticTwist() == M_Twist:
lambda *= SexticNonResidue # A = ξ (X₁ - Z₁X₂)
# Public proc

View File

@ -7,7 +7,7 @@
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
../config/common,
../config/[common, curves],
../primitives,
../arithmetic
@ -30,46 +30,55 @@ type
##
## Placeholder for the appropriate quadratic, cubic or sectic non-residue
CubicExt* = concept x
## Cubic Extension field concept
type BaseField = auto
x.c0 is BaseField
x.c1 is BaseField
x.c2 is BaseField
QuadraticExt*[F] = object
## Quadratic Extension field
coords*: array[2, F]
QuadraticExt* = concept x
## Quadratic Extension field concept
not(x is CubicExt)
CubicExt*[F] = object
## Cubic Extension field
coords*: array[3, F]
type BaseField = auto
x.c0 is BaseField
x.c1 is BaseField
ExtensionField*[F] = QuadraticExt[F] or CubicExt[F]
ExtensionField* = QuadraticExt or CubicExt
template c0*(a: ExtensionField): auto =
a.coords[0]
template c1*(a: ExtensionField): auto =
a.coords[1]
template c2*(a: CubicExt): auto =
a.coords[2]
template `c0=`*(a: ExtensionField, v: auto) =
a.coords[0] = v
template `c1=`*(a: ExtensionField, v: auto) =
a.coords[1] = v
template `c2=`*(a: CubicExt, v: auto) =
a.coords[2] = v
template C*(E: type ExtensionField): Curve =
E.F.C
template fieldMod*(E: type ExtensionField): auto =
Fp[E.F.C].fieldMod()
# Initialization
# -------------------------------------------------------------------
func setZero*(a: var ExtensionField) =
## Set ``a`` to 0 in the extension field
for field in fields(a):
field.setZero()
staticFor i, 0, a.coords.len:
a.coords[i].setZero()
func setOne*(a: var ExtensionField) =
## Set ``a`` to 1 in the extension field
for fieldName, fA in fieldPairs(a):
when fieldName == "c0":
fA.setOne()
else:
fA.setZero()
a.coords[0].setOne()
staticFor i, 1, a.coords.len:
a.coords[i].setZero()
func fromBig*(a: var ExtensionField, src: BigInt) =
## Set ``a`` to the bigint value in the extension field
for fieldName, fA in fieldPairs(a):
when fieldName == "c0":
fA.fromBig(src)
else:
fA.setZero()
a.coords[0].fromBig(src)
staticFor i, 1, a.coords.len:
a.coords[i].setZero()
# Comparison
# -------------------------------------------------------------------
@ -77,32 +86,28 @@ func fromBig*(a: var ExtensionField, src: BigInt) =
func `==`*(a, b: ExtensionField): SecretBool =
## Constant-time equality check
result = CtTrue
for fA, fB in fields(a, b):
result = result and (fA == fB)
staticFor i, 0, a.coords.len:
result = result and (a.coords[i] == b.coords[i])
func isZero*(a: ExtensionField): SecretBool =
## Constant-time check if zero
result = CtTrue
for fA in fields(a):
result = result and fA.isZero()
staticFor i, 0, a.coords.len:
result = result and a.coords[i].isZero()
func isOne*(a: ExtensionField): SecretBool =
## Constant-time check if one
result = CtTrue
for fieldName, fA in fieldPairs(a):
when fieldName == "c0":
result = result and fA.isOne()
else:
result = result and fA.isZero()
result = result and a.coords[0].isOne()
staticFor i, 1, a.coords.len:
result = result and a.coords[i].isZero()
func isMinusOne*(a: ExtensionField): SecretBool =
## Constant-time check if -1
result = CtTrue
for fieldName, fA in fieldPairs(a):
when fieldName == "c0":
result = result and fA.isMinusOne()
else:
result = result and fA.isZero()
result = result and a.coords[0].isMinusOne()
staticFor i, 1, a.coords.len:
result = result and a.coords[i].isZero()
# Copies
# -------------------------------------------------------------------
@ -112,68 +117,56 @@ func ccopy*(a: var ExtensionField, b: ExtensionField, ctl: SecretBool) =
## If ctl is true: b is copied into a
## if ctl is false: b is not copied and a is unmodified
## Time and memory accesses are the same whether a copy occurs or not
for fA, fB in fields(a, b):
ccopy(fA, fB, ctl)
staticFor i, 0, a.coords.len:
a.coords[i].ccopy(b.coords[i], ctl)
# Abelian group
# -------------------------------------------------------------------
func neg*(r: var ExtensionField, a: ExtensionField) =
## Field out-of-place negation
for fR, fA in fields(r, a):
fR.neg(fA)
staticFor i, 0, a.coords.len:
r.coords[i].neg(a.coords[i])
func neg*(a: var ExtensionField) =
## Field in-place negation
for fA in fields(a):
fA.neg()
staticFor i, 0, a.coords.len:
a.coords[i].neg()
func `+=`*(a: var ExtensionField, b: ExtensionField) =
## Addition in the extension field
for fA, fB in fields(a, b):
fA += fB
staticFor i, 0, a.coords.len:
a.coords[i] += b.coords[i]
func `-=`*(a: var ExtensionField, b: ExtensionField) =
## Substraction in the extension field
for fA, fB in fields(a, b):
fA -= fB
staticFor i, 0, a.coords.len:
a.coords[i] -= b.coords[i]
func double*(r: var ExtensionField, a: ExtensionField) =
## Field out-of-place doubling
for fR, fA in fields(r, a):
fR.double(fA)
staticFor i, 0, a.coords.len:
r.coords[i].double(a.coords[i])
func double*(a: var ExtensionField) =
## Field in-place doubling
for fA in fields(a):
fA.double()
staticFor i, 0, a.coords.len:
a.coords[i].double()
func div2*(a: var ExtensionField) =
## Field in-place division by 2
for fA in fields(a):
fA.div2()
staticFor i, 0, a.coords.len:
a.coords[i].div2()
func sum*(r: var QuadraticExt, a, b: QuadraticExt) =
func sum*(r: var ExtensionField, a, b: ExtensionField) =
## Sum ``a`` and ``b`` into ``r``
r.c0.sum(a.c0, b.c0)
r.c1.sum(a.c1, b.c1)
staticFor i, 0, a.coords.len:
r.coords[i].sum(a.coords[i], b.coords[i])
func sum*(r: var CubicExt, a, b: CubicExt) =
## Sum ``a`` and ``b`` into ``r``
r.c0.sum(a.c0, b.c0)
r.c1.sum(a.c1, b.c1)
r.c2.sum(a.c2, b.c2)
func diff*(r: var QuadraticExt, a, b: QuadraticExt) =
func diff*(r: var ExtensionField, a, b: ExtensionField) =
## Diff ``a`` and ``b`` into ``r``
r.c0.diff(a.c0, b.c0)
r.c1.diff(a.c1, b.c1)
func diff*(r: var CubicExt, a, b: CubicExt) =
## Diff ``a`` and ``b`` into ``r``
r.c0.diff(a.c0, b.c0)
r.c1.diff(a.c1, b.c1)
r.c2.diff(a.c2, b.c2)
staticFor i, 0, a.coords.len:
r.coords[i].diff(a.coords[i], b.coords[i])
func conj*(a: var QuadraticExt) =
## Computes the conjugate in-place
@ -211,18 +204,18 @@ func conj*(r: var CubicExt, a: CubicExt) =
func cneg*(a: var ExtensionField, ctl: SecretBool) =
## Constant-time in-place conditional negation
## Only negate if ctl is true
for fA in fields(a):
fA.cneg(ctl)
staticFor i, 0, a.coords.len:
a.coords[i].cneg(ctl)
func cadd*(a: var ExtensionField, b: ExtensionField, ctl: SecretBool) =
## Constant-time in-place conditional addition
for fA, fB in fields(a, b):
fA.cadd(fB, ctl)
staticFor i, 0, a.coords.len:
a.coords[i].cadd(b.coords[i], ctl)
func csub*(a: var ExtensionField, b: ExtensionField, ctl: SecretBool) =
## Constant-time in-place conditional substraction
for fA, fB in fields(a, b):
fA.csub(fB, ctl)
staticFor i, 0, a.coords.len:
a.coords[i].csub(b.coords[i], ctl)
# Multiplication by a small integer known at compile-time
# -------------------------------------------------------------------
@ -603,10 +596,9 @@ func mul_sparse_generic_by_0y(
var t{.noInit.}: typeof(a.c0)
t.prod(a.c1, b)
t *= NonResidue
r.c1.prod(a.c0, b)
# aliasing: a unneeded now
r.c0 = t
r.c0.prod(t, NonResidue)
func mul_sparse_generic_by_0y(
r: var QuadraticExt, a: QuadraticExt,
@ -627,10 +619,9 @@ func mul_sparse_generic_by_0y(
var t{.noInit.}: typeof(a.c0)
t.prod(a.c1, b)
t *= NonResidue
r.c1.prod(a.c0, b)
# aliasing: a unneeded now
r.c0 = t
r.c0.prod(t, NonResidue)
func invImpl(r: var QuadraticExt, a: QuadraticExt) =
## Compute the multiplicative inverse of ``a``

View File

@ -43,8 +43,8 @@ func prod*(r: var Fp, a: Fp, _: type NonResidue){.inline.} =
# ----------------------------------------------------------------
type
Fp2*[C: static Curve] = object
c0*, c1*: Fp[C]
Fp2*[C: static Curve] =
QuadraticExt[Fp[C]]
template fromComplexExtension*[F](elem: F): static bool =
## Returns true if the input is a complex extension
@ -190,11 +190,11 @@ func `/=`*(a: var Fp2, _: type NonResidue) {.inline.} =
# ----------------------------------------------------------------
type
Fp4*[C: static Curve] = object
c0*, c1*: Fp2[C]
Fp4*[C: static Curve] =
QuadraticExt[Fp2[C]]
Fp6*[C: static Curve] = object
c0*, c1*, c2*: Fp2[C]
Fp6*[C: static Curve] =
CubicExt[Fp2[C]]
func prod*(r: var Fp4, a: Fp4, _: type NonResidue) =
## Multiply an element of 𝔽p4 by the non-residue
@ -253,9 +253,8 @@ func `*=`*(a: var Fp6, _: type NonResidue) {.inline.} =
# ----------------------------------------------------------------
type
Fp12*[C: static Curve] = object
c0*, c1*, c2*: Fp4[C]
# c0*, c1*: Fp6[C]
Fp12*[C: static Curve] =
CubicExt[Fp4[C]]
# Sparse functions
# ----------------------------------------------------------------

View File

@ -151,8 +151,8 @@ func random_unsafe(rng: var RngState, a: var FF) =
func random_unsafe(rng: var RngState, a: var ExtensionField) =
## Recursively initialize an extension Field element
## Unsafe: for testing and benchmarking purposes only
for field in fields(a):
rng.random_unsafe(field)
for i in 0 ..< a.coords.len:
rng.random_unsafe(a.coords[i])
func random_word_highHammingWeight(rng: var RngState): BaseType =
let numZeros = rng.random_unsafe(WordBitWidth div 3) # Average Hamming Weight is 1-0.33/2 = 0.83
@ -182,8 +182,8 @@ func random_highHammingWeight(rng: var RngState, a: var FF) =
func random_highHammingWeight(rng: var RngState, a: var ExtensionField) =
## Recursively initialize an extension Field element
## Unsafe: for testing and benchmarking purposes only
for field in fields(a):
rng.random_highHammingWeight(field)
for i in 0 ..< a.coords.len:
rng.random_highHammingWeight(a.coords[i])
func random_long01Seq(rng: var RngState, a: var openArray[byte]) =
## Initialize a bytearray
@ -227,8 +227,8 @@ func random_long01Seq(rng: var RngState, a: var FF) =
func random_long01Seq(rng: var RngState, a: var ExtensionField) =
## Recursively initialize an extension Field element
## Unsafe: for testing and benchmarking purposes only
for field in fields(a):
rng.random_long01Seq(field)
for i in 0 ..< a.coords.len:
rng.random_long01Seq(a.coords[i])
# Elliptic curves
# ------------------------------------------------------------

View File

@ -73,7 +73,7 @@ proc runFrobeniusTowerTests*[N](
var fa {.noInit.}: typeof(a)
fa.frobenius_map(a, k = 1)
a.powUnsafeExponent(Field.C.Mod, window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
check: bool(a == fa)
staticFor(curve, TestCurves):
@ -89,8 +89,8 @@ proc runFrobeniusTowerTests*[N](
var fa {.noInit.}: typeof(a)
fa.frobenius_map(a, k = 2)
a.powUnsafeExponent(Field.C.Mod, window = 3)
a.powUnsafeExponent(Field.C.Mod, window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
check:
bool(a == fa)
@ -108,9 +108,9 @@ proc runFrobeniusTowerTests*[N](
var fa {.noInit.}: typeof(a)
fa.frobenius_map(a, k = 3)
a.powUnsafeExponent(Field.C.Mod, window = 3)
a.powUnsafeExponent(Field.C.Mod, window = 3)
a.powUnsafeExponent(Field.C.Mod, window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
a.powUnsafeExponent(Field.fieldMod(), window = 3)
check: bool(a == fa)
staticFor(curve, TestCurves):