From e9e84abf09af3f3cd0dbd84df8ee49c0a32860e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mamy=20Andr=C3=A9-Ratsimbazafy?= Date: Sun, 14 Jun 2020 14:00:05 +0200 Subject: [PATCH] Implement endomorphism acceleration for BLS12-381 (needed cofactor clearing of the point) --- ...ch_ec_swei_proj_g1.nim => bench_ec_g1.nim} | 8 +- benchmarks/bench_elliptic_template.nim | 53 +++-- constantine.nimble | 14 +- constantine/config/curves_declaration.nim | 2 +- .../elliptic/ec_endomorphism_accel.nim | 105 +++------ .../elliptic/ec_endomorphism_params.nim | 135 ++++++++++++ constantine/elliptic/ec_scalar_mul.nim | 5 +- sage/curve_family_bls12.sage | 8 +- sage/lattice_decomposition_bls12_381_g1.sage | 202 ++++++++++++++++++ ...attice_decomposition_bn254_snarks_g1.sage} | 9 +- sage/testgen_bls12_381.sage | 6 +- tests/test_ec_bls12_381.nim | 89 ++++---- tests/test_ec_bn254.nim | 2 +- 13 files changed, 478 insertions(+), 160 deletions(-) rename benchmarks/{bench_ec_swei_proj_g1.nim => bench_ec_g1.nim} (90%) create mode 100644 constantine/elliptic/ec_endomorphism_params.nim create mode 100644 sage/lattice_decomposition_bls12_381_g1.sage rename sage/{bn254_lattice_decomposition.sage => lattice_decomposition_bn254_snarks_g1.sage} (96%) diff --git a/benchmarks/bench_ec_swei_proj_g1.nim b/benchmarks/bench_ec_g1.nim similarity index 90% rename from benchmarks/bench_ec_swei_proj_g1.nim rename to benchmarks/bench_ec_g1.nim index e079ba238..175e22655 100644 --- a/benchmarks/bench_ec_swei_proj_g1.nim +++ b/benchmarks/bench_ec_g1.nim @@ -10,7 +10,7 @@ import # Internals ../constantine/config/curves, ../constantine/arithmetic, - ../constantine/elliptic/[ec_weierstrass_projective, ec_scalar_mul], + ../constantine/elliptic/ec_weierstrass_projective, # Helpers ../helpers/static_for, ./bench_elliptic_template, @@ -51,14 +51,16 @@ proc main() = separator() doublingBench(ECP_SWei_Proj[Fp[curve]], Iters) separator() + scalarMulUnsafeDoubleAddBench(ECP_SWei_Proj[Fp[curve]], MulIters) + separator() scalarMulGenericBench(ECP_SWei_Proj[Fp[curve]], scratchSpaceSize = 1 shl 2, MulIters) separator() scalarMulGenericBench(ECP_SWei_Proj[Fp[curve]], scratchSpaceSize = 1 shl 3, MulIters) separator() scalarMulGenericBench(ECP_SWei_Proj[Fp[curve]], scratchSpaceSize = 1 shl 4, MulIters) separator() - # scalarMulUnsafeDoubleAddBench(ECP_SWei_Proj[Fp[curve]], MulIters) - # separator() + scalarMulGLV(ECP_SWei_Proj[Fp[curve]], MulIters) + separator() separator() main() diff --git a/benchmarks/bench_elliptic_template.nim b/benchmarks/bench_elliptic_template.nim index b372805a4..a654b5bbb 100644 --- a/benchmarks/bench_elliptic_template.nim +++ b/benchmarks/bench_elliptic_template.nim @@ -17,11 +17,14 @@ import ../constantine/config/curves, ../constantine/arithmetic, ../constantine/io/io_bigints, + ../constantine/elliptic/[ec_weierstrass_projective, ec_scalar_mul, ec_endomorphism_accel], # Helpers ../helpers/[prng_unsafe, static_for], ./platforms, # Standard library - std/[monotimes, times, strformat, strutils, macros] + std/[monotimes, times, strformat, strutils, macros], + # Reference unsafe scalar multiplication + ../tests/support/ec_reference_scalar_mult var rng: RngState let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32 @@ -71,15 +74,15 @@ when SupportsGetTicks: echo "\n=================================================================================================================\n" proc separator*() = - echo "-".repeat(157) + echo "-".repeat(177) proc report(op, elliptic: string, start, stop: MonoTime, startClk, stopClk: int64, iters: int) = let ns = inNanoseconds((stop-start) div iters) let throughput = 1e9 / float64(ns) when SupportsGetTicks: - echo &"{op:<40} {elliptic:<40} {throughput:>15.3f} ops/s {ns:>9} ns/op {(stopClk - startClk) div iters:>9} CPU cycles (approx)" + echo &"{op:<60} {elliptic:<40} {throughput:>15.3f} ops/s {ns:>9} ns/op {(stopClk - startClk) div iters:>9} CPU cycles (approx)" else: - echo &"{op:<40} {elliptic:<40} {throughput:>15.3f} ops/s {ns:>9} ns/op" + echo &"{op:<60} {elliptic:<40} {throughput:>15.3f} ops/s {ns:>9} ns/op" macro fixEllipticDisplay(T: typedesc): untyped = # At compile-time, enums are integers and their display is buggy @@ -124,7 +127,7 @@ proc scalarMulGenericBench*(T: typedesc, scratchSpaceSize: static int, iters: in const bits = T.F.C.getCurveOrderBitwidth() var r {.noInit.}: T - let P = rng.random_unsafe(T) + let P = rng.random_unsafe(T) # TODO: clear cofactor let exponent = rng.random_unsafe(BigInt[bits]) var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte] @@ -136,18 +139,28 @@ proc scalarMulGenericBench*(T: typedesc, scratchSpaceSize: static int, iters: in r = P r.scalarMulGeneric(exponentCanonical, scratchSpace) -# import ../tests/support/ec_reference_scalar_mult -# -# proc scalarMulUnsafeDoubleAddBench*(T: typedesc, iters: int) = -# const bits = T.F.C.getCurveOrderBitwidth() -# -# var r {.noInit.}: T -# let P = rng.random_unsafe(T) -# -# let exponent = rng.random_unsafe(BigInt[bits]) -# var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte] -# exponentCanonical.exportRawUint(exponent, bigEndian) -# -# bench("EC ScalarMul G1 (unsafe DoubleAdd)", T, iters): -# r = P -# r.unsafe_ECmul_double_add(exponentCanonical) +proc scalarMulGLV*(T: typedesc, iters: int) = + const bits = T.F.C.getCurveOrderBitwidth() + + var r {.noInit.}: T + let P = rng.random_unsafe(T) # TODO: clear cofactor + + let exponent = rng.random_unsafe(BigInt[bits]) + + bench("EC ScalarMul G1 (GLV endomorphism accelerated)", T, iters): + r = P + r.scalarMulGLV(exponent) + +proc scalarMulUnsafeDoubleAddBench*(T: typedesc, iters: int) = + const bits = T.F.C.getCurveOrderBitwidth() + + var r {.noInit.}: T + let P = rng.random_unsafe(T) # TODO: clear cofactor + + let exponent = rng.random_unsafe(BigInt[bits]) + var exponentCanonical{.noInit.}: array[(bits+7) div 8, byte] + exponentCanonical.exportRawUint(exponent, bigEndian) + + bench("EC ScalarMul G1 (unsafe reference DoubleAdd)", T, iters): + r = P + r.unsafe_ECmul_double_add(exponentCanonical) diff --git a/constantine.nimble b/constantine.nimble index 2fc633987..94d787adc 100644 --- a/constantine.nimble +++ b/constantine.nimble @@ -124,7 +124,7 @@ task test, "Run all tests": runBench("bench_fp2") runBench("bench_fp6") runBench("bench_fp12") - runBench("bench_ec_swei_proj_g1") + runBench("bench_ec_g1") task test_no_gmp, "Run tests that don't require GMP": # -d:testingCurves is configured in a *.nim.cfg for convenience @@ -320,11 +320,11 @@ task bench_fp12_gcc, "Run benchmark 𝔽p12 with gcc": task bench_fp12_clang, "Run benchmark 𝔽p12 with clang": runBench("bench_fp12", "clang") -task bench_ec_swei_proj_g1, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - GCC": - runBench("bench_ec_swei_proj_g1") +task bench_ec_g1, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - GCC": + runBench("bench_ec_g1") -task bench_ec_swei_proj_g1_gcc, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - GCC": - runBench("bench_ec_swei_proj_g1", "gcc") +task bench_ec_gcc, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - GCC": + runBench("bench_ec_g1", "gcc") -task bench_ec_swei_proj_g1_clang, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - Clang": - runBench("bench_ec_swei_proj_g1", "clang") +task bench_ec_g1_clang, "Run benchmark on Elliptic Curve group 𝔾1 - Short Weierstrass with Projective Coordinates - Clang": + runBench("bench_ec_g1", "clang") diff --git a/constantine/config/curves_declaration.nim b/constantine/config/curves_declaration.nim index 62309962d..3efdfc7c9 100644 --- a/constantine/config/curves_declaration.nim +++ b/constantine/config/curves_declaration.nim @@ -144,7 +144,7 @@ declareCurves: modulus: "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab" family: BarretoLynnScott # u: -(2^63 + 2^62 + 2^60 + 2^57 + 2^48 + 2^16) - cubicRootOfUnity_mod_p: "0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe" + cubicRootOfUnity_mod_p: "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac" # G1 Equation: y² = x³ + 4 # G2 Equation: y² = x³ + 4 (1+i) diff --git a/constantine/elliptic/ec_endomorphism_accel.nim b/constantine/elliptic/ec_endomorphism_accel.nim index 164244388..eece9040b 100644 --- a/constantine/elliptic/ec_endomorphism_accel.nim +++ b/constantine/elliptic/ec_endomorphism_accel.nim @@ -17,7 +17,8 @@ import ../io/io_bigints, ../towers, ./ec_weierstrass_affine, - ./ec_weierstrass_projective + ./ec_weierstrass_projective, + ./ec_endomorphism_params # ############################################################ # @@ -71,9 +72,6 @@ type ## ## Digit-Endianness is bigEndian - MultiScalar[M, LengthInBits: static int] = array[M, BigInt[LengthInBits]] - ## Decomposition of a secret scalar in multiple scalars - const BitSize = 2 Shift = 2 # log2(4) - we can store 4 digit per byte @@ -149,9 +147,9 @@ proc `[]=`(recoding: var Recoded, slot[] = slot[] or shifted -func nDimMultiScalarRecoding[M, LengthInBits, LengthInDigits: static int]( - dst: var GLV_SAC[M, LengthInDigits], - src: MultiScalar[M, LengthInBits] +func nDimMultiScalarRecoding[M, L: static int]( + dst: var GLV_SAC[M, L], + src: MultiScalar[M, L] ) = ## This recodes N scalar for GLV multi-scalar multiplication ## with side-channel resistance. @@ -203,19 +201,17 @@ func nDimMultiScalarRecoding[M, LengthInBits, LengthInDigits: static int]( # For that floored division, bji may be negative!!! # In particular floored division of -1 is -1 not 0. # This means that arithmetic right shift must be used instead of logical right shift - static: doAssert LengthInDigits == LengthInBits+1, - "Length in digits: " & $LengthInDigits & " Length in bits: " & $LengthInBits - # " # VScode broken highlight + # assert src[0].isOdd - Only happen on implementation error, we don't want to leak a single bit var k = src # Keep the source multiscalar in registers template b: untyped {.dirty.} = dst - b[0][LengthInDigits-1] = 1 - for i in 0 .. LengthInDigits-2: + b[0][L-1] = 1 + for i in 0 .. L-2: b[0][i] = 2 * k[0].bit(i+1).int8 - 1 for j in 1 .. M-1: - for i in 0 .. LengthInDigits-1: + for i in 0 .. L-1: let bji = b[0][i] * k[j].bit0.int8 b[j][i] = bji # In the following equation @@ -276,61 +272,6 @@ func buildLookupTable[M: static int, F]( lut[u].sum(lut[u.clearBit(msb)], endomorphisms[msb]) # } # highlight bug, ... -# Chapter 6.3.1 - Guide to Pairing-based Cryptography -const Lattice_BN254_Snarks_G1: array[2, array[2, tuple[b: BigInt[127], isNeg: bool]]] = [ - # Curve of order 254 -> mini scalars of size 127 - # u = 0x44E992B44A6909F1 - [(BigInt[127].fromHex"0x89d3256894d213e3", false), # 2u + 1 - (BigInt[127].fromHex"0x6f4d8248eeb859fd0be4e1541221250b", false)], # 6u² + 4u + 1 - [(BigInt[127].fromHex"0x6f4d8248eeb859fc8211bbeb7d4f1128", false), # 6u² + 2u - (BigInt[127].fromHex"0x89d3256894d213e3", true)] # -2u - 1 -] - -const Babai_BN254_Snarks_G1 = [ - # Vector for Babai rounding - BigInt[127].fromHex"0x89d3256894d213e3", # 2u + 1 - BigInt[127].fromHex"0x6f4d8248eeb859fd0be4e1541221250b" # 6u² + 4u + 1 -] - -func decomposeScalar_BN254_Snarks_G1[M, scalBits, miniBits: static int]( - scalar: BigInt[scalBits], - miniScalars: var MultiScalar[M, miniBits] - ) = - ## Decompose a secret scalar into mini-scalar exploiting - ## BN254_Snarks specificities. - ## - ## TODO: Generalize to all BN curves - ## - needs a Lattice type - ## - needs to better support negative bigints, (extra bit for sign?) - - static: doAssert miniBits == (scalBits + M - 1) div M - # 𝛼0 = (0x2d91d232ec7e0b3d7 * s) >> 256 - # 𝛼1 = (0x24ccef014a773d2d25398fd0300ff6565 * s) >> 256 - const - w = BN254_Snarks.getCurveOrderBitwidth().wordsRequired() - alphaHats = (BigInt[66].fromHex"0x2d91d232ec7e0b3d7", - BigInt[130].fromHex"0x24ccef014a773d2d25398fd0300ff6565") - - var alphas{.noInit.}: array[M, BigInt[scalBits]] # TODO size 66+254 and 130+254 - - staticFor i, 0, M: - alphas[i].prod_high_words(alphaHats[i], scalar, w) - - # We have k0 = s - 𝛼0 b00 - 𝛼1 b10 - # and kj = 0 - 𝛼j b0j - 𝛼1 b1j - var k: array[M, BigInt[scalBits]] - k[0] = scalar - for miniScalarIdx in 0 ..< M: - for basisIdx in 0 ..< M: - var alphaB {.noInit.}: BigInt[scalBits] - alphaB.prod(alphas[basisIdx], Lattice_BN254_Snarks_G1[basisIdx][miniScalarIdx].b) # TODO small lattice size - if Lattice_BN254_Snarks_G1[basisIdx][miniScalarIdx].isNeg: - k[miniScalarIdx] += alphaB - else: - k[miniScalarIdx] -= alphaB - - miniScalars[miniScalarIdx].copyTruncatedFrom(k[miniScalarIdx]) - func tableIndex(glv: GLV_SAC, bit: int): SecretWord = ## Compose the secret table index from ## the GLV-SAC representation and the "bit" accessed @@ -353,9 +294,9 @@ func secretLookup[T](dst: var T, table: openArray[T], index: SecretWord) = let selector = SecretWord(i) == index dst.ccopy(table[i], selector) -func scalarMulGLV_BN254*( +func scalarMulGLV*[scalBits]( P: var ECP_SWei_Proj, - scalar: BigInt[BN254_Snarks.getCurveOrderBitwidth()] + scalar: BigInt[scalBits] ) = ## Elliptic Curve Scalar Multiplication ## @@ -363,19 +304,29 @@ func scalarMulGLV_BN254*( ## ## This is a scalar multiplication accelerated by an endomorphism ## via the GLV (Gallant-lambert-Vanstone) decomposition. - const M = 2 + const C = P.F.C # curve + static: doAssert: scalBits == C.getCurveOrderBitwidth() + when P.F is Fp: + const M = 2 # 1. Compute endomorphisms var endomorphisms: array[M-1, typeof(P)] # TODO: zero-init not required endomorphisms[0] = P - endomorphisms[0].x *= BN254_Snarks.getCubicRootOfUnity_mod_p() + endomorphisms[0].x *= C.getCubicRootOfUnity_mod_p() # 2. Decompose scalar into mini-scalars - const L = (BN254_Snarks.getCurveOrderBitwidth() + M - 1) div M + 1 - var miniScalars: array[M, BigInt[L-1]] # TODO: zero-init not required - scalar.decomposeScalar_BN254_Snarks_G1( - miniScalars - ) + const L = (C.getCurveOrderBitwidth() + M - 1) div M + 1 + var miniScalars: array[M, BigInt[L]] # TODO: zero-init not required + when C == BN254_Snarks: + scalar.decomposeScalar_BN254_Snarks_G1( + miniScalars + ) + elif C == BLS12_381: + scalar.decomposeScalar_BLS12_381_G1( + miniScalars + ) + else: + {.error: "Unsupported curve for GLV acceleration".} # 3. TODO: handle negative mini-scalars # Either negate the associated base and the scalar (in the `endomorphisms` array) diff --git a/constantine/elliptic/ec_endomorphism_params.nim b/constantine/elliptic/ec_endomorphism_params.nim new file mode 100644 index 000000000..1f00a75ba --- /dev/null +++ b/constantine/elliptic/ec_endomorphism_params.nim @@ -0,0 +1,135 @@ +# Constantine +# Copyright (c) 2018-2019 Status Research & Development GmbH +# Copyright (c) 2020-Present Mamy André-Ratsimbazafy +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import + # Internal + ../../helpers/static_for, + ../primitives, + ../config/[common, curves, type_bigint], + ../arithmetic, + ../io/io_bigints, + ../towers, + ./ec_weierstrass_projective + +# Parameters for GLV endomorphisms acceleration +# ---------------------------------------------------------------------------------------- +# TODO: cleanup, those should be derived in the config folder +# and stored in a constant + +type + MultiScalar*[M, LengthInBits: static int] = array[M, BigInt[LengthInBits]] + ## Decomposition of a secret scalar in multiple scalars + +# Chapter 6.3.1 - Guide to Pairing-based Cryptography +const Lattice_BN254_Snarks_G1: array[2, array[2, tuple[b: BigInt[127], isNeg: bool]]] = [ + # Curve of order 254 -> mini scalars of size 127 + # u = 0x44E992B44A6909F1 + [(BigInt[127].fromHex"0x89d3256894d213e3", false), # 2u + 1 + (BigInt[127].fromHex"0x6f4d8248eeb859fd0be4e1541221250b", false)], # 6u² + 4u + 1 + [(BigInt[127].fromHex"0x6f4d8248eeb859fc8211bbeb7d4f1128", false), # 6u² + 2u + (BigInt[127].fromHex"0x89d3256894d213e3", true)] # -2u - 1 +] + +const Babai_BN254_Snarks_G1 = [ + # Vector for Babai rounding + BigInt[127].fromHex"0x89d3256894d213e3", # 2u + 1 + BigInt[127].fromHex"0x6f4d8248eeb859fd0be4e1541221250b" # 6u² + 4u + 1 +] + +func decomposeScalar_BN254_Snarks_G1*[M, scalBits, L: static int]( + scalar: BigInt[scalBits], + miniScalars: var MultiScalar[M, L] + ) = + ## Decompose a secret scalar into mini-scalar exploiting + ## BN254_Snarks specificities. + ## + ## TODO: Generalize to all BN curves + ## - needs a Lattice type + ## - needs to better support negative bigints, (extra bit for sign?) + + static: doAssert L == (scalBits + M - 1) div M + 1 + # 𝛼0 = (0x2d91d232ec7e0b3d7 * s) >> 256 + # 𝛼1 = (0x24ccef014a773d2d25398fd0300ff6565 * s) >> 256 + const + w = BN254_Snarks.getCurveOrderBitwidth().wordsRequired() + alphaHats = (BigInt[66].fromHex"0x2d91d232ec7e0b3d7", + BigInt[130].fromHex"0x24ccef014a773d2d25398fd0300ff6565") + + var alphas{.noInit.}: array[M, BigInt[scalBits]] # TODO size 66+254 and 130+254 + + staticFor i, 0, M: + alphas[i].prod_high_words(alphaHats[i], scalar, w) + + # We have k0 = s - 𝛼0 b00 - 𝛼1 b10 + # and kj = 0 - 𝛼j b0j - 𝛼1 b1j + var k: array[M, BigInt[scalBits]] + k[0] = scalar + for miniScalarIdx in 0 ..< M: + for basisIdx in 0 ..< M: + var alphaB {.noInit.}: BigInt[scalBits] + alphaB.prod(alphas[basisIdx], Lattice_BN254_Snarks_G1[basisIdx][miniScalarIdx].b) # TODO small lattice size + if Lattice_BN254_Snarks_G1[basisIdx][miniScalarIdx].isNeg: + k[miniScalarIdx] += alphaB + else: + k[miniScalarIdx] -= alphaB + + miniScalars[miniScalarIdx].copyTruncatedFrom(k[miniScalarIdx]) + +const Lattice_BLS12_381_G1: array[2, array[2, tuple[b: BigInt[128], isNeg: bool]]] = [ + # Curve of order 254 -> mini scalars of size 127 + # u = 0x44E992B44A6909F1 + [(BigInt[128].fromHex"0xac45a4010001a40200000000ffffffff", false), # u² - 1 + (BigInt[128].fromHex"0x1", true)], # -1 + [(BigInt[128].fromHex"0x1", false), # 1 + (BigInt[128].fromHex"0xac45a4010001a4020000000100000000", false)] # u² +] + +const Babai_BLS12_381_G1 = [ + # Vector for Babai rounding + BigInt[128].fromHex"0xac45a4010001a4020000000100000000", + BigInt[128].fromHex"0x1" +] + +func decomposeScalar_BLS12_381_G1*[M, scalBits, L: static int]( + scalar: BigInt[scalBits], + miniScalars: var MultiScalar[M, L] + ) = + ## Decompose a secret scalar into mini-scalar exploiting + ## BLS12_381 specificities. + ## + ## TODO: Generalize to all BLS curves + ## - needs a Lattice type + ## - needs to better support negative bigints, (extra bit for sign?) + + static: doAssert L == (scalBits + M - 1) div M + 1 + # 𝛼0 = (0x2d91d232ec7e0b3d7 * s) >> 256 + # 𝛼1 = (0x24ccef014a773d2d25398fd0300ff6565 * s) >> 256 + const + w = BLS12_381.getCurveOrderBitwidth().wordsRequired() + alphaHats = (BigInt[129].fromHex"0x17c6becf1e01faadd63f6e522f6cfee30", + BigInt[2].fromHex"0x2") + + var alphas{.noInit.}: array[M, BigInt[scalBits]] # TODO size 256+255 and 132+255 + + staticFor i, 0, M: + alphas[i].prod_high_words(alphaHats[i], scalar, w) + + # We have k0 = s - 𝛼0 b00 - 𝛼1 b10 + # and kj = 0 - 𝛼j b0j - 𝛼1 b1j + var k: array[M, BigInt[scalBits]] + k[0] = scalar + for miniScalarIdx in 0 ..< M: + for basisIdx in 0 ..< M: + var alphaB {.noInit.}: BigInt[scalBits] + alphaB.prod(alphas[basisIdx], Lattice_BLS12_381_G1[basisIdx][miniScalarIdx].b) # TODO small lattice size + if Lattice_BLS12_381_G1[basisIdx][miniScalarIdx].isNeg: + k[miniScalarIdx] += alphaB + else: + k[miniScalarIdx] -= alphaB + + miniScalars[miniScalarIdx].copyTruncatedFrom(k[miniScalarIdx]) diff --git a/constantine/elliptic/ec_scalar_mul.nim b/constantine/elliptic/ec_scalar_mul.nim index bff92476b..3fc8cfd30 100644 --- a/constantine/elliptic/ec_scalar_mul.nim +++ b/constantine/elliptic/ec_scalar_mul.nim @@ -218,8 +218,9 @@ func scalarMul*( ## P <- [k] P # This calls endomorphism accelerated scalar mul if available # or the generic scalar mul otherwise - when ECP_SWei_Proj.F.C == BN254_Snarks: - scalarMulGLV_BN254(P, scalar) + when ECP_SWei_Proj.F.C in {BN254_Snarks, BLS12_381}: + # ⚠️ This requires the cofactor to be cleared + scalarMulGLV(P, scalar) else: var scratchSpace: array[1 shl 4, ECP_SWei_Proj] diff --git a/sage/curve_family_bls12.sage b/sage/curve_family_bls12.sage index adace597e..bda356685 100644 --- a/sage/curve_family_bls12.sage +++ b/sage/curve_family_bls12.sage @@ -55,8 +55,8 @@ def compute_curve_characteristic(u_str): print(f' Lattice b2: ' + str(['0x' + b.hex() for b in [1, u^2]])) # Babai rounding - ahat1 = 2*u+1 - ahat2 = 6*u^2+4*u+1 + ahat1 = u^2 + ahat2 = 1 # We want a1 = ahat1 * s/r with m = 2 (for a 2-dim decomposition) and r the curve order # To handle rounding errors we instead multiply by # 𝜈 = (2^WordBitWidth)^w (i.e. the same as the R magic constant for Montgomery arithmetic) @@ -70,8 +70,8 @@ def compute_curve_characteristic(u_str): print(f' 𝛼\u03021: ' + '0x' + ahat1.hex()) print(f' 𝛼\u03022: ' + '0x' + ahat2.hex()) print(f' Handle rounding errors') - print(f' 𝛼1 = 𝛼\u03021 * s / r with 𝛼1 = (𝛼\u03021 * 𝜈/r) * s/𝜈') - print(f' 𝛼2 = 𝛼\u03022 * s / r with 𝛼2 = (𝛼\u03022 * 𝜈/r) * s/𝜈') + print(f' 𝛼\u03051 = 𝛼\u03021 * s / r with 𝛼1 = (𝛼\u03021 * 𝜈/r) * s/𝜈') + print(f' 𝛼\u03052 = 𝛼\u03022 * s / r with 𝛼2 = (𝛼\u03022 * 𝜈/r) * s/𝜈') print(f' -----------------------------------------------------') l1 = Integer(ahat1 << v) // r l2 = Integer(ahat2 << v) // r diff --git a/sage/lattice_decomposition_bls12_381_g1.sage b/sage/lattice_decomposition_bls12_381_g1.sage new file mode 100644 index 000000000..3d082c87b --- /dev/null +++ b/sage/lattice_decomposition_bls12_381_g1.sage @@ -0,0 +1,202 @@ +# Constantine +# Copyright (c) 2018-2019 Status Research & Development GmbH +# Copyright (c) 2020-Present Mamy André-Ratsimbazafy +# Licensed and distributed under either of +# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT). +# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +# ############################################################ +# +# BN254 GLV Endomorphism +# Lattice Decomposition +# +# ############################################################ + +# Parameters +u = -(2^63 + 2^62 + 2^60 + 2^57 + 2^48 + 2^16) +p = (u - 1)^2 * (u^4 - u^2 + 1)//3 + u +r = u^4 - u^2 + 1 +cofactor = Integer('0x396c8c005555e1568c00aaab0000aaab') +print('p : ' + p.hex()) +print('r : ' + r.hex()) + +# Cube root of unity (mod r) formula for any BLS12 curves +lambda1_r = u^2 - 1 +assert lambda1_r^3 % r == 1 +print('λᵩ1 : ' + lambda1_r.hex()) +print('λᵩ1+r: ' + (lambda1_r+r).hex()) + +lambda2_r = u^4 +assert lambda2_r^3 % r == 1 +print('λᵩ2 : ' + lambda2_r.hex()) + +# Finite fields +F = GF(p) +# K2. = PolynomialRing(F) +# F2. = F.extension(u^2+9) +# K6. = PolynomialRing(F2) +# F6. = F2.extension(v^3-beta) +# K12. = PolynomialRing(F6) +# K12. = F6.extension(w^2-eta) + +# Curves +b = 4 +G1 = EllipticCurve(F, [0, b]) +# G2 = EllipticCurve(F2, [0, b*beta]) + +(phi1, phi2) = (root for root in GF(p)(1).nth_root(3, all=True) if root != 1) +print('𝜑1 :' + Integer(phi1).hex()) +print('𝜑2 :' + Integer(phi2).hex()) +assert phi1^3 % p == 1 +assert phi2^3 % p == 1 + +# Test generator +set_random_seed(1337) + +# Check +def checkEndo(): + Prand = G1.random_point() + assert Prand != G1([0, 1, 0]) # Infinity + + # Clear cofactor + P = Prand * cofactor + + (Px, Py, Pz) = P + Qendo1 = G1([Px*phi1 % p, Py, Pz]) + Qendo2 = G1([Px*phi2 % p, Py, Pz]) + + Q1 = lambda1_r * P + Q2 = lambda2_r * P + + assert P != Q1 + assert P != Q2 + + assert (F(Px)*F(phi1))^3 == F(Px)^3 + assert (F(Px)*F(phi2))^3 == F(Px)^3 + + assert Q1 == Qendo2 + assert Q2 == Qendo2 + + print('Endomorphism OK with 𝜑2') + +checkEndo() + +# Lattice +b = [ + [u^2-1, -1], + [1, u^2] +] +# Babai rounding +ahat = [u^2, 1] +v = int(r).bit_length() +v = int(((v + 64 - 1) // 64) * 64) # round to next multiple of 64 + +l = [Integer(a << v) // r for a in ahat] +print('𝛼\u03051: ' + l[0].hex()) +print('𝛼\u03052: ' + l[1].hex()) + +def getGLV2_decomp(scalar): + + a0 = (l[0] * scalar) >> v + a1 = (l[1] * scalar) >> v + + k0 = scalar - a0 * b[0][0] - a1 * b[1][0] + k1 = 0 - a0 * b[0][1] - a1 * b[1][1] + + assert int(k0).bit_length() <= (int(r).bit_length() + 1) // 2 + assert int(k1).bit_length() <= (int(r).bit_length() + 1) // 2 + + assert scalar == (k0 + k1 * (lambda1_r % r)) % r + assert scalar == (k0 + k1 * (lambda2_r % r)) % r + + return k0, k1 + +def recodeScalars(k): + m = 2 + L = ((int(r).bit_length() + m-1) // m) + 1 # l = ⌈log2 r/m⌉ + 1 + + b = [[0] * L, [0] * L] + b[0][L-1] = 1 + for i in range(0, L-1): # l-2 inclusive + b[0][i] = 2 * ((k[0] >> (i+1)) & 1) - 1 + for j in range(1, m): + for i in range(0, L): + b[j][i] = b[0][i] * (k[j] & 1) + k[j] = (k[j]//2) - (b[j][i] // 2) + + return b + +def buildLut(P0, P1): + m = 2 + lut = [0] * (1 << (m-1)) + lut[0] = P0 + lut[1] = P0 + P1 + return lut + +def pointToString(P): + (Px, Py, Pz) = P + return '(x: ' + Integer(Px).hex() + ', y: ' + Integer(Py).hex() + ', z: ' + Integer(Pz).hex() + ')' + +def scalarMulGLV(scalar, P0): + m = 2 + L = ((int(r).bit_length() + m-1) // m) + 1 # l = ⌈log2 r/m⌉ + 1 + + print('L: ' + str(L)) + + print('scalar: ' + Integer(scalar).hex()) + + k0, k1 = getGLV2_decomp(scalar) + print('k0: ' + k0.hex()) + print('k1: ' + k1.hex()) + + P1 = (lambda1_r % r) * P0 + (Px, Py, Pz) = P0 + P1_endo = G1([Px*phi2 % p, Py, Pz]) + assert P1 == P1_endo + + expected = scalar * P0 + decomp = k0*P0 + k1*P1 + assert expected == decomp + + print('------ recode scalar -----------') + even = k0 & 1 == 1 + if even: + k0 -= 1 + + b = recodeScalars([k0, k1]) + print('b0: ' + str(list(reversed(b[0])))) + print('b1: ' + str(list(reversed(b[1])))) + + print('------------ lut ---------------') + + lut = buildLut(P0, P1) + + print('------------ mul ---------------') + print('b0 L-1: ' + str(b[0][L-1])) + Q = b[0][L-1] * lut[b[1][L-1] & 1] + for i in range(L-2, -1, -1): + Q *= 2 + Q += b[0][i] * lut[b[1][i] & 1] + + if even: + Q += P0 + + print('final Q: ' + pointToString(Q)) + print('expected: ' + pointToString(expected)) + assert Q == expected # TODO debug + +# Test generator +set_random_seed(1337) + +for i in range(1): + print('---------------------------------------') + # scalar = randrange(r) # Pick an integer below curve order + # P = G1.random_point() + scalar = Integer('0xf7e60a832eb77ac47374bc93251360d6c81c21add62767ff816caf11a20d8db') + P = G1([ + Integer('0xf9679bb02ee7f352fff6a6467a5e563ec8dd38c86a48abd9e8f7f241f1cdd29d54bc3ddea3a33b62e0d7ce22f3d244a'), + Integer('0x50189b992cf856846b30e52205ff9ef72dc081e9680726586231cbc29a81a162120082585f401e00382d5c86fb1083f'), + Integer(1) + ]) + scalarMulGLV(scalar, P) diff --git a/sage/bn254_lattice_decomposition.sage b/sage/lattice_decomposition_bn254_snarks_g1.sage similarity index 96% rename from sage/bn254_lattice_decomposition.sage rename to sage/lattice_decomposition_bn254_snarks_g1.sage index 1478cf485..ab2fb491c 100644 --- a/sage/bn254_lattice_decomposition.sage +++ b/sage/lattice_decomposition_bn254_snarks_g1.sage @@ -24,7 +24,6 @@ lambda1_r = (-(36*u^3+18*u^2+6*u+2)) assert lambda1_r^3 % r == 1 print('λᵩ1 : ' + lambda1_r.hex()) print('λᵩ1+r: ' + (lambda1_r+r).hex()) -print('λᵩ1+r: ' + (lambda1_r+r).hex()) lambda2_r = (36*u^4-1) assert lambda2_r^3 % r == 1 @@ -48,9 +47,14 @@ G1 = EllipticCurve(F, [0, b]) print('𝜑1 :' + Integer(phi1).hex()) print('𝜑2 :' + Integer(phi2).hex()) +# Test generator +set_random_seed(1337) + # Check def checkEndo(): P = G1.random_point() + assert P != G1([0, 1, 0]) # Infinity + (Px, Py, Pz) = P Qendo1 = G1([Px*phi1 % p, Py, Pz]) Qendo2 = G1([Px*phi2 % p, Py, Pz]) @@ -61,6 +65,9 @@ def checkEndo(): assert P != Q1 assert P != Q2 + assert (F(Px)*F(phi1))^3 == F(Px)^3 + assert (F(Px)*F(phi2))^3 == F(Px)^3 + assert Q1 == Qendo1 assert Q2 == Qendo1 diff --git a/sage/testgen_bls12_381.sage b/sage/testgen_bls12_381.sage index fb8151927..d681f6476 100644 --- a/sage/testgen_bls12_381.sage +++ b/sage/testgen_bls12_381.sage @@ -37,7 +37,11 @@ set_random_seed(1337) for i in range(10): print('---------------------------------------') - P = G1.random_point() + Prand = G1.random_point() + + # Clear cofactor + P = Prand * cofactor + (Px, Py, Pz) = P print('Px: ' + Integer(Px).hex()) print('Py: ' + Integer(Py).hex()) diff --git a/tests/test_ec_bls12_381.nim b/tests/test_ec_bls12_381.nim index f8f51ce8d..ffe874061 100644 --- a/tests/test_ec_bls12_381.nim +++ b/tests/test_ec_bls12_381.nim @@ -13,7 +13,7 @@ import ../constantine/config/[common, curves], ../constantine/arithmetic, ../constantine/io/[io_bigints, io_ec], - ../constantine/elliptic/[ec_weierstrass_projective, ec_scalar_mul], + ../constantine/elliptic/[ec_weierstrass_projective, ec_scalar_mul, ec_endomorphism_accel], # Test utilities ./support/ec_reference_scalar_mult @@ -33,119 +33,122 @@ proc test( var Q: EC let qOK = Q.fromHex(Qx, Qy) - let exponent = EC.F.C.matchingBigInt.fromHex(scalar) + let exponent = BigInt[EC.F.C.getCurveOrderBitwidth()].fromHex(scalar) var exponentCanonical: array[(exponent.bits+7) div 8, byte] exponentCanonical.exportRawUint(exponent, bigEndian) var impl = P reference = P + endo = P scratchSpace: array[1 shl 4, EC] impl.scalarMulGeneric(exponentCanonical, scratchSpace) reference.unsafe_ECmul_double_add(exponentCanonical) + endo.scalarMulGLV(exponent) doAssert: bool(Q == reference) doAssert: bool(Q == impl) + doAssert: bool(Q == endo) -suite "Scalar Multiplication: BLS12_381 implementation (and unsafe reference impl) vs SageMath": +suite "Scalar Multiplication (cofactor cleared): BLS12_381 implementation (and unsafe reference impl) vs SageMath": # Generated via sage sage/testgen_bls12_381.sage test( id = 1, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "f21eda282230f72b855d48055e68ab3825da87831fa5147a64fa071bade4c26bddd45e8b602e62df4d907414a6ec1b4", - Py = "531b38866cb35c19951f4a1ac62242f11fa714a1b99c6116a630fa75e7f4407fcd1ae9770a821c5899a777d341c915a", + Px = "f9679bb02ee7f352fff6a6467a5e563ec8dd38c86a48abd9e8f7f241f1cdd29d54bc3ddea3a33b62e0d7ce22f3d244a", + Py = "50189b992cf856846b30e52205ff9ef72dc081e9680726586231cbc29a81a162120082585f401e00382d5c86fb1083f", scalar = "f7e60a832eb77ac47374bc93251360d6c81c21add62767ff816caf11a20d8db", - Qx = "18d7ca3fb93d7300a0484233f3bac9bca00b45595a4b9caf66aa0b2237f6fd51559a24a634f3876451332c5f754438b2", - Qy = "edbb203999303fc99ef04368412da4b3555f999c703b425dedff3fdc799317c292751c46275b27990c53d933de2db63" + Qx = "c344f3bcc86df380186311fa502b7943a436a629380f8ee1960515522eedc58fe67ddd47615487668bcf12842c524d8", + Qy = "189e0c154f2631ad26e24ca73d84fb60a21d385fe205df04cf9f2f6fc0c3aa72afe9fbea71a930fa71d9bbfddb2fa571" ) test( id = 2, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "9ca8e33d8a330b04b052af6cf44bf2ed08cc93d83a4eb48cbb0cabfe02ffb2ef910df44862b271354352f15b70e45b5", - Py = "102f6d07ef45f51de9a4ecef5ec34eae16833f4761c2ddfbe2b414173c3580721135e5bbb74269ab85ba83cb03020d9b", + Px = "17d71835ff84f150fabf5c77ac90bf7f6249143abd1f5d8a46a76f243d424d82e1e258fc7983ba8af97a2462adebe090", + Py = "d3e108ee1332067cbe4f4193eae10381acb69f493b40e53d9dee59506b49c6564c9056494a7f987982eb4069512c1c6", scalar = "5f10367bdae7aa872d90b5ac209321ce5a15181ce22848d032a8d452055cbfd0", - Qx = "a50d49e3d8757f994aae312dedd55205687c432bc9d97efbe69e87bef4256b87af1b665a669d06657cda6ff01ee42df", - Qy = "160d50aaa21f9d5b4faada77e4f91d8d4f152a0fcca4d30d271d74b20c1bba8638128f99f52d9603d4a24f8e27219bcd" + Qx = "21073bee733a07b15d83afcd4e6ee11b01e6137fd5ad4589c5045e12d79a9a9490a3ebc59f30633a60fc3635a3c1e51", + Qy = "eb7a97a9d3dfff1667b8fa559bdcdf37c7767e6afb8ca93ad9dd44feb93761e10aa2c4c1a79728a21cd4a6f705398b5" ) test( id = 3, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "173c28687d23de83c950131e548485e8e09d4053d32b814d13b618ee4159e8b61bf6320148ddabcedf2b04d3c9787cd4", - Py = "277f935b4e0a90155915960c617f395dcadead1c7297cf92916add07308fc3f0493aa6dabf31d1f15953f56ac37d3d9", + Px = "f92c9572692e8f3d450483a7a9bb4694e3b54c9cd09441a4dd7f579b0a6984e47f8090c31c172b33d87f3de186d6b58", + Py = "286ede4cb2ae19ead4932d5550c5d3ec8ce3a3ada5e1ed6d202e93dd1b16d3513f0f9b62adc6323f18e272a426ee955", scalar = "4c321d72220c098fc0fd52306de98f8be9446bf854cf1e4d8dbae62375d18faf", - Qx = "16259e878b5921bbe1e5672cccea0f29fedbb93b8ce1bae4d4b602b6dd5708c6d4e5d82ff92868828c46fd333aadf82d", - Qy = "16d09713f4fe5705f2e3491aa9a1d5827fb3b280f5a1fdde0b01a2b75f5803d528d5f5603cc0e9da29d6a07b8e14df7c" + Qx = "4bb385e937582ae32aa7ba89632fcef2eace3f7b57309d979cf35298a430de9ef4d9ac5ba2335c1a4b6e7e5c38d0036", + Qy = "1801154d3a7b0daea772345b7f72a4c88c9677743f267da63490dad4dece2ecc9ec02d4d4d063086ee5d356aa2db914e" ) test( id = 4, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "177d32dfa6e97daf5ea8aee520bc5c33b7bee37cba114fda52dd948030ad81abdffbdda402c930791e1048ad531b2c80", - Py = "14e9f915698dadd2220586a8bcc921b1f855273c3c0e41a88569e5a9fd2a4e886eeff9a7a11b02ec286987c5a52d55ce", + Px = "ec23ff3435b8ebd5e8e0a879d432e11eb974161664b1341fd28f1ffc4c228bf6ada2ae4a565f18c9b66f67a7573502d", + Py = "10c4b647be08db0b49b75320ae891f9f9c5d7bb7c798947e800d681d205d1b24b12e4dfa993d1bd16851b00356627cc1", scalar = "1738857afb76c55f615c2a20b44ca90dcb3267d804ec23fddea431dbee4eb37f", - Qx = "a4bfcfc65eb16562752f5c164349ef673477e19fe020de84eddbc2958f6d40bbbba39fc67ee8c8fdf007922fec97f79", - Qy = "106ccd382d15773e6097f8ea6f012cbec15184d6f4ea08bac2842ed419f0e555f1a43f7434b2e017f9e02971d07eb59d" + Qx = "dc7ae7801152918ee3c13590407b4242a80d0b855a0bf585d3dc30719601d2d5d9e01e99ae735003ecb7c20ef48265", + Qy = "142c01a6aa390426a4ce2f36df43f86442732c35d4e05e5b67f3623832944f0ea5a29138624cb939330652a3cfb282b5" ) test( id = 5, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "1bc38e70e62770489063d3b7a3bebbc6735ab8dc389576ff03272c2883045aa051d74f8407920530b4c719b140cda81", - Py = "bd24e4fb09ed4098d61e3d2cb456f03d7818ded79dfba9cfe7956829797b12e10f1766c46c1a2e1cf2957295124c782", + Px = "df127083c2a5ef2388b02af913c0e4002a52a82db9e5ecbf23ee4f557d3b61c91ebcfe9d4973070b46bc5ea6897bca1", + Py = "318960aeea262ec23ffdd42ec1ba72ae6fa2186a1e2a0fc2659073fb7b5adfb50d581a4d998a94d1accf78b1b3a0163", scalar = "19c47811813444020c999a2b263940b5054cf45bb8ad8e086ff126bfcd5507e1", - Qx = "b310d4688f2c9f8cd4c030b62ed27341f4c71341fe9c56858a949a2d51670eb6ebe1339163bdb833e692b0ee0cf4e92", - Qy = "c92300561e1acb1e1ae6a1b75f83b9d2d2cb5f07c3f8ea945990ceb75e7ea12c4aec115227c13a05be92f5caed9268e" + Qx = "5f93c42fd76a29063efa2ee92607e0b3ae7edc4e419b3914661e5162d6beaeb96a34d2007ff817bc102651f61dca8d1", + Qy = "18dde8666bb1d0a379719d7d1b1512de809b70e49d9553303274ea872e56f7f39da551d6bcb7c57ae88ec7dc1fb354a4" ) test( id = 6, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "48cddafaca93d33caf910a7a6f74dc3489d53da9fa2f940b70b6dcf538cc08da1a369809ab86a8ee49cead0ed6bfef6", - Py = "173f8dfb384aea011bed89aaca625085dc2940d0775e5f2647fc7574ce822643d0d7b1b39e9a51b9f5a0dca7486bddd0", + Px = "101123de23c0f240c583c2368c4118dc942db219c55f58cf54acd500c1fcfa06f651ad75319ebf840cbdb6bddea7fde4", + Py = "5268587d4b844b0708e0336d1bbf48da185aaf5b948eccc3b565d00a856dd55882b9bb31c52af0e275b168cb35eb7b0", scalar = "43ffcda71e45a3e90b7502d92b30a0b06c54c95a91aa21e0438677b1c2714ecb", - Qx = "ef1e4967a3eb19318a66d092eada9810bebf301c168cea7c73fad9d98f7d4c2bde1071fd142c3da90830509f22a82b5", - Qy = "da537922dcb6bf79e4d09237c1a3c5804e3a83b6f18ccb26991d50d77c81bef76139fa73d39c684c7c1616151b1058b" + Qx = "f9871b682c1c76c7f4f0a7ca57ad876c10dc108b65b76987264873278d9f54db95101c173aed06d07062efc7d47ca0c", + Qy = "20d9628d611e72a4251a1f2357d4f53e68e4915383b6a0d126273d216b1a8c5e2cb7b2688ad702ef1682f4c5228fcd9" ) test( id = 7, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "9d56cb273bdeef945078066192b74d2f3077f00f5bd1a50b338c44f7c640005a614f9c6fc89cb4678140b2a721c69a8", - Py = "107b42b9a0c22b9e9cd2191b90fede2ab280532ea26806338a5b28533cf9431bde1a8010677a5078c63482953d4f2451", + Px = "1457ba1bae6eb3afae3261941c65c93e3ae7d784907d15b8d559100da5e13fd29e4a4d6e3103b781a95237b7b2d80a8e", + Py = "6a869a47cb48d01e7d29660932afd7617720262b55de5f430b8aa3d74f9fd2b9d3a07ce192425da58014764fc9532cd", scalar = "64ad0d6c36dba5368e71f0010aebf860288f54611e5aaf18082bae7a404ebfd8", - Qx = "e0c78d1e1ed993fdeb14e4872965bc90014aa39c728c457a720bf3123ebcdcb17ac553a619b9b7073ada436565d4bb4", - Qy = "c2d9ba441ed90bae4f1597da90e434f1668fda320e4fa04cddcdce0eacb3bc54185d5f7cde826f5bd0e3d59b2424906" + Qx = "93e540e26190e161038d985d40f2ab897cbc2346be7d8f2b201a689b59d4020a8740e252606f2f79ba0e121ccc9976d", + Qy = "10568d68f1b993aa1eded3869eda14e509f1cb4d8553bdf97feee175467cea4c0c1316fdb4e5a68440ad04b96b2d3bfc" ) test( id = 8, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "150a83a868fa6a74dbc5658445ea99ec47009572f303ce1d3c76370804c5a8c26d40c8b4b35a6585612d704c5fb090cb", - Py = "31e73ed0aedebcf0b58d60c16f2e5ddd2d4eb2a6e34177939efcca0767cde241966b5950c3333c62ccddee51de26fe6", + Px = "2615f843e8fe68d4c337bcf83b2cf13cbae638edd0740f1eac520dc2146afa3b8d36c540878c1d207ef913634b1e593", + Py = "1787d6eeeceb6e7793073f0bbe7bae522529c126b650c43d5d41e732c581a57df1bfb818061b7b4e6c9145da5df2c43e", scalar = "b0ac3d0e685583075aa46c03a00859dfbec24ccb36e2cae3806d82275adcc03", - Qx = "9c5e69fbd492a64e5811af7cc69e42bc14d8626f6d384d3f479d8e06c20ec5f460a1e3839f33899b4a9e0ada876ac6e", - Qy = "16990d7d308897c74b87368f847df3ac0bb6609091c8d39b22d5778a4229f0bb92fea385d27db41e237dcfb0d05bd0e7" + Qx = "d95ed29c2e15fd2205d83a71478341d6022deb93af4d49f704437678a72ce141d2f6043aa0e34e26f60d17e16b97053", + Qy = "b37cbded112c84116b74ff311b10d148f3e203cb88d4a011b096c74cd2bfdb27255727de4aa8299ae10b32d661d48a7" ) test( id = 9, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "69498486a06c18f836a8e9ed507bbb563d6d03545e03e08f628e8fbd2e5d098e58950071d516ffd044d92b3a8b07184", - Py = "18a169f06fc94f40cd131bdcd23e48e95b1276c0c8daacf56c3a5e278e89ee1094c94aa516113aa4a2455da149f0f989", + Px = "10bc0c4e1ed87246a9d4d7d38546369f275a245f6e1d3b882e8c9a7f05bc6ee8ff97a96a54084c2bef15ed8bfefb1465", + Py = "1782377e5f588576b5ab42fea224e88873dda957202f0c6d72ce8728c2d58dc654be77226fbda385d5f269354e4a176a", scalar = "23941bb3c3659423d6fdafb7cff52e0e02de0ac91e64c537c6203d64905b63d0", - Qx = "482e085550f5e514dd98f2d9b119c284ac165514d228c8f7a179f2b442968984873223af2255a499dc931c63543c0ba", - Qy = "151ce80ca51dd09243d2b1a7937096d6b7494e89190da5ab7604cd913dc4105c871e48c815fefadee2906b8b401e7e71" + Qx = "83f1e7e8bd963c1ccd837dae7bc9336531aaf0aee717537a9a7e2712e220f74cdb73a99f331c0eb6b377be3dafc211f", + Qy = "cd87773d072b1305dfc85c2983aecae2ab316e5e8f31306c32d58d6ce2e431b12685d18c58b6a35ad2113c5b689eeb" ) test( id = 10, EC = ECP_SWei_Proj[Fp[BLS12_381]], - Px = "98cc20aa561769b7ee569304503a94752e236bba52938fed7f3093d5867f65361dc8b48c83bd7db490c26736196e20e", - Py = "10a68394358903122bd649bd30b473f4d3b4f0830bfe7da1c48ae87d9429d8fd26f5b4be8d8fd8e4214017044696da29", + Px = "be4f9f721d98a761a5562bd80ea06f369e9cbb7d33bbb2f0191d4b77d0fd2a10c4083b54157b525f36c522ca3a6ca09", + Py = "166c315ecdd20acb3c5efcc7e038b17d0b37a06ffbf77873f15fc0cd091a1e4102a8b8bf5507919453759e744391b04d", scalar = "4203156dcf70582ea8cbd0388104f47fd5a18ae336b2fed8458e1e4e74d7baf5", - Qx = "18ff1dfd96799b7d0bffaa7480121c3a719047815ae41419f1bd1fdd593288bed8827b3d9e45a3a1e01bf7d603b5ba0", - Qy = "49b95ca2c0f75dfb15fc07e5692d23f8eb38cb1cc9c48cd0e93a80adbff135a3945cc7a5d53d2b7510d6ee7cf97308d" + Qx = "c72bc7087cd22993b7f6d2e49026abfde678a384073ed373b95df722b1ab658eb5ae42211e5528af606e38b59511bc6", + Qy = "96d80593b42fe44e64793e490b1257af0aa26b36773aac93c3686fdb14975917cf60a1a19e32623218d0722dbb88a85" ) diff --git a/tests/test_ec_bn254.nim b/tests/test_ec_bn254.nim index cbadb7bec..60444777b 100644 --- a/tests/test_ec_bn254.nim +++ b/tests/test_ec_bn254.nim @@ -45,7 +45,7 @@ proc test( impl.scalarMulGeneric(exponentCanonical, scratchSpace) reference.unsafe_ECmul_double_add(exponentCanonical) - endo.scalarMulGLV_BN254(exponent) + endo.scalarMulGLV(exponent) doAssert: bool(Q == reference) doAssert: bool(Q == impl)