paritytech / schnorrkel-js Goto Github PK
View Code? Open in Web Editor NEWa Javascript wrapper for schnorrkel signatures on Ristretto using WebAssembly.
License: Apache License 2.0
a Javascript wrapper for schnorrkel signatures on Ristretto using WebAssembly.
License: Apache License 2.0
At least in the https://github.com/polkadot-js projects we need to support Browser/Node/React Native. wasm-pack is great, however the output options either creates something just for the browser or just for node.
Browser assumed webpack so does import * from 'schnorrkel_js_bg'
- which is a WASM file, cannot be done on Node without webpack. The node output (--target nodejs
) emits something where fs.readySync
is used, once again, not quite usable in the Browser or RN.
Basically to get this working, I'm using the following scripts to support both environments.
build.sh -
#!/bin/sh
# install wasm-pack as required
if ! [ -x "$(command -v wasm-pack)" ]; then
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
fi
rm -rf ./pkg
rustup default nightly
wasm-pack build --target nodejs
rustup default stable
# make a backup of the original, use it, don't use it (useful for checking)
mv ./pkg/schnorrkel_js_bg.js ./pkg/schnorrkel_js_bg_node.js
./wasm2js.js
wasm2js.js -
#!/usr/bin/env node
const fs = require('fs');
const buffer = fs.readFileSync('./pkg/schnorrkel_js_bg.wasm');
fs.writeFileSync('./pkg/schnorrkel_js_bg.js', `const imports = {};\n
imports['./schnorrkel_js'] = require('./schnorrkel_js');\nconst bytes = Buffer.from('${buffer.toString('hex')}', 'hex');\nconst wasmModule = new WebAssembly.Module(bytes);\nconst wasmInstance = new WebAssembly.Instance(wasmModule, imports);\n\n
module.exports = wasmInstance.exports;`);
By far from the prettiest hack around, but it basically yields something that I can use as-is.
In an ideal world there would be sign and verify methods able to take a signing context from JS at runtime.
We've been scratching our heads over the current situation. The context is fixed to substrate
, and the requirement seems to be that any signing context is defined at build time. Besides forking this repo and publishing a package with the signing contexts cennznet needs, are there any other methods that might work for us?
The underlying cause of the issue is a static lifetime requirement on the signing context that comes from the merlin
crate, which is used by w3f's schnorrkel
.
Basically webpack displays this -
WARNING in /Users/jacogreeff/Projects/polkadot/apps/node_modules/@parity/schnorrkel-js/schnorrkel_js.js 232:25-39
Critical dependency: the request of a dependency is an expression
Due to schnorrkel_js.js
importing schnorrkel_js_bg.js
and that requiring schnorrkel_js.js
Currently, one of the API functions returns a byte array which is the concatenation of the private and public key respectively.
pub fn keypair_from_seed(seed: &[u8]) -> [u8; KEYPAIR_LENGTH] { ... }
It is the user's duty to properly separate them as documented in the Rust code.
While there also exists another function which does almost the same but only returns the secret/private
portion of the key.
pub fn secret_from_seed(seed: &[u8]) -> [u8; SECRET_KEY_LENGTH] { ... }
Consequently, the sign function is currently accepting the public and private key separately.
pub fn sign(public: &[u8], private: &[u8], message: &[u8]) -> [u8; SIGNATURE_LENGTH] { ... }
Based on the above, I see at least two improvements that could be made:
secret_from_seed
even needed?private_from_pair(keypair)
etc.
Currently, there are two panic!
s and one except()
in the Rust code. They should be removed. Consequently, the entire interface could -> should be replaced with returning Result<T, JsVal>
.
https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/catch.html
... We cannot seem to win.
Works under Node, now breaks under Webpack.
Uncaught TypeError: TextDecoder is not a constructor
at eval (schnorrkel_js.js?2cbf:179)
at Object.../../node_modules/@parity/schnorrkel-js/schnorrkel_js.js (main.d8a8675f.js:351)
Specifically derived_key_simple
enabling us to do this logic from the JS side -
pub fn derive<Iter: Iterator<Item=DeriveJunction>>(&self, path: Iter) -> Option<Public> {
let mut acc = PublicKey::from_bytes(self.as_ref()).ok()?;
for j in path {
match j {
DeriveJunction::Soft(cc) => acc = acc.derived_key_simple(ChainCode(cc), &[]).0,
DeriveJunction::Hard(_cc) => return None,
}
}
Some(Self(acc.to_bytes()))
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.