Skip to content

Commit

Permalink
enhance: generateChallengeScalar( ), finalizing the challenge scala…
Browse files Browse the repository at this point in the history
…r in Montgomery residue form (#352)

* added montgomery residue support for Banderwagon scalars, fixed generateChallengeScalars, added cross-client tests

* rm bin

* comment fix

* using bool instead of custom enum

* rm bin

* comments

* fixes

* Apply suggestions from code review

---------

Co-authored-by: Mamy Ratsimbazafy <[email protected]>
  • Loading branch information
agnxsh and mratsim authored Feb 2, 2024
1 parent 58d8d2c commit 5894a8d
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 28 deletions.
4 changes: 2 additions & 2 deletions constantine/eth_verkle_ipa/ipa_prover.nim
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import

# Further reference refer to this https://dankradfeist.de/ethereum/2021/07/27/inner-product-arguments.html

func genIPAConfig*(res: var IPASettings, ipaTranscript: var IpaTranscript[sha256, 32]) : bool {.inline.} =
func genIPAConfig*(res: var IPASettings, ipaTranscript: var IpaTranscript[CryptoHash, 32]) : bool {.inline.} =
# Initiates a new IPASettings
# IPASettings has all the necessary information related to create an IPA proof
# such as SRS, precomputed weights for Barycentric formula
Expand All @@ -54,7 +54,7 @@ func genIPAConfig*(res: var IPASettings, ipaTranscript: var IpaTranscript[sha256
res.numRounds.computeNumRounds(uint64(VerkleDomain))
return true

func createIPAProof*[IPAProof] (res: var IPAProof, transcript: var sha256, ic: IPASettings, commitment: EC_P, a: var openArray[Fr[Banderwagon]], evalPoint: Fr[Banderwagon]) : bool {.inline.} =
func createIPAProof*[IPAProof] (res: var IPAProof, transcript: var CryptoHash, ic: IPASettings, commitment: EC_P, a: var openArray[Fr[Banderwagon]], evalPoint: Fr[Banderwagon]) : bool {.inline.} =
## createIPAProof creates an IPA proof for a committed polynomial in evaluation form.
## `a` vectors are the evaluation points in the domain, and `evalPoint` represents the evaluation point.
transcript.domain_separator(asBytes"ipa")
Expand Down
4 changes: 2 additions & 2 deletions constantine/eth_verkle_ipa/ipa_verifier.nim
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ import
#
# ############################################################

func generateChallengesForIPA*(res: var openArray[matchingOrderBigInt(Banderwagon)], transcript: var sha256, proof: IPAProof) =
func generateChallengesForIPA*(res: var openArray[matchingOrderBigInt(Banderwagon)], transcript: var CryptoHash, proof: IPAProof) =
for i in 0 ..< 8:
transcript.pointAppend( asBytes"L", proof.L_vector[i])
transcript.pointAppend( asBytes"R", proof.R_vector[i])
res[i].generateChallengeScalar(transcript,asBytes"x")

func checkIPAProof* (ic: IPASettings, transcript: var sha256, commitment: var EC_P, proof: IPAProof, evalPoint: Fr[Banderwagon], res: Fr[Banderwagon]) : bool =
func checkIPAProof* (ic: IPASettings, transcript: var CryptoHash, commitment: var EC_P, proof: IPAProof, evalPoint: Fr[Banderwagon], res: Fr[Banderwagon]) : bool =
# Check IPA proof verifier a IPA proof for a committed polynomial in evaluation form
# It verifies whether the proof is valid for the given polynomial at the evaluation `evalPoint`
# and cross-checking it with `result`
Expand Down
4 changes: 2 additions & 2 deletions constantine/eth_verkle_ipa/multiproof.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func computePowersOfElem*(res: var openArray[Fr], x: Fr, degree: SomeSignedInt)=
# ############################################################


func createMultiProof* [MultiProof] (res: var MultiProof, transcript: var sha256, ipaSetting: IPASettings, Cs: openArray[EC_P], Fs: array[VERKLE_DOMAIN, array[VERKLE_DOMAIN, Fr[Banderwagon]]], Zs: openArray[uint8], precomp: PrecomputedWeights, basis: array[VERKLE_DOMAIN, EC_P]) : bool =
func createMultiProof* [MultiProof] (res: var MultiProof, transcript: var CryptoHash, ipaSetting: IPASettings, Cs: openArray[EC_P], Fs: array[VERKLE_DOMAIN, array[VERKLE_DOMAIN, Fr[Banderwagon]]], Zs: openArray[uint8], precomp: PrecomputedWeights, basis: array[VERKLE_DOMAIN, EC_P]) : bool =
# createMultiProof creates a multi-proof for several polynomials in the evaluation form
# The list of triplets are as follows: (C, Fs, Z) represents each polynomial commitment
# and their evaluation in the domain, and the evaluating point respectively
Expand Down Expand Up @@ -223,7 +223,7 @@ func createMultiProof* [MultiProof] (res: var MultiProof, transcript: var sha256
# ############################################################


func verifyMultiproof*(multiProof: var MultiProof, transcript : var sha256, ipaSettings: IPASettings, Cs: openArray[EC_P], Ys: openArray[Fr[Banderwagon]], Zs: openArray[uint8]) : bool =
func verifyMultiproof*(multiProof: var MultiProof, transcript : var CryptoHash, ipaSettings: IPASettings, Cs: openArray[EC_P], Ys: openArray[Fr[Banderwagon]], Zs: openArray[uint8]) : bool =
# Multiproof verifier verifies the multiproof for several polynomials in the evaluation form
# The list of triplets (C,Y,Z) represents each polynomial commitment, evaluation
# result, and evaluation point in the domain
Expand Down
41 changes: 27 additions & 14 deletions constantine/eth_verkle_ipa/transcript_gen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

# ############################################################
#
# CryptoHash Generator for Challenge Scalars
# Generator for Challenge Scalars
#
# ############################################################

Expand All @@ -17,6 +17,8 @@ import
../platforms/[primitives,abstractions],
../serialization/endians,
../math/config/[type_ff, curves],
../math/io/io_bigints,
../math/arithmetic/limbs_montgomery,
../math/[extension_fields, arithmetic],
../math/elliptic/ec_twistededwards_projective,
../hashes,
Expand All @@ -27,37 +29,48 @@ func newTranscriptGen*(res: var CryptoHash, label: openArray[byte]) =
res.update(label)

func messageAppend*(res: var CryptoHash, message: openArray[byte], label: openArray[byte]) =
res.init()
res.update(label)
res.update(message)

func messageAppend_u64*(res: var CryptoHash, label: openArray[byte], num_value: uint64) =
res.init()
res.update(label)
res.update(num_value.toBytes(bigEndian))

func domainSeparator*(res: var CryptoHash, label: openArray[byte]) =
var state {.noInit.} : CryptoHash
state.update(label)
res.update(label)

func pointAppend*(res: var CryptoHash, label: openArray[byte], point: EC_P) =
var bytes {.noInit.}: array[32, byte]
if bytes.serialize(point) == cttCodecEcc_Success:
res.messageAppend(bytes, label)

let status {.used.} = bytes.serialize(point)
debug: doAssert status == cttCodecEcc_Success, "transcript_gen.pointAppend: Serialization Failure!"
res.messageAppend(bytes, label)

func scalarAppend*(res: var CryptoHash, label: openArray[byte], scalar: matchingOrderBigInt(Banderwagon)) =
var bytes {.noInit.}: array[32, byte]

if bytes.serialize_scalar(scalar) == cttCodecScalar_Success:
res.messageAppend(bytes, label)
let status {.used.} = bytes.serialize_scalar(scalar, littleEndian)

func generateChallengeScalar*(gen: var matchingOrderBigInt(Banderwagon), transcript: var CryptoHash, label: openArray[byte]) =
debug: doAssert status == cttCodecScalar_Success, "transcript_gen.scalarAppend: Serialization Failure!"
res.messageAppend(bytes, label)

func generateChallengeScalar*(challenge: var matchingOrderBigInt(Banderwagon), transcript: var CryptoHash, label: openArray[byte]) =
# Generating Challenge Scalars based on the Fiat Shamir method
transcript.domainSeparator(label)

var hash: array[32, byte]
var hash {.noInit.} : array[32, byte]
# Finalise the transcript state into a hash
transcript.finish(hash)

if gen.deserialize_scalar(hash) == cttCodecScalar_Success:
transcript.clear()
transcript.scalarAppend(label, gen)
var interim_challenge {.noInit.}: Fr[Banderwagon]
# Safely deserialize into the Montgomery residue form
let stat {.used.} = interim_challenge.make_scalar_mod_order(hash, littleEndian)
debug: doAssert stat, "transcript_gen.generateChallengeScalar: Unexpected failure"

# Reset the Transcript state
transcript.clear()
challenge = interim_challenge.toBig()

# Append the challenge into the resetted transcript
transcript.scalarAppend(label, challenge)

34 changes: 34 additions & 0 deletions constantine/serialization/codecs_banderwagon.nim
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import
ec_twistededwards_projective,
ec_twistededwards_batch_ops
],
../math/arithmetic/limbs_montgomery,
../math/[
arithmetic/bigints,
extension_fields,
arithmetic,
constants/banderwagon_subgroups
Expand All @@ -44,6 +46,27 @@ func validate_scalar*(scalar: matchingOrderBigInt(Banderwagon)): CttCodecScalarS
return cttCodecScalar_ScalarLargerThanCurveOrder
return cttCodecScalar_Success

func make_scalar_mod_order*(reduced_scalar: var Fr[Banderwagon], src: array[32, byte], order: static Endianness = bigEndian): bool =
## Convert a 32-byte array to a field element, reducing it modulo Banderwagon's curve order if necessary.

# Which can be safely stored in a 256 BigInt
# Now incase of the scalar overflowing the last 3-bits
# it is converted from its natural representation
# to the Montgomery residue form
var res: bool = false
var scalar {.noInit.}: BigInt[256]
scalar.unmarshal(src, order)

getMont(reduced_scalar.mres.limbs, scalar.limbs,
Fr[Banderwagon].fieldMod().limbs,
Fr[Banderwagon].getR2modP().limbs,
Fr[Banderwagon].getNegInvModWord(),
Fr[Banderwagon].getSpareBits())
res = true
return res



func serialize*(dst: var array[32, byte], P: EC_Prj): CttCodecEccStatus =
## Serialize a Banderwagon point(x, y) in the format
##
Expand Down Expand Up @@ -161,6 +184,17 @@ func deserialize_scalar*(dst: var matchingOrderBigInt(Banderwagon), src: array[3
return status
return cttCodecScalar_Success

func deserialize_scalar_mod_order* (dst: var Fr[Banderwagon], src: array[32, byte], order: static Endianness = bigEndian): CttCodecScalarStatus =
## Deserialize a scalar
## Take mod value of the scalar (MOD CurveOrder)
## If the scalar values goes out of range
let stat {.used.} = dst.make_scalar_mod_order(src, order)
debug: doAssert stat, "transcript_gen.deserialize_scalar_mod_order: Unexpected failure"

return cttCodecScalar_Success

## ############################################################
##
## Banderwagon Batch Serialization
##
## ############################################################
Expand Down
92 changes: 84 additions & 8 deletions tests/t_ethereum_verkle_ipa_primitives.nim
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import
../constantine/math/arithmetic,
../constantine/math/constants/zoo_generators,
../tests/math_elliptic_curves/t_ec_template,
../constantine/ethereum_verkle_primitives
../constantine/ethereum_verkle_primitives,
../constantine/platforms/abstractions


# ############################################################
Expand Down Expand Up @@ -276,46 +277,121 @@ suite "Transcript Tests":

proc testVec()=

# Initializing a new transcript state
var tr {.noInit.}: sha256
# Generating with a new label
tr.newTranscriptGen(asBytes"simple_protocol")

# Generating Challenge Scalar
var challenge1 {.noInit.}: matchingOrderBigInt(Banderwagon)
challenge1.generateChallengeScalar(tr,asBytes"simple_challenge")

var challenge2 {.noInit.}: matchingOrderBigInt(Banderwagon)
challenge2.generateChallengeScalar(tr,asBytes"simple_challenge")
var b1 {.noInit.} : array[32, byte]
let stat = b1.serialize_scalar(challenge1, littleEndian)
doAssert stat == cttCodecScalar_Success, "Serialization Failure"

doAssert (challenge1 == challenge2).bool() == false , "calling ChallengeScalar twice should yield two different challenges"
# Comparing with Go-IPA implementation
doAssert b1.toHex() == "0xc2aa02607cbdf5595f00ee0dd94a2bbff0bed6a2bf8452ada9011eadb538d003", "Incorrect Value!"

testVec()

test "Transcript testing with same challenge scalar to test transcript correctness":

proc testVec1()=

# Initializing 2 new transcript states
var tr {.noInit.}: sha256
var tr2 {.noInit.}: sha256

# Generating 2 new labels into 2 separate transcripts
tr.newTranscriptGen(asBytes"simple_protocol")
tr2.newTranscriptGen(asBytes"simple_protocol")


# Generating Challenge Scalar for Transcript 1
var challenge1 {.noInit.}: matchingOrderBigInt(Banderwagon)
challenge1.generateChallengeScalar(tr,asBytes"ethereum_challenge")

# Generating Challenge Scalar for Transcript 2
var challenge2 {.noInit.}: matchingOrderBigInt(Banderwagon)
challenge2.generateChallengeScalar(tr2,asBytes"ethereum_challenge")

# Challenge 1 should be equal to Challenge 2 as both are coming from different transcript
# states that are being handled similarly
doAssert (challenge1 == challenge2).bool() == true , "calling ChallengeScalar twice should yield the same challenge"

testVec1()

test "Transcript testing with repititive append of scalars, thereby a compound challenge scalar":
proc testVec2()=

# Initializing a new transcript state
var tr {.noInit.}: sha256

# Generating with a new label
tr.newTranscriptGen(asBytes"simple_protocol")

var five {.noInit.} : matchingOrderBigInt(Banderwagon)
five.fromUint(uint64(5))

# Appending some scalars to the transcript state
tr.scalarAppend(asBytes"five", five)
tr.scalarAppend(asBytes"five again", five)

var challenge {.noInit.}: matchingOrderBigInt(Banderwagon)
challenge.generateChallengeScalar(tr, asBytes"simple_challenge")

var c_bytes {.noInit.}: array[32, byte]
discard c_bytes.serialize_scalar(challenge, littleEndian)

# Comparing with Go-IPA Implmentation
doAssert c_bytes.toHex() == "0x498732b694a8ae1622d4a9347535be589e4aee6999ffc0181d13fe9e4d037b0b", "Some issue in Challenge Scalar"

testVec2()

test "Transcript testing with +1 and -1, appending them to be a compound challenge scalar":
proc testVec3() =

# Initializing a new transcript state
var tr {.noInit.}: sha256

# Generating with a new label
tr.newTranscriptGen(asBytes"simple_protocol")

var one {.noInit.}: matchingOrderBigInt(Banderwagon)
var minus_one {.noInit.}: Fr[Banderwagon]
# As scalar append and generating challenge scalars mainly deal with BigInts
# and BigInts usually store unsigned values, this test checks if the Transcript state
# generates the correct challenge scalar, even when a signed BigInt such as -1 is
# appended to the transcript state.
minus_one.setMinusOne()

# Here first `minus_one` is set to -1 MOD (Banderwagon Curve Order)
# and then in-place converted to BigInt while append to the transcript state.
one.setOne()

# Constructing a Compound Challenge Scalar
tr.scalarAppend(asBytes"-1", minus_one.toBig())
tr.domainSeparator(asBytes"separate me")
tr.scalarAppend(asBytes"-1 again", minus_one.toBig())
tr.domainSeparator(asBytes"separate me again")
tr.scalarAppend(asBytes"now 1", one)

var challenge {.noInit.}: matchingOrderBigInt(Banderwagon)
challenge.generateChallengeScalar(tr, asBytes"simple_challenge")

var c_bytes {.noInit.}: array[32, byte]
discard c_bytes.serialize_scalar(challenge, littleEndian)

doAssert c_bytes.toHex() == "0x14f59938e9e9b1389e74311a464f45d3d88d8ac96adf1c1129ac466de088d618", "Computed challenge is incorrect!"

testVec3()

# ############################################################
#
# Test for IPA Proofs
#
# ############################################################


suite "IPA proof tests":
test "Test for initiating IPA proof configuration":
proc testMain()=
Expand All @@ -330,7 +406,7 @@ suite "IPA proof tests":
var point: Fr[Banderwagon]
var ipaConfig: IPASettings
var ipaTranscript: IpaTranscript[sha256, 32]
let stat1 = ipaConfig.genIPAConfig(ipaTranscript)
discard ipaConfig.genIPAConfig(ipaTranscript)

var testGeneratedPoints: array[256, EC_P]
testGeneratedPoints.generate_random_points(ipaTranscript, 256)
Expand Down Expand Up @@ -370,7 +446,7 @@ suite "IPA proof tests":
var point : Fr[Banderwagon]
var ipaConfig: IPASettings
var ipaTranscript: IpaTranscript[sha256, 32]
let stat1 = ipaConfig.genIPAConfig(ipaTranscript)
discard ipaConfig.genIPAConfig(ipaTranscript)

var testGeneratedPoints: array[256,EC_P]
testGeneratedPoints.generate_random_points(ipaTranscript,256)
Expand Down

0 comments on commit 5894a8d

Please sign in to comment.