Skip to Content
ReferenceTest vectors

Copied from docs/TEST-VECTORS.md  at build time. Edit that file.

zx402: Test Vectors

FieldValue
Statusv1.0, 2026-10-06
Machine-readable filesvectors/poseidon-vectors.json , vectors/encoding-vectors.json , vectors/groth16-vectors.json , vectors/key-vectors.json 
CompanionsSPEC.md section 4, TEST-PLAN.md

These are known answers. An implementation is correct only if it reproduces them. Never edit a vector to make a test pass.

1. How these vectors were made

  • Poseidon vectors: computed with poseidon-bls12381 1.0.2. A circom circuit built from poseidon-bls12381-circom 1.0.0 gave the same outputs. The check ran with circom 2.2.3 and snarkjs 0.7.6.
  • Encoding vectors: computed with vectors/encoding_vectors.py , which follows SPEC sections 4.4 and 4.5 line by line.
  • Groth16 vectors: a real snarkjs proof on curve bls12-381, converted to compressed bytes and verified with Plutus builtins in an Aiken test.

All field elements are decimal. All byte strings are lowercase hex.

r is the field prime:

r = 52435875175126190479447740508185965837690552500527637822603658699938581184513 = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001

2. Poseidon255

H1, H2, and H3 are poseidon1, poseidon2, and poseidon3 in the JavaScript library. They are Poseidon255(1), Poseidon255(2), and Poseidon255(3) in circom.

FunctionInputsOutput
H102811068068091031911201269074038037779542827974520177560187358960284013358662
H1133312903538086167554741214005086116725441315171650202128840830167854170336490
H1217889845856397553779318975219882180584831719213776877975727308309479382137869
H1r - 17813170824547960260738571974704552535576767123587963859613076085894492214587
H20, 051576823595707970152643159819788304363803754756066229172775779360774743019614
H21, 228821147804331559602169231704816259064962739503761913593647409715501647586810
H22, 138495653493229404436964394677907381793366115704270664029389503644145292560024
H2r - 1, r - 113749015692973795093326134640289425716893530583220479127948941647063541061741
H30, 0, 02730905762547441968003121309138324946079012218264271483639179080642326469387
H31, 2, 341091099622722973056082071867846799679887891223501702244297781245659866568853
H33, 2, 140534334082547568663372484250048352425565615075186793931897048837941546368699

In hex, H2(1, 2) is 0x3fb8310b0e962b75bffec5f9cfcbf3f965a7b1d2dcac8d95ccb13d434e08e5fa. Both upstream libraries assert this value in their own tests.

Warnings:

  • The JavaScript library does not range-check inputs. H1(r) equals H1(0). Reject any value of r or more before hashing.
  • The library accepts BigInt or numeric strings. A JavaScript Number throws.
  • Other Poseidon parameter sets for this field give different values. These vectors fit this library only.

3. Zero hashes

Z[0] = 0 and Z[i+1] = H2(Z[i], Z[i]). The empty tree root is Z[32].

iZ[i]
00
151576823595707970152643159819788304363803754756066229172775779360774743019614
233646187916922823865935622258451714952164674255482660942215703235411158105736
327818645450144846908742692719385898720249207574255739267233226464286012246073
439404029000907277292464556408734412130261913210564395069696342233560511006152
524907123534309659921713005795092724527532698077589223246276579583330771465031
622103361713848256938655449390262013863291224679776344310249539314760174194771
728665358770471415124367990738618755861132249577405347373337125991381323369983
86786998243528185650306462855937293964443624194496859265310261299800128548513
950997336463747555660384185705133244552288600683323691317203235239320942865561
1013916937046501108967048154641689659101970478684843793251827738918983778486795
1118687330317699879820441947090357020131335081966987817560646762002601404312692
125829984778942235508054786484586420582947187778500268001993713384889194068958
1350753373693280024567332706650665895696517500665837690627852645244127601005954
141121944223990168834607757664588750855677305893915654403458231958042499198410
1536305469446279205776473409399606075705498404819785351200416937243175517105400
1635469255857533658984001872129259281494468859278269474829072253610856427637368
1725002462511210597541252327993404833104943873248749427570203455562220619092990
1810886081007110941254401730551833799559046107841056410372886204429067753525173
1942912979393075378276322569383190765808963985610018715455225906661987202405442
2017829666917206563427639071038301760428441910791113344915950879171718159851699
2119959276178289919454624964033156874212383627630834686313695346050977724605069
2223989753422250835433889368180384720833918212448397225750725913542081009371602
2330676787872348478191822243338725486111070704489819315495569589143785123050098
2425400627233432738585719544580033466956420584769957678836609603389338933363270
2524790024100310572264101231265718453471525549456629575928571511811696933715746
2632075852797240796685207471461798732683947259283520477880592601361588212812696
2732906066193481495156743794651229831300236677336460633963901602814611572398900
2846119376166408719345098363576995150680035627711276296907869001149951372314881
2935770383075372255535430626119192220757841143930722388143862437791520728066325
3017652037977464836264079014691140456808166939095961837218105254669963832997725
3124234508768808309317912829799845407853080987152375512095526136856005911796628
3234147729537948564452788589313828361831422685361580832702235439851958634889397

