/// 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)); }
///// 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); }
/// 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)); }