diff --git a/poseidon2/merkle.nim b/poseidon2/merkle.nim index 3f7ec15..c1f44ce 100644 --- a/poseidon2/merkle.nim +++ b/poseidon2/merkle.nim @@ -1,3 +1,7 @@ +# +# Merkle trees, used a drop-in replacement for hash functions +# + import constantine/math/arithmetic import constantine/math/io/io_fields import ./types @@ -55,12 +59,14 @@ func finish*[which](merkle: var Merkle[which]): F = return merkle.todo[0] +# Merkle root of a sequence of field elements (here the Merkle tree is used as a hash function!) func digest*(_: type Merkle, elements: openArray[F], which: static Flavour = HorizenLabsOld): F = var merkle = Merkle.init(which = which) for element in elements: merkle.update(element) return merkle.finish() +# Merkle root of a sequence of bytes (here the Merkle tree is used as a hash function!) func digest*(_: type Merkle, bytes: openArray[byte], which: static Flavour = HorizenLabsOld): F = var merkle = Merkle.init(which = which) for element in bytes.elements(F): diff --git a/poseidon2/sponge.nim b/poseidon2/sponge.nim index 08e4ce4..a345677 100644 --- a/poseidon2/sponge.nim +++ b/poseidon2/sponge.nim @@ -15,18 +15,45 @@ type #------------------------------------------------------------------------------- # rate = 1 -func init[which](sponge: var Sponge[1,which]) = - # domain separation IV := (2^64 + 256*t + r) - const IV = F.fromHex("0x10000000000000301") +# +# domain separation convention: +# +# The sponge state is initialized to `(0,0,domsep)` with +# +# domsep IV := (2^64 + 2^24*padding + 2^16*inputfmt + 2^8*t + rate) +# +# - t = 3 (the state width) +# - rate = 1 or 2 +# - input format is: +# - 254 when hashing BN254 field elements +# - 8 when hashing bytes +# - 1 when hashing bits (not implemented) +# - padding is +# - 1 the `10*` padding convention for field elements +# - 16 the `10*` padding convention for bytes only (to a multiple of 31 or 62, depending on rate) +# - 17 padding both bytes (to a multiple of 31) and then the resulting field elements (multiple of rate) +# - 255 for no padding +# +# note: domain separation is IMPORTANT, especially when mixing byte sequences +# with field element sequences, and not being very careful with padding! +# + +const DOMSEP_IV_RATE1_FELTS*: F = F.fromHex("0x10000000001fe0301") +const DOMSEP_IV_RATE1_BYTES*: F = F.fromHex("0x10000000011080301") + +const DOMSEP_IV_RATE2_FELTS*: F = F.fromHex("0x10000000001fe0302") +const DOMSEP_IV_RATE2_BYTES*: F = F.fromHex("0x10000000011080302") + +func init[which](sponge: var Sponge[1,which], domSep: F = DOMSEP_IV_RATE1_FELTS) = sponge.s0 = zero sponge.s1 = zero - sponge.s2 = IV + sponge.s2 = domSep -func update*[which](sponge: var Sponge[1,which], element: F) = # , which: static Flavour = HorizenLabsOld) = +func update*[which](sponge: var Sponge[1,which], element: F) = sponge.s0 += element permInPlace(sponge.s0, sponge.s1, sponge.s2, which = which) -func finish*[which](sponge: var Sponge[1,which]): F = # , which: static Flavour = HorizenLabsOld): F = +func finish*[which](sponge: var Sponge[1,which]): F = # padding sponge.s0 += one permInPlace(sponge.s0, sponge.s1, sponge.s2, which = which) @@ -35,15 +62,13 @@ func finish*[which](sponge: var Sponge[1,which]): F = # , which: static Flavour #------------------------------------------------------------------------------- # rate = 2 -func init[which](sponge: var Sponge[2,which]) = - # domain separation IV := (2^64 + 256*t + r) - const IV = F.fromHex("0x10000000000000302") +func init[which](sponge: var Sponge[2,which], domSep: F = DOMSEP_IV_RATE2_FELTS) = sponge.s0 = zero sponge.s1 = zero - sponge.s2 = IV + sponge.s2 = domSep sponge.even = true -func update*[which](sponge: var Sponge[2,which], element: F) = # , which: static Flavour = HorizenLabsOld) = +func update*[which](sponge: var Sponge[2,which], element: F) = if sponge.even: sponge.s0 += element else: @@ -51,7 +76,7 @@ func update*[which](sponge: var Sponge[2,which], element: F) = # , which: static permInPlace(sponge.s0, sponge.s1, sponge.s2, which = which) sponge.even = not sponge.even -func finish*[which](sponge: var Sponge[2,which]): F = #: static Flavour = HorizenLabsOld): F = +func finish*[which](sponge: var Sponge[2,which]): F = if sponge.even: # padding even input sponge.s0 += one @@ -70,14 +95,42 @@ func init*(_: type Sponge, rate: static int = 2, which: static Flavour = Horizen {.error: "only rate 1 and 2 are supported".} result.init +func initWithDomSep*(_: type Sponge, rate: static int = 2, domSep: F, which: static Flavour = HorizenLabsOld): Sponge[rate,which] = + when rate notin {1, 2}: + {.error: "only rate 1 and 2 are supported".} + result.init(domSep = domSep) + # spone.s2 = domSep + +# digest of a sequence of field elements func digest*(_: type Sponge, elements: openArray[F], rate: static int = 2, which: static Flavour = HorizenLabsOld): F = - var sponge = Sponge.init(rate = rate, which = which) + + var domsep: F + if rate == 1: + domsep = DOMSEP_IV_RATE1_FELTS + elif rate == 2: + domsep = DOMSEP_IV_RATE2_FELTS + else: + discard + + var sponge = Sponge.initWithDomSep(rate = rate, domSep = domsep, which = which) for element in elements: sponge.update(element) return sponge.finish() +# digest of a sequence of bytes func digest*(_: type Sponge, bytes: openArray[byte], rate: static int = 2, which: static Flavour = HorizenLabsOld): F = - var sponge = Sponge.init(rate = rate, which = which) + + var domsep: F + if rate == 1: + domsep = DOMSEP_IV_RATE1_BYTES + elif rate == 2: + domsep = DOMSEP_IV_RATE2_BYTES + else: + discard + + var sponge = Sponge.initWithDomSep(rate = rate, domSep = domsep, which = which) for element in bytes.elements(F): sponge.update(element) return sponge.finish() + +#------------------------------------------------------------------------------- diff --git a/poseidon2/spongemerkle.nim b/poseidon2/spongemerkle.nim index 967d03a..5f7d878 100644 --- a/poseidon2/spongemerkle.nim +++ b/poseidon2/spongemerkle.nim @@ -1,3 +1,7 @@ +# +# Merkle trees over a sequence of bytestrings +# + import ./types import ./merkle import ./sponge @@ -18,7 +22,7 @@ func update*[which](spongemerkle: var SpongeMerkle[which], chunk: openArray[byte func finish*[which](spongemerkle: var SpongeMerkle[which]): F = return spongemerkle.merkle.finish() -func digest*(_: type SpongeMerkle, bytes: openArray[byte], chunkSize: int, which: static Flavour = HorizenLabsOld): F = +func digestFixedChunks*(_: type SpongeMerkle, bytes: openArray[byte], chunkSize: int, which: static Flavour = HorizenLabsOld): F = ## Hashes chunks of data with a sponge of rate 2, and combines the ## resulting chunk hashes in a merkle root. var spongemerkle = SpongeMerkle.init(which = which) @@ -29,3 +33,11 @@ func digest*(_: type SpongeMerkle, bytes: openArray[byte], chunkSize: int, which spongemerkle.update(bytes.toOpenArray(start, finish - 1)) index += chunkSize return spongemerkle.finish() + +func digest*(_: type SpongeMerkle, byteSeqs: openArray[seq[byte]], which: static Flavour = HorizenLabsOld): F = + ## Hashes chunks of data with a sponge of rate 2, and combines the + ## resulting chunk hashes in a merkle root. + var spongemerkle = SpongeMerkle.init(which = which) + for index in 0.. Int -> ByteString + # makeInput n j = B.pack $ map (fromIntegral :: Int -> Word8) [0..j-1] + # + # makeInputs :: Int -> [ByteString] + # makeInputs n = [ makeInput n j | j<-[1..n] ] + # + + for n in 1..81: + var inputs: seq[seq[byte]] = newSeq[seq[byte]]() + for j in 1..n: + var bytes: seq[byte] = newSeq[byte](j) + for i in 0..j-1: + bytes[i] = byte(i) + inputs.add(bytes) + + let root = SpongeMerkle.digest(inputs, which = HorizenLabsOld) + let expected = expectedSpongeMerkleResults_oldconstants[n-1] + + check bool( toDecimal(root) == expected) + +#------------------------------------------------------------------------------- + +suite "sponge-merkle root test vectors (new round constants)": + + const expectedSpongeMerkleResults_newconstants : array[81, string] = + [ "16106936217773488732114707136659579475039188182303473285991086909582255760813", + "21749399151008613146906992853707653458950578828151260507349888266882735090033", + "07615848664528200129121474265923162920724325782071238591017928661750099497118", + "04269040087840470508922342006390431168100458550394975870128858129394423837686", + "11909495372117408419064340432441167763732820969531486899351462734507847230120", + "09623551064734467841777505352687228831332065462156396123462342330498656107639", + "01923122361160389809840562134805645636119746122867292253865481252908692241636", + "09374656801801208201915510249757793623583371587325362370560767250768726761702", + "05380781044035989060288046707204064439518450659309200099374350654192946492732", + "20266035748238927774027269735432472351037817093683305679372405236706175735664", + "02416168066522983534720378587673069117497466620465720550127139662589501895384", + "21646315564996404895709641714887124859419926515588970989763359019227476431156", + "03599540780088241030700919263758096707042314521989714394236666205194167639292", + "16342064934103837174048129843168166937561837148488746961577631865123986227842", + "16508518618162518007275769956824846372370426317235608285105885953754139326849", + "00298618134235314604128618009387381464821437895788628314470737986441443733908", + "09132340604368324181809699721169450056473307660602077371154375460533257822910", + "09627689776724825827261802353716361529825159379894616381445783454707265764632", + "20597515270126452023579219644324538936499010488543190919288973617995170615083", + "02138881138580869794840608034391349171932744817542674152871775953181348597362", + "15840379631235293457048455683670448542220216878564098546761115325436270653082", + "06496588082060530023558206142803725199083883589113831025750573586050165485510", + "09096996941419280530522999878310766007172912259819889533479040624955987114936", + "06539079796069232976817752880500625737582033407513792289868656766230505369280", + "12136369185149927301667564117980104605983402989998935140032879392177752276949", + "17891418731598692782915178730675266400990557628342320066399249313681244046057", + "04970437575623654619207537243890797382875919069514429582444124497695825284766", + "09910621566300327115556949555006057474254862620812676329286506138269806168303", + "04927794288800780546142017971468992126674690061858294551922732994110952774055", + "04843699357438086063382848334512197828424626722797762331317888142473399784102", + "09280486434661104381386320501890371432681704710315212305963462426725442981532", + "10771884053877714733123323273165653990323162928924442408538867238579748893264", + "21519328836661449244592449156944420083318785273344153864319619838907089525712", + "09226735909908114913088419137790274963982519549138807409387415251315582594960", + "02889094603530823256270130378620319510697185098978542193238645190142732482171", + "04451133582913418958501568008330579360047913653419584057516702293936931177698", + "13087394952469092373767778107679085631016082317224984033414358183426901028024", + "20074269777739483959077084202692696332895240747453622100621166964735946483771", + "00994124961482610172956773256240164003415620665268537533785482050899591866637", + "10804785206270592442628609926083834977845866272408941750236115952533859766355", + "02368687109817313455166799040925587643597004200291791253163047920441253090435", + "12222337111630828777977981650531037487601367942523278746783946816611008474247", + "18864538446103571516222660327246455540056332692105020001468591895963612481707", + "20330810490097749656019521627006626144901588010272818694725428830664273851196", + "04161861927026241971299783840307709624707246412051375250314147112261412518099", + "04640000953918440669992971009867067034478595026322063124166163191898810376114", + "16066787535396169742674383023081280340994712360840025594454191215927092842016", + "00736034456941105961388640729582608482209338686510087601088518987119727347046", + "19218882574847262543462084675030725289535306720000572960850025935546380708622", + "06326041394779058261647394686665756637183347036048181459758008162052839089459", + "20524992412783385892230376054341084664503037052792685338735818272864502902467", + "06303244711291199980507571856813826291644485110042948017148936644950502800656", + "09687438763363502754353958780409137340373402881771663917442431795283762742200", + "07393721607299654338612163303611615927647381694304414902179001529565436304004", + "00769299206827118828423721238345795180980386231688050996247579479410142733573", + "15356142515946486412361064104631985279516652436112663877624123998857317846062", + "12944394552851636887823569941599653223264312735650698705280915856595690453423", + "19257744271863192120032576801551796358147018485046545304766477230029886225991", + "11553121321170226180235915708569160525393362863129643259015477852812918125982", + "10383932945432596020387936181196688777215063374740862187927809654011866463962", + "13698576125535108584081024020871121284718720353945957107340406960531378082899", + "14766738048837258982368663710755955729966053739719953129479420517306564286057", + "14150370579625075584176186632683221471463481813142770634617948838462973217297", + "15703901400482664258208036264087636185420814463522725816008587625070722774660", + "21628863922296828936108793664365083848175178900851798238279153167762247212544", + "17994964179538203022789294598594696226457805472794747773570869995060134870000", + "14173664202384290972662307152626682324715089270145146626777252634804182088198", + "10259818538204037395642496304708180387331957267869030925460874027794979016914", + "04348517106183457755278591374986616028657425266802126959553253893408186029650", + "15353841401401031036196880589610688940911038016281981833717765850488408078543", + "13184449229727484135058795690270607193246552342045159689255485399024532339099", + "01280799013898452490128673542335363702792730127220297813199628076315500079287", + "17724139026752938082955702370592493012916376150326371546398913067689930803474", + "19681190042322570232370779235592644315085065044612722237027324840799540250394", + "00923102699142118835876108627315848969604392841598826632855749214047808831233", + "12682658082539677084438931331375565342254547419452256411929547954379881796014", + "17246130195602399633915379969768231501448212613503611421115280072337576774889", + "16725278147270471780093184101611238021795389524370940739411544149792098435822", + "15028040181755179383105400700064688696134603419011146558420290355250062242223", + "08369173688811987172616372945331414080137308477947398758527907211441929340149", + "02992056413179761701460849741660292672349406441794960088886456752947775864767", + ] + + for n in 1..81: + var inputs: seq[seq[byte]] = newSeq[seq[byte]]() + for j in 1..n: + var bytes: seq[byte] = newSeq[byte](j) + for i in 0..j-1: + bytes[i] = byte(i) + inputs.add(bytes) + + let root = SpongeMerkle.digest(inputs, which = HorizenLabsNew) + let expected = expectedSpongeMerkleResults_newconstants[n-1] + + check bool( toDecimal(root) == expected) #-------------------------------------------------------------------------------