Summary
Plutus Data integers whose magnitude exceeds 64 bytes (|value| >= 2^512) are encoded as a single
definite-length byte string under CBOR tag 2 or 3. The Conway CDDL, quoted in this repo at
Data.ts L165-167, defines a bignum payload as bounded_bytes = bytes .size (0..64), so a magnitude
of 65 bytes or more must be an indefinite-length byte string split into chunks of at most 64 bytes.
The SDK already applies that rule to Data byte-string leaves, so the same file chunks a 65-byte
bytearray and does not chunk a 65-byte bignum. The result is Plutus data that violates the grammar,
and a datum hash that differs from the one computed over the chunked form.
Affected
packages/evolution/src/CBOR.ts
- encodeUintSync (L985-991): passes
bigintToBytes(value) straight to encodeTagSync(2, ...) (L989-990)
- encodeNintSync (L1028-1035): same for tag 3 (L1033-1034)
- contrast: the
BoundedBytes node (L1231-1239) routes through encodeBoundedBytesSync (L1109),
which chunks at 64 bytes and is applied unconditionally
packages/evolution/src/Data.ts
- CDDL for big_uint / big_nint / bounded_bytes documented at L165-167
Fix
Wrap the bignum magnitude in the existing BoundedBytes node so the chunking rule applies, mirroring
the fix PR #160 made for byte-string leaves:
return encodeTagSync(2, BoundedBytes.make(bigintToBytes(value)), options, fmt)
and the tag 3 analogue in encodeNintSync. Alternatively have encodeTagSync treat tag 2 and 3
payloads as bounded bytes. Note #395 edits the same two lines of encodeNintSync for the negative
bignum boundary, so the two changes will conflict.
Regression test
- given:
Data.int(2n ** 512n)
- before fix: encodes to
c25841... (single 65-byte definite string); toDatumHash is 9b2838f7...
- after fix: encodes to
c25f5840...4100ff; toDatumHash is
939bb1f51ea88f86a070fefb5c1185d10b4d10a13e3b7db24aac02220c18adab
- negative analogue:
Data.int(-(2n ** 520n)) chunks under tag 3 rather than emitting c35841...
- unchanged: a 9-byte bignum such as
2n ** 64n stays definite, so only the over-64-byte case moves
Must FAIL on main today and PASS after the fix.
Reference
Same defect class as #158, which covered Data byte-string leaves and was fixed in PR #160. The
integer path was never routed through BoundedBytes.
Summary
Plutus Data integers whose magnitude exceeds 64 bytes (|value| >= 2^512) are encoded as a single
definite-length byte string under CBOR tag 2 or 3. The Conway CDDL, quoted in this repo at
Data.ts L165-167, defines a bignum payload as
bounded_bytes = bytes .size (0..64), so a magnitudeof 65 bytes or more must be an indefinite-length byte string split into chunks of at most 64 bytes.
The SDK already applies that rule to Data byte-string leaves, so the same file chunks a 65-byte
bytearray and does not chunk a 65-byte bignum. The result is Plutus data that violates the grammar,
and a datum hash that differs from the one computed over the chunked form.
Affected
packages/evolution/src/CBOR.ts
bigintToBytes(value)straight toencodeTagSync(2, ...)(L989-990)BoundedBytesnode (L1231-1239) routes throughencodeBoundedBytesSync(L1109),which chunks at 64 bytes and is applied unconditionally
packages/evolution/src/Data.ts
Fix
Wrap the bignum magnitude in the existing
BoundedBytesnode so the chunking rule applies, mirroringthe fix PR #160 made for byte-string leaves:
and the tag 3 analogue in
encodeNintSync. Alternatively haveencodeTagSynctreat tag 2 and 3payloads as bounded bytes. Note #395 edits the same two lines of
encodeNintSyncfor the negativebignum boundary, so the two changes will conflict.
Regression test
Data.int(2n ** 512n)c25841...(single 65-byte definite string);toDatumHashis9b2838f7...c25f5840...4100ff;toDatumHashis939bb1f51ea88f86a070fefb5c1185d10b4d10a13e3b7db24aac02220c18adabData.int(-(2n ** 520n))chunks under tag 3 rather than emittingc35841...2n ** 64nstays definite, so only the over-64-byte case movesMust FAIL on main today and PASS after the fix.
Reference
Same defect class as #158, which covered Data byte-string leaves and was fixed in PR #160. The
integer path was never routed through
BoundedBytes.