├── .github └── workflows │ └── push-validation.yaml ├── .gitignore ├── LICENSE ├── README.md ├── benchmark ├── curveops.ml └── dune ├── doc └── rfc │ └── rfc7748.txt ├── dune-project ├── examples ├── dune └── quickstart.ml ├── rfc7748.opam ├── src ├── curve.ml ├── curve.mli ├── dune ├── rfc7748.ml ├── rfc7748.mli ├── serde.ml ├── serde.mli └── zfield.ml └── test ├── dune ├── test_misc.ml └── test_rfc7748.ml /.github/workflows/push-validation.yaml: -------------------------------------------------------------------------------- 1 | name: "Push Validation" 2 | 3 | on: 4 | push: 5 | branches: 6 | - "master" 7 | pull_request: 8 | branches: 9 | - "master" 10 | 11 | jobs: 12 | build-and-test: 13 | runs-on: "ubuntu-18.04" 14 | strategy: 15 | matrix: 16 | container: 17 | - "ocaml/opam2:alpine-3.8-ocaml-4.03" 18 | - "ocaml/opam2:alpine-3.12-ocaml-4.11" 19 | container: 20 | image: "${{ matrix.container }}" 21 | options: "--user root" 22 | steps: 23 | - uses: "actions/checkout@v2" 24 | - name: "Prepare container environment" 25 | run: | 26 | apk add --no-cache m4 perl gmp-dev git 27 | chown -R opam . 28 | cd /home/opam/opam-repository 29 | sudo -u opam git fetch 30 | sudo -u opam git checkout 6ef290f5681b7ece5d9c085bcf0c55268c118292 31 | sudo -u opam opam update 32 | - name: "Build and test." 33 | shell: "sudo -u opam sh -e {0}" 34 | run: "opam install -y --with-test ." 35 | - name: "Check formatting" 36 | shell: "sudo -u opam sh -e {0}" 37 | run: | 38 | opam install -y ocp-indent 39 | eval $(opam env) 40 | find src test -name "*.ml" -or -name "*.mli" -type f | xargs ocp-indent -i 41 | git diff --exit-code 42 | - name: "Run benchmark" 43 | shell: "sudo -u opam sh -e {0}" 44 | run: | 45 | opam install -y benchmark 46 | eval $(opam env) 47 | dune exec benchmark/curveops.exe 48 | - name: "Build documentation" 49 | shell: "sudo -u opam sh -e {0}" 50 | run: | 51 | opam install -y odoc 52 | eval $(opam env) 53 | dune build @doc 54 | - name: "Push documentation" 55 | if: ${{ github.event_name == 'push' && matrix.container == 'ocaml/opam2:alpine-3.12-ocaml-4.11' }} 56 | uses: peaceiris/actions-gh-pages@v3 57 | with: 58 | github_token: ${{ secrets.GITHUB_TOKEN }} 59 | publish_dir: ./_build/default/_doc/_html 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | .build 3 | *.native 4 | *.out 5 | *.install 6 | 7 | # editors 8 | .DS_Store 9 | *.swp 10 | *~ 11 | 12 | # jbuilder 13 | .merlin 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018, Markus Rudy. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OCaml-RFC7748 2 | 3 | Elliptic curves for cryptographic purposes, based on [RFC 7748](https://tools.ietf.org/html/rfc7748). 4 | 5 | ## Usage 6 | 7 | The [API](src/rfc7748.mli) contains documentation. Example use: 8 | 9 | ```ocaml 10 | open Rfc7748 11 | 12 | let _ = 13 | let priv = X25519.private_key_of_string 14 | "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4" in 15 | let pub = X25519.public_key_of_string 16 | "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c" in 17 | X25519.scale priv pub 18 | |> X25519.string_of_public_key 19 | |> Printf.printf "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552\n == \n%s" 20 | ``` 21 | 22 | ## License 23 | 24 | BSD 2-clause, see [license](LICENSE). 25 | -------------------------------------------------------------------------------- /benchmark/curveops.ml: -------------------------------------------------------------------------------- 1 | 2 | module type DH = sig 3 | type private_key 4 | type public_key 5 | 6 | val private_key_of_bytes: Bytes.t -> private_key 7 | val public_key_of_private_key: private_key -> public_key 8 | val scale: private_key -> public_key -> public_key 9 | end 10 | 11 | let rand () = 12 | Bytes.init 32 @@ fun _ -> char_of_int @@ Random.int 256 13 | 14 | let run: (module DH) -> unit -> unit = fun m -> 15 | let module M = (val m) in 16 | Random.init 4711; 17 | let pub = rand () |> M.private_key_of_bytes |> M.public_key_of_private_key in 18 | let priv = rand () |> M.private_key_of_bytes in 19 | fun () -> M.scale priv pub |> Sys.opaque_identity |> ignore 20 | 21 | let curveops = [ "Rfc7748", run (module Rfc7748.X25519), () 22 | ] 23 | 24 | let _ = 25 | Benchmark.throughputN 1 curveops |> Benchmark.tabulate 26 | 27 | -------------------------------------------------------------------------------- /benchmark/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name curveops) 3 | (libraries rfc7748 benchmark) 4 | ) 5 | -------------------------------------------------------------------------------- /doc/rfc/rfc7748.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Internet Research Task Force (IRTF) A. Langley 8 | Request for Comments: 7748 Google 9 | Category: Informational M. Hamburg 10 | ISSN: 2070-1721 Rambus Cryptography Research 11 | S. Turner 12 | sn3rd 13 | January 2016 14 | 15 | 16 | Elliptic Curves for Security 17 | 18 | Abstract 19 | 20 | This memo specifies two elliptic curves over prime fields that offer 21 | a high level of practical security in cryptographic applications, 22 | including Transport Layer Security (TLS). These curves are intended 23 | to operate at the ~128-bit and ~224-bit security level, respectively, 24 | and are generated deterministically based on a list of required 25 | properties. 26 | 27 | Status of This Memo 28 | 29 | This document is not an Internet Standards Track specification; it is 30 | published for informational purposes. 31 | 32 | This document is a product of the Internet Research Task Force 33 | (IRTF). The IRTF publishes the results of Internet-related research 34 | and development activities. These results might not be suitable for 35 | deployment. This RFC represents the consensus of the Crypto Forum 36 | Research Group of the Internet Research Task Force (IRTF). Documents 37 | approved for publication by the IRSG are not a candidate for any 38 | level of Internet Standard; see Section 2 of RFC 5741. 39 | 40 | Information about the current status of this document, any errata, 41 | and how to provide feedback on it may be obtained at 42 | http://www.rfc-editor.org/info/rfc7748. 43 | 44 | Copyright Notice 45 | 46 | Copyright (c) 2016 IETF Trust and the persons identified as the 47 | document authors. All rights reserved. 48 | 49 | This document is subject to BCP 78 and the IETF Trust's Legal 50 | Provisions Relating to IETF Documents 51 | (http://trustee.ietf.org/license-info) in effect on the date of 52 | publication of this document. Please review these documents 53 | carefully, as they describe your rights and restrictions with respect 54 | to this document. 55 | 56 | 57 | 58 | Langley, et al. Informational [Page 1] 59 | 60 | RFC 7748 Elliptic Curves for Security January 2016 61 | 62 | 63 | Table of Contents 64 | 65 | 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 2 66 | 2. Requirements Language . . . . . . . . . . . . . . . . . . . . 3 67 | 3. Notation . . . . . . . . . . . . . . . . . . . . . . . . . . 3 68 | 4. Recommended Curves . . . . . . . . . . . . . . . . . . . . . 4 69 | 4.1. Curve25519 . . . . . . . . . . . . . . . . . . . . . . . 4 70 | 4.2. Curve448 . . . . . . . . . . . . . . . . . . . . . . . . 5 71 | 5. The X25519 and X448 Functions . . . . . . . . . . . . . . . . 7 72 | 5.1. Side-Channel Considerations . . . . . . . . . . . . . . . 10 73 | 5.2. Test Vectors . . . . . . . . . . . . . . . . . . . . . . 11 74 | 6. Diffie-Hellman . . . . . . . . . . . . . . . . . . . . . . . 14 75 | 6.1. Curve25519 . . . . . . . . . . . . . . . . . . . . . . . 14 76 | 6.2. Curve448 . . . . . . . . . . . . . . . . . . . . . . . . 15 77 | 7. Security Considerations . . . . . . . . . . . . . . . . . . . 15 78 | 8. References . . . . . . . . . . . . . . . . . . . . . . . . . 16 79 | 8.1. Normative References . . . . . . . . . . . . . . . . . . 16 80 | 8.2. Informative References . . . . . . . . . . . . . . . . . 17 81 | Appendix A. Deterministic Generation . . . . . . . . . . . . . . 19 82 | A.1. p = 1 mod 4 . . . . . . . . . . . . . . . . . . . . . . . 20 83 | A.2. p = 3 mod 4 . . . . . . . . . . . . . . . . . . . . . . . 21 84 | A.3. Base Points . . . . . . . . . . . . . . . . . . . . . . . 21 85 | Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . 22 86 | Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 22 87 | 88 | 1. Introduction 89 | 90 | Since the initial standardization of Elliptic Curve Cryptography (ECC 91 | [RFC6090]) in [SEC1], there has been significant progress related to 92 | both efficiency and security of curves and implementations. Notable 93 | examples are algorithms protected against certain side-channel 94 | attacks, various "special" prime shapes that allow faster modular 95 | arithmetic, and a larger set of curve models from which to choose. 96 | There is also concern in the community regarding the generation and 97 | potential weaknesses of the curves defined by NIST [NIST]. 98 | 99 | This memo specifies two elliptic curves ("curve25519" and "curve448") 100 | that lend themselves to constant-time implementation and an 101 | exception-free scalar multiplication that is resistant to a wide 102 | range of side-channel attacks, including timing and cache attacks. 103 | They are Montgomery curves (where v^2 = u^3 + A*u^2 + u) and thus 104 | have birationally equivalent Edwards versions. Edwards curves 105 | support the fastest (currently known) complete formulas for the 106 | elliptic-curve group operations, specifically the Edwards curve 107 | x^2 + y^2 = 1 + d*x^2*y^2 for primes p when p = 3 mod 4, and the 108 | twisted Edwards curve -x^2 + y^2 = 1 + d*x^2*y^2 when p = 1 mod 4. 109 | The maps to/from the Montgomery curves to their (twisted) Edwards 110 | equivalents are also given. 111 | 112 | 113 | 114 | Langley, et al. Informational [Page 2] 115 | 116 | RFC 7748 Elliptic Curves for Security January 2016 117 | 118 | 119 | This memo also specifies how these curves can be used with the 120 | Diffie-Hellman protocol for key agreement. 121 | 122 | 2. Requirements Language 123 | 124 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", 125 | "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this 126 | document are to be interpreted as described in RFC 2119 [RFC2119]. 127 | 128 | 3. Notation 129 | 130 | Throughout this document, the following notation is used: 131 | 132 | p Denotes the prime number defining the underlying field. 133 | 134 | GF(p) The finite field with p elements. 135 | 136 | A An element in the finite field GF(p), not equal to -2 or 2. 137 | 138 | d A non-zero element in the finite field GF(p), not equal to 139 | 1, in the case of an Edwards curve, or not equal to -1, in 140 | the case of a twisted Edwards curve. 141 | 142 | order The order of the prime-order subgroup. 143 | 144 | P A generator point defined over GF(p) of prime order. 145 | 146 | U(P) The u-coordinate of the elliptic curve point P on a 147 | Montgomery curve. 148 | 149 | V(P) The v-coordinate of the elliptic curve point P on a 150 | Montgomery curve. 151 | 152 | X(P) The x-coordinate of the elliptic curve point P on a 153 | (twisted) Edwards curve. 154 | 155 | Y(P) The y-coordinate of the elliptic curve point P on a 156 | (twisted) Edwards curve. 157 | 158 | u, v Coordinates on a Montgomery curve. 159 | 160 | x, y Coordinates on a (twisted) Edwards curve. 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | Langley, et al. Informational [Page 3] 171 | 172 | RFC 7748 Elliptic Curves for Security January 2016 173 | 174 | 175 | 4. Recommended Curves 176 | 177 | 4.1. Curve25519 178 | 179 | For the ~128-bit security level, the prime 2^255 - 19 is recommended 180 | for performance on a wide range of architectures. Few primes of the 181 | form 2^c-s with s small exist between 2^250 and 2^521, and other 182 | choices of coefficient are not as competitive in performance. This 183 | prime is congruent to 1 mod 4, and the derivation procedure in 184 | Appendix A results in the following Montgomery curve 185 | v^2 = u^3 + A*u^2 + u, called "curve25519": 186 | 187 | p 2^255 - 19 188 | 189 | A 486662 190 | 191 | order 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed 192 | 193 | cofactor 8 194 | 195 | U(P) 9 196 | 197 | V(P) 147816194475895447910205935684099868872646061346164752889648818 198 | 37755586237401 199 | 200 | The base point is u = 9, v = 1478161944758954479102059356840998688726 201 | 4606134616475288964881837755586237401. 202 | 203 | This curve is birationally equivalent to a twisted Edwards curve -x^2 204 | + y^2 = 1 + d*x^2*y^2, called "edwards25519", where: 205 | 206 | p 2^255 - 19 207 | 208 | d 370957059346694393431380835087545651895421138798432190163887855330 209 | 85940283555 210 | 211 | order 2^252 + 0x14def9dea2f79cd65812631a5cf5d3ed 212 | 213 | cofactor 8 214 | 215 | X(P) 151122213495354007725011514095885315114540126930418572060461132 216 | 83949847762202 217 | 218 | Y(P) 463168356949264781694283940034751631413079938662562256157830336 219 | 03165251855960 220 | 221 | 222 | 223 | 224 | 225 | 226 | Langley, et al. Informational [Page 4] 227 | 228 | RFC 7748 Elliptic Curves for Security January 2016 229 | 230 | 231 | The birational maps are: 232 | 233 | (u, v) = ((1+y)/(1-y), sqrt(-486664)*u/x) 234 | (x, y) = (sqrt(-486664)*u/v, (u-1)/(u+1)) 235 | 236 | The Montgomery curve defined here is equal to the one defined in 237 | [curve25519], and the equivalent twisted Edwards curve is equal to 238 | the one defined in [ed25519]. 239 | 240 | 4.2. Curve448 241 | 242 | For the ~224-bit security level, the prime 2^448 - 2^224 - 1 is 243 | recommended for performance on a wide range of architectures. This 244 | prime is congruent to 3 mod 4, and the derivation procedure in 245 | Appendix A results in the following Montgomery curve, called 246 | "curve448": 247 | 248 | p 2^448 - 2^224 - 1 249 | 250 | A 156326 251 | 252 | order 2^446 - 253 | 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d 254 | 255 | cofactor 4 256 | 257 | U(P) 5 258 | 259 | V(P) 355293926785568175264127502063783334808976399387714271831880898 260 | 435169088786967410002932673765864550910142774147268105838985595290 261 | 606362 262 | 263 | This curve is birationally equivalent to the Edwards curve x^2 + y^2 264 | = 1 + d*x^2*y^2 where: 265 | 266 | p 2^448 - 2^224 - 1 267 | 268 | d 611975850744529176160423220965553317543219696871016626328968936415 269 | 087860042636474891785599283666020414768678979989378147065462815545 270 | 017 271 | 272 | order 2^446 - 273 | 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d 274 | 275 | cofactor 4 276 | 277 | 278 | 279 | 280 | 281 | 282 | Langley, et al. Informational [Page 5] 283 | 284 | RFC 7748 Elliptic Curves for Security January 2016 285 | 286 | 287 | X(P) 345397493039729516374008604150537410266655260075183290216406970 288 | 281645695073672344430481787759340633221708391583424041788924124567 289 | 700732 290 | 291 | Y(P) 363419362147803445274661903944002267176820680343659030140745099 292 | 590306164083365386343198191849338272965044442230921818680526749009 293 | 182718 294 | 295 | The birational maps are: 296 | 297 | (u, v) = ((y-1)/(y+1), sqrt(156324)*u/x) 298 | (x, y) = (sqrt(156324)*u/v, (1+u)/(1-u)) 299 | 300 | Both of those curves are also 4-isogenous to the following Edwards 301 | curve x^2 + y^2 = 1 + d*x^2*y^2, called "edwards448", where: 302 | 303 | p 2^448 - 2^224 - 1 304 | 305 | d -39081 306 | 307 | order 2^446 - 308 | 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d 309 | 310 | cofactor 4 311 | 312 | X(P) 224580040295924300187604334099896036246789641632564134246125461 313 | 686950415467406032909029192869357953282578032075146446173674602635 314 | 247710 315 | 316 | Y(P) 298819210078481492676017930443930673437544040154080242095928241 317 | 372331506189835876003536878655418784733982303233503462500531545062 318 | 832660 319 | 320 | The 4-isogeny maps between the Montgomery curve and this Edwards 321 | curve are: 322 | 323 | (u, v) = (y^2/x^2, (2 - x^2 - y^2)*y/x^3) 324 | (x, y) = (4*v*(u^2 - 1)/(u^4 - 2*u^2 + 4*v^2 + 1), 325 | -(u^5 - 2*u^3 - 4*u*v^2 + u)/ 326 | (u^5 - 2*u^2*v^2 - 2*u^3 - 2*v^2 + u)) 327 | 328 | The curve edwards448 defined here is also called "Goldilocks" and is 329 | equal to the one defined in [goldilocks]. 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | Langley, et al. Informational [Page 6] 339 | 340 | RFC 7748 Elliptic Curves for Security January 2016 341 | 342 | 343 | 5. The X25519 and X448 Functions 344 | 345 | The "X25519" and "X448" functions perform scalar multiplication on 346 | the Montgomery form of the above curves. (This is used when 347 | implementing Diffie-Hellman.) The functions take a scalar and a 348 | u-coordinate as inputs and produce a u-coordinate as output. 349 | Although the functions work internally with integers, the inputs and 350 | outputs are 32-byte strings (for X25519) or 56-byte strings (for 351 | X448) and this specification defines their encoding. 352 | 353 | The u-coordinates are elements of the underlying field GF(2^255 - 19) 354 | or GF(2^448 - 2^224 - 1) and are encoded as an array of bytes, u, in 355 | little-endian order such that u[0] + 256*u[1] + 256^2*u[2] + ... + 356 | 256^(n-1)*u[n-1] is congruent to the value modulo p and u[n-1] is 357 | minimal. When receiving such an array, implementations of X25519 358 | (but not X448) MUST mask the most significant bit in the final byte. 359 | This is done to preserve compatibility with point formats that 360 | reserve the sign bit for use in other protocols and to increase 361 | resistance to implementation fingerprinting. 362 | 363 | Implementations MUST accept non-canonical values and process them as 364 | if they had been reduced modulo the field prime. The non-canonical 365 | values are 2^255 - 19 through 2^255 - 1 for X25519 and 2^448 - 2^224 366 | - 1 through 2^448 - 1 for X448. 367 | 368 | The following functions implement this in Python, although the Python 369 | code is not intended to be performant nor side-channel free. Here, 370 | the "bits" parameter should be set to 255 for X25519 and 448 for 371 | X448: 372 | 373 | 374 | def decodeLittleEndian(b, bits): 375 | return sum([b[i] << 8*i for i in range((bits+7)/8)]) 376 | 377 | def decodeUCoordinate(u, bits): 378 | u_list = [ord(b) for b in u] 379 | # Ignore any unused bits. 380 | if bits % 8: 381 | u_list[-1] &= (1<<(bits%8))-1 382 | return decodeLittleEndian(u_list, bits) 383 | 384 | def encodeUCoordinate(u, bits): 385 | u = u % p 386 | return ''.join([chr((u >> 8*i) & 0xff) 387 | for i in range((bits+7)/8)]) 388 | 389 | 390 | 391 | 392 | 393 | 394 | Langley, et al. Informational [Page 7] 395 | 396 | RFC 7748 Elliptic Curves for Security January 2016 397 | 398 | 399 | Scalars are assumed to be randomly generated bytes. For X25519, in 400 | order to decode 32 random bytes as an integer scalar, set the three 401 | least significant bits of the first byte and the most significant bit 402 | of the last to zero, set the second most significant bit of the last 403 | byte to 1 and, finally, decode as little-endian. This means that the 404 | resulting integer is of the form 2^254 plus eight times a value 405 | between 0 and 2^251 - 1 (inclusive). Likewise, for X448, set the two 406 | least significant bits of the first byte to 0, and the most 407 | significant bit of the last byte to 1. This means that the resulting 408 | integer is of the form 2^447 plus four times a value between 0 and 409 | 2^445 - 1 (inclusive). 410 | 411 | 412 | def decodeScalar25519(k): 413 | k_list = [ord(b) for b in k] 414 | k_list[0] &= 248 415 | k_list[31] &= 127 416 | k_list[31] |= 64 417 | return decodeLittleEndian(k_list, 255) 418 | 419 | def decodeScalar448(k): 420 | k_list = [ord(b) for b in k] 421 | k_list[0] &= 252 422 | k_list[55] |= 128 423 | return decodeLittleEndian(k_list, 448) 424 | 425 | 426 | To implement the X25519(k, u) and X448(k, u) functions (where k is 427 | the scalar and u is the u-coordinate), first decode k and u and then 428 | perform the following procedure, which is taken from [curve25519] and 429 | based on formulas from [montgomery]. All calculations are performed 430 | in GF(p), i.e., they are performed modulo p. The constant a24 is 431 | (486662 - 2) / 4 = 121665 for curve25519/X25519 and (156326 - 2) / 4 432 | = 39081 for curve448/X448. 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | Langley, et al. Informational [Page 8] 451 | 452 | RFC 7748 Elliptic Curves for Security January 2016 453 | 454 | 455 | x_1 = u 456 | x_2 = 1 457 | z_2 = 0 458 | x_3 = u 459 | z_3 = 1 460 | swap = 0 461 | 462 | For t = bits-1 down to 0: 463 | k_t = (k >> t) & 1 464 | swap ^= k_t 465 | // Conditional swap; see text below. 466 | (x_2, x_3) = cswap(swap, x_2, x_3) 467 | (z_2, z_3) = cswap(swap, z_2, z_3) 468 | swap = k_t 469 | 470 | A = x_2 + z_2 471 | AA = A^2 472 | B = x_2 - z_2 473 | BB = B^2 474 | E = AA - BB 475 | C = x_3 + z_3 476 | D = x_3 - z_3 477 | DA = D * A 478 | CB = C * B 479 | x_3 = (DA + CB)^2 480 | z_3 = x_1 * (DA - CB)^2 481 | x_2 = AA * BB 482 | z_2 = E * (AA + a24 * E) 483 | 484 | // Conditional swap; see text below. 485 | (x_2, x_3) = cswap(swap, x_2, x_3) 486 | (z_2, z_3) = cswap(swap, z_2, z_3) 487 | Return x_2 * (z_2^(p - 2)) 488 | 489 | (Note that these formulas are slightly different from Montgomery's 490 | original paper. Implementations are free to use any correct 491 | formulas.) 492 | 493 | Finally, encode the resulting value as 32 or 56 bytes in little- 494 | endian order. For X25519, the unused, most significant bit MUST be 495 | zero. 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | Langley, et al. Informational [Page 9] 507 | 508 | RFC 7748 Elliptic Curves for Security January 2016 509 | 510 | 511 | The cswap function SHOULD be implemented in constant time (i.e., 512 | independent of the swap argument). For example, this can be done as 513 | follows: 514 | 515 | cswap(swap, x_2, x_3): 516 | dummy = mask(swap) AND (x_2 XOR x_3) 517 | x_2 = x_2 XOR dummy 518 | x_3 = x_3 XOR dummy 519 | Return (x_2, x_3) 520 | 521 | Where mask(swap) is the all-1 or all-0 word of the same length as x_2 522 | and x_3, computed, e.g., as mask(swap) = 0 - swap. 523 | 524 | 5.1. Side-Channel Considerations 525 | 526 | X25519 and X448 are designed so that fast, constant-time 527 | implementations are easier to produce. The procedure above ensures 528 | that the same sequence of field operations is performed for all 529 | values of the secret key, thus eliminating a common source of side- 530 | channel leakage. However, this alone does not prevent all side- 531 | channels by itself. It is important that the pattern of memory 532 | accesses and jumps not depend on the values of any of the bits of k. 533 | It is also important that the arithmetic used not leak information 534 | about the integers modulo p, for example by having b*c be 535 | distinguishable from c*c. On some architectures, even primitive 536 | machine instructions, such as single-word division, can have variable 537 | timing based on their inputs. 538 | 539 | Side-channel attacks are an active research area that still sees 540 | significant, new results. Implementors are advised to follow this 541 | research closely. 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | Langley, et al. Informational [Page 10] 563 | 564 | RFC 7748 Elliptic Curves for Security January 2016 565 | 566 | 567 | 5.2. Test Vectors 568 | 569 | Two types of tests are provided. The first is a pair of test vectors 570 | for each function that consist of expected outputs for the given 571 | inputs. The inputs are generally given as 64 or 112 hexadecimal 572 | digits that need to be decoded as 32 or 56 binary bytes before 573 | processing. 574 | 575 | X25519: 576 | 577 | Input scalar: 578 | a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4 579 | Input scalar as a number (base 10): 580 | 31029842492115040904895560451863089656 581 | 472772604678260265531221036453811406496 582 | Input u-coordinate: 583 | e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c 584 | Input u-coordinate as a number (base 10): 585 | 34426434033919594451155107781188821651 586 | 316167215306631574996226621102155684838 587 | Output u-coordinate: 588 | c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552 589 | 590 | Input scalar: 591 | 4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d 592 | Input scalar as a number (base 10): 593 | 35156891815674817266734212754503633747 594 | 128614016119564763269015315466259359304 595 | Input u-coordinate: 596 | e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493 597 | Input u-coordinate as a number (base 10): 598 | 88838573511839298940907593866106493194 599 | 17338800022198945255395922347792736741 600 | Output u-coordinate: 601 | 95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | Langley, et al. Informational [Page 11] 619 | 620 | RFC 7748 Elliptic Curves for Security January 2016 621 | 622 | 623 | X448: 624 | 625 | Input scalar: 626 | 3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121 627 | 700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3 628 | Input scalar as a number (base 10): 629 | 599189175373896402783756016145213256157230856 630 | 085026129926891459468622403380588640249457727 631 | 683869421921443004045221642549886377526240828 632 | Input u-coordinate: 633 | 06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9 634 | 814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086 635 | Input u-coordinate as a number (base 10): 636 | 382239910814107330116229961234899377031416365 637 | 240571325148346555922438025162094455820962429 638 | 142971339584360034337310079791515452463053830 639 | Output u-coordinate: 640 | ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239f 641 | e14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f 642 | 643 | Input scalar: 644 | 203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c5 645 | 38345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f 646 | Input scalar as a number (base 10): 647 | 633254335906970592779259481534862372382525155 648 | 252028961056404001332122152890562527156973881 649 | 968934311400345568203929409663925541994577184 650 | Input u-coordinate: 651 | 0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b 652 | 165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db 653 | Input u-coordinate as a number (base 10): 654 | 622761797758325444462922068431234180649590390 655 | 024811299761625153767228042600197997696167956 656 | 134770744996690267634159427999832340166786063 657 | Output u-coordinate: 658 | 884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7 659 | ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | Langley, et al. Informational [Page 12] 675 | 676 | RFC 7748 Elliptic Curves for Security January 2016 677 | 678 | 679 | The second type of test vector consists of the result of calling the 680 | function in question a specified number of times. Initially, set k 681 | and u to be the following values: 682 | 683 | For X25519: 684 | 0900000000000000000000000000000000000000000000000000000000000000 685 | For X448: 686 | 05000000000000000000000000000000000000000000000000000000 687 | 00000000000000000000000000000000000000000000000000000000 688 | 689 | For each iteration, set k to be the result of calling the function 690 | and u to be the old value of k. The final result is the value left 691 | in k. 692 | 693 | X25519: 694 | 695 | After one iteration: 696 | 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079 697 | After 1,000 iterations: 698 | 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51 699 | After 1,000,000 iterations: 700 | 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 701 | 702 | 703 | X448: 704 | 705 | After one iteration: 706 | 3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a 707 | 4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113 708 | After 1,000 iterations: 709 | aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4 710 | af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38 711 | After 1,000,000 iterations: 712 | 077f453681caca3693198420bbe515cae0002472519b3e67661a7e89 713 | cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | Langley, et al. Informational [Page 13] 731 | 732 | RFC 7748 Elliptic Curves for Security January 2016 733 | 734 | 735 | 6. Diffie-Hellman 736 | 737 | 6.1. Curve25519 738 | 739 | The X25519 function can be used in an Elliptic Curve Diffie-Hellman 740 | (ECDH) protocol as follows: 741 | 742 | Alice generates 32 random bytes in a[0] to a[31] and transmits K_A = 743 | X25519(a, 9) to Bob, where 9 is the u-coordinate of the base point 744 | and is encoded as a byte with value 9, followed by 31 zero bytes. 745 | 746 | Bob similarly generates 32 random bytes in b[0] to b[31], computes 747 | K_B = X25519(b, 9), and transmits it to Alice. 748 | 749 | Using their generated values and the received input, Alice computes 750 | X25519(a, K_B) and Bob computes X25519(b, K_A). 751 | 752 | Both now share K = X25519(a, X25519(b, 9)) = X25519(b, X25519(a, 9)) 753 | as a shared secret. Both MAY check, without leaking extra 754 | information about the value of K, whether K is the all-zero value and 755 | abort if so (see below). Alice and Bob can then use a key-derivation 756 | function that includes K, K_A, and K_B to derive a symmetric key. 757 | 758 | The check for the all-zero value results from the fact that the 759 | X25519 function produces that value if it operates on an input 760 | corresponding to a point with small order, where the order divides 761 | the cofactor of the curve (see Section 7). The check may be 762 | performed by ORing all the bytes together and checking whether the 763 | result is zero, as this eliminates standard side-channels in software 764 | implementations. 765 | 766 | Test vector: 767 | 768 | Alice's private key, a: 769 | 77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a 770 | Alice's public key, X25519(a, 9): 771 | 8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a 772 | Bob's private key, b: 773 | 5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb 774 | Bob's public key, X25519(b, 9): 775 | de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f 776 | Their shared secret, K: 777 | 4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | Langley, et al. Informational [Page 14] 787 | 788 | RFC 7748 Elliptic Curves for Security January 2016 789 | 790 | 791 | 6.2. Curve448 792 | 793 | The X448 function can be used in an ECDH protocol very much like the 794 | X25519 function. 795 | 796 | If X448 is to be used, the only differences are that Alice and Bob 797 | generate 56 random bytes (not 32) and calculate K_A = X448(a, 5) or 798 | K_B = X448(b, 5), where 5 is the u-coordinate of the base point and 799 | is encoded as a byte with value 5, followed by 55 zero bytes. 800 | 801 | As with X25519, both sides MAY check, without leaking extra 802 | information about the value of K, whether the resulting shared K is 803 | the all-zero value and abort if so. 804 | 805 | Test vector: 806 | 807 | Alice's private key, a: 808 | 9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28d 809 | d9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b 810 | Alice's public key, X448(a, 5): 811 | 9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c 812 | 22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0 813 | Bob's private key, b: 814 | 1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d 815 | 6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d 816 | Bob's public key, X448(b, 5): 817 | 3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b430 818 | 27d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609 819 | Their shared secret, K: 820 | 07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282b 821 | b60c0b56fd2464c335543936521c24403085d59a449a5037514a879d 822 | 823 | 7. Security Considerations 824 | 825 | The security level (i.e., the number of "operations" needed for a 826 | brute-force attack on a primitive) of curve25519 is slightly under 827 | the standard 128-bit level. This is acceptable because the standard 828 | security levels are primarily driven by much simpler, symmetric 829 | primitives where the security level naturally falls on a power of 830 | two. For asymmetric primitives, rigidly adhering to a power-of-two 831 | security level would require compromises in other parts of the 832 | design, which we reject. Additionally, comparing security levels 833 | between types of primitives can be misleading under common threat 834 | models where multiple targets can be attacked concurrently 835 | [bruteforce]. 836 | 837 | 838 | 839 | 840 | 841 | 842 | Langley, et al. Informational [Page 15] 843 | 844 | RFC 7748 Elliptic Curves for Security January 2016 845 | 846 | 847 | The ~224-bit security level of curve448 is a trade-off between 848 | performance and paranoia. Large quantum computers, if ever created, 849 | will break both curve25519 and curve448, and reasonable projections 850 | of the abilities of classical computers conclude that curve25519 is 851 | perfectly safe. However, some designs have relaxed performance 852 | requirements and wish to hedge against some amount of analytical 853 | advance against elliptic curves and thus curve448 is also provided. 854 | 855 | Protocol designers using Diffie-Hellman over the curves defined in 856 | this document must not assume "contributory behaviour". Specially, 857 | contributory behaviour means that both parties' private keys 858 | contribute to the resulting shared key. Since curve25519 and 859 | curve448 have cofactors of 8 and 4 (respectively), an input point of 860 | small order will eliminate any contribution from the other party's 861 | private key. This situation can be detected by checking for the all- 862 | zero output, which implementations MAY do, as specified in Section 6. 863 | However, a large number of existing implementations do not do this. 864 | 865 | Designers using these curves should be aware that for each public 866 | key, there are several publicly computable public keys that are 867 | equivalent to it, i.e., they produce the same shared secrets. Thus 868 | using a public key as an identifier and knowledge of a shared secret 869 | as proof of ownership (without including the public keys in the key 870 | derivation) might lead to subtle vulnerabilities. 871 | 872 | Designers should also be aware that implementations of these curves 873 | might not use the Montgomery ladder as specified in this document, 874 | but could use generic, elliptic-curve libraries instead. These 875 | implementations could reject points on the twist and could reject 876 | non-minimal field elements. While not recommended, such 877 | implementations will interoperate with the Montgomery ladder 878 | specified here but may be trivially distinguishable from it. For 879 | example, sending a non-canonical value or a point on the twist may 880 | cause such implementations to produce an observable error while an 881 | implementation that follows the design in this text would 882 | successfully produce a shared key. 883 | 884 | 8. References 885 | 886 | 8.1. Normative References 887 | 888 | [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate 889 | Requirement Levels", BCP 14, RFC 2119, 890 | DOI 10.17487/RFC2119, March 1997, 891 | . 892 | 893 | 894 | 895 | 896 | 897 | 898 | Langley, et al. Informational [Page 16] 899 | 900 | RFC 7748 Elliptic Curves for Security January 2016 901 | 902 | 903 | 8.2. Informative References 904 | 905 | [brainpool] 906 | ECC Brainpool, "ECC Brainpool Standard Curves and Curve 907 | Generation", October 2005, 908 | . 910 | 911 | [bruteforce] 912 | Bernstein, D., "Understanding brute force", April 2005, 913 | . 914 | 915 | [curve25519] 916 | Bernstein, D., "Curve25519: new Diffie-Hellman speed 917 | records", 2006, 918 | . 920 | 921 | [ed25519] Bernstein, D., Duif, N., Lange, T., Schwabe, P., and B. 922 | Yang, "High-Speed High-Security Signatures", 2011, 923 | . 925 | 926 | [goldilocks] 927 | Hamburg, M., "Ed448-Goldilocks, a new elliptic curve", 928 | 2015, . 929 | 930 | [montgomery] 931 | Montgomery, P., "Speeding the Pollard and Elliptic Curve 932 | Methods of Factorization", January 1987, 933 | . 935 | 936 | [NIST] National Institute of Standards, "Recommended Elliptic 937 | Curves for Federal Government Use", July 1999, 938 | . 940 | 941 | [reducing] Menezes, A., Okamoto, T., and S. Vanstone, "Reducing 942 | elliptic curve logarithms to logarithms in a finite 943 | field", DOI 10.1109/18.259647, 1993, 944 | . 946 | 947 | [RFC6090] McGrew, D., Igoe, K., and M. Salter, "Fundamental Elliptic 948 | Curve Cryptography Algorithms", RFC 6090, 949 | DOI 10.17487/RFC6090, February 2011, 950 | . 951 | 952 | 953 | 954 | Langley, et al. Informational [Page 17] 955 | 956 | RFC 7748 Elliptic Curves for Security January 2016 957 | 958 | 959 | [safecurves] 960 | Bernstein, D. and T. Lange, "SafeCurves: choosing safe 961 | curves for elliptic-curve cryptography", Oct 2013, 962 | . 963 | 964 | [satoh] Satoh, T. and K. Araki, "Fermat quotients and the 965 | polynomial time discrete log algorithm for anomalous 966 | elliptic curves", 1998. 967 | 968 | [SEC1] Certicom Research, "SEC 1: Elliptic Curve Cryptography", 969 | September 2000, . 970 | 971 | [semaev] Semaev, I., "Evaluation of discrete logarithms on some 972 | elliptic curves", 1998, . 975 | 976 | [smart] Smart, N., "The Discrete Logarithm Problem on Elliptic 977 | Curves of Trace One", 1999, 978 | . 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | Langley, et al. Informational [Page 18] 1011 | 1012 | RFC 7748 Elliptic Curves for Security January 2016 1013 | 1014 | 1015 | Appendix A. Deterministic Generation 1016 | 1017 | This section specifies the procedure that was used to generate the 1018 | above curves; specifically, it defines how to generate the parameter 1019 | A of the Montgomery curve y^2 = x^3 + A*x^2 + x. This procedure is 1020 | intended to be as objective as can reasonably be achieved so that 1021 | it's clear that no untoward considerations influenced the choice of 1022 | curve. The input to this process is p, the prime that defines the 1023 | underlying field. The size of p determines the amount of work needed 1024 | to compute a discrete logarithm in the elliptic curve group, and 1025 | choosing a precise p depends on many implementation concerns. The 1026 | performance of the curve will be dominated by operations in GF(p), so 1027 | carefully choosing a value that allows for easy reductions on the 1028 | intended architecture is critical. This document does not attempt to 1029 | articulate all these considerations. 1030 | 1031 | The value (A-2)/4 is used in several of the elliptic curve point 1032 | arithmetic formulas. For simplicity and performance reasons, it is 1033 | beneficial to make this constant small, i.e., to choose A so that 1034 | (A-2) is a small integer that is divisible by four. 1035 | 1036 | For each curve at a specific security level: 1037 | 1038 | 1. The trace of Frobenius MUST NOT be in {0, 1} in order to rule out 1039 | the attacks described in [smart], [satoh], and [semaev], as in 1040 | [brainpool] and [safecurves]. 1041 | 1042 | 2. MOV Degree [reducing]: the embedding degree MUST be greater than 1043 | (order - 1) / 100, as in [brainpool] and [safecurves]. 1044 | 1045 | 3. CM Discriminant: discriminant D MUST be greater than 2^100, as in 1046 | [safecurves]. 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | Langley, et al. Informational [Page 19] 1067 | 1068 | RFC 7748 Elliptic Curves for Security January 2016 1069 | 1070 | 1071 | A.1. p = 1 mod 4 1072 | 1073 | For primes congruent to 1 mod 4, the minimal cofactors of the curve 1074 | and its twist are either {4, 8} or {8, 4}. We choose a curve with 1075 | the latter cofactors so that any algorithms that take the cofactor 1076 | into account don't have to worry about checking for points on the 1077 | twist, because the twist cofactor will be the smaller of the two. 1078 | 1079 | To generate the Montgomery curve, we find the minimal, positive A 1080 | value such that A > 2 and (A-2) is divisible by four and where the 1081 | cofactors are as desired. The find1Mod4 function in the following 1082 | Sage script returns this value given p: 1083 | 1084 | 1085 | def findCurve(prime, curveCofactor, twistCofactor): 1086 | F = GF(prime) 1087 | 1088 | for A in xrange(3, int(1e9)): 1089 | if (A-2) % 4 != 0: 1090 | continue 1091 | 1092 | try: 1093 | E = EllipticCurve(F, [0, A, 0, 1, 0]) 1094 | except: 1095 | continue 1096 | 1097 | groupOrder = E.order() 1098 | twistOrder = 2*(prime+1)-groupOrder 1099 | 1100 | if (groupOrder % curveCofactor == 0 and 1101 | is_prime(groupOrder // curveCofactor) and 1102 | twistOrder % twistCofactor == 0 and 1103 | is_prime(twistOrder // twistCofactor)): 1104 | return A 1105 | 1106 | def find1Mod4(prime): 1107 | assert((prime % 4) == 1) 1108 | return findCurve(prime, 8, 4) 1109 | 1110 | 1111 | Generating a curve where p = 1 mod 4 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | Langley, et al. Informational [Page 20] 1123 | 1124 | RFC 7748 Elliptic Curves for Security January 2016 1125 | 1126 | 1127 | A.2. p = 3 mod 4 1128 | 1129 | For a prime congruent to 3 mod 4, both the curve and twist cofactors 1130 | can be 4, and this is minimal. Thus, we choose the curve with these 1131 | cofactors and minimal, positive A such that A > 2 and (A-2) is 1132 | divisible by four. The find3Mod4 function in the following Sage 1133 | script returns this value given p: 1134 | 1135 | 1136 | def find3Mod4(prime): 1137 | assert((prime % 4) == 3) 1138 | return findCurve(prime, 4, 4) 1139 | 1140 | 1141 | Generating a curve where p = 3 mod 4 1142 | 1143 | A.3. Base Points 1144 | 1145 | The base point for a curve is the point with minimal, positive u 1146 | value that is in the correct subgroup. The findBasepoint function in 1147 | the following Sage script returns this value given p and A: 1148 | 1149 | 1150 | def findBasepoint(prime, A): 1151 | F = GF(prime) 1152 | E = EllipticCurve(F, [0, A, 0, 1, 0]) 1153 | 1154 | for uInt in range(1, 1e3): 1155 | u = F(uInt) 1156 | v2 = u^3 + A*u^2 + u 1157 | if not v2.is_square(): 1158 | continue 1159 | v = v2.sqrt() 1160 | 1161 | point = E(u, v) 1162 | pointOrder = point.order() 1163 | if pointOrder > 8 and pointOrder.is_prime(): 1164 | return point 1165 | 1166 | 1167 | Generating the base point 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1178 | Langley, et al. Informational [Page 21] 1179 | 1180 | RFC 7748 Elliptic Curves for Security January 2016 1181 | 1182 | 1183 | Acknowledgements 1184 | 1185 | This document is the result of a combination of draft-black-rpgecc-01 1186 | and draft-turner-thecurve25519function-01. The following authors of 1187 | those documents wrote much of the text and figures but are not listed 1188 | as authors on this document: Benjamin Black, Joppe W. Bos, Craig 1189 | Costello, Patrick Longa, Michael Naehrig, Watson Ladd, and Rich Salz. 1190 | 1191 | The authors would also like to thank Tanja Lange, Rene Struik, Rich 1192 | Salz, Ilari Liusvaara, Deirdre Connolly, Simon Josefsson, Stephen 1193 | Farrell, Georg Nestmann, Trevor Perrin, and John Mattsson for their 1194 | reviews and contributions. 1195 | 1196 | The X25519 function was developed by Daniel J. Bernstein in 1197 | [curve25519]. 1198 | 1199 | Authors' Addresses 1200 | 1201 | Adam Langley 1202 | Google 1203 | 345 Spear Street 1204 | San Francisco, CA 94105 1205 | United States 1206 | 1207 | Email: agl@google.com 1208 | 1209 | 1210 | Mike Hamburg 1211 | Rambus Cryptography Research 1212 | 425 Market Street, 11th Floor 1213 | San Francisco, CA 94105 1214 | United States 1215 | 1216 | Email: mike@shiftleft.org 1217 | 1218 | 1219 | Sean Turner 1220 | sn3rd 1221 | 1222 | Email: sean@sn3rd.com 1223 | 1224 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 | Langley, et al. Informational [Page 22] 1235 | 1236 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 1.2) 2 | -------------------------------------------------------------------------------- /examples/dune: -------------------------------------------------------------------------------- 1 | (test 2 | (name quickstart) 3 | (libraries rfc7748) 4 | (modules quickstart) 5 | ) 6 | -------------------------------------------------------------------------------- /examples/quickstart.ml: -------------------------------------------------------------------------------- 1 | 2 | (* Open library to get module [X25519] and function [x25519]. *) 3 | open Rfc7748 4 | 5 | (* Make this example deterministic by fixing the random seed. *) 6 | let _ = Random.init 7748 7 | 8 | (* Create a list of [n] random bytes (could be using [List.init] in OCaml 4.06+). *) 9 | let rec random_bytes = function 10 | | n when n <= 0 -> [] 11 | | n -> Random.int 256 :: random_bytes (n - 1) 12 | 13 | (* This function generates [n] random bytes and encodes them in a hexadecimal 14 | string. *) 15 | let random_bytes_hex n = 16 | random_bytes n 17 | |> List.map @@ Format.sprintf "%02x" 18 | |> String.concat "" 19 | 20 | (* The base point is used to derive public keys from private keys. *) 21 | let base = X25519.(base |> string_of_public_key) 22 | 23 | (* The main function shows how a shared secret can be negotiated using [x25519]. *) 24 | let _ = 25 | (* We define two actors holding their own private keys. *) 26 | let alice = x25519 ~priv:(random_bytes_hex X25519.key_size) in 27 | let bob = x25519 ~priv:(random_bytes_hex X25519.key_size) in 28 | 29 | (* Each actor creates their own public key. *) 30 | let alice_pub = alice ~pub:base in 31 | let bob_pub = bob ~pub:base in 32 | 33 | (* Public keys are transferred over an insecure medium ... *) 34 | 35 | (* Each actor creates the shared secret using their own private key and the 36 | other actor's public key. *) 37 | let alice_shared = alice ~pub:bob_pub in 38 | let bob_shared = bob ~pub:alice_pub in 39 | 40 | (* Both actors hold the same shared secret. *) 41 | if alice_shared <> bob_shared then 42 | failwith @@ alice_shared ^ " != " ^ bob_shared 43 | -------------------------------------------------------------------------------- /rfc7748.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | name: "rfc7748" 3 | version: "1.0" 4 | maintainer: ["Markus Rudy "] 5 | authors: ["Markus Rudy"] 6 | homepage: "https://github.com/burgerdev/ocaml-rfc7748" 7 | bug-reports: "https://github.com/burgerdev/ocaml-rfc7748/issues" 8 | dev-repo: "git+https://github.com/burgerdev/ocaml-rfc7748.git" 9 | license: "BSD" 10 | build: [ 11 | ["dune" "build" "-p" name "-j" jobs] 12 | ["dune" "runtest" "-p" name "-j" jobs] {with-test} 13 | ] 14 | depends: [ 15 | "ocaml" { >= "4.03" } 16 | "zarith" { >= "1.5" } 17 | "dune" { build & >= "1.2.1" } 18 | "ounit" { with-test & >= "2.0.5" } 19 | "hex" { with-test & >= "1.2.0" } 20 | ] 21 | synopsis: "Edwards Curves X25519 and X448 from RFC 7748" 22 | description: """ 23 | This library implements the ECDH functions 'X25519' and 'X448' as specified in 24 | RFC 7748, 'Elliptic curves for security'. In the spirit of the original 25 | publications, the public API is kept as simple as possible to make it easy to 26 | use and hard to misuse. 27 | 28 | The current version is written in plain OCaml, leveraging Zarith for integer 29 | arithmetic. While this makes the implementation straightforward and easy to 30 | reason about, the performance is nowhere near that of DJB's implementation using 31 | floating point registers (https://cr.yp.to/ecdh.html). """ 32 | -------------------------------------------------------------------------------- /src/curve.ml: -------------------------------------------------------------------------------- 1 | 2 | module type Field = sig 3 | type t 4 | val zero: t 5 | 6 | val ( + ): t -> t -> t 7 | val ( - ): t -> t -> t 8 | val double: t -> t 9 | 10 | val one: t 11 | 12 | val ( * ): t -> t -> t 13 | val ( / ): t -> t -> t 14 | val square: t -> t 15 | end 16 | 17 | module type Integral = sig 18 | type t 19 | val zero: t 20 | val one: t 21 | 22 | val ( + ): t -> t -> t 23 | 24 | val ( mod ): t -> t -> t 25 | val ( asr ): t -> int -> t 26 | val logxor: t -> t -> t 27 | val gt: t -> t -> bool 28 | end 29 | 30 | module type Edwards = sig 31 | type integral 32 | type element 33 | 34 | val bits: int 35 | val a24: element 36 | 37 | val constant_time_conditional_swap: integral -> element -> element -> element * element 38 | end 39 | 40 | module Make(F: Field)(I: Integral)(E: Edwards with type integral = I.t and type element = F.t) = struct 41 | open F 42 | 43 | let two = I.(one + one) 44 | let bit z n = I.((z asr n) mod two) 45 | let cswap = E.constant_time_conditional_swap 46 | 47 | let scale priv pub = 48 | let rec aux x1 x2 x3 z2 z3 swap = function 49 | | t when t < 0 -> 50 | let (x2, _) = cswap swap x2 x3 in 51 | let (z2, _) = cswap swap z2 z3 in 52 | x2 / z2 53 | | t -> 54 | let kt = bit priv t in 55 | let swap = I.(logxor swap kt) in 56 | let (x2, x3) = cswap swap x2 x3 in 57 | let (z2, z3) = cswap swap z2 z3 in 58 | let swap = kt in 59 | 60 | let a = x2 + z2 in 61 | let aa = square a in 62 | let b = x2 - z2 in 63 | let bb = square b in 64 | let e = aa - bb in 65 | let c = x3 + z3 in 66 | let d = x3 - z3 in 67 | let da = d * a in 68 | let cb = c * b in 69 | 70 | let x3 = square (da + cb) in 71 | let z3 = x1 * square (da - cb) in 72 | let x2 = aa * bb in 73 | let z2 = e * (aa + E.a24 * e) in 74 | 75 | aux x1 x2 x3 z2 z3 swap (pred t) 76 | in 77 | 78 | let x1 = pub in 79 | let x2 = one in 80 | let z2 = zero in 81 | let x3 = pub in 82 | let z3 = one in 83 | let swap = I.zero in 84 | aux x1 x2 x3 z2 z3 swap (pred E.bits) 85 | end 86 | -------------------------------------------------------------------------------- /src/curve.mli: -------------------------------------------------------------------------------- 1 | 2 | module type Field = sig 3 | type t 4 | val zero: t 5 | 6 | val ( + ): t -> t -> t 7 | val ( - ): t -> t -> t 8 | val double: t -> t 9 | 10 | val one: t 11 | 12 | val ( * ): t -> t -> t 13 | val ( / ): t -> t -> t 14 | val square: t -> t 15 | end 16 | 17 | module type Integral = sig 18 | type t 19 | val zero: t 20 | val one: t 21 | 22 | val ( + ): t -> t -> t 23 | 24 | val ( mod ): t -> t -> t 25 | val ( asr ): t -> int -> t 26 | val logxor: t -> t -> t 27 | val gt: t -> t -> bool 28 | end 29 | 30 | module type Edwards = sig 31 | type integral 32 | type element 33 | 34 | val bits: int 35 | val a24: element 36 | 37 | val constant_time_conditional_swap: integral -> element -> element -> element * element 38 | end 39 | 40 | module Make: functor (F: Field)(I: Integral)(E: Edwards with type integral = I.t and type element = F.t) -> sig 41 | val scale: I.t -> F.t -> F.t 42 | end 43 | -------------------------------------------------------------------------------- /src/dune: -------------------------------------------------------------------------------- 1 | (library 2 | (name rfc7748) 3 | (public_name rfc7748) 4 | 5 | (libraries zarith) 6 | ) 7 | -------------------------------------------------------------------------------- /src/rfc7748.ml: -------------------------------------------------------------------------------- 1 | module type DH = sig 2 | type private_key 3 | type public_key 4 | 5 | val key_size: int 6 | 7 | val base: public_key 8 | 9 | val public_key_of_string: string -> public_key 10 | val private_key_of_string: string -> private_key 11 | 12 | val string_of_public_key: public_key -> string 13 | val string_of_private_key: private_key -> string 14 | 15 | val public_key_of_bytes: Bytes.t -> public_key 16 | val private_key_of_bytes: Bytes.t -> private_key 17 | 18 | val bytes_of_public_key: public_key -> Bytes.t 19 | val bytes_of_private_key: private_key -> Bytes.t 20 | 21 | val scale: private_key -> public_key -> public_key 22 | val public_key_of_private_key: private_key -> public_key 23 | end 24 | 25 | module X25519: DH = struct 26 | type private_key = Private_key of Z.t 27 | type public_key = Public_key of Z.t 28 | 29 | let key_size = 32 30 | 31 | module A = struct 32 | type element = Z.t 33 | type integral = Z.t 34 | 35 | let p = Z.(one lsl 255 - ~$19) 36 | 37 | let bits = 255 38 | 39 | let a24 = Z.of_int 121665 40 | 41 | let two = Z.(~$2) 42 | 43 | let constant_time_conditional_swap cond a b = 44 | let c = Z.(rem cond two) in 45 | let c' = Z.(one - c) in 46 | let a' = Z.(c'*a + c*b) in 47 | let b' = Z.(c'*b + c*a) in 48 | a', b' 49 | end 50 | 51 | module C = Curve.Make(Zfield.Zp(A))(Z)(A) 52 | 53 | (* Quoth the RFC: 54 | set the three least significant bits of the first byte and the most significant bit 55 | of the last to zero, set the second most significant bit of the last byte to 1 56 | *) 57 | let sanitize_scalar = 58 | let unset_this = Z.logor Z.(~$7) (Z.shift_left Z.(~$128) (8*31)) in 59 | let set_that = Z.shift_left Z.(~$64) (8*31) in 60 | fun z -> 61 | Z.(z - (logand z unset_this)) 62 | |> Z.logor set_that 63 | 64 | let public_key_of_string: string -> public_key = fun s -> 65 | let p = Serde.z_of_hex s in 66 | let high = Z.(logand p (~$128 lsl 248)) in 67 | Public_key Z.(p - high) 68 | 69 | let public_key_of_bytes: Bytes.t -> public_key = fun buf -> 70 | assert (Bytes.length buf = key_size); 71 | let p = Serde.z_of_bytes buf in 72 | let high = Z.(logand p (~$128 lsl 248)) in 73 | Public_key Z.(p - high) 74 | 75 | let string_of_public_key: public_key -> string = function Public_key pk -> 76 | Serde.hex_of_z key_size pk 77 | 78 | let bytes_of_public_key: public_key -> Bytes.t = function Public_key pk -> 79 | Serde.bytes_of_z key_size pk 80 | 81 | let private_key_of_string: string -> private_key = fun s -> 82 | let z = Serde.z_of_hex s |> sanitize_scalar in 83 | Private_key z 84 | 85 | let private_key_of_bytes: Bytes.t -> private_key = fun buf -> 86 | assert (Bytes.length buf = key_size); 87 | let z = Serde.z_of_bytes buf |> sanitize_scalar in 88 | Private_key z 89 | 90 | let string_of_private_key: private_key -> string = function Private_key pk -> 91 | Serde.hex_of_z key_size pk 92 | 93 | let bytes_of_private_key: private_key -> Bytes.t = function Private_key pk -> 94 | Serde.bytes_of_z key_size pk 95 | 96 | let scale (Private_key priv) (Public_key pub) = Public_key (C.scale priv pub) 97 | 98 | let base = Public_key (Z.of_int 9) 99 | 100 | let public_key_of_private_key priv = scale priv base 101 | end 102 | 103 | let x25519 ~priv ~pub = 104 | X25519.( 105 | scale (private_key_of_string priv) (public_key_of_string pub) 106 | |> string_of_public_key 107 | ) 108 | 109 | module X448: DH = struct 110 | type private_key = Private_key of Z.t 111 | type public_key = Public_key of Z.t 112 | 113 | let key_size = 56 114 | 115 | module A = struct 116 | type element = Z.t 117 | type integral = Z.t 118 | 119 | let p = Z.(one lsl 448 - one lsl 224 - ~$1) 120 | 121 | let bits = 448 122 | 123 | let a24 = Z.of_int 39081 124 | 125 | let two = Z.(~$2) 126 | 127 | let constant_time_conditional_swap cond a b = 128 | let c = Z.(rem cond two) in 129 | let c' = Z.(one - c) in 130 | let a' = Z.(c'*a + c*b) in 131 | let b' = Z.(c'*b + c*a) in 132 | a', b' 133 | end 134 | 135 | module C = Curve.Make(Zfield.Zp(A))(Z)(A) 136 | 137 | (* Quoth the RFC: 138 | set the two least significant bits of the first byte to 0, and the most 139 | significant bit of the last byte to 1. 140 | *) 141 | let sanitize_scalar = 142 | let unset_this = Z.(~$3) in 143 | let set_that = Z.shift_left Z.(~$128) (8*55) in 144 | fun z -> 145 | Z.(z - (logand z unset_this)) 146 | |> Z.logor set_that 147 | 148 | let public_key_of_string: string -> public_key = fun s -> 149 | let p = Serde.z_of_hex s in 150 | Public_key p 151 | 152 | let public_key_of_bytes buf = 153 | let p = Serde.z_of_bytes buf in 154 | Public_key p 155 | 156 | let string_of_public_key: public_key -> string = function Public_key pk -> 157 | Serde.hex_of_z key_size pk 158 | 159 | let bytes_of_public_key = function Public_key pk -> 160 | Serde.bytes_of_z key_size pk 161 | 162 | let private_key_of_string: string -> private_key = fun s -> 163 | let z = Serde.z_of_hex s |> sanitize_scalar in 164 | Private_key z 165 | 166 | let private_key_of_bytes buf = 167 | let z = Serde.z_of_bytes buf |> sanitize_scalar in 168 | Private_key z 169 | 170 | let string_of_private_key: private_key -> string = function Private_key pk -> 171 | Serde.hex_of_z key_size pk 172 | 173 | let bytes_of_private_key = function Private_key pk -> 174 | Serde.bytes_of_z key_size pk 175 | 176 | let scale (Private_key priv) (Public_key pub) = Public_key (C.scale priv pub) 177 | 178 | let base = Public_key (Z.of_int 5) 179 | 180 | let public_key_of_private_key priv = scale priv base 181 | end 182 | 183 | let x448 ~priv ~pub = 184 | X448.( 185 | scale (private_key_of_string priv) (public_key_of_string pub) 186 | |> string_of_public_key 187 | ) 188 | -------------------------------------------------------------------------------- /src/rfc7748.mli: -------------------------------------------------------------------------------- 1 | (** This library provides the two Diffie-Hellman-like functions defined in the 2 | eponymous RFC, [x25519] and [x448]. *) 3 | 4 | (** {2 Summary} *) 5 | 6 | (** X25519 and X448 are instances of a special subset of elliptic curves, the 7 | so-called {e Edwards curves}, for which point addition has a closed form. 8 | This eliminates a whole class of problems that arise in other elliptic curve 9 | implementations, where addition formulas depend on the arguments (e.g. 10 | whether a point is added to itself). In addition, these curves are also 11 | {e designed} to be safe to implement and use: the addition formula is by 12 | construction resistant to timing attacks, neither public keys nor private 13 | keys need to be validated and the string-based interface is very portable. *) 14 | 15 | (** {2 Quick Start} 16 | 17 | You can use {!Rfc7748.x25519} and {!Rfc7748.x448} as described in the example 18 | program in the source tree. *) 19 | 20 | (** {2 API} 21 | 22 | Below is the public API for this library. It is divided into 23 | - a module type {!Rfc7748.DH} for scalar multiplication on Edwards curves 24 | (the elliptic curve analogon of discrete exponentiation, as used in the 25 | classical Diffie-Hellman key exchange) 26 | - the curves {!Rfc7748.X25519} and {!Rfc7748.X448} and 27 | - the functions {!Rfc7748.x25519} and {!Rfc7748.x448} described in RFC 7748. 28 | *) 29 | 30 | 31 | (** Signature of the modules implementing the Diffie-Hellman functions for 32 | RFC 7748. 33 | *) 34 | module type DH = sig 35 | 36 | (** {2 Types} *) 37 | 38 | type private_key 39 | (** A private key for this curve. Private keys are, generally speaking, natural 40 | numbers for scalar multiplication of curve points. *) 41 | 42 | type public_key 43 | (** A public key for this curve. Public keys form a curve in 2D space and are 44 | uniquely identified by their x-coordinate (up to symmetry). *) 45 | 46 | 47 | (** {2 Constants} *) 48 | 49 | val key_size: int 50 | (** The size of a valid private or public key, in bytes. *) 51 | 52 | val base: public_key 53 | (** The base point of the curve. *) 54 | 55 | (** {2 Key Conversion} *) 56 | 57 | val public_key_of_string: string -> public_key 58 | (** Create a public key from a given string. The key is assumed to be encoded in 59 | hexadecimal and must have a length of [2*key_size]. The string is silently 60 | truncated (if too long) or padded (if too short). An exception is raised if 61 | the string contains characters that are not valid hexadecimal digits. The 62 | curves in RFC 7748 are specially crafted such that public keys received 63 | from untrusted sources can be used safely without validation. 64 | 65 | Note that the creation includes a canonicalization step and thus, in 66 | general, [string_of_public_key (public_key_of_string s) <> s].*) 67 | 68 | val private_key_of_string: string -> private_key 69 | (** Create a private key from a given string. The key is assumed to be encoded in 70 | hexadecimal and must have a length of [2*key_size]. The string is silently 71 | truncated (if too long) or padded (if too short). An exception is raised if 72 | the string contains characters that are not valid hexadecimal digits. The 73 | curves in RFC 7748 are specially crafted such that any random sequence of 74 | bytes of the correct length can be used to create a private key. 75 | 76 | Note that the creation includes a canonicalization step and thus, in 77 | general, [string_of_private_key (private_key_of_string s) <> s].*) 78 | 79 | val string_of_public_key: public_key -> string 80 | (** Convert the public key to its hex-encoded string representation. *) 81 | 82 | val string_of_private_key: private_key -> string 83 | (** Convert the private key to its hex-encoded string representation. *) 84 | 85 | val public_key_of_bytes: Bytes.t -> public_key 86 | (** Create a public key from a byte array of length [key_size]. An exception 87 | is raised if the array has the wrong size. Besides that, the function 88 | behaves like {!public_key_of_string} after hex-decoding. The array is not 89 | modified by this module, and it must not be modified externally while the 90 | [public_key] object is in scope. *) 91 | 92 | val private_key_of_bytes: Bytes.t -> private_key 93 | (** Create a private key from a byte array of length [key_size]. An exception 94 | is raised if the array has the wrong size. Besides that, the function 95 | behaves like {!private_key_of_string} after hex-decoding. The array is not 96 | modified by this module, and it must not be modified externally while the 97 | [public_key] object is in scope. *) 98 | 99 | val bytes_of_public_key: public_key -> Bytes.t 100 | (** Create a byte array from the given public key. *) 101 | 102 | val bytes_of_private_key: private_key -> Bytes.t 103 | (** Create a byte array from the given private key. *) 104 | 105 | (** {2 Curve Operations} *) 106 | 107 | val scale: private_key -> public_key -> public_key 108 | (** [scale priv pub] is the scalar multiplication of [pub] by [priv]. *) 109 | 110 | val public_key_of_private_key: private_key -> public_key 111 | (** [public_key_of_private_key priv] is equal to [scale priv base] *) 112 | end 113 | 114 | (** X25519 (based on Curve25519 by Daniel J. Bernstein) 115 | 116 | This curve is considered to have a strength equivalent to 128 bit in a 117 | symmetric cipher. It was proposed in 118 | {{:https://cr.yp.to/ecdh/curve25519-20060209.pdf} Curve25519} by Daniel J. 119 | Bernstein. *) 120 | module X25519: DH 121 | 122 | (** X448 (based on Ed448-Goldilocks by Mike Hamburg) 123 | 124 | This curve is considered to have a strength equivalent to 224 bit in a 125 | symmetric cipher. It was proposed in 126 | {{:https://eprint.iacr.org/2015/625.pdf} Ed448-Goldilocks} by Mike 127 | Hamburg. *) 128 | module X448: DH 129 | 130 | val x25519: priv:string -> pub:string -> string 131 | (** This is a shortcut for using [X25519.scale] without converting keys. *) 132 | 133 | val x448: priv:string -> pub:string -> string 134 | (** This is a shortcut for using [X448.scale] without converting keys. *) 135 | -------------------------------------------------------------------------------- /src/serde.ml: -------------------------------------------------------------------------------- 1 | 2 | let z_of_bytes buf = Bytes.unsafe_to_string buf |> Z.of_bits 3 | 4 | let z_of_hex hex = 5 | let n = String.length hex / 2 in 6 | let buf = Bytes.create n in 7 | let ic = Scanf.Scanning.from_string hex in 8 | for i = 0 to (n - 1) do 9 | Bytes.set buf i @@ Scanf.bscanf ic "%02x" char_of_int 10 | done; 11 | z_of_bytes buf 12 | 13 | let bytes_of_z n z = 14 | let buf = Bytes.create n in 15 | let zbuf = Z.to_bits z in 16 | Bytes.blit_string zbuf 0 buf 0 String.(length zbuf); 17 | buf 18 | 19 | let hex_of_z n z = 20 | let num_hex = 2 * n in 21 | let upper_bound = n - 1 in 22 | let src = Z.format ("%0" ^ string_of_int num_hex ^ "x") z in 23 | let dst = Bytes.create num_hex in 24 | for i = 0 to upper_bound do 25 | Bytes.blit_string src (2*i) dst (2*(upper_bound-i)) 2 26 | done; 27 | (* This is ok because we created the string and will forget it after returning. *) 28 | Bytes.unsafe_to_string dst 29 | -------------------------------------------------------------------------------- /src/serde.mli: -------------------------------------------------------------------------------- 1 | 2 | val z_of_hex: string -> Z.t 3 | val hex_of_z: int -> Z.t -> string 4 | 5 | val z_of_bytes: Bytes.t -> Z.t 6 | val bytes_of_z: int -> Z.t -> Bytes.t 7 | -------------------------------------------------------------------------------- /src/zfield.ml: -------------------------------------------------------------------------------- 1 | 2 | module Zp(P: sig val p: Z.t end): Curve.Field with type t = Z.t = struct 3 | type t = Z.t 4 | 5 | include P 6 | 7 | let zero = Z.zero 8 | let one = Z.one 9 | 10 | let ( + ) x y = Z.erem (Z.add x y) p 11 | let ( * ) x y = Z.erem (Z.mul x y) p 12 | 13 | let double x = x + x 14 | let square x = x * x 15 | 16 | let invert x = Z.invert x p 17 | 18 | let ( / ) x y = x * invert y 19 | let ( - ) x y = Z.(erem (x - y) p) 20 | 21 | end 22 | -------------------------------------------------------------------------------- /test/dune: -------------------------------------------------------------------------------- 1 | (test 2 | (name test_rfc7748) 3 | (libraries rfc7748 oUnit hex) 4 | (modules test_rfc7748) 5 | ) 6 | (test 7 | (name test_misc) 8 | (libraries rfc7748 oUnit) 9 | (modules test_misc) 10 | ) 11 | -------------------------------------------------------------------------------- /test/test_misc.ml: -------------------------------------------------------------------------------- 1 | open OUnit 2 | 3 | open Rfc7748 4 | 5 | let module_suite: (module DH) -> test list = fun m -> 6 | let module M = (val m) in 7 | let check_key_size _ = 8 | assert_equal ~printer:string_of_int 9 | M.((string_of_public_key base |> String.length)) 10 | M.(key_size * 2) 11 | in 12 | let check_base_point _ = 13 | (* TODO: use a random value instead of a made-up one. *) 14 | let priv = M.private_key_of_string @@ String.make M.(key_size * 2) '4' in 15 | assert_equal ~printer:(M.string_of_public_key) 16 | M.(public_key_of_private_key priv) 17 | M.(scale priv base) 18 | in 19 | [ "key_size" >:: check_key_size 20 | ; "base_point" >:: check_base_point] 21 | 22 | let x25519_dh _ = 23 | let base = "09" in 24 | let alice = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" in 25 | let bob = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" in 26 | let shared_secret_alice = x25519 ~priv:alice ~pub:(x25519 ~priv:bob ~pub:base) in 27 | let shared_secret_bob = x25519 ~priv:bob ~pub:(x25519 ~priv:alice ~pub:base) in 28 | assert_equal shared_secret_alice shared_secret_bob; 29 | assert_equal 30 | "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742" 31 | shared_secret_alice 32 | 33 | let x448_dh _ = 34 | let base = "05" in 35 | let alice = "9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b" in 36 | let bob = "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d" in 37 | let shared_secret_alice = x448 ~priv:alice ~pub:(x448 ~priv:bob ~pub:base) in 38 | let shared_secret_bob = x448 ~priv:bob ~pub:(x448 ~priv:alice ~pub:base) in 39 | assert_equal shared_secret_alice shared_secret_bob; 40 | assert_equal 41 | "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d" 42 | shared_secret_alice 43 | 44 | let _ = 45 | "Library_Suite" >::: [ "x25519" >::: module_suite (module X25519) 46 | ; "x25519_dh" >:: x25519_dh 47 | ; "x448" >::: module_suite (module X448) 48 | ; "x448_dh" >:: x448_dh 49 | ] 50 | |> run_test_tt_main 51 | -------------------------------------------------------------------------------- /test/test_rfc7748.ml: -------------------------------------------------------------------------------- 1 | open OUnit 2 | 3 | open Rfc7748 4 | 5 | (* Simple input-to-output tests based on RFC 7748, Section 5.2. *) 6 | 7 | type case = {priv: string; pub: string; exp: string} 8 | 9 | (* It would be nice to use Hex.to_bytes, but this is only supported after 10 | * Hex >= 1.3.0. Alternatively, we could [opam update] in the integration 11 | * tests, but implementing it here seems easy enough. *) 12 | let to_bytes hex = 13 | Hex.to_string (`Hex hex) |> Bytes.of_string 14 | 15 | let black_box_test: (module DH) -> case -> test_fun = fun m {priv; pub; exp} _ -> 16 | let module M = (val m) in 17 | let out = M.scale (M.private_key_of_string priv) (M.public_key_of_string pub) 18 | |> M.string_of_public_key 19 | in 20 | assert_equal exp out; 21 | let priv = to_bytes priv |> M.private_key_of_bytes in 22 | let pub = to_bytes pub |> M.public_key_of_bytes in 23 | let `Hex out = M.scale priv pub |> M.bytes_of_public_key |> Bytes.to_string |> Hex.of_string in 24 | assert_equal exp out 25 | 26 | let x25519_simple = 27 | [ { priv="a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4" 28 | ; pub="e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c" 29 | ; exp="c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552"} 30 | ; { priv="4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d" 31 | ; pub="e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493" 32 | ; exp="95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957"}] 33 | |> List.map @@ black_box_test (module X25519) 34 | |> List.map @@ fun f -> "simple" >:: f 35 | 36 | let x448_simple = 37 | [ { priv="3d262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3" 38 | ; pub="06fce640fa3487bfda5f6cf2d5263f8aad88334cbd07437f020f08f9814dc031ddbdc38c19c6da2583fa5429db94ada18aa7a7fb4ef8a086" 39 | ; exp="ce3e4ff95a60dc6697da1db1d85e6afbdf79b50a2412d7546d5f239fe14fbaadeb445fc66a01b0779d98223961111e21766282f73dd96b6f"} 40 | ; { priv="203d494428b8399352665ddca42f9de8fef600908e0d461cb021f8c538345dd77c3e4806e25f46d3315c44e0a5b4371282dd2c8d5be3095f" 41 | ; pub="0fbcc2f993cd56d3305b0b7d9e55d4c1a8fb5dbb52f8e9a1e9b6201b165d015894e56c4d3570bee52fe205e28a78b91cdfbde71ce8d157db" 42 | ; exp="884a02576239ff7a2f2f63b2db6a9ff37047ac13568e1e30fe63c4a7ad1b3ee3a5700df34321d62077e63633c575c1c954514e99da7c179d"}] 43 | |> List.map @@ black_box_test (module X448) 44 | |> List.map @@ fun f -> "simple" >:: f 45 | 46 | 47 | (* Repeated iteration based on RFC 7748, Section 5.2. *) 48 | 49 | type case2 = {start: string; iter: int; exp: string} 50 | 51 | let black_box_test: (module DH) -> case2 -> test_fun = fun m {start; iter; exp} _ -> 52 | let module M = (val m) in 53 | let rec apply k u = function 54 | | 0 -> k 55 | | n -> 56 | let pub = M.public_key_of_bytes u in 57 | let priv = M.private_key_of_bytes k in 58 | apply (M.scale priv pub |> M.bytes_of_public_key) k (n - 1) 59 | in 60 | let start = to_bytes start in 61 | let out = apply start start iter in 62 | let `Hex out = Bytes.to_string out |> Hex.of_string in 63 | assert_equal exp out 64 | 65 | let x25519_rep = 66 | [ { start="0900000000000000000000000000000000000000000000000000000000000000" 67 | ; iter=1 68 | ; exp="422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079"} 69 | ; { start="0900000000000000000000000000000000000000000000000000000000000000" 70 | ; iter=1000 71 | ; exp="684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51"} 72 | (* implementation is too slow to run this within a reasonable time frame 73 | ; { start="0900000000000000000000000000000000000000000000000000000000000000" 74 | ; iter=1000000 75 | ; exp="7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424"} 76 | *) 77 | ] 78 | |> List.map @@ black_box_test (module X25519) 79 | |> List.map @@ fun f -> "repeated" >:: f 80 | 81 | let x448_rep = 82 | [ { start="0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 83 | ; iter=1 84 | ; exp="3f482c8a9f19b01e6c46ee9711d9dc14fd4bf67af30765c2ae2b846a4d23a8cd0db897086239492caf350b51f833868b9bc2b3bca9cf4113"} 85 | ; { start="0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 86 | ; iter=1000 87 | ; exp="aa3b4749d55b9daf1e5b00288826c467274ce3ebbdd5c17b975e09d4af6c67cf10d087202db88286e2b79fceea3ec353ef54faa26e219f38"} 88 | (* implementation is too slow to run this within a reasonable time frame 89 | ; { start="0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 90 | ; iter=1000000 91 | ; exp="077f453681caca3693198420bbe515cae0002472519b3e67661a7e89cab94695c8f4bcd66e61b9b9c946da8d524de3d69bd9d9d66b997e37"} 92 | *) 93 | ] 94 | |> List.map @@ black_box_test (module X448) 95 | |> List.map @@ fun f -> "repeated" >:: f 96 | 97 | (* Use for Diffie-Hellman based on RFC 7748, Section 6.1f *) 98 | 99 | type case3 = {a: string; b: string; exp: string} 100 | 101 | let diffie_hellman_test: (module DH) -> case3 -> test_fun = fun m {a; b; exp} _ -> 102 | let module M = (val m) in 103 | let dh priv_a priv_b = 104 | let pub_b = M.(private_key_of_string priv_b |> public_key_of_private_key) in 105 | M.(scale (private_key_of_string priv_a) pub_b |> string_of_public_key) 106 | in 107 | assert_equal (dh a b) (dh b a); 108 | assert_equal exp (dh a b) 109 | 110 | let x25519_dh = 111 | "x25519_dh" >:: diffie_hellman_test (module X25519) 112 | { a="77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a" 113 | ; b="5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb" 114 | ; exp="4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742"} 115 | 116 | let x448_dh = 117 | "x448_dh" >:: diffie_hellman_test (module X448) 118 | { a="9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b" 119 | ; b="1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d" 120 | ; exp="07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d"} 121 | 122 | 123 | let _ = 124 | "Rfc7748_Suite" >::: [ "X25519" >::: x25519_dh :: x25519_simple @ x25519_rep 125 | ; "X448" >::: x448_dh :: x448_simple @ x448_rep ] 126 | |> run_test_tt_main 127 | --------------------------------------------------------------------------------