GithubHelp home page GithubHelp logo

rod-chapman / sparknacl Goto Github PK

View Code? Open in Web Editor NEW
110.0 110.0 8.0 2.98 MB

SPARK 2014 re-implementation of the TweetNaCl crypto library

License: BSD 3-Clause "New" or "Revised" License

Ada 89.04% Makefile 1.51% C 8.98% Assembly 0.47%

sparknacl's People

Contributors

docandrew avatar rod-chapman avatar yannickmoy 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  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

sparknacl's Issues

Proof of * on GF

Type-safety proof of "*" operator for GF is now done. See code in sparknacl.adb and (sub)types in sparknacl.ads.

I have made some use of Ada 2012's "dynamic subtype predicate" feature to declare 3 variants of a "GF" here

"Any GF" where the limbs can take on any value needed for any intermediate calculation, including negative limbs (from subtraction) and very large numbers (needed during multiplication)

"Seminormal_GF" - the result of applying Car_25519 to an "Any GF" ONCE...

"Normal_GF" - all limbs in 0 .. 65535 - produced by apply Car_25519 TWICE to the result of any other operator.

This means actually having TWO versions of Car_25519 with slightly different type signatures - this seems to work pretty well at the expense of a little more code. See sparknacl-utils.ads and its body.

Car25519

I was looking at that function:

   procedure Car_25519 (O : in out GF)
   is
      C : I64;
   begin
      --  In SPARK, we unroll the final (I = 15)'th iteration
      --  of this loop below. This removes the need for
      --  a conditional statement or expression inside the loop
      --  body.
      for I in Index_16 range 0 .. 14 loop
         O (I) := O (I) + 2#1_0000_0000_0000_0000#; --  POV
         C := ASR_16 (O (I));
         O (I + 1) := O (I + 1) + C - 1; --  POV on second + and -

         --  The C code here uses (c << 16) which is UNDEFINED
         --  for negative c according to C standard 6.5.7 (4).
         --  TweetNaCl appears to depend on this being equivalent
         --  to sign-preserving multiplication by 65536.
         pragma Assert (C >= -2**47);
         pragma Assert (C <= (2**47) - 1);

         O (I) := O (I) - (C * 65536); --  POV on -
      end loop;

      --  Final iteration, as would be when I = 15
      O (15) := O (15) + 2#1_0000_0000_0000_0000#; --  POV
      C := ASR_16 (O (15));
      O (0) := O (0) + C - 1 + 37 * (C - 1); --  POV on first 3 ops
      O (15) := O (15) - (C * 65536); --  POV on -
   end Car_25519;

Some comments:

      --  In SPARK, we unroll the final (I = 15)'th iteration
      --  of this loop below. This removes the need for
      --  a conditional statement or expression inside the loop
      --  body.

I did the same in my proof in Coq.


         --  The C code here uses (c << 16) which is UNDEFINED
         --  for negative c according to C standard 6.5.7 (4).
         --  TweetNaCl appears to depend on this being equivalent
         --  to sign-preserving multiplication by 65536.

We actually changed the formula. The function I verified is as follows:

sv car25519(gf o)
{
  int i;
  i64 c;
  FOR(i,15) {
    o[(i+1)]+=o[i]>>16;
    o[i]&=0xffff;
  }
  o[0]+=38*(o[15]>>16);
  o[15]&=0xffff;
}

Which is derived from Jason A. Donenfeld proposed change:

sv car25519(gf o)
{
  int i;
  FOR(i,16) {
    o[(i+1)%16]+=(i<15?1:38)*(o[i]>>16);
    o[i]&=0xffff;
  }
}

All is left is a Right Shift which in the case of negative operand is compiler defined:

The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of
E1/2^E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

Source: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2310.pdf page 68 (or 81 in the pdf)

The change by Jason is likely to be integrated in a future version of TweetNaCl (when...? )

Documentation?

