user4627: I'm looking for a Javascript implementation of the CLI's cardano-cli transaction policyid function, can anyone point me in the right direction here?
Trying to replicate it with blakejs (https://github.com/dcposch/blakejs) and cbor-web (https://github.com/hildjj/node-cbor/tree/main/packages/cbor-web), but failing to get the hashes to match the output of the CLI.
Eg I want to create a PolicyID / ScriptHash from this policy script:
{
  "type": "all",
  "scripts":
  [
   {
     "type": "before",
     "slot": 42863577
   },
   {
     "type": "sig",
     "keyHash": "46a26617f9b59cc48945ccc6c0aecee732f7698fadbe8b5624b44b9e"
   }
  ]
}

(CLI gives me this policyid: 463e9264962cea64efafa576d44c8d2821d09c0c7495c253d4101a9a)
In JS I'm trying something along these lines:
[removed, see correct answer below]

(gives me this: 5db35cd45775e7d7b0d1bd5491a9baea7ac54b41772a8c96ce587579)
Any guidance is very much appreciated

user4043: You can do this using the 10.0 beta version of cardano-serialization-lib which should make it into stable pretty soon (I'm in the process of testing this, you can follow the status on this Github issue).
This should be enough to get you started:
const ttl = protocolParameters.slot+invalidHereafter
const timelockExpiry = S.TimelockExpiry.new(ttl)
const timeLockedPolicyScript = S.NativeScript.new_timelock_expiry(timelockExpiry)
const policyScripts = S.NativeScripts.new()
const policyScripts.add(timeLockedPolicyScript)
const scriptHash = S.ScriptHash.from_bytes(timeLockedPolicyScript.hash().to_bytes())
const policyID = bytesToString(timeLockedPolicyScript.hash().to_bytes())

In order for that code to work, you'll need some valid protocolParameters object which can be retrieved from Blockfrost using this code from Nami wallet, as well as the bytesToString function which is defined using Buffer:
export const bytesToString = (bytes) => {
  return Buffer.from(bytes, "hex").toString("hex")
}


user4627: Finally got my head around this, thanks to this version in Python: Re-Implementing Policy Hashing in Python by @tycl.
Basically we need to

Parse the policy (JSON)
Follow the CDDL specifications to translate the policy to an array
(see link below)
Use the array as input to cbor.encode().
Prepend a "0" byte to the result.
Run that new byte array through blake2bHex.

And we're done.
Here's an example:
The policy used is the one from above and I translate it manually to the array via https://github.com/input-output-hk/cardano-ledger/blob/683bef2e40cbd10339452c9f2009867c855baf1a/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L228-L246;
Cbor-Web used from here: https://github.com/hildjj/node-cbor/tree/main/packages/cbor-web
Blakejs package from here: https://github.com/dcposch/blakejs
// Values from policy json
const keyhash = "46a26617f9b59cc48945ccc6c0aecee732f7698fadbe8b5624b44b9e";
const slot = 42863577;

// Translation via CDDL link above
// [1, [X]] => "script_all"
// [5, slot] => "invalid_hereafter" (~ "valid before")
// [0, keyHashBytes] => "script_pubkey"
// Remember: 1) Buffer conversion and 2) Order matters.
const cborInput = [1, [[5, slot], [0, Buffer.from(hexToBytes(keyhash))]]]

// Cbor encode
let cborResult = cbor.encode(cborInput);

// Prepend the 0 byte
let tmp = new Uint8Array(cborResult.length + 1);
tmp.set(Uint8Array.of(0), 0);
tmp.set(cborResult, 1);
cborResult = tmp;

// Run the result through blake2d with digest size / output length of 28
const blakeHexResult = Blake.blake2bHex(cborResult, null, 28);
console.log(blakeHexResult);


4627: <p>I'm looking for a Javascript implementation of the CLI's <code>cardano-cli transaction policyid</code> function, can anyone point me in the right direction here?</p>
<p>Trying to replicate it with blakejs (<a href="https://github.com/dcposch/blakejs" rel="nofollow noreferrer">https://github.com/dcposch/blakejs</a>) and cbor-web (<a href="https://github.com/hildjj/node-cbor/tree/main/packages/cbor-web" rel="nofollow noreferrer">https://github.com/hildjj/node-cbor/tree/main/packages/cbor-web</a>), but failing to get the hashes to match the output of the CLI.</p>
<p><em>Eg I want to create a PolicyID / ScriptHash from this policy script:</em></p>
<pre><code>{
  &quot;type&quot;: &quot;all&quot;,
  &quot;scripts&quot;:
  [
   {
     &quot;type&quot;: &quot;before&quot;,
     &quot;slot&quot;: 42863577
   },
   {
     &quot;type&quot;: &quot;sig&quot;,
     &quot;keyHash&quot;: &quot;46a26617f9b59cc48945ccc6c0aecee732f7698fadbe8b5624b44b9e&quot;
   }
  ]
}
</code></pre>
<p><em>(CLI gives me this policyid: 463e9264962cea64efafa576d44c8d2821d09c0c7495c253d4101a9a)</em></p>
<p>In JS I'm trying something along these lines:</p>
<pre><code>[removed, see correct answer below]
</code></pre>
<p><em>(gives me this: 5db35cd45775e7d7b0d1bd5491a9baea7ac54b41772a8c96ce587579)</em></p>
<p>Any guidance is very much appreciated</p>
 4043: <p>You can do this using the 10.0 beta version of <code>cardano-serialization-lib</code> which should make it into stable pretty soon (I'm in the process of testing this, you can follow the status on <a href="https://github.com/Emurgo/cardano-serialization-lib/issues/141" rel="nofollow noreferrer">this Github issue</a>).</p>
<p>This should be enough to get you started:</p>
<pre><code>const ttl = protocolParameters.slot+invalidHereafter
const timelockExpiry = S.TimelockExpiry.new(ttl)
const timeLockedPolicyScript = S.NativeScript.new_timelock_expiry(timelockExpiry)
const policyScripts = S.NativeScripts.new()
const policyScripts.add(timeLockedPolicyScript)
const scriptHash = S.ScriptHash.from_bytes(timeLockedPolicyScript.hash().to_bytes())
const policyID = bytesToString(timeLockedPolicyScript.hash().to_bytes())
</code></pre>
<p>In order for that code to work, you'll need some valid protocolParameters object which can be retrieved from Blockfrost using <a href="https://github.com/Berry-Pool/nami-wallet/blob/58c924cfd98fd568ed2ff133d95fde16771e81d8/src/api/extension/wallet.js#L20" rel="nofollow noreferrer">this code from Nami wallet</a>, as well as the <code>bytesToString</code> function which is defined using Buffer:</p>
<pre><code>export const bytesToString = (bytes) =&gt; {
  return Buffer.from(bytes, &quot;hex&quot;).toString(&quot;hex&quot;)
}
</code></pre>
 4627: <p>Finally got my head around this, thanks to this version in Python: <a href="https://cardano.stackexchange.com/questions/486/re-implementing-policy-hashing-in-python">Re-Implementing Policy Hashing in Python</a> by @tycl.</p>
<p>Basically we need to</p>
<ol>
<li>Parse the policy (JSON)</li>
<li>Follow the CDDL specifications to translate the policy to an array
<em>(see link below)</em></li>
<li>Use the array as input to cbor.encode().</li>
<li>Prepend a &quot;0&quot; byte to the result.</li>
<li>Run that new byte array through blake2bHex.</li>
</ol>
<p>And we're done.</p>
<p>Here's an example:</p>
<p>The policy used is the one from above and I translate it manually to the array via <a href="https://github.com/input-output-hk/cardano-ledger/blob/683bef2e40cbd10339452c9f2009867c855baf1a/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L228-L246;" rel="nofollow noreferrer">https://github.com/input-output-hk/cardano-ledger/blob/683bef2e40cbd10339452c9f2009867c855baf1a/shelley-ma/shelley-ma-test/cddl-files/shelley-ma.cddl#L228-L246;</a></p>
<p>Cbor-Web used from here: <a href="https://github.com/hildjj/node-cbor/tree/main/packages/cbor-web" rel="nofollow noreferrer">https://github.com/hildjj/node-cbor/tree/main/packages/cbor-web</a></p>
<p>Blakejs package from here: <a href="https://github.com/dcposch/blakejs" rel="nofollow noreferrer">https://github.com/dcposch/blakejs</a></p>
<pre><code>// Values from policy json
const keyhash = &quot;46a26617f9b59cc48945ccc6c0aecee732f7698fadbe8b5624b44b9e&quot;;
const slot = 42863577;

// Translation via CDDL link above
// [1, [X]] =&gt; &quot;script_all&quot;
// [5, slot] =&gt; &quot;invalid_hereafter&quot; (~ &quot;valid before&quot;)
// [0, keyHashBytes] =&gt; &quot;script_pubkey&quot;
// Remember: 1) Buffer conversion and 2) Order matters.
const cborInput = [1, [[5, slot], [0, Buffer.from(hexToBytes(keyhash))]]]

// Cbor encode
let cborResult = cbor.encode(cborInput);

// Prepend the 0 byte
let tmp = new Uint8Array(cborResult.length + 1);
tmp.set(Uint8Array.of(0), 0);
tmp.set(cborResult, 1);
cborResult = tmp;

// Run the result through blake2d with digest size / output length of 28
const blakeHexResult = Blake.blake2bHex(cborResult, null, 28);
console.log(blakeHexResult);
</code></pre>
