Skip to content

Re-support WASM via simple stub headers #208

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

Merged
merged 3 commits into from
Apr 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
language: rust
# cache:
# directories:
# - cargo_web
cache:
directories:
- wasm

rust:
- stable
- beta
- nightly
- 1.22.0
distro: bionic
os:
- linux
- windows

addons:
chrome: stable
apt:
packages:
- clang-9
- nodejs

matrix:
exclude:
Expand Down Expand Up @@ -46,8 +51,10 @@ script:
cd no_std_test &&
cargo run --release | grep -q "Verified Successfully";
fi
- #if [ ${TRAVIS_RUST_VERSION} == "stable" -a "$TRAVIS_OS_NAME" = "linux" ]; then
#CARGO_TARGET_DIR=cargo_web cargo install --verbose --force cargo-web &&
#cargo web build --verbose --target=asmjs-unknown-emscripten &&
#cargo web test --verbose --target=asmjs-unknown-emscripten;
#fi
- if [ ${TRAVIS_RUST_VERSION} == "stable" -a "$TRAVIS_OS_NAME" = "linux" ]; then
clang --version &&
CARGO_TARGET_DIR=wasm cargo install --verbose --force wasm-pack &&
sed -i 's/\[lib\]/[lib]\ncrate-type = ["cdylib", "rlib"]/' Cargo.toml &&
CC=clang-9 wasm-pack build &&
CC=clang-9 wasm-pack test --node;
fi
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ rand_core = "0.4"
serde_test = "1.0"
bitcoin_hashes = "0.7"

[target.wasm32-unknown-unknown.dev-dependencies]
wasm-bindgen-test = "0.3"
rand = { version = "0.6", features = ["wasm-bindgen"] }

[dependencies.rand]
version = "0.6"
optional = true
Expand Down
4 changes: 4 additions & 0 deletions secp256k1-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ fn main() {
.define("USE_SCALAR_8X32", Some("1"));
}

if env::var("TARGET").unwrap() == "wasm32-unknown-unknown" {
base_config.include("wasm-sysroot");
}

// secp256k1
base_config.file("depend/secp256k1/contrib/lax_der_parsing.c")
.file("depend/secp256k1/src/secp256k1.c")
Expand Down
28 changes: 14 additions & 14 deletions secp256k1-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ extern "C" {

// Contexts
#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_context_preallocated_size")]
pub fn secp256k1_context_preallocated_size(flags: c_uint) -> usize;
pub fn secp256k1_context_preallocated_size(flags: c_uint) -> size_t;

#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_context_preallocated_create")]
pub fn secp256k1_context_preallocated_create(prealloc: *mut c_void, flags: c_uint) -> *mut Context;
Expand All @@ -161,7 +161,7 @@ extern "C" {
pub fn secp256k1_context_preallocated_destroy(cx: *mut Context);

#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_context_preallocated_clone_size")]
pub fn secp256k1_context_preallocated_clone_size(cx: *const Context) -> usize;
pub fn secp256k1_context_preallocated_clone_size(cx: *const Context) -> size_t;

#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_context_preallocated_clone")]
pub fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: *mut c_void) -> *mut Context;
Expand All @@ -174,19 +174,19 @@ extern "C" {
// Pubkeys
#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_ec_pubkey_parse")]
pub fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey,
input: *const c_uchar, in_len: usize)
input: *const c_uchar, in_len: size_t)
-> c_int;

#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_ec_pubkey_serialize")]
pub fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar,
out_len: *mut usize, pk: *const PublicKey,
out_len: *mut size_t, pk: *const PublicKey,
compressed: c_uint)
-> c_int;

// Signatures
#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_ecdsa_signature_parse_der")]
pub fn secp256k1_ecdsa_signature_parse_der(cx: *const Context, sig: *mut Signature,
input: *const c_uchar, in_len: usize)
input: *const c_uchar, in_len: size_t)
-> c_int;

#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_ecdsa_signature_parse_compact")]
Expand All @@ -196,12 +196,12 @@ extern "C" {

#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_ecdsa_signature_parse_der_lax")]
pub fn ecdsa_signature_parse_der_lax(cx: *const Context, sig: *mut Signature,
input: *const c_uchar, in_len: usize)
input: *const c_uchar, in_len: size_t)
-> c_int;

#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_ecdsa_signature_serialize_der")]
pub fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, output: *mut c_uchar,
out_len: *mut usize, sig: *const Signature)
out_len: *mut size_t, sig: *const Signature)
-> c_int;

#[cfg_attr(not(feature = "external-symbols"), link_name = "rustsecp256k1_v0_1_1_ecdsa_signature_serialize_compact")]
Expand Down Expand Up @@ -462,12 +462,12 @@ mod fuzz_dummy {
}

/// Return dummy size of context struct.
pub unsafe fn secp256k1_context_preallocated_size(_flags: c_uint) -> usize {
pub unsafe fn secp256k1_context_preallocated_size(_flags: c_uint) -> size_t {
mem::size_of::<Context>()
}

/// Return dummy size of context struct.
pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *mut Context) -> usize {
pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *mut Context) -> size_t {
mem::size_of::<Context>()
}

Expand All @@ -494,7 +494,7 @@ mod fuzz_dummy {
// Pubkeys
/// Parse 33/65 byte pubkey into PublicKey, losing compressed information
pub unsafe fn secp256k1_ec_pubkey_parse(cx: *const Context, pk: *mut PublicKey,
input: *const c_uchar, in_len: usize)
input: *const c_uchar, in_len: size_t)
-> c_int {
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
match in_len {
Expand All @@ -521,7 +521,7 @@ mod fuzz_dummy {

/// Serialize PublicKey back to 33/65 byte pubkey
pub unsafe fn secp256k1_ec_pubkey_serialize(cx: *const Context, output: *mut c_uchar,
out_len: *mut usize, pk: *const PublicKey,
out_len: *mut size_t, pk: *const PublicKey,
compressed: c_uint)
-> c_int {
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);
Expand All @@ -546,7 +546,7 @@ mod fuzz_dummy {

// Signatures
pub unsafe fn secp256k1_ecdsa_signature_parse_der(_cx: *const Context, _sig: *mut Signature,
_input: *const c_uchar, _in_len: usize)
_input: *const c_uchar, _in_len: size_t)
-> c_int {
unimplemented!();
}
Expand All @@ -562,14 +562,14 @@ mod fuzz_dummy {
}

pub unsafe fn ecdsa_signature_parse_der_lax(_cx: *const Context, _sig: *mut Signature,
_input: *const c_uchar, _in_len: usize)
_input: *const c_uchar, _in_len: size_t)
-> c_int {
unimplemented!();
}

/// Copies up to 72 bytes into output from sig
pub unsafe fn secp256k1_ecdsa_signature_serialize_der(cx: *const Context, output: *mut c_uchar,
out_len: *mut usize, sig: *const Signature)
out_len: *mut size_t, sig: *const Signature)
-> c_int {
assert!(!cx.is_null() && (*cx).0 as u32 & !(SECP256K1_START_NONE | SECP256K1_START_VERIFY | SECP256K1_START_SIGN) == 0);

Expand Down
42 changes: 41 additions & 1 deletion secp256k1-sys/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ use core::fmt;
pub type c_int = i32;
pub type c_uchar = u8;
pub type c_uint = u32;
pub type size_t = usize;

/// This might not match C's `c_char` exactly.
/// The way we use it makes it fine either way but this type shouldn't be used outside of the library.
pub type c_char = i8;

/// This is an exact copy of https://doc.rust-lang.org/core/ffi/enum.c_void.html
/// It should be Equivalent to C's void type when used as a pointer.
///
///
/// We can replace this with `core::ffi::c_void` once we update the rustc version to >=1.30.0.
#[repr(u8)]
pub enum c_void {
Expand Down Expand Up @@ -39,3 +40,42 @@ mod tests {
assert_eq!(TypeId::of::<types::c_char>(), TypeId::of::<raw::c_char>());
}
}


#[doc(hidden)]
#[cfg(target_arch = "wasm32")]
pub fn sanity_checks_for_wasm() {
use std::mem::{size_of, align_of};
extern "C" {
pub static WASM32_INT_SIZE: c_uchar;
pub static WASM32_INT_ALIGN: c_uchar;

pub static WASM32_UNSIGNED_INT_SIZE: c_uchar;
pub static WASM32_UNSIGNED_INT_ALIGN: c_uchar;

pub static WASM32_SIZE_T_SIZE: c_uchar;
pub static WASM32_SIZE_T_ALIGN: c_uchar;

pub static WASM32_UNSIGNED_CHAR_SIZE: c_uchar;
pub static WASM32_UNSIGNED_CHAR_ALIGN: c_uchar;

pub static WASM32_PTR_SIZE: c_uchar;
pub static WASM32_PTR_ALIGN: c_uchar;
}
unsafe {
assert_eq!(size_of::<c_int>(), WASM32_INT_SIZE as usize);
assert_eq!(align_of::<c_int>(), WASM32_INT_ALIGN as usize);

assert_eq!(size_of::<c_uint>(), WASM32_UNSIGNED_INT_SIZE as usize);
assert_eq!(align_of::<c_uint>(), WASM32_UNSIGNED_INT_ALIGN as usize);

assert_eq!(size_of::<size_t>(), WASM32_SIZE_T_SIZE as usize);
assert_eq!(align_of::<size_t>(), WASM32_SIZE_T_ALIGN as usize);

assert_eq!(size_of::<c_uchar>(), WASM32_UNSIGNED_CHAR_SIZE as usize);
assert_eq!(align_of::<c_uchar>(), WASM32_UNSIGNED_CHAR_ALIGN as usize);

assert_eq!(size_of::<*const ()>(), WASM32_PTR_SIZE as usize);
assert_eq!(align_of::<*const ()>(), WASM32_PTR_ALIGN as usize);
}
}
17 changes: 17 additions & 0 deletions secp256k1-sys/wasm-sysroot/stdio.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <stddef.h>
#define alignof(type) offsetof (struct { char c; type member; }, member)

extern const unsigned char WASM32_INT_SIZE = sizeof(int);
extern const unsigned char WASM32_INT_ALIGN = alignof(int);

extern const unsigned char WASM32_UNSIGNED_INT_SIZE = sizeof(unsigned int);
extern const unsigned char WASM32_UNSIGNED_INT_ALIGN = alignof(unsigned int);

extern const unsigned char WASM32_SIZE_T_SIZE = sizeof(size_t);
extern const unsigned char WASM32_SIZE_T_ALIGN = alignof(size_t);

extern const unsigned char WASM32_UNSIGNED_CHAR_SIZE = sizeof(unsigned char);
extern const unsigned char WASM32_UNSIGNED_CHAR_ALIGN = alignof(unsigned char);

extern const unsigned char WASM32_PTR_SIZE = sizeof(void*);
extern const unsigned char WASM32_PTR_ALIGN = alignof(void*);
Empty file.
4 changes: 4 additions & 0 deletions secp256k1-sys/wasm-sysroot/string.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include <stddef.h>
void *memset(void *s, int c, size_t n);
void *memcpy(void *dest, const void *src, size_t n);
int memcmp(const void *s1, const void *s2, size_t n);
6 changes: 6 additions & 0 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ mod std_only {
impl<C: Context> Secp256k1<C> {
/// Lets you create a context in a generic manner(sign/verify/all)
pub fn gen_new() -> Secp256k1<C> {
#[cfg(target_arch = "wasm32")]
ffi::types::sanity_checks_for_wasm();

let buf = vec![0u8; Self::preallocate_size_gen()].into_boxed_slice();
let ptr = Box::into_raw(buf);
Secp256k1 {
Expand Down Expand Up @@ -192,6 +195,9 @@ unsafe impl<'buf> Context for AllPreallocated<'buf> {
impl<'buf, C: Context + 'buf> Secp256k1<C> {
/// Lets you create a context with preallocated buffer in a generic manner(sign/verify/all)
pub fn preallocated_gen_new(buf: &'buf mut [u8]) -> Result<Secp256k1<C>, Error> {
#[cfg(target_arch = "wasm32")]
ffi::types::sanity_checks_for_wasm();

if buf.len() < Self::preallocate_size_gen() {
return Err(Error::NotEnoughMemory);
}
Expand Down
27 changes: 27 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,33 @@ mod tests {
assert_tokens(&sig.compact(), &[Token::BorrowedBytes(&SIG_BYTES[..])]);
assert_tokens(&sig.readable(), &[Token::BorrowedStr(SIG_STR)]);
}

// For WASM, just run through our general tests in this file all at once.
#[cfg(target_arch = "wasm32")]
extern crate wasm_bindgen_test;
#[cfg(target_arch = "wasm32")]
use self::wasm_bindgen_test::*;
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen_test]
fn stuff() {
test_manual_create_destroy();
test_raw_ctx();
// Note that, sadly, WASM doesn't currently properly unwind panics, so use of the library
// via unsafe primitives may cause abort() instead of catch-able panics.
/*assert!(std::panic::catch_unwind(|| {
test_panic_raw_ctx();
}).is_err());*/
test_preallocation();
capabilities();
signature_serialize_roundtrip();
signature_display();
signature_lax_der();
sign_and_verify();
sign_and_verify_extreme();
sign_and_verify_fail();
test_bad_slice();
test_low_s();
}
}

#[cfg(all(test, feature = "unstable"))]
Expand Down