mce_qd: code generation
This commit is contained in:
		
							parent
							
								
									8162d6979c
								
							
						
					
					
						commit
						b04c1508ee
					
				|  | @ -49,6 +49,9 @@ public: | |||
| 	void to_poly (polynomial&, gf2m&); | ||||
| 	void from_poly (const polynomial&, gf2m&); | ||||
| 
 | ||||
| 	void to_poly_cotrace (polynomial&, gf2m&); | ||||
| 	void from_poly_cotrace (const polynomial&, gf2m&); | ||||
| 
 | ||||
| 	void colex_rank (bvector&); | ||||
| 	void colex_unrank (bvector&, uint n, uint k); | ||||
| }; | ||||
|  | @ -127,8 +130,12 @@ public: | |||
| 	void compute_inversion (permutation&) const; | ||||
| 
 | ||||
| 	void generate_random (uint n, prng&); | ||||
| 	void permute (const bvector&, bvector&) const; | ||||
| 	void permute (const matrix&, matrix&) const; | ||||
| 
 | ||||
| 	template<class V> void permute (const V&a, V&r) const { | ||||
| 		r.resize (a.size() ); | ||||
| 		for (uint i = 0; i < size(); ++i) r[item (i) ] = a[i]; | ||||
| 	} | ||||
| 
 | ||||
| 	void permute_rows (const matrix&, matrix&) const; | ||||
| }; | ||||
| 
 | ||||
