Batch Serialization (#283)

* feat: batchSerialization banderwagon elements

* tests for Batch Serialize

* fix: removed failure point in batchOperation

* fix: changed to allocStackArray

* Update constantine/math/elliptic/ec_twistededwards_batch_ops.nim

Co-authored-by: Mamy Ratsimbazafy <mamy_github@numforge.co>

* fix: removed return to bool & changed to debug

---------

Co-authored-by: Mamy Ratsimbazafy <mamy_github@numforge.co>
This commit is contained in:
Advaita Saha 2023-10-25 14:43:57 +05:30 committed by GitHub
parent 3e27f1e831
commit 999482092b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 75 additions and 10 deletions

View File

@ -115,9 +115,9 @@ func batchInvert*[F](
dst[i] *= accumulator
accumulator *= elements[i]
func batchInvert*[F](dst: openArray[F], source: openArray[F]): bool {.inline.} =
if dst.len != source.len:
return false
let N = dst.len
batchInvert(dst.asUnchecked(), source.asUnchecked(), N)
return true
func batchInvert*[F](dst: var openArray[F], source: openArray[F]) {.inline.} =
debug: doAssert dst.len == source.len
batchInvert(dst.asUnchecked(), source.asUnchecked(), dst.len)
func batchInvert*[N: static int, F](dst: var array[N, F], src: array[N, F]) =
batchInvert(dst.asUnchecked(), src.asUnchecked(), N)

View File

@ -17,7 +17,8 @@ import
../math/config/curves,
../math/elliptic/[
ec_twistededwards_affine,
ec_twistededwards_projective
ec_twistededwards_projective,
ec_twistededwards_batch_ops
],
../math/[
extension_fields,
@ -111,3 +112,43 @@ func deserialize*(dst: var EC_Prj, src: array[32, byte]): CttCodecEccStatus =
return cttCodecEcc_PointNotInSubgroup
return cttCodecEcc_Success
## ############################################################
##
## Banderwagon Batch Serialization
##
## ############################################################
func serializeBatch*(
dst: ptr UncheckedArray[array[32, byte]],
points: ptr UncheckedArray[EC_Prj],
N: int,
) : CttCodecEccStatus {.noInline.} =
# collect all the z coordinates
var zs = allocStackArray(Fp[Banderwagon], N)
var zs_inv = allocStackArray(Fp[Banderwagon], N)
for i in 0 ..< N:
zs[i] = points[i].z
zs_inv.batchInvert(zs, N)
for i in 0 ..< N:
var X: Fp[Banderwagon]
var Y: Fp[Banderwagon]
X.prod(points[i].x, zs_inv[i])
Y.prod(points[i].y, zs_inv[i])
let lexicographicallyLargest = Y.toBig() >= Fp[Banderwagon].getPrimeMinus1div2()
if not lexicographicallyLargest.bool():
X.neg()
dst[i].marshal(X, bigEndian)
return cttCodecEcc_Success
func serializeBatch*[N: static int](
dst: var array[N, array[32, byte]],
points: array[N, EC_Prj]): CttCodecEccStatus {.inline.} =
return serializeBatch(dst.asUnchecked(), points.asUnchecked(), N)

View File

@ -303,7 +303,7 @@ suite "Batch Operations on Banderwagon":
one.double()
var arr_fp_inv: array[n, Fp[Banderwagon]]
doAssert arr_fp_inv.batchInvert(arr_fp) == true
arr_fp_inv.batchInvert(arr_fp)
# Checking the correspondence with singular element inversion
for i in 0 ..< n:
@ -341,3 +341,27 @@ suite "Batch Operations on Banderwagon":
doAssert (expected_b == scalars[1]).bool(), "expected scalar for point `B` is incorrect"
testBatchMapToBaseField()
## Check encoding if it is as expected or not
test "Test Batch Encoding from Fixed Vectors":
proc testBatchSerialize(len: static int) =
# First the point is set to generator P
# then with each iteration 2P, 4P, . . . doubling
var points: array[len, EC]
var point {.noInit.}: EC
point.fromAffine(generator)
for i in 0 ..< len:
points[i] = point
point.double() #doubling the point
var arr: array[len, Bytes]
let stat = arr.serializeBatch(points)
# Check if the serialization took place and in expected way
doAssert stat == cttCodecEcc_Success, "Serialization Failed"
for i in 0 ..< len:
doAssert expected_bit_strings[i] == arr[i].toHex(), "bit string does not match expected"
testBatchSerialize(expected_bit_strings.len)