/// <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(m_elements, 0, result.m_elements, 0, q); if (r != 0) { result.m_elements[q] = m_elements[q] & ((1 << r) - 1); } return(result); }
/// <summary> /// The McEliece encryption primitive /// </summary> /// /// <param name="PublicKey">The public key</param> /// <param name="M">The message vector</param> /// <param name="Z">The error vector</param> /// /// <returns><c>m*G + z</c></returns> public static GF2Vector Encrypt(MPKCPublicKey PublicKey, GF2Vector M, GF2Vector Z) { GF2Matrix matrixG = PublicKey.G; Vector mG = matrixG.LeftMultiplyLeftCompactForm(M); return (GF2Vector)mG.Add(Z); }
/// <summary> /// The McEliece decryption primitive /// </summary> /// /// <param name="PrivateKey">The private key</param> /// <param name="C">The ciphertext vector <c>c = m*G + z</c></param> /// /// <returns>The message vector <c>m</c> and the error vector <c>z</c></returns> public static GF2Vector[] Decrypt(MPKCPrivateKey PrivateKey, GF2Vector C) { // obtain values from private key int k = PrivateKey.K; Permutation p = PrivateKey.P1; GF2mField field = PrivateKey.GF; PolynomialGF2mSmallM gp = PrivateKey.GP; GF2Matrix h = PrivateKey.H; PolynomialGF2mSmallM[] q = PrivateKey.QInv; // compute inverse permutation P^-1 Permutation pInv = p.ComputeInverse(); // multiply c with permutation P^-1 GF2Vector cPInv = (GF2Vector)C.Multiply(pInv); // compute syndrome of cP^-1 GF2Vector syndVec = (GF2Vector)h.RightMultiply(cPInv); // decode syndrome GF2Vector errors = GoppaCode.SyndromeDecode(syndVec, field, gp, q); GF2Vector mG = (GF2Vector)cPInv.Add(errors); // multiply codeword and error vector with P mG = (GF2Vector)mG.Multiply(p); errors = (GF2Vector)errors.Multiply(p); // extract plaintext vector (last k columns of mG) GF2Vector m = mG.ExtractRightVector(k); // return vectors return new GF2Vector[] { m, errors }; }
/// <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.IsEqual(m_elements, otherVec.m_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.m_elements[i] = (IntUtils.URShift(m_elements[ind++], r)) | (m_elements[ind] << (32 - r)); } // process last word result.m_elements[length - 1] = IntUtils.URShift(m_elements[ind++], r); if (ind < m_elements.Length) { result.m_elements[length - 1] |= m_elements[ind] << (32 - r); } } else { // no shift necessary Array.Copy(m_elements, q, result.m_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 = m_elements[pVec[i] >> 5] & (1 << (pVec[i] & 0x1f)); if (e != 0) { result.m_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 = m_elements[SetJ[i] >> 5] & (1 << (SetJ[i] & 0x1f)); if (e != 0) { result.m_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).m_elements); for (int i = vec.Length - 1; i >= 0; i--) { vec[i] ^= m_elements[i]; } return(new GF2Vector(Length, vec)); }
/// <summary> /// Encrypt a plain text message /// </summary> /// /// <param name="Input">The plain text</param> /// /// <returns>The cipher text</returns> public byte[] Encrypt(byte[] Input) { if (!_isEncryption) throw new CryptoAsymmetricSignException("FujisakiCipher:Encrypt", "The cipher is not initialized for encryption!", new ArgumentException()); // generate random vector r of length k bits GF2Vector r = new GF2Vector(_K, _rndEngine); // 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)_asmKey, r, z).GetEncoded(); byte[] c2; // get PRNG object using (KDF2Drbg sr0 = new KDF2Drbg(GetDigest(_cprParams.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); }
public byte[] Encrypt(byte[] Input) { if (!_isEncryption) throw new CryptoAsymmetricSignException("PointchevalCipher:Encrypt", "The cipher is not initialized for encryption!", new ArgumentException()); int kDiv8 = _K >> 3; // generate random r of length k div 8 bytes byte[] r = new byte[kDiv8]; _rndEngine.GetBytes(r); // generate random vector r' of length k bits GF2Vector rPrime = new GF2Vector(_K, _rndEngine); // convert r' to byte array byte[] rPrimeBytes = rPrime.GetEncoded(); // compute (input||r) byte[] mr = ByteUtils.Concatenate(Input, r); // compute H(input||r) _dgtEngine.BlockUpdate(mr, 0, mr.Length); byte[] hmr = new byte[_dgtEngine.DigestSize]; _dgtEngine.DoFinal(hmr, 0); // convert H(input||r) to error vector z GF2Vector z = CCA2Conversions.Encode(_N, _T, hmr); // compute c1 = E(rPrime, z) byte[] c1 = CCA2Primitives.Encrypt((MPKCPublicKey)_asmKey, rPrime, z).GetEncoded(); byte[] c2; // get PRNG object using (KDF2Drbg sr0 = new KDF2Drbg(GetDigest(_cprParams.Digest))) { // seed PRNG with r' sr0.Initialize(rPrimeBytes); // generate random c2 c2 = new byte[Input.Length + kDiv8]; sr0.Generate(c2); } // XOR with input for (int i = 0; i < Input.Length; i++) c2[i] ^= Input[i]; // XOR with r for (int i = 0; i < kDiv8; i++) c2[Input.Length + i] ^= r[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> /// 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> /// Copy constructor /// </summary> /// /// <param name="G">The GF2Vector to copy</param> public GF2Vector(GF2Vector G) { this.Length = G.Length; this.m_elements = IntUtils.DeepCopy(G.m_elements); }
/// <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> /// 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; }