4. Note example

FieldValue
nullifier11
secret22
value5000000
label33
precommitment = H2(nullifier, secret)7804547571376060123316069248076895932850031953822444106594559586999678602896
commitment = H3(value, label, precommitment)25774960505238821075274772195585739030769339872205046610252935787521405310031
nullifierHash = H1(nullifier)39931036134437929071662103397633869899593947182626814510062446930794907636202

5. Tree examples

The tree has depth 32. A node is H2(left, right). The empty leaf is 0. Bit i of the leaf index, counted from the least significant bit, is 1 when the node is the right child at level i.

Example 1. The note above is the only leaf, at index 0. Its siblings are Z[0] to Z[31].

root = 41575667297252774047664012125459209856646049272089381757727633024565983987862

Example 2. A second note is appended at index 1.

FieldValue
nullifier12
secret23
value7000000
label34
precommitment24266778378722671668954724274878920486911690898706740720066518505283479047324
commitment29348268626606385949476924076909126625122473558957859785832003957964309116132
nullifierHash1401985395294375214774884236543700766810734519981862875374688073007963619144
root = 1340925349014447301927427273926538909429425436400238753938505309885490857044

For index 1, the path bits are 1 at level 0 and 0 at every other level. The siblings are the first commitment at level 0, then Z[1] to Z[31].

6. Label vectors

Rule: SPEC section 4.4.

label_1

pool_id = 11111111111111111111111111111111111111111111111111111111 deposit_tx_id = 2222222222222222222222222222222222222222222222222222222222222222 output_index = 1 refund_key_hash = 33333333333333333333333333333333333333333333333333333333 label_preimage = 7a783430322f6c6162656c2f76311111111111111111111111111111111111111111111111111111111122222222222222222222222222222222222222222222222222222222222222220000000133333333333333333333333333333333333333333333333333333333 blake2b_256 = 811f2d8bc79ace00d71801918f4ef4e7a3c951ac18e55b0ae487d4cf1279655c label = 228138453411283262991000831398678695771983281117198721375515711136284703077

label_2

pool_id = 11111111111111111111111111111111111111111111111111111111 deposit_tx_id = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f output_index = 0 refund_key_hash = 6465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f label_preimage = 7a783430322f6c6162656c2f763111111111111111111111111111111111111111111111111111111111000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f000000006465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f blake2b_256 = d4bae02984c5fd4b4a31edcf42d3e757e45c4c8696c05eb967e4a7c2ec1854e9 label = 375861345953997730029439589630779369956795022469163435216330634722242467924

7. Context vectors

Rule: SPEC section 4.5. Both use pool_id = 11111111111111111111111111111111111111111111111111111111.

context_1. One payout: key credential 44 repeated 28 times, no stake credential, amount 5,000,000, no datum hash. No relayer. valid_until = 1790000000000.

intent_bytes = 7a783430322f696e74656e742f7631111111111111111111111111111111111111111111111111111111110100444444444444444444444444444444444444444444444444444444440000000000004c4b400000000001a0c4506c00 blake2b_256 = c82426fff0d2d13310e82344746a10cf6472eb3d71180d1ba0c5c98dcb657798 context = 353618927255838097014367112914778006164571628135081790697632992728971961719

