Skip to content

Commit

Permalink
[tests] add test cases for zero window MSM operations
Browse files Browse the repository at this point in the history
  • Loading branch information
Vindaar committed Oct 25, 2024
1 parent 004d6c5 commit 2489912
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 1 deletion.
25 changes: 25 additions & 0 deletions tests/math_elliptic_curves/t_ec_msm_zero_windows_sanity.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 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
# Internals
constantine/named/algebras,
constantine/math/ec_shortweierstrass,
constantine/math/arithmetic,
# Test utilities
./t_ec_template

run_EC_multi_scalar_mul_zero_windows_sanity(
ec = EC_ShortW_Jac[Fp[BN254_Snarks], G1],
moduleName = "test_msm_zero_windows_sanity" & $BN254_Snarks
)

run_EC_multi_scalar_mul_zero_windows_sanity(
ec = EC_ShortW_Jac[Fp[BLS12_381], G1],
moduleName = "test_msm_zero_windows_sanity" & $BLS12_381
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 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
# Internals
constantine/named/algebras,
constantine/math/ec_shortweierstrass,
constantine/math/arithmetic,
# Test utilities
./t_ec_template

const numPoints = [1, 2, 8, 16, 32, 64, 128, 1024, 2048, 4096] # 32768, 262144, 1048576]

run_EC_multi_scalar_mul_different_zero_windows(
ec = EC_ShortW_Jac[Fp[BN254_Snarks], G1],
numPoints = numPoints,
moduleName = "test_ec_shortweierstrass_jacobian_multi_scalar_mul_different_zero_windows_" & $BN254_Snarks
)

run_EC_multi_scalar_mul_different_zero_windows(
ec = EC_ShortW_Jac[Fp[BLS12_381], G1],
numPoints = numPoints,
moduleName = "test_ec_shortweierstrass_jacobian_multi_scalar_mul_different_zero_windows_" & $BLS12_381
)
102 changes: 101 additions & 1 deletion tests/math_elliptic_curves/t_ec_template.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import
# Standard library
std/[unittest, times],
std/[unittest, times, strformat],
# Internals
constantine/platforms/abstractions,
constantine/named/algebras,
Expand Down Expand Up @@ -1405,3 +1405,103 @@ proc run_EC_multi_scalar_mul_impl*[N: static int](
test(ec, gen = Uniform)
test(ec, gen = HighHammingWeight)
test(ec, gen = Long01Sequence)

proc run_EC_multi_scalar_mul_zero_windows_sanity*(
ec: typedesc,
moduleName: string) =
# Random seed for reproducibility
var rng: RngState
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo moduleName, " xoshiro512** seed: ", seed

const testSuiteDesc = "Elliptic curve multi-scalar-multiplication"
const NumPoints = 4096

suite "Scalar coefficients with specific number of zero bits":
const maxBits = [1, 8, 16, 32, 64, 128, 256, 512] # how many bits are set in the coefficients
for bits in maxBits:
test "Zero bits " & $bits:
proc test(EC: typedesc) =
type T = BigInt[EC.getScalarField().bits()]
var coefs = newSeq[T](NumPoints)
for i in 0 ..< NumPoints:
coefs[i] = random_coefficient[EC.getScalarField().bits()](rng, bits)
# verify number of bits needed
let msb = determineBitsSet(cast[ptr UncheckedArray[T]](coefs[0].addr), NumPoints)
## `determineBitsSet` returns the highest set bit in the list of coefficients + 1
## and the size of the BigInt if the target size is larger than the BigInt.
check msb == min(bits, bEC.getScalarField().bits())
test(ec)

import ../../benchmarks/bench_msm_impl_optional_drop_windows
proc run_EC_multi_scalar_mul_different_zero_windows*[N: static int](
ec: typedesc,
numPoints: array[N, int],
moduleName: string) =
# Random seed for reproducibility
var rng: RngState
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
rng.seed(seed)
echo "\n------------------------------------------------------\n"
echo moduleName, " xoshiro512** seed: ", seed

const testSuiteDesc = "Elliptic curve multi-scalar-multiplication with all windows compared to dropping MSB zero windows"

suite &"{testSuiteDesc} - {$ec} - [{WordBitWidth}-bit mode]":
const maxBits = [1, 8, 16, 32, 64, 128, 256, 512] # how many bits are set in the coefficients
# first check a selection of bits with different number of points
for bits in maxBits:
for n in numPoints:
let bucketBits = bestBucketBitSize(n, ec.getScalarField().bits(), useSignedBuckets = false, useManualTuning = false)
test &"{$ec} Multi-scalar-mul (N={n}, bucket bits: {bucketBits}, maxBitsSet={bits})":
proc test(EC: typedesc) =
var points = newSeq[affine(EC)](n)
var coefs = newSeq[BigInt[EC.getScalarField().bits()]](n)

for i in 0 ..< n:
var tmp = rng.random_unsafe(EC)
tmp.clearCofactor()
points[i].affine(tmp)
coefs[i] = random_coefficient[EC.getScalarField().bits()](rng, bits)

var refAll, refWo, optAll, optWo: EC
refAll.multiScalarMul_reference_vartime(coefs, points, useZeroWindows = true)
refWo.multiScalarMul_reference_vartime(coefs, points, useZeroWindows = false)
optAll.multiScalarMul_vartime(coefs, points, useZeroWindows = true)
optWo.multiScalarMul_vartime(coefs, points, useZeroWindows = false)

doAssert bool(refAll == refWo)
doAssert bool(optAll == optWo)
doAssert bool(refWo == optWo)

test(ec)

# now check each possible bit explicitly
# Note: this uses a fixed bucket size, but given the above, that should be fine
for bits in 0 ..< ec.getScalarField().bits():
const n = 32
let bucketBits = bestBucketBitSize(n, ec.getScalarField().bits(), useSignedBuckets = false, useManualTuning = false)
test &"{$ec} Multi-scalar-mul (N={n}, bucket bits: {bucketBits}, maxBitsSet={bits})":
proc test(EC: typedesc) =
var points = newSeq[affine(EC)](n)
var coefs = newSeq[BigInt[EC.getScalarField().bits()]](n)

for i in 0 ..< n:
var tmp = rng.random_unsafe(EC)
tmp.clearCofactor()
points[i].affine(tmp)
coefs[i] = random_coefficient[EC.getScalarField().bits()](rng, bits)

var refAll, refWo, optAll, optWo: EC
refAll.multiScalarMul_reference_vartime(coefs, points, useZeroWindows = true)
refWo.multiScalarMul_reference_vartime(coefs, points, useZeroWindows = false)
optAll.multiScalarMul_vartime(coefs, points, useZeroWindows = true)
optWo.multiScalarMul_vartime(coefs, points, useZeroWindows = false)

doAssert bool(refAll == refWo)
doAssert bool(optAll == optWo)
doAssert bool(refWo == optWo)

test(ec)

0 comments on commit 2489912

Please sign in to comment.