Skip to content

Commit

Permalink
BREAKING CHANGE: remove sha256 from API
Browse files Browse the repository at this point in the history
  • Loading branch information
blake-regalia committed Nov 3, 2023
1 parent de7d43f commit da8d769
Show file tree
Hide file tree
Showing 13 changed files with 48 additions and 110 deletions.
14 changes: 3 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,6 @@ interface Secp256k1 {
* @returns the shared secret (32 bytes)
*/
ecdh(atu8_sk: Uint8Array, atu8_pk: Uint8Array): Uint8Array;

/**
* Synchronous SHA-256 hash function
* @param atu8_data - message to hash synchronously
* @returns the message digest (32 bytes)
*/
sha256(atu8_data: Uint8Array): Uint8Array;
}
```

Expand Down Expand Up @@ -128,10 +121,9 @@ Caller is responsible for zero-ing out private keys in the Typed Arrays it passe

## Is libsecp256k1 modified?

The library is imported as a git submodule directly from upstream.
No, the library is imported as a git submodule directly from upstream.

However, there is one modification made by default to `hash_impl.h` and `hash.h` to make the sha256 hashing functions external. This makes it so that they can be used from JS environment to provide a synchronous hash function, which can be useful in certain contexts where developers would otherwise be relegated to Web Crypto's async API.

The change simply removes the `static` storage modifier and adds `external` in the include header to those three sha256 functions. You can review the changes made [here](./scripts/compile.sh#L81-L82).
## See also

If you don't want or disagree with those changes, you can omit the `--externalize-sha256` option passed to the compile script.
[hash-wasm](https://github.com/Daninet/hash-wasm/tree/master) is a great library that provides performant hashing using optimized WASM binaries. Though its API is asynchronous, it also provides an undocumented synchronous API.
1 change: 0 additions & 1 deletion docs/assets/index-8e6401d6.js.map

This file was deleted.

49 changes: 17 additions & 32 deletions docs/assets/index-8e6401d6.js → docs/assets/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/assets/index.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
border: 1px solid #666;
}
</style>
<script type="module" crossorigin src="./assets/index-8e6401d6.js"></script>
<script type="module" crossorigin src="./assets/index.js"></script>
</head>
<body>
<div id="app"></div>
Expand Down
1 change: 0 additions & 1 deletion docs/out/secp256k1.js

This file was deleted.

Binary file modified docs/out/secp256k1.wasm
Binary file not shown.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@solar-republic/wasm-secp256k1",
"description": "TypeScript wrapper and Web Assembly module of the libsecp256k1 C library",
"version": "0.1.0-alpha.0",
"version": "0.1.0",
"type": "module",
"main": "build/dist/main.js",
"files": [
Expand All @@ -14,7 +14,8 @@
"build:wasm-bin": "docker build -f secp256k1.Dockerfile . -t wasm-secp256k1 && docker run --rm -v $(pwd)/public:/out wasm-secp256k1",
"build:wasm-ts": "bun run ./src/generate.ts public/out/secp256k1.js > ./src/gen/wasm.ts",
"build:wasm": "bun run build:wasm-bin && bun run build:wasm-ts",
"build": "bun run build:wasm && tsc",
"build:demo": "vite build && rm docs/out/secp256k1.js",
"build": "bun run build:wasm && tsc && bun run build:demo",
"demo": "bun run build && vite dev"
},
"dependencies": {},
Expand Down
2 changes: 1 addition & 1 deletion secp256k1.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ COPY scripts/compile.sh /app

WORKDIR /app

RUN ./compile.sh --externalize-sha256
RUN ./compile.sh

# copy outputs to mounted volume
CMD ["cp", "-r", "/app/out", "/out"]
42 changes: 2 additions & 40 deletions src/api/secp256k1.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {PointerNonceFn, PointerPubkey, PointerSeed, PointerSha256, PointerSig, Secp256k1WasmCore, Secp256k1WasmEcdh, Secp256k1WasmEcdsaRaw, Secp256k1WasmSha256} from './secp256k1-types.js';
import type {PointerNonceFn, PointerPubkey, PointerSeed, PointerSig, Secp256k1WasmCore, Secp256k1WasmEcdh, Secp256k1WasmEcdsaRaw} from './secp256k1-types.js';
import type {ByteSize, Pointer} from '../types.js';

import type {Promisable} from '@blake.regalia/belt';
Expand Down Expand Up @@ -68,24 +68,15 @@ export interface Secp256k1 {
* @returns the shared secret (32 bytes)
*/
ecdh(atu8_sk: Uint8Array, atu8_pk: Uint8Array): Uint8Array;

/**
* Synchronous SHA-256 hash function
* @param atu8_data - message to hash synchronously
* @returns the message digest (32 bytes)
*/
sha256(atu8_data: Uint8Array): Uint8Array;
}

/**
* Creates a new instance of the secp256k1 WASM and returns its ES wrapper
* @param dp_res - a Response containing the WASM binary, or a Promise that resolves to one
* @param nb_sha256_buffer - size of the buffer to create in WASM heap for loading data while hashing (defaults to 16 KiB)
* @returns the wrapper API
*/
export const WasmSecp256k1 = async(
dp_res: Promisable<Response>,
nb_sha256_buffer=1024*16
dp_res: Promisable<Response>
): Promise<Secp256k1> => {
// prepare the runtime
const [g_imports, f_bind_heap] = emsimp(map_wasm_imports, 'wasm-secp256k1');
Expand All @@ -98,7 +89,6 @@ export const WasmSecp256k1 = async(
Secp256k1WasmCore
& Secp256k1WasmEcdh
& Secp256k1WasmEcdsaRaw
& Secp256k1WasmSha256
>(d_wasm.instance.exports);

// bind the heap and ref its view(s)
Expand All @@ -115,8 +105,6 @@ export const WasmSecp256k1 = async(
const ip_seed = malloc<PointerSeed>(ByteLens.RANDOM_SEED);
const ip_sk_shared = malloc(ByteLens.ECDH_SHARED_SK);
const ip_msg_hash = malloc(ByteLens.MSG_HASH);
const ip_sh256 = malloc<PointerSha256>(ByteLens.SHA256);
const ip_buffer = malloc(nb_sha256_buffer);

// scratch spaces
const ip_sig_scratch = malloc(ByteLens.ECDSA_SIG_COMPACT);
Expand Down Expand Up @@ -328,32 +316,6 @@ export const WasmSecp256k1 = async(
return ATU8_HEAP.slice(ip_sk_shared, ip_sk_shared+ByteLens.ECDH_SHARED_SK);
});
},

sha256(atu8_data) {
// initialize new hash object
g_wasm.sha256_initialize(ip_sh256);

// each chunk of input data
for(let ib_read=0; ib_read<atu8_data.length;) {
// select the chunk
const atu8_chunk = atu8_data.subarray(ib_read, ib_read+nb_sha256_buffer);

// copy into WASM memory
ATU8_HEAP.set(atu8_chunk, ip_buffer);

// advance the read pointer
ib_read += atu8_chunk.length;

// write to the hash
g_wasm.sha256_write(ip_sh256, ip_buffer, atu8_chunk.length);
}

// finalize the hash
g_wasm.sha256_finalize(ip_sh256, ip_msg_hash);

// return a copy
return ATU8_HEAP.subarray(ip_msg_hash, ip_msg_hash+ByteLens.MSG_HASH);
},
};
};

8 changes: 4 additions & 4 deletions src/demo/webapp.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {buffer_to_hex, hex_to_buffer, text_to_buffer} from '@blake.regalia/belt';
import {buffer_to_hex, hex_to_buffer, sha256, text_to_buffer} from '@blake.regalia/belt';

import {WasmSecp256k1} from '../api/secp256k1';

Expand Down Expand Up @@ -51,11 +51,11 @@ const dm_verified = elem<HTMLInputElement>('verified');

dm_pk.value = buffer_to_hex(atu8_pk);

reload_sig();
void reload_sig();
}

function reload_sig() {
atu8_hash = k_secp.sha256(text_to_buffer(dm_msg.value));
async function reload_sig() {
atu8_hash = await sha256(text_to_buffer(dm_msg.value));

dm_hash.value = buffer_to_hex(atu8_hash);

Expand Down
28 changes: 11 additions & 17 deletions src/gen/wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ export interface WasmImportsExtension extends WasmImports {
}

export interface WasmExportsExtension extends WasmExports {
sha256_initialize: Function;
sha256_write: Function;
sha256_finalize: Function;
context_create: Function;
ec_pubkey_parse: Function;
ec_pubkey_serialize: Function;
Expand Down Expand Up @@ -56,20 +53,17 @@ export const map_wasm_exports = <
>(g_exports: WebAssembly.Exports): g_extension => ({
malloc: g_exports['i'],
free: g_exports['j'],
sha256_initialize: g_exports['l'],
sha256_write: g_exports['m'],
sha256_finalize: g_exports['n'],
context_create: g_exports['o'],
ec_pubkey_parse: g_exports['p'],
ec_pubkey_serialize: g_exports['q'],
ecdsa_signature_parse_compact: g_exports['r'],
ecdsa_signature_serialize_compact: g_exports['s'],
ecdsa_verify: g_exports['t'],
ecdsa_sign: g_exports['u'],
ec_seckey_verify: g_exports['v'],
ec_pubkey_create: g_exports['w'],
context_randomize: g_exports['x'],
ecdh: g_exports['y'],
context_create: g_exports['l'],
ec_pubkey_parse: g_exports['m'],
ec_pubkey_serialize: g_exports['n'],
ecdsa_signature_parse_compact: g_exports['o'],
ecdsa_signature_serialize_compact: g_exports['p'],
ecdsa_verify: g_exports['q'],
ecdsa_sign: g_exports['r'],
ec_seckey_verify: g_exports['s'],
ec_pubkey_create: g_exports['t'],
context_randomize: g_exports['u'],
ecdh: g_exports['v'],
sbrk: g_exports['sbrk'],
memory: g_exports['g'],

Expand Down
5 changes: 5 additions & 0 deletions vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ export default defineConfig(({mode:si_mode}) => ({
sourcemap: true,
minify: false,
emptyOutDir: true,
rollupOptions: {
output: {
entryFileNames: 'assets/[name].js',
},
},
},
base: './',
}));

0 comments on commit da8d769

Please sign in to comment.