|  | @ -324,13 +331,27 @@ int generate (pubkey&, privkey&, prng&, uint m, uint t); | |||
|  * according to Misoczki, Barreto, Compact McEliece Keys from Goppa Codes. | ||||
|  * | ||||
|  * Good security, extremely good speed with extremely reduced key size. | ||||
|  * Recommended for encryption. | ||||
|  * Recommended for encryption, but needs some plaintext conversion -- either | ||||
|  * Fujisaki-Okamoto or Kobara-Imai are known to work good. | ||||
|  */ | ||||
| namespace mce_qd | ||||
| { | ||||
| class privkey | ||||
| { | ||||
| public: | ||||
| 	std::vector<uint> essence; | ||||
| 	gf2m fld;   //we fix q=2^fld.m=fld.n, n=q/2
 | ||||
| 	uint T;     //the QD's t parameter is 2^T.
 | ||||
| 	uint hperm; //dyadic permutation of H to G
 | ||||
| 	permutation block_perm; //order of blocks
 | ||||
| 	uint block_count; //blocks >= block_count are shortened-out
 | ||||
| 	std::vector<uint> block_perms; //dyadic permutations of blocks
 | ||||
| 
 | ||||
| 	//derivable stuff
 | ||||
| 	std::vector<uint> Hsig; //signature of canonical H matrix
 | ||||
| 	std::vector<uint> support; //computed goppa support
 | ||||
| 	polynomial g; //computed goppa polynomial
 | ||||
| 
 | ||||
| 	int decrypt (const bvector&, bvector&); | ||||
| 	int prepare(); | ||||
| 
 | ||||
|  | @ -340,37 +361,25 @@ public: | |||
| 	uint plain_size() { | ||||
| 		return 0; //TODO
 | ||||
| 	} | ||||
| 	uint hash_size() { | ||||
| 		return 0; //TODO
 | ||||
| 	} | ||||
| 	uint signature_size() { | ||||
| 		return 0; //TODO
 | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| class pubkey | ||||
| { | ||||
| public: | ||||
| 	matrix G; | ||||
| 	uint t; | ||||
| 	uint T; | ||||
| 	matrix M; | ||||
| 
 | ||||
| 	int encrypt (const bvector&, bvector&, prng&); | ||||
| 
 | ||||
| 	uint cipher_size() { | ||||
| 		return G.height(); | ||||
| 		return 0; //TODO
 | ||||
| 	} | ||||
| 	uint plain_size() { | ||||
| 		return G.width(); | ||||
| 	} | ||||
| 	uint hash_size() { | ||||
| 		return cipher_size(); | ||||
| 	} | ||||
| 	uint signature_size() { | ||||
| 		return plain_size(); | ||||
| 		return 0; //TODO
 | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| int generate (pubkey&, privkey&, prng&, uint m, uint t); | ||||
| int generate (pubkey&, privkey&, prng&, uint m, uint T, uint b); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  |  | |||
|  | @ -62,6 +62,23 @@ void bvector::from_poly (const polynomial&r, gf2m&fld) | |||
| 		item (i) = (r[i/fld.m] >> (i % fld.m) ) & 1; | ||||
| } | ||||
| 
 | ||||
| void bvector::to_poly_cotrace (polynomial&r, gf2m&fld) | ||||
| { | ||||
| 	r.clear(); | ||||
| 	if (size() % fld.m) return; //impossible
 | ||||
| 	r.resize (size() / fld.m, 0); | ||||
| 	for (uint i = 0; i < size(); ++i) | ||||
| 		if (item (i) ) r[i%fld.m] |= (1 << (i / fld.m) ); | ||||
| } | ||||
| 
 | ||||
| void bvector::from_poly_cotrace (const polynomial&r, gf2m&fld) | ||||
| { | ||||
| 	clear(); | ||||
| 	resize (r.size() *fld.m, 0); | ||||
| 	for (uint i = 0; i < size(); ++i) | ||||
| 		item (i) = (r[i%fld.m] >> (i / fld.m) ) & 1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * utility colex (un)ranking for niederreiter and workalikes. | ||||
|  * see Ruskey's Combinatorial Generation, algorithm 4.10 | ||||
|  |  | |||
							
								
								
									
										153
									
								
								lib/mce_qd.cpp
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								lib/mce_qd.cpp
									
									
									
									
									
								
							|  | @ -6,28 +6,157 @@ using namespace ccr::mce_qd; | |||
| 
 | ||||
| #include "decoding.h" | ||||
| 
 | ||||
| int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, uint m, uint t) | ||||
| #include <set> | ||||
| 
 | ||||
| static uint sample_from_u (gf2m&fld, prng&rng, std::set<uint>&used) | ||||
| { | ||||
| 	uint x; | ||||
| 	for (;;) { | ||||
| 		x = rng.random (fld.n); | ||||
| 		if (used.count (x) ) continue; | ||||
| 		used.insert (x); | ||||
| 		return x; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static uint choose_random (uint limit, prng&rng, std::set<uint>used) | ||||
| { | ||||
| 	if (used.size() >= limit - 1) return 0; //die
 | ||||
| 	for (;;) { | ||||
| 		uint a = 1 + rng.random (limit - 1); | ||||
| 		if (used.count (a) ) continue; | ||||
| 		used.insert (a); | ||||
| 		return a; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int mce_qd::generate (pubkey&pub, privkey&priv, prng&rng, | ||||
|                       uint m, uint T, uint block_count) | ||||
| { | ||||
| 	priv.fld.create (m); | ||||
| 	priv.T = T; | ||||
| 	uint t = 1 << T; | ||||
| 
 | ||||
| 	//convenience
 | ||||
| 	gf2m&fld = priv.fld; | ||||
| 	std::vector<uint>&Hsig = priv.Hsig; | ||||
| 	std::vector<uint>&essence = priv.essence; | ||||
| 	std::vector<uint>&support = priv.support; | ||||
| 	polynomial&g = priv.g; | ||||
| 
 | ||||
| 	//prepare for data
 | ||||
| 	Hsig.resize (fld.n / 2); | ||||
| 	support.resize (fld.n / 2); | ||||
| 	essence.resize (m); | ||||
| 	//note that q=2^m, algo. n=q/2, log n = m-1
 | ||||
| 
 | ||||
| 	//retry generating until goppa code is produced.
 | ||||
| 	for (;;) { | ||||
| 
 | ||||
| 		std::set<uint> used; | ||||
| 		used.clear(); | ||||
| 
 | ||||
| 		//first off, compute the H signature
 | ||||
| 
 | ||||
| 		Hsig[0] = choose_random (fld.n, rng, used); | ||||
| 		essence[m-1] = fld.inv (Hsig[0]); | ||||
| 		//essence[m-1] is now used as precomputed 1/h_0
 | ||||
| 
 | ||||
| 		for (uint s = 0; s < m - 1; ++s) { | ||||
| 			uint i = 1 << s; //i = 2^s
 | ||||
| 
 | ||||
| 			Hsig[i] = choose_random (fld.n, rng, used); | ||||
| 			essence[s] = fld.add (essence[m-1], fld.inv (Hsig[i]) ); | ||||
| 			used.insert (fld.inv (essence[s]) ); | ||||
| 
 | ||||
| 			for (uint j = 1; j < i; ++j) { | ||||
| 				Hsig[i+j] = fld.inv ( | ||||
| 				                fld.add ( | ||||
| 				                    fld.inv (Hsig[i]), | ||||
| 				                    fld.add ( | ||||
| 				                        fld.inv (Hsig[j]), | ||||
| 				                        essence[m-1] | ||||
| 				                    ) ) ); | ||||
| 				used.insert (Hsig[i+j]); | ||||
| 				used.insert (fld.inv ( | ||||
| 				                 fld.add ( | ||||
| 				                     fld.inv (Hsig[i+j]), | ||||
| 				                     essence[m-1]) ) ); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		//from now on, we fix 'omega' from the paper to zero.
 | ||||
| 
 | ||||
| 		//compute the support, retry if it has two equal elements.
 | ||||
| 		used.clear(); | ||||
| 		bool consistent = true; | ||||
| 		for (uint i = 0; i < fld.n / 2; ++i) { | ||||
| 			support[i] = fld.add ( | ||||
| 			                 fld.inv (Hsig[i]), | ||||
| 			                 essence[m-1]); | ||||
| 
 | ||||
| 			if (used.count (support[i]) ) { | ||||
| 				consistent = false; | ||||
| 				break; | ||||
| 			} | ||||
| 			used.insert (support[i]); | ||||
| 		} | ||||
| 		if (!consistent) continue; //retry
 | ||||
| 
 | ||||
| 		//assemble goppa polynomial.
 | ||||
| 		g.clear(); | ||||
| 		g.resize (1, 1); //g(x)=1 so we can multiply it
 | ||||
| 		polynomial tmp; | ||||
| 		tmp.resize (2, 1); //tmp(x)=x-1
 | ||||
| 		for (uint i = 0; i < t; ++i) { | ||||
| 			//tmp(x)=x-z=x-(1/h_i)
 | ||||
| 			tmp[0] = fld.inv (Hsig[i]); | ||||
| 			g.mult (tmp, fld); | ||||
| 		} | ||||
| 
 | ||||
| 		//now the blocks.
 | ||||
| 		uint block_size = 1 << T, | ||||
| 		     h_block_count = (fld.n / 2) / block_size; | ||||
| 
 | ||||
| 		//assemble blocks to bl
 | ||||
| 		std::vector<std::vector<uint> > bl, blp; | ||||
| 		bl.resize (block_size); | ||||
| 		for (uint i = 0; i < h_block_count; ++i) | ||||
| 			bl[i] = std::vector<uint> | ||||
| 			        (Hsig.begin() + i * block_size, | ||||
| 			         Hsig.begin() + (i + 1) * block_size); | ||||
| 
 | ||||
| 		//permute them
 | ||||
| 		permutation bp; | ||||
| 		bp.generate_random (h_block_count, rng); | ||||
| 		bp.permute (bl, blp); | ||||
| 
 | ||||
| 		//discard blocks
 | ||||
| 		blp.resize (block_count); | ||||
| 
 | ||||
| 		//TODO permute individual blocks
 | ||||
| 
 | ||||
| 		//TODO co-trace to binary H^
 | ||||
| 		//TODO systematic H
 | ||||
| 		//TODO systematic G
 | ||||
| 		//TODO signature of G
 | ||||
| 
 | ||||
| 		return 0; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int privkey::prepare() | ||||
| { | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int pubkey::encrypt (const bvector& in, bvector&out, prng&rng) | ||||
| { | ||||
| 	uint s = cipher_size(); | ||||
| 	if (t > s) return 1; | ||||
| 	if (in.size() != plain_size() ) return 2; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int privkey::decrypt (const bvector&in, bvector&out) | ||||
| { | ||||
| 	if (in.size() != cipher_size() ) return 2; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| int privkey::prepare () | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -27,18 +27,6 @@ void permutation::generate_random (uint size, prng&rng) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| void permutation::permute (const bvector&a, bvector&r) const | ||||
| { | ||||
| 	r.resize (a.size() ); | ||||
| 	for (uint i = 0; i < size(); ++i) r[item (i) ] = a[i]; | ||||
| } | ||||
| 
 | ||||
| void permutation::permute (const matrix&a, matrix&r) const | ||||
| { | ||||
| 	r.resize (a.size() ); | ||||
| 	for (uint i = 0; i < size(); ++i) r[item (i) ] = a[i]; | ||||
| } | ||||
| 
 | ||||
| void permutation::permute_rows (const matrix&a, matrix&r) const | ||||
| { | ||||
| 	r.resize (a.size() ); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue