GithubHelp home page GithubHelp logo

ocaml-sodium's Introduction

This repository is now archived. Please use and contribute to https://github.com/ahrefs/ocaml-sodium.

ocaml-sodium

Ctypes bindings to libsodium 1.0.9+ which wraps NaCl. GNU/Linux, FreeBSD, and OS X operating systems are supported. OCaml 4.01.0 or later is required to build.

All original NaCl primitives are wrapped. crypto_shorthash is missing.

open Sodium
let nonce = Box.random_nonce () in
let (sk, pk ) = Box.random_keypair () in
let (sk',pk') = Box.random_keypair () in
let c = Box.Bytes.box sk pk' "Hello, Spooky World!" nonce in
let m = Box.Bytes.box_open sk' pk c nonce in
print_endline (String.escaped c);
print_endline m

Considerations

Originally described in The Security Impact of a New Cryptographic Library, NaCl is a high-level, performant cryptography library exposing a straightforward interface.

This binding has not been thoroughly and independently audited so your use case must be able to tolerate this uncertainty.

Despite ocaml-sodium's thin interface on top of libsodium, it is still important to be mindful of security invariants. In particular, you should ensure that nonces used for cryptographic operations are never repeated with the same key set.

Tests

Internal consistency tests may be found in lib_test.

Salt

Salt is very important for the camel. It needs eight times as much salt as do cattle and sheep. A camel needs 1 kg of salt a week and it is advisable to leave salt with camels every week.

-- UN FAO Manual for Primary Animal Health Care Workers

ocaml-sodium's People

Contributors

avsm avatar chambart avatar cmb avatar dsheets avatar klakplok avatar vbmithr avatar whitequark avatar yallop avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ocaml-sodium's Issues

Change of maintainer

We started to use this library extensively at our organization (Ahrefs). This project does not receive any updates for quite a while. Issues are not fixed, PRs are not approved, so currently we maintain a fork at http://github.com/ahrefs/ocaml-sodium with some of the PRs merged.

If there are no objections or better proposals within a reasonable time, we would like to take over the maintenance of the project and publish new releases to opam from our repository.

Build failure on OSX

opam install sodium fails with:

=-=- Processing actions -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=  🐫
[ERROR] The compilation of sodium failed at "make".
Processing  1/1: [sodium: ocamlfind remove]
#=== ERROR while installing sodium.0.5.0 ======================================#
# opam-version 1.2.2
# os           darwin
# command      make
# path         /Users/amir/.opam/signpost/build/sodium.0.5.0
# compiler     system (4.02.2)
# exit-code    2
# env-file     /Users/amir/.opam/signpost/build/sodium.0.5.0/sodium-10155-6d07ae.env
# stdout-file  /Users/amir/.opam/signpost/build/sodium.0.5.0/sodium-10155-6d07ae.out
# stderr-file  /Users/amir/.opam/signpost/build/sodium.0.5.0/sodium-10155-6d07ae.err
### stdout ###
# [...]
# ocamlfind ocamlc -c -bin-annot -safe-string -package ctypes.stubs -w @5@8@10@11@12@14@23@24@26@29 -I lib_gen -I lib -o lib_gen/sodium_typegen.cmo lib_gen/sodium_typegen.ml
# ocamlfind ocamlc -linkpkg -package ctypes.stubs lib_gen/sodium_types.cmo lib_gen/sodium_typegen.cmo -o lib_gen/sodium_typegen.byte
# lib_gen/sodium_typegen.byte
# cc -I /Users/amir/.opam/signpost/lib/ctypes -I /usr/local/lib/ocaml -o lib_gen/sodium_types_detect lib_gen/sodium_types_detect.c
# + cc -I /Users/amir/.opam/signpost/lib/ctypes -I /usr/local/lib/ocaml -o lib_gen/sodium_types_detect lib_gen/sodium_types_detect.c
# lib_gen/sodium_types_detect.c:1:10: fatal error: 'sodium.h' file not found
# #include <sodium.h>
#          ^
#1 error generated.
# Command exited with code 1.
### stderr ###
# make: *** [all] Error 10