context_2. Two payouts and a relayer. valid_until = 1790000600000.

PayoutPayment credentialStake credentialAmountDatum hash
1script, 55 repeated 28 timesinline key, 66 repeated 28 times12,345,67877 repeated 32 times
2key, 44 repeated 28 timesnone1,000,000none

The relayer key hash is 88 repeated 28 times.

intent_bytes = 7a783430322f696e74656e742f7631111111111111111111111111111111111111111111111111111111110201555555555555555555555555555555555555555555555555555555550100666666666666666666666666666666666666666666666666666666660000000000bc614e01777777777777777777777777777777777777777777777777777777777777777700444444444444444444444444444444444444444444444444444444440000000000000f4240000188888888888888888888888888888888888888888888888888888888000001a0c45993c0 blake2b_256 = b8ed36856044de15f8293453601f1f0681144d0f5a02da54788ecac6df87a1ce context = 326737043686669673531594931321175044914260045932464440162330010849602668449

8. Nullifier key vectors

The key in the nullifier set is the nullifier hash as 32 big-endian bytes.

Nullifier hashKey
12345678901234567890123456789000000000000000000000000000000000000000018ee90ff6c373e0ee4e3f0ad2
5243587517512619047944774050818596583769055250052763782260365869993858118451273eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000

9. Groth16 proof and key vectors

Circuit: d <== a * b + c, with a and b private and c public. The public signals are [d, c]. The key comes from a throwaway development setup. Never use it for anything but this test.

The verification key in compressed bytes (48 bytes for G1, 96 bytes for G2):

alpha_g1 = 91d2818338afc909d485a8d59597eba6fbdab091bd686ef52005e569d256e8fd3077c509e226bd16ea1764f67d0fd999 beta_g2 = 86425dbce28f2bbe8b7fdf5d7b9eaa8f435155643d505a68803d11d92bde56e3df9d3ef3d27f49b23468d74ca60909fa190a478692ae34909355ddf92a83109f900b1384c617b7fe22e9a5debeb88805545bc0660a3a6ab078b0e2b7794f5b9d gamma_g2 = 93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 delta_g2 = 8ab01564d7dc3d4b20872f68a9cfb0f4c4113d400771554cebda3525daefde95ed8b19eef544a5e0b93fec0c20e7f0f8146ae94f8a70dc48b676208a4fba786fbe43cbeb1ffa20649dfd09b3c0b850a08123ffdc17ee7be89696835f03485601 ic[0] = a8bc06cac776073ae33eecef4e6719a88dada0cbbf00c22ebcbda61d4d8811e749792e053651f7d0ea5ef3b80234b07d ic[1] = 97f780c0ddc2cb146123b6d1a5e9c5bd21dd385610feb41dd0079cfbaa261f37e6fad1786938b42e8accc0ce3e01b91c ic[2] = 99f1e0e23f9693023bb97bc1bb7461f0739cc5dd02d0bf48ea62fcec61957f82e47f85b46f05752f1958ee47e6554d01

Proof 1. Inputs a = 3, b = 4, c = 5. Public signals [17, 5].

a = 840679528d4326d7cc856bf3d6fc7ebadd18a5aa6b1a233e93a06dc7a8edefc059e8d775872d5f29f5159aea169fc4c8 b = 97c5a1af533150935877339f5d0376ad86bfb37f3e3f6ddc9d74b440eeff7f0ffb04e56a3b04d8ae5b2d24247828dcdc0fad6f141c7d684778caca6f0af760da0193024af930d31708d799bff19ed8129b32fe58f1eb254a0dd6d3c2e67bc86f c = b0ca2896c7e9adaafb40259a20d4a8fba7859693491e421d89831f63535cd00316984737c61d4b43cf061cef5a9410b2

Proof 2. Inputs a = 6, b = 7, c = 0. Public signals [42, 0].

