Skip to content

Commit

Permalink
feat: vat-safe denomHash using noble sha256 (#9576)
Browse files Browse the repository at this point in the history
refs: #9211

## Description

Prototyping for #9211 suggests we'll want to be [derive IBC denoms](https://tutorials.cosmos.network/tutorials/6-ibc-dev/#how-are-ibc-denoms-derived) using a hash of a path such as `transfer/channel-0/uatom` -> `ibc/27394FB092D2ECCD56123C74F36E4C1F926001CEADA9CA97EA622B25F41E5EB2`.

I tried to use the sha256 function from `@cosmjs/crypto`, but I got error's about node's `crypto` module. `@cosmjs/crypto` imports an old version of `@noble/hashes`. The current version seems to be vat-safe.

### Scaling Considerations

Compute performance: Doing a sha256 computation on XS in pure JS seems a little whacky. We could consider dropping down to C like we do for base64. But since this is a constant time operation, it doesn't seem worthwhile.

Bundle size: A base64 encoded bundle with just this module seems to be around 500k.

```
┌──────────────────────────────┬────────┐
│           (index)            │ Values │
├──────────────────────────────┼────────┤
│ @agoric/orchestration-v0.1.0 │  1702  │
│     @noble/hashes-v1.4.0     │ 18820  │
└──────────────────────────────┴────────┘
total size: 36623
```

### Security Considerations

supply chain: this adds a dependency on the current [@noble/hashes](https://www.npmjs.com/package/@noble/hashes), which is reasonably popular (3m weekly downloads) and seems to be well audited.

### Documentation Considerations

I'm not sure where this shows up in the orchestration API yet.

### Testing Considerations

A test that it works in a compartment is included.

### Upgrade Considerations

Unrelated to any deployed code.
  • Loading branch information
mergify[bot] authored Jul 12, 2024
2 parents 5d18974 + 58ff687 commit 24528f1
Show file tree
Hide file tree
Showing 6 changed files with 9,964 additions and 1 deletion.
5 changes: 4 additions & 1 deletion packages/orchestration/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,16 @@
"@endo/errors": "^1.2.2",
"@endo/far": "^1.1.2",
"@endo/marshal": "^1.5.0",
"@endo/patterns": "^1.4.0"
"@endo/patterns": "^1.4.0",
"@noble/hashes": "github:paulmillr/noble-hashes#ae060da"
},
"devDependencies": {
"@agoric/swingset-liveslots": "^0.10.2",
"@chain-registry/client": "^1.47.4",
"@cosmjs/amino": "^0.32.3",
"@cosmjs/proto-signing": "^0.32.3",
"@endo/bundle-source": "^3.2.3",
"@endo/import-bundle": "^1.1.2",
"@endo/ses-ava": "^1.2.2",
"ava": "^5.3.1",
"c8": "^9.1.0",
Expand Down
22 changes: 22 additions & 0 deletions packages/orchestration/src/utils/denomHash.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @ts-check
import { sha256 } from '@noble/hashes/sha256';
import { bytesToHex } from '@noble/hashes/utils';

/**
* cf. https://tutorials.cosmos.network/tutorials/6-ibc-dev/
*
* @param {object} opts
* @param {string} [opts.portId]
* @param {string} [opts.channelId] required unless `path` is supplied
* @param {string} [opts.path] alternative to portId, channelId
* @param {string} opts.denom base denom
*/
export const denomHash = ({
portId = 'transfer',
channelId = /** @type {string | undefined} */ (undefined),
path = `${portId}/${channelId}`,
denom,
}) => {
const h = sha256.create().update(`${path}/${denom}`).digest();
return bytesToHex(h).toUpperCase();
};
18 changes: 18 additions & 0 deletions packages/orchestration/test/utils/denomHash.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import test from '@endo/ses-ava/prepare-endo.js';

import bundleSource from '@endo/bundle-source';
import { importBundle } from '@endo/import-bundle';
import { createRequire } from 'node:module';
import { denomHash } from '../../src/utils/denomHash.js';

const nodeRequire = createRequire(import.meta.url);

test('compartment use of denomHash', async t => {
const bundle = await bundleSource(nodeRequire.resolve('./denomHashEx.js'));
const { length } = JSON.stringify(bundle);
t.log('bundle length', length);
const expected = denomHash({ channelId: 'channel-0', denom: 'uatom' });

const { denomHashExample } = await importBundle(bundle);
t.deepEqual(denomHashExample(), expected);
});
6 changes: 6 additions & 0 deletions packages/orchestration/test/utils/denomHashEx.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { denomHash } from '../../src/utils/denomHash.js';

export const denomHashExample = () => {
const h = denomHash({ channelId: 'channel-0', denom: 'uatom' });
return h;
};
9,910 changes: 9,910 additions & 0 deletions patches/@agoric+orchestration++@noble+hashes+1.4.0.patch

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2780,6 +2780,10 @@
resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.2.tgz#e9e035b9b166ca0af657a7848eb2718f0f22f183"
integrity sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==

"@noble/hashes@github:paulmillr/noble-hashes#ae060da":
version "1.4.0"
resolved "https://codeload.github.com/paulmillr/noble-hashes/tar.gz/ae060daa6252f3ff2aa2f84e887de0aab491281d"

"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
Expand Down

0 comments on commit 24528f1

Please sign in to comment.