System details:

$ opam config report
# OPAM config report
# opam-version    1.2.2
# self-upgrade    no
# os              darwin
# external-solver aspcud $in $out $criteria
# criteria        -count(removed),-notuptodate(request),-sum(request,version-lag),-count(down),-notuptodate(changed),-count(changed),-notuptodate(solution),-sum(solution,version-lag)
# jobs            4
# repositories    1* (http)
# pinned          0
# current-switch  signpost*
# last-update     2015-07-26 16:00
$ brew --version
0.9.5
$ brew info libsodium
libsodium: stable 1.0.3 (bottled), HEAD
NaCl networking and cryptography library
https://github.com/jedisct1/libsodium/
/usr/local/Cellar/libsodium/1.0.3 (62 files, 1.1M) *
  Poured from bottle
From: https://github.com/Homebrew/homebrew/blob/master/Library/Formula/libsodium.rb
==> Options
--universal
    Build a universal binary
--HEAD
    Install HEAD version
$ cc --version
Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.4.0
Thread model: posix

I'm on OSX 10.10.4 (Yosemite).

Project moribund?

Is anybody home?

I've added bazel support for this but the tests all fail. I'm wondering if that is because I'm using libsodium 1.0.18-RELEASE.

Thanks.

does not work in toplevel

# #require "sodium";;
Cannot load required shared library dllsodium_generated_stubs.
Reason: /home/ygrek/.opam/x/lib/stublibs/dllsodium_generated_stubs.so: /home/ygrek/.opam/x/lib/stublibs/dllsodium_generated_stubs.so: undefined symbol: sodium_init.
Characters -1--1:
  #require "sodium";;
  
Error: Reference to undefined global `Sodium_generated'

The reason is clear, and the following straightforward patch fixes it :

diff -ur sodium.0.6.1~20190305/lib_gen/dune sodium.0.6.1~20190305-fix/lib_gen/dune
--- sodium.0.6.1~20190305/lib_gen/dune	2019-03-04 23:31:55.000000000 -0500
+++ sodium.0.6.1~20190305-fix/lib_gen/dune	2019-05-17 14:00:22.634788033 -0400
@@ -1,6 +1,7 @@
 (library
   (name sodium_generated)
   (public_name sodium.generated)
+  (c_library_flags :standard -lsodium)
   (libraries ctypes.stubs sodium_bindings)
   (modules sodium_generated)
   (c_names sodium_stubs))

A zero-copy interface?

I want to entirely avoid the octets copying thing, e.g. I want to be able to receive an Lwt_bytes.t from the wire and pass it directly to crypto_box.

I have attempted to draft an interface which would allow that. Here's my attempt (only for Random):

The idea was to hide the gory details of ctypes and present an entirely high-level representation to the world. Naturally, this resulted in inability to use anything except String and Bigstring as the backing storage. I think this is not a problem, because anything else would likely have to copy the data into one of these containers, or already operates directly on them. Even with copying, this is still more efficient than the octets thing.

I'm opening this issue to discuss the benefits and drawbacks of such approach. Meanwhile, I'll port all libsodium interfaces in a similar way.

chacha20

Any chance of also exposing chacha20, as well as salsa20?

Automatic key erasure / "wiping"

I just noticed that many of the bindings expose a "wipe" function:

let wipe str =
  C.memzero (Storage.Bytes.to_ptr str) (Storage.Bytes.len_size_t str)

It seems to me like it could be useful to automatically wipe keys as they are garbage collected using a Gc callback by adding a Gc finalization hook:

Gc.finalise (fun key -> wipe key) my_key

Ctypes has something similar for its Ctypes.allocate functions:

val allocate : ?finalise:('a ptr -> unit) -> 'a typ -> 'a -> 'a ptr

Documentation for Gc:
http://caml.inria.fr/pub/docs/manual-ocaml/libref/Gc.html

Documentation for Ctypes:
http://ocamllabs.github.io/ocaml-ctypes/Ctypes.html

Disclaimer:
I'm not super familiar with OCaml internals, so maybe this is silly / not effective, but I thought I'd post the idea here and hear your comments. Is this a viable option, at least for cases where the keys are never converted away from bytes?

Install error: warnings being treated as errors

These are some system combinations that I've tried to install sodium to:

  • Ubuntu 16.04 / OCaml 4.03.0 / opam 1.2.2 (my machine)
  • Ubuntu 16.04 / OCaml 4.04.0 / opam 1.2.2 (docker container)
  • debian 9 / OCaml 4.03.0 / opam 1.2.2 (docker container)

And the command that trigers this and the output is:

+ ocamlfind ocamlc -ccopt -I/usr/local/include -I /home/ql272/.opam/4.03.0/lib/ctypes -ccopt '--std=c99 -Wall -pedantic -Werror -Wno-pointer-sign' -c lib/sodium_stubs.c
lib/sodium_stubs.c: In function ‘caml__1_sodium_init’:
lib/sodium_stubs.c:6:4: error: ignoring return value of ‘sodium_init’, declared with attribute warn_unused_result [-Werror=unused-result]
    sodium_init();
    ^
lib/sodium_stubs.c: In function ‘caml__3_sodium_memcmp’:
lib/sodium_stubs.c:21:4: error: ignoring return value of ‘sodium_memcmp’, declared with attribute warn_unused_result [-Werror=unused-result]
    sodium_memcmp(x13, x14, x15);
    ^
cc1: all warnings being treated as errors
Command exited with code 2.

The whole output could be found here

Simple searching suggests that it's caused by the -Werror option, but I'm not sure where and how to work around this.

FWIW, I want to use ocaml-macaroons in one of my web apps, and ocaml-sodium is its depopts.

undefined symbol: sodium_init

  • I'm just getting up to speed on ocaml & sodium, this is probably an elementary mistake on my part.

I coded and compiled your example:

open Sodium
let () =
let nonce = Box.random_nonce () in
let (sk, pk ) = Box.random_keypair () in
let (sk',pk') = Box.random_keypair () in
let c = Box.Bytes.box sk pk' "Hello, Spooky World!" nonce in
let m = Box.Bytes.box_open sk' pk c nonce in
print_endline (String.escaped c);
print_endline m

.... and got:

Fatal error: exception Dl.DL_error("nacl_test.native: undefined symbol: sodium_init")
Raised by primitive operation at file "lib/iobuf.ml", line 902, characters 2-59
Called from file "lib/iobuf.ml", line 908, characters 12-95

provide String storage

example from README doesn't work :

    let c = Box.Bytes.box sk pk' "Hello, Spooky World!" nonce in
                                 ^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type string but an expression was expected of type
         Sodium.Box.Bytes.storage = bytes

Bind crypto_aead_chacha20poly1305_ietf_encrypt()

Hi, I need the Authenticated Encryption with Additional Data construction bound:

  • crypto_aead_chacha20poly1305_ietf_encrypt()
  • crypto_aead_chacha20poly1305_ietf_decrypt()
    (note that the _ietf_ functions are similar to crypto_aead_chacha20poly1305_en/decrypt functions, but take a longer nonce (96 bit as opposed to 64bit))

I can work on a PR with my own attempt, but you seem like you have a much better grasp of the Ctypes toolchain than I do, so it would be great if you have time.

incorrect ctypes version bound for (sodium > 0.4)?

The opam-builder results for sodium currently show that versions above 0.4 (that is 0.4.1, 0.5) fail to build. The build failure looks like in this report http://opam.ocamlpro.com/builder/html/sodium/sodium.0.5.0/57f96b30bff10fbb79b7d53086df011e, with sodium 5.0, ctypes 0.8.0 and ocaml 4.01.0 (see the report for the other versions of the dependencies).

# File "lib_gen/sodium_bindings.ml", line 26, characters 46-71:
# Error: This expression has type
#          (unit -> unit) Ctypes.fn = (unit -> unit) Ctypes_static.fn
#        but an expression was expected of type ('a -> 'b) F.fn
# Command exited with code 2.

I suppose that this means the version bound on ctypes is not strict enough. What would be correct version constraints?

type 'a key should be string instead of Bytes.t

Internally, the type 'a key in several modules should probably by string instead of Bytes.t, because keys are supposed to be immutable and only exported/imported from storage (if I understand well).

opam build fails while manual build succeeds

Ctypes upgrades from 0.3.0 to 0.4.0 so sodium has to be recompiled, but opam failed to compile. However, manually download the source and compile can be done successfully.

Here are some logs

  • truncated opam errors
#=== ERROR while installing sodium.0.3.0 ======================================#
# opam-version 1.2.0
# os           darwin
# command      make
# path         /Users/marklrh/.opam/4.02.1/build/sodium.0.3.0
# compiler     4.02.1
# exit-code    2
# env-file     /Users/marklrh/.opam/4.02.1/build/sodium.0.3.0/sodium-40451-6d07ae.env
# stdout-file  /Users/marklrh/.opam/4.02.1/build/sodium.0.3.0/sodium-40451-6d07ae.out
# stderr-file  /Users/marklrh/.opam/4.02.1/build/sodium.0.3.0/sodium-40451-6d07ae.err
### stdout ###
# ...[truncated]
# ocamlfind ocamlc -c -bin-annot -safe-string -package ctypes.stubs -w @5@8@10@11@12@14@23@24@26@29 -I lib_gen -I lib -o lib_gen/sodium_bindgen.cmo lib_gen/sodium_bindgen.ml
# ocamlfind ocamlc -linkpkg -package ctypes.stubs lib/sodium_storage.cmo lib_gen/sodium_bindings.cmo lib_gen/sodium_bindgen.cmo -o lib_gen/sodium_bindgen.byte
# lib_gen/sodium_bindgen.byte
# ocamlfind ocamlc -I /Users/marklrh/.opam/4.02.1/lib/ctypes/.. -ccopt '--std=c99 -Wall -pedantic -Werror -Wno-pointer-sign' -c lib/sodium_stubs.c
# + ocamlfind ocamlc -I /Users/marklrh/.opam/4.02.1/lib/ctypes/.. -ccopt '--std=c99 -Wall -pedantic -Werror -Wno-pointer-sign' -c lib/sodium_stubs.c
# lib/sodium_stubs.c:2:10: fatal error: 'ctypes_cstubs_internals.h' file not found
# #include "ctypes_cstubs_internals.h"
#          ^
#1 error generated.
# Command exited with code 2.
### stderr ###
# make: *** [all] Error 10
  • full log
OCAML_LIB_DIR=/Users/marklrh/.opam/4.02.1/lib/ctypes/.. IS_FREEBSD= ocamlbuild -use-ocamlfind -classic-display lib/sodium.cma lib/sodium.cmxa
ocamlfind ocamlopt unix.cmxa -I /Users/marklrh/.opam/4.02.1/lib/ocaml/ocamlbuild /Users/marklrh/.opam/4.02.1/lib/ocaml/ocamlbuild/ocamlbuildlib.cmxa -linkpkg myocamlbuild.ml /Users/marklrh/.opam/4.02.1/lib/ocaml/ocamlbuild/ocamlbuild.cmx -o myocamlbuild
ocamlfind ocamldep -package ctypes.stubs -modules lib_gen/sodium_bindgen.ml > lib_gen/sodium_bindgen.ml.depends
ocamlfind ocamldep -package ctypes.stubs -modules lib_gen/sodium_bindings.ml > lib_gen/sodium_bindings.ml.depends
ocamlfind ocamldep -package bytes -package bigarray -package ctypes.stubs -modules lib/sodium_storage.ml > lib/sodium_storage.ml.depends
ocamlfind ocamlc -c -bin-annot -safe-string -package bytes -package bigarray -package ctypes.stubs -w @5@8@10@11@12@14@23@24@26@29 -I lib -o lib/sodium_storage.cmo lib/sodium_storage.ml
ocamlfind ocamlc -c -bin-annot -safe-string -package ctypes.stubs -w @5@8@10@11@12@14@23@24@26@29 -I lib_gen -I lib -o lib_gen/sodium_bindings.cmo lib_gen/sodium_bindings.ml
ocamlfind ocamlc -c -bin-annot -safe-string -package ctypes.stubs -w @5@8@10@11@12@14@23@24@26@29 -I lib_gen -I lib -o lib_gen/sodium_bindgen.cmo lib_gen/sodium_bindgen.ml
ocamlfind ocamlc -linkpkg -package ctypes.stubs lib/sodium_storage.cmo lib_gen/sodium_bindings.cmo lib_gen/sodium_bindgen.cmo -o lib_gen/sodium_bindgen.byte
lib_gen/sodium_bindgen.byte
ocamlfind ocamlc -I /Users/marklrh/.opam/4.02.1/lib/ctypes/.. -ccopt '--std=c99 -Wall -pedantic -Werror -Wno-pointer-sign' -c lib/sodium_stubs.c
+ ocamlfind ocamlc -I /Users/marklrh/.opam/4.02.1/lib/ctypes/.. -ccopt '--std=c99 -Wall -pedantic -Werror -Wno-pointer-sign' -c lib/sodium_stubs.c
lib/sodium_stubs.c:2:10: fatal error: 'ctypes_cstubs_internals.h' file not found
#include "ctypes_cstubs_internals.h"
         ^
1 error generated.
Command exited with code 2.
  • environment config
PATH=/Users/marklrh/.opam/4.02.1/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/aria2/bin:/usr/local/go/bin:/usr/texbin:/Users/marklrh/go/bin
OCAML_TOPLEVEL_PATH=/Users/marklrh/.opam/4.02.1/lib/toplevel
PERL5LIB=/Users/marklrh/.opam/4.02.1/lib/perl5:
MAKEFLAGS=
MAKELEVEL=
MANPATH=:/Users/marklrh/.opam/4.02.1/man
OPAMUTF8MSGS=1
CAML_LD_LIBRARY_PATH=/Users/marklrh/.opam/4.02.1/lib/stublibs
TERM_PROGRAM=Apple_Terminal
TERM=xterm-256color
SHELL=/bin/bash
TMPDIR=/var/folders/dy/10lmgdp92qgd8p56mcmp22jw0000gn/T/
Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.zTJ8ce5Ius/Render
TERM_PROGRAM_VERSION=343.6
TERM_SESSION_ID=D77A00CF-7694-4BD2-9E6B-AC22B26F1D3E
USER=marklrh
SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.DUV4yR8Mih/Listeners
__CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0
PWD=/Users/marklrh/Dropbox/Projects/OCaml/ocaml-sodium
LANG=en_US.UTF-8
XPC_FLAGS=0x0
XPC_SERVICE_NAME=0
HOME=/Users/marklrh
SHLVL=1
PYTHONPATH=:/Library/Python/2.7/site-packages
LOGNAME=marklrh
LIBFFI_LIBS=-L/usr/local/Cellar/libffi/3.0.13/lib -lffi
GOPATH=/Users/marklrh/go
DISPLAY=/private/tmp/com.apple.launchd.5P43YvkovC/org.macosforge.xquartz:0
LIBFFI_CFLAGS=-I/usr/local/Cellar/libffi/3.0.13/lib/libffi-3.0.13/include
OLDPWD=/Users/marklrh/Dropbox/Projects/OCaml
_=/usr/local/bin/opam
OPAM_PACKAGE_VERSION=0.3.0
OPAM_PACKAGE_NAME=sodium
  • result of $ls $(opam config var prefix)/lib/ctypes/*.h
/Users/marklrh/.opam/4.02.1/lib/ctypes/cstubs_internals.h
/Users/marklrh/.opam/4.02.1/lib/ctypes/ctypes_complex_stubs.h
/Users/marklrh/.opam/4.02.1/lib/ctypes/ctypes_cstubs_internals.h
/Users/marklrh/.opam/4.02.1/lib/ctypes/ctypes_managed_buffer_stubs.h
/Users/marklrh/.opam/4.02.1/lib/ctypes/ctypes_primitives.h
/Users/marklrh/.opam/4.02.1/lib/ctypes/ctypes_raw_pointer.h
/Users/marklrh/.opam/4.02.1/lib/ctypes/ctypes_type_info_stubs.h
/Users/marklrh/.opam/4.02.1/lib/ctypes/ctypes_unsigned_stubs.h

Possible issue with make test on osx/homebrew

When I used brew install nacl, it unpacked the headers and lib files into the $(brew --prefix)/{include,lib} directories, which caused the <nacl/crypto_box.h> include to fail.

I had to modify the makefile to thread flags through to ${CC} and use

-L`brew --prefix`/lib -I`brew --prefix`/include

Error when installing on OS X 10.10.1

#=== ERROR while installing sodium.0.3.0 ======================================#
# opam-version 1.2.0
# os           darwin
# command      make
# path         /Users/mark/.opam/4.01.0/build/sodium.0.3.0
# compiler     4.01.0
# exit-code    2
# env-file     /Users/mark/.opam/4.01.0/build/sodium.0.3.0/sodium-4315-6d07ae.env
# stdout-file  /Users/mark/.opam/4.01.0/build/sodium.0.3.0/sodium-4315-6d07ae.out
# stderr-file  /Users/mark/.opam/4.01.0/build/sodium.0.3.0/sodium-4315-6d07ae.err
### stdout ###
# ...[truncated]
# ocamlfind ocamlc -c -bin-annot -package ctypes.stubs -w @5@8@10@11@12@14@23@24@26@29 -I lib_gen -I lib -o lib_gen/sodium_bindgen.cmo lib_gen/sodium_bindgen.ml
# ocamlfind ocamlc -linkpkg -package ctypes.stubs lib/sodium_storage.cmo lib_gen/sodium_bindings.cmo lib_gen/sodium_bindgen.cmo -o lib_gen/sodium_bindgen.byte
# lib_gen/sodium_bindgen.byte
# ocamlfind ocamlc -I /Users/mark/.opam/4.01.0/lib/ctypes/.. -ccopt '--std=c99 -Wall -pedantic -Werror -Wno-pointer-sign' -c lib/sodium_stubs.c
# + ocamlfind ocamlc -I /Users/mark/.opam/4.01.0/lib/ctypes/.. -ccopt '--std=c99 -Wall -pedantic -Werror -Wno-pointer-sign' -c lib/sodium_stubs.c
# lib/sodium_stubs.c:1:10: fatal error: 'sodium.h' file not found
# #include <sodium.h>
#          ^
#1 error generated.
# Command exited with code 2.
### stderr ###
# make: *** [all] Error 10

sodium.h does exist in /usr/local/lib. Seems that clang/ocamlc still cannot find it? Does the problem have something to do with the ctypes?
Have been struggling with this binding for the last several months...Sometime it upgrades smoothly, sometimes it just troubles me for a long time.

build the .cmxs

The cmxs is not build, I need it in order to use sodium with ocsigen.
Unfortunately I don't know ocamlbuild enough in order to know what to tell it in order for it to build the thing with the right cstubs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.