diff --git a/LICENSE b/LICENSE index 33ed368..d94fdb5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2017 Isis Agora Lovecruft, Henry de Valence. All rights reserved. +Copyright (c) 2016-2018 Isis Agora Lovecruft, Henry de Valence. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are diff --git a/README.md b/README.md index ddf4283..4c7353c 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,10 @@ prime-order group from a non-prime-order Edwards curve. This provides the speed and safety benefits of Edwards curve arithmetic, without the pitfalls of cofactor-related abstraction mismatches. -## WARNING +## Stability -We do not yet consider this code to be production-ready. We intend to -stabilize a production-ready version `1.0` soon. +We have recently released a `1.0.0-pre.0` version of `curve25519-dalek` and +would greatly appreciate testing and feedback on our API and performance. # Documentation @@ -59,13 +59,8 @@ extern crate curve25519_dalek; # Backends and Features -The `yolocrypto` feature enables experimental features. The name `yolocrypto` -is meant to indicate that it is not considered production-ready, and we do not -consider `yolocrypto` features to be covered by semver guarantees. - -The `std` feature is enabled by default, but it can be disabled. - -The `nightly` feature enables nightly-only features. **It is recommended for security**. +The `nightly` feature enables features available only when using a Rust nightly +compiler. **It is recommended for security**. Curve arithmetic is implemented using one of the following backends: @@ -83,6 +78,11 @@ cargo build --no-default-features --features "std avx2_backend" Crates using `curve25519-dalek` can either select a backend on behalf of their users, or expose feature flags that control the `curve25519-dalek` backend. +The `std` feature is enabled by default, but it can be disabled for no-`std` +builds using `--no-default-features`. Note that this requires explicitly +selecting an arithmetic backend using one of the `_backend` features. +If no backend is selected, compilation will fail. + Benchmarks are run using [`criterion.rs`][criterion]: ```sh @@ -93,6 +93,13 @@ cargo bench --no-default-features --features "std u64_backend" cargo bench --no-default-features --features "std avx2_backend" ``` +The `yolocrypto` feature enables experimental features. The name `yolocrypto` +is meant to indicate that it is not considered production-ready, and we do not +consider `yolocrypto` features to be covered by semver guarantees. +This is designed to make it easier to test intended new features +without having to stabilise them first. Use `yolocrypto` at your own, +obvious, risk. + # Contributing Please see [CONTRIBUTING.md][contributing]. @@ -123,7 +130,8 @@ turn a port of the reference `ref10` implementation. Most of this code, including the 32-bit field arithmetic, has since been rewritten. The fast `u32` and `u64` scalar arithmetic was implemented by Andrew Moon, and -the addition chain for scalar inversion was provided by Brian Smith. +the addition chain for scalar inversion was provided by Brian Smith. The +optimised batch inversion was contributed by Sean Bowe and Daira Hopwood. The `no_std` support was contributed by Tony Arcieri. diff --git a/src/backend/avx2/constants.rs b/src/backend/avx2/constants.rs index 304a1be..fa31c9d 100644 --- a/src/backend/avx2/constants.rs +++ b/src/backend/avx2/constants.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/avx2/edwards.rs b/src/backend/avx2/edwards.rs index 43f02f7..d9f0b01 100644 --- a/src/backend/avx2/edwards.rs +++ b/src/backend/avx2/edwards.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/avx2/field.rs b/src/backend/avx2/field.rs index 175ff14..173d28e 100644 --- a/src/backend/avx2/field.rs +++ b/src/backend/avx2/field.rs @@ -1,7 +1,7 @@ // -*- mode: rust; coding: utf-8; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/avx2/mod.rs b/src/backend/avx2/mod.rs index b13ea1d..14a2fcb 100644 --- a/src/backend/avx2/mod.rs +++ b/src/backend/avx2/mod.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/mod.rs b/src/backend/mod.rs index aa44d52..d325715 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/u32/constants.rs b/src/backend/u32/constants.rs index f68f662..e0e0525 100644 --- a/src/backend/u32/constants.rs +++ b/src/backend/u32/constants.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/u32/field.rs b/src/backend/u32/field.rs index 8c65a46..9de460a 100644 --- a/src/backend/u32/field.rs +++ b/src/backend/u32/field.rs @@ -1,7 +1,7 @@ // -*- mode: rust; coding: utf-8; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/u32/mod.rs b/src/backend/u32/mod.rs index bc1148e..4d6bc8b 100644 --- a/src/backend/u32/mod.rs +++ b/src/backend/u32/mod.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/u64/constants.rs b/src/backend/u64/constants.rs index 20ecb7f..0ac7fe3 100644 --- a/src/backend/u64/constants.rs +++ b/src/backend/u64/constants.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/u64/field.rs b/src/backend/u64/field.rs index d685ff3..25a013e 100644 --- a/src/backend/u64/field.rs +++ b/src/backend/u64/field.rs @@ -1,7 +1,7 @@ // -*- mode: rust; coding: utf-8; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/backend/u64/mod.rs b/src/backend/u64/mod.rs index a72dc0f..d329a89 100644 --- a/src/backend/u64/mod.rs +++ b/src/backend/u64/mod.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/constants.rs b/src/constants.rs index fd8298c..c990b09 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/curve_models/mod.rs b/src/curve_models/mod.rs index a88c37d..45c2919 100644 --- a/src/curve_models/mod.rs +++ b/src/curve_models/mod.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/edwards.rs b/src/edwards.rs index 5f03929..1fb4d07 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/field.rs b/src/field.rs index c9f4c49..2241c13 100644 --- a/src/field.rs +++ b/src/field.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/lib.rs b/src/lib.rs index 70f80f5..c28ff31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/macros.rs b/src/macros.rs index 448d32c..3ec9d77 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/montgomery.rs b/src/montgomery.rs index 0b8450d..0c21b00 100644 --- a/src/montgomery.rs +++ b/src/montgomery.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/ristretto.rs b/src/ristretto.rs index 78cd178..5581a19 100644 --- a/src/ristretto.rs +++ b/src/ristretto.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/scalar.rs b/src/scalar.rs index 7e02637..945691c 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // Portions Copyright 2017 Brian Smith // See LICENSE for licensing information. // @@ -11,6 +11,132 @@ // - Brian Smith //! Arithmetic on scalars (integers mod the group order). +//! +//! Both the Ristretto group and the Ed25519 basepoint have prime order +//! \\( \ell = 2\^{252} + 27742317777372353535851937790883648493 \\). +//! +//! This code is intended to be useful with both the Ristretto group +//! (where everything is done modulo \\( \ell \\)), and the X/Ed25519 +//! setting, which mandates specific bit-twiddles that are not +//! well-defined modulo \\( \ell \\). +//! +//! All arithmetic on `Scalars` is done modulo \\( \ell \\). +//! +//! # Constructing a scalar +//! +//! To create a [`Scalar`](struct.Scalar.html) from a supposedly canonical encoding, use +//! [`Scalar::from_canonical_bytes`](struct.Scalar.html#method.from_canonical_bytes). +//! +//! This function does input validation, ensuring that the input bytes +//! are the canonical encoding of a `Scalar`. +//! If they are, we'll get +//! `Some(Scalar)` in return: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let one_as_bytes: [u8; 32] = Scalar::one().to_bytes(); +//! let a: Option = Scalar::from_canonical_bytes(one_as_bytes); +//! +//! assert!(a.is_some()); +//! ``` +//! +//! However, if we give it bytes representing a scalar larger than \\( \ell \\) +//! (in this case, \\( \ell + 2 \\)), we'll get `None` back: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Option = Scalar::from_canonical_bytes(l_plus_two_bytes); +//! +//! assert!(a.is_none()); +//! ``` +//! +//! Another way to create a `Scalar` is by reducing a \\(256\\)-bit integer mod +//! \\( \ell \\), for which one may use the +//! [`Scalar::from_bytes_mod_order`](struct.Scalar.html#method.from_bytes_mod_order) +//! method. In the case of the second example above, this would reduce the +//! resultant scalar \\( \mod \ell \\), producing \\( 2 \\): +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Scalar = Scalar::from_bytes_mod_order(l_plus_two_bytes); +//! +//! let two: Scalar = Scalar::one() + Scalar::one(); +//! +//! assert!(a == two); +//! ``` +//! +//! There is also a constructor that reduces a \\(512\\)-bit integer, +//! [`Scalar::from_bytes_mod_order_wide`](struct.Scalar.html#method.from_bytes_mod_order_wide). +//! +//! To construct a `Scalar` as the hash of some input data, use +//! [`Scalar::hash_from_bytes`](struct.Scalar.html#method.hash_from_bytes), +//! which takes a buffer, or +//! [`Scalar::from_hash`](struct.Scalar.html#method.from_hash), +//! which allows an IUF API. +//! +//! ``` +//! # extern crate curve25519_dalek; +//! # extern crate sha2; +//! # +//! # fn main() { +//! use sha2::{Digest, Sha512}; +//! use curve25519_dalek::scalar::Scalar; +//! +//! // Hashing a single byte slice +//! let a = Scalar::hash_from_bytes::(b"Abolish ICE"); +//! +//! // Streaming data into a hash object +//! let mut hasher = Sha512::default(); +//! hasher.input(b"Abolish "); +//! hasher.input(b"ICE"); +//! let a2 = Scalar::from_hash(hasher); +//! +//! assert_eq!(a, a2); +//! # } +//! ``` +//! +//! Finally, to create a `Scalar` with a specific bit-pattern +//! (e.g., for compatibility with X/Ed25519 +//! ["clamping"](https://github.com/isislovecruft/ed25519-dalek/blob/f790bd2ce/src/ed25519.rs#L349)), +//! use [`Scalar::from_bits`](struct.Scalar.html#method.from_bits). This +//! constructs a scalar with exactly the bit pattern given, without any +//! assurances as to reduction modulo the group order: +//! +//! ``` +//! use curve25519_dalek::scalar::Scalar; +//! +//! let l_plus_two_bytes: [u8; 32] = [ +//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, +//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, +//! ]; +//! let a: Scalar = Scalar::from_bits(l_plus_two_bytes); +//! +//! let two: Scalar = Scalar::one() + Scalar::one(); +//! +//! assert!(a != two); // the scalar is not reduced (mod l)… +//! assert!(! a.is_canonical()); // …and therefore is not canonical. +//! assert!(a.reduce() == two); // if we were to reduce it manually, it would be. +//! ``` +//! +//! The resulting `Scalar` has exactly the specified bit pattern, +//! **except for the highest bit, which will be set to 0**. use core::fmt::Debug; use core::ops::Neg; @@ -51,38 +177,20 @@ type UnpackedScalar = backend::u32::scalar::Scalar32; /// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which /// represents an element of \\(\mathbb Z / \ell\\). -/// -/// Both the Ristretto group and the Ed25519 basepoint have prime order -/// \\( \ell = 2\^{252} + 27742317777372353535851937790883648493 \\). -/// -/// The code is intended to be useful with both the Ristretto group -/// (where everything is done modulo \\( \ell \\)), and the X/Ed25519 -/// setting, which mandates specific bit-twiddles that are not -/// well-defined modulo \\( \ell \\). -/// -/// To create a `Scalar` from a supposedly canonical encoding, use -/// `Scalar::from_canonical_bytes`. -/// -/// To create a `Scalar` by reducing a \\(256\\)-bit integer mod \\( \ell \\), -/// use `Scalar::from_bytes_mod_order`. -/// -/// To create a `Scalar` by reducing a \\(512\\)-bit integer mod \\( \ell \\), -/// use `Scalar::from_bytes_mod_order_wide`. -/// -/// To create a `Scalar` with a specific bit-pattern (e.g., for -/// compatibility with X25519 "clamping"), use `Scalar::from_bits`. -/// -/// All arithmetic on `Scalars` is done modulo \\( \ell \\). #[derive(Copy, Clone)] pub struct Scalar { - /// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the group order. + /// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the + /// group order. /// /// # Invariant /// - /// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or equivalently the high bit of `bytes[31]` must be zero. + /// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or + /// equivalently the high bit of `bytes[31]` must be zero. /// /// This ensures that there is room for a carry bit when computing a NAF representation. - // XXX This is pub(crate) so we can write literal constants. If const fns were stable, we could make the Scalar constructors const fns and use those instead. + // + // XXX This is pub(crate) so we can write literal constants. If const fns were stable, we could + // make the Scalar constructors const fns and use those instead. pub(crate) bytes: [u8; 32], } @@ -414,7 +522,43 @@ impl Scalar { Scalar{ bytes: s_bytes } } - /// Compute the multiplicative inverse of this scalar. + /// Given a nonzero `Scalar`, compute its multiplicative inverse. + /// + /// # Warning + /// + /// `self` **MUST** be nonzero. If you cannot + /// *prove* that this is the case, you **SHOULD NOT USE THIS + /// FUNCTION**. + /// + /// # Returns + /// + /// The multiplicative inverse of the this `Scalar`. + /// + /// # Example + /// + /// ``` + /// use curve25519_dalek::scalar::Scalar; + /// + /// // x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 + /// let X: Scalar = Scalar::from_bytes_mod_order([ + /// 0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, + /// 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2, 0x7d, 0x52, + /// 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, + /// 0xd4, 0x49, 0xf4, 0xa8, 0x79, 0xd9, 0xf2, 0x04, + /// ]); + /// // 1/x = 6859937278830797291664592131120606308688036382723378951768035303146619657244 + /// let XINV: Scalar = Scalar::from_bytes_mod_order([ + /// 0x1c, 0xdc, 0x17, 0xfc, 0xe0, 0xe9, 0xa5, 0xbb, + /// 0xd9, 0x24, 0x7e, 0x56, 0xbb, 0x01, 0x63, 0x47, + /// 0xbb, 0xba, 0x31, 0xed, 0xd5, 0xa9, 0xbb, 0x96, + /// 0xd5, 0x0b, 0xcd, 0x7a, 0x3f, 0x96, 0x2a, 0x0f, + /// ]); + /// + /// let inv_X: Scalar = X.invert(); + /// assert!(XINV == inv_X); + /// let should_be_one: Scalar = &inv_X * &X; + /// assert!(should_be_one == Scalar::one()); + /// ``` pub fn invert(&self) -> Scalar { self.unpack().invert().pack() } @@ -440,7 +584,6 @@ impl Scalar { /// # extern crate curve25519_dalek; /// # use curve25519_dalek::scalar::Scalar; /// # fn main() { - /// /// let mut scalars = [ /// Scalar::from_u64(3), /// Scalar::from_u64(5), diff --git a/src/scalar_mul/window.rs b/src/scalar_mul/window.rs index 91ebb65..c116136 100644 --- a/src/scalar_mul/window.rs +++ b/src/scalar_mul/window.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: diff --git a/src/traits.rs b/src/traits.rs index e706348..aac84d0 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1,7 +1,7 @@ // -*- mode: rust; -*- // // This file is part of curve25519-dalek. -// Copyright (c) 2016-2017 Isis Lovecruft, Henry de Valence +// Copyright (c) 2016-2018 Isis Lovecruft, Henry de Valence // See LICENSE for licensing information. // // Authors: