Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add: IPA Proof and Multiproof Ser/De #350

Merged
merged 6 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions constantine/eth_verkle_ipa/eth_verkle_constants.nim
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ type
const
VerkleDomain*: int = 256

type VerkleIPAProofSerialized* = array[544, byte]

type VerkleMultiproofSerialized* = array[576, byte]

type
PrecomputedWeights* = object
barycentricWeights*: array[510,Fr[Banderwagon]]
Expand Down
150 changes: 149 additions & 1 deletion constantine/eth_verkle_ipa/ipa_prover.nim
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import
./[transcript_gen, common_utils, eth_verkle_constants, barycentric_form],
../platforms/primitives,
../hashes,
../serialization/[
codecs_banderwagon,
codecs_status_codes,
],
../math/config/[type_ff, curves],
../math/elliptic/[ec_twistededwards_projective],
../math/arithmetic,
Expand Down Expand Up @@ -160,6 +164,150 @@ func createIPAProof*[IPAProof] (res: var IPAProof, transcript: var sha256, ic: I
res.A_scalar = a[0]
return true

# ############################################################
#
# IPA proof seriaizer
#
# ############################################################

func serializeVerkleIPAProof* (dst: var VerkleIPAProofSerialized, src: IPAProof): bool =
## IPA Proofs in Verkle consists of a Left array of 8 Base Field points, a Right array of 8 Base Field points, and a Scalar Field element
## During serialization the format goes as follows:
##
## L[0] (32 - byte array) L[1] (32 - byte array) .... L[7] (32 - byte array) ..... R[0] (32 - byte array) ... R[7] (32 - byte array) A (32 - byte array)
##
## Which means the size of the byte array should be :
##
## 32 * 8 (for Left half) + 32 * 8 (for Right half) + 32 * 1 (for Scalar) = 32 * 17 = 544 elements in the byte array.
##
## ----------------------------------------------------------
##
## Note that checks like Subgroup check for Banderwagon Points for Base Field elements in L and R,
## And checks for a valid scalar checking the Banderwagon scalar Curve Order is MANDATORY. They are all checked in the further low level functions
##
var res = false
var L_bytes {.noInit.} : array[8, array[32, byte]]
var R_bytes {.noInit.} : array[8, array[32, byte]]

let stat1 = L_bytes.serializeBatch(src.L_vector)
doAssert stat1 == cttCodecEcc_Success, "Batch serialization Failure!"


let stat2 = R_bytes.serializeBatch(src.R_vector)
doAssert stat2 == cttCodecEcc_Success, "Batch Serialization Failure!"

var A_bytes {.noInit.} : array[32, byte]
let stat3 = A_bytes.serialize_scalar(src.A_scalar.toBig(), littleEndian)
doAssert stat3 == cttCodecScalar_Success, "Scalar Serialization Failure!"

var idx : int = 0

for i in 0 ..< 8:
for j in 0 ..< 32:
dst[idx] = L_bytes[i][j]
idx = idx + 1

discard L_bytes

for i in 0 ..< 8:
for j in 0 ..< 32:
dst[idx] = R_bytes[i][j]
idx = idx + 1

discard R_bytes

for i in 0 ..< 32:
dst[idx] = A_bytes[i]
idx = idx + 1

discard A_bytes

res = true
return res

# ############################################################
#
# IPA proof deserializer
#
# ############################################################

func deserializeVerkleIPAProof* (dst: var IPAProof, src: var VerkleIPAProofSerialized ): bool =
## IPA Proofs in Verkle consists of a Left array of 8 Base Field points, a Right array of 8 Base Field points, and a Scalar Field element
## During deserialization the format goes as follows:
##
## L[0] (32 - byte array) L[1] (32 - byte array) .... L[7] (32 - byte array) ..... R[0] (32 - byte array) ... R[7] (32 - byte array) A (32 - byte array)
##
## Which means the size of the byte array should be :
##
## 32 * 8 (for Left half) + 32 * 8 (for Right half) + 32 * 1 (for Scalar) = 32 * 17 = 544 elements in the byte array.
## ----------------------------------------------------------
##
## Note that check for Lexicographically Largest criteria for the Y - coordinate of the Twisted Edward Banderwagon point is MANDATORY
## And, is pre-checked within this function from the `deserialize` function.
##
var res = false

var L_bytes {.noInit.} : array[8, array[32, byte]]
var R_bytes {.noInit.} : array[8, array[32, byte]]
var A_bytes {.noInit.} : array[32, byte]

var L_side {.noInit.} : array[8, EC_P]
var R_side {.noInit.} : array[8, EC_P]

var A_inter {.noInit.} : matchingOrderBigInt(Banderwagon)
var A_fr {.noInit.} : Fr[Banderwagon]

var idx : int = 0

for i in 0 ..< 8:
for j in 0 ..< 32:
L_bytes[i][j] = src[idx]
idx = idx + 1

for i in 0 ..< 8:
for j in 0 ..< 32:
R_bytes[i][j] = src[idx]
idx = idx + 1

for i in 0 ..< 32:
A_bytes[i] = src[idx]
idx = idx + 1

var i : int = 0
for item in L_bytes.items():
let stat = L_side[i].deserialize(item)
doAssert stat == cttCodecEcc_Success, "Deserialization failure!"
i = i + 1

discard L_bytes

doAssert i == 8, "Should be 8!"

i = 0
for item in R_bytes.items():
let stat = R_side[i].deserialize(item)
doAssert stat == cttCodecEcc_Success, "Deserialization failure!"
i = i + 1

discard R_bytes

doAssert i == 8, "Should be 8!"

let stat2 = A_inter.deserialize_scalar(A_bytes, littleEndian)
doAssert stat2 == cttCodecScalar_Success, "Scalar Deserialization failure!"

discard A_bytes

dst.L_vector = L_side
dst.R_vector = R_side

A_fr.fromBig(A_inter)

dst.A_scalar = A_fr

res = true
return res

# ############################################################
#
# IPA proof equality checker
Expand Down Expand Up @@ -197,4 +345,4 @@ func isIPAProofEqual* (p1: IPAProof, p2: IPAProof) : bool =

else:
res = true
return res
return res
100 changes: 100 additions & 0 deletions constantine/eth_verkle_ipa/multiproof.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import
./[transcript_gen, common_utils, ipa_prover, barycentric_form, eth_verkle_constants, ipa_verifier],
../platforms/primitives,
../hashes,
../serialization/[
codecs_banderwagon,
codecs_status_codes,
],
../math/config/[type_ff, curves],
../math/elliptic/[ec_multi_scalar_mul, ec_multi_scalar_mul_scheduler],
../math/elliptic/[ec_twistededwards_projective, ec_twistededwards_batch_ops],
Expand Down Expand Up @@ -335,3 +339,99 @@ func verifyMultiproof*(multiProof: var MultiProof, transcript : var sha256, ipaS

res = ipaSettings.checkIPAProof(transcript, EMinusD, multiProof.IPAprv, t_fr, g2t)
return res

# ############################################################
#
# Multiproof Serializer
#
# ############################################################

func serializeVerkleMultiproof* (dst: var VerkleMultiproofSerialized, src: var MultiProof) : bool =
##
## Multiproofs in Verkle have a format of
##
## 1) The queried Base Field where the Vector Commitment `opening` is created
## Consider this as the equivalent to the `Merkle Path` in usual Merkle Trees.
##
## 2) The entire IPAProof which is exactly a 576 byte array, go through `serializeIPAProof` for the breakdown
##
## The format of serialization is as:
##
## Query Point (32 - byte array) .... IPAProof (544 - byte array) = 32 + 544 = 576 elements in the byte array
##
var res = false
var ipa_bytes {.noInit.} : array[544, byte]
var d_bytes {.noInit.} : array[32, byte]

let stat = ipa_bytes.serializeVerkleIPAProof(src.IPAprv)
doAssert stat == true, "IPA Serialization failed"

let stat2 = d_bytes.serialize(src.D)
doAssert stat2 == cttCodecEcc_Success, "Query point serialization failed"

var idx : int = 0

for i in 0 ..< 32:
dst[idx] = d_bytes[i]
idx = idx + 1

discard d_bytes

for i in 0 ..< 544:
dst[idx] = ipa_bytes[i]
idx = idx + 1

discard ipa_bytes

res = true
return res

# ############################################################
#
# Multiproof Deserializer
#
# ############################################################

func deserializeVerkleMultiproof* (dst: var MultiProof, src: var VerkleMultiproofSerialized) : bool =
##
## Multiproofs in Verkle have a format of
##
## 1) The queried Base Field where the Vector Commitment `opening` is created
## Consider this as the equivalent to the `Merkle Path` in usual Merkle Trees.
##
## 2) The entire IPAProof which is exactly a 576 byte array, go through `serializeIPAProof` for the breakdown
##
## The format of serialization is as:
##
## Query Point (32 - byte array) .... IPAProof (544 - byte array) = 32 + 544 = 576 elements in the byte array
##
var res = false
var ipa_bytes {.noInit.} : array[544, byte]
var d_bytes {.noInit.} : array[32, byte]

var idx : int = 0

for i in 0 ..< 32:
d_bytes[i] = src[idx]
idx = idx + 1

for i in 0 ..< 544:
ipa_bytes[i] = src[idx]
idx = idx + 1

var ipa_prv {.noInit.} : MultiProof.IPAprv
let stat1 = ipa_prv.deserializeVerkleIPAProof(ipa_bytes)
doAssert stat1 == true, "IPA Deserialization Failure!"

dst.IPAprv = ipa_prv
discard ipa_prv

var d_fp {.noInit.} : MultiProof.D
let stat2 = d_fp.deserialize(d_bytes)
doAssert stat2 == cttCodecEcc_Success, "Query Point Deserialization Failure!"

dst.D = d_fp
discard d_fp

res = true
return res
8 changes: 7 additions & 1 deletion constantine/ethereum_verkle_trees.nim
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export
eth_verkle_constants.IPASettings,
eth_verkle_constants.VerkleSeed,
eth_verkle_constants.Bytes,
eth_verkle_constants.VerkleIPAProofSerialized,
eth_verkle_constants.VerkleMultiproofSerialized,
eth_verkle_constants.IpaTranscript,
eth_verkle_constants.Coord,
eth_verkle_constants.generator
Expand Down Expand Up @@ -64,6 +66,8 @@ export
export
ipa_prover.genIPAConfig,
ipa_prover.createIPAProof,
ipa_prover.serializeVerkleIPAProof,
ipa_prover.deserializeVerkleIPAProof,
ipa_prover.isIPAProofEqual

# IPA Verifier for Verkle
Expand All @@ -79,4 +83,6 @@ export
multiproof.domainToFrElem,
multiproof.computePowersOfElem,
multiproof.createMultiProof,
multiproof.verifyMultiProof
multiproof.verifyMultiProof,
multiproof.serializeVerkleMultiproof,
multiproof.deserializeVerkleMultiproof
26 changes: 26 additions & 0 deletions tests/t_ethereum_verkle_ipa_primitives.nim
Original file line number Diff line number Diff line change
Expand Up @@ -489,3 +489,29 @@ suite "Multiproof Tests":
doAssert stat_verify_mult.bool() == true, "Multiproof verification error!"

testMultiproofCreationAndVerification()

test "Multiproof Serialization and Deserialization (Covers IPAProof Serialization and Deserialization as well)":
proc testMultiproofSerDe() =

## Pull a valid Multiproof from a valid hex test vector as used in Go-IPA https://github.com/crate-crypto/go-ipa/blob/master/multiproof_test.go#L120-L121
var validMultiproof_bytes {.noInit.} : VerkleMultiproofSerialized
validMultiproof_bytes.fromHex(validMultiproof)

var multiprv {.noInit.} : MultiProof

## Deserialize it into the Multiproof type
let stat1 = multiprv.deserializeVerkleMultiproof(validMultiproof_bytes)
doAssert stat1 == true, "Failed to Serialize Multiproof"

discard validMultiproof_bytes

## Serialize the Multiproof type in to a serialize Multiproof byte array
var validMultiproof_bytes2 {.noInit} : VerkleMultiproofSerialized
let stat2 = validMultiproof_bytes2.serializeVerkleMultiproof(multiprv)
doAssert stat2 == true, "Failed to Deserialize Multiproof"

## Check the serialized Multiproof with the valid hex test vector
doAssert validMultiproof_bytes2.toHex() == validMultiproof, "Error in the Multiproof Process!"

testMultiproofSerDe()

9 changes: 9 additions & 0 deletions tests/t_ethereum_verkle_ipa_test_helper.nim
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,15 @@ func getDegreeOfPoly*(res: var int, p: openArray[Fr]) =
else:
res = -1

###################################################################
##
##
## Test Vector for Valid Multiproof Hex
##
##
###################################################################

const validMultiproof* : string = "0x4f53588244efaf07a370ee3f9c467f933eed360d4fbf7a19dfc8bc49b67df4711bf1d0a720717cd6a8c75f1a668cb7cbdd63b48c676b89a7aee4298e71bd7f4013d7657146aa9736817da47051ed6a45fc7b5a61d00eb23e5df82a7f285cc10e67d444e91618465ca68d8ae4f2c916d1942201b7e2aae491ef0f809867d00e83468fb7f9af9b42ede76c1e90d89dd789ff22eb09e8b1d062d8a58b6f88b3cbe80136fc68331178cd45a1df9496ded092d976911b5244b85bc3de41e844ec194256b39aeee4ea55538a36139211e9910ad6b7a74e75d45b869d0a67aa4bf600930a5f760dfb8e4df9938d1f47b743d71c78ba8585e3b80aba26d24b1f50b36fa1458e79d54c05f58049245392bc3e2b5c5f9a1b99d43ed112ca82b201fb143d401741713188e47f1d6682b0bf496a5d4182836121efff0fd3b030fc6bfb5e21d6314a200963fe75cb856d444a813426b2084dfdc49dca2e649cb9da8bcb47859a4c629e97898e3547c591e39764110a224150d579c33fb74fa5eb96427036899c04154feab5344873d36a53a5baefd78c132be419f3f3a8dd8f60f72eb78dd5f43c53226f5ceb68947da3e19a750d760fb31fa8d4c7f53bfef11c4b89158aa56b1f4395430e16a3128f88e234ce1df7ef865f2d2c4975e8c82225f578310c31fd41d265fd530cbfa2b8895b228a510b806c31dff3b1fa5c08bffad443d567ed0e628febdd22775776e0cc9cebcaea9c6df9279a5d91dd0ee5e7a0434e989a160005321c97026cb559f71db23360105460d959bcdf74bee22c4ad8805a1d497507"

###################################################################
##
Expand Down
Loading