Something I've noticed about tweetnacl and this library (and even the original nacl library) is that the documentation is either very little or completely nonexistent. As an example, the SPARKNaCl.SecretBox.Create procedure has this declaration:

   procedure Create (C      :    out Byte_Seq;
                     Status :    out Boolean;
                     M      : in     Byte_Seq;
                     N      : in     Stream.HSalsa20_Nonce;
                     K      : in     Core.Salsa20_Key)
     with Global => null,
          Pre    => (M'First = 0 and
                     C'First = 0 and
                     C'Last  = M'Last and
                     M'Length >= 32) and then
                    Equal (M (0 .. 31), Zero_Bytes_32),
          Post   => Equal (C (0 .. 15), Zero_Bytes_16);

Yet there is no documentation on what these arguments are or how to use this function. The tests are no help, either. The preconditions and postconditions don't help and actually make the declaration harder to understand: I can attempt to infer that M is the message to encrypt, yet the precondition requires that the first byte of M and C is 0, the last byte of M is equivalent to the last byte of C, the length of M be >= 32, and the first 32 bytes of M be zero. So I'm struggling to understand how this function (and related functions) should be used, given the very little amount of data I have to go off of (and having never used TweetNaCl or NaCl but more complex libraries like OpenSSL or Botan). Would it be possible to enhance the documentation of the library, perhaps providing documented examples or something?

use of "native" runtime breaks project on windows

On windows, the project can be neither compiled nor proved, because of the

   for Runtime ("Ada") use "native";

in the project file. I suggest to remove it, it has no purpose (is the default) on linux and is troublesome on windows.

Why Counter parameter in SecretBox.Create

In the new implementation of SecretBox.Create for ChaCha20-Poly1305-AEAD, why is there a need for "Counter" to be a formal parameter, when the RFC 8439 says the value is always "1". Is there another use case where the caller needs to select a different Counter value?

Any interest in adding ChaCha20 stream functionality?

TLS 1.3 supports a limited number of cipher suites - one of which is CHACHA20_POLY1305_SHA256. Given that SPARKNaCl already has support for 25519 ecc operations, POLY1305, and SHA256, it seems like the addition of ChaCha20 support would make it possible to use SPARKNaCl as a drop-in crypto solution for a verified SPARK TLS library (with limited cipher and signature support, of course - RSA certificates probably being the limiting factor to widespread adoption, though I expect those to get phased out in favor of ECC certs in the not-too-distant future). Additionally, SSH supports it as one of its cipher suites, as well as some other protocols.

This would make SPARKNaCl no longer strictly a port of the Tweet NaCl code, but there is some precedent - libsodium has added ChaCha20 support making it possible to be used in TLS libraries. From what I understand, ChaCha20 is similar to Salsa20 but I don't know that the primitive operations you've worked hard to write/prove/optimize would be easily transferrable to a ChaCha20 implementation or not. Do you think this is something worth consideration?

Unproved checks with FSF build

This is really just for info.

I’ve built branch fsf against GCC 12.0.1 of 20220204 (discussion, compiler, spark2014).

The prover versions are

  • alt-ergo: 2.4.1
  • cvc4: 1.8
  • z3: 4.8.12

Running SPARKNaCl fca8934 of 16 December (latest) against this, I get 6 unproved checks:

sparknacl.adb:114:10: medium: assertion might fail
  114>|        ((for all K in Index_31 range 0 .. 15 =>
  ... | ...
  117 |            T (K) = 0));

sparknacl.adb:161:16: medium: loop invariant might fail in first iteration, cannot prove T (K) <= (I64 (I + 1) * MGFLP)
  161 |               T (K) <= (I64 (I + 1) * MGFLP));
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~

sparknacl-sign.adb:479:54: medium: range check might fail
  479 |                  Adjustment := (L16 (J - (I - 32))) * XLI;
      |                                ~~~~~~~~~~~~~~~~~~~~~^~~~~
  reason for check: result of multiplication must fit in the target type of the assignment
  possible fix: loop invariant at line 572 should mention XLI
  572 |            pragma Loop_Invariant
      |            ^ here

sparknacl-sign.adb:481:28: medium: range check might fail
  481 |                  Carry := ASR_8 (XLJ + 128);
      |                           ^~~~~~~~~~~~~~~~
  reason for check: value must fit in the target type of the assignment

sparknacl-sign.adb:496:21: medium: loop invariant might fail in first iteration, cannot prove XL (K) in PRL
  496 |                    XL (K) in PRL);
      |                    ^~~~~~~~~~~~~

sparknacl-sign.adb:667:18: medium: loop invariant might not be preserved by an arbitrary iteration, cannot prove XL (K) in Step2_XL_Limb
  667 |                 XL (K) in Step2_XL_Limb);
      |                 ^~~~~~~~~~~~~~~~~~~~~~~

Provide incrimental interface

So, perhaps I'm missing something or the spec is confusing, but there doesn't appear to be an incremental interface to hash data -- I have to have all the data beforehand. I can't, for example, download a file and, as the file downloads, stream the downloaded information into a hasher to continuously update it before finalizing it. This is something that libsodium has, and its not something that many other Ada crypto libs have (other than the Ada Crypto Library, but that libraries security is questionable, or so the README would have me believe), and it would be nice to have incremental/streaming interfaces for hashing, MACs, encryption/decryption, etc. for those (probably rare but necessary) cases. But maybe I'm missing something really obvious...

I some wrong

cd test
make

gprclean -r -Ptestall "/home/mihail/Projects/sumatoreo/vaniton/third-party/sparknacl/tests/testall.adb.stdout" has been deleted "/home/mihail/Projects/sumatoreo/vaniton/third-party/sparknacl/tests/testall.adb.stderr" has been deleted rm -f fntr rm -f ftestall gprbuild -Ptestall -XSPARKNACL_RUNTIME_CHECKS=disabled -XSPARKNACL_CONTRACTS=disabled -XSPARKNACL_BUILD_MODE=O3 Compile [Ada] testall.adb sparknacl-sign.ads:44:11: "Relaxed_Initialization" is not a valid aspect identifier sparknacl-sign.ads:50:22: unrecognized attribute "Initialized" gprbuild: *** compilation phase failed make: *** [Makefile:21: ftestall] Error 4

Gnat 2022 makes () for arrays obsolescent

When building a project with -gnat2022 then warnings about array obsolescent syntax are generated.

Coupled with gnatwe warnings as errors in gprbuild then the build fails.

I'm not sure of the best method to fix this issue? Personally, I would prefer upgrading the syntax to square brackets but that might break compatibility promises (not sure if they cover just hardware compatibility with the light runtime or if it is also intended to support older language versions). I have removed gnatwe from sparknacl gpr file in my codebase for now.

Note: Square brackets might cause problems with your ada language server such as breaking code formatting due to seeing incorrect code unless on a relatively new version (newer than the one bundled with the released gnat studio continuous release).

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.