Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: vat-safe denomHash using noble sha256 #9576

Merged
merged 2 commits into from
Jul 12, 2024
Merged

Conversation

dckc
Copy link
Member

@dckc dckc commented Jun 24, 2024

refs: #9211

Description

Prototyping for #9211 suggests we'll want to be derive IBC denoms 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, 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.

Copy link

cloudflare-workers-and-pages bot commented Jun 24, 2024

Deploying agoric-sdk with  Cloudflare Pages  Cloudflare Pages

Latest commit: 58ff687
Status: ✅  Deploy successful!
Preview URL: https://0945a778.agoric-sdk.pages.dev
Branch Preview URL: https://dc-vatsafe-denomhash.agoric-sdk.pages.dev

View logs

Copy link
Member

@kriskowal kriskowal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should work. Shame about the bundle bloat but I’m sure we’re not waiting for XS native support.

@@ -0,0 +1,30 @@
// @ts-check
import { sha256 } from '@noble/hashes/sha256';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Watch out for bundler support for "exports" since this pattern will only work when the tools account for package exports.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there an alternative?

Copy link
Member

@kriskowal kriskowal Jun 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not with this package. It’s pretty narrowly prescribed:

https://github.com/paulmillr/noble-hashes/blob/main/package.json#L141-L145

That is, this package cannot be used with bundlers that have not caught up with package exports. There are very few such tools, but node -r esm (loadgen) is among them. Hopefully, there is no risk that this package will get caught up in that, but if you see integration errors to the tune of “I can’t import this”, this is why.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

felgercarb!

loadgen ci failed. :-/

now what do I do? sigh.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could fork or PR upstream to package export package relative paths to files with .js extensions. I’m not against forking this into Endo. We do that for Base64. We could harden the library. We would have recourse to fall through to native on XS if that becomes available.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not against forking this into Endo. We do that for Base64.

I like that idea enough to reify it as an issue:

I'll pursue other options in parallel, so it's not necessarily critical path.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadgen fixed with 58ff687

Downstream imports won't get the patch but they don't need it.

Comment on lines 8 to 10
return [...new Uint8Array(buffer)]
.map(x => x.toString(16).padStart(2, '0'))
.join('');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reasonably concise. An intermediate allocation might be avoidable with Array.prototype.map.call(new Uint8Array(buffer), x => x.toString(16).padStart(2, '0').

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turns out @noble/hashes/utils has a bytesToHex, so I'm going with that.

path = `${portId}/${channelId}`,
denom,
}) => {
const h = sha256.create().update(`${path}/${denom}`).digest();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could avoid an allocation with digestInto, using the same Uint8Array view for both this and toHex.

@dckc dckc marked this pull request as draft June 26, 2024 16:00
@dckc
Copy link
Member Author

dckc commented Jun 26, 2024

@kriskowal @0xpatrickdev PTAAL.

It turns out that after I got it working in a Compartment, I changed the @noble/hashes version to match @cosmjs/crypto... but that version is the reason I didn't import sha256 from @cosmjs/crypto in the first place. Good thing we have ci :)

Also, I flipped the build-vs-buy switch on bytesToHex.

@dckc dckc requested a review from kriskowal June 26, 2024 17:30
@dckc dckc marked this pull request as ready for review June 26, 2024 17:31
Copy link
Member

@0xpatrickdev 0xpatrickdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The denomHash logic LGTM

@dckc dckc added the automerge:rebase Automatically rebase updates, then merge label Jun 26, 2024
@@ -0,0 +1,30 @@
// @ts-check
import { sha256 } from '@noble/hashes/sha256';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could fork or PR upstream to package export package relative paths to files with .js extensions. I’m not against forking this into Endo. We do that for Base64. We could harden the library. We would have recourse to fall through to native on XS if that becomes available.

@turadg turadg force-pushed the dc-vatSafe-denomHash branch 2 times, most recently from 0a9b736 to 92a0751 Compare July 11, 2024 23:22
@turadg turadg added force:integration Force integration tests to run on PR and removed automerge:rebase Automatically rebase updates, then merge labels Jul 11, 2024
@turadg turadg self-assigned this Jul 12, 2024
dckc and others added 2 commits July 12, 2024 06:41
- @noble/hashes dependency
 - unit test using bundle

Co-Authored-By: Turadg Aleahmad <turadg@agoric.com>
@turadg turadg added the automerge:rebase Automatically rebase updates, then merge label Jul 12, 2024
@mergify mergify bot merged commit 24528f1 into master Jul 12, 2024
81 of 86 checks passed
@mergify mergify bot deleted the dc-vatSafe-denomHash branch July 12, 2024 14:14
@gibson042
Copy link
Member

@dckc Out of curiosity, how did you measure the bundle size? I'm wondering if it would be reduced by a roll-your-own bytesToHex:

const hexForByte = Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, '0'));
const bytesToHex = bytes => {
  let hex = '';
  for (let i = 0; i < bytes.length; i += 1) {
    hex += hexForByte[bytes[i]];
  }
  return hex;
};

(but I suspect not, since sha256.ts also imports from utils.js so the savings would only manifest with fine-grained tree-shaking)

@dckc
Copy link
Member Author

dckc commented Jul 16, 2024

@dckc Out of curiosity, how did you measure the bundle size?

silly me knows better than to not show his work

IIRC, I bundled orchestration/test/utils/denomHashEx.js (or a slight variation) and used a recent improvement to bundle-source to get that table.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:rebase Automatically rebase updates, then merge force:integration Force integration tests to run on PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants