Comments (36)
That would be great!
- Checkout the develop branch of a clean OpenSK in a temporary directory:
cd /tmp git clone -b develop https://github.com/google/OpenSK.git cd OpenSK ./setup.sh
- Plug the dev-kit to your computer through the JTAG port (see this picture).
- Compile, flash, and configure OpenSK with debugging:
./deploy.py --board=nrf52840dk_opensk --opensk --debug --panic-console --clear-storage ./tools/configure.py --certificate=crypto_data/opensk_cert.pem --private-key=crypto_data/opensk.key
- Plug the dev-kit to your phone through the USB port, keeping the JTAG port connected to your computer.
- In one terminal run
JLinkExe -device nrf52 -if swd -speed 1000 -autoconnect 1
. - In another (new) terminal run
JLinkRTTClient
. Make sure you have infinite scrolling, there will be a lot of input. - Try to add a security key on your phone.
- Ctrl-C the second terminal and copy the full content of the terminal in a gist or some other place and share the link here.
Thanks!
from opensk.
It's possible that they whitelist AAGUID to the FIDO certified ones.
But my first guess would be to say that they're simply more pedantic about the attestation certificate.
IIRC I haven't patched the certificate generation to include the x509v3 extensions they need (it needs to embed the AAGUID, the supported transports, etc.).
It works 99% of the cases because nobody cares about it, but with CTAP2.1 they seem to do more checks :)
from opensk.
Sorry for the wait (and more waiting is to be expected, see below). A few observations:
- I downloaded the metadata blob from FIDO Alliance to double check, and I can't find OpenSK. The file
metadata/metadata.json
in our repository should be contained. - We are still listed as a certified product, i.e., search for OpenSK as the product name.
So if we are indeed rejected because of attestation problems, then this could be related. I'll reach out to FIDO.
from opensk.
Turns out I missed a step to submit an OpenSK entry to the MDS. So we likely have to fix #457 and / or add register OpenSK correctly to FIDO.
from opensk.
I'll dig a bit deeper into this matter, let me make some tests adding additional dongles, I'll check the following:
- no AAGUID change, no batch attestation (vanilla deploy again now with the 'FIDO_CERTIFIED_L1' status)
- AAGUID change, no batch attestation
- no AAGUID change, batch attestation
That should give some more hints.
from opensk.
Not sure I understand the first paragraph, so let me summarize what I think.
A) I agree that receiving a random batch attestation shouldn't matter to RPs, and any RP that accepts them should accept us without any attestation. So this is not about increased security, it is about making OpenSK work with more RPs.
B) We will not publish the one meaningful batch private key that was used during certification.
C) Our goal is to protect user privacy by increasing the anonymity set, meaning the number of people they are indistinguishable with through fingerprinting. Without attestation, this would ideally be all security keys with the same feature set. With attestation, if you are not a manifacturer and issue your own batch, this would ideally be all other fully open source users.
D) By the way, U2F requires the batch certificate, so if you want to use U2F, all of the above applies. This has been a source of confusion before, when people expected OpenSK to work, but forgot to configure it.
Let me explain my proposed change to how we handle batch attestation with an overview on how we behave with respect to its boolean customization flag, and how we could change that.
Before (bool)
false
(default)
U2F works after you configure, batch attestation is never used.
true
U2F fails until configure, batch attestation is used after configure, otherwise not used.
After (enum)
never
Implies with_u2f
feature flag is disabled, U2F never works, batch attestation is never used
random
(default)
Uses a random batch private key and certificate for both U2F and batch attestation, batch attestation is usable, U2F is usable if compiled with with_u2f
.
Random here can mean two things that have similar functionality and privacy implications:
- We generate a new batch private key and certificate, commit it to the repository, and compile it into the firmware (if this mode is selected). Advantage: OpenSK doesn't need to generate certificates.
- OpenSK during runtime generates a new random batch private key and certificate on each call to MakeCredential or U2F Register. Advantage: We help all users from before this change blend in. Other open source security keys can copy our certificate and don't have to reimplement our generation process to blend in.
This gives people privacy by default, if they just want all features to work. In both cases, other open source users could copy our approach and join OpenSK's anonymity set.
Also I want to remark that the current default self attestation is what we should be doing, if RPs would let us. However, the new approach makes U2F more privacy friendly by default, so it is an improvement in that sense, which inspires the conform
mode.
conform
Uses self attestation on MakeCredential, and a random batch key and certificate for U2F, if compiled with with_u2f
.
Fails with Apple, but this is the idealistic approach that FIDO imagined.
configured
Uses the configured batch private key and certificate for both U2F and batch attestation. MakeCredential fails until configured. U2F fails until configured, or always fails if compiled without with_u2f
.
from opensk.
Hi, thanks for the report!
Could you provide the following information to help debug further:
- How did you compile, flash, and configure OpenSK on the dongle?
- How do you connect the dongle to your phone?
- Does it work with iOS 16?
Thanks!
from opensk.
Thank you for swift response @ia0 ,
How did you compile, flash, and configure OpenSK on the dongle?
I followed exact steps mentioned in install.md and nrf52840_dongle.md i.e DFU flashing
How do you connect the dongle to your phone?
Using Lightning to USB A adaptor
Does it work with iOS 16?
No, just checked on iPad running ios16 with USB C to USB A dongle
FYI, my Yubikey 5 worked flawlessly on both.
from opensk.
Thanks! We will need to find a way to reproduce to be able to debug (unless you happen to also have a dev-board). This may take some time.
from opensk.
I do have a NRF52840DK dev board. But it’s not handy atm. If you could guide me thru the process I could give it a try next week.
from opensk.
Hi @ia0 , I tried this today. Unfortunately getting some errors during flashing. Please note I've copied udev rules and replugged the device. Any idea what else can I do ?
info: Generating Tock TAB file for application/example ctap2
info: Erasing the persistent storage
info: Erasing all installed applications
WARNING:root:Unknown TLV block in TBF header.
WARNING:root:You might want to update tockloader.
info: Flashing padding application
info: Installing Tock application ctap2
WARNING:root:Unknown TLV block in TBF header.
WARNING:root:You might want to update tockloader.
WARNING:root:Unknown TLV block in TBF header.
WARNING:root:You might want to update tockloader.
info: Configuring device.
info: Your device is not yet configured, and lacks some functionality. You can check its configuration status with:
./tools/configure.py
If you run into issues, this command might help:
./tools/configure.py \
--certificate=crypto_data/opensk_cert.pem \
--private-key=crypto_data/opensk.key
Please read the Certificate considerations in docs/customization.md to understand the privacy trade-off.
fatal: No device to configure found.
lsusb output shows SEGGER J-Link connected
from opensk.
That's the expected output. You may ignore those warnings. I have them too and it's not a problem.
You should be able to follow up with the instructions continuing from ./tools/configure.py
.
Note that the device is extremely slow with debug enabled, so you may have to wait longer than expected for some steps.
from opensk.
Thanks @ia0 , I was able to reproduce this issue using the NRF52840 DK dev board. You can find the logs in public gist here. I'm looking forward to learn from your diagnosis, many thanks!
from opensk.
Thanks a lot! So it looks like we send a MakeCredential response which makes me believe that iOS is probably refusing our AAGUID or certificate. @jmichelp what do you think?
from opensk.
Apple has a page talking about Keys specifications : https://support.apple.com/en-in/HT213154
from opensk.
I'm happy to work on a PR if you could guide me thru.
from opensk.
Thanks for the update @kaczmarczyck , happy to test it over once we've the fix.
from opensk.
Update: OpenSK is now listed in the MDS with
AAGUID 664d9f67-84a2-412a-9ff7-b4f7d8ee6d05
For some reason, it still lists the status as NOT_FIDO_CERTIFIED
.
We could test if this already satisfies Apple. I am sceptical it does, but if you want to try, open the file crypto_data/aaguid.txt
and paste the above AAGUID into it. Note that the MDS entry lists the properties from our 2.0 version, not sure if that causes problems.
If that does not work, the next 2 tests would be:
A) Activate batch attestation.
B) Wait for the MDS to acknowledge our certification status, and that to propagate to Apple.
To try A), you can edit libraries/opensk/src/api/customization.rs
so that DEFAULT_CUSTOMIZATION
says:
use_batch_attestation: true,
You will have to configure after deploying to enable batch attestation:
./tools/configure.py \
--certificate=crypto_data/opensk_cert.pem \
--private-key=crypto_data/opensk.key
Note: Our documentation has some info on privacy implications of batch attestation if you want to use that key outside of experimentation.
The attestation certificate you are going to use doesn't match the MDS entry though. That is because you just generated it, and you can't attest yourself. This is basically the open source nature of OpenSK.
If Apple does require batch attestation and checking them through the MDS, then there is intentionally no way you can build your own security key and make it work with them I think.
from opensk.
The MDS blob (downloaded here) still lists us as not certified. We merged #668 , so anyone with a Mac could try Apple ID with OpenSK. Steps:
- checkout
develop
and pull ./reset.sh && ./setup.sh
(save pending changes before this step)- edit
crypto_data/aaguid.txt
and change it to664d9f67-84a2-412a-9ff7-b4f7d8ee6d05
- edit
DEFAULT_CUSTOMIZATION
inlibraries/opensk/src/api/customization.rs
as explained above - deploy
- configure
For debugging purposes, if that works, we coud also try with a random AAGUID (write something else in step 3). That should inform us whether Apple supports self-made security keys.
from opensk.
@iayanpahwa If you are interested in trying, feel free to report all observations here!
from opensk.
I’ll try and test it in soon.
from opensk.
Hi,
I just started evaluating your great project with a pair of nRF52840 dongles and OSX, which might be of interest to you for this issue:
- First key I installed plain vanilla without changing the
aaguid
- Second key I installed with @kaczmarczyck 's instructions,
aaguid
change and turning on batch attestation
Results on an Apple MacBook Air:
- First key was refused with error
- Second key was working
So I'd assume that changing the aaguid
and activating batch attestation works.
I don't have a Lightning to USB adapter here so unfortunately I can't test on my iPad / iPhone.
from opensk.
Thanks for checking! I got a response from FIDO last week that they updated their MDS to include OpenSK as certified. When I downloaded their blob then, it didn't reflect that yet, but today, I tried again and it says:
'status': 'FIDO_CERTIFIED_L1'
With the timing of @JohannesBloecker , I don't think we can find out whether that was necessary for OpenSK to work. But it does mean that OpenSK is now usable on iOS with batch attestation and the right AAGUID! I wonder if we should make it more accessible with a deploy option. Do you know if just one batch attestation or the AAGUID change already works?
from opensk.
It would be weird for Apple to validate the AAGUID against the MDS and not validate the associated certificates.
At least I am aware that some companies start to validate the attestation certificate against the MDS too. Spoofing the AAGUID without using the same root and intermediate CA we used for the FIDO certification might fail.
from opensk.
Ok, tonight I did a combination test to find out what exactly works and what not on Apple MacBook Air M1 macOS Sonoma 14.3.1 (23D60) and iOS 17.2 (21C62).
Summary
The AAGUID does not seem to matter, use_batch_attestation: true
is what makes the dongle work on macOS and iOS.
Full test setup
- Vanilla clone
develop
branch ./setup.sh
./deploy.py --board=nrf52840_dongle_dfu --erase_storage --programmer=nordicdfu_nrfutil_binary --rust-crypto
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Adding key fails on MacBook Air: HTTPError: 500
- Change aaguid.txt to 664d9f67-84a2-412a-9ff7-b4f7d8ee6d05
./deploy.py --board=nrf52840_dongle_dfu --erase_storage --programmer=nordicdfu_nrfutil_binary --rust-crypto
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Adding key fails on MacBook Air: HTTPError: 500
- Set
use_batch_attestation: true
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Test succeeds on MacBook Air, security added
- Change aaguid.txt back to initial (generated?) 7fa228bc-8e4f-4211-beb0-8b00c4dfc2f6
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
--> Test succeeds on MacBook Air, security key added
Revalidate with full vanilla build on iPad Pro 12.9 Gen 4
./deploy.py --board=nrf52840_dongle_dfu --erase_storage --programmer=nordicdfu_nrfutil_binary --rust-crypto
- Fresh git clone
develop
branch - Set
use_batch_attestation: true
- Leave aaguid.txt at (generated?) 3A26CDEA-3DDF-42BC-A2FD-EFA80C47963D
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu_nrfutil_binary --rust-crypto
- Add security key to iPad via USB-A to USB-C adapter
--> Test succeeds on iPad Pro 12.9 Gen 4, security key added
(nordicdfu_nrfutil_binary
I patched the deploy.sh
to work with the nrfutil
binaries from Nordic. See comment in #588.)
from opensk.
Cool, thanks for investigating! Probably means we should have a feature flag for batch attestation then.
Yes, the AAGUID is randomly generated. And interesting to see that people like RustCrypto.
By the way, privacy warning: Since your batch will likely have size < 10, these keys are uniquely identifyable by any relying party you use them with. So if you sign up at a.com
and b.com
, then they could compare notes and realize that both accounts were made by you or someone you created a key for. There is inherently no good way to work around it, if you allow batch attestation. The non-standard ones I see are:
- We publish a freshly minted AAGUID and batch attestation key pair for our open source users as a starting point. Then they share an anonymity set with anyone who uses these (default?) keys, or non-OpenSK usres that choose to also copy these keys.
- We allow disabling batch attestation. So you enable it to sign up with Apple, then disable it again.
from opensk.
I'm not familiar enough with FIDO to tell whether a public batch attestation is something they expect. If yes, then publishing a public AAGUID and batch attestation, and using it by default (or with a compilation flag) in OpenSK sounds good to me.
Regarding disabling batch attestation for Apple, why not do it in the firmware directly? This would be more convenient. AFAICT (not familiar with FIDO enough to be sure), batch attestation is only checked in MakeCredential at which point we know the RP. So we could have a configurable list of RPs that needs batch attestation and only use batch attestation for those. That said, if that list is larger than one element, then we're back to the privacy issue, which is why going with a public AAGUID and batch attestation seems like the best option if it's something FIDO would permit or agree with.
from opensk.
The idea of an allowlist for batch attestation is interesting. (Maybe unintentional in your message, but we want to enable batch attestation for Apple, and disable it for everyone else.)
Such a list would need to be user configurable, because OpenSK shouldn't be biased in favor of certain RPs. Which would make it a different UX than toggling batch attestation, but practically the same idea.
Compared to publishing an AAGUID and batch attestation key pair, the advantage is that we don't just increase the anonymity set, we enforce it for all RPs not on the allowlist. In fact, both measures are orthogonal, and we can consider them independently.
Whether or not FIDO has an opinion on either of these, I don't know. But it should be a user's freedom to decide. For example, Chrome asks for permission to forward the batch attestation to the RP.
from opensk.
Yes that's exactly what I meant. And indeed it's orthogonal except if the list is a singleton (like in this example), because then the second option is almost strictly better (the only difference being that your batch attestation is still unique, but the RP should have no way to correlate it to anything unless you published the public part somewhere).
from opensk.
Wouldn't it be quite impractical for the user to switch batch attestation on and off? I would also assume that you'd then need a kind of CLI tool to add sites to a flashed key in use. Or implement a double or triple click feature on the approve button to turn it on or off.
For TLDR;
Maybe provide compiled versions via a CI/CD approach for your releases, 2.0,
2.1
including standard AAGUID and standard certificates? Then you could leave batch attestation safely enabled.
In more detail:
I just read some more details on what the AAGUID and the batch attestation are really intended for by FIDO. What I understood:
- The AAGUID is intended to be built into the hardware key to enable an RP to identify which type of security is being used by the authenticating user, to also allow refusal for certain devices (if the RP comes to the conclusion that the device is not secure enough for the purpose used, e.g. FIPS classifications).
- The certificate used for the attestation has a similar purpose but bringing in cryptographic safety to prove that the user has a certain type of security key. And allowing the security key manufacturer in conjunction with the RP to identify a certain (compromised) firmware version or production batch of the key.
- In the event of a security key CVE, the RP can contact the user and ask to replace the key or in a security emergency even invalidate the authentication proactively.
Now with the OpenSK approach, having a programmable device as key, this approach does not work as intended. With the user compiling the sources but reusing a certificate and AAGUID it makes no sense anymore for an RP to actually take any conclusions regarding version and security, maybe only "uses a self-built OpenSK key".
What came to my mind as an idea, especially regarding accessibility of the OpenSK key:
Provide compiled versions via a CI/CD approach for your releases, 2.0,
2.1
. And in the binary, issue a certificate and AAGUID for this version. Leave develop
as-is and use a development AAGUID.
- This would allow the RP to identify in minimum that it's "most likely" an OpenSK key in version 2.0 / 2.1 and decide to allow it or not.
- It would also solve the certificate uniqueness issue not allowing RPs to identify the exact user.
- The precompiled versions would also enhance user accessibility to OpenSK. I'd assume many users do not intend to install python and Rust and run scripts, but just want to create their own open source key. Download the image, download nrfutil and flash the ordered empty dongle.
- Surely with OpenSK code access and a programmable device, a user could still reuse the certificate and the AAGUID with their own version of the code. But this is kind of the nature of the OSS approach. And finally lies in the responsibility of the user?
from opensk.
For the AAGUID, I don't see a problem with keeping it stable for a branch. The batch attestation is the problem: It needs a private key that is baked into the (protected) hardware. For example, if the private batch key for a Yubikey would leak, than anyone could pretend to be a Yubikey. So if we published the private key that OpenSK used during certification, it would be worthless, because its possession wouldn't prove that you are a certified key.
Which is why our setup creates random key material. And that is the source of the privacy issue. For closed-source authenticators, the RP only learn that you one of hopefully many Yubikeys. For a self-built OpenSK, you don't have that many people to share you batch key with.
Which is why I proposed workarounds like disabling batch attestation. Thinking about it, another workaround is to automatically generate a new random batch private key each time you register anywhere. This would defeat the purpose of batch attestation. But requiring batch attestation without actually checking if the batch key is registered with FIDO might make this a viable hack. At least, it wouldn't need user intervention, and would let OpenSK work with more RPs.
Downside is that we'd have to implement some code to generate certificates. If we indeed need them. Maybe we can send empty certificates and Apple is still happy? We don't know yet whether they get checked. Opinions?
from opensk.
I like the idea of creating random batch attestation for RPs requiring batch attestation without actually doing any check. However, this seems to me that it's just shifting the problem a bit. Some RPs might check more than others (up to check whether the batch attestation is registered by FIDO). So it looks that for custom-built OpenSK (i.e. with a generated and thus unregistered batch attestation), there will be RPs refusing the key. If we decide to provide a solution, we should decide which RPs we want to support for those custom-built OpenSK:
- Those checking nothing.
- Those checking whether the certificate is well-formed.
- Those checking whether the certificate is well-formed and the signature matches the public key.
- Etc.
If we believe Apple is the most common problematic RP, then we could indeed check what Apple actually checks, and do the minimum to pass those checks.
Generating a certificate will need some code, but using templates we may get away with simple byte sequence manipulation.
from opensk.
@kaczmarczyck, I thought to neither use randomly generated certificate / private key for batch attestation nor expose the private key you received the FIDO2 L1 certification with, as you state would be equally worthless for an RP to trust knowing it could be used with any software / hardware combination.
What I propose is to provide a "common random" certificate, e.g. per branch and tag, reusable by any user to circumvent the privacy issue you mentioned. My tests with a random certificate worked, so a reusable random certificate solving the privacy issue will also work. Batch attestation trust for the RP in terms of "uses a certain hardware/firmware" can anyways not be achieved due to the openness of the approach.
And this would also enable to provide packages / images for each tag with baked in common (random) certificate to gain a better accessibility to self-build vanilla OpenSK dongles without software compilation.
from opensk.
@kaczmarczyck still trying to fully follow you and A,B,C,D, yes, you understood what I meant.
Regarding D I read in the Fido alliance U2F overview chapter 8 Verifying That a U2F Device Is 'genuine' §3: "Every public key output by the U2F device during the registration step is signed with the attestation private key."
So U2F implies batch attestation, got it.
I also conclude that it's best to "simulate" the batch attestation with a certificate uploaded in the repository and change it for every major.minor OpenSK version. random
mode 2 as with the current tests I think would also work regarding registration.
Knowledge gap on my side: Is the randomly generated certificate also used during authentication? Then you'd need to store the random certificates together with the key pair. Otherwise an RP might refuse to authenticate if the challenge response is correct, but suddenly signed with a different batch attestation certificate that got newly generated during the authentication process.
And conform
equals Before (bool) false
and configured
equals Before (bool) true
, correct?
from opensk.
Attestation is for MakeCredential
only, and doesn't happen during GetAssertion
(or the U2F equivalents). So throwaway certificates are possible.
configured
behaves like true
, but there is a difference between conform
and false
: U2F uses the random batch key in conform
, and needs the configure command to work in false
. So conform
is a privacy and usability upgrade. It should probably be called something else. The intention is that it keeps U2F as a working fallback to CTAP2 without privacy compromises.
When I think about it, never
and conform
are the same if U2F is disabled, so with_ctap1
could also function as a switch between these two options.
from opensk.
I checked the logic table based on the batch attestation flags and the proposed with_ctap1
flag.
@kaczmarczyck mentioned that users also have a misunderstanding that batch attestation is required for U2F/CTAP1. How about structuring the parameter settings on the usage per protocol?
ctap2_batch_attestation flag
self
Self-attestation is used for CTAP2
random
Random certificate is used for CTAP2 batch attestation
user
Provided user certificate in ./configure
is used for batch attestation
ctap1_batch_attestation / u2f_batch_attestation flag
never
/ off
/ disabled
CTAP1 / U2F disabled (as it's mandatory in U2F)
random
Random certificate is used for CTAP1 / U2F
user
Provided user certificate in ./configure
is used for batch attestation
Alternatively providing additional switches for on
and off
first and then define the batch attestation mode would also work:
with_ctap2: true
and false
ctap2_batch_attestation: self
,random
,user
with_u2f / with_ctap1: true
and false
ctap1_batch_attestation: random
, user
Defaults to true
and random
for privacy protection.
additional thought
If for the random mode the certificates and keys can be generated on the device, additional settings could enhance the security to not rely on the ./configure at all but add the option to completely handle all key generation as an init procedure on the device making each device unique and keys are never touching the laptop. Then combine this with APPROTECT as you discussed in this comment.
from opensk.
Related Issues (20)
- "configuring device" step needs a confirmation prompt to replug device on nrf52840_dongle_dfu HOT 5
- AuthenticatorConfigParameters swaps pinUvAuthProtocol and pinUvAuthParam field IDs HOT 1
- error: failed to get `arrayref` as a dependency of package `ctap2 v1.0.0 (/home/USER/OpenSK)` HOT 6
- WebUSB compatible? HOT 4
- How to change pin in Makerdiary nRF52840-MDK USB dongle HOT 2
- Improve Tock patches
- Move storage syscalls
- Edit the readme to link to the Quantum paper and point to the implementation file.
- Setup script can't install pip packages to the user's environment on Arch Linux HOT 2
- nordic dfu in develop fails to configure HOT 4
- wrong board type in flashing command in install.md HOT 1
- Suggested environment to be able to build/compile HOT 10
- nrf52840_dongle: deploy.py succeeds programming but testing board not recognised by testing webpages. HOT 12
- How to delete an account you no longer use? HOT 2
- Can't enable JTAG lockdown HOT 4
- `async` API for `Env`? HOT 3
- develop
- Misuse of const in sha256 module HOT 8
- Question: what is the purpose of `feature = "vendor_hid"`? HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from opensk.