Example #1
0
        /// Reduce a 64 byte / 512 bit scalar mod l
        public static UnpackedScalar from_bytes_wide(byte[] bytes)
        {
            var words = new ulong[8];

            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    words[i] |= ((ulong)bytes[(i * 8) + j]) << (j * 8);
                }
            }



            var mask = (((ulong)1) << 52) - 1;
            var lo   = UnpackedScalar.zero();
            var hi   = UnpackedScalar.zero();

            var los = lo.value.Span;
            var his = hi.value.Span;


            los[0] = words[0] & mask;
            los[1] = ((words[0] >> 52) | (words[1] << 12)) & mask;
            los[2] = ((words[1] >> 40) | (words[2] << 24)) & mask;
            los[3] = ((words[2] >> 28) | (words[3] << 36)) & mask;
            los[4] = ((words[3] >> 16) | (words[4] << 48)) & mask;
            his[0] = (words[4] >> 4) & mask;
            his[1] = ((words[4] >> 56) | (words[5] << 8)) & mask;
            his[2] = ((words[5] >> 44) | (words[6] << 20)) & mask;
            his[3] = ((words[6] >> 32) | (words[7] << 32)) & mask;
            his[4] = words[7] >> 20;

            lo = UnpackedScalar.montgomery_mul(lo, Constant.R);  // (lo * R) / R = lo
            hi = UnpackedScalar.montgomery_mul(hi, Constant.RR); // (hi * R^2) / R = hi * R

            return(UnpackedScalar.add(hi, lo));
        }
Example #2
0
        ///// Given a slice of nonzero (possibly secret) `Scalar`s,
        ///// compute their inverses in a batch.
        /////
        ///// # Return
        /////
        ///// Each element of `inputs` is replaced by its inverse.
        /////
        ///// The product of all inverses is returned.
        /////
        ///// # Warning
        /////
        ///// All input `Scalars` **MUST** be nonzero.  If you cannot
        ///// *prove* that this is the case, you **SHOULD NOT USE THIS
        ///// FUNCTION**.
        /////
        ///// # Example
        /////
        ///// ```
        ///// # extern crate curve25519_dalek;
        ///// # use curve25519_dalek::scalar::Scalar;
        ///// # fn main() {
        ///// let mut scalars = [
        /////     Scalar::from(3u64),
        /////     Scalar::from(5u64),
        /////     Scalar::from(7u64),
        /////     Scalar::from(11u64),
        ///// ];
        /////
        ///// let allinv = Scalar::batch_invert(&mut scalars);
        /////
        ///// assert_eq!(allinv, Scalar::from(3*5*7*11u64).invert());
        ///// assert_eq!(scalars[0], Scalar::from(3u64).invert());
        ///// assert_eq!(scalars[1], Scalar::from(5u64).invert());
        ///// assert_eq!(scalars[2], Scalar::from(7u64).invert());
        ///// assert_eq!(scalars[3], Scalar::from(11u64).invert());
        ///// # }
        ///// ```

        public static Scalar batch_invert(Scalar[] inputs)
        {
            // This code is essentially identical to the FieldElement
            // implementation, and is documented there.  Unfortunately,
            // it's not easy to write it generically, since here we want
            // to use `UnpackedScalar`s internally, and `Scalar`s
            // externally, but there's no corresponding distinction for
            // field elements.

            //use clear_on_drop::ClearOnDrop;
            //use clear_on_drop::clear::ZeroSafe;
            // Mark UnpackedScalars as zeroable.
            //unsafe impl ZeroSafe for UnpackedScalar {}

            var n   = inputs.Length;
            var one = Scalar.one().unpack().to_montgomery();

            // Wrap the scratch storage in a ClearOnDrop to wipe it when
            // we pass out of scope.
            Span <Scalar> scratch_vec = new Scalar[n];

            scratch_vec.Fill(Scalar.one());

            // Keep an accumulator of all of the previous products
            var acc = Scalar.one().unpack().to_montgomery();

            // Pass through the input vector, recording the previous
            // products in the scratch space

            for (int i = 0; i < n; i++)
            {
                var input = scratch_vec[n];
                //scratch = acc;

                // Avoid unnecessary Montgomery multiplication in second pass by
                // keeping inputs in Montgomery form
                var tmp = input.unpack().to_montgomery();
                input = tmp.pack();
                acc   = UnpackedScalar.montgomery_mul(acc, tmp);
            }

            // acc is nonzero iff all inputs are nonzero
            Debug.Assert(acc.pack() != zero());

            // Compute the inverse of all products
            acc = acc.montgomery_invert().from_montgomery();

            // We need to return the product of all inverses later
            var ret = acc.pack();

            // Pass through the vector backwards to compute the inverses
            // in place

            for (int i = 0; i < n; i++)
            {
                var scratch = scratch_vec[n];
                var input   = inputs[n];
                var tmp     = UnpackedScalar.montgomery_mul(acc, input.unpack());
                input = UnpackedScalar.montgomery_mul(acc, scratch.unpack()).pack();
                acc   = tmp;
            }

            return(ret);
        }
Example #3
0
        /// Puts a Scalar64 in to Montgomery form, i.e. computes `a*R (mod l)`

        public UnpackedScalar to_montgomery()
        {
            return(UnpackedScalar.montgomery_mul(this, Constant.RR));
        }