From 25ebda0a7812571d412abf8ba46830c688a80e15 Mon Sep 17 00:00:00 2001 From: solidsnakedev Date: Tue, 27 Jan 2026 12:36:42 -0700 Subject: [PATCH 1/2] refactor: move hashPlutusData to Data.hashData --- .changeset/sour-lands-greet.md | 30 ++++++++++++++++ docs/content/docs/modules/Address.mdx | 28 +++++++-------- docs/content/docs/modules/Data.mdx | 35 +++++++++++++++++++ docs/content/docs/modules/utils/Hash.mdx | 8 ++--- packages/evolution/docs/modules/Address.ts.md | 28 +++++++-------- packages/evolution/docs/modules/Data.ts.md | 35 +++++++++++++++++++ .../evolution/docs/modules/utils/Hash.ts.md | 8 ++--- packages/evolution/src/Data.ts | 31 ++++++++++++++++ packages/evolution/src/utils/Hash.ts | 16 --------- packages/evolution/test/UtilsHash.CML.test.ts | 4 +-- 10 files changed, 167 insertions(+), 56 deletions(-) create mode 100644 .changeset/sour-lands-greet.md diff --git a/.changeset/sour-lands-greet.md b/.changeset/sour-lands-greet.md new file mode 100644 index 00000000..83917a9f --- /dev/null +++ b/.changeset/sour-lands-greet.md @@ -0,0 +1,30 @@ +--- +"@evolution-sdk/evolution": patch +--- + +Add `Data.hashData()` function for computing blake2b-256 hash of PlutusData. + +This moves the hashing functionality from `utils/Hash.hashPlutusData()` to the Data module for better organization and discoverability. The function computes the datum hash used for inline datums and datum witnesses. + +**Example:** + +```typescript +import * as Data from "@evolution-sdk/evolution/Data" + +// Hash a simple integer +const intHash = Data.hashData(42n) + +// Hash a constructor (e.g., for a custom datum type) +const constr = new Data.Constr({ index: 0n, fields: [1n, 2n] }) +const constrHash = Data.hashData(constr) + +// Hash a bytearray +const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]) +const bytesHash = Data.hashData(bytes) + +// Hash a map +const map = new Map([[1n, 2n]]) +const mapHash = Data.hashData(map) +``` + +**Breaking Change:** `hashPlutusData` has been removed from `utils/Hash`. Use `Data.hashData()` instead. diff --git a/docs/content/docs/modules/Address.mdx b/docs/content/docs/modules/Address.mdx index 1c14e9c1..8fe4a231 100644 --- a/docs/content/docs/modules/Address.mdx +++ b/docs/content/docs/modules/Address.mdx @@ -6,7 +6,7 @@ parent: Modules ## Address overview -Added in v1.0.0 +Added in v2.0.0 --- @@ -57,7 +57,7 @@ FastCheck arbitrary generator for testing export declare const arbitrary: FastCheck.Arbitrary
``` -Added in v1.0.0 +Added in v2.0.0 # Functions @@ -71,7 +71,7 @@ Sync functions using Schema utilities export declare const fromBech32: (i: string, overrideOptions?: ParseOptions) => Address ``` -Added in v1.0.0 +Added in v2.0.0 # Model @@ -94,7 +94,7 @@ export interface AddressDetails { } ``` -Added in v1.0.0 +Added in v2.0.0 # Schema @@ -106,7 +106,7 @@ Added in v1.0.0 export declare class Address ``` -Added in v1.0.0 +Added in v2.0.0 ### toJSON (method) @@ -164,7 +164,7 @@ export declare const FromBech32: Schema.transformOrFail< > ``` -Added in v1.0.0 +Added in v2.0.0 ## FromBytes @@ -181,7 +181,7 @@ export declare const FromBytes: Schema.transformOrFail< > ``` -Added in v1.0.0 +Added in v2.0.0 ## FromHex @@ -202,7 +202,7 @@ export declare const FromHex: Schema.transform< > ``` -Added in v1.0.0 +Added in v2.0.0 # Utils @@ -236,7 +236,7 @@ if (details) { } ``` -Added in v1.0.0 +Added in v2.0.0 ## getNetworkId @@ -248,7 +248,7 @@ Get network ID from AddressStructure export declare const getNetworkId: (address: Address) => NetworkId.NetworkId ``` -Added in v1.0.0 +Added in v2.0.0 ## getPaymentCredential @@ -261,7 +261,7 @@ Returns undefined if the address cannot be parsed export declare const getPaymentCredential: (address: string) => Credential.Credential | undefined ``` -Added in v1.0.0 +Added in v2.0.0 ## getStakingCredential @@ -274,7 +274,7 @@ Returns undefined if the address has no staking credential or cannot be parsed export declare const getStakingCredential: (address: string) => Credential.Credential | undefined ``` -Added in v1.0.0 +Added in v2.0.0 ## hasStakingCredential @@ -286,7 +286,7 @@ Check if AddressStructure has staking credential (BaseAddress-like) export declare const hasStakingCredential: (address: Address) => boolean ``` -Added in v1.0.0 +Added in v2.0.0 ## isEnterprise @@ -298,7 +298,7 @@ Check if AddressStructure is enterprise-like (no staking credential) export declare const isEnterprise: (address: Address) => boolean ``` -Added in v1.0.0 +Added in v2.0.0 # utils diff --git a/docs/content/docs/modules/Data.mdx b/docs/content/docs/modules/Data.mdx index 1db494cd..d693e788 100644 --- a/docs/content/docs/modules/Data.mdx +++ b/docs/content/docs/modules/Data.mdx @@ -33,6 +33,8 @@ parent: Modules - [arbitraryPlutusData](#arbitraryplutusdata) - [arbitraryPlutusList](#arbitraryplutuslist) - [arbitraryPlutusMap](#arbitraryplutusmap) +- [hashing](#hashing) + - [hashData](#hashdata) - [model](#model) - [Data (type alias)](#data-type-alias) - [DataEncoded (type alias)](#dataencoded-type-alias) @@ -307,6 +309,39 @@ export declare const arbitraryPlutusMap: (depth: number) => FastCheck.Arbitrary< Added in v2.0.0 +# hashing + +## hashData + +Compute the hash of PlutusData using blake2b-256 over its CBOR encoding. +Defaults to CML_DATA_DEFAULT_OPTIONS (indefinite-length arrays/maps). + +**Signature** + +```ts +export declare const hashData: (data: Data, options?: CBOR.CodecOptions) => DatumHash.DatumHash +``` + +**Example** + +```typescript +import * as Data from "@evolution-sdk/evolution/Data" + +// Hash a simple integer +const intData = 42n +const intHash = Data.hashData(intData) + +// Hash a constructor +const constr = new Data.Constr({ index: 0n, fields: [1n, 2n] }) +const constrHash = Data.hashData(constr) + +// Hash a bytearray +const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]) +const bytesHash = Data.hashData(bytes) +``` + +Added in v2.0.0 + # model ## Data (type alias) diff --git a/docs/content/docs/modules/utils/Hash.mdx b/docs/content/docs/modules/utils/Hash.mdx index 01841880..fa03d319 100644 --- a/docs/content/docs/modules/utils/Hash.mdx +++ b/docs/content/docs/modules/utils/Hash.mdx @@ -14,7 +14,7 @@ parent: Modules - [RedeemersFormat (type alias)](#redeemersformat-type-alias) - [computeTotalExUnits](#computetotalexunits) - [hashAuxiliaryData](#hashauxiliarydata) - - [hashPlutusData](#hashplutusdata) + - [~~hashPlutusData~~](#hashplutusdata) - [hashScriptData](#hashscriptdata) - [hashTransaction](#hashtransaction) @@ -55,17 +55,15 @@ Compute hash of auxiliary data (tag 259) per ledger rules. export declare const hashAuxiliaryData: (aux: AuxiliaryData.AuxiliaryData) => AuxiliaryDataHash.AuxiliaryDataHash ``` -## hashPlutusData +## ~~hashPlutusData~~ Compute hash of plutus data using specified CBOR encoding options. Defaults to CML_DATA_DEFAULT_OPTIONS (indefinite-length arrays/maps). -TODO: Consider moving this to the Data module as Data.hash() for better organization - **Signature** ```ts -export declare const hashPlutusData: (pd: Data.Data, options?: CBOR.CodecOptions) => DatumHash.DatumHash +export declare const hashPlutusData: (data: Data.Data, options?: CBOR.CodecOptions) => DatumHash ``` ## hashScriptData diff --git a/packages/evolution/docs/modules/Address.ts.md b/packages/evolution/docs/modules/Address.ts.md index ec0a4377..a9011dda 100644 --- a/packages/evolution/docs/modules/Address.ts.md +++ b/packages/evolution/docs/modules/Address.ts.md @@ -6,7 +6,7 @@ parent: Modules ## Address overview -Added in v1.0.0 +Added in v2.0.0 --- @@ -57,7 +57,7 @@ FastCheck arbitrary generator for testing export declare const arbitrary: FastCheck.Arbitrary
``` -Added in v1.0.0 +Added in v2.0.0 # Functions @@ -71,7 +71,7 @@ Sync functions using Schema utilities export declare const fromBech32: (i: string, overrideOptions?: ParseOptions) => Address ``` -Added in v1.0.0 +Added in v2.0.0 # Model @@ -94,7 +94,7 @@ export interface AddressDetails { } ``` -Added in v1.0.0 +Added in v2.0.0 # Schema @@ -106,7 +106,7 @@ Added in v1.0.0 export declare class Address ``` -Added in v1.0.0 +Added in v2.0.0 ### toJSON (method) @@ -164,7 +164,7 @@ export declare const FromBech32: Schema.transformOrFail< > ``` -Added in v1.0.0 +Added in v2.0.0 ## FromBytes @@ -181,7 +181,7 @@ export declare const FromBytes: Schema.transformOrFail< > ``` -Added in v1.0.0 +Added in v2.0.0 ## FromHex @@ -202,7 +202,7 @@ export declare const FromHex: Schema.transform< > ``` -Added in v1.0.0 +Added in v2.0.0 # Utils @@ -236,7 +236,7 @@ if (details) { } ``` -Added in v1.0.0 +Added in v2.0.0 ## getNetworkId @@ -248,7 +248,7 @@ Get network ID from AddressStructure export declare const getNetworkId: (address: Address) => NetworkId.NetworkId ``` -Added in v1.0.0 +Added in v2.0.0 ## getPaymentCredential @@ -261,7 +261,7 @@ Returns undefined if the address cannot be parsed export declare const getPaymentCredential: (address: string) => Credential.Credential | undefined ``` -Added in v1.0.0 +Added in v2.0.0 ## getStakingCredential @@ -274,7 +274,7 @@ Returns undefined if the address has no staking credential or cannot be parsed export declare const getStakingCredential: (address: string) => Credential.Credential | undefined ``` -Added in v1.0.0 +Added in v2.0.0 ## hasStakingCredential @@ -286,7 +286,7 @@ Check if AddressStructure has staking credential (BaseAddress-like) export declare const hasStakingCredential: (address: Address) => boolean ``` -Added in v1.0.0 +Added in v2.0.0 ## isEnterprise @@ -298,7 +298,7 @@ Check if AddressStructure is enterprise-like (no staking credential) export declare const isEnterprise: (address: Address) => boolean ``` -Added in v1.0.0 +Added in v2.0.0 # utils diff --git a/packages/evolution/docs/modules/Data.ts.md b/packages/evolution/docs/modules/Data.ts.md index e7ea8c88..ce550d8c 100644 --- a/packages/evolution/docs/modules/Data.ts.md +++ b/packages/evolution/docs/modules/Data.ts.md @@ -33,6 +33,8 @@ parent: Modules - [arbitraryPlutusData](#arbitraryplutusdata) - [arbitraryPlutusList](#arbitraryplutuslist) - [arbitraryPlutusMap](#arbitraryplutusmap) +- [hashing](#hashing) + - [hashData](#hashdata) - [model](#model) - [Data (type alias)](#data-type-alias) - [DataEncoded (type alias)](#dataencoded-type-alias) @@ -307,6 +309,39 @@ export declare const arbitraryPlutusMap: (depth: number) => FastCheck.Arbitrary< Added in v2.0.0 +# hashing + +## hashData + +Compute the hash of PlutusData using blake2b-256 over its CBOR encoding. +Defaults to CML_DATA_DEFAULT_OPTIONS (indefinite-length arrays/maps). + +**Signature** + +```ts +export declare const hashData: (data: Data, options?: CBOR.CodecOptions) => DatumHash.DatumHash +``` + +**Example** + +```typescript +import * as Data from "@evolution-sdk/evolution/Data" + +// Hash a simple integer +const intData = 42n +const intHash = Data.hashData(intData) + +// Hash a constructor +const constr = new Data.Constr({ index: 0n, fields: [1n, 2n] }) +const constrHash = Data.hashData(constr) + +// Hash a bytearray +const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]) +const bytesHash = Data.hashData(bytes) +``` + +Added in v2.0.0 + # model ## Data (type alias) diff --git a/packages/evolution/docs/modules/utils/Hash.ts.md b/packages/evolution/docs/modules/utils/Hash.ts.md index 9bd45103..0327e37c 100644 --- a/packages/evolution/docs/modules/utils/Hash.ts.md +++ b/packages/evolution/docs/modules/utils/Hash.ts.md @@ -14,7 +14,7 @@ parent: Modules - [RedeemersFormat (type alias)](#redeemersformat-type-alias) - [computeTotalExUnits](#computetotalexunits) - [hashAuxiliaryData](#hashauxiliarydata) - - [hashPlutusData](#hashplutusdata) + - [~~hashPlutusData~~](#hashplutusdata) - [hashScriptData](#hashscriptdata) - [hashTransaction](#hashtransaction) @@ -55,17 +55,15 @@ Compute hash of auxiliary data (tag 259) per ledger rules. export declare const hashAuxiliaryData: (aux: AuxiliaryData.AuxiliaryData) => AuxiliaryDataHash.AuxiliaryDataHash ``` -## hashPlutusData +## ~~hashPlutusData~~ Compute hash of plutus data using specified CBOR encoding options. Defaults to CML_DATA_DEFAULT_OPTIONS (indefinite-length arrays/maps). -TODO: Consider moving this to the Data module as Data.hash() for better organization - **Signature** ```ts -export declare const hashPlutusData: (pd: Data.Data, options?: CBOR.CodecOptions) => DatumHash.DatumHash +export declare const hashPlutusData: (data: Data.Data, options?: CBOR.CodecOptions) => DatumHash ``` ## hashScriptData diff --git a/packages/evolution/src/Data.ts b/packages/evolution/src/Data.ts index 5a198586..f2ebd6e4 100644 --- a/packages/evolution/src/Data.ts +++ b/packages/evolution/src/Data.ts @@ -1,6 +1,8 @@ +import { blake2b } from "@noble/hashes/blake2" import { Data as EffectData, Effect, Equal, FastCheck, Hash, ParseResult, Schema } from "effect" import * as CBOR from "./CBOR.js" +import * as DatumHash from "./DatumHash.js" import * as Numeric from "./Numeric.js" /** @@ -916,3 +918,32 @@ export const withSchema = ( fromCBORBytes: Schema.decodeSync(Schema.compose(FromCBORBytes(options), schema)) } } + +/** + * Compute the hash of PlutusData using blake2b-256 over its CBOR encoding. + * Defaults to CML_DATA_DEFAULT_OPTIONS (indefinite-length arrays/maps). + * + * @since 2.0.0 + * @category hashing + * @example + * ```typescript + * import * as Data from "@evolution-sdk/evolution/Data" + * + * // Hash a simple integer + * const intData = 42n + * const intHash = Data.hashData(intData) + * + * // Hash a constructor + * const constr = new Data.Constr({ index: 0n, fields: [1n, 2n] }) + * const constrHash = Data.hashData(constr) + * + * // Hash a bytearray + * const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]) + * const bytesHash = Data.hashData(bytes) + * ``` + */ +export const hashData = (data: Data, options: CBOR.CodecOptions = CBOR.CML_DATA_DEFAULT_OPTIONS): DatumHash.DatumHash => { + const bytes = toCBORBytes(data, options) + const digest = blake2b(bytes, { dkLen: 32 }) + return new DatumHash.DatumHash({ hash: digest }) +} diff --git a/packages/evolution/src/utils/Hash.ts b/packages/evolution/src/utils/Hash.ts index 2b12d7b4..f535ad59 100644 --- a/packages/evolution/src/utils/Hash.ts +++ b/packages/evolution/src/utils/Hash.ts @@ -5,7 +5,6 @@ import * as AuxiliaryDataHash from "../AuxiliaryDataHash.js" import * as CBOR from "../CBOR.js" import * as CostModel from "../CostModel.js" import * as Data from "../Data.js" -import * as DatumHash from "../DatumHash.js" import * as Redeemer from "../Redeemer.js" import * as Redeemers from "../Redeemers.js" import * as ScriptDataHash from "../ScriptDataHash.js" @@ -188,21 +187,6 @@ export const hashAuxiliaryData = (aux: AuxiliaryData.AuxiliaryData): AuxiliaryDa return new AuxiliaryDataHash.AuxiliaryDataHash({ bytes: digest }) } -/** - * Compute hash of plutus data using specified CBOR encoding options. - * Defaults to CML_DATA_DEFAULT_OPTIONS (indefinite-length arrays/maps). - * - * TODO: Consider moving this to the Data module as Data.hash() for better organization - */ -export const hashPlutusData = ( - pd: Data.Data, - options: CBOR.CodecOptions = CBOR.CML_DATA_DEFAULT_OPTIONS -): DatumHash.DatumHash => { - const bytes = Data.toCBORBytes(pd, options) - const digest = blake2b(bytes, { dkLen: 32 }) - return new DatumHash.DatumHash({ hash: digest }) -} - /** * Compute total ex_units by summing over redeemers. */ diff --git a/packages/evolution/test/UtilsHash.CML.test.ts b/packages/evolution/test/UtilsHash.CML.test.ts index 578d7f51..a326035b 100644 --- a/packages/evolution/test/UtilsHash.CML.test.ts +++ b/packages/evolution/test/UtilsHash.CML.test.ts @@ -63,10 +63,10 @@ describe("UtilsHash helpers CML parity", () => { ) }) - it("property: hashPlutusData matches CML.hash_plutus_data", () => { + it("property: Data.hashData matches CML.hash_plutus_data", () => { FastCheck.assert( FastCheck.property(Data.arbitrary, (datum) => { - const evolutionHash = UtilsHash.hashPlutusData(datum) + const evolutionHash = Data.hashData(datum) const evolutionBytes = evolutionHash.hash const hex = Data.toCBORHex(datum) From f9f8165f59b9c98f05c79992fc5c3d9ffc547da0 Mon Sep 17 00:00:00 2001 From: solidsnakedev Date: Tue, 27 Jan 2026 12:53:49 -0700 Subject: [PATCH 2/2] docs: update docs --- docs/content/docs/modules/utils/Hash.mdx | 12 ------------ packages/evolution/docs/modules/utils/Hash.ts.md | 12 ------------ 2 files changed, 24 deletions(-) diff --git a/docs/content/docs/modules/utils/Hash.mdx b/docs/content/docs/modules/utils/Hash.mdx index fa03d319..b49b75a0 100644 --- a/docs/content/docs/modules/utils/Hash.mdx +++ b/docs/content/docs/modules/utils/Hash.mdx @@ -14,7 +14,6 @@ parent: Modules - [RedeemersFormat (type alias)](#redeemersformat-type-alias) - [computeTotalExUnits](#computetotalexunits) - [hashAuxiliaryData](#hashauxiliarydata) - - [~~hashPlutusData~~](#hashplutusdata) - [hashScriptData](#hashscriptdata) - [hashTransaction](#hashtransaction) @@ -55,17 +54,6 @@ Compute hash of auxiliary data (tag 259) per ledger rules. export declare const hashAuxiliaryData: (aux: AuxiliaryData.AuxiliaryData) => AuxiliaryDataHash.AuxiliaryDataHash ``` -## ~~hashPlutusData~~ - -Compute hash of plutus data using specified CBOR encoding options. -Defaults to CML_DATA_DEFAULT_OPTIONS (indefinite-length arrays/maps). - -**Signature** - -```ts -export declare const hashPlutusData: (data: Data.Data, options?: CBOR.CodecOptions) => DatumHash -``` - ## hashScriptData Compute script_data_hash using standard module encoders. diff --git a/packages/evolution/docs/modules/utils/Hash.ts.md b/packages/evolution/docs/modules/utils/Hash.ts.md index 0327e37c..91bbb593 100644 --- a/packages/evolution/docs/modules/utils/Hash.ts.md +++ b/packages/evolution/docs/modules/utils/Hash.ts.md @@ -14,7 +14,6 @@ parent: Modules - [RedeemersFormat (type alias)](#redeemersformat-type-alias) - [computeTotalExUnits](#computetotalexunits) - [hashAuxiliaryData](#hashauxiliarydata) - - [~~hashPlutusData~~](#hashplutusdata) - [hashScriptData](#hashscriptdata) - [hashTransaction](#hashtransaction) @@ -55,17 +54,6 @@ Compute hash of auxiliary data (tag 259) per ledger rules. export declare const hashAuxiliaryData: (aux: AuxiliaryData.AuxiliaryData) => AuxiliaryDataHash.AuxiliaryDataHash ``` -## ~~hashPlutusData~~ - -Compute hash of plutus data using specified CBOR encoding options. -Defaults to CML_DATA_DEFAULT_OPTIONS (indefinite-length arrays/maps). - -**Signature** - -```ts -export declare const hashPlutusData: (data: Data.Data, options?: CBOR.CodecOptions) => DatumHash -``` - ## hashScriptData Compute script_data_hash using standard module encoders.