diff --git a/constantine/math/elliptic/ec_twistededwards_batch_ops.nim b/constantine/math/elliptic/ec_twistededwards_batch_ops.nim index cdcf684..442c50b 100644 --- a/constantine/math/elliptic/ec_twistededwards_batch_ops.nim +++ b/constantine/math/elliptic/ec_twistededwards_batch_ops.nim @@ -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) diff --git a/constantine/serialization/codecs_banderwagon.nim b/constantine/serialization/codecs_banderwagon.nim index ea6c918..f381460 100644 --- a/constantine/serialization/codecs_banderwagon.nim +++ b/constantine/serialization/codecs_banderwagon.nim @@ -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, @@ -110,4 +111,44 @@ func deserialize*(dst: var EC_Prj, src: array[32, byte]): CttCodecEccStatus = if not(bool dst.isInSubgroup()): return cttCodecEcc_PointNotInSubgroup - return cttCodecEcc_Success \ No newline at end of file + 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) \ No newline at end of file diff --git a/tests/t_ethereum_verkle_primitives.nim b/tests/t_ethereum_verkle_primitives.nim index 2cb73f6..7fb4764 100644 --- a/tests/t_ethereum_verkle_primitives.nim +++ b/tests/t_ethereum_verkle_primitives.nim @@ -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: @@ -340,4 +340,28 @@ suite "Batch Operations on Banderwagon": doAssert (expected_a == scalars[0]).bool(), "expected scalar for point `A` is incorrect" doAssert (expected_b == scalars[1]).bool(), "expected scalar for point `B` is incorrect" - testBatchMapToBaseField() \ No newline at end of file + 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) \ No newline at end of file