a = 90f19e65a20af7555aa37299913cd9d060b53014a112c208b7374d1a3502d2473e4e2ad7a9c7597f9d7a6fadb1f61145 b = a3fd291b3e6f9d7b722e1ad37019e804cbbd822c7741976959f8e19fa0fbe90f598cb7bc65378ac89ede18a89c9785e6078b203f075ddfeb8123133de9a8294d92f929d505ef10be7caf482d91cac0859cefbca4c07b61c498507d2cf52cb64b c = 8dda982b272c2275d3ec3dd0692dc9a3162bdeabce09369f24820b980f87d8dd32c4634b61dd0ad5c9532c740528d133

The JSON file also holds the original snarkjs proof and key. Use them as input when you test proofToCardano and vkToCardano.

Expected results, all measured in an Aiken 1.1.24 test on 2026-10-06:

CaseResult
Proof 1 with signals [17, 5]Valid
Proof 2 with signals [42, 0]Valid. The zero input is skipped
Proof 1 with signals [18, 5]Invalid
Proof 1 with its c replaced by its aInvalid
Proof 1 with signals [17 + r, 5] and the range checkInvalid
Proof 1 with signals [17 + r, 5] and no range checkValid. This is the attack that rule V1 stops

Conversion rules that these vectors pin down:

  • snarkjs writes plain decimal coordinates, not Montgomery form.
  • snarkjs writes each G2 coordinate as [c0, c1]. The compressed bytes hold c1 first, then c0.
  • The first byte carries three flags: 0x80 for compressed, 0x40 for infinity, 0x20 when y is the larger root.
  • snarkjs sets gamma_g2 to the G2 generator.

10. Key derivation vectors

Rule: SPEC section 4.7. HKDF-SHA256 with an empty salt. The input key is the 32-byte seed. The info strings are zx402/nullifier/v1/, zx402/secret/v1/, and zx402/onetime/v1/, each followed by the decimal index. A nullifier or a secret is 64 bytes of output, read as a big-endian integer, reduced modulo r. A one-time key is 32 bytes of output, used as an Ed25519 seed.

These values come from vectors/key_vectors.py , which uses only the Python standard library. Its HKDF routine reproduces test case 3 of RFC 5869.

SeedIndexNullifierSecretOne-time key
00 01 .. 1f0639216960653700163066448778637054308642116596978191505025368424897155397513345058049200327044039904574757438738825783775994281982784300651022677201309403ebe4f4443ed9f47f48e91927b44837e6f4de02009402b2b593fa41e65ff661c2
00 01 .. 1f1824366202620372031640117558341647071383408110479087015883582359631363890594543679668390930529132309361073242836430924630705813252878806406619189347453481e7e7d932557584aea54f6cf0c0321f7d0df9a108bc6907516ecbe1c2fac4345
00 01 .. 1f7291502211560292129525688878081422553501485830469466715738519652193349606509604595047973783780896283167552042050961074092986937461614901242013470641384302719bb5110b3b717361763a9499372065e2ddaf14a6fef7fcbd425bcb6cd8c273c
00 01 .. 1f100000015679876640936791816373436726626857393043590143310752614165817506816653026357287299233994415351281658498432165946390675491719532547353390041738972436184c4d4a7b44fb125bcaa2a935abb01c3db8352bc293988384ceede208742f1ff4c
ff repeated 32 times01562079745233296144410888204156792415541472533402232587365731984789912246645551130867585472255326539025569510170132666544056980087963162129562051798101057fff18aa63656792f45173dde2fd0fb4a4da087847e621ade182325d8a45bcdd0
ff repeated 32 times12989192437253411145246814522697187195712126560801973847755424167077598391963359971528032696552766759410941094445266859333536956018293429050949799717159974586071dc7f24e2386a7cc4c871585e8c0e2b605fcacd08a5088a57ee16e81ef
ff repeated 32 times757311426364687784048361992204763381583050904675498991497565169191997981324112451012653362983218675415427712979956604645302897687215461761629234114195581104b64135e1977b81df45a5a82e5b411bc5069299bd1c9956f9e934397da9c943
ff repeated 32 times1000000302218015724985627281066519245182566397452063371566069798186961316804870357518511966141615212697416588305076989897917931317827227739181830424916588458140750b7e3132f5be957ae87d5386392c168b8769cc672feda3ba0b579f879e0a0e