/// <summary> /// Decode a binary vector of length n and weight t into a number between 0 and (n|t) (binomial coefficient). /// <para>The result is given as a byte array of length floor[(s+7)/8], where s = floor[log(n|t)].</para> /// </summary> /// /// <param name="N">The "n" integer</param> /// <param name="T">The "t" integer</param> /// <param name="GVector">The binary vector</param> /// /// <returns>The decoded vector as a byte array</returns> public static byte[] Decode(int N, int T, GF2Vector GVector) { if ((GVector.Length != N) || (GVector.HammingWeight() != T)) throw new ArgumentException("vector has wrong length or hamming weight"); int[] vecArray = GVector.VectorArray; BigInteger bc = BigMath.Binomial(N, T); BigInteger d = ZERO; int nn = N; int tt = T; for (int i = 0; i < N; i++) { bc = bc.Multiply(BigInteger.ValueOf(nn - tt)).Divide(BigInteger.ValueOf(nn)); nn--; int q = i >> 5; int e = vecArray[q] & (1 << (i & 0x1f)); if (e != 0) { d = d.Add(bc); tt--; if (nn == tt) bc = ONE; else bc = bc.Multiply(BigInteger.ValueOf(tt + 1)).Divide(BigInteger.ValueOf(nn - tt)); } } return BigIntUtils.ToMinimalByteArray(d); }
/// <summary> /// Return a new vector consisting of the first <c>K</c> elements of this vector /// </summary> /// /// <param name="K">The number of elements to extract</param> /// /// <returns>Returns a new GF2Vector consisting of the first <c>K</c> elements of this vector</returns> public GF2Vector ExtractLeftVector(int K) { if (K > Length) { throw new ArithmeticException("invalid length"); } if (K == Length) { return(new GF2Vector(this)); } GF2Vector result = new GF2Vector(K); int q = K >> 5; int r = K & 0x1f; Array.Copy(_elements, 0, result._elements, 0, q); if (r != 0) { result._elements[q] = _elements[q] & ((1 << r) - 1); } return(result); }
/// <summary> /// Find an error vector <c>E</c> over <c>GF(2)</c> from an input syndrome <c>S</c> over <c>GF(2^M)</c> /// </summary> /// /// <param name="SyndVec">The syndrome</param> /// <param name="Field">The finite field</param> /// <param name="Gp">The irreducible Goppa polynomial</param> /// <param name="SqRootMatrix">The matrix for computing square roots in <c>(GF(2M))<sup>T</sup></c></param> /// /// <returns>The error vector</returns> public static GF2Vector SyndromeDecode(GF2Vector SyndVec, GF2mField Field, PolynomialGF2mSmallM Gp, PolynomialGF2mSmallM[] SqRootMatrix) { int n = 1 << Field.Degree; // the error vector GF2Vector errors = new GF2Vector(n); // if the syndrome vector is zero, the error vector is also zero if (!SyndVec.IsZero()) { // convert syndrome vector to polynomial over GF(2^m) PolynomialGF2mSmallM syndrome = new PolynomialGF2mSmallM(SyndVec.ToExtensionFieldVector(Field)); // compute T = syndrome^-1 mod gp PolynomialGF2mSmallM t = syndrome.ModInverse(Gp); // compute tau = sqRoot(T + X) mod gp PolynomialGF2mSmallM tau = t.AddMonomial(1); tau = tau.ModSquareRootMatrix(SqRootMatrix); // compute polynomials a and b satisfying a + b*tau = 0 mod gp PolynomialGF2mSmallM[] ab = tau.ModPolynomialToFracton(Gp); // compute the polynomial a^2 + X*b^2 PolynomialGF2mSmallM a2 = ab[0].Multiply(ab[0]); PolynomialGF2mSmallM b2 = ab[1].Multiply(ab[1]); PolynomialGF2mSmallM xb2 = b2.MultWithMonomial(1); PolynomialGF2mSmallM a2plusXb2 = a2.Add(xb2); // normalize a^2 + X*b^2 to obtain the error locator polynomial int headCoeff = a2plusXb2.Head; int invHeadCoeff = Field.Inverse(headCoeff); PolynomialGF2mSmallM elp = a2plusXb2.MultWithElement(invHeadCoeff); // for all elements i of GF(2^m) for (int i = 0; i < n; i++) { // evaluate the error locator polynomial at i int z = elp.EvaluateAt(i); // if polynomial evaluates to zero if (z == 0) { // set the i-th coefficient of the error vector errors.SetBit(i); } } } return(errors); }
/// <summary> /// Decides whether the given object <c>other</c> is the same as this field /// </summary> /// /// <param name="Obj">The object for comparison</param> /// /// <returns>Returns <c>(this == other)</c></returns> public override bool Equals(Object Obj) { if (!(Obj is GF2Vector)) { return(false); } GF2Vector otherVec = (GF2Vector)Obj; if (Length != otherVec.Length) { return(false); } if (!Compare.AreEqual(_elements, otherVec._elements)) { return(false); } return(true); }
/// <summary> /// Return a new vector consisting of the last <c>k</c> elements of this vector /// </summary> /// /// <param name="K">The number of elements to extract</param> /// /// <returns>Returns a new GF2Vector consisting of the last <c>K</c> elements of this vector</returns> public GF2Vector ExtractRightVector(int K) { if (K > base.Length) { throw new ArithmeticException("invalid length"); } if (K == base.Length) { return(new GF2Vector(this)); } GF2Vector result = new GF2Vector(K); int q = (base.Length - K) >> 5; int r = (base.Length - K) & 0x1f; int length = (K + 31) >> 5; int ind = q; // if words have to be shifted if (r != 0) { // process all but last word for (int i = 0; i < length - 1; i++) { result._elements[i] = (IntUtils.URShift(_elements[ind++], r)) | (_elements[ind] << (32 - r)); } // process last word result._elements[length - 1] = IntUtils.URShift(_elements[ind++], r); if (ind < _elements.Length) { result._elements[length - 1] |= _elements[ind] << (32 - r); } } else { // no shift necessary Array.Copy(_elements, q, result._elements, 0, length); } return(result); }
/// <summary> /// Multiply this vector with a permutation /// </summary> /// /// <param name="P">The permutation</param> /// /// <returns>Returns <c>this*p = p*this</c></returns> public override Vector Multiply(Permutation P) { int[] pVec = P.GetVector(); if (Length != pVec.Length) { throw new ArithmeticException("GF2Vector: Length mismatch!"); } GF2Vector result = new GF2Vector(Length); for (int i = 0; i < pVec.Length; i++) { int e = _elements[pVec[i] >> 5] & (1 << (pVec[i] & 0x1f)); if (e != 0) { result._elements[i >> 5] |= 1 << (i & 0x1f); } } return(result); }
/// <summary> /// Return a new vector consisting of the elements of this vector with the indices given by the set <c>SetJ</c> /// </summary> /// /// <param name="SetJ">The set of indices of elements to extract</param> /// /// <returns>Return the new GF2Vector <c>[SetJ[0], SetJ[1], ..., SetJ[#SetJ-1]]</c></returns> public GF2Vector ExtractVector(int[] SetJ) { int k = SetJ.Length; if (SetJ[k - 1] > Length) { throw new ArithmeticException("invalid index set"); } GF2Vector result = new GF2Vector(k); for (int i = 0; i < k; i++) { int e = _elements[SetJ[i] >> 5] & (1 << (SetJ[i] & 0x1f)); if (e != 0) { result._elements[i >> 5] |= 1 << (i & 0x1f); } } return(result); }
/// <summary> /// Adds another GF2Vector to this vector /// </summary> /// /// <param name="V">The GF2Vector to add</param> /// /// <returns>Returns <c>this + V</c></returns> public override Vector Add(Vector V) { if (!(V is GF2Vector)) { throw new ArithmeticException("GF2Vector: Vector is not defined over GF(2)!"); } GF2Vector otherVec = (GF2Vector)V; if (Length != otherVec.Length) { throw new ArithmeticException("GF2Vector: Length mismatch!"); } int[] vec = IntUtils.DeepCopy(((GF2Vector)V)._elements); for (int i = vec.Length - 1; i >= 0; i--) { vec[i] ^= _elements[i]; } return(new GF2Vector(Length, vec)); }
/// <summary> /// Return a new vector consisting of the first <c>K</c> elements of this vector /// </summary> /// /// <param name="K">The number of elements to extract</param> /// /// <returns>Returns a new GF2Vector consisting of the first <c>K</c> elements of this vector</returns> public GF2Vector ExtractLeftVector(int K) { if (K > Length) throw new ArithmeticException("invalid length"); if (K == Length) return new GF2Vector(this); GF2Vector result = new GF2Vector(K); int q = K >> 5; int r = K & 0x1f; Array.Copy(_elements, 0, result._elements, 0, q); if (r != 0) result._elements[q] = _elements[q] & ((1 << r) - 1); return result; }
/// <summary> /// Encrypt a plain text message /// </summary> /// /// <param name="Input">The plain text</param> /// /// <returns>The cipher text</returns> public byte[] Encrypt(byte[] Input) { // generate random vector r of length k bits GF2Vector r = new GF2Vector(_K, _secRnd); // convert r to byte array byte[] rBytes = r.GetEncoded(); // compute (r||input) byte[] rm = ByteUtils.Concatenate(rBytes, Input); // compute H(r||input) _dgtEngine.BlockUpdate(rm, 0, rm.Length); byte[] hrm = new byte[_dgtEngine.DigestSize]; _dgtEngine.DoFinal(hrm, 0); // convert H(r||input) to error vector z GF2Vector z = CCA2Conversions.Encode(_N, _T, hrm); // compute c1 = E(r, z) byte[] c1 = CCA2Primitives.Encrypt((MPKCPublicKey)_keyPair.PublicKey, r, z).GetEncoded(); byte[] c2; // get PRNG object using (KDF2Drbg sr0 = new KDF2Drbg(GetDigest(_cipherParams.Digest))) { // seed PRNG with r' sr0.Initialize(rBytes); // generate random c2 c2 = new byte[Input.Length]; sr0.Generate(c2); } // XOR with input for (int i = 0; i < Input.Length; i++) c2[i] ^= Input[i]; // return (c1||c2) return ByteUtils.Concatenate(c1, c2); }
/// <summary> /// Find an error vector <c>E</c> over <c>GF(2)</c> from an input syndrome <c>S</c> over <c>GF(2^M)</c> /// </summary> /// /// <param name="SyndVec">The syndrome</param> /// <param name="Field">The finite field</param> /// <param name="Gp">The irreducible Goppa polynomial</param> /// <param name="SqRootMatrix">The matrix for computing square roots in <c>(GF(2M))<sup>T</sup></c></param> /// /// <returns>The error vector</returns> public static GF2Vector SyndromeDecode(GF2Vector SyndVec, GF2mField Field, PolynomialGF2mSmallM Gp, PolynomialGF2mSmallM[] SqRootMatrix) { int n = 1 << Field.Degree; // the error vector GF2Vector errors = new GF2Vector(n); // if the syndrome vector is zero, the error vector is also zero if (!SyndVec.IsZero()) { // convert syndrome vector to polynomial over GF(2^m) PolynomialGF2mSmallM syndrome = new PolynomialGF2mSmallM(SyndVec.ToExtensionFieldVector(Field)); // compute T = syndrome^-1 mod gp PolynomialGF2mSmallM t = syndrome.ModInverse(Gp); // compute tau = sqRoot(T + X) mod gp PolynomialGF2mSmallM tau = t.AddMonomial(1); tau = tau.ModSquareRootMatrix(SqRootMatrix); // compute polynomials a and b satisfying a + b*tau = 0 mod gp PolynomialGF2mSmallM[] ab = tau.ModPolynomialToFracton(Gp); // compute the polynomial a^2 + X*b^2 PolynomialGF2mSmallM a2 = ab[0].Multiply(ab[0]); PolynomialGF2mSmallM b2 = ab[1].Multiply(ab[1]); PolynomialGF2mSmallM xb2 = b2.MultWithMonomial(1); PolynomialGF2mSmallM a2plusXb2 = a2.Add(xb2); // normalize a^2 + X*b^2 to obtain the error locator polynomial int headCoeff = a2plusXb2.Head; int invHeadCoeff = Field.Inverse(headCoeff); PolynomialGF2mSmallM elp = a2plusXb2.MultWithElement(invHeadCoeff); // for all elements i of GF(2^m) for (int i = 0; i < n; i++) { // evaluate the error locator polynomial at i int z = elp.EvaluateAt(i); // if polynomial evaluates to zero if (z == 0) { // set the i-th coefficient of the error vector errors.SetBit(i); } } } return errors; }
/// <summary> /// Multiply this vector with a permutation /// </summary> /// /// <param name="P">The permutation</param> /// /// <returns>Returns <c>this*p = p*this</c></returns> public override Vector Multiply(Permutation P) { int[] pVec = P.GetVector(); if (Length != pVec.Length) throw new ArithmeticException("GF2Vector: Length mismatch!"); GF2Vector result = new GF2Vector(Length); for (int i = 0; i < pVec.Length; i++) { int e = _elements[pVec[i] >> 5] & (1 << (pVec[i] & 0x1f)); if (e != 0) result._elements[i >> 5] |= 1 << (i & 0x1f); } return result; }
/// <summary> /// Return a new vector consisting of the elements of this vector with the indices given by the set <c>SetJ</c> /// </summary> /// /// <param name="SetJ">The set of indices of elements to extract</param> /// /// <returns>Return the new GF2Vector <c>[SetJ[0], SetJ[1], ..., SetJ[#SetJ-1]]</c></returns> public GF2Vector ExtractVector(int[] SetJ) { int k = SetJ.Length; if (SetJ[k - 1] > Length) throw new ArithmeticException("invalid index set"); GF2Vector result = new GF2Vector(k); for (int i = 0; i < k; i++) { int e = _elements[SetJ[i] >> 5] & (1 << (SetJ[i] & 0x1f)); if (e != 0) result._elements[i >> 5] |= 1 << (i & 0x1f); } return result; }
/// <summary> /// Return a new vector consisting of the last <c>k</c> elements of this vector /// </summary> /// /// <param name="K">The number of elements to extract</param> /// /// <returns>Returns a new GF2Vector consisting of the last <c>K</c> elements of this vector</returns> public GF2Vector ExtractRightVector(int K) { if (K > base.Length) throw new ArithmeticException("invalid length"); if (K == base.Length) return new GF2Vector(this); GF2Vector result = new GF2Vector(K); int q = (base.Length - K) >> 5; int r = (base.Length - K) & 0x1f; int length = (K + 31) >> 5; int ind = q; // if words have to be shifted if (r != 0) { // process all but last word for (int i = 0; i < length - 1; i++) result._elements[i] = (IntUtils.URShift(_elements[ind++], r)) | (_elements[ind] << (32 - r)); // process last word result._elements[length - 1] = IntUtils.URShift(_elements[ind++], r); if (ind < _elements.Length) result._elements[length - 1] |= _elements[ind] << (32 - r); } else { // no shift necessary Array.Copy(_elements, q, result._elements, 0, length); } return result; }
/// <summary> /// Copy constructor /// </summary> /// /// <param name="G">The GF2Vector to copy</param> public GF2Vector(GF2Vector G) { this.Length = G.Length; this._elements = IntUtils.DeepCopy(G._elements); }
/// <summary> /// Encode a number between 0 and (n|t) (binomial coefficient) into a binary vector of length n with weight t. /// <para>The number is given as a byte array. Only the first s bits are used, where s = floor[log(n|t)].</para> /// </summary> /// /// <param name="N">The "n" integer</param> /// <param name="T">The "t" integer</param> /// <param name="M">The message as a byte array</param> /// /// <returns>The encoded message as GF2Vector</returns> public static GF2Vector Encode(int N, int T, byte[] M) { if (N < T) throw new ArgumentException("n < t"); // compute the binomial c = (n|t) BigInteger c = BigMath.Binomial(N, T); // get the number encoded in m BigInteger i = new BigInteger(1, M); // compare if (i.CompareTo(c) >= 0) throw new ArgumentException("Encoded number too large."); GF2Vector result = new GF2Vector(N); int nn = N; int tt = T; for (int j = 0; j < N; j++) { c = c.Multiply(BigInteger.ValueOf(nn - tt)).Divide(BigInteger.ValueOf(nn)); nn--; if (c.CompareTo(i) <= 0) { result.SetBit(j); i = i.Subtract(c); tt--; if (nn == tt) c = ONE; else c = (c.Multiply(BigInteger.ValueOf(tt + 1))).Divide(BigInteger.ValueOf(nn - tt)); } } return result; }